@wjarka/cezarion 0.14.8 → 0.14.9-dev.1004

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 (274) hide show
  1. package/README.md +129 -2
  2. package/dist/application-update/bin-recovery.d.ts +5 -0
  3. package/dist/application-update/bin-recovery.js +96 -0
  4. package/dist/application-update/bin-recovery.js.map +1 -0
  5. package/dist/application-update/discovery.d.ts +22 -0
  6. package/dist/application-update/discovery.js +91 -0
  7. package/dist/application-update/discovery.js.map +1 -0
  8. package/dist/application-update/helper.d.ts +57 -0
  9. package/dist/application-update/helper.js +374 -0
  10. package/dist/application-update/helper.js.map +1 -0
  11. package/dist/application-update/launcher.d.ts +8 -0
  12. package/dist/application-update/launcher.js +53 -0
  13. package/dist/application-update/launcher.js.map +1 -0
  14. package/dist/application-update/lock.d.ts +4 -0
  15. package/dist/application-update/lock.js +70 -0
  16. package/dist/application-update/lock.js.map +1 -0
  17. package/dist/application-update/npm-process.d.ts +17 -0
  18. package/dist/application-update/npm-process.js +133 -0
  19. package/dist/application-update/npm-process.js.map +1 -0
  20. package/dist/application-update/service.d.ts +69 -0
  21. package/dist/application-update/service.js +456 -0
  22. package/dist/application-update/service.js.map +1 -0
  23. package/dist/artifacts/cli.d.ts +1 -0
  24. package/dist/artifacts/cli.js +32 -0
  25. package/dist/artifacts/cli.js.map +1 -0
  26. package/dist/artifacts/lifecycle.d.ts +4 -0
  27. package/dist/artifacts/lifecycle.js +42 -0
  28. package/dist/artifacts/lifecycle.js.map +1 -0
  29. package/dist/artifacts/resolve.d.ts +18 -0
  30. package/dist/artifacts/resolve.js +102 -0
  31. package/dist/artifacts/resolve.js.map +1 -0
  32. package/dist/artifacts/store.d.ts +8 -0
  33. package/dist/artifacts/store.js +323 -0
  34. package/dist/artifacts/store.js.map +1 -0
  35. package/dist/automations/scheduler.d.ts +6 -0
  36. package/dist/automations/scheduler.js +45 -17
  37. package/dist/automations/scheduler.js.map +1 -1
  38. package/dist/automations/store.d.ts +12 -4
  39. package/dist/automations/store.js +199 -22
  40. package/dist/automations/store.js.map +1 -1
  41. package/dist/automations/types.d.ts +2 -0
  42. package/dist/automations/types.js +1 -0
  43. package/dist/automations/types.js.map +1 -1
  44. package/dist/ci-wait/mcp.d.ts +3 -0
  45. package/dist/ci-wait/mcp.js +14 -3
  46. package/dist/ci-wait/mcp.js.map +1 -1
  47. package/dist/contract/application-update.d.ts +32 -0
  48. package/dist/contract/artifacts.d.ts +83 -0
  49. package/dist/contract/ask-schema.d.ts +32 -0
  50. package/dist/contract/ask.d.ts +2 -32
  51. package/dist/contract/automations.d.ts +6 -0
  52. package/dist/contract/conversations.d.ts +165 -0
  53. package/dist/contract/delegation.d.ts +68 -0
  54. package/dist/contract/discovery.d.ts +134 -0
  55. package/dist/contract/events.d.ts +49 -0
  56. package/dist/contract/health.d.ts +12 -0
  57. package/dist/contract/index.d.ts +3 -0
  58. package/dist/contract/index.js +1654 -1454
  59. package/dist/contract/projects.d.ts +40 -0
  60. package/dist/contract/runs.d.ts +186 -0
  61. package/dist/contract/skills.d.ts +33 -0
  62. package/dist/core/agent-runner.d.ts +33 -4
  63. package/dist/core/agent-runner.js +5 -0
  64. package/dist/core/agent-runner.js.map +1 -1
  65. package/dist/core/claude-cli-runner.d.ts +6 -12
  66. package/dist/core/claude-cli-runner.js +90 -20
  67. package/dist/core/claude-cli-runner.js.map +1 -1
  68. package/dist/core/codex-app-server-runner.d.ts +2 -1
  69. package/dist/core/codex-app-server-runner.js +327 -92
  70. package/dist/core/codex-app-server-runner.js.map +1 -1
  71. package/dist/core/codex-app-server-transport.d.ts +13 -1
  72. package/dist/core/codex-app-server-transport.js +58 -17
  73. package/dist/core/codex-app-server-transport.js.map +1 -1
  74. package/dist/core/cursor-acp-runner.d.ts +6 -1
  75. package/dist/core/cursor-acp-runner.js +162 -26
  76. package/dist/core/cursor-acp-runner.js.map +1 -1
  77. package/dist/core/cursor-provider-error.d.ts +3 -0
  78. package/dist/core/cursor-provider-error.js +16 -1
  79. package/dist/core/cursor-provider-error.js.map +1 -1
  80. package/dist/core/input-submissions.d.ts +14 -0
  81. package/dist/core/input-submissions.js +26 -0
  82. package/dist/core/input-submissions.js.map +1 -0
  83. package/dist/core/opencode-server-runner.d.ts +4 -1
  84. package/dist/core/opencode-server-runner.js +156 -26
  85. package/dist/core/opencode-server-runner.js.map +1 -1
  86. package/dist/core/pi-runner.d.ts +2 -1
  87. package/dist/core/pi-runner.js +88 -10
  88. package/dist/core/pi-runner.js.map +1 -1
  89. package/dist/core/provider-auth.d.ts +99 -1
  90. package/dist/core/provider-auth.js +203 -2
  91. package/dist/core/provider-auth.js.map +1 -1
  92. package/dist/delegation/cli.d.ts +1 -0
  93. package/dist/delegation/cli.js +103 -7
  94. package/dist/delegation/cli.js.map +1 -1
  95. package/dist/delegation/conversations.js +13 -5
  96. package/dist/delegation/conversations.js.map +1 -1
  97. package/dist/delegation/input.d.ts +2 -1
  98. package/dist/delegation/input.js +6 -1
  99. package/dist/delegation/input.js.map +1 -1
  100. package/dist/delegation/policy.d.ts +3 -2
  101. package/dist/delegation/policy.js +3 -1
  102. package/dist/delegation/policy.js.map +1 -1
  103. package/dist/delegation/process-liveness.d.ts +66 -0
  104. package/dist/delegation/process-liveness.js +215 -0
  105. package/dist/delegation/process-liveness.js.map +1 -0
  106. package/dist/delegation/provision.d.ts +1 -1
  107. package/dist/delegation/provision.js +10 -5
  108. package/dist/delegation/provision.js.map +1 -1
  109. package/dist/delegation/questions.d.ts +19 -0
  110. package/dist/delegation/questions.js +45 -0
  111. package/dist/delegation/questions.js.map +1 -0
  112. package/dist/delegation/results.d.ts +1 -1
  113. package/dist/delegation/results.js +33 -19
  114. package/dist/delegation/results.js.map +1 -1
  115. package/dist/delegation/routes.d.ts +185 -11
  116. package/dist/delegation/routes.js +6 -2
  117. package/dist/delegation/routes.js.map +1 -1
  118. package/dist/delegation/service.d.ts +16 -5
  119. package/dist/delegation/service.js +161 -13
  120. package/dist/delegation/service.js.map +1 -1
  121. package/dist/delegation/transport.d.ts +228 -65
  122. package/dist/discovery/catalog.d.ts +14 -0
  123. package/dist/discovery/catalog.js +31 -0
  124. package/dist/discovery/catalog.js.map +1 -0
  125. package/dist/discovery/cli.d.ts +8 -0
  126. package/dist/discovery/cli.js +104 -0
  127. package/dist/discovery/cli.js.map +1 -0
  128. package/dist/git-worktree.d.ts +3 -1
  129. package/dist/git-worktree.js +26 -4
  130. package/dist/git-worktree.js.map +1 -1
  131. package/dist/index.js +92 -26
  132. package/dist/index.js.map +1 -1
  133. package/dist/open-url.d.ts +2 -0
  134. package/dist/open-url.js +20 -0
  135. package/dist/open-url.js.map +1 -0
  136. package/dist/release/snapshot.d.ts +3 -3
  137. package/dist/release/snapshot.js +6 -6
  138. package/dist/release/snapshot.js.map +1 -1
  139. package/dist/runs/agent-tmpdir.d.ts +2 -0
  140. package/dist/runs/agent-tmpdir.js +5 -2
  141. package/dist/runs/agent-tmpdir.js.map +1 -1
  142. package/dist/runs/client-request.d.ts +11 -0
  143. package/dist/runs/client-request.js +26 -0
  144. package/dist/runs/client-request.js.map +1 -0
  145. package/dist/runs/delegation-state.d.ts +17 -0
  146. package/dist/runs/event-history.js +6 -0
  147. package/dist/runs/event-history.js.map +1 -1
  148. package/dist/runs/retention.d.ts +7 -2
  149. package/dist/runs/retention.js +39 -7
  150. package/dist/runs/retention.js.map +1 -1
  151. package/dist/runs/store.d.ts +100 -6
  152. package/dist/runs/store.js +245 -2
  153. package/dist/runs/store.js.map +1 -1
  154. package/dist/runs/webhook.d.ts +125 -0
  155. package/dist/runs/webhook.js +256 -0
  156. package/dist/runs/webhook.js.map +1 -0
  157. package/dist/server/provider-auth-runtime.d.ts +30 -4
  158. package/dist/server/provider-auth-runtime.js +71 -6
  159. package/dist/server/provider-auth-runtime.js.map +1 -1
  160. package/dist/server/server.d.ts +8226 -4860
  161. package/dist/server/server.js +309 -15
  162. package/dist/server/server.js.map +1 -1
  163. package/dist/server-install/platforms/ubuntu-vps.d.ts +5 -1
  164. package/dist/server-install/platforms/ubuntu-vps.js +160 -18
  165. package/dist/server-install/platforms/ubuntu-vps.js.map +1 -1
  166. package/dist/server-install/steps.d.ts +4 -2
  167. package/dist/server-install/steps.js +5 -4
  168. package/dist/server-install/steps.js.map +1 -1
  169. package/dist/skills-remote.d.ts +30 -5
  170. package/dist/skills-remote.js +122 -32
  171. package/dist/skills-remote.js.map +1 -1
  172. package/dist/skills.js +15 -6
  173. package/dist/skills.js.map +1 -1
  174. package/dist/task-cli/cli.d.ts +38 -0
  175. package/dist/task-cli/cli.js +580 -0
  176. package/dist/task-cli/cli.js.map +1 -0
  177. package/dist/task-cli/discovery.d.ts +22 -0
  178. package/dist/task-cli/discovery.js +96 -0
  179. package/dist/task-cli/discovery.js.map +1 -0
  180. package/dist/task-cli/http.d.ts +46 -0
  181. package/dist/task-cli/http.js +101 -0
  182. package/dist/task-cli/http.js.map +1 -0
  183. package/dist/task-cli/projections.d.ts +40 -0
  184. package/dist/task-cli/projections.js +45 -0
  185. package/dist/task-cli/projections.js.map +1 -0
  186. package/dist/task-cli/watch.d.ts +78 -0
  187. package/dist/task-cli/watch.js +336 -0
  188. package/dist/task-cli/watch.js.map +1 -0
  189. package/dist/workflows/run.d.ts +160 -2
  190. package/dist/workflows/run.js +1141 -108
  191. package/dist/workflows/run.js.map +1 -1
  192. package/dist/workspace/agent-profiles.d.ts +22 -0
  193. package/dist/workspace/agent-profiles.js +15 -0
  194. package/dist/workspace/agent-profiles.js.map +1 -1
  195. package/dist/workspace/config.d.ts +9 -0
  196. package/dist/workspace/config.js +13 -1
  197. package/dist/workspace/config.js.map +1 -1
  198. package/dist/workspace/projects-cli.js +1 -1
  199. package/dist/workspace/projects.d.ts +24 -1
  200. package/dist/workspace/projects.js +14 -1
  201. package/dist/workspace/projects.js.map +1 -1
  202. package/package.json +5 -5
  203. package/scripts/mock-claude.mjs +64 -2
  204. package/scripts/mock-codex-app-server.mjs +124 -1
  205. package/scripts/mock-cursor-acp.mjs +54 -3
  206. package/scripts/mock-cursor-hang-stdin-late.mjs +35 -0
  207. package/scripts/mock-cursor-hang-stdin.mjs +30 -0
  208. package/scripts/mock-opencode-serve.mjs +102 -2
  209. package/scripts/mock-pi-rpc.mjs +82 -3
  210. package/web/dist/assets/agent-accounts-CerclGiO.js +1 -0
  211. package/web/dist/assets/centered-state-DH8qtCz-.js +43 -0
  212. package/web/dist/assets/collapsible-De2G0xqQ.js +1 -0
  213. package/web/dist/assets/commit-list-CQubP1iS.js +1 -0
  214. package/web/dist/assets/compare-variants-C_NijJvg.js +1 -0
  215. package/web/dist/assets/{diff-tRE59UNb2.js → diff-8M5HlDxq2.js} +2 -2
  216. package/web/dist/assets/diff-controls-B6ok0TtQ.js +1 -0
  217. package/web/dist/assets/{diff-stat-Cgnl_hYF.js → diff-stat-D1AODN2a.js} +1 -1
  218. package/web/dist/assets/{diff-view-DN1ort7Q.js → diff-view-Bs5Gh7UF.js} +2 -2
  219. package/web/dist/assets/dropdown-menu-7KGQMoFj.js +1 -0
  220. package/web/dist/assets/git-toolbar-DqbapMXr.js +1 -0
  221. package/web/dist/assets/github-lMHiuYSx.js +1 -0
  222. package/web/dist/assets/{image-preview-C2JGcBlC.js → image-preview-jzHoEyLM.js} +1 -1
  223. package/web/dist/assets/index-D4OJTArJ.js +7 -0
  224. package/web/dist/assets/index-D5NkwqY7.css +1 -0
  225. package/web/dist/assets/markdown-DvbymqXz.js +2 -0
  226. package/web/dist/assets/pill-BL6ugwXo.js +1 -0
  227. package/web/dist/assets/project-router-ChC5Rb-Y.js +1 -0
  228. package/web/dist/assets/prompt-templates-j8qlK7c-.js +15 -0
  229. package/web/dist/assets/repo-git-BbPAgkqb.js +1 -0
  230. package/web/dist/assets/{run-diff-CyG0Nciv.js → run-diff-BuATgZpx.js} +2 -2
  231. package/web/dist/assets/run-header-DuAWswYM.js +1 -0
  232. package/web/dist/assets/skills-DiC2XrU1.js +1 -0
  233. package/web/dist/assets/{tab-link-BWNp3mLY.js → tab-link-BmGKj9Rt.js} +1 -1
  234. package/web/dist/assets/task-changes-CP9kPnsy.js +1 -0
  235. package/web/dist/assets/task-commits-D6NfTw5r.js +1 -0
  236. package/web/dist/assets/task-files-W-b_gtcb.js +2 -0
  237. package/web/dist/assets/task-thread-Bw_nQuTx.css +1 -0
  238. package/web/dist/assets/task-thread-Q7Nj33DH.js +9 -0
  239. package/web/dist/assets/textarea-ByZ-txS7.js +1 -0
  240. package/web/dist/assets/thread-loading-DHT9p5o5.js +1 -0
  241. package/web/dist/assets/token-metrics-k4XoovDS.js +1 -0
  242. package/web/dist/assets/utils-BTFBhZ55.js +64 -0
  243. package/web/dist/assets/workflows-DqQszPHJ.js +11 -0
  244. package/web/dist/assets/{zoomable-image-Z3JDnm0b.js → zoomable-image-Ba6y6Wyl.js} +1 -1
  245. package/web/dist/index.html +14 -14
  246. package/web/dist/assets/agent-accounts-BZm_2WAv.js +0 -1
  247. package/web/dist/assets/alert-dialog-B422RI-k.js +0 -43
  248. package/web/dist/assets/collapsible-Cy_Fmkrd.js +0 -1
  249. package/web/dist/assets/commit-list-Dcnk7TnI.js +0 -1
  250. package/web/dist/assets/compare-variants-Ciqwvd_f.js +0 -1
  251. package/web/dist/assets/diff-controls-BGrXGi7O.js +0 -1
  252. package/web/dist/assets/dropdown-menu-dwDGT8MM.js +0 -1
  253. package/web/dist/assets/git-toolbar-UiHnGvE0.js +0 -1
  254. package/web/dist/assets/github-D-MrkbJ7.js +0 -1
  255. package/web/dist/assets/ibm-plex-mono-regular-BF3vfe7_.ttf +0 -0
  256. package/web/dist/assets/index-BszfYvBq.js +0 -7
  257. package/web/dist/assets/index-CWh4pKP3.css +0 -1
  258. package/web/dist/assets/markdown-C_IcKVQd.js +0 -2
  259. package/web/dist/assets/pill-BsbO6G7y.js +0 -1
  260. package/web/dist/assets/project-router-DbLkll25.js +0 -1
  261. package/web/dist/assets/prompt-templates-BlTGJB5W.js +0 -15
  262. package/web/dist/assets/repo-git-Bm3s6Why.js +0 -1
  263. package/web/dist/assets/run-header-IFyIGCey.js +0 -1
  264. package/web/dist/assets/skills-C-C4DVFY.js +0 -1
  265. package/web/dist/assets/task-changes-D2PHtWUW.js +0 -1
  266. package/web/dist/assets/task-commits-N5u9U0_R.js +0 -1
  267. package/web/dist/assets/task-files-BS7c7CFm.js +0 -2
  268. package/web/dist/assets/task-thread-BQFdz1dJ.css +0 -1
  269. package/web/dist/assets/task-thread-DGM2dZV-.js +0 -9
  270. package/web/dist/assets/textarea-FjaU370i.js +0 -1
  271. package/web/dist/assets/thread-loading-77sJ8Yu_.js +0 -1
  272. package/web/dist/assets/token-metrics-Clxh03bE.js +0 -1
  273. package/web/dist/assets/utils-PYYcpCFZ.js +0 -64
  274. package/web/dist/assets/workflows-Czl0ZfXH.js +0 -11
