@wjarka/cezarion 0.15.1 → 0.16.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 (462) hide show
  1. package/README.md +167 -46
  2. package/dist/agent-config/catalog.d.ts +6 -2
  3. package/dist/agent-config/catalog.js +78 -3
  4. package/dist/agent-config/catalog.js.map +1 -1
  5. package/dist/agent-config/model-settings/shared.js +6 -3
  6. package/dist/agent-config/model-settings/shared.js.map +1 -1
  7. package/dist/agent-config/models.js +4 -0
  8. package/dist/agent-config/models.js.map +1 -1
  9. package/dist/agent-config/validate.js +6 -0
  10. package/dist/agent-config/validate.js.map +1 -1
  11. package/dist/artifacts/cli.js +10 -2
  12. package/dist/artifacts/cli.js.map +1 -1
  13. package/dist/automations/coordinator.d.ts +7 -0
  14. package/dist/automations/coordinator.js +22 -2
  15. package/dist/automations/coordinator.js.map +1 -1
  16. package/dist/automations/github-poller.d.ts +4 -4
  17. package/dist/automations/github-poller.js.map +1 -1
  18. package/dist/automations/schedule-runner.d.ts +130 -0
  19. package/dist/automations/schedule-runner.js +326 -0
  20. package/dist/automations/schedule-runner.js.map +1 -0
  21. package/dist/automations/scheduler.d.ts +38 -7
  22. package/dist/automations/scheduler.js +90 -22
  23. package/dist/automations/scheduler.js.map +1 -1
  24. package/dist/automations/store.d.ts +80 -3
  25. package/dist/automations/store.js +208 -16
  26. package/dist/automations/store.js.map +1 -1
  27. package/dist/automations/task-template.d.ts +42 -6
  28. package/dist/automations/task-template.js +152 -24
  29. package/dist/automations/task-template.js.map +1 -1
  30. package/dist/automations/types.d.ts +142 -6
  31. package/dist/automations/types.js +64 -6
  32. package/dist/automations/types.js.map +1 -1
  33. package/dist/autosave-holders.js +8 -12
  34. package/dist/autosave-holders.js.map +1 -1
  35. package/dist/ci-wait/client.d.ts +8 -1
  36. package/dist/ci-wait/client.js +43 -1
  37. package/dist/ci-wait/client.js.map +1 -1
  38. package/dist/ci-wait/controller.d.ts +83 -4
  39. package/dist/ci-wait/controller.js +76 -11
  40. package/dist/ci-wait/controller.js.map +1 -1
  41. package/dist/ci-wait/errors.d.ts +7 -1
  42. package/dist/ci-wait/errors.js +36 -0
  43. package/dist/ci-wait/errors.js.map +1 -1
  44. package/dist/ci-wait/github.d.ts +2 -0
  45. package/dist/ci-wait/github.js +3 -1
  46. package/dist/ci-wait/github.js.map +1 -1
  47. package/dist/ci-wait/mcp.d.ts +2 -98
  48. package/dist/ci-wait/mcp.js +11 -25
  49. package/dist/ci-wait/mcp.js.map +1 -1
  50. package/dist/ci-wait/supervisor.d.ts +2 -1
  51. package/dist/ci-wait/supervisor.js +2 -1
  52. package/dist/ci-wait/supervisor.js.map +1 -1
  53. package/dist/ci-wait/tools.d.ts +307 -0
  54. package/dist/ci-wait/tools.js +63 -0
  55. package/dist/ci-wait/tools.js.map +1 -0
  56. package/dist/config.d.ts +3 -0
  57. package/dist/config.js +7 -0
  58. package/dist/config.js.map +1 -1
  59. package/dist/contract/agent-config.d.ts +5 -0
  60. package/dist/contract/agent-profiles.d.ts +15 -0
  61. package/dist/contract/automation-schedule.d.ts +60 -0
  62. package/dist/contract/automations.d.ts +208 -36
  63. package/dist/contract/delegation.d.ts +96 -0
  64. package/dist/contract/discovery.d.ts +7 -0
  65. package/dist/contract/github.d.ts +1 -0
  66. package/dist/contract/health.d.ts +6 -0
  67. package/dist/contract/index.d.ts +3 -0
  68. package/dist/contract/index.js +1445 -745
  69. package/dist/contract/preview.d.ts +508 -0
  70. package/dist/contract/runs.d.ts +716 -15
  71. package/dist/contract/skills.d.ts +39 -0
  72. package/dist/contract/workflows.d.ts +6 -0
  73. package/dist/contract/workspace.d.ts +65 -0
  74. package/dist/contract/zoned-time.d.ts +35 -0
  75. package/dist/core/agent-env.d.ts +11 -0
  76. package/dist/core/agent-env.js +27 -5
  77. package/dist/core/agent-env.js.map +1 -1
  78. package/dist/core/agent-profiles.js +7 -0
  79. package/dist/core/agent-profiles.js.map +1 -1
  80. package/dist/core/agent-runner.d.ts +49 -1
  81. package/dist/core/agent-runner.js +2 -1
  82. package/dist/core/agent-runner.js.map +1 -1
  83. package/dist/core/backend-detect.d.ts +3 -2
  84. package/dist/core/backend-detect.js +27 -1
  85. package/dist/core/backend-detect.js.map +1 -1
  86. package/dist/core/claude-cli-runner.d.ts +1 -0
  87. package/dist/core/claude-cli-runner.js +69 -19
  88. package/dist/core/claude-cli-runner.js.map +1 -1
  89. package/dist/core/codex-app-server-runner.d.ts +1 -0
  90. package/dist/core/codex-app-server-runner.js +200 -25
  91. package/dist/core/codex-app-server-runner.js.map +1 -1
  92. package/dist/core/codex-app-server-transport.d.ts +7 -3
  93. package/dist/core/codex-app-server-transport.js +11 -9
  94. package/dist/core/codex-app-server-transport.js.map +1 -1
  95. package/dist/core/cursor-acp-runner.d.ts +1 -0
  96. package/dist/core/cursor-acp-runner.js +24 -9
  97. package/dist/core/cursor-acp-runner.js.map +1 -1
  98. package/dist/core/host-model-catalog.js +2 -0
  99. package/dist/core/host-model-catalog.js.map +1 -1
  100. package/dist/core/managed-session.js +2 -0
  101. package/dist/core/managed-session.js.map +1 -1
  102. package/dist/core/model-identity.js +2 -0
  103. package/dist/core/model-identity.js.map +1 -1
  104. package/dist/core/model-presets.js +3 -0
  105. package/dist/core/model-presets.js.map +1 -1
  106. package/dist/core/omp-model-catalog.d.ts +43 -0
  107. package/dist/core/omp-model-catalog.js +205 -0
  108. package/dist/core/omp-model-catalog.js.map +1 -0
  109. package/dist/core/omp-runner.d.ts +73 -0
  110. package/dist/core/omp-runner.js +990 -0
  111. package/dist/core/omp-runner.js.map +1 -0
  112. package/dist/core/omp-ui-mapper.d.ts +106 -0
  113. package/dist/core/omp-ui-mapper.js +882 -0
  114. package/dist/core/omp-ui-mapper.js.map +1 -0
  115. package/dist/core/opencode-server-runner.d.ts +18 -4
  116. package/dist/core/opencode-server-runner.js +337 -96
  117. package/dist/core/opencode-server-runner.js.map +1 -1
  118. package/dist/core/opencode-session-error.d.ts +11 -0
  119. package/dist/core/opencode-session-error.js +26 -0
  120. package/dist/core/opencode-session-error.js.map +1 -0
  121. package/dist/core/opencode-ui-mapper.js +4 -36
  122. package/dist/core/opencode-ui-mapper.js.map +1 -1
  123. package/dist/core/pi-runner.d.ts +1 -0
  124. package/dist/core/pi-runner.js +75 -12
  125. package/dist/core/pi-runner.js.map +1 -1
  126. package/dist/core/provider-auth.d.ts +9 -2
  127. package/dist/core/provider-auth.js +43 -6
  128. package/dist/core/provider-auth.js.map +1 -1
  129. package/dist/core/runner-factory.js +3 -0
  130. package/dist/core/runner-factory.js.map +1 -1
  131. package/dist/core/runner-model-catalog.js +1 -0
  132. package/dist/core/runner-model-catalog.js.map +1 -1
  133. package/dist/core/runner-stderr.d.ts +2 -0
  134. package/dist/core/runner-stderr.js +20 -0
  135. package/dist/core/runner-stderr.js.map +1 -0
  136. package/dist/core/session-process.d.ts +22 -0
  137. package/dist/core/session-process.js +202 -0
  138. package/dist/core/session-process.js.map +1 -0
  139. package/dist/core/ui-events.d.ts +1 -1
  140. package/dist/core/usage-limit.js +3 -60
  141. package/dist/core/usage-limit.js.map +1 -1
  142. package/dist/data-gitignore.d.ts +6 -0
  143. package/dist/data-gitignore.js +57 -0
  144. package/dist/data-gitignore.js.map +1 -0
  145. package/dist/delegation/capacity.d.ts +19 -0
  146. package/dist/delegation/capacity.js +34 -0
  147. package/dist/delegation/capacity.js.map +1 -0
  148. package/dist/delegation/cli.js +13 -4
  149. package/dist/delegation/cli.js.map +1 -1
  150. package/dist/delegation/conversations.d.ts +4 -2
  151. package/dist/delegation/conversations.js +8 -12
  152. package/dist/delegation/conversations.js.map +1 -1
  153. package/dist/delegation/credentials.d.ts +2 -0
  154. package/dist/delegation/credentials.js +10 -0
  155. package/dist/delegation/credentials.js.map +1 -1
  156. package/dist/delegation/destroy-observation.d.ts +42 -0
  157. package/dist/delegation/destroy-observation.js +115 -0
  158. package/dist/delegation/destroy-observation.js.map +1 -0
  159. package/dist/delegation/execution-identity.d.ts +6 -0
  160. package/dist/delegation/execution-identity.js +1 -1
  161. package/dist/delegation/execution-identity.js.map +1 -1
  162. package/dist/delegation/policy.d.ts +3 -2
  163. package/dist/delegation/policy.js +7 -5
  164. package/dist/delegation/policy.js.map +1 -1
  165. package/dist/delegation/process-liveness.d.ts +57 -20
  166. package/dist/delegation/process-liveness.js +114 -92
  167. package/dist/delegation/process-liveness.js.map +1 -1
  168. package/dist/delegation/provision.js +6 -6
  169. package/dist/delegation/provision.js.map +1 -1
  170. package/dist/delegation/results.js +4 -2
  171. package/dist/delegation/results.js.map +1 -1
  172. package/dist/delegation/retry-backoff.d.ts +23 -0
  173. package/dist/delegation/retry-backoff.js +18 -0
  174. package/dist/delegation/retry-backoff.js.map +1 -0
  175. package/dist/delegation/routes.d.ts +64 -58
  176. package/dist/delegation/scratch-cleanup.d.ts +29 -0
  177. package/dist/delegation/scratch-cleanup.js +143 -0
  178. package/dist/delegation/scratch-cleanup.js.map +1 -0
  179. package/dist/delegation/service.d.ts +20 -1
  180. package/dist/delegation/service.js +233 -70
  181. package/dist/delegation/service.js.map +1 -1
  182. package/dist/delegation/transport.d.ts +12 -6
  183. package/dist/delegation/workspace.d.ts +23 -4
  184. package/dist/delegation/workspace.js +147 -31
  185. package/dist/delegation/workspace.js.map +1 -1
  186. package/dist/git-worktree-lock-helper.js +8 -3
  187. package/dist/git-worktree-lock-helper.js.map +1 -1
  188. package/dist/git-worktree-lock.d.ts +6 -1
  189. package/dist/git-worktree-lock.js +10 -4
  190. package/dist/git-worktree-lock.js.map +1 -1
  191. package/dist/git-worktree-release.d.ts +20 -0
  192. package/dist/git-worktree-release.js +27 -0
  193. package/dist/git-worktree-release.js.map +1 -0
  194. package/dist/git-worktree.d.ts +8 -2
  195. package/dist/git-worktree.js +19 -2
  196. package/dist/git-worktree.js.map +1 -1
  197. package/dist/handoff.d.ts +2 -2
  198. package/dist/handoff.js +1 -1
  199. package/dist/index.js +109 -76
  200. package/dist/index.js.map +1 -1
  201. package/dist/paths.d.ts +1 -1
  202. package/dist/paths.js +5 -1
  203. package/dist/paths.js.map +1 -1
  204. package/dist/preview/cdp.d.ts +13 -0
  205. package/dist/preview/cdp.js +69 -0
  206. package/dist/preview/cdp.js.map +1 -0
  207. package/dist/preview/chromium.d.ts +75 -0
  208. package/dist/preview/chromium.js +394 -0
  209. package/dist/preview/chromium.js.map +1 -0
  210. package/dist/preview/dev-server.d.ts +68 -0
  211. package/dist/preview/dev-server.js +341 -0
  212. package/dist/preview/dev-server.js.map +1 -0
  213. package/dist/preview/host.d.ts +154 -0
  214. package/dist/preview/host.js +681 -0
  215. package/dist/preview/host.js.map +1 -0
  216. package/dist/preview/registration.d.ts +63 -0
  217. package/dist/preview/registration.js +109 -0
  218. package/dist/preview/registration.js.map +1 -0
  219. package/dist/preview/session.d.ts +73 -0
  220. package/dist/preview/session.js +347 -0
  221. package/dist/preview/session.js.map +1 -0
  222. package/dist/preview/url.d.ts +6 -0
  223. package/dist/preview/url.js +17 -0
  224. package/dist/preview/url.js.map +1 -0
  225. package/dist/runs/agent-tmpdir-removal.d.ts +15 -0
  226. package/dist/runs/agent-tmpdir-removal.js +60 -0
  227. package/dist/runs/agent-tmpdir-removal.js.map +1 -0
  228. package/dist/runs/agent-tmpdir.d.ts +12 -1
  229. package/dist/runs/agent-tmpdir.js +123 -34
  230. package/dist/runs/agent-tmpdir.js.map +1 -1
  231. package/dist/runs/delegation-state.d.ts +5 -1
  232. package/dist/runs/delegation-state.js +9 -0
  233. package/dist/runs/delegation-state.js.map +1 -1
  234. package/dist/runs/event-history.d.ts +4 -4
  235. package/dist/runs/event-history.js +97 -117
  236. package/dist/runs/event-history.js.map +1 -1
  237. package/dist/runs/history-compressor.d.ts +29 -0
  238. package/dist/runs/history-compressor.js +116 -0
  239. package/dist/runs/history-compressor.js.map +1 -0
  240. package/dist/runs/history-file.d.ts +36 -0
  241. package/dist/runs/history-file.js +463 -0
  242. package/dist/runs/history-file.js.map +1 -0
  243. package/dist/runs/human-ask-summary.js +18 -13
  244. package/dist/runs/human-ask-summary.js.map +1 -1
  245. package/dist/runs/legacy-index.d.ts +62 -0
  246. package/dist/runs/legacy-index.js +168 -0
  247. package/dist/runs/legacy-index.js.map +1 -0
  248. package/dist/runs/raw-record.d.ts +52 -0
  249. package/dist/runs/raw-record.js +145 -0
  250. package/dist/runs/raw-record.js.map +1 -0
  251. package/dist/runs/retention.d.ts +13 -6
  252. package/dist/runs/retention.js +42 -13
  253. package/dist/runs/retention.js.map +1 -1
  254. package/dist/runs/run-claims.d.ts +23 -0
  255. package/dist/runs/run-claims.js +24 -0
  256. package/dist/runs/run-claims.js.map +1 -0
  257. package/dist/runs/run-database.d.ts +385 -0
  258. package/dist/runs/run-database.js +930 -0
  259. package/dist/runs/run-database.js.map +1 -0
  260. package/dist/runs/run-index.d.ts +35 -9
  261. package/dist/runs/run-index.js +200 -25
  262. package/dist/runs/run-index.js.map +1 -1
  263. package/dist/runs/run-row.d.ts +44 -0
  264. package/dist/runs/run-row.js +84 -0
  265. package/dist/runs/run-row.js.map +1 -0
  266. package/dist/runs/run-search.d.ts +29 -0
  267. package/dist/runs/run-search.js +63 -0
  268. package/dist/runs/run-search.js.map +1 -0
  269. package/dist/runs/store-open-error.d.ts +24 -0
  270. package/dist/runs/store-open-error.js +61 -0
  271. package/dist/runs/store-open-error.js.map +1 -0
  272. package/dist/runs/store.d.ts +667 -32
  273. package/dist/runs/store.js +2153 -324
  274. package/dist/runs/store.js.map +1 -1
  275. package/dist/runs/transcript-facts.d.ts +77 -0
  276. package/dist/runs/transcript-facts.js +302 -0
  277. package/dist/runs/transcript-facts.js.map +1 -0
  278. package/dist/runs/webhook.js +5 -4
  279. package/dist/runs/webhook.js.map +1 -1
  280. package/dist/runs/worker-execution.d.ts +22 -0
  281. package/dist/runs/worker-execution.js +30 -0
  282. package/dist/runs/worker-execution.js.map +1 -0
  283. package/dist/server/capabilities.d.ts +1 -0
  284. package/dist/server/capabilities.js +2 -0
  285. package/dist/server/capabilities.js.map +1 -1
  286. package/dist/server/cockpit-ownership.d.ts +8 -0
  287. package/dist/server/cockpit-ownership.js +19 -0
  288. package/dist/server/cockpit-ownership.js.map +1 -1
  289. package/dist/server/forge/github.d.ts +1 -4
  290. package/dist/server/forge/github.js +47 -23
  291. package/dist/server/forge/github.js.map +1 -1
  292. package/dist/server/git.js +1 -1
  293. package/dist/server/git.js.map +1 -1
  294. package/dist/server/open-in-app.js +1 -0
  295. package/dist/server/open-in-app.js.map +1 -1
  296. package/dist/server/preview-socket.d.ts +36 -0
  297. package/dist/server/preview-socket.js +126 -0
  298. package/dist/server/preview-socket.js.map +1 -0
  299. package/dist/server/project-context.d.ts +31 -4
  300. package/dist/server/project-context.js +73 -9
  301. package/dist/server/project-context.js.map +1 -1
  302. package/dist/server/provider-action-gate.js +1 -0
  303. package/dist/server/provider-action-gate.js.map +1 -1
  304. package/dist/server/repo-branches.d.ts +4 -3
  305. package/dist/server/repo-branches.js +5 -4
  306. package/dist/server/repo-branches.js.map +1 -1
  307. package/dist/server/server.d.ts +4500 -2727
  308. package/dist/server/server.js +651 -202
  309. package/dist/server/server.js.map +1 -1
  310. package/dist/server/upgrade-router.d.ts +23 -0
  311. package/dist/server/upgrade-router.js +53 -0
  312. package/dist/server/upgrade-router.js.map +1 -0
  313. package/dist/server/validators.d.ts +6 -1
  314. package/dist/server/validators.js +4 -4
  315. package/dist/server/validators.js.map +1 -1
  316. package/dist/server/ws.d.ts +16 -16
  317. package/dist/server/ws.js +56 -54
  318. package/dist/server/ws.js.map +1 -1
  319. package/dist/skills-remote.d.ts +14 -0
  320. package/dist/skills-remote.js +91 -15
  321. package/dist/skills-remote.js.map +1 -1
  322. package/dist/task-cli/cli.js +40 -16
  323. package/dist/task-cli/cli.js.map +1 -1
  324. package/dist/task-cli/discovery.d.ts +4 -3
  325. package/dist/task-cli/discovery.js +4 -3
  326. package/dist/task-cli/discovery.js.map +1 -1
  327. package/dist/task-cli/http.d.ts +2 -0
  328. package/dist/task-cli/http.js +10 -4
  329. package/dist/task-cli/http.js.map +1 -1
  330. package/dist/task-cli/projections.d.ts +5 -2
  331. package/dist/task-cli/projections.js +13 -0
  332. package/dist/task-cli/projections.js.map +1 -1
  333. package/dist/task-cli/watch.d.ts +15 -2
  334. package/dist/task-cli/watch.js +31 -9
  335. package/dist/task-cli/watch.js.map +1 -1
  336. package/dist/ui-state.d.ts +4 -3
  337. package/dist/ui-state.js +8 -3
  338. package/dist/ui-state.js.map +1 -1
  339. package/dist/workflows/grouped-command.d.ts +31 -0
  340. package/dist/workflows/grouped-command.js +143 -0
  341. package/dist/workflows/grouped-command.js.map +1 -0
  342. package/dist/workflows/run.d.ts +223 -42
  343. package/dist/workflows/run.js +1316 -398
  344. package/dist/workflows/run.js.map +1 -1
  345. package/dist/workflows/types.d.ts +12 -0
  346. package/dist/workflows/types.js +20 -0
  347. package/dist/workflows/types.js.map +1 -1
  348. package/dist/workspace/agent-accounts.d.ts +5 -1
  349. package/dist/workspace/agent-accounts.js +1 -0
  350. package/dist/workspace/agent-accounts.js.map +1 -1
  351. package/dist/workspace/agent-profiles.js +1 -1
  352. package/dist/workspace/agent-profiles.js.map +1 -1
  353. package/dist/workspace/config.d.ts +3 -1
  354. package/dist/workspace/config.js +1 -0
  355. package/dist/workspace/config.js.map +1 -1
  356. package/dist/worktree-setup.d.ts +85 -0
  357. package/dist/worktree-setup.js +164 -0
  358. package/dist/worktree-setup.js.map +1 -0
  359. package/package.json +7 -5
  360. package/scripts/benchmark-run-store-fixture.ts +428 -0
  361. package/scripts/benchmark-run-store.ts +743 -0
  362. package/scripts/benchmark-stuck-destroys.ts +143 -0
  363. package/scripts/mock-autonomous.mjs +11 -0
  364. package/scripts/mock-ci-tool.mjs +20 -5
  365. package/scripts/mock-claude.mjs +110 -1
  366. package/scripts/mock-codex-app-server.mjs +117 -2
  367. package/scripts/mock-codex-coalesce-steer.mjs +59 -0
  368. package/scripts/mock-codex-reverse-steer.mjs +130 -0
  369. package/scripts/mock-cursor-acp.mjs +75 -1
  370. package/scripts/mock-omp-rpc.mjs +605 -0
  371. package/scripts/mock-opencode-serve.mjs +312 -22
  372. package/scripts/mock-pi-rpc.mjs +109 -3
  373. package/scripts/mock-runner-crash.mjs +42 -0
  374. package/scripts/mock-silent-tail.mjs +78 -0
  375. package/scripts/mock-turn-messages.mjs +5 -0
  376. package/scripts/omp-ci-wait.mjs +29 -0
  377. package/scripts/omp-restrict-delegation.yml +4 -0
  378. package/scripts/pi-ci-wait.mjs +12 -9
  379. package/scripts/seed-archive-profile.ts +3 -3
  380. package/web/dist/assets/agent-accounts-CFOBMVHc.js +1 -0
  381. package/web/dist/assets/alert-dialog-BrpNUwMt.js +1 -0
  382. package/web/dist/assets/app-window-CSHwDX9N.js +1 -0
  383. package/web/dist/assets/button-C_rd7CPp.js +43 -0
  384. package/web/dist/assets/compare-variants-D6WXhvXA.js +1 -0
  385. package/web/dist/assets/diff-DrEARXTV.js +3 -0
  386. package/web/dist/assets/diff-controls-B1-j7nFg.js +1 -0
  387. package/web/dist/assets/{diff-view-DPn6bQ5W.js → diff-view-DvGLjdTk.js} +3 -3
  388. package/web/dist/assets/dropdown-menu-BegOZFrj.js +1 -0
  389. package/web/dist/assets/format-DpNe3S0A.js +1 -0
  390. package/web/dist/assets/git-toolbar-Cw4ljmhB.js +1 -0
  391. package/web/dist/assets/github-CfV5sqL0.js +1 -0
  392. package/web/dist/assets/{image-preview-DJ8cgb1Z.js → image-preview-FOEfqpZP.js} +1 -1
  393. package/web/dist/assets/index-DgWWlOLy.js +13 -0
  394. package/web/dist/assets/index-fBFnuvxu.css +1 -0
  395. package/web/dist/assets/{nav-row-styles-3j64kH5s.js → nav-row-styles-vp2JbhuJ.js} +1 -1
  396. package/web/dist/assets/play-CmVAj_fu.js +1 -0
  397. package/web/dist/assets/popover-BohP6WTx.js +1 -0
  398. package/web/dist/assets/preview-pane-connected-qTA5KNoJ.js +3 -0
  399. package/web/dist/assets/preview-state-vuMviq6q.js +1 -0
  400. package/web/dist/assets/prompt-templates-Cubdut_C.js +15 -0
  401. package/web/dist/assets/repo-git-Cf4t5PD0.js +1 -0
  402. package/web/dist/assets/{run-diff-5-RRdcVz.js → run-diff-BpkUW37Z.js} +3 -3
  403. package/web/dist/assets/run-header-68WHf9wV.js +1 -0
  404. package/web/dist/assets/skills-DiVIgKeU.js +1 -0
  405. package/web/dist/assets/square-terminal-B6RYYieR.js +1 -0
  406. package/web/dist/assets/status-dot-CqTJHSP9.js +1 -0
  407. package/web/dist/assets/{tab-link-K0hjzEXR.js → tab-link-B07Hu4QX.js} +1 -1
  408. package/web/dist/assets/task-changes--lQF6EYf.js +1 -0
  409. package/web/dist/assets/task-commits-Cx0qy4DN.js +1 -0
  410. package/web/dist/assets/task-files-D50s-gKW.js +2 -0
  411. package/web/dist/assets/task-github-item-DaqmSwYT.js +1 -0
  412. package/web/dist/assets/task-thread-BPQ64lui.js +7 -0
  413. package/web/dist/assets/{task-thread-Bw_nQuTx.css → task-thread-zNE2Q9E-.css} +1 -1
  414. package/web/dist/assets/textarea-D20O4Pw0.js +1 -0
  415. package/web/dist/assets/thread-state-DWcFMrvb.js +4 -0
  416. package/web/dist/assets/use-hand-to-agent-state-BLIGmwbd.css +1 -0
  417. package/web/dist/assets/use-hand-to-agent-state-Cy9eyyfL.js +1 -0
  418. package/web/dist/assets/{utils-fzNfbPzA.js → utils-JsL3ZsJf.js} +1 -1
  419. package/web/dist/assets/workflows-jwG7uxqi.js +11 -0
  420. package/web/dist/assets/{zoomable-image-CDmZ_Rtl.js → zoomable-image-BJJ64KGc.js} +1 -1
  421. package/web/dist/cezarion-lockup-dark.svg +1 -13
  422. package/web/dist/cezarion-lockup-light.svg +1 -13
  423. package/web/dist/cezarion-mark-dark.svg +1 -12
  424. package/web/dist/cezarion-mark-light.svg +1 -12
  425. package/web/dist/index.html +16 -21
  426. package/web/dist/assets/agent-accounts-CU2ZDv24.js +0 -1
  427. package/web/dist/assets/alert-dialog-C-xYE_dg.js +0 -43
  428. package/web/dist/assets/chevron-right-BENZ-1ZN.js +0 -1
  429. package/web/dist/assets/collapsible-DD9J91Iv.js +0 -1
  430. package/web/dist/assets/compare-variants-5FmqpFSN.js +0 -1
  431. package/web/dist/assets/diff-controls-Bj0YrioE.js +0 -1
  432. package/web/dist/assets/diff-rE8rm75J2.js +0 -3
  433. package/web/dist/assets/diff-stat-BKDCSVfJ.js +0 -1
  434. package/web/dist/assets/dropdown-menu-Ch5BYQh_.js +0 -1
  435. package/web/dist/assets/format-dBiNDNVe.js +0 -1
  436. package/web/dist/assets/git-toolbar-ClVvf5iF.js +0 -1
  437. package/web/dist/assets/github-BkNOyour.css +0 -1
  438. package/web/dist/assets/github-DeZMeMwJ.js +0 -1
  439. package/web/dist/assets/github-item-detail-W5F6GVjF.js +0 -1
  440. package/web/dist/assets/github-sidebar-model-DcMu-IK2.js +0 -1
  441. package/web/dist/assets/highlighter-CdHqIwFr.js +0 -3
  442. package/web/dist/assets/index-CatemBEL.js +0 -8
  443. package/web/dist/assets/index-MvfD8bZJ.css +0 -1
  444. package/web/dist/assets/markdown-zdKeLIYA.js +0 -2
  445. package/web/dist/assets/mobile-run-bar-BCfmFi8V.js +0 -1
  446. package/web/dist/assets/prompt-templates-CBPp39IU.js +0 -15
  447. package/web/dist/assets/reference-chip-D6owncJT.js +0 -1
  448. package/web/dist/assets/repo-git-CtdkZFey.js +0 -1
  449. package/web/dist/assets/run-header-BcjoDi0W.js +0 -1
  450. package/web/dist/assets/sheet-ChnYVrp1.js +0 -1
  451. package/web/dist/assets/skills-C8YKp2vr.js +0 -1
  452. package/web/dist/assets/task-changes-BW8YdWG8.js +0 -1
  453. package/web/dist/assets/task-commits-q2kB2y6L.js +0 -1
  454. package/web/dist/assets/task-files-pPL6_3Cr.js +0 -2
  455. package/web/dist/assets/task-github-item-BXF5R52U.js +0 -1
  456. package/web/dist/assets/task-thread-DtkFL3EC.js +0 -10
  457. package/web/dist/assets/textarea-DxlkE-Yd.js +0 -1
  458. package/web/dist/assets/token-metrics-DIAjrPlM.js +0 -1
  459. package/web/dist/assets/use-desktop-CrDny2uG.js +0 -1
  460. package/web/dist/assets/use-submit-shortcut-KWJsC906.js +0 -1
  461. package/web/dist/assets/workflows-TmcPEj2K.js +0 -11
  462. /package/web/dist/assets/{lib-BQXq3kEf2.js → lib-BQXq3kEf.js} +0 -0
