Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
f931162
feat(serve): scope extensions to workspace runtimes
Sep 5, 2026
f65c0e8
test(serve): cover extension runtime capabilities
Sep 5, 2026
9493fa6
Merge remote-tracking branch 'origin/main' into codex/daemon-workspac…
Sep 5, 2026
fbec518
fix(serve): address round-1 review findings on Extension runtime read…
qwen-code-ci-bot Sep 6, 2026
e77c512
Merge branch 'main' into codex/daemon-workspace-runtime-extensions-main
wenshao Sep 6, 2026
d431d17
Merge branch 'main' into codex/daemon-workspace-runtime-extensions-main
qwen-code-dev-bot Sep 6, 2026
e9c084c
test(cli): wait out the serve bootstrap window in the capabilities en…
qwen-code-dev-bot Sep 6, 2026
9fed1f0
Merge branch 'main' into codex/daemon-workspace-runtime-extensions-main
qwen-code-dev-bot Sep 6, 2026
0e3dbea
fix(serve): address extension runtime review findings
Sep 7, 2026
ac63bb4
Merge remote-tracking branch 'origin/main' into codex/daemon-workspac…
Sep 7, 2026
26ed5a5
fix(web-shell): keep split Extension runtime loaders off untrusted wo…
Sep 7, 2026
9ae66ef
Merge remote-tracking branch 'origin/main' into codex/daemon-workspac…
qwen-code-ci-bot Sep 7, 2026
c7030d9
fix(serve): address round-4 extension runtime review findings (#11086)
qwen-code-ci-bot Sep 7, 2026
403b254
Merge remote-tracking branch 'origin/main' into codex/daemon-workspac…
qwen-code-ci-bot Sep 7, 2026
dedac49
fix(web-shell): annotate composer action merge as AtMentionWorkspaceA…
qwen-code-ci-bot Sep 7, 2026
f1a4858
fix(serve): address round-5 extension runtime review findings (#11086)
qwen-code-ci-bot Sep 8, 2026
aae6c06
fix(web-shell): cancel MessageList scroll-settle timer on unmount (#1…
qwen-code-ci-bot Sep 8, 2026
93a7ae7
fix(web-shell): surface extension runtime readiness errors
Sep 8, 2026
e96a0ed
fix(serve): close extension readiness gaps
Sep 8, 2026
882a153
fix(web-shell): merge main, keeping upstream locate scroll timer
qwen-code-dev-bot Sep 8, 2026
69604a9
fix(serve): address round-6 extension runtime findings and merge main…
qwen-code-ci-bot Sep 8, 2026
b97231b
Merge remote-tracking branch 'origin/main' into codex/daemon-workspac…
qwen-code-ci-bot Sep 8, 2026
ca96071
fix(web-shell): address round-7 extension runtime findings (#11086)
qwen-code-ci-bot Sep 8, 2026
80d2ab8
test(web-shell): repair render indicator in split-session rerender te…
qwen-code-ci-bot Sep 8, 2026
1937afd
chore(web-shell): merge main into #11086, keep strengthened split-rer…
qwen-code-dev-bot Sep 9, 2026
6296997
fix(serve): address extension reconciliation and notice review
Sep 9, 2026
8fd4108
Merge remote-tracking branch 'origin/main' into codex/daemon-workspac…
Sep 9, 2026
29ea351
fix(serve): preserve cold-runtime extension install success
Sep 9, 2026
75f6b12
Merge branch 'main' into codex/daemon-workspace-runtime-extensions-main
qwen-code-dev-bot Sep 9, 2026
35bf4f6
Merge branch 'main' into codex/daemon-workspace-runtime-extensions-main
qwen-code-dev-bot Sep 9, 2026
c031c91
fix(serve): Preserve extension reconciliation and operation lifecycle…
Sep 10, 2026
c80017e
Merge origin/main into codex/daemon-workspace-runtime-extensions-main
Sep 10, 2026
abb6fef
fix(extensions): Allow slow reconciliation and show unknown activation
Sep 10, 2026
641804c
fix(extensions): detect reused store generations and harden recovery …
Sep 10, 2026
0774d33
Merge branch 'main' into codex/daemon-workspace-runtime-extensions-main
qwen-code-dev-bot Sep 10, 2026
c246135
Merge remote-tracking branch 'origin/main' into codex/daemon-workspac…
qwen-code-ci-bot Sep 10, 2026
faefc6c
fix(extensions): hash receipts, scope update supersession, flag drain…
qwen-code-ci-bot Sep 10, 2026
26aafd9
fix(extensions): track recovered store identity during reconciliation
Sep 11, 2026
4e35093
Merge remote-tracking branch 'origin/main' into codex/daemon-workspac…
Sep 11, 2026
5fc7d91
fix(extensions): normalize source-addressed update operations
Sep 11, 2026
44983f7
Merge branch 'main' into codex/daemon-workspace-runtime-extensions-main
ytahdn Sep 11, 2026
8c027e5
fix(extensions): address round-15 extension runtime review findings (…
qwen-code-ci-bot Sep 11, 2026
878b891
Merge branch 'main' into codex/daemon-workspace-runtime-extensions-main
qwen-code-dev-bot Sep 12, 2026
4913ac9
Merge branch 'main' into codex/daemon-workspace-runtime-extensions-main
qwen-code-dev-bot Sep 12, 2026
167621f
Merge remote-tracking branch 'origin/main' into codex/daemon-workspac…
qwen-code-dev-bot Sep 12, 2026
357979f
fix(cli): close review-round reconciliation and interaction gaps (#11…
qwen-code-dev-bot Sep 12, 2026
22da331
Merge branch 'main' into codex/daemon-workspace-runtime-extensions-main
qwen-code-dev-bot Sep 12, 2026
3e48daa
fix(cli): keep a late install sweep from cancelling newer parked oper…
qwen-code-dev-bot Sep 13, 2026
8285097
Merge branch 'main' into codex/daemon-workspace-runtime-extensions-main
wenshao Sep 13, 2026
8e4e3c8
fix(cli): re-check extension readiness in-queue and order the install…
qwen-code-dev-bot Sep 13, 2026
4c1733f
Merge branch 'main' into codex/daemon-workspace-runtime-extensions-main
qwen-code-dev-bot Sep 13, 2026
0d75dee
Merge remote-tracking branch 'origin/main' into pr-11086-takeover
wenshao Sep 13, 2026
ef6b267
test(serve): pin extension interaction re-entry and fix activationSou…
wenshao Sep 13, 2026
b231153
fix(cli): close extension-generation certification gaps on ensure and…
qwen-code-dev-bot Sep 14, 2026
e756254
Merge branch 'main' into codex/daemon-workspace-runtime-extensions-main
qwen-code-dev-bot Sep 14, 2026
bd6077c
Merge branch 'main' into codex/daemon-workspace-runtime-extensions-main
qwen-code-dev-bot Sep 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
137 changes: 137 additions & 0 deletions docs/design/daemon-workspace-runtime-extensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Daemon Workspace Runtime Extensions

[English](daemon-workspace-runtime-extensions.md) | [简体中文](daemon-workspace-runtime-extensions.zh-CN.md)

## Goal

Move Extension management onto workspace-owned runtimes without requiring a
chat session. Keep the existing Extension Store as the durable global owner and
use the selected runtime only for the live catalog and reconciliation.

## Ownership

- `GET /extensions` remains the daemon-local global artifact catalog.
- `GET /workspaces/:workspace/extensions` remains the durable activation
projection for one workspace.
- `GET /workspaces/:workspace/runtime/extensions` returns the selected live
runtime catalog and its runtime epoch.
- `WorkspaceRuntimeCoordinator` owns desired/applied Extension generation,
capability readiness, runtime refresh, and stale-result rejection.
- Global mutations invalidate every managed runtime. Workspace activation and
resource-state mutations invalidate only the selected runtime.

The coordinator is the only writable owner of runtime Extension readiness.
The route controller continues to own operation history and durable mutation
sequencing, but reports committed generations to each affected coordinator.

## Reconciliation

An Extension commit is successful once the Extension Store commit succeeds.
For each affected trusted live runtime, the coordinator refreshes the bootstrap
configuration, discovery configuration, and active sessions, then reads the
live Extension catalog. It marks the capability ready only when the response
comes from the current runtime epoch and the applied generation equals the
latest desired generation. Cold runtimes remain deferred and converge on the
Comment thread
ytahdn marked this conversation as resolved.
next `ensureRuntime()`.

Only ensure starts a cold runtime; queued reconciliation rechecks liveness and
never preheats. Applied generation is certified in a particular runtime epoch.
A narrow Skill refresh cannot carry that certification across an epoch change.
An obsolete generation returns `superseded`, not a refresh failure. Deferred
drain work preserves its narrow/full scope; full work takes precedence when
both are pending. A repeated failure re-arms the retry cooldown.

The physical refresh has the same five-minute budget as MCP controls because
it includes MCP discovery. The shorter ensure observation deadline does not
cancel that refresh; a later successful result can still certify readiness.
Hard timeouts retain the bridge's channel-retirement policy.

Observing a new generation invalidates retained Skill snapshots even while the
runtime is cold. Projection generation equality alone is not readiness: use
the current epoch and the coordinator capability state. Restore of a lower
store generation is supported by the poller's fresh authoritative read: it
invalidates applied certification and advances the coordinator revision. A
read overtaken by another observed mutation cannot lower the generation;
operation receipts alone never lower it. A recovery and recommit between two
reads reuses the generation number for different content, which the number
alone cannot show; the poller records the store's content hash, and a changed
hash at the desired generation clears applied certification and re-drives
reconciliation. The hash covers the entire store snapshot, including Skill
overrides and artifact metadata, not just the legacy enablement projection.
Recovery persists a fresh `recoveryId` (optional for existing V2 stores), so
recommits with identical artifact metadata still have a distinct identity.
Changing that recovery identity invalidates certification even when subsequent
commits advance the generation; a narrow Skill refresh cannot certify the
recovered artifacts without a full apply first.
An unknown prior hash or unreadable receipt identity requires reapplication;
reads overtaken by another observation cannot replace its identity, even at
the same generation.

Extension invalidation also invalidates the selected runtime's Skills and MCP
capabilities because both catalogs include Extension contributions. A late
refresh or catalog response from a replaced runtime cannot advance readiness.

## API and SDK

Runtime status adds an `extensions` capability with `state`, `revision`,
`runtimeEpoch`, `desiredGeneration`, and `appliedGeneration`. Extension runtime
catalog responses add `runtimeEpoch`.

`WorkspaceDaemonClient` exposes the runtime catalog. Global install, update,
uninstall, update-check, and default activation remain on `DaemonClient`;
workspace activation, Extension Skill state, projection reads, and runtime
catalog reads remain on `WorkspaceDaemonClient`.

Source installs use the V2 global route. Archive uploads remain on the legacy
workspace route until a V2 archive endpoint exists, so they retain the legacy
default-activation behavior.

Interactive installs and updates share the existing operation interaction
endpoint under `/workspace/extensions/operations`. Their preparation deadline
cancels pending input. Prepared resources remain owned by the route until its
`finally` disposal, including when the deadline prevents commit.

## Web Shell

When the daemon advertises `workspace_extensions_config_runtime`, the
Extensions page:

1. loads the global catalog and selected workspace projection without starting
ACP;
2. calls the shared parameterless runtime ensure;
3. merges live details and `isActive` when the durable catalog generation and
coordinator are available, the runtime catalog is initialized, and capability
and catalog epochs match the coordinator epoch. Readiness and matching
desired/applied generations on the capability and activation projection
determine whether to re-read the catalog and projection, not whether to
retain matching-epoch live rows;
4. shows the workspace selector on the list page and the disabled selector in
detail view.

Older daemons keep the existing primary-workspace flow.

When both the workspace activation projection and live activation state are
unavailable, list and detail badges show unknown, not the global default.

When the daemon also advertises `workspace_extension_mentions`, the composer
uses the selected workspace runtime for both the `+` and `@` Extension menus.
Without that feature, it keeps the legacy primary-workspace loader.

Notice attribution and the in-flight lock are distinct: an unknown or absent
Extension name falls back to the global notice surface without releasing the
active operation's lock.

## Verification

Cover cold/queued-cold runtimes, superseded generations, runtime replacement,
same-epoch narrow refresh, drain replay, repeated failure cooldown, retained
Skills invalidation, expired interactive preparation, and recovered notices.
Run the existing local-install integration test without starting an ACP child.

## Downstream consumers

- runtime status and workspace management routes;
- Extension V2 operation reconciliation and external-generation polling;
- Skills and MCP capability invalidation;
- TypeScript daemon SDK;
- Web Shell Plugin manager and Extensions manager.
103 changes: 103 additions & 0 deletions docs/design/daemon-workspace-runtime-extensions.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Daemon 工作区运行时拓展

[English](daemon-workspace-runtime-extensions.md) | [简体中文](daemon-workspace-runtime-extensions.zh-CN.md)

## 目标

将拓展管理迁移到工作区所属运行时,无需创建聊天 session。现有 Extension Store
继续作为全局持久化所有者,仅实时目录和协调刷新使用选定运行时。

## 所有权

- `GET /extensions` 是 daemon 本地的全局制品目录。
- `GET /workspaces/:workspace/extensions` 是一个工作区的持久化激活投影。
- `GET /workspaces/:workspace/runtime/extensions` 返回选定运行时的实时目录和 epoch。
- `WorkspaceRuntimeCoordinator` 拥有期望/已应用 generation、能力就绪态、运行时刷新及过期结果拒绝。
- 全局变更使所有受管理运行时失效;工作区激活和资源状态变更只使选定运行时失效。

协调器是拓展运行时就绪态的唯一可写所有者。路由控制器仍拥有操作历史和持久化变更
排序,并将已提交 generation 通知受影响协调器。

## 协调刷新

Extension Store 提交成功即表示拓展变更成功。对受影响且可信的活动运行时,协调器
刷新 bootstrap 配置、发现配置及活动 session,然后读取实时目录。只有响应来自当前
epoch,且已应用 generation 等于最新期望 generation,能力才标记为 ready。
冷运行时保持 deferred,等下次 `ensureRuntime()` 再生效。

只有 ensure 启动冷运行时;排队后的协调刷新重新检查存活状态,不执行 preheat。
已应用 generation 的认证属于特定 epoch,窄范围 Skill 刷新不能跨 epoch 继承认证。
过时 generation 返回 `superseded`,不算刷新失败。drain 延后任务保留窄/完整范围,
两者同时待处理时完整刷新优先。冷却结束后再次失败会重新开始冷却。

实际刷新包含 MCP 发现,因此采用与 MCP 控制相同的五分钟预算。较短的 ensure
观察截止时间不会取消刷新;稍后成功的结果仍可认证就绪态。
硬超时保留 bridge 现有的通道退役策略。

观察到新 generation 时,即使运行时是冷的,也使保留的 Skill 快照失效。
投影 generation 相等不独立代表就绪,还需当前 epoch 和协调器能力状态。
轮询器的新鲜权威读取支持存储恢复到较低 generation:清除已应用认证并推进协调器 revision。
读取期间若观察到其他变更,则该读取不能降低 generation;仅操作回执始终不能降低 generation。
若恢复与重新提交发生在两次读取之间,generation 编号会被不同内容复用,仅凭编号无法发现;
轮询器记录存储内容哈希,相同 generation 上哈希变化即清除已应用认证并重新驱动协调。
哈希覆盖完整存储快照,包括 Skill 开关和安装产物元数据,而不只是旧版启用规则投影。
恢复时持久化新的 `recoveryId`(兼容缺少此字段的现有 V2 存储),使产物元数据完全相同的
重新提交仍具有不同身份。恢复身份变化时,即使后续提交推进了 generation,也清除认证;
恢复的产物必须先完整应用,不能由窄范围 Skill 刷新直接认证。
此前哈希未知或回执身份读取失败时需要重新应用;读取期间若已有更新的观察,
即使 generation 相同,也不能用迟到的读取替换内容身份。

拓展应用还会使选定运行时的 Skills 和 MCP 能力失效,因为两个目录均包含拓展贡献。
来自已替换运行时的迟到刷新或目录响应不能推进就绪态。

## API 与 SDK

运行时状态增加 `extensions` 能力,包含 `state`、`revision`、`runtimeEpoch`、
`desiredGeneration`、`appliedGeneration`。实时拓展目录响应增加 `runtimeEpoch`。

`WorkspaceDaemonClient` 提供实时目录。全局安装、更新、卸载、更新检查、默认激活
保留在 `DaemonClient`;工作区激活、拓展 Skill 状态、投影和实时目录读取保留在
`WorkspaceDaemonClient`。

来源安装使用 V2 全局路由。V2 归档端点存在之前,归档上传仍走旧工作区路由,保留旧的
默认激活行为。

交互安装和更新共用 `/workspace/extensions/operations` 下现有的交互应答端点。
准备阶段截止时间取消待输入交互。已准备资源由路由持有,直到其 `finally` 释放,
包括截止时间阻止提交的情况。

## Web Shell

daemon 声明 `workspace_extensions_config_runtime` 时,拓展页面:

1. 读取全局目录和选定工作区投影,不启动 ACP;
2. 调用共享的无参数运行时 ensure;
3. 当持久目录 generation 与协调器可用、实时目录已初始化、能力和目录 epoch 均匹配
协调器 epoch 时,合并实时详情及 `isActive`。能力就绪及能力/投影的期望与已应用
generation 相等决定是否重新读取目录和投影,不决定是否保留 epoch 匹配的实时行;
4. 列表页显示工作区选择器,详情页显示禁用的选择器。

旧 daemon 保留现有主工作区流程。

工作区激活投影和实时激活状态都不可用时,列表及详情徽标显示状态未知,
不使用全局默认值代替。

daemon 同时声明 `workspace_extension_mentions` 时,输入区 `+` 和 `@` 拓展菜单
使用选定工作区运行时;否则保留旧主工作区加载器。

提示归属和进行中操作锁互相独立:未知或缺失的拓展名称回退到全局提示区域,但不释放
活动操作的锁。

## 验证

覆盖冷/排队后变冷运行时、过时 generation、运行时替换、同 epoch 窄刷新、drain
回放、连续失败冷却、保留 Skills 失效、交互准备超时及恢复操作提示。
执行现有本地安装集成测试,确认不启动 ACP child。

## 下游消费者

- 运行时状态和工作区管理路由;
- 拓展 V2 操作协调及外部 generation 轮询;
- Skills 与 MCP 能力失效;
- TypeScript daemon SDK;
- Web Shell Plugin 管理器和拓展管理器。
Loading
Loading