Commit graph

1197 commits

Author SHA1 Message Date
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
sunday
aac663f28a
feat(hooks): add security.allowPrivateNetworkHooks to bypass SSRF range checks for trusted scopes (#7968)
* feat(hooks): add security.allowPrivateNetworkHooks to bypass SSRF range checks for trusted scopes

HTTP hooks hard-block all private/link-local address ranges via ssrfGuard,
which makes them unusable in platform-managed environments where the hook
receiver is a first-party, VPC-internal endpoint (e.g. an internal API
gateway resolving to 172.16.0.0/12).

Add an opt-in setting, security.allowPrivateNetworkHooks (default false),
that skips the SSRF IP-range checks in urlValidator.isBlocked (literal IPs)
and validateResolvedHost (literal + post-DNS-resolution paths).

Security properties:
- Honored only from User/System/SystemDefaults scopes; the value is
  stripped from Workspace settings during the merge (with a startup
  warning), so a cloned repository can never self-grant the bypass.
- BLOCKED_HOSTS (169.254.169.254, metadata.google.internal, ...) remains
  blocked even when the flag is on.
- Default false keeps every code path byte-for-byte compatible with
  current behavior; bare/safe mode forces it off.

* fix(hooks): enforce metadata endpoint blocklist regardless of allowPrivateNetworkHooks

Address review findings on #7968: with the flag on, cloud metadata
endpoints were reachable through gaps in the relaxed checks.

- ssrfGuard: add METADATA_IPS (169.254.169.254, 100.100.100.200) and
  isMetadataAddress(), which normalizes IPv4-mapped IPv6 forms
  (::ffff:a9fe:a9fe, ::ffff:6464:64c8, ...) via the existing
  extractMappedIPv4/expandIPv6Groups helpers.
- urlValidator.isBlocked: BLOCKED_HOSTS matching and the literal-IP
  isMetadataAddress check now run unconditionally; only the general
  range check (isBlockedAddress) is relaxed by the flag.
- httpHookRunner.validateResolvedHost: no longer returns early with the
  flag on — DNS resolution still runs and resolved addresses are checked
  against isMetadataAddress, so a hostname resolving to a metadata
  endpoint is blocked. DNS failures still defer to fetch, as before.
- settings warning text now lists User/System/SystemDefaults, matching
  the schema and docs.
- docs: precise wording — the flag relaxes only range checks; metadata
  endpoints stay blocked in all serialized forms and after DNS resolution.

The flag now opens RFC1918/CGNAT/link-local ranges only; cloud metadata
endpoints (169.254.169.254, 100.100.100.200 in any form, plus the
BLOCKED_HOSTS hostnames) are unreachable in every configuration.

---------

Co-authored-by: 欢伯 <ri.xur@alibaba-inc.com>
2026-07-29 13:04:45 +00:00
ytahdn
59d2ebc851
fix(webui): stabilize history pagination (#8001)
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-07-29 08:13:46 +00:00
ytahdn
6672573433
fix(web-shell): reduce composer input latency (#8015)
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-07-29 08:06:53 +00:00
jinye
4615f84d73
fix(serve): allow bounded reads of large text files (#7947)
* 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>

* fix(serve): harden large text range snapshots

Treat caller-owned file handles as bounded streaming reads, cap them to the captured file size, and reuse the chunk buffer.

Restore strict Serve snapshot stability and align returned-slice metadata with the full-snapshot path.

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

* fix(serve): make large text ranges snapshot-safe

* fix(serve): harden large-text ctime tests and document buffer reuse (#7947)

Address review feedback on the large-text range read PR:

- Pause before restoring mtime in the two ctime-dependent mutation tests so the change-time advances past the pre-read snapshot even on coarse-resolution filesystems, removing a latent flake in the same-size-overwrite precondition. The assertions are unchanged.

- Document at the readFileHandleChunks yield site that the 512 KiB buffer is reused across iterations, so yielded views must be decoded or copied before advancing the generator.

* docs(serve): soften same-size rewrite guarantee to coarse-clock best-effort (#7947)

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
2026-07-29 07:49:51 +00:00
ytahdn
f485970d61
feat(web-shell): refine advanced table controls (#7999)
Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-07-29 07:37:30 +00:00
BaboBen
27428e29e7
feat(channels): add DingTalk interactive cards (#6930)
* docs(channels): design DingTalk interactive cards

* docs(channels): refine DingTalk card boundaries

* docs(channels): map other IM impact

* docs(channels): add other IM extension blueprint

* docs(channels): refine DingTalk card architecture

* docs(channels): tighten DingTalk card contracts

* docs(channels): align card settlement contract

* docs(channels): clarify card settlement behavior

* docs(channels): finalize DingTalk card design

* docs(channels): harden DingTalk card design

* docs(channels): finalize DingTalk card implementation contract

* feat(channels): add exact prompt run identity

* feat(channels): add structured user input presentation

* feat(dingtalk): add interactive card transport

* feat(dingtalk): stream exact-run status cards

* feat(dingtalk): answer structured questions with cards

* fix(channels): close interactive card race boundaries

* fix(dingtalk): preserve completed card content

* feat(dingtalk): coordinate interactive card segments

* docs(dingtalk): define status card runtime metadata

* docs(dingtalk): align status updates with stream flushes

* docs(dingtalk): plan runtime card metadata

* feat(dingtalk): finalize interactive card lifecycle

* fix(dingtalk): keep question cards responsive

* docs(dingtalk): define interaction isolation verification

* test(dingtalk): cover interaction isolation

* docs(dingtalk): define latest main alignment

* docs(dingtalk): plan latest main alignment

* fix(dingtalk): preserve images in status cards

* docs(dingtalk): refresh main alignment baseline

* docs(channels): define interaction compatibility hardening

* docs(channels): plan interaction compatibility hardening

* fix(channels): separate output segment ends

* fix(dingtalk): require interactive card opt-in

* fix(dingtalk): classify card callbacks

* fix(dingtalk): notify rejected card clickers

* fix(channels): settle user input on steer

* refactor(dingtalk): remove unused settlement state

* docs(dingtalk): clarify forbidden card feedback

* fix(dingtalk): harden interactive card callbacks

* fix(sdk): coalesce concurrent session cancellation

* fix(channels): harden DingTalk interactive cards

* docs(channels): refresh interactive card architecture diagrams

* fix(channels): sanitize terminal DingTalk card content

* docs(channels): correct output segment hook contract

* fix(channels): expire superseded DingTalk question cards
2026-07-29 07:32:53 +00:00
DennisYu07
1b5c36ce15
ci: add isolated DSW SWE-bench release pipeline (#7656)
* ci: add isolated DSW SWE release pipeline

* ci: bootstrap branch-only DSW full-suite test

* Revert "ci: bootstrap branch-only DSW full-suite test"

This reverts commit 76c64c162a.

* ci: fix prerelease full-suite bootstrap

* ci: use REST API for DSW release writeback

* ci: grant DSW runner access to model config

* ci: dispatch DSW release benchmarks asynchronously

* ci: remove synchronous DSW runner path

* docs: record completed DSW full-suite validation

* Add benchmark cache preparation and retry backoff

* fix(ci): validate DSW cache permissions before dispatch

* fix(ci): gate release benchmarks by minor version

* docs: define bounded benchmark publication gate

* docs: score valid grader results

* fix(ci): address DSW benchmark review feedback

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-07-29 06:35:58 +00:00
Heyang Wang
2e14fa49d6
feat: robust ripgrep (#7888)
* fix(core): improve ripgrep runtime reliability

Make ripgrep failures distinguishable from true no-match results so the
model avoids unsafe conclusions from partial or failed searches. Add a
narrow recovery path for confirmed worker-thread EAGAIN failures.

- Retry confirmed thread EAGAIN once with a single worker thread
- Treat exit code 1 as no-match only when both streams are empty
- Mark partial runtime results as incomplete, separate from display limits
- Add privacy-safe telemetry and focused coverage for recovery behavior

# Conflicts:
#	packages/core/src/utils/ripgrepUtils.test.ts

* fix(core): restore ripgrep runtime recovery tests

Restore the runRipgrep coverage that was lost during the rebase and keep
EAGAIN detection aligned with the runtime reliability design.

- Re-add coverage for strict no-match handling and incomplete output
- Verify single-thread retry behavior for confirmed EAGAIN failures
- Keep spawn, cancellation, timeout, and max-buffer paths covered
- Treat os error 11 as the short EAGAIN marker documented by the plan

* docs(core): document ripgrep recovery boundaries

Clarify the non-obvious runtime reliability edges around ripgrep recovery so
future changes preserve the intended narrow behavior.

- Document why only confirmed worker EAGAIN failures are retryable
- Explain incomplete-output handling for interrupted ripgrep output
- Note the privacy boundary for runtime recovery telemetry

* fix(core): correct exit-1 no-match gate for --json summary output (#7888)

* test(core): remove duplicate mockReset and add telemetry coverage (#7888)

* fix(core): address review feedback on ripgrep recovery semantics (#7888)

- Fix stale `truncated` property in test mock to match RipgrepRunResult
- Narrow `incomplete` flag to genuinely interrupted executions only
- Add test for exit code 1 with both stdout and stderr
- Add test for EAGAIN retry producing partial stdout
- Alias RipgrepRuntimeRecoveryFailureKind to RipgrepFailureKind

* docs(core): align exit-1 no-match spec with stderr-only gate (#7888)

* fix(core): mark exit-failed ripgrep searches with stdout as incomplete (#7888)

---------

Co-authored-by: heyang.why <heyang.why@alibaba-inc.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.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-07-29 06:08:22 +00:00
zhangxy-zju
1d55d290a0
feat(web-shell): render streaming charts with markdown-chart (#7916)
* feat(web-shell): use markdown-chart for streaming charts

* fix(web-shell): address markdown chart review feedback

* fix(web-shell): preserve legacy chart ref caching

* fix(web-shell): preserve chart safety and loader stability

* test(web-shell): strengthen markdown chart safety contracts

* test(web-shell): cover legacy chart streaming adapter
2026-07-29 06:04:56 +00:00
jinye
58797088be
feat(external-context): Add submitted-prompt auto recall (#7877)
* feat(external-context): add submitted-prompt auto recall

Add an opt-in Hook-only profile that derives bounded retrieval queries from submitted prompt provenance while preserving the existing on-demand MCP contract.

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

* fix(external-context): harden auto recall query sanitization (#7877)

Address review feedback on the submitted-prompt auto recall Hook:

- Bound the sanitizer input before the redaction regexes run so a
  worst-case prompt cannot drive the assignment regex into quadratic
  backtracking that blocks the event loop past the wall-clock budget.
- Test the whole assignment for secret names so a leading label such as
  "Deploy failed:" can no longer claim the match and leak an api_key=.
- Skip the interactive E2E under container sandboxes (docker/podman),
  matching the cron-interactive precedent.
- Restore real undici coverage for a malformed proxy environment value.
- Make the wall-clock-budget test exercise the internal timer rather than
  the provider timeout, and give the backtracking regression test a shape
  that actually backtracks.
- Clarify that the v2 top-level timeoutMs applies only to the on-demand
  MCP path, and note session-lifetime context accumulation in the design
  doc.

* fix(external-context): complete secret redaction, guard MCP config version (#7877)

Anchor the secret keyword to the name that owns the separator so a leading
prose label can no longer claim the match. This redacts spaced separators
(api_key = sk-...) and inline JSON ({"api_key": "..."}), and stops
over-redacting ordinary prose such as "readme: token refresh flow".

Also reject non-version-1 configs in runMcp with a clear startup error so an
auto-recall (v2) config cannot silently expose a second retrieval surface.

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
2026-07-29 05:21:29 +00:00
carffuca
54d3997add
feat(web-shell): suggest BTW for side questions (#7935)
* test(web-shell): define composer intent suggestions

* feat(web-shell): suggest btw for side questions

* test(web-shell): cover pasted image suggestion gating

* fix(web-shell): block btw suggestions for inline tags

* test(web-shell): verify inline attachment snapshots

* feat(web-shell): refine BTW intent suggestions
2026-07-28 15:55:09 +00:00
易良
dc2f61d910
feat(channels): dispatch GitHub notifications by reason (#7826)
* feat(channels): dispatch GitHub notifications by reason

Route each GitHub notification by notification.reason into one of five
lanes, instead of dispatching every new comment regardless of trigger:

- mention: only dispatch comments that actually @ the bot (noise reduction)
- review_requested (PR): fetch PR meta via pulls.get and dispatch a
  review-specific prompt, even with no new comments
- assign: fetch issue meta and dispatch a triage-specific prompt
- author/comment: aggregate the window's new comments into one check-and-
  respond prompt
- other reasons: generic fallback (current behavior)

Add cursor dedup via dispatchedComments (by comment node_id) and
dispatchedNotifications (by notification id), surviving a
markNotificationsAsRead failure that leaves the cursor un-advanced.

Closes #7807

* fix(channels): mark review_requested/assign envelopes as mentioned

GroupGate defaults to requireMention: true, which silently drops
isMentioned:false envelopes as 'mention_required'. The review_requested
and assign lanes are explicit directed triggers — the bot was asked to
review or assigned — equivalent to a mention, so set isMentioned: true
so they pass the gate instead of being inert on the documented default
config.

Addresses review Critical on #7826.

* fix(channels): resolve github routing review comments

* fix(channels): dedupe github meta lane comments

* fix(channels): conditional assign framing for PR threads

The assign route already detected PR threads to use pulls.get, but the
trigger framing text always read 'assigned to this issue' even for PRs.
Make it conditional so PR assignments read 'assigned to this pull request'.

* fix(channels): dedup meta lane dispatch inputs

* fix(channels): simplify GitHub reason dispatch

* fix(channels): respect mention gate for github aggregate lane

* fix(channels): truncate aggregate comment bodies by code points

Match the code-point-aware truncation already used for meta-lane bodies
so a supplementary-plane emoji at the MAX_COMMENT_CHARS boundary is not
split into a lone surrogate.

* fix(channels): harden GitHub dispatch failures, event window, and framing (#7826)

- Classify deleted/transferred subjects (404/410) as terminal so a single
  dead notification is logged and skipped instead of wedging the batch's
  mark-read and cursor advance every poll.
- Widen the review_requested/assign event search to the newest ~100 events
  by merging the preceding page when the last page is partial, instead of
  inspecting only the last page (which can hold a single event).
- Move the aggregate lane's untrusted-data warning to the head of the prompt
  text so it precedes the comment text it describes (metadata is appended
  after text by ChannelBase).
- Add regression tests: permanent-failure two-poll advance, terminal 404
  no-retry, multi-page event search, prompt caps, and the no-actor guard.

* fix(channels): drop lastReadAt filter in findMetaTrigger, add review coverage (#7826)

* fix(github): keep aggregate and meta windows bounded

* fix(channels): apply windowSince lower bound in findMetaTrigger (#7826)

* fix(channels): bound retry wedge, compute aggregate isMentioned, fix pairing pre-filter (#7826)

* fix(github): record dispatch before handler

* fix(github): persist skipped notifications

* fix(github): close dispatch retry loss cases

* test(github): cover cursor trim and meta floor validation

* fix(github): simplify notification reason dispatch

* fix(github): preserve batched dispatch comments

* fix(github): restore direct event dedup

* fix(github): preserve directed mention context

* fix(github): keep review fixes scoped

* fix(github): preserve delayed direct triggers

---------

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 <qwen-code@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-28 14:05:21 +00:00
callmeYe
63166bd544
feat(web-shell): honor voice hold mode (#7839)
* feat(web-shell): honor voice hold mode

* fix(web-shell): finalize held voice after connecting

* fix(web-shell): buffer voice while connecting

* test(web-shell): cover voice buffer overflow

* test(web-shell): add negative test for mouse click guard in hold mode (#7839)

* test(web-shell): add negative test for mouse click guard in hold mode (#7839)

* fix(web-shell): add recording-state pointercancel test and fix buffer error message (#7839)

* test(web-shell): add tap-mode pointer and non-primary button guard tests (#7839)

* fix(web-shell): clear start timeout in deferred-stop path (#7839)

---------

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-28 13:32:02 +00:00
ZevGit
ad1b5f3de1
fix(cli): default to virtualized terminal history (#5738)
* fix(cli): default to virtualized terminal history

* fix(cli): remove redundant alternate screen exit handler

* fix(cli): keep non-interactive output off VP mode

* fix(cli): stabilize VP tests in CI environments

* test(cli): resolve SDK daemon source in vitest

* fix(cli): normalize CI env checks for VP mode

* fix(cli): keep default VP mouse interactions enabled

* fix(cli): align VP mouse behavior with runtime state

* fix(cli): stabilize virtual viewport runtime state

* test(cli): cover virtual viewport fallbacks

* docs(cli): clarify virtual viewport requirements

---------

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>
2026-07-28 12:51:55 +00:00
VitaliBabkin
0afb48b1ea
fix(safe-mode): preserve caller-supplied top-tier MCP servers (#7827)
* fix(safe-mode): preserve caller-supplied top-tier MCP servers

Safe mode is meant to distrust LOCAL/ambient state (settings.json,
extensions, project .mcp.json) so a user can isolate which local
customization is misbehaving. It was also unconditionally dropping
topTierMcpServers -- the caller-supplied servers from an ACP
session/new's mcpServers field or --mcp-config -- which are an
explicit, per-invocation argument, not ambient local state.

The real gate turned out to be in packages/core/src/config/config.ts's
Config.getMcpServers() (the accessor mcp-client-manager.ts actually
reads for discovery), not just the mcpServers assembly in
loadCliConfig -- fixed both so the raw field and the accessor agree.
Also guarded the hot-reload path (hot-reload.ts) with the same
bare/safe-mode check, so a live settings.json edit can't smuggle local
servers into an already-running bare/safe-mode session.

Fixes #7819

* docs: clarify safe-mode's MCP servers note distinguishes local vs caller-supplied

Per CONTRIBUTING.md guideline 5 (docs for user-facing changes).

* fix(safe-mode): apply allowedMcpServers to top-tier servers, skip pendingMcpServers I/O under safe mode

Address Copilot's review of PR #7827:

- getMcpServers() now runs the safe-mode top-tier map through the same
  allowedMcpServers filter as the non-safe-mode path -- safe mode is
  not an exemption from a session's own --allowed-mcp-server-names
  upper bound (High severity finding, confirmed real).

- Re-added safeMode to pendingMcpServers' skip condition in
  loadCliConfig. Functionally a no-op either way (top-tier servers are
  never gated, #4615), but skips getMcpApprovals' local file read
  entirely under safe mode instead of doing a no-op read -- safe mode
  shouldn't touch local/ambient state at all, not even harmlessly
  (Medium severity finding).

* fix(safe-mode): actually run MCP discovery for surviving top-tier servers

Config.getMcpServers() reporting a top-tier server as configured isn't
enough on its own -- something has to actually connect to it and
register its tools with the model. That's a separate gate in
initialize(): startMcpDiscoveryInBackground() was skipped outright
whenever isSafeMode() was true, written back when getMcpServers()
always returned {} under safe mode (so skipping discovery was a
harmless no-op). Left unpatched after the earlier fix, a caller-supplied
top-tier server survives getMcpServers() but is never actually
discovered/connected -- confirmed live against a real ACP session
before this commit: the agent reported the tool as "not configured"
even though Config.getMcpServers() already returned it.

Found by actually running the fix end-to-end against a live ACP
session (qwen --acp --safe-mode + a real stdio MCP fixture server)
instead of relying on unit tests of Config in isolation. After this
commit the same live session correctly discovers and calls the
caller-supplied tool.

Checks getMcpServers() (not topTierMcpServers directly) so the
allowedMcpServers filter still applies -- no discovery is kicked off
if the only top-tier server present is filtered out.

* fix(safe-mode): also run MCP discovery for surviving bare-mode top-tier servers

The discovery-kickoff gate in Config.initialize() special-cased safe
mode (skip only when there's nothing to discover) but left bare mode's
half of the same guard unconditional (!this.getBareMode()), even
though loadCliConfig feeds top-tier MCP servers into bare mode's
mcpServers assembly exactly the way it does safe mode's
topTierMcpServers field. A bare-mode session with a caller-supplied
server (qwen --bare --mcp-config, or ACP session/new under bare mode)
had that server reported as configured by getMcpServers() but never
actually connected/discovered — the same stranded-server regression
already fixed for safe mode in this PR, just the bare-mode twin of it.

Found by an automated review pass on PR #7827 after the safe-mode fix
had already landed. Added the same three-case regression coverage
(present / nothing supplied / filtered out by allowedMcpServers)
mirroring the existing safe-mode tests, using mcpServers (not
topTierMcpServers) since bare mode's "local sources dropped" guarantee
lives entirely in the CLI-layer assembly, not a core-level short-circuit.

* refactor(safe-mode): simplify the bare/safe discovery-gate condition

(!bare || has) && (!safe || has) reduces by distributivity to
!(bare || safe) || has, so factor the has-servers check into a single
hasMcpServers computed once, instead of calling getMcpServers() (which
allocates and filters) twice.

Suggested by an automated review pass on PR #7827, commit 25ddf8b.
No behavior change — same 23 discovery-gate tests pass unmodified.

* fix(safe-mode): stop reading settings.mcp.allowed/excluded under safe mode

allowedMcpServers/excludedMcpServers assembly in loadCliConfig() only
guarded the settings-sourced branch with `!bareMode`, missing `!safeMode`
— so a local settings.json mcp.allowed/excluded list (LOCAL/ambient state,
same category as settings.mcpServers itself, which safe mode already
drops) was still read under safe mode. Combined with getMcpServers()'s own
allowedMcpServers filter (added earlier in this PR for the
--allowed-mcp-server-names case), a settings.json mcp.allowed list
narrower than the caller's own top-tier servers would silently filter
them back out — defeating the guarantee this PR exists to provide, via
the filter's source rather than the mcpServers map directly.

The argv.allowedMcpServerNames branch is unaffected: that's an explicit
per-invocation argument, not local state, so it still applies under safe
mode same as topTierMcpServers itself.

Found by an automated review pass (doudouOUC, CHANGES_REQUESTED) on PR
#7827. Regression test confirmed red before the fix (session-supplied
server silently filtered out) and green after. Full targeted vitest run
(packages/cli config/: 1018 passed, same 3 pre-existing Windows-only
extension-file-watcher failures as before, unrelated), tsc --noEmit,
eslint, prettier --check all clean.

* fix(safe-mode): stop reading settings.mcp.allowed/excluded on hot-reload too

Same class of bug as the previous commit's loadCliConfig fix, found by an
automated review pass on the SAME PR: recomputeMcpGating (hot-reload.ts)
reads settings.merged.mcp.allowed/excluded unconditionally, with no
bare/safe guard of its own. registerMcpHotReload's existing bare/safe
guard only covered the servers map (`next`), not the admission lists
computed right after it — so a live settings.json edit narrowing
mcp.allowed during an already-running safe/bare session would flow
straight into setAllowedMcpServers and silently filter the caller's
top-tier server out of getMcpServers() mid-session. Same stranded-server
outcome as the boot-time bug, reached through the gating list's SOURCE
instead of the mcpServers map.

Fix: under bare/safe mode, skip recomputeMcpGating entirely and build the
gating directly from only the CLI --allowed-mcp-server-names bound
(explicit, per-invocation, not local state — same treatment as
topTierMcpServers itself); excluded/pending are irrelevant once nothing
but the never-gated top-tier servers can be present.

Regression tests (safe mode + bare mode) confirmed red before the fix
(setAllowedMcpServers called with the settings-sourced list) and green
after (called with the CLI bound, undefined here). Full targeted vitest
run (packages/cli config/: 1020 passed, same 3 pre-existing Windows-only
extension-file-watcher failures as before this PR touched anything,
unrelated), tsc --noEmit, eslint, prettier --check all clean.

* fix(safe-mode): stop reading settings.mcp.allowed/excluded on ACP reload too

Third instance of the same bug class found by an automated review pass on
this PR: reloadWorkspaceMcpDiscovery (packages/cli/src/acp-integration/
acpAgent.ts) — the ACP control-endpoint reload path (workspaceMcpReload),
distinct from registerMcpHotReload's settings-file-watcher path fixed in
the previous commit — called assembleMcpServers(settings.merged.mcpServers,
...) and recomputeMcpGating(settings, ...) unconditionally, per live Config
in liveConfigs, with no bare/safe guard. A workspaceMcpReload request
against an already-running safe/bare session would fold local
mcpServers/mcp.allowed/excluded back in, silently stranding or filtering
the caller's own top-tier server mid-session — same outcome as the two
prior fixes, reached through a third independent reload path.

Fix: per-config (liveConfigs holds a Set of potentially differently-moded
Configs — the base config, active session configs, and the discovery
config), skip assembleMcpServers/recomputeMcpGating under bare/safe mode
and build servers/gating directly from that config's own
getTopTierMcpServers()/getCliAllowedMcpServerNames() — same treatment as
the other two fixes.

Regression test (packages/cli/src/acp-integration/acpAgent.test.ts)
confirmed red before the fix (settings-sourced 'local' server leaked
into reinitializeMcpServers alongside the caller's 'probe') and green
after. Also added getBareMode/isSafeMode mocks (defaulting false) to the
two pre-existing Config-shaped mocks in this describe block that didn't
have them — reloadWorkspaceMcpDiscovery now calls these unconditionally
per config, which would otherwise throw "not a function" against any
mock missing them, even for a normal-mode test. Full targeted vitest run
(packages/cli/src/acp-integration/acpAgent.test.ts: 318 passed), tsc
--noEmit, eslint, prettier --check all clean.

* test(safe-mode): add bare-mode counterpart for the workspaceMcpReload guard

Suggested by an automated review pass on PR #7827: the previous commit's
regression test for reloadWorkspaceMcpDiscovery only exercised
isSafeMode: true, leaving the bare-mode half of
config.getBareMode() || config.isSafeMode() unverified at this layer —
unlike the hot-reload.ts tests, which already cover both modes for both
the servers map and the admission lists. A future change narrowing that
guard to isSafeMode() only would go undetected here.

Confirmed red before the fix (temporarily reverted acpAgent.ts to the
prior commit): settings-sourced 'local' leaked into reinitializeMcpServers
alongside the caller's 'probe', same as the safe-mode case. Green with
the fix restored. Full targeted vitest run (acp-integration/acpAgent.test.ts:
319 passed), tsc --noEmit, eslint, prettier --check all clean.
2026-07-28 11:29:53 +00:00
jinye
788e5cd3a8
feat(core): add ARMS session user ID (#7921)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-28 11:10:38 +00:00
jinye
4703cc5432
fix(serve): Release managed session writer locks on shutdown (#7812)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (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(serve): release managed writer locks on shutdown

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

* fix(serve): address shutdown review feedback

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

* fix(serve): release writer locks after flush failures

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

* fix(serve): harden managed shutdown recovery

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-07-28 10:18:35 +00:00
顾盼
9461aa860d
fix(core): bridge tool-result images for text-only models (#7484)
* fix(core): bridge tool-result images for text-only models

* test(vision-bridge): pin tool-result full-turn guards and surface bridge errors (#7484)

* test(cli): cover drain-item model override conflict rejection (#7484)

* test(cli): cover stop-hook full-turn model persistence

* fix(core): disclose tool image routing

* fix(cli): type restored vision notices

* test(cli): fix stop-hook vision fixture

---------

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-28 08:47:40 +00:00
jinye
b3873571aa
fix(daemon): harden Todo Stop Guard continuations (#7821)
* fix(daemon): harden Todo Stop Guard continuations

Linearize Guard continuation ownership across bridge consumers, preserve queued input across failure paths, and tighten session lifecycle and lineage handling.

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

* fix(daemon): yield to event loop in waitForActiveTurnsToSettle (#7821)

* fix(channels): discard retired ACP sessions

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

* fix(cli): preserve superseded continuation state

Preserve unsent continuation results across prompt supersession and cancellation, and keep closing sessions from restoring stale FIFO priority.

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
2026-07-28 06:51:40 +00:00
jinye
05f854b146
fix(test): Restore first-output benchmark measurement validity and correct its artifact schema (#7820)
* fix(test): restore first-output benchmark measurement validity

Anchor the post-session dwell to SSE readiness so a slow connect cannot
silently reduce a dwell scenario to an immediate-prompt run, isolate the
runner in its own serial vitest config, decide the Phase 1 prototype gate
on the paired bootstrap CI instead of a bare difference of two P50s, and
normalize every invalid timing rather than only the first.

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

* fix(test): correct first-output benchmark artifact schema and simplify (#7825)

Drop the bundle git commit, which resolved HEAD of whatever repository
happened to contain the bundle directory rather than the revision it was
built from; the harness commit and bundle hash already record provenance
correctly. Rename the prompt-shape config field, which held a description
of the prompt rather than the prompt itself, and bump the artifact schema
for both field changes.

Also remove an unreachable AB/BA balance check, fold a duplicated success
predicate into one, parse the comparison-only dwell after the mode check
so single mode reports the accurate error, and document the two median
definitions, the compile-cache path lifetime, and the actual buffer
overflow and cold/warm attribution semantics.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

* fix(test): correct copyright years to 2026 (#7820)

* fix(test): reuse metricForOrdinal in coldWarmProviderDeltas (#7820)

* fix(test): strengthen benchmark test fixtures and align config with Vitest defaults (#7820)

* test(integration): cover prototype-gate input validation guards (#7820)

* fix(integration): summarize sseReadyToPromptMs metric and clarify gate error (#7820)

* test(integration): pin prototype-gate artifact shape for empty deltas (#7820)

* fix(integration): fail loudly on missing SSE timestamp; document sseReadyAt (#7820)

Replace the non-null assertion on the dwell anchor with an explicit guard so a
future path that resolves SSE readiness without recording a timestamp fails as
harness_error instead of silently degrading into an immediate-prompt run that
still reports its configured dwell. Also define sseReadyAt in the timestamp
table and note that each metric's bootstrap seed is positional, so inserting or
reordering a metric shifts later seeds and makes artifacts incomparable.

* test(integration): cover findInvalidTimings in the fast CI suite (#7820)

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: qwen-code-autofix[bot] <qwen-code-autofix[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-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: qwen-code-bot <qwen-code-bot@users.noreply.github.com>
2026-07-28 06:51:03 +00:00
易良
45a6a69cf0
feat(triage): add revert-pattern high-risk path detection (#7414)
* feat(triage): add revert-pattern high-risk path detection

Replace the behavior-neutral PR filter (PR #7414 v1, ~2% hit rate) with a
data-backed triage gate based on revert-history analysis of 111 revert
commits and 46 unique reverted PRs in this repo.

Stage 1e checks three signals identified by the analysis:
- touches_high_risk (66.7% precision, 32.3% recall)
- contested-merge pattern (50.0% precision, 19.4% recall)
- non-maintainer + high-risk (58.3% precision, 22.6% recall)

The gate escalates review depth and recommends maintainer sign-off; it
never blocks or closes PRs. Design doc and analysis scripts included.

* fix(triage): avoid stale-exempt hold label

* fix(triage): address review risk detection feedback

* fix(triage): tighten high-risk path patterns

* fix(triage): address review feedback on Stage 1e revert-pattern gate (#7414)

* fix(triage): address round-2 review feedback on Stage 1e gate (#7414)

- Fix APPROVE → APPROVED state name (GitHub API enum)
- Use gh api --paginate for file listing (fixes 100-file truncation)
- Anchor shell/relaunch/sandbox patterns with (^|/) to avoid false positives
- Append || true to grep (exit 1 on no match is the 92% case)
- Scope E2E recommendation to write-access authors per Stage 2c
- Add bot author filter to contested-merge query
- Define core paths explicitly in contested-merge condition
- Wire Stage 1e do-not-auto-approve into Stage 3 guardrail
- Replace precision percentages with p-values/raw counts in skill text
- Add sampling caveat and statistical significance notes to design doc
- Fix design doc errors: 71%→61.5%, 10→8 PRs, Rule 3 attribution,
  ~20% baseline→10% prevalence, Area field, no_e2e inconsistency
- Make test assertions specific to Stage 1e (not vacuous)
- Add Risk: template field assertion
- Revert drive-by prettier reflow
- Note need-discussion label removal by maintainer

* fix(triage): address round-3 review feedback on Stage 1e gate (#7414)

- Separate gh api call from grep so API failures are visible instead of
  being masked by || true (rc:3660753982)
- Include author identity in contested-merge jq output and require
  different reviewers for the disagreement check, avoiding false
  positives from same-reviewer iteration (rc:3660753990)
- Add Stage 1e to the approval summary checklist so it is not omitted
  from the pre-approval conditions (rc:3660753994)

* fix(triage): address round-4 review feedback on Stage 1e gate (#7414)

* fix(triage): use portable ERE grep for test-file exclusion (#7414)

* fix(triage): guard deferred approval on discussion label

* fix(triage): keep only supported revert signal

---------

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-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
2026-07-28 05:53:57 +00:00
jinye
b475d1a263
feat: Gate session writer lease behind opt-in (#7894)
* feat: gate session writer lease behind opt-in

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

* fix(acp): freeze session writer lease per process

Snapshot the effective restart-required lease gate from the bootstrap Config and reuse it for every session Config in the ACP process.

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

* fix(core): align recorder default lease gate

Use the effective session writer lease gate when ChatRecordingService is constructed without an explicit writer mode.

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-28 04:37:02 +00:00
ytahdn
6a432ad2eb
fix(web-shell): isolate history and session drafts (#7810)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (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(web-shell): isolate history and session drafts

* fix(web-shell): reset history-browse flag on early commit return (#7810)

* fix(web-shell): address review feedback on paste and draft handling (#7810)

* fix(web-shell): address review feedback on paste pruning, draft flush, and mobile draft notify (#7810)

* fix(web-shell): update smoke test for large paste placeholder behavior (#7810)

---------

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.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 <qwen-code@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
2026-07-28 01:45:52 +00:00
jinye
17408f1028
feat(hooks): Add submitted prompt provenance (#7762)
* feat(hooks): add submitted prompt provenance

Add an optional pre-expansion prompt sidecar for interactive UserQuery hooks while preserving legacy prompt behavior and fail-closed provenance handling across queues, retries, and continuations.

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

* fix(hooks): harden submitted prompt provenance

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

* fix(hooks): tighten submitted prompt provenance

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-27 15:53:15 +00:00
jinye
2210a18482
feat(web-shell): Scope voice to composer workspace (#7754)
* feat(web-shell): Scope voice to composer workspace

Route voice status, settings, model discovery, and streaming through the workspace that owns each main or split-view composer while preserving legacy primary behavior.

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

* fix(web-shell): Keep legacy voice fallback scoped

Prevent the Voice-only legacy workspace fallback from activating pre-session git polling, and cover both behaviors together.

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

* fix(web-shell): Preserve active Voice capture owners

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

* test(web-shell): Pin Voice trust and ambiguity gates

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-27 15:47:45 +00:00
ytahdn
8785216be5
feat(web-shell): add monitor task details (#7817)
* feat(web-shell): add monitor task details

* fix(web-shell): align monitor tab title with merged snapshot and reset expansion (#7817)

---------

Co-authored-by: ytahdn <ytahdn@gmail.com>
2026-07-27 12:30:17 +00:00
ytahdn
8a44b1b9f7
fix(web-shell): render task notifications as system messages (#7822)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (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(web-shell): render background notifications as system messages

* fix(web-shell): use basic table rendering by default

---------

Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com>
2026-07-27 09:15:18 +00:00
jinye
0f84691b88
test(serve): add first-output latency benchmark (#7761)
Add an opt-in cold-process benchmark, deterministic paired statistics, and artifact reporting to gate any future Provider preload work without changing production behavior.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-27 03:38:20 +00:00
易良
d44030a4c0
feat(core): add model grade selection for subagent spawn (#7685) (#7702)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (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
* docs: add design placeholder for subagent model grade selection (#7685)

* feat(core): add subagent model grade selection

* test(subagent): cover resolveModelGrade deep guards and resume else branch

- subagent-manager: add tests for non-string grade values, blank values,
  array-shaped modelGrades, and missing modelGrades (all return undefined)
- background-agent-resume: assert configured subagent model is preserved
  (not forced to 'inherit') when launch flags (model + authType) are absent

Addresses test-coverage review findings.

* refactor(subagent): extract normalizeModelGradeSettings and merge model validate

- Extract normalizeModelGradeSettings helper shared by resolveModelGrade
  and the Agent tool schema build, so the advertised grades and runtime
  resolution cannot drift (addresses duplicated shape invariant).
- Merge the three model-parameter validate branches under a single
  `params.model !== undefined` guard.
- Update agent.test.ts mock to preserve the real helper while still
  mocking SubagentManager.

* refactor(core): simplify model grade resolution

* fix(core): reject unknown model grades

* docs(core): clarify model grade precedence

* docs: explain subagent model grades

* test(core): update subagent manager mock

* fix(core): list available model grades

* fix(core): trim model grade keys and cover schema removal

Grade keys were checked for emptiness via grade.trim() but stored in the
map and advertised in the tool schema enum untrimmed, while values were
trimmed. A padded key like ' small ' published a padded enum name the
model had to reproduce verbatim, and the allowlist check silently
excluded it. Normalize the key before storing, allowlist matching, and
schema publication.

Also adds a test for the delete schema.properties.model branch that fires
when grades transition from available to empty, so a regression that
breaks the delete leaves no stale model enum in the tool schema.

* fix(core): trim allowed model grade filters

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-07-26 16:23:54 +00:00
jinye
9bdc62c74b
perf(cli): replace comment-json settings parser (#7747)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-26 14:42:51 +00:00
jinye
06df2410b6
fix(core): reliably deliver manual plan-exit notices (#7744)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-26 13:25:56 +00:00
Shaojin Wen
4958120c21
docs(channels): Document loops and proactive delivery (#7628)
* docs(channels): document loops and proactive delivery

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

* docs(channels): clarify standalone vs daemon loop storage paths (#7628)

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
2026-07-26 07:32:18 +00:00
jinye
8fa8085036
perf(core): Lazy-load first-use dependencies (#7686)
* perf(core): Lazy-load first-use dependencies

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

* test(core): Fix simple-git loader mock

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

* test(core): Cover abort during xterm load

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

* fix(core): Address lazy-loader review feedback

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

* fix(core): Validate lazy dependency module shapes

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-26 03:04:33 +00:00
OrbitZore
4895726600
fix(channels): use username as senderId in GitHub adapter to fix allowlist gate (#7727)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (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
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
* fix(channels): use username as senderId in GitHub adapter to fix allowlist gate

isAuthorizedForSharedSessionTarget compares config.allowedUsers (logins)
against envelope.senderId — but senderId was a numeric ID resolved via
getByUsername, so every allowlisted user was rejected from /who, /clear,
/status, /loop, and channel memory commands.

Fix by using user.login as senderId throughout, assuming GitHub users
don't change usernames. This also removes the getByUsername resolution
step that made connect() non-idempotent on daemon reconnect.

- Remove botUserId field; bot self-filter uses botUsername
- Remove allowedUsers login-to-ID resolution in connect()
- Pass config.allowedUsers logins directly to gate
- senderId in envelopes uses user.login

* fix(channels): normalize allowlist/senderId to lowercase for case-insensitive matching

GitHub logins are case-insensitive but Set.has/Array.includes are not.
Without normalization, allowedUsers: ['Alice'] silently rejects a
commenter whose canonical login is 'alice' — a regression from the old
getByUsername round-trip which normalized casing implicitly.

- Normalize config.allowedUsers and gate to lowercase in connect()
- Lowercase senderId at both envelope assignment sites
- Remove dead != null guard in bot self-comment filter
- Add case-insensitive gate test and connect idempotency test
- Add senderId/allowedUsers comparability guard to dispatch test
- Document username-based allowlist rename risk in security section
2026-07-26 00:21:22 +00:00
samuelhsin
3a6c8e0c03
feat(skills): add overridable default-disabled state (#7357)
* feat(skills): add overridable default-disabled state

* fix(skills): address review feedback on default-disabled PR (#7357)

- Fix disabledChanged comparison in SkillsManagerDialog to use
  previousDisabled (locked names filtered) instead of workspaceDisabled,
  preventing spurious settings writes when a skill is disabled at both
  workspace and higher scope
- Import SettingScope as a value instead of string-casting literals in
  skill-settings.ts for compile-time safety
- Add dual-key change test: enabling a workspace-hard-disabled
  default-disabled skill produces both skills.disabled and
  skills.enabled changes in one operation
- Add legacy inactive-extension branch tests: reject when
  disabledReason is undefined and skill is not in settings
  disablements; allow when it is disabled by settings

* fix(cli): address skills picker review feedback (#7357)

Extract the skills picker's workspace persistence computation into a tested pure function so orphaned workspace disables (skills not currently loaded) are explicitly preserved and pinned by a regression test. Also add an integration test asserting a workspace-scope hard disable surfaces disabledReason 'hard' through the full loadSettings -> resolveSkillSettings -> mapSkillConfigToStatus pipeline.

* fix(cli): resolve skill disablements in safe mode for status API (#7357)

* fix(cli): dynamically import skill-settings in serve to keep fast-path closure clean (#7357)

---------

Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.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 Autofix <qwen-code-autofix[bot]@users.noreply.github.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
2026-07-25 18:29:20 +00:00
Shaojin Wen
a8a28a1137
fix(acp-bridge): raise live journal caps and expose as daemon config (#7715)
The live journal (DAEMON-009) caps were too conservative for real-world
agent turns: 2000 events / 2 MiB caused 79% event loss on a typical
long turn (9647 events). Raise defaults to 10 000 events / 8 MiB and
expose them as --max-journal-events / --max-journal-bytes CLI flags,
following the same config path as --compacted-replay-max-bytes.

Also fix stale docs that described the liveJournal as uncapped.
2026-07-25 14:14:09 +00:00
qwen-code-dev-bot
34a3d46006
fix(core): fire StopFailure hook on loop detection early returns (#7592)
* fix(core): fire StopFailure hook on loop detection early returns (#7588)

When loop detection (always-on safety or heuristic) terminates a turn
early via `return turn`, the Stop hook code after the streaming loop
was never reached. StopFailure hooks were only fired from the CLI
layer for API errors, not from client.ts for loop detection.

Added `loop_detected` to StopFailureErrorType and fire the
StopFailure hook via MessageBus before each loop detection early
return, so cleanup/notification hooks run regardless of how the
turn ends.

All 284 client tests and 682 hook tests pass.

* fix(core): use direct hookSystem call for loop-detection StopFailure (#7588)

The MessageBus bridge has no StopFailure case, so the hook never
executed. Switch to config.getHookSystem()?.fireStopFailureEvent()
(matching the CLI's API-error path), make it fire-and-forget per the
StopFailure contract, drop the stale last_assistant_message that
carried the previous turn's text, deduplicate via a private helper,
update docs with loop_detected, regenerate the settings schema, and
add regression tests for both loop-detection paths.

* test(core): add negative-path test for StopFailure hook disable guard (#7592)

* test(core): add negative-path tests for StopFailure hook guards (#7592)

---------

Co-authored-by: qwen-code-dev-bot <qwen-code-dev-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: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
2026-07-25 11:29:02 +00:00
hogeheer499-commits
88782646ab
feat(core): configure stream rate-limit retry delays (#7666)
Co-authored-by: JS van Dijk <267467744+hogeheer499-commits@users.noreply.github.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
2026-07-25 09:43:25 +00:00
OrbitZore
62e009a952
feat(channels): GitHub polling adapter with notification-as-wakeup architecture (#7632)
* feat(channels): add GitHub polling adapter with notification-as-wakeup architecture

Introduce a GitHub channel adapter that monitors notifications and
responds to @mentions on issues/PRs by posting comments. Uses
last_read_at as a per-thread watermark for comment enumeration,
replacing the unreliable latest_comment_url approach.

Foundation changes to ChannelBase:
- sendThreadMessage for thread-targeted delivery (IM adapters unchanged)
- Envelope.metadata appended to prompt after command parsing
- chat_thread session scope (channel:chatId:threadId) prevents
  cross-repo session collision
- polling-helpers: testBotMention/stripBotMention (separate detection
  from stripping, no whitespace collapsing), cursor persistence,
  abortableSleep

GitHub adapter design:
- Notifications as wake-up signals only (unread filtering)
- listComments enumeration with last_read_at watermark
- Bot self-comment filtering, case-insensitive mention regex
- In-memory recentlyProcessed set for mark-read failure dedup
- First-contact: new issue body @bot triggers processing
- Error comment + cursor advance on handleInbound failure
- pollInterval minimum 60s, exponential backoff 2s-30s

* refactor(channels): extract PollingChannelBase from polling-helpers

Replace the loose polling-helpers module with a PollingChannelBase<Cursor>
abstract class that encapsulates the poll loop, cursor persistence (JSON,
atomic write), exponential backoff, and start/stop lifecycle. Subclasses
implement only pollOnce() and createInitialCursor().

- Delete polling-helpers.ts (cursor fns + abortableSleep moved into base)
- Move mention utilities (testBotMention/stripBotMention) to github pkg
- GithubAdapter now extends PollingChannelBase<{ lastProcessedAt }>

* fix(channels): remove Gitea/GitLab mention from sendThreadMessage JSDoc

* fix(channels): match /pulls/N in notification subject URL

GitHub PR notifications use /repos/{owner}/{repo}/pulls/{N} in
subject.url, not /issues/{N}. The regex only matched /issues/,
causing PR notifications to be skipped and marked read.

Also sets threadId to 'pr:N' for PRs (was always 'issue:N').

* test(channels): add PR body first-contact unit test

Verify that PR notifications with @mention in the body (not a comment)
correctly trigger the first-contact path: extractFromSubjectUrl matches
/pulls/N, listComments returns empty, tryFirstContactBody fetches the
PR body and dispatches to handleInbound with threadId 'pr:N'.

* feat(channels): read pollInterval from channel config in PollingChannelBase

Move pollInterval config reading from GithubAdapter to the base class.
The user's configured pollInterval in settings.json is now respected
directly without a minimum enforcement. Defaults to 60000ms when not
configured.

* fix(channels): prepend metadata before prompt text

Agent sees issue/PR context (type, title, URL) before the user's
request, improving comprehension. Metadata is still appended after
slash-command parsing so commands are not affected.

* refactor(channels): route all ChannelBase delivery through sendThreadMessage

Replace all internal sendMessage calls with sendThreadMessage, passing
envelope.threadId (or target.threadId / undefined) so polling adapters
can deliver to the correct thread. IM adapters are unaffected — the
default sendThreadMessage falls through to sendMessage.

* docs(channels): document sendThreadMessage delivery architecture

* fix(channels): address review findings

- Cap recentlyProcessed Set at 10k entries to prevent unbounded growth
- Validate cursor JSON shape (non-null object) in loadCursorFromDisk
- sendThreadMessage falls through to sendMessage when threadId is
  undefined instead of silently dropping
- Remove duplicate pollInterval from GithubConfig (now in ChannelConfig)
- Fix chat_thread routing key trailing colon when threadId is undefined

* docs(channels): fix metadata JSDoc — prepended, not appended

* fix(channels): use recentlyProcessed dedup for first-contact body

Replace the fragile createdAt-vs-cursor check in tryFirstContactBody
with the recentlyProcessed set. The cursor advances globally based on
notification updated_at — when a different notification with a later
updated_at is processed first, the cursor can advance past the issue's
created_at, causing the first-contact check to incorrectly skip the
issue body (forget reply bug, found in E2E TC-2b).

* refactor(channels): two-layer dedup for GitHub adapter

Layer 1: global cursor filters notifications by updated_at (sorted
ascending, old first). Layer 2: server-side last_read_at filters
comments by created_at (sorted ascending).

- Delete recentlyProcessed Set (no longer needed)
- Sort notifications by updated_at ascending before processing
- Sort comments by created_at ascending before processing
- Pass latest comment created_at to markThreadAsRead as last_read_at

* fix(channels): address review findings on GitHub adapter

Blockers:
- sessionScope: add defaultSessionScope to ChannelPlugin, apply in
  parseChannelConfig so router and adapter agree on 'chat_thread'
- channel-registry.test.ts: add 'github' to expected type list

Should-fix:
- Replace per-thread markThreadAsRead (PATCH) with bulk
  markNotificationsAsRead (PUT /notifications + last_read_at).
  API errors stop the batch without marking failed notifications
  read; handleInbound errors still advance (error comment posted).
- connect() throws on bot identity failure instead of failing open
- metadata appended after promptText (inside sender attribution)
- isSharedSessionTarget includes 'chat_thread' scope

Nits:
- startPollLoop re-entrancy guard
- clean-package-build-artifacts.js includes github
- index.ts re-exports GithubChannel

* fix(channels): use max updated_at of all fetched notifications as last_read_at

Prevents re-fetching the same notifications in the next poll cycle.
The bulk PUT /notifications marks all fetched notifications as read
up to the max updated_at, regardless of per-notification success.

* fix(channels): address review round 2 findings

- #12: loadCursorFromDisk rejects arrays
- #13: pollInterval validates positive finite number
- #19: first-contact gate uses dispatchedMention flag (not newComments.length)
- #25: stripBotMention no longer trims (preserves indentation)
- #27: remove adapter-level requireMention, unify on GroupGate
- #31: add chat_thread SessionRouter routing key tests
- #33: clear metadata on collect-mode synthetic envelope
- #35: fix PollingChannelBase.test import path
- #36: add @octokit/rest to 15-channel-adapters.md dependencies

* docs(channels): document known limitations for GitHub adapter

- First start skips existing unread notifications (cursor = now)
- Requires classic PAT (fine-grained PATs lack notifications API)
- PR review comments not enumerated (issue comments only)

* fix(channels): address review round 3 findings

- #9: buildMetadata derives web URL from baseUrl (GHE support)
- #12: sendThreadMessage throws on invalid threadId format
- #19: mention lookbehind matches cc:@bot and "@bot" patterns
- #23: cursor file name uses sha256 hash to prevent collision
- #26: test verifies cursor persistence to disk
- #31: postErrorComment double-failure logs to stderr
- #45: tests use mkdtempSync isolation instead of real QWEN_HOME

* fix(channels): pass threadId through pairing flow + sendResponseMessage test

- #13+16: onPairingRequired receives envelope.threadId and passes it
  to sendThreadMessage, so pairing codes are delivered on threaded
  channels (GitHub) instead of throwing
- #6: add test verifying sendResponseMessage resolves threadId from
  router.getTarget and passes it to sendThreadMessage

* fix(channels): pass proxy to Octokit for daemon-worker environments

- #44: read this.proxy from ChannelBaseOptions and pass
  HttpsProxyAgent to Octokit request.agent, matching the
  Telegram adapter pattern

* fix(channels): address review findings — immutable senderId, comment time window, validateCursor, retry wrapper

- senderId uses immutable user.id; allowedUsers resolved to IDs at connect
- Comment filter upper bound: updated_at <= maxUpdatedAt (batch window)
- Per-notification errors use continue (best-effort), not break
- validateCursor() virtual hook for subclass cursor shape validation
- sendThreadMessage/postErrorComment wrapped in githubApi() retry
- webOrigin handles default api.github.com → github.com
- Docs: classic PAT only, markNotificationsAsRead, dedup claims removed
- Tests: threadId priority, metadata consumption, defaultSessionScope,
  QWEN_HOME isolation, persistent mock rejection

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

* fix(channels): mark notifications read before processing to prevent duplicate replies

Bot's own replies bump notification updated_at past the pre-captured
maxUpdatedAt, so markNotificationsAsRead(maxUpdatedAt) failed to mark
them read — the next poll re-fetched the same comments and replied
again.

Move markNotificationsAsRead + cursor advance before the processing
loop (best-effort delivery). This is safe because bot's own comments
do not flip notifications back to unread. Update docs to reflect the
new poll cycle order and best-effort semantics.

* fix(channels): update sender gate after allowedUser ID resolution and harden tests

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

* fix(channels): cursor-based comment window to prevent duplicate replies

PUT /notifications is async (202) with a last_read_at cutoff — the
bot's reply bumps updated_at past the cutoff before the server
processes the mark, so the notification is never marked read and gets
re-fetched on the next poll, causing duplicate replies.

Use the cursor value before advancement as an exclusive lower bound
for the comment enumeration window: (windowSince, maxUpdatedAt].
Comments already eligible in a previous poll are excluded regardless
of whether the mark succeeded. Zero new persistent state.

* fix(channels): cursor-based comment window to prevent duplicate replies

PUT /notifications is async (202) with a last_read_at cutoff — the
bot's reply bumps updated_at past the cutoff before the server
processes the mark, so the notification is never marked read and gets
re-fetched on the next poll, causing duplicate replies.

Use the cursor value before advancement as an exclusive lower bound
for the comment enumeration window, with per-notification last_read_at
as the preferred lower bound when available (server-side per-thread
watermark). Comments already eligible in a previous poll are excluded
regardless of whether the mark succeeded. Zero new persistent state.

* fix(channels): address review findings — null guard, cursor validation, metadata dedup, abortable sleep, docs

- Guard against null notification.subject.url in pollOnce
- Validate lastProcessedAt is a parseable date in validateCursor
- Add metadata: undefined to second collect-mode drain path
- Refactor abortableSleep as protected method on PollingChannelBase
- Fix docs: requireMention is nested under groups.*
- Add tests: chat_thread shared session, dispatchedBodies eviction,
  cursor enumeration window, last_read_at in mention tests

* docs(channels): sync docs with implementation — cursor shape, error handling, GitHub adapter tables, first-contact

- Design doc: update Cursor to { lastProcessedAt, dispatchedBodies? }, add
  validateCursor date check, abortableSleep protected method, break-on-error
  semantics, subject.url null guard
- Developer docs: add GitHub to adapter table and adapter matrix
- User guide: add first-contact step to How It Works, clarify mark-before-process

* fix(channels): address review round 2 — error dedup, abortable retry, backoff reset, window test

- Record dispatchedBody on first-contact handleInbound failure to prevent
  duplicate error comments when mark-read async hasn't taken effect
- Use abortableSleep instead of raw setTimeout in githubApi retry so
  disconnect() can interrupt rate-limit cooldowns
- Reset consecutiveErrors in startPollLoop so stop/restart cycles don't
  inherit stale elevated backoff
- Add test for cursor window client-side lower-bound exclusion filter

* fix(channels): address review round 3 — cursor validation, error dedup, sender gate, bot-self body

- validateCursor: normalize falsy non-array dispatchedBodies (false/0/""/null)
  to [] instead of passing them through to .includes() which throws TypeError
- Set dispatchedMention after postErrorComment to prevent first-contact from
  posting a duplicate error comment on the same thread
- Only set dispatchedMention when the sender passes the sender gate, so a
  disallowed commenter's mention no longer suppresses a valid first-contact
  body from an allowed issue author
- Skip bot-authored issue bodies in tryFirstContactBody to prevent
  self-response loops under open sender policy

* fix(channels): address review suggestions — test coverage, cursor filename, assertion precision

- Pairing flow: add threadId pass-through regression test
- pollInterval: add table-driven edge cases (0, -1, NaN, Infinity, string)
- Add null-URL notification followed by valid notification batch test
- Fix comment window test to assert paginate call 3 (listComments) not call 2
- Truncate cursor filename encoded prefix to 200 chars (filesystem 255 limit)
- Assert mark-read uses batch maxUpdatedAt, not just { read: true }
- Assert real GitHub plugin declares defaultSessionScope chat_thread
- Add invocationCallOrder assertion for mark-before-process ordering

* fix(channels): address review round 4 — allowedUsers throw on resolve failure, crash table fix, mark-read failure test

* fix(channels): address review round 5 — created_at filter, retry-after NaN guard, retry/sendThreadMessage tests, docs fixes

* fix(channels): address ci-bot review 4778587403 — reconnect idempotency, github type enumerations, retry/webOrigin tests

* chore(channels): align channel-github version to 0.21.0 after upstream merge

* chore(channels): update package-lock.json for channel-github 0.21.0

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

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: OrbitZore <orbitzore@users.noreply.github.com>
2026-07-25 09:31:50 +00:00
destire-mio
dbadf49c6c
feat(stats): show generation timing metrics (#7677)
Co-authored-by: destire-mio <248462155+destire-mio@users.noreply.github.com>
2026-07-25 09:06:33 +00:00
yijie zhao
0b5116a1bb
feat(core): configure stream rate-limit retry delays (#7674) 2026-07-25 08:56:21 +00:00
jinye
c4859627a7
feat(serve): Hot-reload workspace trust changes (#7268)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (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(serve): hot-reload workspace trust changes

Rebuild workspace runtime generations when trust policy changes, fail closed across daemon routes, and expose reconciliation status to SDK and Web Shell clients.

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

* codex: address PR review feedback (#7268)

Document the trust hot-reload capability and reuse the daemon environment fallback so the serve process environment guard remains satisfied.

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

* fix(cli): cache workspace trust status snapshots

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

* fix: address trust reload race regressions

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

* fix(serve): avoid repeated runtime containment

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

* fix(serve): harden workspace generation boundaries

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

* fix(serve): restore stale session owner fallback

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

* fix(serve): preserve workspace metadata across trust reloads

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

* fix(serve): align hot-reload trust semantics

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

* fix(serve): stop git-state watcher on dispose only, fix git chip test (#7268)

beginDrain stopped the git-state watcher but cancelDrain had no way to
restart it, leaving the watcher disposed until the next lazy poll.
disposeRuntime already stops git-state when the drain is committed, so
the beginDrain stop was redundant — remove it.

Also fix the WorkspaceSection git chip test that broke when the trigger
changed from <button> to <span role="button"> inside DropdownMenuTrigger:
use closest('[role="button"]') and interact with the dropdown menu item.

* fix(serve): address review feedback on trust polling and setValue assertion (#7268)

* fix(cli): correct daemon trust policy settings precedence and drain continuation (#7268)

* fix(serve): address review feedback on fork cleanup, persist simplification, sync guard, and a11y (#7268)

* fix(serve): assert before mutate in setValue, add pre-mutation guard, trust-before-generation ordering (#7268)

* fix(serve): honor system defaults in trust policy

Apply the documented settings precedence to daemon folder trust evaluation and keep workspaces outside configured trust rules fail-closed.

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

* fix(serve): preserve managed scratch trust during reloads

Keep daemon-created scratch workspaces trusted across policy reloads while retaining controlled-root validation, and reject trust mutations that cannot apply to these fixed-trust runtimes.

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

* fix(serve): guard auth provider persistence by generation

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

* refactor(serve): remove Web Shell trust UI

Keep this PR focused on daemon and SDK trust reconciliation; the Web Shell integration can follow separately.

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

* fix(sdk): restore workspace trust bundle budget

Preserve the merge-only browser bundle allowance required by the additive workspace trust v2 SDK surface after rebasing.

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

* fix(cli): handle trusted folder write failures

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

* fix(cli): keep capabilities available during trust reload

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

* fix(cli): address review feedback for workspace trust hot reload (#7268)

Drop the closed generation guard before retrying dynamic workspace
runtime creation so the retried runtime starts with a fresh, open guard
instead of inheriting the one closed during the abandoned attempt. Make
the /workspace/reload trust reconcile fire-and-forget with a swallowed
rejection (failures are reported separately), reuse sendGenerationClosedError
for the memory write error path, and assert the subagent deletion commit
boundary once before unlinking so a closed generation fails atomically.
Add coverage for the blocked-entry deep health probe and the /session/:id/cd
generation-close-during-flight path.

* fix(serve): close trust reload cleanup gaps

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

* fix(serve): use fire-and-forget for trust reconcile in workspace-qualified reload (#7268)

* fix(serve): address review feedback on generation guard and trust reconciler (#7268)

* fix(serve): use shared helpers for untrusted/generation-closed responses (#7268)

* fix(serve): continue cleanup after drain commit errors

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

* fix(cli): retry transient trust policy disappearance

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

* fix(serve): align status provider trust default with route-level check (#7268)

* fix(serve): clean up worktree on generation guard abort (#7268)

* fix(cli): guard tool and skill settings commits

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

* test(cli): add discriminating persistent-ENOENT test for trust policy read (#7268)

* fix(serve): close runtime generation gaps

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

* fix(serve): preserve scheduled task cap errors

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

* fix(serve): address review feedback on trust reconciler, settings guard, and route simplification (#7268)

* fix(serve): preserve containment retry semantics

Restore the last verified trust-reconciliation and generation-guard behavior after the automated review fix marked an unconfirmed disposal as contained and removed per-scope commit checks. Defer the remaining late-round suggestions to avoid expanding the PR.

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.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 Autofix <qwen-autofix@alibaba-inc.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
2026-07-25 08:43:07 +00:00
Shaojin Wen
a470ba626c
feat(review): add comment-status helper for existing-thread triage (#7690)
* feat(review): add comment-status helper for existing-thread triage

One deterministic pass over a PR's existing inline comments, replacing
the per-comment `gh api` fetches the orchestrating model used to make
during /review: anchor validity at the live head (outdated detection,
with a file-level exemption), whether the anchored file changed in the
reviewed worktree since each comment's commit and which commits touched
it (the re-check's candidate "fixed by" list), reply participation and
PR-author response, the blocker signal (same carriesBlockerSignal as
pr-context, so the two surfaces agree by construction), and
worktree-vs-live head drift.

Measured on a heavily discussed PR (72+ inline comments), a single
review run burned 20+ model turns re-deriving exactly these fields one
comment id at a time. SKILL.md now runs the subcommand in Step 1 and
routes the Step 6 re-check's status questions at the report; comment
bodies stay in the pr-context file under its untrusted-data preamble,
and a comment-status failure only warns — it is an index, not the
evidence, so it never sets the context-unavailable state.

* test(review): add comment-status to the subcommand registry expectations

* fix(review): comment-status review follow-ups — size warning, --host wiring, scope clauses

Addresses the review at d098e4feb:

- High: warn when the report exceeds read_file's truncation threshold,
  mirroring pr-context — measured 53k chars on the benchmark PR, where a
  single read lost 36 of 71 threads (24 blocker-flagged) and the cut JSON
  did not parse. The warning points at jq first: the file is
  machine-shaped in a way the Markdown context file is not.
- Medium: thread --host through — the SKILL.md command block now says to
  pass it (each subcommand is its own process, so a host set elsewhere
  cannot carry over), and comment-status joins the host-required lists in
  SKILL.md and the code-review docs.
- Minor: Step 6's routing sentence now states both scope limits — the
  report exists only when Step 1 wrote it (worktree mode), and it indexes
  inline threads only; issue-/review-level blockers keep the context-file
  walk.
- Minor: touchedByTotal exposes the real commit count behind the capped
  touchedBy list, so a cut list is visible instead of reading as "the fix
  is not among them".
- Nits: drop the never-read `side` field; guard authorReplied against a
  deleted-author/deleted-replier '' === '' match; correct the force-push
  doc comment (a shared object database usually retains the old commit,
  so the range widens — fail-safe — rather than going unknown).

* fix(review): comment-status second-round follow-ups — CWD-safe pathspec, shared walk, stale flag

Addresses the LGTM-with-suggestions round:

- The git probe's pathspec is anchored with `:(top)`: run from a
  subdirectory of the worktree, the old CWD-relative form returned empty
  output with exit 0 and every thread read as "untouched since the
  comment" — silent, and pointing the one direction this index must not
  fail in. A real-git integration test now drives the probe from the
  repo root AND a subdirectory (plus the cap, the memo, and the
  missing-commit gate — none of which the injected-probe unit tests
  could see).
- findRootId is imported from pr-context (made generic and exported)
  instead of duplicated — the thread walk now agrees by construction,
  like the blocker signal already did.
- Head drift is denormalized onto every thread as code.staleWorktree, so
  a jq consumer of threads[] cannot skip the top-level flag by
  construction.
- Commit existence is memoized per SHA (it never depended on the path),
  halving git spawns on thread-heavy PRs; summarizeThreads gets a named
  return interface like every other exported shape here.
- DESIGN.md gains the missing section: why comment-status is a separate
  subcommand and why the second fetch of pulls/{n}/comments is
  deliberate (process boundary — pr-context must stay pure-API for
  lightweight mode; this one exists to join API facts with worktree git).

* fix(review): harden comment-status against untrusted-PR inputs

Addresses the security review round:

- Symlink --out: the command now runs from the trusted main checkout (so
  a relative --out cannot be redirected through a symlink an untrusted PR
  planted in its own worktree) and scopes its git queries to the worktree
  with `git -C <worktreePath>`, which it locates itself. SKILL.md no
  longer cd's into the worktree for it. The report lands in the main
  checkout's .qwen/tmp alongside every sibling report.
- Non-ancestor comment commit: after a force-push the anchor commit can
  survive in the shared object store without being on HEAD's history, so
  `sinceSha..HEAD` is empty and a changed file reads as changed:false —
  the one direction this index must not fail in. A single
  `merge-base --is-ancestor` gate now returns 'unknown' for a
  non-ancestor OR a missing commit, replacing the cat-file existence
  check (one git process instead of two).
- Literal pathspec: the GitHub-supplied path is passed as
  `:(top,literal)<path>` so a value like `:(exclude)a.ts` cannot be read
  as pathspec magic and inspect unrelated files.
- Fetch-race drift: the live head is sampled before AND after the
  comments fetch; a push landing mid-fetch (which would pair newer
  anchor mappings with a stale comparison) is now detected, recorded as
  both samples, and warned on distinctly from ordinary worktree lag.
- pr-context renders the root comment id in the Open and Already-discussed
  sections, giving Step 6 a stable join key back to comment-status's
  per-thread rootId (the blocker renderer already did this).
- Handler-level tests (mocked gh/git/fs) for the three drift outcomes,
  plus real-git integration cases for the non-ancestor gate and the
  literal pathspec. Multi-page pagination is a non-issue: gh api
  --paginate merges top-level arrays into one (verified on the live
  93-comment PR).

* fix(review): comment-status round 3 — precise staleWorktree, worktree-missing warning, discriminating pathspec test

Addresses three Suggestions:

- staleWorktree is now keyed on worktreeStale alone, not the headDrift
  union. A head that merely moved between the two samples while the
  worktree already matches the final head is NOT a superseded checkout,
  so its threads no longer carry staleWorktree:true against the field's
  documented meaning. headMovedDuringFetch stays a separate top-level
  flag + warning.
- A missing worktree (comment-status run before fetch-pr or after
  cleanup) now sets worktreeMissing on the report and prints a warning —
  previously every thread degraded to code:'unknown' silently, readable
  as "nothing changed".
- The literal-pathspec test now uses a discriminating pathspec
  (`:(glob)pkg/**`): magic would match the changed file (true), literal
  is a nonexistent filename (false), so asserting false actually fails if
  the `:(top,literal)` prefix is dropped — the old `:(exclude)…` read
  false under both interpretations. A plain-path control proves the probe
  is live.

* test(review): make the comment-status negation test actually exercise negation

The body 'No blockers here' matched no BLOCKER_PATTERN (the bare plural
never triggers /\bblocking\b/ etc.), so isBlocker returned false before
the negation branch ran — false coverage. It now uses 'No blocking
issues', which matches the signal and must be suppressed by the leading
'No', plus an un-negated control that asserts true.

* test(review): assert per-thread staleWorktree and --host wiring; document ghApiAll merge contract

Two test gaps + one recurring-review clarification:

- The worktree-lag drift test now includes a thread and asserts
  staleWorktree:true is denormalized onto its code object — the old
  positive case had zero threads, so the denormalization loop iterated
  over nothing and would pass even if the block were deleted.
- A --host test now asserts setGhHost is called with the argv host,
  matching the presubmit analog; without it a dropped setGhHost would
  silently target github.com for a GHE review.
- ghApiAll's doc now explains why one JSON.parse is correct on multi-page
  output: gh --paginate MERGES top-level arrays into one (it does not emit
  one array per page); the per-page-concat failure only affects
  key-nested arrays, which is exactly why ghApiAllNested exists. Verified
  on a 4-page 97-comment response.

* fix(review): comment-status degrades gracefully on failure per its SKILL.md contract

SKILL.md promises this command is an index, not evidence — "if it fails
(auth, network), warn and continue" — but runCommentStatus had no
try/catch, so an ensureAuthenticated() or gh throw propagated as an
unhandled rejection and killed the whole review. The runtime body is now
wrapped: any throw writes a minimal empty report ({prNumber, ownerRepo,
error, threads: []}) so downstream jq still parses, prints a
"comment-status failed" warning, and exits 0. Handler test pins the
auth-failure path (no throw, empty report, warning). Reported by
@yiliang114.

* test(review): pin comment-status owner_repo guard and truncation-size warning

Two untested paths flagged in review: the owner_repo-without-slash guard
(a caller error that must still throw, distinct from the runtime
graceful-degradation path) and the report-size warning that fires when
the JSON crosses read_file's truncation threshold.

* fix(review): comment-status degraded report carries the full shape, not a stripped one

The graceful-degradation path wrote { prNumber, ownerRepo, error,
threads: [] }, omitting headDrift/summary/headMovedDuringFetch/etc. A
consumer reading report.headDrift then got undefined (falsy = "no
drift"), silently mistaking a total index failure for a clean "nothing
moved" — and the review orchestrator keys code-fact warnings on exactly
that field. The degraded report now emits the same shape as the success
report with safe defaults plus `error`, so a consumer that checks `error`
sees the failure and one that reads a fact gets a neutral value, never a
misleading one. Reported by @doudouOUC.

* fix(review): degraded report's worktreeMissing must not contradict worktreeHeadSha: null

The catch-block report hardcoded worktreeMissing: false beside
worktreeHeadSha: null — a positive "worktree present" assertion the
success path (worktreeMissing = worktreeHeadSha === null) would never
make for a null head. A consumer reading worktreeMissing without gating
on error would conclude the worktree exists on a run where nothing is
known. Now true, matching the null head and the fail-safe reading (code
facts unavailable). Reported by qwen-code-ci-bot.

---------

Co-authored-by: verify <verify@local>
2026-07-25 08:26:08 +00:00
jinye
8f667f5bdc
feat(integrations): add retrieval-only external context search (#7586)
* feat(integrations): add direct external context provider

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

* fix(integrations): harden external context failure handling

Preserve provider timeout classification, reject ambiguous Mem0 statuses, release rejected response bodies, and clarify credential and workspace deployment boundaries.

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

* refactor(integrations): narrow external context to retrieval

Limit Phase 1 to one provider-bound search tool, remove hooks and writes, and document the direct profile's actual permission and isolation boundaries.

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

* fix(integrations): harden external context deployment

Pin the managed MCP source through an administrator-owned command-line configuration, document the Direct Profile trust boundary, and remove unused logging/runtime abstractions.

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

* fix(integrations): preserve external context results

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

* fix(integrations): honor provider proxy settings

Install an environment-aware dispatcher before the external context MCP server starts so enterprise egress proxy and NO_PROXY settings apply to provider requests. Document the managed launcher environment and cover startup wiring.

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

* fix(integrations): diagnose invalid proxy settings

Classify proxy dispatcher construction failures as sanitized configuration errors so managed deployments can identify an invalid proxy environment without exposing proxy credentials.

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-25 08:18:27 +00:00
Shaojin Wen
d61b0ea475
perf(web-shell): paint the composer git chip before git status completes (#7680)
* perf(web-shell): paint the composer git chip before git status completes

New sessions gated the chip on a full `git status --porcelain` subprocess
behind GET /workspaces/:ws/git, so the branch chip appeared hundreds of
milliseconds (worst case seconds) after the composer was ready.

The daemon now keeps a per-workspace last-known summary with in-flight
dedup and a 2s background-refresh throttle: the default GET returns the
cached status (branch-only on a cold start) immediately and recomputes in
the background, publishing git_status_changed over SSE only on a delta,
while ?wait=1 keeps the previous blocking semantics. The composer fetches
both paths concurrently — the fresh GET also covers the no-session state,
which has no per-session SSE stream — so the branch paints in ~3ms and
the counters land when the computation finishes. The sidebar keeps
wait:true since it has no SSE fill-in path.

* fix(web-shell): add exhaustiveness guard and worktree git-status test (#7680)

* fix(web-shell): add exhaustiveness guard and worktree git-status test (#7680)

* fix(web-shell): add exhaustiveness guard and worktree git-status test (#7680)

* fix(cli): use writeStderrLineSafe in git-status refresh error path (#7680)

* fix(web-shell): add debug trail to fresh-path catch and test branch-watcher dispose guard (#7680)

* fix(cli): assert writeStderrLineSafe in git-status refresh failure test (#7680)

---------

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-25 07:05:52 +00:00