@platless/axom-cli 0.1.0 → 0.5.9

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.
Files changed (281) hide show
  1. package/README.md +1 -1
  2. package/dist/authScopes.js +19 -0
  3. package/dist/axom-patch/cli/README.md +132 -0
  4. package/dist/axom-patch/cli/account-limits/README.md +27 -0
  5. package/dist/axom-patch/cli/account-limits/antigravity-proxy.mjs +47 -0
  6. package/dist/axom-patch/cli/account-limits/antigravity-read.mjs +90 -0
  7. package/dist/axom-patch/cli/account-limits/antigravity.mjs +46 -0
  8. package/dist/axom-patch/cli/account-limits/generate.py +120 -0
  9. package/dist/axom-patch/cli/account-limits/kimi-proxy.mjs +64 -0
  10. package/dist/axom-patch/cli/account-limits/normalize.mjs +151 -0
  11. package/dist/axom-patch/cli/claude-account-limits.json +37 -0
  12. package/dist/axom-patch/cli/codex-account-limits.json +37 -0
  13. package/dist/axom-patch/cli/commandcode-account-limits.json +30 -0
  14. package/dist/axom-patch/cli/nightly-task.md +152 -0
  15. package/dist/axom-patch/cli/pi-steering.json +37 -0
  16. package/dist/axom-patch/cli/pi-subagent-subwork.json +23 -0
  17. package/dist/axom-patch/cli/probes/claude-late-async-terminal.mjs +38 -0
  18. package/dist/axom-patch/cli/probes/pi-steering.mjs +80 -0
  19. package/dist/axom-patch/cli/probes/pi-subagent-subwork.mjs +211 -0
  20. package/dist/axom-patch/cli/probes/qoder-steering.mjs +89 -0
  21. package/dist/axom-patch/cli/probes/qoder-subagent-origin.mjs +61 -0
  22. package/dist/axom-patch/cli/probes/zcode-subagent-subwork.mjs +257 -0
  23. package/dist/axom-patch/cli/qoder-background-terminal.md +82 -0
  24. package/dist/axom-patch/cli/qoder-foreground-output.md +42 -0
  25. package/dist/axom-patch/cli/qoder-steering.json +52 -0
  26. package/dist/axom-patch/cli/qoder-steering.md +30 -0
  27. package/dist/axom-patch/cli/qoder-subagent-origin.json +73 -0
  28. package/dist/axom-patch/cli/qoder-subagent-subwork.md +73 -0
  29. package/dist/axom-patch/cli/runtime.json +63 -0
  30. package/dist/axom-patch/cli/steering/claude-steering-js.patch +89 -0
  31. package/dist/axom-patch/cli/steering/claude-steering-types.patch +28 -0
  32. package/dist/axom-patch/cli/steering/codex-steering.patch +57 -0
  33. package/dist/axom-patch/cli/steering/pi-steering.js +79 -0
  34. package/dist/axom-patch/cli/zcode-account-limits.json +31 -0
  35. package/dist/axom-patch/cli/zcode-models.json +38 -0
  36. package/dist/axom-patch/cli/zcode-subagent-subwork.json +73 -0
  37. package/dist/cli.js +36 -1
  38. package/dist/commands/auth.js +4 -13
  39. package/dist/commands/execute.js +4 -4
  40. package/dist/commands/record.js +6 -6
  41. package/dist/commands/struct.js +4 -4
  42. package/dist/commands/workstation.js +2 -2
  43. package/dist/credentials.js +2 -2
  44. package/dist/install/claude/commands.js +13 -13
  45. package/dist/keepers/acp/keeper.mjs +3083 -0
  46. package/dist/keepers/acp/manifest.json +9 -0
  47. package/dist/keepers/terminal/keeper.mjs +8469 -0
  48. package/dist/keepers/terminal/manifest.json +9 -0
  49. package/dist/keepers/terminal/node_modules/node-pty/lib/conpty_console_list_agent.js +25 -0
  50. package/dist/keepers/terminal/node_modules/node-pty/lib/eventEmitter2.js +47 -0
  51. package/dist/keepers/terminal/node_modules/node-pty/lib/index.js +52 -0
  52. package/dist/keepers/terminal/node_modules/node-pty/lib/interfaces.js +7 -0
  53. package/dist/keepers/terminal/node_modules/node-pty/lib/shared/conout.js +10 -0
  54. package/dist/keepers/terminal/node_modules/node-pty/lib/terminal.js +190 -0
  55. package/dist/keepers/terminal/node_modules/node-pty/lib/types.js +7 -0
  56. package/dist/keepers/terminal/node_modules/node-pty/lib/unixTerminal.js +351 -0
  57. package/dist/keepers/terminal/node_modules/node-pty/lib/utils.js +38 -0
  58. package/dist/keepers/terminal/node_modules/node-pty/lib/windowsConoutConnection.js +131 -0
  59. package/dist/keepers/terminal/node_modules/node-pty/lib/windowsPtyAgent.js +344 -0
  60. package/dist/keepers/terminal/node_modules/node-pty/lib/windowsTerminal.js +209 -0
  61. package/dist/keepers/terminal/node_modules/node-pty/lib/worker/conoutSocketWorker.js +22 -0
  62. package/dist/keepers/terminal/node_modules/node-pty/package.json +66 -0
  63. package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-arm64/pty.node +0 -0
  64. package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-arm64/spawn-helper +0 -0
  65. package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-x64/pty.node +0 -0
  66. package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-x64/spawn-helper +0 -0
  67. package/dist/keepers/terminal/node_modules/node-pty/prebuilds/linux-arm64/pty.node +0 -0
  68. package/dist/keepers/terminal/node_modules/node-pty/prebuilds/linux-x64/pty.node +0 -0
  69. package/dist/mcp.js +32 -14
  70. package/dist/runtime-deps/qoder-sdk/package-lock.json +1189 -0
  71. package/dist/runtime-deps/qoder-sdk/package.json +8 -0
  72. package/dist/test/keeperKit.js +67 -0
  73. package/dist/workstation/acp/acpAgents.js +2514 -681
  74. package/dist/workstation/acp/acpClient.js +95 -318
  75. package/dist/workstation/acp/activityBusy.js +43 -0
  76. package/dist/workstation/acp/activityReporting.js +54 -0
  77. package/dist/workstation/acp/adoption.js +28 -356
  78. package/dist/workstation/acp/authUrlSniffer.js +36 -0
  79. package/dist/workstation/acp/binaryInstall.js +100 -27
  80. package/dist/workstation/acp/builds/gc.js +245 -0
  81. package/dist/workstation/acp/builds/install/binary.js +28 -0
  82. package/dist/workstation/acp/builds/install/npm.js +235 -0
  83. package/dist/workstation/acp/builds/install/uv.js +254 -0
  84. package/dist/workstation/acp/builds/migrate.js +195 -0
  85. package/dist/workstation/acp/builds/model.js +128 -0
  86. package/dist/workstation/acp/builds/nodeGate.js +100 -0
  87. package/dist/workstation/acp/builds/store.js +352 -0
  88. package/dist/workstation/acp/commandTableProbe.js +68 -0
  89. package/dist/workstation/acp/configOptions.js +103 -1
  90. package/dist/workstation/acp/delegationMcp.js +24 -0
  91. package/dist/workstation/acp/envSecrets.js +27 -0
  92. package/dist/workstation/acp/initializeResponse.js +285 -0
  93. package/dist/workstation/acp/installErrors.js +12 -2
  94. package/dist/workstation/acp/installProbe.js +1 -1
  95. package/dist/workstation/acp/managedPatches.js +144 -0
  96. package/dist/workstation/acp/outbox.js +330 -0
  97. package/dist/workstation/acp/patchAssets.js +80 -0
  98. package/dist/workstation/acp/permission.js +335 -37
  99. package/dist/workstation/acp/processor/checkpoint.js +87 -0
  100. package/dist/workstation/acp/processor/commands.js +35 -0
  101. package/dist/workstation/acp/processor/control.js +355 -0
  102. package/dist/workstation/acp/processor/emit.js +26 -0
  103. package/dist/workstation/acp/processor/jsonrpc.js +172 -0
  104. package/dist/workstation/acp/processor/memoryLog.js +49 -0
  105. package/dist/workstation/acp/processor/origins.js +48 -0
  106. package/dist/workstation/acp/processor/output.js +67 -0
  107. package/dist/workstation/acp/processor/projection.js +42 -0
  108. package/dist/workstation/acp/processor/record.js +128 -0
  109. package/dist/workstation/acp/processor/runtime.js +181 -0
  110. package/dist/workstation/acp/processor/sdkSchemas.js +61 -0
  111. package/dist/workstation/acp/processor/session.js +525 -0
  112. package/dist/workstation/acp/processor/sideChannel.js +80 -0
  113. package/dist/workstation/acp/processor/state.js +74 -0
  114. package/dist/workstation/acp/processor/step.js +459 -0
  115. package/dist/workstation/acp/processor/test/fixtureLog.js +65 -0
  116. package/dist/workstation/acp/processor/test/harness.js +120 -0
  117. package/dist/workstation/acp/processor/test/largeIdEcho.js +50 -0
  118. package/dist/workstation/acp/processor/test/rawAgent.js +70 -0
  119. package/dist/workstation/acp/processor/transport/generations.js +76 -0
  120. package/dist/workstation/acp/processor/transport/keeper.js +130 -0
  121. package/dist/workstation/acp/processor/transport/local.js +269 -0
  122. package/dist/workstation/acp/processor/transport/types.js +78 -0
  123. package/dist/workstation/acp/processor/updates.js +364 -0
  124. package/dist/workstation/acp/processorSession.js +1512 -0
  125. package/dist/workstation/acp/qoderStartup.js +45 -0
  126. package/dist/workstation/acp/registry/catalog.js +385 -4
  127. package/dist/workstation/acp/registry/detect.js +55 -0
  128. package/dist/workstation/acp/registry/launch.js +61 -119
  129. package/dist/workstation/acp/sessionUpdateMapper.js +56 -27
  130. package/dist/workstation/acp/steering.js +58 -0
  131. package/dist/workstation/acp/switching.js +114 -0
  132. package/dist/workstation/acp/terminalLogin.js +171 -0
  133. package/dist/workstation/acp/terminalLoginSpec.js +41 -0
  134. package/dist/workstation/acp/test/adapterFixtures.js +256 -0
  135. package/dist/workstation/acp/test/daemonLife.js +106 -0
  136. package/dist/workstation/acp/test/fakeAgent.js +185 -9
  137. package/dist/workstation/acp/test/keeperWorld.js +267 -0
  138. package/dist/workstation/acp/test/memoryOutbox.js +55 -0
  139. package/dist/workstation/acp/test/raw/fixtures.js +196 -0
  140. package/dist/workstation/acp/test/raw/qoderCaptures.js +125 -0
  141. package/dist/workstation/acp/test/raw/sanitize.js +344 -0
  142. package/dist/workstation/acp/test/raw/sources.js +249 -0
  143. package/dist/workstation/acp/test/realAdapter.js +377 -0
  144. package/dist/workstation/acp/test/scriptAgent.js +206 -0
  145. package/dist/workstation/acp/test/sessionFrames.js +42 -0
  146. package/dist/workstation/acp/timedCommand.js +4 -2
  147. package/dist/workstation/acp/uvxInstall.js +72 -122
  148. package/dist/workstation/acp/validate.js +33 -5
  149. package/dist/workstation/agentFlow.js +103 -0
  150. package/dist/workstation/agentSessions.js +1686 -348
  151. package/dist/workstation/channels/agent.js +14 -6
  152. package/dist/workstation/channels/computer.js +203 -7
  153. package/dist/workstation/channels/computerExecs.js +200 -0
  154. package/dist/workstation/channels/management.js +86 -6
  155. package/dist/workstation/config.js +3 -1
  156. package/dist/workstation/connection/encryptedChannel.js +88 -21
  157. package/dist/workstation/daemon.js +309 -6
  158. package/dist/workstation/daemonctl.js +28 -2
  159. package/dist/workstation/desktop/binding.js +36 -0
  160. package/dist/workstation/desktop/bridge.js +212 -0
  161. package/dist/workstation/desktop/flow-control.js +52 -0
  162. package/dist/workstation/desktop/focused-text.js +130 -0
  163. package/dist/workstation/desktop/protocol.js +35 -0
  164. package/dist/workstation/exec/attach.js +126 -0
  165. package/dist/workstation/exec/command.js +40 -0
  166. package/dist/workstation/exec/durable.js +517 -0
  167. package/dist/workstation/exec/fallback.js +106 -0
  168. package/dist/workstation/exec/policy.js +837 -0
  169. package/dist/workstation/exec/shaping.js +211 -0
  170. package/dist/workstation/exec.js +3 -112
  171. package/dist/workstation/files/adapters/computerFileFrames.js +51 -0
  172. package/dist/workstation/files/adapters/toolRequests.js +121 -0
  173. package/dist/workstation/files/client.js +455 -0
  174. package/dist/workstation/files/errors.js +28 -0
  175. package/dist/workstation/files/fence.js +350 -0
  176. package/dist/workstation/files/find/fileIndex.js +153 -0
  177. package/dist/workstation/files/find/fuzzy.js +155 -0
  178. package/dist/workstation/files/host.js +122 -0
  179. package/dist/workstation/files/hostProtocol.js +2 -0
  180. package/dist/workstation/files/media/cache.js +620 -0
  181. package/dist/workstation/files/media/encoding.js +308 -0
  182. package/dist/workstation/files/media/estimator.js +100 -0
  183. package/dist/workstation/files/media/media.js +325 -0
  184. package/dist/workstation/files/media/packedAudio.js +23 -0
  185. package/dist/workstation/files/media/scheduler.js +551 -0
  186. package/dist/workstation/files/media/types.js +5 -0
  187. package/dist/workstation/files/scope.js +45 -0
  188. package/dist/workstation/files/structured.js +284 -0
  189. package/dist/workstation/files/text.js +356 -0
  190. package/dist/workstation/files/uploads.js +351 -0
  191. package/dist/workstation/journal.js +65 -236
  192. package/dist/workstation/keepers/acp/client.js +101 -0
  193. package/dist/workstation/keepers/acp/envelope.js +62 -0
  194. package/dist/workstation/keepers/acp/host.js +419 -0
  195. package/dist/workstation/keepers/acp/main.js +18 -0
  196. package/dist/workstation/keepers/acp/memoryStream.js +121 -0
  197. package/dist/workstation/keepers/acp/params.js +137 -0
  198. package/dist/workstation/keepers/acp/protocol.js +66 -0
  199. package/dist/workstation/keepers/acp/recover.js +120 -0
  200. package/dist/workstation/keepers/acp/session.js +584 -0
  201. package/dist/workstation/keepers/acp/stderr.js +154 -0
  202. package/dist/workstation/keepers/kit/activity.js +103 -0
  203. package/dist/workstation/keepers/kit/bootstrap.js +164 -0
  204. package/dist/workstation/keepers/kit/buildVersion.js +51 -0
  205. package/dist/workstation/keepers/kit/bundle.js +120 -0
  206. package/dist/workstation/keepers/kit/client.js +432 -0
  207. package/dist/workstation/keepers/kit/identity.js +21 -0
  208. package/dist/workstation/keepers/kit/ipc.js +112 -0
  209. package/dist/workstation/keepers/kit/launchConfig.js +8 -0
  210. package/dist/workstation/keepers/kit/launcher.js +249 -0
  211. package/dist/workstation/keepers/kit/lock.js +123 -0
  212. package/dist/workstation/keepers/kit/orphanSweep.js +86 -0
  213. package/dist/workstation/keepers/kit/paths.js +75 -0
  214. package/dist/workstation/keepers/kit/protocol.js +43 -0
  215. package/dist/workstation/keepers/kit/server.js +518 -0
  216. package/dist/workstation/keepers/kit/streamLog.js +697 -0
  217. package/dist/workstation/keepers/legacy.js +296 -0
  218. package/dist/workstation/keepers/policy.js +576 -0
  219. package/dist/workstation/keepers/stop.js +34 -0
  220. package/dist/workstation/keepers/terminal/client.js +213 -0
  221. package/dist/workstation/keepers/terminal/exec.js +981 -0
  222. package/dist/workstation/keepers/terminal/generations.js +129 -0
  223. package/dist/workstation/keepers/terminal/keeper.js +62 -0
  224. package/dist/workstation/keepers/terminal/main.js +43 -0
  225. package/dist/workstation/keepers/terminal/orphanSweep.js +3 -0
  226. package/dist/workstation/keepers/terminal/params.js +27 -0
  227. package/dist/workstation/keepers/terminal/protocol.js +56 -0
  228. package/dist/workstation/keepers/terminal/pty.js +330 -0
  229. package/dist/workstation/oauth/deviceAuthorization.js +21 -12
  230. package/dist/workstation/protocol/accountLimits.js +47 -0
  231. package/dist/workstation/protocol/agent.js +201 -8
  232. package/dist/workstation/protocol/common.js +36 -0
  233. package/dist/workstation/protocol/computer.js +107 -7
  234. package/dist/workstation/protocol/management.js +50 -2
  235. package/dist/workstation/qoderAdapter/backgroundProcess.js +118 -0
  236. package/dist/workstation/qoderAdapter/backgroundTerminal.js +193 -0
  237. package/dist/workstation/qoderAdapter/backgroundTerminalFold.js +372 -0
  238. package/dist/workstation/qoderAdapter/callbackContext.js +76 -0
  239. package/dist/workstation/qoderAdapter/completedContinuation.js +139 -0
  240. package/dist/workstation/qoderAdapter/contract.js +78 -0
  241. package/dist/workstation/qoderAdapter/foregroundOutput.js +36 -0
  242. package/dist/workstation/qoderAdapter/history.js +85 -0
  243. package/dist/workstation/qoderAdapter/identityIndex.js +191 -0
  244. package/dist/workstation/qoderAdapter/inputQueue.js +42 -0
  245. package/dist/workstation/qoderAdapter/main.js +95 -0
  246. package/dist/workstation/qoderAdapter/mapper.js +117 -0
  247. package/dist/workstation/qoderAdapter/observerPlugin.js +245 -0
  248. package/dist/workstation/qoderAdapter/observerReceiver.js +187 -0
  249. package/dist/workstation/qoderAdapter/permissions.js +61 -0
  250. package/dist/workstation/qoderAdapter/profile.js +93 -0
  251. package/dist/workstation/qoderAdapter/sdkDriver.js +48 -0
  252. package/dist/workstation/qoderAdapter/sdkRuntime.js +93 -0
  253. package/dist/workstation/qoderAdapter/sdkRuntimeInstall.js +145 -0
  254. package/dist/workstation/qoderAdapter/session.js +319 -0
  255. package/dist/workstation/qoderAdapter/subagentMeta.js +28 -0
  256. package/dist/workstation/qoderAdapter/subwork.js +85 -0
  257. package/dist/workstation/qoderAdapter/taskControl.js +38 -0
  258. package/dist/workstation/qoderAdapter/taskLedger.js +163 -0
  259. package/dist/workstation/qoderAdapter/types.js +1 -0
  260. package/dist/workstation/qoderAdapter/usage.js +37 -0
  261. package/dist/workstation/register.js +4 -0
  262. package/dist/workstation/systemMetrics.js +110 -1
  263. package/dist/workstation/tools/browser.js +394 -0
  264. package/dist/workstation/tools/client.js +277 -0
  265. package/dist/workstation/tools/info.js +50 -0
  266. package/dist/workstation/tools/keeperProcess.js +124 -0
  267. package/dist/workstation/tools/router.js +55 -0
  268. package/dist/workstation/tools/terminalRouter.js +222 -0
  269. package/dist/workstation/tools/validation.js +86 -0
  270. package/dist/workstation/update/coordinator.js +32 -0
  271. package/dist/workstation/update/npmInstaller.js +2 -0
  272. package/dist/workstation/update/ptyPreflight.js +45 -0
  273. package/dist/workstation/update/taskRegistry.js +141 -23
  274. package/dist/workstation/update/watchdog.js +66 -0
  275. package/package.json +20 -7
  276. package/skills/axom/SKILL.md +55 -17
  277. package/skills/axom-definition/SKILL.md +32 -32
  278. package/skills/axom-platform/SKILL.md +39 -39
  279. package/dist/workstation/acp/acpSession.js +0 -1047
  280. package/dist/workstation/acp/contract.js +0 -494
  281. package/dist/workstation/acp/draftInterceptor.js +0 -154
