@open-mercato/cezar 0.9.1 → 0.9.2
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 +19 -11
- package/dist/agent-config/catalog.d.ts +1 -1
- package/dist/agent-config/files.d.ts +1 -1
- package/dist/agent-config/service.d.ts +1 -1
- package/dist/agent-config/validate.d.ts +1 -1
- package/dist/automations/coordinator.d.ts +26 -0
- package/dist/automations/coordinator.js +66 -0
- package/dist/automations/coordinator.js.map +1 -0
- package/dist/automations/github-poller.d.ts +74 -0
- package/dist/automations/github-poller.js +234 -0
- package/dist/automations/github-poller.js.map +1 -0
- package/dist/automations/scheduler.d.ts +42 -0
- package/dist/automations/scheduler.js +192 -0
- package/dist/automations/scheduler.js.map +1 -0
- package/dist/automations/store.d.ts +65 -0
- package/dist/automations/store.js +298 -0
- package/dist/automations/store.js.map +1 -0
- package/dist/automations/task-template.d.ts +18 -0
- package/dist/automations/task-template.js +95 -0
- package/dist/automations/task-template.js.map +1 -0
- package/dist/automations/types.d.ts +251 -0
- package/dist/automations/types.js +158 -0
- package/dist/automations/types.js.map +1 -0
- package/dist/config.d.ts +9 -111
- package/dist/contract/agent-config.d.ts +151 -0
- package/dist/contract/automations.d.ts +911 -0
- package/dist/contract/events.d.ts +45 -0
- package/dist/contract/github.d.ts +467 -0
- package/dist/contract/health.d.ts +96 -0
- package/dist/contract/index.d.ts +15 -0
- package/dist/contract/index.js +1421 -0
- package/dist/contract/projects.d.ts +182 -0
- package/dist/contract/repo.d.ts +234 -0
- package/dist/contract/runs.d.ts +1226 -0
- package/dist/contract/skills.d.ts +225 -0
- package/dist/contract/workflows.d.ts +212 -0
- package/dist/contract/workspace.d.ts +442 -0
- package/dist/core/agent-env.d.ts +1 -1
- package/dist/core/agent-runner.d.ts +12 -1
- package/dist/core/agent-runner.js +13 -0
- package/dist/core/agent-runner.js.map +1 -1
- package/dist/core/ask.d.ts +45 -124
- package/dist/core/ask.js +103 -13
- package/dist/core/ask.js.map +1 -1
- package/dist/core/claude-cli-runner.d.ts +2 -2
- package/dist/core/claude-cli-runner.js +52 -9
- package/dist/core/claude-cli-runner.js.map +1 -1
- package/dist/core/claude-ui-mapper.d.ts +1 -1
- package/dist/core/codex-app-server-runner.d.ts +1 -1
- package/dist/core/codex-app-server-runner.js +55 -3
- package/dist/core/codex-app-server-runner.js.map +1 -1
- package/dist/core/codex-app-server-transport.d.ts +6 -1
- package/dist/core/codex-app-server-transport.js +12 -3
- package/dist/core/codex-app-server-transport.js.map +1 -1
- package/dist/core/codex-model-catalog.d.ts +1 -1
- package/dist/core/codex-ui-mapper.d.ts +5 -1
- package/dist/core/codex-ui-mapper.js +74 -17
- package/dist/core/codex-ui-mapper.js.map +1 -1
- package/dist/core/model-identity.d.ts +1 -1
- package/dist/core/model-presets.d.ts +2 -2
- package/dist/core/model-presets.js +1 -1
- package/dist/core/opencode-server-runner.d.ts +2 -2
- package/dist/core/opencode-ui-mapper.d.ts +4 -1
- package/dist/core/opencode-ui-mapper.js +45 -7
- package/dist/core/opencode-ui-mapper.js.map +1 -1
- package/dist/core/provider-auth.d.ts +62 -0
- package/dist/core/provider-auth.js +290 -0
- package/dist/core/provider-auth.js.map +1 -0
- package/dist/core/provider-availability.d.ts +3 -0
- package/dist/core/provider-availability.js +13 -0
- package/dist/core/provider-availability.js.map +1 -0
- package/dist/core/runner-factory.d.ts +1 -1
- package/dist/core/runner-model-catalog.d.ts +1 -1
- package/dist/core/tool-display.d.ts +1 -1
- package/dist/core/ui-events.d.ts +1 -1
- package/dist/core/ui-events.js +1 -1
- package/dist/git-diff-base.d.ts +60 -0
- package/dist/git-diff-base.js +54 -0
- package/dist/git-diff-base.js.map +1 -0
- package/dist/git-worktree.d.ts +37 -6
- package/dist/git-worktree.js +39 -9
- package/dist/git-worktree.js.map +1 -1
- package/dist/handoff.d.ts +2 -2
- package/dist/handoff.js +1 -1
- package/dist/index.js +65 -8
- package/dist/index.js.map +1 -1
- package/dist/paths.d.ts +16 -1
- package/dist/paths.js +24 -1
- package/dist/paths.js.map +1 -1
- package/dist/planner.d.ts +2 -2
- package/dist/planner.js +1 -1
- package/dist/planner.js.map +1 -1
- package/dist/release/manifests.d.ts +81 -0
- package/dist/release/manifests.js +74 -0
- package/dist/release/manifests.js.map +1 -0
- package/dist/release/snapshot.d.ts +9 -23
- package/dist/release/snapshot.js +9 -22
- package/dist/release/snapshot.js.map +1 -1
- package/dist/release/stable.d.ts +15 -29
- package/dist/release/stable.js +14 -27
- package/dist/release/stable.js.map +1 -1
- package/dist/runs/auto-name.d.ts +1 -1
- package/dist/runs/retention.d.ts +1 -1
- package/dist/runs/store.d.ts +142 -336
- package/dist/runs/store.js +136 -9
- package/dist/runs/store.js.map +1 -1
- package/dist/runs/ui-event-sink.d.ts +1 -1
- package/dist/server/app-type.d.ts +21 -0
- package/dist/server/app-type.js +2 -0
- package/dist/server/app-type.js.map +1 -0
- package/dist/server/capabilities.d.ts +6 -5
- package/dist/server/capabilities.js +11 -0
- package/dist/server/capabilities.js.map +1 -1
- package/dist/server/forge/github.d.ts +58 -151
- package/dist/server/forge/github.js +530 -6
- package/dist/server/forge/github.js.map +1 -1
- package/dist/server/forge/index.d.ts +10 -3
- package/dist/server/forge/index.js +14 -1
- package/dist/server/forge/index.js.map +1 -1
- package/dist/server/forge/types.d.ts +86 -1
- package/dist/server/git-changes.d.ts +8 -8
- package/dist/server/git-changes.js +14 -17
- package/dist/server/git-changes.js.map +1 -1
- package/dist/server/git.d.ts +2 -0
- package/dist/server/git.js +9 -0
- package/dist/server/git.js.map +1 -1
- package/dist/server/github.d.ts +3 -3
- package/dist/server/github.js +1 -1
- package/dist/server/github.js.map +1 -1
- package/dist/server/pr.d.ts +2 -2
- package/dist/server/project-context.d.ts +20 -3
- package/dist/server/project-context.js +30 -1
- package/dist/server/project-context.js.map +1 -1
- package/dist/server/provider-action-gate.d.ts +8 -0
- package/dist/server/provider-action-gate.js +54 -0
- package/dist/server/provider-action-gate.js.map +1 -0
- package/dist/server/provider-auth-runtime.d.ts +21 -0
- package/dist/server/provider-auth-runtime.js +66 -0
- package/dist/server/provider-auth-runtime.js.map +1 -0
- package/dist/server/server.d.ts +11142 -47
- package/dist/server/server.js +1714 -806
- package/dist/server/server.js.map +1 -1
- package/dist/server/validators.d.ts +97 -0
- package/dist/server/validators.js +86 -0
- package/dist/server/validators.js.map +1 -0
- package/dist/server/ws.d.ts +2 -2
- package/dist/server/ws.js +2 -2
- package/dist/server/ws.js.map +1 -1
- package/dist/server-install/engine.d.ts +1 -1
- package/dist/server-install/platforms/macosx-ngrok.d.ts +1 -1
- package/dist/server-install/platforms/ubuntu-vps.d.ts +16 -1
- package/dist/server-install/platforms/ubuntu-vps.js +83 -1
- package/dist/server-install/platforms/ubuntu-vps.js.map +1 -1
- package/dist/server-install/state.d.ts +1 -1
- package/dist/server-install/steps.d.ts +2 -2
- package/dist/server-install/strategies.d.ts +1 -1
- package/dist/server-install/types.d.ts +38 -424
- package/dist/server-install/ui.d.ts +1 -1
- package/dist/skills-banner.d.ts +7 -6
- package/dist/skills-banner.js +7 -6
- package/dist/skills-banner.js.map +1 -1
- package/dist/skills-remote.d.ts +2 -2
- package/dist/skills-update.d.ts +88 -0
- package/dist/skills-update.js +392 -0
- package/dist/skills-update.js.map +1 -0
- package/dist/skills.d.ts +2 -0
- package/dist/skills.js +3 -2
- package/dist/skills.js.map +1 -1
- package/dist/todos.d.ts +2 -28
- package/dist/todos.js +1 -1
- package/dist/ui-state.d.ts +16 -2
- package/dist/ui-state.js +14 -1
- package/dist/ui-state.js.map +1 -1
- package/dist/workflows/load.d.ts +1 -1
- package/dist/workflows/run.d.ts +53 -12
- package/dist/workflows/run.js +436 -64
- package/dist/workflows/run.js.map +1 -1
- package/dist/workflows/types.d.ts +59 -224
- package/dist/workflows/types.js +14 -0
- package/dist/workflows/types.js.map +1 -1
- package/dist/workspace/config.d.ts +68 -206
- package/dist/workspace/config.js +145 -14
- package/dist/workspace/config.js.map +1 -1
- package/dist/workspace/migrations.d.ts +1 -1
- package/dist/workspace/migrations.js +19 -4
- package/dist/workspace/migrations.js.map +1 -1
- package/dist/workspace/projects.d.ts +8 -2
- package/dist/workspace/projects.js +9 -3
- package/dist/workspace/projects.js.map +1 -1
- package/dist/workspace/semaphore.d.ts +6 -0
- package/dist/workspace/semaphore.js +14 -1
- package/dist/workspace/semaphore.js.map +1 -1
- package/dist/workspace/ui-state.d.ts +13 -3
- package/dist/workspace/ui-state.js +15 -5
- package/dist/workspace/ui-state.js.map +1 -1
- package/package.json +17 -39
- package/scripts/inline-contract.mjs +112 -0
- package/scripts/mock-claude.mjs +39 -1
- package/scripts/sync-readme.mjs +20 -0
- package/web/dist/assets/alert-dialog-ghffK6g9.js +1 -0
- package/web/dist/assets/arrow-down-Cz8qb71e.js +1 -0
- package/web/dist/assets/arrow-left-wcYKQXI_.js +1 -0
- package/web/dist/assets/bundle-mjs-BT31bpU6.js +1 -0
- package/web/dist/assets/centered-state-ZtnFHA-n.js +43 -0
- package/web/dist/assets/chevron-right-G4caF2QV.js +1 -0
- package/web/dist/assets/{chunk-BO2N2NFS-DtrdTCWa.js → chunk-BO2N2NFS-DE6qKn3r.js} +8 -8
- package/web/dist/assets/circle-check--KvBxXWp.js +1 -0
- package/web/dist/assets/circle-x-C3EFZ3xf.js +1 -0
- package/web/dist/assets/collapsible-B0JVzd0B.js +1 -0
- package/web/dist/assets/commit-list-wm6DPHNs.js +1 -0
- package/web/dist/assets/compare-variants-DbdP4Y5T.js +1 -0
- package/web/dist/assets/{core-DePtBHcl.js → core-BCsw8oQw.js} +1 -1
- package/web/dist/assets/diff-Bizc96qe.js +3 -0
- package/web/dist/assets/diff-stat-Dyfg3ltF.js +1 -0
- package/web/dist/assets/{diff-view-DCeSegKk.js → diff-view-CG8ek6tC.js} +4 -4
- package/web/dist/assets/dropdown-menu-C1Dlf35P.js +1 -0
- package/web/dist/assets/editable-title-5rC_QRBZ.js +1 -0
- package/web/dist/assets/{ellipsis-vertical-CNnSLn5a.js → ellipsis-vertical-DpGTRqC2.js} +1 -1
- package/web/dist/assets/{file-D4GBh1ao.js → file-DlUGpUlb.js} +1 -1
- package/web/dist/assets/folder-BAY6Vddy.js +1 -0
- package/web/dist/assets/{git-pull-request-DnR8Xh4_.js → git-pull-request-agOG0iGM.js} +1 -1
- package/web/dist/assets/git-toolbar-DGiNMmtY.js +1 -0
- package/web/dist/assets/github-Vp7lxYGQ.js +1 -0
- package/web/dist/assets/highlighted-body-OFNGDK62-BL-MfFgl.js +1 -0
- package/web/dist/assets/highlighter-CdHqIwFr.js +3 -0
- package/web/dist/assets/image-preview-BWGk5fPX.js +1 -0
- package/web/dist/assets/index-DSxyJpuK.css +2 -0
- package/web/dist/assets/index-DiawI6RX.js +6 -0
- package/web/dist/assets/lib-BQXq3kEf.js +1 -0
- package/web/dist/assets/lib-BxQXEXDF.js +1 -0
- package/web/dist/assets/markdown-BGBOGCA_.js +2 -0
- package/web/dist/assets/mermaid-GHXKKRXX-C4jxqUUb.js +1 -0
- package/web/dist/assets/new-task-form-BpAw_Dks.js +1 -0
- package/web/dist/assets/pill-Dvs-P0xy.js +1 -0
- package/web/dist/assets/project-router-Cx8NPoqn.js +1 -0
- package/web/dist/assets/prompt-templates-CSBYBR1I.js +15 -0
- package/web/dist/assets/react-runtime-CCIEwYL0.js +9 -0
- package/web/dist/assets/{refresh-cw-BT8E96Tm.js → refresh-cw-BoGdAykg.js} +1 -1
- package/web/dist/assets/repo-git-PmX-BNMo.js +1 -0
- package/web/dist/assets/rolldown-runtime-QTnfLwEv.js +1 -0
- package/web/dist/assets/run-diff-EcOkf3ti.js +3 -0
- package/web/dist/assets/run-header-BGiv6_qX.js +1 -0
- package/web/dist/assets/{search-x-BDjaMrzG.js → search-x-X3EpVhgs.js} +1 -1
- package/web/dist/assets/skill-empty-hint-CZLALx6l.js +1 -0
- package/web/dist/assets/skills-BiWfHmCR.js +1 -0
- package/web/dist/assets/skills-CC91ouGH.js +1 -0
- package/web/dist/assets/sparkles-Dt4q7pbG.js +1 -0
- package/web/dist/assets/{square-terminal-Ckjjn0vb.js → square-terminal-hwBL8XsC.js} +1 -1
- package/web/dist/assets/tab-link-DIlR5T07.js +1 -0
- package/web/dist/assets/task-changes-XkHDxzQA.js +1 -0
- package/web/dist/assets/task-commits-BTTA5k5T.js +1 -0
- package/web/dist/assets/task-files-Da8_4C9g.js +2 -0
- package/web/dist/assets/task-thread-DoNXUsHr.js +9 -0
- package/web/dist/assets/textarea-CUdokhkv.js +1 -0
- package/web/dist/assets/thread-loading-B8q8ukXJ.js +1 -0
- package/web/dist/assets/{trash-2-DAyZ0VSi.js → trash-2-DhVIdWv8.js} +1 -1
- package/web/dist/assets/{triangle-alert-Uy8rokUh.js → triangle-alert-XYT0DGCI.js} +1 -1
- package/web/dist/assets/{upload-CDdyPPo_.js → upload-BKjN59-1.js} +1 -1
- package/web/dist/assets/use-desktop-Bf5LS_P4.js +1 -0
- package/web/dist/assets/use-submit-shortcut-CzVyoAMd.js +1 -0
- package/web/dist/assets/utils-DsLuRXwV.js +64 -0
- package/web/dist/assets/workflows-o2QU_pvU.js +11 -0
- package/web/dist/assets/zoomable-image-7WyUiaVD.js +1 -0
- package/web/dist/index.html +32 -13
- package/scripts/dev.mjs +0 -74
- package/scripts/release-snapshot.mjs +0 -130
- package/scripts/release.mjs +0 -119
- package/web/dist/assets/arrow-left-CnSdp92h.js +0 -1
- package/web/dist/assets/bundle-mjs-BegPhL5c.js +0 -1
- package/web/dist/assets/centered-state-DOsTcJZF.js +0 -43
- package/web/dist/assets/commit-list-BrxBEzRK.js +0 -1
- package/web/dist/assets/compare-variants-Bv2c9ORF.js +0 -1
- package/web/dist/assets/dist-B6XQOhgM.js +0 -1
- package/web/dist/assets/git-toolbar-pIC1ubPM.js +0 -1
- package/web/dist/assets/github-DTTSG0ht.js +0 -1
- package/web/dist/assets/highlighted-body-OFNGDK62-BuFJwunK.js +0 -1
- package/web/dist/assets/image-preview-DEhW0TFz.js +0 -1
- package/web/dist/assets/index-Cijmlz7q.js +0 -30
- package/web/dist/assets/index-DzroxqBG.css +0 -2
- package/web/dist/assets/lib-DPEZDBUN.js +0 -1
- package/web/dist/assets/lib-uHpeUPzK.js +0 -1
- package/web/dist/assets/mermaid-GHXKKRXX-CN2zQue0.js +0 -1
- package/web/dist/assets/open-mercato-toBr6SOa.svg +0 -11
- package/web/dist/assets/project-router-BMx4e8m-.js +0 -1
- package/web/dist/assets/repo-git-BusYfa3t.js +0 -1
- package/web/dist/assets/run-diff-wOJ3odA-.js +0 -3
- package/web/dist/assets/run-header-Cg5incil.js +0 -1
- package/web/dist/assets/skill-empty-hint-DTUSp6Vl.js +0 -1
- package/web/dist/assets/skills-PpP2owbM.js +0 -1
- package/web/dist/assets/tab-link-F3uQrdm2.js +0 -1
- package/web/dist/assets/task-changes-iD9kS79I.js +0 -1
- package/web/dist/assets/task-commits-COkLaUri.js +0 -1
- package/web/dist/assets/task-files-Ckttz7XH.js +0 -2
- package/web/dist/assets/task-thread-CQD91VPt.js +0 -9
- package/web/dist/assets/textarea-Bj_LCreg.js +0 -1
- package/web/dist/assets/use-desktop-DUh0STzq.js +0 -3
- package/web/dist/assets/utils-B8s5qIcK.js +0 -1
- package/web/dist/assets/workflows-BFk8C0co.js +0 -11
- package/web/dist/assets/zoomable-image-PEDOqyLQ.js +0 -1
- /package/web/{open-mercato.svg → dist/open-mercato.svg} +0 -0
|
@@ -23,234 +23,87 @@ export declare const PROJECT_ID_RE: RegExp;
|
|
|
23
23
|
* degrade per-key so one bad value never evicts the project.
|
|
24
24
|
*/
|
|
25
25
|
declare const workspaceProjectSchema: z.ZodObject<{
|
|
26
|
-
/** Unique slug — URL segment, sidebar key, worktree namespace. */
|
|
27
26
|
id: z.ZodString;
|
|
28
|
-
|
|
29
|
-
* job — `registerProject` in step 1.3; the schema only demands absolute). */
|
|
30
|
-
root: z.ZodEffects<z.ZodString, string, string>;
|
|
31
|
-
/** Display name (basename by default). `''` = caller derives a fallback. */
|
|
27
|
+
root: z.ZodString;
|
|
32
28
|
name: z.ZodCatch<z.ZodString>;
|
|
33
29
|
addedAt: z.ZodCatch<z.ZodString>;
|
|
34
30
|
lastOpenedAt: z.ZodCatch<z.ZodString>;
|
|
35
|
-
source: z.ZodCatch<z.ZodEnum<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
* default, and `.passthrough()` preserves the key across cezar round-trips. */
|
|
31
|
+
source: z.ZodCatch<z.ZodEnum<{
|
|
32
|
+
checkout: "checkout";
|
|
33
|
+
local: "local";
|
|
34
|
+
}>>;
|
|
40
35
|
maxParallel: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
|
|
41
|
-
},
|
|
42
|
-
/** Unique slug — URL segment, sidebar key, worktree namespace. */
|
|
43
|
-
id: z.ZodString;
|
|
44
|
-
/** Absolute, realpath-normalized repo root (normalization is the writer's
|
|
45
|
-
* job — `registerProject` in step 1.3; the schema only demands absolute). */
|
|
46
|
-
root: z.ZodEffects<z.ZodString, string, string>;
|
|
47
|
-
/** Display name (basename by default). `''` = caller derives a fallback. */
|
|
48
|
-
name: z.ZodCatch<z.ZodString>;
|
|
49
|
-
addedAt: z.ZodCatch<z.ZodString>;
|
|
50
|
-
lastOpenedAt: z.ZodCatch<z.ZodString>;
|
|
51
|
-
source: z.ZodCatch<z.ZodEnum<["local", "checkout"]>>;
|
|
52
|
-
/** Per-project cap on concurrently running tasks. Absent = inherit the
|
|
53
|
-
* workspace `resources.maxParallel`. Bounded like the workspace cap; a bad
|
|
54
|
-
* value degrades to "inherit" (`.catch(undefined)`) rather than a hard
|
|
55
|
-
* default, and `.passthrough()` preserves the key across cezar round-trips. */
|
|
56
|
-
maxParallel: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
|
|
57
|
-
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
58
|
-
/** Unique slug — URL segment, sidebar key, worktree namespace. */
|
|
59
|
-
id: z.ZodString;
|
|
60
|
-
/** Absolute, realpath-normalized repo root (normalization is the writer's
|
|
61
|
-
* job — `registerProject` in step 1.3; the schema only demands absolute). */
|
|
62
|
-
root: z.ZodEffects<z.ZodString, string, string>;
|
|
63
|
-
/** Display name (basename by default). `''` = caller derives a fallback. */
|
|
64
|
-
name: z.ZodCatch<z.ZodString>;
|
|
65
|
-
addedAt: z.ZodCatch<z.ZodString>;
|
|
66
|
-
lastOpenedAt: z.ZodCatch<z.ZodString>;
|
|
67
|
-
source: z.ZodCatch<z.ZodEnum<["local", "checkout"]>>;
|
|
68
|
-
/** Per-project cap on concurrently running tasks. Absent = inherit the
|
|
69
|
-
* workspace `resources.maxParallel`. Bounded like the workspace cap; a bad
|
|
70
|
-
* value degrades to "inherit" (`.catch(undefined)`) rather than a hard
|
|
71
|
-
* default, and `.passthrough()` preserves the key across cezar round-trips. */
|
|
72
|
-
maxParallel: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
|
|
73
|
-
}, z.ZodTypeAny, "passthrough">>;
|
|
36
|
+
}, z.core.$loose>;
|
|
74
37
|
export type WorkspaceProject = z.infer<typeof workspaceProjectSchema>;
|
|
75
38
|
declare const workspaceConfigSchema: z.ZodObject<{
|
|
76
|
-
/** Migration cursor (src/workspace/migrations.ts). Absent/bad → 0, which
|
|
77
|
-
* means "run every migration" — each one is idempotent, so that is safe. */
|
|
78
|
-
schemaVersion: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
79
|
-
/** Root exposed by the Add project folder browser. Environment supplies
|
|
80
|
-
* the zero-config default; an explicit workspace value wins thereafter. */
|
|
81
|
-
browseRoot: z.ZodCatch<z.ZodDefault<z.ZodString>>;
|
|
82
|
-
/** Checkout root for GUI-cloned projects. Stored as written (a literal
|
|
83
|
-
* `~` is expanded by the checkout flow, not here); validated writable
|
|
84
|
-
* when *changed*, never at load. */
|
|
85
|
-
projectsDir: z.ZodCatch<z.ZodDefault<z.ZodString>>;
|
|
86
|
-
resources: z.ZodCatch<z.ZodDefault<z.ZodObject<{
|
|
87
|
-
/** Workspace-wide parallel-task cap (moved from per-repo config.json). */
|
|
88
|
-
maxParallel: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
89
|
-
/** Per-task memory ceiling in MiB; null = no limit (matches the file's
|
|
90
|
-
* literal `"memoryLimitMb": null` in the spec's Data Model). */
|
|
91
|
-
memoryLimitMb: z.ZodCatch<z.ZodDefault<z.ZodNullable<z.ZodNumber>>>;
|
|
92
|
-
/** Default worktree retention for projects that don't override it. */
|
|
93
|
-
worktreeRetentionDefault: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
94
|
-
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
95
|
-
/** Workspace-wide parallel-task cap (moved from per-repo config.json). */
|
|
96
|
-
maxParallel: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
97
|
-
/** Per-task memory ceiling in MiB; null = no limit (matches the file's
|
|
98
|
-
* literal `"memoryLimitMb": null` in the spec's Data Model). */
|
|
99
|
-
memoryLimitMb: z.ZodCatch<z.ZodDefault<z.ZodNullable<z.ZodNumber>>>;
|
|
100
|
-
/** Default worktree retention for projects that don't override it. */
|
|
101
|
-
worktreeRetentionDefault: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
102
|
-
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
103
|
-
/** Workspace-wide parallel-task cap (moved from per-repo config.json). */
|
|
104
|
-
maxParallel: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
105
|
-
/** Per-task memory ceiling in MiB; null = no limit (matches the file's
|
|
106
|
-
* literal `"memoryLimitMb": null` in the spec's Data Model). */
|
|
107
|
-
memoryLimitMb: z.ZodCatch<z.ZodDefault<z.ZodNullable<z.ZodNumber>>>;
|
|
108
|
-
/** Default worktree retention for projects that don't override it. */
|
|
109
|
-
worktreeRetentionDefault: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
110
|
-
}, z.ZodTypeAny, "passthrough">>>>;
|
|
111
|
-
/** Per-entry salvage: a corrupt entry is dropped, the rest of the registry
|
|
112
|
-
* survives (a whole-array `.catch([])` would evict every project over one
|
|
113
|
-
* bad row). */
|
|
114
|
-
projects: z.ZodEffects<z.ZodCatch<z.ZodDefault<z.ZodArray<z.ZodUnknown, "many">>>, z.objectOutputType<{
|
|
115
|
-
/** Unique slug — URL segment, sidebar key, worktree namespace. */
|
|
116
|
-
id: z.ZodString;
|
|
117
|
-
/** Absolute, realpath-normalized repo root (normalization is the writer's
|
|
118
|
-
* job — `registerProject` in step 1.3; the schema only demands absolute). */
|
|
119
|
-
root: z.ZodEffects<z.ZodString, string, string>;
|
|
120
|
-
/** Display name (basename by default). `''` = caller derives a fallback. */
|
|
121
|
-
name: z.ZodCatch<z.ZodString>;
|
|
122
|
-
addedAt: z.ZodCatch<z.ZodString>;
|
|
123
|
-
lastOpenedAt: z.ZodCatch<z.ZodString>;
|
|
124
|
-
source: z.ZodCatch<z.ZodEnum<["local", "checkout"]>>;
|
|
125
|
-
/** Per-project cap on concurrently running tasks. Absent = inherit the
|
|
126
|
-
* workspace `resources.maxParallel`. Bounded like the workspace cap; a bad
|
|
127
|
-
* value degrades to "inherit" (`.catch(undefined)`) rather than a hard
|
|
128
|
-
* default, and `.passthrough()` preserves the key across cezar round-trips. */
|
|
129
|
-
maxParallel: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
|
|
130
|
-
}, z.ZodTypeAny, "passthrough">[], unknown>;
|
|
131
|
-
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
132
|
-
/** Migration cursor (src/workspace/migrations.ts). Absent/bad → 0, which
|
|
133
|
-
* means "run every migration" — each one is idempotent, so that is safe. */
|
|
134
39
|
schemaVersion: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
135
|
-
/** Root exposed by the Add project folder browser. Environment supplies
|
|
136
|
-
* the zero-config default; an explicit workspace value wins thereafter. */
|
|
137
40
|
browseRoot: z.ZodCatch<z.ZodDefault<z.ZodString>>;
|
|
138
|
-
/** Checkout root for GUI-cloned projects. Stored as written (a literal
|
|
139
|
-
* `~` is expanded by the checkout flow, not here); validated writable
|
|
140
|
-
* when *changed*, never at load. */
|
|
141
41
|
projectsDir: z.ZodCatch<z.ZodDefault<z.ZodString>>;
|
|
142
|
-
|
|
143
|
-
|
|
42
|
+
skillsAutoUpdate: z.ZodCatch<z.ZodOptional<z.ZodBoolean>>;
|
|
43
|
+
resources: z.ZodCatch<z.ZodPrefault<z.ZodObject<{
|
|
144
44
|
maxParallel: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
145
|
-
|
|
146
|
-
|
|
45
|
+
maxMonitoringSessions: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
46
|
+
monitoringWakeIntervalMinutes: z.ZodCatch<z.ZodDefault<z.ZodNullable<z.ZodNumber>>>;
|
|
147
47
|
memoryLimitMb: z.ZodCatch<z.ZodDefault<z.ZodNullable<z.ZodNumber>>>;
|
|
148
|
-
/** Default worktree retention for projects that don't override it. */
|
|
149
48
|
worktreeRetentionDefault: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
150
|
-
},
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
/** Per-entry salvage: a corrupt entry is dropped, the rest of the registry
|
|
168
|
-
* survives (a whole-array `.catch([])` would evict every project over one
|
|
169
|
-
* bad row). */
|
|
170
|
-
projects: z.ZodEffects<z.ZodCatch<z.ZodDefault<z.ZodArray<z.ZodUnknown, "many">>>, z.objectOutputType<{
|
|
171
|
-
/** Unique slug — URL segment, sidebar key, worktree namespace. */
|
|
172
|
-
id: z.ZodString;
|
|
173
|
-
/** Absolute, realpath-normalized repo root (normalization is the writer's
|
|
174
|
-
* job — `registerProject` in step 1.3; the schema only demands absolute). */
|
|
175
|
-
root: z.ZodEffects<z.ZodString, string, string>;
|
|
176
|
-
/** Display name (basename by default). `''` = caller derives a fallback. */
|
|
177
|
-
name: z.ZodCatch<z.ZodString>;
|
|
178
|
-
addedAt: z.ZodCatch<z.ZodString>;
|
|
179
|
-
lastOpenedAt: z.ZodCatch<z.ZodString>;
|
|
180
|
-
source: z.ZodCatch<z.ZodEnum<["local", "checkout"]>>;
|
|
181
|
-
/** Per-project cap on concurrently running tasks. Absent = inherit the
|
|
182
|
-
* workspace `resources.maxParallel`. Bounded like the workspace cap; a bad
|
|
183
|
-
* value degrades to "inherit" (`.catch(undefined)`) rather than a hard
|
|
184
|
-
* default, and `.passthrough()` preserves the key across cezar round-trips. */
|
|
185
|
-
maxParallel: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
|
|
186
|
-
}, z.ZodTypeAny, "passthrough">[], unknown>;
|
|
187
|
-
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
188
|
-
/** Migration cursor (src/workspace/migrations.ts). Absent/bad → 0, which
|
|
189
|
-
* means "run every migration" — each one is idempotent, so that is safe. */
|
|
190
|
-
schemaVersion: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
191
|
-
/** Root exposed by the Add project folder browser. Environment supplies
|
|
192
|
-
* the zero-config default; an explicit workspace value wins thereafter. */
|
|
193
|
-
browseRoot: z.ZodCatch<z.ZodDefault<z.ZodString>>;
|
|
194
|
-
/** Checkout root for GUI-cloned projects. Stored as written (a literal
|
|
195
|
-
* `~` is expanded by the checkout flow, not here); validated writable
|
|
196
|
-
* when *changed*, never at load. */
|
|
197
|
-
projectsDir: z.ZodCatch<z.ZodDefault<z.ZodString>>;
|
|
198
|
-
resources: z.ZodCatch<z.ZodDefault<z.ZodObject<{
|
|
199
|
-
/** Workspace-wide parallel-task cap (moved from per-repo config.json). */
|
|
200
|
-
maxParallel: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
201
|
-
/** Per-task memory ceiling in MiB; null = no limit (matches the file's
|
|
202
|
-
* literal `"memoryLimitMb": null` in the spec's Data Model). */
|
|
203
|
-
memoryLimitMb: z.ZodCatch<z.ZodDefault<z.ZodNullable<z.ZodNumber>>>;
|
|
204
|
-
/** Default worktree retention for projects that don't override it. */
|
|
205
|
-
worktreeRetentionDefault: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
206
|
-
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
207
|
-
/** Workspace-wide parallel-task cap (moved from per-repo config.json). */
|
|
208
|
-
maxParallel: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
209
|
-
/** Per-task memory ceiling in MiB; null = no limit (matches the file's
|
|
210
|
-
* literal `"memoryLimitMb": null` in the spec's Data Model). */
|
|
211
|
-
memoryLimitMb: z.ZodCatch<z.ZodDefault<z.ZodNullable<z.ZodNumber>>>;
|
|
212
|
-
/** Default worktree retention for projects that don't override it. */
|
|
213
|
-
worktreeRetentionDefault: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
214
|
-
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
215
|
-
/** Workspace-wide parallel-task cap (moved from per-repo config.json). */
|
|
216
|
-
maxParallel: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
217
|
-
/** Per-task memory ceiling in MiB; null = no limit (matches the file's
|
|
218
|
-
* literal `"memoryLimitMb": null` in the spec's Data Model). */
|
|
219
|
-
memoryLimitMb: z.ZodCatch<z.ZodDefault<z.ZodNullable<z.ZodNumber>>>;
|
|
220
|
-
/** Default worktree retention for projects that don't override it. */
|
|
221
|
-
worktreeRetentionDefault: z.ZodCatch<z.ZodDefault<z.ZodNumber>>;
|
|
222
|
-
}, z.ZodTypeAny, "passthrough">>>>;
|
|
223
|
-
/** Per-entry salvage: a corrupt entry is dropped, the rest of the registry
|
|
224
|
-
* survives (a whole-array `.catch([])` would evict every project over one
|
|
225
|
-
* bad row). */
|
|
226
|
-
projects: z.ZodEffects<z.ZodCatch<z.ZodDefault<z.ZodArray<z.ZodUnknown, "many">>>, z.objectOutputType<{
|
|
227
|
-
/** Unique slug — URL segment, sidebar key, worktree namespace. */
|
|
228
|
-
id: z.ZodString;
|
|
229
|
-
/** Absolute, realpath-normalized repo root (normalization is the writer's
|
|
230
|
-
* job — `registerProject` in step 1.3; the schema only demands absolute). */
|
|
231
|
-
root: z.ZodEffects<z.ZodString, string, string>;
|
|
232
|
-
/** Display name (basename by default). `''` = caller derives a fallback. */
|
|
233
|
-
name: z.ZodCatch<z.ZodString>;
|
|
234
|
-
addedAt: z.ZodCatch<z.ZodString>;
|
|
235
|
-
lastOpenedAt: z.ZodCatch<z.ZodString>;
|
|
236
|
-
source: z.ZodCatch<z.ZodEnum<["local", "checkout"]>>;
|
|
237
|
-
/** Per-project cap on concurrently running tasks. Absent = inherit the
|
|
238
|
-
* workspace `resources.maxParallel`. Bounded like the workspace cap; a bad
|
|
239
|
-
* value degrades to "inherit" (`.catch(undefined)`) rather than a hard
|
|
240
|
-
* default, and `.passthrough()` preserves the key across cezar round-trips. */
|
|
241
|
-
maxParallel: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
|
|
242
|
-
}, z.ZodTypeAny, "passthrough">[], unknown>;
|
|
243
|
-
}, z.ZodTypeAny, "passthrough">>;
|
|
49
|
+
}, z.core.$loose>>>;
|
|
50
|
+
composerDefaults: z.ZodCatch<z.ZodDefault<z.ZodObject<{
|
|
51
|
+
autonomous: z.ZodCatch<z.ZodOptional<z.ZodBoolean>>;
|
|
52
|
+
worktree: z.ZodCatch<z.ZodOptional<z.ZodBoolean>>;
|
|
53
|
+
}, z.core.$loose>>>;
|
|
54
|
+
disabledProviders: z.ZodPipe<z.ZodCatch<z.ZodDefault<z.ZodArray<z.ZodUnknown>>>, z.ZodTransform<("claude" | "codex" | "opencode")[], unknown[]>>;
|
|
55
|
+
projects: z.ZodPipe<z.ZodCatch<z.ZodDefault<z.ZodArray<z.ZodUnknown>>>, z.ZodTransform<{
|
|
56
|
+
[x: string]: unknown;
|
|
57
|
+
id: string;
|
|
58
|
+
root: string;
|
|
59
|
+
name: string;
|
|
60
|
+
addedAt: string;
|
|
61
|
+
lastOpenedAt: string;
|
|
62
|
+
source: "checkout" | "local";
|
|
63
|
+
maxParallel?: number | undefined;
|
|
64
|
+
}[], unknown[]>>;
|
|
65
|
+
}, z.core.$loose>;
|
|
244
66
|
export type WorkspaceConfig = z.infer<typeof workspaceConfigSchema>;
|
|
67
|
+
/** Resolve the auto-update preference without mutating or materializing it. */
|
|
68
|
+
export declare function effectiveSkillsAutoUpdate(config: Pick<WorkspaceConfig, 'skillsAutoUpdate'>, env?: NodeJS.ProcessEnv): boolean;
|
|
69
|
+
export declare function effectiveComposerDefault(stored: boolean | undefined, envValue: string | undefined, fallback: boolean): boolean;
|
|
245
70
|
/** The in-memory default — what a missing/corrupt file behaves like. */
|
|
246
71
|
export declare function defaultWorkspaceConfig(): WorkspaceConfig;
|
|
72
|
+
/**
|
|
73
|
+
* The last-known-good copy of a NON-EMPTY registry, written beside the config
|
|
74
|
+
* by every successful merge-write. The registry is cheap to rebuild in theory
|
|
75
|
+
* ("open the project again"), but in practice it is a hand-curated list, and a
|
|
76
|
+
* single bad write — a crash between `writeFileSync` and `rename`, a full
|
|
77
|
+
* disk, a stray process — costs the user every entry. One extra file, no
|
|
78
|
+
* configuration, and `loadWorkspaceConfig` falls back to it.
|
|
79
|
+
*
|
|
80
|
+
* Removing `~/.cezar` still resets cezar completely; removing only
|
|
81
|
+
* `config.json` no longer does, because this snapshot restores it.
|
|
82
|
+
*
|
|
83
|
+
* A cezar older than this change does not refresh the snapshot, so on a machine
|
|
84
|
+
* that alternates between versions it can lag behind the registry — which only
|
|
85
|
+
* shows if the config file is also lost, and the worst case is a project the
|
|
86
|
+
* user unregistered reappearing. Cheap next to losing the whole list.
|
|
87
|
+
*/
|
|
88
|
+
export declare function workspaceConfigBackupPath(path?: string): string;
|
|
247
89
|
/**
|
|
248
90
|
* Read `~/.cezar/config.json` on demand — never cached, never throws. A
|
|
249
91
|
* missing file is the zero-config default (silent); an unreadable or
|
|
250
92
|
* malformed one degrades to the same default with a one-line warning and is
|
|
251
93
|
* left on disk untouched (the next successful merge-write replaces it).
|
|
94
|
+
*
|
|
95
|
+
* Before degrading, a missing, empty, or corrupt file is restored from the
|
|
96
|
+
* `config.json.bak` snapshot when that still holds projects. The restore is
|
|
97
|
+
* read-only: the recovered registry is handed back in memory and lands on disk
|
|
98
|
+
* again through the next merge-write, so a read never writes. A file that
|
|
99
|
+
* parses and simply has no projects is NOT restored — that is a user who
|
|
100
|
+
* removed their last project, not a lost registry.
|
|
101
|
+
*
|
|
102
|
+
* `path` defaults to the current `workspaceConfigPath()`, but a caller that
|
|
103
|
+
* will also WRITE passes the path it resolved itself — see
|
|
104
|
+
* `mergeWriteWorkspaceConfig` for why resolving it twice is a data-loss bug.
|
|
252
105
|
*/
|
|
253
|
-
export declare function loadWorkspaceConfig(): Promise<WorkspaceConfig>;
|
|
106
|
+
export declare function loadWorkspaceConfig(path?: string): Promise<WorkspaceConfig>;
|
|
254
107
|
/**
|
|
255
108
|
* The tmp path an atomic write stages through — UNIQUE PER WRITE, never a
|
|
256
109
|
* fixed `${path}.tmp`. `~/.cezar/` is shared by every cezar process on the
|
|
@@ -276,6 +129,15 @@ export declare function atomicWriteJsonSync(path: string, value: unknown): void;
|
|
|
276
129
|
* boot). The mutator may mutate its argument in place or return a replacement.
|
|
277
130
|
* Returns the config that was written. Throws on write failure (e.g. a
|
|
278
131
|
* read-only home) — degrading is the caller's policy, per house rules.
|
|
132
|
+
*
|
|
133
|
+
* The path is resolved ONCE, before the `await`, and the same value feeds the
|
|
134
|
+
* read and the write. Resolving it twice used to lose the whole registry:
|
|
135
|
+
* `workspaceConfigPath()` re-reads `CEZ_HOME` on every call, so if the variable
|
|
136
|
+
* changed while the read was in flight — a test's `afterEach` dropping its pin
|
|
137
|
+
* after a timeout is the way this happens in practice — the read came from one
|
|
138
|
+
* home and the write landed in another, replacing that file's registry with a
|
|
139
|
+
* config it never held. One resolution keeps a merge-write inside exactly one
|
|
140
|
+
* file, whatever the environment does mid-flight.
|
|
279
141
|
*/
|
|
280
142
|
export declare function mergeWriteWorkspaceConfig(mutator: (config: WorkspaceConfig) => WorkspaceConfig | void): Promise<WorkspaceConfig>;
|
|
281
143
|
export {};
|
package/dist/workspace/config.js
CHANGED
|
@@ -3,7 +3,8 @@ import { chmodSync, mkdirSync, renameSync, writeFileSync } from 'node:fs';
|
|
|
3
3
|
import { readFile } from 'node:fs/promises';
|
|
4
4
|
import { dirname } from 'node:path';
|
|
5
5
|
import { z } from 'zod';
|
|
6
|
-
import {
|
|
6
|
+
import { PROVIDER_IDS } from '../core/provider-auth.js';
|
|
7
|
+
import { assertCezarHomeWriteIsSandboxed, workspaceConfigPath } from '../paths.js';
|
|
7
8
|
/**
|
|
8
9
|
* `~/.cezar/config.json` — the per-user workspace config + project registry
|
|
9
10
|
* (spec 2026-07-20-multi-project-workspace). House rules from the spec's Data
|
|
@@ -50,6 +51,10 @@ const resourcesSchema = z
|
|
|
50
51
|
.object({
|
|
51
52
|
/** Workspace-wide parallel-task cap (moved from per-repo config.json). */
|
|
52
53
|
maxParallel: z.number().int().min(1).max(16).default(2).catch(2),
|
|
54
|
+
/** Extra durable `CEZ:MONITORING` sessions exempt from the active-task cap. */
|
|
55
|
+
maxMonitoringSessions: z.number().int().min(0).max(16).default(2).catch(2),
|
|
56
|
+
/** Optional cadence for re-checking monitored work; null parks at zero model cost. */
|
|
57
|
+
monitoringWakeIntervalMinutes: z.number().int().min(1).max(60).nullable().default(null).catch(null),
|
|
53
58
|
/** Per-task memory ceiling in MiB; null = no limit (matches the file's
|
|
54
59
|
* literal `"memoryLimitMb": null` in the spec's Data Model). */
|
|
55
60
|
memoryLimitMb: z.number().int().min(0).max(1_048_576).nullable().default(null).catch(null),
|
|
@@ -57,10 +62,30 @@ const resourcesSchema = z
|
|
|
57
62
|
worktreeRetentionDefault: z.number().int().min(0).max(1000).default(10).catch(10),
|
|
58
63
|
})
|
|
59
64
|
.passthrough();
|
|
65
|
+
const composerDefaultsSchema = z
|
|
66
|
+
.object({
|
|
67
|
+
autonomous: z.boolean().optional().catch(undefined),
|
|
68
|
+
worktree: z.boolean().optional().catch(undefined),
|
|
69
|
+
})
|
|
70
|
+
.passthrough();
|
|
60
71
|
const workspacePathSchema = (envName, fallback) => {
|
|
61
72
|
const defaultValue = () => process.env[envName]?.trim() || fallback;
|
|
62
73
|
return z.string().min(1).max(4096).default(defaultValue).catch(defaultValue);
|
|
63
74
|
};
|
|
75
|
+
const providerIdSet = new Set(PROVIDER_IDS);
|
|
76
|
+
const disabledProvidersSchema = z
|
|
77
|
+
.array(z.unknown())
|
|
78
|
+
.default(() => [])
|
|
79
|
+
.catch(() => [])
|
|
80
|
+
.transform((values) => {
|
|
81
|
+
const seen = new Set();
|
|
82
|
+
for (const value of values) {
|
|
83
|
+
if (typeof value !== 'string' || !providerIdSet.has(value))
|
|
84
|
+
continue;
|
|
85
|
+
seen.add(value);
|
|
86
|
+
}
|
|
87
|
+
return PROVIDER_IDS.filter((provider) => seen.has(provider));
|
|
88
|
+
});
|
|
64
89
|
const workspaceConfigSchema = z
|
|
65
90
|
.object({
|
|
66
91
|
/** Migration cursor (src/workspace/migrations.ts). Absent/bad → 0, which
|
|
@@ -73,9 +98,16 @@ const workspaceConfigSchema = z
|
|
|
73
98
|
* `~` is expanded by the checkout flow, not here); validated writable
|
|
74
99
|
* when *changed*, never at load. */
|
|
75
100
|
projectsDir: workspacePathSchema('CEZ_PROJECTS_DIR', '~/cezar/projects'),
|
|
101
|
+
/** Optional auto-update override. Absence inherits the environment/default
|
|
102
|
+
* and must stay absent on unrelated merge-writes. */
|
|
103
|
+
skillsAutoUpdate: z.boolean().optional().catch(undefined),
|
|
76
104
|
// Function-form default/catch: mutators (step 1.3's registerProject) edit
|
|
77
105
|
// these objects in place, so parses must never share one reference.
|
|
78
|
-
resources: resourcesSchema.
|
|
106
|
+
resources: resourcesSchema.prefault(() => ({})).catch(() => resourcesSchema.parse({})),
|
|
107
|
+
/** Optional New Task policy. Missing keys inherit exact 0/1 environment seeds. */
|
|
108
|
+
composerDefaults: composerDefaultsSchema.default(() => ({})).catch(() => ({})),
|
|
109
|
+
/** Host-wide provider preferences; absent means every provider is enabled. */
|
|
110
|
+
disabledProviders: disabledProvidersSchema,
|
|
79
111
|
/** Per-entry salvage: a corrupt entry is dropped, the rest of the registry
|
|
80
112
|
* survives (a whole-array `.catch([])` would evict every project over one
|
|
81
113
|
* bad row). */
|
|
@@ -89,33 +121,108 @@ const workspaceConfigSchema = z
|
|
|
89
121
|
})),
|
|
90
122
|
})
|
|
91
123
|
.passthrough();
|
|
124
|
+
/** Resolve the auto-update preference without mutating or materializing it. */
|
|
125
|
+
export function effectiveSkillsAutoUpdate(config, env = process.env) {
|
|
126
|
+
if (config.skillsAutoUpdate !== undefined)
|
|
127
|
+
return config.skillsAutoUpdate;
|
|
128
|
+
if (env.CEZ_SKILLS_AUTO_UPDATE === '0')
|
|
129
|
+
return false;
|
|
130
|
+
if (env.CEZ_SKILLS_AUTO_UPDATE === '1')
|
|
131
|
+
return true;
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
export function effectiveComposerDefault(stored, envValue, fallback) {
|
|
135
|
+
if (stored !== undefined)
|
|
136
|
+
return stored;
|
|
137
|
+
if (envValue === '0')
|
|
138
|
+
return false;
|
|
139
|
+
if (envValue === '1')
|
|
140
|
+
return true;
|
|
141
|
+
return fallback;
|
|
142
|
+
}
|
|
92
143
|
/** The in-memory default — what a missing/corrupt file behaves like. */
|
|
93
144
|
export function defaultWorkspaceConfig() {
|
|
94
145
|
return workspaceConfigSchema.parse({});
|
|
95
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* The last-known-good copy of a NON-EMPTY registry, written beside the config
|
|
149
|
+
* by every successful merge-write. The registry is cheap to rebuild in theory
|
|
150
|
+
* ("open the project again"), but in practice it is a hand-curated list, and a
|
|
151
|
+
* single bad write — a crash between `writeFileSync` and `rename`, a full
|
|
152
|
+
* disk, a stray process — costs the user every entry. One extra file, no
|
|
153
|
+
* configuration, and `loadWorkspaceConfig` falls back to it.
|
|
154
|
+
*
|
|
155
|
+
* Removing `~/.cezar` still resets cezar completely; removing only
|
|
156
|
+
* `config.json` no longer does, because this snapshot restores it.
|
|
157
|
+
*
|
|
158
|
+
* A cezar older than this change does not refresh the snapshot, so on a machine
|
|
159
|
+
* that alternates between versions it can lag behind the registry — which only
|
|
160
|
+
* shows if the config file is also lost, and the worst case is a project the
|
|
161
|
+
* user unregistered reappearing. Cheap next to losing the whole list.
|
|
162
|
+
*/
|
|
163
|
+
export function workspaceConfigBackupPath(path = workspaceConfigPath()) {
|
|
164
|
+
return `${path}.bak`;
|
|
165
|
+
}
|
|
166
|
+
function parseWorkspaceConfig(raw) {
|
|
167
|
+
try {
|
|
168
|
+
const parsed = workspaceConfigSchema.safeParse(JSON.parse(raw));
|
|
169
|
+
return parsed.success ? parsed.data : null;
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/** The snapshot is only worth restoring while it still holds projects — an
|
|
176
|
+
* empty one carries no information the defaults do not already have. */
|
|
177
|
+
async function loadWorkspaceConfigBackup(path) {
|
|
178
|
+
let raw;
|
|
179
|
+
try {
|
|
180
|
+
raw = await readFile(workspaceConfigBackupPath(path), 'utf8');
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
const parsed = parseWorkspaceConfig(raw);
|
|
186
|
+
return parsed && parsed.projects.length > 0 ? parsed : null;
|
|
187
|
+
}
|
|
96
188
|
/**
|
|
97
189
|
* Read `~/.cezar/config.json` on demand — never cached, never throws. A
|
|
98
190
|
* missing file is the zero-config default (silent); an unreadable or
|
|
99
191
|
* malformed one degrades to the same default with a one-line warning and is
|
|
100
192
|
* left on disk untouched (the next successful merge-write replaces it).
|
|
193
|
+
*
|
|
194
|
+
* Before degrading, a missing, empty, or corrupt file is restored from the
|
|
195
|
+
* `config.json.bak` snapshot when that still holds projects. The restore is
|
|
196
|
+
* read-only: the recovered registry is handed back in memory and lands on disk
|
|
197
|
+
* again through the next merge-write, so a read never writes. A file that
|
|
198
|
+
* parses and simply has no projects is NOT restored — that is a user who
|
|
199
|
+
* removed their last project, not a lost registry.
|
|
200
|
+
*
|
|
201
|
+
* `path` defaults to the current `workspaceConfigPath()`, but a caller that
|
|
202
|
+
* will also WRITE passes the path it resolved itself — see
|
|
203
|
+
* `mergeWriteWorkspaceConfig` for why resolving it twice is a data-loss bug.
|
|
101
204
|
*/
|
|
102
|
-
export async function loadWorkspaceConfig() {
|
|
103
|
-
|
|
104
|
-
let raw;
|
|
205
|
+
export async function loadWorkspaceConfig(path = workspaceConfigPath()) {
|
|
206
|
+
let raw = null;
|
|
105
207
|
try {
|
|
106
208
|
raw = await readFile(path, 'utf8');
|
|
107
209
|
}
|
|
108
210
|
catch {
|
|
109
|
-
|
|
211
|
+
// missing/unreadable — the backup below is the next chance
|
|
110
212
|
}
|
|
111
|
-
|
|
112
|
-
const parsed =
|
|
113
|
-
if (parsed
|
|
114
|
-
return parsed
|
|
213
|
+
if (raw !== null && raw.trim() !== '') {
|
|
214
|
+
const parsed = parseWorkspaceConfig(raw);
|
|
215
|
+
if (parsed)
|
|
216
|
+
return parsed;
|
|
115
217
|
}
|
|
116
|
-
|
|
117
|
-
|
|
218
|
+
const restored = await loadWorkspaceConfigBackup(path);
|
|
219
|
+
if (restored) {
|
|
220
|
+
const cause = raw === null ? 'is missing' : 'is empty or corrupt';
|
|
221
|
+
console.warn(`[cez] workspace config ${path} ${cause} — restored ${restored.projects.length} project(s) from ${workspaceConfigBackupPath(path)}`);
|
|
222
|
+
return restored;
|
|
118
223
|
}
|
|
224
|
+
if (raw === null)
|
|
225
|
+
return defaultWorkspaceConfig();
|
|
119
226
|
console.warn(`[cez] workspace config ${path} is corrupt — using defaults (registry rebuilds)`);
|
|
120
227
|
return defaultWorkspaceConfig();
|
|
121
228
|
}
|
|
@@ -137,6 +244,7 @@ export function atomicTmpPath(path) {
|
|
|
137
244
|
* shared by the workspace config and ui-state writers. Throws on write
|
|
138
245
|
* failure (e.g. a read-only home) — degrading is the caller's policy. */
|
|
139
246
|
export function atomicWriteJsonSync(path, value) {
|
|
247
|
+
assertCezarHomeWriteIsSandboxed(path);
|
|
140
248
|
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
141
249
|
const tmp = atomicTmpPath(path);
|
|
142
250
|
writeFileSync(tmp, `${JSON.stringify(value, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 });
|
|
@@ -157,11 +265,34 @@ export function atomicWriteJsonSync(path, value) {
|
|
|
157
265
|
* boot). The mutator may mutate its argument in place or return a replacement.
|
|
158
266
|
* Returns the config that was written. Throws on write failure (e.g. a
|
|
159
267
|
* read-only home) — degrading is the caller's policy, per house rules.
|
|
268
|
+
*
|
|
269
|
+
* The path is resolved ONCE, before the `await`, and the same value feeds the
|
|
270
|
+
* read and the write. Resolving it twice used to lose the whole registry:
|
|
271
|
+
* `workspaceConfigPath()` re-reads `CEZ_HOME` on every call, so if the variable
|
|
272
|
+
* changed while the read was in flight — a test's `afterEach` dropping its pin
|
|
273
|
+
* after a timeout is the way this happens in practice — the read came from one
|
|
274
|
+
* home and the write landed in another, replacing that file's registry with a
|
|
275
|
+
* config it never held. One resolution keeps a merge-write inside exactly one
|
|
276
|
+
* file, whatever the environment does mid-flight.
|
|
160
277
|
*/
|
|
161
278
|
export async function mergeWriteWorkspaceConfig(mutator) {
|
|
162
|
-
const
|
|
279
|
+
const path = workspaceConfigPath();
|
|
280
|
+
const current = await loadWorkspaceConfig(path);
|
|
163
281
|
const next = mutator(current) ?? current;
|
|
164
|
-
atomicWriteJsonSync(
|
|
282
|
+
atomicWriteJsonSync(path, next);
|
|
283
|
+
// Refresh the snapshot after EVERY successful write, including an emptied
|
|
284
|
+
// registry (#731). Skipping the empty case left a stale non-empty backup:
|
|
285
|
+
// removing the last project, then losing config.json, resurrected the project
|
|
286
|
+
// the user had deliberately unregistered. An empty snapshot is not restored on
|
|
287
|
+
// load (see loadWorkspaceConfigBackup), so recovery now settles on the empty
|
|
288
|
+
// registry the user intended rather than the old projects.
|
|
289
|
+
try {
|
|
290
|
+
atomicWriteJsonSync(workspaceConfigBackupPath(path), next);
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
// Best-effort: the registry itself is already safely on disk, and a
|
|
294
|
+
// failed snapshot must never turn a successful write into an error.
|
|
295
|
+
}
|
|
165
296
|
return next;
|
|
166
297
|
}
|
|
167
298
|
//# sourceMappingURL=config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/workspace/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/workspace/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { mergeWriteWorkspaceUiState } from './ui-state.
|
|
1
|
+
export { mergeWriteWorkspaceUiState } from './ui-state.ts';
|
|
2
2
|
/**
|
|
3
3
|
* Workspace config migrations (spec 2026-07-20-multi-project-workspace,
|
|
4
4
|
* "Migrations"). Deliberately tiny and **config-files-only** — run state
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
+
import { workspaceUiStateSchema } from '../contract/index.js';
|
|
3
4
|
import { cezarHomeDir, workspaceConfigPath } from '../paths.js';
|
|
4
5
|
import { readUiState } from '../ui-state.js';
|
|
5
6
|
import { loadWorkspaceConfig, mergeWriteWorkspaceConfig } from './config.js';
|
|
@@ -82,13 +83,27 @@ const migration001 = {
|
|
|
82
83
|
if (!bootRepoRoot)
|
|
83
84
|
return;
|
|
84
85
|
const repoUiState = await readUiState(bootRepoRoot);
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
// The two prefs that went GLOBAL at step 3.5, read out of the per-repo bag and validated with
|
|
87
|
+
// the DESTINATION's own field schemas. `notifications` is not named by the per-repo contract
|
|
88
|
+
// at all (it left at 3.5), so it arrives through the open catchall as `unknown` — parsing it
|
|
89
|
+
// here is what makes it assignable, and it is also the honest thing: `GET /workspace/ui-state`
|
|
90
|
+
// promises these two keys' shapes, so a hand-edited value must not be promoted into the global
|
|
91
|
+
// file unchecked. A value that does not parse is simply not imported — never a failed boot.
|
|
92
|
+
const shape = workspaceUiStateSchema.shape;
|
|
93
|
+
const importable = {};
|
|
94
|
+
const appearance = shape.appearance.safeParse(repoUiState.appearance);
|
|
95
|
+
if (appearance.success && appearance.data !== undefined)
|
|
96
|
+
importable.appearance = appearance.data;
|
|
97
|
+
const notifications = shape.notifications.safeParse(repoUiState.notifications);
|
|
98
|
+
if (notifications.success && notifications.data !== undefined) {
|
|
99
|
+
importable.notifications = notifications.data;
|
|
100
|
+
}
|
|
101
|
+
if (Object.keys(importable).length === 0)
|
|
87
102
|
return; // nothing to import — don't create the file
|
|
88
103
|
await mergeWriteWorkspaceUiState((state) => {
|
|
89
|
-
for (const key of
|
|
104
|
+
for (const [key, value] of Object.entries(importable)) {
|
|
90
105
|
if (state[key] === undefined)
|
|
91
|
-
state[key] =
|
|
106
|
+
state[key] = value;
|
|
92
107
|
}
|
|
93
108
|
});
|
|
94
109
|
},
|