mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-10-20 05:11:33 +00:00
423 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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 <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmvfl3pgdj1 --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
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 <266654365+qqqys@users.noreply.github.com> |
||
|
|
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: 易良 <1204183885@qq.com> |
||
|
|
c4f0acdef8
|
feat(extensions): add bounded generated HTML and JavaScript views (#14338)
Co-authored-by: qqqys <266654365+qqqys@users.noreply.github.com> |
||
|
|
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 <266654365+qqqys@users.noreply.github.com> |
||
|
|
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: 易良 <1204183885@qq.com> |
||
|
|
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: 钉萁 <dingqi.jww@alibaba-inc.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> |
||
|
|
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 <266654365+qqqys@users.noreply.github.com> |
||
|
|
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 <djy1989418@126.com> |
||
|
|
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 <qwen-coder@alibabacloud.com> * 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 <qwen-coder@alibabacloud.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * 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 <qwen-coder@alibabacloud.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * 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 <qwen-coder@alibabacloud.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * 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 <qwen-coder@alibabacloud.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * 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 <qwen-coder@alibabacloud.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * 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 <qwen-coder@alibabacloud.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * 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 <qwen-coder@alibabacloud.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * 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 <qwen-coder@alibabacloud.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
612a552959
|
feat(channels): add IMAP and SMTP email channel (#12939)
* feat(channels): add IMAP and SMTP email channel * test(channels): include email in managed channel catalog expectations --------- Co-authored-by: destire-mio <248462155+destire-mio@users.noreply.github.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
354ae9292d
|
feat(core): resolve model limits and modalities from a models.dev catalog (#11959)
* feat(core): resolve model limits and modalities from a models.dev catalog
Bundle a trimmed models.dev snapshot (12 first-party providers, 237
models) and refresh it in the background once a day into
~/.qwen/model-registry.json with ETag revalidation, so a model that
appears on models.dev gets its context window, output limit, and input
modalities without a CLI release. tokenLimit()/knownTokenLimit()/
hasExplicitOutputLimit() consult the catalog before the regex tables;
defaultModalities() merges both so the catalog can only add modalities.
QWEN_CODE_MODELS_DEV=off restores the regex-only behavior (default in the
unit test setups), QWEN_CODE_MODELS_DEV_REFRESH=off disables the network
refresh, QWEN_CODE_MODELS_DEV_URL points at a mirror. `npm run
generate:model-catalog` regenerates the committed snapshot.
Implements PR2 and PR3 of the design in #9851. Refs #8558.
* feat(core): add model.customCatalog for offline model metadata
Offline and proxy-restricted users cannot reach models.dev, so let them
point `model.customCatalog` at a URL or local file whose entries are
merged over the bundled catalog per model and field. Both the trimmed
`{ models: { id: entry } }` shape and models.dev-style payloads are
accepted. A file is re-read synchronously at every start so the first
model resolution already sees it; a URL is cached like models.dev and
is still fetched when QWEN_CODE_MODELS_DEV_REFRESH=off. The cache
records its source, so a changed or removed setting drops the overlay.
Also sort snapshot keys with a plain comparator instead of localeCompare
so regeneration is deterministic across machines.
* docs: add a verification brief for the models.dev catalog
CI covers the mechanism, but every unit test stubs fetch and the test
setups run with the catalog off, so neither the data values nor the real
runtime behavior are verified anywhere. This brief is the handoff for a
machine that can run the CLI against live endpoints: an on/off A/B with
measured reference numbers, the refresh and offline paths, and the two
values that may still be wrong (Anthropic 1M context, qwen3.8-max PDF).
* fix(core): only catalog models the endpoint question has one answer for
Two projection bugs, both found by reviewing the magnitude of the changes
the catalog was making rather than their direction.
The provider whitelist filtered by vendor but never by model type, so the
catalog also carried embedding, text-to-speech, image, video, OCR and
translation models whose limits mean something else entirely:
gemini-embedding-001 reported an output limit of 1 and veo-3.1-generate a
context of 480, and those numbers outranked the family fallbacks that keep
such ids harmless today. Require tool calling and text output, which drops
34 ids and no real chat model.
Conflict resolution picked the vendor's numbers when several providers
served one id, but a context window is a property of the endpoint, not the
weights. DashScope caps GLM-5 output at 16,384 where Z.ai allows 131,072;
both are correct for their own endpoint. Worse, kimi-k2.6 has no matching
output pattern today, so it is treated as unknown and the user's max_tokens
is respected, and the catalog would have clamped it to 262,144. Drop such
ids instead of guessing: 220 of 237 ids have no conflict, and the 11 that
remain keep exactly the answer they get today.
Snapshot goes from 237 models to 192, 29,824 to 24,685 bytes.
* fix(core): validate catalog defaults and reject alias conflicts
* fix(core): narrow catalog defaults to verified behavior
* fix(core): preserve curated output limits over catalog defaults
* fix(core): harden models.dev catalog refresh and keying
- Reject a 200 response that projects to zero models so a gateway error
body or an upstream field rename cannot shadow the bundled snapshot,
and treat an already-empty cache as absent so a 304 cannot re-stamp it.
- Omit catalog candidates whose key is not a normalize() fixed point:
deepseek-v3 was unreachable by its own name while its dated alias
inherited a 163,840 output limit. Snapshot drops that entry (194).
- Exclude QWEN_CODE_MODELS_DEV_URL from project .env files: the refresh
writes the global cache every project reads.
- Reject false-valued modalities when parsing catalog caches.
- Document the fixed-point keying rule and the accurate REFRESH=off
semantics in the settings table.
* fix(core): preserve explicit budgets for catalog-only models
* fix(core): harden catalog cache reads and correct qwen3-coder-plus window
- loadModelCatalog drops cache keys no normalized spelling can reach and
treats a cache that is empty after validation as absent, so a stale or
poisoned cache can no longer displace the bundled snapshot.
- Correct qwen3-coder-plus to its vendor-declared 1,000,000-token window
(models.dev's alibaba buckets approximate it as 1,048,576), applied in
the loader so a refreshed cache cannot reintroduce the approximation.
- Pin the cross-origin refresh guard with a non-empty cache fixture, the
normalized-id catalog lookup for modalities, the env-budget clamp
precondition for glm-4.7, and control keys plus reload/snapshot arms
for the project-scoped catalog URL exclusion.
- Align the QWEN_CODE_MODELS_DEV_REFRESH docs and JSDoc with the
newer-than-bundled selection rule.
* fix(core): project catalog modalities across providers and test against the real catalog
Review round on PR #11959:
- trimModelsDevCatalog: token limits stay gated on the first-party
allowlist with disagreement-drop; input modalities describe the
weights, so they now union across every provider that serves the
model. First-party vendors outside the allowlist (issue #8558's
thinkingmachines/inkling) project image/pdf support again, while
their endpoint limits stay untrusted.
- modalityDefaults.test.ts: drop the file-scoped catalog mock that let
three assertions pin the opposite of shipped behavior; run against
the real bundled snapshot in an isolated QWEN_HOME and correct the
qwen3.8-max / glm-5v-turbo / glm-5.3-flash expectations. The
mock-based merge tests move to modalityDefaults.catalog.test.ts.
- vscode-ide-companion: add the missing QWEN_CODE_MODELS_DEV=off test
default via test-setup.ts so a host's ~/.qwen/model-registry.json
cache cannot flip its contextLimit assertions.
* revert(vscode-ide-companion): drop out-of-footprint catalog test wiring
Deterministic verification rejected the setupFiles addition to
packages/vscode-ide-companion/vitest.config.ts: per-package vitest
configs are test-config verification machinery, and this PR's
footprint does not include that package. Revert the wiring and remove
the now-orphaned test-setup.ts.
The underlying hazard (R4-2: acpModelInfo contextLimit assertions
resolve against the host's ~/.qwen/model-registry.json cache) is real
and reproduced on this head — a poisoned cache flips exactly the two
witness tests red — but every fix lives outside this PR's footprint,
so it is deferred to the follow-up queue with an open question for
maintainers.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix: close model catalog environment gaps
* fix(core): validate refreshed model metadata
* fix(core): reject incomplete model catalogs
* fix(core): keep catalog defaults agent-safe
* fix(core): preserve DeepSeek vision boundary
* fix(core): harden the catalog refresh fetch and pin the catalog fixture clock
Six review findings on the refresh/generator path:
- Bound the download: the refresh now reads the 200 body with a
200KB ceiling (the generator's budget) instead of buffering an
unbounded payload, rejects a present-but-non-JSON Content-Type one
step earlier than JSON.parse, and cancels the body on the HTTP-error
path so the socket is released.
- Clock skew: a cache stamped by a faster clock (negative or unreadable
age) now refetches instead of serving indefinitely; the re-stamp uses
the local clock so the skew self-heals.
- The refresh failure log goes through the canonical getErrorMessage,
so error.cause survives into the debug channel.
- The 'serves it immediately' test pins its clock ahead of the bundled
snapshot's committed fetchedAt, decoupling it from the runner's wall
clock (the snapshot is regenerated by whichever host runs the
generator).
- The generator refuses a non-OK response and an empty projection
instead of overwriting the committed snapshot with either.
Each new test is red under its corresponding revert (byte cap, content
-type check, skew guard); the clock-pin witness mutates the snapshot's
fetchedAt to 9999 and stays green.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(core): drop mirror providers from catalog limits and keep parse fidelity
Seven more review findings on the catalog path:
- MODELS_DEV_PROVIDERS no longer includes modelscope. Measured against
the live payload: its only contributions were four dated -2507 qwen3
snapshots recorded under the bare ids plus vetoing z.ai's first-party
glm-4.6 numbers into a conflict drop. volcengine stays — it is the
first-party endpoint for the doubao/seed family (dropping it costs 16
keys). Snapshot regenerated: 203 entries, glm-4.6 restored to the
first-party figures.
- parseModelCatalog no longer lets one bad modalities member take a
whole entry down: unknown or mistyped modality keys are filtered and
the entry keeps its limits; context/output stay strict. The parser
also skips an own-property __proto__ key instead of invoking the
prototype setter (the refresh path can legitimately write one).
- A declared text-only modalities list now survives projection as {}
on entries that ship limits, instead of being indistinguishable from
"upstream said nothing" — inert under today's union, recorded so a
future narrowing can tell the two apart. A bare {} never creates an
entry on its own, so conflict-dropped and limit-less models still
drop.
- The committed snapshot now has a parse-and-budget gate: every shipped
entry must survive parseModelCatalog and stay within the 200KB budget
(corrupting one entry turns the new test red).
- The gpt-4o resolver expectation's comment now says it pins the
catalog-off regex answer; the catalog-on production value already has
its own twin test.
- The verification README's evidence pointers no longer reference a
gitignored .qwen path; they name the committed suites that pin the
same numbers.
Modality list is now single-sourced as CATALOG_MODALITIES exported from
model-catalog.ts. Each behavior change is red under its revert:
restoring modelscope re-drops glm-4.6, restoring whole-entry modality
rejection or the __proto__ assignment reds the parse test, restoring
the empty-modalities drop reds the projection expectations.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(core): narrow catalog modality keys with a type predicate
Object.entries widens the key to string, and includes() on the widened
readonly string[] does not narrow it back, so the indexed write into
InputModalities was an implicit any under noImplicitAny. That failed the
packages/core build with TS7053 and cascaded into every required check.
Extract the membership test into an isCatalogModality predicate so the
write is type-safe. Type-level only, no behavior change: the existing
"drops malformed entries while parsing" coverage still pins that an
unrecognised modality key degrades that one field instead of discarding
the entry.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Patrol-Run: qwen-pr-closeout/jmunuawz4h7
* fix(core): keep catalog refresh usable and process-consistent
* fix(core): invalidate incompatible model catalog projections
* fix(core): stamp canonical models.dev URL as bundled catalog provenance
The generator passed its input locator straight through as the provenance
stamp, so generating from a local payload copy recorded a machine-specific
path (e.g. /tmp/11959-models-dev.json) in the committed snapshot. Stamp
MODELS_DEV_URL for local-path inputs (the payload is models.dev data
regardless of where the machine stored it), keep URL inputs stamping
themselves, regenerate the snapshot, and pin the artifact's source field
with a test.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Patrol-Run: qwen-pr-closeout/jmuofqisz0a
* fix(core): share the provider-coverage guard and key DeepSeek narrowing on the family root
Round-9 review findings on
|
||
|
|
e767e223c5
|
fix(hooks): deliver pre-tool and ACP failure context to the model (#13006)
* fix(hooks): deliver pre-tool and ACP failure context to the model PreToolUse additionalContext was dropped on the deny/ask/stop branches of the hook helper and never attached to the tool result in core or ACP, and ACP only logged PostToolUseFailure context on both the returned-error and thrown-error paths. Append the sanitized context to the owning call's functionResponse: - core keeps it per call across an ask bounce and assembles it after PostToolBatch, before the final batch budget; cancelled calls drop it - ACP appends Pre and failure context to model-facing parts only, keeping UI updates and error projections unchanged - the added text is bounded per call by truncateToolOutputThreshold * fix(hooks): keep hook context out of nested and App results - exec: a nested call's result is a value for the script, so its hook context is handed to the parent exec and delivered with that result (core via the nested scheduler, ACP via the nested run result) - ACP MCP App calls have no model consumer and never append context - core rechecks each call's abort signal at final assembly, so a turn cancelled during PostToolBatch drops the stored context - share the functionResponse text append with PostToolBatch context - run the hook-context integration test in the no-AK PR lane * fix(hooks): route nested failure context and pin review cases - core: a code-mode nested call's PostToolUseFailure context goes to the parent exec result instead of the error handed to the script, matching ACP and nested PreToolUse context - ACP: nested hook context keeps dispatch order under concurrent nested calls, so truncation does not depend on completion order - docs: scope delivery to Code Mode nested calls, the turn-cancel exception, the per-surface limits, and transcript/detail visibility - tests: sandbox-safe decision file, self-delimiting markers and a real value check in the integration test, ACP agent-exit handling, plus ACP cancel/truncation/nested-failure and core contentLength and nested-failure regressions * fix(hooks): drop hook context when the turn is cancelled before recording - core: after the final output budget (which can await persistence), redo the budget without the context of any call whose turn was aborted - ACP: queued records keep their parts without hook context; if the turn is aborted before finalizeAndRecord records them (e.g. while notifying the client or persisting), finalize and record those parts instead - tests: cancellation during the final budget (core) and while notifying a completed or denied result (ACP); the ACP integration agent gets its own QWEN_HOME and is awaited before teardown --------- Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> |
||
|
|
34dbaf6741
|
chore(release): v0.24.7 (#13025)
* chore(release): v0.24.7 * docs(changelog): sync for v0.24.7 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
cc45337481
|
fix(cli): report completion for saved workflow slash commands (#12415)
* fix(cli): report completion for saved workflow slash commands * test(cli): run workflow completion regression in PR CI * fix(cli): preserve foreground workflow completion delivery * fix(cli): refresh workflow progress after cancellation * fix(cli): address workflow completion review feedback * fix(workflow): preserve bounded completion details Pass storage snapshot destinations into completion notices and keep reported failures outside the result preview. Share serialization and Unicode-safe XML budgeting with tool cards and sub-session notifications. Clarify Ink and OpenTUI guidance and cover truncation, terminal controls, and throwing failure getters. Validation: 594 focused unit tests, 4 interactive workflow cases, build and bundle, workspace and integration typechecks, and changed-file lint and formatting checks. * fix(workflow): preserve error details in completion reports * fix(workflow): retain collection failures and concise error reasons * fix(workflow): qualify truncated result snapshot notices --------- Co-authored-by: destire-mio <248462155+destire-mio@users.noreply.github.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> |
||
|
|
c7c6def8bc
|
test(managed-agent): add Hosted no-tool process gates (#12733)
* test(managed-agent): add Hosted no-tool process gates Refs #12728 * fix(ci): satisfy YAML quoting rules in hosted process gates |
||
|
|
16496a71ec
|
chore(release): v0.24.6 (#12722)
* chore(release): v0.24.6 * docs(changelog): sync for v0.24.6 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
34246c6606
|
feat(managed-agent): Spring control plane and dual-path WebShell (#12692)
* feat(managed-agent): add Spring control plane and dual-path WebShell Bring the standalone managed-agent server, its embedded broker listener, and the WebShell Java panel onto the current broker contract. Legacy daemon sessions stay available beside the new path. Co-authored-by: jinye <doudouOUC@users.noreply.github.com> * fix(managed-agent): address review defects and wire server CI * fix(managed-agent): preserve case-sensitive store identities * fix(managed-agent): bind locally and return 404 for missing routes * codex: address PR review feedback (#12692) --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: jinye <doudouOUC@users.noreply.github.com> Co-authored-by: jinye.djy <jinye.djy@U-Y37CF7G3-1943.local> |
||
|
|
73aa65a4b4
|
chore(desktop): rename packages/desktop-shell to packages/desktop (#12653)
* chore(desktop): rename packages/desktop-shell to packages/desktop The Electron-era packages/desktop was removed in #9085 and the OpenWork downstream has forked, so the short name is free and the shell suffix is the only thing left of the transition. Rename the package directory and every load-bearing reference: workspace negations (npm + pnpm), the ci.yml crate filter, desktop-release.yml, the isolation guard, lint/ignore configs, scripts tests, CLI workspace-fixture tests, and living docs. User-facing identity is untouched: the crate stays qwen-code-desktop, productName stays "Qwen Code Desktop", the bundle identifier, updater feed, release tag scheme, and the legacy electron-bridge asset names are all unchanged. check-desktop-isolation now guards both path names so the old one cannot re-enter a workspace set. Dated design docs under docs/design/ keep their historical paths deliberately. Refs #8596 * docs(design): follow the rename in the undated notification design notes The web-shell-browser-notification-details pair is a living doc without a date prefix, so it falls under the PR's update rule rather than the historical-record exception. * docs(desktop): stop citing paths the rename invalidated Three prose sites and one CI comment still described the pre-rename world, or contradicted themselves once `packages/desktop` named both the removed Electron app and the living Tauri shell. - ci.yml `desktop_shell`: the comment this branch added credited the Cargo.toml guard with keeping "branches from either side of the rename" green. It does not. A pre-rename head's files sit under `packages/desktop-shell`, which the changed-files filter no longer matches, so the job skips before the guard ever runs. Say that, and say what the guard does cover (a head the filter matched because ci.yml itself changed, with no crate at the new path). - docs/design/web-shell-user-message-links.md: "desktop-shell routing" / "desktop-shell clicks" -> "desktop-host", the wording this branch already chose in LinkifiedText.tsx for the same rule. - docs/design/telemetry-runtime-client-attribution-design.md: repoint the `runtime.rs` citation. It backs the live `QWEN_CODE_DESKTOP=1` claim, and the other document of record for that invariant -- the comment in acp-channel-fallback.ts -- was already repointed by this branch, so the two disagreed. Only the path token changes; the doc's dated findings are untouched. - brand-create.mjs / SKILL.md / src-tauri/src/main.rs: name the historical referent as historical (the Electron `packages/desktop` removed in PR 9085) instead of letting it read as a self-reference. In main.rs the citation `packages/desktop/packages/shared/src/config/storage.ts` now looked like a subpath of the file's own package. Rewritten, not deleted: the `QWEN_DEFAULT_WORKSPACE_DIR` clause next to it is the only in-code documentation of that override and still resolves. Deliberately not swept: `scripts/check-desktop-isolation.js`'s `packages/desktop-shell` tripwire, ci.yml's #8132 history comment, `docs/design/9152-architecture-invariant-classification.md` (names both spellings and is accurate), and the date-prefixed `docs/design/2026-07-31-desktop-web-shell-release.md`. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmug1iw422v * test(scripts): pin the desktop crate path and the isolation guard's coverage Both invariants fail green today, and this rename is the second time the crate directory has moved. `scripts/check-desktop-isolation.js` gained `'packages/desktop'` in `nativePrefixes` -- the only production-logic line in this branch -- and nothing read it. Deleting that line leaves the guard's output and exit code byte-identical, because `isNativeLocation('packages/desktop')` then matches no remaining prefix; a later PR that drops `!packages/desktop` from the root workspace list would re-admit the package with CI green. The `desktop_shell` job names the crate directory in five places (the changed-files filter, the Cargo.toml guard and its `::notice::` text, the rust-cache `workspaces:`, and two `working-directory:` values). Nothing asserted they agree with each other or with a directory that exists, so the next drift reports a skipped job as a passed one. The new suite parses both instead of re-running them, and is superset-shaped on purpose: `nativePrefixes` carries a fourth entry (the `packages/desktop-shell` tripwire) that nothing negates, and an exact-match assertion would invite deleting it. The npm/pnpm mirror of the negation list is already pinned by package-scripts.test.js, so this reads package.json only. Verified by mutation, each applied alone and then restored: reverting the filter alternative or either `working-directory` to `packages/desktop-shell`, dropping `'packages/desktop'` from `nativePrefixes`, and dropping `!packages/desktop` from package.json all turn this suite red. Today no other test does. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmug1iw422v * test(scripts): pin what the desktop-isolation tests actually claim Four review findings on scripts/tests/desktop-isolation.test.js, each verified by mutating the thing it claims to pin, before and after. - The comment above the local `isNativeLocation` copy claimed a change to the script's rule "has to be made here too". Nothing reads the rule back from the producer -- `nativePrefixesFromSource` parses the array literal only -- and narrowing the script's rule to prefix equality leaves the suite green. Describe the copy instead of claiming coupling that does not exist. - `still carries the Cargo.toml existence guard` matched only the guard's condition text. Flip the body's `changed=false` to `changed=true`, or move it after `fi`, and the suite stayed green at 5/5 while the job runs every gated step against a crate that is not there. Assert the assignment sits inside the guard's own `if ... fi` body. - Both on-disk checks keyed on the bare directory, so git-ignored residue under `packages/desktop-shell` (`node_modules`, which survives a branch switch with an empty `git status`) reddened two tests on a tree with no defect and blamed the root workspace set. Key on `package.json`, which is what `packages/*` requires to make a directory a workspace member; a real re-entry still reddens both. - The `startsWith(filterAlternative)` assertion compared a path built from `crateDir` -- `filterAlternative` with one trailing slash stripped -- back against `filterAlternative`, so it could not fail for any input. Dropping the trailing slash from the changed-files filter in ci.yml left it green. Replace it with the property that makes the alternative a path prefix rather than a bare string prefix. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmugedurp3j --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
010941d202
|
fix(standalone): pin @lydell/node-pty-linux-arm64 and fail release on missing prebuilds (#12649)
* fix(standalone): pin @lydell/node-pty-linux-arm64 and make missing prebuilds fatal at release The wrapper publishes a linux-arm64 prebuild at the same 1.2.0-beta.10 pin, but the root and core manifests never declared it, so the linux-arm64 standalone archive and the linux-arm64 Desktop runtime both degraded to "PTY not available" while every other target shipped a working web terminal. With the pin in place every shipped target resolves a prebuild package, so the release archive build can stop degrading silently: release.yml now exports QWEN_STANDALONE_REQUIRE_NODE_PTY_PREBUILD=1 next to the existing audio-capture gate, turning a missing prebuild into a hard failure instead of another #11872. Fixes #11872 * fix(standalone): update pnpm lockfile for the linux-arm64 node-pty pin The two package.json manifests gained @lydell/node-pty-linux-arm64 but pnpm-lock.yaml was not regenerated, so every CI job failed at the frozen-lockfile install with ERR_PNPM_OUTDATED_LOCKFILE. * docs(standalone): align the linux-arm64 PTY guide and tripwire with the pin Pinning @lydell/node-pty-linux-arm64 makes linux-arm64 a supported PTY target, but INSTALLATION_GUIDE.md still told users that archive ships without PTY and reports "PTY not available". CI could not catch the drift because install-script.test.js pinned that exact sentence as its tripwire, so the guide and the assertion have to move together. List all five shipped targets in the guide, retarget the tripwire at the new sentence, and refresh the matching stale comment in desktop-shell's test-release.js degrade fixture - that arm now only fires for a target the map does not know. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(standalone): complete the node-pty linux-arm64 pin in esbuild externals `create-standalone-package.js` documents that "esbuild.config.js keeps every node-pty specifier external" so the bundled CLI resolves the platform prebuild from `lib/node_modules` at runtime. The external list carried five of the six pinned platform packages and omitted `@lydell/node-pty-linux-arm64` — the exact platform this PR pins. Nothing imports that specifier statically today, so the bundle is unaffected; the gap is that the invariant the archive's PTY support rests on was one entry short of complete. Probe (esbuild, `--platform=node --format=esm`, entry importing both specifiers): - without the entry: `Could not resolve "@lydell/node-pty-linux-arm64"` - with the entry: builds clean and emits the import left external, matching the other five platforms Also corrects two comments this PR rewrote in the previous round. Both claimed the desktop degrade arm "fires only for a target the map does not know (a future platform)". That trigger is unreachable: `desktopTarget()` throws `Unsupported desktop target` for anything outside its five-entry allowlist and `NODE_PTY_PREBUILD_PACKAGE` maps exactly those five, so `prebuildPackage` is always a real name. Verified by running the script: $ QWEN_DESKTOP_SKIP_BUILD=1 QWEN_DESKTOP_TARGET=freebsd-x64 \ node packages/desktop-shell/scripts/prepare-runtime.js Error: Unsupported desktop target: freebsd-x64 at desktopTarget (prepare-runtime.js:351:11) The reachable trigger is the one the warn string already names and the one `test-release.js` reproduces four lines below its own comment: a known target whose prebuild package is unpinned in the source root manifest. Comment-only apart from the single external entry. prettier --check and eslint --max-warnings 0 clean on all three files; node --check passes. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(standalone): pin the node-pty release gate and its target map Closes out three review findings on the node-pty pin. Test- and comment-only apart from one new export; no production behavior changes. R1-1 prepare-runtime.js: the nodePtyPackageSpecs() docstring still claimed its null return "is how an unsupported target degrades". desktopTarget() throws for anything outside its five-entry allowlist, and test-release.js:testRuntimeNodePtyTargetMapping() asserts NODE_PTY_PREBUILD_PACKAGE's keys equal exactly that allowlist, so an unknown target can never reach it. A null here is a dropped pin. Verified by re-running that tripwire's extraction against the edited file: both literals still match and keys == allowlist == the same five targets. R1-2 create-standalone-package.js: export TARGET_PREBUILD_DIR and assert every release target maps to a package the manifests actually pin. The guide sentence this PR adds states that invariant while release.yml:707 makes violating it abort the whole archive step, yet the map had zero test references. The expectation is derived from readNodePtyPackageSpecs() so the version list stays single-sourced, and is one-directional because @lydell/node-pty-win32-arm64 is pinned while no target maps to it. R1-3 install-script.test.js: the release.yml assertion matched only the variable name, which also appears in the packager's usage text, so nothing connected producer to consumer and no test executed the fail() branch at create-standalone-package.js:578. Tightened to the full wiring line and added the behavioral twin of the audio-capture pair: gate on with the addon removed must throw, gate off must still build a PTY-less archive. packageFakeStandalone() gained an env option for this; spreading process.env leaves its 15 existing callers unchanged. Mutation-checked, each mutant applied alone then restored and md5 verified: win-x64 mapped to an unpinned name, gate reader renamed to '2', gate polarity flipped to !==, and release.yml no longer evaluating to '1' are each caught by a new or tightened assertion. The polarity flip was previously undetectable on the PR lane, where the linux-x64 prebuild is present so the gate is never reached. Focused: install-script.test.js 130 passed / 11 skipped (141). prettier --check and eslint --max-warnings 0 clean on all three files. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmufv3et42h * docs(standalone): state the real node-pty degrade conditions in comments prepare-runtime.js said the degrade arm fires only "where the repo pins nothing", but nodePtyPackageSpecs returns null at the first unpinned name of the pair, so it also fires when the wrapper pin is the one that went missing while the warning names the prebuild package. Say "either name in the pair" and note which package the warning names. create-standalone-package.js justified the non-fatal default with "a developer archive stays usable on an unmapped future target", which cannot happen: main() calls copyNativeAddon first and it reads the same TARGET_PREBUILD_DIR in an unconditional path.join(), so an unmapped target dies with a TypeError in the audio step before copyNodePtyAddon runs. Replace the rationale with the case that does reach the warn arm (a target whose prebuild the host install does not have). Comment-only; no behaviour change. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmug1iw422v * test(standalone): make the node-pty gate assertions discriminate Pin the `Required ` prefix on the fatal-gate regex. copyNodePtyAddon builds one message and emits it on both paths, so the prefix-less regex was also satisfied by the degrade warning folded into the child's stderr — the suite would have reported the gate as covered after the prefix was dropped from fail(). The sibling clipboard gate assertion already spells the prefix. Assert QWEN_STANDALONE_REQUIRE_NODE_PTY_PREBUILD structurally on the `Build Standalone Archives` step env instead of as a whole-file substring, so commenting the line out or moving it into a neighbouring step's env goes red. build-standalone-release.js spawns the packager with no env override, so that step's env is the only route to the gate. The comment defending the substring pin named a collision with create-standalone-package.js's usage text, which cannot occur: the searched string is release.yml alone. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmug1iw422v * test(standalone): cover the node-pty target map and the win-x64 dir name Two coverage gaps left by the previous round of gate tests: - The map test looped over TARGET_PREBUILD_DIR itself, so a release target with no map entry was never visited, deleting a whole entry merely removed an iteration, and an emptied map passed vacuously. Drive the loop from TARGETS and assert the lookup before the pin. Still one-directional: @lydell/node-pty-win32-arm64 is pinned while no target maps to it. - Both gate tests reached the packager through packageFakeStandalone, which hardcoded --target linux-x64, the one dialect where the prebuild dir name equals the target name. Add a win-x64 arm so the 'win-x64' -> 'win32-x64' translation in copyNodePtyAddon is covered on every lane rather than only on test_windows. Parameterise the staged-modules fixture and the packaging helper to make that reachable without a Windows host. Test-only change; no production code is modified. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmug5t7mp33 --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
af5e90bfb2
|
chore(release): v0.24.5 (#12661)
* chore(release): v0.24.5 * docs(changelog): sync for v0.24.5 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
1b26d38b5c
|
chore(release): v0.24.4 (#12476)
* chore(release): v0.24.4 * docs(changelog): sync for v0.24.4 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
baf0ff41f7
|
refactor(build,release): Use pnpm workspace builds and publishing (#12400)
* refactor(release): Use pnpm for workspace publishing and versioning * fix(ci): revert desktop-release install to npm ci for Windows compatibility The pnpm migration added a bash conditional to check for pnpm-lock.yaml, but the step did not specify shell: 'bash'. Windows runners default to PowerShell, which cannot parse bash syntax, causing the build to fail with a ParserError. Since desktop-release always checks out the same commit and the root lockfile is now pnpm-lock.yaml, the conditional is unnecessary. Revert to the simple npm ci command that works on all platforms. Fixes the Windows build failure in Desktop release v0.24.2. * refactor(build): Schedule workspace builds with pnpm * fix(ci): Preserve Windows release installation and version filters --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
364032a032
|
chore(release): v0.24.3 (#12418)
* chore(release): v0.24.3 * docs(changelog): sync for v0.24.3 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
eceaede18e
|
chore(release): v0.24.2 (#12359)
Some checks are pending
Qwen Code CI / Classify PR (push) Waiting to run
Qwen Code CI / Test (ubuntu-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Lint & Static (ubuntu-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / web-shell E2E Smoke (ubuntu-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Test (macos-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Test (windows-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Integration Tests (no-AK, No Sandbox) (push) Blocked by required conditions
Qwen Code CI / Integration Tests (CLI, No Sandbox) (push) Blocked by required conditions
Qwen Code CI / Desktop Shell (ubuntu-22.04) (push) Blocked by required conditions
Qwen Code CI / Desktop Shell (windows-2022) (push) Blocked by required conditions
E2E Tests / Build for E2E (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/1 (push) Blocked by required conditions
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/1 (push) Blocked by required conditions
E2E Tests / E2E Test - macOS - shard 1/2 (push) Blocked by required conditions
E2E Tests / E2E Test - macOS - shard 2/2 (push) Blocked by required conditions
E2E Tests / E2E Interactive - OpenTUI renderer (bun) (push) Blocked by required conditions
E2E Tests / channel-plugin E2E (nightly) (push) Blocked by required conditions
E2E Tests / cron-interactive E2E (nightly) (push) Blocked by required conditions
E2E Tests / web-shell Browser Regression (push) Waiting to run
pnpm Worktree Smoke / Install (macos-latest) (push) Waiting to run
pnpm Worktree Smoke / Install (ubuntu-latest) (push) Waiting to run
pnpm Worktree Smoke / Install (windows-latest) (push) Waiting to run
SDK Java / ubuntu-latest / Java 11 (push) Waiting to run
SDK Java / ubuntu-latest / Java 17 (push) Waiting to run
SDK Java / macos-latest / Java 21 (push) Waiting to run
SDK Java / ubuntu-latest / Java 21 (push) Waiting to run
SDK Java / windows-latest / Java 21 (push) Waiting to run
SDK Java / Real daemon E2E / Java 11 (push) Waiting to run
* chore(release): v0.24.2 * docs(changelog): sync for v0.24.2 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
64dd058c9c
|
ci(pnpm): install with pnpm everywhere and retire package-lock.json (#11859)
* ci(pnpm): install dependencies with pnpm in CI and release CI tests the graph release ships only if both install it the same way, so this moves both, keeping every `npm run` script and `npm publish` as they are. - ci.yml (7), release.yml (3) and release-vscode-companion.yml (2) install with `corepack pnpm install --frozen-lockfile`; release keeps --ignore-scripts plus its explicit postinstall and generate steps. - setup-node drops the npm cache and sets package-manager-cache: false, which setup-node v5+ needs once package.json declares a pnpm packageManager. - A composite action caches the pnpm store on the three always-hosted jobs; the ECS pool keeps its store on local disk. - version.js no longer lets npm reify node_modules: --no-workspaces-update on both `npm version` calls, and a package-lock-only refresh in step 9. - The notices generator, prepare-package's sharp pin and the standalone release's native package specs read the installed tree or pnpm-lock.yaml instead of package-lock.json keys. - New size baselines for the three workflows, which were already over them. * chore(vscode): regenerate NOTICES from the pnpm-installed tree Generated in CI (pnpm Worktree Smoke on ubuntu-latest) by the ported generator. Same entry set as before except the five packages npm and pnpm resolve differently: fdir 6.5.0, picomatch 4.0.5, mdurl 2.1.0, @types/node 22.20.1 and mime-db 1.52.0 (form-data's pinned copy). No entry lacks a license text or repository. * fix(pnpm): resolve undeclared zod peers to the repo's zod, as npm does The first CI run on this branch failed the export renderer's size budget: 1,930,015 bytes against 1,930,000, where the same commit built on npm's tree comes to 1,858,186. Comparing both trees' esbuild metafiles and prebuilt bundles put the whole difference in web-shell's transcript.js (+100,903 bytes pre-minify), and the added code is zod 4 plus the @modelcontextprotocol/ext-apps schemas; the sdk daemon bundle is identical. web-shell bundles ext-apps, whose zod and MCP SDK are peers, and declares no zod itself, so pnpm filled the peer with the highest locked zod (4.4.3) while npm serves the hoisted 3.25.76. Declaring zod 3.25.76 as a root devDependency makes pnpm resolve every such peer to it (resolve-peers-from-workspace-root is on by default), which is npm's hoisting behaviour. mobile-mcp keeps its own zod 4.4.3, as under npm; the npm tree does not change. * fix(pnpm): keep npm's root @types/node so root-level typechecks match The no-AK integration gate typechecks integration-tests/, which takes Node's types from the root node_modules. npm hoists @types/node 20.19.1 there, because acp-bridge and core pin it; pnpm, with no root declaration, hoisted 22.20.1, whose spawnSync overloads type process-registry.ts's stdout as string | NonSharedBuffer and fail TS2322. The same code passes on every npm-installed PR. Declaring 20.19.1 as a root devDependency puts npm's copy back where a root-level tsconfig looks. The npm tree does not change. * ci(pnpm): install with pnpm in the remaining workflows The follow-up to switching CI and release: every other workflow that installs the root workspace now uses the pinned pnpm with --frozen-lockfile, so no job tests a graph that release does not ship. - e2e, tui-parity, repo-hygiene, web-shell-visuals, serve-ab, sdk-java, windows-runner-smoke, qwen-autofix, the SDK releases, finalize-release, sync-release-to-oss, the root install in desktop-release and cd-cua-driver, and the sandbox Dockerfile. - setup-node drops the root npm cache (package-manager-cache: false); hosted jobs restore the pnpm store through the shared composite action, and qwen-autofix keeps af-012's rule that the persistent pool restores no remote cache. - serve-ab and web-shell-visuals install a separate base checkout that can predate pnpm-lock.yaml, so those installs fall back to npm ci there. - Out of scope, unchanged: packages with their own lockfile (cua-driver's TypeScript SDK, desktop-shell, live-host, mobile-mcp), and the triage lanes with npm-cache.yml and the npm audit gate, which move with the package-lock.json retirement. - New size baselines for the touched workflows; qwen-autofix stays under the 470000-byte gate. * fix(pnpm): link the workspace packages that root-level code imports npm links every workspace package into the root node_modules, so integration-tests/ and scripts/, which are not workspace packages themselves, can import @qwen-code/* by name. pnpm links a workspace package only where it is a declared dependency, and the root declared none, so the no-AK integration gate could not find @qwen-code/qwen-code-core. The root now declares the seven packages that root-level code imports at runtime as file: devDependencies: acp-bridge, channel-base, the CLI, core, sdk, web-shell and web-templates. npm already links them, so its tree does not change (letting npm re-resolve the lock reproduces the same root entry); .pnpmfile.mjs rewrites them to workspace:*, which pnpm links at the root. * ci(pnpm): move triage, the store producer and the root audit to pnpm - qwen-triage's verify and tmux-testing lanes install the PR with `corepack pnpm install --frozen-lockfile` from a restored pnpm store. The one retry clears node_modules first, because pnpm install, unlike npm ci, keeps it. - npm-cache.yml becomes pnpm-store.yml, keyed on pnpm-lock.yaml. - security-checks audits the root workspace with `pnpm audit`, which reads the lockfile, so the root install step goes. The vendored lockfiles keep npm, and the retry recognises pnpm's endpoint error too. - qwen-autofix drops the hosted-only store cache: its heavy jobs forbid local `uses: './...'` actions, and the file sits at the size gate. - cd-cua-driver: setup-node@v4 has no package-manager-cache input. - package-assets fixtures install sharp rather than listing it in package-lock.json, matching how prepare-package now resolves it. - AGENTS.md, CONTRIBUTING.md and the npm workspace guide install with pnpm. * feat(review): install pnpm repos in qwen review's build/test qwen review installed dependencies only for a repo with package-lock.json and reported a pnpm repo as unsupported, so reviews of qwen-code would lose their build and test once its npm lockfile goes. - lockfileInstaller() picks npm or pnpm from the committed lockfile. With both, `packageManager: pnpm@...` chooses pnpm; anything else keeps npm. - A pnpm repo installs with `corepack pnpm install --frozen-lockfile` through the same disk, budget and sandbox path as `npm ci`, and counts as installed once node_modules/.modules.yaml exists. - Scripts still run through `npm run`, and the npm path is unchanged. * ci(pnpm): retire the root package-lock.json pnpm-lock.yaml is now the only root lockfile. - check-lockfile keeps the pnpm integrity check and Playwright parity, which now reads pnpm importers and snapshots. The npm-vs-pnpm agreement and build-approval checks go: pnpm 11's strictDepBuilds and every CI install's --frozen-lockfile enforce what they covered. - pnpm-lock-freshness.yml goes; it regenerated pnpm-lock.yaml from package-lock.json. - Release: version.js drops its package-lock refresh, the release commit stages pnpm-lock.yaml and the SDK release stages no lockfile, so neither `git add` fails on the missing file. `npm version` in the SDK and mobile-mcp releases passes --no-workspaces-update so it cannot reinstall the root with npm. - cd-mobile-mcp installs from the root pnpm lockfile. setup-node in cd-mobile-mcp, qwen-code-pr-review and desktop-release no longer keys an npm cache on the root lockfile. - check-desktop-isolation reads pnpm importers; build.js, build_sandbox.js and preflight install with pnpm. - pnpm-lock.yaml, pnpm-workspace.yaml and .pnpmfile.mjs join the autofix supply-chain class and repo-hygiene's deny list; pnpm-lock.yaml joins autofix's generated-diff exclusions, sdk-java's path filter and the platform-sensitivity manifests. - .gitignore lists /package-lock.json so an npm install cannot commit it back. Tests and docs follow. * fix(standalone): read the node-pty versions from the pnpm lockfile * chore(vscode-ide-companion): regenerate NOTICES.txt after the lockfile swap * chore(vscode-ide-companion): regenerate NOTICES.txt from the pnpm dependency tree The committed NOTICES.txt was generated from an npm install and does not match the tree produced by the pnpm install the release pipeline now uses (659 resolved dependencies, differing @types/node and mime-db versions). Regenerating with the pinned pnpm install makes the freshness check reproducible. * fix(ci): drop the npm cache from the daily dependency audit actions/setup-node's npm cache keys off the root package-lock.json, which this branch retires, so the scheduled job would fail at Set up Node before the audit ran. No pull_request run reaches this workflow to catch it. The root tree is never installed here either: pnpm audit reads pnpm-lock.yaml directly. Matches the sibling workflows that already set package-manager-cache: false; scripts/tests/security-workflows.test.js now pins it. * chore(ci): stop banking main-side drift in the workflow size ratchet The ratchet exists to turn a workflow's growth into one reviewed line. This branch re-recorded entries for 17 workflows it never touches, several upward by 0.4-2.8 KB - drift that happened on main, banked into the manifest without review. Restore those to their merge-base values, so .size-baseline changes only for the 22 workflows this branch actually edits. The entries were not needed to go green: ci.yml passes the PR's base commit, so a file that drifted on main and is otherwise untouched earns a warning, not a failure. * fix(release): initialize standalone state before main * test(browser-use): read Playwright pin from pnpm lock * fix(ci): address pnpm migration review blockers * fix(desktop): stop reading the retired root lockfile --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
94946f1bf8
|
chore(release): v0.24.1 (#12239)
* chore(release): v0.24.1 * docs(changelog): sync for v0.24.1 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
535dfd9a11
|
feat(web-shell): add PWA installability and Android development shell (#11722)
* feat(web-shell): add installable PWA support * fix(build): skip incomplete Web Shell assets when bundling * feat(web-shell): declare browser support matrix and compat fallbacks * feat(web-shell): make the Web Shell installable as a PWA Serves /manifest.webmanifest and /sw.js pre-auth, registers the worker deferred to load, and replaces the earlier service-worker.js draft with sw.js as a Vite entry (PNG icons included). * feat(mobile-shell): add Android WebView shell skeleton WebView shell around the daemon-served Web Shell (no second UI), profile tuples of URL/token/display name with #token= fragment delivery, native WebView version check at the Chrome 107 floor, and a foreground-service skeleton for SSE/notifications. * chore(web-shell): drop superseded service worker draft files * test(web-shell): cover service worker routing and lifecycle * chore(web-shell): align @playwright/test with main lockfile * chore: register mobile-shell importer in pnpm lockfile * test(web-shell): parse sidebar stylesheet with postcss for @supports nesting * chore: register mobile-shell in pnpm rewrite set * fix(web-shell): address PWA and Android acceptance blockers * docs(mobile-shell): make remaining native acceptance limits explicit * fix(web-shell): address fourth PWA review round * fix(mobile-shell): restore web view on back --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
c53287da5f
|
chore(release): v0.24.0 (#12031)
* chore(release): v0.24.0 * docs(changelog): sync for v0.24.0 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
aff26a8f36
|
fix(cli): register model-invocable commands before headless turns (#11994)
* fix(cli): register model-invocable commands before headless turns * test(ci): include headless workflow regression in expected no-AK suite --------- Co-authored-by: qqqys <266654365+qqqys@users.noreply.github.com> |
||
|
|
af4da34719
|
chore(release): v0.23.4 (#11880)
* chore(release): v0.23.4 * docs(changelog): sync for v0.23.4 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
c666ec1a0a
|
fix(ci): restore Windows test baseline (#11787)
* fix(live): restore Windows filesystem compatibility
* fix(ci): restore Windows test baseline
* fix(ci): keep release-age excludes internal and re-arm two witnesses
- pnpm-workspace.yaml: drop '@tybys/wasm-util@0.10.4' from
minimumReleaseAgeExclude. scripts/tests/package-scripts.test.js pins
that list to internal, version-independent entries. The exclusion is
also inert: minimumReleaseAge is not configured anywhere in the repo,
and pnpm-lock.yaml records `overrides` but not minimumReleaseAgeExclude
-- so the '@tybys/wasm-util': '0.10.4' override stays, because dropping
it would desync the lockfile and fail --frozen-lockfile.
- web-shell-brand.test.ts: build the swapped-file fake as BigIntStats.
Production compares bigint fields with a bare `!==`, so a number-backed
fake tripped `dev` first and the perturbed inode was never reached;
removing the perturbation now turns the test red again.
- run-qwen-serve.test.ts: '0' is unresolvable on Windows (getaddrinfo
ENOTFOUND 0), so the wildcard case keeps '0.0.0.0' and witnesses the
socket rather than a spelling: the operator typed port 0, so the report
must carry the ephemeral port the listener actually got. Spelling
normalisation stays pinned platform-independently in
remote-quickstart.test.ts.
- artifact-snapshots.ts: revert the readdir hoist to main. It is
behaviourally inert (the catch rethrows ENOENT on the operationId path
either way), has no test and no Windows link.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Patrol-Run: qwen-pr-closeout/jmu07e78o2w
* fix(ci): restore the load-bearing release-age exclude, keep the witness fixes
The previous commit dropped '@tybys/wasm-util@0.10.4' from
minimumReleaseAgeExclude to satisfy scripts/tests/package-scripts.test.js:390,
on the reasoning that the entry was inert because minimumReleaseAge is not
configured in this repo. That reasoning was wrong and CI measured it: the gate
is enforced by pnpm itself, not by repo config, so removing the exclude failed
'Install frozen pnpm worktree dependencies' on all three platforms with
Lockfile failed supply-chain policy check (1975 entries)
@tybys/wasm-util@0.10.4 was published at 2026-09-13T08:00:13.464Z,
within the minimumReleaseAge cutoff (2026-09-12T20:03:50.286Z)
(run 34779568628; Install was green at
|
||
|
|
7e0beb9d18
|
fix(skills): re-apply a Skill's side effects when a session is resumed (#11280)
* fix(skills): re-apply a Skill's side effects when a session is resumed A resumed session restored a Skill's instructions without restoring the state that enforces them: the restore path only rebuilt the dedup sets, while session hooks and allowedTools allow rules live in per-process memory. So --continue / --resume came back with the Skill's body in the model's context and its PreToolUse gate gone, silently. Each restored Skill now goes through the same shared side-effect helper both live invocation paths use. Two refusals carry over from those paths, so a resume never re-arms what a fresh invocation would refuse today: a Skill disabled since it was invoked, and a conditional (paths:) Skill whose activation has not fired in this session. Folder trust is re-checked inside the helper, and both registrations dedup, so the replay cannot stack duplicates. Bookkeeping stays unconditional, since the body really is in the restored context. The paths that still do not restore now say why in the debug log — at warn when the Skill declares hooks:, matching the existing rule — instead of falling through silently. A Skill started with /<skill-name> leaves no tool-call record to key on and is documented as a limitation. Fixes #11180 * fix(skills): scope a restored Skill's grants to its session and name what resume declines Review round 1 on #11280. A skill's `allowedTools` were granted as process-wide session allow rules that no session transition clears, while its hooks die with the session they were registered for. Re-applying them on resume made that gap reachable from a failed `/resume`: the rollback returns the user to the old session with the abandoned one's grants still live. Grants made for a skill now carry the session they were made for, and the permission manager filters on it alongside the existing folder-trust check, so `/clear` and a session swap drop them the way they drop the skill body. The dedup contract widens the same way trust gating does. Restore also declined more cases than it explained, and explained one it got wrong: a same-session re-invocation records the dedup message rather than a body, and every such response was reported as an edited SKILL.md — a steady-state warning pointing at a file that never changed. An already restored skill is now a no-op, and the mismatch reason is chosen by whether the recorded output is a skill body at all. A skill hidden from the model since it was invoked is no longer re-armed: frontmatter is not part of the recorded body, so that change is invisible to the match. Also: collect the cached skills once instead of twice per resume, pin the two `await`s and the mismatch log with tests that red without them, scope the integration test's send wait to the request carrying its prompt, and correct the skills doc — resume re-applies both halves, a frontmatter-only edit is restored, and the cases that log elsewhere or not at all are named. * fix(skills): single-source the skill availability rule resume re-checks Review round 2 on #11280. Resume decided whether to re-arm a restored skill's `allowedTools` and `hooks:` from its own copy of the model-facing availability rule, which the availability filter also hand-rolls. Two copies of one rule drift, and this pair already had: the filter's visibility condition was missing from the resume copy until last round. Both now ask `skillModelInvocationBlock`, which returns which condition failed so the resume path can still name it in the log — the reason that branch exists. Every condition is read live off `Config` / `SkillManager` rather than off the snapshots an unsequenced `refreshSkills()` commits, and `pendingConditionalSkillNames` keeps its own filter, which is this trio minus the activation check. The session scoping added last round was pinned only against a stubbed `PermissionManagerConfig`, leaving the wiring it depends on — that the id tagged onto the grant is the one `startNewSession` replaces — untested. A `config.test.ts` case now drives a real `Config`, a real `PermissionManager` and `applySkillSideEffects` across a session boundary, and reds if either the scoping or the id passed through `applySkillSideEffects` is removed. Both `PreToolUse`-gate integration suites drove copies of one fixture, already diverged in the place that decides their assertions: only the resume suite's gate wrote the hit counter, and nothing at the parity call site said why. The skill, the gate script (counter always written), the fake-model env stubs, the launch args, the poll helper and the exit sequence move to `integration-tests/helpers/gated-skill-fixture.ts`. The two fake models stay separate: parity dispatches on a request counter, resume on the last user message, because its second session replays the first one's turns. * fix(skills): scope the AUTO stash, key resume declines on the record Round 2 review follow-ups. R1-1 (Critical): `addSessionAllowRule`'s AUTO-mode stash branch deduped on `raw` and returned before the live re-point, so a dangerous `allowedTools` grant stashed in session A kept A's id; leaving AUTO re-attached that same object and the session filter dropped it for good. It now updates the stashed entry in place, never pushing it into `sessionRules.allow` while AUTO is on. R2-3: `activeSessionAllowRules()` was the only reader applying the session predicate. `getAllowRawStrings()` (the `StartSessionEvent` at a session boundary) now goes through it, and the AUTO strip candidates go through the new session-only half — not the full predicate, so a mid-AUTO trust grant cannot activate an unstripped dangerous rule. R1-3: `skillModelInvocationBlock` checks `disableModelInvocation` before `isSkillActive`. Such a skill never enters the activation registry, so `inactive` is permanently unsatisfiable and masked the cause that explains the decline. R2-4: the decline log is deferred to after the history scan and emitted only for skills nothing later restored, so a stale first pair no longer warns "your gate is gone" about a gate the same loop arms. R2-7: `logSkillNotRestored` keys on the record rather than the declaration. A non-body record (a recorded refusal) logs at debug saying nothing was ever armed; the warn level now covers `allowedTools` as well as `hooks:` (nine bundled skills declare the former and none the latter); and each reason names the route that works — `/<skill-name>` for inactive and hidden, `/skills` first for disabled. R1-5, R2-1, R2-6: the docs bullet, the `sessionId` JSDoc and the `SkillCommandLoader` assertion comment now describe what the code does — a recorded-response mismatch covers a moved skill directory as well as an edited body, no in-tree caller produces an unscoped session grant, and the "Exactly `{ trustGated: true }`" pin covers both keys. R2-2, R2-8: the shared fixture derives `SKILL_DESCRIPTION` from its prefix, names each generated on-disk path once, is imported by the parity suite instead of re-spelling `gated-skill`, and emits the description as a quoted YAML scalar — a bare one with a colon-space flattens the `hooks:` block into `{"PreToolUse":"","- matcher":"Shell"}`, which `parseHooksConfig` discards, leaving the gate silently absent. * fix(skills): hold the AUTO and trust invariants at the read side on resume Round-3 review findings on #11280, fixed at the shared cause rather than per instance. `sessionRules.allow` keeps a previous session's grants as inert entries and nothing ever removes one, so every path that reads the array had to re-derive "is this rule mine?" — and each derived it differently: - The AUTO strip takes candidates from the session-scoped half, so a grant tagged with another session was neither stripped nor stashed, and the strip's latch never re-scans. Re-entering that session id under a latched AUTO made the rule live again with the classifier bypassed. Enforce the AUTO half in `activeSessionAllowRules()`, the predicate `evaluate()` decides on, where session provenance cannot defeat it. - `restoreDangerousRules()` re-attached the stash by concatenation, seating two entries with the same `raw` once a cycle spanned a session swap. Merge by `raw`, keeping the stashed object so the next strip can still remove it by identity. - The live dedup re-pointed a kept entry across a session boundary while keeping the dead session's `trustGated`, so a previous session's ungated grant de-gated a later project skill's repository-controlled one and the folder-trust gate failed open. Take the arrival's gating on a cross-scope re-point, widen only within one scope, and route the AUTO stash branch through the same rule instead of re-pointing the session alone. On the resume path: - A skill body the scheduler truncated before recording starts with the truncation sentinel, not the body prefix, so it was classified as "not this skill's body" and declined at `debug` under a sentence asserting nothing was ever armed — false for a record whose `execute()` had already applied the side effects. Classify it as the truncated body it is. The decline stands: the record can no longer be compared against SKILL.md. - Declines were keyed last-write-wins, so a later refusal pair overwrote a body-shaped decline and discarded the one actionable signal. Rank them. - The body-mismatch arm hardcoded `reinvoke`, which `validateToolParams` refuses whenever a block condition co-occurs — and it does by construction for a `paths:` skill. Consult the block for the remedy. - Remedies named `/<skill-name>` unconditionally, but `user-invocable: false` drops the command from every dispatch accessor. Branch on it. Also corrects the in-code rationale for the warn/debug split: `warn` and `debug` share one sink gated only on `QWEN_DEBUG_LOG_FILE`, so the level buys grep and triage inside the debug log, not operator visibility. Every behavioural fix is pinned by a test verified to red when the fix is removed. * fix(skills): read unmatched resume records as uncorroborated bodies Addresses the round-4 review of the resume re-arming path. - An unmatched recorded response is now reported as a declined body (warn, with a route) unless it is one of the strings execute() returns in place of a body. The persisted-output stub, the budget-exhausted stub and the spill-failure fallback no longer land in the arm that claims nothing was armed; none of them is re-armed. - The restore lookup keys on the exact skill name, as the live path does, so two skills whose names differ only by case no longer collapse into one entry. - A declined project skill in an untrusted folder names folder trust as the precondition, and a disabled user-invocable: false skill is no longer sent to /skills. - Pin the stash path's cross-session trust narrowing and the merge's object replacement in permission-manager tests, and correct the merge comment's stated reason. * refactor(skills): simplify resume re-arming - Drop session-scoped allow rules. Config.startNewSession now clears session allow rules (including the AUTO stash) when the session changes, and a resumed session re-arms its own skills during initialize(). This removes the sessionId tag and its AUTO-mode merge and trust re-pointing logic. - Replace the decline classification, remedy text and warn/debug ranking with one factual warn line for a skipped skill that declares hooks or allowedTools. - Trim comments and the docs bullet. * fix(skills): do not re-arm Skills recorded inside exec output An exec script can print the nested-results line itself, so it now restores the Skill body only. The docs now state which skips log and that the match covers the body only. --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
ef0b8a6baf
|
fix(ci): raise the build heap cap from 3072 to 4096 MB (#11781)
main alone peaks at ~3.14 GB RSS building packages/cli under the 3072 MB --max-old-space-size cap, so whether tsc --build survives is decided by runner load: under CPU contention GC throughput drops and the build dies with 'Ineffective mark-compacts near heap limit'. Three OOM failures on three distinct runners versus green builds of the identical commit on quieter ones were observed on a single PR head. 4096 gives ~30% headroom over the measured footprint; worst-case RSS (~4.3 GB) stays safe on GitHub-hosted 16 GB runners and the ECS fleet. The test lanes keep 3072 — per-package vitest heaps are far smaller and have no OOM evidence. Fixes #11780 |
||
|
|
4ec9f63d0a
|
feat(core): add CodeModeOnly tool execution (#10607)
* feat(core): add CodeModeOnly tool execution * fix(core): preserve CodeModeOnly execution semantics * fix(core): drop the tool_search reminder in CodeModeOnly CodeModeOnly hides `tool_search` and binds every deferred tool — schema included — into the `exec` description, so progressive discovery has nothing left to do. The session prelude still announced those tools as "reachable via `tool_search`", pointing the model at a tool that is never declared and re-billing the text on every cached prefix. Worse, tools already callable as `tools.web_fetch(...)` looked gated behind a lookup step that does not exist. The subagent and fork-resume callers already opted out, but the main-session prelude sites did not, so the gate now lives where the prelude is built rather than in each caller. * chore: refresh settings schema * chore: refresh companion notices * fix: register exec tool metadata * fix(cli): localize exec tool display name * fix(core): stop offering ToolSearch lookups in CodeModeOnly CodeModeOnly hides tool_search and binds every deferred schema into the exec description, so text that tells the model to look a tool up describes a surface it cannot reach. Return an empty deferred summary from the registry itself - this also covers the fork-resume reminder that bypassed the earlier call-site gate - and point the image zoom hint at tools.zoom_image. * feat(core): teach the system prompt CodeModeOnly's tool surface In CodeModeOnly the model can only call exec, so the tool guidance and the worked examples described a surface it does not have: bare tool names it cannot call, an instruction to issue several tool calls in one response, and examples in a direct tool-call syntax that does not exist there. Give "Using Your Tools" a code-mode branch that routes every tool through tools.<name>, states which tools are direct controls instead, and replaces multi-call parallelism with batching inside one exec program. Swap the four model-family example sets for one shared exec set, since the syntax differences they exist for do not apply. The mechanics of exec itself stay in its tool description; the prompt carries only policy. * test: include code mode host in standalone fixture * fix(core): return code mode media as multimodal output * feat(core): support image tool results in code mode * fix(core): carry deferred tool schemas in the exec description CodeModeOnly hides tool_search and never surfaces a nested call as a history functionCall, so a signature collapsed to Record<string, unknown> could never be filled in later: parameter names were reachable only by guessing, or by reading them off validation errors one at a time. Deferred tools keep their registry state; only the generated signature gains the schema. * fix(node-repl): restore the bin exec bit after rebuild npm chmods dist/index.js when it links the bin at install time, but the build deletes that exact file and tsc re-emits it as 0644. After any rebuild node_modules/.bin/node-repl-mcp therefore points at a non-executable target and spawning it fails with EACCES (exit 126) before the shebang is ever read. OR the exec bits into the emitted mode instead of setting 0o755, so a restrictive umask is preserved rather than widened. * fix(cli): pin patched Ink version * feat(cli): add collapsible tool call details * fix(dev): use CLI tsconfig outside repository * fix(cli): preserve expanded tool details after completion * fix(cli): fail headless runs on model API errors * fix(core): expose shell timeout bounds in code mode * feat(core): add code mode timeout helpers * feat(cli): expose code mode in settings * fix(mcp): preserve structured results for model and exec consumers * fix(core): preserve code mode output and truncate inline * feat(core): port scoped context tools to code mode * fix(build): synchronize pnpm lockfile and capability docs * fix(core): recover from rejected Responses encrypted reasoning |
||
|
|
38513b591b
|
chore(release): v0.23.3 (#11583)
* chore(release): v0.23.3 * docs(changelog): sync for v0.23.3 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
bae90d7afa
|
chore(release): v0.23.2 (#11469)
* chore(release): v0.23.2 * docs(changelog): sync for v0.23.2 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
b661a2cdb2
|
fix(deps): Bump sharp to 0.35.4 to resolve high-severity libheif CVE (#11435)
* fix(deps): Bump sharp to 0.35.4 to resolve high-severity libheif CVE The dependency CVE audit gates on high-severity findings. sharp 0.35.3 pulls in a vulnerable libheif (GHSA-rgj7-g3m4-5g8c), which fails the audit. Bump sharp (and its @img platform/libvips binaries) to 0.35.4, which ships the fixed libvips 1.3.3. * fix(deps): regenerate pnpm-lock.yaml for sharp 0.35.4 Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmttlhdvjsx * chore(deps): Refresh VS Code companion notices for sharp 0.35.4 The sharp bump changes the generated NOTICES.txt version string; Lint & Static gates on the file being up-to-date. * chore(deps): Clear transitive sharp 0.35.3 from pnpm lockfile @mobilewright/core (mobile-mcp) still resolved sharp 0.35.3 through its ^0.35.3 range, leaving the vulnerable libheif build reachable from the worktree bootstrap. Refresh the resolution so every sharp and @img platform entry in the pnpm lockfile is 0.35.4 / 1.3.3. --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
c26f6d299f
|
chore(release): v0.23.1 (#11400)
Some checks are pending
Qwen Code CI / Classify PR (push) Waiting to run
Qwen Code CI / Test (ubuntu-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Lint & Static (ubuntu-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / web-shell E2E Smoke (ubuntu-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Test (macos-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Test (windows-latest, Node 22.x) (push) Blocked by required conditions
Qwen Code CI / Integration Tests (no-AK, No Sandbox) (push) Blocked by required conditions
Qwen Code CI / Integration Tests (CLI, No Sandbox) (push) Blocked by required conditions
Qwen Code CI / Desktop Shell (ubuntu-22.04) (push) Blocked by required conditions
Qwen Code CI / Desktop Shell (windows-2022) (push) Blocked by required conditions
E2E Tests / Build for E2E (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/1 (push) Blocked by required conditions
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/1 (push) Blocked by required conditions
E2E Tests / E2E Test - macOS - shard 1/2 (push) Blocked by required conditions
E2E Tests / E2E Test - macOS - shard 2/2 (push) Blocked by required conditions
E2E Tests / E2E Interactive - OpenTUI renderer (bun) (push) Blocked by required conditions
E2E Tests / channel-plugin E2E (nightly) (push) Blocked by required conditions
E2E Tests / cron-interactive E2E (nightly) (push) Blocked by required conditions
E2E Tests / web-shell Browser Regression (push) Waiting to run
npm cache producer / Save npm cache (push) Waiting to run
pnpm Worktree Smoke / Install (macos-latest) (push) Waiting to run
pnpm Worktree Smoke / Install (ubuntu-latest) (push) Waiting to run
pnpm Worktree Smoke / Install (windows-latest) (push) Waiting to run
SDK Java / ubuntu-latest / Java 11 (push) Waiting to run
SDK Java / ubuntu-latest / Java 17 (push) Waiting to run
SDK Java / macos-latest / Java 21 (push) Waiting to run
SDK Java / ubuntu-latest / Java 21 (push) Waiting to run
SDK Java / windows-latest / Java 21 (push) Waiting to run
SDK Java / Real daemon E2E / Java 11 (push) Waiting to run
* chore(release): v0.23.1 * docs(changelog): sync for v0.23.1 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
32f51a330b
|
chore: restore regression coverage after WebUI retirement (#11101)
* chore(web-shell): follow up #9812 review findings and deferred suggestions Address the remaining review suggestions from the @qwen-code/webui retirement (#9812) and the deferred items tracked in #11076: - Fix the 01-architecture.md adapter diagram path (missing session/). - Correct the followup-suggestions doc: generation fires on end_turn, and headless/SDK daemon clients should opt out to avoid the per-turn LLM cost. - Pin playwright to 1.61.1 to restore version parity with @playwright/test. - Restore file: scheme rejection coverage in Markdown.test.ts. - Pin the historical sessionStorage key prefix with a literal assertion. - Cover the legacy exported JSONL rejection and ChatRecord happy path. - Restore the shell-substring classifier trap with a live path. - Point useDaemonFollowupSuggestion docs at ChatEditor, not the deleted InputForm. - Replace the theme-toggle timing-race assertion and exercise the unhandledrejection fail-closed path in the document browser gate. Closes #11076 * fix(test): poll the theme class instead of a matcher vitest lacks The browser gate imports expect from vitest and drives playwright's Locator directly, so toHaveClass does not exist on the assertion and typecheck:integration failed with TS2339 on this line. Poll the class attribute through the same expect.poll idiom the neighbouring assertions use, which keeps the retry the assertion was switched to and needs no @playwright/test dependency. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-conflict/jmtooas8sln * fix(test): assert the exported theme class exactly `document-main.tsx` toggles `dark` and `light` on <html> mutually exclusively and nothing else writes `documentElement` classes, so the attribute is always exactly one of them. Matching `/light/` as an unanchored substring would also accept `dark light`, which is the theme-toggle breakage this poll exists to catch. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmtow5pgslz * fix(test): realpath the exporter main check and pin its JSONL guard Node realpath-resolves `import.meta.url` for the ESM main module but leaves `process.argv[1]` as invoked, so comparing the raw spellings made a symlinked invocation skip `main()` and exit 0 having written nothing — a silent no-op the harness reads as success. Compare realpaths instead and export the predicate so both directions are pinned. Also extract the input gate into `assertRenderableJsonl` so the legacy exported-JSONL rejection can be asserted directly: the previous tests only pinned the two predicates feeding it, so deleting the guard and losing the remediation hint kept every test green. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmtow5pgslz * docs(followup): name the real ACP stop reasons, drop "unconditional" The parenthetical this PR added named `interrupted` as a daemon stop reason. The ACP `StopReason` union is `end_turn | max_tokens | max_turn_requests | refusal | cancelled`, so there is no `interrupted`; an interrupted turn reports `cancelled`. Name the four suppressing values the union actually defines so an integrator writing `stopReason === '...'` gets a branch that can fire. "unconditional" was wider than the code and contradicted the condition list on the same page: `Session.ts#maybeEmitFollowupSuggestion` returns early on the stop reason, the todo stop guard, `ui.enableFollowupSuggestions`, PLAN approval mode, a missing chat, and a non-model last history entry. Point at those conditions instead; the cost advice still holds because the `enableFollowupSuggestions === false` return sits before `generatePromptSuggestion` is reached. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmtp6vibomd * test(web-shell): drop the duplicate historical-key assertion `persists under the literal historical key prefix`, added on this branch, became a byte-equivalent twin of `writes under the historical WebUI key`, which reached main with #11107 and arrived here through the merge at this PR's head: same `persistStableClientId('client-a', 'session-a')`, same literal `qwen-code-webui-client-id:session:session-a`, same expectation. One fact was reported under two names, so a prefix rename reddened two tests and an auditor could not tell which copy was load-bearing. The surviving test's comment already carries the rename rationale, so dropping the copy loses no coverage. Verified with `cd packages/web-shell && npx vitest run client/daemon/session/clientLifecycle.test.ts`: 19 passed before, 18 passed after. Mutating SESSION_CLIENT_ID_STORAGE_PREFIX to `qwen-code-webshell-client-id:session:` after the dedupe still reddens 3 tests (15 passed), including the surviving `writes under the historical WebUI key`; reverting the mutation returns to 18 passed. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmtp6vibomd * test(integration): drop the unreachable unhandledrejection arm The block this PR added after the CDN-failure loop could not reach the `window.addEventListener('unhandledrejection', showLoadError)` handler its comment claimed to exercise. `page.route('**/*', route => route.abort('blockedbyclient'))` fails the `<script id="transcript-renderer">` load, the template's capture-phase `error` listener (document-index.html:45-56, matching `event.target.id === 'transcript-renderer'`) calls `showLoadError()` first, and `setContent(..., { waitUntil: 'load' })` only resolves after that subresource has failed - so `data-render-complete='error'` and the alert text were already in place before `page.evaluate` dispatched anything, and showLoadError's one-shot guard (`if (document.body.dataset.renderComplete) return;`, document-index.html:30) made the synthetic rejection a no-op. The block was a strict duplicate of the loop's own `rendererBody === null` iteration: identical all-abort route, identical two assertions. Exercising the handler for real needs a renderer body that passes the document's pinned SRI integrity and then rejects during boot; no body this gate can serve passes SRI, so the arm cannot be made honest here. Deleting it returns the file to origin/main's state for this test - the handler and its missing coverage are both pre-existing on main (packages/web-templates is not in this PR's diff), so no coverage this PR was responsible for is lost. Verified: `npm run typecheck:integration` reports 0 errors in this file (6 remain, all in packages/** against generated/dist paths absent from an unbuilt worktree: channels/feishu, cli/src/generated/git-commit.js, web-templates/src/generated/*); `npx prettier --check` and `npx eslint` clean on the file. The browser gate itself was not executed locally - it needs the full build chain plus Chromium. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmtpfg5ewmp * ci(review-context): route concurrent-runner changes to the helper-tests lane This PR added `integration-tests/concurrent-runner/export-html-from-chatrecord-jsonl.test.mjs`, the first `node:test` file under `integration-tests/`, and wired it into CI through the `HELPER_TESTS` env list in `.github/workflows/ci.yml`. The tracked review-context manifest still mapped the whole `integration-tests/**` path to `recommendedTests: ['integration-tests']`, whose vitest lane collects `**/*.test.ts` only (`integration-tests/vitest.config.ts:21`), so a future PR touching only the exporter and its `.mjs` test is told to run a lane that cannot collect the file - the same silent drop `HELPER_TESTS` exists to prevent. Add a narrower rule for `integration-tests/concurrent-runner/**` recommending `helper-tests`. Matching rules merge rather than first-match, so the lane list for that directory becomes the union and every other `integration-tests/` path is untouched. The pinned `expectedManifest` in `manifest-repository-context.committed.test.ts` moves with it, which is what that pin is for. Verified through the real provider (tsx importing `packages/cli/src/commands/review/lib/manifest-repository-context.ts`) because the packages/cli vitest globalSetup gate refuses to run on this unbuilt worktree: concurrent-runner .mjs -> ["helper-tests","integration-tests"] concurrent-runner .js -> ["helper-tests","integration-tests"] chat-transcript-document.test.ts -> ["integration-tests"] (unchanged) all 10 rules co-matching -> non-null, 80 relatedPaths, and every `paths` probe matched some rule Also checked the committed manifest deep-equals the test's pinned literal (10 rules on both sides), and that dropping the new rule breaks that equality, so the pin is not tautological. `npx prettier --check` and `npx eslint` clean on both files. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-closeout/jmtpfg5ewmp * fix(deps): sync pnpm lockfile for Playwright pin --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
3ecfaffdf8
|
perf(dev): add pnpm worktree bootstrap foundation (#10449)
* perf(dev): add pnpm worktree bootstrap foundation Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(dev): harden worktree bootstrap process handling Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * perf(dev): prefer cache-only worktree installs Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(dev): preserve cached install cancellation Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(build): harden pnpm worktree bootstrap Validate pnpm lock updates in releases and exercise real installs and builds across supported hosts. Preserve npm release compatibility and keep dependency-only setup from rewriting npm-layout notices. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * chore: record merge attribution Record the required attribution for the Stage 1 merge without rewriting published history. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(dev): keep worktree bootstrap clean Use a bootstrap-scoped notice guard because nested npm lifecycle commands replace npm_lifecycle_event. This preserves explicit notice generation while preventing dependency setup from rewriting tracked output. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * ci: track pnpm smoke workflow size Register the new workflow in the repository size ratchet as required by the main CI gate. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(ci): drop stale importers from the new pnpm lockfile The lockfile was generated before the WebShell cutover (#9811) removed @qwen-code/webui from web-shell and the tailwind tooling plus @qwen-code/webui from vscode-ide-companion, so frozen-lockfile installs fail on all three smoke platforms with ERR_PNPM_OUTDATED_LOCKFILE. Drop the five stale importer entries so the lockfile matches the current package.json manifests; verified with pnpm 11.24.0 install --frozen-lockfile --lockfile-only. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(ci): refresh pnpm lockfile after merging main The merge of origin/main added remend@^1.3.1 to packages/cli/package.json without updating pnpm-lock.yaml, breaking the pnpm Worktree Smoke workflow frozen-lockfile install. Regenerated with pnpm install. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-conflict/jmtid3rse9h * fix(scripts): resolve the path variable case-insensitively on Windows A spread of process.env is an ordinary object, and native Windows shells expose the path variable as `Path`, so `env.PATH` was undefined there and findOnPath never located corepack — the offline-first Corepack bootstrap silently degraded to npx on exactly the hosts it exists for. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(scripts): pin the worktree bootstrap guards against mutation - Split the fallback log on /\r?\n/ like the sibling cmd.exe mocks, so the assertion holds on the Windows lane's CRLF output. - Add a win32 variant bootstrapping with the native `Path` casing to pin the case-insensitive lookup. - Assert the smoke workflow's fail-fast flag, the install-before-clean step order, and the no-build guard via a substring on the raw job text. - Extend the pnpmfile rewrite fixture to devDependencies and optionalDependencies, which the committed lockfile already uses. - Assert the notice-skip guard by effect (writeFile never called) and add the flag-absent companion test with I/O stubbed. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * chore(deps): sync pnpm-lock.yaml with qwen-live ACP backend deps Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-conflict/jmtjyz3tdco * fix(dev): stop patch-package from corrupting the pnpm store The root postinstall runs patch-package, which rewrites files under node_modules in place. With pnpm's default import method those files are hard links into the content-addressable store, so the patch rewrites the store entry too and its contents stop matching the sha512 it is filed under. Every subsequent fresh worktree then fails its --offline stage with ERR_PNPM_NO_OFFLINE_TARBALL, silently falls back to the registry (exit 0), and the fallback's postinstall corrupts the store again, so the offline path never hits. The advertised offline timing was only reachable on a same-tree reinstall, which needs no relinking. Set packageImportMethod to clone-or-copy: a copy-on-write clone where the filesystem supports it, a plain copy elsewhere. Either way patch-package edits only the worktree's own copy and the store entry stays intact, so later worktrees resolve entirely from the store. Verified on an isolated fixture store: under the default method the node_modules file and its store entry share an inode, and an in-place edit moves the store file's sha512 off its address, after which a fresh offline install fails with ERR_PNPM_NO_OFFLINE_TARBALL; under clone-or-copy the same edit leaves the store hash unchanged and the fresh offline install reports reused 1, downloaded 0. Also add pnpm-lock.yaml to .prettierignore. prettier reflows it into a shape pnpm does not emit, so `npm run format` and `pnpm install` fight over the file; .yamllint.yml already ignores it for the same reason. Both facts are pinned by tests in scripts/tests/package-scripts.test.js. Claude-Session: https://claude.ai/code/session_012797rgiteWJxLT9TLkKq8G * fix(ci): refresh pnpm-lock.yaml for qwen-live prompts deps Main added prompts/@types/prompts (and the ACP sdk) to packages/qwen-live/package.json after this branch generated its lockfile, so the pnpm Worktree Smoke frozen-lockfile install failed with ERR_PNPM_OUTDATED_LOCKFILE. Regenerated with pnpm 11.24.0 (--lockfile-only); frozen-lockfile and supply-chain policy checks pass. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Patrol-Run: qwen-pr-conflict/jmtlc9sozfg * fix(pnpm): close review findings on worktree bootstrap - Declare @qwen-code/qwen-code-core in vscode-ide-companion so the pnpm linker materializes it; regenerate both lockfiles and assert the link in the smoke workflow (R5-1) - Pin @types/node 20.19.1 in packages/core so the pnpm layout compiles against the same types npm hoists (D6-1) - Accept and pin the corepack +sha512 integrity suffix on packageManager; strip it for the npx fallback spec (D6-2) - Cover every workspace member in the pnpmfile rewrite set, mirror the npm channel list in pnpm-workspace.yaml, and cross-check both in tests - Run setup-worktree.js installs with cwd pinned to the checkout, gate the smoke clean-check on git status --porcelain, stop post-merge runs from cancelling each other, and extend check-lockfile.js to pnpm-lock.yaml * merge(main): realign pnpm workspace set and lockfiles Main removed the webui and cua-driver packages; drop both from the pnpm rewrite set and regenerate the pnpm lockfile against the merged manifests (picks up playwright, react-markdown, and the other main-side dependency changes) so the frozen bootstrap matches what the PR merge ref will run. * style(ci): quote smoke workflow scalars per yamllint * fix(dev): require Corepack for pnpm bootstrap * fix(dev): close pnpm bootstrap review blockers --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: yiliang114 <jinjing.zzj@gmail.com> |
||
|
|
55926e4617
|
feat(serve): allow concurrent standalone daemons with session fencing (#11207)
* feat(serve): allow concurrent standalone daemons with session fencing * fix(serve): address standalone ownership review feedback Preserve writer-blocked navigation and queued drafts, retain Live admission diagnostics, and cover concurrent daemon and filesystem ownership boundaries. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(serve): handle all writer fences and legacy publishers Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(ci): sync standalone concurrency allowlist assertion Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: jinye <3007091+doudouOUC@users.noreply.github.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
5b470befa0
|
ci: make the Prettier lane a real gate (#11117)
* chore: format the 35 files CI had been silently rewriting
`scripts/lint.js --prettier` and the release workflow's `Format Project`
step both run `prettier --write`, which reformats in place and exits 0.
Neither is followed by a dirty-tree check, so the rewrites are discarded
when the job ends and these files have stayed unformatted on `main`.
This is the output of `prettier --write` over exactly those files, so the
next commit can turn the check into a real gate without failing on a
backlog. No behaviour change: every hunk is whitespace, quoting or
wrapping.
Verified with prettier 3.6.1, the version pinned in package-lock.json.
`prettier --check .` over the whole repo reports these 35 and nothing
else.
Refs #11109
* fix(ci): make the Prettier lane a real gate
`runPrettier()` ran `prettier --write .`. Prettier exits 0 after
reformatting, and no caller checks the tree afterwards, so the lane
passed on unformatted code and CI threw the rewrites away — the 35 files
in the previous commit are what it had been silently fixing and
discarding.
ESLint does not cover the gap: eslint.config.js loads
eslint-config-prettier, which disables formatting rules rather than
enforcing them. With this change the only enforcement point outside the
husky pre-commit hook actually enforces something.
`npm run lint:all` now reports unformatted files instead of fixing them;
`npm run format` is the fix. Prettier's own failure message says so.
Refs #11109
* fix(release): drop Format Project, it writes and discards
The step ran `npm run format` (`prettier --write .`) and nothing in
release.yml inspected the tree afterwards — no `git diff --exit-code`, no
`git status --porcelain` anywhere in the file. The rewrites died with the
job, so the only failure it could produce was Prettier crashing on an
unparsable file, which the Run Lint step reports anyway.
It cost 13m58s on a quiet host and 20m45s on a contended one, against a
30-minute cap that `quality_static` hit twice today (runs 33957952281 and
33963757913, both cancelled mid-lint with nothing failing). The remaining
steps are `npm ci` (1m44s) and `lint:ci` (~8m20s), so the job now has real
headroom instead of finishing 24 seconds over the wall.
Formatting is now gated where it belongs: the previous commit makes the
PR-CI Prettier lane `--check`.
Refs #11109
* fix(ci): keep prettier --check out of .qwen/ and the pre-paint theme script
Two things the `--write` → `--check` flip broke that `--write` had hidden.
`.qwen/` is gitignored as `.qwen/*` and holds machine-written state —
pending-skills/, auto-skill-*/, learned-skill-*/,
computer-use/installed.json. Prettier does not read .gitignore, so it was
walking in and silently reformatting whatever a contributor had there;
under `--check` that turns into a failed `npm run lint:all` on files git
does not even track. CI never saw it (fresh checkout, tracked files only),
which is exactly why it went unnoticed. Adding `.qwen/` to
.prettierignore also drops the one tracked file under it —
skills/find-simplifications/SKILL.md, force-added past .gitignore — from
the previous formatting commit, since a directory the gate should not
police should not be reformatted for it either.
The inline theme script in web-shell's index.html is restored to its
original single line behind `<!-- prettier-ignore -->`. It is a
render-blocking script in <head> that applies the stored theme before
first paint; the expanded form ships ~600 more bytes on the critical path
and buys no readability the comment above it does not already give. A
change about CI hygiene should not be reshaping that.
Refs #11109
* fix(ci): keep prettier --check out of vendored packages/mobile-mcp
eslint.config.js has ignored `packages/mobile-mcp/**` since it landed —
"vendored mobile-next/mobile-mcp; has own eslint config" — and
.prettierignore already carries its sibling `packages/cua-driver/`, listed
one line above with the same rationale. mobile-mcp was simply missed.
`--write` hid that: it reformatted the vendored package's own eslint
config to our house style every run and threw the result away. The
formatting commit in this PR would have made that permanent, widening the
diff against upstream on the next sync for a package this repo has already
decided not to lint. That file is reverted here and the directory is
ignored.
Same class as the .qwen/ fix in the previous commit: the gate reaching
somewhere the repo had already decided it should not.
Refs #11109
* fix(ci): mirror eslint's remaining global ignores in .prettierignore
`--check` makes .prettierignore load-bearing in a way `--write` never was:
under `--write` a file prettier should not touch was reformatted and the
result discarded, so nobody noticed; under `--check` it fails the lane.
These three are the rest of eslint.config.js's global ignores, added for
the reasons it already states. `scripts/codemod/fixtures/` is the one that
matters: those files are "intentionally non-idiomatic ink input/output",
so the obvious response to a `--check` failure there — reformat to house
style — would corrupt the fixtures the codemod tests assert against. The
trap is not live today (all three currently satisfy prettier), which is
precisely why it is worth closing before someone meets it.
Refs #11109
* chore: format converter.test.ts, which drifted onto main since this branch
This branch merged main 32 commits after its base and `prettier --check .`
found one new offender. It is the same gate failing the same way: nothing
enforces formatting, so `--write` reformatted this file on every CI run
since it landed and threw the result away.
Worth noting as evidence rather than noise — the backlog this PR fixes was
not a one-off from before someone got careless; it accrues continuously,
and it accrued again while the PR was open.
Refs #11109
* Revert "fix(release): drop Format Project, it writes and discards"
This reverts the release.yml half of this PR. #11195 removes that step on
its own, in one file and four lines, and two PRs racing on the same
deletion helps nobody.
The reasoning and the evidence are unchanged and now live on #11195: the
dry-run release dispatched from this branch with the step removed
(34022919438) went 18/18 green in 65m43s, quality_static finished in
7m00s against main's 8m57s, and Run Lint was 4m52s vs 4m43s — nothing
downstream ever read what the step produced.
Dropping release.yml from this PR also widens who can review it. It was
the only file here owned by @pomelo-nwu and @wenshao alone; what remains
under CODEOWNERS is /packages/core/, whose owner list is six people. The
Prettier gate no longer waits on the two maintainers who must sign off on
release workflow changes.
Refs #11109, #11195
* fix(ci): make the gate resolve the file set npm run format resolves
Two review findings, one root cause: the gate was checking a different set
of files than the tree it is supposed to police.
**The `.qwen/` ignore rested on a false premise (R1-1, @chiga0).** Prettier
3.6's `--ignore-path` already defaults to `[.gitignore, .prettierignore]`,
so every machine-written path that entry's comment named —
`pending-skills/`, `auto-skill-*/`, `learned-skill-*/` — was outside the
gate before it via `.gitignore:32`. What the entry actually excluded is the
corpus `.gitignore` deliberately re-includes: `.qwen/commands/**`,
`skills/**`, `agents/**`, `team-memory/**`, `review-context.json` — 57
tracked, hand-authored files. The gate then passed because the surface had
been narrowed, not because the tree was formatted, and contributors editing
those docs could ship them unformatted with both enforcement points silent.
The entry is dropped and the first commit's formatting of
`skills/find-simplifications/SKILL.md`, reverted alongside it, is re-landed.
**The gate and the remedy used different CLIs (R1-2).** `runPrettier()` ran
the classic `prettier --check .` while `npm run format` runs
`prettier --experimental-cli --write .`. The classic CLI reads only the
repo-root `.gitignore`; the experimental one also honours nested ones, and
this repo has 23 of those. Verified on a scratch tree: given
`pkg/.gitignore` containing `lib/`, classic reports `pkg/lib/nested.js` and
experimental skips it. So the lane could go red on a locally built package's
output that `npm run format` provably cannot clear. The gate now uses the
same CLI as the remedy it names.
Refs #11109
* fix(ci): let the pre-commit hook cover what the gate now checks, and pin it
**The hook was narrower than the gate (R1-5).** `lint-staged` formatted only
`*.{js,jsx,ts,tsx}` and `*.{json,md}`, but the gate checks every extension
Prettier has a parser for. Of the 35 files the first commit formatted, 29
(83%) are in classes the hook never touched — 13 `.yml`, 12 `.mjs`, 3
`.css`, 1 `.html`. Left alone, the backlog this PR just cleared would
re-accumulate, and now as a red CI step on someone else's PR rather than as
silent drift. `.mjs`, `.cjs`, `.yml`, `.yaml`, `.css` and `.html` join the
Prettier-only group; ESLint's globs are unchanged, since the gap is about
formatting coverage, not lint coverage.
**Nothing pinned the flag (R1-4).** `scripts/tests/lint.test.js` exercised
only the linter-directory helpers, and `ci-platform-lanes.test.js` asserts
that the `Run Prettier` step exists and is profile-gated, not what it runs.
A refactor, or a well-meant "make lint auto-fix again", could restore the
silent pass with every suite green. Two assertions now pin it: that
`runPrettier()` checks rather than writes, and that it uses the same
Prettier CLI as `npm run format`, so the two cannot drift apart again the
way R1-2 found them.
Refs #11109
* docs: correct the instructions and comments the --check flip falsified
**Three tracked instructions to automation agents now say the opposite of
what the code does (R1-9), and one is fed to a CI lane today** —
`.github/workflows/qwen-triage.yml` re-pins `verify-pr` from the base commit
and hands it to the verifying agent.
- `verify-pr/SKILL.md` told agents never to run `scripts/lint.js` with no
arguments because it would rewrite the working tree under their A/B
harness. That is no longer why. The prohibition is kept — it is still
right — but re-grounded in what the no-arg form actually does now
(`setupLinters()` wipes the linter temp dir and re-downloads three pinned
binaries), and `--prettier` joins the enumerated non-mutating checks it
was the only flag missing from.
- `find-simplifications/SKILL.md` and its `references/land.md` told the
simplification agent that a formatting diff "carries zero signal" because
CI runs `--write`. An agent believing that would skip `npm run format`
after a deletion changed line shape — on the very extensions the hook does
not cover — and go red on formatting it was told could not matter.
- `update-ecs-runner-qwen-workflow.test.js`'s comment justified parsing two
matrix layouts by "CI runs `prettier --write .` before this suite". CI no
longer rewrites anything; the two layouts are still worth parsing, so the
comment is re-grounded in the checked-in form versus older branches.
**The index.html rationale overstated its own number (R1-8, @chiga0).** It
claimed the expanded script ships "~600 more bytes"; measured against this
repo's Prettier 3.6.1 and its `tabWidth: 2`, it is +258 source and +8
gzipped here, +287/+20 by the reviewer's method — either way roughly half
what was claimed, and "~600" is what the same expansion costs at
`--tab-width 4`. Since the prose ships verbatim inside the built
`index.html`, the fix is to drop the contested figure and keep the comment
short. The `<!-- prettier-ignore -->` guard itself stays: it is load-bearing.
Refs #11109
* chore: format classify-profile.test.mjs, drifted again after commit 1
Third instance in this PR's lifetime, and the sharpest: commit `
|
||
|
|
92a8a8d179
|
fix(skills): register frontmatter hooks on the /<skill-name> path (#11068)
* fix(skills): register frontmatter hooks on the /<skill-name> path A skill's frontmatter `hooks:` were registered only by `SkillTool`, the model-invocation path. The user-invocation path — `SkillCommandLoader` and `BundledSkillLoader`, reached by typing `/<skill-name>` — injected the skill body and granted its `allowedTools`, but never registered its hooks. A `PreToolUse` gate is the one mechanism that enforces a skill's rule regardless of what the model decides to do, so users reach for it exactly where a model mistake is expensive. Dropping it on the slash-command path made that gate fail open, silently: nothing in the UI or the logs indicated that a declared hook had been skipped. Extract the side-effect application into `applySkillSideEffects` in `skill-utils.ts`, alongside the existing `applySkillAllowedTools` and `canApplySkillSideEffects`, and route all three call sites through it. Both underlying registrations already dedup, and project skills stay trust-gated on every path. Bundling the two side effects behind one helper also stops a future invocation path from applying half of them. Documents the `hooks:` frontmatter in the Skills guide, which had no user documentation for it, making the deterministic path hard to discover. Tests: unit regressions on both loaders (the two positive cases fail without this fix), plus an end-to-end parity test driving the real interactive CLI over a PTY, asserting the gate blocks the shell call on both paths. Fixes #11067 * fix(skills): address review — sandbox reachability, CI coverage, resume path R1-1: the parity test bound the fake server to loopback and hand-stubbed NO_PROXY, so under the docker/podman sandbox legs the containerized CLI could not reach it and both cases failed. Use `fakeServerHostOptions()` and `applyContainerSandboxNoProxy()` like every sibling fake-server test; both are no-ops outside a container sandbox. R1-2: the test sat outside every suite that gates a PR, so a regression would only surface post-merge. Add it to `test:integration:no-ak:sandbox:none` (it needs no credentials) and to the pinned list in the CI wiring guard test. R1-4: session hooks are in-memory only, so `--continue` / `--resume` restored a skill's body without its side effects — and the dedup guard answers "already loaded in context", so nothing prompted the re-invocation that would have re-registered them. The gate silently stopped firing after a resume: the same fail-open shape this PR fixes. `restoreLoadedSkillsFromHistory` now re-applies side effects per restored skill, through `applySkillSideEffects` so the folder-trust gate still applies. Documentation says so. R1-5: restore the trace the refactor dropped. Sessions that disable hooks (`disableAllHooks`, safe mode, bare mode, ACP `skipHooks`) build no hook system, so a skill's gate is discarded — previously with a debug line naming `hasHookSystem: false`, now silently. R1-6: cover the guard branch. It is reachable in hooks-disabled sessions, and deleting it would throw on `undefined` and crash every skill invocation there, with nothing going red. R1-3: `[hook](hooks)` 404s on GitHub — the target is `hooks.md`, and no docs-site generator resolves extensionless links. Each fix was verified to red when the fix is removed. * fix(skills): don't re-arm disabled skills on resume; correct the docs claim Both problems were introduced by the resume repair added in the previous round, and both have the shape this PR exists to close: an operator believes a gate is armed when it is not. R2-1: `restoreLoadedSkillsFromHistory` applied side effects for every matched skill with no enabledness check. `applySkillSideEffects` gates only folder trust, and the candidate map comes from `getCachedSkills()`, which does not consult `skills.disabled` — so invoke-skill → disable → `--continue` reinstated the skill's `allowedTools` auto-approval rules and re-registered its hooks. Both live paths refuse a disabled skill before applying anything (`executeDisabledSkill`; the loader's disabled branch), so restore was the only way back in. Gate the side-effect call on `isSkillEnabled`; bookkeeping of `loadedSkillNames`/`loadedSkillContents` stays unconditional, since the body is in the restored context either way and the dedup guard must know. R1-5: the docs bullet claimed resume re-registers hooks on both invocation paths. It does not. The restore matcher requires a `ToolNames.SKILL` functionCall/functionResponse pair, which only the model path writes; the slash command submits the body as an ordinary prompt and leaves no such record, so a `/<skill-name>` skill's hooks are gone after resume while its instructions stay resident. State the truth per path, say how to re-arm the gate, and note the disabled-skill case. Making the parity claim true needs a restorable trace for the slash path — out of scope here. Tests: a probe asserting zero hook and zero allow-rule calls for a disabled skill on restore, verified to red when the enabledness gate is removed. * fix(skills): drop the resume repair, returning this PR to its original scope The resume repair added in round 1 has produced one Critical and three Suggestions across two review rounds, all in the same two files, and none of them are the bug this PR set out to fix. Both maintainers and the review bot converged on the same advice: the cluster belongs in its own change. Removing it entirely, rather than continuing to patch it, is also the honest call. The integration leg written for R3-3 showed the repair does not work in a real resumed session: the gate fired 0 times after `--continue` and the shell command actually ran, while the unit tests stayed green because they mock the hook system wholesale. Shipping a re-arm that does not re-arm would reproduce the exact fail-open this PR exists to close. `restoreLoadedSkillsFromHistory` is now byte-identical to its pre-PR form. The docs bullet takes round 1's other offered option and states the truth for the reverted behavior: session hooks are in-memory only and are not restored on resume, on either path — re-run the Skill to re-arm its gate. What remains is the change reviewed as sound: one shared side-effect helper, both loader paths routed through it, and the tests and documentation for it. The resume gap is pre-existing, now documented, and left to a follow-up. Removed: the resume re-arm and its `isSkillEnabled` / `pendingConditionalSkillNames` gates, the mismatch-branch trace, three resume unit tests, and the resume integration leg. * test(skills): close the three suggestions left open from rounds 1-2 R1-6 (fix-induced): the trace added for the silent-drop finding was `debug`, which `debugLogger` drops entirely without `QWEN_DEBUG_LOG_FILE` — quiet was asked for, invisible was not. Raise it to `warn`: control only reaches this branch for a skill that actually declares hooks (`applySkillHooks` returns early on `!skill.hooks`), so it fires exactly when a promised gate is being dropped and cannot become a steady-state warning. The docs sold the guarantee without naming the exception, so the Notes list now says hooks are not registered in sessions that disable them (`disableAllHooks`, safe mode, bare mode, an ACP client's `skipHooks`), where the body and `allowedTools` still apply but the gate does not. R2-3: the no-session-id test pinned only the hooks half, so hoisting that guard above `applySkillAllowedTools` shipped untested. It now asserts the grant still lands, matching its no-hook-system sibling. R2-2: the parity test sequenced its legs with unconditional `setTimeout` sleeps that neither shortened on a fast runner nor extended on a slow one. Every wait now polls the condition it is actually waiting on — the command echoing, the model call the submitted body produces, the gate firing, the exit prompt. Incidentally 2.4x faster locally (15.6s -> 6.6s), which is the fixed budget that was being burned. Both new assertions are load-bearing: reverting the trace to `debug` reds the no-hook-system case, and hoisting the session-id guard above the allowedTools grant reds the no-session-id case. * fix(skills): correct the trust claim, pin the hookless early return, fix the recipe All four from @wenshao's round-3 verification report. The Notes list claimed folder trust is re-checked at fire time, so revoking it mid-session silences a project Skill's hooks without a restart. Measured on the real CLI, neither direction takes effect: `Config.trustedFolder` is `private readonly`, assigned once in the constructor with no setter, so the fire-time check returns a constant for the life of a Config — and both of the CLI's own trust-change paths set `needsRestart`. The sentence was copied faithfully from a pre-existing code comment, but this PR is what promotes it into user-facing docs where a reader will act on it, which is exactly the shape of overpromise this PR exists to remove. It now says trust changes take effect on restart. The surviving mutant: deleting `if (!skill.hooks) return;` from `applySkillHooks` left the whole core suite green, while that early return is what lets the branch below it be a `warn` rather than steady-state noise — without it every hookless Skill invoked in a hooks-disabled session warns. Pinned by a case that reds when it is removed. Two fixes to the doc recipe: it is the first copy-pasteable hook example, and run verbatim with the script left at 0644 the gate fails open silently, so it now says to `chmod +x`. The example also used `matcher: Shell`, which works but is the compatibility alias; hooks.md tells new configs to prefer runtime ids, so it uses `run_shell_command`. Also fixes a soundness bug the new assertion exposed: `debugLoggerSpies` is module-scoped and was never cleared between cases, so log assertions were reading calls made by earlier tests. Cleared in `beforeEach`, which makes the previous round's two log assertions meaningful as well. * fix(skills): correct the trust claim, guard an empty hooks block, wait for command registration Round 4 review (#11068): two Criticals and two Suggestions, all four verified locally with intact/flip arms rather than by reading the diff. - docs: the trust bullet rewritten in 80c2fcb asserted unconditionally that a mid-session trust change takes effect only on restart. `isTrustedFolder()` reads the IDE context store first and falls back to the readonly `trustedFolder` field only when the store is empty, so the value is live under an IDE connection. A probe on a real Config confirms it: with `trustedFolder: true`, an `ideContextStore.set({workspaceState: {isTrusted:false}})` flips `isTrustedFolder()` to false mid-session, and clearing the store restores true. State both branches instead, and align the `applySkillHooks` / `applySkillAllowedTools` JSDoc with the same wording so the two documents stop disagreeing about one gate. - docs: bare mode was listed with the sessions where only hooks are dropped. `listSkillsAtLevel` returns [] for every level in bare mode and the tool registry returns before the Skill tool is registered, so there is no body and no allowedTools there either. Safe mode differs — discovery is limited to ['bundled'] rather than emptied — so it stays in the first group. - `applySkillHooks`: `{}` is truthy, and `parseSkillContent` assigns an empty object for `hooks: {}` and for a block whose event names are all unknown. Such a skill fell through the `!skill.hooks` guard and, with the warn level this branch now uses, emitted a per-invocation warning about dropping a gate it never declared. Widen the guard and pin the empty-object shape with a test; dropping the new operand turns that test red and nothing else. - parity test: the poll that replaced the fixed sleep waited for the typed text to echo, which lands before the skill command registry does. Submitting into that gap gets `Unknown command: /gated-skill`, undetectable downstream because the error text contains the command. Poll for the completion menu rendering the skill's own description — a signal only a registered command produces — and assert the unknown-command error never appears. Verified with the skill command loader artificially slowed by 1500ms, same bundle, only the wait predicate differing: the echo poll fails 3/3 on the user-invoked leg with `Unknown command: /gated-skill`, the registration poll passes 3/3 and absorbs the delay (4.3s vs 3.0s). Unslowed, the fix arm is 3/3 green with zero unknown-command occurrences. `test:integration:no-ak:sandbox:none` 23 files / 187 tests, core tools+hooks+skills 1333 tests, CLI skill loaders 63 tests, typecheck, eslint and prettier all clean. * fix(skills): close the six deferred findings from rounds 2-4 Every deferral recorded across rounds 2, 3 and 4, verified with intact/flip arms and probes on the real classes rather than by reading the diff. - docs recipe: `$QWEN_SKILL_ROOT` was unquoted. The command string is handed to a shell (`bash -c`), so a project path containing a space splits into two words: measured `bash: /tmp/My: No such file or directory`, exit 127, which is not 2 and therefore fails open — the same shape as #11067, in the recipe that teaches the fix. Quote it, and say why. - docs: an omitted `matcher:` on a tool event is stored as '' and compiled to `^$`, which matches no tool name. A probe on a real SessionHooksManager confirms it: two hooks registered, only the `*` one matches `run_shell_command`. The hook registers and never fires, silently. Say so, and point at `*`. - docs: hook commands run through the platform shell — bash on macOS and Linux, Git Bash on Windows when `MSYSTEM`/`TERM` say so, otherwise cmd.exe or PowerShell, where `$VAR` is not expanded and a `.sh` is not executable. `shell: bash` forces bash but resolves to whatever is on PATH, so the note stops short of promising it works on a stock Windows box. - `BundledSkillLoader`: the load-time `skills.disabled` filter cannot help a command that was already built, so a skill disabled afterwards still had its side effects applied on invocation. `SkillCommandLoader` has refused this since before this PR; mirror it. Pre-existing for `allowedTools`, but this PR widened the same call to hooks. - `packages/core/src/index.ts`: stop exporting `applySkillHooks`. It is the one entry point whose caller must apply the folder-trust gate itself, it had no consumer outside its own module, and exporting it invites the bypass that caused #11067. `applySkillSideEffects` stays exported and applies the gate. - test: the untrusted-folder warn fired on `allowedTools?.length || hooks`, but the only case used a skill carrying both, so dropping the hooks operand left all tests green. Pin a hooks-only project skill. Both new tests are discriminating: removing the bundled enabledness check reds only the new bundled case (1 failed / 28 passed), and dropping the `|| hooks` operand reds only the new skill-utils case (1 failed / 23 passed). `test:integration:no-ak:sandbox:none` 23 files / 187 tests, core tools+hooks+skills 4588 tests, CLI services 551 tests, eslint and prettier clean. The Windows shell behaviour is read from `getShellConfiguration`, not executed — no Windows host was available. |