@qodeca/xezar 0.11.1 → 0.13.0

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 (140) hide show
  1. package/README.md +90 -18
  2. package/dist/agent-config/catalog.d.ts +10 -0
  3. package/dist/agent-config/catalog.js.map +1 -1
  4. package/dist/automations/coordinator.js +8 -0
  5. package/dist/automations/coordinator.js.map +1 -1
  6. package/dist/automations/types.d.ts +2 -0
  7. package/dist/contract/automations.d.ts +8 -0
  8. package/dist/contract/events.test.d.ts +1 -0
  9. package/dist/contract/index.js +87 -3
  10. package/dist/contract/runs.d.ts +25 -0
  11. package/dist/contract/runs.test.d.ts +1 -0
  12. package/dist/contract/skills.d.ts +1 -0
  13. package/dist/contract/workflows.d.ts +6 -0
  14. package/dist/contract/workspace.d.ts +37 -4
  15. package/dist/core/agent-env.js +8 -1
  16. package/dist/core/agent-env.js.map +1 -1
  17. package/dist/core/agent-runner.d.ts +13 -0
  18. package/dist/core/agent-runner.js +22 -0
  19. package/dist/core/agent-runner.js.map +1 -1
  20. package/dist/core/backend-detect.js +11 -1
  21. package/dist/core/backend-detect.js.map +1 -1
  22. package/dist/core/claude-cli-runner.js +8 -2
  23. package/dist/core/claude-cli-runner.js.map +1 -1
  24. package/dist/core/codex-app-server-runner.js +6 -2
  25. package/dist/core/codex-app-server-runner.js.map +1 -1
  26. package/dist/core/opencode-server-runner.d.ts +12 -0
  27. package/dist/core/opencode-server-runner.js +326 -17
  28. package/dist/core/opencode-server-runner.js.map +1 -1
  29. package/dist/core/pi-model-catalog.d.ts +52 -0
  30. package/dist/core/pi-model-catalog.js +135 -0
  31. package/dist/core/pi-model-catalog.js.map +1 -0
  32. package/dist/core/pi-runner.d.ts +3 -0
  33. package/dist/core/pi-runner.js +139 -12
  34. package/dist/core/pi-runner.js.map +1 -1
  35. package/dist/core/pi-ui-mapper.js +39 -3
  36. package/dist/core/pi-ui-mapper.js.map +1 -1
  37. package/dist/core/provider-auth.js +23 -1
  38. package/dist/core/provider-auth.js.map +1 -1
  39. package/dist/core/runner-model-catalog.js +11 -2
  40. package/dist/core/runner-model-catalog.js.map +1 -1
  41. package/dist/index.js +2 -0
  42. package/dist/index.js.map +1 -1
  43. package/dist/paths.d.ts +7 -0
  44. package/dist/paths.js +8 -0
  45. package/dist/paths.js.map +1 -1
  46. package/dist/runs/event-corrections.d.ts +12 -0
  47. package/dist/runs/event-corrections.js +141 -0
  48. package/dist/runs/event-corrections.js.map +1 -0
  49. package/dist/runs/event-history.d.ts +5 -1
  50. package/dist/runs/event-history.js +66 -5
  51. package/dist/runs/event-history.js.map +1 -1
  52. package/dist/runs/project-writer.d.ts +11 -0
  53. package/dist/runs/project-writer.js +115 -0
  54. package/dist/runs/project-writer.js.map +1 -0
  55. package/dist/runs/store.d.ts +2 -0
  56. package/dist/runs/store.js +13 -2
  57. package/dist/runs/store.js.map +1 -1
  58. package/dist/runs/task-markers.d.ts +4 -0
  59. package/dist/runs/task-markers.js +63 -5
  60. package/dist/runs/task-markers.js.map +1 -1
  61. package/dist/server/capabilities.d.ts +7 -5
  62. package/dist/server/capabilities.js +11 -7
  63. package/dist/server/capabilities.js.map +1 -1
  64. package/dist/server/project-context.js +2 -0
  65. package/dist/server/project-context.js.map +1 -1
  66. package/dist/server/server.d.ts +199 -47
  67. package/dist/server/server.js +195 -11
  68. package/dist/server/server.js.map +1 -1
  69. package/dist/workflows/run.d.ts +67 -2
  70. package/dist/workflows/run.js +190 -44
  71. package/dist/workflows/run.js.map +1 -1
  72. package/dist/workflows/types.d.ts +41 -0
  73. package/dist/workflows/types.js +72 -0
  74. package/dist/workflows/types.js.map +1 -1
  75. package/dist/workspace/config.d.ts +42 -0
  76. package/dist/workspace/config.js +132 -3
  77. package/dist/workspace/config.js.map +1 -1
  78. package/dist/workspace/semaphore.d.ts +63 -3
  79. package/dist/workspace/semaphore.js +76 -3
  80. package/dist/workspace/semaphore.js.map +1 -1
  81. package/package.json +3 -3
  82. package/web/dist/assets/{alert-dialog-CGskMvgc.js → alert-dialog-BVsVcbFy.js} +1 -1
  83. package/web/dist/assets/arrow-down-CYgAlZtW.js +1 -0
  84. package/web/dist/assets/arrow-left-BOqE0a3k.js +1 -0
  85. package/web/dist/assets/{centered-state-B_V_Ai2h.js → centered-state-Djgly6Ni.js} +1 -1
  86. package/web/dist/assets/chevron-right-Cc9BWnbN.js +1 -0
  87. package/web/dist/assets/{collapsible-B_8uYwHb.js → collapsible-DZ4D-DHG.js} +1 -1
  88. package/web/dist/assets/{commit-list-C4Dv6vUL.js → commit-list-B-z1JL9G.js} +1 -1
  89. package/web/dist/assets/{compare-variants-C68kZAYC.js → compare-variants-CdS8r8E2.js} +1 -1
  90. package/web/dist/assets/{diff-CbozNUJq.js → diff-BKew9rQX.js} +2 -2
  91. package/web/dist/assets/{diff-stat-btAmKFJr.js → diff-stat-D0mc5V6Z.js} +1 -1
  92. package/web/dist/assets/{diff-view-BpFTcG3R.js → diff-view-xpIcuLIC.js} +1 -1
  93. package/web/dist/assets/{dropdown-menu-Z80KMInL.js → dropdown-menu-CEQziH7X.js} +1 -1
  94. package/web/dist/assets/editable-title-BCX3T2BY.js +1 -0
  95. package/web/dist/assets/{ellipsis-vertical-Bmi2u2TG.js → ellipsis-vertical-ByVdDc4z.js} +1 -1
  96. package/web/dist/assets/{file-DKoYWRsv.js → file-xBSB5hXO.js} +1 -1
  97. package/web/dist/assets/{folder-u01HScRT.js → folder-CldgbZ5A.js} +1 -1
  98. package/web/dist/assets/{git-toolbar-CuwdZGjY.js → git-toolbar-BYlnf4qf.js} +1 -1
  99. package/web/dist/assets/github-CqGK62Lw.js +1 -0
  100. package/web/dist/assets/{image-preview-BR3iIIhf.js → image-preview-Cv5mZr0n.js} +1 -1
  101. package/web/dist/assets/index-3nxVmdn5.css +2 -0
  102. package/web/dist/assets/index-qX7n11FX.js +9 -0
  103. package/web/dist/assets/{markdown-5FuCZDA4.js → markdown-CgEEE2ND.js} +1 -1
  104. package/web/dist/assets/{new-task-form-BydHBbef.js → new-task-form-1r2bgsdD.js} +1 -1
  105. package/web/dist/assets/{pill-vNzaaYxj.js → pill-q-x22_ej.js} +1 -1
  106. package/web/dist/assets/{project-router-BbCzrHKs.js → project-router-VDN4jQM8.js} +1 -1
  107. package/web/dist/assets/{prompt-templates-B7Fs2b1S.js → prompt-templates-BmZtCe-L.js} +1 -1
  108. package/web/dist/assets/{refresh-cw-DGliez3E.js → refresh-cw-DcNCj2nu.js} +1 -1
  109. package/web/dist/assets/{repo-git-C_w_dYCj.js → repo-git-C2On8SlI.js} +1 -1
  110. package/web/dist/assets/{run-diff-Bq9vkSNK.js → run-diff-vguEMJzh.js} +1 -1
  111. package/web/dist/assets/{run-header-Cd8mSKBG.js → run-header-DM7MiKj9.js} +1 -1
  112. package/web/dist/assets/{search-x-69n_672Y.js → search-x-QmhaAbg5.js} +1 -1
  113. package/web/dist/assets/{skill-empty-hint-CL0g7WBL.js → skill-empty-hint-BrzUwByZ.js} +1 -1
  114. package/web/dist/assets/{skills-DoXLGvuf.js → skills-Bj-uG_Hz.js} +1 -1
  115. package/web/dist/assets/{sparkles-B8agSxBZ.js → sparkles-CP8QDOgX.js} +1 -1
  116. package/web/dist/assets/{square-terminal-Cf4Og6ct.js → square-terminal-CGypshSD.js} +1 -1
  117. package/web/dist/assets/{tab-link-Cp2-CJS8.js → tab-link-D4lFzzI1.js} +1 -1
  118. package/web/dist/assets/{task-changes-DZUO7q_X.js → task-changes-6aopqAmV.js} +1 -1
  119. package/web/dist/assets/{task-commits-CRlMB09k.js → task-commits-u-dwaCyw.js} +1 -1
  120. package/web/dist/assets/{task-files-CeDPRo86.js → task-files-IMOZnIUK.js} +1 -1
  121. package/web/dist/assets/task-thread-CbMPmrWq.js +9 -0
  122. package/web/dist/assets/{textarea--cpYshee.js → textarea-CyBCyKIk.js} +1 -1
  123. package/web/dist/assets/{thread-loading-ZhJref0J.js → thread-loading-Cuq2jchC.js} +1 -1
  124. package/web/dist/assets/{trash-2--ZtrzUx3.js → trash-2-B6Dp3ZNs.js} +1 -1
  125. package/web/dist/assets/{triangle-alert-D5tJwRD2.js → triangle-alert-xBya8FUp.js} +1 -1
  126. package/web/dist/assets/{upload-SnwVxKOA.js → upload-D6MXEB9p.js} +1 -1
  127. package/web/dist/assets/{use-desktop-C-tsTFEF.js → use-desktop-fLDKEJoB.js} +1 -1
  128. package/web/dist/assets/{use-submit-shortcut-JY8M_MPL.js → use-submit-shortcut-JTpNzU-u.js} +1 -1
  129. package/web/dist/assets/{utils-Bb8ohcr3.js → utils--z9hRtl3.js} +1 -1
  130. package/web/dist/assets/{workflows-kxdOo5D_.js → workflows-BY3KTkFw.js} +3 -3
  131. package/web/dist/assets/{zoomable-image-0G3IBXWC.js → zoomable-image-GTYwLtkS.js} +1 -1
  132. package/web/dist/index.html +23 -23
  133. package/web/dist/assets/arrow-down-G8adPhbu.js +0 -1
  134. package/web/dist/assets/arrow-left-BJsIW6A0.js +0 -1
  135. package/web/dist/assets/chevron-right-CFzn-von.js +0 -1
  136. package/web/dist/assets/editable-title-wS5NWwob.js +0 -1
  137. package/web/dist/assets/github-BjeW9iJb.js +0 -1
  138. package/web/dist/assets/index-BcI5hug3.css +0 -2
  139. package/web/dist/assets/index-Yp8woQLH.js +0 -7
  140. package/web/dist/assets/task-thread-Dhkupf1-.js +0 -9
