@open-mercato/cezar 0.9.0 → 0.9.1-pr470.729

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 (147) hide show
  1. package/README.md +30 -10
  2. package/dist/config.d.ts +21 -3
  3. package/dist/config.js +42 -1
  4. package/dist/config.js.map +1 -1
  5. package/dist/core/agent-env.js +21 -15
  6. package/dist/core/agent-env.js.map +1 -1
  7. package/dist/core/agent-runner.d.ts +16 -6
  8. package/dist/core/agent-runner.js +15 -3
  9. package/dist/core/agent-runner.js.map +1 -1
  10. package/dist/core/backend-detect.d.ts +5 -5
  11. package/dist/core/backend-detect.js +37 -5
  12. package/dist/core/backend-detect.js.map +1 -1
  13. package/dist/core/claude-ui-mapper.d.ts +9 -0
  14. package/dist/core/claude-ui-mapper.js +31 -2
  15. package/dist/core/claude-ui-mapper.js.map +1 -1
  16. package/dist/core/codex-app-server-runner.js +19 -18
  17. package/dist/core/codex-app-server-runner.js.map +1 -1
  18. package/dist/core/model-identity.js +4 -0
  19. package/dist/core/model-identity.js.map +1 -1
  20. package/dist/core/model-presets.js +5 -0
  21. package/dist/core/model-presets.js.map +1 -1
  22. package/dist/core/opencode-server-runner.js +25 -5
  23. package/dist/core/opencode-server-runner.js.map +1 -1
  24. package/dist/core/pi-runner.d.ts +24 -0
  25. package/dist/core/pi-runner.js +342 -0
  26. package/dist/core/pi-runner.js.map +1 -0
  27. package/dist/core/pi-ui-mapper.d.ts +24 -0
  28. package/dist/core/pi-ui-mapper.js +255 -0
  29. package/dist/core/pi-ui-mapper.js.map +1 -0
  30. package/dist/core/runner-factory.js +3 -0
  31. package/dist/core/runner-factory.js.map +1 -1
  32. package/dist/core/tool-display.d.ts +2 -1
  33. package/dist/core/tool-display.js +6 -1
  34. package/dist/core/tool-display.js.map +1 -1
  35. package/dist/core/ui-events.d.ts +1 -1
  36. package/dist/core/v1-text-coalescer.d.ts +36 -0
  37. package/dist/core/v1-text-coalescer.js +72 -0
  38. package/dist/core/v1-text-coalescer.js.map +1 -0
  39. package/dist/index.js +40 -4
  40. package/dist/index.js.map +1 -1
  41. package/dist/runs/auto-name.js +6 -0
  42. package/dist/runs/auto-name.js.map +1 -1
  43. package/dist/runs/store.d.ts +19 -12
  44. package/dist/runs/store.js +51 -15
  45. package/dist/runs/store.js.map +1 -1
  46. package/dist/server/capabilities.d.ts +6 -0
  47. package/dist/server/capabilities.js +6 -0
  48. package/dist/server/capabilities.js.map +1 -1
  49. package/dist/server/open-in-app.d.ts +2 -1
  50. package/dist/server/open-in-app.js +1 -0
  51. package/dist/server/open-in-app.js.map +1 -1
  52. package/dist/server/server.d.ts +56 -0
  53. package/dist/server/server.js +428 -21
  54. package/dist/server/server.js.map +1 -1
  55. package/dist/server/ws.d.ts +85 -0
  56. package/dist/server/ws.js +218 -0
  57. package/dist/server/ws.js.map +1 -0
  58. package/dist/server-install/engine.d.ts +5 -0
  59. package/dist/server-install/engine.js +6 -0
  60. package/dist/server-install/engine.js.map +1 -1
  61. package/dist/server-install/platforms/ubuntu-vps.d.ts +11 -2
  62. package/dist/server-install/platforms/ubuntu-vps.js +123 -10
  63. package/dist/server-install/platforms/ubuntu-vps.js.map +1 -1
  64. package/dist/server-install/steps.js +6 -2
  65. package/dist/server-install/steps.js.map +1 -1
  66. package/dist/server-install/types.d.ts +39 -0
  67. package/dist/server-install/types.js +13 -0
  68. package/dist/server-install/types.js.map +1 -1
  69. package/dist/skills-remote.d.ts +11 -0
  70. package/dist/skills-remote.js +31 -2
  71. package/dist/skills-remote.js.map +1 -1
  72. package/dist/skills-update.d.ts +88 -0
  73. package/dist/skills-update.js +392 -0
  74. package/dist/skills-update.js.map +1 -0
  75. package/dist/skills.d.ts +29 -0
  76. package/dist/skills.js +72 -14
  77. package/dist/skills.js.map +1 -1
  78. package/dist/workflows/run.d.ts +50 -10
  79. package/dist/workflows/run.js +216 -103
  80. package/dist/workflows/run.js.map +1 -1
  81. package/dist/workflows/types.d.ts +14 -14
  82. package/dist/workflows/types.js +2 -1
  83. package/dist/workflows/types.js.map +1 -1
  84. package/dist/workspace/config.d.ts +41 -0
  85. package/dist/workspace/config.js +18 -0
  86. package/dist/workspace/config.js.map +1 -1
  87. package/dist/workspace/projects-cli.d.ts +2 -0
  88. package/dist/workspace/projects-cli.js +21 -4
  89. package/dist/workspace/projects-cli.js.map +1 -1
  90. package/dist/workspace/projects.d.ts +5 -1
  91. package/dist/workspace/projects.js +5 -8
  92. package/dist/workspace/projects.js.map +1 -1
  93. package/dist/workspace/semaphore.d.ts +53 -2
  94. package/dist/workspace/semaphore.js +93 -5
  95. package/dist/workspace/semaphore.js.map +1 -1
  96. package/package.json +3 -1
  97. package/scripts/mock-pi-rpc.mjs +83 -0
  98. package/web/dist/assets/centered-state-Dk2G08OJ.js +43 -0
  99. package/web/dist/assets/circle-check-ClxqLJCI.js +1 -0
  100. package/web/dist/assets/commit-list-BKRBe1ff.js +1 -0
  101. package/web/dist/assets/compare-variants-BcWTGJrd.js +1 -0
  102. package/web/dist/assets/diff-view-CFQ0zXBT.js +6 -0
  103. package/web/dist/assets/{dist-Cw_CDvC3.js → dist-DC3TJo3T.js} +1 -1
  104. package/web/dist/assets/git-toolbar-CaBCbiSp.js +1 -0
  105. package/web/dist/assets/github-Dn-ZvcbO.js +1 -0
  106. package/web/dist/assets/index-CDk4tcLt.js +30 -0
  107. package/web/dist/assets/index-CwNZ1v7S.css +2 -0
  108. package/web/dist/assets/lib-DPEZDBUN.js +1 -0
  109. package/web/dist/assets/{project-router-CT8Rt5Eu.js → project-router-CXmL3t6s.js} +1 -1
  110. package/web/dist/assets/repo-git-D5N2okPE.js +1 -0
  111. package/web/dist/assets/{run-diff-CxIDdRwy.js → run-diff-3xRPsGI4.js} +2 -2
  112. package/web/dist/assets/run-header-Bd1vyMz_.js +1 -0
  113. package/web/dist/assets/skill-empty-hint-DTUSp6Vl.js +1 -0
  114. package/web/dist/assets/skills-C5b1tbwv.js +1 -0
  115. package/web/dist/assets/{tab-link-C_bk_Kvn.js → tab-link-Q8NhDqnE.js} +1 -1
  116. package/web/dist/assets/task-changes-DHpP7WS3.js +1 -0
  117. package/web/dist/assets/task-commits-D0IcDbGX.js +1 -0
  118. package/web/dist/assets/task-files-DvKQHU1f.js +2 -0
  119. package/web/dist/assets/task-thread-JlVT8p1a.js +9 -0
  120. package/web/dist/assets/textarea-Bj_LCreg.js +1 -0
  121. package/web/dist/assets/use-desktop-M42tdz-1.js +3 -0
  122. package/web/dist/assets/workflows-D_gHO2WW.js +11 -0
  123. package/web/dist/index.html +6 -12
  124. package/web/dist/assets/centered-state-zzWBfO_1.js +0 -43
  125. package/web/dist/assets/command-ylf8-fG0.js +0 -1
  126. package/web/dist/assets/compare-variants-BcR3zdtB.js +0 -1
  127. package/web/dist/assets/dialog-BYr_BAil.js +0 -1
  128. package/web/dist/assets/diff-view-DPCR7gon.js +0 -4
  129. package/web/dist/assets/dropdown-menu-C3GD8eLA.js +0 -1
  130. package/web/dist/assets/git-toolbar-CiMaCi03.js +0 -1
  131. package/web/dist/assets/github-BJEZbEOp.js +0 -1
  132. package/web/dist/assets/index-DmW_TYjO.js +0 -16
  133. package/web/dist/assets/index-Qbs-JRWQ.css +0 -2
  134. package/web/dist/assets/loader-circle-CGwIVNTv.js +0 -1
  135. package/web/dist/assets/prompt-templates-DW7_d8Ys.js +0 -15
  136. package/web/dist/assets/repo-git-BkmyKcvN.js +0 -1
  137. package/web/dist/assets/run-header-8nwDIWWO.js +0 -1
  138. package/web/dist/assets/skill-empty-hint-Cl3ESoPu.js +0 -1
  139. package/web/dist/assets/skills-BIpb0mqO.js +0 -1
  140. package/web/dist/assets/task-changes-D1bJx2uW.js +0 -1
  141. package/web/dist/assets/task-commits-DlhB21mR.js +0 -1
  142. package/web/dist/assets/task-files-ChJDOFg5.js +0 -2
  143. package/web/dist/assets/task-thread-J7ckxJJh.js +0 -9
  144. package/web/dist/assets/tasks-table--V1pKwuK.js +0 -1
  145. package/web/dist/assets/use-desktop-CuDnWju1.js +0 -3
  146. package/web/dist/assets/workflows-BksgdYAQ.js +0 -11
  147. package/web/dist/assets/x-DgoqYQOJ.js +0 -1
