@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
@@ -0,0 +1,168 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import { closeSync, fstatSync, fsyncSync, linkSync, openSync, readFileSync, renameSync, statSync, unlinkSync, writeSync } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+ import { anotherCockpitOwner } from '../server/cockpit-ownership.js';
5
+ /**
6
+ * The legacy run index at the moment `runs.db` imports it (#779, plan step 4): its exact bytes,
7
+ * a durable copy of them beside it, and the checks that no older cezar is still writing it.
8
+ *
9
+ * An older cezar writes only `runs.json` and knows nothing of `runs.db`, so importing while one
10
+ * still runs would freeze a file that keeps moving. Two signals say one does:
11
+ * - a live cockpit other than this process holds `cockpit.lock`. A new cockpit takes that lock
12
+ * before it opens its store, so with no import done yet the holder is an older cockpit (v0.15.1
13
+ * and later write the lock), or a new one about to import, which a retry lets finish first;
14
+ * - `runs.json` is not the file that was read. Older cezars save it by temp file and rename, so
15
+ * every save replaces the inode, and a save during the import shows.
16
+ * An older process that holds no lock (a `cez run`, a cockpit before v0.15.1) and saves nothing
17
+ * while the import runs is not seen; whatever it writes later is never imported.
18
+ */
19
+ /** The legacy index (#779): read once, imported into `runs.db`, never written again. */
20
+ export const LEGACY_INDEX_FILE = 'runs.json';
21
+ /** The exact bytes `runs.json` held when it was imported, kept beside it. */
22
+ export const LEGACY_INDEX_BACKUP_FILE = 'runs.json.pre-sqlite.bak';
23
+ const identityOf = (stats) => ({ dev: stats.dev, ino: stats.ino, size: stats.size, mtimeMs: stats.mtimeMs });
24
+ const sha256 = (bytes) => createHash('sha256').update(bytes).digest('hex');
25
+ /** `path` read in one go through one descriptor, so its bytes and identity belong together.
26
+ * Undefined when there is no such file. */
27
+ export function readLegacyIndex(path) {
28
+ let fd;
29
+ try {
30
+ fd = openSync(path, 'r');
31
+ }
32
+ catch (error) {
33
+ if (error.code === 'ENOENT')
34
+ return undefined;
35
+ throw error;
36
+ }
37
+ try {
38
+ const identity = identityOf(fstatSync(fd));
39
+ const bytes = readFileSync(fd);
40
+ return { bytes, sha256: sha256(bytes), identity };
41
+ }
42
+ finally {
43
+ closeSync(fd);
44
+ }
45
+ }
46
+ /** Whether `path` holds exactly `snapshot`'s bytes. */
47
+ function holds(path, snapshot) {
48
+ try {
49
+ if (statSync(path).size !== snapshot.bytes.length)
50
+ return false;
51
+ return sha256(readFileSync(path)) === snapshot.sha256;
52
+ }
53
+ catch {
54
+ return false;
55
+ }
56
+ }
57
+ /**
58
+ * Create `path` holding `bytes`, durably and never half-written: a temp file is written and
59
+ * synced, then linked into place, which refuses a name that already exists. False when it does.
60
+ * The directory is synced too, so a crash cannot forget the new name. A file system without hard
61
+ * links gets a rename, guarded by an existence check instead.
62
+ */
63
+ function createDurably(path, bytes) {
64
+ const temp = `${path}.${randomUUID()}.tmp`;
65
+ // Removed on every way out, a failed write (ENOSPC) included: the name is either linked or gone.
66
+ try {
67
+ const fd = openSync(temp, 'wx');
68
+ try {
69
+ for (let written = 0; written < bytes.length;)
70
+ written += writeSync(fd, bytes, written);
71
+ fsyncSync(fd);
72
+ }
73
+ finally {
74
+ closeSync(fd);
75
+ }
76
+ try {
77
+ linkSync(temp, path);
78
+ }
79
+ catch (error) {
80
+ const code = error.code;
81
+ if (code === 'EEXIST')
82
+ return false;
83
+ if (code !== 'EPERM' && code !== 'ENOTSUP' && code !== 'EXDEV')
84
+ throw error;
85
+ if (statSync(path, { throwIfNoEntry: false }))
86
+ return false;
87
+ renameSync(temp, path);
88
+ }
89
+ }
90
+ finally {
91
+ try {
92
+ unlinkSync(temp);
93
+ }
94
+ catch { /* never created, or renamed into place */ }
95
+ }
96
+ syncDirectory(path);
97
+ return true;
98
+ }
99
+ function syncDirectory(path) {
100
+ let fd;
101
+ try {
102
+ fd = openSync(dirname(path), 'r');
103
+ fsyncSync(fd);
104
+ }
105
+ catch {
106
+ // Not every platform can sync a directory; the file itself is already synced.
107
+ }
108
+ finally {
109
+ if (fd !== undefined)
110
+ closeSync(fd);
111
+ }
112
+ }
113
+ /**
114
+ * Keep `snapshot`'s exact bytes beside `runs.json` and answer the backup's file name. An existing
115
+ * `runs.json.pre-sqlite.bak` is trusted only when it holds those very bytes (same size and
116
+ * sha256). One that does not — an earlier snapshot, a file a crash cut short — is never touched:
117
+ * the bytes go to `runs.json.pre-sqlite.<sha256 prefix>.bak` instead.
118
+ *
119
+ * The import calls this only inside its transaction, once nothing can refuse it any more: an
120
+ * attempt an older cezar's writes refuse leaves no backup, so retries cannot multiply them.
121
+ */
122
+ export function backUpLegacyIndex(dataDir, snapshot) {
123
+ for (const name of [LEGACY_INDEX_BACKUP_FILE, `runs.json.pre-sqlite.${snapshot.sha256.slice(0, 12)}.bak`]) {
124
+ const path = join(dataDir, name);
125
+ if (holds(path, snapshot))
126
+ return name;
127
+ // Re-checked only after creating it: a file this did not create may hold other bytes.
128
+ if (createDurably(path, snapshot.bytes) || holds(path, snapshot))
129
+ return name;
130
+ }
131
+ throw new Error(`cannot back up ${LEGACY_INDEX_FILE}: both backup names are taken by other contents`);
132
+ }
133
+ /** An older cezar still writes `runs.json`, so it was not imported. */
134
+ export class LegacyWriterError extends Error {
135
+ /** `cockpit`: a live cockpit other than this process holds `cockpit.lock`. `changed`: the file
136
+ * changed between the read and the import. */
137
+ reason;
138
+ constructor(reason, message) {
139
+ super(message);
140
+ this.name = 'LegacyWriterError';
141
+ this.reason = reason;
142
+ }
143
+ }
144
+ /** Throw `LegacyWriterError` when a live cockpit other than this process owns `dataDir`. Cheap: one
145
+ * small file read and a liveness probe, so the import asks it before it reads anything. */
146
+ export function assertNoLegacyCockpit(dataDir) {
147
+ const owner = anotherCockpitOwner(dataDir);
148
+ if (owner) {
149
+ throw new LegacyWriterError('cockpit', `An older cezar (pid ${owner.pid}${owner.url ? ` at ${owner.url}` : ''}) still serves this project and writes ${LEGACY_INDEX_FILE}. Stop it, then restart cezar: ${LEGACY_INDEX_FILE} is imported once, while nothing else writes it.`);
150
+ }
151
+ }
152
+ /**
153
+ * Throw `LegacyWriterError` when an older cezar may still be writing `runs.json`: another live
154
+ * cockpit owns `dataDir` (`assertNoLegacyCockpit`), or the file is no longer what `snapshot` read
155
+ * (undefined: there was none). Inside the import transaction, right before it commits, this is
156
+ * the authority; asked earlier it only saves the work of an import that could not commit.
157
+ */
158
+ export function assertNoLegacyWriter(dataDir, snapshot) {
159
+ assertNoLegacyCockpit(dataDir);
160
+ const now = statSync(join(dataDir, LEGACY_INDEX_FILE), { throwIfNoEntry: false });
161
+ const read = snapshot?.identity;
162
+ const same = now === undefined ? read === undefined
163
+ : read !== undefined && now.dev === read.dev && now.ino === read.ino && now.size === read.size && now.mtimeMs === read.mtimeMs;
164
+ if (!same) {
165
+ throw new LegacyWriterError('changed', `${LEGACY_INDEX_FILE} changed while cezar was importing it: an older cezar process still writes it. Stop every older cezar process for this project, then restart cezar.`);
166
+ }
167
+ }
168
+ //# sourceMappingURL=legacy-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legacy-index.js","sourceRoot":"","sources":["../../src/runs/legacy-index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The raw-record codec (#779, plan step 4): a run row keeps what this cezar cannot read.
3
+ *
4
+ * A record goes through the runtime schema on the way in, and zod drops every key it does not
5
+ * declare. Before this codec, the next write serialized the parsed record, so a field an older or
6
+ * newer cezar stored was lost the first time this one touched the run. Now the parse still
7
+ * produces the unchanged runtime record, and `collectRawExtras` notes, beside it, what the stored
8
+ * JSON held that the parse dropped. A write goes through `encodeRawRecord`: every field the
9
+ * runtime record has is written exactly as it is now, so changes and deletions of known fields
10
+ * apply at every depth, and the dropped fields go back in wherever their parent still exists.
11
+ *
12
+ * Plain JSON only: nothing here knows the run schema. Arrays whose elements all carry a distinct
13
+ * string `id` (steps, queued messages) are matched by that id, so an unknown field follows its
14
+ * step through reordering, insertion and removal. Any other array is matched by position, and
15
+ * only while its known content is exactly what was read; once the runtime changes it, the array is
16
+ * written as the runtime has it and whatever unknown fields it carried are dropped with it.
17
+ */
18
+ /** What one stored record held beyond its parse. Opaque outside this module. */
19
+ export type RawExtras = ObjectExtras | KeyedArrayExtras | IndexedArrayExtras;
20
+ interface ObjectExtras {
21
+ kind: 'object';
22
+ /** Keys the parse dropped, with their stored values. */
23
+ fields: Map<string, unknown>;
24
+ /** Keys the parse kept whose values hold dropped fields further down. */
25
+ children: Map<string, RawExtras>;
26
+ }
27
+ interface KeyedArrayExtras {
28
+ kind: 'keyed';
29
+ elements: Map<string, RawExtras>;
30
+ }
31
+ interface IndexedArrayExtras {
32
+ kind: 'indexed';
33
+ /** The array's known content when it was read: the extras apply only while it is unchanged. */
34
+ known: string;
35
+ elements: Map<number, RawExtras>;
36
+ }
37
+ /**
38
+ * What `raw` (a record as stored) holds that `parsed` (the same record through the runtime schema)
39
+ * does not: undefined when the parse kept every stored field, which is the common case and makes
40
+ * every later write a plain `JSON.stringify`. Defaults the parse added are not extras.
41
+ */
42
+ export declare function collectRawExtras(raw: unknown, parsed: unknown): RawExtras | undefined;
43
+ /**
44
+ * The JSON to store for `record`: exactly `JSON.stringify(record)` without extras, else the record
45
+ * with every extra that still fits put back. `extras` in the result is what the stored JSON now
46
+ * holds beyond the record, for the next write of the same row.
47
+ */
48
+ export declare function encodeRawRecord(record: unknown, extras: RawExtras | undefined): {
49
+ data: string;
50
+ extras: RawExtras | undefined;
51
+ };
52
+ export {};
@@ -0,0 +1,145 @@
1
+ /**
2
+ * The raw-record codec (#779, plan step 4): a run row keeps what this cezar cannot read.
3
+ *
4
+ * A record goes through the runtime schema on the way in, and zod drops every key it does not
5
+ * declare. Before this codec, the next write serialized the parsed record, so a field an older or
6
+ * newer cezar stored was lost the first time this one touched the run. Now the parse still
7
+ * produces the unchanged runtime record, and `collectRawExtras` notes, beside it, what the stored
8
+ * JSON held that the parse dropped. A write goes through `encodeRawRecord`: every field the
9
+ * runtime record has is written exactly as it is now, so changes and deletions of known fields
10
+ * apply at every depth, and the dropped fields go back in wherever their parent still exists.
11
+ *
12
+ * Plain JSON only: nothing here knows the run schema. Arrays whose elements all carry a distinct
13
+ * string `id` (steps, queued messages) are matched by that id, so an unknown field follows its
14
+ * step through reordering, insertion and removal. Any other array is matched by position, and
15
+ * only while its known content is exactly what was read; once the runtime changes it, the array is
16
+ * written as the runtime has it and whatever unknown fields it carried are dropped with it.
17
+ */
18
+ function isObject(value) {
19
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
20
+ }
21
+ /** The ids of an array whose every element is an object with a distinct string `id`. */
22
+ function elementIds(array) {
23
+ const ids = array.map((element) => (isObject(element) && typeof element.id === 'string' ? element.id : undefined));
24
+ if (ids.length === 0 || ids.some((id) => id === undefined) || new Set(ids).size !== ids.length)
25
+ return undefined;
26
+ return ids;
27
+ }
28
+ /**
29
+ * What `raw` (a record as stored) holds that `parsed` (the same record through the runtime schema)
30
+ * does not: undefined when the parse kept every stored field, which is the common case and makes
31
+ * every later write a plain `JSON.stringify`. Defaults the parse added are not extras.
32
+ */
33
+ export function collectRawExtras(raw, parsed) {
34
+ if (isObject(raw) && isObject(parsed)) {
35
+ const fields = new Map();
36
+ const children = new Map();
37
+ for (const [key, value] of Object.entries(raw)) {
38
+ if (value === undefined)
39
+ continue;
40
+ if (parsed[key] === undefined) {
41
+ fields.set(key, value);
42
+ continue;
43
+ }
44
+ const child = collectRawExtras(value, parsed[key]);
45
+ if (child)
46
+ children.set(key, child);
47
+ }
48
+ return fields.size > 0 || children.size > 0 ? { kind: 'object', fields, children } : undefined;
49
+ }
50
+ if (!Array.isArray(raw) || !Array.isArray(parsed))
51
+ return undefined;
52
+ const rawIds = elementIds(raw);
53
+ const parsedIds = elementIds(parsed);
54
+ if (rawIds && parsedIds) {
55
+ const byId = new Map(parsedIds.map((id, index) => [id, parsed[index]]));
56
+ const elements = new Map();
57
+ rawIds.forEach((id, index) => {
58
+ const child = byId.has(id) ? collectRawExtras(raw[index], byId.get(id)) : undefined;
59
+ if (child)
60
+ elements.set(id, child);
61
+ });
62
+ return elements.size > 0 ? { kind: 'keyed', elements } : undefined;
63
+ }
64
+ // Positions only line up while the parse kept every element.
65
+ if (raw.length !== parsed.length)
66
+ return undefined;
67
+ const elements = new Map();
68
+ raw.forEach((element, index) => {
69
+ const child = collectRawExtras(element, parsed[index]);
70
+ if (child)
71
+ elements.set(index, child);
72
+ });
73
+ return elements.size > 0 ? { kind: 'indexed', known: JSON.stringify(parsed), elements } : undefined;
74
+ }
75
+ /** `current` with `extras` put back where they still fit, and the extras that did. Never changes
76
+ * `current`: only the containers on the way to a restored field are copied. */
77
+ function merge(current, extras) {
78
+ if (extras.kind === 'object') {
79
+ if (!isObject(current))
80
+ return [current, undefined];
81
+ const out = { ...current };
82
+ const fields = new Map();
83
+ const children = new Map();
84
+ for (const [key, value] of extras.fields) {
85
+ // A key the runtime now has a value for is its own: it was dropped as unreadable before.
86
+ if (out[key] !== undefined)
87
+ continue;
88
+ out[key] = value;
89
+ fields.set(key, value);
90
+ }
91
+ for (const [key, child] of extras.children) {
92
+ // The known parent is gone: everything stored under it goes with it.
93
+ if (out[key] === undefined)
94
+ continue;
95
+ const [value, kept] = merge(out[key], child);
96
+ out[key] = value;
97
+ if (kept)
98
+ children.set(key, kept);
99
+ }
100
+ if (fields.size === 0 && children.size === 0)
101
+ return [current, undefined];
102
+ return [out, { kind: 'object', fields, children }];
103
+ }
104
+ if (!Array.isArray(current))
105
+ return [current, undefined];
106
+ if (extras.kind === 'keyed') {
107
+ const elements = new Map();
108
+ const out = current.map((element) => {
109
+ const id = isObject(element) && typeof element.id === 'string' ? element.id : undefined;
110
+ const child = id === undefined ? undefined : extras.elements.get(id);
111
+ if (!child)
112
+ return element;
113
+ const [value, kept] = merge(element, child);
114
+ if (kept)
115
+ elements.set(id, kept);
116
+ return value;
117
+ });
118
+ return elements.size > 0 ? [out, { kind: 'keyed', elements }] : [current, undefined];
119
+ }
120
+ if (JSON.stringify(current) !== extras.known)
121
+ return [current, undefined];
122
+ const elements = new Map();
123
+ const out = current.map((element, index) => {
124
+ const child = extras.elements.get(index);
125
+ if (!child)
126
+ return element;
127
+ const [value, kept] = merge(element, child);
128
+ if (kept)
129
+ elements.set(index, kept);
130
+ return value;
131
+ });
132
+ return elements.size > 0 ? [out, { kind: 'indexed', known: extras.known, elements }] : [current, undefined];
133
+ }
134
+ /**
135
+ * The JSON to store for `record`: exactly `JSON.stringify(record)` without extras, else the record
136
+ * with every extra that still fits put back. `extras` in the result is what the stored JSON now
137
+ * holds beyond the record, for the next write of the same row.
138
+ */
139
+ export function encodeRawRecord(record, extras) {
140
+ if (!extras)
141
+ return { data: JSON.stringify(record), extras: undefined };
142
+ const [value, kept] = merge(record, extras);
143
+ return { data: JSON.stringify(value), extras: kept };
144
+ }
145
+ //# sourceMappingURL=raw-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raw-record.js","sourceRoot":"","sources":["../../src/runs/raw-record.ts"],"names":[],"mappings":"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"}
@@ -1,23 +1,28 @@
1
+ import type { PreviewHostLike } from '../preview/registration.ts';
1
2
  import type { RunRecord } from './store.ts';