package/README.md CHANGED
@@ -97,7 +97,7 @@ and an orchestrator keeps a whole queue of them moving.
97
97
  **orchestrates** them: it runs up to your parallel limit and holds the rest in
98
98
  an ordered queue. Point it at a GitHub issue and it runs straight on that, so
99
99
  working the tracker down stops being a manual chore. Turn on the opt-in
100
- **Inbox** (`XEZ_FOLLOWUPS=1`) and an agent's leftover follow-ups become the
100
+ **Inbox** (Settings → Resources, or `XEZ_FOLLOWUPS=1`) and an agent's leftover follow-ups become the
101
101
  next tasks too — one click each.
102
102
  - 🤖 **"Autonomous" means you still have to sit there.** Flip the **Autonomous**
103
103
  flag and a run never parks to ask — it keeps going until the task is done. Pair
@@ -269,18 +269,22 @@ Five moves that make the cockpit worth the browser tab:
269
269
  everything still `queued` is re-enqueued in order. It's the orchestration layer
270
270
  that turns "one agent at a time" into a backlog that drains itself.
271
271
  - 🧠 **Memory-aware runs.** Each run's whole process tree is sampled (~2 s) for CPU
272
- and RSS, and its **peak memory** is recorded and shown in the task table. Set an
273
- optional per-task **memory ceiling** (`memoryLimitMb`) and a run that crosses it
274
- is *paused* freeing its tree so the queue keeps advancing and resumes on
275
- demand. Event logs are append-only NDJSON and streamed rather than re-serialized,
272
+ and RSS, and its **peak memory** is recorded and shown in the task table. The
273
+ per-task **memory ceiling** (`memoryLimitMb`) is **on out of the box**: with no
274
+ setting at all xezar derives a host-sized ceiling from your machine's RAM, and a
275
+ run that crosses it is *paused* freeing its tree so the queue keeps advancing —
276
+ and resumes on demand. Adjust it in **Settings → Resources**; an explicit
277
+ `"memoryLimitMb": null` still means *no limit*, and a repo that sets its own value
278
+ overrides the workspace ceiling for its own runs. Event logs are append-only NDJSON and streamed rather than re-serialized,
276
279
  and live UI deltas are coalesced so they never hit disk.
