@wjarka/cezarion 0.16.0 → 0.17.0

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 (907) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +594 -207
  3. package/dist/agent-config/account-identity.d.ts +3 -19
  4. package/dist/agent-config/account-identity.js +8 -5
  5. package/dist/agent-config/account-identity.js.map +1 -1
  6. package/dist/agent-config/catalog.d.ts +3 -14
  7. package/dist/agent-config/catalog.js.map +1 -1
  8. package/dist/agent-config/files.d.ts +2 -6
  9. package/dist/agent-config/files.js +2 -6
  10. package/dist/agent-config/files.js.map +1 -1
  11. package/dist/agent-config/model-settings/types.d.ts +1 -1
  12. package/dist/agent-config/seed.d.ts +11 -3
  13. package/dist/agent-config/seed.js +52 -48
  14. package/dist/agent-config/seed.js.map +1 -1
  15. package/dist/agent-config/service.js +3 -2
  16. package/dist/agent-config/service.js.map +1 -1
  17. package/dist/agent-config/validate.d.ts +1 -4
  18. package/dist/agent-config/validate.js.map +1 -1
  19. package/dist/application-update/helper.d.ts +2 -2
  20. package/dist/application-update/helper.js +7 -12
  21. package/dist/application-update/helper.js.map +1 -1
  22. package/dist/application-update/launcher.d.ts +4 -0
  23. package/dist/application-update/launcher.js +18 -12
  24. package/dist/application-update/launcher.js.map +1 -1
  25. package/dist/application-update/service.d.ts +3 -3
  26. package/dist/application-update/service.js +1 -1
  27. package/dist/application-update/service.js.map +1 -1
  28. package/dist/archive-on-merge-setting.d.ts +15 -0
  29. package/dist/archive-on-merge-setting.js +14 -0
  30. package/dist/archive-on-merge-setting.js.map +1 -0
  31. package/dist/artifacts/cli.d.ts +8 -0
  32. package/dist/artifacts/cli.js +21 -2
  33. package/dist/artifacts/cli.js.map +1 -1
  34. package/dist/artifacts/resolve.js +2 -1
  35. package/dist/artifacts/resolve.js.map +1 -1
  36. package/dist/artifacts/store.js.map +1 -1
  37. package/dist/automations/automation-cli.d.ts +59 -0
  38. package/dist/automations/automation-cli.js +509 -0
  39. package/dist/automations/automation-cli.js.map +1 -0
  40. package/dist/automations/builtin-skill.d.ts +7 -0
  41. package/dist/automations/builtin-skill.js +14 -0
  42. package/dist/automations/builtin-skill.js.map +1 -0
  43. package/dist/automations/github-baseline.d.ts +3 -0
  44. package/dist/automations/github-baseline.js +17 -0
  45. package/dist/automations/github-baseline.js.map +1 -0
  46. package/dist/automations/github-poller.d.ts +23 -4
  47. package/dist/automations/github-poller.js +157 -88
  48. package/dist/automations/github-poller.js.map +1 -1
  49. package/dist/automations/prompts.d.ts +12 -0
  50. package/dist/automations/prompts.js +160 -0
  51. package/dist/automations/prompts.js.map +1 -0
  52. package/dist/automations/schedule-runner.d.ts +43 -24
  53. package/dist/automations/schedule-runner.js +207 -20
  54. package/dist/automations/schedule-runner.js.map +1 -1
  55. package/dist/automations/scheduler.d.ts +10 -2
  56. package/dist/automations/scheduler.js +200 -54
  57. package/dist/automations/scheduler.js.map +1 -1
  58. package/dist/automations/service.d.ts +777 -0
  59. package/dist/automations/service.js +444 -0
  60. package/dist/automations/service.js.map +1 -0
  61. package/dist/automations/store.d.ts +17 -7
  62. package/dist/automations/store.js +88 -17
  63. package/dist/automations/store.js.map +1 -1
  64. package/dist/automations/task-template.d.ts +7 -2
  65. package/dist/automations/task-template.js +93 -44
  66. package/dist/automations/task-template.js.map +1 -1
  67. package/dist/automations/tool-adapter.d.ts +6 -0
  68. package/dist/automations/tool-adapter.js +108 -0
  69. package/dist/automations/tool-adapter.js.map +1 -0
  70. package/dist/automations/types.d.ts +1 -405
  71. package/dist/automations/types.js +1 -218
  72. package/dist/automations/types.js.map +1 -1
  73. package/dist/autosave-cleanup.d.ts +26 -0
  74. package/dist/autosave-cleanup.js +87 -0
  75. package/dist/autosave-cleanup.js.map +1 -0
  76. package/dist/autosave-git.d.ts +3 -0
  77. package/dist/autosave-git.js +67 -35
  78. package/dist/autosave-git.js.map +1 -1
  79. package/dist/autosave-group.d.ts +8 -0
  80. package/dist/autosave-group.js +61 -0
  81. package/dist/autosave-group.js.map +1 -0
  82. package/dist/autosave-holders.d.ts +31 -4
  83. package/dist/autosave-holders.js +92 -7
  84. package/dist/autosave-holders.js.map +1 -1
  85. package/dist/autosave-windows.d.ts +14 -0
  86. package/dist/autosave-windows.js +36 -2
  87. package/dist/autosave-windows.js.map +1 -1
  88. package/dist/ci-wait/client.d.ts +20 -3
  89. package/dist/ci-wait/client.js +40 -44
  90. package/dist/ci-wait/client.js.map +1 -1
  91. package/dist/ci-wait/controller.d.ts +622 -36
  92. package/dist/ci-wait/controller.js +152 -20
  93. package/dist/ci-wait/controller.js.map +1 -1
  94. package/dist/ci-wait/errors.d.ts +19 -0
  95. package/dist/ci-wait/errors.js +180 -2
  96. package/dist/ci-wait/errors.js.map +1 -1
  97. package/dist/ci-wait/github.d.ts +25 -1
  98. package/dist/ci-wait/github.js +76 -9
  99. package/dist/ci-wait/github.js.map +1 -1
  100. package/dist/ci-wait/mcp.d.ts +0 -1
  101. package/dist/ci-wait/mcp.js +0 -2
  102. package/dist/ci-wait/mcp.js.map +1 -1
  103. package/dist/ci-wait/supervisor.d.ts +7 -0
  104. package/dist/ci-wait/supervisor.js +113 -17
  105. package/dist/ci-wait/supervisor.js.map +1 -1
  106. package/dist/ci-wait/tools.d.ts +536 -16
  107. package/dist/ci-wait/tools.js +165 -20
  108. package/dist/ci-wait/tools.js.map +1 -1
  109. package/dist/config.d.ts +3 -17
  110. package/dist/config.js +4 -60
  111. package/dist/config.js.map +1 -1
  112. package/dist/contract/active-provider.d.ts +12 -0
  113. package/dist/contract/agent-profiles.d.ts +2 -10
  114. package/dist/contract/ask-schema.d.ts +22 -4
  115. package/dist/contract/ask.d.ts +6 -4
  116. package/dist/contract/attachments.d.ts +35 -0
  117. package/dist/contract/attention.d.ts +46 -37
  118. package/dist/contract/automation-requests.d.ts +308 -0
  119. package/dist/contract/automation-schedule.d.ts +40 -11
  120. package/dist/contract/automation-storage.d.ts +512 -0
  121. package/dist/contract/automations.d.ts +421 -40
  122. package/dist/contract/ci-wait.d.ts +41 -4
  123. package/dist/contract/config-requests.d.ts +36 -0
  124. package/dist/contract/conversations.d.ts +24 -10
  125. package/dist/contract/defined.d.ts +8 -0
  126. package/dist/contract/delegation.d.ts +312 -8
  127. package/dist/contract/events.d.ts +24 -3
  128. package/dist/contract/github-requests.d.ts +26 -0
  129. package/dist/contract/github.d.ts +60 -27
  130. package/dist/contract/handoff.d.ts +43 -0
  131. package/dist/contract/health.d.ts +2 -2
  132. package/dist/contract/image-path.d.ts +6 -0
  133. package/dist/contract/index.d.ts +31 -0
  134. package/dist/contract/index.js +3756 -1525
  135. package/dist/contract/live-coordination.d.ts +158 -0
  136. package/dist/contract/live-limits.d.ts +8 -0
  137. package/dist/contract/live.d.ts +123 -0
  138. package/dist/contract/pending-ask.d.ts +58 -0
  139. package/dist/contract/permissions.d.ts +54 -0
  140. package/dist/contract/preview.d.ts +33 -0
  141. package/dist/contract/project-limits.d.ts +33 -0
  142. package/dist/contract/projects.d.ts +486 -20
  143. package/dist/contract/provider-requests.d.ts +77 -0
  144. package/dist/contract/query-requests.d.ts +52 -0
  145. package/dist/contract/repo-requests.d.ts +12 -0
  146. package/dist/contract/run-labels.d.ts +8 -0
  147. package/dist/contract/run-limits.d.ts +8 -0
  148. package/dist/contract/run-predicates.d.ts +32 -0
  149. package/dist/contract/run-requests.d.ts +33 -0
  150. package/dist/contract/run-search.d.ts +193 -0
  151. package/dist/contract/runs.d.ts +2232 -1894
  152. package/dist/contract/scheduled-tasks.d.ts +187 -0
  153. package/dist/contract/skills.d.ts +22 -772
  154. package/dist/contract/team-skill-ref.d.ts +10 -0
  155. package/dist/{core → contract}/tool-display.d.ts +4 -10
  156. package/dist/contract/ui-state-requests.d.ts +60 -0
  157. package/dist/contract/version.d.ts +3 -0
  158. package/dist/contract/voice.d.ts +213 -0
  159. package/dist/contract/waits.d.ts +1204 -0
  160. package/dist/contract/workflow-file.d.ts +37 -0
  161. package/dist/contract/workflow-requests.d.ts +7 -0
  162. package/dist/contract/workflows.d.ts +1 -2
  163. package/dist/contract/workspace.d.ts +34 -82
  164. package/dist/contract/zoned-time.d.ts +2 -11
  165. package/dist/core/agent-env.d.ts +4 -16
  166. package/dist/core/agent-env.js +14 -16
  167. package/dist/core/agent-env.js.map +1 -1
  168. package/dist/core/agent-profiles.d.ts +28 -40
  169. package/dist/core/agent-profiles.js +56 -51
  170. package/dist/core/agent-profiles.js.map +1 -1
  171. package/dist/core/agent-runner.d.ts +88 -44
  172. package/dist/core/agent-runner.js +17 -18
  173. package/dist/core/agent-runner.js.map +1 -1
  174. package/dist/core/ask.d.ts +3 -0
  175. package/dist/core/ask.js +12 -0
  176. package/dist/core/ask.js.map +1 -1
  177. package/dist/core/backend-detect.js +16 -2
  178. package/dist/core/backend-detect.js.map +1 -1
  179. package/dist/core/claude-cli-runner.d.ts +23 -4
  180. package/dist/core/claude-cli-runner.js +280 -76
  181. package/dist/core/claude-cli-runner.js.map +1 -1
  182. package/dist/core/claude-model-catalog.d.ts +2 -10
  183. package/dist/core/claude-model-catalog.js +2 -10
  184. package/dist/core/claude-model-catalog.js.map +1 -1
  185. package/dist/core/claude-ui-mapper.d.ts +2 -2
  186. package/dist/core/claude-ui-mapper.js +94 -2
  187. package/dist/core/claude-ui-mapper.js.map +1 -1
  188. package/dist/core/codex-app-server-runner.d.ts +3 -4
  189. package/dist/core/codex-app-server-runner.js +146 -51
  190. package/dist/core/codex-app-server-runner.js.map +1 -1
  191. package/dist/core/codex-app-server-transport.d.ts +4 -3
  192. package/dist/core/codex-app-server-transport.js +11 -7
  193. package/dist/core/codex-app-server-transport.js.map +1 -1
  194. package/dist/core/codex-approvals.d.ts +12 -0
  195. package/dist/core/codex-approvals.js +161 -0
  196. package/dist/core/codex-approvals.js.map +1 -0
  197. package/dist/core/codex-permissions.d.ts +1 -1
  198. package/dist/core/codex-ui-mapper.js +45 -1
  199. package/dist/core/codex-ui-mapper.js.map +1 -1
  200. package/dist/core/cursor-acp-runner.d.ts +1 -1
  201. package/dist/core/cursor-acp-runner.js +39 -15
  202. package/dist/core/cursor-acp-runner.js.map +1 -1
  203. package/dist/core/cursor-cli-flags.d.ts +19 -0
  204. package/dist/core/cursor-cli-flags.js +47 -0
  205. package/dist/core/cursor-cli-flags.js.map +1 -0
  206. package/dist/core/cursor-model-catalog.d.ts +22 -0
  207. package/dist/core/cursor-model-catalog.js +53 -24
  208. package/dist/core/cursor-model-catalog.js.map +1 -1
  209. package/dist/core/cursor-print-capabilities.d.ts +16 -0
  210. package/dist/core/cursor-print-capabilities.js +141 -0
  211. package/dist/core/cursor-print-capabilities.js.map +1 -0
  212. package/dist/core/cursor-print-process.d.ts +31 -0
  213. package/dist/core/cursor-print-process.js +117 -0
  214. package/dist/core/cursor-print-process.js.map +1 -0
  215. package/dist/core/cursor-print-runner.d.ts +31 -0
  216. package/dist/core/cursor-print-runner.js +555 -0
  217. package/dist/core/cursor-print-runner.js.map +1 -0
  218. package/dist/core/cursor-print-tool-catalog.d.ts +10 -0
  219. package/dist/core/cursor-print-tool-catalog.js +91 -0
  220. package/dist/core/cursor-print-tool-catalog.js.map +1 -0
  221. package/dist/core/cursor-print-ui-mapper.d.ts +47 -0
  222. package/dist/core/cursor-print-ui-mapper.js +553 -0
  223. package/dist/core/cursor-print-ui-mapper.js.map +1 -0
  224. package/dist/core/cursor-runner.d.ts +24 -0
  225. package/dist/core/cursor-runner.js +149 -0
  226. package/dist/core/cursor-runner.js.map +1 -0
  227. package/dist/core/cursor-ui-mapper.js +5 -2
  228. package/dist/core/cursor-ui-mapper.js.map +1 -1
  229. package/dist/core/defined.d.ts +1 -0
  230. package/dist/core/defined.js +2 -0
  231. package/dist/core/defined.js.map +1 -0
  232. package/dist/core/hook-items.d.ts +14 -0
  233. package/dist/core/hook-items.js +13 -0
  234. package/dist/core/hook-items.js.map +1 -0
  235. package/dist/core/host-model-catalog.d.ts +2 -9
  236. package/dist/core/host-model-catalog.js +2 -9
  237. package/dist/core/host-model-catalog.js.map +1 -1
  238. package/dist/core/managed-session.js +15 -3
  239. package/dist/core/managed-session.js.map +1 -1
  240. package/dist/core/model-identity.d.ts +4 -21
  241. package/dist/core/model-identity.js.map +1 -1
  242. package/dist/core/model-presets.d.ts +2 -13
  243. package/dist/core/model-presets.js +2 -13
  244. package/dist/core/model-presets.js.map +1 -1
  245. package/dist/core/omp-model-catalog.js.map +1 -1
  246. package/dist/core/omp-runner.d.ts +6 -7
  247. package/dist/core/omp-runner.js +92 -33
  248. package/dist/core/omp-runner.js.map +1 -1
  249. package/dist/core/omp-ui-mapper.js +1 -1
  250. package/dist/core/omp-ui-mapper.js.map +1 -1
  251. package/dist/core/opencode-model-catalog.js.map +1 -1
  252. package/dist/core/opencode-permissions.d.ts +52 -0
  253. package/dist/core/opencode-permissions.js +101 -0
  254. package/dist/core/opencode-permissions.js.map +1 -0
  255. package/dist/core/opencode-server-runner.d.ts +10 -9
  256. package/dist/core/opencode-server-runner.js +286 -28
  257. package/dist/core/opencode-server-runner.js.map +1 -1
  258. package/dist/core/opencode-session-error.d.ts +15 -7
  259. package/dist/core/opencode-session-error.js +25 -9
  260. package/dist/core/opencode-session-error.js.map +1 -1
  261. package/dist/core/opencode-ui-mapper.js +2 -2
  262. package/dist/core/opencode-ui-mapper.js.map +1 -1
  263. package/dist/core/pi-model-catalog.js.map +1 -1
  264. package/dist/core/pi-runner.d.ts +12 -4
  265. package/dist/core/pi-runner.js +171 -63
  266. package/dist/core/pi-runner.js.map +1 -1
  267. package/dist/core/pi-ui-mapper.js +1 -1
  268. package/dist/core/pi-ui-mapper.js.map +1 -1
  269. package/dist/core/process-usage.d.ts +5 -0
  270. package/dist/core/process-usage.js +24 -4
  271. package/dist/core/process-usage.js.map +1 -1
  272. package/dist/core/provider-auth.d.ts +16 -107
  273. package/dist/core/provider-auth.js +16 -132
  274. package/dist/core/provider-auth.js.map +1 -1
  275. package/dist/core/runner-factory.d.ts +4 -1
  276. package/dist/core/runner-factory.js +3 -3
  277. package/dist/core/runner-factory.js.map +1 -1
  278. package/dist/core/runner-runtime.d.ts +22 -0
  279. package/dist/core/runner-runtime.js +66 -5
  280. package/dist/core/runner-runtime.js.map +1 -1
  281. package/dist/core/runner-tool-grants.d.ts +21 -0
  282. package/dist/core/runner-tool-grants.js +64 -0
  283. package/dist/core/runner-tool-grants.js.map +1 -0
  284. package/dist/core/secret-redaction.d.ts +3 -20
  285. package/dist/core/secret-redaction.js +3 -20
  286. package/dist/core/secret-redaction.js.map +1 -1
  287. package/dist/core/session-process.d.ts +22 -2
  288. package/dist/core/session-process.js +170 -12
  289. package/dist/core/session-process.js.map +1 -1
  290. package/dist/core/shell-env.d.ts +2 -15
  291. package/dist/core/shell-env.js +2 -15
  292. package/dist/core/shell-env.js.map +1 -1
  293. package/dist/core/ui-events.d.ts +60 -47
  294. package/dist/core/ui-events.js +0 -23
  295. package/dist/core/ui-events.js.map +1 -1
  296. package/dist/core/usage-limit.js.map +1 -1
  297. package/dist/data-gitignore.js +3 -1
  298. package/dist/data-gitignore.js.map +1 -1
  299. package/dist/delegation/capacity.d.ts +4 -8
  300. package/dist/delegation/capacity.js +4 -8
  301. package/dist/delegation/capacity.js.map +1 -1
  302. package/dist/delegation/cli.js +123 -21
  303. package/dist/delegation/cli.js.map +1 -1
  304. package/dist/delegation/context.d.ts +19 -3
  305. package/dist/delegation/context.js +217 -22
  306. package/dist/delegation/context.js.map +1 -1
  307. package/dist/delegation/conversations.d.ts +4 -3
  308. package/dist/delegation/conversations.js +7 -5
  309. package/dist/delegation/conversations.js.map +1 -1
  310. package/dist/delegation/destroy-observation.d.ts +1 -1
  311. package/dist/delegation/destroy-observation.js.map +1 -1
  312. package/dist/delegation/effort.js.map +1 -1
  313. package/dist/delegation/execution-identity.d.ts +1 -1
  314. package/dist/delegation/execution-identity.js +41 -7
  315. package/dist/delegation/execution-identity.js.map +1 -1
  316. package/dist/delegation/idle-test-app.d.ts +4 -0
  317. package/dist/delegation/idle-test-app.js +174 -0
  318. package/dist/delegation/idle-test-app.js.map +1 -0
  319. package/dist/delegation/input.js.map +1 -1
  320. package/dist/delegation/park-notice.d.ts +42 -0
  321. package/dist/delegation/park-notice.js +71 -0
  322. package/dist/delegation/park-notice.js.map +1 -0
  323. package/dist/delegation/policy.d.ts +2 -0
  324. package/dist/delegation/policy.js +9 -1
  325. package/dist/delegation/policy.js.map +1 -1
  326. package/dist/delegation/process-liveness.d.ts +10 -15
  327. package/dist/delegation/process-liveness.js +11 -35
  328. package/dist/delegation/process-liveness.js.map +1 -1
  329. package/dist/delegation/provision.js +21 -19
  330. package/dist/delegation/provision.js.map +1 -1
  331. package/dist/delegation/questions.d.ts +3 -1
  332. package/dist/delegation/questions.js +10 -5
  333. package/dist/delegation/questions.js.map +1 -1
  334. package/dist/delegation/readiness.d.ts +2 -2
  335. package/dist/delegation/results.d.ts +4 -1
  336. package/dist/delegation/results.js +49 -18
  337. package/dist/delegation/results.js.map +1 -1
  338. package/dist/delegation/retry-backoff.d.ts +8 -0
  339. package/dist/delegation/retry-backoff.js +8 -0
  340. package/dist/delegation/retry-backoff.js.map +1 -1
  341. package/dist/delegation/routes.d.ts +114 -30
  342. package/dist/delegation/routes.js +4 -1
  343. package/dist/delegation/routes.js.map +1 -1
  344. package/dist/delegation/scratch-cleanup.d.ts +4 -5
  345. package/dist/delegation/scratch-cleanup.js +10 -8
  346. package/dist/delegation/scratch-cleanup.js.map +1 -1
  347. package/dist/delegation/service.d.ts +12 -4
  348. package/dist/delegation/service.js +76 -28
  349. package/dist/delegation/service.js.map +1 -1
  350. package/dist/delegation/transport.d.ts +154 -70
  351. package/dist/delegation/wait.d.ts +11 -0
  352. package/dist/delegation/wait.js +24 -0
  353. package/dist/delegation/wait.js.map +1 -1
  354. package/dist/delegation/windows-test-app.d.ts +5 -0
  355. package/dist/delegation/windows-test-app.js +63 -0
  356. package/dist/delegation/windows-test-app.js.map +1 -0
  357. package/dist/delegation/windows-workspace-identity.d.ts +3 -0
  358. package/dist/delegation/windows-workspace-identity.js +22 -0
  359. package/dist/delegation/windows-workspace-identity.js.map +1 -0
  360. package/dist/delegation/workspace.d.ts +5 -10
  361. package/dist/delegation/workspace.js +136 -75
  362. package/dist/delegation/workspace.js.map +1 -1
  363. package/dist/detached-process.d.ts +103 -0
  364. package/dist/detached-process.js +301 -0
  365. package/dist/detached-process.js.map +1 -0
  366. package/dist/discovery/catalog.d.ts +2 -1
  367. package/dist/discovery/catalog.js.map +1 -1
  368. package/dist/discovery/cli.js +3 -1
  369. package/dist/discovery/cli.js.map +1 -1
  370. package/dist/git-diff-base.d.ts +6 -61
  371. package/dist/git-diff-base.js +6 -70
  372. package/dist/git-diff-base.js.map +1 -1
  373. package/dist/git-index-copy.d.ts +4 -0
  374. package/dist/git-index-copy.js +10 -0
  375. package/dist/git-index-copy.js.map +1 -0
  376. package/dist/git-worktree-lock.d.ts +2 -4
  377. package/dist/git-worktree-lock.js +2 -4
  378. package/dist/git-worktree-lock.js.map +1 -1
  379. package/dist/git-worktree-release.d.ts +2 -2
  380. package/dist/git-worktree-release.js.map +1 -1
  381. package/dist/git-worktree.d.ts +47 -76
  382. package/dist/git-worktree.js +240 -94
  383. package/dist/git-worktree.js.map +1 -1
  384. package/dist/handoff.d.ts +51 -41
  385. package/dist/handoff.js +130 -78
  386. package/dist/handoff.js.map +1 -1
  387. package/dist/index.js +60 -39
  388. package/dist/index.js.map +1 -1
  389. package/dist/merge-observations.d.ts +13 -0
  390. package/dist/merge-observations.js +55 -0
  391. package/dist/merge-observations.js.map +1 -0
  392. package/dist/open-url.js +4 -14
  393. package/dist/open-url.js.map +1 -1
  394. package/dist/paths.d.ts +10 -13
  395. package/dist/paths.js +36 -17
  396. package/dist/paths.js.map +1 -1
  397. package/dist/planner.d.ts +2 -1
  398. package/dist/planner.js +9 -6
  399. package/dist/planner.js.map +1 -1
  400. package/dist/preview/agent-address.d.ts +34 -0
  401. package/dist/preview/agent-address.js +51 -0
  402. package/dist/preview/agent-address.js.map +1 -0
  403. package/dist/preview/agent-marker.d.ts +17 -0
  404. package/dist/preview/agent-marker.js +71 -0
  405. package/dist/preview/agent-marker.js.map +1 -0
  406. package/dist/preview/cdp-proxy.d.ts +54 -0
  407. package/dist/preview/cdp-proxy.js +151 -0
  408. package/dist/preview/cdp-proxy.js.map +1 -0
  409. package/dist/preview/cdp.d.ts +39 -3
  410. package/dist/preview/cdp.js +155 -57
  411. package/dist/preview/cdp.js.map +1 -1
  412. package/dist/preview/chromium.d.ts +18 -6
  413. package/dist/preview/chromium.js +112 -25
  414. package/dist/preview/chromium.js.map +1 -1
  415. package/dist/preview/dev-server.d.ts +1 -1
  416. package/dist/preview/dev-server.js +20 -44
  417. package/dist/preview/dev-server.js.map +1 -1
  418. package/dist/preview/host.d.ts +70 -3
  419. package/dist/preview/host.js +314 -28
  420. package/dist/preview/host.js.map +1 -1
  421. package/dist/preview/registration.d.ts +10 -5
  422. package/dist/preview/registration.js +2 -0
  423. package/dist/preview/registration.js.map +1 -1
  424. package/dist/preview/session.d.ts +2 -0
  425. package/dist/preview/session.js +10 -0
  426. package/dist/preview/session.js.map +1 -1
  427. package/dist/process-wait/exit-file.d.ts +29 -0
  428. package/dist/process-wait/exit-file.js +67 -0
  429. package/dist/process-wait/exit-file.js.map +1 -0
  430. package/dist/process-wait/supervisor.d.ts +30 -0
  431. package/dist/process-wait/supervisor.js +71 -0
  432. package/dist/process-wait/supervisor.js.map +1 -0
  433. package/dist/release/snapshot.d.ts +6 -6
  434. package/dist/runs/agent-tmpdir.d.ts +51 -36
  435. package/dist/runs/agent-tmpdir.js +389 -132
  436. package/dist/runs/agent-tmpdir.js.map +1 -1
  437. package/dist/runs/auto-name.d.ts +6 -6
  438. package/dist/runs/auto-name.js +1 -1
  439. package/dist/runs/auto-name.js.map +1 -1
  440. package/dist/runs/client-request.d.ts +3 -3
  441. package/dist/runs/client-request.js +3 -3
  442. package/dist/runs/client-request.js.map +1 -1
  443. package/dist/runs/delegation-state.d.ts +11 -2
  444. package/dist/runs/delegation-state.js.map +1 -1
  445. package/dist/runs/event-history-agent-context.d.ts +14 -0
  446. package/dist/runs/event-history-agent-context.js +105 -0
  447. package/dist/runs/event-history-agent-context.js.map +1 -0
  448. package/dist/runs/event-history-context.d.ts +15 -0
  449. package/dist/runs/event-history-context.js +109 -0
  450. package/dist/runs/event-history-context.js.map +1 -0
  451. package/dist/runs/event-history.d.ts +4 -1
  452. package/dist/runs/event-history.js +29 -130
  453. package/dist/runs/event-history.js.map +1 -1
  454. package/dist/runs/history-stream.d.ts +2 -0
  455. package/dist/runs/history-stream.js +62 -0
  456. package/dist/runs/history-stream.js.map +1 -0
  457. package/dist/runs/legacy-index.d.ts +6 -19
  458. package/dist/runs/legacy-index.js +6 -19
  459. package/dist/runs/legacy-index.js.map +1 -1
  460. package/dist/runs/live-item-snapshots.d.ts +13 -0
  461. package/dist/runs/live-item-snapshots.js +79 -0
  462. package/dist/runs/live-item-snapshots.js.map +1 -0
  463. package/dist/runs/loaded-run-healing.d.ts +3 -0
  464. package/dist/runs/loaded-run-healing.js +17 -0
  465. package/dist/runs/loaded-run-healing.js.map +1 -0
  466. package/dist/runs/outcome-commit.d.ts +98 -0
  467. package/dist/runs/outcome-commit.js +132 -0
  468. package/dist/runs/outcome-commit.js.map +1 -0
  469. package/dist/runs/pull-requests.d.ts +14 -0
  470. package/dist/runs/pull-requests.js +96 -0
  471. package/dist/runs/pull-requests.js.map +1 -0
  472. package/dist/runs/raw-record.d.ts +3 -15
  473. package/dist/runs/raw-record.js +3 -15
  474. package/dist/runs/raw-record.js.map +1 -1
  475. package/dist/runs/retention.d.ts +2 -2
  476. package/dist/runs/retention.js +7 -0
  477. package/dist/runs/retention.js.map +1 -1
  478. package/dist/runs/review-gate.d.ts +1 -1
  479. package/dist/runs/review-gate.js.map +1 -1
  480. package/dist/runs/run-claims.d.ts +2 -9
  481. package/dist/runs/run-claims.js.map +1 -1
  482. package/dist/runs/run-database.d.ts +29 -34
  483. package/dist/runs/run-database.js +124 -46
  484. package/dist/runs/run-database.js.map +1 -1
  485. package/dist/runs/run-index.d.ts +6 -25
  486. package/dist/runs/run-index.js +25 -38
  487. package/dist/runs/run-index.js.map +1 -1
  488. package/dist/runs/run-row.d.ts +5 -34
  489. package/dist/runs/run-row.js +13 -38
  490. package/dist/runs/run-row.js.map +1 -1
  491. package/dist/runs/store.d.ts +1597 -744
  492. package/dist/runs/store.js +1231 -739
  493. package/dist/runs/store.js.map +1 -1
  494. package/dist/runs/task-markers.d.ts +1 -0
  495. package/dist/runs/task-markers.js +5 -1
  496. package/dist/runs/task-markers.js.map +1 -1
  497. package/dist/runs/task-refs.d.ts +3 -3
  498. package/dist/runs/transcript-facts-fold.d.ts +64 -0
  499. package/dist/runs/transcript-facts-fold.js +109 -0
  500. package/dist/runs/transcript-facts-fold.js.map +1 -0
  501. package/dist/runs/transcript-facts-load.d.ts +11 -0
  502. package/dist/runs/transcript-facts-load.js +66 -0
  503. package/dist/runs/transcript-facts-load.js.map +1 -0
  504. package/dist/runs/transcript-facts-queue.d.ts +30 -0
  505. package/dist/runs/transcript-facts-queue.js +227 -0
  506. package/dist/runs/transcript-facts-queue.js.map +1 -0
  507. package/dist/runs/transcript-facts-worker.d.ts +15 -0
  508. package/dist/runs/transcript-facts-worker.js +26 -0
  509. package/dist/runs/transcript-facts-worker.js.map +1 -0
  510. package/dist/runs/transcript-facts.d.ts +13 -51
  511. package/dist/runs/transcript-facts.js +86 -202
  512. package/dist/runs/transcript-facts.js.map +1 -1
  513. package/dist/runs/ui-event-sink.d.ts +5 -30
  514. package/dist/runs/ui-event-sink.js +8 -30
  515. package/dist/runs/ui-event-sink.js.map +1 -1
  516. package/dist/runs/webhook.d.ts +104 -38
  517. package/dist/runs/webhook.js +180 -77
  518. package/dist/runs/webhook.js.map +1 -1
  519. package/dist/server/app-type.d.ts +2 -17
  520. package/dist/server/archive-on-merge.d.ts +35 -0
  521. package/dist/server/archive-on-merge.js +202 -0
  522. package/dist/server/archive-on-merge.js.map +1 -0
  523. package/dist/server/capabilities.d.ts +3 -15
  524. package/dist/server/capabilities.js +6 -19
  525. package/dist/server/capabilities.js.map +1 -1
  526. package/dist/server/checkout-progress.d.ts +10 -0
  527. package/dist/server/checkout-progress.js +27 -0
  528. package/dist/server/checkout-progress.js.map +1 -0
  529. package/dist/server/checkout.d.ts +10 -19
  530. package/dist/server/checkout.js +15 -45
  531. package/dist/server/checkout.js.map +1 -1
  532. package/dist/server/cockpit-ownership.d.ts +2 -0
  533. package/dist/server/cockpit-ownership.js +9 -0
  534. package/dist/server/cockpit-ownership.js.map +1 -1
  535. package/dist/server/cold-repo-handles.d.ts +2 -7
  536. package/dist/server/cold-repo-handles.js +2 -7
  537. package/dist/server/cold-repo-handles.js.map +1 -1
  538. package/dist/server/completion-actions.d.ts +30 -0
  539. package/dist/server/completion-actions.js +204 -0
  540. package/dist/server/completion-actions.js.map +1 -0
  541. package/dist/server/create-project.d.ts +71 -0
  542. package/dist/server/create-project.js +448 -0
  543. package/dist/server/create-project.js.map +1 -0
  544. package/dist/server/forge/github-filters.d.ts +7 -1
  545. package/dist/server/forge/github-filters.js +66 -51
  546. package/dist/server/forge/github-filters.js.map +1 -1
  547. package/dist/server/forge/github-merge-requirements.d.ts +18 -0
  548. package/dist/server/forge/github-merge-requirements.js +137 -0
  549. package/dist/server/forge/github-merge-requirements.js.map +1 -0
  550. package/dist/server/forge/github.d.ts +98 -111
  551. package/dist/server/forge/github.js +625 -306
  552. package/dist/server/forge/github.js.map +1 -1
  553. package/dist/server/forge/types.d.ts +25 -22
  554. package/dist/server/fs-browse.d.ts +3 -28
  555. package/dist/server/fs-browse.js.map +1 -1
  556. package/dist/server/git-changes.d.ts +5 -15
  557. package/dist/server/git-changes.js +3 -50
  558. package/dist/server/git-changes.js.map +1 -1
  559. package/dist/server/git.d.ts +3 -1
  560. package/dist/server/git.js +12 -0
  561. package/dist/server/git.js.map +1 -1
  562. package/dist/server/github.d.ts +1 -1
  563. package/dist/server/github.js +1 -1
  564. package/dist/server/github.js.map +1 -1
  565. package/dist/server/launch-key.d.ts +2 -4
  566. package/dist/server/launch-key.js +2 -4
  567. package/dist/server/launch-key.js.map +1 -1
  568. package/dist/server/live-routes.d.ts +68 -0
  569. package/dist/server/live-routes.js +147 -0
  570. package/dist/server/live-routes.js.map +1 -0
  571. package/dist/server/open-in-app.d.ts +4 -13
  572. package/dist/server/open-in-app.js +5 -41
  573. package/dist/server/open-in-app.js.map +1 -1
  574. package/dist/server/open-in-targets.d.ts +42 -0
  575. package/dist/server/open-in-targets.js +110 -0
  576. package/dist/server/open-in-targets.js.map +1 -0
  577. package/dist/server/open-in-terminal.d.ts +3 -0
  578. package/dist/server/open-in-terminal.js +6 -26
  579. package/dist/server/open-in-terminal.js.map +1 -1
  580. package/dist/server/preview-cdp-socket.d.ts +21 -0
  581. package/dist/server/preview-cdp-socket.js +112 -0
  582. package/dist/server/preview-cdp-socket.js.map +1 -0
  583. package/dist/server/preview-socket.d.ts +11 -11
  584. package/dist/server/preview-socket.js +22 -22
  585. package/dist/server/preview-socket.js.map +1 -1
  586. package/dist/server/preview-sockets.d.ts +14 -0
  587. package/dist/server/preview-sockets.js +18 -0
  588. package/dist/server/preview-sockets.js.map +1 -0
  589. package/dist/server/project-context.d.ts +54 -18
  590. package/dist/server/project-context.js +178 -5
  591. package/dist/server/project-context.js.map +1 -1
  592. package/dist/server/provider-action-gate.d.ts +0 -2
  593. package/dist/server/provider-action-gate.js +0 -21
  594. package/dist/server/provider-action-gate.js.map +1 -1
  595. package/dist/server/provider-auth-runtime.d.ts +3 -18
  596. package/dist/server/provider-auth-runtime.js +3 -18
  597. package/dist/server/provider-auth-runtime.js.map +1 -1
  598. package/dist/server/repo-branches.d.ts +3 -9
  599. package/dist/server/repo-branches.js +6 -22
  600. package/dist/server/repo-branches.js.map +1 -1
  601. package/dist/server/run-event-feed.d.ts +20 -0
  602. package/dist/server/run-event-feed.js +190 -0
  603. package/dist/server/run-event-feed.js.map +1 -0
  604. package/dist/server/server-deps.d.ts +37 -0
  605. package/dist/server/server-deps.js +114 -0
  606. package/dist/server/server-deps.js.map +1 -0
  607. package/dist/server/server.d.ts +14082 -11998
  608. package/dist/server/server.js +785 -1647
  609. package/dist/server/server.js.map +1 -1
  610. package/dist/server/start-run-options.d.ts +82 -0
  611. package/dist/server/start-run-options.js +111 -0
  612. package/dist/server/start-run-options.js.map +1 -0
  613. package/dist/server/validators.d.ts +3 -29
  614. package/dist/server/validators.js +1 -2
  615. package/dist/server/validators.js.map +1 -1
  616. package/dist/server/ws.d.ts +3 -23
  617. package/dist/server/ws.js +3 -23
  618. package/dist/server/ws.js.map +1 -1
  619. package/dist/server-install/engine.d.ts +6 -9
  620. package/dist/server-install/engine.js +2 -9
  621. package/dist/server-install/engine.js.map +1 -1
  622. package/dist/server-install/platforms/ubuntu-vps.d.ts +1 -1
  623. package/dist/server-install/state.d.ts +2 -4
  624. package/dist/server-install/state.js +2 -4
  625. package/dist/server-install/state.js.map +1 -1
  626. package/dist/server-install/steps.d.ts +2 -5
  627. package/dist/server-install/steps.js +3 -6
  628. package/dist/server-install/steps.js.map +1 -1
  629. package/dist/server-install/types.d.ts +3 -6
  630. package/dist/server-install/types.js +2 -5
  631. package/dist/server-install/types.js.map +1 -1
  632. package/dist/server-install/ui.d.ts +2 -8
  633. package/dist/server-install/ui.js +3 -3
  634. package/dist/server-install/ui.js.map +1 -1
  635. package/dist/session-context.d.ts +64 -0
  636. package/dist/session-context.js +264 -0
  637. package/dist/session-context.js.map +1 -0
  638. package/dist/skills-provision.d.ts +62 -0
  639. package/dist/skills-provision.js +325 -0
  640. package/dist/skills-provision.js.map +1 -0
  641. package/dist/skills-remote.d.ts +29 -27
  642. package/dist/skills-remote.js +236 -100
  643. package/dist/skills-remote.js.map +1 -1
  644. package/dist/skills.d.ts +25 -36
  645. package/dist/skills.js +43 -54
  646. package/dist/skills.js.map +1 -1
  647. package/dist/subcommands.d.ts +11 -0
  648. package/dist/subcommands.js +24 -0
  649. package/dist/subcommands.js.map +1 -0
  650. package/dist/task-cli/cli.js +78 -25
  651. package/dist/task-cli/cli.js.map +1 -1
  652. package/dist/task-cli/discovery.d.ts +4 -2
  653. package/dist/task-cli/discovery.js +14 -13
  654. package/dist/task-cli/discovery.js.map +1 -1
  655. package/dist/task-cli/hint.d.ts +20 -0
  656. package/dist/task-cli/hint.js +14 -0
  657. package/dist/task-cli/hint.js.map +1 -0
  658. package/dist/task-cli/http.d.ts +1 -0
  659. package/dist/task-cli/http.js +3 -1
  660. package/dist/task-cli/http.js.map +1 -1
  661. package/dist/task-cli/projections.d.ts +14 -11
  662. package/dist/task-cli/projections.js +15 -11
  663. package/dist/task-cli/projections.js.map +1 -1
  664. package/dist/task-cli/watch.d.ts +18 -10
  665. package/dist/task-cli/watch.js +128 -20
  666. package/dist/task-cli/watch.js.map +1 -1
  667. package/dist/ui-state.d.ts +17 -3
  668. package/dist/ui-state.js +56 -9
  669. package/dist/ui-state.js.map +1 -1
  670. package/dist/update-check.d.ts +0 -10
  671. package/dist/update-check.js +1 -16
  672. package/dist/update-check.js.map +1 -1
  673. package/dist/voice/decide.d.ts +32 -0
  674. package/dist/voice/decide.js +297 -0
  675. package/dist/voice/decide.js.map +1 -0
  676. package/dist/voice/decision-log.d.ts +52 -0
  677. package/dist/voice/decision-log.js +107 -0
  678. package/dist/voice/decision-log.js.map +1 -0
  679. package/dist/voice/engine.d.ts +119 -0
  680. package/dist/voice/engine.js +60 -0
  681. package/dist/voice/engine.js.map +1 -0
  682. package/dist/voice/fake-engine.d.ts +10 -0
  683. package/dist/voice/fake-engine.js +192 -0
  684. package/dist/voice/fake-engine.js.map +1 -0
  685. package/dist/voice/jev-engine.d.ts +17 -0
  686. package/dist/voice/jev-engine.js +110 -0
  687. package/dist/voice/jev-engine.js.map +1 -0
  688. package/dist/voice/pending-ask.d.ts +17 -0
  689. package/dist/voice/pending-ask.js +50 -0
  690. package/dist/voice/pending-ask.js.map +1 -0
  691. package/dist/voice/routes.d.ts +115 -0
  692. package/dist/voice/routes.js +91 -0
  693. package/dist/voice/routes.js.map +1 -0
  694. package/dist/voice/sentence.d.ts +21 -0
  695. package/dist/voice/sentence.js +61 -0
  696. package/dist/voice/sentence.js.map +1 -0
  697. package/dist/voice/thresholds.d.ts +28 -0
  698. package/dist/voice/thresholds.js +29 -0
  699. package/dist/voice/thresholds.js.map +1 -0
  700. package/dist/webhooks/cli.d.ts +18 -0
  701. package/dist/webhooks/cli.js +145 -0
  702. package/dist/webhooks/cli.js.map +1 -0
  703. package/dist/webhooks/prompt.d.ts +5 -0
  704. package/dist/webhooks/prompt.js +26 -0
  705. package/dist/webhooks/prompt.js.map +1 -0
  706. package/dist/workflows/active-run.d.ts +167 -0
  707. package/dist/workflows/active-run.js +21 -0
  708. package/dist/workflows/active-run.js.map +1 -0
  709. package/dist/workflows/continuation-admission.d.ts +913 -0
  710. package/dist/workflows/continuation-admission.js +265 -0
  711. package/dist/workflows/continuation-admission.js.map +1 -0
  712. package/dist/workflows/execution-account.d.ts +13 -0
  713. package/dist/workflows/execution-account.js +18 -0
  714. package/dist/workflows/execution-account.js.map +1 -0
  715. package/dist/workflows/input-acknowledgement.d.ts +152 -0
  716. package/dist/workflows/input-acknowledgement.js +38 -0
  717. package/dist/workflows/input-acknowledgement.js.map +1 -0
  718. package/dist/workflows/line-order.d.ts +5 -0
  719. package/dist/workflows/line-order.js +25 -0
  720. package/dist/workflows/line-order.js.map +1 -0
  721. package/dist/workflows/outcome-batches.d.ts +20 -0
  722. package/dist/workflows/outcome-batches.js +25 -0
  723. package/dist/workflows/outcome-batches.js.map +1 -0
  724. package/dist/workflows/question-routing.d.ts +8 -0
  725. package/dist/workflows/question-routing.js +18 -0
  726. package/dist/workflows/question-routing.js.map +1 -0
  727. package/dist/workflows/run-scheduling.d.ts +35 -0
  728. package/dist/workflows/run-scheduling.js +61 -0
  729. package/dist/workflows/run-scheduling.js.map +1 -0
  730. package/dist/workflows/run-states.d.ts +190 -0
  731. package/dist/workflows/run-states.js +295 -0
  732. package/dist/workflows/run-states.js.map +1 -0
  733. package/dist/workflows/run.d.ts +1296 -278
  734. package/dist/workflows/run.js +5730 -3265
  735. package/dist/workflows/run.js.map +1 -1
  736. package/dist/workflows/turn-end.d.ts +116 -0
  737. package/dist/workflows/turn-end.js +68 -0
  738. package/dist/workflows/turn-end.js.map +1 -0
  739. package/dist/workflows/types.d.ts +35 -130
  740. package/dist/workflows/types.js +47 -100
  741. package/dist/workflows/types.js.map +1 -1
  742. package/dist/workflows/waits.d.ts +74 -0
  743. package/dist/workflows/waits.js +197 -0
  744. package/dist/workflows/waits.js.map +1 -0
  745. package/dist/workspace/agent-accounts.d.ts +5 -38
  746. package/dist/workspace/agent-accounts.js +14 -40
  747. package/dist/workspace/agent-accounts.js.map +1 -1
  748. package/dist/workspace/agent-profiles.d.ts +40 -16
  749. package/dist/workspace/agent-profiles.js +77 -17
  750. package/dist/workspace/agent-profiles.js.map +1 -1
  751. package/dist/workspace/config.d.ts +48 -49
  752. package/dist/workspace/config.js +68 -72
  753. package/dist/workspace/config.js.map +1 -1
  754. package/dist/workspace/migrations.d.ts +3 -13
  755. package/dist/workspace/migrations.js.map +1 -1
  756. package/dist/workspace/projects-cli.d.ts +1 -1
  757. package/dist/workspace/projects-cli.js.map +1 -1
  758. package/dist/workspace/projects.d.ts +15 -18
  759. package/dist/workspace/projects.js +20 -16
  760. package/dist/workspace/projects.js.map +1 -1
  761. package/dist/workspace/semaphore.d.ts +11 -45
  762. package/dist/workspace/semaphore.js +6 -18
  763. package/dist/workspace/semaphore.js.map +1 -1
  764. package/dist/workspace/ui-state.d.ts +6 -4
  765. package/dist/workspace/ui-state.js +6 -4
  766. package/dist/workspace/ui-state.js.map +1 -1
  767. package/dist/workspace/webhooks.d.ts +40 -0
  768. package/dist/workspace/webhooks.js +146 -0
  769. package/dist/workspace/webhooks.js.map +1 -0
  770. package/dist/worktree-manifest.d.ts +165 -0
  771. package/dist/worktree-manifest.js +530 -0
  772. package/dist/worktree-manifest.js.map +1 -0
  773. package/dist/worktree-setup.js.map +1 -1
  774. package/package.json +6 -5
  775. package/scripts/benchmark-run-store-fixture.ts +7 -3
  776. package/scripts/check-pack.mjs +3 -1
  777. package/scripts/inline-contract.mjs +80 -27
  778. package/scripts/install-as-command.mjs +3 -1
  779. package/scripts/measure-transcript-facts-health.mjs +87 -0
  780. package/scripts/measure-transcript-facts-lag.mjs +68 -0
  781. package/scripts/mock-ci-tool.mjs +49 -6
  782. package/scripts/mock-claude-model-refusal.mjs +42 -0
  783. package/scripts/mock-claude.mjs +833 -591
  784. package/scripts/mock-codex-app-server.mjs +785 -418
  785. package/scripts/mock-cursor-acp.mjs +296 -125
  786. package/scripts/mock-cursor-print.mjs +256 -0
  787. package/scripts/mock-deferred-turn-start.mjs +16 -0
  788. package/scripts/mock-delivery-control.d.mts +23 -0
  789. package/scripts/mock-delivery-control.mjs +80 -0
  790. package/scripts/mock-env-record.mjs +11 -0
  791. package/scripts/mock-failure-control.d.mts +13 -0
  792. package/scripts/mock-failure-control.mjs +68 -0
  793. package/scripts/mock-multi-pr.mjs +7 -0
  794. package/scripts/mock-nudge.mjs +45 -0
  795. package/scripts/mock-omp-rpc.mjs +429 -255
  796. package/scripts/mock-opencode-serve.mjs +972 -557
  797. package/scripts/mock-pi-rpc.mjs +558 -331
  798. package/scripts/mock-runner-crash.mjs +18 -2
  799. package/scripts/mock-session-context.d.mts +5 -0
  800. package/scripts/mock-session-context.mjs +56 -0
  801. package/scripts/mock-silent-tail.mjs +10 -3
  802. package/scripts/pi-default-tools.mjs +22 -0
  803. package/scripts/pi-project-skills.mjs +59 -0
  804. package/scripts/probe-cursor-print.mjs +627 -0
  805. package/scripts/transcript-facts-fixture.mjs +53 -0
  806. package/scripts/voice-replay.ts +50 -0
  807. package/scripts/windows-workspace-identity.cs +208 -0
  808. package/scripts/windows-workspace-identity.ps1 +10 -0
  809. package/web/dist/assets/alert-dialog-DfctKUMw.js +1 -0
  810. package/web/dist/assets/button-CeupvoKG.js +41 -0
  811. package/web/dist/assets/centered-state-hDsyXrnH.js +1 -0
  812. package/web/dist/assets/cez-idle-D3aj_9lp.js +1 -0
  813. package/web/dist/assets/diff-BnIXZK3i2.js +3 -0
  814. package/web/dist/assets/diff-controls-GewpW9aF.js +1 -0
  815. package/web/dist/assets/diff-view-Byo7gpvW.js +11 -0
  816. package/web/dist/assets/dropdown-menu-COj_J5wd.js +6 -0
  817. package/web/dist/assets/eye-B8okNWXU.js +1 -0
  818. package/web/dist/assets/git-toolbar-DY0z0n4S.js +1 -0
  819. package/web/dist/assets/github-DwU6ALRK.js +1 -0
  820. package/web/dist/assets/{image-preview-FOEfqpZP.js → image-preview-C_t9q45f.js} +1 -1
  821. package/web/dist/assets/index-BOfE8pyD.js +34 -0
  822. package/web/dist/assets/index-D9HpsmdW.css +1 -0
  823. package/web/dist/assets/live-protocol-Uce2NwEX.js +64 -0
  824. package/web/dist/assets/live-worker-BizfZSoh.ts +33 -0
  825. package/web/dist/assets/markdown-BBDDg-4t.js +1 -0
  826. package/web/dist/assets/nav-row-styles-AoIhhIwf.js +1 -0
  827. package/web/dist/assets/popover-D56fhiXj.js +1 -0
  828. package/web/dist/assets/preview-pane-connected-BmVqfSU5.js +3 -0
  829. package/web/dist/assets/reference-chip-gQNk-4jc.js +1 -0
  830. package/web/dist/assets/repo-git-B5ECDUuv.js +1 -0
  831. package/web/dist/assets/{repo-git-CoKp-g9K.css → repo-git-DVXNOJDT.css} +1 -1
  832. package/web/dist/assets/run-header-C0Y1NvEM.js +2 -0
  833. package/web/dist/assets/run-header-CC7VUTg9.css +1 -0
  834. package/web/dist/assets/skills-DUeTkZ9z.js +1 -0
  835. package/web/dist/assets/status-dot-1PR0i69P.js +1 -0
  836. package/web/dist/assets/tab-link-DmWk4l5O.js +1 -0
  837. package/web/dist/assets/task-changes-DKZXuW89.js +1 -0
  838. package/web/dist/assets/task-commits-BZ6KxWdF.js +1 -0
  839. package/web/dist/assets/task-files-DlF7Apcn.js +2 -0
  840. package/web/dist/assets/task-github-item-CVPo3geZ.js +1 -0
  841. package/web/dist/assets/task-thread-DtQ6uGfQ.css +1 -0
  842. package/web/dist/assets/task-thread-mm4-ECyo.js +9 -0
  843. package/web/dist/assets/thread-state-CIw2BlhT.js +4 -0
  844. package/web/dist/assets/use-hand-to-agent-state-BCDjzHnG.js +1 -0
  845. package/web/dist/assets/use-hand-to-agent-state-C7esPJ-N.css +1 -0
  846. package/web/dist/assets/workflows-D8vYD-ql.js +7 -0
  847. package/web/dist/assets/zoomable-image-CxQSsfcn.js +1 -0
  848. package/web/dist/index.html +13 -17
  849. package/web/dist/live-worker.js +4 -0
  850. package/dist/core/tool-display.js +0 -179
  851. package/dist/core/tool-display.js.map +0 -1
  852. package/dist/runs/human-ask-summary.d.ts +0 -9
  853. package/dist/runs/human-ask-summary.js +0 -39
  854. package/dist/runs/human-ask-summary.js.map +0 -1
  855. package/dist/runs/run-search.d.ts +0 -29
  856. package/dist/runs/run-search.js +0 -63
  857. package/dist/runs/run-search.js.map +0 -1
  858. package/dist/skills-banner.d.ts +0 -22
  859. package/dist/skills-banner.js +0 -41
  860. package/dist/skills-banner.js.map +0 -1
  861. package/dist/skills-update.d.ts +0 -88
  862. package/dist/skills-update.js +0 -392
  863. package/dist/skills-update.js.map +0 -1
  864. package/dist/todos.d.ts +0 -48
  865. package/dist/todos.js +0 -201
  866. package/dist/todos.js.map +0 -1
  867. package/web/dist/assets/agent-accounts-CFOBMVHc.js +0 -1
  868. package/web/dist/assets/alert-dialog-BrpNUwMt.js +0 -1
  869. package/web/dist/assets/button-C_rd7CPp.js +0 -43
  870. package/web/dist/assets/compare-variants-D6WXhvXA.js +0 -1
  871. package/web/dist/assets/diff-DrEARXTV.js +0 -3
  872. package/web/dist/assets/diff-controls-B1-j7nFg.js +0 -1
  873. package/web/dist/assets/diff-view-DvGLjdTk.js +0 -6
  874. package/web/dist/assets/dropdown-menu-BegOZFrj.js +0 -1
  875. package/web/dist/assets/format-DpNe3S0A.js +0 -1
  876. package/web/dist/assets/git-toolbar-Cw4ljmhB.js +0 -1
  877. package/web/dist/assets/github-CfV5sqL0.js +0 -1
  878. package/web/dist/assets/index-DgWWlOLy.js +0 -13
  879. package/web/dist/assets/index-fBFnuvxu.css +0 -1
  880. package/web/dist/assets/nav-row-styles-vp2JbhuJ.js +0 -1
  881. package/web/dist/assets/popover-BohP6WTx.js +0 -1
  882. package/web/dist/assets/preview-pane-connected-qTA5KNoJ.js +0 -3
  883. package/web/dist/assets/preview-state-vuMviq6q.js +0 -1
  884. package/web/dist/assets/prompt-templates-Cubdut_C.js +0 -15
  885. package/web/dist/assets/repo-git-Cf4t5PD0.js +0 -1
  886. package/web/dist/assets/run-diff-BpkUW37Z.js +0 -3
  887. package/web/dist/assets/run-header-68WHf9wV.js +0 -1
  888. package/web/dist/assets/run-header-8GObNx6F.css +0 -1
  889. package/web/dist/assets/search-x-I9Q8pgUa.js +0 -1
  890. package/web/dist/assets/skills-DFBiAuJG.js +0 -1
  891. package/web/dist/assets/skills-DiVIgKeU.js +0 -1
  892. package/web/dist/assets/square-terminal-B6RYYieR.js +0 -1
  893. package/web/dist/assets/status-dot-CqTJHSP9.js +0 -1
  894. package/web/dist/assets/tab-link-B07Hu4QX.js +0 -1
  895. package/web/dist/assets/task-changes--lQF6EYf.js +0 -1
  896. package/web/dist/assets/task-commits-Cx0qy4DN.js +0 -1
  897. package/web/dist/assets/task-files-D50s-gKW.js +0 -2
  898. package/web/dist/assets/task-github-item-DaqmSwYT.js +0 -1
  899. package/web/dist/assets/task-thread-BPQ64lui.js +0 -7
  900. package/web/dist/assets/task-thread-zNE2Q9E-.css +0 -1
  901. package/web/dist/assets/textarea-D20O4Pw0.js +0 -1
  902. package/web/dist/assets/thread-state-DWcFMrvb.js +0 -4
  903. package/web/dist/assets/use-hand-to-agent-state-BLIGmwbd.css +0 -1
  904. package/web/dist/assets/use-hand-to-agent-state-Cy9eyyfL.js +0 -1
  905. package/web/dist/assets/utils-JsL3ZsJf.js +0 -64
  906. package/web/dist/assets/workflows-jwG7uxqi.js +0 -11
  907. package/web/dist/assets/zoomable-image-BJJ64KGc.js +0 -1
