Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
116 commits
Select commit Hold shift + click to select a range
0a9fcc3
feat(cli): workspace-qualified extensions REST (daemon multi-workspace)
doudouOUC Jul 10, 2026
563a173
qwen: address PR review feedback (#6638)
doudouOUC Jul 10, 2026
59b2f88
qwen: address PR review feedback (#6638)
doudouOUC Jul 10, 2026
9dd2e92
qwen: address PR review feedback (#6638)
doudouOUC Jul 10, 2026
d6c3b70
feat(cli): add concurrent extension preparation
doudouOUC Jul 10, 2026
f3e76ff
fix(cli): remove redundant extension context build
doudouOUC Jul 10, 2026
40c9118
codex: address PR review feedback (#6638)
doudouOUC Jul 10, 2026
d47f4a7
codex: address PR review feedback (#6638)
doudouOUC Jul 10, 2026
d2c3e81
fix(cli): address extension review feedback
doudouOUC Jul 10, 2026
4ff8c18
merge: resolve conflicts with origin/main for PR #6638
qwen-code-dev-bot Jul 11, 2026
db259e7
fix(extensions): address final review feedback
doudouOUC Jul 11, 2026
8d9db32
fix(extensions): address latest review feedback
doudouOUC Jul 11, 2026
c6d4c83
codex: address PR review feedback (#6638)
doudouOUC Jul 11, 2026
3c1cede
fix(core): reject links in npm extension archives
doudouOUC Jul 11, 2026
f34fbb8
fix(core): limit npm extension archive downloads
doudouOUC Jul 11, 2026
e8e5f84
fix(extensions): address review follow-ups
doudouOUC Jul 11, 2026
113f896
fix(extensions): address latest review feedback
doudouOUC Jul 11, 2026
3067e51
chore: merge main into workspace extension branch
doudouOUC Jul 11, 2026
8e25074
chore: merge latest main into extension branch
doudouOUC Jul 11, 2026
6cff963
fix(extensions): release rejected operation slots
doudouOUC Jul 11, 2026
15004ea
fix(extensions): address operation review feedback
doudouOUC Jul 11, 2026
c1cae5e
fix(extensions): align archive handling contracts
doudouOUC Jul 11, 2026
2643a3a
fix(extensions): preserve watcher generation state
doudouOUC Jul 11, 2026
21207cc
docs(extensions): align management contracts
doudouOUC Jul 11, 2026
2904340
fix(sdk): bound extension operation polls
doudouOUC Jul 12, 2026
1e26633
test(core): cover forged prepared commits
doudouOUC Jul 12, 2026
5658cb3
test(core): assert activation generation increment
doudouOUC Jul 12, 2026
44afb9c
fix(extensions): close archive and polling gaps
doudouOUC Jul 12, 2026
1654fa5
fix(cli): retry suppressed extension generations
doudouOUC Jul 12, 2026
96f80ec
test(cli): cover archive URL extension updates
doudouOUC Jul 12, 2026
b60129c
fix(sdk): preserve unbounded operation waits
doudouOUC Jul 12, 2026
cce3571
fix(core): share npm redirect download deadline
doudouOUC Jul 12, 2026
85387ec
fix(core): preserve extension reload diagnostics
doudouOUC Jul 12, 2026
a9aea07
fix(core): preserve installed Claude plugin paths
doudouOUC Jul 12, 2026
25ccbc1
fix(cli): return committed activation state
doudouOUC Jul 12, 2026
ab3496f
fix(cli): preserve extension preparation errors
doudouOUC Jul 12, 2026
5f23e58
fix(core): validate extension setting env vars
doudouOUC Jul 12, 2026
59ab121
fix(cli): target extension reconciliation
doudouOUC Jul 12, 2026
abde5b4
codex: address PR review feedback (#6638)
doudouOUC Jul 12, 2026
b81c7be
codex: address PR review feedback (#6638)
doudouOUC Jul 12, 2026
1e57061
codex: address PR review feedback (#6638)
doudouOUC Jul 12, 2026
83cb011
codex: address PR review feedback (#6638)
doudouOUC Jul 12, 2026
6b61cbb
codex: address PR review feedback (#6638)
doudouOUC Jul 12, 2026
f5ee95d
codex: address PR review feedback (#6638)
doudouOUC Jul 12, 2026
9c5bb7c
codex: address PR review feedback (#6638)
doudouOUC Jul 12, 2026
65e50f0
test(cli): cover resultless legacy commit warnings
doudouOUC Jul 12, 2026
bee57c8
fix(cli): retain suppressed extension generations
doudouOUC Jul 12, 2026
abffbc3
fix(cli): record legacy runtime reconciliation
doudouOUC Jul 12, 2026
e7cf348
fix(cli): validate extension clients by runtime
doudouOUC Jul 12, 2026
d92f71c
fix(cli): record workspace activation refresh
doudouOUC Jul 12, 2026
85f9c35
test(cli): stop extension reconcilers after cases
doudouOUC Jul 12, 2026
19885ce
fix(cli): resolve global runtimes at reconciliation
doudouOUC Jul 12, 2026
0ed83ab
fix(cli): reconcile newly registered runtimes
doudouOUC Jul 12, 2026
adb59a4
fix(cli): prevent overlapping runtime reconciliation
doudouOUC Jul 12, 2026
774975f
fix(cli): dispose late runtime apps during shutdown
doudouOUC Jul 12, 2026
cb38bdc
fix(core): keep projection repair best effort
doudouOUC Jul 12, 2026
9183308
fix(core): preserve committed store results
doudouOUC Jul 12, 2026
2566f1f
fix(core): quarantine corrupt store journals
doudouOUC Jul 12, 2026
7a1679d
fix(core): harden npm download redirects
doudouOUC Jul 12, 2026
420a5df
fix(extensions): address review edge cases
doudouOUC Jul 12, 2026
04640a5
merge(serve): reconcile extension_management_v2 with origin/main work…
qwen-code-dev-bot Jul 12, 2026
7f07ad7
chore: merge upstream main into extension management
doudouOUC Jul 12, 2026
60c8596
chore: reconcile concurrent upstream merges
doudouOUC Jul 12, 2026
4f34aa3
fix(extensions): honor cancellation between preparation stages
doudouOUC Jul 12, 2026
c0fbc57
fix(extensions): retry prepared cleanup failures
doudouOUC Jul 12, 2026
4ab8a71
test(extensions): cover committed artifact recovery boundary
doudouOUC Jul 12, 2026
8e3f2e8
fix(serve): release extension refresh queue on timeout
doudouOUC Jul 12, 2026
6f38769
codex: address PR review feedback (#6638)
doudouOUC Jul 12, 2026
8249a65
codex: address PR review feedback (#6638)
doudouOUC Jul 12, 2026
d557154
codex: address PR review feedback (#6638)
doudouOUC Jul 12, 2026
f524413
codex: address PR review feedback (#6638)
doudouOUC Jul 12, 2026
ec653f9
fix: address extension review feedback
doudouOUC Jul 12, 2026
9fa98ca
codex: address PR review feedback (#6638)
doudouOUC Jul 12, 2026
2f5e496
codex: address PR review feedback (#6638)
doudouOUC Jul 12, 2026
c1c6199
codex: address PR review feedback (#6638)
doudouOUC Jul 12, 2026
4d55a5c
codex: address PR review feedback (#6638)
doudouOUC Jul 12, 2026
bd8c4d2
fix(core): reconcile extension store compatibility state
doudouOUC Jul 12, 2026
2c7c08d
fix(core): bound npm redirects and isolate extension tests
doudouOUC Jul 12, 2026
8893d3a
fix(core): make extension uninstall store-authoritative
doudouOUC Jul 12, 2026
ea1d112
fix(core): defer prepared extension secret mutations
doudouOUC Jul 12, 2026
4549a39
fix(core): validate staged extensions before commit
doudouOUC Jul 12, 2026
47b575e
fix(core): enforce public extension network policy
doudouOUC Jul 12, 2026
4029e5a
fix(core): handle extension response failures
doudouOUC Jul 13, 2026
eaf6e7a
fix(extensions): surface committed refresh warnings
doudouOUC Jul 13, 2026
ba9fa61
fix(cli): guard timer unref calls
doudouOUC Jul 13, 2026
a81fe71
fix(extensions): release commit lane after durable writes
doudouOUC Jul 13, 2026
5437ecc
test(serve): update mutation callback assertions
doudouOUC Jul 13, 2026
bb93910
fix(serve): refresh live extension instructions
doudouOUC Jul 13, 2026
0bf9de6
fix(extensions): address latest review feedback
doudouOUC Jul 13, 2026
7077c24
fix(extensions): address follow-up review findings
doudouOUC Jul 13, 2026
b3a8623
fix(extensions): address remaining activation feedback
doudouOUC Jul 13, 2026
31e1b4a
fix(serve): preserve preparation queue status
doudouOUC Jul 13, 2026
20c44fa
fix(extensions): enforce network request deadlines
doudouOUC Jul 13, 2026
f1d9ab2
docs(serve): clarify single-workspace capabilities
doudouOUC Jul 13, 2026
d8242a7
fix(extensions): guard deferred settings commit
doudouOUC Jul 13, 2026
330d1e6
fix(extensions): cancel archive extraction
doudouOUC Jul 13, 2026
e70ab39
fix(extensions): harden refresh recovery
doudouOUC Jul 13, 2026
d5ebf30
fix(serve): serialize extension reconciliation
doudouOUC Jul 13, 2026
c215581
fix(extensions): address post-commit review feedback
doudouOUC Jul 13, 2026
15b158f
codex: address PR review feedback (#6825)
doudouOUC Jul 13, 2026
79dbbd8
codex: address PR review feedback (#6825)
doudouOUC Jul 13, 2026
469e40e
merge: resolve conflicts with origin/main
qwen-code-dev-bot Jul 13, 2026
8b31fb3
codex: address PR review feedback (#6825)
doudouOUC Jul 13, 2026
ad3094a
chore: merge latest main into extension branch
doudouOUC Jul 13, 2026
2b109cf
codex: fix CI failure on PR #6825
doudouOUC Jul 13, 2026
4a54041
codex: fix CI failure on PR #6825
doudouOUC Jul 13, 2026
604ff49
codex: address PR review feedback (#6825)
doudouOUC Jul 13, 2026
ddc23db
fix: address critical PR review feedback
doudouOUC Jul 13, 2026
da49ee2
fix(cli): bound legacy extension update checks
doudouOUC Jul 13, 2026
31cc191
fix(acp): deduplicate extension refresh requests
doudouOUC Jul 13, 2026
72340c0
codex: address PR review feedback (#6825)
doudouOUC Jul 14, 2026
c313731
codex: address PR review feedback (#6825)
doudouOUC Jul 14, 2026
8a0be85
codex: address PR review feedback (#6825)
doudouOUC Jul 14, 2026
425d9df
codex: address PR review feedback (#6825)
doudouOUC Jul 14, 2026
01d845b
merge: resolve conflicts with origin/main for extension management v2
qwen-code-dev-bot Jul 14, 2026
26ca02f
fix(sdk): update browser bundle budget after main merge
doudouOUC Jul 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 223 additions & 0 deletions docs/design/extension-management-v2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
# Extension Management V2

## Status

This design extends daemon protocol `v1` under the additive
`extension_management_v2` capability. The already-published
`workspace_extensions` capability and `/workspace/extensions/*` routes remain
available as a primary-workspace compatibility adapter.

## Resource model

An installed extension is one user-level artifact in `QWEN_HOME/extensions`.
Activation is policy, not a second copy of that artifact:

1. An exact workspace override (`enabled` or `disabled`).
2. An internal exact `inherit` mask created while migrating legacy path rules.
3. An ordered V1 path rule.
4. The global default.

Workspace identity uses the daemon's canonical workspace path. A workspace
route selects an existing runtime by workspace id first and canonical cwd
second. Reads are allowed for untrusted runtimes; activation changes, refresh,
and workspace-scoped install require a trusted target. Global mutation uses the
normal daemon mutation authentication and install consent, not the trust state
of whichever workspace initiated the request.

## Store and transaction boundary

`ExtensionStore` is the only writer of final extension directories and V2
activation state. `ExtensionManager` remains the workspace-facing facade, but
CLI, TUI, auto-update, daemon, and SDK-backed operations delegate mutations to
the store.

The layout is:

```text
~/.qwen/
├── extensions/
└── extension-store/
├── lock
├── state.json
├── state.previous.json
├── staging/
├── rollback/
└── transactions/
```

The store and artifacts share a filesystem so artifact swaps are directory
renames. An in-process mutex and a `proper-lockfile` lock serialize commits
across all V2-aware processes. Every mutation re-reads state while holding the
lock and increments a monotonic generation, preventing lost updates.

Install/update preparation happens outside the final artifact directory. The
commit writes a `prepared` journal, moves the old artifact to rollback, moves
staging into place, and atomically writes `state.json`. That state rename is the
commit point. Before it, recovery rolls back; after it, recovery only completes
projection and cleanup. A committed policy is never rolled back because one
runtime refresh failed. If both a pre-commit operation and its rollback fail,
the caller receives both errors and the journal remains for fail-closed recovery;
the store does not continue writing through an ambiguous artifact state.

Store files use owner-only permissions and atomic no-follow writes. Extension
ids, direct-child artifact paths, transaction paths, and names are validated.
Failures are reported with credential-redacted sources.

## V1 migration and downgrade projection

The first V2-aware process imports ordered rules from
`extension-enablement.json` without materializing the current set of registered
workspaces as exact overrides. V2 writes a compatible projection after each
state commit and stores its hash in `state.json`.

If hashes differ, modification order decides the recovery direction: an older
projection is repaired from authoritative V2 state; a projection modified after
V2 state is treated as a sequential write by a downgraded binary and is
re-imported with a new generation. Concurrent V1 and V2 writers sharing one
`QWEN_HOME` are intentionally unsupported.

Clearing a public workspace override normally deletes the exact record. If an
older path rule would then change the effective value, the store writes an
internal `inherit` mask so DELETE still means “inherit the global default.”

## Daemon API

The global surface is:

```text
GET /extensions
POST /extensions/install
POST /extensions/check-updates
POST /extensions/:extensionId/update
DELETE /extensions/:extensionId
PUT /extensions/:extensionId/activation
GET /extensions/operations/:operationId
```

Install requires explicit consent and initial activation:

```ts
type InitialActivation =
| { scope: 'user' }
| { scope: 'workspace'; workspaceId: string };
```

The daemon install endpoint accepts HTTPS Git, GitHub Release, and npm sources
under the public network policy. SSH and local/link sources remain local CLI
features. Update preserves the extension id,
manifest name, settings, and activation policy. “Already current” is a
successful `updated: false` result. Uninstall is idempotent and removes both the
artifact and policy.

The workspace projection is:

```text
GET /workspaces/:workspace/extensions
PUT /workspaces/:workspace/extensions/:extensionId/activation
DELETE /workspaces/:workspace/extensions/:extensionId/activation
POST /workspaces/:workspace/extensions/refresh
```

It intentionally has no workspace artifact mutation routes. Projection entries
include default, exact workspace value, effective value, and source. Desired
generation and locally applied generation are top-level response fields.

Potentially slow mutations return `202`, `Location`, and `Retry-After`. The
operation record is daemon-local memory, retains at most 100 terminal records,
and can disappear on restart. Catalog/store recovery is authoritative. SDK
polling timeout stops polling only; it never cancels accepted work.

The daemon admits at most 10 unfinished extension operations. A daemon-wide
FIFO preparation queue runs at most two downloads, extractions, conversions,
or single-extension update checks at once. Install and update use an explicit
`prepare -> commit/dispose` lifecycle: preparation owns staging files and
revisioned credential snapshots but does not change the store, cache, runtime,
or credentials selected by the installed artifact. Prepared mutations enter a
separate single-concurrency FIFO commit queue in the order preparation
finishes. Activation and uninstall enter only the commit queue; check-updates
enters only the preparation queue. Manual refresh is serialized through the
commit queue. Its HTTP timeout releases that lane so a stalled runtime refresh
cannot permanently block later extension mutations; the already-started refresh
may still settle afterward. Sensitive settings are staged as one atomic secret
bundle under a per-prepare revision. A non-secret selector records that revision
and secure-storage backend inside the staged artifact, so only the winning
artifact commit activates a complete bundle. The store commit is therefore the
durability point and releases the commit lane immediately. Extension reload,
legacy per-key settings synchronization, manager runtime refresh, prepared-file
cleanup, and daemon runtime reconciliation run outside it. These post-commit
steps do not occupy either slot, so later commits may proceed while an earlier
generation is being applied or cleaned up.

Disposing a prepared mutation removes its unselected credential snapshot, and a
successful commit removes the previously selected snapshot best-effort. A hard
process crash before disposal can leave an unreachable entry in the secure
backend; no artifact selector references it, so it cannot become active or be
mistaken for the committed credentials.

The preparation deadline starts when an operation first acquires a preparation
slot, not while it waits. Abort is propagated to network operations and active
archive scanning and extraction streams. A started task continues to occupy its
slot until its underlying promise settles even if it ignores abort. Commit is
not cancellable. Prepared updates carry the target artifact generation:
unrelated extension or activation changes safely rebase, while a stale update
of the same artifact fails with `extension_conflict`.

Remote npm metadata is streamed with a 10 MiB response cap. npm and GitHub
archives have separate 100 MiB download caps, request deadlines, redirect
limits, and archive-entry validation before extraction.

## Runtime reconciliation

A successful commit invalidates local status and refreshes affected runtimes.
Global artifact/default changes reconcile all runtimes in this daemon; an exact
workspace override reconciles only its target. Runtime reconciliation refreshes
extension and skill caches, extension tools, hierarchical memory, active chat
system instructions, and available commands. A failed component does not skip
the remaining refresh components; the session RPC reports the combined failure
after all components have been attempted. Runtime generation reconciliation
uses a daemon-wide FIFO shared by mutations and the generation poller. A
mutation reserves its position at the durable commit callback, so later
generations cannot refresh a runtime first even when earlier post-commit work
finishes later.
The ACP bridge bounds each session refresh at 30 seconds. If the aggregate
refresh still exceeds the route deadline, the controller releases the commit
lane without cancelling the underlying RPC. Applying generation N also
satisfies waiters for older generations,
and a late lower-generation refresh therefore cannot move the applied
generation backwards. Partial refresh failure or post-commit reload/cleanup
failure produces `succeeded_with_warnings` with workspace-specific or commit
diagnostics, without rolling back the artifact.

Legacy workspace migration treats a committed artifact as failed only when it
could not be reloaded. Settings compatibility synchronization, cleanup, or
runtime-refresh warnings do not trigger a retry of an artifact that is already
durably installed. Update callers receive warning details; compatibility and
cleanup warnings use a distinct `updated with warnings` state, while reload or
runtime-refresh failures remain `updated, needs restart`.

The extension file watcher observes only `extension-store/state.json` for
policy generation and continues to observe installed/linked extension content
for command, skill, agent, hook, and MCP changes. A 30-second generation poll
repairs missed filesystem events and bounds convergence for other daemons that
share the store.

## Compatibility

`workspace_extensions` remains the capability for the existing singular
surface. Its handlers call the same manager/coordinator and adapt responses:
project activation becomes a primary workspace override; user activation keeps
the legacy rule-clearing behavior; global mutation reconciles every local
runtime. The legacy operation endpoint maps V2 warning completion back to the
published legacy refresh-error status.

Clients must check `extension_management_v2`; neither daemon mode nor another
workspace capability implies this API. The abandoned
`workspace_qualified_extensions` proposal is not part of the protocol.

## Non-goals

- Per-workspace artifact copies.
- A daemon registry or remote acknowledgement protocol.
- User cancellation of accepted operations.
- Concurrent old-binary and V2-aware writes to one `QWEN_HOME`.
- Removing the V1 adapter before a future protocol-v2 migration.
2 changes: 2 additions & 0 deletions docs/developers/daemon/11-capabilities-versioning.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ Permissions: `session_permission_vote`, `permission_vote`, **`permission_mediati

Workspace read-only snapshots: `workspace_mcp`, `workspace_skills`, `workspace_providers`, `workspace_env`, `workspace_preflight`, `workspace_hooks`, `workspace_extensions`.

Extension management: `extension_management_v2` adds the global `/extensions/*` catalog/mutation/operation contract and the workspace activation projection. It is separate from the published `workspace_extensions` compatibility surface and from `workspace_qualified_rest_core`.

Workspace mutation (Wave 4+): `workspace_memory`, `workspace_agents`, `workspace_agent_generate`, `workspace_tool_toggle`, **`workspace_settings`** (conditional), `workspace_permissions`, `workspace_init`, `workspace_github_setup`, `workspace_trust`, `workspace_mcp_restart`, `workspace_mcp_manage`, `workspace_file_read`, `workspace_file_bytes`, `workspace_file_write`, **`workspace_reload`** (conditional).

MCP guardrails: **`mcp_guardrails`** (`modes: ['warn', 'enforce']`), `mcp_guardrail_events`, `mcp_server_runtime_mutation`, **`mcp_workspace_pool`** (conditional), **`mcp_pool_restart`** (conditional).
Expand Down
Loading
Loading