277
280
  - 🪞 **Parallel variants (×2 / ×3).** Run the same task as competing agents in
278
281
  separate worktrees, then compare their diffs side by side and **pick** one —
279
282
  the losers are archived and their worktrees cleaned up.
280
283
  - 🧹 **Bounded worktree disk.** By default each git task runs in its own full checkout, so a busy
281
284
  cockpit would otherwise grow without limit. xezar keeps only the last
282
- `worktreeRetention` **finished** worktrees on disk (default **10**; `0` =
283
- unlimited) and reclaims the rest directory only, the `xez/<id8>` branch is
285
+ `worktreeRetention` **finished** worktrees on disk (default **10**, itself a
286
+ workspace setting`resources.worktreeRetentionDefault`, which every project
287
+ without its own value inherits; `0` = unlimited) and reclaims the rest — directory only, the `xez/<id8>` branch is
284
288
  always kept, so the work stays recoverable. Settings → Resources shows every
285
289
  worktree's disk use with per-row delete and a **Reclaim now** button.
286
290
  - 🛡️ **Review gate (optional, off by default).** Turn it on in Settings → Agents
@@ -300,15 +304,16 @@ Five moves that make the cockpit worth the browser tab:
300
304
 
301
305
  ## Cockpit tour
302
306
 
303
- Eight views, one browser window, all live over Server-Sent Events (seven until you opt into the Inbox):
307
+ Nine views, one browser window, all live over Server-Sent Events (seven by default the Inbox and Automations are each opt-in):
304
308
 
305
309
  | View | What's in it |
306
310
  |---|---|
307
- | **Tasks** | Every task with its status, live event stream (agent text · tool calls · tool results · pasted/generated screenshots and file attachments), tokens and cost. Continue, cancel, open in terminal (`claude --resume`), review the diff, or push a draft PR. |
311
+ | **Tasks** | Every task with its status, the tool and model it ran on, live event stream (agent text · tool calls · tool results · pasted/generated screenshots and file attachments), tokens and cost. Continue, cancel, open in terminal (`claude --resume`), review the diff, or push a draft PR. |
308
312
  | **All tasks** | Every *registered project's* tasks in one table, filtered and grouped by tag, project, status or workflow — see [Grouping connected repositories](#grouping-connected-repositories-tags-and-the-all-tasks-page). Appears once a second project is registered. |
309
- | **Inbox** | **Opt-in** (`XEZ_FOLLOWUPS=1`; hidden by default). Follow-ups an agent left behind (`todos.json`) — one click turns a suggestion into the next task, pre-wired to its suggested skill. Off, agents are never asked to leave follow-ups; each task's own **Notes** handoff journal is unaffected. |
313
+ | **Inbox** | **Opt-in**, hidden by default. Turn it on in **Settings → Resources** (the stored choice wins and needs no restart) or start with `XEZ_FOLLOWUPS=1`. Follow-ups an agent left behind (`todos.json`) — one click turns a suggestion into the next task, pre-wired to its suggested skill. Off, agents are never asked to leave follow-ups; each task's own **Notes** handoff journal is unaffected. |
310
314
  | **Git** | Branch, working-tree status, diff vs HEAD, recent commits (click one for its inline patch + GitHub link), and the configurable base branch that worktrees fork from and PRs target. |
311
315
  | **GitHub** | Open issues and PRs of the repo's origin, read through your logged-in `gh`. Hand an issue straight to the agent — pick a workflow and skills, one click runs it. |
316
+ | **Automations** | **Opt-in** (`XEZ_AUTOMATIONS=1`; hidden by default). Scheduled GitHub watches: each automation polls on its own interval and launches a task when its bounded filter matches. Test a filter before enabling it, and read the per-check log. |
312
317
  | **Skills** | Local skills plus the team skills repo, with a rendered body + prompt preview. Refresh pulls the latest from the remote. |
313
318
  | **Workflows** | Build a chain by drag-ordering skills, save it as portable YAML, import/export, or delete. Built-ins always come back. |
314
319
  | **Settings** | Appearance (dark/light theme, accent, density), agent backends, notifications, and the skills catalog. |
@@ -325,7 +330,7 @@ a GitHub page.
325
330
  One `xezar serve` hosts **every repo you work in**, not just the one you started
326
331
  it in. Each repo xezar boots in registers itself in a per-user registry at
327
332
  `~/.xezar/config.json` — the workspace file that also holds the global knobs
328
- (the parallel cap, the memory ceiling, the browse root, and the checkout root). Nothing is added to
333
+ (the parallel cap, the memory ceiling, the idle timeout, the default worktree retention, the Inbox switch, the agent env passthrough list, the browse root, and the checkout root). Nothing is added to
329
334
  the repo: per-project state stays exactly where it was, in that repo's
330
335
  `.local/xezar/`.
331
336
 
@@ -463,6 +468,7 @@ steps:
463
468
  # model: opus # optional per-step model override
464
469
  # runner: codex # optional per-step backend: claude · codex · opencode · pi
465
470
  # allowedTools: [Read, Edit, Write, Grep, Glob, Bash]
471
+ # timeout: 90m # optional per-step wall clock: 45s · 90m · 2h · none
466
472
  - id: verify
467
473
  name: Verify
468
474
  command: "npm test" # a check step: exit 0 passes
@@ -475,6 +481,34 @@ steps:
475
481
  back, its failing output is appended to the retried agent's prompt so the next
476
482
  attempt can see what broke.
477
483
 