@@ -14,6 +14,13 @@ function watchdogStall(prompt) {
14
14
  if (prompt.includes('held-pipe')) {
15
15
  watchdogSpawn(process.execPath, ['-e', 'setTimeout(() => {}, 5000)'], { stdio: ['ignore', process.stdout, process.stderr] });
16
16
  }
17
+ if (prompt.includes('leftover')) {
18
+ // hearsay-tools/cezarion#890: one child stays in the session's process group and ignores
19
+ // 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)`;
21
+ watchdogSpawn(process.execPath, ['-e', leftover('leftover-group.pid')], { stdio: 'ignore' });
22
+ watchdogSpawn(process.execPath, ['-e', leftover('leftover-session.pid')], { stdio: 'ignore', detached: true }).unref();
23
+ }
17
24
  return true;
18
25
  }
19
26
 
@@ -24,8 +31,30 @@ function watchdogStall(prompt) {
24
31
  // response resolves immediately — every part and the closing `session.idle`
25
32
  // arrive over SSE afterwards, so a correct stream (v1 and v2 alike) must
26
33
  // take its turn-end from `session.idle`, never from the HTTP response.
27
- import { appendFileSync } from 'node:fs';
34
+ import { createHash } from 'node:crypto';
35
+ // Aliased: owned-input-delivery.testkit.ts prepends its own `existsSync`/`writeFileSync` import,
36
+ // and a second import of the same name is a SyntaxError.
37
+ import { appendFileSync, existsSync as sessionStoreExists, mkdirSync, readFileSync, writeFileSync as sessionStoreWrite } from 'node:fs';
28
38
  import { createServer } from 'node:http';
39
+ import { tmpdir } from 'node:os';
40
+ import { dirname, join } from 'node:path';
41
+
42
+ // #872: the first N starts die before listening, the way opencode 1.18.33 did
43
+ // when started within ~2 s of SIGTERM to the previous server on the same DB.
44
+ // Starts are counted across processes in a file, so start N+1 listens normally.
45
+ const failStarts = Number(process.env.CEZ_MOCK_OPENCODE_SERVE_FAIL_STARTS ?? 0);
46
+ if (failStarts > 0) {
47
+ const counter = process.env.CEZ_MOCK_OPENCODE_SERVE_FAIL_FILE
48
+ || (process.env.CEZ_MOCK_ARGS_FILE ? `${process.env.CEZ_MOCK_ARGS_FILE}.opencode-serve-starts`
49
+ : join(tmpdir(), `cez-mock-opencode-serve-starts-${createHash('sha256').update(process.cwd()).digest('hex')}`));
50
+ const start = (sessionStoreExists(counter) ? Number(readFileSync(counter, 'utf8')) || 0 : 0) + 1;
51
+ sessionStoreWrite(counter, String(start));
52
+ if (start <= failStarts) {
53
+ // Pipe writes to stderr are synchronous on POSIX, so exiting right away loses nothing.
54
+ process.stderr.write(`Error: Unexpected error (start ${start})\nServeError\n`);
55
+ process.exit(1);
56
+ }
57
+ }
29
58
 
30
59
  if (process.env.CEZ_MOCK_ARGS_FILE && process.env.OPENCODE_CONFIG_CONTENT) appendFileSync(process.env.CEZ_MOCK_ARGS_FILE, JSON.stringify({ type: 'runtime-config', config: JSON.parse(process.env.OPENCODE_CONFIG_CONTENT) }) + '\n');
31
60
  if (process.env.CEZ_MOCK_CI_PR) { const { probeCiTool } = await import('./mock-ci-tool.mjs'); await probeCiTool('opencode', JSON.parse(process.env.OPENCODE_CONFIG_CONTENT ?? '{}')); }
@@ -37,6 +66,15 @@ async function afterParityPark(prompt) {
37
66
  if (!gate) throw new Error('post-park scenario requires a release path');
38
67
  while (!parityGateFs.existsSync(gate)) await new Promise(resolve => setTimeout(resolve, 10));
39
68
  }
69
+ async function waitForMockRelease(fallbackMs) {
70
+ const file = process.env.CEZ_MOCK_RELEASE_FILE;
71
+ if (!file) { if (fallbackMs) await new Promise(r => setTimeout(r, fallbackMs)); return; }
72
+ const deadline = Date.now() + 15_000;
73
+ while (!parityGateFs.existsSync(file)) {
74
+ if (Date.now() > deadline) throw new Error('CEZ_MOCK_RELEASE_FILE was not created');
75
+ await new Promise(r => setTimeout(r, 10));
76
+ }
77
+ }
40
78
 
41
79
  const args = process.argv.slice(2);
42
80
  const arg = (flag, fallback) => {
@@ -45,9 +83,81 @@ const arg = (flag, fallback) => {
45
83
  };
46
84
  const hostname = arg('--hostname', '127.0.0.1');
47
85
 
48
- const SESSION_ID = 'ses_mock_1';
86
+ const DEFAULT_SESSION_ID = 'ses_mock_1';
87
+ let SESSION_ID = DEFAULT_SESSION_ID;
49
88
  const MESSAGE_ID = 'msg_mock_1';
50
89
 
90
+ function sessionStorePath() {
91
+ if (process.env.CEZ_MOCK_OPENCODE_SESSIONS_FILE) return process.env.CEZ_MOCK_OPENCODE_SESSIONS_FILE;
92
+ // Keyed on the args file, not its directory: spec-support probes and D1 share a
93
+ // cwd and would otherwise increment ses_mock_N across unrelated launches.
94
+ if (process.env.CEZ_MOCK_ARGS_FILE) return `${process.env.CEZ_MOCK_ARGS_FILE}.opencode-sessions.json`;
95
+ // Dry-run Continue (no args file) must resume in the same worktree: persist by cwd.
96
+ const key = createHash('sha256').update(process.cwd()).digest('hex');
97
+ return join(tmpdir(), `cez-mock-opencode-sessions-${key}.json`);
98
+ }
99
+ function emptySessionStore() {
100
+ return { seq: 0, sessions: {} };
101
+ }
102
+ function readPersistedSessionStore() {
103
+ const path = sessionStorePath();
104
+ if (!path || !sessionStoreExists(path)) return null;
105
+ try {
106
+ const parsed = JSON.parse(readFileSync(path, 'utf8'));
107
+ if (parsed && typeof parsed === 'object' && parsed.sessions && typeof parsed.sessions === 'object') return parsed;
108
+ } catch {
109
+ // A corrupt store is treated as missing so a later POST can mint a session.
110
+ }
111
+ return null;
112
+ }
113
+ let memorySessionStore = readPersistedSessionStore() ?? emptySessionStore();
114
+ function loadSessionStore() {
115
+ return readPersistedSessionStore() ?? memorySessionStore;
116
+ }
117
+ function saveSessionStore(store) {
118
+ memorySessionStore = store;
119
+ const path = sessionStorePath();
120
+ if (!path) return;
121
+ mkdirSync(dirname(path), { recursive: true });
122
+ sessionStoreWrite(path, JSON.stringify(store));
123
+ }
124
+ function getSession(id) {
125
+ return loadSessionStore().sessions[id] ?? null;
126
+ }
127
+ function createSession(body = {}) {
128
+ const store = loadSessionStore();
129
+ store.seq += 1;
130
+ const id = store.seq === 1 ? DEFAULT_SESSION_ID : `ses_mock_${store.seq}`;
131
+ store.sessions[id] = {
132
+ id,
133
+ title: typeof body.title === 'string' ? body.title : 'cezar task',
134
+ prompts: [],
135
+ ...(Array.isArray(body.permission) ? { permission: [...body.permission] } : {}),
136
+ };
137
+ saveSessionStore(store);
138
+ return id;
139
+ }
140
+ function addPrompt(id, text) {
141
+ const store = loadSessionStore();
142
+ if (!store.sessions[id]) return;
143
+ store.sessions[id].prompts = [...(store.sessions[id].prompts ?? []), text];
144
+ saveSessionStore(store);
145
+ }
146
+ function patchSession(id, body) {
147
+ const store = loadSessionStore();
148
+ if (!store.sessions[id]) return null;
149
+ // OpenCode 1.18.33: PATCH permission APPENDS (no replace, no dedupe); a
150
+ // title-only PATCH leaves permission alone.
151
+ const next = { ...store.sessions[id], ...body, id };
152
+ if (Array.isArray(body.permission)) {
153
+ const existing = Array.isArray(store.sessions[id].permission) ? store.sessions[id].permission : [];
154
+ next.permission = [...existing, ...body.permission];
155
+ }
156
+ store.sessions[id] = next;
157
+ saveSessionStore(store);
158
+ return store.sessions[id];
159
+ }
160
+
51
161
  let sse = null;
52
162
  const write = (event) => {
53
163
  if (sse) sse.write(`data: ${JSON.stringify(event)}\n\n`);
@@ -117,6 +227,9 @@ const info = (extra) => ({
117
227
  ...extra,
118
228
  });
119
229
 
230
+ let autonomousTurn = 0;
231
+ let autonomousCap = false;
232
+ let autonomousReadinessIdle = false;
120
233
  const server = createServer((req, res) => {
121
234
  const url = req.url ?? '';
122
235
  if (req.method === 'GET' && url === '/question') {
@@ -151,15 +264,63 @@ const server = createServer((req, res) => {
151
264
  else acknowledge();
152
265
  return;
153
266
  }
267
+ const sessionGet = req.method === 'GET' && /^\/session\/([^/]+)$/.exec(url);
268
+ if (sessionGet) {
269
+ const session = getSession(sessionGet[1]);
270
+ if (!session) {
271
+ res.writeHead(404, { 'content-type': 'application/json' });
272
+ res.end(JSON.stringify({ error: 'NotFoundError' }));
273
+ return;
274
+ }
275
+ res.writeHead(200, { 'content-type': 'application/json' });
276
+ res.end(JSON.stringify({
277
+ id: session.id,
278
+ title: session.title,
279
+ ...(Array.isArray(session.permission) ? { permission: session.permission } : {}),
280
+ }));
281
+ return;
282
+ }
283
+ const sessionPatch = req.method === 'PATCH' && /^\/session\/([^/]+)$/.exec(url);
284
+ if (sessionPatch) {
285
+ const session = patchSession(sessionPatch[1], body ? JSON.parse(body) : {});
286
+ if (!session) {
287
+ res.writeHead(404, { 'content-type': 'application/json' });
288
+ res.end(JSON.stringify({ error: 'NotFoundError' }));
289
+ return;
290
+ }
291
+ res.writeHead(200, { 'content-type': 'application/json' });
292
+ res.end(JSON.stringify({
293
+ id: session.id,
294
+ title: session.title,
295
+ ...(Array.isArray(session.permission) ? { permission: session.permission } : {}),
296
+ }));
297
+ return;
298
+ }
154
299
  if (req.method === 'POST' && url === '/session') {
300
+ const parsed = body ? JSON.parse(body) : {};
301
+ SESSION_ID = createSession(parsed);
155
302
  res.writeHead(200, { 'content-type': 'application/json' });
156
- res.end(JSON.stringify({ id: SESSION_ID, title: 'cezar task' }));
303
+ res.end(JSON.stringify({
304
+ id: SESSION_ID,
305
+ title: parsed.title ?? 'cezar task',
306
+ ...(Array.isArray(parsed.permission) ? { permission: parsed.permission } : {}),
307
+ }));
157
308
  return;
158
309
  }
159
- if (
160
- req.method === 'POST' &&
161
- (url === `/session/${SESSION_ID}/prompt_async` || url === `/session/${SESSION_ID}/message`)
162
- ) {
310
+ const sessionPrompt = req.method === 'POST' && /^\/session\/([^/]+)\/(prompt_async|message)$/.exec(url);
311
+ if (sessionPrompt && getSession(sessionPrompt[1])) {
312
+ SESSION_ID = sessionPrompt[1];
313
+ try {
314
+ const text = body ? JSON.parse(body).parts?.map(part => part.text ?? '').join('\n') ?? '' : '';
315
+ if (text) addPrompt(SESSION_ID, text);
316
+ } catch {
317
+ // Keep the scripted turn even when the body is not JSON.
318
+ }
319
+ if (body.includes('mock:crash-stderr-pre-ack')) {
320
+ const { crashWithStderr } = await import('./mock-runner-crash.mjs');
321
+ crashWithStderr(body);
322
+ return;
323
+ }
163
324
  if (body.includes('mock:reject-agent-post')) {
164
325
  res.writeHead(503, { 'content-type': 'application/json' });
165
326
  res.end(JSON.stringify({ error: 'agent prompt rejected' }));
@@ -180,13 +341,42 @@ const server = createServer((req, res) => {
180
341
  turnActive = true;
181
342
  // `prompt_async` semantics: acknowledge now, stream the turn over SSE.
182
343
  res.writeHead(200, { 'content-type': 'application/json' });
344
+ // #426: a nudged turn can finish on SSE before its HTTP acceptance arrives.
345
+ // Force that ordering in the cap scenario; the first opening stays ordinary.
346
+ if (autonomousReadinessIdle && body.includes('Continue working autonomously until the task is fully complete.')) {
347
+ // Keep the portable answer HTTP request unacknowledged while its SSE turn finishes.
348
+ } else if (autonomousCap && body.includes('Continue working autonomously until the task is fully complete.')) {
349
+ setTimeout(() => res.end(JSON.stringify({ info: info({}), parts: [] })), 100);
350
+ } else if (body.includes('f7-delay-ack')) {
351
+ // F7: SSE turn-end before HTTP ACK so parkAfterAck applies the silent-tail nudge.
352
+ setTimeout(() => res.end(JSON.stringify({ info: info({}), parts: [] })), 250);
353
+ } else {
183
354
  res.end(JSON.stringify({ info: info({}), parts: [] }));
355
+ }
356
+ if (body.includes('mock:autonomous-readiness-idle')) autonomousReadinessIdle = true;
357
+ if (body.includes('mock:autonomous-cap') || body.includes('mock:autonomous-ask-cap')) autonomousCap = true;
358
+ if (body.includes('mock:silent-tail') || body.includes('Your last turn ended without a message to the user.')) {
359
+ const silent = await import('./mock-silent-tail.mjs');
360
+ const prompt = (() => { try { return JSON.parse(body).parts.map(part => part.text ?? '').join('\n'); } catch { return body; } })();
361
+ silent.noteSilentTailPrompt(prompt);
362
+ if (silent.isAckOnlyNudge(prompt)) {
363
+ const beats = setInterval(() => { if (sse) sse.write(': heartbeat\n\n'); }, 50);
364
+ beats.unref?.();
365
+ return;
366
+ }
367
+ if (silent.isLateNudge(prompt)) await silent.sleep(silent.LATE_REPLY_MS);
368
+ }
184
369
  if (url.endsWith('/prompt_async')) {
185
370
  currentUserId = `msg_user_${++steerSerial}`;
186
371
  const text = JSON.parse(body).parts.map(part => part.text ?? '').join('\n');
187
372
  send({ type: 'message.updated', properties: { info: { id: currentUserId, sessionID: SESSION_ID, role: 'user', time: { created: Date.now() } } } });
188
373
  send({ type: 'message.part.updated', properties: { part: { id: `prt_${currentUserId}`, messageID: currentUserId, sessionID: SESSION_ID, type: 'text', text } } });
189
374
  }
375
+ if (body.includes('mock:crash-stderr')) {
376
+ const { crashWithStderr } = await import('./mock-runner-crash.mjs');
377
+ if (body.includes('mock:crash-stderr-clean')) crashWithStderr(body);
378
+ else { setTimeout(() => crashWithStderr(body), 30); return; }
379
+ }
190
380
  if (body.includes('mock:steer-tool')) {
191
381
  send({ type: 'message.updated', properties: { info: info({}) } });
192
382
  send({ type: 'message.part.updated', properties: { part: { id: 'prt_steer_tool', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'tool', callID: 'call_steer', tool: 'bash', state: { status: 'running', input: { command: 'wait' } } } } });
@@ -212,6 +402,15 @@ const server = createServer((req, res) => {
212
402
  send({ type: 'session.idle', properties: { sessionID: SESSION_ID } });
213
403
  return;
214
404
  }
405
+ if (body.includes('mock:turn-messages:')) {
406
+ const { turnMessages } = await import('./mock-turn-messages.mjs');
407
+ send({ type: 'message.updated', properties: { info: info({}) } });
408
+ for (const text of turnMessages(JSON.parse(body).parts.map(part => part.text ?? '').join('\n'))) {
409
+ send({ type: 'message.part.updated', properties: { part: { id: `prt_multi_${++echoSerial}`, messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'text', text, time: { start: 1, end: 2 } } } });
410
+ }
411
+ send({ type: 'session.idle', properties: { sessionID: SESSION_ID } });
412
+ return;
413
+ }
215
414
  if (body.includes('mock:agent-echo')) {
216
415
  send({ type: 'message.updated', properties: { info: info({}) } });
217
416
  send({ type: 'message.part.updated', properties: { part: {
@@ -288,6 +487,22 @@ const server = createServer((req, res) => {
288
487
  }, 60);
289
488
  return;
290
489
  }
490
+ // #723: native GET /skill diagnostic captured on 1.18.33; upstream
491
+ // packages/opencode/src/skill/index.ts:96-111 skips the unreadable skill.
492
+ if (body.includes('mock:skill-warning')) {
493
+ for (const root of ['.claude', '.agents']) send({ type: 'session.error', properties: {
494
+ error: { name: 'UnknownError', data: { message: `Failed to parse skill /home/agent/${root}/skills/pen-design/SKILL.md` } },
495
+ } });
496
+ }
497
+ if (body.includes('mock:unscoped-provider-failure') || body.includes('mock:scoped-skill-failure')) {
498
+ send({ type: 'session.error', properties: {
499
+ ...(body.includes('mock:scoped-skill-failure') ? { sessionID: SESSION_ID } : {}),
500
+ error: { name: 'UnknownError', data: { message: body.includes('mock:scoped-skill-failure')
501
+ ? 'Failed to parse skill /skills/required/SKILL.md' : 'provider unavailable — retry after restoring service' } },
502
+ } });
503
+ setTimeout(() => send({ type: 'session.idle', properties: { sessionID: SESSION_ID } }), 30);
504
+ return;
505
+ }
291
506
  if (body.includes('mock:provider-error-early')) {
292
507
  // #505 review: the provider rejects before any assistant message exists.
293
508
  send({ type: 'session.error', properties: { sessionID: SESSION_ID, error: { name: 'ProviderAuthError', data: { message: 'API key expired' } } } });
@@ -331,10 +546,53 @@ const server = createServer((req, res) => {
331
546
  setTimeout(() => send({ type: 'session.idle', properties: { sessionID: SESSION_ID } }), 30);
332
547
  return;
333
548
  }
549
+ if (body.includes('mock:autonomous') || body.includes('Continue working autonomously until the task is fully complete.')) {
550
+ const { autonomousReply } = await import('./mock-autonomous.mjs');
551
+ send({ type: 'message.updated', properties: { info: info({}) } });
552
+ send({ type: 'message.part.updated', properties: { part: { id: `autonomous-${++autonomousTurn}`, messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'text', text: autonomousReply(JSON.parse(body).parts.map(part => part.text ?? '').join('\n')), time: { start: 1, end: 2 } } } });
553
+ send({ type: 'session.idle', properties: { sessionID: SESSION_ID } });
554
+ return;
555
+ }
556
+ if (body.includes('mock:silent-tail') || body.includes('mock:tool-tail') || body.includes('Your last turn ended without a message to the user.')) {
557
+ const silent = await import('./mock-silent-tail.mjs');
558
+ const prompt = (() => { try { return JSON.parse(body).parts.map(part => part.text ?? '').join('\n'); } catch { return body; } })();
559
+ silent.noteSilentTailPrompt(prompt);
560
+ if (silent.isFinalMessageNudge(prompt)) {
561
+ const kind = silent.finalMessageNudgeKind();
562
+ send({ type: 'message.updated', properties: { info: info({}) } });
563
+ if (kind === 'silent') {
564
+ send({ type: 'message.part.updated', properties: { part: { id: 'silent-nudge-rsn', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'reasoning', text: silent.SILENT_TAIL_REASONING, time: { start: 1, end: 2 } } } });
565
+ } else {
566
+ if (kind === 'slow-done') {
567
+ send({ type: 'message.part.updated', properties: { part: { id: 'silent-nudge-prefix', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'text', text: silent.SLOW_DONE_PREFIX, time: { start: 1, end: 2 } } } });
568
+ await silent.sleep(silent.SLOW_DONE_TAIL_MS);
569
+ }
570
+ const text = kind === 'standing' ? silent.FINAL_MESSAGE_STANDING : silent.SILENT_TAIL_DONE;
571
+ send({ type: 'message.part.updated', properties: { part: { id: 'silent-nudge-done', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'text', text, time: { start: 1, end: 2 } } } });
572
+ }
573
+ send({ type: 'session.idle', properties: { sessionID: SESSION_ID } });
574
+ return;
575
+ }
576
+ if (silent.isSilentTailScenario(prompt)) {
577
+ send({ type: 'message.updated', properties: { info: info({}) } });
578
+ send({ type: 'message.part.updated', properties: { part: { id: 'silent-open', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'text', text: silent.SILENT_TAIL_OPENING, time: { start: 1, end: 2 } } } });
579
+ send({ type: 'message.part.updated', properties: { part: { id: 'silent-gh', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'tool', callID: 'call_silent_gh', tool: 'bash', state: { status: 'completed', input: { command: 'gh issue create' }, output: 'created', time: { start: 1, end: 2 } } } } });
580
+ send({ type: 'message.part.updated', properties: { part: { id: 'silent-rsn', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'reasoning', text: silent.SILENT_TAIL_REASONING, time: { start: 1, end: 2 } } } });
581
+ send({ type: 'session.idle', properties: { sessionID: SESSION_ID } });
582
+ return;
583
+ }
584
+ if (silent.isToolTailScenario(prompt)) {
585
+ send({ type: 'message.updated', properties: { info: info({}) } });
586
+ send({ type: 'message.part.updated', properties: { part: { id: 'tool-tail-open', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'text', text: silent.TOOL_TAIL_OPENING, time: { start: 1, end: 2 } } } });
587
+ send({ type: 'message.part.updated', properties: { part: { id: 'tool-tail-git', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'tool', callID: 'call_tool_tail', tool: 'bash', state: { status: 'completed', input: { command: 'git status --short' }, output: ' M src/example.ts', time: { start: 1, end: 2 } } } } });
588
+ send({ type: 'session.idle', properties: { sessionID: SESSION_ID } });
589
+ return;
590
+ }
591
+ }
334
592
  // #401: one completed text snapshot, without an earlier streaming part.
335
593
  if (body.includes('mock:ask-snapshot')) {
336
594
  send({ type: 'message.updated', properties: { info: info({}) } });
337
- send({ type: 'message.part.updated', properties: { part: { id: 'ask-snapshot', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'text', text: 'Using the CEZ:ASK structured question format instead:\n\nCEZ:ASK {"questions":[{"header":"Library","question":"Which test library?","options":[{"label":"Vitest"},{"label":"Node test"}]}]}', time: { start: 1, end: 2 } } } });
595
+ send({ type: 'message.part.updated', properties: { part: { id: 'ask-snapshot', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'text', text: body.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"}]}]}', time: { start: 1, end: 2 } } } });
338
596
  send({ type: 'session.idle', properties: { sessionID: SESSION_ID } });
339
597
  return;
340
598
  }
@@ -371,6 +629,22 @@ const server = createServer((req, res) => {
371
629
  }] });
372
630
  return;
373
631
  }
632
+ if (body.includes('mock:hold-done')) {
633
+ // Pause, then CEZ:DONE, so a mid-turn sendMessage can queue behind the
634
+ // running turn and race the close (#486).
635
+ await waitForMockRelease(400);
636
+ send({ type: 'message.updated', properties: { info: info({}) } });
637
+ send({ type: 'message.part.updated', properties: { part: {
638
+ id: 'prt_mock_hold_done', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'text',
639
+ text: 'parity hold-done: content after the pause\n\nCEZ:DONE',
640
+ time: { start: 1760000000500, end: 1760000000600 },
641
+ } } });
642
+ send({ type: 'message.updated', properties: { info: info({
643
+ cost: 0.0001, tokens: { input: 20, output: 10, reasoning: 0, cache: { read: 0, write: 0 } },
644
+ }) } });
645
+ setTimeout(() => send({ type: 'session.idle', properties: { sessionID: SESSION_ID } }), 30);
646
+ return;
647
+ }
374
648
  if (body.includes('mock:done')) {
375
649
  // Declares the task complete so the run reaches cezar's review gate; a
376
650
  // markerless turn-end correctly parks as `waiting` instead (harness
@@ -390,19 +664,18 @@ const server = createServer((req, res) => {
390
664
  if (body.includes('mock:hold-ask')) {
391
665
  // Portable CEZ:ASK after a pause, so a mid-turn sendMessage can queue
392
666
  // and then race the park (run.ts must discard that waiter).
393
- setTimeout(() => {
394
- const ask = 'Pick one.\n\nCEZ:ASK {"questions":[{"header":"Library","question":"Which date library should I standardize on?","options":[{"label":"date-fns","description":"Tree-shakeable, functional"},{"label":"Luxon","description":"Immutable, tz-aware"}]}]}';
395
- send({ type: 'message.updated', properties: { info: info({}) } });
396
- send({ type: 'message.part.updated', properties: { part: {
397
- id: 'prt_mock_hold_ask', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'text',
398
- text: ask,
399
- time: { start: 1760000000500, end: 1760000000600 },
400
- } } });
401
- send({ type: 'message.updated', properties: { info: info({
402
- cost: 0.0001, tokens: { input: 20, output: 10, reasoning: 0, cache: { read: 0, write: 0 } },
403
- }) } });
404
- setTimeout(() => send({ type: 'session.idle', properties: { sessionID: SESSION_ID } }), 30);
405
- }, 250);
667
+ await waitForMockRelease(250);
668
+ const ask = 'Pick one.\n\nCEZ:ASK {"questions":[{"header":"Library","question":"Which date library should I standardize on?","options":[{"label":"date-fns","description":"Tree-shakeable, functional"},{"label":"Luxon","description":"Immutable, tz-aware"}]}]}';
669
+ send({ type: 'message.updated', properties: { info: info({}) } });
670
+ send({ type: 'message.part.updated', properties: { part: {
671
+ id: 'prt_mock_hold_ask', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'text',
672
+ text: ask,
673
+ time: { start: 1760000000500, end: 1760000000600 },
674
+ } } });
675
+ send({ type: 'message.updated', properties: { info: info({
676
+ cost: 0.0001, tokens: { input: 20, output: 10, reasoning: 0, cache: { read: 0, write: 0 } },
677
+ }) } });
678
+ setTimeout(() => send({ type: 'session.idle', properties: { sessionID: SESSION_ID } }), 30);
406
679
  return;
407
680
  }
408
681
  if (watchdogStall(body)) return;
@@ -414,6 +687,19 @@ const server = createServer((req, res) => {
414
687
  }, 100);
415
688
  return;
416
689
  }
690
+ if (body.includes('mock:hold-gated')) {
691
+ await waitForMockRelease(250);
692
+ const gated = 'parity hold-gated: content after the pause';
693
+ send({ type: 'message.updated', properties: { info: info({}) } });
694
+ send({ type: 'message.part.updated', properties: { part: {
695
+ id: 'prt_mock_hold_gated', messageID: MESSAGE_ID, sessionID: SESSION_ID, type: 'text', text: gated,
696
+ } } });
697
+ send({ type: 'message.updated', properties: { info: info({
698
+ cost: 0.0001, tokens: { input: 20, output: 10, reasoning: 0, cache: { read: 0, write: 0 } },
699
+ }) } });
700
+ setTimeout(() => send({ type: 'session.idle', properties: { sessionID: SESSION_ID } }), 30);
701
+ return;
702
+ }
417
703
  if (body.includes('mock:hold')) {
418
704
  // The response above is the ack (this is the #4 wire: `prompt_async`
419
705
  // resolves immediately, the turn arrives over SSE afterwards). Holding
@@ -522,4 +808,8 @@ server.listen(0, hostname, () => {
522
808
  // The runner reads the bound URL back from stdout, like the real server.
523
809
  console.log(`opencode server listening on http://${hostname}:${server.address().port}`);
524
810
  });
525
- process.on('SIGTERM', () => process.exit(0));
811
+ process.on('SIGTERM', () => {
812
+ // Expose the end-request/process-exit interval to the root idle regression.
813
+ if (autonomousReadinessIdle) setTimeout(() => process.exit(0), 250);
814
+ else process.exit(0);
815
+ });
@@ -14,11 +14,28 @@ function watchdogStall(prompt) {
14
14
  if (prompt.includes('held-pipe')) {
15
15
  watchdogSpawn(process.execPath, ['-e', 'setTimeout(() => {}, 5000)'], { stdio: ['ignore', process.stdout, process.stderr] });
16
16
  }
17
+ if (prompt.includes('leftover')) {
18
+ // hearsay-tools/cezarion#890: one child stays in the session's process group and ignores
19
+ // 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)`;
21
+ watchdogSpawn(process.execPath, ['-e', leftover('leftover-group.pid')], { stdio: 'ignore' });
22
+ watchdogSpawn(process.execPath, ['-e', leftover('leftover-session.pid')], { stdio: 'ignore', detached: true }).unref();
23
+ }
17
24
  return true;
18
25
  }
19
26
 
20
27
  import readline from 'node:readline';
21
- import { appendFileSync } from 'node:fs';
28
+ import { appendFileSync, existsSync as mockReleaseExists } from 'node:fs';
29
+ const sleep = (ms) => new Promise(r => setTimeout(r, ms));
30
+ async function waitForMockRelease(fallbackMs) {
31
+ const file = process.env.CEZ_MOCK_RELEASE_FILE;
32
+ if (!file) { if (fallbackMs) await sleep(fallbackMs); return; }
33
+ const deadline = Date.now() + 15_000;
34
+ while (!mockReleaseExists(file)) {
35
+ if (Date.now() > deadline) throw new Error('CEZ_MOCK_RELEASE_FILE was not created');
36
+ await sleep(10);
37
+ }
38
+ }
22
39
  if (process.env.CEZ_MOCK_ARGS_FILE) appendFileSync(process.env.CEZ_MOCK_ARGS_FILE, `${JSON.stringify(process.argv.slice(2))}\n`);
23
40
 
24
41
  // Pi handles SIGTERM and reports 128 + signal, rather than a null exit code.
@@ -66,7 +83,6 @@ const send = (value) => {
66
83
  }
67
84
  write(value);
68
85
  };
69
- const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
70
86
 
71
87
  /** One valid CEZ:ASK payload (spec #473), used by the `mock:ask` scenario. */
72
88
  const ASK_MARKER_BODY = "{\"questions\":[{\"header\":\"Library\",\"question\":\"Which test library?\",\"multiSelect\":false,\"options\":[{\"label\":\"Vitest\",\"description\":\"Use the existing test runner\"},{\"label\":\"Node test\",\"description\":\"Use node:test\"}]}]}";
@@ -81,6 +97,13 @@ function sendText(deltas) {
81
97
  send({ type: 'message_update', message: {}, assistantMessageEvent: { type: 'text_end', contentIndex: 0, content, partial: {} } });
82
98
  }
83
99
 
100
+ /** Native thinking block — contentIndex 1 when a text block already occupied 0. */
101
+ function sendThinking(text, contentIndex = 0) {
102
+ send({ type: 'message_update', message: {}, assistantMessageEvent: { type: 'thinking_start', contentIndex, partial: {} } });
103
+ send({ type: 'message_update', message: {}, assistantMessageEvent: { type: 'thinking_delta', contentIndex, delta: text, partial: {} } });
104
+ send({ type: 'message_update', message: {}, assistantMessageEvent: { type: 'thinking_end', contentIndex, content: text, partial: {} } });
105
+ }
106
+
84
107
  /** The terminal quartet: usage-bearing message_end, then turn/agent settle. */
85
108
  function sendTurnEnd(usage = { input: 10, output: 5, cacheRead: 0, cacheWrite: 0, cost: { total: 0.001 } }) {
86
109
  send({ type: 'message_end', message: { role: 'assistant', usage } });
@@ -104,6 +127,60 @@ rl.on('line', (line) => {
104
127
  rl.on('close', () => { queue.then(() => process.exit(0)); });
105
128
 
106
129
  async function handle(command) {
130
+ if (command.type === 'prompt' && (command.message.includes('mock:autonomous') || command.message.startsWith('Continue working autonomously until the task is fully complete.'))) {
131
+ const { autonomousReply } = await import('./mock-autonomous.mjs');
132
+ send({ id: command.id, type: 'response', command: 'prompt', success: true });
133
+ send({ type: 'agent_start' });
134
+ send({ type: 'turn_start' });
135
+ sendText([autonomousReply(command.message)]);
136
+ sendTurnEnd();
137
+ return;
138
+ }
139
+ if (command.type === 'prompt' && (command.message.includes('mock:silent-tail') || command.message.includes('mock:tool-tail') || command.message.includes('Your last turn ended without a message to the user.'))) {
140
+ const silent = await import('./mock-silent-tail.mjs');
141
+ silent.noteSilentTailPrompt(command.message);
142
+ if (silent.isFinalMessageNudge(command.message)) {
143
+ send({ id: command.id, type: 'response', command: 'prompt', success: true });
144
+ const kind = silent.finalMessageNudgeKind();
145
+ if (kind === 'ack-only') return;
146
+ if (kind === 'late') await silent.sleep(silent.LATE_REPLY_MS);
147
+ send({ type: 'agent_start' });
148
+ send({ type: 'turn_start' });
149
+ if (kind === 'silent') sendThinking(silent.SILENT_TAIL_REASONING);
150
+ else if (kind === 'slow-done') {
151
+ sendText([silent.SLOW_DONE_PREFIX]);
152
+ await silent.sleep(silent.SLOW_DONE_TAIL_MS);
153
+ sendText([silent.SILENT_TAIL_DONE]);
154
+ } else sendText([kind === 'standing' ? silent.FINAL_MESSAGE_STANDING : silent.SILENT_TAIL_DONE]);
155
+ sendTurnEnd();
156
+ return;
157
+ }
158
+ if (silent.isSilentTailScenario(command.message)) {
159
+ send({ id: command.id, type: 'response', command: 'prompt', success: true });
160
+ send({ type: 'agent_start' });
161
+ send({ type: 'turn_start' });
162
+ sendText([silent.SILENT_TAIL_OPENING]);
163
+ send({ type: 'tool_execution_start', toolCallId: 'tool-silent-gh', toolName: 'bash', args: { command: 'gh issue create' } });
164
+ send({ type: 'tool_execution_end', toolCallId: 'tool-silent-gh', toolName: 'bash', result: { content: [{ type: 'text', text: 'created' }] }, isError: false });
165
+ sendThinking(silent.SILENT_TAIL_REASONING, 1);
166
+ sendTurnEnd();
167
+ return;
168
+ }
169
+ if (silent.isToolTailScenario(command.message)) {
170
+ send({ id: command.id, type: 'response', command: 'prompt', success: true });
171
+ send({ type: 'agent_start' });
172
+ send({ type: 'turn_start' });
173
+ sendText([silent.TOOL_TAIL_OPENING]);
174
+ send({ type: 'tool_execution_start', toolCallId: 'tool-tail-git', toolName: 'bash', args: { command: 'git status --short' } });
175
+ send({ type: 'tool_execution_end', toolCallId: 'tool-tail-git', toolName: 'bash', result: { content: [{ type: 'text', text: ' M src/example.ts' }] }, isError: false });
176
+ sendTurnEnd();
177
+ return;
178
+ }
179
+ }
180
+ if (command.type === 'prompt' && command.message.includes('mock:crash-stderr')) {
181
+ const { crashWithStderr } = await import('./mock-runner-crash.mjs');
182
+ if (crashWithStderr(command.message, '{"type":"tool_execution_update","toolCallId":"truncated')) return;
183
+ }
107
184
  // Testability hook, mirroring mock-claude: CEZ_MOCK_STDIN_FILE=<path> appends
108
185
  // each inbound prompt's text and image count, so tests can assert what the
109
186
  // runner actually wrote onto the RPC (harness parity's AgentRunSpec probes).
@@ -153,6 +230,12 @@ async function handle(command) {
153
230
  activeTurn.late = true;
154
231
  await sleep(300);
155
232
  sendTurnEnd();
233
+ } else if (command.type === 'prompt' && command.message.includes('mock:turn-messages:')) {
234
+ const { turnMessages } = await import('./mock-turn-messages.mjs');
235
+ send({ id: command.id, type: 'response', command: 'prompt', success: true });
236
+ send({ type: 'agent_start' }); send({ type: 'turn_start' });
237
+ for (const text of turnMessages(command.message)) sendText([text]);
238
+ sendTurnEnd();
156
239
  } else if (command.type === 'prompt' && command.message.includes('mock:agent-echo')) {
157
240
  // rpc-lifecycle.ndjson's normal prompt/assistant/settled sequence.
158
241
  send({ id: command.id, type: 'response', command: 'prompt', success: true });
@@ -191,6 +274,20 @@ async function handle(command) {
191
274
  errorMessage: 'Not Found',
192
275
  } });
193
276
  send({ type: 'agent_settled' });
277
+ } else if (command.type === 'prompt' && command.message.includes('mock:hold-done')) {
278
+ send({ id: command.id, type: 'response', command: 'prompt', success: true });
279
+ send({ type: 'agent_start' });
280
+ send({ type: 'turn_start' });
281
+ await waitForMockRelease(400);
282
+ sendText(['parity hold-done: content after the pause\n\nCEZ:DONE']);
283
+ sendTurnEnd();
284
+ } else if (command.type === 'prompt' && command.message.includes('mock:hold-ask')) {
285
+ send({ id: command.id, type: 'response', command: 'prompt', success: true });
286
+ send({ type: 'agent_start' });
287
+ send({ type: 'turn_start' });
288
+ await waitForMockRelease(400);
289
+ sendText(['Pick one.\n\nCEZ:ASK {"questions":[{"header":"Library","question":"Which test library?","options":[{"label":"Vitest"},{"label":"Node test"}]}]}']);
290
+ sendTurnEnd();
194
291
  } else if (command.type === 'prompt' && (command.message.includes('mock:done') || (resumeAfterAsk && command.message.trim() === 'Library: Vitest'))) {
195
292
  resumeAfterAsk = false;
196
293
  // Declares the task complete so the run reaches cezar's review gate; a
@@ -206,7 +303,7 @@ async function handle(command) {
206
303
  send({ id: command.id, type: 'response', command: 'prompt', success: true });
207
304
  send({ type: 'agent_start' });
208
305
  send({ type: 'turn_start' });
209
- send({ type: 'message_update', message: {}, assistantMessageEvent: { type: 'text_end', contentIndex: 0, content: 'Using the CEZ:ASK structured question format instead:\n\nCEZ:ASK {"questions":[{"header":"Library","question":"Which test library?","options":[{"label":"Vitest"},{"label":"Node test"}]}]}', partial: {} } });
306
+ send({ type: 'message_update', message: {}, assistantMessageEvent: { type: 'text_end', contentIndex: 0, content: command.message.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"}]}]}', partial: {} } });
210
307
  sendTurnEnd();
211
308
  } else if (command.type === 'prompt' && command.message.includes('mock:ask-prose')) {
212
309
  send({ id: command.id, type: 'response', command: 'prompt', success: true });
@@ -241,6 +338,14 @@ async function handle(command) {
241
338
  for (let i = 0; i < 24; i++) { send({ type: 'tool_execution_update', toolCallId: 'busy', toolName: 'bash', partialResult: { content: [{ type: 'text', text: 'working' }] } }); await sleep(100); }
242
339
  sendTurnEnd();
243
340
  }
341
+ } else if (command.type === 'prompt' && command.message.includes('mock:hold-gated')) {
342
+ send({ id: command.id, type: 'response', command: 'prompt', success: true });
343
+ send({ type: 'agent_start' });
344
+ send({ type: 'turn_start' });
345
+ await waitForMockRelease(250);
346
+ sendText(['parity hold-gated: content after the pause']);
347
+ await sleep(250);
348
+ sendTurnEnd();
244
349
  } else if (command.type === 'prompt' && command.message.includes('mock:hold')) {
245
350
  // The `response` below is the ack. Holding the content AND the terminal
246
351
  // quartet behind it is what makes harness parity S2 meaningful: a runner
@@ -292,6 +397,7 @@ async function handle(command) {
292
397
  result: { content: [{ type: 'text', text: 'mock file' }] },
293
398
  isError: false,
294
399
  });
400
+ if (!monitoringMarker) sendText(['Done with the first pass.']);
295
401
  send({
296
402
  type: 'message_end',
297
403
  message: {