@@ -1,10 +1,23 @@
1
1
  #!/usr/bin/env node
2
+ // Load only when configured: ordinary mock turns retain their event-loop ordering.
3
+ const failureControl = process.env.CEZ_MOCK_FAILURE_CONTROL === undefined ? undefined
4
+ : (await import('./mock-failure-control.mjs')).readFailureControl(['provider', 'usage-limit', 'unread']);
5
+ // Claude acknowledges agent input with the local stdin write, so only a held response is native.
6
+ const delivery = process.env.CEZ_MOCK_DELIVERY_CONTROL === undefined ? undefined
7
+ : (await import('./mock-delivery-control.mjs')).readDeliveryControl(['hold-response']);
2
8
  // Keep this fixture standalone: lifecycle tests copy the runner into a temp directory.
3
9
  import { spawn as watchdogSpawn } from 'node:child_process';
4
- import { writeFileSync as watchdogWritePid } from 'node:fs';
10
+ import { closeSync as watchdogCloseInput, renameSync as watchdogRename, writeFileSync as watchdogWrite } from 'node:fs';
11
+ // Publish a pid atomically (temporary sibling, then rename): a test reading it sees no
12
+ // file or a whole pid, never the empty file whose Number() is 0 (hearsay-tools/cezarion#953).
13
+ function watchdogWritePid(file, pid) { const tmp = `${file}.${process.pid}.tmp`; watchdogWrite(tmp, pid); watchdogRename(tmp, file); }
5
14
  function watchdogStall(prompt) {
6
15
  if (!prompt.includes('mock:no-progress')) return false;
7
- watchdogWritePid('watchdog.pid', String(process.pid));
16
+ if (prompt.includes('input-closed')) {
17
+ watchdogCloseInput(0);
18
+ watchdogWritePid('input-closed.pid', String(process.pid));
19
+ setTimeout(() => process.exit(0), 300);
20
+ }
8
21
  if (prompt.includes('ignore-term')) {
9
22
  process.removeAllListeners('SIGTERM');
10
23
  process.on('SIGTERM', () => {});
@@ -17,10 +30,12 @@ function watchdogStall(prompt) {
17
30
  if (prompt.includes('leftover')) {
18
31
  // hearsay-tools/cezarion#890: one child stays in the session's process group and ignores
19
32
  // SIGTERM; one leaves the group with setsid. Both exit on their own as a cleanup backstop.
20
- const leftover = (file) => `process.on('SIGTERM',()=>{}); require('fs').writeFileSync(${JSON.stringify(file)}, String(process.pid)); setTimeout(()=>{},20000)`;
33
+ const leftover = (file) => `process.on('SIGTERM',()=>{}); const fs = require('fs'); fs.writeFileSync(${JSON.stringify(`${file}.tmp`)}, String(process.pid)); fs.renameSync(${JSON.stringify(`${file}.tmp`)}, ${JSON.stringify(file)}); setTimeout(()=>{},20000)`;
21
34
  watchdogSpawn(process.execPath, ['-e', leftover('leftover-group.pid')], { stdio: 'ignore' });
22
35
  watchdogSpawn(process.execPath, ['-e', leftover('leftover-session.pid')], { stdio: 'ignore', detached: true }).unref();
23
36
  }
37
+ // Publish readiness after mode setup: another process may signal us as soon as it sees it.
38
+ watchdogWritePid('watchdog.pid', String(process.pid));
24
39
  return true;
25
40
  }
26
41
 
@@ -32,8 +47,11 @@ function watchdogStall(prompt) {
32
47
 
33
48
  import { createInterface } from 'node:readline';
34
49
  import { appendFileSync, readFileSync, writeFileSync } from 'node:fs';
50
+ // Dynamic, like every sibling import here, so a test's copy of this mock can repoint it.
51
+ const { answerNudge, silentNudge } = await import('./mock-nudge.mjs');
35
52
 
36
53
  import * as parityGateFs from 'node:fs';
54
+ import { withoutSessionContext } from './mock-session-context.mjs';
37
55
  async function waitForMockRelease(fallbackMs) {
38
56
  const file = process.env.CEZ_MOCK_RELEASE_FILE;
39
57
  if (!file) { if (fallbackMs) await sleep(fallbackMs); return; }
@@ -52,11 +70,44 @@ async function afterParityPark(prompt) {
52
70
  }
53
71
 
54
72
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
55
- const emit = (obj) => process.stdout.write(`${JSON.stringify(obj)}\n`);
73
+ /** Leave a visible trace in the cwd (the task worktree under spec 006) so
74
+ * the Diff view has something real to show in dry runs. Exactly one line
75
+ * per spawned session: tests read this file back as a per-step trace, so
76
+ * a multi-line prompt must not become multiple lines here. CEZ_MOCK_NOTES=0 leaves the
77
+ * worktree clean, so a suite that never reads it pays no autosave commit (hearsay-tools/cezarion#1665). */
78
+ function writeNotesTrace(userText) {
79
+ if (process.env.CEZ_MOCK_NOTES === '0') return;
80
+ try {
81
+ const head = userText.replace(/\s+/g, ' ').trim().slice(0, 400);
82
+ appendFileSync('notes.md', `mock notes — ${new Date().toISOString()}: ${head}\n`);
83
+ } catch {
84
+ // read-only cwd — the mock still works, just without a diff
85
+ }
86
+ }
87
+ // `mock:steer-tool` holds its tool call for CEZ_MOCK_STEER_MS, or, with CEZ_MOCK_STEER_LINES=<n>,
88
+ // until it has read n steered lines, so a loaded host cannot close the turn first (hearsay-tools/cezarion#1280).
89
+ async function holdSteerTool() {
90
+ const lines = Number(process.env.CEZ_MOCK_STEER_LINES ?? 0);
91
+ if (!lines) { await sleep(Number(process.env.CEZ_MOCK_STEER_MS ?? 600)); return; }
92
+ const deadline = Date.now() + 15_000;
93
+ while (steering.length < lines) {
94
+ if (Date.now() > deadline) throw new Error(`CEZ_MOCK_STEER_LINES: ${steering.length} of ${lines} steered lines arrived`);
95
+ await sleep(10);
96
+ }
97
+ }
98
+ // Lines a `mock:ack-only` reply read and never answered (hearsay-tools/cezarion#1301): the turn they
99
+ // opened is still running, so the next turn's result settles them with its own, as Claude settles
100
+ // every line one turn consumed (#505).
101
+ let heldUuids = [];
102
+ let respondingUuid;
103
+ const emit = (obj) => {
104
+ if (obj?.type === 'result' && heldUuids.length) obj = { ...obj, user_message_uuids: [...heldUuids.splice(0), ...(obj.user_message_uuids ?? [respondingUuid].filter(Boolean))] };
105
+ process.stdout.write(`${JSON.stringify(obj)}\n`);
106
+ };
56
107
 
57
108
  // `--help` lists the options cezar feature-detects (#505).
58
109
  if (process.argv.includes('--help')) {
59
- process.stdout.write('Usage: claude [options]\n --input-format <format>\n --replay-user-messages Re-emit user messages from stdin back on stdout\n');
110
+ process.stdout.write('Usage: claude [options]\n --input-format <format>\n --replay-user-messages Re-emit user messages from stdin back on stdout\n --include-hook-events Include all hook lifecycle events in the output stream\n');
60
111
  process.exit(0);
61
112
  }
62
113
 
@@ -89,11 +140,9 @@ let droppedOnce = false;
89
140
  const MOCK_SCREENSHOT_B64 =
90
141
  'iVBORw0KGgoAAAANSUhEUgAAAUAAAADICAIAAAAWZq/8AAACMklEQVR42u3csQnAIBRFUQdJY+b4tfvP4AhCLKyyghAMMRw4Ezz/bU0RBdhUMgEIGBAwIGAQMCBgQMCAgEHAgIABAYOAAQEDAgYEDAIGBAwsCLhfDdiUgEHAgIABAYOAAQEDAgYEDAIGBAwIGAT8vlEr/ImAQcACBgELGAQsYAQsYBCwgEHAAgYBe3IELGAQsIBBwAJGwAIGAQsYBCxgELCAEbCAQcACBgELGAQMAhYwCFjAIGABI2D/QgMCBgEDAgYEDAgYBAwIGBAwCBgQMCBgQMAgYEDAgIBBwCYAAQMCBgQMAgYEDAgYEDAIGBAwIGAQMCBgQMCAgEHAgIABAQMCBgEDAgYEDAIGBAwIGBAwCBgQMCBgQMAgYEDAgIBBwICAAQEDAgYBAwIGBAwCtgIIGBAwIGAQMCBgQMCAgEHAgIABAYOAeejMB/McjIAFLGABW0HAAhYwmhSwgAUsYAQsYAELGAELWMACRsACFrCAEbCABSxgBCxgAQtYwAhYwAIWMAIWsIAFjIAFLGABI2ABC1jACFjAAhYwAhawgAWMgAUsYAEjYAELWMACRsACFrCAEbCABSxgBCxgAQsYAQtYwAJGwAIWMCBgQMAgYEDAgIBBwICAAQEDAgYBAwIGBAwCBgQMCBgQMAgYEDAgYEDAIGBAwICAQcCAgAEBAwIGAQMCBgQMCBgEDAgYEDAIGBAwIGBAwCBgQMCAgAEBg4ABAQMCBgEDAgYEDAgYBAx8xQ1bxBr9kelHqgAAAABJRU5ErkJggg==';
91
142
 
92
-
93
- // Spec 007: behave like an agent that read the handoff/todos instructions —
94
- // append a progress line to CEZ_HANDOFF_FILE and a follow-up entry to
95
- // CEZ_TODOS_FILE, so the inbox loop is testable without tokens.
96
- function writeHandoffAndTodo() {
143
+ // Spec 007: behave like an agent that read the handoff instructions —
144
+ // append a progress line to CEZ_HANDOFF_FILE so handoff continuity is testable without tokens.
145
+ function writeHandoff() {
97
146
  try {
98
147
  const handoff = process.env.CEZ_HANDOFF_FILE;
99
148
  if (handoff) {
@@ -110,648 +159,652 @@ function writeHandoffAndTodo() {
110
159
  } catch {
111
160
  // best effort — the mock still answers without a handoff file
112
161
  }
113
- try {
114
- const todosFile = process.env.CEZ_TODOS_FILE;
115
- if (todosFile) {
116
- let items = [];
117
- try {
118
- items = JSON.parse(readFileSync(todosFile, 'utf8'));
119
- } catch {
120
- items = []; // missing or broken file — start fresh, append-only
121
- }
122
- if (!Array.isArray(items)) items = [];
123
- items.push({
124
- ts: new Date().toISOString(),
125
- taskId: process.env.CEZ_TASK_ID,
126
- summary: 'Follow up: verify the mock change',
127
- suggestedPrompt: 'Verify the change from the previous task',
128
- });
129
- writeFileSync(todosFile, JSON.stringify(items, null, 2), 'utf8');
130
- }
131
- } catch {
132
- // best effort
133
- }
134
162
  }
135
163
 
136
164
  async function respond(userText, imageCount, uuid) {
165
+ respondingUuid = uuid;
166
+ if (delivery) await delivery.holdResponse(userText);
167
+ // Native refusal and crash handling stay before deferred input and replay.
168
+ // hearsay-tools/cezarion#1351: native refusals before any model work.
169
+ if (userText.startsWith('mock:model-refusal')) {
170
+ const { modelRefusalReply } = await import('./mock-claude-model-refusal.mjs');
171
+ await modelRefusalReply(userText, uuid, emit, emitReplay);
172
+ return;
173
+ }
137
174
  if (userText.includes('mock:crash-stderr')) {
138
175
  const { crashWithStderr } = await import('./mock-runner-crash.mjs');
139
176
  if (crashWithStderr(userText, '{"type":"assistant","message":')) return;
140
177
  }
178
+ // hearsay-tools/cezarion#1112: the line waits in the pipe before the model reads it.
179
+ if (userText.includes('mock:deferred-turn-start')) await (await import('./mock-deferred-turn-start.mjs')).deferredTurnStart();
141
180
  emitReplay(uuid, userText);
142
- if (userText.includes('mock:autonomous') || userText.startsWith('Continue working autonomously until the task is fully complete.')) {
143
- const { autonomousReply } = await import('./mock-autonomous.mjs');
144
- const text = autonomousReply(userText);
145
- emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text }] } });
146
- emit({ type: 'result', subtype: 'success', result: text, user_message_uuids: [uuid].filter(Boolean), usage: { input_tokens: 10, output_tokens: 5 } });
147
- return;
148
- }
149
- if (userText.includes('mock:silent-tail') || userText.includes('mock:tool-tail') || userText.includes('Your last turn ended without a message to the user.')) {
150
- const silent = await import('./mock-silent-tail.mjs');
151
- silent.noteSilentTailPrompt(userText);
152
- if (silent.isFinalMessageNudge(userText)) {
153
- const kind = silent.finalMessageNudgeKind();
154
- if (kind === 'ack-only') return;
155
- if (kind === 'late') await silent.sleep(silent.LATE_REPLY_MS);
156
- if (kind === 'silent') {
157
- emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'thinking', thinking: silent.SILENT_TAIL_REASONING }] } });
158
- emit({ type: 'result', subtype: 'success', result: '', user_message_uuids: [uuid].filter(Boolean), usage: { input_tokens: 10, output_tokens: 5 } });
159
- } else {
160
- if (kind === 'slow-done') {
161
- emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text: silent.SLOW_DONE_PREFIX }] } });
162
- await silent.sleep(silent.SLOW_DONE_TAIL_MS);
163
- }
164
- const text = kind === 'standing' ? silent.FINAL_MESSAGE_STANDING : silent.SILENT_TAIL_DONE;
165
- emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text }] } });
166
- emit({ type: 'result', subtype: 'success', result: text, user_message_uuids: [uuid].filter(Boolean), usage: { input_tokens: 10, output_tokens: 5 } });
167
- }
168
- return;
169
- }
170
- if (silent.isSilentTailScenario(userText)) {
171
- emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text: silent.SILENT_TAIL_OPENING }] } });
172
- emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'tool_use', id: 'toolu_silent_gh', name: 'Bash', input: { command: 'gh issue create' } }] } });
173
- emit({ type: 'user', message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: 'toolu_silent_gh', content: 'created' }] } });
174
- emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'thinking', thinking: silent.SILENT_TAIL_REASONING }] } });
175
- emit({ type: 'result', subtype: 'success', result: silent.SILENT_TAIL_OPENING, user_message_uuids: [uuid].filter(Boolean), usage: { input_tokens: 20, output_tokens: 10 } });
176
- return;
177
- }
178
- if (silent.isToolTailScenario(userText)) {
179
- emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text: silent.TOOL_TAIL_OPENING }] } });
180
- emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'tool_use', id: 'toolu_tool_tail', name: 'Bash', input: { command: 'git status --short' } }] } });
181
- emit({ type: 'user', message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: 'toolu_tool_tail', content: ' M src/example.ts' }] } });
182
- emit({ type: 'result', subtype: 'success', result: silent.TOOL_TAIL_OPENING, user_message_uuids: [uuid].filter(Boolean), usage: { input_tokens: 20, output_tokens: 10 } });
183
- return;
184
- }
185
- }
186
- // `mock:steer-tool` → one tool call; lines written while it runs are consumed after
187
- // it (replayed with their uuid) and settled by the SAME result, like Claude 2.1.280 (#505).
188
- if (userText.includes('mock:steer-tool')) {
189
- steering = [];
190
- emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'tool_use', id: 'toolu_steer', name: 'Bash', input: { command: 'wait' } }] } });
191
- await sleep(Number(process.env.CEZ_MOCK_STEER_MS ?? 600));
192
- const steered = steering; steering = null;
193
- emit({ type: 'user', message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: 'toolu_steer', content: 'waited' }] } });
194
- for (const s of steered) emitReplay(s.uuid, s.userText);
195
- const text = ['steer tool done', ...steered.map(s => `saw: ${s.userText}`)].join('\n');
196
- emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text }] } });
197
- emit({ type: 'result', subtype: 'success', result: text, user_message_uuids: [uuid, ...steered.map(s => s.uuid)].filter(Boolean), usage: { input_tokens: 20, output_tokens: 10 } });
198
- return;
199
- }
200
- // Native child attribution from __fixtures__/claude/subagent-task.ndjson.
201
- if (!userText.includes('[cez-namer]') && userText.includes('mock:subagent-after-park')) {
202
- const task = `toolu_park_${turn}`;
203
- emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'tool_use', id: task, name: 'Task', input: { description: 'Review' } }] } });
204
- emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text: 'Watching the child.\nCEZ:MONITORING' }] } });
205
- emit({ type: 'result', subtype: 'success', result: 'Watching the child.\nCEZ:MONITORING', usage: { input_tokens: 10, output_tokens: 5 } });
206
- await afterParityPark(userText);
207
- emit({ type: 'assistant', parent_tool_use_id: task, message: { role: 'assistant', content: [{ type: 'tool_use', id: 'late-read', name: 'Read', input: { file_path: 'README.md' } }] } });
208
- emit({ type: 'user', parent_tool_use_id: task, message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: 'late-read', content: 'Read the file.' }] } });
209
- emit({ type: 'assistant', parent_tool_use_id: task, message: { role: 'assistant', content: [{ type: 'text', text: 'Post-park child update processed.' }] } });
210
- return;
211
- }
212
- // #401: result-only full text; mapResult and v1 use the same fallback.
213
- if (userText.includes('mock:turn-messages:')) {
214
- const { turnMessages } = await import('./mock-turn-messages.mjs');
215
- const messages = turnMessages(userText);
216
- for (const text of messages) emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text }] } });
217
- emit({ type: 'result', subtype: 'success', result: messages.join('\n'), usage: { input_tokens: 10, output_tokens: 5 } });
218
- return;
219
- }
220
- if (!userText.includes('[cez-namer]') && userText.includes('mock:ask-snapshot')) {
221
- emit({ type: 'result', subtype: 'success', result: userText.includes('mock:ask-snapshot-bad') ? 'CEZ:ASK {not valid json' : 'Using the CEZ:ASK structured question format instead:\n\nCEZ:ASK {"questions":[{"header":"Library","question":"Which test library?","options":[{"label":"Vitest"},{"label":"Node test"}]}]}', usage: { input_tokens: 10, output_tokens: 5 } });
222
- return;
223
- }
224
- if (!userText.includes('[cez-namer]') && userText.includes('mock:ask-prose')) {
225
- emit({ type: 'result', subtype: 'success', result: 'Use `CEZ:ASK {"questions":[]}` in your reply.\n> CEZ:ASK {not valid json', usage: { input_tokens: 10, output_tokens: 5 } });
226
- return;
227
- }
228
- if (userText.includes('mock:ci-wait')) {
229
- const { ciPrompt } = await import('./mock-ci-tool.mjs');
230
- const text = await ciPrompt('claude', process.argv.slice(2), userText);
231
- emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text }] } });
232
- emit({ type: 'result', subtype: 'success', result: text, usage: { input_tokens: 20, output_tokens: 10 } });
233
- return;
234
- }
235
- if (!userText.includes('[cez-namer]') && userText.includes('mock:preview-serve')) {
236
- const { previewPrompt } = await import('./mock-ci-tool.mjs');
237
- const text = await previewPrompt('claude', process.argv.slice(2), userText);
238
- emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text }] } });
239
- emit({ type: 'result', subtype: 'success', result: text, usage: { input_tokens: 20, output_tokens: 10 } });
240
- return;
241
- }
181
+ // Early scenarios do not advance the ordinary turn counter.
182
+ if (await dispatchReply(earlyReplies, userText, uuid)) return;
242
183
  turn += 1;
