@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,23 @@
1
+ import type { IncomingMessage } from 'node:http';
2
+ import type { Duplex } from 'node:stream';
3
+ /**
4
+ * The HTTP server's one `upgrade` listener (#781, spec 2026-10-02-live-preview-v1 "WebSocket").
5
+ * Each WebSocket endpoint is a route; the first whose `match` returns params handles the upgrade,
6
+ * and an unmatched path is destroyed. Upgrade-only endpoints never reach Hono, so each one is
7
+ * inventoried by hand in BACKWARD_COMPATIBILITY.md §2.
8
+ */
9
+ export interface UpgradeRoute {
10
+ /** Path params when `pathname` is this route's, else undefined. */
11
+ match(pathname: string): Record<string, string> | undefined;
12
+ handle(req: IncomingMessage, socket: Duplex, head: Buffer, params: Record<string, string>): void;
13
+ }
14
+ /** The server surface the router needs: the `http.Server` that `serve()` returns has it. */
15
+ export interface UpgradeCapableServer {
16
+ on(event: 'upgrade', listener: (req: IncomingMessage, socket: Duplex, head: Buffer) => void): unknown;
17
+ }
18
+ export declare function attachUpgradeRouter(server: UpgradeCapableServer, routes: readonly UpgradeRoute[]): void;
19
+ /**
20
+ * A `match` for one or more `/a/:param/b` patterns. A param is one non-empty segment, decoded;
21
+ * one that does not decode is no match.
22
+ */
23
+ export declare function matchPath(patterns: readonly string[]): UpgradeRoute['match'];
@@ -0,0 +1,53 @@
1
+ export function attachUpgradeRouter(server, routes) {
2
+ server.on('upgrade', (req, socket, head) => {
3
+ let pathname;
4
+ try {
5
+ // `req.url` on an upgrade is the path (+query); the base only satisfies URL parsing.
6
+ pathname = new URL(req.url ?? '', 'http://localhost').pathname;
7
+ }
8
+ catch {
9
+ socket.destroy();
10
+ return;
11
+ }
12
+ for (const route of routes) {
13
+ const params = route.match(pathname);
14
+ if (params)
15
+ return route.handle(req, socket, head, params);
16
+ }
17
+ // With an `upgrade` listener installed, Node no longer destroys unhandled upgrades.
18
+ socket.destroy();
19
+ });
20
+ }
21
+ /**
22
+ * A `match` for one or more `/a/:param/b` patterns. A param is one non-empty segment, decoded;
23
+ * one that does not decode is no match.
24
+ */
25
+ export function matchPath(patterns) {
26
+ const compiled = patterns.map(pattern => pattern.split('/'));
27
+ return pathname => {
28
+ const parts = pathname.split('/');
29
+ for (const segments of compiled) {
30
+ if (segments.length !== parts.length)
31
+ continue;
32
+ const params = {};
33
+ const matched = segments.every((segment, i) => {
34
+ const part = parts[i];
35
+ if (!segment.startsWith(':'))
36
+ return segment === part;
37
+ if (!part)
38
+ return false;
39
+ try {
40
+ params[segment.slice(1)] = decodeURIComponent(part);
41
+ return true;
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ });
47
+ if (matched)
48
+ return params;
49
+ }
50
+ return undefined;
51
+ };
52
+ }
53
+ //# sourceMappingURL=upgrade-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade-router.js","sourceRoot":"","sources":["../../src/server/upgrade-router.ts"],"names":[],"mappings":"AAqBA,MAAM,UAAU,mBAAmB,CAAC,MAA4B,EAAE,MAA+B;IAC/F,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;QACzC,IAAI,QAAgB,CAAC;QACrB,IAAI,CAAC;YACH,qFAAqF;YACrF,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,EAAE,kBAAkB,CAAC,CAAC,QAAQ,CAAC;QACjE,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACrC,IAAI,MAAM;gBAAE,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAC7D,CAAC;QACD,oFAAoF;QACpF,MAAM,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,QAA2B;IACnD,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7D,OAAO,QAAQ,CAAC,EAAE;QAChB,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAClC,KAAK,MAAM,QAAQ,IAAI,QAAQ,EAAE,CAAC;YAChC,IAAI,QAAQ,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM;gBAAE,SAAS;YAC/C,MAAM,MAAM,GAA2B,EAAE,CAAC;YAC1C,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE;gBAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;gBACvB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;oBAAE,OAAO,OAAO,KAAK,IAAI,CAAC;gBACtD,IAAI,CAAC,IAAI;oBAAE,OAAO,KAAK,CAAC;gBACxB,IAAI,CAAC;oBACH,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;oBACpD,OAAO,IAAI,CAAC;gBACd,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,KAAK,CAAC;gBACf,CAAC;YACH,CAAC,CAAC,CAAC;YACH,IAAI,OAAO;gBAAE,OAAO,MAAM,CAAC;QAC7B,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC;AACJ,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { Env, MiddlewareHandler } from 'hono';
1
+ import type { Context, Env, MiddlewareHandler } from 'hono';
2
2
  import type { z } from 'zod';
3
3
  /**
4
4
  * Request validation as ROUTE MIDDLEWARE — the `json` / `param` / `query` trio every mutating
@@ -50,6 +50,11 @@ type JsonOptions = ErrorOptions & {
50
50
  * behaviour moved with it rather than being lost in the move.
51
51
  */
52
52
  malformed?: unknown;
53
+ /**
54
+ * Builds the rejection itself, from the issues and the parsed input. The private preview tool
55
+ * route (#781) answers its agent a typed 200 result naming the field, not this API's 400.
56
+ */
57
+ invalid?: (c: Context, error: z.ZodError, input: unknown) => Response;
53
58
  };