484
+ ### How long a step may run
485
+
486
+ Every agent step has a wall clock. Leave `timeout` out and nothing changes: the
487
+ workflow's **last** step stays open for your follow-ups with no cap, and every
488
+ **earlier** agent step is killed after **30 minutes** — which is fine for a
489
+ review or a docs pass, and too short for a long investigate-and-implement step.
490
+ `timeout` is how that step asks for more:
491
+
492
+ ```yaml
493
+ - id: investigate
494
+ prompt: "{{task}}"
495
+ timeout: 3h # this step only
496
+ ```
497
+
498
+ - `45s`, `90m`, `2h` — whole numbers with `s`, `m` or `h`. Nothing else parses:
499
+ `90 minutes`, `1.5h` and `30d` are load-time errors, and so is `0s` (say
500
+ `none` if you mean no cap). The ceiling is `596h`, where Node's own timer
501
+ stops being able to count.
502
+ - `none` — no wall clock at all. The step ends when the agent ends.
503
+ - The field belongs to an **agent** step. A check step is a shell command, and
504
+ putting `timeout` on one is a load-time error rather than a key that quietly
505
+ does nothing.
506
+
507
+ **All four backends honour it.** `claude`, `codex`, `opencode` and `pi` each arm
508
+ the deadline from the same per-step value; on `claude`, `codex` and `pi` a step
509
+ that overruns is interrupted and then `SIGKILL`ed after a short grace period,
510
+ while `opencode` interrupts and waits for the session to close.
511
+
478
512
  Prefer skills over steps? A workflow can also be written in the portable
479
513
  shorthand — an ordered list of skill names, each becoming one agent step:
480
514
 
@@ -507,7 +541,7 @@ Useful environment variables:
507
541
  | `XEZ_DRY_RUN=1` | Use the bundled mock instead of the real `claude` CLI — the entire cockpit works offline, for demos and development. |
508
542
  | `XEZ_AGENT_MODELS_LOCKED=1` | Globally lock each runner to the model configured in its native Claude/Codex/OpenCode settings while keeping runner selection available. Exact `1` also delegates authentication and provider enablement to those native agents, so Xezar skips its credential probes and provider-disable preferences. Existing Xezar presets are preserved but ignored, and an environment change requires a restart. The config-file equivalent is `"modelsLocked": true` in global `~/.xezar/config.json` or one repository's `.xezar/config.json`; config-file locks do not disable provider checks. |
509
543
  | `XEZ_APPROVAL_GATE=1` | Opt into Claude's interactive approval UI; by default, unapproved tools are denied without interrupting the run. |
510
- | `XEZ_FOLLOWUPS=1` | Turn on the global follow-up **Inbox**: agents are asked to leave follow-ups in `todos.json` when they finish, and the Inbox view appears. Off by default — each task's own **Notes** handoff journal runs either way. |
544
+ | `XEZ_FOLLOWUPS=1` | Turn on the global follow-up **Inbox**: agents are asked to leave follow-ups in `todos.json` when they finish, and the Inbox view appears. Off by default — each task's own **Notes** handoff journal runs either way. The Settings → Resources toggle overrides this default and needs no restart. |
511
545
  | `XEZ_AUTOMATIONS=1` | Turn on **GitHub automations**: the Automations view appears and xezar polls GitHub on each enabled automation's interval, launching tasks from what it finds. Off by default, and only the exact value `1` enables it — without it nothing polls GitHub, the automations endpoints answer `409`, and the nav item is absent. Read at boot, so restart after changing it; definitions, receipts and high-watermarks are retained, so unsetting it and restarting restores the feature without migration or data loss. |
512
546
  | `XEZ_AUTOSAVE=1` | Re-enable the periodic (90 s) autosave commit in task worktrees. Off by default (#471) — turn-end and pre-PR flushes always run, so branches still end complete. Every autosave names its trigger in the commit subject (`xezar autosave (periodic)` vs `(turn end)` / `(run finalize)` / `(pre-PR)`), so the flushes you keep are distinguishable from the timer you disabled. |
513
547
  | `XEZ_CLAUDE_BIN=/path/to/claude` | Override which `claude` binary is used. |
@@ -527,7 +561,7 @@ Useful environment variables:
527
561
  | `XEZ_HIDE_COST=1` | Hide backend-reported monetary cost throughout the browser cockpit while leaving raw input/output token counts visible. Only the exact value `1` enables it; telemetry and API payloads are unchanged, and a restart is required after changing it. |
528
562
  | `XEZ_HIDE_TOKEN_METRICS=1` | Legacy master switch that hides both token usage and cost. It takes precedence over the two independent flags; only the exact value `1` enables it, payloads are unchanged, and a restart is required. |
529
563
  | `GITHUB_TOKEN` | Fallback for GitHub reads/PRs when `gh` isn't authenticated. |
530
- | `XEZ_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` + `XEZ_*`), not your full environment — use this to add a var an agent needs. |
564
+ | `XEZ_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` + `XEZ_*`), not your full environment — use this to add a var an agent needs. The Settings → Resources control overrides this default and needs no restart. |
531
565
  | `XEZ_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. |
532
566
  | `XEZ_AGENT_TMPDIR=0` | Stop giving each task its own temp directory and hand agents the host `TMPDIR` again (pre-#785 behavior). On by default: every run gets `TMPDIR`/`TEMP`/`TMP` pointing at `.local/xezar/tmp/<task-id>`, created and write-probed before the agent spawns and reaped when the run ends, so concurrent tasks stop sharing one directory and a task refuses to start rather than run against a temp directory that silently swallows its shell output (see Troubleshooting below). Only an exact `0` disables it, and it disables the whole thing — the pre-spawn check included, so this stays an escape hatch you can actually take. |
533
567
  | `XEZ_REDACT_SECRETS=0` | Disable scrubbing of credential values/token shapes from the on-disk state (the NDJSON transcript and the free-text fields of `runs.json`). On by default; leave it on. Best-effort defense-in-depth, not a guarantee: it catches known token shapes and the values of your own secret-named env vars, so a credential in neither category can still get through. |
@@ -602,6 +636,27 @@ host-local catalog yet, always shows its built-in entries. `auto` — send no
602
636
  model at all and let the CLI decide — is always available, and a model you
603
637
  pinned by hand stays selectable even when it is no longer advertised.
604
638
 
639
+ **OpenCode connection checks include native model configuration.** A LAN/local
640
+ provider can be configured without stored login credentials. When
641
+ `opencode auth list` reports no stored or environment credentials, xezar also
642
+ runs `opencode models`:
643
+
644
+ - A successful listing with a recognized `provider/model` marks OpenCode as
645
+ configured. Connect recognizes that state without opening a login terminal.
646
+ The Providers card says **Configured**, rather than **Credentials found**.
647
+ - A successful empty listing leaves OpenCode **Not connected**. Connect opens
648
+ `opencode auth login` to configure credentials.
649
+ - A failed, unrecognized or timed-out listing reports **Could not verify**,
650
+ rather than assuming login is needed. Each CLI probe has a ten-second timeout.
651
+
652
+ If OpenCode works directly but xezar asks you to connect, compare
653
+ `opencode auth list` and `opencode models` from the same project directory and
654
+ environment used by xezar. Zero credentials alone does not mean a local provider
655
+ needs login. A model listing establishes configuration, not endpoint health or
656
+ successful inference; an authentication rejection from an actual task still
657
+ overrides the probe result and requires attention. Xezar does not add credentials
658
+ or change OpenCode's provider configuration during these checks.
659
+
605
660
  **Pick a backend at three levels** (most specific wins):
606
661
 
607
662
  1. **Config default** — `"defaultRunner": "codex"` in `.xezar/config.json`.
@@ -718,12 +773,24 @@ Run data (`runs.json`, NDJSON event logs, worktrees, `todos.json`) is
718
773
  git-ignored automatically; your workflows and skills stay committable.
719
774
 
720
775
  Settings that belong to *you* rather than to a repo — the parallel cap
721
- (`maxParallel`, default **2**), the per-task memory ceiling and the checkout
722
- root live once in `~/.xezar/config.json`, alongside the
776
+ (`maxParallel`, default **2**), the per-task memory ceiling, the **idle timeout**
777
+ (`idleTimeoutMinutes`, default **15**), the default worktree retention
778
+ (`worktreeRetentionDefault`), the Inbox switch and the agent env passthrough list,
779
+ and the checkout root — live once in `~/.xezar/config.json`, alongside the
723
780
  [project registry](#multiple-projects-one-cockpit), and are edited from
724
- **Settings → Resources** and **Settings → Projects**. A `maxParallel` left over
725
- in a repo's `.xezar/config.json` is imported into the workspace file the
726
- first time xezar boots there, and ignored afterwards.
781
+ **Settings → Resources** and **Settings → Projects**.
782
+
783
+ The idle timeout is how long a task parked at `waiting` keeps its agent session
784
+ alive with nobody talking to it. After it expires the session is closed. Set it to
785
+ **Never** if you run long interactive sessions and would rather keep them — a
786
+ waiting task holds no parallel-task slot, so your queue keeps moving either way,
787
+ but its agent process stays alive and keeps using memory until you send it a
788
+ message or cancel it.
789
+
790
+ A `maxParallel` left over in a repo's `.xezar/config.json` is imported into the
791
+ workspace file the first time xezar boots there, and ignored afterwards. A per-repo
792
+ `memoryLimitMb` behaves differently on purpose: it is still honoured, and overrides
793
+ the workspace ceiling for runs in that repo.
727
794
 
728
795
  ### Editing the agents' own config (Settings → Agent config)
729
796
 
@@ -819,6 +886,11 @@ npm run test:package # pack/install and exercise the built CLI
819
886
  npm run test:e2e # real-browser cockpit suite (agent-browser)
820
887
  ```