243
184
  await sleep(250);
244
- // `mock:done` anywhere in the message → the reply ends with the CEZ:DONE
245
- // completion marker (#347), so the auto-close path is testable dry.
246
- const answered = resumeAfterAsk && userText.trim() === 'Library: Vitest';
247
- resumeAfterAsk = userText.includes('mock:ask') && userText.includes('mock:resume-done');
248
- const doneMarker = (userText.includes('mock:done') || answered) ? '\n\nCEZ:DONE' : '';
249
- // `mock:monitoring` → the reply ends with CEZ:MONITORING, the "still working
250
- // on downstream work" marker (#490), so the monitoring-status path is testable dry.
251
- const monitoringMarker = userText.includes('mock:monitoring') ? '\n\nCEZ:MONITORING' : '';
252
- // `mock:ask` → the reply ends with a valid CEZ:ASK marker (#473), so the
253
- // AskUser card path (park `waiting` + emit `ask.requested`) is testable dry.
254
- // `mock:ask-bad` → a MALFORMED marker (invalid JSON), to prove graceful
255
- // degradation: the run still parks `waiting`, no ask card, prose preserved.
256
- // `mock:ask-invalid` → syntactically valid JSON that FAILS the ask schema
257
- // (empty questions) — the shape behind the blank-question bug: no card will
258
- // ever render it, so the marker must survive in the v1 text.
259
- // `mock:ask-near` → bounded presentation drift: harmless extra keys plus
260
- // an overlong header/description. It should normalize into exactly one card.
261
- // `mock:ask-truncated` → a complete payload one closing brace short (#936):
262
- // the closer repair should still produce one card, note the recovery, and
263
- // strip the raw marker (which ends on `]`, not `}`).
264
- const askMarker = userText.includes('mock:ask-bad')
265
- ? '\n\nCEZ:ASK {not valid json'
266
- : userText.includes('mock:ask-invalid')
267
- ? '\n\nCEZ:ASK {"questions":[]}'
268
- : userText.includes('mock:ask-truncated')
269
- ? '\n\nCEZ:ASK {"questions":[{"header":"Lint scope","question":"How much of the lint backlog should I land now?","multiSelect":false,"options":[{"label":"First slice only"},{"label":"Rule by rule"},{"label":"Whole backlog"}]}]'
270
- : userText.includes('mock:ask-near')
271
- ? '\n\nCEZ:ASK ' +
272
- JSON.stringify({
273
- transportHint: 'render as chips',
274
- questions: [
275
- {
276
- header: 'Implementation path',
277
- question: 'Which implementation should I use?',
278
- presentation: 'compact',
279
- options: [
280
- { label: 'Minimal', description: 'd'.repeat(300), recommended: true },
281
- { label: 'Expanded', description: 'Touch the wider surface' },
282
- ],
283
- },
284
- ],
285
- })
286
- : userText.includes('mock:ask')
287
- ? '\n\nCEZ:ASK ' +
288
- JSON.stringify({
289
- questions: [
290
- {
291
- header: 'Library',
292
- question: 'Which date library should I standardize on?',
293
- options: [
294
- { label: 'date-fns', description: 'Tree-shakeable, functional' },
295
- { label: 'Luxon', description: 'Immutable, tz-aware' },
296
- ],
297
- },
298
- ],
299
- })
300
- : '';
301
- // `mock:refs` → the reply carries the in-band task-reference markers
302
- // (spec 2026-07-18-task-ref-markers), so the declaration path is testable dry.
303
- const refsMarkers = userText.includes('mock:refs')
304
- ? '\nCEZ:PR=4242\nCEZ:ISSUE=17\nCEZ:TITLE=implementing marker refs'
305
- : '';
306
-
185
+ const markers = markersFor(userText);
307
186
  // `mock:slow` → hold the turn for ~25 s so queue states are observable.