package/README.md CHANGED
@@ -38,6 +38,19 @@ That's the whole setup. If your `claude` CLI is logged in (Pro/Max) and `gh` is
38
38
  authenticated, there is nothing else to configure. State lives in `.ai/cezar/`
39
39
  inside your repo — plain JSON, NDJSON and Markdown you can `cat` and fix by hand.
40
40
 
41
+ Local npm installations have a workspace update API. `POST
42
+ /api/v1/workspace/application-update/apply` with `{}` prepares the release
43
+ advertised by health while the current server keeps running; `POST
44
+ /api/v1/workspace/application-update/restart` with `{}` then restarts it. A
45
+ successful restart updates the original global installation or ordinary npx
46
+ cache entry, so the same command uses the new version on its next launch.
47
+ Update preparation and recovery state is generated under
48
+ `~/.cezar/application-updates/` (or `CEZ_HOME`).
49
+ Pinned npx invocations, source checkouts, npm links, and hosted deployments use
50
+ their existing manual update paths. Cezar holds its own installation lock and
51
+ npm's npx lock during promotion; a separate manual `npm install` does not honor
52
+ those locks, so avoid one while an update is preparing or restarting.
53
+
41
54
  ## A look inside
42
55
 
43
56
  Click any thumbnail for the full-size screenshot.
