@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.
- package/README.md +76 -2
- package/dist/application-update/bin-recovery.d.ts +5 -0
- package/dist/application-update/bin-recovery.js +96 -0
- package/dist/application-update/bin-recovery.js.map +1 -0
- package/dist/application-update/discovery.d.ts +22 -0
- package/dist/application-update/discovery.js +91 -0
- package/dist/application-update/discovery.js.map +1 -0
- package/dist/application-update/helper.d.ts +57 -0
- package/dist/application-update/helper.js +374 -0
- package/dist/application-update/helper.js.map +1 -0
- package/dist/application-update/launcher.d.ts +8 -0
- package/dist/application-update/launcher.js +53 -0
- package/dist/application-update/launcher.js.map +1 -0
- package/dist/application-update/lock.d.ts +4 -0
- package/dist/application-update/lock.js +70 -0
- package/dist/application-update/lock.js.map +1 -0
- package/dist/application-update/npm-process.d.ts +17 -0
- package/dist/application-update/npm-process.js +133 -0
- package/dist/application-update/npm-process.js.map +1 -0
- package/dist/application-update/service.d.ts +69 -0
- package/dist/application-update/service.js +456 -0
- package/dist/application-update/service.js.map +1 -0
- package/dist/artifacts/cli.d.ts +1 -0
- package/dist/artifacts/cli.js +32 -0
- package/dist/artifacts/cli.js.map +1 -0
- package/dist/artifacts/lifecycle.d.ts +4 -0
- package/dist/artifacts/lifecycle.js +42 -0
- package/dist/artifacts/lifecycle.js.map +1 -0
- package/dist/artifacts/resolve.d.ts +18 -0
- package/dist/artifacts/resolve.js +102 -0
- package/dist/artifacts/resolve.js.map +1 -0
- package/dist/artifacts/store.d.ts +8 -0
- package/dist/artifacts/store.js +323 -0
- package/dist/artifacts/store.js.map +1 -0
- package/dist/ci-wait/mcp.d.ts +3 -0
- package/dist/ci-wait/mcp.js +14 -3
- package/dist/ci-wait/mcp.js.map +1 -1
- package/dist/contract/application-update.d.ts +32 -0
- package/dist/contract/artifacts.d.ts +83 -0
- package/dist/contract/ask-schema.d.ts +32 -0
- package/dist/contract/ask.d.ts +2 -32
- package/dist/contract/conversations.d.ts +165 -0
- package/dist/contract/delegation.d.ts +39 -0
- package/dist/contract/events.d.ts +49 -0
- package/dist/contract/health.d.ts +12 -0
- package/dist/contract/index.d.ts +2 -0
- package/dist/contract/index.js +1374 -1247
- package/dist/contract/runs.d.ts +143 -0
- package/dist/contract/skills.d.ts +28 -0
- package/dist/core/agent-runner.d.ts +33 -4
- package/dist/core/agent-runner.js +5 -0
- package/dist/core/agent-runner.js.map +1 -1
- package/dist/core/claude-cli-runner.d.ts +6 -12
- package/dist/core/claude-cli-runner.js +89 -19
- package/dist/core/claude-cli-runner.js.map +1 -1
- package/dist/core/codex-app-server-runner.d.ts +2 -1
- package/dist/core/codex-app-server-runner.js +327 -92
- package/dist/core/codex-app-server-runner.js.map +1 -1
- package/dist/core/codex-app-server-transport.d.ts +13 -1
- package/dist/core/codex-app-server-transport.js +58 -17
- package/dist/core/codex-app-server-transport.js.map +1 -1
- package/dist/core/cursor-acp-runner.d.ts +4 -1
- package/dist/core/cursor-acp-runner.js +3 -0
- package/dist/core/cursor-acp-runner.js.map +1 -1
- package/dist/core/cursor-provider-error.js +3 -1
- package/dist/core/cursor-provider-error.js.map +1 -1
- package/dist/core/input-submissions.d.ts +14 -0
- package/dist/core/input-submissions.js +26 -0
- package/dist/core/input-submissions.js.map +1 -0
- package/dist/core/opencode-server-runner.d.ts +4 -1
- package/dist/core/opencode-server-runner.js +144 -21
- package/dist/core/opencode-server-runner.js.map +1 -1
- package/dist/core/pi-runner.d.ts +2 -1
- package/dist/core/pi-runner.js +72 -7
- package/dist/core/pi-runner.js.map +1 -1
- package/dist/delegation/cli.js +102 -6
- package/dist/delegation/cli.js.map +1 -1
- package/dist/delegation/conversations.js +13 -5
- package/dist/delegation/conversations.js.map +1 -1
- package/dist/delegation/input.d.ts +2 -1
- package/dist/delegation/input.js +6 -1
- package/dist/delegation/input.js.map +1 -1
- package/dist/delegation/provision.js +5 -3
- package/dist/delegation/provision.js.map +1 -1
- package/dist/delegation/questions.d.ts +19 -0
- package/dist/delegation/questions.js +45 -0
- package/dist/delegation/questions.js.map +1 -0
- package/dist/delegation/results.d.ts +1 -1
- package/dist/delegation/results.js +23 -13
- package/dist/delegation/results.js.map +1 -1
- package/dist/delegation/routes.d.ts +142 -15
- package/dist/delegation/routes.js +4 -1
- package/dist/delegation/routes.js.map +1 -1
- package/dist/delegation/service.d.ts +9 -5
- package/dist/delegation/service.js +106 -7
- package/dist/delegation/service.js.map +1 -1
- package/dist/delegation/transport.d.ts +138 -11
- package/dist/index.js +72 -26
- package/dist/index.js.map +1 -1
- package/dist/open-url.d.ts +2 -0
- package/dist/open-url.js +20 -0
- package/dist/open-url.js.map +1 -0
- package/dist/release/snapshot.d.ts +3 -3
- package/dist/release/snapshot.js +6 -6
- package/dist/release/snapshot.js.map +1 -1
- package/dist/runs/client-request.d.ts +11 -0
- package/dist/runs/client-request.js +26 -0
- package/dist/runs/client-request.js.map +1 -0
- package/dist/runs/delegation-state.d.ts +17 -0
- package/dist/runs/event-history.js +6 -0
- package/dist/runs/event-history.js.map +1 -1
- package/dist/runs/store.d.ts +78 -6
- package/dist/runs/store.js +163 -1
- package/dist/runs/store.js.map +1 -1
- package/dist/server/server.d.ts +3761 -1648
- package/dist/server/server.js +170 -4
- package/dist/server/server.js.map +1 -1
- package/dist/task-cli/cli.d.ts +38 -0
- package/dist/task-cli/cli.js +463 -0
- package/dist/task-cli/cli.js.map +1 -0
- package/dist/task-cli/discovery.d.ts +22 -0
- package/dist/task-cli/discovery.js +95 -0
- package/dist/task-cli/discovery.js.map +1 -0
- package/dist/task-cli/http.d.ts +43 -0
- package/dist/task-cli/http.js +101 -0
- package/dist/task-cli/http.js.map +1 -0
- package/dist/task-cli/projections.d.ts +40 -0
- package/dist/task-cli/projections.js +45 -0
- package/dist/task-cli/projections.js.map +1 -0
- package/dist/task-cli/watch.d.ts +78 -0
- package/dist/task-cli/watch.js +336 -0
- package/dist/task-cli/watch.js.map +1 -0
- package/dist/workflows/run.d.ts +93 -0
- package/dist/workflows/run.js +816 -81
- package/dist/workflows/run.js.map +1 -1
- package/dist/workspace/projects-cli.js +1 -1
- package/package.json +3 -3
- package/scripts/mock-claude.mjs +38 -2
- package/scripts/mock-codex-app-server.mjs +98 -1
- package/scripts/mock-cursor-acp.mjs +3 -0
- package/scripts/mock-opencode-serve.mjs +69 -2
- package/scripts/mock-pi-rpc.mjs +63 -2
- package/web/dist/assets/agent-accounts-JPfZPgKn.js +1 -0
- package/web/dist/assets/centered-state-HwCqQkH3.js +43 -0
- package/web/dist/assets/collapsible-CTymFdL7.js +1 -0
- package/web/dist/assets/commit-list-BZpYGQl2.js +1 -0
- package/web/dist/assets/compare-variants-9VkybaQ7.js +1 -0
- package/web/dist/assets/{diff-tRE59UNb2.js → diff-CZcD4D1r2.js} +2 -2
- package/web/dist/assets/diff-controls-CpcHG3Mm.js +1 -0
- package/web/dist/assets/{diff-stat-Cgnl_hYF.js → diff-stat-Cn7rzy1H.js} +1 -1
- package/web/dist/assets/{diff-view-DN1ort7Q.js → diff-view-C46nHiP2.js} +2 -2
- package/web/dist/assets/dropdown-menu-_YAzCaoQ.js +1 -0
- package/web/dist/assets/git-toolbar-BvKDz6uS.js +1 -0
- package/web/dist/assets/github-CgjJCGrD.js +1 -0
- package/web/dist/assets/{image-preview-C2JGcBlC.js → image-preview-B618kDBH.js} +1 -1
- package/web/dist/assets/index-BJtve0Pm.js +7 -0
- package/web/dist/assets/index-D0WAgmTQ.css +1 -0
- package/web/dist/assets/markdown-CFWZnvMh.js +2 -0
- package/web/dist/assets/pill-QfwkuR50.js +1 -0
- package/web/dist/assets/project-router-CkAA39N5.js +1 -0
- package/web/dist/assets/prompt-templates-Cfna_S0T.js +15 -0
- package/web/dist/assets/repo-git-DgzgJ0cP.js +1 -0
- package/web/dist/assets/{run-diff-CyG0Nciv.js → run-diff-YbCEQn5I.js} +2 -2
- package/web/dist/assets/run-header-DMgIbr1d.js +1 -0
- package/web/dist/assets/skills-BW79kUTd.js +1 -0
- package/web/dist/assets/{tab-link-BWNp3mLY.js → tab-link-MIHvczEm.js} +1 -1
- package/web/dist/assets/task-changes-C96ekt94.js +1 -0
- package/web/dist/assets/task-commits-DBfcMZyG.js +1 -0
- package/web/dist/assets/task-files-BKpH8dKQ.js +2 -0
- package/web/dist/assets/task-thread-Bw_nQuTx.css +1 -0
- package/web/dist/assets/task-thread-Dnq7Ek6W.js +9 -0
- package/web/dist/assets/textarea-D2vAVgYW.js +1 -0
- package/web/dist/assets/thread-loading-NW8Mthco.js +1 -0
- package/web/dist/assets/token-metrics-D188e6_0.js +1 -0
- package/web/dist/assets/utils-DKheTxGD.js +64 -0
- package/web/dist/assets/workflows-BFY1hgp3.js +11 -0
- package/web/dist/assets/{zoomable-image-Z3JDnm0b.js → zoomable-image-YW3Qdrr_.js} +1 -1
- package/web/dist/index.html +14 -14
- package/web/dist/assets/agent-accounts-BZm_2WAv.js +0 -1
- package/web/dist/assets/alert-dialog-B422RI-k.js +0 -43
- package/web/dist/assets/collapsible-Cy_Fmkrd.js +0 -1
- package/web/dist/assets/commit-list-Dcnk7TnI.js +0 -1
- package/web/dist/assets/compare-variants-Ciqwvd_f.js +0 -1
- package/web/dist/assets/diff-controls-BGrXGi7O.js +0 -1
- package/web/dist/assets/dropdown-menu-dwDGT8MM.js +0 -1
- package/web/dist/assets/git-toolbar-UiHnGvE0.js +0 -1
- package/web/dist/assets/github-D-MrkbJ7.js +0 -1
- package/web/dist/assets/ibm-plex-mono-regular-BF3vfe7_.ttf +0 -0
- package/web/dist/assets/index-BszfYvBq.js +0 -7
- package/web/dist/assets/index-CWh4pKP3.css +0 -1
- package/web/dist/assets/markdown-C_IcKVQd.js +0 -2
- package/web/dist/assets/pill-BsbO6G7y.js +0 -1
- package/web/dist/assets/project-router-DbLkll25.js +0 -1
- package/web/dist/assets/prompt-templates-BlTGJB5W.js +0 -15
- package/web/dist/assets/repo-git-Bm3s6Why.js +0 -1
- package/web/dist/assets/run-header-IFyIGCey.js +0 -1
- package/web/dist/assets/skills-C-C4DVFY.js +0 -1
- package/web/dist/assets/task-changes-D2PHtWUW.js +0 -1
- package/web/dist/assets/task-commits-N5u9U0_R.js +0 -1
- package/web/dist/assets/task-files-BS7c7CFm.js +0 -2
- package/web/dist/assets/task-thread-BQFdz1dJ.css +0 -1
- package/web/dist/assets/task-thread-DGM2dZV-.js +0 -9
- package/web/dist/assets/textarea-FjaU370i.js +0 -1
- package/web/dist/assets/thread-loading-77sJ8Yu_.js +0 -1
- package/web/dist/assets/token-metrics-Clxh03bE.js +0 -1
- package/web/dist/assets/utils-PYYcpCFZ.js +0 -64
- 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@
|
|
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
|
-
|
|
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":"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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>;
|