mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-11-07 06:19:43 -10:00
0a562773f76140e6c62a2c48a7e2eb806c120baf
12060
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0a562773f7 |
fix(core): match one sed character for . and bracket expressions (#15701)
* fix(core): match one sed character for . and bracket expressions The simulated sed path compiled patterns without the s and u flags, so `.` did not match `\r` in CRLF files and astral characters were matched as two UTF-16 code units, leaving a lone surrogate that was written as U+FFFD. Compile with su/gsu and escape a literal ] outside bracket expressions so the stricter u mode still accepts patterns such as [\[\]]. Closes #15675 * ci: rerun the checks on the unchanged tree * fix(core): decline sed escapes that mean something else under u `\p{…}`, `\P{…}` and `\u{…}` are literals to sed but Unicode property and code-point escapes to a `u`-flagged regex, so the simulator accepted patterns real sed rejects or leaves alone and wrote the simulated bytes to disk. Widen the divergent-escape guard and pin the declines, plus the `u`-only rejection class the flag introduced. * fix(core): judge a simulated sed edit by the bytes it will write On a CRLF file, `s/.$//` consumes the trailing carriage return, but the write path restores CRLF, so the edit reported success while the bytes on disk were unchanged. Compare the prepared write content against the original instead of the parser's intermediate string. * fix(core): judge a simulated sed edit by the content a read-back returns The write-back prediction decoded the prepared bytes as UTF-8 and compared them with the read content, so a file carrying a BOM or a non-UTF-8 encoding never matched and the false `sed edit applied` this PR removes survived. Compare content strings instead, and only predict the CRLF normalization when the writer applies it: a client-side write stores the content verbatim, so `s/\r$//` is a real edit there and must not be suppressed. * fix(core): decline \0 in simulated sed patterns `\0` is NUL to a `u`-flagged regex but a literal `0` to sed, so the simulator found no match and answered `sed edit made no changes` instead of falling back to the real binary. * fix(core): predict the CRLF restoration for every delegated write * test(core): pin the \0 decline in simulated sed patterns * fix(core): decline mixed POSIX bracket classes in simulated sed * feat(cli): have an Ink TUI turn await its shared tool batch (#16385) With experimental.unifiedAgentLoop on, the stream processor hands a shared round's tool batch to the round's submitQuery, which awaits it, its completion step and the round that step sends, once its own stream and activity ended. While another stream is active, which may be the stream that sent the round (a response of provider replays alone), the batch completes on its own as before. - The Ink executor takes a scheduler hold: the scheduler's completion callback returns once the completion step stopped the turn or is about to send the next round, as the current path holds it, up to the round whose calls need the scheduler. - A batch whose executed calls history all answered no longer sends its replay answers alone. The design doc describes PR 3b-2b. * feat(serve): add atomic user Skill activation (#16186) * feat(serve): add atomic user Skill activation * test(serve): cover conditional user Skill activation capability * docs(serve): index user Skill activation endpoint * fix(serve): preserve User Skill refresh recovery * feat(skills): add file-backed archive installation kernel (#16421) * feat(skills): expose native archive routes and receipts (2/4) (#16422) * feat(skills): add file-backed archive installation kernel * feat(skills): expose native archive routes and receipts * chore(release): sdk-typescript v0.1.28 (#16412) * chore(release): v0.26.8 * chore(release): sdk-typescript v0.1.28 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Shaojin Wen <[email protected]> * fix(core): keep plain bracket classes in simulated sed Matching `[:`/`[.`/`[=` anywhere in the pattern rejected ordinary classes such as `[.]` -- a common literal-dot idiom that sed and the translator both handle. Only open a POSIX construct when the opening bracket sits inside a bracket expression, so `[^[:space:]]` and `[[=a=]]` stay declined while `s/[.]/X/g` keeps the simulated path. * fix(core): decline an escaped `[` followed by a POSIX-looking class `s/\\[[:alpha:]]/X/g` is a literal `[` and an ordinary class to BSD sed, so the simulation rewrote the file. GNU sed rejects that pattern outright as a malformed bracket expression, so a simulated edit writes a change the user's own sed would have refused. The bracket scanner skipped the escaped `[` and so never saw the nested class. Decline the POSIX-shaped lookalike outside a bracket expression and leave a plain escaped `[`, and an escaped `[` inside a class, on the fast path they already had. --------- Co-authored-by: 肖洪进 <[email protected]> Co-authored-by: Shaojin Wen <[email protected]> Co-authored-by: 2SinceJuly <[email protected]> Co-authored-by: qqqys <[email protected]> Co-authored-by: callmeYe <[email protected]> Co-authored-by: Bob.qwencode <[email protected]> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
3f99e022b7 |
feat(cli): have an Ink TUI turn send the round its tool batch continues with (#16428)
With experimental.unifiedAgentLoop on, the shared tool batch's completion step hands the next round to the turn, which takes the input queued for the tool boundary and sends it. The batch keeps the scheduler and the TUI's activity until then; a turn that does not wait leaves the round to the batch. The Ink parity suite adds retry and queued-input scenarios. Part of #15327. |
||
|
|
11c83aa21e |
feat(managed-agent): allow concurrent child questions (#16484)
Release local execution membership while questions wait, recover the original runtime owner, and isolate root-page action selection and drafts. Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
80fd7c3353 |
fix(core): re-read a grown local journal prefix even when its timestamps did not move (#16483)
readLocalJournalBytes accepted a read when ctime and mtime were unchanged, without checking the size. Linux takes file timestamps from a coarse clock, so a growth that also rewrote the prefix within one tick of the previous write was accepted, and "refuses a frozen prefix rewrite even when the file also grows" failed in about half of its runs. Equal timestamps now count only while the size is unchanged. A file that grew is read again up to the size read the first time, bounded or not, and accepted only when those bytes match. An unbounded read during a pure append therefore returns the generation its first stat saw instead of failing, which writer acquisition and the session list relied on. The tests pin fstatSync's timestamps so the one-tick cases hold on every run. |
||
|
|
754b27dcf1 |
refactor(managed-agent): share JDBC statement helper and reuse JSON mappers (#16486)
Six runtime broker persistence classes each carried an identical private helper that prepares a statement with the default 10 second query timeout. The helper now lives once in the package's JDBC support class and the copies are removed; the timeout value is unchanged. Three call sites built a new ObjectMapper on every invocation: the Hosted Harness lifecycle settlement, the resident Workspace registration check and the preflight version readers. Each now reuses a static mapper with exactly the configuration it built before. Co-authored-by: Claude Opus 5.5 <[email protected]> |
||
|
|
a63a26dc84 |
refactor(managed-agent): consolidate storage alias keys and use DigestUtils (#16485)
The qwen-csi-alias/1 storage alias key had four independent copies of the
same length-prefixed SHA-256 routine. The JDBC repository entry point now
delegates to the shared registration key, and the two private copies in the
CSI ready/progress admissions are removed.
Hand-rolled MessageDigest.getInstance("SHA-256") calls are replaced with
Commons Codec DigestUtils as the module guide requires; incremental
length-prefixed digests keep their exact input bytes. runtime-local now
declares commons-codec directly.
A golden-value test pins the alias, physical, value and raw SHA-256 outputs
to independently computed digests so stored keys cannot drift.
Co-authored-by: Claude Opus 5.5 <[email protected]>
|
||
|
|
e98e4db75e |
perf(managed-agent): cache parsed statements on the MySQL pools by default (#16414)
Connector/J parses a statement's SQL on every prepareStatement unless its per-connection parse cache is on, and that parse was the largest share of the control plane's Java CPU under load. The server and embedded MySQL pools now add cachePrepStmts=true, prepStmtCacheSize=512 and prepStmtCacheSqlLimit=8192 as connection properties. A connection property overrides the URL in Connector/J, so each setting is added only when neither the URL nor the Druid connection properties name it, ignoring case, percent-encoding and surrounding spaces. Nothing is added when either names useServerPrepStmts or useCursorFetch, since the cache would then hold statements open on the server. The server pool binds spring.datasource.druid inside its factory, before the defaults are added: @ConfigurationProperties bound it only after the factory returned, and the string form of connection-properties replaces every connection property. |
||
|
|
24effd60a4 |
fix(managed-agent): lock storage rows through their alias key (#16376)
* fix(managed-agent): lock storage rows through their alias key A storage row has a primary record and three secondary indexes, and a locking read through one of them locks that record and then the primary record. Storage admission read the row for its fence through (tenant_key, storage_key), locking the primary record first, and then asked for the alias record in requirePhysicalOpen. Runtime binding creation, execution membership and journal commits lock the alias record first, so they deadlocked with it (#16320). - owner() and clearFence go through alias_key. - lockCovered lists the physical storage's aliases on a fresh read and locks them through alias_key, in alias_key order, before its physical_key scan, which is forced onto the physical index. Its scan used to take each alias's primary record first; it would otherwise deadlock with alias-first storage admission, and two recoveries of aliases sharing a storage take the aliases in one order. - StorageRowLockOrderMySqlIT pauses one transaction after a chosen statement until the other queues, for each pair, and pins the scan's plan. * test(managed-agent): pin the alias pre-lock to a range read of the alias index The pre-lock that orders lockCovered's alias locks carried no index hint and no plan assertion. It now forces uk_ma_storage_business_key and reads physical_key as well: a covering read of a list as long as the estimated row count becomes a scan of the whole alias index, which locks every gap. The plan case asserts a range read on that index, including a storage whose aliases are the whole table; the covering form fails it. The alias-list read on the separate connection now fails with its own message, so a log tells it apart from the later authority read. * fix(managed-agent): keep lockCovered's side reads off a single-connection caller lockCovered reads the alias list and the other aliases' authorities on a connection of its own, set to autocommit and read-only, so they see what is committed. On the offline recovery entry the DataSource is a SingleConnectionDataSource, whose every connection is the caller's own: the read committed the caller's work and the next FOR UPDATE failed in a read-only transaction. Both reads now go through committedRead, which reads on the caller's connection there and on an independent one otherwise. StorageRowLockOrderMySqlIT records what each second transaction queues on and requires the alias index, covers an alias committed after the recovery's snapshot, and runs lockCovered on a single connection inside a transaction that then rolls back. * test(managed-agent): pin clearFence's alias index and the offline write StorageRowLockOrderMySqlIT now drives a migration abort on MySQL and checks that the UPDATE clearing the fence plans through uk_ma_storage_business_key, the index owner() already locked the row through. The single-connection case asserts the caller's write matched its row before relying on the rollback discarding it. The alias-list comment in lockCovered says what the single-connection entry reads. |
||
|
|
acea5b1335 |
docs(design): correct the daemon PR state transitions design (#16487)
Fold the unposted findings of #16246's final docs-only review, and what the audits of those fixes turned up, into both language versions: - v0.26.8 (2026-11-05) ships the watch:* keys of #16258, so they follow the same deprecation window as prWatchEvents. - The view identity check normalises both URLs as pullRequestKey does (any path after the number and the port ignored) and compares host and number only. - Latency is stated as nominal (one interval, or ceil(n/30) for a view set of n), with the cases that make it longer. - The shared template contract moves key and template validation, chain resolution (event vocabulary and comment lane as parameters) and rendering from variable values into channel-base; %sender% is GitHub, %repo%/%url% keep the winner's bound URL spelling. - Every watch-file change reads and writes within one hold of the per-PR lock; a daemon claims the watch only when its refresh timer runs and its uid owns the watch directory and files, so writes stay temp-and-rename; a non-owner writes nothing. - The alias guarantees, the untrusted-primary exposure and the validation plan are updated to match; the Chinese twin carries the technical templates verbatim. |
||
|
|
301b61ddcc |
fix(channels): deliver plain conversation comments to PR-bound sessions (#16416)
* fix(channels): deliver plain conversation comments to PR-bound sessions With deliverToBoundSessions on, a plain comment on a bound PR still had to pass the repository's mention requirement before it reached the session. On threads GitHub lists as a mention, an assignment or a review request, the comment lane dropped it whatever the setting. On subscribed and similar threads the bound path's preflight rejected it, and the workaround, turning requireMention off, also made the channel answer plain comments on unbound PRs and issues there in public. Threads the bot account opened or commented on were not affected. The mention requirement keeps ambient chatter out of public replies; it is no authorization boundary. The private path now waives it through a preflight option that admits a message whose only group rejection is the mention requirement. The waiver covers a comment, not the PR's own first-contact description, from a sender the repository's allowlist names, in a repository the group gate admits, unless the sender is in operators: a bound session usually acts on GitHub as an operator's account, and its own comments would come back to it as turns. Sender, repository, pairing and message-route checks still run, and repositories that admit any sender keep the requirement. On the mention-type threads the lane admits such a comment only when the private path would deliver it: the routes match and a target resolves for it as a comment event, so templates keyed by the thread's reason do not apply to it. Its task is marked private-only: it never takes the channel path or posts a public error comment, and it is retired when no bound session is left. Comments only the waiver admits are dispatched after the rest of the lane and the first-contact body, so their outcome, a deferral or a gone session evicted from the binding map, cannot change how those are handled. Two failure paths that predate this change no longer post a public error comment for a bound event when the task store fails: the gone-session deferral under a partial scan and the retirement at the deferral cap. * test(channels): pin the default route, audit refusal and window hold of waived comments - Admit an unprefixed plain comment through `defaultMessageRoute`. - Keep a waived comment's key out of the cursor when an unreadable publication audit refuses its dispatch, and deliver it once the audit reads again. - Feed the first-contact body on the re-read when a failed waived delivery holds the notification window. |
||
|
|
3ec010e490 |
fix(web-shell): place the session search right of the activity toggle (#16481)
Follow-up to #16467: the search magnifier is now the rightmost control in the top row, immediately right of View activity, instead of sitting to its left. The open field still expands to the left of the bell, so the bell keeps its position while searching. |
||
|
|
dd4515ca27 |
feat(ci): isolate triage agent credentials and run all triage on ECS (#16468)
* feat(ci): isolate triage agent credentials and run all triage on ECS The triage agent carried a write PAT, so comment reruns and external fork-PR triage had to stay on ephemeral hosted runners while hosted capacity is tight and the ECS pool has headroom. Wire the token-isolation follow-up the workflow already documented: the agent reads GitHub with the job's read-only GITHUB_TOKEN and expresses every write as a draft; a separate publish job validates and executes drafts with the bot PAT, using one publisher script shared with local /triage runs. Contain the agent job, launch the CLI directly behind the hardened loopback model proxy, and move the deterministic maintainer resolver into the publisher. With no write credential in the agent environment, route every triage trigger to ECS behind the existing kill switch, and retire author_can_write. Markers, bot identity, and the finalize workflow's approve-on-green protocol are unchanged. Co-authored-by: Qwen-Coder <[email protected]> * fix(ci): bump triage CI budget and address triage review findings The new publish-triage job crossed the .ci-budget ratchet (7->8 jobs, 280->290 declared timeout-minutes), aborting Lint & Static before any lint or helper test ran. Bump the budget entry, mirror the artifact-name fallback expression on the upload side so an early-death run's drafts stay addressable, and enforce SKILL.md's process-label rule at the publisher chokepoint (welcome-pr, maintainer, help wanted, good first issue) with fail-closed tests, aligning the issue-workflow instruction that previously contradicted the rule. Co-authored-by: Qwen-Coder <[email protected]> * fix(ci): harden the triage draft pipeline after an adversarial audit Six findings from a multi-round pre-push audit, each with a mutation witness: kill lingering agent-user processes before the drafts strip/upload so a detached child cannot re-plant symlinks in the race window (upload-artifact follows them and RUNNER_TEMP is host-shared; unkillable survivors drop the draft set deny-by-default); lstat the draft containers themselves in the publisher preflight, since a symlinked bodies/ redirects the realpath containment base; reject cross-kind actions (review/close-pr on issues, close-issue on PRs); install util-linux for runuser as the sibling lanes do; make the mktemp'd proxy-wrapper directory traversable by the agent user so the gh/git wrappers do not silently fall out of its PATH; pin the artifact-name symmetry, the kill-before-strip ordering, and the toolchain install line. Design pair updated in both languages. Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
1ea05364a6 |
perf(managed-agent): take tool execution admission off tenant placement (#16478)
* docs(managed-agent): design tool execution admission without tenant placement Admission still takes tenant placement on every tool call. It orders admission's plain read of the harness drain fence against requestHarnessDrain, the only fence writer that holds no row admission takes. Lifecycle phases already hold the Session root, and the storage fence is backstopped by migration's retirement check. The design has the drain take the Session root after placement, and lets an ordinary session-class admission with an existing root skip placement, taking the root as its first statement so a REPEATABLE READ snapshot cannot predate the drain. Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs(managed-agent): record the storage alias order blocker for placement-free admission Co-Authored-By: Claude Opus 5.5 <[email protected]> * perf(managed-agent): take tool execution admission off tenant placement Every tool call still took tenant placement in admitExecution. Placement ordered admission's plain read of the Harness drain fence against requestHarnessDrain, the only fence writer holding no row admission takes. requestHarnessDrain now locks the Session root after placement. An ordinary session-class admission with an existing root, no lifecycle authority and no storage or LOCAL storage skips placement and locks that root as its first statement, so its REPEATABLE READ snapshot cannot predate a committed drain. Other admissions take placement first, as before. completeStoppedSessionRelease locked the storage alias and owner rows before the binding, the reverse of admission and createSession. It now locks the binding first, so a placement-free admission cannot close a cycle with it. Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs(managed-agent): format the admission design with the pinned Prettier Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: Claude Opus 5.5 <[email protected]> |
||
|
|
06a0cb3250 |
perf(managed-agent): take runtime binding control off the tenant guards (#16480)
Binding control took tenant placement and the publication guard for every session-class binding, so each periodic lease renewal queued on both tenant-wide rows. The publication guard only tells whether a CSI profile original's retention root exists; any other binding is answered null or refused whatever it says, so lockBindingControl now takes it for profile bindings only. Claim, renew and release change only the operation lease and move no binding out of its state. Like dispatch, they now decide the CSI pin under the Session root alone when it exists. compareAndSet keeps placement, which it takes next and which must precede the root. Co-authored-by: Claude Opus 5.5 <[email protected]> |
||
|
|
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> |
||
|
|
8660f75430 |
fix(ci): refresh host assets on older PR checkouts (#16476)
* fix(ci): refresh host assets on older PR checkouts Co-authored-by: Qwen-Coder <[email protected]> * style(ci): format host asset regression cases Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
ad83860092 |
feat(web-shell): move session search beside the activity toggle (#16467)
* feat(web-shell): move session search beside the activity toggle The sidebar search lived in the Workspaces header, where it appeared only on hover and moved its input into a separate row. Put the toggle in the top brand row next to View activity, expand the field inline when the column is wide enough, and fall back to a full-width row under the brand row for narrow drawers and columns. Hide the control while the activity view replaces the session list, and keep the collapsed strip's search in its session popover. * test(web-shell): scope the drawer brand assertion to the logo The always-visible search toggle adds a second SVG to the sidebar brand row, so the drawer smoke test parent-level svg locator matched both the logo and the search icon and failed in strict mode. Target the logo own aria-hidden container instead. |
||
|
|
cb282ef5cf |
test(web-shell): unit-test settings development route (#16456)
Replace the full Vite dev-server startup with a direct middleware test so the settings route contract no longer depends on Babel and App.tsx cold-start time. Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
0964c4bc3c |
test(serve): cover the workspace_runtime_stop boot-time conjunction (#16469)
The stop surface is advertised only when five boot-time legs hold: managedChildProcesses, workspaceRuntimeRemoval, a live ACP http handle, manageScheduledTaskSessions, and a managed runtime whose bridge exposes stopWorkspaceRuntime/getRuntimeStopCompletion/getRuntimeStopSnapshot. Nothing exercised that computation from /capabilities: the only existing references inject the workspaceRuntimeStopAvailable toggle directly, so any single leg could regress while the suite stayed green. The new test mounts the real app with every leg wired and asserts the feature is advertised, then drops one required leg and asserts it is not. Part of #12563, does not close it. Patrol-Run: qwen-issue-patrol/jmw51qoerzl Co-authored-by: yiliang114 <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
45cde86998 |
feat(cli): align managed agent basic tools with daemon (#16445)
Expose glob in ordinary file sessions, durable todos in Shell sessions, and PDF page selection in Hosted read_file. Restore saved todo state on session reload while keeping exact current-schema validation and restricted resident/CSI tools. Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
478c2f87ab |
feat(ci): make flaky-patrol rerun and no_action decisions visible (#16459)
* feat(ci): make flaky-patrol rerun and no_action decisions visible The CI Failure Patrol posted only a hidden HTML marker when it re-ran a flaky failure or could not classify one, so maintainers saw a red PR with no explanation and clicked Update Branch — advancing the head, dismissing approvals, and re-running the whole CI for a failure that was already being handled on the same commit. Post a short bilingual notice alongside the marker for both decisions: the rerun notice states the transient cause and that no Update Branch is needed; the no_action notice asks for manual review before rerunning or updating the branch. The deterministic-failure comment is byte-identical, and the post-success reset marker stays hidden. Pin the visible notices, the marker round-trip through dedup and the per-head action count, and reason escaping for all three actions. * fix(ci): strip bidi overrides from flaky-patrol notice reasons An adversarial audit of the visible patrol notices found that bidi control characters (U+200E/U+200F, U+202A-U+202E, U+2066-U+2069) passed through the reason escaping untouched. The reason is classifier output derived from untrusted CI logs, and a right-to-left override can visually rewrite the very sentence maintainers trust when deciding whether to update a branch. Drop those characters in the shared escaping helper so all three visible decisions (and the deflake issue signature) are covered, and pin the stripping for each action. Removing the strip line fails the new test. * fix(ci): cover the Arabic letter mark in the patrol bidi strip An escalated audit round compared the strip class against the full Unicode Bidi_Control set and found U+061C (Arabic letter mark) missing; it can reorder adjacent Arabic-script text in a visible notice. Add it to the class and extend the per-action pin payload, so the class now matches the complete Bidi_Control set. Removing just U+061C fails the pin test. * fix(ci): collapse newlines in patrol reasons and pin the audit gaps The verification round found that a newline plus a line-start fence in a classifier reason opens a block-level code fence in the visible notice: the folded Chinese block and the tracking marker render as visible code. Collapse newlines and their surrounding whitespace to a single space in the shared escaping helper, keeping every reason single-line. Close the coverage gaps the same round measured: feed all twelve Bidi_Control code points individually, pin the English-before-fold and Chinese-inside-fold placement of the deterministic comment, and assert the fold's closing tag in all three notices. Witnesses: removing the collapse, narrowing the bidi class, dropping U+200F alone, swapping EN/ZH, or dropping the closing tag each fails the suite; a marked rendering probe shows the fence swallowing the fold before the fix and a clean render after; benign comment bodies remain byte-identical to base. |
||
|
|
99c2e28d3a | fix(web-shell): show readable Skill completion details (#16451) | ||
|
|
ee1a9b1e1e |
fix(ci): move audio prebuilds to macOS 15 (#16464)
Co-authored-by: luoyun <[email protected]> |
||
|
|
7cb46d9fed |
feat(hooks): add FileChanged notifications for local sessions (#13969)
* feat(hooks): add FileChanged notifications for local sessions * fix(ci): preserve shell gate coverage and trim transcript data * fix(ci): flush debug prompts and isolate git fixtures * fix(hooks): respect ACP watcher ownership and skill registration * test: stabilize hosted recovery and failed spawn fixtures * fix(ci): budget the complete hosted integration fork * fix(runtime-broker): accept MariaDB CSI guard metadata * test: align schema baseline and hook dispatch waits * fix(ci): allow hosted shared fork to finish all classes * fix(hooks): preserve file watching across errors and cwd changes * fix(ci): isolate reference archive extraction per run * test(ci): keep reference archive checks dependency-free * fix(hooks): constrain recursive watches and repair CI * test(web-shell): synchronize verified connection return * fix(ci): correct runtime broker callback indentation * test(web-shell): match the managed workspace registration label Keep the remote workspace registration smoke checks in sync with the service label added by unified workspace navigation. Preserve exact text matching and all registration and replay assertions. * fix(ci): reduce standalone runtime fixture overhead * fix(hooks): ignore implicit atomic-write temporary files * test(managed-agent): recover initial node port conflicts * fix(hooks): observe parents before discovery anchors disappear * test(managed-agent): await stream cleanup before recovery teardown * test(managed-agent): align hosted shell fixture capabilities * test(managed-agent): let OS choose initial harness port * fix(ci): restore runner-local Java cache permissions * test(runtime-broker): use native execution profile paths * test(managed-agent): bind valid workspace upload probes * test(managed-agent): reuse the upload probe digest fixture * test(managed-agent): bind hook fault listeners to available ports * test(managed-agent): align the native profile path fixture * test(managed-agent): Wait for projection refusal retries * ci: Prepare daemon Java cache before Node preflight * test(managed-agent): check channel model calls after delivery * fix(hooks): observe explicitly registered symlink targets * test(managed-agent): separate consumption from relay snapshots * test(managed-agent): target tamper injection by resource key * test(managed-agent): exhaust attestation EOF retry in fault gates * fix(ci): bound RocketMQ release downloads * test(tui): await the restored assistant before capturing history * fix(ci): use a checksum-pinned RocketMQ mirror * fix(ci): provision missing browser test fonts * fix(ci): quote the font probe environment * fix(ci): prepare browser fonts without elevation * test(core): compare complete prune reports without ordering * fix(ci): repair only runner-local Java tool caches * test(managed-agent): qualify fixture JDBC templates * fix: isolate reconnect hooks and cancellation test fixtures Skip chat initialization so MCP reconnect cannot re-enable file hooks, and keep cancellation fixtures isolated from the background worktree scanner. * fix(ci): tolerate a missing Java cache helper on resumed releases Resuming an existing release checks out a tag that may predate the helper, which failed all five Java jobs before setup-java ran. * fix: finish the main merge for harness deadlines and workflow size Use the renamed settle-timeout accessor in the merged hosted-harness tests, and record sdk-java.yml's new size after the resumed-release cache guard. * style(managed-agent): restore import grouping in merged verification tests * test(managed-agent): require consumed child result mirrors * test(web-shell): center repository settings capture --------- Co-authored-by: yiliang114 <[email protected]> Co-authored-by: yungsen.hys <[email protected]> Co-authored-by: Shaojin Wen <[email protected]> |
||
|
|
e61ad3959e |
fix(managed-agent): settle a title the dispatcher claimed first (#16447)
* fix(managed-agent): settle a title the dispatcher claimed first renameSession admits the RENAME row and then claims it. The background SessionRenameCoordinator scans rows a request has just admitted, so its claim can win without any concurrent caller, and the request answered 503 "The Session title is already being delivered." for its own rename. Wait a bounded 2s for that delivery to settle and answer the recorded command instead of failing the request. Fixes #16431 Co-authored-by: Qwen-Coder <[email protected]> * fix(managed-agent): keep the creator gate on the rename settle arm The settle arm answered the recorded rename outcome without re-running the replay actor gate, although it shares the COMPLETED read-back's TOCTOU window: a pre-read that missed the recorder's row lets a non-creator OPERATOR reach the settle through the duplicate-key winner path and take a 200 the COMPLETED arm refuses with 409. Mirror that arm's gates — requireReplayActor on the settled Session, and the last-visible serialization — so both arms answer identically. Test: a non-creator OPERATOR racing the recorder's key through the settle arm meets the same 409 workspace_unavailable as through the COMPLETED arm, while the recorder still replays its own outcome; the dispatcher's completion is asserted so the refusal provably comes from the settle arm. Load-bearing: reverting the gate answers the raced request 200 and fails the test. --------- Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
989d31ee9e |
test(managed-agent): retarget the lifecycle IT and retry snapshot claim deadlocks (#16446)
The publication-lane IT still parked the receipt thread on the placement guard's `INSERT INTO ma_tenant_guard`, but #16354 moved ordinary publication lanes onto the Session root, so that statement never runs and the test now fails on its own latch instead of on a product lock cycle. Park the receipt on the root statement its lane actually executes. The sibling native-snapshot IT exposed a real gap: two publishers of the same snapshot claim the manifest row with `INSERT ... ON DUPLICATE KEY`, and InnoDB can resolve that by rolling one side back as a deadlock victim. Retry the claim a bounded number of times so the loser reads the winner's row and answers the replay descriptor instead of surfacing a deadlock. Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
1ecf444010 |
test(interactive): poll the foreground-shell frame instead of snapshotting it (#16455)
#15712 recurred on 2026-11-05 (run 42069115052, macOS): the case asserted `compact(frame('mode-before'))` contains `YOLO mode` straight after a PTY write, and on a loaded host the approval footer had not repainted yet — the captured frame still held the startup banner, so the assertion failed on a correct UI. The draft snapshot just above it has the same shape. Poll both through the suite's `until`, which already scales its budget 3x under CI (#16276), so a slow repaint is waited out while a genuinely missing footer still fails on the same message, with the frame kept in FRAMES.json. Verified locally: the case passes (16.9s) and the whole file passes (3 passed, 1 skipped). |
||
|
|
1853b1505f |
fix(subscription): isolate activation and restore sign-in recovery (#16453)
* fix(web-shell): wait for session before checking subscription commands * fix(cli): keep signed-out subscription startup in the composer * fix(subscription): preserve model selection across sign-in * fix(subscription): align sign-in with model selection scope * fix(subscription): apply reasoning defaults across models * fix(subscription): tag Qwen web links by client * fix(subscription): prefix Qwen web client tags * fix(subscription): attribute Qwen web links by paywall scene * fix(subscription): recover historical sessions with saved API models * fix(cli): remove the signed-out subscription startup notice * fix(subscription): support standalone desktop activation and expose errors * fix(subscription): isolate activation and session model selection * fix(subscription): enforce auth policy and restore home login * test(cli): preserve the default initializer mock on restore --------- Co-authored-by: luoyun <[email protected]> Co-authored-by: 易良 <[email protected]> |
||
|
|
1b1f4455d9 |
ci: build the PR tree once and shorten the required path (#16450)
* ci: build the PR tree once and shorten the required path The no-AK integration gate, the four web-shell smoke shards and Lint & Static each rebuilt the tree test_build already uploads, and the build cache rarely helped: most runs logged "29 of 29 workspaces changed" because the arch-keyed cache was split across the mixed x64/ARM64 pool and a prefix restore returned the newest entry instead of the base commit's. - test_build restores the build its base commit saved (ci-build-cache.mjs key --at), drops runner.arch from the key, and runs the serve fast-path closure and core subpath checks against the built tree. - The no-AK integration gate unpacks that tree and runs as three shards; integration_no_ak_result keeps the required check name. - The web-shell smoke unpacks the same tree instead of building; consumers recopy the opentui native assets for their host (host-assets). - The standalone runtime regression moves from unit shard 1 to shard 4. - A java_only profile skips the TypeScript lanes for changes confined to the Java packages; Lint & Static runs the scripts/tests suites that name them. - Drafts skip the integration gate and the browser smoke; ready_for_review starts the full run. * ci: check the settings schema in test_build, which has the core dist Lint & Static only had core's dist because the serve fast-path check built it; with that check moved, Generate settings schema failed to import it. * ci: keep the standalone regression on unit shard 1 Moving it did not shorten shard 1: the regression runs in the side lane, in parallel with the CLI and core suites, and shard 1's time is its CLI slice (576 s against 147 s on shard 4 for the same 181 files). That imbalance is left to duration-based sharding. |
||
|
|
1d64177286 |
docs(providers): document OCI Generative AI under OpenAI-compatible providers (#16345)
* docs(providers): document OCI Generative AI under OpenAI-compatible providers Adds a subsection to model-providers.md covering OCI Generative AI's two OpenAI-compatible base URLs (Chat Completions and Responses), Bearer API-key auth, the publisher-prefixed model ids, a ready-to-paste settings.json, and the endpoint behaviours a user otherwise has to discover by trial: pinned contextWindowSize, no model discovery, the max_completion_tokens requirement of GPT-5 / o-series on Chat Completions, the Responses-wire requirement for gpt-5.6 / GPT-6 tool calling, gpt-oss staying on Chat Completions, compressed error bodies, and imported models addressed by endpoint OCID. Refs #16332 (docs-first path recommended in triage). * docs(providers): list the API-key regions for OCI Generative AI The OCI section named `uk-london-1` among the regions that serve the OpenAI-compatible endpoints and omitted Hyderabad and Osaka. The API Keys page is the source of truth for the Bearer-key path this section documents, and it lists Frankfurt, Hyderabad, Osaka, Ashburn, Chicago and Phoenix; London is only on the IAM-auth agentic-inference list. Name those six regions and link the API Keys page instead of the agentic regions page, since it also lists the model families the key covers. |
||
|
|
f9124d6b1d | test(managed-agent): cover pending sibling approval holds (#15994) | ||
|
|
e777fc7502 |
feat(managed-agent): enable automation by default (#16448)
* feat(managed-agent): enable automation by default Co-authored-by: Qwen-Coder <[email protected]> * style(docs): match pinned Prettier formatting Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
3b39fc2a19 | fix(core): accept images for Qwen VL models under their Ollama names (#16309) | ||
|
|
a051a6a796 |
fix(web-shell): batch session deletions at the route limit (#14637)
* fix(web-shell): batch session deletions at the route limit * test(web-shell): cover bulk delete in visual previews * fix(web-shell): retain bulk delete interruption errors * fix(web-shell): retain deletion failures across workspace batches Collect per-session and request failures throughout a deletion without losing later causes or earlier successful current-session cleanup. Keep archive behavior unchanged and document the daemon request-limit coupling. Add gated regressions for both cross-workspace failure orders and multiple per-session errors across batches. The new gates reject parallel-workspace and per-workspace-error-reset mutations. * test(web-shell): cover bulk delete merge boundaries Preserve workspace and standalone failure causes for per-session and rejected requests. Verify each deletion batch captures its UI owner before the request and invokes its own invalidation callback with that batch result. --------- Co-authored-by: qwen-code-dev-bot <[email protected]> |
||
|
|
666d0cae7b |
fix(web-shell): preserve wrapped drafts during arrow navigation (#14909)
* fix(web-shell): preserve wrapped drafts during arrow navigation * fix(web-shell): handle bidi composer history boundaries Compare caret and document edges by visual row so RTL and mixed-direction drafts can reach history without breaking soft-wrap caret movement. Cover genuine edits after history recall in both arrow directions and make the selected-history regression exercise the single-line paging branch. * fix(web-shell): reset navigation on history selection Start a fresh navigation sequence when selecting a search or panel result, preserving browse suppression while dropping stale prompt draft tags. Cover prior paging, selected-draft restoration, and visual row decisions with focused unit and browser regressions. * fix(web-shell): keep focus on recalled prompts Consume ArrowDown while an explicit recall has no next history entry, keeping ordinary footer navigation after returning to the draft. Cover both prior paging states and the subsequent normal footer handoff. |
||
|
|
ff775787f5 |
feat(channels): journal private bound-session delivery and scan health (#16237)
* feat(channels): journal private bound-session delivery and scan health The event timeline could not tell the private delivery lane's story. A prompt injected into a PR-bound session ended on the same `running` word as an event still in flight, no task row named the session it reached, and the three private watch retires plus the dead-letter left only stderr behind — so a silent consumption looked like a quiet repository. A bound event rejected by the channel's own gates was worse than invisible: its skip row was followed by running rows, reading as a delivery. The private delivery method returned a boolean meaning "settled", which conflated an injected prompt, a private retire and the public fallback. It now returns a verdict, and the task runner derives the journal's terminal word from it, so an event that was never delivered can no longer be recorded as delivered. Routing, fallback, retry-budget and cursor decisions are unchanged. The binding scan is a new hard dependency: while it has never succeeded the cold-start gate stalls every notification, yet the poll reports ok. Degraded rows now surface that beside the stderr lines the adapter already throttles, and on the edge of the existing watch-reconcile flag, so a permanent outage cannot flood the journal. Attaching this to the poll detail was rejected: both cold-start gates return before the detail is set, which is exactly when it would matter. No new event type and no protocol change — an outcome is already an open string. The dead-letter's message body and its failure-path payload dump stay out of the journal. Also labels `failed_ambiguous`, which was already written but rendered as a raw token. * fix(channels): make the bound-delivery journal claims true Review round 1 found sixteen places where the journal, its labels or its documentation promised something the code did not do. All sixteen are addressed here; none is deferred. Three were ordering or attribution defects in the new rows. A watch retire was journaled before the removal it describes, so a throwing removal left a terminal claim for an event the next poll re-runs and retires again under a different reason. Rows written while a delivery is cleared lost the session they were about, which is the one fact the private lane's attribution adds. And the pre-claim watch retire sliced the loaded state before saving with no rollback, so a failed save lost the event with no trace at all — the comment claimed the opposite. Two were counts that measured something other than their label: the partial scan published the routing map's size, which counts bound PRs, as a session count; and the streak advances per binding scan, not per poll, because a gone-session retry refreshes again inside the same poll. The session count now comes from the scan's own rows, and the streak is labelled as scans in both languages and in the stderr lines that share the counter. Re-cadencing the counter itself would change the throttle timing the previous PR shipped, so the label moved instead. Two were missing surfaces: the pending-queue-overflow retire wrote only stderr and the dead-letter file, and an unreadable watch state was reported as a pending backlog whose stated remedy cannot clear it. The overflow now journals a body-free skip, and the watch guard classifies a read failure separately while its gate stays fail-closed. The recovery signal the prose promised did not exist: a poll/ok row is written after every poll that does not throw, including all of an outage, so it cannot mark the end of one. The watch guard now journals its clearing edge, and the prose says why ok rows cannot serve. The rest were documentation and test-coverage corrections: the protocol reference promised detail.streak on every degraded row when only the binding-scan rows carry it; the design file map certified the protocol reference as unchanged while this branch edits it; the override's stated consequence was backwards; and five guards had no witness or only half of one. Each now has a test, and the suite grew from 438 to 444 in the GitHub package. Verified by 37 mutations, all killed. Two initially survived and were investigated rather than accepted: a loose sessionId count that three unattributed-row-free rows still satisfied, and a filter that matched no test after a rename. Both were tightened until the mutation died. * docs(channels): align the journal ledger with the round-2 verification The validation section still cited the round-1 mutation count after the review fixes added fifteen more, and the Chinese half had lost the count altogether during the rewrite. Both now state 37 applied and 37 killed. Also records why two mutations initially survived and what was done about them, since a sweep that cannot distinguish "no test ran" from "the guard held" is not evidence: a loose sessionId count that three correctly attributed rows still satisfied, and a filter left matching nothing by a test rename. The Web Shell line now mentions the absence coverage too. * fix(channels): keep the lost bound session named on every journal row The second review round of the bound-session journal found fifteen gaps. Three were consequential, and two of those were introduced by this PR's own previous round: The gone-session retry never updated the local delivery, so with two followers both gone the terminal row named the first one — a session evicted a step earlier — while the row above it named the last. An operator reading "which session lost this event" would open the wrong workspace. Remembering the target only for the transition that clears the delivery is not enough: once the clear is persisted, every later poll re-enters the absence gate with no delivery to read, and the dead-letter at the deferral horizon reads a record that has none either. A driven run of that sequence left 239 of 242 rows unattributed, with the terminal row naming nobody — the one fact this lane's attribution exists to supply. The lost target is now persisted as attribution only; the delivery is deliberately not restored, since that would re-enter bound delivery and change routing. The overflow retire was journaled before its queue shift was durable, with no rollback, so a failed save left a skip row for an event a restart would later deliver. It now saves before it journals and restores the shift when the save throws, matching the sibling pre-claim path. Also: the partial-scan session count now includes the sessions retention keeps routing (a draining workspace lists none while still delivering to three), and both pre-claim retires carry the frozen target so the timeline and the dead-letter agree about the same event. Four coverage gaps whose mutants left the whole suite green are closed: the guard keeping the partial-scan row off the cold-start path, the session on the no-candidate retire, a second healthy poll so the recovery row's edge trigger is distinguishable from an unconditional write, and both a shape test and a Chinese render test for the interpolating labels. The docs said more or less than the code: detail.sessions is carried by one row, not by every partial scan; the normative sessionId definition read a retire chip as a delivery; the emit-point inventory missed the overflow site; and bindings_partial was described as recovering implicitly when a successful multi-page scan is its producer. Auditing that last correction found the stderr census was still incomplete — the lane has five recurring health and capacity sites, not three — so it now names all five, ranks them by consequence and states its own scope. * docs(channels): define what the partial-scan session count actually counts The count became listed-plus-retained when retention was included, but three surfaces still described the old value. The protocol reference called it "the sessions the map still routes to", which is wider than the code: the map also skips channel-owned sessions and unparseable binding URLs. Both design halves still said it was "the scan's own row count", which is narrower than the code and was the exact wording the review asked to correct. Define it as a session-row count — the rows this scan listed plus the sessions retention keeps routing, bounded by the retention cap — and say explicitly that it is not the number of entries surviving the map's own filters. Also record that "listed" in the row label and in the stderr line is shorthand for listed-or-retained and that both print the same number, so the wording cannot quietly drift apart from the value again. Documentation only: the adapter and its tests are byte-identical to the previous commit, so every runtime result reported for this branch still applies. * fix(channels): close the review gaps in the private-lane journal Address the eight open suggestions and the five deferred findings from the round-3 review, each with a mutation-verified guard (10 new mutations, 10 killed; one cap-count fixture initially survived because the first empty partial already capped lastBindings, and was rebuilt so retention is above the cap exactly at the emitting scan). - R1-15: the overflow dead-letter append and the sidecar save now fail independently. A failed save rolls the shift back, names the watch-state path instead of blaming the dead-letter file, drops the payload dump (the body is already durable), and remembers the head so the next detection skips the re-append. The save-throws test now drives a second detection and asserts exactly one dead-letter line. - R2-6: the pre-claim skip comment and both design languages now say only the overflow retire writes a dead-letter record; watch_no_candidate and no_role_matched leave the skip row as the event's only trace. - R2-3: bindings_cold_empty no longer claims implicit recovery — an empty partial is a successful scan, the streak resets only on a complete or non-empty snapshot, and past the escape the silence is the throttle maxing out, not recovery. - R3-1: a 1100-session fixture pins detail.sessions to the 1024 retention cap at the emitting scan; swapping retainedCapped.length for retained.length reds it while the two sibling count tests stay green. - R3-5/R3-6/R3-15: the design's outcome cell lists failed_ambiguous and degraded, the watch-guard bullet admits the read-failure error field, and the sessionId carve-out covers every row written on a clear plus the pre-claim skip; the chip sentence says reached-or-lost. Both languages. - R3-7: the three private-retire watch tests assert the public path stayed empty; leaking the envelope through handleInbound reds them. - Deferred: the gone-horizon attributes the in-memory task before retiring and the dead-letter record names the lost session; the watch-guard row re-journals when the blocking cause changes; the subscriptions-off recovery edge has a test; the recovery row renders Recovered/已恢复 instead of Degraded (wire outcome unchanged); a gone-retry fixture pins the scan-scoped streak at 10 inside poll 4. Verified: channels/github 595 passed, web-shell channels 343 passed, eslint and prettier clean; design mutation ledger updated to 47/47. * fix(channels): rework the overflow retire ordering and close round-4 review Critical R4-1: the overflow branch saved the sidecar mid-pass, committing the advanced baseline before the pass's later events were queued; a crash then never re-derived them. Remove the mid-pass save entirely — the head is sliced in memory only, and the baseline and full queue commit together in the single end-of-pass save, with the skip rows journalled after it. The dead-letter record is now the retire's commit point. A lazily loaded, file-backed key set (restart-durable, replacing the process-local map) skips the re-append (R4-16), and both drains recognize a dead-lettered head and complete its retire instead of delivering it, so no event is both delivered and filed as retired undelivered (R1-15 follow-up). Also addressed: - R4-12/13/14: terminal, transition lost-session and pre-claim rows carry sessionWorkspaceCwd so Open-session reaches a session in another workspace. - R4-11: the no_role_matched comment states the real ordering — the dedupe cursor is in memory until the base saves it, so the skip row is at-least-once. - R4-15: already_delivered_other_role is documented as a defensive, unreachable guard and dropped from the published vocabulary. - R4-2/3, R3-5: §1 outcome cell adds suppressed/posting, reason covers task and poll rows, sessionId carve-out adds cancelled and distinguishes live running rows. Both languages. - R4-4/5/6: the pre-claim census acknowledges the role-aware drain's pre-existing fourth retire; the retire-carries-session rationale notes the preflight exception; the dead-letter write-failure note names the non-recoverable public-suppression exception. Both languages. - R2-3/R4-7: cold-empty reset is keyed on the routing map and trust flag, and the escape's lane-open claim is qualified for the refresh-failure producer. - R4-8/9: the recurring-site census adds the credential/rate-limit pass abort and corrects the no-existing-flag claim for the stale-map refresh failure. - R4-10: watch-guard error wording covers reconciliation failure too. - R4-17/18/19: openTarget joins the interpolation guard with a ZH render assertion, the EN streak label says consecutive, and ZH degraded/retired/ recovered labels get render assertions. Verified: channels/github 601 passed, web-shell channels 331 passed, eslint and prettier clean; 4 new mutations killed (mid-pass save, file-dedupe, drain guard, workspace lookup); design ledger updated to 51/51. --------- Co-authored-by: verify-round <verify-round@local> Co-authored-by: verify-pr <verify@local> |
||
|
|
07a467c38a |
feat(web-shell): upload Skill archives and reconcile results (4/4) (#16424)
* feat(skills): add file-backed archive installation kernel * feat(skills): expose native archive routes and receipts * feat(sdk): support native Skill archives and receipt lookup * feat(web-shell): upload Skill archives and reconcile results * fix(web-shell): retain archive results across owner and dialog changes * fix(web-shell): allow abandoning an unconfirmed archive lookup |
||
|
|
a1d713e747 |
feat(cli): report interactive program status with OSC 7501 (#16407)
* feat(cli): report interactive program status with OSC 7501 Report a single root OSC 7501 record from the interactive UI so terminals and agent inboxes can show whether Qwen Code is working, waiting on the user, or finished, without parsing the screen. - idle / working / blocked (permission, question, auth) / done / error, with app=qwen-code on every report - done and error latch until the next turn; a cancelled turn returns to idle; done and error are kept on exit, everything else is cleared - msg names the tool at most, never its arguments or model text - TTY only, deduplicated, retried after a failed write; never wrapped for tmux passthrough - cleared while an external editor owns the terminal, rewritten on return and on SIGCONT Closes #13870 * fix(cli): latch the OSC 7501 turn outcome when the turn ends The outcome was recomputed from a history index on every history change, so an error added while idle (a failed slash command) flipped `done` to `error`, and memory compaction reset it to `idle` or hid an error from the turn. Decide it once when streaming state returns to Idle, bound the turn by item id, and reset only when history is cleared. Also count a blocked prompt and a stop-hook loop as failed turns, and pin the msg-only report, release/restore and editor call sites with tests. * fix(cli): reset the OSC 7501 outcome on /clear and cap msg by decoded size /clear only masked the latched outcome: the tracker kept `done` or `error`, so the next item added while idle brought it back, and exit could keep a stale badge. Reset the tracker when history empties. The msg limit checked only the encoded length, which lets a 2049-byte message through as 2732 base64 characters. Cap the decoded text at 2048 bytes, which also bounds the encoded form. Correct the design doc: a slash command runs as a turn and decides its own outcome; it is not an idle history change. * test(cli): assert the decoded msg is present before measuring it decodeMsg returns string | null, which tsc --build rejects as a Buffer.byteLength argument. * fix(cli): ignore errors already pending when an OSC 7501 turn starts A terminal API error stays in the pending area until the next submit commits it, and a Goal submission skips that commit. The next Goal turn then ended with the old error still pending and latched `error`, which exit kept. Record the failure items pending at turn start and count only new ones. Also restore the program status before the raw-mode restore in useLaunchEditor, which can throw; say control characters become spaces in the msg encoder; and note in the design that the OpenTUI renderer does not report status yet. |
||
|
|
32d22f950c |
feat(managed-agent): support durable structured user questions (#16433)
Connect Hosted question actions, structured answers, durable continuation, and the WebShell question form. Cover canonical response replay and pending-question recovery across Harness and Java context restarts. Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
1a20792cfa |
ci: route the no-AK integration gate to ECS for every pull request (#16132)
* ci: route the no-AK integration gate to ECS for every pull request
Same trust class as lint_and_static (2026-11-02 extension of the
2026-10-31 decision): the integration step executes PR code, but the
lane carries zero secrets by construction — every model key is emptied
at the step and the job's only token is the read-only checkout grant.
The gate's step-level runner.temp HOME becomes run-unique and is
cleared before use (the R2-1 lesson: RUNNER_TEMP survives across jobs
on this pool). test and integration_cli keep the association-gated
ubuntu_runner. Mutation-verified: runs-on revert, fixed HOME, and a
real key in the PR-code step each red the routing battery.
* fix(ci): isolate no-AK HOME from the first step; value-pinned zero-secrets
Round-2 review findings: (1) Critical — the gate-scoped HOME missed the
lane's actual fork-code start: checkout's local action and the install
(lifecycle scripts plus scripts/prepare.js, un-skipped) ran under the
runner's real shared home with a shared COREPACK_HOME — the exact
cross-job poisoning channel the lint acceptance closed. Mirror lint:
first-step GITHUB_ENV run-unique HOME + COREPACK_HOME inside it +
shared verified XDG cache + always() reclamation. (2) Critical — the
zero-secrets guard was name-based and missed odd-named secrets; enforce
by VALUE (every non-path env key empty, no secrets.* anywhere in the
gate). (3) runs-on literal pin tightened (timeout line also mentions
lint_runner). Docs: EN single-lane phrasing, stale merge-queue claim,
2026-11-02 paragraph rewritten for the first-step shape. Six mutations
red (first-step removal, shared corepack, odd-name secret, no cleanup,
runs-on revert, fixed HOME).
* docs(ci): correct the enforcement-order claim and stale trust-basis note
Round-2 review: the doc claimed the routing battery runs before
dependency install — false (HELPER_TESTS imports yaml, runs after
install, and not at all on github_ci_only PRs' own runs); and the
ci.yml trust-basis comment still described the round-1 gate-scoped
HOME shape. State the actual timing and detection latency, and the
shipped first-step shape.
* fix(ci): scrub ANTHROPIC_AUTH_TOKEN at the no-AK gate; honest cache naming
Round-3 review: the Anthropic SDK's auth resolver back-fills
ANTHROPIC_AUTH_TOKEN from env, so a runner-account residue would survive
into fork PR code on the pool — add it to the gate's scrub list (pinned
by both suites). The 'Configure persistent npm cache' step name promised
persistence the per-run HOME removes; rename it and record the accepted
cold-install cost (shared pnpm store stays a follow-up).
* fix(ci): scrub ANTHROPIC_AUTH_TOKEN at the no-AK gate; honest cache naming
Round-3 review: the Anthropic SDK's auth resolver back-fills
ANTHROPIC_AUTH_TOKEN from env, so a runner-account residue would survive
into fork PR code on the pool — add it to the gate's scrub list. The
value whitelist only iterates present keys, so the deletion mutation
escaped it; pin the key's presence-and-empty in the battery and the
28-key literal list. The 'Configure persistent npm cache' step name
promised persistence the per-run HOME removes; rename and record the
accepted cold-install cost (shared pnpm store stays a follow-up).
* test(ci): pin the no-AK grant, HOME template and reclamation path
Three assertions in the no-AK routing battery proved less than they read:
- the job's `permissions` was never inspected, so the read-only-checkout
grant that justifies routing untrusted fork code onto the pool could be
widened without a red test;
- `create.includes('HOME=')` is satisfied by `COREPACK_HOME=` and
`XDG_CACHE_HOME=`, so deleting the real HOME/USERPROFILE publication kept
the test green;
- the cleanup only had to contain the `qwen-no-ak-home-` prefix, so a path
that dropped `-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}` would still pass
while removing a directory nothing used.
Pin the grant by value, the publication by its printf template, and the
reclamation by the exact run-unique path the create step builds.
Co-authored-by: Qwen-Coder <[email protected]>
Patrol-Run: qwen-pr-closeout/jmw48g5gafx
* test(ci): pin the realized HOME values in the shared ungated lane loop
R2-1: assert the create `home=` line, the gate QWEN_HOME and the cleanup
command by value, and require the exact set of `$GITHUB_ENV` writers. An
`echo` stand-in for the cleanup, a `-v2` create path and an appended second
HOME writer all kept the battery green under containment checks.
R1-2 / R1-1: hoist those pins into the shared `ungated` loop so
`lint_and_static` gets them too. Its create step was pinned by
`includes('HOME=')` (satisfied by `COREPACK_HOME=`) and its cleanup by
`includes('qwen-')`, so a dropped `HOME=%s` or a retargeted `rm -rf` survived.
Co-authored-by: Qwen-Coder <[email protected]>
Patrol-Run: qwen-pr-closeout/jmw4h0sl6g9
* test(ci): red on later republishes of the isolated HOME keys
R3-1: the GITHUB_ENV equality guard read step 0 only, so a later step that
republished HOME reverted the run-unique home by last-write-wins while every
assertion stayed green — the isolation would silently stop applying to the
steps that run PR code. Scan the remaining steps for isolated-key
$GITHUB_ENV writers and for step-level HOME/USERPROFILE/COREPACK_HOME/
XDG_CACHE_HOME overrides, leaving the npm cache step's own key a legitimate
later write.
Mutation-verified on this head: appending printf 'HOME=%s\n' ... to
integration_no_ak's 'Configure per-run npm cache (self-hosted)' step and
adding a step-level `env: HOME` each turn the suite red (103 pass -> 102
pass / 1 fail); reverting restores 103/103.
Co-authored-by: Qwen-Coder <[email protected]>
Patrol-Run: qwen-pr-closeout/jmw4ng9wvgi
---------
Co-authored-by: Qwen-Coder <[email protected]>
|
||
|
|
738c4bbf7e |
fix(serve): bound command snapshot replay memory (#16413)
* fix(serve): bound command snapshot replay memory Suppress unchanged command snapshots and retain only the latest full skill details so periodic refreshes cannot grow daemon heap indefinitely. Bound replay rings by serialized bytes while preserving ACP live delivery and reconnect IDs, and expose retention diagnostics. * fix(serve): avoid redundant replay seed serialization Size only retained complete command snapshots when seeding replay history, and forward the replay byte limit through the development daemon launcher. Pin snapshot accounting and lifetime eviction counters with independent regression assertions, and document the count/byte retention bounds and conditional command notifications. Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
2666e3552d |
fix(core): make persisted session pagination safe for equal mtimes (#16024)
* fix(core): make persisted session pagination safe for equal mtimes
listSessions() ordered files by mtime alone and resumed the next page with a
strict `mtime < cursor`. An mtime is not unique — bulk copies, backup restores
and coarse-timestamp filesystems all produce ties — so a group of files sharing
an mtime that straddled a page boundary was dropped while hasMore still reported
progress, then the next page came back empty: 25 files at one mtime with size 5
showed 5 items in total.
Sort on (mtime desc, name asc) so the order is total, and let the cursor carry
that position: nextCursor is now `"<mtime>|<name>"`. A bare number is still
accepted with its existing strict `<` meaning, so callers holding a legacy
cursor keep working, and the daemon's opaque string cursor now passes the
composite form through instead of rejecting it as invalid.
Co-authored-by: Qwen-Coder <[email protected]>
Patrol-Run: qwen-issue-patrol/jmvwpo7jxrk
* fix(cli): carry the composite session cursor type through callers
listSessions() now hands back a "<mtime>|<name>" cursor so a page boundary
inside a group of equal mtimes does not drop sessions. The widened
`number | string` contract left the CLI callers that store or compare that
cursor typed as `number`, which is a type error in `tsc --build` even though
nothing changes at runtime.
Widen the three consumers to `number | string`: the daemon's persisted scan
cursor, the live coordinator's paging plus its loop guard, and the session
picker state used by both the ink and opentui pickers. No behaviour change.
Co-authored-by: Qwen-Coder <[email protected]>
Patrol-Run: qwen-issue-patrol/jmvwrtdc1rm
* fix(cli): route composite session cursors to the persisted listing
The persisted listing mints `"<mtime>|<name>"` cursors when a page ends
inside a group of files sharing an mtime, but the route still chose between
the persisted and the live listing path with a numeric-only predicate. A
composite cursor therefore fell through to the live path, whose parser only
accepts numbers, and the second page answered 400.
Export one predicate from session-list.ts carrying the same shape test the
cursor parser already applies, and use it for that routing decision.
Co-authored-by: Qwen-Coder <[email protected]>
Patrol-Run: qwen-issue-patrol/jmvwtyj3bro
* fix(session-list): keep composite cursors usable by ACP and VS Code clients
listSessions mints "<mtime>|<name>" cursors whenever a page ends inside a
group of files sharing an mtime, but two consumers still parsed every cursor
as a number: ACP session/list rejected page 2 with "not a valid numeric
cursor", and the VS Code companion turned the composite cursor into NaN so
hasMore read false and only page 1 was ever listed. A malformed "|name"
cursor also slipped through the persisted-cursor classifier and answered 200
with an empty page instead of invalid_cursor.
- acpAgent: accept and forward "<mtime>|<name>" cursors to listSessions
- session-list: require a non-empty mtime prefix before classifying a
cursor as persisted
- vscode companion: pass the daemon cursor back verbatim, widen the cursor
type and treat only a non-empty cursor as "append to the current page"
Tests: ACP composite passthrough + empty-prefix rejection, VS Code
getSessionListPaged composite nextCursor round trip.
Co-authored-by: Qwen-Coder <[email protected]>
Patrol-Run: qwen-pr-closeout/jmvxke6bm6i
* fix(vscode): keep composite session cursors type-safe in the companion
|
||
|
|
45f71b3714 |
fix(ci): apply the apt-mirror probe to the release docker lane too (#16278)
* fix(ci): apply the apt-mirror probe to the release docker lane too The release docker integration lane builds the same sandbox image as the E2E leg but never selected an apt mirror, and it prunes the builder cache on every run so its apt layers are always cold. On mainland pool hosts that rebuilt against the throttled deb.debian.org path (11-45 kB/s) — the same defect #16214 fixed for E2E, left unfixed here because it was out of scope (#16271). Extract the probe (apt_mirror_probe_rate / select_apt_mirror) and a new apply_apt_mirror helper into a shared .github/scripts/apt-mirror-probe.sh, sourced by both run-e2e-tests.sh and run-release-docker-integration.sh. Each calls apply_apt_mirror before build:sandbox, so a mainland host builds against the VPC intranet mirror (6-9 MB/s, verified for E2E) while a healthy default is left untouched. The Dockerfile APT_MIRROR ARG already exists from #16218. Contract tests read the shared probe and pin the candidate loop and the source statement (not substrings the comments also satisfy); both callers must apply the probe before the build. Mutation-verified: removing the release call, a candidate, or a source line each reddens the suite. * fix(ci): carry the apt-mirror probe into the shard-retry test rig run-e2e-tests.sh now sources its sibling apt-mirror-probe.sh at startup. The shard-retry meta-test copies only run-e2e-tests.sh into a temp dir, so the source resolved to a missing file and 'set -e' aborted before any shard ran — all eight cases saw zero npm calls. Copy the probe file alongside the script in the rig so the source resolves; sourcing only defines functions (no network at source time) and the sandbox:none path never calls apply_apt_mirror, so the rig stays hermetic. Witness: CI at |
||
|
|
255d5cd2ae |
feat(web-shell): polish composer action menu presentation (#16181)
* feat(web-shell): polish composer action menu presentation * style(web-shell): use regular composer menu labels * fix(web-shell): address composer menu review feedback --------- Co-authored-by: 钉萁 <[email protected]> |
||
|
|
3663209c3d |
chore(ci): shorten stale PR window to 30 + 14 days (#16435)
* chore(ci): shorten stale PR window to 30 + 14 days The open PR backlog keeps growing, and the 60 + 30 day window only reaches PRs inactive for two months, leaving the 30-60 day band untouched. Lower the stale threshold to 30 days and the close window to 14 days, and raise operations-per-run to 300 so the first sweep can label the backlog in one or two runs. The stale/close messages and the fleet-shepherd design docs are updated to match. Co-authored-by: Qwen-Coder <[email protected]> * docs: keep the stale-window reference in the design current Avoid pinning the note to a merge-date guess: name the policy change instead, and reflow the paragraph to the file width. Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
6fb741642f |
perf(managed-agent): take tool execution control off the tenant guards (#16415)
Every tool call admits an execution and authorizes its dispatch. Both went through lockBindingControl, which for a session-class binding (the default isolation class) took tenant placement, the publication guard, every slot and binding row of the Session and then its root, only to prove the Session is not CSI-pinned. lockExecutionControl now decides that under the Session root alone: the pin lives on the root, and profile slots and bindings require a committed pin. lockManagedSession and requireProvisionPin lock the root before slot and binding rows, so every placement owner shares the root-then-binding order that guard-free dispatch uses. Without an existing root, a locking read takes only a gap lock and orders nothing; dispatch then keeps the guarded path (a MySQL stress test reproduced the deadlock between the binding's unique-index and primary-key lookups otherwise). Admission still takes placement for the harness drain fence. |
||
|
|
1bac51b7d9 |
feat(sdk): support native Skill archives and receipt lookup (3/4) (#16423)
* feat(skills): add file-backed archive installation kernel * feat(skills): expose native archive routes and receipts * feat(sdk): support native Skill archives and receipt lookup |
||
|
|
16794c25ad |
chore(release): sdk-typescript v0.1.28 (#16412)
* chore(release): v0.26.8 * chore(release): sdk-typescript v0.1.28 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Shaojin Wen <[email protected]> |
||
|
|
da7af136e5 |
feat(skills): expose native archive routes and receipts (2/4) (#16422)
* feat(skills): add file-backed archive installation kernel * feat(skills): expose native archive routes and receipts |
||
|
|
17ad9cdb04 | feat(skills): add file-backed archive installation kernel (#16421) |