@wjarka/cezarion 0.14.8 → 0.14.9-dev.829

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 (207) hide show
  1. package/README.md +76 -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/ci-wait/mcp.d.ts +3 -0
  36. package/dist/ci-wait/mcp.js +14 -3
  37. package/dist/ci-wait/mcp.js.map +1 -1
  38. package/dist/contract/application-update.d.ts +32 -0
  39. package/dist/contract/artifacts.d.ts +83 -0
  40. package/dist/contract/ask-schema.d.ts +32 -0
  41. package/dist/contract/ask.d.ts +2 -32
  42. package/dist/contract/conversations.d.ts +165 -0
  43. package/dist/contract/delegation.d.ts +39 -0
  44. package/dist/contract/events.d.ts +49 -0
  45. package/dist/contract/health.d.ts +12 -0
  46. package/dist/contract/index.d.ts +2 -0
  47. package/dist/contract/index.js +1374 -1247
  48. package/dist/contract/runs.d.ts +143 -0
  49. package/dist/contract/skills.d.ts +28 -0
  50. package/dist/core/agent-runner.d.ts +33 -4
  51. package/dist/core/agent-runner.js +5 -0
  52. package/dist/core/agent-runner.js.map +1 -1
  53. package/dist/core/claude-cli-runner.d.ts +6 -12
  54. package/dist/core/claude-cli-runner.js +89 -19
  55. package/dist/core/claude-cli-runner.js.map +1 -1
  56. package/dist/core/codex-app-server-runner.d.ts +2 -1
  57. package/dist/core/codex-app-server-runner.js +327 -92
  58. package/dist/core/codex-app-server-runner.js.map +1 -1
  59. package/dist/core/codex-app-server-transport.d.ts +13 -1
  60. package/dist/core/codex-app-server-transport.js +58 -17
  61. package/dist/core/codex-app-server-transport.js.map +1 -1
  62. package/dist/core/cursor-acp-runner.d.ts +4 -1
  63. package/dist/core/cursor-acp-runner.js +3 -0
  64. package/dist/core/cursor-acp-runner.js.map +1 -1
  65. package/dist/core/cursor-provider-error.js +3 -1
  66. package/dist/core/cursor-provider-error.js.map +1 -1
  67. package/dist/core/input-submissions.d.ts +14 -0
  68. package/dist/core/input-submissions.js +26 -0
  69. package/dist/core/input-submissions.js.map +1 -0
  70. package/dist/core/opencode-server-runner.d.ts +4 -1
  71. package/dist/core/opencode-server-runner.js +144 -21
  72. package/dist/core/opencode-server-runner.js.map +1 -1
  73. package/dist/core/pi-runner.d.ts +2 -1
  74. package/dist/core/pi-runner.js +72 -7
  75. package/dist/core/pi-runner.js.map +1 -1
  76. package/dist/delegation/cli.js +102 -6
  77. package/dist/delegation/cli.js.map +1 -1
  78. package/dist/delegation/conversations.js +13 -5
  79. package/dist/delegation/conversations.js.map +1 -1
  80. package/dist/delegation/input.d.ts +2 -1
  81. package/dist/delegation/input.js +6 -1
  82. package/dist/delegation/input.js.map +1 -1
  83. package/dist/delegation/provision.js +5 -3
  84. package/dist/delegation/provision.js.map +1 -1
  85. package/dist/delegation/questions.d.ts +19 -0
  86. package/dist/delegation/questions.js +45 -0
  87. package/dist/delegation/questions.js.map +1 -0
  88. package/dist/delegation/results.d.ts +1 -1
  89. package/dist/delegation/results.js +23 -13
  90. package/dist/delegation/results.js.map +1 -1
  91. package/dist/delegation/routes.d.ts +142 -15
  92. package/dist/delegation/routes.js +4 -1
  93. package/dist/delegation/routes.js.map +1 -1
  94. package/dist/delegation/service.d.ts +9 -5
  95. package/dist/delegation/service.js +106 -7
  96. package/dist/delegation/service.js.map +1 -1
  97. package/dist/delegation/transport.d.ts +138 -11
  98. package/dist/index.js +72 -26
  99. package/dist/index.js.map +1 -1
  100. package/dist/open-url.d.ts +2 -0
  101. package/dist/open-url.js +20 -0
  102. package/dist/open-url.js.map +1 -0
  103. package/dist/release/snapshot.d.ts +3 -3
  104. package/dist/release/snapshot.js +6 -6
  105. package/dist/release/snapshot.js.map +1 -1
  106. package/dist/runs/client-request.d.ts +11 -0
  107. package/dist/runs/client-request.js +26 -0
  108. package/dist/runs/client-request.js.map +1 -0
  109. package/dist/runs/delegation-state.d.ts +17 -0
  110. package/dist/runs/event-history.js +6 -0
  111. package/dist/runs/event-history.js.map +1 -1
  112. package/dist/runs/store.d.ts +78 -6
  113. package/dist/runs/store.js +163 -1
  114. package/dist/runs/store.js.map +1 -1
  115. package/dist/server/server.d.ts +3761 -1648
  116. package/dist/server/server.js +170 -4
  117. package/dist/server/server.js.map +1 -1
  118. package/dist/task-cli/cli.d.ts +38 -0
  119. package/dist/task-cli/cli.js +463 -0
  120. package/dist/task-cli/cli.js.map +1 -0
  121. package/dist/task-cli/discovery.d.ts +22 -0
  122. package/dist/task-cli/discovery.js +95 -0
  123. package/dist/task-cli/discovery.js.map +1 -0
  124. package/dist/task-cli/http.d.ts +43 -0
  125. package/dist/task-cli/http.js +101 -0
  126. package/dist/task-cli/http.js.map +1 -0
  127. package/dist/task-cli/projections.d.ts +40 -0
  128. package/dist/task-cli/projections.js +45 -0
  129. package/dist/task-cli/projections.js.map +1 -0
  130. package/dist/task-cli/watch.d.ts +78 -0
  131. package/dist/task-cli/watch.js +336 -0
  132. package/dist/task-cli/watch.js.map +1 -0
  133. package/dist/workflows/run.d.ts +93 -0
  134. package/dist/workflows/run.js +816 -81
  135. package/dist/workflows/run.js.map +1 -1
  136. package/dist/workspace/projects-cli.js +1 -1
  137. package/package.json +3 -3
  138. package/scripts/mock-claude.mjs +38 -2
  139. package/scripts/mock-codex-app-server.mjs +98 -1
  140. package/scripts/mock-cursor-acp.mjs +3 -0
  141. package/scripts/mock-opencode-serve.mjs +69 -2
  142. package/scripts/mock-pi-rpc.mjs +63 -2
  143. package/web/dist/assets/agent-accounts-JPfZPgKn.js +1 -0
  144. package/web/dist/assets/centered-state-HwCqQkH3.js +43 -0
  145. package/web/dist/assets/collapsible-CTymFdL7.js +1 -0
  146. package/web/dist/assets/commit-list-BZpYGQl2.js +1 -0
  147. package/web/dist/assets/compare-variants-9VkybaQ7.js +1 -0
  148. package/web/dist/assets/{diff-tRE59UNb2.js → diff-CZcD4D1r2.js} +2 -2
  149. package/web/dist/assets/diff-controls-CpcHG3Mm.js +1 -0
  150. package/web/dist/assets/{diff-stat-Cgnl_hYF.js → diff-stat-Cn7rzy1H.js} +1 -1
  151. package/web/dist/assets/{diff-view-DN1ort7Q.js → diff-view-C46nHiP2.js} +2 -2
  152. package/web/dist/assets/dropdown-menu-_YAzCaoQ.js +1 -0
  153. package/web/dist/assets/git-toolbar-BvKDz6uS.js +1 -0
  154. package/web/dist/assets/github-CgjJCGrD.js +1 -0
  155. package/web/dist/assets/{image-preview-C2JGcBlC.js → image-preview-B618kDBH.js} +1 -1
  156. package/web/dist/assets/index-BJtve0Pm.js +7 -0
  157. package/web/dist/assets/index-D0WAgmTQ.css +1 -0
  158. package/web/dist/assets/markdown-CFWZnvMh.js +2 -0
  159. package/web/dist/assets/pill-QfwkuR50.js +1 -0
  160. package/web/dist/assets/project-router-CkAA39N5.js +1 -0
  161. package/web/dist/assets/prompt-templates-Cfna_S0T.js +15 -0
  162. package/web/dist/assets/repo-git-DgzgJ0cP.js +1 -0
  163. package/web/dist/assets/{run-diff-CyG0Nciv.js → run-diff-YbCEQn5I.js} +2 -2
  164. package/web/dist/assets/run-header-DMgIbr1d.js +1 -0
  165. package/web/dist/assets/skills-BW79kUTd.js +1 -0
  166. package/web/dist/assets/{tab-link-BWNp3mLY.js → tab-link-MIHvczEm.js} +1 -1
  167. package/web/dist/assets/task-changes-C96ekt94.js +1 -0
  168. package/web/dist/assets/task-commits-DBfcMZyG.js +1 -0
  169. package/web/dist/assets/task-files-BKpH8dKQ.js +2 -0
  170. package/web/dist/assets/task-thread-Bw_nQuTx.css +1 -0
  171. package/web/dist/assets/task-thread-Dnq7Ek6W.js +9 -0
  172. package/web/dist/assets/textarea-D2vAVgYW.js +1 -0
  173. package/web/dist/assets/thread-loading-NW8Mthco.js +1 -0
  174. package/web/dist/assets/token-metrics-D188e6_0.js +1 -0
  175. package/web/dist/assets/utils-DKheTxGD.js +64 -0
  176. package/web/dist/assets/workflows-BFY1hgp3.js +11 -0
  177. package/web/dist/assets/{zoomable-image-Z3JDnm0b.js → zoomable-image-YW3Qdrr_.js} +1 -1
  178. package/web/dist/index.html +14 -14
  179. package/web/dist/assets/agent-accounts-BZm_2WAv.js +0 -1
  180. package/web/dist/assets/alert-dialog-B422RI-k.js +0 -43
  181. package/web/dist/assets/collapsible-Cy_Fmkrd.js +0 -1
  182. package/web/dist/assets/commit-list-Dcnk7TnI.js +0 -1
  183. package/web/dist/assets/compare-variants-Ciqwvd_f.js +0 -1
  184. package/web/dist/assets/diff-controls-BGrXGi7O.js +0 -1
  185. package/web/dist/assets/dropdown-menu-dwDGT8MM.js +0 -1
  186. package/web/dist/assets/git-toolbar-UiHnGvE0.js +0 -1
  187. package/web/dist/assets/github-D-MrkbJ7.js +0 -1
  188. package/web/dist/assets/ibm-plex-mono-regular-BF3vfe7_.ttf +0 -0
  189. package/web/dist/assets/index-BszfYvBq.js +0 -7
  190. package/web/dist/assets/index-CWh4pKP3.css +0 -1
  191. package/web/dist/assets/markdown-C_IcKVQd.js +0 -2
  192. package/web/dist/assets/pill-BsbO6G7y.js +0 -1
  193. package/web/dist/assets/project-router-DbLkll25.js +0 -1
  194. package/web/dist/assets/prompt-templates-BlTGJB5W.js +0 -15
  195. package/web/dist/assets/repo-git-Bm3s6Why.js +0 -1
  196. package/web/dist/assets/run-header-IFyIGCey.js +0 -1
  197. package/web/dist/assets/skills-C-C4DVFY.js +0 -1
  198. package/web/dist/assets/task-changes-D2PHtWUW.js +0 -1
  199. package/web/dist/assets/task-commits-N5u9U0_R.js +0 -1
  200. package/web/dist/assets/task-files-BS7c7CFm.js +0 -2
  201. package/web/dist/assets/task-thread-BQFdz1dJ.css +0 -1
  202. package/web/dist/assets/task-thread-DGM2dZV-.js +0 -9
  203. package/web/dist/assets/textarea-FjaU370i.js +0 -1
  204. package/web/dist/assets/thread-loading-77sJ8Yu_.js +0 -1
  205. package/web/dist/assets/token-metrics-Clxh03bE.js +0 -1
  206. package/web/dist/assets/utils-PYYcpCFZ.js +0 -64
  207. 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