@@ -202,7 +215,7 @@ Every green CI run also publishes an installable npm snapshot
202
215
  merged yet:
203
216
 
204
217
  ```bash
205
- npx cezarion@develop # current develop head
218
+ npx cezarion@dev # current main head
206
219
  ```
207
220
 
208
221
  Every pull request gets its own preview too — the CI bot posts a sticky comment
@@ -495,6 +508,21 @@ not settings to create or share. If the tool is unavailable or denied, its error
495
508
  is surfaced while ordinary tasks continue. See [the CI-wait protocol](AGENT_PROTOCOL.md#ci-wait-tool-contract-474)
496
509
  for limits and the executable harness verification required before release.
497
510
 
511
+ ## Discover runners and models
512
+
513
+ Inspect the same host catalog the cockpit uses before selecting a runner or model:
514
+
515
+ ```sh
516
+ cez discover runners
517
+ cez discover models --runner=codex
518
+ ```
519
+
520
+ Both commands return JSON. `runners` lists connection status (`connected`, `disconnected`, `not-installed`, or `unknown`) and enablement, with `scope: "host-default-account"`. Model rows include `effortLevels` when the runner advertises them: an absent field means unknown; an empty array means no advertised levels. Omit `--effort` when spawning to keep the existing default. Model responses retain `source`, `stale`, and any unavailable `reason`; discovery never invents model IDs or effort support.
521
+
522
+ For operators, the command finds the running cockpit for the current checkout; `--repo`, `--url`, and `CEZ_URL` work as they do for `cez task`. A missing cockpit returns an error and never starts a server. Inside a parent delegation session, the same command uses that session's authenticated controller, including headless runs. It rejects `--url` and `--repo` in that context and never falls back to a public cockpit after an authentication failure. Owned workers cannot use the private discovery route.
523
+
524
+ The catalog describes host default accounts, not every named account or the selections permitted by a task's model locks and workflow pins. Existing `cez task start` and `cez worker spawn` still call their runner flag `--backend`; discovery uses `--runner`.
525
+
498
526
  ## Owned workers (opt-in)
499
527
 
500
528
  Start the cockpit or a headless task with `CEZ_DELEGATION=1`. Each eligible parent session receives the absolute bundled Node/CLI invocation and its own environment credentials; no `cez` installation on the agent's PATH, config file, separate daemon, or remembered port is needed. If the private listener cannot start, ordinary tasks keep working without delegation tools. `.env` is never loaded automatically.
@@ -530,6 +558,8 @@ Use `cez worker --help` to list operations and flags, or `cez worker <operation>
530
558
 
531
559
  `--workflow <name>` runs a catalog workflow inside the worker: the built-in `quick-task` or any `.ai/cezar/workflows/*.yaml` by name, with its agent and check steps, `skill:` bodies and `onFail` loops, so a repo's `review.yaml` becomes a dedicated reviewer. Omitted `--workflow` runs `quick-task` exactly as before. `--backend`, `--model` and `--effort` fill only the steps that leave those fields unset; a step's own `allowedTools`/`bashAllowlist` narrow the parent's grants and never widen them. An unknown name is refused. Agent steps may mix runners: at spawn every agent step is resolved and pinned separately, so an implement-with-codex, review-with-claude chain runs each step under its own runner, account, model, effort and grants. A step's optional `agentProfile` names the account it runs under (an id the registry does not know is refused); same-backend steps otherwise inherit the parent's account and other runners resolve their project/default one. Run-level columns show the first agent step.
532
560
 
561
+ Explicit default-account model pins are checked against a fresh, nonempty host catalog after account/model resolution and before a worker is created. Named accounts retain existing validation because a default-account catalog cannot disprove their model access. A miss returns `invalid_input`, available models with advertised efforts, and other runners listing the requested ID in `modelChoices`. Empty, stale, or unavailable discovery leaves existing selection validation in place. Accepted retries and omitted model defaults are unchanged.
562
+
533
563
  Omitted `--backend` inherits the parent's active backend. Same-backend workers inherit omitted model/account/effort; `--backend <claude|codex|opencode|pi|cursor>` selecting another backend resolves that backend's project/default account and model without forwarding another provider's settings. `--model <model>` selects a supported model, subject to existing locks. `--effort <low|medium|high|xhigh|max>` pins reasoning effort on same-backend and mixed-backend spawn; omitted `--effort` still inherits the parent pin on same-backend spawn and drops it on mixed-backend spawn. Accepted identity and grants remain fixed across queuing, restart and Continue, including explicit empty grants. Changing or deleting an account registry entry does not rebind a worker. Missing accepted identity evidence or account homes, incompatible Claude state-file layouts, and conflicting later model locks refuse execution explicitly. Credentials and vendor configuration are never copied; each worker receives its own delegation credential, and unspecified native models stay unspecified.
534
564
 
535
565
  Wait registers immediately. End the parent turn to release scheduler capacity; Cezar resumes it on a selected settled outcome or the finite deadline. `any` is the default, `one` requires exactly one worker, and `all` waits for every selected worker. Review, completion, failure, cancellation with proven termination, and destruction are outcomes. Timeout defaults to 600 seconds (1–1800 accepted). `cancel-wait` is idempotent for the retained wait ID and cannot cancel a newer wait. Timeout and wait cancellation report partial outcomes and unresolved workers, never cancel workers, and never automatically re-wait. Steering is attributed agent input and cannot answer a pending human question.
@@ -538,7 +568,7 @@ Parents and owned workers can converse in both directions; a worker may address
538
568
 
539
569
  Messages allow 100,000 characters each, with at most 32 undelivered inputs per recipient, 1,024 messages per family, and 32 pending requests. Request deadlines default to 600 seconds, configurable per message with `--timeout-seconds 1–1800`. Request waits use the same limits and `one`/`any`/`all` modes as worker waits, and each run has one active wait. Incoming conversation can interrupt a parked wait without settling its requests. `cancel-request` cancels an obligation; `cancel-wait` only stops waiting. Completion without a reply, failure, cancellation, destruction, timeout, or sender closure settle obligations distinctly. Late replies remain visible without reopening them.
540
570
 
541
- Pending conversations are delivered together at the next safe turn boundary, in order, up to 32 messages and 100,000 formatted characters per batch. A single valid message is never split. Messages arriving during that turn wait for the next boundary. Every message retains its ID, sender, delivery receipt and request outcome. Human questions, active turns and scheduler capacity can delay delivery. The thread's Details distinguish creation, delivery confirmation and event-recording times.
571
+ Messages reach a live recipient as soon as they are accepted, including mid-turn: Claude, Codex, Pi and OpenCode steer them into the running turn, and the model reads them at its next step. Cursor delivers at the turn boundary, because a second prompt would cancel its running turn. Pending conversations go together, in order, up to 32 messages and 100,000 formatted characters per batch; a single valid message is never split. Every message keeps its ID, sender, delivery receipt and request outcome; receipts show queued, delivered and read (when the agent's harness can tell) separately. A pending human question holds messages until it is answered, then they follow right behind the answer. The thread's Details distinguish creation, delivery confirmation and event-recording times.
542
572
 
543
573
  Sending to a review or terminal participant without `--resume` reports `not-delivered` and `continuation-required`, with the reason and next command; the CLI exits 1. An active parent can use `worker send --resume` (request or progress) to continue its settled done/review/failed worker with that message as the new instruction. No human Continue is needed for this parent-controlled action. A retry with the same payload and ID never creates another continuation; changing a rejected send to use `--resume` requires a new ID. Stopped or destroyed workers need a new worker. Workers cannot resume parents, and conversation never answers a pending human question. Durable IDs deduplicate accepted queue entries and event replay, but a crash between provider acceptance and its durable delivery checkpoint can leave transport delivery ambiguous; this is not an exactly-once execution guarantee.
544
574
 
@@ -552,6 +582,67 @@ Stop requests cancellation; `stopping` does not prove termination. Destroy check
552
582
  Provisioned sessions prefer cezar workers and suppress verified native delegation entry points through per-run adapter controls: Claude `Agent`/legacy `Task` denies, Codex multi-agent feature overrides, OpenCode session `task` denies, and pi's known `subagent` extension exclusion. See [the backend capability table](AGENT_PROTOCOL.md#governed-delegation-controls-d1) for tested versions and exemptions. Native workers are not tracked by cezar. Pi has no native delegation primitive or universal identifier for arbitrary custom delegation extensions; guidance does not enforce those cases. With delegation disabled or unavailable, ordinary tools/settings stay unchanged. The listener binds to `127.0.0.1`, including hosted cockpit mode. Its credentials authorize only the parent's own workers through that listener. This is cooperative local-agent supervision; same-user unrestricted shell and custom tools are not hard isolation. Workers cannot delegate or message peers through cezar. Review remains a human gate with no automatic acceptance. Never read, echo, forward, or persist the generated token.
553
583
 
554
584
 
585
+ ## From the terminal: `cez task`
586
+
587
+ `cez task` starts, watches and steers tasks **in the running cockpit** from a shell — for you, or
588
+ for a bot driving one. Every command prints one JSON object and exits with a code the caller can
589
+ branch on, so nothing has to parse prose. It never starts a server: it finds the cockpit whose
590
+ project registry holds this checkout (ports 4321–4370; a task worktree resolves to its parent
591
+ project), or you point it at one with `--url` / `CEZ_URL`.
592
+
593
+ ```bash
594
+ id=$(cez task start --task-file - <<'EOF' | jq -r .id
595
+ Fix the `cez task` docs. Keep $(example) and "quotes" literal.
596
+ EOF
597
+ )
598
+ cez task wait "$id" --until attention --timeout-seconds 900 # 0 done/review · 1 failed · 3 timeout
599
+ cez task status "$id" # slim JSON: status, question, branch, diffStat…
600
+ cez task send "$id" 'Use the retry helper instead' # queued, delivered, or --resume to reopen
601
+ cez task log "$id" --follow --timeout-seconds 300 # JSON lines until it ends
602
+ ```
603
+
604
+ Use `--task-file PATH` to read a saved task (for example, `cez task start --task-file task.md`),
605
+ or `--task-file -` to read stdin as above. The quoted heredoc delimiter (`<<'EOF'`) keeps
606
+ backticks and `$()` literal in the task text.
607
+
608
+ POSIX shells, including Bash, expand backticks and `$()` in double-quoted arguments before
609
+ cez receives the text. **Do not put raw backticks in double-quoted task arguments.** This can
610
+ execute parts of your prompt as shell commands and leave holes in the stored task, including
611
+ when starting tasks through SSH and `bash -lc`. Prefer a task file or stdin with a quoted
612
+ heredoc delimiter. A single-quoted positional argument still works for short tasks:
613
+ `cez task start 'Fix the typo'`.
614
+
615
+ `cez task start --task-file task.md --skill <name>` names one skill as the task's agent step;
616
+ `--skill` and `--workflow` are mutually exclusive. The CLI checks `GET /skills` first and
617
+ includes a `warning` in its JSON result if the skill is missing or the catalog cannot be
618
+ checked; it still starts the run. Like a cockpit skill start, if the skill is missing at
619
+ execution, the agent uses the plain prompt and the run logs a note. CLI starts do not change
620
+ the cockpit composer's recent picks or skill-usage ranking.
621
+ Without either flag, `start` still runs `quick-task`.
622
+
623
+ `start` is retry-safe: it sends a request id (`--request-id <UUID>` to pick your own), and a
624
+ retry with the same id and task answers with the run the first one created (`created: false`)
625
+ instead of starting a second. Also: `list`, `stop`, `finish`, `diff [--stat]`, `open`.
626
+ Use `archive <id>` to hide a task from `list`, `unarchive <id>` to restore it, and
627
+ `list --all` to include archived tasks. `archive-finished` sweeps finished tasks and prints
628
+ `{"archived": count}`. The single-task commands print `{"id": "…", "archived": true|false}`.
629
+ Exit codes:
630
+ `0` ok, `1` task failed/cancelled or a message was not delivered, `2` no cockpit or the cockpit
631
+ refused (its `error` is passed through), `3` timed out, `64` usage error. `cez task --help` lists
632
+ every flag.
633
+
634
+ **A bot that lives behind an HTTP endpoint** does not have to poll. Set a **Task webhook** (URL
635
+ and an optional Bearer token) in the project's **Settings → General**, and every task that opts
636
+ in POSTs `task.status` on each status change, `task.question` when it asks something,
637
+ `task.activity` when monitoring starts or ends, and `task.subscribed` when it opts in (at start, or when it is handed off). Each
638
+ body carries the same slim projection `cez task status` prints, under `task`. `cez task start`
639
+ opts in whenever the project has a webhook (`--no-notify` to skip it); the cockpit's New task form
640
+ has a **Notify webhook** toggle; and a running task's **Hand off** button (or
641
+ `cez task notify <id> --message '…'`) turns it on later with a note for the bot. The note goes to
642
+ the webhook only, never to the agent. Delivery is best-effort: 10 s timeout, 3 attempts, and a
643
+ failure shows in the thread without touching the task. The token is stored in `~/.cezar` and never
644
+ sent back to a browser. Under `CEZ_DRY_RUN=1` nothing is sent; the payload is logged in the thread.
645
+
555
646
  ## Workflow format
556
647
 
557
648
  A workflow is a small YAML file in `.ai/cezar/workflows/`:
@@ -611,6 +702,7 @@ Useful environment variables:
611
702
  |---|---|
612
703
  | `CEZ_DELEGATION=1` | Enable owned workers and the private loopback listener for this controller. Off by default; works with the cockpit and headless `cez run`. Session instructions and credentials are automatic. |
613
704
  | `CEZ_DELEGATION_URL`, `CEZ_DELEGATION_TOKEN` | Internal generated session values; do not configure or copy them. Tokens rotate on Continue/restart and are revoked when the session/controller closes. |
705
+ | `CEZ_URL` | Cockpit origin for `cez task` and operator `cez discover` (e.g. a hosted `CEZ_REMOTE` cockpit). Unset, they find the local cockpit serving this checkout on ports 4321–4370. Parent discovery uses its delegation controller instead. |
614
706
  | `CEZ_DRY_RUN=1` | Use bundled mocks for all five agent backends — the cockpit works offline for demos and development. Explicit backend binary overrides still win. |
615
707
  | `CEZ_AGENT_MODELS_LOCKED=1` | Globally lock each runner to the model configured in its native Claude/Codex/OpenCode settings while keeping runner selection available. Exact `1` also delegates authentication and provider enablement to those native agents, so Cezar skips its credential probes and provider-disable preferences. Existing Cezar presets are preserved but ignored, and an environment change requires a restart. The config-file equivalent is `"modelsLocked": true` in global `~/.cezar/config.json` or one repository's `.ai/cezar/config.json`; config-file locks do not disable provider checks. |
616
708
  | `CEZ_APPROVAL_GATE=1` | Opt into Claude's interactive approval UI; by default, unapproved tools are denied without interrupting the run. Ignored when `CEZ_CLAUDE_PERMISSION_MODE` is a recognized value (`dontAsk`, `acceptEdits`, or `bypass`). |
@@ -645,6 +737,7 @@ Useful environment variables:
645
737
  | `CEZ_REVIEW_GATE=1` | Turn ON the optional diff-first review gate (#489): a successful, non-autonomous run with changes parks at `review` (Accept / Send back / Draft PR) instead of finishing. Off by default — changed runs settle to `done` with the diff left in the worktree. Only `1` enables. The Settings → Agents toggle overrides this; autonomous runs always skip it. |
646
738
  | `CEZ_NO_BANNER=1` | Skip the `open-mercato/skills` banner on `cez serve` startup. (The cockpit no longer shows a banner — its skills now live on the Skills page's Manage panel — so this env var is the terminal banner's only switch.) |
647
739
  | `VITE_CEZ_API_BASE=http://localhost:4321` | **Build time only**, and only when the cockpit bundle is deployed apart from the service it talks to. Empty (the default) means "the origin that served this page", which is right for both normal cases: the CLI serves the bundle itself, and `npm run dev` proxies `/api` to the local service. A deployment that must be configured without a rebuild can put `<meta name="cez-api-base" content="…">` in the served HTML instead, which wins over this. |
740
+ | `VITE_CEZ_E2E=1` | **Build time only.** The cockpit e2e suite sets this when it builds the bundle it drives. It pins `useNow` and every `refetchInterval` so a wait cannot span a 30s tick or a 4s poll. Leave unset for production. |
648
741
 
649
742
  ### Troubleshooting: the agent's shell returns nothing
650
743
 
@@ -834,6 +927,32 @@ works and how to redeploy new versions.
834
927
 
835
928
  ---
836
929
 
930
+ ## Reviewing task files
931
+
932
+ File links in task messages open the Files tab at the selected file, rather than
933
+ navigating to a host path under the cockpit URL. The selection stays in the URL,
934
+ so bookmarks and browser Back work. This works with local and remote cockpits.
935
+
936
+ For a deliverable outside the project, an agent must explicitly publish a snapshot:
937
+
938
+ ```sh
939
+ cez artifact publish /tmp/decision.md
940
+ ```
941
+
942
+ Cezar supplies the bundled command and task context to agent sessions automatically
943
+ (`CEZ_TASK_ID` and `CEZ_ARTIFACTS_DIR`; do not configure these yourself). The command
944
+ returns JSON with a Markdown link for the agent to share. The Files tab also lists
945
+ published artifacts. It previews text, Markdown and raster images; other formats
946
+ can be downloaded. HTML/scripts never execute inside the cockpit, and embedded
947
+ images in Markdown documents do not load automatically.
948
+
949
+ Snapshots do not change when the original file changes. They survive worktree
950
+ removal and are removed with task history, including normal history retention.
951
+ Publication is limited to 10 MiB per file, 64 snapshots and 64 MiB per task; reaching
952
+ a limit refuses the new publication without evicting earlier files. There is no
953
+ arbitrary host-file reader or automatic collection of mentioned paths. Publish
954
+ only intended review material, never credentials or unrelated private files.
955
+
837
956
  ## Configuration (optional)
838
957
 
839
958
  Zero config is the default — everything below is opt-in via
@@ -965,11 +1084,19 @@ npm run build # tsc → packages/cezar/dist/, vite build → packages/cez
965
1084
  npm run typecheck # refresh server declarations, then check all four workspaces
966
1085
  npm run typecheck:web # refresh server declarations, then check web sources
967
1086
  npm test # vitest — server + cockpit unit suites
1087
+ npm run test:changed # iteration only: tests related to branch + working-tree changes
968
1088
  npm run test:unit # node:test — fast core-module tests
969
1089
  npm run test:package # pack/install and exercise the built CLI
970
1090
  npm run test:e2e # real-browser cockpit suite (agent-browser)
971
1091
  ```
972
1092
 
1093
+ For iteration, run affected test files or `npm run test:changed` (inspect with
1094
+ `-- --plan`; override the local main comparison with `-- --base=<ref>`).
1095
+ The changed-test command includes staged, unstaged and untracked changes and
1096
+ falls back to full Vitest on shared/configuration/unknown input or missing Git
1097
+ history. It is not a substitute for final verification. See `AGENTS.md` § Validation
1098
+ for targeted browser commands and the final-gate/evidence-reuse policy.
1099
+
973
1100
  Both `npm run typecheck:web` and
974
1101
  `npm run typecheck -w @open-mercato/cezar-web` rebuild server declarations from
975
1102
  the current checkout before checking web sources. Run `npm ci` in each new
@@ -0,0 +1,5 @@
1
+ /** Discovery already proved one of these two canonical global layouts. */
2
+ export declare function windowsGlobalLayout(prefix: string, outerRoot: string, outerPackage: string): boolean;
3
+ export declare function snapshotGlobalBins(directory: string, names: string[], windows: boolean, destination: string, assertOwned: () => Promise<void>): Promise<void>;
4
+ /** Validate the entire private snapshot before touching any command path. */
5
+ export declare function restoreGlobalBins(prefix: string, names: string[], windows: boolean, source: string, assertOwned: () => Promise<void>): Promise<void>;
@@ -0,0 +1,96 @@
1
+ import { chmod, lstat, readFile, readlink, rm, symlink, writeFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ const validName = (name) => typeof name === 'string' && /^[a-zA-Z0-9-]+$/.test(name);
4
+ const fail = () => { throw new Error('invalid recovery command snapshot'); };
5
+ /** Discovery already proved one of these two canonical global layouts. */
6
+ export function windowsGlobalLayout(prefix, outerRoot, outerPackage) {
7
+ return outerRoot === join(prefix, 'node_modules', outerPackage);
8
+ }
9
+ function filenames(names, windows) {
10
+ if (!names.every(validName))
11
+ fail();
12
+ return names.flatMap(name => windows ? [name, `${name}.cmd`, `${name}.ps1`] : [name]);
13
+ }
14
+ export async function snapshotGlobalBins(directory, names, windows, destination, assertOwned) {
15
+ const entries = [];
16
+ for (const name of filenames(names, windows)) {
17
+ await assertOwned();
18
+ const path = join(directory, name);
19
+ const info = await lstat(path).catch((error) => {
20
+ if (error.code === 'ENOENT')
21
+ return undefined;
22
+ throw error; // Permission and I/O failures must not become "absent".
23
+ });
24
+ if (!info)
25
+ entries.push({ name, kind: 'absent' });
26
+ else if (info.isSymbolicLink())
27
+ entries.push({ name, kind: 'link', target: await readlink(path) });
28
+ else if (info.isFile())
29
+ entries.push({ name, kind: 'file', bytes: (await readFile(path)).toString('base64'), mode: info.mode & 0o777 });
30
+ else
31
+ throw new Error('unsupported npm command file');
32
+ }
33
+ await assertOwned();
34
+ await writeFile(destination, JSON.stringify({ version: 1, windows, entries }), { mode: 0o600 });
35
+ }
36
+ /** Validate the entire private snapshot before touching any command path. */
37
+ export async function restoreGlobalBins(prefix, names, windows, source, assertOwned) {
38
+ const raw = JSON.parse(await readFile(source, 'utf8'));
39
+ const allowed = new Set(filenames(names, windows));
40
+ let entries;
41
+ // Keep already-prepared POSIX updates resumable across this change.
42
+ if (Array.isArray(raw)) {
43
+ if (windows)
44
+ fail();
45
+ entries = raw.map((link) => {
46
+ if (!link || typeof link !== 'object')
47
+ return fail();
48
+ const item = link;
49
+ if (!allowed.has(item.name) || typeof item.target !== 'string')
50
+ return fail();
51
+ return { name: item.name, kind: 'link', target: item.target };
52
+ });
53
+ }
54
+ else {
55
+ if (!raw || typeof raw !== 'object')
56
+ fail();
57
+ const snapshot = raw;
58
+ if (snapshot.version !== 1 || snapshot.windows !== windows || !Array.isArray(snapshot.entries))
59
+ fail();
60
+ const seen = new Set();
61
+ entries = snapshot.entries.map((value) => {
62
+ if (!value || typeof value !== 'object')
63
+ return fail();
64
+ const entry = value;
65
+ if (typeof entry.name !== 'string' || !allowed.has(entry.name) || seen.has(entry.name))
66
+ return fail();
67
+ seen.add(entry.name);
68
+ if (entry.kind === 'absent')
69
+ return { name: entry.name, kind: 'absent' };
70
+ if (entry.kind === 'link' && typeof entry.target === 'string' && !entry.target.includes('\0')) {
71
+ return { name: entry.name, kind: 'link', target: entry.target };
72
+ }
73
+ if (entry.kind === 'file' && typeof entry.bytes === 'string' && Buffer.from(entry.bytes, 'base64').toString('base64') === entry.bytes
74
+ && typeof entry.mode === 'number' && Number.isInteger(entry.mode) && entry.mode >= 0 && entry.mode <= 0o777) {
75
+ return { name: entry.name, kind: 'file', bytes: entry.bytes, mode: entry.mode };
76
+ }
77
+ return fail();
78
+ });
79
+ if (seen.size !== allowed.size)
80
+ fail();
81
+ }
82
+ const directory = windows ? prefix : join(prefix, 'bin');
83
+ for (const entry of entries) {
84
+ await assertOwned();
85
+ const path = join(directory, entry.name);
86
+ await rm(path, { force: true }); // Do not follow replaced symlinks or remove directories.
87
+ await assertOwned();
88
+ if (entry.kind === 'link')
89
+ await symlink(entry.target, path);
90
+ if (entry.kind === 'file') {
91
+ await writeFile(path, Buffer.from(entry.bytes, 'base64'), { mode: entry.mode, flag: 'wx' });
92
+ await chmod(path, entry.mode);
93
+ }
94
+ }
95
+ }
96
+ //# sourceMappingURL=bin-recovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin-recovery.js","sourceRoot":"","sources":["../../src/application-update/bin-recovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export type Installation = {
2
+ kind: 'unsupported';
3
+ reason: string;
4
+ } | {
5
+ kind: 'global' | 'npx';
6
+ prefix: string;
7
+ cache: string;
8
+ installRoot: string;
9
+ packageRoot: string;
10
+ outerRoot: string;
11
+ launchEntry: string;
12
+ outerPackage: '@wjarka/cezarion' | 'cezarion';
13
+ request: string;
14
+ };
15
+ export interface DiscoveryInput {
16
+ prefix: string;
17
+ cache: string;
18
+ packageRoot: string;
19
+ launchEntry: string;
20
+ }
21
+ /** Match only npm-owned, canonical layouts. A matched but unsafe layout is explicit. */
22
+ export declare function discoverInstallation(input: DiscoveryInput): Installation;
@@ -0,0 +1,91 @@
1
+ import { realpathSync, readFileSync } from 'node:fs';
2
+ import { join, relative, resolve, sep } from 'node:path';
3
+ function inside(path, root) {
4
+ const rel = relative(root, path);
5
+ return rel === '' || (rel !== '..' && !rel.startsWith(`..${sep}`) && !rel.startsWith(sep));
6
+ }
7
+ function json(path) {
8
+ return JSON.parse(readFileSync(path, 'utf8'));
9
+ }
10
+ /** Match only npm-owned, canonical layouts. A matched but unsafe layout is explicit. */
11
+ export function discoverInstallation(input) {
12
+ const unsupported = (reason) => ({ kind: 'unsupported', reason });
13
+ try {
14
+ let prefix;
15
+ try {
16
+ prefix = realpathSync(input.prefix);
17
+ }
18
+ catch {
19
+ prefix = resolve(input.prefix);
20
+ }
21
+ // A fresh global npm install need not have created its cache yet.
22
+ let cache;
23
+ try {
24
+ cache = realpathSync(input.cache);
25
+ }
26
+ catch {
27
+ cache = resolve(input.cache);
28
+ }
29
+ const packageRoot = realpathSync(input.packageRoot);
30
+ const launchEntry = realpathSync(input.launchEntry);
31
+ const manifest = json(join(packageRoot, 'package.json'));
32
+ if (manifest.name !== '@wjarka/cezarion' || typeof manifest.version !== 'string') {
33
+ return unsupported('running package is not @wjarka/cezarion');
34
+ }
35
+ let kind;
36
+ let installRoot;
37
+ let modules;
38
+ if (inside(packageRoot, join(prefix, 'lib/node_modules')) || inside(packageRoot, join(prefix, 'node_modules'))) {
39
+ kind = 'global';
40
+ installRoot = prefix;
41
+ modules = inside(packageRoot, join(prefix, 'lib/node_modules')) ? join(prefix, 'lib/node_modules') : join(prefix, 'node_modules');
42
+ }
43
+ else {
44
+ const parts = relative(cache, packageRoot).split(sep);
45
+ if (parts[0] !== '_npx' || !/^[a-z0-9]+$/i.test(parts[1] ?? '') || parts[2] !== 'node_modules') {
46
+ return unsupported('not an npm global or npx cache installation');
47
+ }
48
+ kind = 'npx';
49
+ installRoot = join(cache, '_npx', parts[1]);
50
+ modules = join(installRoot, 'node_modules');
51
+ }
52
+ const direct = join(modules, '@wjarka/cezarion');
53
+ const alias = join(modules, 'cezarion');
54
+ let outerPackage;
55
+ if (packageRoot !== direct && packageRoot !== join(alias, 'node_modules/@wjarka/cezarion')) {
56
+ return unsupported('linked or mixed package layout');
57
+ }
58
+ outerPackage = inside(launchEntry, alias) ? 'cezarion' : '@wjarka/cezarion';
59
+ let request = outerPackage;
60
+ if (kind === 'npx') {
61
+ const root = json(join(installRoot, 'package.json'));
62
+ const requests = root._npx?.packages;
63
+ if (!Array.isArray(requests) || requests.length !== 1 ||
64
+ !['cezarion', '@wjarka/cezarion'].includes(requests[0])) {
65
+ return unsupported('pinned or mixed npx request');
66
+ }
67
+ request = requests[0];
68
+ // npm may link .bin/cezarion to the scoped dependency even when the _npx
69
+ // request and root dependency are the alias. Metadata owns this choice.
70
+ outerPackage = request;
71
+ }
72
+ if (outerPackage === '@wjarka/cezarion' && packageRoot !== direct)
73
+ return unsupported('mixed launch layout');
74
+ const outerPath = outerPackage === 'cezarion' ? alias : direct;
75
+ if (!inside(launchEntry, outerPath) && !(kind === 'npx' && inside(launchEntry, packageRoot))) {
76
+ return unsupported('launch entry does not belong to installation');
77
+ }
78
+ if (outerPackage === 'cezarion') {
79
+ const outer = json(join(alias, 'package.json'));
80
+ const deps = outer.dependencies;
81
+ if (outer.name !== 'cezarion' || typeof deps?.['@wjarka/cezarion'] !== 'string')
82
+ return unsupported('alias is not linked to scoped package');
83
+ }
84
+ return { kind, prefix, cache, installRoot, packageRoot, outerRoot: outerPath,
85
+ launchEntry: resolve(input.launchEntry), outerPackage, request };
86
+ }
87
+ catch {
88
+ return unsupported('installation metadata is unavailable');
89
+ }
90
+ }
91
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/application-update/discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import { type AddressInfo } from 'node:net';
2
+ export interface HelperPlan {
3
+ installation: {
4
+ kind: 'global' | 'npx';
5
+ prefix: string;
6
+ cache: string;
7
+ installRoot: string;
8
+ packageRoot: string;
9
+ outerRoot: string;
10
+ launchEntry: string;
11
+ outerPackage: '@wjarka/cezarion' | 'cezarion';
12
+ request: string;
13
+ };
14
+ targetVersion: string;
15
+ oldVersion: string;
16
+ recovery: string;
17
+ recoveryPackage?: string;
18
+ binLinks?: string;
19
+ recordPath: string;
20
+ oldPid: number;
21
+ nodeExecutable: string;
22
+ nodeArgs: string[];
23
+ cliArgs: string[];
24
+ cwd: string;
25
+ repoRoot: string;
26
+ host: string;
27
+ port: number;
28
+ npmBin: string;
29
+ claimId: string;
30
+ }
31
+ /** Only a listening TCP server can supply the private restart destination. */
32
+ export declare function restartEndpoint(address: AddressInfo | string | null): Pick<HelperPlan, 'host' | 'port'>;
33
+ export declare function restartHealthUrl(endpoint: Pick<HelperPlan, 'host' | 'port'>): string;
34
+ /** A private loopback probe must not use Node's environment-proxied global agent. */
35
+ export declare function requestRestartHealth(endpoint: Pick<HelperPlan, 'host' | 'port'>, signal: AbortSignal): Promise<{
36
+ version?: string;
37
+ repoRoot?: string;
38
+ } | undefined>;
39
+ export interface RestartIO {
40
+ waitForOldExit(): Promise<void>;
41
+ promote(): Promise<void>;
42
+ validateOriginal(): Promise<void>;
43
+ launch(): Promise<void>;
44
+ verifyHealth(): Promise<void>;
45
+ reapReplacement(): Promise<void>;
46
+ restore(): Promise<void>;
47
+ launchPrevious(): Promise<void>;
48
+ reportSuccess(): Promise<void>;
49
+ reportFailure(rollbackFailed: boolean): Promise<void>;
50
+ assertOwned?(): Promise<void>;
51
+ }
52
+ /** Only the helper owns the promotion transaction. Rollback waits for its child to exit. */
53
+ export declare function runRestartWorkflow(io: RestartIO): Promise<void>;
54
+ export declare function manualRepairCommand(installation: Pick<HelperPlan['installation'], 'kind' | 'prefix' | 'installRoot' | 'outerPackage'>, version: string): string;
55
+ export declare function promoteOriginal(plan: HelperPlan, npxLockAlreadyHeld?: boolean, signal?: AbortSignal): Promise<void>;
56
+ export declare function restoreOriginal(plan: HelperPlan, assertOwned?: () => Promise<void>): Promise<void>;
57
+ export declare function runHelper(plan: HelperPlan, onArmed?: () => void): Promise<void>;