308
187
  if (userText.includes('mock:slow')) await sleep(25_000);
188
+ if (await dispatchReply(timedReplies, userText, uuid)) return;
189
+ // Failure selection stays after timed holds and before markdown/naming.
190
+ if (await replyWithNativeFailure(userText)) return;
191
+ if (await dispatchReply(trailingReplies, userText, uuid)) return;
192
+ if (userText.includes('mock:schedule-wakeup')) await replyWithScheduleWakeup(userText);
193
+ if (turn === 1) { await replyWithFirstTurn(userText, markers); return; }
194
+ await replyWithFollowup(userText, imageCount, markers);
195
+ }
309
196
 
310
- // `mock:split-text` → the reply as TWO assistant blocks, the second being the
311
- // bare `CEZ:MONITORING` marker. stream-json has no text deltas (one frame is
312
- // one whole block, see `__fixtures__/claude/text-turn.ndjson`), so claude's
313
- // strongest form of the harness parity S8 split is a multi-block reply: the
314
- // assembled turn text must still end with the marker, or the run parks as
315
- // "needs you" instead of monitoring (#2's failure mode on claude's wire).
316
- if (userText.includes('mock:split-text')) {
317
- for (const block of ['parity split text', 'CEZ:MONITORING']) {
318
- emit({
319
- type: 'assistant',
320
- message: { role: 'assistant', content: [{ type: 'text', text: block }], usage: { input_tokens: 20, output_tokens: 10 } },
321
- });
322
- await sleep(50);
323
- }
324
- emit({
325
- type: 'result',
326
- subtype: 'success',
327
- result: 'parity split text\n\nCEZ:MONITORING',
328
- usage: { input_tokens: 20, output_tokens: 10 },
329
- total_cost_usd: 0.0001,
330
- });
331
- return;
332
- }
197
+ // `mock:ack-only` → the line is read (replayed) and its turn says nothing until more input
198
+ // arrives (hearsay-tools/cezarion#1301).
199
+ async function acknowledgeOnly(userText, uuid) {
200
+ if (uuid) heldUuids.push(uuid); return;
201
+ }
333
202
 
