Commit graph

1242 commits

Author SHA1 Message Date
Dragon
e9db70a072
feat(cli): add TUI image display tool (#8217)
* feat(cli): add TUI image display tool

* fix(cli): report terminal image rendering failures

* fix(cli): disable Kitty placeholders in Warp

* fix(cli): constrain terminal image previews

* fix(core): preserve fork image tool cache prefix

* fix(cli): address display_image review feedback (#8217)

Add the missing DisplayImage zh/zh-TW locale entries (and en for parity)
that broke the i18n guard test, detect chafa via a PATH lookup instead of a
synchronous probe render during display_image execution, and reject
truncated PNGs by reading the full 24-byte header before reporting success.

* fix(web-shell): add display_image to tool display contract (#8217)

* test(cli): cover display image validation edges

* fix(cli): harden chafa executable lookup (#8217)

Resolve chafa through the mermaid renderer's hardened findExecutable and
spawn the resolved path, so a project-local node_modules/.bin/chafa is
never executed unless the user opted in. display_image is a
non-prompting Read tool, so the previous bare-name PATH resolution
allowed arbitrary code execution from a malicious repository.

Also add review-requested coverage: isTerminalImageDisplay routing, the
truncated-PNG rejection branch, the chafa stderr fallback, and the Kitty
re-emit dedup guard.

* fix(cli): address TUI image display review feedback (#8217)

- Cache rendered terminal images (bounded LRU keyed on path, mtime, size,
  shape, and renderer) so a terminal resize or a restored session no longer
  re-reads the file or re-spawns chafa for every visible image.
- Reject cmd.exe metacharacters in the model-supplied path before spawning
  chafa through a shell, closing a command-injection surface on Windows
  .cmd/.bat shims.
- Bound a failing chafa's stderr to a capped first line before rendering it
  into permanent scrollback.
- Enforce the main-agent-only display_image ban inside the tool execution
  (isInForkExecution) and fail resolveForkExecutionAllowedTools closed when
  display_image is advertised without a concrete allowlist.
- Move the fileName computation to its use site, drop misleading awaits on the
  synchronous renderer, and add Kitty/Ghostty detection plus renderer cache,
  truncation, and shell-metacharacter tests.

* fix(cli): preserve color in chafa image fallback

* feat(cli): render images directly in Warp

* fix(cli): disable native images in Warp

* test(cli): cover chafa shell path guard

* fix(cli): skip re-transmitting Kitty image payload on remount (#8217)

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
2026-08-01 12:39:52 +00:00
易良
bd85599139
feat: visualize ordinary-session plan execution (#7580)
* feat: visualize ordinary session plan execution

* fix(web-shell): complete plan workflow rendering

* fix: preserve authoritative plan state

* fix(core): isolate teammate todo state

* fix: reject ambiguous empty plan snapshots

* test(web-shell): cover workflow dialog wiring

* feat(web-shell): preview workflow before execution

* feat(web-shell): inspect workflow step details

* feat(web-shell): preserve session workflow history

* test: align failing CI tests with plan-isolation behavior

SubAgentTracker: the emitter now guards subagent TodoWrite results
(tool-call-emitter emitResult early-returns on subagentMeta), so a
subagent todo no longer promotes into a session-level plan. Flip the
stale assertion to expect no plan emission, mirroring the dedicated
guard test in tool-call-emitter.test.ts.

HistoricalPlanExecution: the pagination fixture's onLoadOlderHistory
returned Promise<void>, but PlanExecutionHistoryProvider requires
Promise<boolean> and throws 'Unable to load earlier session history'
on a falsy resolution. Production wires loadOlderHistory (resolves
true after layout); return true in the fixture to model a successful
load.

* refactor: simplify session plan execution workflow

* fix(web-shell): preserve split plan approval workflow

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-08-01 10:48:30 +00:00
ytahdn
554c5e44ba
feat(web-shell): support mutable default mid-turn messages (#8229)
* feat(web-shell): support mutable default mid-turn messages

* fix(serve): register mid-turn removal telemetry route

* test(serve): update telemetry route totals

* fix(test): add session_mid_turn_message_mutation to expected features list

* fix(webui): forward clientId on cross-session mid-turn removal (#8229)

- Forward the session clientId in the cross-session removeMidTurnMessage
  branch so the bridge's exact-originator match can succeed; without it the
  removal resolved to an undefined originator and could never remove the
  message stamped at enqueue.
- Strip a misaligned/malformed messageIds from mid_turn_message_injected in
  asKnownDaemonEvent instead of rejecting the whole event, mirroring the
  sidechannel parser so a buggy daemon can't silently lose the injection
  signal.
- Log a mid-turn removal miss in the bridge like the enqueue/pending-removal
  siblings, to make removal races diagnosable from daemon logs.

* fix(web-shell): exclude annotations from mid-turn path and harden idle cleanup (#8229)

* fix(web-shell): add container-type to .queuedPrompts so @container query applies (#8229)

* fix(web-shell): harden mid-turn dedupe and capability gate per review (#8229)

- removeInjectedFromQueue now matches by id first (position-independent)
  and falls back to text only when no id match exists, so two same-text
  sends can't remove the wrong row and double-deliver.
- Thread canMutateMidTurn into useQueuedPrompts and gate the mid-turn
  delete/edit mutation on it, so the keyboard path can't hit a DELETE
  route the daemon doesn't advertise.
- asMidTurnMessageInjectedData omits a malformed messageIds key instead
  of leaving a present undefined, matching the sidechannel parser.
- Narrow MidTurnQueueItem.midTurnState, document the load-bearing effect
  order, and make clearQueuedPrompts return false on a no-op clear.

* fix: harden mid-turn removal per review (log escape, cross-session client id) (#8229)

- Escape the caller-controlled messageId (and sessionId) in the mid-turn
  removal-miss stderr line to prevent log injection (CWE-117).
- Forward the target session's persisted client id on cross-session mid-turn
  removal so the bridge's exact-originator match no longer rejects valid
  removals after a session switch with per-session client ids.
- Strengthen tests: distinct-id independence for two queued messages, deferred
  removal proving the composer waits for daemon removal, and the active-turn
  delete failed-action flag.

---------

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
2026-08-01 10:41:29 +00:00
Shaojin Wen
6f8ad2b4a5
feat(review): Include CLI version in attribution (#8294)
* feat(review): Include CLI version in attribution

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* test(review): Decouple footer test from package version

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-08-01 09:40:57 +00:00
Dragon
e569734a1e
feat(skills): add auto-skill curator (#7846)
* feat(skills): add auto-skill curator

* fix(i18n): translate /curator command descriptions for zh and zh-TW

The strict-parity locale coverage test failed because the new /curator
command and its status/run/restore subcommands fell back to English
descriptions in zh-CN and zh-TW. Add Simplified and Traditional Chinese
translations for the curator command descriptions and its user-facing
output strings.

* fix(i18n): add English source keys for /curator command

The strict-parity i18n check failed because zh and zh-TW defined the
new /curator command keys while en.js (the source of truth) did not,
producing extra-key parity errors. Add the matching English source
entries so all supported locales share the same key set.

* fix(skills): align curator lifecycle safeguards

* fix(skills): harden curator trust and name guards

* fix(skills): guard curator mutations by workspace trust

* test(skills): cover curator stale-to-active reactivation path

* test(skills): cover curator rollback and restore-collision paths

Add coverage for two previously untested error paths in the auto-skill
curator:
- restoreArchivedAutoSkill refusing to overwrite an existing active
  directory, leaving both the reused directory and the archived copy
  intact.
- runAutoSkillCurator rolling back an archive rename when the post-move
  state persistence fails, returning the skill to the live library and
  leaving nothing stranded in the archive (new isolated test file that
  mocks atomicWriteJSON to fail once).

* test(cli): cover curator command errors and stacked auto-skill usage

- Add mockRejectedValue error-path tests for the /curator status, run,
  restore, and pin commands, asserting each surfaces messageType 'error'
  and that a failed run/restore skips skill-discovery refresh.
- Add positive stacked auto-skill tests to both the non-interactive and
  interactive slash-command paths, asserting recordAutoSkillUsage is
  called once per successful stacked skill carrying project skillDetail.

* fix(skills): reject control-byte auto-skill directory names

isManagedDirectoryName only checked the auto-skill- prefix and basename,
so a crafted directory whose name embeds ANSI/control bytes was treated as
a managed skill and its name printed verbatim by the non-interactive
/curator output (which, unlike the TUI, does not run escapeAnsiCtrlCodes),
enabling terminal control-sequence injection from a cloned repo.

Require the directory name to match SKILL_NAME_PATTERN. A managed dir is
always auto-skill-<name> where <name> passes validateSkillName and the
prefix chars are within the same charset, so this never rejects a
legitimately generated directory (including Unicode skill names, which an
ASCII-only guard would wrongly drop) while excluding ESC/control bytes.

Add a regression test covering a crafted directory with a valid manifest
name so only the directory-name guard can exclude it.

* fix(skills): guard curator state reads and clarify restore errors

Align the curator state read path with the noFollow/lstat guards every
write already uses: refuse a symlinked or non-regular-file state file
(which could otherwise be followed to an external path, /dev/zero, or a
FIFO, causing OOM or a boot hang in untrusted workspaces) and cap the
read size. Also distinguish a present-but-ineligible archived skill from
a missing one in restore error messages.

* fix(skills): close curator TOCTOU reads and preserve seeding baseline

Address review feedback on the auto-skill curator:

- readManagedSkill previously read the manifest via Promise.all([lstat,
  lstat, readFile]); the readFile ran concurrently with the lstat guards,
  so a symlinked SKILL.md pointing at /dev/zero could start an unbounded
  read before the guard rejected it. Read the manifest with O_NOFOLLOW +
  an fstat size bound instead (shared readRegularFileNoFollow helper),
  refusing symlinks atomically and bounding the read.
- readState had the same lstat->readFile TOCTOU window; the O_NOFOLLOW
  read closes it while keeping the existing friendly error messages.
- First-run seeding overwrote firstSeenAt/lastActivityAt with now even
  when recordAutoSkillUsage had already created a record, resetting the
  inactivity clock. Preserve an existing baseline (like useCount/pinned/
  lastUsedAt), while a brand-new skill still gets a fresh now baseline.

Adds regression tests for the seeding-baseline preservation and for
refusing a symlinked manifest.

* fix(core): harden auto-skill curator per review feedback (#7846)

- Resolve node:fs constants lazily so importing the curator does not crash tests that mock node:fs without a constants export.

- Preserve the original error via cause when a rollback also fails.

- Apply the skill-name charset guard to archived directory names reserved in the review-agent task prompt.

* test(core): cover curator restore rollback and re-read guard (#7846)

* fix(core): record auto-skill usage on re-invocation (#7846)

* fix(skills): preserve curator read failures

* fix(skills): harden curator lifecycle guards

* test(skills): cover curator safety paths

* fix(skills): address curator review findings (#7846)

- Ignore future manifest mtimes in lastActivityMs so a bogus timestamp
  cannot make a skill permanently un-curatable
- Skip archived status entries whose directory is also live, preventing
  contradictory double-listing in /curator status
- Check the weekly interval before acquiring the cross-process lock in
  maybeRunAutoSkillCurator so most boots skip the lock entirely
- Use handle.readFile() instead of a single handle.read() to avoid
  silent truncation on short reads

* fix(cli): localize curator messages

* test(skills): cover curator usage safeguards

* fix(skills): address curator review feedback (#7846)

- Isolate per-skill rename failures so a transient error no longer
  aborts the whole pass and prevents state persistence (boot-loop fix)
- Make usage recording fire-and-forget (void instead of await) since
  it is already best-effort and nothing consumes the result
- Skip state file creation when no auto-skills exist
- Prune dead records whose directory exists in neither root
- Sanitize user-supplied directory names in error messages
  (JSON.stringify) to close the ANSI control-sequence echo path
- Split reserved skill names into active/archived lists in the
  review-agent task prompt
- Make collision output actionable with remediation guidance
- Fix rollbackMoves mutating its argument (moved.reverse → copy)
- Add null guard to isMissing for non-object rejections
- Add locale keys for skippedErrors output (9 locales)

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: Qwen Autofix <qwen-autofix@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
2026-08-01 07:37:20 +00:00
易良
2bbd82f14b
fix(cli): complete image routing across entry points (#7206)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (push) Waiting to run
npm cache producer / Save npm cache (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
* fix(cli): complete image routing across entry points

resolve local image @ references consistently in TUI, ACP, and non-interactive entry points
validate aliases and canonical targets against workspace, ignore, MIME, and file-identity boundaries
route image turns through the full-turn agent or vision bridge while failing closed on unsupported/fallback paths
integrate with tool-result vision bridge from #7484: @ image routing and tool-result image routing coexist with \0 suffix priority convention

Refs #6988

* test(cli): complete session config fixture

* fix(cli): close image routing review gaps

* test(core): fix readManyFiles config mock cast

* fix(cli): address image routing review feedback

* fix(cli): address image routing review comments

* test(core): cover validated file read safeguards

* chore: trim review followup scope

* fix(core): preserve custom fs text reads

* fix(core): harden validated file snapshots

* fix(core): resolve validated attachment review findings

* fix(core): share file display label with errors

* fix(core): unify snapshot cleanup through finally block (#7206)

* fix(cli): accept repeated full-turn model override

* test(cli): align drain prompt id expectation

* fix(cli): continue directory loop on workspace/ignore check failure (#7206)

The multi-root workspace directory loop used break on workspace-boundary
and canonical-ignore check failures, preventing resolution from remaining
directories. Switch to continue and defer the ignoredByReason push until
after the loop so a path that resolves from a later directory does not
leave a stale entry in the ignored-paths report.

* fix(cli): cover validated image routing edge cases

* test(core): type snapshot growth read mock

* fix(core): bound validated text reads

* test(cli): align large at-file read expectation

* fix(readManyFiles): key FileReadCache by canonical path, add size pre-check

* test(cli): deflake InstalledTab activation warning render sync (#7206)

* test(cli): cover full-turn model override rejection

* fix(core): keep unbounded validated text reads handle-bound

* fix(core): per-file error boundary and scan budget for validated reads (#7206)

* fix(core): surface size errors for validated files too large to snapshot (#7206)

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
2026-08-01 02:40:44 +00:00
易良
eabf312a06
feat(autofix): unify local and CI flows in one skill (#8121)
* feat(core): add current PR autofix controls

* fix(core): align autofix ci status wording

* feat(core): add current PR Autofix watcher

* feat(cli): route Autofix watcher ticks

* fix(autofix): fail closed on invalid watchers

* fix(acp): reject malformed autofix ticks

* fix(autofix): stop malformed watcher jobs

* fix(autofix): preserve unrelated cron jobs

* fix(autofix): separate watcher command from workflow skill

* test(autofix): cover headless watcher delivery

* test(autofix): cover watcher safety edges

* test(autofix): cover watcher failure paths

* fix(autofix): preserve non-watcher cron jobs

* fix(cli): fail closed on malformed autofix ticks

* test(cli): type autofix child process mock

* test(autofix): align malformed watcher coverage

* test(autofix): assert detached head skips gh

* fix(autofix): close watcher control gaps

* fix(autofix): preserve ordinary cron queue semantics

* fix(autofix): extract shared constants, validate job id, broaden off filter

* test(autofix): cover malformed watcher cleanup

* refactor(autofix): keep current PR controls minimal

* feat(autofix): reuse project skill for local runs

* fix(autofix): harden local review boundaries

* fix(autofix): enforce nested review containment

* fix(autofix): require local repository trust
2026-08-01 02:40:25 +00:00
ChiGao
907c7dea70
fix(cli): stabilize thinking block height, replace transcript overlay with inline Ctrl+O toggle (#8077)
* fix(cli): hide streaming thinking preview, rebind Ctrl+O to inline fullDetail toggle

The streaming thinking block showed a 4-line preview that varied in
height due to empty lines in the model's reasoning output, causing
constant page reflow and flicker during generation.

Changes:
- ThinkBody now renders nothing when collapsed (both streaming and
  committed), keeping the block at a stable 1-line header height.
- Ctrl+O now toggles inline fullDetail mode (like Claude Code): all
  thinking blocks, tool groups, and tool results expand/collapse in
  the main conversation view — no alternate-screen overlay.
- Alt+T preserved as hidden shortcut (same toggle, not shown in UI).
- MainContent passes fullDetail to HistoryItemDisplay via the existing
  ThoughtExpandedContext, so the toggle works in both VP and Static
  rendering paths.
- Removed TranscriptView overlay rendering, transcriptItems memo,
  StreamingContext import, and EMPTY_HISTORY_ITEMS constant.
- Removed dead code: tailVisualLines, grow-only height tracker,
  MAX_STREAMING_THINKING_VISUAL_LINES, openTranscript callback.

* refactor(cli): remove orphaned transcript full-detail infrastructure (#8077)

* fix(cli): update Ctrl+O help text and add thinking-expansion integration test (#8077)

* fix(cli): update docs, help text, and remove transcript dead code (#8077)

* fix(cli): strengthen Ctrl+O full-detail tests and refresh stale docs (#8077)

* fix(cli): address review feedback on test isolation, dead i18n keys, and missing negative case (#8077)

* fix(cli): add M1 mutation-killing assertion to Ctrl+O test (#8077)

The existing test only asserted clearTerminal (a refreshStatic side
effect) and never verified the setThoughtExpanded state flip.  Under
the vi.mock('ink') harness the mocked App never re-renders from a
directly-called handler, so a behavioural allExpanded assertion is
not possible.  Add a structural guard on the handler source that
fails when setThoughtExpanded is removed (mutation M1 verified).

* fix(cli): strengthen Ctrl+O toggle assertion and document non-VP redraw (#8077)

Tighten the structural M1 assertion from .toContain to a regex that
matches the (prev) => !prev updater pattern, catching mutations like
(prev) => true that the old check would miss.  Document the non-VP
scrollback redraw in keyboard-shortcuts.md per maintainer request.

---------

Co-authored-by: 秦奇 <gary.gq@alibaba-inc.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
2026-08-01 02:39:53 +00:00
zhangxy-zju
de022664dc
feat(skills): add disabled skill levels (#8057)
* feat(skills): add disabled skill levels

* fix(core): guard getDisabledSkillLevels for partial Config shims (#8057)

* test(cli): cover disabledLevels safe/bare guard and daemon wiring (#8057)

* fix(cli): guard daemon disabledLevels for safe mode consistency (#8057)

* test(core): add regression guard for missing getDisabledSkillLevels (#8057)

* test(core): pin partial config skill discovery (#8057)

---------

Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
2026-08-01 02:22:47 +00:00
destire-mio
412eae24b4
feat(core): add project-level fork profiles (#8148)
* feat(core): add project-level fork profiles

* fix(core): harden fork profile loading

---------

Co-authored-by: destire-mio <248462155+destire-mio@users.noreply.github.com>
2026-08-01 02:20:51 +00:00
destire-mio
4dc50b18e9
feat(memory): protect pinned files during forked Dream (#7714)
* feat(memory): protect pinned files during forked Dream

* fix(memory): harden pinned path protection

* perf(memory): avoid repeated pinned path resolution

* fix(memory): protect pinned memory during extraction

---------

Co-authored-by: destire-mio <248462155+destire-mio@users.noreply.github.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-08-01 00:55:45 +00:00
ytahdn
1e2932a637
feat(web-shell): add artifact downloads (#8234)
* feat(web-shell): add artifact downloads

* fix(web-shell): scope review download state per file and cancel on unmount (#8234)

* fix(web-shell): restore mount ref under StrictMode and test review MIME mapping (#8234)

Reset mountedRef in the effect setup so React StrictMode's dev-time
double-mount no longer leaves it false and silently cancels artifact and
review downloads. Move getReviewDownloadMimeType into artifactUtils and
cover the extension-to-MIME mapping with a unit test.

* test(web-shell): cover ReviewChanges cancellation-on-unmount path (#8234)

* test(web-shell): assert artifact download MIME type (#8234)

---------

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
2026-08-01 00:40:57 +00:00
Shaojin Wen
77d8a27eda
feat(daemon): raise default max sessions from 20 to 32 (#8235)
* feat(daemon): raise default max sessions from 20 to 32

* fix(daemon): update test assertion and docs for new default max sessions (32)

* fix(daemon): sync default max sessions

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-31 17:47:51 +00:00
Shaojin Wen
8efdf749ad
fix(autofix): guard review thread resolution (#8231)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-31 16:04:30 +00:00
qqqys
7189a68334
fix(serve): isolate managed memory by selected workspace (#8056)
* fix(serve): isolate managed memory by workspace

* feat(serve): add memory project scope option

* test(serve): fix clean build type assertion

* test(serve): cover untrusted workspace memory tasks

* test(memory): cover remaining workspace paths

* test(serve): cover unavailable memory lanes

* test(memory): isolate default scope

* fix(serve): address review feedback on workspace memory isolation (#8056)

- Create secondary ACP mounts on demand for dynamically-registered
  workspaces so the qualified memory routes work beyond boot-time
  runtimes (rename getWorkspaceRememberLane → ensureWorkspaceRememberLane)
- Remove the symlink-alias machinery from getAutoMemoryRoot: it had no
  producer, relaxed a documented invariant, and could throw on the
  per-turn hot path; workspace mode now uses the same plain path.join
  as git-root mode
- Move memoryProjectScope validation into the pre-listen block
- Use the shared sendWorkspaceRuntimeUnavailable helper in server.ts
- Revert an unrelated test mock change; fix misleading 'compatibility
  fallback' wording in ServeOptions
- Add workspace_qualified_memory capability tag, docs for the new flag
  and env var

* docs(serve): add workspace_qualified_memory to conditional features table (#8056)

* fix(serve): address follow-up review feedback on workspace memory isolation (#8056)

* fix(serve): address follow-up review feedback on workspace memory isolation (#8056)

Extract MEMORY_PROJECT_SCOPES const and MemoryProjectScope type in core
so yargs choices, ServeOptions, ServeArgs, and the runQwenServe guard
share one source of truth (reduces drift risk from five to three edit
points; the fast-path guard keeps inline comparisons because an import
boundary test forbids core imports on the lightweight startup path).

Document memory-project-scope caveats in the user-facing docs: daemon
vs standalone CLI split-brain, sanitizeCwd punctuation collisions, and
flag vs env normalization differences. Add the per-lane MAX_PENDING
resource note to the developer configuration reference.

* fix(cli): add missing sessionRuntimeBaseDir to late-add workspace test (#8056)

* test(serve): cover untrusted forget/dream and no-lane memory poll (#8056)

* fix(core): extract MEMORY_PROJECT_SCOPES into zero-import leaf module (#8056)

Importing the constant as a value from the core barrel turned it into a
real static edge that pulled the entire 5.6 MB barrel into the serve
pre-listen bundle closure, breaking the fast-path gate.

Move MEMORY_PROJECT_SCOPES and MemoryProjectScope into a new
memory/scopes.ts with no imports of its own, re-export from paths.ts so
the barrel surface is unchanged, add a ./memoryScopes subpath export,
and switch run-qwen-serve.ts to the narrow import.

Also derive the unknown-scope guard in resolveWorkspaceProjectScope()
from the constant instead of hardcoding 'git-root'.

* test(cli): pin non-allocating contract in workspace memory poll test (#8056)

---------

Co-authored-by: qwen-code-dev-bot <269191875+qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Qwen Autofix <qwen-autofix@users.noreply.github.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
2026-07-31 15:06:38 +00:00
Baby Blue Viper
e3479a6251
docs: worked example for a PreToolUse HTTP hook backed by an external judgment service (#8202)
* docs: worked example for a PreToolUse HTTP hook backed by an external judgment service

The existing remote-security-check config example points at a service
that has to already exist, without showing what that service actually
looks like. Adds a minimal, stdlib-only, runnable adapter (invinoveritas
/review as the judgment source) implementing the exact contract PreToolUse
HTTP hooks expect -- verified live against the real production API, not
just written to look plausible: a genuinely destructive shell command
returns permissionDecision: "deny" with a real explanation, a benign one
returns "allow", and the adapter fails open on any judgment-service-side
error so an outage never blocks legitimate tool calls.

* docs: address review feedback -- disclose affiliation, note swap point clearly

* docs: fix timeout mismatch, add data-handling note, make backend URL configurable, log fail-open state

---------

Co-authored-by: babyblueviper1 <babyblueviper1@users.noreply.github.com>
2026-07-31 13:56:33 +00:00
jinye
95657feb6e
feat(core): add GenAI time-to-first-chunk tracing (#8150)
* feat(core): add GenAI time-to-first-chunk tracing

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(core): address review feedback on GenAI streaming telemetry (#8150)

* fix(core): correct ttft_ms migration claim in telemetry docs (#8150)

* fix(core): address review feedback on GenAI streaming telemetry (#8150)

* fix(core): address review feedback on GenAI streaming telemetry (#8150)

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
2026-07-31 13:46:46 +00:00
ChiGao
2ed7874409
feat(core): add a host tool invocation guard (#8032)
* feat(core): add a host tool invocation guard

* docs(core): clarify guard correlation identity

* fix(core): add guard debug logging, narrow doc scope, pin fast path (#8032)

* fix(core): log unrecognized guard decisions before failing closed (#8032)

* test(core): cover blank and non-string guard denial reasons (#8032)

* fix(core): log guard evaluation and document fail-closed contract (#8032)

* test(core): cover speculation guard allow path (#8032)

* fix(core): log speculation guard denial reason at debug level (#8032)

---------

Co-authored-by: 秦奇 <gary.gq@alibaba-inc.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
2026-07-31 13:46:29 +00:00
qwen-code-dev-bot
63780e0d2f
fix(cli): add Option+V for clipboard image paste on macOS (#8120)
* fix(cli): add Option+V for clipboard image paste on macOS (#8118)

macOS terminals intercept Cmd+V for text paste, so the existing
Cmd+V binding for clipboard image paste never fires. Users had to
discover Ctrl+V through trial and error.

Changes:
- keyBindings.ts: add { key: 'v', meta: true } (Option/Alt+V) to
  PASTE_CLIPBOARD_IMAGE bindings on non-Windows platforms
- KeyboardShortcuts.tsx: update macOS hint from 'cmd+v' to
  'ctrl+v / opt+v' to reflect what actually works

* fix(cli): correct macOS image-paste shortcut hint (#8118)

* test(cli): cover platform-specific image-paste shortcut hint (#8118)

* fix(cli): make option+v image paste work on stock macOS terminals (#8118)

* fix(cli): address review feedback on macOS image-paste shortcut (#8118)

- Guard the option-composed glyph lookup with Object.hasOwn so inherited Object.prototype members can never resolve as a composed key.

- Add a non-macOS pass-through test for the "√" glyph, mirroring the existing "†" coverage.

- Correct the keyboard-shortcuts docs: Ctrl+V also pastes on macOS, matching the overlay hint.

---------

Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-07-31 13:42:18 +00:00
Dragon
29e9b352d4
feat(cli): run safe slash commands during streaming (#8130) 2026-07-31 13:41:38 +00:00
sunday
cf547b6a3c
feat(hooks): add SessionDelete event (#8059)
* feat(hooks): add SessionDelete event

* test(hooks): cover SessionDelete failure paths

* fix(hooks): standardize SessionDelete failure handling

* fix(hooks): include session id in SessionDelete hook failure logs (#8059)

* docs(hooks): note that transcript_path is empty over ACP for SessionDelete (#8059)

* refactor(cli): deduplicate SessionDelete hook dispatch (#8059)

* fix(cli): keep SessionDelete hook dispatch ACP-safe

* fix(cli): align SessionDelete short description with other references (#8059)

---------

Co-authored-by: 欢伯 <ri.xur@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
2026-07-31 13:05:44 +00:00
Dragon
c50137cf86
fix(core): prevent subagents from asking users (#8219) 2026-07-31 12:39:04 +00:00
jinye
08798b4832
feat(core): Normalize tool-call terminal telemetry (#8176)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / web-shell Browser Regression (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (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
* feat(core): normalize tool-call terminal telemetry

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(desktop): handle cancelled tool telemetry replay

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-31 11:51:14 +00:00
OrbitZore
153d781a34
feat(gitlab-channel): add transient 👀 award emoji while agent is working (#8119)
* feat(gitlab-channel): add transient 👀 award emoji while agent is working

Adds a working-reaction feature to the GitLab channel adapter, mirroring
the GitHub adapter's eyes reaction (PR #8061). When the agent starts
processing a note mention, a 👀 award emoji is added to the note; it is
removed when the run completes, fails, or is cancelled. Both operations
are best-effort and never block the response.

Also replaces the custom Todo interface with gitbeaker's TodoSchema,
introduces GitlabTarget to consolidate target info, and simplifies
processTodo/buildMetadata signatures by passing the parsed target
directly instead of redundant targetType/threadId parameters.

Co-Authored-By: Qwen Code <noreply@alibaba.com>

* fix(gitlab-channel): guard null target and fix reactions leak

Restore null guard for todo.target (dropped in the TodoSchema refactor)
to prevent TypeError when GitLab returns a todo without target. Use
try/finally instead of try/catch for reactions cleanup so entries are
removed on all handleInbound return paths, not just throws.

Co-Authored-By: Qwen Code <noreply@alibaba.com>

* test(gitlab-channel): add poll-driven reaction tests, fix fragile sequencing

Add ReactingGitlabChannel that drives real pollOnce → handleInbound →
onPromptStart/onPromptEnd path, covering #note_ parse, key derivation,
and finally cleanup. Replace the tautological description-mention test
with one that exercises the real isNoteMention guard. Replace bare
Promise.resolve() microtask waits with vi.waitFor in the award-failure
test.

Co-Authored-By: Qwen Code <noreply@alibaba.com>

* test(gitlab-channel): pin double-award guard with dedup test

Add test that calls startPromptForTest twice on the same messageId and
asserts award is called exactly once, pinning the `|| entry.award`
guard in onPromptStart against surviving mutations.

Co-Authored-By: Qwen Code <noreply@alibaba.com>

---------

Co-authored-by: Qwen Code <noreply@alibaba.com>
2026-07-31 10:45:38 +00:00
jinye
e887e334be
fix(core): Tolerate transcript timestamp drift (#7886)
* fix(core): tolerate transcript timestamp drift

Treat transcript timestamps as advisory and verify content before fencing a live writer. Preserve exact shutdown release semantics while aborting slow acquisition scans.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(core): Address transcript reconciliation review

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(core): address transcript snapshot review

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(core): isolate FileHandle prototype spies to prevent test flakiness (#7886)

Capture the real native FileHandle.prototype.read/stat once in beforeAll
and use them as delegation targets in all reconciliation tests, instead
of each test capturing whatever is currently on the prototype (which
could be a previous test's spy if cleanup ordering varied). Add
vi.restoreAllMocks() and explicit prototype restoration to afterEach as
a safety net against spy chaining across the shared prototype.

* test(core): add append-path symlink-race regression test (#7886)

* fix(core): replace unreliable chmod with utimes in reconciliation tests (#7886)

Seven content-verification tests used chmod(path, sameMode) to create a
timestamp drift that forces the reconciliation path. On filesystems that
coalesce same-mode chmod ctime updates (e.g. ext4 with lazytime), the
drift is not observed and the fast path is taken, so the read/stat spy
never fires and the test fails non-deterministically.

Replace with utimes(path, atime, mtime + offset), which explicitly sets
a different mtime and is deterministic across all filesystems. Tests
whose spies also inject utimes offsets use +500 for the setup to avoid
colliding with the spy's +N*1000 offsets.

* fix(core): replace unreliable chmod with utimes in reconciliation tests (#7886)

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
2026-07-31 08:11:44 +00:00
易良
9a4e924cf1
fix(github-channel): retry definite no-write deliveries (#8087)
* fix(github-channel): retry definite no-write deliveries

* fix(github-channel): preserve concurrent pending deliveries

* fix(github-channel): harden pending retry updates

* fix(github-channel): avoid duplicate pending retries on reconnect

* fix(github-channel): audit recovered deliveries before cleanup

* fix(github-channel): avoid duplicate recovered comments

* fix(github-channel): skip malformed audit entries

* fix(github-channel): bound pending retry recovery

* fix(serve): restore session service import

* fix(serve): remove unused session service import

* fix(github-channel): harden pending delivery recovery

* docs(github): update channel state paths

* fix(github-channel): audit ambiguous pending retries

* fix(github-channel): guard legacy state migration

* fix(github-channel): avoid pending delivery id collisions
2026-07-31 08:06:28 +00:00
sunday
01afcb0bba
feat(hooks): include session source in lifecycle payloads (#8155)
Co-authored-by: 欢伯 <ri.xur@alibaba-inc.com>
2026-07-31 05:59:09 +00:00
ytahdn
e379ea4e53
feat(web-shell): enhance composer and empty-session animations (#8098)
* feat(web-shell): enhance composer animations

* fix(web-shell): refresh DPR on resize and cover animation a11y guards

Re-read devicePixelRatio inside each resize so the specular composer
effect and the new-session dot field keep a correctly sized backing
store when the page zoom or display scale factor changes. Add
component-level coverage for the prefers-reduced-motion guards and for
the typewriter replay after the empty editor loses focus.

* fix(web-shell): localise specular highlight, fix rotation direction, add idle bail-out (#8098)

* fix(web-shell): correct specular angle wrap and dot field pointer baseline (#8098)

* fix(web-shell): paint static dot grid and idle animation loops (#8098)

* fix(web-shell): reset specular proximity on pointer leave and test WebGL cleanup (#8098)

---------

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
2026-07-31 02:20:27 +00:00
jinye
3bdaeac046
fix(serve): Isolate daemon session maintenance writers (#7975)
* fix(serve): isolate daemon session maintenance writers

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* codex: fix CI failure on PR #7975

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* codex: address PR review feedback (#7975)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* codex: fix CI failure on PR #7975

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(cli): address review feedback on daemon session writer maintenance (#7975)

- Extract teardownBoundSession helper to deduplicate bound-session
  teardown in scheduled-tasks create handler
- Extract shared cleanupSession callback in createServeApp to eliminate
  three verbatim copies of the orphan-deletion wrapper
- Fire onError callback on the SessionNotFoundError deletion path in
  deleteDaemonSessions, matching the normal close-succeeded path
- Update stale @priority docstring on Storage.getRuntimeBaseDir()

* codex: address PR review feedback (#7975)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* test(cli): cover orphan-delete paths and draining guards (#7975)

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
2026-07-30 14:01:50 +00:00
destire-mio
079ce5346a
feat(agent): add fork tool execution allowlist (#8066)
* feat(agent): add fork tool execution allowlist

* fix(agent): address fork allowlist review feedback

---------

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>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-30 13:58:51 +00:00
ytahdn
0a3098a279
feat(web-shell): add contextual task panels (#7929)
* feat(web-shell): add contextual task panels

* fix(web-shell): harden contextual task panels

* fix(web-shell): preserve side task titles

* fix(web-shell): address review feedback on context panels PR (#7929)

- Add POST /session/:id/side-task to telemetry route catalog (51 routes)
- Increase SDK browser bundle size limit to 184KB
- Fix duplicated data-testid="chat-pane" → "chat-pane-container" on container
- Gate sourceType behind session_source_metadata capability check
- Add removeSession cleanup after killSession in !res.writable path
- Add i18n key sideTask.renameFailed for error fallback
- Add unit tests for selectVisibleHistoryRecords invariant

* fix(cli): update telemetry-catalog route drift guard to 51 routes (#7929)

* fix(web-shell): address review feedback round 2 on context panels PR (#7929)

- Fix /fork sider discarding createSideTask() return value: show toast
  when side tasks are unavailable
- Fix layout feedback loop: availableWidth no longer depends on
  environmentPanelVisible since the CSS overlay does not change the
  chat pane DOM width
- Remove dead environmentPanelSuppressed state (never set to true)
- Restore setArtifactPanelOpen(false) in closeArtifactPanelTab when
  the last tab is closed
- Extract agentDisplayName(task) to a local variable to avoid triple
  invocation per render

* fix(web-shell): dedupe completed background agents in environment panel (#7929)

getEnvironmentAgentTasks correlated a transcript tool card with the live
/tasks snapshot only on toolUseId, the notification taskId, and a
<subagentType>-<callId> derived id. A completed background agent can lose
that linkage (its live task carries no usable toolUseId and its daemon id
is general-purpose-<internalId>), so the trailing loop appended the live
task as a second entry. Add a conservative content fallback (prompt, or
description+subagentType) mirroring the daemon's legacy resolver.

* feat(web-shell): support side tasks during active turns

* fix(web-shell): deduplicate completed subagents and gate sourceType on capability (#7929)

* fix(web-shell): restore background agent reconciliation and fix agent dedupe (#7929)

Restore the one-shot subagent reconciliation for inline background Agent tool
cards. Persisted notification records do not always retain a toolUseId, so the
SSE discrete-notification path alone can leave a card stuck in Running; the
documented fallback resolves pending cards through the subagent endpoint after
catch-up, reconnect, and terminal notifications.

Also stop the loose description content fallback in getEnvironmentAgentTasks
from claiming a live task that another transcript tool call already links
precisely (by toolUseId, message taskId, or derived id). Two agents sharing a
description previously collapsed into one: the fallback stole the linked task,
its owner re-matched the same task, and the orphan was dropped.

* fix(web-shell): address critical review feedback on context panels (#7929)

* fix(web-shell): reconcile side-task state across sessions and listings (#7929)

* fix(web-shell): preserve contextual panel fallbacks

---------

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
2026-07-30 13:45:30 +00:00
jinye
c50120985b
fix(serve): Prevent repeated workspace skill rescans (#8080)
* fix(serve): prevent repeated workspace skill rescans

Make workspace skill status reads use committed snapshots and move refresh work to explicit mutation paths. Add generation-safe daemon caching, conditional HTTP responses, SDK revalidation, and multi-session extension refresh safeguards.

Refs #8079

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(serve): narrow the workspace-skills read model and close its regressions

Follow-up to the previous commit on this branch, from reviewing it.

Subtractions — these were separable from the fix and carried more surface
than value, so they move out of this change:

- Revert the ETag / If-None-Match layer (CORS allow+expose headers, the SDK
  conditional JSON cache, the browser bundle budget bump). Express already
  emits an ETag and answers 304 for these routes, so the only new behavior
  was the SDK cache. It saves transfer bytes but no daemon work — the ETag is
  a hash of the already-serialized body — and it shipped without a paired
  `Cache-Control`, which is what actually keeps an intermediary from serving
  a stale snapshot of an authenticated, mutable resource. The SDK cache was
  also unbounded, with no eviction or clear entry point.
- Revert moving `extensions_final` ahead of skill initialization in
  `Config.initialize`. In non-safe, non-bare mode `extensions_initial` is
  already the same argument-less `refreshCache()`, and it runs
  `applyStoreActivation`, so `getActiveExtensions()` is fully populated
  before skills are enumerated either way. The move changed only startup
  event order (and pushed permissionManager past the extension refresh) for
  every surface including the interactive CLI.

Regression fixes — the read went pure, but two of its inputs lost their only
path back to disk:

- Extension sources have no watcher, unlike skills. With the per-read
  `extensionManager.refreshCache()` gone, an extension installed, removed,
  enabled, or disabled outside the daemon would never reach the snapshot
  until the child restarted — and because extension-level skills are derived
  from the extension set, a skill-watcher tick could not recover it either.
  Adds `ExtensionManager.refreshCacheIfSourcesChanged()`: a stat-based
  fingerprint over the extension directory entries, each manifest, the
  enablement file, and the store state, which refreshes only when they moved.
  A status read pays one readdir plus one stat per entry instead of a
  directory scan and a full parse, and stays self-healing.

  The baseline is the pre-load fingerprint, so a change landing during a
  refresh stays visible to the next check instead of being masked by a
  post-load stat. The directory and store halves are captured at different
  points because a refresh writes the store itself but never the manifests.

- Revalidation is skipped in safe and bare mode, and the whole of it —
  including that mode check — sits inside its error boundary. Those modes never
  populate the extension cache by design, while the snapshot derives extension
  skills from `getExtensions()`, so revalidating there would have loaded the
  extensions the mode exists to exclude. Keeping the mode check outside the
  boundary would also have let a config missing those accessors fail a read.

- `initialized: true` with an empty list when the config has no
  `SkillManager` is now `initialized: false`. The daemon latches any
  initialized answer into `lastWorkspaceSkillsStatus` and then prefers it
  over its own local enumeration, so the old value could suppress the
  fallback permanently.

Also:

- The retained-snapshot path bumped the freshness timestamp without checking
  its generation, so a read that started before an invalidation could push
  out the TTL of a snapshot a later read had committed — letting a
  post-mutation snapshot go unrevalidated for longer than the window.
- `setWorkspaceSkillEnabled` folded `configsFailed` into `sessionsFailed`,
  but it sends `reason: 'settings'`, which never refreshes a skill cache, so
  the term was structurally zero. Report `configsFailed` from the `content`
  path instead, where it can actually be non-zero.
- Documents the settings-freshness gap this read model accepts: enablement
  now comes from the child's in-memory `LoadedSettings`, which `SettingsWatcher`
  keeps current for the User and Workspace scopes but not for System /
  SystemDefaults (locked-skill policy) or an untrusted workspace.

Tests: adds a real-filesystem guard that drives 50 consecutive cached reads
and asserts zero additional readdir/readFile calls — the mocked suites could
only prove `refreshCache` was not *called*, which is not the invariant that
broke. Adds coverage for the fingerprint gate (steady state, install,
removal, in-place manifest edit, concurrent callers, and the mid-refresh
race), for the null-manager, moved-sources, and safe/bare-mode read paths, and
for the generation guard. The generation-guard and safe/bare-mode tests were
each verified to fail with their fix reverted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 12:52:37 +00:00
jinye
f3ad4fcffb
feat(serve): page large text files by byte cursor (#8002)
* fix(serve): allow bounded reads of large text files

* fix(serve): bound large-text reads by scan cost, not by which knob was set

Follow-up to the bounded large-text read path. Three changes:

Gate on any explicit window argument, not on `limit`. Gating on `limit`
had the cost model backwards in both directions: `{ line: 900_000_000,
limit: 20 }` was admitted despite walking the whole file, while
`{ maxBytes: 4096 }` — satisfiable from the first 4 KiB — was refused. A
read with no window argument at all still fails, since a caller that
believes it holds the whole file may write it back truncated.

Add MAX_TEXT_SCAN_BYTES (8 MiB). MAX_READ_BYTES caps what a read
returns; nothing capped what it cost. Line offsets are resolved by
scanning from byte 0, so a query param could turn into an
uninterruptible multi-second scan of an arbitrarily large file — and on
Windows hold a read handle for that span, blocking renames and deletes.
Past the budget the read is refused with `file_too_large` pointing at
readBytes, which reaches any offset in O(1).

Tolerate appends on streamed windows. Requiring whole-file size/mtime
stability after reading a prefix rejected reads whose returned bytes
were still valid, and the case it rejected — tailing a live log — is the
one this path exists for. Streamed windows now assert inode identity
plus "did not shrink"; truncation and replacement are still rejected.

Also: non-UTF-8 large text now returns `binary_file` rather than
`file_too_large`, so a client retrying on 413 with a smaller window
can't loop forever; and `readFileWithLineAndLimit` throws instead of
silently ignoring a caller-supplied `fileHandle` on the by-path
fallback.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor(core): thread the descriptor instead of forking text-read helpers

PR #7947 pinned large-text reads to one inode by threading a caller-owned
FileHandle into readTextRange as an optional field, plus a second field,
forceStreaming, to suppress the buffering fast path. Two optional fields
produced four combinations: one meaningful, one used by a single test, one
unreachable, and — in readFileWithLineAndLimit — one that silently fell
through to a by-path read, defeating the reason the caller opened a handle.

Unify the two encoding detectors. detectFileEncoding now takes a path or a
borrowed handle, so detectFileHandleEncoding is deleted along with the
message discrepancy between them: an encoding iconv-lite cannot load now
raises LargeNonUtf8TextError naming that encoding rather than deferring to
the decoder's generic invalid-utf8 variant. Both still refuse the file, and
the Serve boundary maps both to binary_file.

Split the reader into readTextRange (path) and readTextRangeFromHandle
(always streams, both byte bounds required). The unreachable combination and
its untested readFileHandleBuffer are gone, and with no fileHandle parameter
left for readFileWithLineAndLimit to ignore, the RangeError guarding that
fallthrough is deleted too — the trap can no longer be expressed.

CoreReadTextFileHandleRequest drops its required stats field. Nothing
downstream read it, and because the ACP request type it extends permits
extra properties, TypeScript accepted the dead argument silently.

readFileHandleChunks becomes chunksFromHandle(fh, from) — the one seam
byte-cursor text paging needs.

No observable change at the Serve boundary: its 222 tests pass unmodified.
Two fileSystemService tests were deleted rather than repaired; they asserted
the arguments readFileWithLineAndLimit received, which is nothing once the
handle path stops calling it. Their coverage lives in read-text-range.test.ts
against real files and in workspace-file-system.test.ts at the real boundary.

258 production lines in core, net -71 overall.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor(core): make CoreReadTextFileHandleRequest standalone

Self-audit follow-up to f55c867a. Two fields survived the reshape that the
handle path never reads:

- `stats` was documented as required ("must pass the Stats captured from that
  handle") and nothing downstream read it. The handle path always streams, so
  it never needs a size to choose a strategy, and the encoding probe does its
  own fstat.
- `path` became dead once readTextRangeFromHandle replaced the path-plus-handle
  call. Errors are labelled with the path by the Serve boundary that owns it.

Neither was caught by the compiler: the ACP ReadTextFileRequest the type
derived from permits extra properties, so the CLI kept passing both silently.
That is the argument for declaring the type standalone rather than Omit-ing
four of six inherited fields and quietly re-admitting the rest.

Also record the second behaviour delta of the detector merge in the design
doc: detectFileEncoding catches I/O errors and falls back to 'utf-8', where
detectFileHandleEncoding let them propagate. The failure is not lost — a handle
that fails the 8 KiB probe fails the streaming read immediately after — but a
different call now reports it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* feat(serve): page large text files by byte cursor

Line offsets address a byte stream, so `readText` resolves them by scanning
from byte 0. Paging a large log that way is O(n^2) across pages, and past
MAX_TEXT_SCAN_BYTES (8 MiB) a deep page is refused outright — agents had no
O(1) path short of dropping to GET /file/bytes and splitting lines themselves,
losing encoding handling, multibyte safety, and the binary_file refusal.

A response that leaves content behind now returns `hasMore`, and where a file
byte offset is derivable, an opaque `nextCursor`. Passing it back as `cursor`
resumes in O(1). Page 1 is an ordinary `limit` read, so clients never compute
byte offsets themselves, and a paging loop does not break when a file happens
to be small.

The cursor is unsigned base64url JSON carrying {off, size, dev, ino}, matching
encodeOrganizedCursor rather than the HMAC-signed transcript codec: the path is
re-resolved through the workspace boundary on every request, so a forged cursor
can only move the offset within a file the caller may already read — what
GET /file/bytes?offset= allows today. What the payload is for is staleness:
a replaced or truncated file yields hash_mismatch instead of bytes from the
wrong place, while an append leaves an outstanding cursor valid — the case the
feature exists for.

Every minted cursor points at the start of a line. When a single line exceeds
maxOutputBytes the reader emits a truncated prefix and skips to the next line
rather than resuming mid-line, because a mid-line cursor makes the following
page snap forward and silently drop the rest of that line at the seam. Windows
cut mid-line by a byte cap therefore report hasMore with no cursor, as do
non-UTF-8 snapshot reads whose decoded text is a UTF-8 re-encoding with no
mapping back to file offsets. That is why hasMore is a field rather than a
restatement of nextCursor.

Cursor reads branch before the size check, not by widening the window gate:
a cursor read of a file under MAX_READ_BYTES would otherwise land on the
snapshot path, which knows only line/limit, and silently return line 0.

Adds the workspace_file_read_cursor capability, per the convention that new
behavior gets a new tag, and retargets the scan-budget hint at cursor paging.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(core): advance UTF-8 cursors after truncation

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* docs(serve): clarify cursor bootstrap limits

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(sdk): raise daemon browser bundle budget

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* test(serve): cover ACP cursor dispatch and cursor binary_file mapping (#8002)

* fix(core): only set sawCrlf for emitted lines in cursor paging (#8002)

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
2026-07-30 12:07:05 +00:00
zjgzx1988
953c9d8177
feat(core): tag UserPromptSubmit hook context and record display provenance (#7956)
* feat(core): tag UserPromptSubmit hook context and record display provenance

UserPromptSubmit additionalContext was appended to the request as a bare
text part and persisted verbatim, so hook-injected text was
indistinguishable from user-authored text in the transcript, polluted
resumed sessions, telemetry, and auto-memory recall queries.

- Wrap injected context in a reserved
  <qwen:user-prompt-submit-context> tag (hook output already escapes
  angle brackets, so the tag cannot be forged from inside).
- Record the pre-injection user prompt as systemPayload.displayText plus
  the injected string as hookContext on the user record; the model-bound
  message stays verbatim for faithful resume replay.
- Use the pre-injection prompt text for telemetry prompt attributes and
  managed auto-memory recall.
- Resume projection prefers displayText, strips a trailing whole-part
  tagged block when no payload exists, and leaves legacy bare-injected
  records unchanged.
- Apply the same tag wrapping on the ACP session injection path, which
  already records the pre-injection prompt.

Closes #7940

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs: note UPS promptText TDZ ordering and sole-part resume guard

Document the conflict-resolution constraint that promptText must be
declared before the injection assignment, and the sole-part read-path
guard that keeps a user-authored whole-tag message intact.

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(cli): cover at_command resume with tagged UPS context

Confirm the at_command branch still prefers payload.userText when a
paired user record carries a trailing tagged hook-context part, and
falls back to the tag-stripping projection only when userText is absent.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(core): address PR 7956 review findings and Goal recording spy

Omit the optional UserPromptRecordPayload third arg when no hook
injected, so Goal admission spies expecting two args stay exact and
CI client-goal.test.ts passes.

Project plain UserPromptSubmit-augmented records through
transcript-replay with the same displayText / trailing-tag strip
fallback as the TUI, covering ACP/export surfaces. Strengthen the
displayText preference fixture so it disagrees with the tag-strip
path, and use the named UserPromptRecordPayload type in resume.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(acp-bridge): import UPS tag helper via Node-free package export

transcript-replay is inlined into the browser daemon/transcript SDK
bundle. Importing isUserPromptSubmitContextPartText from the core
package barrel pulled the whole Node-bound core graph into that
bundle and failed CI (esbuild Could not resolve "node:*") across
Test, web-shell E2E, and Real daemon E2E.

Export the pure helper as @qwen-code/qwen-code-core/userPromptSubmitContext
and import that path instead.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(test): alias userPromptSubmitContext for Vitest source resolution

CLI and acp-bridge Vitest configs already map goalWire/transcriptRecords
to TypeScript sources; without the same alias the new package export
fails import analysis and breaks dozens of CLI suites.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(acp-bridge): keep images when projecting displayText user records

Preferring UserPromptSubmit displayText previously returned early and
skipped projectMessageParts, dropping multimodal inlineData. Rebuild
parts so displayText replaces text while images keep their order.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(core): drop unused hookContext and cover image-only displayText

UserPromptRecordPayload.hookContext had no read sites; keep displayText
only and recover injected text from the tagged message part. Also cover
the image-only !replaced append path and simplify the recording guard.

Co-authored-by: Cursor <cursoragent@cursor.com>

* test: cover remaining UserPromptSubmit provenance Suggestions

Share stripTrailingUserPromptSubmitContextPart between TUI resume and
ACP replay, assert ACP Session tags additionalContext, and lock
telemetry to the pre-injection prompt text.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-30 11:45:23 +00:00
ytahdn
81367b562c
fix(web-shell): make question submission retryable (#8096)
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-07-30 08:58:12 +00:00
ytahdn
0c0bc5e92a
fix(web-shell): add prompt send retry feedback (#8106)
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-07-30 08:49:43 +00:00
易良
f005f3eee8
feat(github-channel): add transient working reaction (#8061)
* feat(channels): acknowledge GitHub requests

* fix(channels): remove transient GitHub reactions

* test(github-channel): cover reaction failures

* test(github-channel): cover pending reaction dedup

* docs(github-channel): clarify final-only output

---------

Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-30 03:00:29 +00:00
Shaojin Wen
0a9db38221
feat(review): add review run — headless review with a machine-readable verdict (#7983)
* feat(review): add `review run` — headless review with a machine-readable verdict

The review pipeline already runs non-interactively: `qwen --prompt "/review …"`
expands the bundled skill, launches the dimension agents, and honors the
approval mode. What that path lacks is a contract. The verdict lives in the
model's prose and in files whose names the caller must simply know, the exit
code says nothing about the outcome, and piped stdin silently defeats
slash-command detection (the runner prepends piped input, so the leading `/` is
no longer first). Anyone who wants "run a review, tell me what it decided" ends
up scraping a terminal.

`qwen review run [target]` is that contract and nothing more. It assembles the
/review invocation from typed flags (--effort, --comment), re-enters this
build's own CLI in a child process with stdin closed, streams the child's
progress to stderr, and then reads the verdict from the artifact compose-review
wrote — the same JSON the skill treats as the verdict authority — never from
anything the model printed. stdout carries only the result (human lines, or the
full JSON with --json).

Exit codes make the outcome scriptable without parsing: 0 = the review
completed (whatever it decided), 1 = it never reached a verdict (child failure,
timeout, or no composed artifact — a clean child exit without one is a run that
wandered off, not an approve), 3 = completed AND --fail-on request-changes AND
the event is REQUEST_CHANGES, so a CI gate can tell "blocking verdict" from
"the tool broke".

Artifact discovery is scoped to this run (mtime cutoff with a small slack for
coarse filesystem clocks): a stale composed JSON from an earlier review says
whatever THAT review decided, which is exactly the wrong thing to republish.

* fix(cli): harden review run against EPIPE, target injection, and drift (#7983)

- Use writeStderrLineSafe in the timeout and spawn-error handlers and guard
  the progress stream, so an EPIPE on stderr can no longer skip the child
  kill, hang the promise, or orphan the review.
- Reject a review target carrying whitespace or a leading dash before it is
  re-tokenized by the child CLI (e.g. `123 --comment` silently authorising
  posting).
- Constrain --approval-mode to the same choices as the top-level CLI.
- Capture the child's exit signal and surface it (OOM/SIGKILL vs spawn fail).
- Sync the top-level `qwen --help` review description with the command.
- Register `run` in the review.test.ts subcommand expectation and add tests
  for the timeout branch, the readComposed guard, and target rejection.

* fix(cli): kill process group on review run timeout, harden edge cases (#7983)

The CLI relaunches itself in a child process (for --max-old-space-size),
so child.kill() only reached the relaunch wrapper — the real review was
reparented to PID 1 and kept burning API calls. Spawn with detached:true
and kill the process group (-pid) so the timeout actually terminates the
review.

Also: clamp negative --timeout-minutes to a 1-minute floor, distinguish
a corrupt composed artifact from a missing one in human-readable output,
and add test coverage for the default (non-JSON) output path.

* fix(cli): use specific MockInstance type for process.kill spy (#7983)

* fix(cli): capture review run verdict before cleanup, forward signals (#7983)

* fix(cli): reject quoted review targets, pin signal forwarding (#7983)

* fix(cli): keep captured review verdict when timeout fires after compose (#7983)

---------

Co-authored-by: verify <verify@local>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: qwen-code-bot <qwen-code-bot@users.noreply.github.com>
2026-07-30 02:40:10 +00:00
易良
2abfa3d54e
fix(core): preserve active Todo context across tool turns (#7919)
* fix(core): preserve active Todo context across tool turns

* test(cli): update automatic turn prompt expectation

* fix(core): preserve Todo ownership across automatic turns

* fix(core): preserve Todo ownership at prompt boundaries

* test(todo): cover automatic reminder boundaries

* fix(core): throttle active Todo reminder re-injection to bound history growth

Every injected reminder copy lands permanently in chat history, so per-turn
injection grew the live context linearly with tool turns. Tool-turn injection
now re-issues the reminder only every third tool turn since the state was
last presented; turn-start injections always fire and reset the cadence. The
payload becomes a compact status/content line list capped at 800 characters.
History stays append-only, so provider prefix caching is unaffected.

Also: cover the new-ordinary-prompt-clears-stale-reminders invariant on the
real Config, add TUI coverage for the work-chain notification batch split,
cover todoWorkChainId continuation forwarding, and document the deliberate
enterWith binding in the daemon tool runner.

* fix(core): keep todo reminder before drained input

---------

Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-30 01:33:40 +00:00
易良
3d5924bd2f
fix(github-channel): validate and document reasonFilter (#8035)
* feat(github-channel): add reasonFilter config to skip unwanted notification reasons

Adds an optional `reasonFilter` allowlist to the GitHub channel config.
When set, notifications whose `reason` is not in the list are skipped
before any lane dispatch, reducing unnecessary API calls and agent work
for notification types the operator does not care about.

- New `reasonFilter?: string[]` field on `GithubConfig`
- O(1) Set lookup (`reasonFilterSet`); undefined = no filter (all reasons)
- Early-skip in the poll loop, before subject URL extraction and lane dispatch
- Two tests: filtered reasons skipped, unset filter processes all

Default behavior is unchanged (undefined = process all reasons).

* fix(channels): log github reason filter skips

* fix(channels): validate github reason filter

* fix(channels): address github reason filter comments

* fix(github-channel): reject invalid reason filters

* fix(github-channel): validate reason filters on connect

---------

Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
2026-07-30 01:17:44 +00:00
jinye
1643a6c9ae
test(integration): Measure immediate prompt dispatch stages (#7994)
* test(integration): measure immediate prompt dispatch stages

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* test(integration): cover update-level replay guard in user-echo matching (#7994)

* test(integration): exercise first-wins user echo latch in benchmark tracker (#7994)

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
2026-07-29 23:37:46 +00:00
jinye
58eb07117b
fix(serve): Add certified session writer handoff (#7976)
* fix(core): add certified session writer handoff

Seal managed writer ownership after a durable recorder drain and allow trusted replacements to take over only when the transcript proof still matches.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(core): retain writer claim after failed rollback

Keep the fixed transition claim unless the exact predecessor primary is restored, and avoid rollback after claim ownership changes or unlink completes with a reported error.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(core): close session handoff claim races

Wait for claim-aware primary candidates to back out of transition gaps, and release losing claims when no primary transition started.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(core): bound session handoff candidate waits

Fail closed when a claim-aware primary candidate is abandoned during a handoff transition, preserving the transition fence for authoritative recovery.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(core): reconcile session handoff proof edges

Reject dangling transcript paths and reconcile ambiguous lock-record link outcomes by exact bytes before continuing a certified handoff.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(core): preserve inspect error cause and document handoff fail-closed paths (#7976)

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-07-29 23:36:58 +00:00
易良
00fe203499
fix(channels): make GitHub final response publication single-shot (#8033)
* fix(channels): make GitHub publication single-shot

* fix(channels): include GitHub publication policy per turn

* fix(channels): retry final publication on GitHub 429

* fix(channels): complete GitHub publication audit metadata

* fix(github): preserve final publication diagnostics

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-07-29 23:15:04 +00:00
Dragon
18cb393e4b
feat(core): preload deferred tools within a context-window threshold (#7922)
* feat(core): preload deferred tools within a context-window threshold

Adds tools.toolSearch.threshold (default 10, percent of the context
window). At session start, when the combined estimated schema footprint
of every deferred tool - bundled built-ins and MCP alike - fits within
the budget, all are revealed upfront so the declaration list stays
stable for the whole session and prefix KV caches survive; otherwise
everything stays deferred. Set 0 to always defer. Mirrors Claude Code's
ENABLE_TOOL_SEARCH=auto threshold mode, extended to bundled deferred
tools because here every reveal rewrites the declaration list and busts
the prompt-cache prefix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(core): log deferred-tool preload budget decision

Emit debugLogger diagnostics in preloadDeferredToolsWithinBudget covering
the computed budget, estimated token footprint, candidate count, and which
branch of the all-or-nothing gate was taken (no candidates, over budget, or
preloaded). Lets an operator diagnosing session-startup cost tell from debug
logs whether the deferred set fit the budget or was left behind ToolSearch,
without adding temporary instrumentation. No behavior change.

* fix(tools): bound toolSearch.threshold to 0-100%

The threshold setting is a percentage of the context window but had no
upper bound, so a value like 200 (a typo or misreading of the "(%)"
label) made the preload budget exceed the whole window and
unconditionally preloaded every deferred tool — the opposite of the
prefix-stability the threshold buys.

- Add minimum:0/maximum:100 to the setting schema (jsonSchemaOverride,
  like autoCompactThreshold) and regenerate the VS Code settings schema.
- Add a symmetric runtime upper guard next to the existing
  'thresholdPercent <= 0' lower guard in client.ts, clamping to 100% so a
  hand-edited settings file cannot slip a larger budget past validation.

Adds a client test asserting a 200% threshold clamps to a full-context
budget.

* test(core): cover configured preload budget

* fix(tool-search): harden preload threshold

* test(tool-search): cover preload exclusions

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 23:01:01 +00:00
Dragon
6cfa25c967
fix(core): rebind fork capabilities on resume (#7927)
* fix(core): rebind fork capabilities on resume

* refactor(core): share fork parent-tool extraction and cover resume guards

Extract the duplicated parent-tool-name derivation (flatten function
declarations, drop EXCLUDED_TOOLS_FOR_SUBAGENTS, dedupe) into a shared
extractParentToolNames() helper in agent-core, used by both fork launch
(the Agent tool) and fork resume (resolveCurrentForkRuntime), so the two
paths cannot silently diverge when the extraction or exclusion logic changes.

Add tests for the two previously-uncovered resolveCurrentForkRuntime
early-return branches: (1) every advertised parent tool is excluded from
subagents, and (2) no advertised tool is still registered in the live
ToolRegistry. Both keep the fork paused with the current-runtime-unavailable
blocked reason.

* test(core): cover fork-resume runtime guards and add resolve diagnostics

Address review feedback on the fork capability-rebind path:

- Add a direct unit test for extractParentToolNames (agent-core.test.ts)
  covering cross-group flattening, dedup, EXCLUDED_TOOLS_FOR_SUBAGENTS
  filtering, empty/undefined name filtering, and undefined/empty config.
- Add a fork-resume test asserting the MCP, skill, and deferred-tool
  reminder branches of buildForkResumeCapabilityReminder are injected into
  the resumed task prompt (previously only exercised with empty data).
- Emit debug diagnostics at each early return in resolveCurrentForkRuntime
  (no_system_instruction / no_advertised_tools / no_registered_tools) so a
  paused fork's blocking cause is distinguishable in logs.

* fix(core): address fork capability review

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-29 22:59:14 +00:00
Nothing Chan
a771e4449e
fix(channels): reject unusable GitHub self-allowlists (#8055) 2026-07-29 15:48:56 +00:00
Mark Xian
c19d321d1f
feat(github-channel): filter notification reasons (#8031) 2026-07-29 15:34:16 +00:00
qqqys
c97026040e
feat(channels): add pairing approval management API (#8045)
* feat(channels): add pairing approval management API

* fix(sdk): expose pairing approval types

Re-export the new approval and revocation types from the public SDK entry, and pin the qualified workspace DELETE request body in regression coverage.

---------

Co-authored-by: qwen-code-dev-bot <269191875+qwen-code-dev-bot@users.noreply.github.com>
2026-07-29 14:55:03 +00:00
OrbitZore
ec9c36ef82
feat(channels): add GitLab polling channel adapter (#7862)
* feat(channels): add GitLab polling channel adapter

Poll GitLab todos via @gitbeaker/rest, dispatch notes through the
existing PollingChannelBase pipeline. Key design points:

- action_prompt_template config drives event filtering and metadata
  rendering (unconfigured actions are skipped)
- Per-repo cursor (repo[chatId].last_read) as notes window lower bound,
  global lastProcessedAt for todo-level dedup
- mark_done after successful processing; failure skips mark_done for
  retry on next poll
- Mention gating delegated to base GroupGate (adapter only sets
  isMentioned flag)
- First-contact body fallback for todos with no notes (e.g. mention in
  issue description)

* fix(channels/gitlab): persist cursor after each successful todo

Call saveCursor() immediately after advancing lastProcessedAt so that
progress is durable even if the process crashes mid-poll. Also removes
the local watermark variable in favor of direct assignment.

* fix(channels/gitlab): persist cursor on every advancement including skips

* fix(channels/gitlab): address review critical issues

- Remove non-functional proxyAgent (gitbeaker doesn't support it)
- Construct repo_url from host + path (API doesn't return web_url)
- Handle directly_addressed action (falls back to mentioned template)
- First-contact fetches target description instead of using todo.body
- Move todo.project dereference inside try block
- Filter confidential notes
- Update channel-registry.test.ts for gitlab entry

* fix(channels/gitlab): address review suggestions

- Warn on connect if action_prompt_template is not configured
- Guard todo.target.iid before use
- Skip paths now mark_done (best-effort) to clean GitLab UI
- Remove postErrorComment (avoids duplicate comments on retry)
- Fetch only first page of notes (desc, maxPages:1, perPage:100)
  instead of paginating entire note history
- Extract fetchRecentNotes for single-page windowed enumeration

* refactor(channels/gitlab): simplify to todo.body dispatch, add description mention support

- Remove notes API fetching; dispatch todo.body directly
- Detect description mentions via target_url anchor (#note_ absence)
- Always fetch target description for %description% metadata
- Remove per-repo cursor; dedup via cursor + mark_done only
- Cursor advances regardless of success/failure (no retry)
- Use zod for cursor validation
- Rename template vars to GitLab terminology:
  %project% %project_url% %target_type% %iid% %title% %description% %todo_id%
- Support %% escape for literal percent

* docs(channels): add GitLab adapter documentation

- New user guide: docs/users/features/channels/gitlab.md
- Update _meta.ts navigation
- Update developer adapter matrix and SDK list

* fix(channels/gitlab): use correct Issues.show(issueIid, { projectId }) signature

* chore: regenerate NOTICES.txt for new gitlab channel dependencies

* fix(channels/gitlab): address review suggestions

- Add todo.project null guard (item 2)
- Single-pass regex for %% escape + %var% substitution (item 4)
- sendThreadMessage throws directly on undefined threadId (item 5)
- Dedup fetchDescription with per-poll cache (item 6)
- Remove per-todo saveCursor; base class saves after pollOnce (item 7)
- Add undefined threadId test (item 8)
- Expand confidential notes limitation in docs (item 3)

* test(channels/gitlab): add mention tests, directly_addressed coverage, skip assertions, temp cleanup

- New mention.test.ts: 14 cases for testBotMention/stripBotMention/escapeRegex
- Add directly_addressed fallback test
- Skip tests now assert TodoLists.done + cursor advancement
- afterEach cleans up mkdtempSync temp dirs

* fix(channels/gitlab): address review round 4

- Non-mention actions (assigned, etc.) set forceMentioned=true to bypass GroupGate
- Merge dead note-filter tests into single 'skips todo authored by bot'
- Log fetchDescription errors to stderr instead of silent swallow
- Post error comment on issue/MR when handleInbound fails (best-effort)

* fix(channels/gitlab): always force isMentioned=true, remove regex re-derivation

The action_prompt_template config is already the event filter, and
GitLab has already decided the mention when creating the todo.
Re-deriving isMentioned via regex on todo.body causes permanent
message loss when the regex misses (description mention + fetch
failure, group mentions). Always set forceMentioned=true so
GroupGate never drops a todo that passed the template filter.

* fix(channels/gitlab): propagate fetchDescription errors for description mentions

For note mentions, description is metadata-only — fetch failure is
logged and swallowed. For description mentions, description IS the
message — fetch failure now propagates to the outer catch, which
posts the ⚠️ error comment so the user knows to re-mention.

* perf(channels/gitlab): clean up stale todos, skip unnecessary fetchDescription

- Mark stale todos (updated_at <= cursor) as done on each poll to
  prevent perpetual re-fetching of pre-existing pending todos
- Skip fetchDescription for note mentions when template does not
  contain %description%, saving one API call per todo
- Update docs: stale todo cleanup, error comment on failure

* docs(channels/gitlab): clarify requireMention is bypassed, template is the real filter

* Apply suggestions from code review

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>

* fix(channels/gitlab): use todo ID cursor instead of timestamp to eliminate equal-timestamp loss

Timestamp-based cursors (second granularity) could silently destroy
todos sharing the same updated_at as the cursor boundary. Switch to
monotonically increasing todo IDs which are unique and collision-free.

Add initialized flag to preserve first-start drain semantics: pre-existing
pending todos are marked done without dispatch on the first poll cycle.

* fix(channels/gitlab): harden first-poll drain, add ordering tests, fix lockfile

- Replace Math.max(...spread) with reduce to avoid RangeError on large
  backlogs (~100k+ todos). Move initialized=true after the drain work so
  any throw retries the drain instead of falling through to dispatch.
- Add unit tests: identical-timestamp delivery and id-order-when-updated_at-disagrees
  (kills M2 sort mutant).
- Align lockfile: file:../base → ^0.21.0 for channel-base dep.

* fix(channels/gitlab): include dot in mention lookahead for GitLab usernames

GitLab usernames may contain dots (e.g. bot.name). The lookahead
character class inherited from GitHub omitted '.', causing @bot.name
to match as @bot. Add '.' to the negated class.

* docs(channels/gitlab): align docs with ID cursor and drain semantics

- Add first-poll drain as step 2 in How It Works
- Clarify GroupGate always passes (isMentioned forced true)
- Document initialized flag in Known Limitations

* Apply suggestions from code review

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>

* fix(channels/gitlab): align package version and channel-base dependency to 0.21.1

Bump version from 0.21.0 to 0.21.1 to match other channel packages after
upstream merge. Pin @qwen-code/channel-base to exact 0.21.1 instead of
^0.21.0, matching the convention used by other published channels.

* fix(channels/gitlab): regenerate lockfile to match package.json versions

Manually add only gitlab-related lockfile entries (workspace, @gitbeaker
packages, transitive deps, channel-gitlab link) without unrelated npm
normalization churn.

* test(channels/gitlab): add regression tests for first-poll drain hardening

Two tests that kill the M1 (Math.max spread RangeError) and M2 (flag
ordering) mutants which survived the original 46-test suite:

- 150k todo drain verifies reduce() handles large backlogs without
  RangeError and without dispatching
- Drain throw verifies initialized stays false so the next poll retries
  the drain instead of falling through to dispatch

Test file duration: ~40ms → ~170ms.

* docs(channels/gitlab): clarify groupPolicy must be "open" and add runtime warning

The default groupPolicy "disabled" silently drops all mentions — todos are
marked done and cursor advances, but no dispatch occurs. Fix misleading docs
that said "GroupGate always passes" (only true at groupPolicy: "open") and
add a connect()-time warning when groupPolicy is not "open".

* fix(channels/gitlab): correct xcase integrity hash in lockfile

The manually added xcase entry had a typo in the sha512 hash (ys → ks),
causing npm ci EINTEGRITY failures in CI.

* fix(channels/gitlab): correct requester-utils integrity hash in lockfile

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(channels/gitlab): allow groupPolicy "allowlist" in warning and docs

The groupPolicy warning and docs incorrectly stated that groupPolicy
must be "open". In reality "allowlist" with the project listed also
works because isMentioned is forced true and GroupGate only requires
the group to be listed. Also fix the inaccurate "no error is logged"
claim — ChannelBase logs preflight rejected reason=group_disabled.

Fixes R5-🟡3 from PR #7862 review.

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-29 14:28:31 +00:00
samuelhsin
26600896d5
feat(web-shell): add split pane header action slot with overflow (#7808)
* feat(web-shell): add split pane header action slot with overflow

Let hosts render per-session actions in each split pane header, collapsing them into a … menu when the pane is too narrow.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(web-shell): add pane header actions PR screenshots

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web-shell): tighten pane header overflow measurement

Drop the per-render children effect dependency that rebuilt ResizeObserver during streaming, and reserve workspace-tag width when computing available header space.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web-shell): address pane header overflow review blockers

Mount host actions in only one tree, and wrap overflow entries as DropdownMenuItems so Radix selection and keyboard navigation work.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web-shell): keep pane header actions alive across overflow

Flatten Fragment host actions before building the overflow menu, and keep the same host instances mounted when collapsing so stateful actions are not reset.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web-shell): address pane header overflow review suggestions (#7808)

* fix(web-shell): proxy overflow clicks via action slots

Wrap host pane actions in stable slots so the overflow menu can activate interactive descendants without requiring opaque custom components to forward internal data attributes.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web-shell): address overflow menu review suggestions (#7808)

* fix(web-shell): harden pane header overflow actions (#7808)

Restore the 8px gap between the built-in maximize/close controls, ignore
aria-hidden glyphs when labelling overflow items, omit non-interactive
children from the overflow menu, and document the popover constraint on
renderHeaderActions. Refreshes the design doc to match the mount-once
implementation.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
2026-07-29 13:06:48 +00:00