@@ -538,7 +551,7 @@ Parents and owned workers can converse in both directions; a worker may address
538
551
 
539
552
  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
553
 
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.
554
+ 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
555
 
543
556
  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
557
 
@@ -552,6 +565,32 @@ Stop requests cancellation; `stopping` does not prove termination. Destroy check
552
565
  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
566
 
554
567
 
568
+ ## From the terminal: `cez task`
569
+
570
+ `cez task` starts, watches and steers tasks **in the running cockpit** from a shell — for you, or
571
+ for a bot driving one. Every command prints one JSON object and exits with a code the caller can
572
+ branch on, so nothing has to parse prose. It never starts a server: it finds the cockpit whose
573
+ project registry holds this checkout (ports 4321–4370; a task worktree resolves to its parent
574
+ project), or you point it at one with `--url` / `CEZ_URL`.
575
+
576
+ ```bash
577
+ id=$(cez task start --task-file - <<'EOF' | jq -r .id
578
+ Fix the flaky login test. Quote "anything" you like here.
579
+ EOF
580
+ )
581
+ cez task wait "$id" --until attention --timeout-seconds 900 # 0 done/review · 1 failed · 3 timeout
582
+ cez task status "$id" # slim JSON: status, question, branch, diffStat…
583
+ cez task send "$id" 'Use the retry helper instead' # queued, delivered, or --resume to reopen
584
+ cez task log "$id" --follow --timeout-seconds 300 # JSON lines until it ends
585
+ ```
586
+
587
+ `start` is retry-safe: it sends a request id (`--request-id <UUID>` to pick your own), and a
588
+ retry with the same id and task answers with the run the first one created (`created: false`)
589
+ instead of starting a second. Also: `list`, `stop`, `finish`, `diff [--stat]`, `open`. Exit codes:
590
+ `0` ok, `1` task failed/cancelled or a message was not delivered, `2` no cockpit or the cockpit
591
+ refused (its `error` is passed through), `3` timed out, `64` usage error. `cez task --help` lists
592
+ every flag.
593
+
555
594
  ## Workflow format