821
888
 
889
+ Coverage is measured separately, and is not part of the validation gate:
890
+ `npm run test:coverage` runs the vitest suites under the v8 provider and writes line and branch
891
+ numbers to `.local/coverage/`. The behaviour-led gap analysis built from it lives in
892
+ [docs/testing/coverage-gaps.md](docs/testing/coverage-gaps.md).
893
+
822
894
  The stack is deliberately small: **TypeScript** (strict, ESM), **Hono** + SSE for
823
895
  the server, **Zod** at every boundary, **YAML** for workflows, and a **React 19 +
824
896
  Vite + Tailwind v4 + shadcn/ui** cockpit shipped pre-built in `packages/xezar/web/dist/` — the
@@ -28,6 +28,16 @@ export interface AgentHomePaths {
28
28
  codex: string;
29
29
  /** `$XDG_CONFIG_HOME/opencode` or `~/.config/opencode` */
30
30
  opencodeConfig: string;
31
+ /**
32
+ * `~/.pi/agent` — pi's whole per-user directory (`models.json`, `settings.json`, and the
33
+ * `auth.json` xezar never reads). No vendor variable relocates it (verified against pi 0.85.1,
34
+ * 2026-09-10), which is why this slot carries no `env.` alternative the way the three above do.
35
+ *
36
+ * `CONFIG_FILES` lists no pi entry yet, so nothing in the raw config editor resolves through
37
+ * this slot today; model discovery (#152) does, and it lives here so pi's home is derived in
38
+ * the one place every other agent's is.
39
+ */
40
+ pi: string;
31
41
  }