@@ -0,0 +1,63 @@
1
+ {
2
+ "schema_version": 1,
3
+ "overrides": [
4
+ {
5
+ "id": "qoder-registry-catch-up",
6
+ "agent": "qoder",
7
+ "distribution": {
8
+ "version": "1.1.71",
9
+ "npx": {
10
+ "package": "@qoder-ai/qodercli@1.1.71",
11
+ "args": [
12
+ "--acp"
13
+ ]
14
+ }
15
+ },
16
+ "until_registry_version": "1.1.71"
17
+ },
18
+ {
19
+ "id": "claude-plan-tools",
20
+ "agent": "claude-acp",
21
+ "env": {
22
+ "CLAUDE_CODE_ENABLE_TODO_TOOLS": "1"
23
+ }
24
+ },
25
+ {
26
+ "id": "codex-plan-tools",
27
+ "agent": "codex-acp",
28
+ "env": {
29
+ "CODEX_CONFIG": "{\"tools\":{\"update_plan\":{\"enabled\":true}}}"
30
+ }
31
+ }
32
+ ],
33
+ "package_patches": [
34
+ "pi-steering.json",
35
+ "pi-subagent-subwork.json",
36
+ "qoder-subagent-origin.json",
37
+ "qoder-steering.json",
38
+ "codex-account-limits.json",
39
+ "claude-account-limits.json",
40
+ "commandcode-account-limits.json",
41
+ "zcode-account-limits.json",
42
+ "zcode-models.json",
43
+ "zcode-subagent-subwork.json"
44
+ ],
45
+ "native_extensions": [
46
+ {
47
+ "agent": "kimi-code",
48
+ "versions": [
49
+ "2.1.1"
50
+ ],
51
+ "entry": "account-limits/kimi-proxy.mjs"
52
+ },
53
+ {
54
+ "agent": "antigravity-acp",
55
+ "versions": [
56
+ "1.3.0",
57
+ "1.4.0"
58
+ ],
59
+ "entry": "account-limits/antigravity-proxy.mjs",
60
+ "accountLimitsVersion": 5
61
+ }
62
+ ]
63
+ }
@@ -0,0 +1,89 @@
1
+ --- a/dist/acp-agent.js
2
+ +++ b/dist/acp-agent.js
3
+ @@ -180,12 +180,29 @@
4
+ return { sessionId, asyncTaskId };
5
+ }
6
+ /** How urgently the SDK delivers a steered message relative to the running
7
+ - * turn — an internal Claude implementation detail, not part of the wire
8
+ - * contract. `now` pre-empts the current generation, while `later` waits for a
9
+ - * pending permission/elicitation callback to settle instead of cancelling its
10
+ - * ACP request and hiding the client's user-input card (IJAI-1191). */
11
+ + * turn. `now` pre-empts the current generation, `next` waits for the next
12
+ + * natural boundary without aborting, and `later` waits for a pending
13
+ + * permission/elicitation callback to settle instead of cancelling its ACP
14
+ + * request and hiding the client's user-input card (IJAI-1191).
15
+ + *
16
+ + * This is both the agent's own default choice and — since the
17
+ + * `_session/steering` response is identical whichever timing was used, so a
18
+ + * Host cannot discover the difference by trying — the vocabulary a Host may
19
+ + * name explicitly through `_meta.steering.priority`. The set is advertised on
20
+ + * `InitializeResponse._meta.steering.timings` so the capability is declared
21
+ + * rather than probed. */
22
+ const STEER_PRIORITY_NOW = "now";
23
+ +const STEER_PRIORITY_NEXT = "next";
24
+ const STEER_PRIORITY_LATER = "later";
25
+ +/** The delivery timings this agent accepts on `_meta.steering.priority`, and the
26
+ + * value advertised as `InitializeResponse._meta.steering.timings`. Both reads
27
+ + * come from this one array so the accepted set and the advertised set cannot
28
+ + * drift apart. */
29
+ +const STEER_TIMINGS = [
30
+ + STEER_PRIORITY_NOW,
31
+ + STEER_PRIORITY_NEXT,
32
+ + STEER_PRIORITY_LATER,
33
+ +];
34
+ /** Validate raw JSON-RPC params into a {@link SteerRequest}. Kept minimal — the
35
+ * content blocks are handed to `promptToClaude`, which tolerates unknown block
36
+ * types — but `sessionId` and a non-empty `prompt` array are required. */
37
+ @@ -206,6 +223,16 @@
38
+ : undefined;
39
+ if (idleBehavior !== undefined && idleBehavior !== "promptRequired") {
40
+ throw RequestError.invalidParams(undefined, "unsupported steering idleBehavior");
41
+ + }
42
+ + const priority = steering && typeof steering === "object"
43
+ + ? steering.priority
44
+ + : undefined;
45
+ + // Rejected rather than ignored: a silently dropped priority is
46
+ + // indistinguishable from an honoured one on the response, so a Host that
47
+ + // asked for `next` and got `now` would only find out by losing the running
48
+ + // turn's remaining work.
49
+ + if (priority !== undefined && !STEER_TIMINGS.includes(priority)) {
50
+ + throw RequestError.invalidParams(undefined, "unsupported steering priority");
51
+ }
52
+ return {
53
+ sessionId,
54
+ @@ -947,6 +974,10 @@
55
+ ...airSessionFailureCapabilityMeta(AGENT_FILE_CHANGE_REPORT_CAPABILITY, AIR_NATIVE_SUBAGENT_SESSIONS_CAPABILITY, AIR_ASYNC_TASKS_CAPABILITY, AIR_RECOMMENDED_CONFIG_VALUE_CAPABILITY),
56
+ steering: {
57
+ supported: true,
58
+ + // The timings a Host may name on `_meta.steering.priority`
59
+ + // (see STEER_TIMINGS). Declared, not probed: the response to
60
+ + // `_session/steering` is the same whichever timing was used.
61
+ + timings: [...STEER_TIMINGS],
62
+ },
63
+ goal: {
64
+ version: GOAL_EXTENSION_VERSION,
65
+ @@ -1758,9 +1789,22 @@
66
+ const steeredUuid = randomUUID();
67
+ userMessage.uuid = steeredUuid;
68
+ // Deliver into the running turn rather than queuing behind it as a fresh
69
+ - // prompt would.
70
+ + // prompt would. With no priority in `_meta` this is byte-for-byte the
71
+ + // established behavior: `now`, held back to `later` only while a
72
+ + // permission/elicitation callback is awaiting input.
73
+ + const defaultPriority = (session.pendingUserInputCount ?? 0) > 0
74
+ + ? STEER_PRIORITY_LATER
75
+ + : STEER_PRIORITY_NOW;
76
+ + // A Host that named a timing gets it, with one exception: an explicit
77
+ + // `now` is still held back while a callback is awaiting input, because
78
+ + // pre-empting ABORTS the cycle, which cancels that ACP request and can
79
+ + // strand the prompt (IJAI-1191). `next` and `later` never pre-empt, so
80
+ + // they carry no such hazard and are honoured verbatim.
81
+ + const requestedPriority = params._meta?.steering?.priority;
82
+ userMessage.priority =
83
+ - (session.pendingUserInputCount ?? 0) > 0 ? STEER_PRIORITY_LATER : STEER_PRIORITY_NOW;
84
+ + requestedPriority === undefined || requestedPriority === STEER_PRIORITY_NOW
85
+ + ? defaultPriority
86
+ + : requestedPriority;
87
+ // Mark before the push and in the same synchronous section as the in-flight
88
+ // check: the interrupt can have the CLI finalizing the aborted cycle by the
89
+ // time the consumer next runs, and an unmarked result would settle the turn
@@ -0,0 +1,28 @@
1
+ --- a/dist/acp-agent.d.ts
2
+ +++ b/dist/acp-agent.d.ts
3
+ @@ -47,17 +47,22 @@
4
+ stopped: boolean;
5
+ };
6
+ /** Request-level steering options. `promptRequired` is opt-in so existing Hosts
7
+ - * keep the established idle fallback behavior. */
8
+ + * keep the established idle fallback behavior, and `priority` is optional so a
9
+ + * Host that names none keeps the agent's established default. */
10
+ type SteerMeta = {
11
+ [key: string]: unknown;
12
+ steering?: {
13
+ idleBehavior?: "promptRequired";
14
+ + priority?: SteerTiming;
15
+ };
16
+ };
17
+ +/** A delivery timing a Host may name on {@link SteerMeta}, and a member of the
18
+ + * set advertised as `InitializeResponse._meta.steering.timings`. */
19
+ +export type SteerTiming = "now" | "next" | "later";
20
+ /** Params of a {@link STEER_METHOD} request. Shaped like the relevant subset of
21
+ * a `PromptRequest` so the same `promptToClaude` conversion applies. Delivery
22
+ - * priority is deliberately NOT exposed here — it's an internal detail the agent
23
+ - * chooses (see {@link STEER_PRIORITY}). */
24
+ + * priority is the agent's own choice (see {@link STEER_TIMINGS}) unless the
25
+ + * Host names one it advertised. */
26
+ export type SteerRequest = {
27
+ sessionId: string;
28
+ prompt: PromptRequest["prompt"];
@@ -0,0 +1,57 @@
1
+ --- a/dist/index.js
2
+ +++ b/dist/index.js
3
+ @@ -31723,6 +31723,20 @@
4
+ // src/AcpExtensions.ts
5
+ var LEGACY_SET_SESSION_MODEL_METHOD = "session/set_model";
6
+ var SESSION_STEERING_METHOD = "_session/steering";
7
+ +/**
8
+ + * The delivery timings this agent accepts on a `_session/steering` request's
9
+ + * `_meta.steering.priority`, and the value advertised as
10
+ + * `InitializeResponse._meta.steering.timings`. Both reads come from this one
11
+ + * array so the accepted set and the advertised set cannot drift apart.
12
+ + *
13
+ + * `now` is the only entry because injecting into the live turn is the only
14
+ + * thing this adapter can ask the app-server for: `turn/steer` carries no timing
15
+ + * field. A Host that needs `next` (deliver at a boundary without discarding the
16
+ + * running turn's remaining work) must hold the message itself; declaring the
17
+ + * set is what lets it know that without having to try and lose work finding
18
+ + * out.
19
+ + */
20
+ +var SESSION_STEERING_TIMINGS = ["now"];
21
+ function isExtMethodRequest(request) {
22
+ return request.method === "authentication/status" || request.method === "authentication/logout" || request.method === LEGACY_SET_SESSION_MODEL_METHOD || request.method === GOAL_CONTROL_METHOD || request.method === LEGACY_GOAL_CONTROL_METHOD || request.method === SESSION_STEERING_METHOD || request.method === ASYNC_TASK_STOP_METHOD;
23
+ }
24
+ @@ -32334,7 +32348,11 @@
25
+ authMethods: getCodexAuthMethods(_params.clientCapabilities),
26
+ _meta: {
27
+ steering: {
28
+ - supported: true
29
+ + supported: true,
30
+ + // Declared, not probed: `_session/steering` answers the same
31
+ + // `{outcome}` whichever timing was used, so a Host cannot discover
32
+ + // this by trying. See SESSION_STEERING_TIMINGS.
33
+ + timings: [...SESSION_STEERING_TIMINGS]
34
+ },
35
+ goal: {
36
+ version: GOAL_EXTENSION_VERSION,
37
+ @@ -33502,6 +33520,20 @@
38
+ const prompt = params["prompt"];
39
+ if (typeof sessionId !== "string" || !Array.isArray(prompt)) {
40
+ throw RequestError.invalidParams();
41
+ + }
42
+ + // `_meta` reaches us because sessionSteerParamsParser passes unknown keys
43
+ + // through. A priority outside the advertised set is REJECTED rather than
44
+ + // ignored: the `{outcome}` this method answers is identical either way, so
45
+ + // a Host that asked for a timing we cannot honour would otherwise learn it
46
+ + // only by losing the running turn's remaining work.
47
+ + const meta = params["_meta"];
48
+ + const steering = meta && typeof meta === "object" ? meta["steering"] : void 0;
49
+ + const priority = steering && typeof steering === "object" ? steering["priority"] : void 0;
50
+ + if (priority !== void 0 && !SESSION_STEERING_TIMINGS.includes(priority)) {
51
+ + throw RequestError.invalidParams(
52
+ + void 0,
53
+ + `Unsupported steering priority; this agent accepts ${SESSION_STEERING_TIMINGS.join(", ")}`
54
+ + );
55
+ }
56
+ return {
57
+ sessionId,
@@ -0,0 +1,79 @@
1
+ // Injected into pi-acp 0.0.34. Uses its existing RPC process and ACP prompt ownership.
2
+ // Pi 0.87.1 accepts prompt(streamingBehavior=steer) before streaming events finish.
3
+ // Holding the ACP prompt open also tracks a native continuation admitted at the idle boundary.
4
+ class AxomPiSteering {
5
+ constructor(session) {
6
+ this.session = session;
7
+ this.tail = Promise.resolve();
8
+ this.pending = 0;
9
+ this.requested = false;
10
+ this.finishing = false;
11
+ this.settling = null;
12
+ this.revision = 0;
13
+ }
14
+ steer(message, images) {
15
+ const session = this.session;
16
+ if (!session.pendingTurn || session.cancelRequested || this.finishing) {
17
+ return Promise.resolve({ outcome: "promptRequired" });
18
+ }
19
+ const turn = session.pendingTurn;
20
+ this.pending++;
21
+ const operation = this.tail.then(async () => {
22
+ if (session.pendingTurn !== turn || session.cancelRequested) return { outcome: "promptRequired" };
23
+ const state = await session.proc.getState();
24
+ if (state?.isStreaming !== true || state?.isCompacting === true) return { outcome: "promptRequired" };
25
+ // No await between checking ACP ownership and starting the native request.
26
+ if (session.pendingTurn !== turn || session.cancelRequested) return { outcome: "promptRequired" };
27
+ const result = await session.proc.request({ type: "prompt", message, images, streamingBehavior: "steer" });
28
+ if (!result.success) return { outcome: "promptRequired" };
29
+ return { outcome: "injected" };
30
+ });
31
+ this.tail = operation.catch(() => {});
32
+ return operation.finally(() => {
33
+ this.pending--;
34
+ if (!this.pending && this.requested) this.settle();
35
+ });
36
+ }
37
+ settle() {
38
+ this.requested = true;
39
+ this.revision++;
40
+ if (this.pending || this.settling || this.finishing) return this.settling;
41
+ const session = this.session;
42
+ const turn = session.pendingTurn;
43
+ if (!turn) return;
44
+ const revision = this.revision;
45
+ this.settling = (async () => {
46
+ const state = await session.proc.getState();
47
+ // An old agent_settled notification may arrive during admission of a new native loop.
48
+ if (this.pending || session.pendingTurn !== turn || state?.isStreaming === true || state?.isCompacting === true) return;
49
+ this.finishing = true;
50
+ this.requested = false;
51
+ try { await session.axomFinishTurn(); }
52
+ finally { this.finishing = false; }
53
+ })().catch(error => {
54
+ if (session.pendingTurn === turn) {
55
+ session.pendingTurn = null;
56
+ turn.reject(error);
57
+ }
58
+ }).finally(() => {
59
+ this.settling = null;
60
+ if (!this.pending && this.requested && this.revision !== revision) this.settle();
61
+ });
62
+ return this.settling;
63
+ }
64
+ }
65
+
66
+ async function axomPiSupportsSteering() {
67
+ const command = getPiCommand(process.env.PI_ACP_PI_COMMAND);
68
+ const launch = shouldUseShellForPiCommand(command) ? crossSpawn : spawn;
69
+ return new Promise(resolve => {
70
+ let output = "";
71
+ let child;
72
+ try { child = launch(command, ["--version"], { stdio: ["ignore", "pipe", "ignore"], env: process.env }); }
73
+ catch { resolve(false); return; }
74
+ const timeout = setTimeout(() => { child.kill(); resolve(false); }, 5000);
75
+ child.stdout.on("data", data => { output += data; });
76
+ child.on("error", () => { clearTimeout(timeout); resolve(false); });
77
+ child.on("close", code => { clearTimeout(timeout); resolve(code === 0 && output.trim() === "0.87.1"); });
78
+ });
79
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "id": "zcode-account-limits",
3
+ "package": "zcode-acp-server",
4
+ "versions": [
5
+ "0.69.3",
6
+ "0.69.4"
7
+ ],
8
+ "edits": [
9
+ {
10
+ "file": "dist/index.js",
11
+ "before_sha256": "3f7286e9380681ca22bce5ed5d4faaaad595edee745589337babe4d3f2e0113d",
12
+ "after_sha256": "8ae15d912cd451fa155fadf8fa7707553a51477d2f3974a1deb0ebf9bed55a00",
13
+ "before": " .onRequest(\"account/usage_stats\", z.object({}).passthrough(), () => accountUsageStats())",
14
+ "after": " .onRequest(axomQuota.READ, z.object({}).passthrough(), async () => {\n const { buildAccountProviderConfig, codingPlanRequestAuthFor } = await import(\"./config/account-provider.js\");\n const { resolveQuotaHost } = await import(\"./quota/client.js\");\n let apiKey = null, family = \"\";\n for (const [providerId, provider] of Object.entries(buildAccountProviderConfig()?.providers ?? {})) {\n if (!provider?.access?.entitled) continue;\n const auth = codingPlanRequestAuthFor(providerId);\n if (auth?.apiKey) { apiKey = auth.apiKey; family = providerId; break; }\n }\n if (!apiKey) throw new Error(\"No entitled GLM coding plan: sign in once in the ZCode desktop app\");\n const resp = await fetch(resolveQuotaHost(family.startsWith(\"account:zai\") ? \"https://api.z.ai\" : \"\") + \"/api/monitor/usage/quota/limit\", { headers: { Accept: \"application/json, text/plain, */*\", Authorization: \"Bearer \" + apiKey }, signal: AbortSignal.timeout(8000) });\n const text = await resp.text();\n let json = null; try { json = text ? JSON.parse(text) : null; } catch {}\n if (resp.status === 429 || !json || json.success !== true) throw new Error(\"GLM quota read failed\" + (json?.msg ? \": \" + json.msg : \" (HTTP \" + resp.status + \")\"));\n const snapshot = axomQuota.zcode({ provider: family, level: json.data?.level, limits: json.data?.limits });\n axomQuotaNotify(snapshot);\n return snapshot;\n })\n .onRequest(\"account/usage_stats\", z.object({}).passthrough(), () => accountUsageStats())"
15
+ },
16
+ {
17
+ "file": "dist/index.js",
18
+ "before_sha256": "8ae15d912cd451fa155fadf8fa7707553a51477d2f3974a1deb0ebf9bed55a00",
19
+ "after_sha256": "a3047f20115eb8bcad7dfee1eac6689a73127f589dce6131138b22e9ca2712d1",
20
+ "before": " .onRequest(\"initialize\", (ctx) => server.initialize(ctx.params, ctx.client))",
21
+ "after": " .onRequest(\"initialize\", async (ctx) => { const result = await server.initialize(ctx.params, ctx.client); const caps = result.agentCapabilities ?? {}; result.agentCapabilities = { ...caps, _meta: { ...caps._meta, \"axom/accountRateLimits\": { ...axomQuota.CAPABILITY, provider: \"zcode\" } } }; return result; })"
22
+ },
23
+ {
24
+ "file": "dist/index.js",
25
+ "before_sha256": "a3047f20115eb8bcad7dfee1eac6689a73127f589dce6131138b22e9ca2712d1",
26
+ "after_sha256": "1dcc36538826c874d851254d56f91b9f9f12a93652668688f5ed53baa803823f",
27
+ "before": "#!/usr/bin/env node\n/**\n * Entry point: wire the ZcodeAcpServer to a stdio ACP stream.\n *\n * The ACP",
28
+ "after": "#!/usr/bin/env node\n\nconst axomQuota = (() => {\n/** Account quota normalization. No I/O: passive events must never trigger a query. */\nconst READ = '_axom/account/rateLimits/read';\nconst UPDATED = '_axom/account/rateLimits/updated';\nconst CAPABILITY = { version: 2, read: true, updated: true };\nconst percent = v => typeof v === 'number' && Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : null;\nconst finite = v => { if (v == null || typeof v === 'boolean') return null; const n = typeof v === 'number' ? v : Number(v); return Number.isFinite(n) ? n : null; };\nconst time = (v, milliseconds = false) => {\n if (v == null || v === 0) return null;\n const d = new Date(typeof v === 'number' ? v * (milliseconds ? 1 : 1000) : v);\n return Number.isFinite(d.getTime()) ? d.toISOString() : null;\n};\nconst status = v => ({ allowed: 'allowed', allowed_warning: 'warning', rejected: 'blocked', normal: 'allowed' }[v] ?? 'unknown');\n/** Canonical window key rides the snapshot; the UI owns the key → display-label translation.\n * Windows without a canonical key keep their vendor content untouched. */\nconst windowKey = (seconds, period) => period === 'month' ? 'monthly' : seconds === 18000 ? 'five_hour' : seconds === 604800 ? 'weekly' : null;\nconst base = (provider, mode, raw, observedAt) => ({ schemaVersion: 1, updateMode: 'snapshot', provider, billingMode: mode, availability: mode === 'subscription' ? 'available' : mode === 'unknown' ? 'unknown' : 'not_applicable', observedAt: observedAt ?? new Date().toISOString(), plan: null, limits: [], balances: [], _meta: { ['_' + provider]: structuredClone(raw) } });\nfunction codex(raw, authType = 'chatgpt', observedAt) {\n const out = base('codex', ['chatgpt', 'chatgptAuthTokens'].includes(authType) ? 'subscription' : ['apiKey','apikey','amazonBedrock'].includes(authType) ? 'non_subscription' : 'unknown', raw, observedAt);\n if (out.billingMode !== 'subscription') return out;\n const buckets = Object.entries(raw.rateLimitsByLimitId ?? {});\n if (!buckets.length && raw.rateLimits) buckets.push([raw.rateLimits.limitId ?? 'codex', raw.rateLimits]);\n for (const [id, bucket] of buckets) {\n if (!bucket) continue;\n if (bucket.planType) out.plan = { id: bucket.planType, label: bucket.planType };\n for (const name of ['primary', 'secondary']) {\n const w = bucket[name]; if (!w) continue;\n const seconds = w.windowDurationMins == null ? null : w.windowDurationMins * 60;\n out.limits.push({ id: `${id}.${name}`, label: bucket.limitName ?? id, kind: 'subscription', windowSeconds: seconds, key: windowKey(seconds), usedPercent: percent(w.usedPercent), resetsAt: time(w.resetsAt), status: bucket.rateLimitReachedType ? 'blocked' : 'unknown', scope: { bucket: id } });\n }\n if (bucket.credits) out.balances.push({ id: `${id}.credits`, label: 'Credits', remaining: bucket.credits.balance ?? null, unit: 'credits', unlimited: bucket.credits.unlimited === true });\n }\n // Account IDs must not escape via provider extensions.\n delete out._meta._codex.accountId;\n return out;\n}\nfunction claude(raw, observedAt) {\n const mode = raw.billing_mode ?? (raw.subscription_type || raw.rate_limits_available === true ? 'subscription' : 'unknown');\n const out = base('claude', mode, raw, observedAt);\n out.plan = raw.subscription_type ? { id: raw.subscription_type, label: raw.subscription_type } : null;\n if (mode === 'subscription' && !raw.rate_limits_available) out.availability = 'unavailable';\n const limits = raw.rate_limits ?? {};\n const rows = Array.isArray(limits.limits) ? limits.limits : [];\n if (rows.length) {\n rows.forEach((w, i) => {\n const seconds = w.group === 'session' ? 18000 : w.group === 'weekly' ? 604800 : null;\n out.limits.push({ id: `claude.${w.kind}.${i}`, label: w.scope?.model?.display_name ?? w.kind, kind: 'subscription', windowSeconds: seconds, key: windowKey(seconds), usedPercent: percent(w.percent), resetsAt: time(w.resets_at), status: status(w.severity), active: w.is_active ?? null, scope: w.scope ?? null });\n });\n } else for (const [id, seconds] of [['five_hour', 18000], ['seven_day', 604800], ['seven_day_opus',604800], ['seven_day_sonnet',604800]]) {\n const w = limits[id]; if (!w) continue;\n out.limits.push({ id: `claude.${id}`, label: id, kind: 'subscription', windowSeconds: seconds, key: windowKey(seconds), usedPercent: percent(w.utilization), resetsAt: time(w.resets_at), status: 'unknown', scope: id.endsWith('opus') || id.endsWith('sonnet') ? { model: id.split('_').at(-1) } : null });\n }\n const spend=limits.spend;\n if(spend?.enabled && spend.used && spend.limit) out.limits.push({id:'claude.extra_spend',label:'Extra usage',kind:'spend',windowSeconds:null,usedPercent:percent(spend.percent),resetsAt:null,status:status(spend.severity),used:String(spend.used.amount_minor),limit:String(spend.limit.amount_minor),unit:'money',currency:spend.used.currency,exponent:spend.used.exponent});\n if(spend?.balance?.amount_minor != null) out.balances.push({id:'claude.extra_balance',label:'Extra usage balance',remaining:String(spend.balance.amount_minor),unit:'money',currency:spend.balance.currency,exponent:spend.balance.exponent});\n return out;\n}\nfunction claudeEvent(raw, previous = null, observedAt) {\n const out = previous ? structuredClone(previous) : base('claude',raw.rateLimitType?'subscription':'unknown',{},observedAt);\n out.updateMode = 'delta';\n out.balances = [];\n out.observedAt = observedAt ?? new Date().toISOString();\n out._meta._claude = { ...out._meta._claude, rateLimitEvent: raw };\n const seconds = raw.rateLimitType === 'five_hour' ? 18000 : raw.rateLimitType?.startsWith('seven_day') ? 604800 : null;\n if (seconds !== null) {\n const id = `claude.${raw.rateLimitType}`;\n const scoped = !['five_hour','seven_day'].includes(raw.rateLimitType);\n const prior=out.limits.find(w => w.windowSeconds===seconds && JSON.stringify(w.scope??null)===JSON.stringify(scoped ? {model:raw.rateLimitType.split('_').at(-1)}:null));\n const nextReset=time(raw.resetsAt);\n const rolled=prior?.resetsAt && nextReset && Math.abs(Date.parse(nextReset)-Date.parse(prior.resetsAt))>1000;\n const row = { id, label: raw.rateLimitType, kind: 'subscription', windowSeconds: seconds, key: windowKey(seconds), usedPercent: raw.utilization == null ? (rolled ? null : prior?.usedPercent ?? null) : percent(raw.utilization * 100), resetsAt: raw.resetsAt == null ? prior?.resetsAt ?? null : time(raw.resetsAt), status: status(raw.status), scope: scoped ? { model: raw.rateLimitType.split('_').at(-1) } : null };\n // Event utilization is a ratio, unlike get_usage's percentage. Match the existing window without duplicating it.\n const i = out.limits.findIndex(w => w.windowSeconds === seconds && JSON.stringify(w.scope ?? null) === JSON.stringify(row.scope));\n out.limits = [i >= 0 ? { ...out.limits[i], ...row, id: out.limits[i].id } : row];\n } else out.limits = [];\n return out;\n}\nfunction kimi(raw, observedAt) {\n const quota = raw.quota ?? raw;\n const out = base('kimi','subscription',quota,observedAt);\n for (const [id, seconds] of [['limit5h',18000],['limit7d',604800],['monthTotal',null]]) {\n const w = quota.usages?.[id]; if (!w) continue;\n out.limits.push({ id: `kimi.${id}`, label: id, kind: 'subscription', windowSeconds: seconds, period: id === 'monthTotal' ? 'month' : null, key: windowKey(seconds, id === 'monthTotal' ? 'month' : null), usedPercent: percent(w.usedRatio * 100), resetsAt: time(w.resetAt), status: 'unknown' });\n }\n const wallet = quota.extraUsage;\n if (wallet) out.balances.push({ id:'kimi.extra',label:'Extra usage',remaining:String(wallet.balanceCents),unit:'money',currency:wallet.currency,exponent:2 });\n return out;\n}\n/** GLM quota `percentage` is the USED share (measured: 5% for 58/1000); counters win when present.\n * Counter-derived shares are rounded to 2 decimals — 100-94.2 keeps fp noise otherwise. */\nconst glmPercent = limit => {\n const used = finite(limit.currentValue), remaining = finite(limit.remaining), total = finite(limit.usage);\n const cap = remaining !== null && used !== null ? remaining + used : total;\n const round2 = v => v == null ? null : Math.round(v * 100) / 100;\n if (cap !== null && cap > 0 && remaining !== null && remaining >= 0 && remaining <= cap) return round2(100 - percent(remaining / cap * 100));\n if (cap !== null && cap > 0 && used !== null && used >= 0 && used <= cap) return round2(percent(used / cap * 100));\n return percent(limit.percentage);\n};\nfunction zcode(raw, observedAt) {\n // Raw: the GLM quota endpoint's data block — { level, limits: [{ type, number, usage,\n // currentValue, remaining, percentage, nextResetTime(epoch ms), usageDetails }] }. Which windows\n // exist is plan-dependent (measured pro plan: 5h prompts + a tool/MCP allowance; no weekly row —\n // a `number: 7` window maps when a plan returns one, and nothing is invented when it doesn't).\n const limits = Array.isArray(raw?.limits) ? raw.limits : [];\n const level = typeof raw?.level === 'string' && raw.level ? raw.level : null;\n const out = base('zcode', limits.length ? 'subscription' : 'unknown', raw, observedAt);\n out.plan = level ? { id: level, label: level } : null;\n let tools = 0;\n limits.forEach((limit, i) => {\n if (!limit || typeof limit !== 'object') return;\n const resetsAt = time(limit.nextResetTime, true);\n if (limit.type === 'TOKENS_LIMIT') {\n // GLM window convention: number 5 → the 5-hour prompt window, 7 → weekly.\n // Ids mirror the adapter's own /quota keys (token_5h / token_week).\n const seconds = limit.number === 5 ? 18000 : limit.number === 7 ? 604800 : null;\n const label = limit.number === 5 ? '5h' : limit.number === 7 ? 'Week' : `token ${limit.number ?? i}`;\n const id = limit.number === 5 ? 'zcode.token_5h' : limit.number === 7 ? 'zcode.token_week' : `zcode.token_${limit.number ?? i}`;\n out.limits.push({ id, label, kind: 'subscription', windowSeconds: seconds, key: windowKey(seconds), usedPercent: glmPercent(limit), resetsAt, status: 'unknown' });\n } else if (limit.type === 'TIME_LIMIT' || limit.type === 'MCP_LIMIT') {\n // Built-in tool/MCP allowance: absolute counters (unit 'calls'); per-model detail stays in _meta.\n const used = finite(limit.currentValue), total = finite(limit.usage), remaining = finite(limit.remaining);\n out.limits.push({ id: tools ? `zcode.mcp.${i}` : 'zcode.mcp', label: 'MCP', kind: 'subscription', windowSeconds: null, usedPercent: glmPercent(limit), ...(used !== null && total !== null ? { used: String(used), limit: String(total), unit: 'calls' } : {}), resetsAt, status: remaining === 0 ? 'blocked' : used !== null || limit.percentage != null ? 'allowed' : 'unknown' });\n tools++;\n }\n });\n return out;\n}\nfunction commandcode(raw, observedAt) {\n const subscription = raw.subscription?.data ?? raw.subscription;\n const windows = raw.credits?.windowLimits ?? raw.windowLimits;\n const subscribed = ['active','trialing','past_due'].includes(subscription?.status) || windows?.limited === true;\n const mode = subscribed ? 'subscription' : subscription || windows ? 'non_subscription' : 'unknown';\n const out = base('commandcode',mode,raw,observedAt);\n out.plan = subscription?.planId ? { id:subscription.planId,label:subscription.planId } : null;\n for (const [id, seconds] of [['fiveHour',18000],['weekly',604800]]) {\n const w=windows?.[id]; if (!w) continue;\n out.limits.push({ id:`commandcode.${id}`,label:id,kind:'subscription',windowSeconds:seconds,key:windowKey(seconds),usedPercent:w.cap > 0 ? percent(w.used / w.cap * 100) : null,used:String(w.used),limit:String(w.cap),unit:'credits',resetsAt:time(w.resetAt,true),status:w.exceeded === true ? 'blocked' : 'allowed' });\n }\n const credits=raw.credits?.credits ?? raw.credits;\n if (subscribed && credits?.monthlyCredits != null) {\n const cap=raw.monthly?.limit;\n const known=typeof cap==='number' && Number.isFinite(cap) && cap>0;\n const used=known ? Math.max(0,cap-credits.monthlyCredits) : null;\n out.limits.push({id:'commandcode.monthly',label:'Monthly',kind:'subscription',windowSeconds:null,period:'month',key:windowKey(null,'month'),usedPercent:known?percent(used/cap*100):null,resetsAt:time(subscription?.currentPeriodEnd,true),status:'unknown',...(known?{used:String(used),limit:String(cap),unit:'credits'}:{})});\n }\n for (const [id,label] of [['monthlyCredits','Monthly credits'],['purchasedCredits','Purchased credits'],['freeCredits','Free credits']]) if (credits?.[id] != null) out.balances.push({ id:`commandcode.${id}`,label,remaining:String(credits[id]),unit:'credits' });\n return out;\n}\n\nreturn {READ,UPDATED,CAPABILITY,codex,claude,claudeEvent,kimi,commandcode,zcode};\n})();\nconst axomQuotaNotify = snapshot => process.stdout.write(JSON.stringify({jsonrpc:\"2.0\",method:axomQuota.UPDATED,params:snapshot})+\"\\n\");\n/**\n * Entry point: wire the ZcodeAcpServer to a stdio ACP stream.\n *\n * The ACP"
29
+ }
30
+ ]
31
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "id": "zcode-models",
3
+ "package": "zcode-acp-server",
4
+ "versions": [
5
+ "0.69.3",
6
+ "0.69.4"
7
+ ],
8
+ "edits": [
9
+ {
10
+ "file": "dist/config/options.js",
11
+ "before_sha256": "7f30e0dbf281280b7043cc686990eff3785bc62206a4b369313b27333cf9c330",
12
+ "after_sha256": "4641e5097c667e9b351ee7f0dee89a5a517332f452b1fc878e0396775b9870f8",
13
+ "before": "import { configProviderIdFor } from \"./account-provider.js\";",
14
+ "after": "import { buildAccountProviderConfig as axomAccountProviders, codingPlanRequestAuthFor as axomPlanAuth, configProviderIdFor } from \"./account-provider.js\";"
15
+ },
16
+ {
17
+ "file": "dist/config/options.js",
18
+ "before_sha256": "4641e5097c667e9b351ee7f0dee89a5a517332f452b1fc878e0396775b9870f8",
19
+ "after_sha256": "286ad8d2b6f734ae1168cbe2095c25660016db10eee6ccc4d285a64fe8cc2cd4",
20
+ "before": "/** Read the config.json contents (UTF-8). Throws on read/parse failure. */",
21
+ "after": "function axomFreshInstallModels() {\n const fallback = { providerId: DEFAULT_PROVIDER_ID, providerName: DEFAULT_PROVIDER_NAME, modelId: DEFAULT_MODEL_ID };\n try {\n const out = [];\n for (const [pid, p] of Object.entries(axomAccountProviders()?.providers ?? {})) {\n if (!p?.access?.entitled || !axomPlanAuth(pid)?.apiKey) continue;\n const providerId = configProviderIdFor(pid);\n for (const modelId of p.builtinModelIds ?? []) {\n if (out.some((m) => m.providerId === providerId && m.modelId === modelId)) continue;\n out.push({ providerId, providerName: providerId, modelId });\n }\n }\n if (out.length === 0) return [fallback];\n return out.some((m) => m.providerId === fallback.providerId && m.modelId === fallback.modelId)\n ? [fallback, ...out.filter((m) => !(m.providerId === fallback.providerId && m.modelId === fallback.modelId))]\n : [fallback, ...out];\n }\n catch {\n return [fallback];\n }\n}\n\n/** Read the config.json contents (UTF-8). Throws on read/parse failure. */"
22
+ },
23
+ {
24
+ "file": "dist/config/options.js",
25
+ "before_sha256": "286ad8d2b6f734ae1168cbe2095c25660016db10eee6ccc4d285a64fe8cc2cd4",
26
+ "after_sha256": "c6fae88f596ee0cbb633317c0f83c2c883a2b2a5d8978bfc4fd6a6d152f77ccb",
27
+ "before": " if (out.length === 0 && Object.keys(cfg.provider ?? {}).length === 0) {\n return [\n {\n providerId: DEFAULT_PROVIDER_ID,\n providerName: DEFAULT_PROVIDER_NAME,\n modelId: DEFAULT_MODEL_ID,\n },\n ];\n }",
28
+ "after": " if (out.length === 0 && Object.keys(cfg.provider ?? {}).length === 0) {\n return axomFreshInstallModels();\n }"
29
+ },
30
+ {
31
+ "file": "dist/config/options.js",
32
+ "before_sha256": "c6fae88f596ee0cbb633317c0f83c2c883a2b2a5d8978bfc4fd6a6d152f77ccb",
33
+ "after_sha256": "d12eded70f22d8d9010de9949c0809b1f56f2c33635899764ca9f893fec0d256",
34
+ "before": " if (out.length > 0)\n return out;\n return [\n {\n providerId: DEFAULT_PROVIDER_ID,\n providerName: DEFAULT_PROVIDER_NAME,\n modelId: DEFAULT_MODEL_ID,\n },\n ];\n }\n}",
35
+ "after": " if (out.length > 0)\n return out;\n return axomFreshInstallModels();\n }\n}"
36
+ }
37
+ ]
38
+ }
@@ -0,0 +1,73 @@
1
+ {
2
+ "id": "zcode-subagent-subwork",
3
+ "package": "zcode-acp-server",
4
+ "versions": [
5
+ "0.69.3",
6
+ "0.69.4"
7
+ ],
8
+ "edits": [
9
+ {
10
+ "file": "dist/handlers/dispatch.js",
11
+ "before_sha256": "7d095dc00eb9b8a55a8452ac390cbf56f71056da7ae0f575541602de23222483",
12
+ "after_sha256": "b82e262b6ffcd4d74262515f3d1465912b9508b22597cef5cf8db702bec52225",
13
+ "before": "import { isBroadcastSource, sendSessionUpdate, sendSessionUpdateToOthers } from \"./io.js\";\n/** True once the EPERM hint fired for this process — throttled to one shot. */",
14
+ "after": "import { isBroadcastSource, sendSessionUpdate, sendSessionUpdateToOthers } from \"./io.js\";\n/** Axom patch `zcode-subagent-subwork`: the backend addresses a foreground sub-agent's\n * internal tool calls as `tool_subagent_<child-suffix>_call_<id>`; the child ACP session\n * id is `sess_` + that middle segment (measured: tool id\n * `tool_subagent_agent_<uuid>_call_<x>` ↔ child session `sess_subagent_agent_<uuid>`).\n * Deterministic from the id alone — no state. */\nfunction axomSubagentChildScope(callId) {\n if (typeof callId !== \"string\" || !callId.startsWith(\"tool_subagent_\"))\n return null;\n const middle = callId.slice(\"tool_\".length);\n const cut = middle.indexOf(\"_call_\");\n if (cut <= 0)\n return null;\n return `sess_${middle.slice(0, cut)}`;\n}\n/** Draft RFD #1992 subagents negotiated by the client (the axom daemon always does). */\nfunction axomNativeSubagents(server) {\n return !!(server && server.clientCapabilities && server.clientCapabilities.subagents);\n}\n/** True once the EPERM hint fired for this process — throttled to one shot. */"
15
+ },
16
+ {
17
+ "file": "dist/handlers/dispatch.js",
18
+ "before_sha256": "b82e262b6ffcd4d74262515f3d1465912b9508b22597cef5cf8db702bec52225",
19
+ "after_sha256": "ecfb04258456577d61f3d20b2f1b8f0a950c58d8efefbdf58221b0b8c9a34c4e",
20
+ "before": "function dispatchToolCallNew(server, cx, acpSid, ev) {\n const termSupported = server.supportsTerminalOutput() && (ev.tool === \"Bash\" || ev.tool === \"bash\");\n const meta = { claudeCode: { toolName: ev.tool } };\n if (termSupported)\n meta[\"terminal_info\"] = { terminal_id: ev.callId };\n // Mark sub-agent dispatch cards so editors can badge them from creation.\n if (ev.tool === \"Agent\" || ev.tool === \"Task\")\n meta[\"subagent\"] = true;",
21
+ "after": "function dispatchToolCallNew(server, cx, acpSid, ev) {\n acpSid = axomSubagentChildScope(ev.callId) ?? acpSid;\n const termSupported = server.supportsTerminalOutput() && (ev.tool === \"Bash\" || ev.tool === \"bash\");\n const meta = { claudeCode: { toolName: ev.tool } };\n if (termSupported)\n meta[\"terminal_info\"] = { terminal_id: ev.callId };\n // Mark sub-agent dispatch cards so editors can badge them from creation.\n // Axom: with draft subagents (RFD #1992) negotiated, the native events own the\n // projection and this mark would double-project the child on such clients.\n if ((ev.tool === \"Agent\" || ev.tool === \"Task\") && !axomNativeSubagents(server))\n meta[\"subagent\"] = true;"
22
+ },
23
+ {
24
+ "file": "dist/handlers/dispatch.js",
25
+ "before_sha256": "ecfb04258456577d61f3d20b2f1b8f0a950c58d8efefbdf58221b0b8c9a34c4e",
26
+ "after_sha256": "a4ece2260d22b8791a9230afc4652aede39d7c10252ce47692f8208a668388c5",
27
+ "before": "function dispatchToolCallUpdate(server, cx, acpSid, ev) {\n const toolName = ev.tool ?? \"\";",
28
+ "after": "function dispatchToolCallUpdate(server, cx, acpSid, ev) {\n acpSid = axomSubagentChildScope(ev.callId) ?? acpSid;\n const toolName = ev.tool ?? \"\";"
29
+ },
30
+ {
31
+ "file": "dist/server.js",
32
+ "before_sha256": "547d640a68ad56a97bd587348ea38ee3eca57d1fad9ea1d14e04c486e1efc85a",
33
+ "after_sha256": "df37fa0b7e5873d13a2cdd71a5fbc931a7ea9ffca521b0218d60a7a9b11e1d3c",
34
+ "before": "export class ZcodeAcpServer {",
35
+ "after": "/** Axom patch `zcode-subagent-subwork`: normalize ZCode sub-agents and background\n * tasks into the draft ACP subagent variants (RFD #1992) and the AIR async-task\n * extension — the same contracts claude-agent-acp ships. The backend already emits\n * first-class lifecycle events on `session.updated` (agentId/childSessionId for\n * sub-agents, taskId for background tasks); this listener forwards them so hosts\n * can project subworks, and dispatch.js re-scopes a foreground sub-agent's internal\n * `tool_subagent_*` tool calls onto its child session. */\nclass AxomZcodeSubagents {\n constructor(server, zcodeSid) {\n this.server = server;\n this.sid = zcodeSid;\n /** agentId → { agentId, child, background, terminal, pendingState, pendingP, resultSeen, preview } */\n this.agents = new Map();\n /** parentToolCallId → agent record (foreground result flush). */\n this.parents = new Map();\n /** taskId → { terminal } (bash/exec background tasks only). */\n this.tasks = new Map();\n }\n /** Draft RFD #1992 negotiated — the axom daemon always declares this. */\n nativeOk() {\n const caps = this.server.clientCapabilities;\n return !!(caps && caps.subagents);\n }\n /** AIR async-task capability declared (`_meta.jetbrains.air.capabilities`). */\n asyncOk() {\n const air = this.server.clientCapabilities?._meta?.jetbrains?.air;\n return !!(air && Array.isArray(air.capabilities) && air.capabilities.includes(\"asyncTasks\"));\n }\n handleEvent(ev) {\n try {\n void this.onEvent(ev);\n }\n catch {\n // Never crash the bridge from a normalization observer.\n }\n }\n async onEvent(ev) {\n if (!ev || ev.type !== \"session.updated\") {\n this.onToolEvent(ev);\n return;\n }\n const p = ev.payload ?? {};\n if (typeof p.agentId === \"string\" && p.agentId && typeof p.childSessionId === \"string\" && p.childSessionId) {\n this.onAgent(p);\n return;\n }\n // Sub-agent background tasks also carry taskId with taskKind \"subagent\" —\n // the agentId path above owns those. Workflow runs have their own poller.\n if (typeof p.taskId === \"string\" && p.taskId && p.taskKind !== \"subagent\" && p.taskKind !== \"workflow\") {\n this.onTask(p);\n }\n }\n onAgent(p) {\n if (!this.nativeOk())\n return;\n const agentId = p.agentId;\n const child = p.childSessionId;\n const status = typeof p.status === \"string\" ? p.status : \"running\";\n let rec = this.agents.get(agentId);\n if (!rec) {\n rec = { agentId, child, background: p.background === true, terminal: false, pendingState: null, pendingP: null, resultSeen: false, preview: null };\n this.agents.set(agentId, rec);\n if (typeof p.parentToolCallId === \"string\" && p.parentToolCallId)\n this.parents.set(p.parentToolCallId, rec);\n // First sighting already terminal (adapter restart): adopt — emit the\n // spawn so the host can still link the child, then the state below.\n if (status !== \"running\")\n rec.resultSeen = true;\n this.emit({\n sessionUpdate: \"subagent_spawned\",\n subagentSessionId: child,\n name: (typeof p.description === \"string\" && p.description) || (typeof p.agentType === \"string\" && p.agentType) || \"Subagent\",\n task: typeof p.prompt === \"string\" ? p.prompt : (p.description ?? \"\"),\n capabilities: {},\n _meta: { zcode: { agentId, parentToolCallId: p.parentToolCallId, background: rec.background, adopted: status !== \"running\" } },\n });\n }\n if (rec.child !== child)\n return;\n const mapped = status === \"completed\" ? \"completed\"\n : status === \"failed\" || status === \"error\" ? \"failed\"\n : status === \"cancelled\" || status === \"stopped\" ? \"cancelled\"\n : status === \"disconnected\" ? \"disconnected\" : null;\n if (!mapped || rec.terminal)\n return;\n if (rec.background || rec.resultSeen || mapped !== \"completed\") {\n this.finishAgent(rec, mapped, p);\n return;\n }\n // Foreground completion: hold the state until the parent Agent tool's own\n // result event arrives (one event later, measured) so the child-scoped\n // preview precedes the terminal state on the wire.\n rec.pendingState = mapped;\n rec.pendingP = p;\n }\n finishAgent(rec, state, p) {\n rec.terminal = true;\n if (rec.preview) {\n this.emitChild(rec.child, { sessionUpdate: \"agent_message_chunk\", content: { type: \"text\", text: rec.preview } });\n rec.preview = null;\n }\n const meta = { zcode: { agentId: rec.agentId } };\n if (p) {\n for (const key of [\"parentToolCallId\", \"outputFile\"])\n if (typeof p[key] === \"string\")\n meta.zcode[key] = p[key];\n if (typeof p.totalTokens === \"number\")\n meta.zcode.totalTokens = p.totalTokens;\n if (typeof p.totalDurationMs === \"number\")\n meta.zcode.totalDurationMs = p.totalDurationMs;\n }\n this.emit({ sessionUpdate: \"subagent_state_update\", subagentSessionId: rec.child, state, _meta: meta });\n }\n onToolEvent(ev) {\n if (!ev || ev.type !== \"tool.updated\")\n return;\n const p = ev.payload ?? {};\n if (p.kind !== \"result\" || typeof p.toolCallId !== \"string\")\n return;\n const rec = this.parents.get(p.toolCallId);\n if (!rec || rec.terminal || rec.background)\n return;\n rec.resultSeen = true;\n const text = axomSubagentResultPreview(p.result);\n if (text)\n rec.preview = text;\n if (rec.pendingState)\n this.finishAgent(rec, rec.pendingState, rec.pendingP);\n }\n onTask(p) {\n if (!this.asyncOk())\n return;\n const taskId = p.taskId;\n let task = this.tasks.get(taskId);\n const status = typeof p.status === \"string\" ? p.status : \"running\";\n if (!task) {\n task = { terminal: false };\n this.tasks.set(taskId, task);\n this.emit({\n sessionUpdate: \"async_task_spawned\",\n asyncTaskId: taskId,\n name: (typeof p.description === \"string\" && p.description) || (typeof p.command === \"string\" && p.command) || \"background task\",\n taskType: typeof p.taskKind === \"string\" ? p.taskKind : \"shell\",\n description: typeof p.description === \"string\" ? p.description : \"\",\n showInTranscript: false,\n canStop: p.cancellable === true,\n ...(typeof p.outputPath === \"string\" ? { outputFilePath: p.outputPath } : {}),\n ...(typeof p.toolCallId === \"string\" ? { toolCallId: p.toolCallId } : {}),\n _meta: { zcode: { taskKind: p.taskKind, command: p.command } },\n });\n }\n const mapped = status === \"completed\" ? \"completed\"\n : status === \"failed\" || status === \"error\" ? \"failed\"\n : status === \"cancelled\" ? \"stopped\" : null;\n if (!mapped || task.terminal)\n return;\n task.terminal = true;\n this.emit({\n sessionUpdate: \"async_task_state_update\",\n asyncTaskId: taskId,\n state: mapped,\n ...(typeof p.toolCallId === \"string\" ? { toolCallId: p.toolCallId } : {}),\n });\n }\n emit(update) {\n void this.server.notifyByZcodeSid(this.sid, update);\n }\n emitChild(childId, update) {\n const server = this.server;\n if (!server.clients || server.clients.size === 0)\n return;\n void enqueueSessionSend(childId, () => server.clients.broadcast().notify(\"session/update\", { sessionId: childId, update }));\n }\n}\n/** The parent Agent tool's result carries the sub-agent's final message plus an\n * `agentId:` line and a `<usage>` block that belong to the envelope, not the\n * answer. The backend delivers the payload as a JSON string or as an already\n * parsed object (both measured) — accept either. */\nfunction axomSubagentResultPreview(result) {\n let content = null;\n if (typeof result === \"string\") {\n try {\n const parsed = JSON.parse(result);\n if (parsed && typeof parsed.content === \"string\")\n content = parsed.content;\n }\n catch {\n content = result;\n }\n }\n else if (result && typeof result === \"object\" && typeof result.content === \"string\") {\n content = result.content;\n }\n if (typeof content !== \"string\" || !content.trim())\n return null;\n const stripped = content\n .replace(/<usage>[\\s\\S]*?<\\/usage>/g, \"\")\n .split(\"\\n\")\n .filter((line) => !/^agentId:\\s*\\S+/.test(line))\n .join(\"\\n\")\n .trim();\n return stripped ? stripped.slice(0, 2000) : null;\n}\nexport { AxomZcodeSubagents };\nexport class ZcodeAcpServer {"
36
+ },
37
+ {
38
+ "file": "dist/server.js",
39
+ "before_sha256": "df37fa0b7e5873d13a2cdd71a5fbc931a7ea9ffca521b0218d60a7a9b11e1d3c",
40
+ "after_sha256": "55d776521298e0a59d7512be34aeb2b86bc10a4cce9b038a9387ab860ab1aa2c",
41
+ "before": " backend.registerEventListener(zcodeSid, new SessionTitleListener(this, zcodeSid));\n this.backgroundListenerBackend.set(zcodeSid, backend);",
42
+ "after": " backend.registerEventListener(zcodeSid, new SessionTitleListener(this, zcodeSid));\n backend.registerEventListener(zcodeSid, new AxomZcodeSubagents(this, zcodeSid));\n this.backgroundListenerBackend.set(zcodeSid, backend);"
43
+ },
44
+ {
45
+ "file": "dist/handlers/background-tasks.js",
46
+ "before_sha256": "c0e1eb4ca1585ab419fc1bb6e8878a8b9c9ab680ef664ec3c0a9c542d3b561ca",
47
+ "after_sha256": "4dead20a31589b1ac79d526160272ac84cb8d12626a80d6085fb5c3e131d80a4",
48
+ "before": "/** Map a zcode background task status string to an ACP ToolCallStatus. */\nfunction toAcpStatus(status) {\n if (status === \"completed\")\n return \"completed\";\n if (status === \"failed\" || status === \"error\" || status === \"cancelled\")\n return \"failed\";\n return \"in_progress\"; // running / pending / unknown\n}",
49
+ "after": "/** Map a zcode background task status string to an ACP ToolCallStatus. */\nfunction toAcpStatus(status) {\n if (status === \"completed\")\n return \"completed\";\n if (status === \"failed\" || status === \"error\" || status === \"cancelled\")\n return \"failed\";\n return \"in_progress\"; // running / pending / unknown\n}\n/** Axom patch `zcode-subagent-subwork`: when the client declared the AIR async-task\n * capability, the AxomZcodeSubagents listener forwards these same events as\n * `async_task_*` session updates bound to the launch card (and sub-agent tasks as\n * subagent variants) — minting this listener's own [background] card on top would\n * render one task twice on such clients. */\nfunction axomAsyncTasksOwned(server) {\n const air = server?.clientCapabilities?._meta?.jetbrains?.air;\n return !!(air && Array.isArray(air.capabilities) && air.capabilities.includes(\"asyncTasks\"));\n}"
50
+ },
51
+ {
52
+ "file": "dist/handlers/background-tasks.js",
53
+ "before_sha256": "4dead20a31589b1ac79d526160272ac84cb8d12626a80d6085fb5c3e131d80a4",
54
+ "after_sha256": "c01f1d9f7dfae968d06afa142150ec9f6770f0d1f5a2c64b9e6475325882b223",
55
+ "before": " async onTaskStatus(p) {\n const taskId = p.taskId;",
56
+ "after": " async onTaskStatus(p) {\n // Axom patch `zcode-subagent-subwork`: with the AIR async-task capability declared,\n // AxomZcodeSubagents forwards these events as async_task variants bound to the\n // launch card (sub-agent tasks as subagent variants) — skip this listener's own\n // [background] card so one task does not render twice on such clients.\n if (p.taskKind !== \"workflow\" && axomAsyncTasksOwned(this.server))\n return;\n const taskId = p.taskId;"
57
+ },
58
+ {
59
+ "file": "dist/handlers/session.js",
60
+ "before_sha256": "e36756aa50f823d97df4861566fafc2ea6b36d7baf6d1f9aa9f918930e1c40a6",
61
+ "after_sha256": "799343ea4036b518ad7d411d192c696ebe821a4eb2b32e87c0b8b5f288cf509f",
62
+ "before": "async function adoptStoredTitle(server, acpSid, zcodeSid) {\n if (server.sessionTitles.has(acpSid))\n return;",
63
+ "after": "async function adoptStoredTitle(server, acpSid, zcodeSid) {\n // Axom patch `zcode-subagent-subwork`: the in-memory title is usually the first\n // prompt's echo; the backend's stored generated title is the real answer, and the\n // live titleUpdated push is routinely lost at a backend respawn boundary — this\n // load-time read is then the only surviving copy. A user-pinned rename still wins.\n if (server.sessionTitles.has(acpSid) && server.titleUserSetBy.has(acpSid))\n return;"
64
+ },
65
+ {
66
+ "file": "dist/handlers/session.js",
67
+ "before_sha256": "799343ea4036b518ad7d411d192c696ebe821a4eb2b32e87c0b8b5f288cf509f",
68
+ "after_sha256": "e28f651c842a85e308e12f3e97d742bcb49a2f470530f7fe3babe4c04fdca4c9",
69
+ "before": " if (hit?.title) {\n server.sessionTitles.set(acpSid, hit.title);\n server.touchSessionSummary(acpSid, hit.title);\n refreshTerminalTabTitle(server, acpSid);\n log(`adopted stored title for ${acpSid.slice(0, 8)}: ${hit.title}`);\n }",
70
+ "after": " if (hit?.title && server.sessionTitles.get(acpSid) !== hit.title) {\n server.sessionTitles.set(acpSid, hit.title);\n server.touchSessionSummary(acpSid, hit.title);\n refreshTerminalTabTitle(server, acpSid);\n // Axom patch `zcode-subagent-subwork`: broadcast so hosts sync the stored\n // generated title on (re-)attach — the live push was lost at a respawn.\n void sendSessionUpdate(server.clients.broadcast(), acpSid, {\n sessionUpdate: \"session_info_update\",\n title: hit.title,\n updatedAt: new Date().toISOString(),\n }).catch(() => { });\n log(`adopted stored title for ${acpSid.slice(0, 8)}: ${hit.title}`);\n }"
71
+ }
72
+ ]
73
+ }
package/dist/cli.js CHANGED
@@ -25,7 +25,8 @@ export function buildProgram() {
25
25
  .command('auth')
26
26
  .description('Authorize axom-cli with an Axomwork server')
27
27
  .option('--server <url>', 'Axomwork server URL')
28
- .action((options) => runCommand(() => authAction({ server: options.server ?? serverOption() })));
28
+ .option('--cowork', 'Request delegated cowork session access')
29
+ .action((options) => runCommand(() => authAction({ server: options.server ?? serverOption(), cowork: options.cowork })));
29
30
  program
30
31
  .command('whoami')
31
32
  .description('Print the authenticated Axomwork user')
@@ -38,6 +39,40 @@ export function buildProgram() {
38
39
  program
39
40
  .command('__credential-broker', { hidden: true })
40
41
  .action(() => runCredentialBroker());
42
+ const qoderCommand = program.command('qoder-acp')
43
+ .description('Prepare or run the Qoder SDK ACP adapter')
44
+ .option('--qodercli <path>', 'Explicit Qoder CLI executable')
45
+ .option('--prepare-sdk', 'Install the separate SDK runtime, then exit');
46
+ qoderCommand.action(async (options) => {
47
+ if (Boolean(options.qodercli) === Boolean(options.prepareSdk))
48
+ qoderCommand.error('Choose exactly one of --prepare-sdk or --qodercli <path>');
49
+ try {
50
+ if (options.prepareSdk) {
51
+ const { prepareSdkRuntime } = await import('./workstation/qoderAdapter/sdkRuntimeInstall.js');
52
+ const controller = new AbortController();
53
+ const cancel = () => controller.abort();
54
+ process.once('SIGINT', cancel);
55
+ process.once('SIGTERM', cancel);
56
+ try {
57
+ console.error('Preparing Qoder SDK…');
58
+ const result = await prepareSdkRuntime({ signal: controller.signal });
59
+ console.error(`Qoder SDK ready${result.alreadyInstalled ? ' (already prepared)' : ''}: ${result.instance}`);
60
+ }
61
+ finally {
62
+ process.removeListener('SIGINT', cancel);
63
+ process.removeListener('SIGTERM', cancel);
64
+ }
65
+ }
66
+ else {
67
+ const { runQoderAdapter } = await import('./workstation/qoderAdapter/main.js');
68
+ await runQoderAdapter(options.qodercli);
69
+ }
70
+ }
71
+ catch (error) {
72
+ console.error(error instanceof Error ? error.message : String(error));
73
+ process.exitCode = 1;
74
+ }
75
+ });
41
76
  registerStructCommands(program);
42
77
  registerRecordCommands(program);
43
78
  registerExecuteCommand(program);
@@ -2,13 +2,14 @@ import { hostname } from 'node:os';
2
2
  import { loadConfig, resolveServer, saveConfig } from '../config.js';
3
3
  import { callAxomTool } from '../mcp.js';
4
4
  import { authorizeDevice } from '../workstation/oauth/deviceAuthorization.js';
5
- import { revokeAndClearTokens, saveTokens } from '../credentials.js';
5
+ import { revokeAndClearTokens, revokeRefreshToken, saveTokens } from '../credentials.js';
6
+ import { cliRequestedScopes } from '../authScopes.js';
6
7
  export const DEFAULT_SERVER_URL = 'http://localhost:8080';
7
8
  export async function authAction(options, deps = {}) {
8
9
  const config = await loadConfig();
9
10
  const server = resolveServer(config, options.server ?? config.defaultServer ?? DEFAULT_SERVER_URL);
10
11
  const host = hostname();
11
- const { accessToken, refreshToken, expiresInSeconds } = await authorizeDevice(server, `Axomwork CLI (${host})`, host, deps);
12
+ const { accessToken, refreshToken, expiresInSeconds, scopes } = await authorizeDevice(server, `Axomwork CLI (${host})`, host, deps, cliRequestedScopes(options.cowork));
12
13
  const updated = await loadConfig();
13
14
  try {
14
15
  await saveTokens(server, { accessToken, refreshToken, expiresAt: new Date(Date.now() + expiresInSeconds * 1000).toISOString() });
@@ -22,6 +23,7 @@ export async function authAction(options, deps = {}) {
22
23
  updated.defaultServer = server;
23
24
  }
24
25
  await saveConfig(updated);
26
+ console.log(`Authorized scopes: ${scopes.join(', ')}`);
25
27
  const outcome = await callAxomTool(server, 'axom__system__whoami', {});
26
28
  if (outcome.isError) {
27
29
  throw new Error(outcome.text);
@@ -39,14 +41,3 @@ export async function logoutAction(options) {
39
41
  await saveConfig(config);
40
42
  console.log(`Logged out from ${server}`);
41
43
  }
42
- async function revokeRefreshToken(server, refreshToken) {
43
- await fetch(`${server}/oauth/revoke`, {
44
- method: 'POST',
45
- headers: { 'content-type': 'application/x-www-form-urlencoded' },
46
- body: new URLSearchParams({
47
- token: refreshToken,
48
- token_type_hint: 'refresh_token',
49
- client_id: 'axom-cli',
50
- }),
51
- }).catch(() => undefined);
52
- }