@platless/axom-cli 0.6.36 → 0.6.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/dist/axom-patch/cli/README.md +31 -2
- package/dist/axom-patch/cli/account-limits/generate.py +2 -2
- package/dist/axom-patch/cli/claude-replay-lifecycle.json +16 -0
- package/dist/axom-patch/cli/codex-terminal-output.json +2 -2
- package/dist/axom-patch/cli/probes/claude-replay-lifecycle.mjs +31 -0
- package/dist/axom-patch/cli/probes/codex-terminal-output.mjs +1 -1
- package/dist/axom-patch/cli/probes/zcode-env-account.mjs +81 -0
- package/dist/axom-patch/cli/probes/zcode-subagent-subwork.mjs +7 -0
- package/dist/axom-patch/cli/qoder/dist/axom-acp-compat.mjs +137 -41
- package/dist/axom-patch/cli/qoder/releases/1.1.75.json +5 -88
- package/dist/axom-patch/cli/qoder-native-acp.json +23 -23
- package/dist/axom-patch/cli/runtime.json +3 -1
- package/dist/axom-patch/cli/zcode/env-account.mjs +13 -0
- package/dist/axom-patch/cli/zcode/generate-env-account.py +52 -0
- package/dist/axom-patch/cli/zcode-account-limits.json +7 -7
- package/dist/axom-patch/cli/zcode-env-account.json +58 -0
- package/dist/axom-patch/cli/zcode-models.json +9 -9
- package/dist/axom-patch/cli/zcode-subagent-subwork.json +10 -10
- package/dist/cli.js +9 -11
- package/dist/commands/auth.js +4 -1
- package/dist/commands/update.js +68 -7
- package/dist/commands/workstation.js +94 -223
- package/dist/commands/workstationRegistrations.js +116 -0
- package/dist/credentialBroker.js +13 -2
- package/dist/credentials.js +16 -0
- package/dist/install/claude/commands.js +2 -2
- package/dist/keepers/terminal/keeper.mjs +1089 -673
- package/dist/keepers/terminal/manifest.json +4 -4
- package/dist/native/darwin-x64/axom-quic +0 -0
- package/dist/workstation/acp/acpAgents.js +11 -4
- package/dist/workstation/acp/outbox.js +12 -5
- package/dist/workstation/acp/permission.js +2 -2
- package/dist/workstation/acp/processor/checkpoint.js +4 -3
- package/dist/workstation/acp/processor/control.js +2 -2
- package/dist/workstation/acp/processor/jsonrpc.js +8 -0
- package/dist/workstation/acp/processor/session.js +3 -2
- package/dist/workstation/acp/processor/state.js +1 -0
- package/dist/workstation/acp/processor/transport/local.js +19 -3
- package/dist/workstation/acp/processor/updates.js +25 -0
- package/dist/workstation/acp/processorSession.js +12 -1
- package/dist/workstation/acp/registry/catalog.js +6 -6
- package/dist/workstation/acp/test/keeperWorld.js +4 -3
- package/dist/workstation/agentSessions.js +76 -23
- package/dist/workstation/channels/agent.js +9 -1
- package/dist/workstation/channels/computer.js +27 -4
- package/dist/workstation/channels/management.js +36 -5
- package/dist/workstation/config.js +18 -6
- package/dist/workstation/control/bindingStore.js +4 -0
- package/dist/workstation/control/commands.js +1 -0
- package/dist/workstation/control/daemonIdentity.js +90 -0
- package/dist/workstation/control/deviceCommands.js +191 -0
- package/dist/workstation/control/deviceProtocol.js +68 -0
- package/dist/workstation/control/locks.js +51 -4
- package/dist/workstation/control/rootFormat.js +16 -0
- package/dist/workstation/control/runtimeClient.js +60 -5
- package/dist/workstation/control/runtimeHost.js +96 -9
- package/dist/workstation/control/serverIdentity.js +2 -2
- package/dist/workstation/control/updateTransition.js +91 -0
- package/dist/workstation/daemon.js +262 -360
- package/dist/workstation/daemonctl.js +150 -12
- package/dist/workstation/desktopControl/automationDevice.js +219 -0
- package/dist/workstation/desktopControl/automationJson.js +74 -0
- package/dist/workstation/desktopControl/automationLocalState.js +23 -0
- package/dist/workstation/desktopControl/automationPreparation.js +1 -0
- package/dist/workstation/desktopControl/automationProtocol.js +253 -0
- package/dist/workstation/desktopControl/automationSchema.generated.js +1 -0
- package/dist/workstation/desktopControl/automationSession.js +81 -0
- package/dist/workstation/desktopControl/automationTransport.js +138 -0
- package/dist/workstation/desktopControl/capabilities.js +2 -1
- package/dist/workstation/desktopControl/deviceAdmission.js +229 -0
- package/dist/workstation/desktopControl/deviceOwnership.js +130 -0
- package/dist/workstation/desktopControl/deviceSockets.js +2 -2
- package/dist/workstation/desktopControl/helperProcess.js +250 -1
- package/dist/workstation/desktopControl/hostGrant.js +65 -0
- package/dist/workstation/desktopControl/lobby.js +4 -2
- package/dist/workstation/desktopControl/macProvider.js +41 -40
- package/dist/workstation/desktopControl/nativeDeviceAdmission.js +207 -0
- package/dist/workstation/desktopControl/nativeProvider.js +31 -5
- package/dist/workstation/desktopControl/ownershipProtocol.js +31 -0
- package/dist/workstation/desktopControl/protocol.js +15 -6
- package/dist/workstation/desktopControl/supervisor.js +110 -17
- package/dist/workstation/desktopControl/wallpaper.js +26 -6
- package/dist/workstation/exec/policy.js +5 -0
- package/dist/workstation/files/client.js +10 -1
- package/dist/workstation/files/host.js +9 -2
- package/dist/workstation/journal.js +5 -2
- package/dist/workstation/keepers/acp/client.js +38 -2
- package/dist/workstation/keepers/kit/buildVersion.js +35 -11
- package/dist/workstation/keepers/kit/client.js +2 -2
- package/dist/workstation/keepers/kit/launcher.js +80 -4
- package/dist/workstation/keepers/legacy.js +16 -2
- package/dist/workstation/keepers/policy.js +5 -34
- package/dist/workstation/keepers/terminal/client.js +115 -23
- package/dist/workstation/keepers/terminal/exec.js +6 -3
- package/dist/workstation/keepers/terminal/frames.js +73 -0
- package/dist/workstation/keepers/terminal/generations.js +5 -8
- package/dist/workstation/keepers/terminal/gridProtocol.js +16 -0
- package/dist/workstation/keepers/terminal/input.js +146 -0
- package/dist/workstation/keepers/terminal/keeper.js +22 -8
- package/dist/workstation/keepers/terminal/main.js +1 -1
- package/dist/workstation/keepers/terminal/metadata.js +138 -0
- package/dist/workstation/keepers/terminal/protocol.js +4 -28
- package/dist/workstation/keepers/terminal/pty.js +1 -330
- package/dist/workstation/keepers/terminal/screen.js +246 -0
- package/dist/workstation/keepers/terminal/sessions.js +526 -0
- package/dist/workstation/oauth/deviceAuthorization.js +31 -17
- package/dist/workstation/protocol/management.js +23 -4
- package/dist/workstation/rd/artifact.js +4 -3
- package/dist/workstation/rd/control.js +3 -5
- package/dist/workstation/rd/host.js +213 -0
- package/dist/workstation/rd/migrationReadiness.js +46 -0
- package/dist/workstation/rd/provider.js +44 -10
- package/dist/workstation/rd/state.js +14 -2
- package/dist/workstation/rd/update.js +5 -8
- package/dist/workstation/rd/upkeep.js +44 -2
- package/dist/workstation/registrations/enrollment.js +250 -0
- package/dist/workstation/registrations/enrollmentPending.js +361 -0
- package/dist/workstation/registrations/migration.js +356 -0
- package/dist/workstation/registrations/model.js +34 -0
- package/dist/workstation/registrations/removal.js +222 -0
- package/dist/workstation/registrations/store.js +737 -0
- package/dist/workstation/runtime/desktopBinding.js +20 -0
- package/dist/workstation/runtime/deviceDesktop.js +193 -0
- package/dist/workstation/runtime/deviceRuntime.js +568 -0
- package/dist/workstation/runtime/deviceServices.js +117 -0
- package/dist/workstation/runtime/events.js +20 -0
- package/dist/workstation/runtime/ownership.js +100 -0
- package/dist/workstation/runtime/registrationRuntime.js +575 -0
- package/dist/workstation/runtime/remoteDesktopAdapter.js +186 -0
- package/dist/workstation/runtime/removalActivity.js +184 -0
- package/dist/workstation/service/installer.js +93 -1
- package/dist/workstation/service/launchd.js +1 -0
- package/dist/workstation/service/systemd.js +1 -0
- package/dist/workstation/systemMetrics.js +3 -0
- package/dist/workstation/tools/client.js +8 -27
- package/dist/workstation/tools/info.js +6 -13
- package/dist/workstation/tools/terminalRouter.js +17 -172
- package/dist/workstation/tools/validation.js +55 -1
- package/dist/workstation/update/archiveEvidence.js +206 -0
- package/dist/workstation/update/coordinator.js +34 -13
- package/dist/workstation/update/deviceCompatibility.js +119 -0
- package/dist/workstation/update/deviceCoordinator.js +369 -0
- package/dist/workstation/update/deviceHealth.js +104 -0
- package/dist/workstation/update/deviceHealthProtocol.js +26 -0
- package/dist/workstation/update/deviceRecoveryLifecycle.js +46 -0
- package/dist/workstation/update/deviceRollback.js +78 -0
- package/dist/workstation/update/globalInstall.js +80 -10
- package/dist/workstation/update/legacyBridge.js +414 -0
- package/dist/workstation/update/legacyOwner.js +39 -0
- package/dist/workstation/update/npmInstaller.js +2 -2
- package/dist/workstation/update/privateDurability.js +61 -0
- package/dist/workstation/update/recoveryPlan.js +124 -0
- package/dist/workstation/update/runUpdate.js +7 -1
- package/dist/workstation/update/taskRegistry.js +161 -3
- package/dist/workstation/update/watchdog.js +27427 -14410
- package/dist/workstation/update/watchdogProcess.js +72 -0
- package/package.json +7 -3
- package/dist/native/darwin-arm64/axom-quic +0 -0
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @platless/axom-cli
|
|
2
2
|
|
|
3
|
+
服务端 Docker、Workstation、Access Token、AI Provider 和 Ori 助手的端到端部署步骤见仓库的 [`docs/USER_GUIDE.md`](../docs/USER_GUIDE.md)。发布到 NPM 后,本文件也会随包一起提供。
|
|
4
|
+
|
|
3
5
|
One npm package, one bin: `axom`. An authenticated MCP client for Axomwork (`struct`/`record`/`execute`/`knowledge`), plus the personal Workstation daemon — registration, encrypted tunnels, self-update, and OS service lifecycle — merged into the same package.
|
|
4
6
|
|
|
5
7
|
## Install
|
|
@@ -50,10 +52,14 @@ axom execute healthCheck '{}'
|
|
|
50
52
|
|
|
51
53
|
## Workstation
|
|
52
54
|
|
|
53
|
-
`axom workstation
|
|
55
|
+
`axom workstation list [--json]` shows this device's registrations. Use `axom workstation add [address]` to add a server/account registration, and `axom workstation remove <registrationId> [--force]` to remove that exact local registration. Add chooses its positional address, then global `--server`, then the ordinary auth default (stored server or `http://localhost:8080`); `AXOM_SERVER` does not override that default. It checks actual workstation permission and may request a separate approval when valid cached access is unavailable, expired, or lacks permission. This approval leaves ordinary CLI credentials, device identity, and default server unchanged.
|
|
56
|
+
|
|
57
|
+
`axom workstation install` explicitly installs the service definition (launchd/systemd); `start`/`stop`/`restart` control the whole device, including an empty registration collection. They never register it implicitly. `status` queries the device, and `uninstall` removes its service definition. A stopped removal or an unavailable original removal owner remains pending and preserves registration data; inspect the pending operation before retrying. Lifecycle server/name selectors and the old `workstation auth`/`register` commands are removed; use `add [address]` and exact registration IDs instead.
|
|
54
58
|
|
|
55
59
|
On Debian 13 amd64, `axom workstation start --enable-rd` installs native remote desktop support and reuses the user's X11 desktop, or starts a managed Xfce desktop when none exists. `workstation rd status` reports its state; `workstation rd disable` revokes it without removing registration. See [Linux workstation RD](../docs/handbook/linux-workstation-rd.md) for session selection and package delivery.
|
|
56
60
|
|
|
61
|
+
Remote desktop uses one local native host shared by this device's registrations. Its installation source does not choose which registration may use it; viewer and automation control share one device owner, while observers remain scoped to their creating registration. On macOS, Desktop retains the device sharing preference across server selection and restarts. Turning sharing off stops native admission; Exit leaves the CLI service and non-desktop work running. A host whose original cleanup is unknown remains unavailable until its original resources are confirmed retired.
|
|
62
|
+
|
|
57
63
|
Disk heartbeats discover mounted local data storage independently of configured workspaces.
|
|
58
64
|
Linux partitions and bind mounts are deduplicated by filesystem identity; macOS APFS volumes
|
|
59
65
|
share one entry per physical capacity container. Boot/recovery partitions, memory filesystems,
|
|
@@ -65,12 +65,14 @@ catalog 是 Axom 对官方 ACP registry 的本地扩展层,随 CLI 发布:
|
|
|
65
65
|
| qoder-native-acp | active;Catalog 固定官方 `@qoder-ai/qodercli@1.1.75 --acp`,由 `qoder-native-acp.json` 提供精确版本、资产和原/补丁哈希 | 与其他发布包补丁相同,Install/Update 只按 Catalog 钉版本和配方哈希应用;不读取认证表,也不要求用户提供 Qoder 登录态 |
|
|
66
66
|
| kimi-code-distribution | active;catalog.ts 补充条目 `kimi-code`(Kimi Code 2.3.3 官方二进制,六平台 tar.gz + sha256,2026-10-27 nightly),隐藏已归档的 `kimi` | registry#458 合入后补充条目自动让位、版本由 registry 跟进;验证 Install/Update、复用登录后删除 supplement |
|
|
67
67
|
| command-code-distribution | active;catalog.ts 补充条目 `command-code`(npx `command-code@1.88.0 acp`) | registry 收录后自动让位;确认 registry 版本带 `acp` 子命令后删除 supplement |
|
|
68
|
-
| zcode-acp-distribution | active;catalog.ts 补充条目 `zcode-acp`(npx `zcode-acp-server@0.
|
|
68
|
+
| zcode-acp-distribution | active;catalog.ts 补充条目 `zcode-acp`(npx `zcode-acp-server@0.80.0`),前置依赖 ZCode 本体 | registry#566/#650 合入后自动让位;删除 supplement 时保留 prerequisite |
|
|
69
69
|
| zcode-models | active;fresh-install 模型兑底并入账号目录(`loadAllModels` 兜底读 entitled builtin 表,GLM-5.3-Flash 等不再丢) | 上游 `loadAllModels` 并入账号快照目录后删除 |
|
|
70
|
-
| zcode-
|
|
70
|
+
| zcode-env-account | active;`ZCODE_PROVIDER` + `ZCODE_API_KEY` 在 adapter 进程内覆盖 Coding Plan 账号,模型、原生请求与配额共用;不写桌面配置 | 上游原生支持同样的 env 账号覆盖后删除 |
|
|
71
|
+
| zcode-subagent-subwork | active;zcode-acp-server 0.80.0 四文件九编辑:`AxomZcodeSubagents` 监听器把后端 `session.updated`(agentId/childSessionId/taskId)转发为 `subagent_spawned`/`subagent_state_update`(RFD #1992)与 `async_task_*`(保留 shell command,并转发去重后的累计输出快照);dispatch 把 `tool_subagent_*` 内部调用重定址到 `sess_subagent_*` 子会话,协商到原生能力时抑制 `_meta.subagent` 标记(防双投影),声明 AIR asyncTasks 时抑制上游 `[后台]` 合成卡(防与 async_task 双重呈现,workflow 折叠不受影响);`adoptStoredTitle` 在 (重)挂载时补发 `session_info_update` 同步后端已生成的标题(titleUpdated 推送会丢在 backend 重启断点上) | 上游 zcode-acp 原生发出 T2/T3 变体并路由子会话、且 load 时同步存量标题后删除配方;验收含并发、失败/取消、后台迟到、重启重放 |
|
|
71
72
|
| claude-plan-tools | active;启动任务清单工具变量 | 无变量真实 ACP 会话能发布 plan 后下线 |
|
|
72
73
|
| codex-plan-tools | active;CODEX_CONFIG 的 update_plan 开关 | 无覆盖真实 ACP 会话能发布 plan;保留显式用户配置优先级 |
|
|
73
74
|
| claude-account-limits | active;配方 0.97.0,catalog 钉 0.97.0 | 上游 adapter 暴露标准化账号配额能力且不自动查询后删除;版本升级走 ../DAILY_UPGRADE_CHECK.md |
|
|
75
|
+
| claude-replay-lifecycle | active;0.97.0,链在 claude-account-limits 后;AIR 子会话历史已发终态后不再补发模型配置,历史中的模型快照保留,RFD current states 不变 | 上游不再向已结束的 AIR 回放子会话补发配置后删除;探针 `probes/claude-replay-lifecycle.mjs` 对原版复现 72 条越界通知,对补丁版验证零通知与 RFD 状态保留 |
|
|
74
76
|
| codex-account-limits | active;配方 2.3.0,catalog 钉 2.3.0 | 同上 |
|
|
75
77
|
| codex-terminal-output | active;2.3.0,链在 codex-account-limits 后;终态保留完整 stdout 与退出码,避免流式输出遗漏首段 | 上游 AIR 命令终态无补丁即可保留完整输出后删除;探针 `probes/codex-terminal-output.mjs` 覆盖流式/非流式与成功/失败 |
|
|
76
78
|
| commandcode-account-limits | active;配方 1.88.0(supplement 同钉) | 同上 |
|
|
@@ -95,6 +97,33 @@ catalog 各 agent 的上游版本核查、补丁必要性判定与钉版本升
|
|
|
95
97
|
|
|
96
98
|
## 验证
|
|
97
99
|
|
|
100
|
+
### ZCode API key
|
|
101
|
+
|
|
102
|
+
在工作站的 external agent 条目中配置以下 `env`,安装适配器后即可使用,无需执行 `npx setup`:
|
|
103
|
+
|
|
104
|
+
```yaml
|
|
105
|
+
env:
|
|
106
|
+
ZCODE_PROVIDER: builtin:bigmodel-coding-plan
|
|
107
|
+
ZCODE_API_KEY: <个人 Coding Plan API key>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
国际站使用 `builtin:zai-coding-plan`。`ZCODE_MODEL` 可选,未指定时从本机 ZCode
|
|
111
|
+
内置目录选择该套餐的首个模型。仍需要安装 ZCode 本体,但 API key 模式不依赖桌面登录。
|
|
112
|
+
环境变量只作用于该适配器进程,不生成 `acp-accounts.json`,不修改桌面凭据或配置。
|
|
113
|
+
不设置 `ZCODE_API_KEY` 时沿用上游桌面凭据读取方式;本补丁不修复新版桌面 OAuth 的兼容问题。
|
|
114
|
+
|
|
115
|
+
保存 external agent 的 env 修改后,新会话立即使用新配置;已有会话在下一条普通消息发送前
|
|
116
|
+
自动重启适配器并通过 `session/load` 恢复原会话。正在运行的回合和待答审批/问答不会被配置
|
|
117
|
+
修改中断,回复仍发回原进程。删除 env 覆盖也遵循同样的刷新规则。恢复失败明确报错,
|
|
118
|
+
不会静默新建对话。此行为要求同时部署更新后的服务端和带此补丁的 CLI 0.6.40。
|
|
119
|
+
|
|
120
|
+
原包/补丁的隔离探针(不联网、不读取真实凭据):
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
node axom-patch/cli/probes/zcode-env-account.mjs /path/to/pristine/zcode-acp-server --expect-unsupported
|
|
124
|
+
node axom-patch/cli/probes/zcode-env-account.mjs /path/to/patched/zcode-acp-server
|
|
125
|
+
```
|
|
126
|
+
|
|
98
127
|
```bash
|
|
99
128
|
cd axom-cli
|
|
100
129
|
npm run build
|
|
@@ -38,7 +38,7 @@ patch('commandcode','dist/cli.mjs','1.88.0','command-code',[
|
|
|
38
38
|
# the enum renames every release (hn->vn->bn). The read method still goes first in the same map.
|
|
39
39
|
('const m={[bn.INITIALIZE]:e=>handleInitialize(e),[bn.AUTHENTICATE]','const m={["_axom/account/rateLimits/read"]:async()=>{const raw=await fetchUsageData2(); if(raw.errors.length) throw new Error("Failed to fetch usage"); const snapshot=axomQuota.commandcode({credits:raw.credits,subscription:raw.subscription,orgLimits:raw.whoami?.orgLimits??[],monthly:{limit:raw.subscription?.data?.status==="active"?(getPlanInfo({planId:raw.subscription?.data?.planId??""})?.monthlyCredits??null):null}}); axomQuotaNotify(snapshot); return snapshot;},[bn.INITIALIZE]:e=>handleInitialize(e),[bn.AUTHENTICATE]'),
|
|
40
40
|
('agentCapabilities:{loadSession:!0,promptCapabilities:', 'agentCapabilities:{_meta:{"axom/accountRateLimits":{...axomQuota.CAPABILITY,provider:"commandcode"}},loadSession:!0,promptCapabilities:')])
|
|
41
|
-
if options.zcode: patch('zcode','dist/index.js','0.
|
|
41
|
+
if options.zcode: patch('zcode','dist/index.js','0.80.0','zcode-acp-server',[
|
|
42
42
|
# 0.72.0 moved the legacy usage_stats body to handlers/account.js as accountUsageStatsViaHub.
|
|
43
43
|
(' .onRequest("account/usage_stats", z.object({}).passthrough(), () => accountUsageStatsViaHub())',
|
|
44
44
|
' .onRequest(axomQuota.READ, z.object({}).passthrough(), async () => {\n'
|
|
@@ -84,7 +84,7 @@ models_fn='''function axomFreshInstallModels() {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
'''
|
|
87
|
-
if options.zcode: patch('zcode-models','dist/config/options.js','0.
|
|
87
|
+
if options.zcode: patch('zcode-models','dist/config/options.js','0.80.0','zcode-acp-server',[
|
|
88
88
|
('import { configProviderIdFor } from "./account-provider.js";',
|
|
89
89
|
'import { buildAccountProviderConfig as axomAccountProviders, codingPlanRequestAuthFor as axomPlanAuth, configProviderIdFor } from "./account-provider.js";'),
|
|
90
90
|
('/** Read the config.json contents (UTF-8). Throws on read/parse failure. */',
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "claude-replay-lifecycle",
|
|
3
|
+
"package": "@agentclientprotocol/claude-agent-acp",
|
|
4
|
+
"versions": [
|
|
5
|
+
"0.97.0"
|
|
6
|
+
],
|
|
7
|
+
"edits": [
|
|
8
|
+
{
|
|
9
|
+
"file": "dist/acp-agent.js",
|
|
10
|
+
"before_sha256": "efd325571a7c7cd0e9caaa7e143ec5ba32e2eec998ebb359dc4f5627c399de7f",
|
|
11
|
+
"after_sha256": "6c82fd616f4be545a0930588995183f2fc179a05875e7e7fcc534450ac3c1231",
|
|
12
|
+
"before": " async publishReplayedChildModels(sessionId) {\n const childModels = this.replayedChildModels.get(sessionId);\n if (!childModels)\n return;\n this.replayedChildModels.delete(sessionId);\n const models = this.subagentModels(sessionId);\n try {\n for (const [childSessionId, { model, sent }] of childModels) {\n const entry = responseModelEntry(model, models);\n if (!entry || sameModelEntry(entry, sent))\n continue;\n await this.client.sessionUpdate({\n sessionId: childSessionId,\n update: {\n sessionUpdate: \"config_option_update\",\n configOptions: [childModelOption(entry)],\n },\n });\n }\n }\n catch (error) {\n this.logger.error(`Session ${sessionId}: failed to send subagent models:`, error);\n }\n }\n",
|
|
13
|
+
"after": " async publishReplayedChildModels(sessionId) {\n // Axom: AIR replay children already ended inside session/load. Publishing\n // a refined model after that terminal boundary addresses an ended scope\n // whose replay relation a resuming host need not import. Keep the model\n // snapshot already emitted in history; never turn refinement into a\n // live update (or synthesize a new child just to deliver metadata).\n this.replayedChildModels.delete(sessionId);\n }\n"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
"edits": [
|
|
8
8
|
{
|
|
9
9
|
"file": "dist/index.js",
|
|
10
|
-
"before_sha256": "
|
|
11
|
-
"after_sha256": "
|
|
10
|
+
"before_sha256": "ee0276757b18277f5ee827fa08f12df52cb7266d33b5d82d90e538c47efced45",
|
|
11
|
+
"after_sha256": "d15de18e9ce3d2321b20d6e98e3455c20a9b2f299b5cece8b60f807bc50ee226",
|
|
12
12
|
"before": " terminalExit: { exitCode: item.exitCode }\n };\n}\nfunction singleAction(actions) {",
|
|
13
13
|
"after": " opaqueResult: { formatted_output: output2, exit_code: item.exitCode },\n terminalExit: { exitCode: item.exitCode }\n };\n}\nfunction singleAction(actions) {"
|
|
14
14
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Actual adapter methods, without starting a model or reading credentials.
|
|
2
|
+
// node <probe> <package-directory> [--expect-bug]
|
|
3
|
+
import assert from 'node:assert/strict';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { pathToFileURL } from 'node:url';
|
|
6
|
+
|
|
7
|
+
const directory = process.argv[2];
|
|
8
|
+
assert.ok(directory, 'Supply the adapter package directory');
|
|
9
|
+
const { ClaudeAcpAgent } = await import(pathToFileURL(path.resolve(directory, 'dist/acp-agent.js')));
|
|
10
|
+
const expectBug = process.argv.includes('--expect-bug');
|
|
11
|
+
const events = [];
|
|
12
|
+
const agent = Object.create(ClaudeAcpAgent.prototype);
|
|
13
|
+
agent.client = { sessionUpdate: async (notification) => { events.push(notification); } };
|
|
14
|
+
agent.logger = { error: (...args) => { throw new Error(String(args)); } };
|
|
15
|
+
agent.sessions = {};
|
|
16
|
+
agent.replayedChildModels = new Map([['root', new Map(Array.from({ length: 72 }, (_, i) => [
|
|
17
|
+
`root:replay-subagent:call-${i}`, { model: 'claude-sonnet-test', sent: { value: 'old', name: 'Old' } },
|
|
18
|
+
]))]]);
|
|
19
|
+
agent.subagentModels = () => ({ entry: () => ({ value: 'sonnet', name: 'Sonnet' }) });
|
|
20
|
+
// A separate RFD current-state publication must continue unchanged.
|
|
21
|
+
const current = { sessionId: 'root', update: { sessionUpdate: 'subagent_state_update', subagentSessionId: 'active', state: 'running' } };
|
|
22
|
+
agent.replayedSubagents = new Map([['root', { currentStates: () => [current] }]]);
|
|
23
|
+
await agent.publishCurrentSubagentStates('root');
|
|
24
|
+
const late = events.filter((event) => event.update.sessionUpdate === 'config_option_update');
|
|
25
|
+
assert.equal(late.length, expectBug ? 72 : 0, 'ended AIR replay children must receive no live model refinements');
|
|
26
|
+
assert.ok(events.includes(current), 'RFD current states still publish');
|
|
27
|
+
assert.equal(agent.replayedChildModels.size, 0, 'release replay-only model memory');
|
|
28
|
+
events.length = 0;
|
|
29
|
+
await agent.publishCurrentSubagentStates('root');
|
|
30
|
+
assert.equal(events.length, 0, 'publication stays idempotent');
|
|
31
|
+
console.log(expectBug ? 'Reproduced 72 upstream post-terminal replay snapshots' : 'Passed: no post-terminal snapshots; current subagent states preserved');
|
|
@@ -6,7 +6,7 @@ import vm from 'node:vm';
|
|
|
6
6
|
const packageRoot = process.argv[2];
|
|
7
7
|
assert.ok(packageRoot, 'Pass the codex-acp package directory');
|
|
8
8
|
const source = readFileSync(path.join(packageRoot, 'dist/index.js'), 'utf8');
|
|
9
|
-
const helpers = source.slice(source.indexOf('function
|
|
9
|
+
const helpers = source.slice(source.indexOf('function commandUsesTerminal(item)'), source.indexOf('function startFacts(item)')) +
|
|
10
10
|
source.slice(source.indexOf('function completionFacts(item,'), source.indexOf('function searchTitle(')) +
|
|
11
11
|
source.slice(source.indexOf('function toTerminalToolStatus(status)'), source.indexOf('// src/tool-calls/reporters/CommandReporter.ts'));
|
|
12
12
|
const context = vm.createContext({});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Run against the real published package and the managed patched copy. No network or real credentials.
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, existsSync, rmSync } from 'node:fs';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
8
|
+
|
|
9
|
+
const packageDir = path.resolve(process.argv[2]);
|
|
10
|
+
const unsupported = process.argv.includes('--expect-unsupported');
|
|
11
|
+
if (!process.env.AXOM_ENV_PROBE_CASE) {
|
|
12
|
+
const directory = mkdtempSync(path.join(tmpdir(), 'axom-zcode-env-'));
|
|
13
|
+
try {
|
|
14
|
+
const home = path.join(directory, '.zcode');
|
|
15
|
+
const bin = path.join(directory, 'bin');
|
|
16
|
+
mkdirSync(path.join(home, 'v2'), { recursive: true });
|
|
17
|
+
mkdirSync(path.join(bin, 'provider'), { recursive: true });
|
|
18
|
+
writeFileSync(path.join(bin, 'zcode.cjs'), '// fixture');
|
|
19
|
+
const table = { revision: 1, config: { providerConfigRules: { providerRules:
|
|
20
|
+
['bigmodel', 'zai'].map(family => ({
|
|
21
|
+
providerId: `account:${family}-individual-coding-plan`,
|
|
22
|
+
config: {
|
|
23
|
+
access: { type: 'zhipu-account', accountType: family, mode: 'individual-coding-plan' },
|
|
24
|
+
api: { baseUrl: family === 'zai' ? 'https://api.z.ai/api/anthropic' : 'https://open.bigmodel.cn/api/anthropic' },
|
|
25
|
+
builtinModelIds: ['GLM-5.3', 'GLM-5.3-Flash'],
|
|
26
|
+
},
|
|
27
|
+
})) } } };
|
|
28
|
+
writeFileSync(path.join(bin, 'provider/zcode-builtin.json'), JSON.stringify(table));
|
|
29
|
+
for (const scenario of unsupported ? ['fresh'] : ['fresh', 'legacy', 'saved', 'corrupt', 'zai', 'removed', 'invalid', 'model']) {
|
|
30
|
+
const result = spawnSync(process.execPath, [fileURLToPath(import.meta.url), packageDir, ...(unsupported ? ['--expect-unsupported'] : [])], {
|
|
31
|
+
encoding: 'utf8', env: {
|
|
32
|
+
...process.env, HOME: directory, ZCODE_HOME: home, ZCODE_BIN: path.join(bin, 'zcode.cjs'),
|
|
33
|
+
ZCODE_PROVIDER: scenario === 'zai' ? 'builtin:zai-coding-plan' : scenario === 'invalid' ? 'custom:other' : 'builtin:bigmodel-coding-plan',
|
|
34
|
+
ZCODE_API_KEY: scenario === 'removed' ? '' : 'fixture-env-key', ZCODE_MODEL: scenario === 'model' ? 'missing' : '',
|
|
35
|
+
AXOM_ENV_PROBE_CASE: scenario,
|
|
36
|
+
}, timeout: 15000,
|
|
37
|
+
});
|
|
38
|
+
assert.equal(result.status, 0, `${scenario}: ${result.stderr}\n${result.stdout}`);
|
|
39
|
+
}
|
|
40
|
+
console.log(`PASS zcode-env-account (${unsupported ? 'pristine lacks env account' : 'env auth, models, registry, isolation, validation, removal'})`);
|
|
41
|
+
} finally { rmSync(directory, { recursive: true, force: true }); }
|
|
42
|
+
} else {
|
|
43
|
+
const scenario = process.env.AXOM_ENV_PROBE_CASE;
|
|
44
|
+
const file = path.join(process.env.ZCODE_HOME, 'v2/config.json');
|
|
45
|
+
const accountFile = path.join(process.env.ZCODE_HOME, 'v2/acp-accounts.json');
|
|
46
|
+
const saved = scenario === 'saved' ? JSON.stringify({ version: 1, accounts: { bigmodel: { apiKey: 'fixture-saved-key' } } }) : 'invalid JSON';
|
|
47
|
+
if (['saved', 'corrupt'].includes(scenario)) writeFileSync(accountFile, saved, { mode: 0o600 });
|
|
48
|
+
else rmSync(accountFile, { force: true });
|
|
49
|
+
const fixture = JSON.stringify({ provider: { 'builtin:bigmodel-coding-plan': {
|
|
50
|
+
enabled: true, kind: 'anthropic', options: { apiKey: 'fixture-desktop-key' }, models: { 'GLM-5.3': {} },
|
|
51
|
+
} } });
|
|
52
|
+
if (['legacy', 'removed'].includes(scenario)) writeFileSync(file, fixture);
|
|
53
|
+
else rmSync(file, { force: true });
|
|
54
|
+
const load = relative => import(pathToFileURL(path.join(packageDir, 'dist', relative)));
|
|
55
|
+
if (['invalid', 'model'].includes(scenario)) {
|
|
56
|
+
const { bridgeOverlays } = await load('config/bridge-accounts.js');
|
|
57
|
+
assert.throws(bridgeOverlays, /ZCODE_PROVIDER|ZCODE_MODEL/);
|
|
58
|
+
} else {
|
|
59
|
+
const { buildAccountProviderConfig, codingPlanRequestAuthFor } = await load('config/account-provider.js');
|
|
60
|
+
const family = scenario === 'zai' ? 'zai' : 'bigmodel';
|
|
61
|
+
const account = `account:${family}-individual-coding-plan`;
|
|
62
|
+
if (unsupported) {
|
|
63
|
+
assert.equal(codingPlanRequestAuthFor(account), null);
|
|
64
|
+
assert.equal(buildAccountProviderConfig().states[account].entitled, false);
|
|
65
|
+
} else {
|
|
66
|
+
assert.equal(buildAccountProviderConfig().states[account].entitled, true);
|
|
67
|
+
assert.equal(codingPlanRequestAuthFor(account).apiKey, scenario === 'removed' ? 'fixture-desktop-key' : 'fixture-env-key');
|
|
68
|
+
const { loadAllModels } = await load('config/options.js');
|
|
69
|
+
assert.deepEqual(loadAllModels().map(m => m.modelId), scenario === 'removed' ? ['GLM-5.3'] : ['GLM-5.3', 'GLM-5.3-Flash']);
|
|
70
|
+
const { loadZcodeCredentials } = await load('backend/credentials.js');
|
|
71
|
+
assert.equal(loadZcodeCredentials().ANTHROPIC_API_KEY, scenario === 'removed' ? 'fixture-desktop-key' : 'fixture-env-key');
|
|
72
|
+
const { buildProviderRegistry } = await load('config/provider-registry.js');
|
|
73
|
+
assert.equal(buildProviderRegistry().providers.find(p => p.providerId === process.env.ZCODE_PROVIDER).apiKey.value,
|
|
74
|
+
scenario === 'removed' ? 'fixture-desktop-key' : 'fixture-env-key');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
assert.equal(existsSync(file), ['legacy', 'removed'].includes(scenario));
|
|
78
|
+
if (existsSync(file)) assert.equal(readFileSync(file, 'utf8'), fixture);
|
|
79
|
+
assert.equal(existsSync(accountFile), ['saved', 'corrupt'].includes(scenario));
|
|
80
|
+
if (existsSync(accountFile)) assert.equal(readFileSync(accountFile, 'utf8'), saved);
|
|
81
|
+
}
|
|
@@ -171,6 +171,13 @@ rootCxReset();
|
|
|
171
171
|
assert.equal(spawned.outputFilePath, '/tmp/out.log');
|
|
172
172
|
assert.equal(spawned.canStop, true);
|
|
173
173
|
assert.equal(spawned.showInTranscript, false);
|
|
174
|
+
assert.equal(spawned._meta.zcode.command, 'sleep 6', 'shell source survives separately from its description');
|
|
175
|
+
obs.handleEvent(taskEvent({ outputTail: 'first\n' }));
|
|
176
|
+
obs.handleEvent(taskEvent({ outputTail: 'first\nsecond\n' }));
|
|
177
|
+
obs.handleEvent(taskEvent({ outputTail: 'first\nsecond\n' })); // same snapshot is not sent twice
|
|
178
|
+
const progress = rootCx.sent.filter(s => s.params.update.sessionUpdate === 'async_task_progress');
|
|
179
|
+
assert.deepEqual(progress.map(s => s.params.update._meta.zcode.outputTail), ['first\n', 'first\nsecond\n']);
|
|
180
|
+
assert.equal(progress[0].params.update.outputFilePath, '/tmp/out.log');
|
|
174
181
|
obs.handleEvent(taskEvent({ status: 'failed' }));
|
|
175
182
|
obs.handleEvent(taskEvent({ status: 'completed' })); // single-shot terminal
|
|
176
183
|
const states = rootCx.sent.filter((s) => s.params.update.sessionUpdate === 'async_task_state_update').map((s) => s.params.update.state);
|