556
595
 
557
596
  A workflow is a small YAML file in `.ai/cezar/workflows/`:
@@ -611,6 +650,7 @@ Useful environment variables:
611
650
  |---|---|
612
651
  | `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
652
  | `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. |
653
+ | `CEZ_URL` | Cockpit origin for `cez task` (e.g. a hosted `CEZ_REMOTE` cockpit). Unset, `cez task` finds the local cockpit serving this checkout on ports 4321–4370. |
614
654
  | `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
655
  | `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
656
  | `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`). |
@@ -834,6 +874,32 @@ works and how to redeploy new versions.
834
874
 
835
875
  ---
836
876
 
877
+ ## Reviewing task files
878
+
879
+ File links in task messages open the Files tab at the selected file, rather than
880
+ navigating to a host path under the cockpit URL. The selection stays in the URL,
881
+ so bookmarks and browser Back work. This works with local and remote cockpits.
882
+
883
+ For a deliverable outside the project, an agent must explicitly publish a snapshot:
884
+
885
+ ```sh
886
+ cez artifact publish /tmp/decision.md
887
+ ```
888
+
889
+ Cezar supplies the bundled command and task context to agent sessions automatically
890
+ (`CEZ_TASK_ID` and `CEZ_ARTIFACTS_DIR`; do not configure these yourself). The command
891
+ returns JSON with a Markdown link for the agent to share. The Files tab also lists
892
+ published artifacts. It previews text, Markdown and raster images; other formats
893
+ can be downloaded. HTML/scripts never execute inside the cockpit, and embedded
894
+ images in Markdown documents do not load automatically.
895
+
896
+ Snapshots do not change when the original file changes. They survive worktree
897
+ removal and are removed with task history, including normal history retention.
898
+ Publication is limited to 10 MiB per file, 64 snapshots and 64 MiB per task; reaching
899
+ a limit refuses the new publication without evicting earlier files. There is no
900
+ arbitrary host-file reader or automatic collection of mentioned paths. Publish
901
+ only intended review material, never credentials or unrelated private files.
902
+
837
903
  ## Configuration (optional)