package/README.md CHANGED
@@ -5,8 +5,8 @@
5
5
  **Parallel coding agents orchestrator** — a local cockpit for running and
6
6
  tracking AI coding-agent tasks in your repo.
7
7
 
8
- Type a task, pick a workflow and an agent — **Claude Code, Codex or OpenCode
9
- (experimental), or a mix of them per step** — and watch it work live: steps, tool calls,
8
+ Type a task, pick a workflow and an agent — **Claude Code, Codex, OpenCode or pi
9
+ (the latter two experimental), or a mix of them per step** — and watch it work live: steps, tool calls,
10
10
  tokens, diffs, in a browser cockpit that runs entirely on your machine.
11
11
  Your CLI logins, your `gh`, your files. No accounts, no database, no cloud.
12
12
 
@@ -382,7 +382,7 @@ steps:
382
382
  prompt: "{{task}}"
383
383
  skill: project-conventions # optional — from .ai/skills or .ai/cezar/skills
384
384
  # model: opus # optional per-step model override
385
- # runner: codex # optional per-step backend: claude · codex · opencode
385
+ # runner: codex # optional per-step backend: claude · codex · opencode · pi
386
386
  # allowedTools: [Read, Edit, Write, Grep, Glob, Bash]
387
387
  - id: verify
388
388
  name: Verify
@@ -432,8 +432,11 @@ Useful environment variables:
432
432
  | `CEZ_CLAUDE_BIN=/path/to/claude` | Override which `claude` binary is used. |
433
433
  | `CEZ_CODEX_BIN=/path/to/codex` | Override which `codex` binary is used. |
434
434
  | `CEZ_OPENCODE_BIN=/path/to/opencode` | Override which `opencode` binary is used. |
435
+ | `CEZ_PI_BIN=/path/to/pi` | Override which `pi` binary is used. |
435
436
  | `CEZ_BROWSE_ROOT=~/` | Default root for **Add project → Open local folder…**. The picker cannot navigate above it; a saved workspace value overrides the environment default and must name an existing folder. |
436
437
  | `CEZ_PROJECTS_DIR=~/cezar/projects` | Default destination for **Clone from GitHub**. Saved workspace settings override it, and missing directories are created recursively. |
438
+ | `CEZ_SKILLS_AUTO_UPDATE=0` | Disable automatic checks and updates for upstream-CLI-tracked Open Mercato skill installations. On by default; a saved global Skills setting overrides this environment default. Checks are delayed, bounded, cached, and non-blocking. |
439
+ | `CEZ_SINGLE_PROJECT=1` | Opt into a launch-project-only cockpit: only the exact value `1` enables it. Project add, edit, checkout, folder browsing, and removal are refused and only the launch project is shown. Off by default; stored registry rows are retained, so unsetting it and restarting restores the full multi-project workspace without migration or data loss. |
437
440
  | `GITHUB_TOKEN` | Fallback for GitHub reads/PRs when `gh` isn't authenticated. |