32
42
  export interface ConfigFileDef {
33
43
  /** Stable, opaque, URL-safe. The ONLY thing a client may name (traversal-proof). */
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/agent-config/catalog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/agent-config/catalog.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import { projectDataDir } from '../project-data-paths.js';
2
2
  import { existsSync } from 'node:fs';
3
3
  import { join } from 'node:path';
4
4
  import { AutomationStore } from './store.js';
5
+ import { ownProjectData } from '../runs/project-writer.js';
5
6
  /**
6
7
  * Lightweight workspace index for project automation state. Discovery checks
7
8
  * only the optional definitions file and never materializes a RunManager or a
@@ -46,6 +47,13 @@ export class AutomationCoordinator {
46
47
  const projectRoot = root ?? this.roots.get(projectId);
47
48
  if (!projectRoot)
48
49
  return undefined;
50
+ try {
51
+ ownProjectData(projectDataDir(projectRoot));
52
+ }
53
+ catch (error) {
54
+ this.options.warn?.(`Automation project is unavailable: ${error instanceof Error ? error.message : String(error)}`);
55
+ return undefined;
56
+ }
49
57
  const store = AutomationStore.open(projectDataDir(projectRoot), { warn: this.options.warn });
50
58
  this.stores.set(projectId, store);
51
59
  this.roots.set(projectId, projectRoot);
@@ -1 +1 @@
1
- {"version":3,"file":"coordinator.js","sourceRoot":"","sources":["../../src/automations/coordinator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"coordinator.js","sourceRoot":"","sources":["../../src/automations/coordinator.ts"],"names":[],"mappings":"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"}
@@ -32,6 +32,7 @@ export declare const automationTaskSchema: z.ZodObject<{
32
32
  }>>;
33
33
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
34
34
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
35
+ timeout: z.ZodOptional<z.ZodString>;
35
36
  command: z.ZodOptional<z.ZodString>;
36
37
  onFail: z.ZodOptional<z.ZodObject<{
37
38
  retry: z.ZodString;
@@ -91,6 +92,7 @@ export declare const automationDefinitionSchema: z.ZodObject<{
91
92
  }>>;
92
93
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
93
94
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
95
+ timeout: z.ZodOptional<z.ZodString>;
94
96
  command: z.ZodOptional<z.ZodString>;
95
97
  onFail: z.ZodOptional<z.ZodObject<{
96
98
  retry: z.ZodString;
@@ -73,6 +73,7 @@ export declare const automationTaskSchema: z.ZodObject<{
73
73
  }>>;
74
74
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
75
75
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
76
+ timeout: z.ZodOptional<z.ZodString>;
76
77
  command: z.ZodOptional<z.ZodString>;
77
78
  onFail: z.ZodOptional<z.ZodObject<{
78
79
  retry: z.ZodString;
@@ -135,6 +136,7 @@ export declare const automationDefinitionSchema: z.ZodObject<{
135
136
  }>>;
136
137
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
137
138
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
139
+ timeout: z.ZodOptional<z.ZodString>;
138
140
  command: z.ZodOptional<z.ZodString>;
139
141
  onFail: z.ZodOptional<z.ZodObject<{
140
142
  retry: z.ZodString;
@@ -290,6 +292,7 @@ export declare const automationListEntrySchema: z.ZodObject<{
290
292
  }>>;
291
293
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
292
294
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
295
+ timeout: z.ZodOptional<z.ZodString>;
293
296
  command: z.ZodOptional<z.ZodString>;
294
297
  onFail: z.ZodOptional<z.ZodObject<{
295
298
  retry: z.ZodString;
@@ -435,6 +438,7 @@ export declare const automationsResponseSchema: z.ZodObject<{
435
438
  }>>;
436
439
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
437
440
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
441
+ timeout: z.ZodOptional<z.ZodString>;
438
442
  command: z.ZodOptional<z.ZodString>;
439
443
  onFail: z.ZodOptional<z.ZodObject<{
440
444
  retry: z.ZodString;
@@ -565,6 +569,7 @@ export declare const automationResponseSchema: z.ZodObject<{
565
569
  }>>;
566
570
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
567
571
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
572
+ timeout: z.ZodOptional<z.ZodString>;
568
573
  command: z.ZodOptional<z.ZodString>;
569
574
  onFail: z.ZodOptional<z.ZodObject<{
570
575
  retry: z.ZodString;
@@ -632,6 +637,7 @@ export declare const automationDetailResponseSchema: z.ZodObject<{
632
637
  }>>;
633
638
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
634
639
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
640
+ timeout: z.ZodOptional<z.ZodString>;
635
641
  command: z.ZodOptional<z.ZodString>;
636
642
  onFail: z.ZodOptional<z.ZodObject<{
637
643
  retry: z.ZodString;
@@ -835,6 +841,7 @@ export declare const createAutomationInputSchema: z.ZodObject<{
835
841
  }>>;
836
842
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
837
843
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
844
+ timeout: z.ZodOptional<z.ZodString>;
838
845
  command: z.ZodOptional<z.ZodString>;
839
846
  onFail: z.ZodOptional<z.ZodObject<{
840
847
  retry: z.ZodString;
@@ -900,6 +907,7 @@ export declare const updateAutomationInputSchema: z.ZodObject<{
900
907
  }>>;
901
908
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
902
909
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
910
+ timeout: z.ZodOptional<z.ZodString>;
903
911
  command: z.ZodOptional<z.ZodString>;
904
912
  onFail: z.ZodOptional<z.ZodObject<{
905
913
  retry: z.ZodString;
@@ -0,0 +1 @@
1
+ export {};
@@ -357,6 +357,12 @@ var workflowStepDefSchema = z4.object({
357
357
  runner: runnerSchema.optional(),
358
358
  allowedTools: z4.array(z4.string()).optional(),
359
359
  bashAllowlist: z4.array(z4.string()).optional(),
360
+ /** This step's own wall-clock cap (#22): `45s` / `90m` / `2h`, or `none` for no cap.
361
+ * Typed as a plain string here, exactly as `model` is: the DURATION FORMAT is validated
362
+ * by `src/workflows/types.ts`'s `stepTimeoutSchema`, which is the single source of truth
363
+ * for what a user may author (workflow YAML and the inline chain on `POST /runs` both go
364
+ * through it). Restating the grammar here would be a second copy free to drift. */
365
+ timeout: z4.string().optional(),
360
366
  // check step
361
367
  command: z4.string().optional(),
362
368
  onFail: z4.object({
@@ -660,6 +666,43 @@ var runIndexEntrySchema = z5.object({
660
666
  * refinement `workflowLabel` applies needs `steps[]`, which this row deliberately omits, so
661
667
  * a `(planned)` chain reads as itself here rather than as its first agent's name. */
662
668
  workflow: z5.string(),
669
+ /**
670
+ * The backend this run ran as — RESOLVED server-side, in order of how good the evidence is.
671
+ *
672
+ * 1. `RunRecord.runner`. NOT "what the caller asked for": `execute` writes the resolved backend
673
+ * onto the record the moment a run starts, so for anything that ever ran this is a fact.
674
+ * 2. Otherwise the last step that recorded a backend — steps stamp theirs at spawn, so a record
675
+ * written before run-level backend affinity still says what it used.
676
+ * 3. Otherwise the project's current `defaultRunner`, and only then is `runnerInherited` set.
677
+ *
678
+ * Resolved HERE rather than in the browser because these rows span every registered project:
679
+ * finishing step 3 client-side would be one config request per project. A project-scoped surface
680
+ * does it itself, from the one `GET /config` it already holds.
681
+ */
682
+ runner: runnerSchema,
683
+ /**
684
+ * Present ONLY when true: the run carried no runner and no step backend, so `runner` above is
685
+ * the project's current default.
686
+ *
687
+ * That is the one case that is not history. A run with no evidence at all has not started, so
688
+ * the value is what the task WOULD run as — which is why the cockpit renders it muted. Absent
689
+ * means the row is reporting what actually ran.
690
+ */
691
+ runnerInherited: z5.boolean().optional(),
692
+ /** The model string the run recorded, VERBATIM (`RunRecord.model`). Absent means none was
693
+ * recorded and the backend picked, which the cockpit prints as a muted `auto` — the same word
694
+ * the task detail header uses. Never prettified through a catalog: a locally-hosted backend's
695
+ * own id is the only honest answer. */
696
+ model: z5.string().optional(),
697
+ /**
698
+ * How many DISTINCT backends this run's recorded steps used — a workflow may name one per step.
699
+ *
700
+ * A COUNT, deliberately, and present only when it is greater than 1. This row exists to be
701
+ * slim; `steps[]` is exactly the half it refuses to carry, so the mixed-chain signal is derived
702
+ * server-side and reduced to the one number the cell renders (`Claude Code +1`). Absent means
703
+ * one backend or none — which is every ordinary run.
704
+ */
705
+ stepBackends: z5.number().int().min(2).optional(),
663
706
  /** The task's branch, when it has one — a column on the global page, and the one field that
664
707
  * makes a cross-project row identifiable at a glance without opening it. */
665
708
  branch: z5.string().optional(),
@@ -1081,6 +1124,15 @@ var workspaceConfigResponseSchema = z8.object({
1081
1124
  /** Stored override; `null` means inherit `XEZ_SKILLS_AUTO_UPDATE`, then true. */
1082
1125
  skillsAutoUpdate: z8.boolean().nullable(),
1083
1126
  effectiveSkillsAutoUpdate: z8.boolean(),
1127
+ /** Stored follow-up Inbox override (F); `null` = no stored key, `XEZ_FOLLOWUPS` decides. */
1128
+ followups: z8.boolean().nullable(),
1129
+ /** What `followups` + the env actually resolve to right now — what the cockpit shows. */
1130
+ effectiveFollowups: z8.boolean(),
1131
+ /** Stored extra agent env-passthrough names (F); `null` = no stored key,
1132
+ * `XEZ_ENV_PASSTHROUGH` decides. `[]` is a real stored "forward nothing". */
1133
+ agentEnvPassthrough: z8.array(z8.string()).nullable(),
1134
+ /** What `agentEnvPassthrough` + the env actually resolve to right now. */
1135
+ effectiveAgentEnvPassthrough: z8.array(z8.string()),
1084
1136
  composerDefaults: z8.object({
1085
1137
  autonomous: z8.boolean().nullable(),
1086
1138
  worktree: z8.boolean().nullable(),
@@ -1094,7 +1146,13 @@ var workspaceConfigResponseSchema = z8.object({
1094
1146
  monitoringWakeIntervalMinutes: z8.number().nullable(),
1095
1147
  /** Resume a run a provider usage limit stopped, once the limit resets. Default `true`. */
1096
1148
  autoResumeOnUsageLimit: z8.boolean(),
1149
+ /** Wall clock for a session parked at `waiting`, in minutes; `null` = never close on
1150
+ * idle. Default 15. */
1151
+ idleTimeoutMinutes: z8.number().nullable(),
1097
1152
  memoryLimitMb: z8.number().nullable(),
1153
+ /** The host-derived ceiling an ABSENT `memoryLimitMb` falls back to (B1) — reported so
1154
+ * the settings pane can name the machine's own default instead of guessing it. */
1155
+ memoryLimitDefaultMb: z8.number(),
1098
1156
  worktreeRetentionDefault: z8.number()
1099
1157
  }),
1100
1158
  /**
@@ -1119,6 +1177,11 @@ var setWorkspaceConfigInputSchema = z8.object({
1119
1177
  browseRoot: z8.string().trim().min(1).max(4096).optional(),
1120
1178
  projectsDir: z8.string().trim().min(1).max(4096).optional(),
1121
1179
  skillsAutoUpdate: z8.boolean().nullable().optional(),
1180
+ /** Stored Inbox override (F): `null` clears the key back to the `XEZ_FOLLOWUPS` default. */
1181
+ followups: z8.boolean().nullable().optional(),
1182
+ /** Stored env-passthrough names (F): `null` clears the key back to the
1183
+ * `XEZ_ENV_PASSTHROUGH` default; `[]` stores a real "forward nothing". */
1184
+ agentEnvPassthrough: z8.array(z8.string().trim().min(1).max(200)).max(64).nullable().optional(),
1122
1185
  composerDefaults: z8.object({
1123
1186
  autonomous: z8.boolean().nullable().optional(),
1124
1187
  worktree: z8.boolean().nullable().optional()
@@ -1139,6 +1202,8 @@ var setWorkspaceConfigInputSchema = z8.object({
1139
1202
  maxMonitoringSessions: z8.number().int().min(0).max(16).optional(),
1140
1203
  monitoringWakeIntervalMinutes: z8.number().int().min(1).max(60).nullable().optional(),
1141
1204
  autoResumeOnUsageLimit: z8.boolean().optional(),
1205
+ /** `null` = never close an idle session; a number is minutes (1 to 1440). */
1206
+ idleTimeoutMinutes: z8.number().int().min(1).max(1440).nullable().optional(),
1142
1207
  memoryLimitMb: z8.number().int().min(0).max(1048576).nullable().optional(),
1143
1208
  worktreeRetentionDefault: z8.number().int().min(0).max(1e3).optional()
1144
1209
  }).optional()
@@ -1282,7 +1347,15 @@ var configResponseSchema = z8.object({
1282
1347
  liveTitleUpdates: z8.boolean().nullable(),
1283
1348
  /** Optional review gate (#489): null = no config key, the `XEZ_REVIEW_GATE` env default (OFF)
1284
1349
  * decides. */
1285
- reviewGate: z8.boolean().nullable()
1350
+ reviewGate: z8.boolean().nullable(),
1351
+ /** Model the chain planner runs on (Claude aliases only; other backends pick their own).
1352
+ * Always materialized — the file schema defaults it to `sonnet` (E). */
1353
+ plannerModel: z8.string(),
1354
+ /** Model the task namer runs on, same rule as `plannerModel`. Defaults to `haiku` (E). */
1355
+ namerModel: z8.string(),
1356
+ /** Team skill sources (E). Always materialized: the file schema defaults it to the shared
1357
+ * catalog, and `[]` is a real "no team skills" choice. */
1358
+ skillsRepos: z8.array(z8.object({ repo: z8.string(), ref: z8.string() }))
1286
1359
  });
1287
1360
  var setConfigResponseSchema = configResponseSchema;
1288
1361
  var setConfigInputSchema = z8.object({
@@ -1303,7 +1376,18 @@ var setConfigInputSchema = z8.object({
1303
1376
  /** null clears the key back to the env-default behavior. */
1304
1377
  liveTitleUpdates: z8.boolean().nullable().optional(),
1305
1378
  /** null clears the key back to the env-default behavior (OFF). */
1306
- reviewGate: z8.boolean().nullable().optional()
1379
+ reviewGate: z8.boolean().nullable().optional(),
1380
+ /** `null` clears the key back to the schema default (`sonnet`). */
1381
+ plannerModel: z8.string().trim().min(1).max(200).nullable().optional(),
1382
+ /** `null` clears the key back to the schema default (`haiku`). */
1383
+ namerModel: z8.string().trim().min(1).max(200).nullable().optional(),
1384
+ /** `null` clears the key back to the default catalog; `[]` disables team skills. */
1385
+ skillsRepos: z8.array(
1386
+ z8.object({
1387
+ repo: z8.string().trim().min(1).max(500),
1388
+ ref: z8.string().trim().min(1).max(200).optional()
1389
+ })
1390
+ ).max(32).nullable().optional()
1307
1391
  });
1308
1392
  var skillsUpdateStatusSchema = z8.enum([
1309
1393
  "idle",
@@ -1359,7 +1443,7 @@ var providerConnectResponseSchema = z8.discriminatedUnion("opened", [
1359
1443
  z8.object({ opened: z8.literal(true), command: z8.string() }),
1360
1444
  z8.object({ opened: z8.literal(false), connected: z8.literal(true), command: z8.string() })
1361
1445
  ]);
1362
- var modelDiscoveryRunnerSchema = z8.enum(["claude", "codex", "opencode"]);
1446
+ var modelDiscoveryRunnerSchema = z8.enum(["claude", "codex", "opencode", "pi"]);
1363
1447
  var MODEL_DISCOVERY_RUNNERS = modelDiscoveryRunnerSchema.options;
1364
1448
  function runnerDiscoversModels(runner) {
1365
1449
  return MODEL_DISCOVERY_RUNNERS.includes(runner);
@@ -268,6 +268,7 @@ export declare const runRecordSchema: z.ZodObject<{
268
268
  }>>;
269
269
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
270
270
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
271
+ timeout: z.ZodOptional<z.ZodString>;
271
272
  command: z.ZodOptional<z.ZodString>;
272
273
  onFail: z.ZodOptional<z.ZodObject<{
273
274
  retry: z.ZodString;
@@ -437,6 +438,7 @@ export declare const apiRunSchema: z.ZodObject<{
437
438
  }>>;
438
439
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
439
440
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
441
+ timeout: z.ZodOptional<z.ZodString>;
440
442
  command: z.ZodOptional<z.ZodString>;
441
443
  onFail: z.ZodOptional<z.ZodObject<{
442
444
  retry: z.ZodString;
@@ -501,6 +503,15 @@ export declare const runIndexEntrySchema: z.ZodObject<{
501
503
  archived: z.ZodBoolean;
502
504
  autoResumeAt: z.ZodOptional<z.ZodString>;
503
505
  workflow: z.ZodString;
506
+ runner: z.ZodEnum<{
507
+ claude: "claude";
508
+ codex: "codex";
509
+ opencode: "opencode";
510
+ pi: "pi";
511
+ }>;
512
+ runnerInherited: z.ZodOptional<z.ZodBoolean>;
513
+ model: z.ZodOptional<z.ZodString>;
514
+ stepBackends: z.ZodOptional<z.ZodNumber>;
504
515
  branch: z.ZodOptional<z.ZodString>;
505
516
  startedAt: z.ZodOptional<z.ZodString>;
506
517
  pullRequestUrl: z.ZodOptional<z.ZodString>;
@@ -596,6 +607,15 @@ export declare const runsIndexResponseSchema: z.ZodObject<{
596
607
  archived: z.ZodBoolean;
597
608
  autoResumeAt: z.ZodOptional<z.ZodString>;
598
609
  workflow: z.ZodString;
610
+ runner: z.ZodEnum<{
611
+ claude: "claude";
612
+ codex: "codex";
613
+ opencode: "opencode";
614
+ pi: "pi";
615
+ }>;
616
+ runnerInherited: z.ZodOptional<z.ZodBoolean>;
617
+ model: z.ZodOptional<z.ZodString>;
618
+ stepBackends: z.ZodOptional<z.ZodNumber>;
599
619
  branch: z.ZodOptional<z.ZodString>;
600
620
  startedAt: z.ZodOptional<z.ZodString>;
601
621
  pullRequestUrl: z.ZodOptional<z.ZodString>;
@@ -804,6 +824,7 @@ export declare const createRunResponseSchema: z.ZodUnion<readonly [z.ZodObject<{
804
824
  }>>;
805
825
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
806
826
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
827
+ timeout: z.ZodOptional<z.ZodString>;
807
828
  command: z.ZodOptional<z.ZodString>;
808
829
  onFail: z.ZodOptional<z.ZodObject<{
809
830
  retry: z.ZodString;
@@ -967,6 +988,7 @@ export declare const createRunResponseSchema: z.ZodUnion<readonly [z.ZodObject<{
967
988
  }>>;
968
989
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
969
990
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
991
+ timeout: z.ZodOptional<z.ZodString>;
970
992
  command: z.ZodOptional<z.ZodString>;
971
993
  onFail: z.ZodOptional<z.ZodObject<{
972
994
  retry: z.ZodString;
@@ -1337,6 +1359,7 @@ export declare const pickVariantResponseSchema: z.ZodObject<{
1337
1359
  }>>;
1338
1360
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
1339
1361
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
1362
+ timeout: z.ZodOptional<z.ZodString>;
1340
1363
  command: z.ZodOptional<z.ZodString>;
1341
1364
  onFail: z.ZodOptional<z.ZodObject<{
1342
1365
  retry: z.ZodString;
@@ -1426,6 +1449,7 @@ export declare const createRunInputBaseSchema: z.ZodObject<{
1426
1449
  }>>;
1427
1450
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
1428
1451
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
1452
+ timeout: z.ZodOptional<z.ZodString>;
1429
1453
  command: z.ZodOptional<z.ZodString>;
1430
1454
  onFail: z.ZodOptional<z.ZodObject<{
1431
1455
  retry: z.ZodString;
@@ -1474,6 +1498,7 @@ export declare const createRunInputSchema: z.ZodObject<{
1474
1498
  }>>;
1475
1499
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
1476
1500
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
1501
+ timeout: z.ZodOptional<z.ZodString>;
1477
1502
  command: z.ZodOptional<z.ZodString>;
1478
1503
  onFail: z.ZodOptional<z.ZodObject<{
1479
1504
  retry: z.ZodString;
@@ -0,0 +1 @@
1
+ export {};
@@ -217,6 +217,7 @@ export declare const startTodoResponseSchema: z.ZodObject<{
217
217
  }>>;
218
218
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
219
219
  bashAllowlist: z.ZodOptional<z.ZodArray<z.ZodString>>;
220
+ timeout: z.ZodOptional<z.ZodString>;
220
221
  command: z.ZodOptional<z.ZodString>;
221
222
  onFail: z.ZodOptional<z.ZodObject<{
222
223
  retry: z.ZodString;