334
- // Same assistant/result envelopes as the baseline stream-json fixture.
335
- if (userText.includes('mock:agent-echo')) {
336
- emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text: userText }] } });
337
- emit({ type: 'result', subtype: 'success', result: userText, usage: { input_tokens: 20, output_tokens: 10 } });
338
- return;
339
- }
203
+ async function replyAutonomously(userText, uuid) {
204
+ const { autonomousReply } = await import('./mock-autonomous.mjs');
205
+ const text = autonomousReply(userText);
206
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text }] } });
207
+ emit({ type: 'result', subtype: 'success', result: text, user_message_uuids: [uuid].filter(Boolean), usage: { input_tokens: 10, output_tokens: 5 } });
208
+ return;
209
+ }
340
210
 
341
- // `mock:hold` → pause, THEN stream the content and the terminal `result`.
342
- // The harness parity matrix's S2 row asserts turn-end follows the last
343
- // content event, so the pause has to sit BEFORE the content: a runner that
344
- // closed the turn on a timer after writing the prompt would report it early.
345
- // Short on purpose — `mock:slow` above is the 25 s queue-state hold.
346
- if (watchdogStall(userText)) return;
347
- if (userText.includes('mock:busy-progress')) {
348
- for (let i = 0; i < 24; i++) { emit({ type: 'ping' }); await sleep(100); }
349
- emit({ type: 'result', subtype: 'success', result: 'busy complete' });
350
- return;
351
- }
352
- if (userText.includes('mock:hold-done')) {
353
- await waitForMockRelease(400);
354
- const held = 'parity hold-done: content after the pause\n\nCEZ:DONE';
355
- emit({
356
- type: 'assistant',
357
- message: { role: 'assistant', content: [{ type: 'text', text: held }], usage: { input_tokens: 20, output_tokens: 10 } },
358
- });
359
- emit({ type: 'result', subtype: 'success', result: held, usage: { input_tokens: 20, output_tokens: 10 }, total_cost_usd: 0.0001 });
360
- return;
361
- }
362
- if (userText.includes('mock:hold-ask')) {
363
- await waitForMockRelease(400);
364
- const ask = 'Pick one.\n\nCEZ:ASK {"questions":[{"header":"Library","question":"Which test library?","options":[{"label":"Vitest"},{"label":"Node test"}]}]}';
365
- emit({
366
- type: 'assistant',
367
- message: { role: 'assistant', content: [{ type: 'text', text: ask }], usage: { input_tokens: 20, output_tokens: 10 } },
368
- });
369
- emit({ type: 'result', subtype: 'success', result: ask, usage: { input_tokens: 20, output_tokens: 10 }, total_cost_usd: 0.0001 });
370
- return;
371
- }
372
- if (userText.includes('mock:hold-gated')) {
373
- await waitForMockRelease(250);
374
- const gated = 'parity hold-gated: content after the pause';
375
- emit({
376
- type: 'assistant',
377
- message: { role: 'assistant', content: [{ type: 'text', text: gated }], usage: { input_tokens: 20, output_tokens: 10 } },
378
- });
379
- await sleep(250);
380
- emit({ type: 'result', subtype: 'success', result: gated, usage: { input_tokens: 20, output_tokens: 10 }, total_cost_usd: 0.0001 });
381
- return;
382
- }
383
- if (userText.includes('mock:hold')) {
384
- await sleep(250);
385
- const held = 'parity hold: content after the pause';
386
- emit({
387
- type: 'assistant',
388
- message: { role: 'assistant', content: [{ type: 'text', text: held }], usage: { input_tokens: 20, output_tokens: 10 } },
389
- });
390
- await sleep(250);
391
- emit({ type: 'result', subtype: 'success', result: held, usage: { input_tokens: 20, output_tokens: 10 }, total_cost_usd: 0.0001 });
392
- return;
211
+ async function replyToFinalMessageNudge(silent, uuid) {
212
+ const kind = silent.finalMessageNudgeKind();
213
+ if (kind === 'ack-only') return;
214
+ if (kind === 'late') await waitForMockRelease(silent.LATE_REPLY_MS);
215
+ if (kind === 'silent') {
216
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'thinking', thinking: silent.SILENT_TAIL_REASONING }] } });
217
+ emit({ type: 'result', subtype: 'success', result: '', user_message_uuids: [uuid].filter(Boolean), usage: { input_tokens: 10, output_tokens: 5 } });
218
+ } else {
219
+ await replyWithFinalTailText(silent, uuid, kind);
393
220
  }
221
+ return;
222
+ }
394
223
 
395
- // Mirrors the real Claude Code 2.1.148 revoked-token envelope: the CLI puts
396
- // the credential failure in an `is_error` result even though its subtype is
397
- // `success`, rather than emitting a dedicated error frame.
398
- if (userText.includes('mock:auth-error')) {
399
- emit({
400
- type: 'result',
401
- subtype: 'success',
402
- is_error: true,
403
- result: 'Failed to authenticate. API Error: 401 OAuth access token has been revoked.',
404
- usage: { input_tokens: 0, output_tokens: 0 },
405
- total_cost_usd: 0,
406
- });
407
- return;
408
- }
224
+ async function replyWithFinalTailText(silent, uuid, kind) {
225
+ if (kind === 'slow-done') {
226
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text: silent.SLOW_DONE_PREFIX }] } });
227
+ await silent.sleep(silent.SLOW_DONE_TAIL_MS);
228
+ }
229
+ const text = kind === 'standing' ? silent.FINAL_MESSAGE_STANDING : silent.SILENT_TAIL_DONE;
230
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text }] } });
231
+ emit({ type: 'result', subtype: 'success', result: text, user_message_uuids: [uuid].filter(Boolean), usage: { input_tokens: 10, output_tokens: 5 } });
232
+ }
409
233
 
410
- // `mock:limit` → the envelope Claude Code emits when the subscription window is
411
- // exhausted: an `is_error` result whose text is the machine-readable
412
- // `Claude AI usage limit reached|<epoch seconds>` marker. Makes the auto-resume path
413
- // (spec 2026-08-03-auto-resume-after-usage-limit) reachable under CEZ_DRY_RUN=1 for QA and
414
- // the e2e smoke. `CEZ_MOCK_LIMIT_RESET_SECONDS` moves the reset instant (default 60 s out),
415
- // so a dry run can actually watch the resume fire instead of reading about it.
416
- if (userText.includes('mock:limit')) {
417
- const configured = Number(process.env.CEZ_MOCK_LIMIT_RESET_SECONDS ?? '60');
418
- const seconds = Number.isFinite(configured) ? configured : 60;
419
- emit({
420
- type: 'result',
421
- subtype: 'success',
422
- is_error: true,
423
- result: `Claude AI usage limit reached|${Math.floor(Date.now() / 1000) + seconds}`,
424
- usage: { input_tokens: 0, output_tokens: 0 },
425
- total_cost_usd: 0,
426
- });
427
- return;
428
- }
234
+ async function replyWithSilentTail(silent, uuid) {
235
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text: silent.SILENT_TAIL_OPENING }] } });
236
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'tool_use', id: 'toolu_silent_gh', name: 'Bash', input: { command: 'gh issue create' } }] } });
237
+ emit({ type: 'user', message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: 'toolu_silent_gh', content: 'created' }] } });
238
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'thinking', thinking: silent.SILENT_TAIL_REASONING }] } });
239
+ emit({ type: 'result', subtype: 'success', result: silent.SILENT_TAIL_OPENING, user_message_uuids: [uuid].filter(Boolean), usage: { input_tokens: 20, output_tokens: 10 } });
240
+ return;
241
+ }
429
242
 
