@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,55 @@
1
+ /**
2
+ * Test stand-in for a transport's outbox stream (Task 20): what `acp.outbox.append` / `acp.commit` do to one session's outbox,
3
+ * in memory — strictly increasing seqs, offsets, truncation through an offset with its `committedTail` watermark, checkpoints and
4
+ * raw truncation recorded. Kept per sessionRef by the manager tests' fake agents so a "reopen" reads back what an earlier life
5
+ * left, as `ProcessorSession.start` does from the real stream.
6
+ */
7
+ import { SessionOutbox } from '../outbox.js';
8
+ export class MemoryOutboxStream {
9
+ records = [];
10
+ next = 0;
11
+ committed = -1;
12
+ committedTail = null;
13
+ checkpoints = [];
14
+ rawTruncations = [];
15
+ commits = [];
16
+ /** Non-null: the next appends fail with it (a transport that went away). */
17
+ failAppend = null;
18
+ async append(entries) {
19
+ if (this.failAppend)
20
+ throw this.failAppend;
21
+ let last = this.records.at(-1)?.seq ?? this.committedTail?.seq ?? -Infinity;
22
+ for (const entry of entries) {
23
+ if (!(entry.seq > last))
24
+ throw new Error(`Outbox seq ${entry.seq} does not follow ${last}`);
25
+ last = entry.seq;
26
+ }
27
+ const first = this.next;
28
+ for (const entry of entries)
29
+ this.records.push({ o: this.next++, t: 0, seq: entry.seq, src: { ...entry.src }, frame: { ...entry.frame } });
30
+ return { first, last: this.next - 1 };
31
+ }
32
+ async commit(params) {
33
+ this.commits.push(params);
34
+ if (params.checkpoint)
35
+ this.checkpoints.push({ offset: params.checkpoint.offset, blob: String(params.checkpoint.blob) });
36
+ if (params.outbox) {
37
+ if (params.outbox.through >= this.next)
38
+ throw new Error('Outbox commit is beyond the outbox head');
39
+ this.committed = Math.max(this.committed, params.outbox.through);
40
+ this.committedTail = params.outbox.tail;
41
+ this.records = this.records.filter((r) => r.o > this.committed);
42
+ }
43
+ if (params.rawThrough !== undefined) {
44
+ const latest = this.checkpoints.at(-1)?.offset ?? -1;
45
+ if (params.rawThrough > latest)
46
+ throw new Error('Raw may only be truncated through the latest checkpoint');
47
+ this.rawTruncations.push(params.rawThrough);
48
+ }
49
+ return {};
50
+ }
51
+ /** What a new life reads back: the records past the watermark. */
52
+ leftovers() { return this.records.filter((r) => r.o > this.committed); }
53
+ /** A new life's {@link SessionOutbox} over this stream, as `ProcessorSession.start` builds it. */
54
+ outbox() { return new SessionOutbox(this, { leftovers: this.leftovers(), committedTail: this.committedTail }); }
55
+ }
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Real-capture fixtures (Task 17d) and the transducer that turns one into a processor raw log.
3
+ *
4
+ * ## What a fixture is
5
+ *
6
+ * A sanitised capture (`sanitize.ts`) in the kit-stream spelling: the wire between an ACP adapter and
7
+ * the client that captured it — `scripts/acp-capture.mjs` or the legacy capture harness. The `down`
8
+ * lines are **that client's**, with its own JSON-RPC ids; nothing in a fixture depends on the
9
+ * processor's id scheme, so a fixture stays valid when the processor changes.
10
+ *
11
+ * ## The transducer
12
+ *
13
+ * {@link transduce} plays the daemon against a fixture: every client decision the capture shows
14
+ * becomes the note the daemon would write (`session/new` → `agent_session_open`, `session/prompt` →
15
+ * `agent_prompt`, `session/set_mode` → `agent_set_config_option`, a permission answer →
16
+ * `agent_answer`, `session/cancel` → `agent_interrupt`, anything else → `rpc.request`), the processor
17
+ * writes its own `down` lines through the real record loop (`processor/test/harness.ts` `run`), and the
18
+ * adapter's `up` lines follow in capture order — a response's id rewritten from the capture client's
19
+ * request to the processor's. The result is the raw log keeper-acp would have recorded for the same
20
+ * conversation: the input of the determinism, batching, checkpoint and equivalence tests.
21
+ */
22
+ import { readdirSync, readFileSync } from 'node:fs';
23
+ import { join } from 'node:path';
24
+ import { fileURLToPath } from 'node:url';
25
+ import { permissionRequestId } from '../../permission.js';
26
+ import { MemoryRawLog } from '../../processor/memoryLog.js';
27
+ import { decodeStreamRecord } from '../../processor/record.js';
28
+ import { createProcessor } from '../../processor/step.js';
29
+ import { run } from '../../processor/test/harness.js';
30
+ export const RAW_DIR = fileURLToPath(new URL('.', import.meta.url));
31
+ /** The spawn id every transduced log uses (card ids are `perm:<SPAWN_ID>:<agent id>`). */
32
+ export const SPAWN_ID = 'spawn-fixture';
33
+ /** Every committed fixture, by discovery (never a hand-kept list). */
34
+ export function fixtureNames() {
35
+ return readdirSync(RAW_DIR).filter((name) => name.endsWith('.jsonl')).sort();
36
+ }
37
+ export function readFixtureText(name) {
38
+ return readFileSync(join(RAW_DIR, name), 'utf8');
39
+ }
40
+ /** A fixture's records, decoded through the processor's own stream decoder. */
41
+ export function loadFixture(name) {
42
+ return readFixtureText(name).split('\n').filter((line) => line.trim()).map((line) => decodeStreamRecord(JSON.parse(line)));
43
+ }
44
+ const isResponse = (m) => m.method === undefined && m.id !== undefined && ('result' in m || 'error' in m);
45
+ /** Fold a capture into the processor raw log keeper-acp would have recorded for the same conversation. */
46
+ export function transduce(capture, options = {}) {
47
+ let clock = 0;
48
+ const stdin = [];
49
+ const log = new MemoryRawLog(() => clock, (line) => stdin.push(line));
50
+ const session = { log, stdin, outbox: [], blocks: new Map() };
51
+ const processor = createProcessor();
52
+ const actions = [];
53
+ /** capture request id → processor request id (both as JSON). */
54
+ const ids = new Map();
55
+ /** capture request id → method, for the agent's requests (to classify the client's answers). */
56
+ const agentRequests = new Map();
57
+ let next = 0;
58
+ let turns = 0;
59
+ /** An interrupt was decided since the last prompt: the cards it cancelled are answered by the processor itself. */
60
+ let interrupted = false;
61
+ let configs = 0;
62
+ /** The capture id of a `session/load`: its response is where the daemon closes the history window. */
63
+ let loadRequest;
64
+ const fold = () => { next = run(processor, session, next); };
65
+ /** Append a note (and any entries that must precede its fold), fold, and return the requests the processor wrote for it. */
66
+ const decide = (entry, ...with_) => {
67
+ const before = stdin.length;
68
+ log.append(entry);
69
+ for (const extra of with_)
70
+ log.append(extra);
71
+ fold();
72
+ return stdin.slice(before).map((line) => JSON.parse(line)).filter((m) => m.method !== undefined && m.id !== undefined);
73
+ };
74
+ const map = (captured, written) => {
75
+ const own = written.find((m) => m.method === captured.method);
76
+ if (!own)
77
+ throw new Error(`transduce: the processor wrote no ${captured.method} for capture request ${JSON.stringify(captured.id)}`);
78
+ ids.set(JSON.stringify(captured.id), own.id);
79
+ };
80
+ for (const record of capture) {
81
+ clock = record.t;
82
+ if (record.kind === 'proc') {
83
+ if (record.proc.type === 'spawn') {
84
+ decide({ kind: 'proc', proc: { ...record.proc, spawnId: SPAWN_ID } });
85
+ if (options.launch !== undefined)
86
+ decide({ kind: 'note', note: { type: 'agent_launch', launch: options.launch } });
87
+ }
88
+ else {
89
+ decide({ kind: 'proc', proc: record.proc });
90
+ }
91
+ }
92
+ else if (record.kind === 'err') {
93
+ decide({ kind: 'err', line: record.line });
94
+ }
95
+ else if (record.kind === 'note') {
96
+ decide({ kind: 'note', note: record.note });
97
+ }
98
+ else if (record.kind === 'up') {
99
+ let line = record.line;
100
+ let message;
101
+ try {
102
+ message = JSON.parse(line);
103
+ }
104
+ catch { /* a parse error is the processor's business */ }
105
+ if (message && isResponse(message)) {
106
+ const own = ids.get(JSON.stringify(message.id));
107
+ if (own !== undefined)
108
+ line = JSON.stringify({ ...message, id: own });
109
+ }
110
+ else if (message && message.method !== undefined && message.id !== undefined) {
111
+ agentRequests.set(JSON.stringify(message.id), message.method);
112
+ }
113
+ decide({ kind: 'up', line });
114
+ // T19: the daemon writes `historyEnd` as soon as it has seen the load's result (the open result
115
+ // the processor reports on this record) — every update after it is live, never history.
116
+ if (message && isResponse(message) && loadRequest !== undefined && JSON.stringify(message.id) === loadRequest) {
117
+ loadRequest = undefined;
118
+ decide({ kind: 'note', note: { type: 'historyEnd' } });
119
+ }
120
+ }
121
+ else {
122
+ const message = JSON.parse(record.line);
123
+ const params = message.params ?? {};
124
+ if (message.method === 'initialize') {
125
+ const own = stdin.map((l) => JSON.parse(l)).filter((m) => m.method === 'initialize').at(-1);
126
+ if (!own)
127
+ throw new Error('transduce: no initialize was written at spawn');
128
+ ids.set(JSON.stringify(message.id), own.id);
129
+ }
130
+ else if (message.method === 'session/new' || message.method === 'session/load' || message.method === 'session/resume') {
131
+ const mode = message.method.slice('session/'.length);
132
+ const mcpServers = Array.isArray(params.mcpServers) ? params.mcpServers : [];
133
+ actions.push({ kind: 'open', mode: mode, cwd: String(params.cwd), mcpServers,
134
+ ...(mode !== 'new' ? { sessionId: String(params.sessionId) } : {}) });
135
+ if (mode === 'load')
136
+ loadRequest = JSON.stringify(message.id);
137
+ map(message, decide({ kind: 'note', note: {
138
+ type: 'agent_session_open', mode, cwd: params.cwd, mcpServers,
139
+ ...(mode !== 'new' ? { sessionId: params.sessionId } : {}),
140
+ } }, ...(mode === 'load' && options.afterLoadOpen ? options.afterLoadOpen(String(params.sessionId)) : [])));
141
+ }
142
+ else if (message.method === 'session/prompt') {
143
+ turns += 1;
144
+ const blocksRef = `blocks-${turns}`;
145
+ const blocks = params.prompt;
146
+ const platformTurnId = `turn-${turns}`;
147
+ session.blocks.set(blocksRef, blocks);
148
+ interrupted = false;
149
+ actions.push({ kind: 'prompt', blocks, platformTurnId });
150
+ map(message, decide({ kind: 'note', note: { type: 'agent_prompt', blocksRef, platformTurnId } }));
151
+ }
152
+ else if (message.method === 'session/set_mode' || message.method === 'session/set_config_option') {
153
+ configs += 1;
154
+ const configId = message.method === 'session/set_mode' ? 'acp:modes' : String(params.configId);
155
+ const value = message.method === 'session/set_mode' ? params.modeId : params.value;
156
+ actions.push({ kind: 'config', configId, value });
157
+ map(message, decide({ kind: 'note', note: { type: 'agent_set_config_option', id: `cfg-${configs}`, configId, value } }));
158
+ }
159
+ else if (message.method === 'session/cancel') {
160
+ actions.push({ kind: 'interrupt', o: record.o });
161
+ interrupted = true;
162
+ decide({ kind: 'note', note: { type: 'agent_interrupt' } });
163
+ }
164
+ else if (message.method !== undefined && message.id !== undefined) {
165
+ actions.push({ kind: 'rpc', method: message.method });
166
+ map(message, decide({ kind: 'note', note: { type: 'rpc.request', method: message.method, ...(message.params !== undefined ? { params } : {}) } }));
167
+ }
168
+ else if (isResponse(message)) {
169
+ const method = agentRequests.get(JSON.stringify(message.id));
170
+ if (method === 'session/request_permission') {
171
+ const outcome = message.result?.outcome;
172
+ const optionId = outcome?.outcome === 'selected' && typeof outcome.optionId === 'string' ? outcome.optionId : null;
173
+ // A `cancelled` answer after the client's interrupt is the interrupt's own doing: the processor
174
+ // answered that card on the `agent_interrupt` note, as `AcpSession.interrupt` does.
175
+ const byInterrupt = optionId === null && interrupted;
176
+ actions.push({ kind: 'answer', agentRequestId: message.id, optionId, byInterrupt });
177
+ if (!byInterrupt) {
178
+ decide({ kind: 'note', note: {
179
+ type: 'agent_answer', requestId: permissionRequestId(SPAWN_ID, message.id), outcome: optionId ?? '__cancelled__',
180
+ } });
181
+ }
182
+ }
183
+ // Any other answer (the capture client refusing fs/terminal with -32601) the processor
184
+ // already gave itself on the request's own record.
185
+ }
186
+ else {
187
+ throw new Error(`transduce: no daemon decision for the capture's down line ${record.line.slice(0, 200)}`);
188
+ }
189
+ }
190
+ const extra = options.after?.get(record.o);
191
+ if (extra)
192
+ for (const entry of extra())
193
+ decide(entry);
194
+ }
195
+ return { session, records: log.read(0), frames: session.outbox, processor, actions };
196
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Qoder captures for Task 17d, built from the update-level Qoder fixtures — there is **no raw Qoder
3
+ * capture** (ruling: a real one is the T23 real-machine gate's).
4
+ *
5
+ * Each one is wrapped into the same raw-record spelling as a sanitised real capture, as the wire
6
+ * `qoder-cli` / the SDK adapter would put it between a client and itself: `initialize` (the adapter's
7
+ * identity), `session/new`, one `session/prompt`, the fixture's `session/update` lines, the prompt's
8
+ * response. Side-channel inputs (the root transcript rows the background terminal repair reads) are
9
+ * returned beside the capture: the live path reads them from a history home, the processor gets them
10
+ * as `qoder_side` notes from the daemon's reader.
11
+ *
12
+ * Sources: `acp/test/qoder-parallel-foreground.json`, `acp/test/qoder-delegation.json` (the `live`
13
+ * phase of both probes), `acp/test/qoder-background-terminal.json` (updates + native rows, plus a
14
+ * variant whose result is large enough to be chunked into several notes), and
15
+ * `qoderAdapter/fixtures/native-events.json` through the real SDK adapter `QoderMessageMapper` and
16
+ * `PermissionBridge` (SDK callback cards).
17
+ */
18
+ import { readFileSync } from 'node:fs';
19
+ import { fileURLToPath } from 'node:url';
20
+ import { QoderMessageMapper } from '../../../qoderAdapter/mapper.js';
21
+ import { PermissionBridge } from '../../../qoderAdapter/permissions.js';
22
+ import { QODER_PROFILE } from '../../processor/test/fixtureLog.js';
23
+ const json = (path) => JSON.parse(readFileSync(fileURLToPath(new URL(path, import.meta.url)), 'utf8'));
24
+ export const CERTIFIED_QODER = { name: 'qoder-cli', version: '1.1.61' };
25
+ export const QODER_SDK = { name: 'axom-qoder-sdk', version: '1.0.50' };
26
+ /** Lines → kit-stream ndjson (a synthetic `proc spawn` first, `t` = position). */
27
+ export function captureText(lines) {
28
+ const records = [JSON.stringify({ o: 0, t: 0, k: 'proc', kind: 'spawn', spawnId: 'capture', pid: 0, pgid: 0, startTime: 0 })];
29
+ lines.forEach((line, index) => records.push(JSON.stringify({ o: index + 1, t: index + 1, k: line.k, l: JSON.stringify(line.message) })));
30
+ return `${records.join('\n')}\n`;
31
+ }
32
+ export const up = (message) => ({ k: 'up', message });
33
+ export const down = (message) => ({ k: 'down', message });
34
+ export const update = (sessionId, value) => up({ jsonrpc: '2.0', method: 'session/update', params: { sessionId, update: value } });
35
+ /** initialize → session/new → (between) → prompt → updates → response. */
36
+ function oneTurn(options) {
37
+ return captureText([
38
+ down({ jsonrpc: '2.0', id: 1, method: 'initialize', params: { protocolVersion: 1, clientCapabilities: {} } }),
39
+ up({ jsonrpc: '2.0', id: 1, result: { protocolVersion: 1, agentCapabilities: { loadSession: true }, authMethods: [],
40
+ agentInfo: options.agentInfo, ...(options.initializeMeta ? { _meta: options.initializeMeta } : {}) } }),
41
+ down({ jsonrpc: '2.0', id: 2, method: 'session/new', params: { cwd: options.cwd, mcpServers: [] } }),
42
+ up({ jsonrpc: '2.0', id: 2, result: { sessionId: options.sessionId } }),
43
+ ...(options.afterOpen ?? []),
44
+ down({ jsonrpc: '2.0', id: 3, method: 'session/prompt', params: { sessionId: options.sessionId, prompt: [{ type: 'text', text: 'xxxxx' }] } }),
45
+ ...options.updates.map((value) => update(options.sessionId, value)),
46
+ ...(options.inTurn ?? []),
47
+ up({ jsonrpc: '2.0', id: 3, result: { stopReason: options.stopReason ?? 'end_turn' } }),
48
+ ]);
49
+ }
50
+ function parallelForeground() {
51
+ const fixture = json('../qoder-parallel-foreground.json');
52
+ const sessionId = 'qoder-root';
53
+ const cwd = '/work/baseline';
54
+ return { name: 'qoder-parallel-foreground', sessionId, cwd,
55
+ text: oneTurn({ agentInfo: CERTIFIED_QODER, sessionId, cwd, updates: fixture.updates }) };
56
+ }
57
+ function delegationProbes() {
58
+ const fixture = json('../qoder-delegation.json');
59
+ return fixture.probes.map((probe) => {
60
+ const sessionId = probe.events[0].sessionId;
61
+ const cwd = '/work/delegation';
62
+ return { name: `qoder-delegation-${probe.name}`, sessionId, cwd, text: oneTurn({ agentInfo: CERTIFIED_QODER, sessionId, cwd,
63
+ updates: probe.events.filter((event) => event.phase === 'live').map((event) => event.update) }) };
64
+ });
65
+ }
66
+ function backgroundTerminal(large) {
67
+ const fixture = json('../qoder-background-terminal.json');
68
+ // The large variant: task B's result grows to ~96 KiB (under the 128 KiB result cap, over one
69
+ // 64 KiB note), so its `terminal` fact reaches the processor as several `qoder_side` chunks.
70
+ const rows = large
71
+ ? fixture.nativeRows.map((row) => JSON.parse(JSON.stringify(row).replace('QODER_TERMINAL_20261003_B_DONE', `QODER_TERMINAL_20261003_B_DONE ${'0123456789abcdef'.repeat(6 * 1024)}`)))
72
+ : fixture.nativeRows;
73
+ return { name: large ? 'qoder-background-terminal-large' : 'qoder-background-terminal', sessionId: fixture.nativeSessionId, cwd: fixture.cwd,
74
+ nativeRows: rows, text: oneTurn({ agentInfo: CERTIFIED_QODER, sessionId: fixture.nativeSessionId, cwd: fixture.cwd, updates: fixture.updates }) };
75
+ }
76
+ /**
77
+ * The SDK adapter's callback cards: `native-events.json`'s two child tool calls mapped by the real
78
+ * `QoderMessageMapper`, and one permission request per child raised through the real
79
+ * `PermissionBridge` (its random request id replaced by a fixed UUID), answered allow / reject.
80
+ */
81
+ async function sdkCards() {
82
+ const fixture = json('../../../qoderAdapter/fixtures/native-events.json');
83
+ const binding = { rootSessionId: fixture.rootSessionId, runtimeGeneration: fixture.runtimeGeneration };
84
+ const corrections = [];
85
+ const mapper = new QoderMessageMapper(binding, { correction: (value) => corrections.push(value) });
86
+ const updates = [];
87
+ const tools = fixture.hooks.filter((hook) => hook.event === 'tool');
88
+ for (const [index, hook] of tools.entries()) {
89
+ updates.push(...mapper.map({ type: 'assistant', session_id: fixture.rootSessionId, uuid: `assistant-${index}`, parent_tool_use_id: null,
90
+ message: { role: 'assistant', content: [{ type: 'tool_use', id: hook.toolUseId, name: 'Edit', input: { path: '/work/sdk/fixture.txt' } }] } }, `run-${hook.agentId}`));
91
+ mapper.observe({ ...binding, toolUseId: hook.toolUseId, agentId: hook.agentId, launchingToolUseId: hook.launchingToolUseId });
92
+ }
93
+ updates.push(...corrections);
94
+ mapper.dispose();
95
+ const requests = [];
96
+ const bridge = new PermissionBridge({ ...binding, request: async (request) => {
97
+ requests.push(request);
98
+ return { outcome: { outcome: 'cancelled' } };
99
+ } });
100
+ for (const hook of tools) {
101
+ await bridge.canUseTool('Edit', { path: '/work/sdk/fixture.txt' }, {
102
+ toolUseID: hook.toolUseId, agentID: hook.agentId, signal: new AbortController().signal,
103
+ permissionOptions: [{ outcome: 'proceed_once', allowed: true }],
104
+ });
105
+ }
106
+ bridge.close();
107
+ const cards = [];
108
+ requests.forEach((request, index) => {
109
+ const meta = request.toolCall._meta.qoderSdk;
110
+ const fixed = { ...request, toolCall: { ...request.toolCall, _meta: { qoderSdk: { ...meta, requestId: `00000000-0000-4000-8000-${String(index + 1).padStart(12, '0')}` } } } };
111
+ cards.push(up({ jsonrpc: '2.0', id: 10 + index, method: 'session/request_permission', params: fixed }));
112
+ cards.push(down({ jsonrpc: '2.0', id: 10 + index, result: { outcome: { outcome: 'selected', optionId: index === 0 ? 'allow' : 'reject' } } }));
113
+ });
114
+ const sdkProfile = { ...QODER_PROFILE, mode: 'sdk-adapter' };
115
+ const sessionId = fixture.rootSessionId;
116
+ return { name: 'qoder-sdk-cards', sessionId, cwd: '/work/sdk', text: oneTurn({
117
+ agentInfo: QODER_SDK, initializeMeta: { qoderProfile: sdkProfile }, sessionId, cwd: '/work/sdk',
118
+ afterOpen: [up({ jsonrpc: '2.0', method: '_axom/qoder/profile', params: { sessionId, revision: 1,
119
+ profile: { ...sdkProfile, rootSessionId: sessionId, runtimeGeneration: fixture.runtimeGeneration, rootConfirmed: true, initialized: true } } })],
120
+ updates, inTurn: cards,
121
+ }) };
122
+ }
123
+ export async function qoderCaptures() {
124
+ return [parallelForeground(), ...delegationProbes(), backgroundTerminal(false), backgroundTerminal(true), await sdkCards()];
125
+ }