54
59
  /**
55
60
  * The request/response split, spelled out rather than inferred.
@@ -25,13 +25,13 @@ schema, options = {}) {
25
25
  // `= null` default would silently overwrite exactly that case.
26
26
  const absent = 'absent' in options ? options.absent : null;
27
27
  const malformed = 'malformed' in options ? options.malformed : absent;
28
- const { message, code } = options;
28
+ const { message, code, invalid } = options;
29
29
  const check = (input, c) => {
30
30
  const resolved = typeof schema === 'function' ? schema() : schema;
31
31
  const parsed = resolved.safeParse(input);
32
- return parsed.success
33
- ? { ok: true, data: parsed.data }
34
- : { ok: false, response: reject(c, parsed.error, message, code) };
32
+ if (parsed.success)
33
+ return { ok: true, data: parsed.data };
34
+ return { ok: false, response: invalid ? invalid(c, parsed.error, input) : reject(c, parsed.error, message, code) };
35
35
  };
36
36
  const validate = validator('json', (value, c) => {
37
37
  const result = check(value, c);
@@ -1 +1 @@
1
- {"version":3,"file":"validators.js","sourceRoot":"","sources":["../../src/server/validators.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validators.js","sourceRoot":"","sources":["../../src/server/validators.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import type { IncomingMessage } from 'node:http';
2
2
  import type { Duplex } from 'node:stream';
3
+ import type { UpgradeRoute } from './upgrade-router.ts';
3
4
  /**
4
5
  * The cockpit's WebSocket subscription bus (`GET /api/v1/ws`, upgrade-only).
5
6
  * Design + the subscribe/unsubscribe discipline: spec
@@ -16,10 +17,14 @@ import type { Duplex } from 'node:stream';
16
17
  * to mean N polls every 5 s forever; now they mean one publisher while at
17
18
  * least one tab subscribes, and none afterwards.
18
19
  *
19
- * Security: the hub itself never decides who may connect — `attach` takes the
20
- * upgrade guard as a function, and server.ts supplies the WebSocket twin of
21
- * the `/api/*` request-origin guard (#426). See `verifyWsUpgrade` there for
20
+ * Security: the hub itself never decides who may connect — `handleUpgrade`
21
+ * takes the upgrade guard's verdict, and server.ts supplies the WebSocket twin
22
+ * of the `/api/*` request-origin guard (#426). See `verifyWsUpgrade` there for
22
23
  * what it admits, and the caveat about which topics may live on this hub.
24
+ *
25
+ * The hub does not listen on the HTTP server itself: the one `upgrade` listener
26
+ * is `attachUpgradeRouter` (upgrade-router.ts, #781), and `socketHubRoute` is
27
+ * this hub's route in it.
23
28
  */