430
- // `mock:md` → answer with a markdown-rich reply (#346 QA: tables, nested
431
- // lists, emphasis, fences, quotes) instead of the scripted turn.
432
- if (userText.includes('mock:md')) {
433
- const md = [
434
- '## Markdown fixture',
435
- 'This paragraph is soft-wrapped\nacross two source lines.',
436
- '',
437
- '| Column | Align | Result |',
438
- '|:-------|:-----:|-------:|',
439
- '| left `code` | *center* | **42** |',
440
- '| ~~old~~ new | mid | $1.50 |',
441
- '',
442
- '- top item with *emphasis*',
443
- ' - nested child with `code`',
444
- ' - [x] deep done task',
445
- ' - [ ] nested todo',
446
- '- second top',
447
- '',
448
- '> quoted intro',
449
- '> - quoted list item',
450
- '',
451
- '```ts',
452
- 'const answer: number = 42;',
453
- '```',
454
- 'Literal guards: snake_case_name, 2*3 and <script>alert(1)</script>.',
455
- ].join('\n');
456
- emit({
457
- type: 'assistant',
458
- message: { role: 'assistant', content: [{ type: 'text', text: md }], usage: { input_tokens: 100, output_tokens: 200 } },
459
- });
460
- await sleep(100);
461
- emit({ type: 'result', subtype: 'success', result: md, usage: { input_tokens: 100, output_tokens: 200 }, total_cost_usd: 0.001 });
462
- return;
243
+ async function replyWithToolTail(silent, uuid) {
244
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text: silent.TOOL_TAIL_OPENING }] } });
245
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'tool_use', id: 'toolu_tool_tail', name: 'Bash', input: { command: 'git status --short' } }] } });
246
+ emit({ type: 'user', message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: 'toolu_tool_tail', content: ' M src/example.ts' }] } });
247
+ emit({ type: 'result', subtype: 'success', result: silent.TOOL_TAIL_OPENING, user_message_uuids: [uuid].filter(Boolean), usage: { input_tokens: 20, output_tokens: 10 } });
248
+ return;
249
+ }
250
+
251
+ async function replyToSilentTail(userText, uuid) {
252
+ const silent = await import('./mock-silent-tail.mjs');
253
+ silent.noteSilentTailPrompt(userText);
254
+ const scenarios = [
255
+ [() => silent.isFinalMessageNudge(userText), replyToFinalMessageNudge],
256
+ [() => silent.isSilentTailScenario(userText), replyWithSilentTail],
257
+ [() => silent.isToolTailScenario(userText), replyWithToolTail]
258
+ ];
259
+ for (const [matches, reply] of scenarios) {
260
+ if (matches()) { await reply(silent, uuid); return; }
463
261
  }
262
+ return false;
263
+ }
464
264
 
465
- // `mock:subagents` → a parallel fan-out: two `Task` spawns whose child items
466
- // carry `parent_tool_use_id`, interleaved the way a real fan-out interleaves,
467
- // then their results. Makes the Agents dock and its drill-down sheet reachable
468
- // under CEZ_DRY_RUN=1 for QA, screenshots and the e2e smoke (spec
469
- // `.ai/specs/2026-07-20-grouped-subagent-display.md` §"Testability hook", #474).
470
- // Derived from the `subagent-task.ndjson` golden fixture's wire shape.
471
- if (userText.includes('mock:subagents')) {
472
- const agents = [
473
- {
474
- id: `toolu_task_a_${turn}`,
475
- description: 'Audit the auth flow',
476
- subagent_type: 'general-purpose',
477
- steps: [
478
- { text: 'Scanning the auth middleware.' },
479
- { tool: 'Grep', id: `toolu_sub_a1_${turn}`, input: { pattern: 'session', path: 'src' }, result: 'src/middleware.ts:12: clearSession()' },
480
- { tool: 'Read', id: `toolu_sub_a2_${turn}`, input: { file_path: 'src/middleware.ts' }, result: 'export function middleware() { clearSession() }' },
481
- ],
482
- result: 'The session cookie is dropped in src/middleware.ts:12 (clearSession on every redirect).',
483
- },
484
- {
485
- id: `toolu_task_b_${turn}`,
486
- description: 'Review the store layer',
487
- subagent_type: 'code-reviewer',
488
- steps: [
489
- { text: 'Reading the runs store.' },
490
- { tool: 'Bash', id: `toolu_sub_b1_${turn}`, input: { command: 'npm test -- runs/store' }, result: '12 passed' },
491
- ],
492
- result: 'Store layer looks correct; one debounce edge case worth a follow-up.',
493
- },
494
- ];
265
+ // `mock:steer-tool` → one tool call; lines written while it runs are consumed after
266
+ // it (replayed with their uuid) and settled by the SAME result, like Claude 2.1.280 (#505).
267
+ async function replyToSteering(userText, uuid) {
268
+ steering = [];
269
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'tool_use', id: 'toolu_steer', name: 'Bash', input: { command: 'wait' } }] } });
270
+ await holdSteerTool();
271
+ const steered = steering; steering = null;
272
+ emit({ type: 'user', message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: 'toolu_steer', content: 'waited' }] } });
273
+ for (const s of steered) emitReplay(s.uuid, s.userText);
274
+ const text = ['steer tool done', ...steered.map(s => `saw: ${s.userText}`)].join('\n');
275
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text }] } });
276
+ emit({ type: 'result', subtype: 'success', result: text, user_message_uuids: [uuid, ...steered.map(s => s.uuid)].filter(Boolean), usage: { input_tokens: 20, output_tokens: 10 } });
277
+ return;
278
+ }
495
279
 
496
- // Both spawns first — that is what makes it a FAN-OUT rather than two
497
- // sequential agents, and what the dock's "N/M" odometer counts.
498
- for (const agent of agents) {
499
- emit({
500
- type: 'assistant',
501
- message: {
502
- role: 'assistant',
503
- content: [
504
- {
505
- type: 'tool_use',
506
- id: agent.id,
507
- name: 'Task',
508
- input: { description: agent.description, prompt: `${agent.description}.`, subagent_type: agent.subagent_type },
509
- },
510
- ],
511
- usage: { input_tokens: 900, output_tokens: 95 },
512
- },
513
- parent_tool_use_id: null,
514
- });
515
- await sleep(200);
516
- }
280
+ // #961: hook_response frames as `--include-hook-events` emits them (CLI 2.1.301) — one
281
+ // mid-turn, one after the run parked (Squeal's async `waiter` completes this late).
282
+ async function replyWithParkedHook(userText, uuid) {
283
+ const hook = (id, event, text) => ({
284
+ type: 'system', subtype: 'hook_response', hook_id: `hook-${id}-${turn}`, hook_name: event, hook_event: event,
285
+ stdout: JSON.stringify({ hookSpecificOutput: { hookEventName: event, additionalContext: text } }), stderr: '', exit_code: 0, outcome: 'success',
286
+ });
287
+ emit(hook('mid', 'PostToolBatch', 'Mid-turn hook context.'));
288
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text: 'Watching.\nCEZ:MONITORING' }] } });
289
+ emit({ type: 'result', subtype: 'success', result: 'Watching.\nCEZ:MONITORING', usage: { input_tokens: 10, output_tokens: 5 } });
290
+ await afterParityPark(userText);
291
+ emit(hook('late', 'Stop', 'Late hook processed.'));
292
+ return;
293
+ }
517
294
 
518
- // Children, interleaved across agents so the activity lines visibly race.
519
- const maxSteps = Math.max(...agents.map((agent) => agent.steps.length));
520
- for (let i = 0; i < maxSteps; i += 1) {
521
- for (const agent of agents) {
522
- const step = agent.steps[i];
523
- if (!step) continue;
524
- if (step.text !== undefined) {
525
- emit({
526
- type: 'assistant',
527
- message: { role: 'assistant', content: [{ type: 'text', text: step.text }], usage: { input_tokens: 300, output_tokens: 25 } },
528
- parent_tool_use_id: agent.id,
529
- });
530
- } else {
531
- emit({
532
- type: 'assistant',
533
- message: {
534
- role: 'assistant',
535
- content: [{ type: 'tool_use', id: step.id, name: step.tool, input: step.input }],
536
- usage: { input_tokens: 40, output_tokens: 50 },
537
- },
538
- parent_tool_use_id: agent.id,
539
- });
540
- await sleep(250);
541
- emit({
542
- type: 'user',
543
- message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: step.id, content: step.result }] },
544
- parent_tool_use_id: agent.id,
545
- });
546
- }
547
- await sleep(250);
548
- }
549
- }
295
+ // Native child attribution from __fixtures__/claude/subagent-task.ndjson.
296
+ async function replyWithParkedChild(userText, uuid) {
297
+ const task = `toolu_park_${turn}`;
298
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'tool_use', id: task, name: 'Task', input: { description: 'Review' } }] } });
299
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text: 'Watching the child.\nCEZ:MONITORING' }] } });
300
+ emit({ type: 'result', subtype: 'success', result: 'Watching the child.\nCEZ:MONITORING', usage: { input_tokens: 10, output_tokens: 5 } });
301
+ await afterParityPark(userText);
302
+ emit({ type: 'assistant', parent_tool_use_id: task, message: { role: 'assistant', content: [{ type: 'tool_use', id: 'late-read', name: 'Read', input: { file_path: 'README.md' } }] } });
303
+ emit({ type: 'user', parent_tool_use_id: task, message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: 'late-read', content: 'Read the file.' }] } });
304
+ emit({ type: 'assistant', parent_tool_use_id: task, message: { role: 'assistant', content: [{ type: 'text', text: 'Post-park child update processed.' }] } });
305
+ return;
306
+ }
550
307
 
551
- // The spawns settle — `parent_tool_use_id: null`, they belong to the main turn.
552
- for (const agent of agents) {
553
- emit({
554
- type: 'user',
555
- message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: agent.id, content: agent.result }] },
556
- parent_tool_use_id: null,
557
- });
558
- await sleep(200);
559
- }
308
+ // hearsay-tools/cezarion#1284: a `context: fork` skill through the Skill tool, from
309
+ // __fixtures__/claude/forked-skill.ndjson (CLI 2.1.303). Real Claude starts the fork
310
+ // whatever --disallowedTools denies, so this branch ignores the argv too.
311
+ async function replyWithForkedSkill(userText, uuid) {
312
+ const skill = `toolu_skill_fork_${turn}`;
313
+ const bash = `toolu_fork_bash_${turn}`;
314
+ const task = { task_id: `a1284f0000000f0a${turn}`, tool_use_id: skill };
315
+ const child = { parent_tool_use_id: skill, agent_id: task.task_id, subagent_type: 'general-purpose' };
316
+ const text = 'The fxfork skill returned: `FXFORK-2W`';
317
+ emit({ type: 'assistant', parent_tool_use_id: null, message: { role: 'assistant', content: [{ type: 'tool_use', id: skill, name: 'Skill', input: { skill: 'fxfork' } }] } });
318
+ emit({ type: 'system', subtype: 'task_started', ...task, description: '/fxfork', subagent_type: 'general-purpose', spawn_depth: 1, task_type: 'local_agent' });
319
+ emit({ type: 'user', ...child, message: { role: 'user', content: [{ type: 'text', text: 'Run the shell command `echo forked > /dev/null` and reply with exactly FXFORK-2W.' }] } });
320
+ emit({ type: 'assistant', ...child, message: { role: 'assistant', content: [{ type: 'tool_use', id: bash, name: 'Bash', input: { command: 'echo forked > /dev/null' } }] } });
321
+ emit({ type: 'user', ...child, message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: bash, content: '(Bash completed with no output)', is_error: false }] } });
322
+ emit({ type: 'system', subtype: 'task_notification', ...task, status: 'completed', summary: '/fxfork' });
323
+ emit({ type: 'user', parent_tool_use_id: null, message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: skill, content: 'Skill "fxfork" completed (forked execution).\n\nResult:\nFXFORK-2W' }] } });
324
+ emit({ type: 'assistant', parent_tool_use_id: null, message: { role: 'assistant', content: [{ type: 'text', text }] } });
325
+ emit({ type: 'result', subtype: 'success', result: text, usage: { input_tokens: 10, output_tokens: 5 } });
326
+ return;
327
+ }
560
328
 
561
- const summary = 'Both sub-agents reported back: the redirect drops the cookie in src/middleware.ts:12, and the store layer is clean. (dry-run mock)\nCEZ:MONITORING';
562
- emit({
563
- type: 'assistant',
564
- message: { role: 'assistant', content: [{ type: 'text', text: summary }], usage: { input_tokens: 400, output_tokens: 60 } },
565
- parent_tool_use_id: null,
566
- });
567
- // #149: a child assistant frame can arrive after the parent's final marker.
568
- emit({
569
- type: 'assistant',
570
- message: { role: 'assistant', content: [{ type: 'text', text: 'Child review finished.' }] },
571
- parent_tool_use_id: agents[0].id,
572
- });
573
- await sleep(150);
574
- emit({
575
- type: 'result',
576
- subtype: 'success',
577
- result: summary,
578
- usage: { input_tokens: 2100, output_tokens: 380 },
579
- total_cost_usd: 0.0512,
580
- });
581
- return;
582
- }
329
+ // #401: result-only full text; mapResult and v1 use the same fallback.
330
+ async function replyWithMultiplePrs(userText, uuid) {
331
+ const { multiPrText, unrelatedPr } = await import('./mock-multi-pr.mjs');
332
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'tool_use', id: 'multi-read', name: 'Read', input: { file_path: 'other.txt' } }] } });
333
+ emit({ type: 'user', message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: 'multi-read', content: unrelatedPr }] } });
334
+ emit({ type: 'assistant', parent_tool_use_id: 'multi-read', message: { role: 'assistant', content: [{ type: 'text', text: unrelatedPr }] } });
335
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'thinking', thinking: unrelatedPr }] } });
336
+ const text = multiPrText(userText);
337
+ for (const block of text.split('\n')) emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text: block }] } });
338
+ emit({ type: 'result', subtype: 'success', result: text, usage: { input_tokens: 10, output_tokens: 5 } });
339
+ return;
340
+ }
583
341
 
584
- // Task auto-naming spec: a naming call (marked `[cez-namer]`) answers a
585
- // deterministic short title + a PR classification of the sample number so
586
- // dry-run tests can assert the full apply pipeline.
587
- if (userText.includes('[cez-namer]')) {
588
- const numbered = /(?:^|\D)(\d{1,7})(?:\D|$)/.exec(userText);
589
- const name = JSON.stringify({
590
- title: 'implementing cr fixes',
591
- ...(numbered ? { pr: Number(numbered[1]) } : {}),
592
- });
342
+ async function replyWithTurnMessages(userText, uuid) {
343
+ const { turnMessages } = await import('./mock-turn-messages.mjs');
344
+ const messages = turnMessages(userText);
345
+ for (const text of messages) emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text }] } });
346
+ emit({ type: 'result', subtype: 'success', result: messages.join('\n'), usage: { input_tokens: 10, output_tokens: 5 } });
347
+ return;
348
+ }
349
+
350
+ async function replyWithAskSnapshot(userText, uuid) {
351
+ emit({ type: 'result', subtype: 'success', result: userText.includes('mock:ask-snapshot-bad') ? 'CEZ:ASK {not valid json' : 'Using the CEZ:ASK structured question format instead:\n\nCEZ:ASK {"questions":[{"header":"Library","question":"Which test library?","options":[{"label":"Vitest"},{"label":"Node test"}]}]}', usage: { input_tokens: 10, output_tokens: 5 } });
352
+ return;
353
+ }
354
+
355
+ async function replyWithAskProse(userText, uuid) {
356
+ emit({ type: 'result', subtype: 'success', result: 'Use `CEZ:ASK {"questions":[]}` in your reply.\n> CEZ:ASK {not valid json', usage: { input_tokens: 10, output_tokens: 5 } });
357
+ return;
358
+ }
359
+
360
+ async function replyWithCezarTool(userText, uuid) {
361
+ const { toolPrompt } = await import('./mock-ci-tool.mjs');
362
+ const text = await toolPrompt('claude', process.argv.slice(2), userText);
363
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text }] } });
364
+ emit({ type: 'result', subtype: 'success', result: text, usage: { input_tokens: 20, output_tokens: 10 } });
365
+ return;
366
+ }
367
+
368
+ async function replyWithCiWait(userText, uuid) {
369
+ const { ciPrompt } = await import('./mock-ci-tool.mjs');
370
+ const text = await ciPrompt('claude', process.argv.slice(2), userText);
371
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text }] } });
372
+ emit({ type: 'result', subtype: 'success', result: text, usage: { input_tokens: 20, output_tokens: 10 } });
373
+ return;
374
+ }
375
+
376
+ async function replyWithPreview(userText, uuid) {
377
+ const { previewPrompt } = await import('./mock-ci-tool.mjs');
378
+ const text = await previewPrompt('claude', process.argv.slice(2), userText);
379
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text }] } });
380
+ emit({ type: 'result', subtype: 'success', result: text, usage: { input_tokens: 20, output_tokens: 10 } });
381
+ return;
382
+ }
383
+
384
+ // `mock:split-text` → the reply as TWO assistant blocks, the second being the
385
+ // bare `CEZ:MONITORING` marker. stream-json has no text deltas (one frame is
386
+ // one whole block, see `__fixtures__/claude/text-turn.ndjson`), so claude's
387
+ // strongest form of the harness parity S8 split is a multi-block reply: the
388
+ // assembled turn text must still end with the marker, or the run parks as
389
+ // "needs you" instead of monitoring (#2's failure mode on claude's wire).
390
+ async function replyWithSplitText(userText, uuid) {
391
+ for (const block of ['parity split text', 'CEZ:MONITORING']) {
593
392
  emit({
594
393
  type: 'assistant',
595
- message: {
596
- role: 'assistant',
597
- content: [{ type: 'text', text: name }],
598
- usage: { input_tokens: 200, output_tokens: 30 },
599
- },
394
+ message: { role: 'assistant', content: [{ type: 'text', text: block }], usage: { input_tokens: 20, output_tokens: 10 } },
600
395
  });
601
396
  await sleep(50);
602
- emit({
603
- type: 'result',
604
- subtype: 'success',
605
- result: name,
606
- usage: { input_tokens: 200, output_tokens: 30 },
607
- total_cost_usd: 0.0002,
608
- });
609
- return;
610
397
  }
398
+ emit({
399
+ type: 'result',
400
+ subtype: 'success',
401
+ result: 'parity split text\n\nCEZ:MONITORING',
402
+ usage: { input_tokens: 20, output_tokens: 10 },
403
+ total_cost_usd: 0.0001,
404
+ });
405
+ return;
406
+ }
407
+
408
+ // Same assistant/result envelopes as the baseline stream-json fixture.
409
+ async function replyWithEcho(userText, uuid) {
410
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text: userText }] } });
411
+ emit({ type: 'result', subtype: 'success', result: userText, usage: { input_tokens: 20, output_tokens: 10 } });
412
+ return;
413
+ }
414
+
415
+ async function acknowledgeStall(userText, uuid) {
416
+ }
417
+
418
+ async function replyWithBusyProgress(userText, uuid) {
419
+ for (let i = 0; i < 24; i++) { emit({ type: 'ping' }); await sleep(100); }
420
+ const busy = 'busy complete\n\nCEZ:DONE';
421
+ emit({ type: 'assistant', message: { role: 'assistant', content: [{ type: 'text', text: busy }], usage: { input_tokens: 20, output_tokens: 10 } } });
422
+ emit({ type: 'result', subtype: 'success', result: busy });
423
+ return;
424
+ }
425
+
426
+ async function replyWithHeldDone(userText, uuid) {
427
+ await waitForMockRelease(400);
428
+ const held = 'parity hold-done: content after the pause\n\nCEZ:DONE';
429
+ emit({
430
+ type: 'assistant',
431
+ message: { role: 'assistant', content: [{ type: 'text', text: held }], usage: { input_tokens: 20, output_tokens: 10 } },
432
+ });
433
+ emit({ type: 'result', subtype: 'success', result: held, usage: { input_tokens: 20, output_tokens: 10 }, total_cost_usd: 0.0001 });
434
+ return;
435
+ }
611
436
 