2
3
  /** A run is reclaimable when it is finished, still has a materialized worktree
3
4
  * directory, and has not already been reclaimed. Finished owned workers count
4
5
  * (#575) once their parent is gone or `done` (collection-gated). A live,
5
6
  * failed, or cancelled parent can still collect/diff from the dir. Live runs,
6
- * `review`, `invalid`, and workers mid-destroy do not. */
7
- export declare function isReclaimable(run: RunRecord, runs?: readonly RunRecord[]): boolean;
7
+ * `review`, `invalid`, and workers mid-destroy do not. `lookup` finds the parent
8
+ * by id (the store's `getRun`; a parent need not have a worktree of its own). */
9
+ export declare function isReclaimable(run: RunRecord, lookup?: (id: string) => RunRecord | undefined): boolean;
8
10
  /**
9
- * Given every run and the keep-count `keep`, return the ids of the finished
11
+ * Given the runs with a worktree and the keep-count `keep`, return the ids of the finished
10
12
  * worktrees whose *directory* should be reclaimed: keep the `keep`
11
- * most-recently-finished reclaimable worktrees, reclaim the rest.
13
+ * most-recently-finished reclaimable worktrees, reclaim the rest. `lookup` finds an owned
14
+ * worker's parent; without it, the parent is looked for among `runs`.
12
15
  *
13
16
  * `keep === 0` means "unlimited — never auto-reclaim" and returns `[]`.
14
17
  * Pure: no I/O, no mutation of the input.
15
18
  */
16
- export declare function selectReclaimableWorktrees(runs: readonly RunRecord[], keep: number): string[];
19
+ export declare function selectReclaimableWorktrees(runs: readonly RunRecord[], keep: number, lookup?: (id: string) => RunRecord | undefined): string[];
17
20
  /** The slice of the runs store the enforcer needs. Kept structural so the
18
21
  * enforcer stays easy to test and never imports the concrete store. */
19
22
  export interface RetentionStore {
20
- listRuns(): RunRecord[];
23
+ /** The candidates: runs with a materialized worktree (an indexed query, #779). */
24
+ listRunsWithWorktree(): RunRecord[];
25
+ getRun(id: string): RunRecord | undefined;
21
26
  updateRun(id: string, patch: {
22
27
  worktreeReclaimedAt?: string;
23
28
  }): unknown;
@@ -70,6 +75,8 @@ export interface ReclaimOptions {
70
75
  * worker's evidence snapshot; a person pressing Reclaim on one row (issue 08 §B4) is not shown
71
76
  * that a diff snapshot drops binary content and caps its size, so that path asks for clean. */
72
77
  requireClean?: boolean;
78
+ /** The workspace preview host (#781): the default reclaimer releases the run's preview first. */
79
+ previewHost?: Pick<PreviewHostLike, 'release'>;
73
80
  }
74
81
  export declare function reclaimWorktrees(repoRoot: string, store: RetentionStore, keep: number, opts?: ReclaimOptions): Promise<string[]>;
75
82
  /**
@@ -6,8 +6,9 @@
6
6
  // is pure and unit-testable; the enforcer never throws (helper discipline).
7
7
  import { existsSync } from 'node:fs';
8
8
  import { collectWorkerEvidence } from '../delegation/results.js';
9
- import { createWorktree, removeWorktree } from '../git-worktree.js';
10
- /** The "finished" status set — mirrors `RunStore.archiveFinished`. A run at the
9
+ import { createWorktree } from '../git-worktree.js';
10
+ import { releaseThenRemoveWorktree } from '../git-worktree-release.js';
11
+ /** The "finished" status set — mirrors the statuses `RunStore.archiveFinished` sweeps. A run at the
11
12
  * `review` gate is deliberately excluded: it still needs its worktree to render
12
13
  * the diff and open a draft PR, so reclaiming it would break the gate. */
13
14
  const FINISHED = new Set(['done', 'failed', 'cancelled']);
@@ -21,8 +22,9 @@ function recencyKey(run) {
21
22
  * directory, and has not already been reclaimed. Finished owned workers count
22
23
  * (#575) once their parent is gone or `done` (collection-gated). A live,
23
24
  * failed, or cancelled parent can still collect/diff from the dir. Live runs,
24
- * `review`, `invalid`, and workers mid-destroy do not. */
25
- export function isReclaimable(run, runs = []) {
25
+ * `review`, `invalid`, and workers mid-destroy do not. `lookup` finds the parent
26
+ * by id (the store's `getRun`; a parent need not have a worktree of its own). */
27
+ export function isReclaimable(run, lookup = () => undefined) {
26
28
  if (run.delegation?.role === 'invalid')
27
29
  return false;
28
30
  if (run.delegation?.role === 'worker' && run.delegation.destroy)
@@ -30,8 +32,7 @@ export function isReclaimable(run, runs = []) {
30
32
  if (!FINISHED.has(run.status) || !run.worktreePath || !existsSync(run.worktreePath) || run.worktreeReclaimedAt)
31
33
  return false;
32
34
  if (run.delegation?.role === 'worker') {
33
- const parentId = run.delegation.parentRunId;
34
- const parent = runs.find((candidate) => candidate.id === parentId);
35
+ const parent = lookup(run.delegation.parentRunId);
35
36
  // `done` is collection-gated. failed/cancelled parents can still collect later.
36
37
  if (parent && parent.status !== 'done')
37
38
  return false;
@@ -39,18 +40,19 @@ export function isReclaimable(run, runs = []) {
39
40
  return true;
40
41
  }
41
42
  /**
42
- * Given every run and the keep-count `keep`, return the ids of the finished
43
+ * Given the runs with a worktree and the keep-count `keep`, return the ids of the finished
43
44
  * worktrees whose *directory* should be reclaimed: keep the `keep`
44
- * most-recently-finished reclaimable worktrees, reclaim the rest.
45
+ * most-recently-finished reclaimable worktrees, reclaim the rest. `lookup` finds an owned
46
+ * worker's parent; without it, the parent is looked for among `runs`.
45
47
  *
46
48
  * `keep === 0` means "unlimited — never auto-reclaim" and returns `[]`.
47
49
  * Pure: no I/O, no mutation of the input.
48
50
  */
49
- export function selectReclaimableWorktrees(runs, keep) {
51
+ export function selectReclaimableWorktrees(runs, keep, lookup = (id) => runs.find((run) => run.id === id)) {
50
52
  if (!Number.isFinite(keep) || keep <= 0)
51
53
  return [];
52
54
  const reclaimable = runs
53
- .filter((run) => isReclaimable(run, runs))
55
+ .filter((run) => isReclaimable(run, lookup))
54
56
  .sort((a, b) => (recencyKey(a) < recencyKey(b) ? 1 : recencyKey(a) > recencyKey(b) ? -1 : 0));
55
57
  return reclaimable.slice(keep).map((r) => r.id);
56
58
  }
@@ -95,10 +97,10 @@ async function preserveWorkerResult(repoRoot, store, run) {
95
97
  return evidence.diffSnapshot !== undefined || evidence.result.diff.state === 'available';
96
98
  }
97
99
  export async function reclaimWorktrees(repoRoot, store, keep, opts = {}) {
98
- const runs = store.listRuns();
100
+ const runs = store.listRunsWithWorktree();
99
101
  const byId = new Map(runs.map((r) => [r.id, r]));
100
102
  const reclaimed = [];
101
- for (const id of selectReclaimableWorktrees(runs, keep)) {
103
+ for (const id of selectReclaimableWorktrees(runs, keep, (parentId) => store.getRun(parentId))) {
102
104
  const run = byId.get(id);
103
105
  if (run && (await reclaimWorktree(repoRoot, store, run, opts)))
104
106
  reclaimed.push(id);
@@ -119,15 +121,41 @@ export async function reclaimWorktree(repoRoot, store, run, opts = {}) {
119
121
  // Branch kept. An owned worker's evidence (uncommitted diff included) is snapshotted first; any
120
122
  // other run's uncommitted work lives only in the directory, so a dirty one is left for later.
121
123
  const onlyClean = opts.requireClean === true || run.delegation?.role !== 'worker';
122
- const remove = opts.remove ?? ((root, path) => removeWorktree(root, path, undefined, { reclaimOwnedDirectory: true, onlyClean }));
124
+ const execution = run.delegation?.role === 'worker' ? store.readWorkerExecution?.(run.id) : undefined;
125
+ const assertSafe = () => {
126
+ if (run.delegation?.role !== 'worker')
127
+ return;
128
+ const real = store;
129
+ // Structural test stores have no private execution machinery. Real stores must attest both
130
+ // generation ownership and fresh resource holders, including after async evidence/preview.
131
+ if (typeof real.workerResourcesSafe === 'function' && (!execution ||
132
+ !real.workerResourcesSafe(run.id, execution.generation, run.delegation.workspace.resourceId)))
133
+ throw Error('Worker resources are not safe to reclaim');
134
+ };
135
+ const remove = opts.remove ?? ((root, path) => releaseThenRemoveWorktree({ previewHost: opts.previewHost }, run.id, root, path, undefined, { reclaimOwnedDirectory: true, onlyClean, assertCurrent: assertSafe }));
123
136
  if (!run.worktreePath)
124
137
  return null;
125
138
  const release = opts.claim ? opts.claim(run) : () => undefined;
126
139
  if (!release)
127
140
  return null; // in use since it was selected
141
+ // Claimed in the run database too, for the whole reclaim (#779, plan step 3): no other cezar
142
+ // process writes this run or reclaims it meanwhile, and another process's run is left alone.
143
+ // Structural test stores have no claims.
144
+ const real = store;
145
+ let pinned = typeof real.pin !== 'function';
146
+ try {
147
+ pinned ||= real.pin.call(store, run.id, 'cleanup') !== undefined;
148
+ }
149
+ catch { /* busy: not claimed */ }
150
+ if (!pinned) {
151
+ release();
152
+ return null;
153
+ }
128
154
  try {
129
155
  if (!(await preserveWorkerResult(repoRoot, store, run).catch(() => false)))
130
156
  return null;
157
+ if (opts.remove)
158
+ assertSafe(); // injected reclaimer has no final callback
131
159
  await remove(repoRoot, run.worktreePath);
132
160
  if (existsSync(run.worktreePath))
133
161
  return null; // reclaim failed; retry next pass
@@ -140,6 +168,7 @@ export async function reclaimWorktree(repoRoot, store, run, opts = {}) {
140
168
  return null;
141
169
  }
142
170
  finally {
171
+ real.unpin?.call(store, run.id, 'cleanup');
143
172
  release();
144
173
  }
145
174
  }
@@ -1 +1 @@
1
- {"version":3,"file":"retention.js","sourceRoot":"","sources":["../../src/runs/retention.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"retention.js","sourceRoot":"","sources":["../../src/runs/retention.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Who owns a run claim, and whether that owner can still be writing (#779, plan step 3).
3
+ *
4
+ * A claim in `run_claims` names the RunStore that holds a delegation family: a session id (one per
5
+ * `RunStore.open`), its process id, and that process's start identity (`processStartToken`: the
6
+ * Linux `/proc/<pid>/stat` start time scoped by boot id, or macOS `ps -o lstart`). Only a PROVEN
7
+ * dead owner's claim may be taken over: its pid is gone, the pid now belongs to a process with a
8
+ * different start identity, or — for our own pid, which can only be this process or a dead earlier
9
+ * one — its session is not open here. Anything that cannot be proven dead counts as live, which is
10
+ * what a claim with no start identity on a pid that exists is: there is nothing to compare it with.
11
+ */
12
+ export interface ClaimOwner {
13
+ session: string;
14
+ pid: number;
15
+ /** Null only where the platform cannot read a start identity. */
16
+ startToken: string | null;
17
+ }
18
+ /** A fresh owner identity for one store, live until `closeClaimSession`. */
19
+ export declare function openClaimSession(): ClaimOwner;
20
+ /** The store behind `session` is gone: any claim it left behind is now provably dead. */
21
+ export declare function closeClaimSession(session: string): void;
22
+ /** Whether the owner of `claim` may still be writing. False only when it is proven gone. */
23
+ export declare function claimOwnerLive(claim: ClaimOwner): boolean;
@@ -0,0 +1,24 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { isCurrentProcess, processStartToken, recordedProcessLive } from '../delegation/process-liveness.js';
3
+ /** The sessions open in this process: the only way to tell two stores in one process apart. */
4
+ const openSessions = new Set();
5
+ let ownStartToken;
6
+ /** A fresh owner identity for one store, live until `closeClaimSession`. */
7
+ export function openClaimSession() {
8
+ ownStartToken ??= processStartToken(process.pid) ?? null;
9
+ const owner = { session: randomUUID(), pid: process.pid, startToken: ownStartToken };
10
+ openSessions.add(owner.session);
11
+ return owner;
12
+ }
13
+ /** The store behind `session` is gone: any claim it left behind is now provably dead. */
14
+ export function closeClaimSession(session) {
15
+ openSessions.delete(session);
16
+ }
17
+ /** Whether the owner of `claim` may still be writing. False only when it is proven gone. */
18
+ export function claimOwnerLive(claim) {
19
+ const entry = { pid: claim.pid, ...(claim.startToken === null ? {} : { startToken: claim.startToken }) };
20
+ if (claim.pid === process.pid)
21
+ return isCurrentProcess(entry) && openSessions.has(claim.session);
22
+ return recordedProcessLive(entry);
23
+ }
24
+ //# sourceMappingURL=run-claims.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-claims.js","sourceRoot":"","sources":["../../src/runs/run-claims.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAqB7G,+FAA+F;AAC/F,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;AACvC,IAAI,aAAwC,CAAC;AAE7C,4EAA4E;AAC5E,MAAM,UAAU,gBAAgB;IAC9B,aAAa,KAAK,iBAAiB,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;IACzD,MAAM,KAAK,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC;IACrF,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAChC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,cAAc,CAAC,KAAiB;IAC9C,MAAM,KAAK,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC;IACzG,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG;QAAE,OAAO,gBAAgB,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjG,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAC;AACpC,CAAC"}