838
904
 
839
905
  Zero config is the default — everything below is opt-in via
@@ -965,11 +1031,19 @@ npm run build # tsc → packages/cezar/dist/, vite build → packages/cez
965
1031
  npm run typecheck # refresh server declarations, then check all four workspaces
966
1032
  npm run typecheck:web # refresh server declarations, then check web sources
967
1033
  npm test # vitest — server + cockpit unit suites
1034
+ npm run test:changed # iteration only: tests related to branch + working-tree changes
968
1035
  npm run test:unit # node:test — fast core-module tests
969
1036
  npm run test:package # pack/install and exercise the built CLI
970
1037
  npm run test:e2e # real-browser cockpit suite (agent-browser)
971
1038
  ```
972
1039
 
1040
+ For iteration, run affected test files or `npm run test:changed` (inspect with
1041
+ `-- --plan`; override the local main comparison with `-- --base=<ref>`).
1042
+ The changed-test command includes staged, unstaged and untracked changes and
1043
+ falls back to full Vitest on shared/configuration/unknown input or missing Git
1044
+ history. It is not a substitute for final verification. See `AGENTS.md` § Validation
1045
+ for targeted browser commands and the final-gate/evidence-reuse policy.
1046
+
973
1047
  Both `npm run typecheck:web` and
974
1048
  `npm run typecheck -w @open-mercato/cezar-web` rebuild server declarations from
975
1049
  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":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAazD,SAAS,MAAM,CAAC,IAAY,EAAE,IAAY;IACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACjC,OAAO,GAAG,KAAK,EAAE,IAAI,CAAC,GAAG,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7F,CAAC;AAED,SAAS,IAAI,CAAC,IAAY;IACxB,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAA4B,CAAC;AAC3E,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,oBAAoB,CAAC,KAAqB;IACxD,MAAM,WAAW,GAAG,CAAC,MAAc,EAAgB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,CAAC;IACxF,IAAI,CAAC;QACH,IAAI,MAAc,CAAC;QACnB,IAAI,CAAC;YAAC,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAAC,CAAC;QACtF,kEAAkE;QAClE,IAAI,KAAa,CAAC;QAClB,IAAI,CAAC;YAAC,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAAC,CAAC;QAClF,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACpD,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC;QACzD,IAAI,QAAQ,CAAC,IAAI,KAAK,kBAAkB,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YACjF,OAAO,WAAW,CAAC,yCAAyC,CAAC,CAAC;QAChE,CAAC;QACD,IAAI,IAAsB,CAAC;QAC3B,IAAI,WAAmB,CAAC;QACxB,IAAI,OAAe,CAAC;QACpB,IAAI,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,IAAI,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;YAC/G,IAAI,GAAG,QAAQ,CAAC;YAAC,WAAW,GAAG,MAAM,CAAC;YACtC,OAAO,GAAG,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;QACpI,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACtD,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,cAAc,EAAE,CAAC;gBAC/F,OAAO,WAAW,CAAC,6CAA6C,CAAC,CAAC;YACpE,CAAC;YACD,IAAI,GAAG,KAAK,CAAC;YAAC,WAAW,GAAG,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;YAAC,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;QAC1G,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QACxC,IAAI,YAA6C,CAAC;QAClD,IAAI,WAAW,KAAK,MAAM,IAAI,WAAW,KAAK,IAAI,CAAC,KAAK,EAAE,+BAA+B,CAAC,EAAE,CAAC;YAC3F,OAAO,WAAW,CAAC,gCAAgC,CAAC,CAAC;QACvD,CAAC;QACD,YAAY,GAAG,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,kBAAkB,CAAC;QAC5E,IAAI,OAAO,GAAW,YAAY,CAAC;QACnC,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YACnB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC;YACrD,MAAM,QAAQ,GAAI,IAAI,CAAC,IAA2C,EAAE,QAAQ,CAAC;YAC7E,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;gBACnD,CAAC,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAW,CAAC,EAAE,CAAC;gBACpE,OAAO,WAAW,CAAC,6BAA6B,CAAC,CAAC;YACpD,CAAC;YACD,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAW,CAAC;YAChC,yEAAyE;YACzE,wEAAwE;YACxE,YAAY,GAAG,OAA8B,CAAC;QAChD,CAAC;QACD,IAAI,YAAY,KAAK,kBAAkB,IAAI,WAAW,KAAK,MAAM;YAAE,OAAO,WAAW,CAAC,qBAAqB,CAAC,CAAC;QAC7G,MAAM,SAAS,GAAG,YAAY,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;QAC/D,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,KAAK,IAAI,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC;YAC7F,OAAO,WAAW,CAAC,8CAA8C,CAAC,CAAC;QACrE,CAAC;QACD,IAAI,YAAY,KAAK,UAAU,EAAE,CAAC;YAChC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC;YAChD,MAAM,IAAI,GAAG,KAAK,CAAC,YAAmD,CAAC;YACvE,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,IAAI,EAAE,CAAC,kBAAkB,CAAC,KAAK,QAAQ;gBAAE,OAAO,WAAW,CAAC,uCAAuC,CAAC,CAAC;QAC/I,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS;YAC1E,WAAW,EAAE,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,WAAW,CAAC,sCAAsC,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC"}
@@ -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>;