612
- // Spec 008: a planning call (marked `[cez-planner]` in the user prompt)
613
- // gets a canned chain plan. The `code-review` skill is deliberately made up:
614
- // the planner's sanitizer strips unknown skills, and the step survives on
615
- // its prompt — which is exactly the path worth exercising in dry runs.
616
- if (userText.includes('[cez-planner]')) {
617
- const plan = JSON.stringify({
618
- title: 'implement-verify-review',
437
+ async function replyWithHeldAsk(userText, uuid) {
438
+ await waitForMockRelease(400);
439
+ const ask = 'Pick one.\n\nCEZ:ASK {"questions":[{"header":"Library","question":"Which test library?","options":[{"label":"Vitest"},{"label":"Node test"}]}]}';
440
+ emit({
441
+ type: 'assistant',
442
+ message: { role: 'assistant', content: [{ type: 'text', text: ask }], usage: { input_tokens: 20, output_tokens: 10 } },
443
+ });
444
+ emit({ type: 'result', subtype: 'success', result: ask, usage: { input_tokens: 20, output_tokens: 10 }, total_cost_usd: 0.0001 });
445
+ return;
446
+ }
447
+
448
+ async function replyWithGatedHold(userText, uuid) {
449
+ await waitForMockRelease(250);
450
+ const gated = 'parity hold-gated: content after the pause';
451
+ emit({
452
+ type: 'assistant',
453
+ message: { role: 'assistant', content: [{ type: 'text', text: gated }], usage: { input_tokens: 20, output_tokens: 10 } },
454
+ });
455
+ await sleep(250);
456
+ emit({ type: 'result', subtype: 'success', result: gated, usage: { input_tokens: 20, output_tokens: 10 }, total_cost_usd: 0.0001 });
457
+ return;
458
+ }
459
+
460
+ // `mock:hold` → pause, THEN stream the content and the terminal `result`.
461
+ // The harness parity matrix's S2 row asserts turn-end follows the last
462
+ // content event, so the pause has to sit BEFORE the content: a runner that
463
+ // closed the turn on a timer after writing the prompt would report it early.
464
+ async function replyWithHold(userText, uuid) {
465
+ // Short on purpose — `mock:slow` above is the 25 s queue-state hold.
466
+ await sleep(250);
467
+ const held = 'parity hold: content after the pause';
468
+ emit({
469
+ type: 'assistant',
470
+ message: { role: 'assistant', content: [{ type: 'text', text: held }], usage: { input_tokens: 20, output_tokens: 10 } },
471
+ });
472
+ await sleep(250);
473
+ emit({ type: 'result', subtype: 'success', result: held, usage: { input_tokens: 20, output_tokens: 10 }, total_cost_usd: 0.0001 });
474
+ return;
475
+ }
476
+
477
+ // `mock:md` → answer with a markdown-rich reply (#346 QA: tables, nested
478
+ // lists, emphasis, fences, quotes) instead of the scripted turn.
479
+ async function replyWithMarkdown(userText, uuid) {
480
+ const md = [
481
+ '## Markdown fixture',
482
+ 'This paragraph is soft-wrapped\nacross two source lines.',
483
+ '',
484
+ '| Column | Align | Result |',
485
+ '|:-------|:-----:|-------:|',
486
+ '| left `code` | *center* | **42** |',
487
+ '| ~~old~~ new | mid | $1.50 |',
488
+ '',
489
+ '- top item with *emphasis*',
490
+ ' - nested child with `code`',
491
+ ' - [x] deep done task',
492
+ ' - [ ] nested todo',
493
+ '- second top',
494
+ '',
495
+ '> quoted intro',
496
+ '> - quoted list item',
497
+ '',
498
+ '```ts',
499
+ 'const answer: number = 42;',
500
+ '```',
501
+ 'Literal guards: snake_case_name, 2*3 and <script>alert(1)</script>.',
502
+ ].join('\n');
503
+ emit({
504
+ type: 'assistant',
505
+ message: { role: 'assistant', content: [{ type: 'text', text: md }], usage: { input_tokens: 100, output_tokens: 200 } },
506
+ });
507
+ await sleep(100);
508
+ emit({ type: 'result', subtype: 'success', result: md, usage: { input_tokens: 100, output_tokens: 200 }, total_cost_usd: 0.001 });
509
+ return;
510
+ }
511
+
512
+ // `mock:subagents` → a parallel fan-out: two `Task` spawns whose child items
513
+ // carry `parent_tool_use_id`, interleaved the way a real fan-out interleaves,
514
+ // then their results. Makes the Agents dock and its drill-down sheet reachable
515
+ // under CEZ_DRY_RUN=1 for QA, screenshots and the e2e smoke (spec
516
+ // `.ai/specs/2026-07-20-grouped-subagent-display.md` §"Testability hook", #474).
517
+ // Derived from the `subagent-task.ndjson` golden fixture's wire shape.
518
+ async function replyWithSubagents(userText, uuid) {
519
+ const agents = [
520
+ {
521
+ id: `toolu_task_a_${turn}`,
522
+ description: 'Audit the auth flow',
523
+ subagent_type: 'general-purpose',
619
524
  steps: [
620
- { name: 'Implement', prompt: '{{task}}' },
621
- { name: 'Verify', command: 'npm test' },
622
- { name: 'Review', skill: 'code-review', prompt: 'Review the changes for {{task}}' },
525
+ { text: 'Scanning the auth middleware.' },
526
+ { tool: 'Grep', id: `toolu_sub_a1_${turn}`, input: { pattern: 'session', path: 'src' }, result: 'src/middleware.ts:12: clearSession()' },
527
+ { tool: 'Read', id: `toolu_sub_a2_${turn}`, input: { file_path: 'src/middleware.ts' }, result: 'export function middleware() { clearSession() }' },
623
528
  ],
624
- rationale: 'Implement, verify with tests, then review.',
625
- });
626
- emit({
627
- type: 'assistant',
628
- message: {
629
- role: 'assistant',
630
- content: [{ type: 'text', text: plan }],
631
- usage: { input_tokens: 500, output_tokens: 120 },
632
- },
633
- });
634
- await sleep(100);
635
- emit({
636
- type: 'result',
637
- subtype: 'success',
638
- result: plan,
639
- usage: { input_tokens: 500, output_tokens: 120 },
640
- total_cost_usd: 0.0011,
641
- });
642
- return;
643
- }
529
+ result: 'The session cookie is dropped in src/middleware.ts:12 (clearSession on every redirect).',
530
+ },
531
+ {
532
+ id: `toolu_task_b_${turn}`,
533
+ description: 'Review the store layer',
534
+ subagent_type: 'code-reviewer',
535
+ steps: [
536
+ { text: 'Reading the runs store.' },
537
+ { tool: 'Bash', id: `toolu_sub_b1_${turn}`, input: { command: 'npm test -- runs/store' }, result: '12 passed' },
538
+ ],
539
+ result: 'Store layer looks correct; one debounce edge case worth a follow-up.',
540
+ },
541
+ ];
542
+ await replyWithSubagentSpawns(agents);
543
+ await replyWithSubagentSteps(agents);
544
+ await replyWithSubagentResults(agents);
545
+ const summary = 'Both sub-agents reported back: the redirect drops the cookie in src/middleware.ts:12, and the store layer is clean. (dry-run mock)\nCEZ:MONITORING';
546
+ emit({
547
+ type: 'assistant',
548
+ message: { role: 'assistant', content: [{ type: 'text', text: summary }], usage: { input_tokens: 400, output_tokens: 60 } },
549
+ parent_tool_use_id: null,
550
+ });
551
+ // #149: a child assistant frame can arrive after the parent's final marker.
552
+ emit({
553
+ type: 'assistant',
554
+ message: { role: 'assistant', content: [{ type: 'text', text: 'Child review finished.' }] },
555
+ parent_tool_use_id: agents[0].id,
556
+ });
557
+ await sleep(150);
558
+ emit({
559
+ type: 'result',
560
+ subtype: 'success',
561
+ result: summary,
562
+ usage: { input_tokens: 2100, output_tokens: 380 },
563
+ total_cost_usd: 0.0512,
564
+ });
565
+ return;
566
+ }
644
567
 
645
- // `mock:schedule-wakeup` → Claude's native park tool, without also emitting
646
- // CEZ:MONITORING. The workflow engine must recognize the completed turn's
647
- // tool use rather than depending on the textual agent contract marker (#46).
648
- if (userText.includes('mock:schedule-wakeup')) {
649
- const id = `toolu_schedule_wakeup_${turn}`;
568
+ // Both spawns first — that is what makes it a FAN-OUT rather than two
569
+ // sequential agents, and what the dock's "N/M" odometer counts.
570
+ async function replyWithSubagentSpawns(agents) {
571
+ for (const agent of agents) {
650
572
  emit({
651
573
  type: 'assistant',
652
574
  message: {
653
575
  role: 'assistant',
654
- content: [{ type: 'tool_use', id, name: 'ScheduleWakeup', input: { delay: '5m' } }],
655
- usage: { input_tokens: 40, output_tokens: 20 },
656
- },
657
- });
658
- await sleep(100);
659
- emit({
660
- type: 'user',
661
- message: {
662
- role: 'user',
663
- content: [{ type: 'tool_result', tool_use_id: id, content: 'Wakeup scheduled.' }],
576
+ content: [
577
+ {
578
+ type: 'tool_use',
579
+ id: agent.id,
580
+ name: 'Task',
581
+ input: { description: agent.description, prompt: `${agent.description}.`, subagent_type: agent.subagent_type },
582
+ },
583
+ ],
584
+ usage: { input_tokens: 900, output_tokens: 95 },
664
585
  },
586
+ parent_tool_use_id: null,
665
587
  });
666
- await sleep(100);
588
+ await sleep(200);
667
589
  }
590
+ }
668
591
 
669
- if (turn === 1) {
670
- // Leave a visible trace in the cwd (the task worktree under spec 006) so
671
- // the Diff view has something real to show in dry runs. Exactly one line
672
- // per spawned session: tests read this file back as a per-step trace, so
673
- // a multi-line prompt must not become multiple lines here.
674
- try {
675
- const head = userText.replace(/\s+/g, ' ').trim().slice(0, 400);
676
- appendFileSync('notes.md', `mock notes — ${new Date().toISOString()}: ${head}\n`);
677
- } catch {
678
- // read-only cwd — the mock still works, just without a diff
592
+ // Children, interleaved across agents so the activity lines visibly race.
593
+ async function replyWithSubagentSteps(agents) {
594
+ const maxSteps = Math.max(...agents.map((agent) => agent.steps.length));
595
+ for (let i = 0; i < maxSteps; i += 1) {
596
+ for (const agent of agents) {
597
+ const step = agent.steps[i];
598
+ if (!step) continue;
599
+ await replyWithSubagentStep(agent, step);
679
600
  }
680
- writeHandoffAndTodo();
601
+ }
602
+ }
603
+
604
+ async function replyWithSubagentStep(agent, step) {
605
+ if (step.text !== undefined) {
681
606
  emit({
682
607
  type: 'assistant',
683
- message: {
684
- role: 'assistant',
685
- content: [{ type: 'text', text: `Okay — looking into: ${userText.slice(0, 120)}` }],
686
- usage: { input_tokens: 850, output_tokens: 40 },
687
- },
608
+ message: { role: 'assistant', content: [{ type: 'text', text: step.text }], usage: { input_tokens: 300, output_tokens: 25 } },
609
+ parent_tool_use_id: agent.id,
688
610
  });
689
- await sleep(300);
611
+ } else {
690
612
  emit({
691
613
  type: 'assistant',
692
614
  message: {
693
615
  role: 'assistant',
694
- content: [{ type: 'tool_use', id: `toolu_mock_${turn}`, name: 'Bash', input: { command: 'git status --short' } }],
695
- usage: { input_tokens: 120, output_tokens: 55 },
616
+ content: [{ type: 'tool_use', id: step.id, name: step.tool, input: step.input }],
617
+ usage: { input_tokens: 40, output_tokens: 50 },
696
618
  },
619
+ parent_tool_use_id: agent.id,
697
620
  });
698
- await sleep(300);
621
+ await sleep(250);
699
622
  emit({
700
623
  type: 'user',
701
- message: {
702
- role: 'user',
703
- content: [{ type: 'tool_result', tool_use_id: `toolu_mock_${turn}`, content: ' M src/example.ts' }],
704
- },
624
+ message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: step.id, content: step.result }] },
625
+ parent_tool_use_id: agent.id,
705
626
  });
706
- await sleep(200);
707
- // Agent screenshot in a tool result — exercises the image pipeline
708
- // (persist to <id>-images/, serve via /api/runs/:id/images/, zoomable
709
- // card + lightbox in the transcript).
710
- emit({
711
- type: 'assistant',
712
- message: {
713
- role: 'assistant',
714
- content: [{ type: 'tool_use', id: `toolu_mock_shot_${turn}`, name: 'Screenshot', input: { name: 'repro-login-redirect.png' } }],
715
- usage: { input_tokens: 80, output_tokens: 30 },
716
- },
717
- });
718
- await sleep(200);
627
+ }
628
+ await sleep(250);
629
+ }
630
+
631
+ // The spawns settle — `parent_tool_use_id: null`, they belong to the main turn.
632
+ async function replyWithSubagentResults(agents) {
633
+ for (const agent of agents) {
719
634
  emit({
720
635
  type: 'user',
721
- message: {
722
- role: 'user',
723
- content: [
724
- {
725
- type: 'tool_result',
726
- tool_use_id: `toolu_mock_shot_${turn}`,
727
- content: [
728
- { type: 'text', text: 'Repro captured: after reload the session toast appears and you are back on /login.' },
729
- { type: 'image', source: { type: 'base64', media_type: 'image/png', data: MOCK_SCREENSHOT_B64 } },
730
- ],
731
- },
732
- ],
733
- },
734
- });
735
- await sleep(300);
736
- emit({
737
- type: 'assistant',
738
- message: {
739
- role: 'assistant',
740
- content: [{ type: 'text', text: `Done with the first pass — opened a draft PR: https://github.com/open-mercato/demo/pull/123. Anything to adjust? (dry-run mock)${refsMarkers}${doneMarker}${monitoringMarker}${askMarker}` }],
741
- usage: { input_tokens: 300, output_tokens: 90 },
742
- },
743
- });
744
- await sleep(150);
745
- emit({
746
- type: 'result',
747
- subtype: 'success',
748
- result: 'Done with the first pass (dry run).',
749
- usage: { input_tokens: 1270, output_tokens: 185 },
750
- total_cost_usd: 0.0342,
636
+ message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: agent.id, content: agent.result }] },
637
+ parent_tool_use_id: null,
751
638
  });
752
- return;
639
+ await sleep(200);
753
640
  }
641
+ }
754
642
 