438
441
  | `CEZ_ENV_PASSTHROUGH=A,B` | Forward these extra host env vars to spawned agents. By default agents get a least-privilege env (safe shell/toolchain vars + the backend's own auth + `GITHUB_TOKEN` + `CEZ_*`), not your full environment — use this to add a var an agent needs. |
439
442
  | `CEZ_AGENT_ENV_FULL=1` | Escape hatch: give spawned agents the full host environment (pre-hardening behavior). Off by default; only set it if you understand that this hands every host secret to the agent process. |
@@ -441,27 +444,29 @@ Useful environment variables:
441
444
  | `CEZ_TITLE_UPDATES=0` | Turn off the live task-title refresh (namer re-runs on each turn end). The Settings → Agents toggle overrides this default. |
442
445
  | `CEZ_AUTONAME=0` | Disable ALL LLM task naming (creation + live) — titles stay heuristic (`437: /om-auto-review-pr`). Under `CEZ_DRY_RUN=1` naming is already off unless forced with `CEZ_AUTONAME=1`. |
443
446
  | `CEZ_REVIEW_GATE=1` | Turn ON the optional diff-first review gate (#489): a successful, non-autonomous run with changes parks at `review` (Accept / Send back / Draft PR) instead of finishing. Off by default — changed runs settle to `done` with the diff left in the worktree. Only `1` enables. The Settings → Agents toggle overrides this; autonomous runs always skip it. |
444
- | `CEZ_NO_BANNER=1` | Skip the `open-mercato/skills` banner on `cezar serve` startup. Dismissing the same banner in the cockpit silences the terminal one too. |
447
+ | `CEZ_NO_BANNER=1` | Skip the `open-mercato/skills` banner on `cezar serve` startup. (The cockpit no longer shows a banner its skills now live on the Skills page's Manage panel — so this env var is the terminal banner's only switch.) |
445
448
 
446
449
  ---
447
450
 
448
451
  ## Coding agent backends
449
452
 
450
453
  cezar is not married to one vendor. Every agent step runs through a single
451
- `AgentRunner` seam with three built-in backends:
454
+ `AgentRunner` seam with four built-in backends:
452
455
 
453
456
  | Backend | CLI | How cezar drives it | Tool access |
454
457
  |---|---|---|---|
455
458
  | **Claude Code** (default) | [`claude`](https://github.com/anthropics/claude-code) | Headless `stream-json` mode. | Per-tool `--allowedTools` (`bashAllowlist` scopes `Bash`); `dontAsk` denies unapproved tools without prompting (`CEZ_APPROVAL_GATE=1` → `acceptEdits` + approval UI). |
456
459
  | **Codex** | [`codex`](https://github.com/openai/codex) | `codex app-server` — JSON-RPC over stdio, the same transport the Codex IDE extensions use. | Ignores `allowedTools`; the default auto mode uses `danger-full-access` with `approvalPolicy: never` (`CEZ_CODEX_NETWORK=0` opts into the network-blocked `workspace-write` sandbox). |
457
460
  | **OpenCode** _(experimental)_ | [`opencode`](https://opencode.ai) | `opencode serve` — a local HTTP server with an SSE event stream. | Ignores `allowedTools` entirely; every permission is auto-approved. |
461
+ | **pi** _(experimental)_ | [`pi`](https://github.com/badlogic/pi-mono) | Persistent `--mode rpc` over JSONL; models are picked with the `provider/model` convention. | Maps `allowedTools` onto pi's `--tools` allowlist; a configured `bashAllowlist` disables Bash because pi cannot express command-prefix rules. |
458
462
 
459
- > ⚠️ **OpenCode support is experimental.** The runner works but is less battle-tested
460
- > than the Claude Code and Codex backends, and OpenCode auto-approves every permission
461
- > (it ignores `allowedTools`). Treat it as a preview and expect rough edges.
463
+ > ⚠️ **OpenCode and pi support are experimental.** Both runners work but are less
464
+ > battle-tested than the Claude Code and Codex backends, and OpenCode auto-approves
465
+ > every permission (it ignores `allowedTools`). Treat them as previews and expect
466
+ > rough edges.
462
467
 
463
468
  On startup cezar probes which CLIs are installed and the cockpit only offers
464
- the backends it found — install any one of the three and you're operational.
469
+ the backends it found — install any one of the four and you're operational.
465
470
 
466
471
  **Pick a backend at three levels** (most specific wins):
467
472
 
@@ -520,9 +525,24 @@ On `ubuntu-vps` a single host can run several independent cockpits — add
520
525
  `--domain <host>` and each gets its own port, nginx site, login and service; a
521
526
  new domain never resumes or clobbers the first install.
522
527
 
528
+ **Already running a reverse proxy?** If Dokploy, Coolify, Caddy or your own
529
+ nginx already owns `:80/:443`, cezar's would fight it for the ports. Install the
530
+ service only and let your proxy front it:
531
+
532
+ ```bash
533
+ npx cezar-cli server-install --platform ubuntu-vps \
534
+ --external-proxy --domain cezar.example.com --bind-host 172.17.0.1
535
+ ```
536
+
537
+ `--bind-host` is only needed when the proxy runs in a **container** (Traefik
538
+ can't reach the host's loopback); a host-installed proxy uses the `127.0.0.1`
539
+ default. In this mode **your proxy must enforce authentication** — cezar has
540
+ none of its own. [Details →](docs/server-install/ubuntu-vps.md#the-box-already-has-a-reverse-proxy-dokploy-coolify-caddy)
541
+
523
542
  | Provider | `--platform` | Public front | Guide |
524
543
  |----------|--------------|--------------|-------|
525
544
  | Ubuntu / Debian VPS | `ubuntu-vps` | nginx + Let's Encrypt HTTPS, htpasswd login, systemd | [Step-by-step →](docs/server-install/ubuntu-vps.md) |
545
+ | Ubuntu + existing proxy | `ubuntu-vps --external-proxy` | your Dokploy/Traefik/Caddy front; cezar ships the service only | [Step-by-step →](docs/server-install/ubuntu-vps.md#the-box-already-has-a-reverse-proxy-dokploy-coolify-caddy) |
526
546
  | macOS + ngrok | `macosx-ngrok` | ngrok tunnel + `--basic-auth`, launchd | [Step-by-step →](docs/server-install/macosx-ngrok.md) |
527
547
 
528
548
  See the **[Remote access overview](docs/server-install/README.md)** for how it
@@ -546,7 +566,7 @@ never blocks startup):
546
566
  // the source against a moving branch head — cezar verifies it resolves to
547
567
  // exactly that commit, and reports it as `team.commit`.
548
568
  "worktreeRetention": 10, // keep the last N finished worktrees on disk; 0 = unlimited (branch always kept)
549
- "defaultRunner": "claude", // agent backend: "claude" (default) · "codex" · "opencode"
569
+ "defaultRunner": "claude", // agent backend: "claude" (default) · "codex" · "opencode" · "pi"
550
570
  "plannerModel": "sonnet", // model the "Plan first" button uses to draft chains
551
571
  "baseBranch": "develop" // branch worktrees fork from + PRs target (also settable in the Git tab)
552
572
  }
package/dist/config.d.ts CHANGED
@@ -54,7 +54,7 @@ declare const configSchema: z.ZodObject<{
54
54
  * step (workflow). The GUI only offers runners actually installed; this is
55
55
  * the preselected default. Also the runner the chain planner uses.
56
56
  */
57
- defaultRunner: z.ZodDefault<z.ZodEnum<["claude", "codex", "opencode"]>>;
57
+ defaultRunner: z.ZodDefault<z.ZodEnum<["claude", "codex", "opencode", "pi"]>>;
58
58
  /** Model for the chain planner (spec 008) — cheap but reliable at JSON. */
59
59
  plannerModel: z.ZodDefault<z.ZodString>;
60
60
  /** Model for the task namer (spec 2026-07-17-task-auto-naming) — the cheapest
@@ -94,14 +94,17 @@ declare const configSchema: z.ZodObject<{
94
94
  claude: z.ZodOptional<z.ZodString>;
95
95
  codex: z.ZodOptional<z.ZodString>;
96
96
  opencode: z.ZodOptional<z.ZodString>;
97
+ pi: z.ZodOptional<z.ZodString>;
97
98
  }, "strip", z.ZodTypeAny, {
98
99
  claude?: string | undefined;
99
100
  codex?: string | undefined;
100
101
  opencode?: string | undefined;
102
+ pi?: string | undefined;
101
103
  }, {
102
104
  claude?: string | undefined;
103
105
  codex?: string | undefined;
104
106
  opencode?: string | undefined;
107
+ pi?: string | undefined;
105
108
  }>>>;
106
109
  }, "strip", z.ZodTypeAny, {
107
110
  skillsRepos: {
@@ -111,7 +114,7 @@ declare const configSchema: z.ZodObject<{
111
114
  maxParallel: number;
112
115
  worktreeRetention: number;
113
116
  memoryLimitMb?: number | undefined;
114
- defaultRunner: "claude" | "codex" | "opencode";
117
+ defaultRunner: "claude" | "codex" | "opencode" | "pi";
115
118
  plannerModel: string;
116
119
  namerModel: string;
117
120
  liveTitleUpdates?: boolean | undefined;
@@ -122,6 +125,7 @@ declare const configSchema: z.ZodObject<{
122
125
  claude?: string | undefined;
123
126
  codex?: string | undefined;
124
127
  opencode?: string | undefined;
128
+ pi?: string | undefined;
125
129
  } | undefined;
126
130
  }, {
127
131
  skillsRepos?: {
@@ -131,7 +135,7 @@ declare const configSchema: z.ZodObject<{
131
135
  maxParallel?: number | undefined;
132
136
  worktreeRetention?: unknown;
133
137
  memoryLimitMb?: unknown;
134
- defaultRunner?: "claude" | "codex" | "opencode" | undefined;
138
+ defaultRunner?: "claude" | "codex" | "opencode" | "pi" | undefined;
135
139
  plannerModel?: string | undefined;
136
140
  namerModel?: string | undefined;
137
141
  liveTitleUpdates?: boolean | undefined;
@@ -143,6 +147,20 @@ declare const configSchema: z.ZodObject<{
143
147
  export type CezConfig = z.infer<typeof configSchema>;
144
148
  /** Read `.ai/cezar/config.json` on demand — never cached, never throws. */
145
149
  export declare function loadConfig(repoRoot: string): Promise<CezConfig>;
150
+ /**
151
+ * The default skills repos that are *opt-in per skill* (the "import OM skills"
152
+ * flow): the set of repo identifiers a user must explicitly import from before
153
+ * their skills join the catalog. This is exactly `DEFAULT_SKILLS_REPOS` when the
154
+ * repo has NOT configured its own `skillsRepos` — the zero-config majority — and
155
+ * empty once a repo takes control by setting `skillsRepos` (then everything it
156
+ * lists auto-loads, unchanged).
157
+ *
158
+ * `loadConfig` cannot answer this: the schema's `.default(DEFAULT_SKILLS_REPOS)`
159
+ * materializes the key, so a parsed config can't tell "the user chose these" from
160
+ * "the user said nothing". So we probe the raw file for the key's presence — the
161
+ * same reason `ownWorktreeRetention` below reads the raw JSON.
162
+ */
163
+ export declare function gatedSkillsRepos(repoRoot: string): Promise<Set<string>>;
146
164
  /**
147
165
  * Effective worktree retention for a repo (#483 + spec
148
166
  * 2026-07-20-multi-project-workspace). Precedence, exactly what Settings →
package/dist/config.js CHANGED
@@ -2,6 +2,7 @@ import { readFile } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  import { z } from 'zod';
4
4
  import { loadWorkspaceConfig } from './workspace/config.js';
5
+ import { RUNNER_IDS } from './core/agent-runner.js';
5
6
  /**
6
7
  * Optional advanced config at `.ai/cezar/config.json`. Zero-config rule:
7
8
  * a missing file behaves exactly like the default below, an unreadable or
@@ -46,7 +47,7 @@ const configSchema = z.object({
46
47
  * step (workflow). The GUI only offers runners actually installed; this is
47
48
  * the preselected default. Also the runner the chain planner uses.
48
49
  */
49
- defaultRunner: z.enum(['claude', 'codex', 'opencode']).default('claude'),
50
+ defaultRunner: z.enum(RUNNER_IDS).default('claude'),
50
51
  /** Model for the chain planner (spec 008) — cheap but reliable at JSON. */
51
52
  plannerModel: z.string().min(1).default('sonnet'),
52
53
  /** Model for the task namer (spec 2026-07-17-task-auto-naming) — the cheapest
@@ -87,6 +88,7 @@ const configSchema = z.object({
87
88
  claude: z.string().trim().min(1).max(200).optional(),
88
89
  codex: z.string().trim().min(1).max(200).optional(),
89
90
  opencode: z.string().trim().min(1).max(200).optional(),
91
+ pi: z.string().trim().min(1).max(200).optional(),
90
92
  })
91
93
  .optional()
92
94
  .catch(undefined),
@@ -141,6 +143,45 @@ async function ownWorktreeRetention(repoRoot) {
141
143
  return undefined; // malformed JSON — same as unset
142
144
  }
143
145
  }
146
+ /**
147
+ * The default skills repos that are *opt-in per skill* (the "import OM skills"
148
+ * flow): the set of repo identifiers a user must explicitly import from before
149
+ * their skills join the catalog. This is exactly `DEFAULT_SKILLS_REPOS` when the
150
+ * repo has NOT configured its own `skillsRepos` — the zero-config majority — and
151
+ * empty once a repo takes control by setting `skillsRepos` (then everything it
152
+ * lists auto-loads, unchanged).
153
+ *
154
+ * `loadConfig` cannot answer this: the schema's `.default(DEFAULT_SKILLS_REPOS)`
155
+ * materializes the key, so a parsed config can't tell "the user chose these" from
156
+ * "the user said nothing". So we probe the raw file for the key's presence — the
157
+ * same reason `ownWorktreeRetention` below reads the raw JSON.
158
+ */
159
+ export async function gatedSkillsRepos(repoRoot) {
160
+ const none = new Set();
161
+ let raw;
162
+ try {
163
+ raw = await readFile(join(repoRoot, '.ai/cezar', 'config.json'), 'utf8');
164
+ }
165
+ catch {
166
+ // No file — the defaults are in effect, so they are the opt-in set.
167
+ return new Set(DEFAULT_SKILLS_REPOS.map((r) => r.repo));
168
+ }
169
+ try {
170
+ const parsed = JSON.parse(raw);
171
+ if (!parsed || typeof parsed !== 'object') {
172
+ return new Set(DEFAULT_SKILLS_REPOS.map((r) => r.repo));
173
+ }
174
+ // The user took control of the source list — nothing is gated; a value the
175
+ // schema would refuse degrades to the default too (same as `loadConfig`).
176
+ if (parsed.skillsRepos !== undefined)
177
+ return none;
178
+ return new Set(DEFAULT_SKILLS_REPOS.map((r) => r.repo));
179
+ }
180
+ catch {
181
+ // Malformed JSON degrades to the default (which loadConfig also does).
182
+ return new Set(DEFAULT_SKILLS_REPOS.map((r) => r.repo));
183
+ }
184
+ }
144
185
  /**
145
186
  * Effective worktree retention for a repo (#483 + spec
146
187
  * 2026-07-20-multi-project-workspace). Precedence, exactly what Settings →
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -192,26 +192,32 @@ const BASE_ALLOW_PREFIXES = [
192
192
  'MISE_',
193
193
  'COMPOSER_',
194
194
  ];
195
+ /** The provider credentials a backend that selects models as `provider/model` may need — it can
196
+ * be pointed at any of them, so none can be pruned without breaking a legitimate model id. */
197
+ const MULTI_PROVIDER_PREFIXES = [
198
+ 'OPENAI_',
199
+ 'ANTHROPIC_',
200
+ 'AZURE_OPENAI_',
201
+ 'OPENROUTER_',
202
+ 'GROQ_',
203
+ 'MISTRAL_',
204
+ 'GEMINI_',
205
+ 'GOOGLE_GENERATIVE_AI_',
206
+ 'DEEPSEEK_',
207
+ 'XAI_',
208
+ 'PERPLEXITY_',
209
+ 'TOGETHER_',
210
+ 'FIREWORKS_',
211
+ ];
195
212
  /** Per-backend auth/config the runner genuinely needs, by prefix. */
196
213
  const BACKEND_ALLOW_PREFIXES = {
197
214
  claude: ['ANTHROPIC_', 'CLAUDE_'],
198
215
  'claude-cli': ['ANTHROPIC_', 'CLAUDE_'],
199
216
  codex: ['OPENAI_', 'CODEX_', 'AZURE_OPENAI_'],
200
- opencode: [
201
- 'OPENAI_',
202
- 'ANTHROPIC_',
203
- 'AZURE_OPENAI_',
204
- 'OPENROUTER_',
205
- 'GROQ_',
206
- 'MISTRAL_',
207
- 'GEMINI_',
208
- 'GOOGLE_GENERATIVE_AI_',
209
- 'DEEPSEEK_',
210
- 'XAI_',
211
- 'PERPLEXITY_',
212
- 'TOGETHER_',
213
- 'FIREWORKS_',
214
- ],
217
+ opencode: MULTI_PROVIDER_PREFIXES,
218
+ // pi selects models as `provider/model` (#387), so it needs both its own config and any
219
+ // provider a configured model id can name.
220
+ pi: ['PI_', 'CLAUDE_', ...MULTI_PROVIDER_PREFIXES],
215
221
  };
216
222
  /** `gh` handoff (draft PRs) works in every backend — the one credential the
217
223
  * project deliberately keeps in the environment (AGENTS.md "No secrets in
@@ -1 +1 @@
1
- {"version":3,"file":"agent-env.js","sourceRoot":"","sources":["../../src/core/agent-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD;;;;;;;GAOG;AACH,SAAS,QAAQ,CAAC,KAAwB;IACxC,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,6EAA6E;AAC7E,MAAM,gBAAgB,GAAwB,QAAQ,CAAC;IACrD,gCAAgC;IAChC,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,SAAS;IACT,OAAO;IACP,KAAK;IACL,QAAQ;IACR,OAAO;IACP,UAAU;IACV,MAAM;IACN,UAAU;IACV,UAAU;IACV,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,KAAK;IACL,IAAI;IACJ,SAAS;IACT,MAAM;IACN,UAAU;IACV,qBAAqB;IACrB,MAAM;IACN,UAAU;IACV,WAAW;IACX,SAAS;IACT,OAAO;IACP,UAAU;IACV,aAAa;IACb,UAAU;IACV,SAAS;IACT,iBAAiB;IACjB,YAAY;IACZ,uEAAuE;IACvE,eAAe;IACf,eAAe;IACf,mBAAmB;IACnB,QAAQ;IACR,QAAQ;IACR,OAAO;IACP,MAAM;IACN,SAAS;IACT,UAAU;IACV,oCAAoC;IACpC,WAAW;IACX,YAAY;IACZ,qBAAqB;IACrB,SAAS;IACT,iBAAiB;IACjB,eAAe;IACf,yEAAyE;IACzE,YAAY;IACZ,aAAa;IACb,WAAW;IACX,WAAW;IACX,UAAU;IACV,2EAA2E;IAC3E,wEAAwE;IACxE,wEAAwE;IACxE,4EAA4E;IAC5E,oCAAoC;IACpC,YAAY;IACZ,aAAa;IACb,QAAQ;IACR,SAAS;IACT,SAAS;IACT,aAAa;IACb,WAAW;IACX,UAAU;IACV,SAAS;IACT,cAAc;IACd,aAAa;IACb,iBAAiB;IACjB,QAAQ;IACR,cAAc;IACd,mBAAmB;IACnB,cAAc;IACd,oBAAoB;IACpB,yBAAyB;IACzB,oBAAoB;IACpB,cAAc;IACd,UAAU;IACV,YAAY;IACZ,cAAc;IACd,aAAa;IACb,aAAa;IACb,IAAI;IACJ,sBAAsB;IACtB,wBAAwB;IACxB,sBAAsB;IACtB,iBAAiB;IACjB,oBAAoB;CACrB,CAAC,CAAC;AAEH;;gEAEgE;AAChE,MAAM,mBAAmB,GAAsB;IAC7C,KAAK;IACL,MAAM;IACN,OAAO;IACP,YAAY;IACZ,OAAO;IACP,aAAa;IACb,MAAM;IACN,OAAO;IACP,OAAO;IACP,MAAM;IACN,OAAO;IACP,QAAQ;IACR,MAAM;IACN,WAAW;IACX,SAAS;IACT,OAAO;IACP,QAAQ;IACR,MAAM;IACN,SAAS;IACT,SAAS;IACT,aAAa;IACb,QAAQ;IACR,KAAK;IACL,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,SAAS;IACT,OAAO;IACP,SAAS;IACT,QAAQ;IACR,OAAO;IACP,KAAK;IACL,QAAQ;IACR,QAAQ;IACR,OAAO;IACP,SAAS;IACT,YAAY;IACZ,SAAS;IACT,SAAS;IACT,WAAW;IACX,aAAa;IACb,MAAM;IACN,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,aAAa;IACb,yBAAyB;IACzB,MAAM;IACN,MAAM;IACN,QAAQ;IACR,SAAS;IACT,SAAS;IACT,UAAU;IACV,SAAS;IACT,eAAe;IACf,SAAS;IACT,QAAQ;IACR,OAAO;IACP,OAAO;IACP,WAAW;IACX,OAAO;IACP,OAAO;IACP,WAAW;CACZ,CAAC;AAEF,qEAAqE;AACrE,MAAM,sBAAsB,GAA4C;IACtE,MAAM,EAAE,CAAC,YAAY,EAAE,SAAS,CAAC;IACjC,YAAY,EAAE,CAAC,YAAY,EAAE,SAAS,CAAC;IACvC,KAAK,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,eAAe,CAAC;IAC7C,QAAQ,EAAE;QACR,SAAS;QACT,YAAY;QACZ,eAAe;QACf,aAAa;QACb,OAAO;QACP,UAAU;QACV,SAAS;QACT,uBAAuB;QACvB,WAAW;QACX,MAAM;QACN,aAAa;QACb,WAAW;QACX,YAAY;KACb;CACF,CAAC;AAEF;;+DAE+D;AAC/D,MAAM,cAAc,GAAwB,QAAQ,CAAC;IACnD,cAAc;IACd,UAAU;IACV,SAAS;IACT,qBAAqB;IACrB,eAAe;CAChB,CAAC,CAAC;AAEH;;;;;;;;;;GAUG;AACH,MAAM,cAAc,GAAG,yBAAyB,CAAC;AACjD,MAAM,aAAa,GAAG,wBAAwB,CAAC;AAC/C;gFACgF;AAChF,MAAM,sBAAsB,GAAsB,CAAC,MAAM,CAAC,CAAC;AAC3D,MAAM,kBAAkB,GAAwB,QAAQ,CAAC;IACvD,gCAAgC;IAChC,iBAAiB;IACjB,2EAA2E;CAC5E,CAAC,CAAC;AACH,MAAM,qBAAqB,GAAsB,CAAC,eAAe,CAAC,CAAC;AAEnE,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,0EAA0E;AAC1E,SAAS,aAAa,CAAC,IAAY,EAAE,QAA2B;IAC9D,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,+EAA+E;AAC/E,SAAS,OAAO,CAAC,MAAyB,EAAE,IAAY;IACtD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,KAAK;YAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,oEAAoE;AACpE,SAAS,QAAQ,CAAC,KAAyB;IACzC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACtC,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,OAAO,CAAC;AAChD,CAAC;AAUD;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAA0B;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;IAElC,0EAA0E;IAC1E,uEAAuE;IACvE,0EAA0E;IAC1E,4DAA4D;IAC5D,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,EAAE,CAAC;QACpD,OAAO,EAAE,GAAG,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACjC,CAAC;IAED,MAAM,eAAe,GAAG,sBAAsB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,sBAAsB,CAAC,MAAM,CAAC;IAC9F,MAAM,WAAW,GAAG,QAAQ,CAC1B,CAAC,OAAO,CAAC,MAAM,EAAE,qBAAqB,CAAC,IAAI,EAAE,CAAC;SAC3C,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC,CACnB,CAAC;IAEF,0EAA0E;IAC1E,wEAAwE;IACxE,MAAM,WAAW,GAAG,eAAe,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IACxD,MAAM,aAAa,GAAa,EAAE,CAAC;IACnC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,IAAI,WAAW,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;QAC7D,aAAa,CAAC,IAAI,CAAC,GAAG,sBAAsB,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,WAAW,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC;QAC5D,aAAa,CAAC,IAAI,CAAC,GAAG,qBAAqB,CAAC,CAAC;QAC7C,KAAK,MAAM,CAAC,IAAI,kBAAkB;YAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,GAAG,GAAsB,EAAE,CAAC;IAClC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnD,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAClC,IAAI,KAAK,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACrC,CAAC;IACD,2EAA2E;IAC3E,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACrE,OAAO,GAAG,CAAC;IAEX,4EAA4E;IAC5E,SAAS,KAAK,CAAC,IAAY;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAC/B,wEAAwE;QACxE,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC;QACxC,uEAAuE;QACvE,4EAA4E;QAC5E,qEAAqE;QACrE,wDAAwD;QACxD,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,IAAI,aAAa,CAAC,GAAG,EAAE,eAAe,CAAC;YAAE,OAAO,IAAI,CAAC;QACrD,IAAI,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,GAAG,EAAE,aAAa,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1E,+BAA+B;QAC/B,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACtC,0EAA0E;QAC1E,uEAAuE;QACvE,uEAAuE;QACvE,IAAI,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAC3C,IAAI,aAAa,CAAC,GAAG,EAAE,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAC9E,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"agent-env.js","sourceRoot":"","sources":["../../src/core/agent-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD;;;;;;;GAOG;AACH,SAAS,QAAQ,CAAC,KAAwB;IACxC,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,6EAA6E;AAC7E,MAAM,gBAAgB,GAAwB,QAAQ,CAAC;IACrD,gCAAgC;IAChC,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,SAAS;IACT,OAAO;IACP,KAAK;IACL,QAAQ;IACR,OAAO;IACP,UAAU;IACV,MAAM;IACN,UAAU;IACV,UAAU;IACV,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,KAAK;IACL,IAAI;IACJ,SAAS;IACT,MAAM;IACN,UAAU;IACV,qBAAqB;IACrB,MAAM;IACN,UAAU;IACV,WAAW;IACX,SAAS;IACT,OAAO;IACP,UAAU;IACV,aAAa;IACb,UAAU;IACV,SAAS;IACT,iBAAiB;IACjB,YAAY;IACZ,uEAAuE;IACvE,eAAe;IACf,eAAe;IACf,mBAAmB;IACnB,QAAQ;IACR,QAAQ;IACR,OAAO;IACP,MAAM;IACN,SAAS;IACT,UAAU;IACV,oCAAoC;IACpC,WAAW;IACX,YAAY;IACZ,qBAAqB;IACrB,SAAS;IACT,iBAAiB;IACjB,eAAe;IACf,yEAAyE;IACzE,YAAY;IACZ,aAAa;IACb,WAAW;IACX,WAAW;IACX,UAAU;IACV,2EAA2E;IAC3E,wEAAwE;IACxE,wEAAwE;IACxE,4EAA4E;IAC5E,oCAAoC;IACpC,YAAY;IACZ,aAAa;IACb,QAAQ;IACR,SAAS;IACT,SAAS;IACT,aAAa;IACb,WAAW;IACX,UAAU;IACV,SAAS;IACT,cAAc;IACd,aAAa;IACb,iBAAiB;IACjB,QAAQ;IACR,cAAc;IACd,mBAAmB;IACnB,cAAc;IACd,oBAAoB;IACpB,yBAAyB;IACzB,oBAAoB;IACpB,cAAc;IACd,UAAU;IACV,YAAY;IACZ,cAAc;IACd,aAAa;IACb,aAAa;IACb,IAAI;IACJ,sBAAsB;IACtB,wBAAwB;IACxB,sBAAsB;IACtB,iBAAiB;IACjB,oBAAoB;CACrB,CAAC,CAAC;AAEH;;gEAEgE;AAChE,MAAM,mBAAmB,GAAsB;IAC7C,KAAK;IACL,MAAM;IACN,OAAO;IACP,YAAY;IACZ,OAAO;IACP,aAAa;IACb,MAAM;IACN,OAAO;IACP,OAAO;IACP,MAAM;IACN,OAAO;IACP,QAAQ;IACR,MAAM;IACN,WAAW;IACX,SAAS;IACT,OAAO;IACP,QAAQ;IACR,MAAM;IACN,SAAS;IACT,SAAS;IACT,aAAa;IACb,QAAQ;IACR,KAAK;IACL,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,SAAS;IACT,OAAO;IACP,SAAS;IACT,QAAQ;IACR,OAAO;IACP,KAAK;IACL,QAAQ;IACR,QAAQ;IACR,OAAO;IACP,SAAS;IACT,YAAY;IACZ,SAAS;IACT,SAAS;IACT,WAAW;IACX,aAAa;IACb,MAAM;IACN,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,aAAa;IACb,yBAAyB;IACzB,MAAM;IACN,MAAM;IACN,QAAQ;IACR,SAAS;IACT,SAAS;IACT,UAAU;IACV,SAAS;IACT,eAAe;IACf,SAAS;IACT,QAAQ;IACR,OAAO;IACP,OAAO;IACP,WAAW;IACX,OAAO;IACP,OAAO;IACP,WAAW;CACZ,CAAC;AAEF;+FAC+F;AAC/F,MAAM,uBAAuB,GAAsB;IACjD,SAAS;IACT,YAAY;IACZ,eAAe;IACf,aAAa;IACb,OAAO;IACP,UAAU;IACV,SAAS;IACT,uBAAuB;IACvB,WAAW;IACX,MAAM;IACN,aAAa;IACb,WAAW;IACX,YAAY;CACb,CAAC;AAEF,qEAAqE;AACrE,MAAM,sBAAsB,GAA4C;IACtE,MAAM,EAAE,CAAC,YAAY,EAAE,SAAS,CAAC;IACjC,YAAY,EAAE,CAAC,YAAY,EAAE,SAAS,CAAC;IACvC,KAAK,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,eAAe,CAAC;IAC7C,QAAQ,EAAE,uBAAuB;IACjC,wFAAwF;IACxF,2CAA2C;IAC3C,EAAE,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,uBAAuB,CAAC;CACnD,CAAC;AAEF;;+DAE+D;AAC/D,MAAM,cAAc,GAAwB,QAAQ,CAAC;IACnD,cAAc;IACd,UAAU;IACV,SAAS;IACT,qBAAqB;IACrB,eAAe;CAChB,CAAC,CAAC;AAEH;;;;;;;;;;GAUG;AACH,MAAM,cAAc,GAAG,yBAAyB,CAAC;AACjD,MAAM,aAAa,GAAG,wBAAwB,CAAC;AAC/C;gFACgF;AAChF,MAAM,sBAAsB,GAAsB,CAAC,MAAM,CAAC,CAAC;AAC3D,MAAM,kBAAkB,GAAwB,QAAQ,CAAC;IACvD,gCAAgC;IAChC,iBAAiB;IACjB,2EAA2E;CAC5E,CAAC,CAAC;AACH,MAAM,qBAAqB,GAAsB,CAAC,eAAe,CAAC,CAAC;AAEnE,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,0EAA0E;AAC1E,SAAS,aAAa,CAAC,IAAY,EAAE,QAA2B;IAC9D,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,+EAA+E;AAC/E,SAAS,OAAO,CAAC,MAAyB,EAAE,IAAY;IACtD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,KAAK;YAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,oEAAoE;AACpE,SAAS,QAAQ,CAAC,KAAyB;IACzC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACtC,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,OAAO,CAAC;AAChD,CAAC;AAUD;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAA0B;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;IAElC,0EAA0E;IAC1E,uEAAuE;IACvE,0EAA0E;IAC1E,4DAA4D;IAC5D,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,EAAE,CAAC;QACpD,OAAO,EAAE,GAAG,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IACjC,CAAC;IAED,MAAM,eAAe,GAAG,sBAAsB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,sBAAsB,CAAC,MAAM,CAAC;IAC9F,MAAM,WAAW,GAAG,QAAQ,CAC1B,CAAC,OAAO,CAAC,MAAM,EAAE,qBAAqB,CAAC,IAAI,EAAE,CAAC;SAC3C,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC,CACnB,CAAC;IAEF,0EAA0E;IAC1E,wEAAwE;IACxE,MAAM,WAAW,GAAG,eAAe,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IACxD,MAAM,aAAa,GAAa,EAAE,CAAC;IACnC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,IAAI,WAAW,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;QAC7D,aAAa,CAAC,IAAI,CAAC,GAAG,sBAAsB,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,WAAW,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC;QAC5D,aAAa,CAAC,IAAI,CAAC,GAAG,qBAAqB,CAAC,CAAC;QAC7C,KAAK,MAAM,CAAC,IAAI,kBAAkB;YAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,GAAG,GAAsB,EAAE,CAAC;IAClC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnD,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAClC,IAAI,KAAK,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACrC,CAAC;IACD,2EAA2E;IAC3E,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACrE,OAAO,GAAG,CAAC;IAEX,4EAA4E;IAC5E,SAAS,KAAK,CAAC,IAAY;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAC/B,wEAAwE;QACxE,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC;QACxC,uEAAuE;QACvE,4EAA4E;QAC5E,qEAAqE;QACrE,wDAAwD;QACxD,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,IAAI,aAAa,CAAC,GAAG,EAAE,eAAe,CAAC;YAAE,OAAO,IAAI,CAAC;QACrD,IAAI,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,GAAG,EAAE,aAAa,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1E,+BAA+B;QAC/B,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACtC,0EAA0E;QAC1E,uEAAuE;QACvE,uEAAuE;QACvE,IAAI,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAC3C,IAAI,aAAa,CAAC,GAAG,EAAE,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAC9E,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -4,18 +4,28 @@
4
4
  * no token-budget circuit breaker, no zod response schemas — one run is one
5
5
  * agent-CLI session streaming normalized events.
6
6
  *
7
- * Three interchangeable backends implement this seam, each as a persistent
7
+ * Four interchangeable backends implement this seam, each as a persistent
8
8
  * process so multi-turn follow-ups, `waiting`, interrupt and resume all work:
9
9
  * - `claude` — Claude Code CLI, stream-json over stdin/stdout;
10
10
  * - `codex` — `codex app-server`, JSON-RPC 2.0 (JSONL) over stdin/stdout;
11
- * - `opencode` — `opencode serve`, HTTP + SSE.
11
+ * - `opencode` — `opencode serve`, HTTP + SSE;
12
+ * - `pi` — pi coding CLI, RPC over JSONL stdin/stdout, selecting its
13
+ * model with `provider/model`.
12
14
  */
13
15
  import type { UiEvent } from './ui-events.js';
14
- /** `claude-cli` is the legacy id kept so old run records still parse. */
15
- export type AgentBackend = 'claude' | 'codex' | 'opencode' | 'claude-cli';
16
+ /**
17
+ * The user-selectable runners (what config/GUI expose), in display order — the SINGLE source of
18
+ * truth for the set. Every runtime enumeration derives from this tuple (zod schemas, the
19
+ * server-install "at least one agent CLI" gate, the CLI-handoff registry) rather than repeating
20
+ * the literals, so adding runner #5 is a one-line change here and typecheck finds the rest.
21
+ */
22
+ export declare const RUNNER_IDS: readonly ['claude', 'codex', 'opencode', 'pi'];
16
23
  /** The user-selectable runners (what config/GUI expose). */
17
- export type RunnerId = 'claude' | 'codex' | 'opencode';
18
- export declare const RUNNER_IDS: readonly RunnerId[];
24
+ export type RunnerId = (typeof RUNNER_IDS)[number];
25
+ /** `claude-cli` is the legacy id kept so old run records still parse. */
26
+ export type AgentBackend = RunnerId | 'claude-cli';
27
+ /** Narrow an arbitrary string (a config value, a check name) to a runner id. */
28
+ export declare function isRunnerId(value: string): value is RunnerId;
19
29
  export interface AgentRunSpec {
20
30
  /** Appended to the CLI's default system prompt (`--append-system-prompt`). */
21
31
  systemPrompt?: string;
@@ -4,13 +4,25 @@
4
4
  * no token-budget circuit breaker, no zod response schemas — one run is one
5
5
  * agent-CLI session streaming normalized events.
6
6
  *
7
- * Three interchangeable backends implement this seam, each as a persistent
7
+ * Four interchangeable backends implement this seam, each as a persistent
8
8
  * process so multi-turn follow-ups, `waiting`, interrupt and resume all work:
9
9
  * - `claude` — Claude Code CLI, stream-json over stdin/stdout;
10
10
  * - `codex` — `codex app-server`, JSON-RPC 2.0 (JSONL) over stdin/stdout;
11
- * - `opencode` — `opencode serve`, HTTP + SSE.
11
+ * - `opencode` — `opencode serve`, HTTP + SSE;
12
+ * - `pi` — pi coding CLI, RPC over JSONL stdin/stdout, selecting its
13
+ * model with `provider/model`.
12
14
  */
13
- export const RUNNER_IDS = ['claude', 'codex', 'opencode'];
15
+ /**
16
+ * The user-selectable runners (what config/GUI expose), in display order — the SINGLE source of
17
+ * truth for the set. Every runtime enumeration derives from this tuple (zod schemas, the
18
+ * server-install "at least one agent CLI" gate, the CLI-handoff registry) rather than repeating
19
+ * the literals, so adding runner #5 is a one-line change here and typecheck finds the rest.
20
+ */
21
+ export const RUNNER_IDS = ['claude', 'codex', 'opencode', 'pi'];
22
+ /** Narrow an arbitrary string (a config value, a check name) to a runner id. */
23
+ export function isRunnerId(value) {
24
+ return RUNNER_IDS.includes(value);
25
+ }
14
26
  /**
15
27
  * Backends without a dedicated system-prompt channel (codex app-server,
16
28
  * opencode serve) deliver `spec.systemPrompt` as a leading block of the
@@ -1 +1 @@
1
- {"version":3,"file":"agent-runner.js","sourceRoot":"","sources":["../../src/core/agent-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,MAAM,CAAC,MAAM,UAAU,GAAwB,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;AAsC/E;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,YAAgC,EAAE,UAAkB;IACtF,OAAO,YAAY,CAAC,CAAC,CAAC,GAAG,YAAY,cAAc,UAAU,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;AAC/E,CAAC"}
1
+ {"version":3,"file":"agent-runner.js","sourceRoot":"","sources":["../../src/core/agent-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,CAAU,CAAC;AAQzE,gFAAgF;AAChF,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAQ,UAAgC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC3D,CAAC;AAsCD;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,YAAgC,EAAE,UAAkB;IACtF,OAAO,YAAY,CAAC,CAAC,CAAC,GAAG,YAAY,cAAc,UAAU,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;AAC/E,CAAC"}
@@ -1,15 +1,15 @@
1
1
  export interface BackendCheck {
2
- name: 'claude' | 'codex' | 'opencode' | 'gh' | 'git';
2
+ name: 'claude' | 'codex' | 'opencode' | 'pi' | 'gh' | 'git';
3
3
  available: boolean;
4
4
  version?: string;
5
5
  hint?: string;
6
6
  }
7
7
  /**
8
8
  * Probe the host for everything cez leans on: the agent CLIs (`claude`, and
9
- * the optional `codex` / `opencode` alternatives), `gh` (GitHub auth for PR
10
- * creation) and `git`. Nothing is required except at least one agent CLI — the
11
- * GUI degrades gracefully, only offers the runners that are present, and shows
12
- * the hints for the rest.
9
+ * the optional `codex` / `opencode` / `pi` alternatives), `gh` (GitHub auth for
10
+ * PR creation) and `git`. Nothing is required except at least one agent CLI —
11
+ * the GUI degrades gracefully, only offers the runners that are present, and
12
+ * shows the hints for the rest.
13
13
  */
14
14
  export declare function detectEnvironment(): Promise<BackendCheck[]>;
15
15
  /** The host's GitHub token: logged-in `gh` first, `GITHUB_TOKEN` fallback. */
@@ -3,13 +3,20 @@ import { promisify } from 'node:util';
3
3
  const exec = promisify(execFile);
4
4
  /**
5
5
  * Probe the host for everything cez leans on: the agent CLIs (`claude`, and
6
- * the optional `codex` / `opencode` alternatives), `gh` (GitHub auth for PR
7
- * creation) and `git`. Nothing is required except at least one agent CLI — the
8
- * GUI degrades gracefully, only offers the runners that are present, and shows
9
- * the hints for the rest.
6
+ * the optional `codex` / `opencode` / `pi` alternatives), `gh` (GitHub auth for
7
+ * PR creation) and `git`. Nothing is required except at least one agent CLI —
8
+ * the GUI degrades gracefully, only offers the runners that are present, and
9
+ * shows the hints for the rest.
10
10
  */
11
11
  export async function detectEnvironment() {
12
- return Promise.all([probeClaude(), probeCodex(), probeOpencode(), probeGh(), probeGit()]);
12
+ return Promise.all([
13
+ probeClaude(),
14
+ probeCodex(),
15
+ probeOpencode(),
16
+ probePi(),
17
+ probeGh(),
18
+ probeGit(),
19
+ ]);
13
20
  }
14
21
  async function probeClaude() {
15
22
  if (process.env.CEZ_DRY_RUN === '1') {
@@ -80,6 +87,31 @@ async function probeOpencode() {
80
87
  };
81
88
  }
82
89
  }
90
+ async function probePi() {
91
+ // Dry-run stands the runner up on the shared mock, so report it present.
92
+ if (process.env.CEZ_DRY_RUN === '1') {
93
+ return { name: 'pi', available: true, version: 'mock (CEZ_DRY_RUN=1)' };
94
+ }
95
+ const bin = process.env.CEZ_PI_BIN ?? 'pi';
96
+ try {
97
+ const { stdout } = await exec(bin, ['--version'], { timeout: 10_000 });
98
+ return {
99
+ name: 'pi',
100
+ available: true,
101
+ version: stdout.trim(),
102
+ hint: 'if not authenticated, run `pi` once and log in',
103
+ };
104
+ }
105
+ catch {
106
+ // A missing `pi` CLI is never a boot failure — the runner just isn't
107
+ // offered, exactly like an absent codex/opencode.
108
+ return {
109
+ name: 'pi',
110
+ available: false,
111
+ hint: 'optional: install the pi CLI and log in to use the pi runner',
112
+ };
113
+ }
114
+ }
83
115
  async function probeGh() {
84
116
  try {
85
117
  const { stdout } = await exec('gh', ['auth', 'token'], { timeout: 10_000 });
@@ -1 +1 @@
1
- {"version":3,"file":"backend-detect.js","sourceRoot":"","sources":["../../src/core/backend-detect.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"backend-detect.js","sourceRoot":"","sources":["../../src/core/backend-detect.ts"],"names":[],"mappings":"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"}
@@ -35,6 +35,15 @@ export interface ClaudeUiMapperState {
35
35
  readonly turnSeq: number;
36
36
  readonly currentTurnId: string | null;
37
37
  readonly itemSeq: number;
38
+ /** True once any assistant `text` block minted a message item. SESSION-scoped,
39
+ * never reset per turn — it mirrors `ctx.textChunks` in claude-cli-runner.ts,
40
+ * which is allocated once per `runAgent` and accumulates across turns. When a
41
+ * session streams no text block at all, the runner falls back to emitting the
42
+ * v1 `text` from `msg.result` (`textChunks.length === 0`), and `mapResult`
43
+ * must mint the v2 twin under the SAME guard — otherwise that prose exists
44
+ * only in v1 and the cockpit's "v2 wins per turn" dedup drops it with no
45
+ * replacement, which is exactly the vanishing-message bug. */
46
+ readonly sawAssistantText: boolean;
38
47
  /** `tool_use` items awaiting their `tool_result`, keyed by tool_use id. */
39
48
  readonly openTools: ReadonlyMap<string, UiToolItem>;
40
49
  /** The running plan built incrementally by Claude's task tools, keyed by the
@@ -32,6 +32,7 @@ export function createClaudeUiState(opts = {}) {
32
32
  turnSeq: 0,
33
33
  currentTurnId: null,
34
34
  itemSeq: 0,
35
+ sawAssistantText: false,
35
36
  openTools: new Map(),
36
37
  tasks: new Map(),
37
38
  pendingTaskCreates: new Map(),
@@ -100,12 +101,17 @@ function mapAssistant(msg, state) {
100
101
  let openTools = null;
101
102
  let tasks = state.tasks;
102
103
  let pendingTaskCreates = state.pendingTaskCreates;
104
+ let sawAssistantText = state.sawAssistantText;
103
105
  for (const raw of content) {
104
106
  if (!isRecord(raw))
105
107
  continue;
106
108
  if (raw.type === 'text' && typeof raw.text === 'string') {
107
109
  // Whole blocks per API round-trip — claude sends no deltas in this
108
110
  // mode, so we never fake `item.delta`s: started + completed.
111
+ // Counted against the result fallback exactly as the runner counts it:
112
+ // every text block, sub-agent ones included (`ctx.textChunks.push` runs
113
+ // regardless of `parent_tool_use_id`).
114
+ sawAssistantText = true;
109
115
  const item = { kind: 'message', id: `item_${++itemSeq}`, role: 'assistant', text: raw.text };
110
116
  if (parentItemId !== undefined)
111
117
  item.parentItemId = parentItemId;
@@ -177,7 +183,7 @@ function mapAssistant(msg, state) {
177
183
  return { events, state };
178
184
  return {
179
185
  events,
180
- state: { ...state, itemSeq, openTools: openTools ?? state.openTools, tasks, pendingTaskCreates },
186
+ state: { ...state, itemSeq, openTools: openTools ?? state.openTools, tasks, pendingTaskCreates, sawAssistantText },
181
187
  };
182
188
  }
183
189
  /** claude `Edit`/`Write` inputs carry the diff inline (§7.1). */
@@ -453,6 +459,22 @@ function mapResult(msg, state) {
453
459
  events.push({ type: 'item.completed', item });
454
460
  }
455
461
  }
462
+ // The result fallback, mirroring claude-cli-runner.ts's `textChunks.length === 0`
463
+ // branch: a session that streamed no assistant text block carries its whole
464
+ // reply on `msg.result`. The runner emits a v1 `text` for it; without the v2
465
+ // twin below, the cockpit's per-turn "v2 wins" dedup drops that line and the
466
+ // turn renders tool cards with no prose at all.
467
+ let sawAssistantText = state.sawAssistantText;
468
+ if (!sawAssistantText && typeof msg.result === 'string' && msg.result !== '') {
469
+ sawAssistantText = true;
470
+ const item = {
471
+ kind: 'message',
472
+ id: `item_${++itemSeq}`,
473
+ role: 'assistant',
474
+ text: msg.result,
475
+ };
476
+ events.push({ type: 'item.started', item }, { type: 'item.completed', item });
477
+ }
456
478
  const turnId = state.currentTurnId ?? `turn_${++turnSeq}`;
457
479
  const usage = rawTokenUsage(msg.usage);
458
480
  const costUsd = typeof msg.total_cost_usd === 'number' && Number.isFinite(msg.total_cost_usd)
@@ -472,7 +494,14 @@ function mapResult(msg, state) {
472
494
  }
473
495
  return {
474
496
  events,
475
- state: { ...state, itemSeq, turnSeq, currentTurnId: null, openTools: openTools ?? state.openTools },
497
+ state: {
498
+ ...state,
499
+ itemSeq,
500
+ turnSeq,
501
+ currentTurnId: null,
502
+ openTools: openTools ?? state.openTools,
503
+ sawAssistantText,
504
+ },
476
505
  };
477
506
  }
478
507
  /** §7.1: success→end_turn, error_max_turns→max_tokens,