mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-11-07 06:19:43 -10:00
main
457
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
208beb2b3b |
chore(release): v0.26.9 [skip ci]
* chore(release): v0.26.9 * docs(changelog): sync for v0.26.9 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
3718b57fa8 |
chore(release): v0.26.8 (#16409)
* chore(release): v0.26.8 * docs(changelog): sync for v0.26.8 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
08f1843c22 |
feat(mods): run the prompts a Mod submits in the Ink terminal (#16373)
* feat(mods): run the prompts a Mod submits in the Ink terminal * test(mods): run a Mod's prompt in a real Ink terminal * fix(mods): stop a Mod's prompts when the person stops a turn in Ink - Esc or declining every tool a turn asks to run drops the Mods' queued prompts and refuses new ones until the person sends a prompt again. The stopped turn's turn.complete hooks run after the stop, and a call a hook does not await reaches the host after the hook returns, so dropping the queue alone let such a hook start the next turn. $.turn.abort still keeps the queue. - A Monitor update waiting out its minimum interval no longer holds a Mod's prompt, which a Monitor printing within every interval held for good. - A prompt put back after losing the idle moment runs once the winning submission settles, since that one may start no turn. - The dual-output sidecar gets the Mod's text and a mod_prompt system message, as a stream-json client does, instead of the frame. - The guide's capability table lists Ink for a Mod's turn events. * fix(mods): drain Mod prompts after any settle and strip a stopped one A Mod prompt queued while a submission that starts no turn held the session (a cron's Mod command, a notification dropped before sending) stayed queued with the session idle: the drain re-ran on settle only for a prompt it had put back. Re-run it whenever a Mod prompt waits. When the person stops a Mod prompt's turn before it answers, the framed prompt stayed at the end of the model history, so the next prompt reached the model behind it. The cancel info now says the turn ran a Mod's prompt, and the handler strips it as it does a Goal continuation's. * fix(mods): run a waiting Mod prompt once a Goal lets go of the turns A Mod prompt queued while a Goal owned the session's turns waited for the next submission to settle or another prompt to be queued. The Goal often releases its turns after the session is already idle (its verifier accepts, its last turn is released), so the prompt could sit until some unrelated event. The drain now also re-runs on the Goal runtime's broadcasts while a Mod prompt waits. The test no longer queues a second prompt to wake the drain; it changes the Goal snapshot and broadcasts, and fails without the fix. |
||
|
|
de6ccb4e3c |
feat(serve): allow configuring the Conversations working-directory root (#16105)
* feat(serve): allow configuring the Conversations working-directory root * test(serve): register Conversations root E2E in no-AK CI * fix(serve): address Conversations root review feedback * fix(serve): clarify Conversations root configuration errors --------- Co-authored-by: Jiankai Xiao <[email protected]> |
||
|
|
a818643533 |
feat(mods): let a Mod submit a prompt of its own in headless runs (#16302)
* feat(mods): let a Mod submit a prompt of its own in headless runs
$.prompt.submit({ text, asUser? }) raises prompt.submit through every hook
but the caller's, with the Mod as its origin, and queues what arrives
beneath them. The headless run takes it once idle and runs it as a turn of
its own: UserPromptSubmit hears it, turn.start and turn.complete fire, and
the transcript records it with the provenance mod_prompt and the Mod's
name. Unless the Mod passes asUser, the model reads the text inside a block
that names the Mod and says the person did not type it.
The call resolves once its prompt is queued, as next(e) does for a typed
prompt. The Mods' prompts start at most 8 turns before the person sends a
prompt. The terminals do not run these prompts yet: there the method is not
listed and a call resolves to a drop.
* fix(mods): queue a Mod's prompt once, outside its caller's lifetime
- Run the hooks a `$.prompt.submit` raises outside the calling hook, so a
call the hook does not await still queues after the hook returns.
- Queue what last arrived beneath the hooks once they have all answered,
so a hook that calls `next(e)` twice queues one prompt.
- Drop an empty or whitespace-only text, from the call or from a hook.
- Discard Mod prompts that have not started when a headless run ends, so a
stream-json session does not run them on the client's next message.
- Escape every `<` and `>` in the framed text.
- Recall memory for the Mod's text rather than the frame, keep a Mod's
prompt out of the session title (in its turn's place) and out of the
commit attribution's prompt count.
* fix(mods): keep the title, SDK output and turn count right for Mod prompts
- Mark a Mod's prompt as `null` in the title projection, not `''`, so it
no longer switches a session whose prompts recorded no display text to
an empty projection, which stopped auto-title and `/rename --auto`.
- Tell a stream-json client of a Mod's prompt: its text as a user message,
then a `mod_prompt` system message naming the Mod, before the turn runs.
- Reset the Mods' turn count for the person's slash commands too.
- End a Mod turn that a duplicate provider call stops as an error on the
shared loop, as on the legacy loop and for the main turn.
- Refuse a prompt submitted while /clear or /resume ends the session, and
start the new session with nothing queued and the count at 0.
* fix(mods): keep charging a hook while the other Mods hear its submit
A $.prompt.submit call outlives its caller, yet it lent the caller's
budget for the whole submit chain, so a hook that did not await it ran
unbudgeted until the other Mods' prompt.submit hooks answered. It now
runs as the void notices do, charging the caller as it goes.
The frame also no longer says the Mod sent its prompt while the session
was idle: most are sent mid-turn and wait for the session to be idle.
* fix(mods): run a Mod command's submitted prompt and keep it out of the title
A Mod command in a headless run always answers with a message, and that
branch returned before the drain, so a prompt the command submitted with
$.prompt.submit was discarded while the call had resolved as queued. The
reply is now shown without a turn of its own and the run goes on to the
drain, ending with one result.
A session whose prompts recorded no display text drew its title from the
conversation, which held the Mod's framed prompt. The recorder now keeps
the text the model read for each Mod prompt, and the conversation-based
title leaves those messages out.
* fix(mods): keep a Mod's prompt within its payload and its command's reply in view
- Drop a submitted prompt past half a Mod payload, from the call or a
hook's rewrite, before it is queued, so a queued prompt is never
reported as failed; an input too large for the bridge now rejects.
- Print a Mod command's reply in text output, and give the worktree notice
the command would have carried to the first request the run sends.
- Leave an `asUser` Mod prompt out of the title keys, which matched a
prompt the person typed alike, and keep the keys least recently used.
- Make Goal evidence leave a Mod's prompt out explicitly.
- Pin the documented turn limit and the tool-result guard in tests, and
add a built-CLI test of `$.prompt.submit` against the fake server.
- Docs: six steps, the non-goal narrowed, the hook docs and the budget
paragraph naming Mod prompts.
* test(mods): run the $.prompt.submit integration test in the no-AK job
|
||
|
|
a85370b38f |
feat(cli): run the Ink TUI's model rounds on the shared loop's round (#16206)
* feat(cli): run the Ink TUI's model rounds on the shared loop's round With experimental.unifiedAgentLoop on, every model round of the Ink TUI goes through the shared loop's runModelRound, which collects the tool calls, drops those of an attempt a retry or fallback replaced, and turns the client's terminal events into a stop reason. The TUI keeps its stream processor and its tool step. Adds the Ink parity suite. Part of #15327. * test(cli): tighten the Ink parity suite and fix the no-AK script pin - add the suite to the no-AK script pin - check each run's request count, and through the debug log that only the run with the setting on sends its rounds on the shared loop - compare the system prompt, the tools offered and recorded usage - run each scenario once, without the root config's retries, with a source pin - describe the suite as it is in the design doc - say in the setting's description that the Ink TUI sends its model requests through the shared loop |
||
|
|
7d5a82443a |
chore(release): v0.26.7 [skip ci]
* chore(release): v0.26.7 * docs(changelog): sync for v0.26.7 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
b1cd4ac0c6 |
refactor(managed-agent): align shared MySQL schema conventions (#16143)
* docs(managed-agent): document database tables and columns * refactor(managed-agent): align shared MySQL schema conventions |
||
|
|
5e267805c3 |
chore(release): v0.26.6 (#16163)
* chore(release): v0.26.6 * docs(changelog): sync for v0.26.6 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
e26f377a28 |
chore(release): v0.26.5 (#16035)
* chore(release): v0.26.5 * docs(changelog): sync for v0.26.5 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Shaojin Wen <[email protected]> |
||
|
|
bc8ad53f95 |
test(managed-agent): gate the B3 round-and-cost-budget crash window (#15981)
* test(managed-agent): gate the B3 round-and-cost-budget crash window
Matrix row B3 ("after earlier tools") had focused/integration evidence
only: nothing crashed a replacement after several tool rounds and proved
the numeric round counter and the turn cost ledger survive it. A recovery
that restarts the round at 0 or zeroes the token ledger would pass CI.
Package the W2 window in hosted-failover-e2e: a multi-round fake fixture
runs two earlier tools (each its own approval, execution and file effect),
the replacement is crashed while the later post-tool request is held on
the fake-model side (no new serve hook), and the next generation must,
from MySQL alone after scrashing the crashed disk, resume the saved
logical round, restore the TurnBudget snapshot and per-model token ledger
(asserted as per-model output-token totals with non-vacuity guards, since
an unrestored ledger is a truthy {}), reissue the saved request deep-equal,
retract the published prefix, and project one terminal. "Cost budget" here
is the snapshot plus the ledger, not a cumulative spend gate.
Real-stack (.75) evidence: head green twice (round 2->2, budget 500000
deep-equal, ledger 600->700 = restored 600 + final round 100, parity equal,
both earlier Actions decided under their original IDs); three named
mutation kills (round reset, ledger wipe, snapshot re-baselining). The
execution-count assertion is defense-in-depth in this window: three
mutation cells survived because exactly-once rides three independent
guards (replay routing, continuation settled-batch adoption, Runtime
runtimeCallId idempotency), documented in the design.
No production behavior change; failover ceiling 26 -> 27 arms (285 min).
* test(managed-agent): harden the B3 arm per review (R1-1..R1-4)
R1-1: the W2 rationale claimed the saved request carries the budget; it
carries only the round (budget lives on the attempt's route/usage
resources). Corrected in both design languages.
R1-2: the behavioural fixture could not distinguish a newest-first from
an oldest-first budget/models scan, and the ledger assertion had only
text pins. Add a discriminating fixture (older attempt with a different
budget and smaller ledger) and lift the cost block into a top-level
assertB3CostContinuity helper with injected-state behavioural cases:
healthy growth passes; null-budget snapshot, missing snapshot,
re-baselined snapshot, empty before-ledger, zeroed after-ledger and
shrunk per-model totals all throw.
R1-3: the budget non-vacuity guard tested the snapshot object, but a
non-null snapshot with budget: null is a legal production state (lost
+Nk directive), so null == null passed vacuously. Guard the numeric
field instead.
R1-4: site-anchor the B3 post-tool request count (? 3) like the
neighbouring R1-7/F1 pins so a conflict resolution back to the pre-PR
ternary reds at unit speed, not only in the real-stack lane.
Each fix has a demonstrated witness: oldest-first scan, deleted ? 3
clause, object-truthy guard and candidates->prompt repath each red the
new cases/pins; all restored. Contract suites 132/132, typecheck green,
and the .75 head arm re-run with the hardened runner is green (round
2->2, budget 500000 deep-equal, ledger 600->700).
|
||
|
|
b3e9ce0cd1 |
test(managed-agent): gate the A3 mixed-sibling approval crash window (#15945)
* test(managed-agent): gate the A3 mixed-sibling approval crash window Package the native half of recovery-matrix row A3 (#14481) as a hosted-failover-e2e arm: crash a replacement inside a two-call approval batch (sibling[0] decided, sibling[1] still requested) and prove the surviving siblings recover from MySQL alone — earlier decisions persist, the pending sibling keeps its original Action/deadline and earns its own Allow, and both calls settle once each in their original order. The rewritten-input / Hook-no-rerun half stays a commandStep follow-up because a native continuation refuses Hook/MCP sessions. * chore: re-trigger CI after the main merge The web 'Update branch' merge incorporated main's .prettierignore (lint gate freshness) but did not trigger a CI run on the updated head; this empty commit re-triggers the lanes on the merged tree. * test(managed-agent): harden the A3 arm per review (R1-1..R1-7) Address the seven inline review suggestions on the mixed-sibling approval arm: read the decided sibling and require it still decided with its original deadline before answering the pending one (R1-4); gate execution settle order on settled_at along the plan (R1-5); add an ascending-link behavioural case so a first-match plan-link selection reds (R1-6); anchor the execution-count pin and pin the per-call identity loop (R1-7). Correct the design docs in both languages: the fixture is two write_file calls, the validation plan lists the reds actually produced, and the arm proves matrix clauses 1-2 plus a narrower pending-sibling observation, not the rewritten-input clause 3 (R1-1/R1-2/R1-3). |
||
|
|
0c1b42fa31 |
test(managed-agent): gate the B3a finished-before-commit crash window (#15881)
* test(managed-agent): gate the B3a finished-before-commit crash window Package the recovery-matrix B3a row: crash the replacement Harness after its post-tool main stream records the durable Finished marker but before the assistant output commits. A test-gated hook (QWEN_E2E_CRASH_BEFORE_ASSISTANT_COMMIT, set only on the crashing generation, never in production) holds the turn in that window; the runner asserts the barrier landed, kills the generation, and requires the next one to reissue the saved request deep-equal and project one terminal with the recovered answer rather than compensate an already-committed output. Adds the failover arm, CI step and ceiling (25 arms), contract pins, the serve env-guard allowance, and bilingual design/README updates. * test(managed-agent): harden the B3a arm barrier, hold and contract pins Address review R1-1..R1-4: assert the durable crash precondition (the approved execution SETTLED) from MySQL before the SIGKILL like the sibling crash arms, instead of trusting the hook log alone; wire the test-gated hold to the Turn abort signal so a leaked flag cannot park a real Session uncancellably; pin the crashing/recovery generation call sites and the parameter default rather than bare identifiers; and pin the combined deep-equal parity gate so reverting it to after-result-only reds the fast-tier contract suite. * test(managed-agent): assert the B3a crash window from the durable journal The finished-before-commit barrier proved only that the approved execution settled (executionAtCrash=SETTLED) and that the hook printed its log line. It did not read the post-tool main model attempt's durable Finished marker, so a hold moved above the model layer's usage-only output_committed commit could crash with no durable Finished marker and still pass every downstream check (the recovery reader also accepts a saved request whose attempt is started). Before the SIGKILL, read the same journal the recovery reads (ma_session_journal_tx) and assert findHostedCommittedModelOutput's own discriminator: the latest <promptId>:main: model.attempt is output_committed and no assistant message.committed follows it. Retain the attempt identity and sequence in approval-crash-barrier.json. Add a window-shaped fast-tier contract pin for the new assertion, keeping the existing pins. Verified on real MySQL/Spring/Broker: head green (attempt retained, parity equal); moving the hold above output_committed reds at the new pre-crash assertion; removing the hook still reds at the barrier timeout; moving the hook after the assistant commit now reds at the new post-commit assertion. * test(cli): cover the finished-before-commit hold's abort release The QWEN_E2E_CRASH_BEFORE_ASSISTANT_COMMIT hold's abort wiring had no test that reds without it: the env-guard only counts AST reads, the meta-tests grep source text, and the packaged arm SIGKILLs the pending generation, so no lane exercised the release path. Arm the module-scope switch via a vi.hoisted env stub set before the static import under a dedicated Session id, then drive a real turn into the hold and assert the abort settles it cancelled with no assistant message.committed; a non-matching-id case pins that the hold never fires. Removing the release/addEventListener wiring makes the matching case time out. Test-only; the single env read and the hold's park-until-killed behaviour are unchanged. * test(managed-agent): pin the B3a hold id-guard and window arming R4-1: run the non-matching finished-before-commit hold case before the abort case so the module-scope one-way latch is still unset, letting the session-id comparison (not a spent latch) suppress the hold. Deleting the id conjunct now reds the non-matching case. R4-2: pin the finishedBeforeCommitWindow arming ternary condition, so narrowing its guard can no longer silently delete the arm's only durable-window check while the scripts suite stays green. * test(managed-agent): exercise the B3a window helper on injected journal rows Address the round-5 deferred suggestion: finishedBeforeCommitWindow had only source-spelling pins. Add a behavioural test that injects runMysql through the existing load() machinery and asserts the latest-attempt selection and both throw branches on journal rows (the output_committed window holds; a started or newer-started latest attempt reds before the Finished marker; a following assistant commit reds after it; role/prompt/sequence filters hold). Witness: mutating the latest-attempt index to mainAttempts[0] — a change the source pins survive — reds the behavioural test. |
||
|
|
d4e8d9ffde |
test(managed-agent): gate the A4 takeover-load reply-loss handoff (#15857)
* test(managed-agent): gate the A4 takeover-load reply-loss handoff The A4 load half was recorded as a recovery gap (a lost takeover-load reply leaving the original Turn stuck RUNNING). On the current tree that variant does not reproduce: when the replacement loses the reply to its first drive load and the control plane redrives the same load into the now-active driver, the redrive restates the active attachment and the original Turn projects exactly one terminal with the recovered answer. Two clean real-stack runs (Linux aarch64, MySQL 8.0.46, JDK 21) recover correctly with the fault injected. Rather than leave the row focused, package it as a regression gate so the handoff cannot silently regress: - A test-gated Harness hook (QWEN_E2E_DROP_LOAD_REPLY=<sessionId>, set only on the replacement by the arm, never in production) destroys the first load attach reply once, after the driver started. - The arm asserts the reply was actually lost (via the replacement's captured log) before trusting the recovery, then requires one terminal, the recovered answer, one settled execution and one file effect. - Refusing the redrive's active-branch restatement makes the arm fail at the adoption barrier, proving the gate is load-bearing. The failover job grows to 24 arms (ceiling 255). The bilingual Step 3 design and the server README flip the A4 load row from a focused gap to packaged and note that the earlier stuck-RUNNING variant did not reproduce on the current tree. * test(cli): document the A4 load-reply fault flag in the serve env guard The packaged load-reply-lost arm reads QWEN_E2E_DROP_LOAD_REPLY once at session-bridge construction in hosted-harness-session.ts. The serve process.env guard requires every access to be a documented process-scoped exception, so register the test-gated flag with its reason. Fixes the Qwen Code CI env-guard red on the merged head. |
||
|
|
ae51b081ce |
chore(release): v0.26.4 [skip ci]
* chore(release): v0.26.4 * docs(changelog): sync for v0.26.4 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
702c1773a1 |
fix(managed-agent): retry owed Hosted cleanup after its generation dies (#15824)
* test(managed-agent): gate G3 cleanup and terminal recovery faults Add three packaged fault arms to hosted-failover-e2e: a refused Runtime cleanup release followed by another crash, a committed terminal whose reply is lost, and a refused terminal write over a payable checkpoint. Each keeps the original Action, execution, file effect and terminal identity, and the runner now witnesses the fault on the store or Broker boundary rather than on a client-side retry. Part of #14481. * test(managed-agent): harden the G3 cleanup and terminal fault arms Drop every bounded terminal retry so the terminal reply-loss crash lands on a committed-but-undelivered terminal, and require the surviving public transcript to carry the recovered answer. Document both observations. Part of #14481. * test(managed-agent): address the G3 terminal arm review findings Arm C1's crash barrier only on a confirmed store 200, record that pre-crash count, and state that the replacement projects the committed terminal without a second store commit. Snapshot fault counts before the relief Turn, keep the result-commit diagnostic for after-result, and fail loudly on an unhandled crash barrier. Remove the cleanup arm: a delayed replacement reproduces a control-plane cleanup/adoption gap, so C3 stays open as a product follow-up. Part of #14481. * fix(managed-agent): retry owed Hosted cleanup after its generation dies A Turn that completed with cleanup still owed had no driver once its Harness generation died: no Turn was left to dispatch, and the operator recheck route was the only path that could pay the durable `HOSTED_CLEANUP` projection. A delayed replacement therefore never received a load, kept the original Runtime binding family retained, and the packaged C3 arm passed or failed depending on whether the terminal projection beat the crash. The control plane now scans that projection. For each Session with no active Turn it resolves the owed Turn from the cleanup descriptor and issues the existing prompt-scoped cleanup-only load, which pays the original Runtime identity and commits `confirmed`. Attempts back off in memory from 10 seconds to 5 minutes, one debt per Session per scan tick, and a failed attempt drops the connector's cached attachment so the retry performs its own cold load. Unreadable or foreign descriptors are logged once and stay owed. The C3 arm is packaged again: it refuses every release until the crash, waits for the control plane to project the terminal before killing the generation, and requires the replacement's own release, one `confirmed` event and no remaining debt. Disabling the scan makes it time out at the retry barrier. Design: docs/design/2026-10-28-hosted-cleanup-debt-retry.md * fix(managed-agent): qualify the cleanup retry executor and clock Main now publishes the shared executor and clock as named beans, and every coordinator injects them by qualifier. Without the qualifiers the new coordinator fails context startup, which breaks every Hosted Spring test and the packaged server. * fix(managed-agent): keep a live attachment when a cleanup retry is refused The debt scan dropped the connector's cached attachment on every failure. A named refusal (409/503: a Turn still owns the Session, or recovery is required) is not evidence that the cached generation is dead, and evicting it churns a Session whose Turn is still running — the scan can race a Turn admitted between its query and its attempt. Only transport loss, a moved generation, a vanished reference (404) and the connector's own generation-moved signals now evict; a named refusal just backs off. Two tests pin both sides, and the design and README state the rule. * fix(managed-agent): address the cleanup debt scan review findings Two P2 findings from the review of the cleanup debt retry: The store injected an unqualified JdbcTemplate. In an embedded deployment the managed template is defaultCandidate=false, so the scan bound the host's business database and failed every tick with "ma_resource_ref not found", never retrying the dedicated database's debts. Qualify the injection with managedJdbcTemplate; a new embedding regression test fails with the exact table-not-found error when the qualifier is removed. The scan always read the oldest fixed page and validated descriptors after the LIMIT, so a prefix of unclearable debts (unsupported profile, unreadable descriptor) starved every recoverable debt behind it across all Sessions and tenants. Make the scan keyset-paginated: the cursor advances over every raw row it reads, including unreadable ones, and wraps when a page comes up short. Pacing entries now expire by idle time rather than by page membership, so rotation never resets a still-owed debt's backoff. New tests pin the cursor advancing past an unreadable prefix and wrapping on a short page; reverting the cursor to advance only over valid rows reproduces the starvation. The packaged C3 arm and the terminal reply-loss regression stay green on the real MySQL/Spring/Broker stack after both changes. * fix(managed-agent): address the second cleanup debt review round - Name the scheduler. retryOwedCleanup was the module's only @Scheduled tick without scheduler = "managedAgentScheduler"; managedAgentScheduler is defaultCandidate=false, so the bare tick bound the shared one-thread sessionWorktreeScheduler that a blocking Git scan already owns. Align it with its siblings and pin its 1s fallback in the (now four-site) scan-delay test. - Register HostedCleanupDebtStore in the row-lock-order audit. Its read-only NOT EXISTS guard on ma_turn made it a turn reader, so the exact-set sibling boundary test (SessionRowLockOrderTest) failed on SDK Java (fast). It takes no row lock and never writes, so it is a turn reader but not a session locker; list it explicitly rather than relax the audit. - Classify attachment staleness by an explicit whitelist mirroring HarnessPoolConnector's reachability set (transport loss, moved generation, unknown mutation outcome) plus 404/5xx. Named refusals that are not DaemonHttpException — HostedHarnessRecoveryDeclinedException, harness_pool_unavailable — and 4xx now only back off instead of evicting a live Session's attachment. A table-driven test pins every branch; reverting the fallback to "evict" reds the declined and pool-unavailable cases. - Pin the backoff ladder (10/20/40/80/160/300) and prove the idle-time prune keeps a still-owed debt's backoff when it leaves the scan page; clearing the pacing map each tick reds that test. The packaged C3 arm and the terminal reply-loss regression stay green on the real MySQL/Spring/Broker stack. |
||
|
|
08d97f383a |
chore(release): sdk-typescript v0.1.25 [skip ci]
* chore(release): v0.26.3 * chore(release): sdk-typescript v0.1.25 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
c3e1c9bcd6 |
test(managed-agent): gate G3 terminal recovery faults (#15756)
* test(managed-agent): gate G3 cleanup and terminal recovery faults Add three packaged fault arms to hosted-failover-e2e: a refused Runtime cleanup release followed by another crash, a committed terminal whose reply is lost, and a refused terminal write over a payable checkpoint. Each keeps the original Action, execution, file effect and terminal identity, and the runner now witnesses the fault on the store or Broker boundary rather than on a client-side retry. Part of #14481. * test(managed-agent): harden the G3 cleanup and terminal fault arms Drop every bounded terminal retry so the terminal reply-loss crash lands on a committed-but-undelivered terminal, and require the surviving public transcript to carry the recovered answer. Document both observations. Part of #14481. * test(managed-agent): address the G3 terminal arm review findings Arm C1's crash barrier only on a confirmed store 200, record that pre-crash count, and state that the replacement projects the committed terminal without a second store commit. Snapshot fault counts before the relief Turn, keep the result-commit diagnostic for after-result, and fail loudly on an unhandled crash barrier. Remove the cleanup arm: a delayed replacement reproduces a control-plane cleanup/adoption gap, so C3 stays open as a product follow-up. Part of #14481. |
||
|
|
5180685d97 |
chore(release): sdk-typescript v0.1.24 [skip ci]
* chore(release): v0.26.2 * chore(release): sdk-typescript v0.1.24 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
9a41afe0d4 |
feat: add persistent session Workflow mode (DW-04A) (#15422)
* feat(core): persist session Workflow mode and dispatch reminders * feat(sdk): expose session Workflow mode through native and daemon controls * feat(cli): add Workflow mode controls and end-to-end coverage * fix(cli): preserve pasted text when recalling prompt history * fix(sdk): complete Workflow mode routing and owner-safe replies * test: verify Workflow mode recording and Mod permission boundaries * test(sdk): select the secondary workspace ACP mount * test(cli): assert headless Workflow mode eligibility * fix(workflow): enforce owner trust for prompt mode writes * fix(workflow): keep daemon write policy out of MCP metadata * fix(workflow): preserve retry and restore state across lifecycle failures * fix(workflow): align ACP retry types with shared loop * test(workflow): isolate ACP cadence from followup suggestions * fix(sdk): close query after initialization failure * fix(cli): serialize workflow mode writes with session switches * fix(sdk): keep mode errors async and reject pending reinitialization * fix(cli): filter workflow mode from SSH raw session state * fix(cli): preserve workflow mode startup failures * fix(acp): refresh restored session config options * fix(core): rearm workflow notices after cancellation * fix(core): rearm workflow notices after failed switches --------- Co-authored-by: qqqys <[email protected]> |
||
|
|
3521066b4f |
feat(serve): allow secondary sessions to cd within their workspace (#15323)
* [to #DW-549] feat(serve): allow secondary session cd within its workspace * [to #DW-549] fix(serve): preserve cd rejection diagnostics * [to #DW-549] test(serve): cover session cd in no-AK CI --------- Co-authored-by: 罗辉 <[email protected]> Co-authored-by: 易良 <[email protected]> |
||
|
|
645d32eed3 |
feat(acp): run the model round of fresh prompts on the shared agent loop (#15509)
* feat(core): let a host run its own rounds on the shared model round ACP keeps its tool step while its model round moves to LlmClient, so it needs a few things the client did not expose: - Turn gives Thought the chunk's raw text and ToolCallRequest the functionCall it was built from; - with SendMessageOptions.toolCallPreparations, Turn yields a ToolCallPreparation event for a call the model started streaming, also in a blocking Stop hook's continuation; without it Turn yields the events it did, which matters to the Hosted Harness; - SendMessageOptions.userTurnRecordedByHost skips the UserQuery's user message record and todo work chain start; - admitUserPrompt takes the hook's submitted_prompt and a signal; - the agent loop exports runModelRound. Part of #15327. * docs(design): plan PR 2 in three steps and describe PR 2a * feat(acp): run the model round of fresh prompts on the shared agent loop With experimental.unifiedAgentLoop on, a fresh user prompt outside a Goal, channel or goal-proposal approval turn sends each model round through LlmClient via runModelRound. The client then does what ACP re-implements: UserPromptSubmit on the verdict admitUserPrompt took at the same point, memory recall, the file-history snapshot, system reminders, workflow intent, MessageDisplay, compaction, the session token gate and the external Stop hook. ACP keeps its tool step, its user message record, its Stop loop for the Todo Stop Guard and background results, mid-turn input and its session/update output. The Web Shell settings panel now lists the setting. A new no-AK suite drives ACP twice per scenario and requires the same requests, updates and stop reasons, apart from three asserted differences. Part of #15327. * docs(design): link the PR 2a pull request * fix(acp): keep the Stop hook in ACP's Stop loop on the shared round Review fixes for the shared model round of fresh ACP prompts: - the client skips its Stop hook (new stopHookRunByHost send option) and ACP's Stop loop fires it as with the setting off, so ACP's own continuations stay interruptible and are judged by the hook, and the Todo Stop Guard is suspended at the cap - the queued-input window closes when a response finishes - a round that ends with a stop reason discards its resolved tool cards - ACP throws the error the provider threw (getStructuredErrorCause) - one failure helper for both rounds, one compression notice, and getThoughtSummary built on getThoughtText * fix(acp): leave the interaction span and tool-call guards to ACP on the shared round Second review round for the shared model round of fresh ACP prompts: - interactionSpanByHost: the client neither starts nor ends an interaction span, so ACP's span (with its daemon parent) is the only one - toolLoopGuardsByHost: the client skips its always-on tool-call checks, the exploration budget and reminder, the stateful-read result checks and the tool-call heuristics (new LoopCheckOptions.toolCallPatterns); ACP's daemon guards stay the only ones, so the reminder is no longer sent twice - a stream Error is thrown after the round, so the client's error epilogue runs first - ACP schedules the managed memory tasks itself when no UserQuery or ToolResult round ended the response, as after queued input cut it short - parity: a scenario past the per-turn tool-call cap; fix the typecheck:integration errors in the parity suite * docs(design): list host-owned send options and move each surface's default on its own - Add a ledger of the send options that tell the client to skip part of its work for one host, with the step that removes each, and a Stop-point continuations subsection for ACP's own continuations. - Swap ACP's next steps: PR 2b moves the tool batch of fresh prompt turns onto the scheduler, PR 2c moves the other turns onto the whole loop, so each ACP loop body changes once. - Each surface changes its default on its own once it meets the listed conditions, starting with headless, and drops its current loop one release later. * fix(acp): keep tool-result recall and run memory tasks after the Stop loop on the shared round Third review round for the shared model round of fresh ACP prompts: - toolLoopGuardsByHost now skips only the tool-call guards, the exploration reminder and the todo reminder ACP's tool-result message carries; a tool-result send again delivers the memory recall and the queued loop reminder and runs the size-only microcompaction - under stopHookRunByHost the client no longer schedules the managed memory tasks when a round ends; ACP runs them through the now public runManagedAutoMemoryBackgroundTasks once its Stop loop ends the turn, with its existing end_turn and loop-protection conditions - a UserPromptSubmit block of a tool-result round shows the block notice and suspends the Todo Stop Guard instead of ending the turn silently - core values come from their defining modules, not the package root * test(acp): leave the follow-up suggestion out of the ACP parity suite The suggestion request runs after session/prompt returns and may or may not land before the agent is stopped, so one arm could record an extra request. The suite compares the prompt's model rounds only. * fix(acp): snapshot the user turn and open send-now from the request on the shared round ACP records the user turn before the shared round's first send, but the round left the file-history snapshot to that send. A prompt cancelled between admission and the first send kept its user turn without a snapshot, and rewindToTurn indexes snapshots by user-turn position. ACP takes the snapshot again, as on the current path, and userTurnRecordedByHost also turns off the client's snapshot. The response-interrupt window opened on the client's first event, while the current path's watch() is open once the request is out, so input sent before a slow first token waited for the first chunk. The window now opens at the send; a cut is held while the round's request has not reached history, so it cannot drop the message it carries, and the first event pulls again. * fix(acp): recall from the prompt text and close blocked tool results on the shared round - Pass the raw prompt text as `memoryRecallQuery`, so managed-memory recall no longer searches resolved @-file contents and host notices. - When UserPromptSubmit blocks a tool-result round, close its calls with an explicit block result instead of leaving them to the orphan repair, whose "retry if needed" text invites rerunning the tool into the same block. - Take the memory task promises the client queues after each turn; ACP reports no memory updates, so they otherwise accumulate for the session. * docs(design): drop the recall-text difference and note the blocked tool-result close * fix(acp): keep unsent input and per-response facts on the shared round - Start fresh response facts and report usage per request when the client's next-speaker check continues within one round, so a continuation's complete edit is not refused for the earlier response's max-tokens cut, and its usage is not dropped. - When the round throws before its request pushed the message, such as a cancel during a tool-result round's UserPromptSubmit hook, keep the message in history as the non-throwing stops do, so tool results that already ran are not left to the "retry if needed" repair. - When UserPromptSubmit blocks a tool-result round, keep the input taken with the results (already shown as delivered) beside the blocked results instead of dropping it. - Cover the merged hook-context dedup's empty-request append in core. * test(acp): pin the unsent-message keep on a tool-result hook timeout A tool-result round's UserPromptSubmit request carries no abort signal, so a cancel does not make it throw; the case that throws before the push is the hook request failing, such as its 60 s message-bus timeout. Test that case instead, and say so in the comment. |
||
|
|
1df5031e70 |
perf(ci): overlap web-shell and standalone tests with the CLI suite (#15438)
* perf(ci): overlap web-shell and standalone tests with the CLI suite The Linux Test job ran every workspace suite, the standalone runtime regression and scripts/tests one after another. The CLI suite keeps its workers busy for 13-20 minutes, while web-shell's suite spends most of its run on App.test.tsx alone and the standalone regression starts one runtime process at a time, so those two added their mostly idle minutes straight to the job. Run them in a side lane beside the other workspaces instead. .github/scripts/ci/run-unit-test-lanes.sh starts web-shell and the standalone regression in the background, runs every other workspace's test:ci (listed with npm pkg get, in npm's workspace order) and then scripts/tests, and replays the side lane's log after the main lane so the two never interleave. The step runs the script under the same setpriv wrapper, so every test command still runs without the DAC override capabilities. test:scripts now reaches its Vitest run through a new test:scripts:unit script with a trailing --, so the main lane can run it without the standalone regression while test:ci, test:ci:workspaces and test:scripts run what they ran before. * fix(ci): name the cause when the lane script cannot start a lane - Fail with an ::error:: line when mktemp cannot create the side lane's log file, instead of running the main lane alone and dying in tail. - Check the exit status of `npm pkg get` and of the parser. A failing `npm pkg get --json` prints an error object, which used to parse as an empty listing and report "Found no workspaces". - Note in the header that the replay puts side-lane failures after the main lane's in main-failure-signature.mjs's title and search markers. - Lane test: clear the caller's NODE_OPTIONS, assert the main lane's output is present before checking its order, and cover the failed listing and the missing temp dir. - Cross-check npm's workspace resolution against the selector in scripts/workspaces.js. * fix(ci): halve web-shell's worker cap beside the main lane Each Vitest run applies VITEST_MAX_FORKS / VITEST_MAX_THREADS on its own, so running two lanes at once doubled the step's worker cap, and on the hosted runners, where no cap is set, put two all-CPUs pools on 4 vCPU. The lane script now runs web-shell at half the cap, at least 1, and at 2 where the cap is unset; the main lane keeps the full cap. - Refuse a workspace name with whitespace in it: the main lane's arguments are read one per line, so a line break would split a name into other arguments, flags among them. - Lane test: web-shell and the main lane's suites now wait for each other, so a side lane serialized before or after the main lane fails; record each call's worker caps; run the script against npm's real listing and compare its main lane with the selector the release pins use; cover a name with a line break in it. - ci.yml: the standalone runtime cache comment names the lane script's side lane, not test:scripts, as what runs the regression in this job. - ci-variables.md: say the cap applies per Vitest run and what the two-lane step runs at its peak. - release-workflow.test.js: follow test:scripts through test:scripts:unit to vitest; #15102 pinned the shape before the split. |
||
|
|
aa6b65a52a |
chore(release): v0.26.1 (#15468)
* chore(release): v0.26.1 * docs(changelog): sync for v0.26.1 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: 易良 <[email protected]> |
||
|
|
bafe530a84 |
feat(core): add an experimental shared agent loop and run headless on it (#15369)
* feat(core): add an experimental shared agent loop and run headless on it Every surface implements its own send, run tools, repeat loop. This adds runAgentLoop to core: one model round through LlmClient, the returned tool calls as one batch on a single CoreToolScheduler, the results finalized and recorded once in request order, then the next round. The client's terminal events become typed stop reasons. CoreToolScheduler gains an optional beforeToolLaunch callback that runs serially in request order before each launch; a concurrent batch asks for every call that fits in flight before launching any of them. Without the callback the scheduler is unchanged. With experimental.unifiedAgentLoop (or QWEN_CODE_ENABLE_UNIFIED_AGENT_LOOP=1), headless runs its rounds and drain items on the shared loop. With it off, headless runs the current code, which only moved into an else branch. A no-AK parity suite runs each scenario through the built CLI with the setting off and on and requires the same requests, stream-json frames and exit code. Part of #15327 * docs(design): update the unified agent loop design for PR 1 Record what implementing PR 1 settled: the launch hook asks a whole in-flight window and every call of a batch once, results reach the surface at batch end, the intended headless differences, how the design relates to #8775, and the status. Part of #15327 |
||
|
|
c61044fae4 |
feat(managed-agent): Start daemon and Managed locally with one command (#14928)
* feat(managed-agent): add local serve and lightweight runtime packages Co-authored-by: Qwen-Coder <[email protected]> * feat(managed-agent): download local server runtime on first use Require local Java 21, install the exact-version service JAR atomically from OSS or GitHub, and reuse verified runtime caches offline. Add protected signed Central publication and identical release distribution without bundling Java in the CLI. Co-authored-by: Qwen-Coder <[email protected]> * fix(ci): register managed runtime workflow size Record the new release workflow in the repository size baseline so the static CI gate can track it. Co-authored-by: Qwen-Coder <[email protected]> * feat(managed-agent): Share the local daemon and Managed entry Serve daemon APIs and the signed Managed proxy from one loopback listener. Keep workspace ownership explicit, enable authorized local directory import and preserve the daemon trust boundary. Co-authored-by: Qwen-Coder <[email protected]> * fix(cli): expose configured models in local Managed tasks Co-authored-by: Qwen-Coder <[email protected]> * test(web-shell): Cover Managed and local deep-link restoration Co-authored-by: Qwen-Coder <[email protected]> * test(managed-agent): Align local database expectation with main schema Co-authored-by: Qwen-Coder <[email protected]> * fix(managed): Keep local model and approval choices independent Use native initial model selection for local model presets and persist it with the selected approval mode before admitting the first Turn. Preserve custom Agent definition policy pins and creation replay semantics. Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
7091697f00 | fix(ci): enroll the OpenTUI parity tests in the no-AK lane (#15142) | ||
|
|
8f259db527 |
chore(release): v0.26.0 [skip ci]
* chore(release): v0.26.0 * docs(changelog): sync for v0.26.0 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
b51ce2c305 |
feat(workflow): add per-turn human-origin workflow hints (#14876)
* feat(workflow): add per-turn human-origin workflow hints * fix(workflow): preserve intent across recall and cached submissions --------- Co-authored-by: qqqys <[email protected]> |
||
|
|
a791e47a54 |
feat(cua): streamline computer use and port native reliability fixes (#14846)
* feat(cua): preload the JavaScript computer use runtime * refactor(cua): remove the native Wayland backend * feat(cua): move app computer use into the driver * feat(cua): preserve background delivery and port platform fixes * feat(cua): add explicit desktop input and browser runtime facade * feat(cua): package the unified 0.26.0 computer use runtime * fix(cua): finalize cross-platform native reliability * fix(cua): isolate runtime releases from CLI versioning * fix(cua): keep Electron out of root workspace installs * fix(cua): synchronize consumers and async cleanup tests * fix(browser): migrate smoke to preloaded cua runtime * docs(cua): document MCP setup for Qwen Code Claude Code and Codex |
||
|
|
8f3c7e15e4 |
fix(cli): preserve runtime boundaries during standalone updates (#14934)
* fix(cli): preserve runtime boundaries during standalone updates
Preserve Node/Bun archive flavor and validate actual CLI loading, package
identity, version and prepared installation identity before activation.
Keep Node npm transport and restrict Bun registry lookup to trusted config.
Integrates chiga0's update stack through
|
||
|
|
6e6598e35c |
fix(cli): restore bounded OpenTUI dialogs and add migration gates (#14933)
* fix(cli): restore bounded OpenTUI dialogs and add migration gates * fix(tui): harden migration cleanup and evidence after review * test(tui): fail acceptance on unhandled errors |
||
|
|
a1fb0306ae |
feat(mods): support tool middleware in interactive terminals (#14565)
* feat(mods): support tool middleware in interactive terminals * fix(mods): preserve nested approvals and final terminal results * style(mods): keep terminal imports below file headers * test(mods): assert terminal middleware drains on quit * test(mods): verify native attempt approval and validation isolation * fix(mods): retain hook owner across worker tool callbacks * fix(cli): Drain revoked Mod tool turns in OpenTUI * fix(cli): Clear approvals when the owning turn ends * fix(cli): Restore tool eligibility after failed session switches --------- Co-authored-by: qqqys <[email protected]> Co-authored-by: Shaojin Wen <[email protected]> |
||
|
|
d2e12e404f |
test(managed-agent): crash the approval result-commit barrier (#14733)
* test(managed-agent): crash the approval result-commit barrier A5's last packaged barrier: after the approved tool result commits, hold the post-tool model round and crash the Harness. The next generation must reissue the saved request (deep-equal), retract the published prefix, and finish with one execution, one file effect and one terminal. Part of #14481. * test(managed-agent): gate the result crash on the published prefix Review findings: wait for the public feed to carry the held prefix before SIGKILL and record it in the crash evidence, so the transcript assertion cannot pass on a no-op retraction. Also decouple the source pins from prettier whitespace and the comparison operator. * test(managed-agent): pin the after-result model count Review follow-up: keep the two-request expectation tied to the after-result arm via expectedModelsAfterResults, without reintroducing the indentation coupling that the previous split removed. * test(managed-agent): strengthen the result-commit assertions Review findings: name the two pre-dispatch barriers and pin after-result's exclusion from the held start, assert the stream.reconciled ordering beside the reload text, retain both request bodies in model-request-parity.json, and pin the retraction throw. * ci: record the sdk-java workflow growth The five approval fault arms add steps and comments to sdk-java.yml: 104042 bytes, 4100 over the previous 99942 baseline. Update the ratchet in the same PR, as check-workflow-size.sh prescribes for real growth. |
||
|
|
eeec911c20 |
fix(ci): raise the build heap cap from 4096 to 6144 MB (#14822)
The packages/cli TypeScript build inside the Desktop Checks 'Prepare bundled runtime' step now dies with 'Ineffective mark-compacts near heap limit' at exactly 4030 MB on both macOS jobs, i.e. it hits the 4096 MB ceiling the root build script sets via NODE_OPTIONS; the Linux and Windows legs of the same run finish under the cap (#14793). The CLI project graph crossing the 4 GiB type-checking threshold leaves neither macOS leg headroom. Raise the build-time ceiling to 6144 MB, mirroring #11781's earlier 3072 -> 4096 bump. It is still a ceiling: V8 only consumes what a build actually needs, so local builds and runners whose jobs fit under 4 GiB are unaffected. |
||
|
|
5ac26809fe |
fix(ci): include updatedInput hook integration tests in PR checks (#14747)
* fix(ci): include updatedInput integration coverage in PR checks * test(scripts): pin that every no-AK entry still resolves to a test file Vitest positional args are filename filters, not paths: a renamed entry matches nothing while the other filters keep vitest exiting 0, so the gate would report pass with that suite's coverage silently gone. Assert every pinned entry still exists under integration-tests/. Co-authored-by: Qwen-Coder <[email protected]> Patrol-Run: qwen-pr-closeout/jmvfl3pgdj1 --------- Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
de20ab6a30 |
feat(workflow): authorize daemon ancestor workflows (#14646)
* feat(workflow): authorize daemon ancestor workflows * fix(workflows): fence ancestor trust across policy and cwd changes Preserve the actual admission publication through reconciler rebuilds. Reject in-flight and stale-directory replies throughout physical cwd changes, including partial failures. Refs #14646 * fix(workflows): retain ancestor trust after context clear * fix(workflows): normalize restored ancestor trust session ID * test(workflows): use native cwd for restore trust fixture --------- Co-authored-by: qqqys <[email protected]> |
||
|
|
c076c699af |
test(managed-agent): add G3 approval fault-point E2E arms (#14687)
* test(managed-agent): add G3 approval fault-point E2E arms Step 3's packaged gates crossed the approval path without a fault. Four new arms layer one failure on the Allow arm: a crash after the decision commits, a crash after the approved execution reaches PREPARED behind a held Runtime Broker start, a lost decision reply retried under the same Idempotency-Key, and a lost Turn admission reply retried the same way. Part of #14481 (step 2). * test(managed-agent): gate the approval crash on the committed decision The response endpoint's 202 only admits the response operation; the Action row stays requested until delivery commits. The after-decision arm now holds the Runtime Broker start and waits for state=decided with a decision receipt and digest before SIGKILL, and a predicate test rejects the admitted-only answer. Also add the four fault arms to the hosted-process-ci inventory and raise its step/ceiling expectations to 190/205. * fix(managed-agent): scope the approval decision barrier query The after-decision arm's durable-decision wait referenced actionFilter, a const inside the earlier approval-setup block, so the new arm threw ReferenceError before it could crash the Harness. Build the same predicate from the in-scope sessionFilter and the record/action columns instead. --------- Co-authored-by: 易良 <[email protected]> |
||
|
|
c4f0acdef8 |
feat(extensions): add bounded generated HTML and JavaScript views (#14338)
Co-authored-by: qqqys <[email protected]> |
||
|
|
530a22680d |
chore(release): v0.25.3 [skip ci]
* chore(release): v0.25.3 * docs(changelog): sync for v0.25.3 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
bd63f900c7 |
feat(workflow): discover trusted ancestor workflows in local sessions (#14369)
* feat(workflow): discover trusted ancestor workflows in local sessions * fix(workflow): enforce ancestor trust authority and preserve scoped loading * test(workflow): use discovery fixture agent type for initialization * test(workflow): support partial settings fixtures in ACP trust mock * test(acp): provide operator trust view in worktree fixtures * fix(workflow): preserve safe discovery on root I/O errors --------- Co-authored-by: qqqys <[email protected]> |
||
|
|
25ef506c03 |
chore(release): sdk-typescript v0.1.20 [skip ci]
* chore(release): v0.25.2 * chore(release): sdk-typescript v0.1.20 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
95468e293f |
test(managed-agent): gate G3 Step 3 recovery, model-round takeover and control-plane fencing (#14181)
* test(managed-agent): gate G3 Step 3 recovery, model-round takeover and control-plane fencing Run the five Step 3 packaged gates (approval Allow, Deny, Cancel and expiry, and the continuation closeout) as hosted-harness-mysql steps through a new --g3-verify flag; G3_VERIFY_MODE keeps working. Add a model-round arm: the first model round of a Session with no Workspace survives two Harness-only replacements, each reissuing the same saved request and retracting the dead owner's prefix, with no tool execution and a clean next-Turn history. Add a frozen control-plane arm for the binding half of #12952 Q2: the original Spring and Harness are SIGSTOPped mid-round, a second pair on the same MySQL finishes the Turn, and after SIGCONT the woken Spring's stale claim, witnessed in the MySQL general log, must leave the Session binding, the Turn row, the public events and the journal unchanged. The woken coordinator never reaches a bind call, so a store test pins the bind guards directly: a former owner whose claim lapsed cannot rebind, renew or admit, and a terminal Turn cannot be bound. Fix the server README paragraph that still said a model-round park wedges the Session, document every G3 arm and the first-release recovery scope, and record decision D11 in both languages of the G3 design. Refs #12952 * test(managed-agent): answer the first review of the G3 residual gates The README no longer says a parked model round or approval in a Session with Hooks or MCP ends with a typed decline: a Hooks Session never takes over and an MCP approval plain-attaches. It now says Step 3 neither reissues nor resumes those states and no gate covers how they end. The model-round arm requires the writer generation, journal revision and committed sequence to advance across every takeover, and its terminal wait watches both the live control plane and the Harness finishing the round; waitUntil and waitForTerminal accept several children for this. The frozen control-plane arm gains a writer-side witness: the woken Harness must meet the store's stale-writer refusal after the wake and not before, counted on its output since the wake rather than the rolling log tail. It also refuses to wake a Harness whose home is gone, reports the retained home, and splits a poll budget across the snapshot's synchronous probes while one-shot snapshots keep 10 s each. The store test pins the owner check of recordRecoveryAdmission for a former owner, and both admission refusals now check their message. New pins cover the writer side of the Step 3 evidence path, the awaited waits, the pre-wake baseline and the checks above. The design doc's stale CI budget item now points at D11, which states the step sum. Refs #12952 * test(managed-agent): answer the second review of the G3 residual gates waitUntil's deadline message now takes its log tails from the normalised child list, so a deadline on the model-round terminal wait reports both tails instead of throwing a TypeError on the array. An early exit names the child that died, which tells the control plane apart from the Harness generation finishing the round. The waitUntil tests cover a dead first child, a dead last child and a deadline with both children alive, and the signal-death comment sits on its own test again. The frozen control-plane arm watches the replacement Spring and Harness through the quiet window and every wait after the wake, and checks them once more before the fenced verdict: a dead owner would otherwise hold every snapshot still. The README and both design docs no longer say the new gates run in CI. They are steps of the Hosted MySQL job, which runs daily or on demand and reaches them only after its verification step passes; that step was failing on main when the gates were added. The D11 snapshot list now says the journal probe is a per-generation, per-operation count and highest revision. Refs #12952 * test(managed-agent): let the frozen arm see an owner exit during its probes The fenced snapshot's probes are synchronous, so a replacement that exits while they run is not recorded until the event loop turns. The arm now yields once before checking the owners, and the pin covers the check's body, not only its position. The docs say the new steps run only when every earlier step of the job passes, not only the Verify step, and state in the past tense that no CI run had executed them when they were added. The README's no-change statement is bounded by what the D11 snapshot can see. Refs #12952 --------- Co-authored-by: 易良 <[email protected]> |
||
|
|
ef38ad7753 |
feat(web-shell): add read-only Excel artifact previews (#13664)
* feat(web-shell): add read-only Excel artifact previews * fix(vscode): refresh notices for Excel preview dependencies * fix(web-shell): bound Excel merge loading and preserve preview content * fix(web-shell): bound Excel preview work and preserve recovery * fix(web-shell): harden Excel preview values and recovery * fix(web-shell): include bundled ExcelJS dependency licenses * fix(web-shell): guard column expansion and complete ExcelJS notices * fix(web-shell): complete Excel color fallback and review guards * test(web-shell): follow artifact filename labels in Excel previews --------- Co-authored-by: 钉萁 <[email protected]> Co-authored-by: qwen-code-dev-bot <[email protected]> |
||
|
|
6775f24927 |
feat(extensions): add test failure report explorer (#13854)
* feat(extensions): add test failure report explorer * fix(extensions): bound report snapshots before serialization * fix(extensions): bound test report validation --------- Co-authored-by: qqqys <[email protected]> |
||
|
|
726e8d77f7 |
chore(release): v0.25.1 (#13904)
* chore(release): v0.25.1 * docs(changelog): sync for v0.25.1 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
2a69a2ff22 |
fix(managed-agent): commit oversized message records as inline chunks (#13375)
* fix(managed-agent): commit oversized message records as inline chunks A Hosted answer past the 64 KiB inline resource limit streamed in full through message.delta events and then failed its turn when the final message.committed record exceeded the limit with OSS disabled. Split an oversized record body into ordered managed-message-part resources behind a managed-message-chunks manifest — the shape Hook message snapshots already use — and reassemble on every read path (projection hot and cold reads, the hosted SSE feed, workspace recovery). Each part stays under the per-resource limit and the transaction stays within the server budget, so a long answer completes instead of failing after publishing. Fixes #13326 * fix(managed-agent): preserve long answers through recovery Refs #13326. Builds on #13375 with the 64 KiB inline boundary, sequential chunk reads, and full-stack integrity regressions. * test(managed-agent): allow streamed message settlement to finish * fix(managed-agent): address long-answer PR review feedback Strengthen recovery, streaming and transaction-budget regressions, wire the long-output E2E into CI, and clarify the supported persistence scope. Refs #13326, PR #13375 * test: address long-answer persistence review feedback * codex: address PR review feedback (#13375) --------- Co-authored-by: jinye <[email protected]> |
||
|
|
4970bfa172 |
feat(managed-agent): adopt the next Hosted Harness generation (G3) (#13174)
* feat(managed-agent): adopt the next Hosted Harness generation (G3) A Hosted Session no longer dies with the Harness process generation that first served it (#12952 G3, Steps 1+2). On a generation signal the control plane renegotiates once through the connector instead of failing every bound Session until its own restart; pending Turns re-attach through the takeover load as their retries come due. Takeover refusals split into a typed terminal decline (deterministic in the journal) and the existing retriable code; the takeover load is idempotent against a lost reply and gets its own timeout; negotiation requires the journal-contract feature token so a rolled-back Harness is refused once; a marked-but-never-admitted Turn withdraws its submission mark, backstopped by journal commandId idempotency. The failover runner gains a Harness-only restart arm on all three scenarios (harness_boot_id moves with no Java restart) and a SIGSTOP/SIGCONT frozen former-owner fencing arm, wired into hosted-harness-mysql together with the previously local-only basic mode. Design docs included in English and Chinese. * fix(managed-agent): tolerate the bootstrap 404 of a restarting Hosted Harness The serve delegating app answers every routed path with a bare pre-contract 404 while its runtime is still starting. The Harness-restart arms raced that window: a prompt submitted milliseconds after the new process bound the port could meet the bare 404, which the client read as a generation contract violation and ended the Turn as hosted_harness_protocol_error without any retry. A missing boot header on 404 now maps to a transient transport error so the coordinator retries through the window, and the failover runner waits on deep health (?deep=1) before driving turns into a restarted Harness. Terminal turn failures now also log their underlying exception. * fix(managed-agent): freeze only the Harness writer in the former-owner fencing arm SIGSTOPping both original owners left the original Spring's workspace binding unreclaimable: the reclaim proves death from /proc liveness, and a stopped JVM still reads as alive there, so the replacement's reconcile timed out (runtime_broker_reconcile_timeout) and the Turn never completed. The arm now stops only the original Harness (reclaiming its workspace binding requires the Spring to die anyway — the continuation mode's crashProcess), completes the Turn with a full replacement, then wakes the frozen writer and asserts the journal, transcript, and session binding are untouched. Design D7 updated in both languages with the discovered boundary: resource-level takeover of a surviving owner is structurally out of reach today, which is exactly what this issue's sequential-generation scope excludes. * ci: retrigger sdk-java workflow after event delivery stall * fix(managed-agent): pin the fencing proof on writer identity, not head revision The first merge-base run of the freeze arm failed its own gate: after waking the frozen Harness the journal head moved (rev 30 -> 45) while the writer generation, boot binding, transcript, and terminal count all held. The moved revisions were the replacement's own legal churn, not old-writer mutation, so the head-equality assertion conflated the two. The exit-check claim is identity: no transaction out of the old writer generation after it wakes. Count that straight off qwen_managed_session_journal_tx (which carries writer_generation), keep the binding/transcript/terminal assertions, and align design D7 in both languages. The error string now also reports the old-writer tx count. * fix(managed-agent): qualify the journal tx schema in the freeze-arm gate The identity-based old-writer count queried qwen_managed_session_journal_tx unqualified; the runner's MySQL connection has no default schema, so the arm died with ERROR 1046 instead of evaluating the fence. Qualify it as qwen_managed_agent.qwen_managed_session_journal_tx like every other query in this runner. No behavior change to the assertions themselves. * fix(managed-agent): harden takeover correctness from the R1 review - settle turn_settled checkpoints through the load route's own tail instead of a terminal decline, and keep transient store verdicts (missing_state/missing_checkpoint) retriable on both authorization reads - exempt only takeover-shaped 409s from the pre-admission retry budget; every other failure kind meets it - scope the 120s load-timeout to recovery loads so plain attaches under the CHM bin locks stay on 30s - adoptGeneration: move map churn out of the connector monitor (lock-order inversion), evict only stale-boot entries on equal-boot mismatches - answer a duplicate submit of an already-settled prompt with a 202 replay anchored at its input.accepted sequence - withdrawSubmissionAttempted: guard on the same status window as its peer CAS methods; complete capability mismatch terminally in both remaining coordinator layers - runner: freeze-arm pre-freeze liveness assertion, /health-proven wake non-vacuity, teardown SIGCONT, exact-string dispatch-generation bounds - CI: job ceiling 95 with corrected ceiling math; pin all seven failover arms in hosted-process-ci.test.js - sync both design-doc languages with the shipped behavior * fix(managed-agent): close the R2 review round on the replaceable-host-harness slice - withdraw + cancel interference (R2-1, Critical): a CANCELLING Turn whose never-admitted mark was withdrawn is fast-cancelled instead of being re-dispatched into a second live execution at the adopted generation - the generation-mismatch catch escapes the pre-admission budget only on a bound Session, like every sibling arm (R2-3) - bound the remote-supplied decline reason to the error_message column so the terminal write itself never throws (R2-5) - the last fail(...) in the catch ladder is failTerminally with the exception logged, like its siblings (R2-6); the withdrawal itself is logged too (R2-7) - freeze arm: the replacement Spring inherits the original port so the woken writer meets a live fencing control plane, not a dead socket (R2-2); the wake block asserts the head actually advanced past the frozen owner's writer generation, drops the wrong heartbeat claim (R1-8 follow-up), separates the two disk-audit meanings, and asserts the retained Harness home (R2-8) - the hosted /capabilities feature list derives from the registry instead of a hand-maintained literal (R2-9) - docs: D7 scoped to the journal half of the Q2 exit check, the binding half and the pre-contract-404 classification recorded in Boundaries (R2-4, R2-10) * docs(sdk-java): correct the load-timeout coverage comment in the client test * fix(managed-agent): reference the frozen Harness through the children registry in teardown The R1-4 teardown SIGCONT referenced the try-block-scoped `harness` binding from the finally block, so every freeze-arm run died with ReferenceError after all fencing assertions had already passed (CI run 37009843147). Reach the child through the children registry by its start() name instead. * docs(managed-agent): scope the adoption sentence to this slice's takeover reach * fix(managed-agent): close the R3 review round at its five shared roots - retract the turn_settled settle tail to a typed decline: the tail answered 200 with no recovery watermark (Java then failed the bind, orphaned a completed journal turn), fabricated state:'completed' on phase alone, ran mutating work under a passive load, and retained no snapshot for the lost-reply retry. D10 already owns rebind-and-keep-reading as the Step 3 row (R1-25-re, R3-2 .. R3-5) - the load route's restore guard applies the same durable-vs-transient verdict read, because the bundle collapses both into one blocked bit and the durable decline was unreachable from production (R1-26-re) - the pre-admission exemption keys on lease-shaped 409 codes only: configuration-shaped 409s (e.g. hosted_tool_profile_conflict) meet the budget, and the same 409 exempts nothing on an unbound Session (R1-1-re, R1-30-re, R3-13) - equal-boot adoption keeps pendingRecovery: the markers were minted by the same live client (R1-29-re) - lifecycle capability mismatch: revert completing-as-unconfirmed — that skipped the drain, flipped the session, and recorded a clean row with no FAILED vocabulary to tell it apart; the reason-loud retry is the honest end of the line until an operator realigns versions, and the README sentence says so. Action-response outbox keeps its honest FAILED-with-code terminal (R1-45-re, R3-5, R3-15) - test hardening: concurrency close-once now surfaces worker assertion failures via Future.get and pins that no real client build happened (R3-12); loadTimeout-vs-requestTimeout discriminated at the call site (R3-9); single-walk acceptedInputSequence (R3-18) - runner: 5-column execution queries pin runtime_session_id unchanged under --harness-only (R3-14); frozen-arm teardown looks the child up by a shared label constant and fails the run on a drift (R3-17) - CI: ceiling 105 covers the nine summed step ceilings (92) plus the uncapped setup steps (R3-6); the seven-arm pin also asserts each script's flags and the install step's existence (R3-16) - docs: both languages re-synced (D5 retraction, D9a code allow-list, D7 teardown, D8 runtime identity, honest validation digests, the four missing changes-table rows, README retry clause) * fix(managed-agent): replay takeover snapshots only to a same-shape request A passive load only asks broker.status(), so its snapshot keeps phase='await_runtime'; replaying it to a drive load handed the coordinator a checkpoint that isContinuationReady() can never accept, terminally failing an otherwise continuable Turn. Record the request shape with the snapshot and replay only on a mode match; the clear conditions stay promptId-only. Also make the adoption race test deterministic: a package-private createClient() seam lets the test inject the replacement instead of a real /capabilities call (proven flaky on CI), worker assertion failures now surface through Future.get, and the pendingRecovery fixture seeds its marker through the recovery path. * fix(managed-agent): close the self-audit round on the replaceable-harness slice Three rounds of undirected plus adversarial audit over the whole PR diff (31 files), with three parallel deep-dive passes over the Java, TypeScript and runner/docs surfaces. Every finding was re-verified against the tree before acting; five reported defects were rejected on evidence. Correctness: - the load route read the blocked-restore verdict AFTER managed.close(); sealing the journal makes every later store read fail as "writer is not active", which the authority erases into missing_state, so the durable branch this PR added could never fire and a corrupt checkpoint stayed in the retry-forever class. Read the verdict first, and pin the order with a witness that goes red when the read moves back (the local authority's seal does not disable reads, so only the ordering assertion catches it). - drop hosted_session_already_attached from the lease-bounded 409 set: the daemon removes an attachment only on an explicit detach or delete and this control plane never detaches, so a Spring restart against a surviving Harness retried a permanent refusal forever instead of ending the Turn. - adoptGeneration evicts by boot identity in both branches instead of clearing, so a marker minted by a concurrent rebuild can no longer be erased between two adjacent clears (which left a live attachment with a null recovery report), and markers follow their attachment. - the post-withdrawal fast-cancel reads the row again: a cancel landing after the claim is invisible in the claimed snapshot, and acting on it submitted a live execution only to cancel it below. - a durable verdict re-read after settling now declines as checkpoint_blocked, matching the identical pre-settle classification. - an unrecognized blocked reason throws instead of declining, so a reason core adds later cannot silently become a terminal Turn failure. - the operator-settable load-timeout is validated at connector construction; a bad value previously threw on every client() call and surfaced as an endless transient retry naming only the exception class. Tests: already_attached and lost-withdrawal-CAS witnesses; the fast-cancel witness now pins the re-read (cancel after claim); the concurrent-adoption test surfaces worker assertions through Future.get and injects the replacement through a package-private createClient() seam instead of standing up a live /capabilities call; the CI pin gains each arm's mode flag and a ceiling-sum invariant. Docs (both languages): D1 now describes the boot-identity eviction and lists what this slice really added to HostedHarnessClient; D3 no longer claims the bind-refusal path stops being reached (it is D4's trigger); D6 records the same-shape replay clause; D7's fence rationale no longer blames heartbeats (lease renewal touches writer_lease_until only); D9a names the two exempt codes and why already_attached is not one; the validation digest states which claims are pinned and which are not; the CI arithmetic reads 12 + 8x10 = 92; the stale workflow nit is dropped. * chore(ide): regenerate NOTICES for the merged dependency set (email channel) * fix(ide): replace the workspace-polluted NOTICES with the pristine regeneration The file committed in |
||
|
|
8d864a9f21 |
chore(release): v0.25.0 (#13448)
* chore(release): v0.25.0 * docs(changelog): sync for v0.25.0 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
aca4d03c7e |
feat(managed-agent): Add dev:managed-agent one-shot dev launcher (#13218)
* feat(managed-agent): Add dev:managed-agent one-shot dev launcher Developing against the Managed dual-path WebShell previously meant starting an ordinary daemon, a private Hosted Harness, and the Spring control plane by hand, keeping their ports, tokens, and capability digest consistent by copy-paste. The new launcher mirrors daemon-dev: it serves the daemon and the Hosted Harness from TypeScript source with rotating tokens and digest, writes the Spring wiring to the git-ignored (0600) .qwen/managed-agent-dev/spring.env, waits for /actuator/health on the Java side (--skip-java-wait bypasses), then opens the WebShell Vite dev server with the Managed panel selected. Ports auto-increment when busy, and any child exiting aborts the group so the stack cannot half-start. Co-authored-by: Qwen-Coder <[email protected]> * fix(managed-agent): Harden dev:managed-agent against review findings Round-1 review found 4 Critical and 14 Suggestion-level issues in the launcher; this commit addresses all 18: - Windows teardown now uses taskkill /T so the dev.js grandchild that owns the sockets cannot be orphaned (R1-1). - Equal --daemon-port/--harness-port is rejected, the daemon probe excludes an explicit harness port, and both health gates assert responder identity through /capabilities (the harness must present this run's capability digest), so a busy-port bump can no longer be reported as a healthy mis-wired stack (R1-2). - The two serve children boot in serialized stages: dev.js destructively re-stages the shared browser-use runtime on every boot, and the parallel spawns raced on it (R1-3). - The token-bearing open path travels via QWEN_WEB_SHELL_OPEN_PATH, consumed as server.open in the web-shell Vite config, instead of a --open argv that npm echoed and cmd.exe would split on '&' (R1-4, R1-17). - spring.env moved to the OS temp directory (mode 0600) so the harness bearer token no longer sits inside the served workspace; a PowerShell sibling is written for Windows, a warning fires when a previous run's file (and a possibly stale Spring) exists, and the Spring recipe now carries the datasource exports and one-time sibling installs in both README and the startup banner (R1-5, R1-6, R1-11, R1-12, R1-14). - --tenant is validated against Spring's own pattern, waitForHttpOk carries the last HTTP status/error into its timeout, a Java timeout no longer tears down the healthy local stack, signal handlers live inside the entry guard, and the isMain guard is symlink-safe (R1-8, R1-9, R1-10, R1-16, R1-18). - Exported builders (kill plan, harness wiring, serve stages, web launch, URL) with mutation-witness tests pin the contracts the first round showed unpinned (R1-7, R1-13, R1-15). Co-authored-by: Qwen-Coder <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> * fix(managed-agent): Probe the web port on Vite's bind family Vite binds 'localhost', which resolves to ::1 only on IPv6-first hosts, but the web-port probe listened on 127.0.0.1 and called a held port free — observed in a two-launcher dry run where the second launcher's probe passed and Vite silently bumped past the probed value (the printed URL then names the wrong port; the TTY URL also used the IPv4 spelling that cannot connect to an ::1-only bind). The probe now takes a host parameter and the web probe uses 'localhost', matching Vite's own bind attempt by construction; the printed URL uses the localhost spelling. A unit witness binds a server on 'localhost' and requires the probe to walk past it. Co-authored-by: Qwen-Coder <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> * fix(managed-agent): Close round-2 review findings on dev:managed-agent The second review round (2 Critical, 8 Suggestions) found the round-1 remedies themselves creating new edges; this commit addresses all ten: - The env-file write is now fail-closed: the directory is keyed by uid and a hash of the checkout root (multi-user and multi-worktree runs no longer collide or cross-truncate), created 0700, verified owned, each target lstat-checked and refused when it is not our regular file (a planted symlink is bounced, its victim untouched), and 0600 is applied by chmod so it holds on the overwrite path too. POSIX-only enforcement: NTFS owns the boundary on Windows, where stat mode masks and chmod read-only would have broken the launcher outright (R1-11). - Teardown now covers SIGHUP plus a synchronous exit hook, so a closed terminal tab or dropped SSH session no longer orphans the credentialed serves that detached:true would strand (R2-1); registrations stay inside the entry guard and are pinned via TEARDOWN_SIGNALS. - Explicitly pinned ports are probed and rejected when busy, because qwen serve bumps on EADDRINUSE regardless, which previously meant a 60-second misleading timeout (R2-2); Vite gets --strictPort and a pinned --host so it fails closed instead of drifting past the probed port (R2-3). - waitForHttpOk captures err.cause.code (ECONNREFUSED now visible through undici's generic 'fetch failed') and clears stale accumulators so a fresher error supersedes an older response (R1-9 residual). - The Java gate applies its siblings' identity logic through springHealthExpectBody instead of certifying any 2xx (R2-6). - The PowerShell recipe line is uncommented and self-enabling (Set-ExecutionPolicy -Scope Process), emitted by an exported buildSpringRecipeLines that also carries the database/user creation step matching the reference e2e, mirrored into the README (R1-14, recipe gap). - Effectful decisions moved into exported, injectable helpers (executeKillPlan, runServeStages, ensurePortFree) with interleaving and argv witnesses, and nine loose oracles tightened (rotation, ::1 family fixture, daemon argv, launch env/argv, sharper retry message, the vite env-consumer case in web-shell, the Authorization header, the harness port in both base URLs, ambient-credential collision) (R2-4, R2-5). Dry-run witnesses: staged healthy with digest pairing, recipe lines and the env-file layout (0700 dir, 0600 file, no ps1 on POSIX) verified, pinned-busy fails in milliseconds with exit 1, and a live SIGHUP drains daemon, harness and Vite with no orphaned listeners. Co-authored-by: Qwen-Coder <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> * fix(managed-agent): Skip the web-shell spawn once teardown has begun Self-audit after the round-2 fixes found two edges: a child dying during the Java wait now lands in the non-fatal continue branch, which would print the Managed URL and spawn Vite into a group teardown was already reaping (the exit hook caught it, but the output misleads); and killChild's re-entrancy comment overclaimed a no-op second pass — the group/taskkill plans do not set child.killed, so a second pass is a redundant signal to a dying tree, which is safe but not a no-op. Guard the spawn on shuttingDown and correct the comment. No behavior change on the happy paths; the script suite stays at 60/60. Co-authored-by: Qwen-Coder <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> * fix(managed-agent): Close round-3 review findings on dev:managed-agent The third review round (4 Critical, 18 Suggestions), including three defects the round-2 fixes introduced, now addressed together with the review's batching recommendation: - shutdown() counted only signal-dead children (the >>continue<< predicate read 'signalCode === null'), so Ctrl-C/SIGHUP launched process.exit immediately, orphaned every live server, and a sole signal-killed child exited 0. The probe now reads isLiveChild, which the suite pins in both directions (R2-1). - The credential writer's checks resolved through symlinks: a planted link at the directory walked the lstat refusal, and a dangling link at a target skipped it entirely. The writer now lstats everything and refuses any symlink up front (R1-11), with planted-link victim- untouched cases. - Teardown now hears SIGQUIT (Ctrl-\) and escalates to SIGKILL after the 5 s grace instead of just exiting (R2-1/R3-1); the exit-hook comment narrows to what an in-process hook can promise instead of claiming coverage for unhandled signals and hard aborts. - Pinned-port checks moved from launcher start to each stage's own spawn step, so a port taken between the daemon's 60 s boot and the harness's spawn can no longer be silently bumped past (R2-2); the web port resolves at spawn time through an exported launch seam, so a squatter in the Java window cannot turn --strictPort into a full teardown (R2-3, R3-2). - The Java gate's teardown path is silent: no 'stays up' continuation line while children are reaping (R3-4), extracted into a runJavaGate seam with an injected health wait so the path is test-reachable. - healthFailureAction left only a literal-'continue' call site; the dead policy table, the unreachable abort branch and its describe are removed per the review's KISS option (R3-5). - The MySQL recipe grants the 'qwen' user at both 'localhost' and '127.0.0.1' (official images enable skip-name-resolve) with a container-topology note, and a pairing test ties the granted hosts/password to the exported SPRING_DATASOURCE_* literals (R2-7, R3-10). - Test-oracle batch (R3-3, R3-6..R3-9, R3-14, R3-15): default-runner witness for the kill plan, detached flag via an exported spawnDevProcess, first-run mkdir 0700 gate, stalled-responder rejection, both uid arms, stages[1].args pin, : prefix pins for the ps1 BASE_URL/digest lines, the printed ps1 path tied to the writer's filename, '503' replaced by the port-safe 'last response' suffix assertion with an in-range budget and a missing-finally close, the ephemeral-port-safe family fixture (property, not exact port), usable-on-Windows branch-shape cases decoupled from POSIX mode assertions, and parsed-actionable-line checks for the PowerShell recipe. ensurePortFree's unused probeHost parameter is gone (R3-13), and the env-transport comments now record the browser-hop argv the token still rides (R3-12). 78/78 in the script suite; live dry run healthy (dual-user recipe, argv clean), and a real SIGQUIT drains daemon, harness and Vite with no orphaned ports. Co-authored-by: Qwen-Coder <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> * fix(managed-agent): Wire the Session Store every Managed Turn needs Real-stack verification on the PR thread found F1: since #12754 the Hosted Harness answers 400 invalid_managed_session_store to any POST /session without a managedSessionStore descriptor, and Spring only sends one when its HTTP Session Store is enabled — so the launcher's recipe brought up a perfectly healthy stack in which every Managed Turn failed with hosted_harness_rejected. The stub-Spring dry-run and env-name checks in earlier rounds never drove a real Turn through the wiring. Adopts the reviewed candidate patch (wenshao assets-pr13218 @ ef748da, measured 3/3 Turns against a freshly created DB) and adds the remaining notes: - spring.env/ps1 now also carry QWEN_MANAGED_AGENT_SESSION_STORE_* (enabled, base URL = --java-url since the Harness calls Spring back, and a dev workspace id), so the recipe by itself produces a usable Session Store (F1). - SERVER_PORT is emitted from --java-url for plain-http loopback URLs, so a non-default --java-url no longer leaves Spring on 8080 while the launcher waits elsewhere (N2). - Thrown messages no longer carry the '[managed-agent-dev]' prefix that main()'s catch prepends once (N3). - '--java-url' is trimmed before validation, so surrounding whitespace can't pass the checks and then fail every health attempt (N5). - The README states the hosted_harness_rejected diagnostic mapping (Harness 400 = Session Store not loaded; 401 = stale Spring) (N1). - The first-run 0700/0600 writer case is re-gated for POSIX semantics (R4-1); content/branch-shape cases keep running everywhere. The supervisor data point from N4 (SIGKILL of the launcher) stays a deliberate follow-up on the launcher family, unchanged. Co-authored-by: Qwen-Coder <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> * fix(managed-agent): Gate the POSIX-arm writer case on the host, not the flag The round-5 review found the split's new case reproducing R4-1's exact failure on the Windows lane one level up: 'writes the env content and no ps1 sibling on the POSIX arm' injected isWinPlatform: false unguarded, so on a real Windows runner the production 0700 gate reads the synthesized 777 directory mode and writeSpringEnvFiles throws before either assertion — the mechanism and message R4-1 described, on the case I believed the split had made portable. It now gates on the host like its six siblings. Also adopts the round-3 verification's wording note: the two sibling installs are labeled once per clone, and re-run after pulling changes to qwencode or runtime-broker, since a snapshot install before a main pull leaves spring-boot:run compiling against stale artifacts (the banner builder and the README recipe say the same thing either way). Co-authored-by: Qwen-Coder <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> * fix(managed-agent): Close the actionable slice of the round-4 deferred list Five items from the round-4 review body's deferred Suggestions were covered here because each is a small consistency hole in the seam this PR just built: - main() re-checks pinned ports at t0 before writeSpringEnvFiles runs, so a busy --daemon-port/--harness-port no longer rotates credentials and prints the banner before failing at stage spawn the same run (R4-14); the per-stage recheck stays for the boot window it was added for. - launchWebShell re-consults the teardown flag after resolveWebPort, so a launcher dying mid-probe no longer prints a Managed URL for a group the exit hook is about to reap (R4-10), with a witness that flips the flag mid-resolve. - findWebPort is now held against a stand-in bound to this host's localhost resolution at DEFAULT_WEB_PORT, so the family walk is operational rather than vacuous (R4-17). - installTeardownHandlers' captured handlers are asserted to be functions, not only named functions (R4-19). - The vi.mock child-process fixture spawns fake children with pid=undefined, so teardown code can never signal a real process through the registry it is pushed into (R4-20). Co-authored-by: Qwen-Coder <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen-Coder <[email protected]> |