24
29
  /** The one upgrade path. Workspace-level like `/api/workspace/events` — never
25
30
  * mirrored under `/api/p/:projectId` (topics carry workspace data). */
@@ -56,25 +61,18 @@ export interface TopicOptions {
56
61
  export type WsUpgradeVerdict = false | {
57
62
  trusted: boolean;
58
63
  };
59
- /** The minimal server surface `attach` needs — satisfied by the `http.Server`
60
- * that `@hono/node-server`'s `serve()` returns. */
61
- export interface UpgradeCapableServer {
62
- on(event: 'upgrade', listener: (req: IncomingMessage, socket: Duplex, head: Buffer) => void): unknown;
63
- on(event: 'close', listener: () => void): unknown;
64
- }
65
64
  export interface SocketHub {
66
65
  /** Register a topic clients may subscribe to. Registration is boot-time
67
66
  * wiring (createApp), so a duplicate name is a programming error: throw.
68
67
  * `options.loopbackReadable` defaults to `false` (topic legible to trusted
69
68
  * connections only) — see `TopicOptions`. */
70
69
  registerTopic(name: string, publisher: TopicPublisher, options?: TopicOptions): void;
71
- /** Start accepting `WS_PATH` upgrades on `server`. `verifyUpgrade` is the
72
- * request-origin guard — `false` answers 403 before the handshake, otherwise
73
- * its `trusted` flag decides which topics the connection may read. Boot-time
74
- * wiring like `registerTopic`: attaching twice throws. */
75
- attach(server: UpgradeCapableServer, verifyUpgrade: (req: IncomingMessage) => WsUpgradeVerdict): void;
76
- /** Stop publishers, terminate clients, clear timers. Idempotent; also runs
77
- * on the attached server's own `close`. */
70
+ /** Accept one `WS_PATH` upgrade under the request-origin guard's verdict:
71
+ * `false` answers 403 before the handshake, otherwise its `trusted` flag
72
+ * decides which topics the connection may read. */
73
+ handleUpgrade(req: IncomingMessage, socket: Duplex, head: Buffer, verdict: WsUpgradeVerdict): void;
74
+ /** Stop publishers, terminate clients, clear timers. Idempotent; the server
75
+ * that routes upgrades here calls it on its own `close`. */
78
76
  close(): void;
79
77
  }
80
78
  export interface SocketHubOptions {
@@ -83,3 +81,5 @@ export interface SocketHubOptions {
83
81
  heartbeatMs?: number;
84
82
  }
85
83
  export declare function createSocketHub(options?: SocketHubOptions): SocketHub;
84
+ /** The hub's route in the upgrade router: `WS_PATH`, under `verifyUpgrade`. */
85
+ export declare function socketHubRoute(hub: SocketHub, verifyUpgrade: (req: IncomingMessage) => WsUpgradeVerdict): UpgradeRoute;
package/dist/server/ws.js CHANGED
@@ -16,10 +16,14 @@ import { z } from 'zod';
16
16
  * to mean N polls every 5 s forever; now they mean one publisher while at
17
17
  * least one tab subscribes, and none afterwards.
18
18
  *
19
- * Security: the hub itself never decides who may connect — `attach` takes the
20
- * upgrade guard as a function, and server.ts supplies the WebSocket twin of
21
- * the `/api/*` request-origin guard (#426). See `verifyWsUpgrade` there for
19
+ * Security: the hub itself never decides who may connect — `handleUpgrade`
20
+ * takes the upgrade guard's verdict, and server.ts supplies the WebSocket twin
21
+ * of the `/api/*` request-origin guard (#426). See `verifyWsUpgrade` there for
22
22
  * what it admits, and the caveat about which topics may live on this hub.
23
+ *
24
+ * The hub does not listen on the HTTP server itself: the one `upgrade` listener
25
+ * is `attachUpgradeRouter` (upgrade-router.ts, #781), and `socketHubRoute` is
26
+ * this hub's route in it.
23
27
  */
24
28
  /** The one upgrade path. Workspace-level like `/api/workspace/events` — never
25
29
  * mirrored under `/api/p/:projectId` (topics carry workspace data). */
@@ -99,6 +103,33 @@ export function createSocketHub(options = {}) {
99
103
  state.stop = null;
100
104
  }
101
105
  };
106
+ /** Started by the first upgrade, so a hub nobody connects to holds no timer. */
107
+ const startHeartbeat = () => {
108
+ if (heartbeat !== undefined)
109
+ return;
110
+ heartbeat = setInterval(() => {
111
+ for (const [ws, client] of clients) {
112
+ if (!client.alive) {
113
+ // Missed the previous beat's pong — the peer is gone. Terminate (not
114
+ // a polite close, there is nobody to handshake with); 'close' fires
115
+ // synchronously and dropClient releases its topics.
116
+ ws.terminate();
117
+ continue;
118
+ }
119
+ client.alive = false;
120
+ ws.ping(); // protocol ping — a live browser auto-pongs, flipping `alive` back
121
+ // App-level beat too. The browser NEVER surfaces the protocol ping to
122
+ // page JS, so a client cannot tell a silent-dead socket (sleep, network
123
+ // partition — no FIN ever arrives) from an idle-but-healthy one on the
124
+ // protocol ping alone. This visible frame is what the client's own
125
+ // watchdog watches to decide to reconnect. Sent to every client,
126
+ // subscribed or not; the client ignores it beyond noting liveness.
127
+ send(ws, { type: 'ping' });
128
+ }
129
+ }, heartbeatMs);
130
+ // Never the reason the process stays up — the HTTP server owns lifetime.
131
+ heartbeat.unref?.();
132
+ };
102
133
  const dropClient = (ws) => {
103
134
  const client = clients.get(ws);
104
135
  if (!client)
@@ -108,7 +139,7 @@ export function createSocketHub(options = {}) {
108
139
  clients.delete(ws);
109
140
  };
110
141
  wss.on('connection', (ws, _req, trusted) => {
111
- // `trusted` is emitted by `attach` from the upgrade verdict; default false is
142
+ // `trusted` is emitted by `handleUpgrade` from the upgrade verdict; default false is
112
143
  // the safe read for any path that reaches here without one.
113
144
  const client = { alive: true, topics: new Set(), trusted: trusted === true };
114
145
  clients.set(ws, client);
@@ -150,56 +181,20 @@ export function createSocketHub(options = {}) {
150
181
  loopbackReadable: options?.loopbackReadable ?? false,
151
182
  });
152
183
  },
153
- attach(server, verifyUpgrade) {
154
- // Boot-time wiring like `registerTopic`, so a second call is a programming
155
- // error rather than something to absorb: it would install a second
156
- // `upgrade` listener and orphan the first heartbeat interval (`close`
157
- // clears only the last one). Throw the same way registration does.
158
- if (heartbeat !== undefined)
159
- throw new Error('ws hub already attached');
160
- server.on('upgrade', (req, socket, head) => {
161
- // `req.url` on an upgrade is the request path (+query); the base is
162
- // only there to satisfy URL parsing of a relative reference.
163
- const pathname = new URL(req.url ?? '', 'http://localhost').pathname;
164
- if (pathname !== WS_PATH) {
165
- // With an `upgrade` listener installed, Node no longer auto-destroys
166
- // unhandled upgrades — do it explicitly or the socket leaks.
167
- socket.destroy();
168
- return;
169
- }
170
- const verdict = verifyUpgrade(req);
171
- if (!verdict) {
172
- socket.write('HTTP/1.1 403 Forbidden\r\nconnection: close\r\n\r\n');
173
- socket.destroy();
174
- return;
175
- }
176
- // Carry the verdict's trust flag onto the connection — `subscribe` reads
177
- // it to gate non-`loopbackReadable` topics.
178
- wss.handleUpgrade(req, socket, head, (ws) => wss.emit('connection', ws, req, verdict.trusted));
179
- });
180
- server.on('close', () => hub.close());
181
- heartbeat = setInterval(() => {
182
- for (const [ws, client] of clients) {
183
- if (!client.alive) {
184
- // Missed the previous beat's pong — the peer is gone. Terminate (not
185
- // a polite close, there is nobody to handshake with); 'close' fires
186
- // synchronously and dropClient releases its topics.
187
- ws.terminate();
188
- continue;
189
- }
190
- client.alive = false;
191
- ws.ping(); // protocol ping — a live browser auto-pongs, flipping `alive` back
192
- // App-level beat too. The browser NEVER surfaces the protocol ping to
193
- // page JS, so a client cannot tell a silent-dead socket (sleep, network
194
- // partition — no FIN ever arrives) from an idle-but-healthy one on the
195
- // protocol ping alone. This visible frame is what the client's own
196
- // watchdog watches to decide to reconnect. Sent to every client,
197
- // subscribed or not; the client ignores it beyond noting liveness.
198
- send(ws, { type: 'ping' });
199
- }
200
- }, heartbeatMs);
201
- // Never the reason the process stays up — the HTTP server owns lifetime.
202
- heartbeat.unref?.();
184
+ handleUpgrade(req, socket, head, verdict) {
185
+ if (closed) {
186
+ socket.destroy();
187
+ return;
188
+ }
189
+ if (!verdict) {
190
+ socket.write('HTTP/1.1 403 Forbidden\r\nconnection: close\r\n\r\n');
191
+ socket.destroy();
192
+ return;
193
+ }
194
+ startHeartbeat();
195
+ // Carry the verdict's trust flag onto the connection — `subscribe` reads
196
+ // it to gate non-`loopbackReadable` topics.
197
+ wss.handleUpgrade(req, socket, head, (ws) => wss.emit('connection', ws, req, verdict.trusted));
203
198
  },
204
199
  close() {
205
200
  if (closed)
@@ -215,4 +210,11 @@ export function createSocketHub(options = {}) {
215
210
  };
216
211
  return hub;
217
212
  }
213
+ /** The hub's route in the upgrade router: `WS_PATH`, under `verifyUpgrade`. */
214
+ export function socketHubRoute(hub, verifyUpgrade) {
215
+ return {
216
+ match: (pathname) => (pathname === WS_PATH ? {} : undefined),
217
+ handle: (req, socket, head) => hub.handleUpgrade(req, socket, head, verifyUpgrade(req)),
218
+ };
219
+ }
218
220
  //# sourceMappingURL=ws.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ws.js","sourceRoot":"","sources":["../../src/server/ws.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ws.js","sourceRoot":"","sources":["../../src/server/ws.ts"],"names":[],"mappings":"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"}
@@ -96,6 +96,13 @@ export declare function shouldRecordFetchFailure(opts: {
96
96
  }): boolean;
97
97
  /** Test hook: simulate a process-local failed attempt for this source. */
98
98
  export declare function __markCloneAttemptedForTests(repo: string): void;
99
+ /** Test hook: hold this source's clone/fetch open until `until` settles (#859). */
100
+ export declare function __holdFetchForTests(repo: string, until: Promise<void>): void;
101
+ /**
102
+ * Test hook: park this project's next passive load right after its list-only
103
+ * pass until `until` settles (#859). Resolves once the load has parked there.
104
+ */
105
+ export declare function __pauseAfterCachedListForTests(repoRoot: string, until: Promise<void>): Promise<void>;
99
106
  /**
100
107
  * The current team-skill list for this project, straight from memory. The
101
108
  * first call per `repoRoot` kicks off an async background load (clone + list)
@@ -109,5 +116,12 @@ export declare function getTeamSkillsCached(repoRoot: string): Skill[];
109
116
  * background convergence read after they have already rendered local skills.
110
117
  */
111
118
  export declare function waitForTeamSkills(repoRoot: string): Promise<Skill[]>;
119
+ /**
120
+ * The first load's list of the bare clones already on disk, published before
121
+ * any passive fetch (#859). Never waits on the network: no clone yet means an
122
+ * empty list, not a clone. When a refresh started this project's first load
123
+ * there is no list-only pass, and this answers with the current list.
124
+ */
125
+ export declare function waitForCachedTeamSkills(repoRoot: string): Promise<Skill[]>;
112
126
  /** Refresh: clone missing sources, `git fetch` existing ones, reload the list. */
113
127
  export declare function refreshTeamSkills(repoRoot: string): Promise<Skill[]>;
@@ -452,16 +452,41 @@ export function shouldRecordFetchFailure(opts) {
452
452
  export function __markCloneAttemptedForTests(repo) {
453
453
  cloneAttempted.add(repo);
454
454
  }
455
+ /** Test hook: hold this source's clone/fetch open until `until` settles (#859). */
456
+ export function __holdFetchForTests(repo, until) {
457
+ const held = until.finally(() => {
458
+ if (fetchInFlight.get(repo) === held)
459
+ fetchInFlight.delete(repo);
460
+ });
461
+ fetchInFlight.set(repo, held);
462
+ }
463
+ const cachedListPauses = new Map();
464
+ /**
465
+ * Test hook: park this project's next passive load right after its list-only
466
+ * pass until `until` settles (#859). Resolves once the load has parked there.
467
+ */
468
+ export function __pauseAfterCachedListForTests(repoRoot, until) {
469
+ return new Promise((reached) => { cachedListPauses.set(repoRoot, { reached, until }); });
470
+ }
455
471
  // Both maps are keyed by `repoRoot` (multi-project workspace, step 2.6): each
456
472
  // project resolves its own `.ai/cezar/config.json` → `skillsRepos`, so one
457
473
  // project's team-skill list must never be served under another project's scope.
458
474
  const teamSkillsByRoot = new Map();
459
475
  const firstLoadByRoot = new Map();
476
+ // The first load's list-only pass over the clones already on disk (#859).
477
+ const cachedListByRoot = new Map();
478
+ // Bumped by every post-fetch publication, so a list-only pass that finishes
479
+ // late never replaces a newer list (a concurrent refresh) in `teamSkillsByRoot`.
480
+ const postFetchListsByRoot = new Map();
460
481
  function initialTeamSkillsLoad(repoRoot) {
461
482
  const existing = firstLoadByRoot.get(repoRoot);
462
483
  if (existing)
463
484
  return existing;
464
- const load = loadTeamSkills(repoRoot, false).catch(() => teamSkillsByRoot.get(repoRoot) ?? []);
485
+ let listed;
486
+ cachedListByRoot.set(repoRoot, new Promise((resolve) => { listed = resolve; }));
487
+ const load = loadTeamSkills(repoRoot, false, listed).catch(() => teamSkillsByRoot.get(repoRoot) ?? []);
488
+ // A load that failed before its list-only pass still settles the cached wait.
489
+ void load.then((skills) => listed(skills));
465
490
  firstLoadByRoot.set(repoRoot, load);
466
491
  return load;
467
492
  }
@@ -483,6 +508,16 @@ export function getTeamSkillsCached(repoRoot) {
483
508
  export function waitForTeamSkills(repoRoot) {
484
509
  return initialTeamSkillsLoad(repoRoot);
485
510
  }
511
+ /**
512
+ * The first load's list of the bare clones already on disk, published before
513
+ * any passive fetch (#859). Never waits on the network: no clone yet means an
514
+ * empty list, not a clone. When a refresh started this project's first load
515
+ * there is no list-only pass, and this answers with the current list.
516
+ */
517
+ export function waitForCachedTeamSkills(repoRoot) {
518
+ void initialTeamSkillsLoad(repoRoot);
519
+ return cachedListByRoot.get(repoRoot) ?? Promise.resolve(teamSkillsByRoot.get(repoRoot) ?? []);
520
+ }
486
521
  /** Refresh: clone missing sources, `git fetch` existing ones, reload the list. */
487
522
  export async function refreshTeamSkills(repoRoot) {
488
523
  const load = loadTeamSkills(repoRoot, true).catch(() => teamSkillsByRoot.get(repoRoot) ?? []);
@@ -528,16 +563,55 @@ function fetchBareSource(repo) {
528
563
  fetchInFlight.set(repo, work);
529
564
  return work;
530
565
  }
531
- async function loadTeamSkills(repoRoot, refresh) {
532
- const config = await loadConfig(repoRoot);
566
+ /** First source wins a name, in configured source order. */
567
+ function mergeSourceLists(lists) {
533
568
  const out = [];
534
569
  const seen = new Set();
535
- for (const src of config.skillsRepos) {
570
+ for (const skill of lists.flatMap((list) => list ?? [])) {
571
+ if (seen.has(skill.name))
572
+ continue;
573
+ seen.add(skill.name);
574
+ out.push(skill);
575
+ }
576
+ return out;
577
+ }
578
+ async function loadTeamSkills(repoRoot, refresh, onCachedList) {
579
+ const config = await loadConfig(repoRoot);
580
+ // Passive loads list the clones already on disk BEFORE any fetch (#859): the
581
+ // first restart past the TTL otherwise hides every team skill — and starves a
582
+ // recovered Continue of its playbook — for as long as the fetch takes.
583
+ let cached = [];
584
+ // Each source's stamp as the snapshot saw it. The bare clone and its stamp
585
+ // are shared by every project and process, so a fetch made for another
586
+ // project never bumps this one's generation; a moved stamp is how it shows.
587
+ let snapshotStamps = [];
588
+ const generation = postFetchListsByRoot.get(repoRoot) ?? 0;
589
+ // True once another load has published a post-fetch list since this one
590
+ // started: its snapshot may predate that list, so it must not win (#859).
591
+ const superseded = () => (postFetchListsByRoot.get(repoRoot) ?? 0) !== generation;
592
+ if (!refresh) {
593
+ snapshotStamps = config.skillsRepos.map((src) => readLastFetchAt(bareDirFor(src.repo)));
594
+ cached = await Promise.all(config.skillsRepos.map((src) => listRemoteSkills(src).catch(() => undefined)));
595
+ const pause = cachedListPauses.get(repoRoot);
596
+ if (pause) {
597
+ cachedListPauses.delete(repoRoot);
598
+ pause.reached();
599
+ await pause.until;
600
+ }
601
+ const listed = mergeSourceLists(cached);
602
+ if (!superseded())
603
+ teamSkillsByRoot.set(repoRoot, listed);
604
+ onCachedList?.(listed);
605
+ }
606
+ const lists = [];
607
+ for (const [index, src] of config.skillsRepos.entries()) {
536
608
  const now = Date.now();
537
609
  if (stampIsFresh(src.repo, now))
538
610
  cloneAttempted.delete(src.repo);
611
+ let fetched = false;
539
612
  try {
540
613
  if (refresh) {
614
+ fetched = true;
541
615
  await fetchBareSource(src.repo);
542
616
  }
543
617
  else if (shouldPassiveFetch({
@@ -546,24 +620,26 @@ async function loadTeamSkills(repoRoot, refresh) {
546
620
  ttlMs: PASSIVE_FETCH_TTL_MS,
547
621
  }) &&
548
622
  !cloneAttempted.has(src.repo)) {
623
+ fetched = true;
549
624
  await fetchBareSource(src.repo);
550
625
  }
551
626
  }
552
627
  catch {
553
628
  // offline / no access — list whatever an older clone has (or nothing)
554
629
  }
555
- try {
556
- for (const skill of await listRemoteSkills(src)) {
557
- if (seen.has(skill.name))
558
- continue;
559
- seen.add(skill.name);
560
- out.push(skill);
561
- }
562
- }
563
- catch {
564
- // degrade: this source contributes nothing
565
- }
630
+ // An unfetched source has not moved since the list-only pass unless
631
+ // another load fetched it meanwhile; reuse the snapshot only then.
632
+ const unmoved = !superseded() && readLastFetchAt(bareDirFor(src.repo)) === snapshotStamps[index];
633
+ const listed = fetched || !unmoved ? undefined : cached[index];
634
+ // degrade: a source that fails to list contributes nothing
635
+ lists.push(listed ?? (await listRemoteSkills(src).catch(() => undefined)));
566
636
  }
637
+ const out = mergeSourceLists(lists);
638
+ // A refresh always publishes. A passive load that a newer post-fetch list
639
+ // overtook defers to it rather than replacing it with an older view.
640
+ if (!refresh && superseded())
641
+ return teamSkillsByRoot.get(repoRoot) ?? out;
642
+ postFetchListsByRoot.set(repoRoot, (postFetchListsByRoot.get(repoRoot) ?? 0) + 1);
567
643
  teamSkillsByRoot.set(repoRoot, out);
568
644
  return out;
569
645
  }