643
+ // Task auto-naming spec: a naming call (marked `[cez-namer]`) answers a
644
+ // deterministic short title + a PR classification of the sample number so
645
+ // dry-run tests can assert the full apply pipeline.
646
+ async function replyWithName(userText, uuid) {
647
+ const numbered = /(?:^|\D)(\d{1,7})(?:\D|$)/.exec(userText);
648
+ const name = JSON.stringify({
649
+ title: 'implementing cr fixes',
650
+ ...(numbered ? { pr: Number(numbered[1]) } : {}),
651
+ });
652
+ emit({
653
+ type: 'assistant',
654
+ message: {
655
+ role: 'assistant',
656
+ content: [{ type: 'text', text: name }],
657
+ usage: { input_tokens: 200, output_tokens: 30 },
658
+ },
659
+ });
660
+ await sleep(50);
661
+ emit({
662
+ type: 'result',
663
+ subtype: 'success',
664
+ result: name,
665
+ usage: { input_tokens: 200, output_tokens: 30 },
666
+ total_cost_usd: 0.0002,
667
+ });
668
+ return;
669
+ }
670
+
671
+ // Spec 008: a planning call (marked `[cez-planner]` in the user prompt)
672
+ // gets a canned chain plan. The `code-review` skill is deliberately made up:
673
+ // the planner's sanitizer strips unknown skills, and the step survives on
674
+ // its prompt — which is exactly the path worth exercising in dry runs.
675
+ async function replyWithPlan(userText, uuid) {
676
+ const plan = JSON.stringify({
677
+ title: 'implement-verify-review',
678
+ steps: [
679
+ { name: 'Implement', prompt: '{{task}}' },
680
+ { name: 'Verify', command: 'npm test' },
681
+ { name: 'Review', skill: 'code-review', prompt: 'Review the changes for {{task}}' },
682
+ ],
683
+ rationale: 'Implement, verify with tests, then review.',
684
+ });
685
+ emit({
686
+ type: 'assistant',
687
+ message: {
688
+ role: 'assistant',
689
+ content: [{ type: 'text', text: plan }],
690
+ usage: { input_tokens: 500, output_tokens: 120 },
691
+ },
692
+ });
693
+ await sleep(100);
694
+ emit({
695
+ type: 'result',
696
+ subtype: 'success',
697
+ result: plan,
698
+ usage: { input_tokens: 500, output_tokens: 120 },
699
+ total_cost_usd: 0.0011,
700
+ });
701
+ return;
702
+ }
703
+
704
+ // `mock:schedule-wakeup` → Claude's native park tool, without also emitting
705
+ // CEZ:MONITORING. The workflow engine must recognize the completed turn's
706
+ // tool use rather than depending on the textual agent contract marker (#46).
707
+ // `mock:schedule-wakeup:<n>` sends the tool's `delaySeconds` (hearsay-tools/cezarion#1233).
708
+ async function replyWithScheduleWakeup(userText, uuid) {
709
+ const id = `toolu_schedule_wakeup_${turn}`;
710
+ const seconds = /mock:schedule-wakeup:(\d+)/.exec(userText)?.[1];
711
+ emit({
712
+ type: 'assistant',
713
+ message: {
714
+ role: 'assistant',
715
+ content: [{ type: 'tool_use', id, name: 'ScheduleWakeup', input: seconds ? { delaySeconds: Number(seconds) } : { delay: '5m' } }],
716
+ usage: { input_tokens: 40, output_tokens: 20 },
717
+ },
718
+ });
719
+ await sleep(100);
720
+ emit({
721
+ type: 'user',
722
+ message: {
723
+ role: 'user',
724
+ content: [{ type: 'tool_result', tool_use_id: id, content: 'Wakeup scheduled.' }],
725
+ },
726
+ });
727
+ await sleep(100);
728
+ }
729
+
730
+ async function replyWithFirstTurn(userText, { refsMarkers, doneMarker, monitoringMarker, askMarker }) {
731
+ writeNotesTrace(userText);
732
+ writeHandoff();
733
+ emit({
734
+ type: 'assistant',
735
+ message: {
736
+ role: 'assistant',
737
+ content: [{ type: 'text', text: `Okay — looking into: ${userText.slice(0, 120)}` }],
738
+ usage: { input_tokens: 850, output_tokens: 40 },
739
+ },
740
+ });
741
+ await sleep(300);
742
+ emit({
743
+ type: 'assistant',
744
+ message: {
745
+ role: 'assistant',
746
+ content: [{ type: 'tool_use', id: `toolu_mock_${turn}`, name: 'Bash', input: { command: 'git status --short' } }],
747
+ usage: { input_tokens: 120, output_tokens: 55 },
748
+ },
749
+ });
750
+ await sleep(300);
751
+ emit({
752
+ type: 'user',
753
+ message: {
754
+ role: 'user',
755
+ content: [{ type: 'tool_result', tool_use_id: `toolu_mock_${turn}`, content: ' M src/example.ts' }],
756
+ },
757
+ });
758
+ await sleep(200);
759
+ // Agent screenshot in a tool result — exercises the image pipeline
760
+ // (persist to <id>-images/, serve via /api/runs/:id/images/, zoomable
761
+ // card + lightbox in the transcript).
762
+ emit({
763
+ type: 'assistant',
764
+ message: {
765
+ role: 'assistant',
766
+ content: [{ type: 'tool_use', id: `toolu_mock_shot_${turn}`, name: 'Screenshot', input: { name: 'repro-login-redirect.png' } }],
767
+ usage: { input_tokens: 80, output_tokens: 30 },
768
+ },
769
+ });
770
+ await sleep(200);
771
+ emit({
772
+ type: 'user',
773
+ message: {
774
+ role: 'user',
775
+ content: [
776
+ {
777
+ type: 'tool_result',
778
+ tool_use_id: `toolu_mock_shot_${turn}`,
779
+ content: [
780
+ { type: 'text', text: 'Repro captured: after reload the session toast appears and you are back on /login.' },
781
+ { type: 'image', source: { type: 'base64', media_type: 'image/png', data: MOCK_SCREENSHOT_B64 } },
782
+ ],
783
+ },
784
+ ],
785
+ },
786
+ });
787
+ await sleep(300);
788
+ emit({
789
+ type: 'assistant',
790
+ message: {
791
+ role: 'assistant',
792
+ content: [{ type: 'text', text: `Done with the first pass — opened a draft PR: https://github.com/open-mercato/demo/pull/123. Anything to adjust? (dry-run mock)${refsMarkers}${doneMarker}${monitoringMarker}${askMarker}` }],
793
+ usage: { input_tokens: 300, output_tokens: 90 },
794
+ },
795
+ });
796
+ await sleep(150);
797
+ emit({
798
+ type: 'result',
799
+ subtype: 'success',
800
+ result: 'Done with the first pass (dry run).',
801
+ usage: { input_tokens: 1270, output_tokens: 185 },
802
+ total_cost_usd: 0.0342,
803
+ });
804
+ return;
805
+ }
806
+
807
+ async function replyWithFollowup(userText, imageCount, { refsMarkers, doneMarker, monitoringMarker, askMarker }) {
755
808
  const imgNote = imageCount > 0 ? ` I can see ${imageCount} image(s) you attached.` : '';
756
809
  emit({
757
810
  type: 'assistant',
@@ -771,6 +824,194 @@ async function respond(userText, imageCount, uuid) {
771
824
  });
772
825
  }
773
826
 
827
+ // Mirrors the real Claude Code 2.1.148 revoked-token envelope: the CLI puts
828
+ // the credential failure in an `is_error` result even though its subtype is
829
+ // `success`, rather than emitting a dedicated error frame.
830
+ async function replyWithAuthenticationFailure(userText, uuid) {
831
+ emit({
832
+ type: 'result',
833
+ subtype: 'success',
834
+ is_error: true,
835
+ result: 'Failed to authenticate. API Error: 401 OAuth access token has been revoked.',
836
+ usage: { input_tokens: 0, output_tokens: 0 },
837
+ total_cost_usd: 0,
838
+ });
839
+ return;
840
+ }
841
+
842
+ // `mock:limit` → the envelope Claude Code emits when the subscription window is
843
+ // exhausted: an `is_error` result whose text is the machine-readable
844
+ // `Claude AI usage limit reached|<epoch seconds>` marker. Makes the auto-resume path
845
+ // (spec 2026-08-03-auto-resume-after-usage-limit) reachable under CEZ_DRY_RUN=1 for QA and
846
+ // the e2e smoke. `CEZ_MOCK_LIMIT_RESET_SECONDS` moves the reset instant (default 60 s out),
847
+ // so a dry run can actually watch the resume fire instead of reading about it.
848
+ async function replyWithUsageLimit(userText, uuid) {
849
+ const configured = Number(process.env.CEZ_MOCK_LIMIT_RESET_SECONDS ?? '60');
850
+ const seconds = Number.isFinite(configured) ? configured : 60;
851
+ emit({
852
+ type: 'result',
853
+ subtype: 'success',
854
+ is_error: true,
855
+ result: `Claude AI usage limit reached|${Math.floor(Date.now() / 1000) + seconds}`,
856
+ usage: { input_tokens: 0, output_tokens: 0 },
857
+ total_cost_usd: 0,
858
+ });
859
+ return;
860
+ }
861
+
862
+ async function replyWithNativeFailure(userText) {
863
+ const selectedFailure = failureControl?.failureFor(userText);
864
+ const nativeFailure = selectedFailure instanceof Promise ? await selectedFailure : selectedFailure;
865
+ if (nativeFailure === 'unread') process.exit(1);
866
+ if (failureControl?.failure === 'provider' ? nativeFailure === 'provider' : userText.includes('mock:auth-error')) { await replyWithAuthenticationFailure(); return true; }
867
+ if (failureControl?.failure === 'usage-limit' ? nativeFailure === 'usage-limit' : userText.includes('mock:limit')) { await replyWithUsageLimit(); return true; }
868
+ return false;
869
+ }
870
+
871
+ function multiAskMarker() {
872
+ return '\n\nCEZ:ASK ' +
873
+ JSON.stringify({
874
+ questions: [
875
+ {
876
+ header: 'Library',
877
+ question: 'Which test library?',
878
+ options: [{ label: 'Vitest' }, { label: 'Node test' }],
879
+ },
880
+ {
881
+ header: 'Build',
882
+ question: 'Which build tool?',
883
+ options: [{ label: 'Vite' }, { label: 'Webpack' }],
884
+ },
885
+ ],
886
+ });
887
+ }
888
+
889
+ function invalidJsonAskMarker() { return '\n\nCEZ:ASK {not valid json'; }
890
+
891
+ function invalidSchemaAskMarker() { return '\n\nCEZ:ASK {"questions":[]}'; }
892
+
893
+ function truncatedAskMarker() { return '\n\nCEZ:ASK {"questions":[{"header":"Lint scope","question":"How much of the lint backlog should I land now?","multiSelect":false,"options":[{"label":"First slice only"},{"label":"Rule by rule"},{"label":"Whole backlog"}]}]'; }
894
+
895
+ function nearAskMarker() {
896
+ return '\n\nCEZ:ASK ' +
897
+ JSON.stringify({
898
+ transportHint: 'render as chips',
899
+ questions: [
900
+ {
901
+ header: 'Implementation path',
902
+ question: 'Which implementation should I use?',
903
+ presentation: 'compact',
904
+ options: [
905
+ { label: 'Minimal', description: 'd'.repeat(300), recommended: true },
906
+ { label: 'Expanded', description: 'Touch the wider surface' },
907
+ ],
908
+ },
909
+ ],
910
+ });
911
+ }
912
+
913
+ function ordinaryAskMarker() {
914
+ return '\n\nCEZ:ASK ' +
915
+ JSON.stringify({
916
+ questions: [
917
+ {
918
+ header: 'Library',
919
+ question: 'Which date library should I standardize on?',
920
+ options: [
921
+ { label: 'date-fns', description: 'Tree-shakeable, functional' },
922
+ { label: 'Luxon', description: 'Immutable, tz-aware' },
923
+ ],
924
+ },
925
+ ],
926
+ });
927
+ }
928
+
929
+ const askMarkers = [
930
+ [userText => userText.includes('mock:multi-ask'), multiAskMarker],
931
+ [userText => userText.includes('mock:ask-bad'), invalidJsonAskMarker],
932
+ [userText => userText.includes('mock:ask-invalid'), invalidSchemaAskMarker],
933
+ [userText => userText.includes('mock:ask-truncated'), truncatedAskMarker],
934
+ [userText => userText.includes('mock:ask-near'), nearAskMarker],
935
+ [userText => userText.includes('mock:ask'), ordinaryAskMarker]
936
+ ];
937
+ function askMarkerFor(userText) {
938
+ const entry = askMarkers.find(([matches]) => matches(userText));
939
+ return entry ? entry[1]() : '';
940
+ }
941
+
942
+ // `mock:done` anywhere in the message → the reply ends with the CEZ:DONE
943
+ // completion marker (#347), so the auto-close path is testable dry.
944
+ // `mock:monitoring` → the reply ends with CEZ:MONITORING, the "still working
945
+ // on downstream work" marker (#490), so the monitoring-status path is testable dry.
946
+ // `mock:ask` → the reply ends with a valid CEZ:ASK marker (#473), so the
947
+ // AskUser card path (park `waiting` + emit `ask.requested`) is testable dry.
948
+ // `mock:ask-bad` → a MALFORMED marker (invalid JSON), to prove graceful
949
+ // degradation: the run still parks `waiting`, no ask card, prose preserved.
950
+ // `mock:ask-invalid` → syntactically valid JSON that FAILS the ask schema
951
+ // (empty questions) — the shape behind the blank-question bug: no card will
952
+ // ever render it, so the marker must survive in the v1 text.
953
+ // `mock:ask-near` → bounded presentation drift: harmless extra keys plus
954
+ // an overlong header/description. It should normalize into exactly one card.
955
+ // `mock:ask-truncated` → a complete payload one closing brace short (#936):
956
+ // the closer repair should still produce one card, note the recovery, and
957
+ // strip the raw marker (which ends on `]`, not `}`).
958
+ // `mock:multi-ask` → ONE marker with two questions (Library, Build), for the voice-mode E2E
959
+ // (spec 2026-10-21-voice-mode). Checked before every `mock:ask` form so none of them can
960
+ // claim the prompt first.
961
+ // `mock:refs` → the reply carries the in-band task-reference markers
962
+ // (spec 2026-07-18-task-ref-markers), so the declaration path is testable dry.
963
+ function markersFor(userText) {
964
+ const answered = resumeAfterAsk && userText.trim() === 'Library: Vitest';
965
+ resumeAfterAsk = userText.includes('mock:ask') && userText.includes('mock:resume-done');
966
+ const doneMarker = (userText.includes('mock:done') || answered) ? '\n\nCEZ:DONE' : '';
967
+ const monitoringMarker = userText.includes('mock:monitoring') ? '\n\nCEZ:MONITORING' : '';
968
+ const askMarker = askMarkerFor(userText);
969
+ const refsMarkers = userText.includes('mock:refs')
970
+ ? '\nCEZ:PR=4242\nCEZ:ISSUE=17\nCEZ:TITLE=implementing marker refs'
971
+ : '';
972
+ return { doneMarker, monitoringMarker, askMarker, refsMarkers };
973
+ }
974
+
975
+ // Ordered matchers preserve scenario priority and the silent-tail fall-through.
976
+ const earlyReplies = [
977
+ [userText => userText.includes('mock:ack-only'), acknowledgeOnly],
978
+ [userText => userText.includes('mock:autonomous') || userText.startsWith('Continue working autonomously until the task is fully complete.'), replyAutonomously],
979
+ [userText => userText.includes('mock:silent-tail') || userText.includes('mock:tool-tail') || silentNudge(userText), replyToSilentTail],
980
+ [userText => userText.includes('mock:steer-tool'), replyToSteering],
981
+ [userText => !userText.includes('[cez-namer]') && userText.includes('mock:hook-after-park'), replyWithParkedHook],
982
+ [userText => !userText.includes('[cez-namer]') && userText.includes('mock:subagent-after-park'), replyWithParkedChild],
983
+ [userText => !userText.includes('[cez-namer]') && userText.includes('mock:forked-skill'), replyWithForkedSkill],
984
+ [userText => userText.includes('mock:multi-pr-refs'), replyWithMultiplePrs],
985
+ [userText => userText.includes('mock:turn-messages:'), replyWithTurnMessages],
986
+ [userText => !userText.includes('[cez-namer]') && userText.includes('mock:ask-snapshot'), replyWithAskSnapshot],
987
+ [userText => !userText.includes('[cez-namer]') && userText.includes('mock:ask-prose'), replyWithAskProse],
988
+ [userText => !userText.includes('[cez-namer]') && userText.includes('mock:cezar-tool'), replyWithCezarTool],
989
+ [userText => userText.includes('mock:ci-wait'), replyWithCiWait],
990
+ [userText => !userText.includes('[cez-namer]') && userText.includes('mock:preview-serve'), replyWithPreview]
991
+ ];
992
+ const timedReplies = [
993
+ [userText => userText.includes('mock:split-text'), replyWithSplitText],
994
+ [userText => userText.includes('mock:agent-echo'), replyWithEcho],
995
+ [watchdogStall, acknowledgeStall],
996
+ [userText => userText.includes('mock:busy-progress'), replyWithBusyProgress],
997
+ [userText => userText.includes('mock:hold-done'), replyWithHeldDone],
998
+ [userText => userText.includes('mock:hold-ask'), replyWithHeldAsk],
999
+ [userText => userText.includes('mock:hold-gated'), replyWithGatedHold],
1000
+ [userText => userText.includes('mock:hold'), replyWithHold]
1001
+ ];
1002
+ const trailingReplies = [
1003
+ [userText => userText.includes('mock:md'), replyWithMarkdown],
1004
+ [userText => userText.includes('mock:subagents'), replyWithSubagents],
1005
+ [userText => userText.includes('[cez-namer]'), replyWithName],
1006
+ [userText => userText.includes('[cez-planner]'), replyWithPlan]
1007
+ ];
1008
+ async function dispatchReply(scenarios, userText, uuid) {
1009
+ for (const [matches, reply] of scenarios) {
1010
+ if (matches(userText) && await reply(userText, uuid) !== false) return true;
1011
+ }
1012
+ return false;
1013
+ }
1014
+
774
1015
  const rl = createInterface({ input: process.stdin });
775
1016
  let queue = Promise.resolve();
776
1017
  rl.on('line', (line) => {
@@ -814,6 +1055,7 @@ rl.on('line', (line) => {
814
1055
  // and never runs it). CEZ_MOCK_DROP_ONCE=1 drops only the first match.
815
1056
  const drop = process.env.CEZ_MOCK_DROP_LINES;
816
1057
  if (drop && userText.includes(drop) && !(process.env.CEZ_MOCK_DROP_ONCE === '1' && droppedOnce)) { droppedOnce = true; return; }
1058
+ userText = answerNudge(withoutSessionContext(userText));
817
1059
  if (steering) { steering.push({ userText, uuid }); return; }
818
1060
  queue = queue.then(() => respond(userText, imageCount, uuid));
819
1061
  });