@open-mercato/cezar 0.9.2 → 0.10.0-pr892.1298

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 (269) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +169 -38
  3. package/dist/agent-config/account-identity.d.ts +44 -0
  4. package/dist/agent-config/account-identity.js +128 -0
  5. package/dist/agent-config/account-identity.js.map +1 -0
  6. package/dist/agent-config/catalog.d.ts +8 -0
  7. package/dist/agent-config/catalog.js +18 -0
  8. package/dist/agent-config/catalog.js.map +1 -1
  9. package/dist/agent-config/model-settings/claude.d.ts +2 -0
  10. package/dist/agent-config/model-settings/claude.js +11 -0
  11. package/dist/agent-config/model-settings/claude.js.map +1 -0
  12. package/dist/agent-config/model-settings/codex.d.ts +2 -0
  13. package/dist/agent-config/model-settings/codex.js +16 -0
  14. package/dist/agent-config/model-settings/codex.js.map +1 -0
  15. package/dist/agent-config/model-settings/opencode.d.ts +2 -0
  16. package/dist/agent-config/model-settings/opencode.js +8 -0
  17. package/dist/agent-config/model-settings/opencode.js.map +1 -0
  18. package/dist/agent-config/model-settings/pi.d.ts +12 -0
  19. package/dist/agent-config/model-settings/pi.js +18 -0
  20. package/dist/agent-config/model-settings/pi.js.map +1 -0
  21. package/dist/agent-config/model-settings/shared.d.ts +9 -0
  22. package/dist/agent-config/model-settings/shared.js +93 -0
  23. package/dist/agent-config/model-settings/shared.js.map +1 -0
  24. package/dist/agent-config/model-settings/types.d.ts +9 -0
  25. package/dist/agent-config/model-settings/types.js +2 -0
  26. package/dist/agent-config/model-settings/types.js.map +1 -0
  27. package/dist/agent-config/models.d.ts +9 -0
  28. package/dist/agent-config/models.js +32 -0
  29. package/dist/agent-config/models.js.map +1 -0
  30. package/dist/agent-config/service.js +4 -4
  31. package/dist/agent-config/service.js.map +1 -1
  32. package/dist/automations/types.d.ts +4 -0
  33. package/dist/automations/types.js +2 -1
  34. package/dist/automations/types.js.map +1 -1
  35. package/dist/config.d.ts +10 -1
  36. package/dist/config.js +48 -5
  37. package/dist/config.js.map +1 -1
  38. package/dist/contract/agent-config.d.ts +2 -0
  39. package/dist/contract/agent-profiles.d.ts +347 -0
  40. package/dist/contract/automations.d.ts +24 -0
  41. package/dist/contract/events.d.ts +59 -0
  42. package/dist/contract/github.d.ts +88 -0
  43. package/dist/contract/health.d.ts +7 -1
  44. package/dist/contract/index.d.ts +1 -0
  45. package/dist/contract/index.js +1005 -555
  46. package/dist/contract/projects.d.ts +33 -5
  47. package/dist/contract/runs.d.ts +247 -0
  48. package/dist/contract/skills.d.ts +7 -0
  49. package/dist/contract/workflows.d.ts +6 -0
  50. package/dist/contract/workspace.d.ts +137 -2
  51. package/dist/core/agent-env.js +41 -16
  52. package/dist/core/agent-env.js.map +1 -1
  53. package/dist/core/agent-model-policy.d.ts +10 -0
  54. package/dist/core/agent-model-policy.js +36 -0
  55. package/dist/core/agent-model-policy.js.map +1 -0
  56. package/dist/core/agent-profiles.d.ts +62 -0
  57. package/dist/core/agent-profiles.js +90 -0
  58. package/dist/core/agent-profiles.js.map +1 -0
  59. package/dist/core/agent-runner.d.ts +37 -6
  60. package/dist/core/agent-runner.js +35 -3
  61. package/dist/core/agent-runner.js.map +1 -1
  62. package/dist/core/backend-detect.d.ts +5 -5
  63. package/dist/core/backend-detect.js +44 -7
  64. package/dist/core/backend-detect.js.map +1 -1
  65. package/dist/core/claude-cli-runner.js +10 -5
  66. package/dist/core/claude-cli-runner.js.map +1 -1
  67. package/dist/core/codex-app-server-runner.js +13 -3
  68. package/dist/core/codex-app-server-runner.js.map +1 -1
  69. package/dist/core/codex-app-server-transport.js +7 -2
  70. package/dist/core/codex-app-server-transport.js.map +1 -1
  71. package/dist/core/model-identity.d.ts +23 -11
  72. package/dist/core/model-identity.js +41 -24
  73. package/dist/core/model-identity.js.map +1 -1
  74. package/dist/core/model-presets.d.ts +8 -2
  75. package/dist/core/model-presets.js +51 -8
  76. package/dist/core/model-presets.js.map +1 -1
  77. package/dist/core/opencode-model-catalog.d.ts +32 -0
  78. package/dist/core/opencode-model-catalog.js +153 -0
  79. package/dist/core/opencode-model-catalog.js.map +1 -0
  80. package/dist/core/opencode-server-runner.d.ts +2 -0
  81. package/dist/core/opencode-server-runner.js +42 -11
  82. package/dist/core/opencode-server-runner.js.map +1 -1
  83. package/dist/core/pi-runner.d.ts +24 -0
  84. package/dist/core/pi-runner.js +349 -0
  85. package/dist/core/pi-runner.js.map +1 -0
  86. package/dist/core/pi-ui-mapper.d.ts +34 -0
  87. package/dist/core/pi-ui-mapper.js +270 -0
  88. package/dist/core/pi-ui-mapper.js.map +1 -0
  89. package/dist/core/provider-auth.d.ts +95 -3
  90. package/dist/core/provider-auth.js +234 -15
  91. package/dist/core/provider-auth.js.map +1 -1
  92. package/dist/core/provider-availability.d.ts +1 -1
  93. package/dist/core/provider-availability.js +2 -1
  94. package/dist/core/provider-availability.js.map +1 -1
  95. package/dist/core/runner-factory.js +3 -0
  96. package/dist/core/runner-factory.js.map +1 -1
  97. package/dist/core/shell-env.d.ts +28 -0
  98. package/dist/core/shell-env.js +56 -0
  99. package/dist/core/shell-env.js.map +1 -0
  100. package/dist/core/ui-events.d.ts +1 -1
  101. package/dist/core/usage-limit.d.ts +42 -0
  102. package/dist/core/usage-limit.js +209 -0
  103. package/dist/core/usage-limit.js.map +1 -0
  104. package/dist/git-diff-base.d.ts +51 -26
  105. package/dist/git-diff-base.js +163 -37
  106. package/dist/git-diff-base.js.map +1 -1
  107. package/dist/git-worktree.d.ts +15 -6
  108. package/dist/git-worktree.js +10 -3
  109. package/dist/git-worktree.js.map +1 -1
  110. package/dist/index.js +3 -2
  111. package/dist/index.js.map +1 -1
  112. package/dist/paths.d.ts +53 -5
  113. package/dist/paths.js +63 -9
  114. package/dist/paths.js.map +1 -1
  115. package/dist/planner.js +6 -0
  116. package/dist/planner.js.map +1 -1
  117. package/dist/release/snapshot.d.ts +13 -2
  118. package/dist/release/snapshot.js +25 -1
  119. package/dist/release/snapshot.js.map +1 -1
  120. package/dist/runs/agent-tmpdir.d.ts +41 -0
  121. package/dist/runs/agent-tmpdir.js +183 -0
  122. package/dist/runs/agent-tmpdir.js.map +1 -0
  123. package/dist/runs/auto-name.js +6 -1
  124. package/dist/runs/auto-name.js.map +1 -1
  125. package/dist/runs/event-history.d.ts +50 -0
  126. package/dist/runs/event-history.js +613 -0
  127. package/dist/runs/event-history.js.map +1 -0
  128. package/dist/runs/run-index.d.ts +19 -0
  129. package/dist/runs/run-index.js +43 -0
  130. package/dist/runs/run-index.js.map +1 -0
  131. package/dist/runs/store.d.ts +78 -19
  132. package/dist/runs/store.js +175 -43
  133. package/dist/runs/store.js.map +1 -1
  134. package/dist/server/capabilities.d.ts +15 -1
  135. package/dist/server/capabilities.js +16 -1
  136. package/dist/server/capabilities.js.map +1 -1
  137. package/dist/server/forge/github.d.ts +169 -0
  138. package/dist/server/forge/github.js +511 -0
  139. package/dist/server/forge/github.js.map +1 -1
  140. package/dist/server/forge/index.d.ts +9 -0
  141. package/dist/server/forge/index.js +14 -0
  142. package/dist/server/forge/index.js.map +1 -1
  143. package/dist/server/git-changes.d.ts +7 -5
  144. package/dist/server/git-changes.js +15 -10
  145. package/dist/server/git-changes.js.map +1 -1
  146. package/dist/server/github.d.ts +2 -2
  147. package/dist/server/github.js +1 -1
  148. package/dist/server/github.js.map +1 -1
  149. package/dist/server/open-in-app.d.ts +2 -1
  150. package/dist/server/open-in-app.js +3 -1
  151. package/dist/server/open-in-app.js.map +1 -1
  152. package/dist/server/open-in-terminal.d.ts +46 -1
  153. package/dist/server/open-in-terminal.js +72 -13
  154. package/dist/server/open-in-terminal.js.map +1 -1
  155. package/dist/server/provider-action-gate.js +3 -1
  156. package/dist/server/provider-action-gate.js.map +1 -1
  157. package/dist/server/server.d.ts +2206 -434
  158. package/dist/server/server.js +1219 -136
  159. package/dist/server/server.js.map +1 -1
  160. package/dist/server-install/engine.js +5 -18
  161. package/dist/server-install/engine.js.map +1 -1
  162. package/dist/server-install/steps.js +6 -2
  163. package/dist/server-install/steps.js.map +1 -1
  164. package/dist/skills.js +4 -0
  165. package/dist/skills.js.map +1 -1
  166. package/dist/workflows/run.d.ts +229 -9
  167. package/dist/workflows/run.js +877 -147
  168. package/dist/workflows/run.js.map +1 -1
  169. package/dist/workflows/types.d.ts +3 -0
  170. package/dist/workflows/types.js +11 -2
  171. package/dist/workflows/types.js.map +1 -1
  172. package/dist/workspace/agent-accounts.d.ts +153 -0
  173. package/dist/workspace/agent-accounts.js +304 -0
  174. package/dist/workspace/agent-accounts.js.map +1 -0
  175. package/dist/workspace/agent-profiles.d.ts +78 -0
  176. package/dist/workspace/agent-profiles.js +115 -0
  177. package/dist/workspace/agent-profiles.js.map +1 -0
  178. package/dist/workspace/config.d.ts +27 -1
  179. package/dist/workspace/config.js +83 -2
  180. package/dist/workspace/config.js.map +1 -1
  181. package/dist/workspace/projects-cli.js +54 -4
  182. package/dist/workspace/projects-cli.js.map +1 -1
  183. package/dist/workspace/projects.d.ts +19 -1
  184. package/dist/workspace/projects.js +34 -1
  185. package/dist/workspace/projects.js.map +1 -1
  186. package/dist/workspace/semaphore.d.ts +46 -1
  187. package/dist/workspace/semaphore.js +41 -4
  188. package/dist/workspace/semaphore.js.map +1 -1
  189. package/dist/workspace/ui-state.d.ts +3 -2
  190. package/dist/workspace/ui-state.js +3 -2
  191. package/dist/workspace/ui-state.js.map +1 -1
  192. package/package.json +3 -3
  193. package/scripts/mock-claude.mjs +20 -0
  194. package/scripts/mock-pi-rpc.mjs +83 -0
  195. package/web/dist/assets/{alert-dialog-ghffK6g9.js → alert-dialog-Byp42_IG.js} +1 -1
  196. package/web/dist/assets/arrow-down-CGDbDYKD.js +1 -0
  197. package/web/dist/assets/arrow-left-ESCjr1Hq.js +1 -0
  198. package/web/dist/assets/centered-state-LfAW-igm.js +43 -0
  199. package/web/dist/assets/chevron-right-Du-P1IUd.js +1 -0
  200. package/web/dist/assets/{collapsible-B0JVzd0B.js → collapsible-CBiiqDJM.js} +1 -1
  201. package/web/dist/assets/{commit-list-wm6DPHNs.js → commit-list-6PPve7PE.js} +1 -1
  202. package/web/dist/assets/{compare-variants-DbdP4Y5T.js → compare-variants-BDnp6mXJ.js} +1 -1
  203. package/web/dist/assets/{diff-Bizc96qe.js → diff-_jK0OWpF.js} +2 -2
  204. package/web/dist/assets/{diff-stat-Dyfg3ltF.js → diff-stat-CIrTu4Ym.js} +1 -1
  205. package/web/dist/assets/{diff-view-CG8ek6tC.js → diff-view-COA_5IyY.js} +1 -1
  206. package/web/dist/assets/dropdown-menu-BofYpFFw.js +1 -0
  207. package/web/dist/assets/editable-title-_J0zFDl-.js +1 -0
  208. package/web/dist/assets/{ellipsis-vertical-DpGTRqC2.js → ellipsis-vertical-BeMR-l62.js} +1 -1
  209. package/web/dist/assets/{file-DlUGpUlb.js → file-DY996Pee.js} +1 -1
  210. package/web/dist/assets/{folder-BAY6Vddy.js → folder-NO3Ec-TY.js} +1 -1
  211. package/web/dist/assets/git-toolbar-BqJeUWcD.js +1 -0
  212. package/web/dist/assets/github-C96HPV9E.js +1 -0
  213. package/web/dist/assets/{image-preview-BWGk5fPX.js → image-preview-D9cCDfKQ.js} +1 -1
  214. package/web/dist/assets/index-Bx-grqa9.css +2 -0
  215. package/web/dist/assets/index-DoVvGDfW.js +7 -0
  216. package/web/dist/assets/{markdown-BGBOGCA_.js → markdown-DDzk11zj.js} +1 -1
  217. package/web/dist/assets/new-task-form-BNLLgC6P.js +1 -0
  218. package/web/dist/assets/pill-CVM1EmV4.js +1 -0
  219. package/web/dist/assets/{project-router-Cx8NPoqn.js → project-router-LRCtP48W.js} +1 -1
  220. package/web/dist/assets/prompt-templates-DFOvYgtW.js +15 -0
  221. package/web/dist/assets/{refresh-cw-BoGdAykg.js → refresh-cw-D1ys6QY2.js} +1 -1
  222. package/web/dist/assets/repo-git-CzUnsgWY.js +1 -0
  223. package/web/dist/assets/{run-diff-EcOkf3ti.js → run-diff-BlnqwfSS.js} +2 -2
  224. package/web/dist/assets/run-header-Bn7cN0Z1.js +1 -0
  225. package/web/dist/assets/{search-x-X3EpVhgs.js → search-x-D6FSpxId.js} +1 -1
  226. package/web/dist/assets/{skill-empty-hint-CZLALx6l.js → skill-empty-hint-iwpCcqgI.js} +1 -1
  227. package/web/dist/assets/skills-CezbOaol.js +1 -0
  228. package/web/dist/assets/{sparkles-Dt4q7pbG.js → sparkles-MrQrgCI9.js} +1 -1
  229. package/web/dist/assets/{square-terminal-hwBL8XsC.js → square-terminal-TTH64lO7.js} +1 -1
  230. package/web/dist/assets/tab-link-FYksz037.js +1 -0
  231. package/web/dist/assets/task-changes-ClWlnzBL.js +1 -0
  232. package/web/dist/assets/{task-commits-BTTA5k5T.js → task-commits-Crbrl86b.js} +1 -1
  233. package/web/dist/assets/{task-files-Da8_4C9g.js → task-files-uSCWyD0-.js} +2 -2
  234. package/web/dist/assets/task-thread-DPmamBA1.js +9 -0
  235. package/web/dist/assets/{textarea-CUdokhkv.js → textarea-B9Ahj4E4.js} +1 -1
  236. package/web/dist/assets/thread-loading-BH_ypQoy.js +1 -0
  237. package/web/dist/assets/{trash-2-DhVIdWv8.js → trash-2-D8S3V3fu.js} +1 -1
  238. package/web/dist/assets/{triangle-alert-XYT0DGCI.js → triangle-alert-bB7p9n5E.js} +1 -1
  239. package/web/dist/assets/{upload-BKjN59-1.js → upload-Bd5oRLPV.js} +1 -1
  240. package/web/dist/assets/{use-desktop-Bf5LS_P4.js → use-desktop-BNvbRBeZ.js} +1 -1
  241. package/web/dist/assets/{use-submit-shortcut-CzVyoAMd.js → use-submit-shortcut-B-xhu4Bf.js} +1 -1
  242. package/web/dist/assets/utils-BhpbVMwN.js +64 -0
  243. package/web/dist/assets/{workflows-o2QU_pvU.js → workflows-RmfbM9Vy.js} +3 -3
  244. package/web/dist/assets/{zoomable-image-7WyUiaVD.js → zoomable-image-BCW6ZBV0.js} +1 -1
  245. package/web/dist/index.html +24 -23
  246. package/web/dist/assets/arrow-down-Cz8qb71e.js +0 -1
  247. package/web/dist/assets/arrow-left-wcYKQXI_.js +0 -1
  248. package/web/dist/assets/centered-state-ZtnFHA-n.js +0 -43
  249. package/web/dist/assets/chevron-right-G4caF2QV.js +0 -1
  250. package/web/dist/assets/circle-check--KvBxXWp.js +0 -1
  251. package/web/dist/assets/circle-x-C3EFZ3xf.js +0 -1
  252. package/web/dist/assets/dropdown-menu-C1Dlf35P.js +0 -1
  253. package/web/dist/assets/editable-title-5rC_QRBZ.js +0 -1
  254. package/web/dist/assets/git-pull-request-agOG0iGM.js +0 -1
  255. package/web/dist/assets/git-toolbar-DGiNMmtY.js +0 -1
  256. package/web/dist/assets/github-Vp7lxYGQ.js +0 -1
  257. package/web/dist/assets/index-DSxyJpuK.css +0 -2
  258. package/web/dist/assets/index-DiawI6RX.js +0 -6
  259. package/web/dist/assets/new-task-form-BpAw_Dks.js +0 -1
  260. package/web/dist/assets/pill-Dvs-P0xy.js +0 -1
  261. package/web/dist/assets/prompt-templates-CSBYBR1I.js +0 -15
  262. package/web/dist/assets/repo-git-PmX-BNMo.js +0 -1
  263. package/web/dist/assets/run-header-BGiv6_qX.js +0 -1
  264. package/web/dist/assets/skills-CC91ouGH.js +0 -1
  265. package/web/dist/assets/tab-link-DIlR5T07.js +0 -1
  266. package/web/dist/assets/task-changes-XkHDxzQA.js +0 -1
  267. package/web/dist/assets/task-thread-DoNXUsHr.js +0 -9
  268. package/web/dist/assets/thread-loading-B8q8ukXJ.js +0 -1
  269. package/web/dist/assets/utils-DsLuRXwV.js +0 -64
@@ -6,6 +6,37 @@ var runEventSchema = z.looseObject({
6
6
  stepId: z.string().optional(),
7
7
  type: z.string()
8
8
  });
9
+ var RUN_HISTORY_PAGE_ITEMS = 100;
10
+ var runIdParamSchema = z.object({
11
+ id: z.string().min(1).max(128).regex(/^[A-Za-z0-9._-]+$/)
12
+ });
13
+ var runHistoryCursorSchema = z.string().min(1).max(2048);
14
+ var runHistoryQuerySchema = z.object({
15
+ cursor: runHistoryCursorSchema.optional()
16
+ });
17
+ var runEventsQuerySchema = z.object({
18
+ cursor: runHistoryCursorSchema.optional(),
19
+ afterSeq: z.coerce.number().int().nonnegative().optional()
20
+ });
21
+ var runHistoryEventSchema = z.object({
22
+ seq: z.number(),
23
+ ts: z.string(),
24
+ stepId: z.string().optional(),
25
+ type: z.string()
26
+ }).catchall(z.any());
27
+ var runHistoryPageSchema = z.object({
28
+ events: z.array(runHistoryEventSchema),
29
+ itemCount: z.number().int().min(0).max(RUN_HISTORY_PAGE_ITEMS),
30
+ olderCursor: runHistoryCursorSchema.optional(),
31
+ newerCursor: runHistoryCursorSchema.optional(),
32
+ liveCursor: runHistoryCursorSchema,
33
+ asOfSeq: z.number().int().nonnegative(),
34
+ hasOlder: z.boolean()
35
+ });
36
+ var runHistoryContextSchema = z.object({
37
+ contextEvents: z.array(runHistoryEventSchema),
38
+ asOfSeq: z.number().int().nonnegative()
39
+ });
9
40
  var checkoutProgressEventSchema = z.object({
10
41
  checkoutId: z.string().optional(),
11
42
  name: z.string(),
@@ -16,14 +47,14 @@ var checkoutProgressEventSchema = z.object({
16
47
 
17
48
  // ../contract/src/health.ts
18
49
  import { z as z2 } from "zod";
19
- var runnerSchema = z2.enum(["claude", "codex", "opencode"]);
50
+ var runnerSchema = z2.enum(["claude", "codex", "opencode", "pi"]);
20
51
  var repoInfoSchema = z2.object({
21
52
  root: z2.string(),
22
53
  branch: z2.string(),
23
54
  remote: z2.string().optional()
24
55
  });
25
56
  var backendCheckSchema = z2.object({
26
- name: z2.enum(["claude", "codex", "opencode", "gh", "git"]),
57
+ name: z2.enum(["claude", "codex", "opencode", "pi", "gh", "git"]),
27
58
  available: z2.boolean(),
28
59
  version: z2.string().optional(),
29
60
  hint: z2.string().optional()
@@ -44,6 +75,14 @@ var capabilitiesSchema = z2.object({
44
75
  localHandoff: z2.boolean(),
45
76
  followups: z2.boolean(),
46
77
  singleProject: z2.boolean(),
78
+ /**
79
+ * `true` means `CEZ_AUTOMATIONS=1` opted this server into GitHub automations (#801). Off — the
80
+ * default — the whole feature is absent: no `Automations` nav item anywhere it is rendered, the
81
+ * `/api/v1/…/automations*` family answers `409`, and the workspace scheduler never polls GitHub.
82
+ *
83
+ * REQUIRED for the same reason as `tokenMetrics` below: this server always sends it.
84
+ */
85
+ automations: z2.boolean(),
47
86
  /**
48
87
  * `false` means `CEZ_HIDE_TOKEN_METRICS=1` asks the browser to omit token counts and monetary
49
88
  * cost (#481). The telemetry itself still rides in run/event payloads — this is presentation
@@ -80,78 +119,268 @@ var healthResponseSchema = z2.object({
80
119
  });
81
120
 
82
121
  // ../contract/src/runs.ts
83
- import { z as z4 } from "zod";
122
+ import { z as z5 } from "zod";
84
123
 
85
- // ../contract/src/workflows.ts
124
+ // ../contract/src/github.ts
86
125
  import { z as z3 } from "zod";
87
- var workflowStepDefSchema = z3.object({
88
- id: z3.string().min(1),
89
- name: z3.string().optional(),
126
+ var checksGlyphSchema = z3.enum(["passing", "failing", "pending"]).nullable();
127
+ var githubItemSchema = z3.object({
128
+ kind: z3.enum(["issue", "pr"]),
129
+ number: z3.number(),
130
+ title: z3.string(),
131
+ author: z3.string(),
132
+ createdAt: z3.string(),
133
+ labels: z3.array(z3.string()),
134
+ body: z3.string(),
135
+ url: z3.string(),
136
+ comments: z3.number(),
137
+ /** PRs only. */
138
+ isDraft: z3.boolean().optional(),
139
+ additions: z3.number().optional(),
140
+ deletions: z3.number().optional(),
141
+ checks: checksGlyphSchema.optional()
142
+ });
143
+ var githubDataSchema = z3.object({
144
+ available: z3.boolean(),
145
+ /** Why it is unavailable (`gh` missing, no remote, offline…). Never an error — a hint. */
146
+ reason: z3.string().optional(),
147
+ /** owner/name, when known. */
148
+ repo: z3.string().optional(),
149
+ syncedAt: z3.string().optional(),
150
+ issues: z3.array(githubItemSchema),
151
+ prs: z3.array(githubItemSchema),
152
+ /** Repo-wide label name → 6-hex color (no `#`); lets chips tint like GitHub. Additive. */
153
+ labelColors: z3.record(z3.string(), z3.string()).optional()
154
+ });
155
+ var githubChecksDataSchema = z3.discriminatedUnion("available", [
156
+ z3.object({
157
+ available: z3.literal(true),
158
+ checks: z3.record(z3.number(), checksGlyphSchema)
159
+ }),
160
+ z3.object({
161
+ available: z3.literal(false),
162
+ reason: z3.string()
163
+ })
164
+ ]);
165
+ var referenceStatusSchema = z3.enum([
166
+ "draft",
167
+ "review-required",
168
+ "changes-requested",
169
+ "checks-pending",
170
+ "checks-failing",
171
+ "ready",
172
+ "merged",
173
+ "closed",
174
+ "open",
175
+ "completed",
176
+ "not-planned"
177
+ ]);
178
+ var recheckAfterMsSchema = z3.number().nullable();
179
+ var REFERENCE_STATUS_MAX = 100;
180
+ var githubRefStatusDataSchema = z3.discriminatedUnion("available", [
181
+ z3.object({
182
+ available: z3.literal(true),
183
+ prs: z3.record(z3.number(), referenceStatusSchema),
184
+ issues: z3.record(z3.number(), referenceStatusSchema),
185
+ recheckAfterMs: recheckAfterMsSchema
186
+ }),
187
+ z3.object({
188
+ available: z3.literal(false),
189
+ reason: z3.string(),
190
+ recheckAfterMs: recheckAfterMsSchema
191
+ })
192
+ ]);
193
+ var githubCommentSchema = z3.object({
194
+ id: z3.number(),
195
+ /** Author login, `'?'` fallback when gh omits the user. */
196
+ author: z3.string(),
197
+ avatarUrl: z3.string().optional(),
198
+ createdAt: z3.string(),
199
+ body: z3.string(),
200
+ kind: z3.enum(["comment", "review"]),
201
+ /** Reviews only — drives the state chip. */
202
+ reviewState: z3.enum(["approved", "changes_requested", "commented", "dismissed"]).optional(),
203
+ url: z3.string()
204
+ });
205
+ var githubTimelineEventKindSchema = z3.enum([
206
+ "committed",
207
+ "labeled",
208
+ "unlabeled",
209
+ "assigned",
210
+ "unassigned",
211
+ "merged",
212
+ "closed",
213
+ "reopened",
214
+ "head_ref_force_pushed",
215
+ "cross-referenced",
216
+ "renamed"
217
+ ]);
218
+ var githubTimelineEventSchema = z3.object({
219
+ id: z3.string(),
220
+ kind: githubTimelineEventKindSchema,
221
+ /** Login — or the git author name for `committed`, which carries no GitHub actor. */
222
+ actor: z3.string(),
223
+ /** Absent for `committed`. */
224
+ avatarUrl: z3.string().optional(),
225
+ createdAt: z3.string(),
226
+ url: z3.string().optional(),
227
+ /** `committed` — full 40-char SHA. */
228
+ sha: z3.string().optional(),
229
+ /** `committed` — first line, capped at 120 chars. */
230
+ message: z3.string().optional(),
231
+ /** `committed` — **absent** (lookup failed/skipped) and **`null`** (no CI configured) both
232
+ * render no glyph, but stay distinct values. */
233
+ checks: checksGlyphSchema.optional(),
234
+ label: z3.object({ name: z3.string(), color: z3.string().optional() }).optional(),
235
+ /** `assigned`/`unassigned` login, or the new title for `renamed`. */
236
+ subject: z3.string().optional(),
237
+ refNumber: z3.number().optional(),
238
+ refTitle: z3.string().optional(),
239
+ refIsPr: z3.boolean().optional()
240
+ });
241
+ var githubCommentsDataSchema = z3.object({
242
+ available: z3.boolean(),
243
+ reason: z3.string().optional(),
244
+ /** Chronological, oldest first. */
245
+ comments: z3.array(githubCommentSchema),
246
+ /** True when either stream hit its cap, or the timeline fetch stopped short. */
247
+ truncated: z3.boolean().optional(),
248
+ /** Timeline events (#525) — additive; absent when the server degraded to the legacy
249
+ * comments-only fetch. Capped independently of `comments`. */
250
+ events: z3.array(githubTimelineEventSchema).optional()
251
+ });
252
+ var githubMergeMethodSchema = z3.enum(["merge", "squash", "rebase"]);
253
+ var githubPrCheckSchema = z3.object({
254
+ name: z3.string(),
255
+ state: z3.enum(["passing", "failing", "pending", "unknown"]),
256
+ required: z3.boolean().nullable(),
257
+ url: z3.string().optional()
258
+ });
259
+ var githubPrMergeStateSchema = z3.object({
260
+ number: z3.number(),
261
+ title: z3.string(),
262
+ url: z3.string(),
263
+ state: z3.enum(["open", "closed", "merged"]),
264
+ isDraft: z3.boolean(),
265
+ headRef: z3.string(),
266
+ baseRef: z3.string(),
267
+ headSha: z3.string(),
268
+ mergeable: z3.enum(["mergeable", "conflicting", "unknown"]),
269
+ reviewDecision: z3.enum(["approved", "changes-requested", "review-required", "unknown"]),
270
+ checks: z3.array(githubPrCheckSchema),
271
+ methods: z3.array(githubMergeMethodSchema),
272
+ defaultMethod: githubMergeMethodSchema.nullable(),
273
+ eligibility: z3.enum(["ready", "blocked", "pending", "unauthorized", "terminal", "unknown"]),
274
+ blockers: z3.array(z3.object({ code: z3.string(), message: z3.string() })),
275
+ canMerge: z3.boolean(),
276
+ canOverride: z3.boolean()
277
+ });
278
+ var githubPrMergeStateResponseSchema = z3.discriminatedUnion("available", [
279
+ z3.object({ available: z3.literal(true), mergeState: githubPrMergeStateSchema }),
280
+ z3.object({ available: z3.literal(false), reason: z3.string() })
281
+ ]);
282
+ var githubMergeResponseSchema = z3.object({
283
+ merged: z3.literal(true),
284
+ number: z3.number(),
285
+ url: z3.string(),
286
+ method: githubMergeMethodSchema,
287
+ mergeCommitSha: z3.string().optional()
288
+ });
289
+ var githubPrChangeSchema = z3.object({
290
+ path: z3.string(),
291
+ previousPath: z3.string().optional(),
292
+ status: z3.enum(["added", "modified", "removed", "renamed", "copied", "changed"]),
293
+ additions: z3.number(),
294
+ deletions: z3.number(),
295
+ patch: z3.string().optional(),
296
+ patchUnavailableReason: z3.enum(["binary", "too-large", "not-provided"]).optional(),
297
+ truncated: z3.boolean().optional()
298
+ });
299
+ var githubPrChangesDataSchema = z3.discriminatedUnion("available", [
300
+ z3.object({
301
+ available: z3.literal(true),
302
+ number: z3.number(),
303
+ headSha: z3.string(),
304
+ files: z3.array(githubPrChangeSchema),
305
+ additions: z3.number(),
306
+ deletions: z3.number(),
307
+ truncated: z3.boolean(),
308
+ /** Present when the payload is complete but partial in some other way (a capped patch). */
309
+ reason: z3.string().optional()
310
+ }),
311
+ z3.object({ available: z3.literal(false), reason: z3.string() })
312
+ ]);
313
+
314
+ // ../contract/src/workflows.ts
315
+ import { z as z4 } from "zod";
316
+ var workflowStepDefSchema = z4.object({
317
+ id: z4.string().min(1),
318
+ name: z4.string().optional(),
90
319
  // agent step
91
- prompt: z3.string().optional(),
92
- skill: z3.string().optional(),
93
- model: z3.string().optional(),
320
+ prompt: z4.string().optional(),
321
+ skill: z4.string().optional(),
322
+ model: z4.string().optional(),
94
323
  /** Per-step agent backend override (falls back to the task / config default). */
95
324
  runner: runnerSchema.optional(),
96
- allowedTools: z3.array(z3.string()).optional(),
97
- bashAllowlist: z3.array(z3.string()).optional(),
325
+ allowedTools: z4.array(z4.string()).optional(),
326
+ bashAllowlist: z4.array(z4.string()).optional(),
98
327
  // check step
99
- command: z3.string().optional(),
100
- onFail: z3.object({
101
- retry: z3.string().min(1),
102
- max: z3.number().int().positive().default(2)
328
+ command: z4.string().optional(),
329
+ onFail: z4.object({
330
+ retry: z4.string().min(1),
331
+ max: z4.number().int().positive().default(2)
103
332
  }).optional()
104
333
  }).refine((s) => Boolean(s.command) !== Boolean(s.prompt ?? s.skill), {
105
334
  message: "a step is either an agent step (prompt/skill) or a check step (command), not both"
106
335
  });
107
- var workflowDefSchema = z3.object({
108
- name: z3.string(),
109
- description: z3.string().optional(),
110
- steps: z3.array(workflowStepDefSchema),
111
- source: z3.enum(["built-in", "file"]),
336
+ var workflowDefSchema = z4.object({
337
+ name: z4.string(),
338
+ description: z4.string().optional(),
339
+ steps: z4.array(workflowStepDefSchema),
340
+ source: z4.enum(["built-in", "file"]),
112
341
  /** Absent on built-ins — which is exactly what makes them undeletable. */
113
- path: z3.string().optional()
342
+ path: z4.string().optional()
114
343
  });
115
- var workflowLoadIssueSchema = z3.object({
116
- path: z3.string(),
117
- message: z3.string()
118
- });
119
- var workflowsResponseSchema = z3.object({
120
- workflows: z3.array(workflowDefSchema),
121
- issues: z3.array(workflowLoadIssueSchema)
122
- });
123
- var saveWorkflowInputSchema = z3.object({
124
- name: z3.string().trim().min(1).max(80),
125
- description: z3.string().max(2e3, "must be at most 2000 characters").optional(),
126
- steps: z3.array(workflowStepDefSchema).min(1).max(8).optional(),
127
- skills: z3.array(z3.string().trim().min(1)).min(1).max(8).optional(),
128
- overwrite: z3.boolean().optional()
344
+ var workflowLoadIssueSchema = z4.object({
345
+ path: z4.string(),
346
+ message: z4.string()
347
+ });
348
+ var workflowsResponseSchema = z4.object({
349
+ workflows: z4.array(workflowDefSchema),
350
+ issues: z4.array(workflowLoadIssueSchema)
351
+ });
352
+ var saveWorkflowInputSchema = z4.object({
353
+ name: z4.string().trim().min(1).max(80),
354
+ description: z4.string().max(2e3, "must be at most 2000 characters").optional(),
355
+ steps: z4.array(workflowStepDefSchema).min(1).max(8).optional(),
356
+ skills: z4.array(z4.string().trim().min(1)).min(1).max(8).optional(),
357
+ overwrite: z4.boolean().optional()
129
358
  }).refine((b) => Boolean(b.steps) !== Boolean(b.skills), {
130
359
  message: 'provide either "steps" or "skills", not both'
131
360
  });
132
- var saveWorkflowResponseSchema = z3.object({
133
- path: z3.string(),
134
- name: z3.string()
361
+ var saveWorkflowResponseSchema = z4.object({
362
+ path: z4.string(),
363
+ name: z4.string()
135
364
  });
136
- var parsedWorkflowSchema = z3.object({
137
- name: z3.string(),
138
- description: z3.string().optional(),
139
- steps: z3.array(workflowStepDefSchema)
365
+ var parsedWorkflowSchema = z4.object({
366
+ name: z4.string(),
367
+ description: z4.string().optional(),
368
+ steps: z4.array(workflowStepDefSchema)
140
369
  });
141
- var deleteWorkflowResponseSchema = z3.object({
142
- ok: z3.literal(true),
143
- path: z3.string()
370
+ var deleteWorkflowResponseSchema = z4.object({
371
+ ok: z4.literal(true),
372
+ path: z4.string()
144
373
  });
145
- var planResponseSchema = z3.object({
374
+ var planResponseSchema = z4.object({
146
375
  /** The kebab-case workflow title the planner proposed. Absent on the degraded fallback. */
147
- name: z3.string().optional(),
148
- steps: z3.array(workflowStepDefSchema),
149
- rationale: z3.string(),
150
- fallback: z3.boolean()
376
+ name: z4.string().optional(),
377
+ steps: z4.array(workflowStepDefSchema),
378
+ rationale: z4.string(),
379
+ fallback: z4.boolean()
151
380
  });
152
381
 
153
382
  // ../contract/src/runs.ts
154
- var runStatusSchema = z4.enum([
383
+ var runStatusSchema = z5.enum([
155
384
  "queued",
156
385
  "running",
157
386
  "waiting",
@@ -160,8 +389,8 @@ var runStatusSchema = z4.enum([
160
389
  "failed",
161
390
  "cancelled"
162
391
  ]);
163
- var runActivitySchema = z4.enum(["monitoring"]);
164
- var stepStatusSchema = z4.enum([
392
+ var runActivitySchema = z5.enum(["monitoring"]);
393
+ var stepStatusSchema = z5.enum([
165
394
  "pending",
166
395
  "running",
167
396
  "waiting",
@@ -171,14 +400,14 @@ var stepStatusSchema = z4.enum([
171
400
  "cancelled",
172
401
  "skipped"
173
402
  ]);
174
- var usageCounterSchema = z4.number().finite().nonnegative();
175
- var stepStateSchema = z4.object({
176
- id: z4.string(),
177
- name: z4.string(),
178
- kind: z4.enum(["agent", "check"]),
403
+ var usageCounterSchema = z5.number().finite().nonnegative();
404
+ var stepStateSchema = z5.object({
405
+ id: z5.string(),
406
+ name: z5.string(),
407
+ kind: z5.enum(["agent", "check"]),
179
408
  status: stepStatusSchema,
180
- iterations: z4.number(),
181
- tokensUsed: z4.number(),
409
+ iterations: z5.number(),
410
+ tokensUsed: z5.number(),
182
411
  inputTokens: usageCounterSchema.optional(),
183
412
  outputTokens: usageCounterSchema.optional(),
184
413
  usageInvocationsStarted: usageCounterSchema.optional(),
@@ -186,65 +415,74 @@ var stepStateSchema = z4.object({
186
415
  usageTurnsStarted: usageCounterSchema.optional(),
187
416
  usageTurnsRecorded: usageCounterSchema.optional(),
188
417
  usageInvocationEpoch: usageCounterSchema.optional(),
189
- startedAt: z4.string().optional(),
190
- finishedAt: z4.string().optional(),
191
- error: z4.string().optional(),
418
+ startedAt: z5.string().optional(),
419
+ finishedAt: z5.string().optional(),
420
+ error: z5.string().optional(),
192
421
  /** Latest agent session id — `claude --resume <id>` and friends. */
193
- sessionId: z4.string().optional(),
422
+ sessionId: z5.string().optional(),
194
423
  /** Backend that owns `sessionId`; absent on records written before backend affinity. */
195
424
  backend: runnerSchema.optional(),
196
- costUsd: z4.number().optional()
197
- });
198
- var diffStatSchema = z4.object({
199
- adds: z4.number(),
200
- dels: z4.number(),
201
- files: z4.number(),
202
- /** Additive since #751, and present ONLY when true: the numbers cover uncommitted work
203
- * alone, because the worktree's HEAD had been repointed off the task's own branch (every
204
- * review/QA run does this) and the merge-base anchor would otherwise have reported the
205
- * checked-out branch's entire diff as this task's. Absent on every normal run and on every
206
- * record written before #751 — a consumer that ignores it sees exactly the old shape. */
207
- repointed: z4.boolean().optional()
208
- });
209
- var queuedMessageSchema = z4.object({
210
- id: z4.string(),
211
- text: z4.string(),
425
+ /** Agent account (spec 2026-07-29-agent-profiles) that owns `sessionId` — `default`, or a
426
+ * stored profile id. The two are a PAIR: a session id only resolves inside the config dir
427
+ * that created it, so resume and Continue read this rather than the project's current
428
+ * selection. Absent on records written before accounts existed. */
429
+ profileId: z5.string().optional(),
430
+ costUsd: z5.number().optional()
431
+ });
432
+ var diffStatSchema = z5.object({
433
+ adds: z5.number(),
434
+ dels: z5.number(),
435
+ files: z5.number(),
436
+ /** Additive since #751, and present ONLY when true: the numbers were measured against a
437
+ * branch the agent checked out into the task's worktree, as the run found it, because the
438
+ * worktree's HEAD had been repointed off the task's own branch (every review/QA run does
439
+ * this) and the merge-base anchor would otherwise have reported that branch's entire diff
440
+ * as this task's. Absent on every normal run and on every record written before #751 — a
441
+ * consumer that ignores it sees exactly the old shape. */
442
+ repointed: z5.boolean().optional()
443
+ });
444
+ var queuedMessageSchema = z5.object({
445
+ id: z5.string(),
446
+ text: z5.string(),
212
447
  /** `/api/v1/runs/:id/images/…` URLs — attachments are persisted, never inlined. */
213
- images: z4.array(z4.string()).optional(),
214
- createdAt: z4.string()
448
+ images: z5.array(z5.string()).optional(),
449
+ createdAt: z5.string()
215
450
  });
216
- var processUsageSchema = z4.object({
451
+ var processUsageSchema = z5.object({
217
452
  /** Sum of `%cpu` across the tree — can exceed 100 on multi-core work. */
218
- cpuPct: z4.number(),
219
- rssBytes: z4.number(),
220
- procCount: z4.number()
453
+ cpuPct: z5.number(),
454
+ rssBytes: z5.number(),
455
+ procCount: z5.number()
221
456
  });
222
- var runRecordSchema = z4.object({
223
- id: z4.string(),
224
- title: z4.string(),
457
+ var runRecordSchema = z5.object({
458
+ id: z5.string(),
459
+ title: z5.string(),
225
460
  /** Display title (#389): auto-derived from the first agent turn, or the user's inline edit
226
461
  * (`PATCH /runs/:id` sets it together with `title`). Show `titleSummary ?? title`. */
227
- titleSummary: z4.string().optional(),
462
+ titleSummary: z5.string().optional(),
228
463
  /** Refreshed on every turn-end; absent until the first turn ends (and on worktree-less runs). */
229
464
  diffStat: diffStatSchema.optional(),
230
- workflow: z4.string(),
231
- task: z4.string(),
465
+ workflow: z5.string(),
466
+ task: z5.string(),
232
467
  /** Prompt messages stacked onto the run while it waited for a free agent slot (#472). Folded
233
468
  * into the prompt at dequeue — never delivered as their own turns. Absent on pre-#472 runs. */
234
- queuedMessages: z4.array(queuedMessageSchema).optional(),
469
+ queuedMessages: z5.array(queuedMessageSchema).optional(),
235
470
  /** URLs of images attached to the initial task prompt (#image-display). */
236
- taskImages: z4.array(z4.string()).optional(),
237
- model: z4.string().optional(),
471
+ taskImages: z5.array(z5.string()).optional(),
472
+ model: z5.string().optional(),
238
473
  /** Normalized provider/model identity used for attribution and reproducible replay. */
239
- modelIdentity: z4.string().optional(),
474
+ modelIdentity: z5.string().optional(),
240
475
  runner: runnerSchema.optional(),
476
+ /** The composer's per-task agent account (spec 2026-07-29-agent-profiles), applying to steps
477
+ * on `runner`. Absent = the run follows the project's own selection. */
478
+ agentProfile: z5.string().optional(),
241
479
  /** Echo of the extra system prompt the run used (POST override or config default). */
242
- systemPrompt: z4.string().optional(),
480
+ systemPrompt: z5.string().optional(),
243
481
  /** false when the run deliberately disabled follow-up todo generation. Absent means enabled. */
244
- generateFollowups: z4.boolean().optional(),
482
+ generateFollowups: z5.boolean().optional(),
245
483
  /** Autonomous mode (#autonomous): the run never parks at `waiting` or the terminal `review`
246
484
  * gate. Absent = falsy = not autonomous. */
247
- autonomous: z4.boolean().optional(),
485
+ autonomous: z5.boolean().optional(),
248
486
  /**
249
487
  * Provenance for a task a project GitHub automation launched (#694). Absent on every ordinary
250
488
  * run, which is what makes it additive — the cockpit shows the "from automation" link only when
@@ -254,76 +492,83 @@ var runRecordSchema = z4.object({
254
492
  * launching definition matched, recorded on the run for the audit trail, and `src/runs/store.ts`
255
493
  * persists it as free text so an older cezar can still read a record written by a newer one.
256
494
  */
257
- automation: z4.object({
258
- automationId: z4.string(),
259
- automationRevision: z4.number(),
260
- receiptId: z4.string(),
261
- event: z4.string(),
262
- githubUrl: z4.string()
495
+ automation: z5.object({
496
+ automationId: z5.string(),
497
+ automationRevision: z5.number(),
498
+ receiptId: z5.string(),
499
+ event: z5.string(),
500
+ githubUrl: z5.string()
263
501
  }).optional(),
264
502
  status: runStatusSchema,
265
503
  /** `monitoring` while `status === 'running'` and the agent is working on downstream work.
266
504
  * Absent on old runs; cleared on resume/end. */
267
505
  activity: runActivitySchema.optional(),
268
506
  /** Exact ISO-8601 deadline for the next automatic monitoring check. */
269
- monitoringWakeAt: z4.string().optional(),
507
+ monitoringWakeAt: z5.string().optional(),
270
508
  /** The current live monitoring epoch exhausted its 40 automatic checks. */
271
- monitoringWakeCapReached: z4.boolean().optional(),
272
- createdAt: z4.string(),
273
- startedAt: z4.string().optional(),
274
- finishedAt: z4.string().optional(),
275
- tokensUsed: z4.number(),
509
+ monitoringWakeCapReached: z5.boolean().optional(),
510
+ /** Exact ISO-8601 instant this run resumes itself after a provider usage limit stopped it
511
+ * (spec 2026-08-03-auto-resume-after-usage-limit). Present only on a `failed` run with a
512
+ * pending automatic resume — its absence is what "no resume is scheduled" looks like. */
513
+ autoResumeAt: z5.string().optional(),
514
+ /** Consecutive automatic resumes since the last human turn, against the safety cap. */
515
+ autoResumeAttempts: z5.number().optional(),
516
+ createdAt: z5.string(),
517
+ startedAt: z5.string().optional(),
518
+ finishedAt: z5.string().optional(),
519
+ tokensUsed: z5.number(),
276
520
  inputTokens: usageCounterSchema.optional(),
277
521
  outputTokens: usageCounterSchema.optional(),
278
- costUsd: z4.number().optional(),
279
- pullRequestUrl: z4.string().optional(),
522
+ costUsd: z5.number().optional(),
523
+ pullRequestUrl: z5.string().optional(),
280
524
  /** The PR this task is ABOUT (#407) — auto-discovered from conversation references. Display
281
525
  * tier only: `pullRequestUrl` (the PR this task CREATED) wins, and the action gates ignore it. */
282
- referencedPullRequestUrl: z4.string().optional(),
526
+ referencedPullRequestUrl: z5.string().optional(),
283
527
  /** The PR/issue number this task is ABOUT (task auto-naming spec) — display tier only. */
284
- prNumber: z4.number().optional(),
285
- issueNumber: z4.number().optional(),
528
+ prNumber: z5.number().optional(),
529
+ issueNumber: z5.number().optional(),
286
530
  /** Server-side provenance: referenced-issue discovery currently owns `issueNumber`. */
287
- referencedIssueNumberSeeded: z4.boolean().optional(),
531
+ referencedIssueNumberSeeded: z5.boolean().optional(),
288
532
  /** 'user' = renamed via PATCH, never auto-overwritten; 'marker' = agent-declared via
289
533
  * CEZ:TITLE (spec 2026-07-18-task-ref-markers); 'auto' = namer-owned. */
290
- titleOrigin: z4.enum(["user", "auto", "marker"]).optional(),
534
+ titleOrigin: z5.enum(["user", "auto", "marker"]).optional(),
291
535
  /** References the agent declared via CEZ:PR/CEZ:ISSUE markers — authoritative over the namer
292
536
  * for the matching kind. */
293
- markerRefs: z4.object({ pr: z4.number().optional(), issue: z4.number().optional() }).optional(),
537
+ markerRefs: z5.object({ pr: z5.number().optional(), issue: z5.number().optional() }).optional(),
294
538
  /** The referenced tier's working set (distinct PR URLs spotted, capped server-side). */
295
- referencedPrCandidates: z4.array(z4.string()).optional(),
539
+ referencedPrCandidates: z5.array(z5.string()).optional(),
296
540
  /** The issue this task is ABOUT (spec 2026-07-21-report-ref-discovery). Display-only. */
297
- referencedIssueUrl: z4.string().optional(),
541
+ referencedIssueUrl: z5.string().optional(),
298
542
  /** The referenced-issue working set, persisted like `referencedPrCandidates`. Capped. */
299
- referencedIssueCandidates: z4.array(z4.string()).optional(),
543
+ referencedIssueCandidates: z5.array(z5.string()).optional(),
300
544
  /** Explicit execution policy. `false` means the run intentionally uses the repo root;
301
545
  * absent on older runs and for the default isolated-worktree mode. */
302
- worktree: z4.literal(false).optional(),
546
+ worktree: z5.literal(false).optional(),
303
547
  /** Absent for in-place runs and after an isolated worktree is removed. */
304
- worktreePath: z4.string().optional(),
305
- branch: z4.string().optional(),
548
+ worktreePath: z5.string().optional(),
549
+ branch: z5.string().optional(),
306
550
  /** Stable baseline for session git views: a worktree's fork ref, or an in-place run's starting commit. */
307
- baseBranch: z4.string().optional(),
551
+ baseBranch: z5.string().optional(),
308
552
  /** Set when count-based retention (#483) reclaimed the worktree DIRECTORY (the branch is
309
553
  * kept): the dir is gone but recoverable. */
310
- worktreeReclaimedAt: z4.string().optional(),
554
+ worktreeReclaimedAt: z5.string().optional(),
311
555
  /** Parallel variants (spec 010): runs sharing a groupId are one group. */
312
- groupId: z4.string().optional(),
556
+ groupId: z5.string().optional(),
313
557
  /** Variant letter within the group — 'A' | 'B' | 'C'. */
314
- variant: z4.string().optional(),
315
- peakRssBytes: z4.number().optional(),
316
- peakProcCount: z4.number().optional(),
317
- archived: z4.boolean(),
318
- archivedAt: z4.string().optional(),
558
+ variant: z5.string().optional(),
559
+ peakRssBytes: z5.number().optional(),
560
+ peakProcCount: z5.number().optional(),
561
+ archived: z5.boolean(),
562
+ archivedAt: z5.string().optional(),
319
563
  /** Read receipt (#unread-done-items): ISO time the cockpit last opened this run's
320
564
  * thread. A finished (`done`/`failed`) run reads as *unread* until seen since it
321
565
  * finished — see `isUnread()` in the cockpit's `lib/read-state.ts`. Absent on old
322
- * runs and on any run not yet opened, both of which count as unread. */
323
- seenAt: z4.string().optional(),
324
- currentStepId: z4.string().optional(),
325
- error: z4.string().optional(),
326
- steps: z4.array(stepStateSchema),
566
+ * runs, on any run not yet opened, and on one deliberately put back to unread via
567
+ * `POST /runs/:id/unread` (#775) — all three count as unread. */
568
+ seenAt: z5.string().optional(),
569
+ currentStepId: z5.string().optional(),
570
+ error: z5.string().optional(),
571
+ steps: z5.array(stepStateSchema),
327
572
  /**
328
573
  * The persisted workflow definition, so a `queued` run survives a restart — including the ad-hoc
329
574
  * "(planned)" chains that exist nowhere else.
@@ -341,206 +586,299 @@ var runRecordSchema = z4.object({
341
586
  var apiRunSchema = runRecordSchema.extend({
342
587
  usage: processUsageSchema.optional()
343
588
  });
344
- var createRunResponseSchema = z4.union([
589
+ var runIndexEntrySchema = z5.object({
590
+ /** The registered project this run belongs to. Joins against `GET /projects`. */
591
+ projectId: z5.string(),
592
+ id: z5.string(),
593
+ title: z5.string(),
594
+ titleSummary: z5.string().optional(),
595
+ titleOrigin: z5.enum(["user", "auto", "marker"]).optional(),
596
+ status: runStatusSchema,
597
+ activity: runActivitySchema.optional(),
598
+ createdAt: z5.string(),
599
+ finishedAt: z5.string().optional(),
600
+ /** With `status`/`finishedAt`/`archived`, the four inputs `isUnread` reads — what lets the
601
+ * palette lead with "finished while you weren't looking" across every project, not just the
602
+ * one you happen to be standing in. */
603
+ seenAt: z5.string().optional(),
604
+ /** Always present, like `RunRecord.archived`: absent would read as "not archived", and the
605
+ * unread rule treats archiving as a stronger "done with this" than reading. */
606
+ archived: z5.boolean(),
607
+ /** A run parked by a provider usage limit is `failed` on the record with a resume booked
608
+ * (spec 2026-08-03-auto-resume-after-usage-limit). Both `deriveAttention` and `isUnread` read
609
+ * it, so without it here a cross-project row would show a red "failed" dot and land in
610
+ * Recently finished for work that is simply waiting for its appointment. */
611
+ autoResumeAt: z5.string().optional(),
612
+ /** The workflow the run executes — the global Tasks page shows it in a column and groups by
613
+ * it. Always present on the record (`RunRecord.workflow`), so required here; the display
614
+ * refinement `workflowLabel` applies needs `steps[]`, which this row deliberately omits, so
615
+ * a `(planned)` chain reads as itself here rather than as its first agent's name. */
616
+ workflow: z5.string(),
617
+ /** The task's branch, when it has one — a column on the global page, and the one field that
618
+ * makes a cross-project row identifiable at a glance without opening it. */
619
+ branch: z5.string().optional(),
620
+ /** When the agent actually started, as opposed to when the task was created. The global page's
621
+ * age column prefers it and falls back to `createdAt`, exactly as the per-project table does. */
622
+ startedAt: z5.string().optional(),
623
+ /**
624
+ * The six fields `taskReference()` (`web/src/lib/tasks-table.ts`) reads to decide a task's PR
625
+ * or issue chip. Carried verbatim rather than pre-resolved into a `{kind, number, url}` on the
626
+ * server, because the rule that picks between them is subtle (#407, #526: a run that REVIEWED
627
+ * a PR must not claim it as its own, an issue-subject run must not adopt an incidental
628
+ * transcript PR) and it already exists, tested, on the client. Resolving it a second time
629
+ * server-side would be a second rule, and the two would drift.
630
+ *
631
+ * Six scalars is still the slim row this schema exists to keep: `steps[]` and `workflowDef`,
632
+ * the expensive half, stay off it.
633
+ */
634
+ pullRequestUrl: z5.string().optional(),
635
+ referencedPullRequestUrl: z5.string().optional(),
636
+ prNumber: z5.number().optional(),
637
+ issueNumber: z5.number().optional(),
638
+ referencedIssueUrl: z5.string().optional(),
639
+ markerRefs: z5.object({ pr: z5.number().optional(), issue: z5.number().optional() }).optional(),
640
+ /** What the run has cost so far. Absent means nothing was recorded, which is NOT `$0` — the
641
+ * cockpit prints an em dash rather than claiming a measurement that never happened. */
642
+ costUsd: z5.number().optional(),
643
+ /** The persisted high-water marks a FINISHED run leaves behind. `usage` below stops existing
644
+ * the moment the process tree does, so without these a finished row could say nothing at all
645
+ * about what it took to run. */
646
+ peakRssBytes: z5.number().optional(),
647
+ peakProcCount: z5.number().optional(),
648
+ /**
649
+ * The live CPU/RSS sample of this run's process tree, attached on the way out exactly as
650
+ * `GET /runs` attaches it (`withUsage`) — never persisted.
651
+ *
652
+ * It can ride a WORKSPACE-level answer because the sampler is process-wide: one cezar process
653
+ * runs every project's agents, so `currentUsage(runId)` knows about a run whatever project it
654
+ * belongs to. That is what lets a cross-project table show live usage without opening one
655
+ * event stream per project (it could not — the run stream is project-scoped).
656
+ */
657
+ usage: processUsageSchema.optional()
658
+ });
659
+ var referenceStatusesByProjectSchema = z5.record(
660
+ z5.string(),
661
+ z5.object({
662
+ prs: z5.record(z5.number(), referenceStatusSchema),
663
+ issues: z5.record(z5.number(), referenceStatusSchema)
664
+ })
665
+ );
666
+ var runsIndexResponseSchema = z5.object({
667
+ /** Newest first, across every registered project. Archived runs are included — `GET /runs`
668
+ * carries them for the project you are standing in, and a finder that dropped them elsewhere
669
+ * would make a task vanish the moment you left its project. */
670
+ runs: z5.array(runIndexEntrySchema),
671
+ /** Additive: absent statuses mean "nothing warm", never "nothing to show". */
672
+ referenceStatuses: referenceStatusesByProjectSchema,
673
+ /** The per-project cap that produced this list. */
674
+ perProjectLimit: z5.number(),
675
+ /** Ids of the projects that had more runs than the cap allowed. */
676
+ truncated: z5.array(z5.string())
677
+ });
678
+ var createRunResponseSchema = z5.union([
345
679
  runRecordSchema,
346
- z4.object({ runs: z4.array(runRecordSchema) })
680
+ z5.object({ runs: z5.array(runRecordSchema) })
347
681
  ]);
348
- var cancelResponseSchema = z4.object({ cancelled: z4.boolean() });
349
- var archiveFinishedResponseSchema = z4.object({ archived: z4.number() });
350
- var markAllReadResponseSchema = z4.object({ read: z4.number() });
351
- var deleteRunResponseSchema = z4.object({ deleted: z4.literal(true) });
352
- var finishResponseSchema = z4.object({ finished: z4.literal(true) });
353
- var continueResponseSchema = z4.object({ continued: z4.literal(true) });
354
- var createPrResponseSchema = z4.object({
355
- url: z4.string(),
356
- dryRun: z4.boolean()
357
- });
358
- var messageResponseSchema = z4.union([
359
- z4.object({ delivered: z4.literal(true) }),
360
- z4.object({ queued: z4.literal(true), message: queuedMessageSchema }),
361
- z4.object({ deferred: z4.literal(true) })
682
+ var cancelResponseSchema = z5.object({ cancelled: z5.boolean() });
683
+ var cancelAutoResumeResponseSchema = z5.object({ cancelled: z5.literal(true) });
684
+ var archiveFinishedResponseSchema = z5.object({ archived: z5.number() });
685
+ var markAllReadResponseSchema = z5.object({ read: z5.number() });
686
+ var deleteRunResponseSchema = z5.object({ deleted: z5.literal(true) });
687
+ var finishResponseSchema = z5.object({ finished: z5.literal(true) });
688
+ var continueResponseSchema = z5.object({ continued: z5.literal(true) });
689
+ var createPrResponseSchema = z5.object({
690
+ url: z5.string(),
691
+ dryRun: z5.boolean()
692
+ });
693
+ var messageResponseSchema = z5.union([
694
+ z5.object({ delivered: z5.literal(true) }),
695
+ z5.object({ queued: z5.literal(true), message: queuedMessageSchema }),
696
+ z5.object({ deferred: z5.literal(true) })
362
697
  ]);
363
- var editQueuedMessageResponseSchema = z4.object({ message: queuedMessageSchema });
364
- var removeQueuedMessageResponseSchema = z4.object({ removed: z4.literal(true) });
365
- var openInCliResponseSchema = z4.object({
366
- opened: z4.literal(true),
367
- command: z4.string()
368
- });
369
- var removeWorktreeResponseSchema = z4.object({ removed: z4.literal(true) });
370
- var gitCommitResponseSchema = z4.object({
371
- committed: z4.literal(true),
372
- sha: z4.string()
373
- });
374
- var gitPushResponseSchema = z4.object({
375
- pushed: z4.literal(true),
376
- branch: z4.string(),
377
- remote: z4.string(),
378
- upstreamSet: z4.boolean()
379
- });
380
- var runCommitSchema = z4.object({
381
- sha: z4.string(),
382
- subject: z4.string(),
383
- author: z4.string(),
698
+ var editQueuedMessageResponseSchema = z5.object({ message: queuedMessageSchema });
699
+ var removeQueuedMessageResponseSchema = z5.object({ removed: z5.literal(true) });
700
+ var openInCliResponseSchema = z5.object({
701
+ opened: z5.literal(true),
702
+ command: z5.string()
703
+ });
704
+ var removeWorktreeResponseSchema = z5.object({ removed: z5.literal(true) });
705
+ var gitCommitResponseSchema = z5.object({
706
+ committed: z5.literal(true),
707
+ sha: z5.string()
708
+ });
709
+ var gitPushResponseSchema = z5.object({
710
+ pushed: z5.literal(true),
711
+ branch: z5.string(),
712
+ remote: z5.string(),
713
+ upstreamSet: z5.boolean()
714
+ });
715
+ var runCommitSchema = z5.object({
716
+ sha: z5.string(),
717
+ subject: z5.string(),
718
+ author: z5.string(),
384
719
  /** Relative time ("3 hours ago") — git's `%cr`. */
385
- when: z4.string()
720
+ when: z5.string()
386
721
  });
387
- var runCommitsResponseSchema = z4.object({ commits: z4.array(runCommitSchema) });
388
- var groupVariantSchema = z4.object({
389
- id: z4.string(),
722
+ var runCommitsResponseSchema = z5.object({ commits: z5.array(runCommitSchema) });
723
+ var groupVariantSchema = z5.object({
724
+ id: z5.string(),
390
725
  /** 'A' | 'B' | 'C' in practice; `'?'` for a record that lost its letter. */
391
- variant: z4.string(),
392
- title: z4.string(),
726
+ variant: z5.string(),
727
+ title: z5.string(),
393
728
  status: runStatusSchema,
394
- archived: z4.boolean(),
395
- tokensUsed: z4.number(),
729
+ archived: z5.boolean(),
730
+ tokensUsed: z5.number(),
396
731
  inputTokens: usageCounterSchema.optional(),
397
732
  outputTokens: usageCounterSchema.optional(),
398
- costUsd: z4.number().optional(),
399
- diffStat: z4.string(),
733
+ costUsd: z5.number().optional(),
734
+ diffStat: z5.string(),
400
735
  /** First lines of the handoff journal's "## Progress log" section, as markdown. */
401
- handoffExcerpt: z4.string()
736
+ handoffExcerpt: z5.string()
402
737
  });
403
- var groupResponseSchema = z4.object({
404
- groupId: z4.string(),
405
- runs: z4.array(groupVariantSchema)
738
+ var groupResponseSchema = z5.object({
739
+ groupId: z5.string(),
740
+ runs: z5.array(groupVariantSchema)
406
741
  });
407
- var pickVariantResponseSchema = z4.object({
742
+ var pickVariantResponseSchema = z5.object({
408
743
  winner: runRecordSchema.optional()
409
744
  });
410
- var imageInputSchema = z4.object({
411
- mediaType: z4.string().regex(/^image\//),
412
- data: z4.string().min(1).max(7e6)
745
+ var imageInputSchema = z5.object({
746
+ mediaType: z5.string().regex(/^image\//),
747
+ data: z5.string().min(1).max(7e6)
413
748
  });
414
- var createRunInputBaseSchema = z4.object({
415
- workflow: z4.string().min(1).optional(),
749
+ var createRunInputBaseSchema = z5.object({
750
+ workflow: z5.string().min(1).optional(),
416
751
  /** An inline chain (spec 008 — an approved plan runs as an ad-hoc workflow, never written to
417
752
  * a file). The catalog's own step shape, not a copy of it. */
418
- steps: z4.array(workflowStepDefSchema).min(1).max(8).optional(),
419
- task: z4.string().min(1).max(1e5, "must be at most 100000 characters"),
420
- model: z4.string().optional(),
753
+ steps: z5.array(workflowStepDefSchema).min(1).max(8).optional(),
754
+ task: z5.string().min(1).max(1e5, "must be at most 100000 characters"),
755
+ model: z5.string().optional(),
421
756
  runner: runnerSchema.optional(),
757
+ /** Agent account for this task (spec 2026-07-29-agent-profiles). Omit to follow the
758
+ * project's own selection; an id that no longer exists is a 400, not a silent default. */
759
+ agentProfile: z5.string().max(64).optional(),
422
760
  /** 1–3. Above 1 the response is `{ runs }` rather than a single record. */
423
- variants: z4.number().int().min(1).max(3).optional(),
761
+ variants: z5.number().int().min(1).max(3).optional(),
424
762
  /** false → run in the repo working tree instead of an isolated worktree (read-only skills).
425
763
  * Omit for the default. Ignored server-side when variants > 1. */
426
- worktree: z4.boolean().optional(),
764
+ worktree: z5.boolean().optional(),
427
765
  /** true → autonomous run: never parks at "waiting"; auto-continues until done. */
428
- autonomous: z4.boolean().optional(),
766
+ autonomous: z5.boolean().optional(),
429
767
  /** false → keep the handoff journal but do not expose or request a follow-up todos file.
430
768
  * Omit for the default (enabled); a server with the capability off pins it to false. */
431
- generateFollowups: z4.boolean().optional(),
769
+ generateFollowups: z5.boolean().optional(),
432
770
  /** Per-run system-prompt override (R2 2.3) — programmatic callers only. Wins over the
433
771
  * config.json default; whitespace-only degrades to absent. */
434
- systemPrompt: z4.string().trim().max(2e4, "must be at most 20000 characters").optional().transform((s) => s ? s : void 0),
772
+ systemPrompt: z5.string().trim().max(2e4, "must be at most 20000 characters").optional().transform((s) => s ? s : void 0),
435
773
  /** Screenshots pasted into the new-task form; delivered with the first agent step. */
436
- images: z4.array(imageInputSchema).max(4).optional(),
774
+ images: z5.array(imageInputSchema).max(4).optional(),
437
775
  /** The inbox entry this task came from (#374). Best-effort bookkeeping: an unknown or
438
776
  * already-started id never fails the run. For ×2/×3 the FIRST variant is recorded. */
439
- todoId: z4.string().min(1).max(200, "must be at most 200 characters").optional()
777
+ todoId: z5.string().min(1).max(200, "must be at most 200 characters").optional()
440
778
  });
441
779
  var createRunInputSchema = createRunInputBaseSchema.refine(
442
780
  (b) => Boolean(b.workflow) !== Boolean(b.steps),
443
781
  { message: 'provide either "workflow" or "steps", not both' }
444
782
  );
445
- var messageInputSchema = z4.object({
446
- text: z4.string().max(1e5).default(""),
447
- images: z4.array(imageInputSchema).max(4).default([])
783
+ var messageInputSchema = z5.object({
784
+ text: z5.string().max(1e5).default(""),
785
+ images: z5.array(imageInputSchema).max(4).default([])
448
786
  }).refine((m) => m.text.trim().length > 0 || m.images.length > 0, {
449
787
  message: "message needs text or at least one image"
450
788
  });
451
- var patchRunInputSchema = z4.object({
452
- title: z4.string().trim().min(1).max(300).optional(),
453
- task: z4.string().trim().min(1).max(1e5).optional()
789
+ var patchRunInputSchema = z5.object({
790
+ title: z5.string().trim().min(1).max(300).optional(),
791
+ task: z5.string().trim().min(1).max(1e5).optional()
454
792
  });
455
793
 
456
794
  // ../contract/src/repo.ts
457
- import { z as z5 } from "zod";
458
- var statusEntrySchema = z5.object({
459
- status: z5.string(),
460
- path: z5.string()
795
+ import { z as z6 } from "zod";
796
+ var statusEntrySchema = z6.object({
797
+ status: z6.string(),
798
+ path: z6.string()
461
799
  });
462
- var logEntrySchema = z5.object({
463
- hash: z5.string(),
464
- subject: z5.string(),
465
- author: z5.string(),
466
- when: z5.string()
800
+ var logEntrySchema = z6.object({
801
+ hash: z6.string(),
802
+ subject: z6.string(),
803
+ author: z6.string(),
804
+ when: z6.string()
467
805
  });
468
- var repoResponseSchema = z5.union([
469
- z5.object({
470
- info: z5.null(),
471
- status: z5.array(z5.never()),
472
- log: z5.array(z5.never()),
473
- branches: z5.array(z5.never()),
474
- baseBranch: z5.null()
806
+ var repoResponseSchema = z6.union([
807
+ z6.object({
808
+ info: z6.null(),
809
+ status: z6.array(z6.never()),
810
+ log: z6.array(z6.never()),
811
+ branches: z6.array(z6.never()),
812
+ baseBranch: z6.null()
475
813
  }),
476
- z5.object({
814
+ z6.object({
477
815
  info: repoInfoSchema,
478
- status: z5.array(statusEntrySchema),
479
- log: z5.array(logEntrySchema),
480
- branches: z5.array(z5.string()),
481
- baseBranch: z5.string().nullable()
816
+ status: z6.array(statusEntrySchema),
817
+ log: z6.array(logEntrySchema),
818
+ branches: z6.array(z6.string()),
819
+ baseBranch: z6.string().nullable()
482
820
  })
483
821
  ]);
484
- var repoBranchResponseSchema = z5.object({
485
- branch: z5.string(),
486
- created: z5.boolean()
822
+ var repoBranchResponseSchema = z6.object({
823
+ branch: z6.string(),
824
+ created: z6.boolean()
487
825
  });
488
- var diffStatSchema2 = z5.object({
489
- adds: z5.number(),
490
- dels: z5.number(),
491
- files: z5.number()
826
+ var diffStatSchema2 = z6.object({
827
+ adds: z6.number(),
828
+ dels: z6.number(),
829
+ files: z6.number()
492
830
  });
493
- var changedFileSchema = z5.object({
494
- path: z5.string(),
831
+ var changedFileSchema = z6.object({
832
+ path: z6.string(),
495
833
  /** Rename/copy source — present only when `status` is renamed/copied. */
496
- oldPath: z5.string().optional(),
497
- status: z5.enum(["added", "modified", "deleted", "renamed", "copied"]),
498
- adds: z5.number(),
499
- dels: z5.number(),
834
+ oldPath: z6.string().optional(),
835
+ status: z6.enum(["added", "modified", "deleted", "renamed", "copied"]),
836
+ adds: z6.number(),
837
+ dels: z6.number(),
500
838
  /** Binary per numstat — there is no text patch to render. */
501
- binary: z5.boolean(),
839
+ binary: z6.boolean(),
502
840
  /** True when the path is one the raw-bytes route serves as an `<img>` (#365) — present only
503
841
  * when true, so old clients that never read it stay correct. */
504
- image: z5.boolean().optional(),
842
+ image: z6.boolean().optional(),
505
843
  /** This file's unified-diff section; possibly `… (patch truncated)`, possibly empty. */
506
- patch: z5.string()
844
+ patch: z6.string()
507
845
  });
508
- var changesPayloadSchema = z5.object({
509
- files: z5.array(changedFileSchema),
846
+ var changesPayloadSchema = z6.object({
847
+ files: z6.array(changedFileSchema),
510
848
  stat: diffStatSchema2,
511
849
  /** Additive context for review tasks whose worktree HEAD no longer matches their own branch. */
512
- repointedHead: z5.object({ headBranch: z5.string(), taskBranch: z5.string() }).optional()
850
+ repointedHead: z6.object({ headBranch: z6.string(), taskBranch: z6.string() }).optional()
513
851
  });
514
- var repoCommitPayloadSchema = z5.object({
515
- sha: z5.string(),
516
- subject: z5.string(),
517
- author: z5.string(),
852
+ var repoCommitPayloadSchema = z6.object({
853
+ sha: z6.string(),
854
+ subject: z6.string(),
855
+ author: z6.string(),
518
856
  /** Relative time ("3 hours ago") — same `%cr` format as the /api/v1/repo log. */
519
- when: z5.string(),
520
- files: z5.array(changedFileSchema),
857
+ when: z6.string(),
858
+ files: z6.array(changedFileSchema),
521
859
  stat: diffStatSchema2
522
860
  });
523
- var worktreeDirEntrySchema = z5.object({
524
- name: z5.string(),
525
- type: z5.enum(["dir", "file"]),
526
- size: z5.number().optional()
861
+ var worktreeDirEntrySchema = z6.object({
862
+ name: z6.string(),
863
+ type: z6.enum(["dir", "file"]),
864
+ size: z6.number().optional()
527
865
  });
528
- var worktreeEntrySchema = z5.discriminatedUnion("type", [
529
- z5.object({
530
- type: z5.literal("dir"),
531
- path: z5.string(),
532
- entries: z5.array(worktreeDirEntrySchema)
866
+ var worktreeEntrySchema = z6.discriminatedUnion("type", [
867
+ z6.object({
868
+ type: z6.literal("dir"),
869
+ path: z6.string(),
870
+ entries: z6.array(worktreeDirEntrySchema)
533
871
  }),
534
- z5.object({
535
- type: z5.literal("file"),
536
- path: z5.string(),
537
- size: z5.number(),
538
- binary: z5.boolean(),
539
- tooLarge: z5.boolean(),
540
- content: z5.string().optional()
872
+ z6.object({
873
+ type: z6.literal("file"),
874
+ path: z6.string(),
875
+ size: z6.number(),
876
+ binary: z6.boolean(),
877
+ tooLarge: z6.boolean(),
878
+ content: z6.string().optional()
541
879
  })
542
880
  ]);
543
- var worktreeRunStatusSchema = z5.enum([
881
+ var worktreeRunStatusSchema = z6.enum([
544
882
  "queued",
545
883
  "running",
546
884
  "waiting",
@@ -549,185 +887,23 @@ var worktreeRunStatusSchema = z5.enum([
549
887
  "failed",
550
888
  "cancelled"
551
889
  ]);
552
- var worktreeInfoSchema = z5.object({
553
- runId: z5.string(),
554
- title: z5.string(),
555
- status: worktreeRunStatusSchema,
556
- branch: z5.string().nullable(),
557
- sizeBytes: z5.number().nullable(),
558
- finishedAt: z5.string().nullable(),
559
- reclaimable: z5.boolean()
560
- });
561
- var worktreesResponseSchema = z5.object({
562
- worktrees: z5.array(worktreeInfoSchema),
563
- totalBytes: z5.number().nullable(),
564
- keep: z5.number()
565
- });
566
- var reclaimWorktreesResponseSchema = z5.object({
567
- reclaimed: z5.array(z5.string())
568
- });
569
-
570
- // ../contract/src/github.ts
571
- import { z as z6 } from "zod";
572
- var checksGlyphSchema = z6.enum(["passing", "failing", "pending"]).nullable();
573
- var githubItemSchema = z6.object({
574
- kind: z6.enum(["issue", "pr"]),
575
- number: z6.number(),
890
+ var worktreeInfoSchema = z6.object({
891
+ runId: z6.string(),
576
892
  title: z6.string(),
577
- author: z6.string(),
578
- createdAt: z6.string(),
579
- labels: z6.array(z6.string()),
580
- body: z6.string(),
581
- url: z6.string(),
582
- comments: z6.number(),
583
- /** PRs only. */
584
- isDraft: z6.boolean().optional(),
585
- additions: z6.number().optional(),
586
- deletions: z6.number().optional(),
587
- checks: checksGlyphSchema.optional()
588
- });
589
- var githubDataSchema = z6.object({
590
- available: z6.boolean(),
591
- /** Why it is unavailable (`gh` missing, no remote, offline…). Never an error — a hint. */
592
- reason: z6.string().optional(),
593
- /** owner/name, when known. */
594
- repo: z6.string().optional(),
595
- syncedAt: z6.string().optional(),
596
- issues: z6.array(githubItemSchema),
597
- prs: z6.array(githubItemSchema),
598
- /** Repo-wide label name → 6-hex color (no `#`); lets chips tint like GitHub. Additive. */
599
- labelColors: z6.record(z6.string(), z6.string()).optional()
600
- });
601
- var githubChecksDataSchema = z6.discriminatedUnion("available", [
602
- z6.object({
603
- available: z6.literal(true),
604
- checks: z6.record(z6.number(), checksGlyphSchema)
605
- }),
606
- z6.object({
607
- available: z6.literal(false),
608
- reason: z6.string()
609
- })
610
- ]);
611
- var githubCommentSchema = z6.object({
612
- id: z6.number(),
613
- /** Author login, `'?'` fallback when gh omits the user. */
614
- author: z6.string(),
615
- avatarUrl: z6.string().optional(),
616
- createdAt: z6.string(),
617
- body: z6.string(),
618
- kind: z6.enum(["comment", "review"]),
619
- /** Reviews only — drives the state chip. */
620
- reviewState: z6.enum(["approved", "changes_requested", "commented", "dismissed"]).optional(),
621
- url: z6.string()
622
- });
623
- var githubTimelineEventKindSchema = z6.enum([
624
- "committed",
625
- "labeled",
626
- "unlabeled",
627
- "assigned",
628
- "unassigned",
629
- "merged",
630
- "closed",
631
- "reopened",
632
- "head_ref_force_pushed",
633
- "cross-referenced",
634
- "renamed"
635
- ]);
636
- var githubTimelineEventSchema = z6.object({
637
- id: z6.string(),
638
- kind: githubTimelineEventKindSchema,
639
- /** Login — or the git author name for `committed`, which carries no GitHub actor. */
640
- actor: z6.string(),
641
- /** Absent for `committed`. */
642
- avatarUrl: z6.string().optional(),
643
- createdAt: z6.string(),
644
- url: z6.string().optional(),
645
- /** `committed` — full 40-char SHA. */
646
- sha: z6.string().optional(),
647
- /** `committed` — first line, capped at 120 chars. */
648
- message: z6.string().optional(),
649
- /** `committed` — **absent** (lookup failed/skipped) and **`null`** (no CI configured) both
650
- * render no glyph, but stay distinct values. */
651
- checks: checksGlyphSchema.optional(),
652
- label: z6.object({ name: z6.string(), color: z6.string().optional() }).optional(),
653
- /** `assigned`/`unassigned` login, or the new title for `renamed`. */
654
- subject: z6.string().optional(),
655
- refNumber: z6.number().optional(),
656
- refTitle: z6.string().optional(),
657
- refIsPr: z6.boolean().optional()
658
- });
659
- var githubCommentsDataSchema = z6.object({
660
- available: z6.boolean(),
661
- reason: z6.string().optional(),
662
- /** Chronological, oldest first. */
663
- comments: z6.array(githubCommentSchema),
664
- /** True when either stream hit its cap, or the timeline fetch stopped short. */
665
- truncated: z6.boolean().optional(),
666
- /** Timeline events (#525) — additive; absent when the server degraded to the legacy
667
- * comments-only fetch. Capped independently of `comments`. */
668
- events: z6.array(githubTimelineEventSchema).optional()
893
+ status: worktreeRunStatusSchema,
894
+ branch: z6.string().nullable(),
895
+ sizeBytes: z6.number().nullable(),
896
+ finishedAt: z6.string().nullable(),
897
+ reclaimable: z6.boolean()
669
898
  });
670
- var githubMergeMethodSchema = z6.enum(["merge", "squash", "rebase"]);
671
- var githubPrCheckSchema = z6.object({
672
- name: z6.string(),
673
- state: z6.enum(["passing", "failing", "pending", "unknown"]),
674
- required: z6.boolean().nullable(),
675
- url: z6.string().optional()
899
+ var worktreesResponseSchema = z6.object({
900
+ worktrees: z6.array(worktreeInfoSchema),
901
+ totalBytes: z6.number().nullable(),
902
+ keep: z6.number()
676
903
  });
677
- var githubPrMergeStateSchema = z6.object({
678
- number: z6.number(),
679
- title: z6.string(),
680
- url: z6.string(),
681
- state: z6.enum(["open", "closed", "merged"]),
682
- isDraft: z6.boolean(),
683
- headRef: z6.string(),
684
- baseRef: z6.string(),
685
- headSha: z6.string(),
686
- mergeable: z6.enum(["mergeable", "conflicting", "unknown"]),
687
- reviewDecision: z6.enum(["approved", "changes-requested", "review-required", "unknown"]),
688
- checks: z6.array(githubPrCheckSchema),
689
- methods: z6.array(githubMergeMethodSchema),
690
- defaultMethod: githubMergeMethodSchema.nullable(),
691
- eligibility: z6.enum(["ready", "blocked", "pending", "unauthorized", "terminal", "unknown"]),
692
- blockers: z6.array(z6.object({ code: z6.string(), message: z6.string() })),
693
- canMerge: z6.boolean(),
694
- canOverride: z6.boolean()
695
- });
696
- var githubPrMergeStateResponseSchema = z6.discriminatedUnion("available", [
697
- z6.object({ available: z6.literal(true), mergeState: githubPrMergeStateSchema }),
698
- z6.object({ available: z6.literal(false), reason: z6.string() })
699
- ]);
700
- var githubMergeResponseSchema = z6.object({
701
- merged: z6.literal(true),
702
- number: z6.number(),
703
- url: z6.string(),
704
- method: githubMergeMethodSchema,
705
- mergeCommitSha: z6.string().optional()
904
+ var reclaimWorktreesResponseSchema = z6.object({
905
+ reclaimed: z6.array(z6.string())
706
906
  });
707
- var githubPrChangeSchema = z6.object({
708
- path: z6.string(),
709
- previousPath: z6.string().optional(),
710
- status: z6.enum(["added", "modified", "removed", "renamed", "copied", "changed"]),
711
- additions: z6.number(),
712
- deletions: z6.number(),
713
- patch: z6.string().optional(),
714
- patchUnavailableReason: z6.enum(["binary", "too-large", "not-provided"]).optional(),
715
- truncated: z6.boolean().optional()
716
- });
717
- var githubPrChangesDataSchema = z6.discriminatedUnion("available", [
718
- z6.object({
719
- available: z6.literal(true),
720
- number: z6.number(),
721
- headSha: z6.string(),
722
- files: z6.array(githubPrChangeSchema),
723
- additions: z6.number(),
724
- deletions: z6.number(),
725
- truncated: z6.boolean(),
726
- /** Present when the payload is complete but partial in some other way (a capped patch). */
727
- reason: z6.string().optional()
728
- }),
729
- z6.object({ available: z6.literal(false), reason: z6.string() })
730
- ]);
731
907
 
732
908
  // ../contract/src/projects.ts
733
909
  import { z as z7 } from "zod";
@@ -746,9 +922,31 @@ var projectListEntrySchema = z7.object({
746
922
  /** Which forge this project's remote belongs to (#698) — classified server-side from the
747
923
  * remote URL alone. Gates the project group's GitHub nav item; omitted = no forge remote. */
748
924
  forge: z7.literal("github").optional(),
925
+ /**
926
+ * The remote's web root, `https://github.com/owner/repo`. Rebuilt server-side from the parsed
927
+ * remote rather than passed through, so a remote carrying credentials cannot leak into the
928
+ * cockpit. Omitted when the project has no forge remote.
929
+ *
930
+ * It exists for the cross-project surfaces: a run often knows a PR or issue only by NUMBER, and
931
+ * the global Tasks page has one row per project, so it cannot use any single repo's base the
932
+ * way a project-scoped view can. With this, every reference it shows is a link.
933
+ */
934
+ repoUrl: z7.string().optional(),
749
935
  /** Per-project cap on concurrently running tasks (spec 2026-07-22). Omitted = inherit the
750
936
  * workspace `resources.maxParallel`; a number pins this project. */
751
- maxParallel: z7.number().optional()
937
+ maxParallel: z7.number().optional(),
938
+ /**
939
+ * Free-form labels grouping CONNECTED repositories — a `storefront` tag on the API, the web
940
+ * app and the design system says those three are one piece of work spread over three repos.
941
+ * The global Tasks page (`/tasks`) filters and groups by them.
942
+ *
943
+ * Omitted rather than `[]` when a project has none, exactly like `maxParallel`: the registry
944
+ * stores nothing for a project nobody has tagged, and an empty array on the wire would make
945
+ * "never tagged" indistinguishable from "tagged, then emptied" for no gain. Normalized
946
+ * server-side (trimmed, deduped case-insensitively, sorted), so a consumer may compare them
947
+ * directly.
948
+ */
949
+ tags: z7.array(z7.string()).optional()
752
950
  });
753
951
  var projectsResponseSchema = z7.object({
754
952
  projects: z7.array(projectListEntrySchema),
@@ -766,9 +964,15 @@ var removeProjectResponseSchema = z7.object({
766
964
  var updateProjectResponseSchema = z7.object({
767
965
  project: projectListEntrySchema
768
966
  });
967
+ var PROJECT_TAG_MAX_LENGTH = 32;
968
+ var PROJECT_TAGS_MAX = 20;
769
969
  var updateProjectInputSchema = z7.object({
770
- maxParallel: z7.number().int().min(1).max(16).nullable()
771
- });
970
+ maxParallel: z7.number().int().min(1).max(16).nullable().optional(),
971
+ tags: z7.array(z7.string().trim().min(1).max(PROJECT_TAG_MAX_LENGTH)).max(PROJECT_TAGS_MAX).nullable().optional()
972
+ }).refine(
973
+ (body) => body.maxParallel !== void 0 || body.tags !== void 0,
974
+ "specify maxParallel or tags"
975
+ );
772
976
  var checkoutProjectInputSchema = z7.object({
773
977
  url: z7.string().trim().min(1).max(512),
774
978
  name: z7.string().trim().max(128).optional(),
@@ -817,8 +1021,27 @@ var workspaceConfigResponseSchema = z8.object({
817
1021
  maxParallel: z8.number(),
818
1022
  maxMonitoringSessions: z8.number(),
819
1023
  monitoringWakeIntervalMinutes: z8.number().nullable(),
1024
+ /** Resume a run a provider usage limit stopped, once the limit resets. Default `true`. */
1025
+ autoResumeOnUsageLimit: z8.boolean(),
820
1026
  memoryLimitMb: z8.number().nullable(),
821
1027
  worktreeRetentionDefault: z8.number()
1028
+ }),
1029
+ /**
1030
+ * What a repo that has set none of its own runs (spec 2026-07-29-agent-profiles).
1031
+ *
1032
+ * Both keys are OPTIONAL on the wire, and that is load-bearing rather than lax: absent means
1033
+ * "this machine has no opinion, the built-in default applies", and it has to stay distinguishable
1034
+ * from a value someone chose or the fallback collapses into "always claude". Consulted only where
1035
+ * the repo's own `.ai/cezar/config.json` is silent — a repo that chose is never overruled.
1036
+ */
1037
+ agentDefaults: z8.object({
1038
+ runner: runnerSchema.optional(),
1039
+ models: z8.object({
1040
+ claude: z8.string().optional(),
1041
+ codex: z8.string().optional(),
1042
+ opencode: z8.string().optional(),
1043
+ pi: z8.string().optional()
1044
+ }).optional()
822
1045
  })
823
1046
  });
824
1047
  var setWorkspaceConfigInputSchema = z8.object({
@@ -829,17 +1052,34 @@ var setWorkspaceConfigInputSchema = z8.object({
829
1052
  autonomous: z8.boolean().nullable().optional(),
830
1053
  worktree: z8.boolean().nullable().optional()
831
1054
  }).optional(),
1055
+ /** Machine-wide agent defaults. `null` on a key CLEARS it back to "no opinion", which a bare
1056
+ * absent key cannot say in a partial patch. */
1057
+ agentDefaults: z8.object({
1058
+ runner: runnerSchema.nullable().optional(),
1059
+ models: z8.object({
1060
+ claude: z8.string().trim().min(1).max(200).nullable().optional(),
1061
+ codex: z8.string().trim().min(1).max(200).nullable().optional(),
1062
+ opencode: z8.string().trim().min(1).max(200).nullable().optional(),
1063
+ pi: z8.string().trim().min(1).max(200).nullable().optional()
1064
+ }).optional()
1065
+ }).optional(),
832
1066
  resources: z8.object({
833
1067
  maxParallel: z8.number().int().min(1).max(16).optional(),
834
1068
  maxMonitoringSessions: z8.number().int().min(0).max(16).optional(),
835
1069
  monitoringWakeIntervalMinutes: z8.number().int().min(1).max(60).nullable().optional(),
1070
+ autoResumeOnUsageLimit: z8.boolean().optional(),
836
1071
  memoryLimitMb: z8.number().int().min(0).max(1048576).nullable().optional(),
837
1072
  worktreeRetentionDefault: z8.number().int().min(0).max(1e3).optional()
838
1073
  }).optional()
839
1074
  });
840
1075
  var appearanceSchema = z8.object({
841
1076
  accent: z8.enum(["lime", "violet"]).optional(),
842
- density: z8.enum(["comfortable", "compact", "ultra"]).optional()
1077
+ density: z8.enum(["comfortable", "compact", "ultra"]).optional(),
1078
+ width: z8.enum(["narrow", "wide"]).optional()
1079
+ });
1080
+ var taskTableUiStateSchema = z8.looseObject({
1081
+ /** Explicit user choices only. Missing ids keep the registry-owned default. */
1082
+ expandedColumns: z8.record(z8.string(), z8.boolean()).optional()
843
1083
  });
844
1084
  var uiStateSchema = z8.looseObject({
845
1085
  lastTask: z8.object({ source: z8.enum(["workflow", "skill"]), ref: z8.string() }).optional(),
@@ -881,9 +1121,11 @@ var workspaceLastLocationSchema = z8.strictObject({
881
1121
  hash: z8.string().max(2048).startsWith("#").optional()
882
1122
  });
883
1123
  var workspaceUiStateSchema = z8.looseObject({
884
- /** The sidebar's per-project collapse map (step 3.3) — `true` collapses a group, `false` pins
885
- * it open, absent means the default (the active project expands, the rest collapse). Loose for
886
- * the same round-trip reason as its parent. */
1124
+ /** LEGACY — the sidebar's per-project collapse map (step 3.3). Still accepted and still
1125
+ * round-tripped so an older cockpit sharing this home keeps working, but the current cockpit
1126
+ * neither reads nor writes it: which groups are shut describes the WINDOW, not the workspace,
1127
+ * so it lives in that browser's localStorage (`packages/web/src/lib/sidebar-collapse.ts`).
1128
+ * One shared answer meant a phone collapsing a group collapsed it on the desktop too. */
887
1129
  sidebar: z8.looseObject({ collapsed: z8.record(z8.string(), z8.boolean()).optional() }).optional(),
888
1130
  /** Dismissed runtime-auth incident IDs, keyed by provider. An ID is only dismissed until the
889
1131
  * provider reports a different incident, so this stays workspace-global with the browser
@@ -891,7 +1133,8 @@ var workspaceUiStateSchema = z8.looseObject({
891
1133
  dismissedProviderAuthFailures: z8.object({
892
1134
  claude: z8.string().optional(),
893
1135
  codex: z8.string().optional(),
894
- opencode: z8.string().optional()
1136
+ opencode: z8.string().optional(),
1137
+ pi: z8.string().optional()
895
1138
  }).optional(),
896
1139
  /** Settings → Appearance, GLOBAL since step 3.5: accent + density describe the person at the
897
1140
  * keyboard, not a repo. */
@@ -899,24 +1142,60 @@ var workspaceUiStateSchema = z8.looseObject({
899
1142
  /** Settings → Notifications, GLOBAL since step 3.5 — one answer for the whole workspace, since
900
1143
  * the delivering browser is one browser whichever project you are looking at. */
901
1144
  notifications: z8.looseObject({ enabled: z8.boolean().optional() }).optional(),
902
- /** Last settled project-scoped page. Used only when entering at the exact bare root;
903
- * explicit deep links always win. */
1145
+ /** Desktop Tasks-table density, shared across every project in this workspace. */
1146
+ taskTable: taskTableUiStateSchema.optional(),
1147
+ /** LEGACY, exactly like `sidebar` above — the last settled project-scoped page, restored when
1148
+ * entering at the exact bare root. The shape is unchanged and still accepted, but the current
1149
+ * cockpit keeps it in localStorage (`packages/web/src/lib/last-location.ts`): stored here, the
1150
+ * last client to navigate decided where every OTHER client's next launch landed. */
904
1151
  lastLocation: workspaceLastLocationSchema.optional(),
905
1152
  /** The user's curated selection of default (vendor) skills. Tri-state: ABSENT means "not
906
1153
  * curated", so every default skill shows; a PRESENT array (even `[]`) means only those names
907
1154
  * show from that repo. */
908
1155
  importedSkills: z8.array(z8.string()).optional()
909
1156
  });
1157
+ var WORKSPACE_UI_STATE_MAX_KEYS = 200;
1158
+ var TASK_TABLE_MAX_COLUMNS = 50;
1159
+ var setWorkspaceUiStateInputSchema = z8.looseObject({
1160
+ ...workspaceUiStateSchema.shape,
1161
+ sidebar: z8.looseObject({
1162
+ collapsed: z8.record(z8.string().min(1).max(64), z8.boolean()).refine((map) => Object.keys(map).length <= WORKSPACE_UI_STATE_MAX_KEYS, {
1163
+ message: `sidebar.collapsed must have at most ${WORKSPACE_UI_STATE_MAX_KEYS} entries`
1164
+ }).optional()
1165
+ }).optional(),
1166
+ dismissedProviderAuthFailures: z8.strictObject({
1167
+ claude: z8.string().min(1).max(128).optional(),
1168
+ codex: z8.string().min(1).max(128).optional(),
1169
+ opencode: z8.string().min(1).max(128).optional(),
1170
+ pi: z8.string().min(1).max(128).optional()
1171
+ }).optional(),
1172
+ importedSkills: z8.array(z8.string().min(1).max(200)).max(WORKSPACE_UI_STATE_MAX_KEYS).optional(),
1173
+ taskTable: taskTableUiStateSchema.extend({
1174
+ expandedColumns: z8.record(z8.string().min(1).max(64), z8.boolean()).refine((map) => Object.keys(map).length <= TASK_TABLE_MAX_COLUMNS, {
1175
+ message: `taskTable.expandedColumns must have at most ${TASK_TABLE_MAX_COLUMNS} entries`
1176
+ }).optional()
1177
+ }).optional()
1178
+ }).superRefine((data, ctx) => {
1179
+ if (Object.keys(data).length > WORKSPACE_UI_STATE_MAX_KEYS) {
1180
+ ctx.addIssue({
1181
+ code: "custom",
1182
+ message: `ui-state has too many keys (max ${WORKSPACE_UI_STATE_MAX_KEYS})`
1183
+ });
1184
+ }
1185
+ });
910
1186
  var runnerModelsSchema = z8.object({
911
1187
  claude: z8.string().optional(),
912
1188
  codex: z8.string().optional(),
913
- opencode: z8.string().optional()
1189
+ opencode: z8.string().optional(),
1190
+ pi: z8.string().optional()
914
1191
  });
915
1192
  var configResponseSchema = z8.object({
916
1193
  baseBranch: z8.string().nullable(),
917
1194
  defaultRunner: runnerSchema,
918
1195
  systemPrompt: z8.string().nullable(),
919
1196
  defaultModels: runnerModelsSchema,
1197
+ /** True when native coding-agent settings are authoritative and model picks are read-only. */
1198
+ modelsLocked: z8.boolean(),
920
1199
  /** How many tasks run at once (1–16). */
921
1200
  maxParallel: z8.number(),
922
1201
  /** Per-task memory ceiling in MiB (whole process tree); null = no limit. */
@@ -938,7 +1217,8 @@ var setConfigInputSchema = z8.object({
938
1217
  defaultModels: z8.object({
939
1218
  claude: z8.string().trim().max(200).nullable().optional(),
940
1219
  codex: z8.string().trim().max(200).nullable().optional(),
941
- opencode: z8.string().trim().max(200).nullable().optional()
1220
+ opencode: z8.string().trim().max(200).nullable().optional(),
1221
+ pi: z8.string().trim().max(200).nullable().optional()
942
1222
  }).optional(),
943
1223
  maxParallel: z8.number().int().min(1).max(16).optional(),
944
1224
  /** null or 0 clears the ceiling back to "no limit". */
@@ -990,7 +1270,12 @@ var providerStatusSchema = z8.object({
990
1270
  status: providerConnectionStateSchema,
991
1271
  enabled: z8.boolean().optional(),
992
1272
  hint: z8.string().optional(),
993
- authFailureId: z8.string().optional()
1273
+ authFailureId: z8.string().optional(),
1274
+ /** Which agent account this row describes (spec 2026-07-29-agent-profiles). ABSENT on
1275
+ * `GET /api/v1/providers/status`, which deliberately keeps answering exactly one row per
1276
+ * provider — the discovered default — so an older client sees no change at all. Per-account
1277
+ * rows are carried by `GET /api/v1/workspace/agent-profiles` instead. */
1278
+ profileId: z8.string().optional()
994
1279
  });
995
1280
  var providerStatusResponseSchema = z8.object({
996
1281
  providers: z8.array(providerStatusSchema)
@@ -999,6 +1284,11 @@ var providerConnectResponseSchema = z8.discriminatedUnion("opened", [
999
1284
  z8.object({ opened: z8.literal(true), command: z8.string() }),
1000
1285
  z8.object({ opened: z8.literal(false), connected: z8.literal(true), command: z8.string() })
1001
1286
  ]);
1287
+ var modelDiscoveryRunnerSchema = z8.enum(["codex", "opencode"]);
1288
+ var MODEL_DISCOVERY_RUNNERS = modelDiscoveryRunnerSchema.options;
1289
+ function runnerDiscoversModels(runner) {
1290
+ return MODEL_DISCOVERY_RUNNERS.includes(runner);
1291
+ }
1002
1292
  var runnerModelOptionSchema = z8.object({
1003
1293
  id: z8.string(),
1004
1294
  label: z8.string(),
@@ -1021,6 +1311,14 @@ var openTargetSchema = z8.object({
1021
1311
  var openTargetsResponseSchema = z8.object({
1022
1312
  targets: z8.array(openTargetSchema)
1023
1313
  });
1314
+ var openProjectInSchema = z8.object({
1315
+ // A short bound (#429): matched against a downstream allowlist, so an app id is never long.
1316
+ target: z8.string().trim().min(1, "target required").max(200)
1317
+ });
1318
+ var openProjectInResponseSchema = z8.object({
1319
+ opened: z8.literal(true),
1320
+ path: z8.string()
1321
+ });
1024
1322
 
1025
1323
  // ../contract/src/skills.ts
1026
1324
  import { z as z9 } from "zod";
@@ -1131,69 +1429,182 @@ var setAgentConfigInputSchema = z10.object({
1131
1429
  version: z10.string().nullable()
1132
1430
  });
1133
1431
 
1134
- // ../contract/src/automations.ts
1432
+ // ../contract/src/agent-profiles.ts
1135
1433
  import { z as z11 } from "zod";
1136
- var automationEventSchema = z11.enum([
1434
+ var DEFAULT_AGENT_ACCOUNT_ID = "default";
1435
+ var agentAccountFileSchema = z11.object({
1436
+ id: z11.string(),
1437
+ /** e.g. `settings.json` — the file's own name, since the folder is shown once on the account. */
1438
+ label: z11.string(),
1439
+ /** Absolute, resolved inside this account's config folder. */
1440
+ path: z11.string(),
1441
+ exists: z11.boolean()
1442
+ });
1443
+ var agentProfileSchema = z11.object({
1444
+ /** `default` for the discovered profile, else the stored slug. */
1445
+ id: z11.string(),
1446
+ provider: providerIdSchema,
1447
+ label: z11.string(),
1448
+ /** As the user wrote it — a literal `~` is preserved, matching `browseRoot`/`projectsDir`. */
1449
+ configDir: z11.string(),
1450
+ /** Expanded absolute path. Same-origin route, like `ProjectListEntry.root`. */
1451
+ path: z11.string(),
1452
+ /** False for a dir the CLI has not created yet — legitimate, and NOT a reason to fall back
1453
+ * to another account at run time (that would silently bill the wrong subscription). */
1454
+ exists: z11.boolean(),
1455
+ /** Whether the dir carries this agent's own marker files. ADVISORY: an unrecognised dir is
1456
+ * still accepted, because "add profile → Connect → the CLI creates it" is the real flow. */
1457
+ looksValid: z11.boolean(),
1458
+ /** True for the profile cezar discovers from the environment. Never stored, never deletable. */
1459
+ isDefault: z11.boolean(),
1460
+ /** This account's own authentication state — two Claude logins answer independently.
1461
+ *
1462
+ * **Absent until the probe has warmed.** Every probe shells out to an agent CLI, and this
1463
+ * listing refuses to pay that (it would be one spawn per provider plus one per account, on
1464
+ * every cold load); it serves only what is already cached, exactly as `GET /api/v1/health`
1465
+ * serves a cached forge answer. Absent means "not determined yet" — NOT `unknown`, which is a
1466
+ * real probe result — and the cockpit fills it in from `…/:id/status`. */
1467
+ status: providerStatusSchema.optional(),
1468
+ /** This agent's own user-scope config files, resolved inside THIS account's folder — so a
1469
+ * second login's `settings.json` is the one you open, not the default account's. */
1470
+ files: z11.array(agentAccountFileSchema)
1471
+ });
1472
+ function agentAccountRouteId(profile) {
1473
+ return profile.isDefault ? `default:${profile.provider}` : profile.id;
1474
+ }
1475
+ var agentAccountSelectionSchema = z11.object({
1476
+ claude: z11.string().optional(),
1477
+ codex: z11.string().optional(),
1478
+ opencode: z11.string().optional(),
1479
+ pi: z11.string().optional()
1480
+ });
1481
+ var agentProfilesResponseSchema = z11.object({
1482
+ editable: z11.boolean(),
1483
+ profiles: z11.array(agentProfileSchema),
1484
+ /** Providers that can carry more than one account at all — what "Add account" is offered for.
1485
+ * OpenCode is absent: its credentials live in a SQLite DB behind a separate `OPENCODE_DB`, so
1486
+ * a config-dir profile would swap settings while still billing the other account. */
1487
+ profileCapableProviders: z11.array(providerIdSchema),
1488
+ /** Which account each project uses, keyed by the project's realpath'd ROOT.
1489
+ *
1490
+ * Served here rather than on `GET /api/v1/projects` because it is stored beside the accounts it
1491
+ * names (`~/.cezar/agent-accounts.json`) — one file, so deleting an account and scrubbing every
1492
+ * reference to it is one atomic write, and neither can be dropped by a cezar version that never
1493
+ * heard of accounts. Empty in hosted mode, where the whole family is withheld. */
1494
+ selections: z11.record(z11.string(), agentAccountSelectionSchema),
1495
+ /** The machine-wide fallback account per provider, used by any repo that has chosen none. */
1496
+ defaults: agentAccountSelectionSchema
1497
+ });
1498
+ var selectAgentProfileInputSchema = z11.object({
1499
+ /**
1500
+ * Registry slug, or the reserved `default` boot alias. Resolved to a root server-side.
1501
+ *
1502
+ * `null` targets the MACHINE-WIDE default instead of one repo — the account a repo that has
1503
+ * chosen nothing uses, so a second login is set up once rather than per checkout. A repo's own
1504
+ * choice always wins over it, which is what keeps this a default and not an override.
1505
+ */
1506
+ projectId: z11.string().min(1).max(64).nullable(),
1507
+ provider: providerIdSchema,
1508
+ profileId: z11.string().max(64).nullable()
1509
+ });
1510
+ var agentProfileSelectionsResponseSchema = z11.object({
1511
+ selections: z11.record(z11.string(), agentAccountSelectionSchema),
1512
+ /** The machine-wide fallback, for repos with no selection of their own. */
1513
+ defaults: agentAccountSelectionSchema
1514
+ });
1515
+ var agentAccountStatusResponseSchema = z11.object({ status: providerStatusSchema });
1516
+ var agentAccountDetailsResponseSchema = z11.object({
1517
+ available: z11.boolean(),
1518
+ reason: z11.string().optional(),
1519
+ fields: z11.array(z11.object({ label: z11.string(), value: z11.string() }))
1520
+ });
1521
+ var openAgentAccountFileInputSchema = z11.object({
1522
+ file: z11.string().min(1).max(200),
1523
+ target: z11.string().min(1).max(64).optional()
1524
+ });
1525
+ var openAgentAccountFileResponseSchema = z11.object({
1526
+ opened: z11.literal(true),
1527
+ path: z11.string()
1528
+ });
1529
+ var createAgentProfileInputSchema = z11.object({
1530
+ provider: providerIdSchema,
1531
+ label: z11.string().trim().max(200).optional(),
1532
+ /** Stored as written; validated absolute after `~` expansion, server-side. */
1533
+ configDir: z11.string().trim().min(1).max(4096)
1534
+ });
1535
+ var agentProfileResponseSchema = z11.object({ profile: agentProfileSchema });
1536
+ var updateAgentProfileInputSchema = z11.object({
1537
+ label: z11.string().trim().max(200).optional(),
1538
+ configDir: z11.string().trim().min(1).max(4096).optional()
1539
+ });
1540
+ var removeAgentProfileResponseSchema = z11.object({
1541
+ removed: z11.literal(true),
1542
+ id: z11.string()
1543
+ });
1544
+
1545
+ // ../contract/src/automations.ts
1546
+ import { z as z12 } from "zod";
1547
+ var automationEventSchema = z12.enum([
1137
1548
  "pull_request.opened",
1138
1549
  "issue.opened",
1139
1550
  "issue.labeled",
1140
1551
  "issue.unlabeled"
1141
1552
  ]);
1142
- var automationFiltersSchema = z11.object({
1143
- authors: z11.array(z11.string()).optional(),
1144
- assignees: z11.array(z11.string()).optional(),
1145
- allLabels: z11.array(z11.string()).optional(),
1146
- anyLabels: z11.array(z11.string()).optional(),
1147
- excludeLabels: z11.array(z11.string()).optional(),
1553
+ var automationFiltersSchema = z12.object({
1554
+ authors: z12.array(z12.string()).optional(),
1555
+ assignees: z12.array(z12.string()).optional(),
1556
+ allLabels: z12.array(z12.string()).optional(),
1557
+ anyLabels: z12.array(z12.string()).optional(),
1558
+ excludeLabels: z12.array(z12.string()).optional(),
1148
1559
  /** Required for the two label events — the server rejects a definition without it. */
1149
- changedLabels: z11.array(z11.string()).optional(),
1150
- lookbackDays: z11.number(),
1151
- maxRecords: z11.number()
1560
+ changedLabels: z12.array(z12.string()).optional(),
1561
+ lookbackDays: z12.number(),
1562
+ maxRecords: z12.number()
1152
1563
  });
1153
1564
  var automationTaskSchema = createRunInputBaseSchema.omit({ task: true, images: true, todoId: true, systemPrompt: true }).extend({
1154
1565
  /** The prompt template. `{{github.number}}`, `{{github.title}}`, `{{github.url}}` and
1155
1566
  * `{{github.labels}}` are substituted per match; GitHub content is appended as untrusted
1156
1567
  * context, never interpolated into instructions. */
1157
- prompt: z11.string(),
1158
- variants: z11.union([z11.literal(1), z11.literal(2), z11.literal(3)]).optional(),
1159
- systemPrompt: z11.string().optional()
1568
+ prompt: z12.string(),
1569
+ variants: z12.union([z12.literal(1), z12.literal(2), z12.literal(3)]).optional(),
1570
+ systemPrompt: z12.string().optional()
1160
1571
  });
1161
- var automationDefinitionSchema = z11.object({
1162
- id: z11.string(),
1572
+ var automationDefinitionSchema = z12.object({
1573
+ id: z12.string(),
1163
1574
  /** Bumped on every edit; a PUT must echo the revision it read (optimistic concurrency). */
1164
- revision: z11.number(),
1165
- name: z11.string(),
1166
- description: z11.string().optional(),
1575
+ revision: z12.number(),
1576
+ name: z12.string(),
1577
+ description: z12.string().optional(),
1167
1578
  /** Always present: the storage schema defaults it to `false`, so a definition is created
1168
1579
  * PAUSED and enabling it is a separate, baseline-establishing act. */
1169
- enabled: z11.boolean(),
1170
- events: z11.array(automationEventSchema),
1171
- intervalSeconds: z11.number(),
1580
+ enabled: z12.boolean(),
1581
+ events: z12.array(automationEventSchema),
1582
+ intervalSeconds: z12.number(),
1172
1583
  filters: automationFiltersSchema,
1173
1584
  task: automationTaskSchema,
1174
- createdAt: z11.string(),
1175
- updatedAt: z11.string()
1585
+ createdAt: z12.string(),
1586
+ updatedAt: z12.string()
1176
1587
  });
1177
- var automationCursorSchema = z11.object({
1178
- timestamp: z11.string(),
1179
- tieBreaker: z11.string().optional()
1588
+ var automationCursorSchema = z12.object({
1589
+ timestamp: z12.string(),
1590
+ tieBreaker: z12.string().optional()
1180
1591
  });
1181
- var automationRuntimeStateSchema = z11.object({
1592
+ var automationRuntimeStateSchema = z12.object({
1182
1593
  /** The definition revision this state belongs to; a bumped revision re-baselines. */
1183
- revision: z11.number().optional(),
1594
+ revision: z12.number().optional(),
1184
1595
  /** Enabling establishes a CURRENT-TIME baseline: records older than this never launch. */
1185
- baselineAt: z11.string().optional(),
1596
+ baselineAt: z12.string().optional(),
1186
1597
  cursor: automationCursorSchema.optional(),
1187
- frozenHighWatermark: automationCursorSchema.extend({ tieBreaker: z11.string() }).optional(),
1188
- backlogAfter: automationCursorSchema.extend({ tieBreaker: z11.string() }).optional(),
1189
- nextCheckAt: z11.string().optional(),
1190
- lastSuccessAt: z11.string().optional(),
1598
+ frozenHighWatermark: automationCursorSchema.extend({ tieBreaker: z12.string() }).optional(),
1599
+ backlogAfter: automationCursorSchema.extend({ tieBreaker: z12.string() }).optional(),
1600
+ nextCheckAt: z12.string().optional(),
1601
+ lastSuccessAt: z12.string().optional(),
1191
1602
  /** Per-query GitHub ETags, so an unchanged page costs no rate-limit budget. */
1192
- etags: z11.record(z11.string(), z11.string()).optional(),
1193
- backoffUntil: z11.string().optional(),
1194
- consecutiveFailures: z11.number().optional()
1603
+ etags: z12.record(z12.string(), z12.string()).optional(),
1604
+ backoffUntil: z12.string().optional(),
1605
+ consecutiveFailures: z12.number().optional()
1195
1606
  });
1196
- var automationLogResultSchema = z11.enum([
1607
+ var automationLogResultSchema = z12.enum([
1197
1608
  "launched",
1198
1609
  "no-match",
1199
1610
  "duplicate",
@@ -1202,80 +1613,91 @@ var automationLogResultSchema = z11.enum([
1202
1613
  "baseline",
1203
1614
  "preview"
1204
1615
  ]);
1205
- var automationLogRecordSchema = z11.object({
1206
- seq: z11.number(),
1207
- ts: z11.string(),
1208
- automationId: z11.string(),
1209
- revision: z11.number(),
1616
+ var automationLogRecordSchema = z12.object({
1617
+ seq: z12.number(),
1618
+ ts: z12.string(),
1619
+ automationId: z12.string(),
1620
+ revision: z12.number(),
1210
1621
  event: automationEventSchema.optional(),
1211
1622
  result: automationLogResultSchema,
1212
- reason: z11.string().optional(),
1213
- durationMs: z11.number().optional(),
1214
- receiptId: z11.string().optional(),
1215
- runId: z11.string().optional(),
1216
- githubNumber: z11.number().optional(),
1217
- githubTitle: z11.string().optional(),
1218
- githubUrl: z11.string().optional(),
1219
- rateLimit: z11.object({
1220
- bucket: z11.enum(["core", "search"]),
1221
- remaining: z11.number().optional(),
1222
- resetAt: z11.string().optional()
1623
+ reason: z12.string().optional(),
1624
+ durationMs: z12.number().optional(),
1625
+ receiptId: z12.string().optional(),
1626
+ runId: z12.string().optional(),
1627
+ githubNumber: z12.number().optional(),
1628
+ githubTitle: z12.string().optional(),
1629
+ githubUrl: z12.string().optional(),
1630
+ rateLimit: z12.object({
1631
+ bucket: z12.enum(["core", "search"]),
1632
+ remaining: z12.number().optional(),
1633
+ resetAt: z12.string().optional()
1223
1634
  }).optional()
1224
1635
  });
1225
- var automationCountsSchema = z11.object({
1226
- matches: z11.number(),
1227
- launched: z11.number(),
1228
- duplicates: z11.number(),
1229
- errors: z11.number()
1636
+ var automationCountsSchema = z12.object({
1637
+ matches: z12.number(),
1638
+ launched: z12.number(),
1639
+ duplicates: z12.number(),
1640
+ errors: z12.number()
1230
1641
  });
1231
1642
  var automationListEntrySchema = automationDefinitionSchema.extend({
1232
1643
  state: automationRuntimeStateSchema.optional(),
1233
1644
  latestLog: automationLogRecordSchema.optional(),
1234
1645
  counts: automationCountsSchema
1235
1646
  });
1236
- var automationsResponseSchema = z11.object({
1237
- available: z11.boolean(),
1238
- reason: z11.string().optional(),
1239
- scheduler: z11.object({
1240
- state: z11.enum(["scheduled", "idle"]),
1241
- nextDue: z11.string().optional()
1647
+ var automationsResponseSchema = z12.object({
1648
+ available: z12.boolean(),
1649
+ reason: z12.string().optional(),
1650
+ scheduler: z12.object({
1651
+ state: z12.enum(["scheduled", "idle"]),
1652
+ nextDue: z12.string().optional()
1242
1653
  }),
1243
- automations: z11.array(automationListEntrySchema)
1654
+ automations: z12.array(automationListEntrySchema)
1244
1655
  });
1245
- var automationResponseSchema = z11.object({ automation: automationDefinitionSchema });
1246
- var automationDetailResponseSchema = z11.object({
1656
+ var automationResponseSchema = z12.object({ automation: automationDefinitionSchema });
1657
+ var automationDetailResponseSchema = z12.object({
1247
1658
  automation: automationDefinitionSchema,
1248
1659
  state: automationRuntimeStateSchema.optional(),
1249
1660
  latestLog: automationLogRecordSchema.optional()
1250
1661
  });
1251
- var automationCheckSchema = z11.object({
1252
- id: z11.string(),
1253
- automationId: z11.string(),
1254
- mode: z11.enum(["preview", "execute"]),
1255
- status: z11.enum(["queued", "running", "complete", "error"]),
1256
- createdAt: z11.string(),
1257
- completedAt: z11.string().optional(),
1258
- matches: z11.number().optional(),
1259
- truncated: z11.boolean().optional(),
1260
- error: z11.string().optional()
1261
- });
1262
- var automationCheckQueuedResponseSchema = z11.object({ checkId: z11.string() });
1263
- var automationLogResponseSchema = z11.object({
1264
- records: z11.array(automationLogRecordSchema)
1265
- });
1266
- var automationRetryResponseSchema = z11.object({
1267
- receiptId: z11.string(),
1268
- runId: z11.string()
1269
- });
1270
- var createAutomationInputSchema = automationDefinitionSchema.omit({ id: true, revision: true, createdAt: true, updatedAt: true, enabled: true }).extend({ enable: z11.boolean().optional() });
1662
+ var automationCheckSchema = z12.object({
1663
+ id: z12.string(),
1664
+ automationId: z12.string(),
1665
+ mode: z12.enum(["preview", "execute"]),
1666
+ status: z12.enum(["queued", "running", "complete", "error"]),
1667
+ createdAt: z12.string(),
1668
+ completedAt: z12.string().optional(),
1669
+ matches: z12.number().optional(),
1670
+ truncated: z12.boolean().optional(),
1671
+ error: z12.string().optional()
1672
+ });
1673
+ var automationCheckQueuedResponseSchema = z12.object({ checkId: z12.string() });
1674
+ var automationLogResponseSchema = z12.object({
1675
+ records: z12.array(automationLogRecordSchema)
1676
+ });
1677
+ var automationRetryResponseSchema = z12.object({
1678
+ receiptId: z12.string(),
1679
+ runId: z12.string()
1680
+ });
1681
+ var createAutomationInputSchema = automationDefinitionSchema.omit({ id: true, revision: true, createdAt: true, updatedAt: true, enabled: true }).extend({ enable: z12.boolean().optional() });
1271
1682
  var updateAutomationInputSchema = createAutomationInputSchema.omit({ enable: true }).extend({
1272
- enabled: z11.boolean().optional(),
1273
- expectedRevision: z11.number()
1683
+ enabled: z12.boolean().optional(),
1684
+ expectedRevision: z12.number()
1274
1685
  });
1275
- var automationCheckInputSchema = z11.object({
1276
- mode: z11.enum(["preview", "execute"])
1686
+ var automationCheckInputSchema = z12.object({
1687
+ mode: z12.enum(["preview", "execute"])
1277
1688
  });
1278
1689
  export {
1690
+ DEFAULT_AGENT_ACCOUNT_ID,
1691
+ MODEL_DISCOVERY_RUNNERS,
1692
+ PROJECT_TAGS_MAX,
1693
+ PROJECT_TAG_MAX_LENGTH,
1694
+ REFERENCE_STATUS_MAX,
1695
+ RUN_HISTORY_PAGE_ITEMS,
1696
+ agentAccountDetailsResponseSchema,
1697
+ agentAccountFileSchema,
1698
+ agentAccountRouteId,
1699
+ agentAccountSelectionSchema,
1700
+ agentAccountStatusResponseSchema,
1279
1701
  agentConfigFileContentSchema,
1280
1702
  agentConfigFileSchema,
1281
1703
  agentConfigFormatSchema,
@@ -1283,6 +1705,10 @@ export {
1283
1705
  agentConfigListingSchema,
1284
1706
  agentConfigScopeSchema,
1285
1707
  agentConfigTrackedSchema,
1708
+ agentProfileResponseSchema,
1709
+ agentProfileSchema,
1710
+ agentProfileSelectionsResponseSchema,
1711
+ agentProfilesResponseSchema,
1286
1712
  apiRunSchema,
1287
1713
  archiveFinishedResponseSchema,
1288
1714
  automationCheckInputSchema,
@@ -1304,6 +1730,7 @@ export {
1304
1730
  automationTaskSchema,
1305
1731
  automationsResponseSchema,
1306
1732
  backendCheckSchema,
1733
+ cancelAutoResumeResponseSchema,
1307
1734
  cancelResponseSchema,
1308
1735
  capabilitiesSchema,
1309
1736
  changedFileSchema,
@@ -1312,6 +1739,7 @@ export {
1312
1739
  checkoutProjectInputSchema,
1313
1740
  configResponseSchema,
1314
1741
  continueResponseSchema,
1742
+ createAgentProfileInputSchema,
1315
1743
  createAutomationInputSchema,
1316
1744
  createPrResponseSchema,
1317
1745
  createRunInputBaseSchema,
@@ -1339,6 +1767,7 @@ export {
1339
1767
  githubPrCheckSchema,
1340
1768
  githubPrMergeStateResponseSchema,
1341
1769
  githubPrMergeStateSchema,
1770
+ githubRefStatusDataSchema,
1342
1771
  githubTimelineEventKindSchema,
1343
1772
  githubTimelineEventSchema,
1344
1773
  groupResponseSchema,
@@ -1351,7 +1780,12 @@ export {
1351
1780
  markAllReadResponseSchema,
1352
1781
  messageInputSchema,
1353
1782
  messageResponseSchema,
1783
+ modelDiscoveryRunnerSchema,
1784
+ openAgentAccountFileInputSchema,
1785
+ openAgentAccountFileResponseSchema,
1354
1786
  openInCliResponseSchema,
1787
+ openProjectInResponseSchema,
1788
+ openProjectInSchema,
1355
1789
  openTargetSchema,
1356
1790
  openTargetsResponseSchema,
1357
1791
  parsedWorkflowSchema,
@@ -1368,7 +1802,10 @@ export {
1368
1802
  providerStatusSchema,
1369
1803
  queuedMessageSchema,
1370
1804
  reclaimWorktreesResponseSchema,
1805
+ referenceStatusSchema,
1806
+ referenceStatusesByProjectSchema,
1371
1807
  registerProjectResponseSchema,
1808
+ removeAgentProfileResponseSchema,
1372
1809
  removeProjectResponseSchema,
1373
1810
  removeQueuedMessageResponseSchema,
1374
1811
  removeTodoResponseSchema,
@@ -1381,18 +1818,30 @@ export {
1381
1818
  runCommitSchema,
1382
1819
  runCommitsResponseSchema,
1383
1820
  runEventSchema,
1821
+ runEventsQuerySchema,
1822
+ runHistoryContextSchema,
1823
+ runHistoryCursorSchema,
1824
+ runHistoryEventSchema,
1825
+ runHistoryPageSchema,
1826
+ runHistoryQuerySchema,
1827
+ runIdParamSchema,
1828
+ runIndexEntrySchema,
1384
1829
  runRecordSchema,
1385
1830
  runStatusSchema,
1831
+ runnerDiscoversModels,
1386
1832
  runnerModelCatalogResponseSchema,
1387
1833
  runnerModelOptionSchema,
1388
1834
  runnerModelsSchema,
1389
1835
  runnerSchema,
1836
+ runsIndexResponseSchema,
1390
1837
  saveWorkflowInputSchema,
1391
1838
  saveWorkflowResponseSchema,
1839
+ selectAgentProfileInputSchema,
1392
1840
  setAgentConfigInputSchema,
1393
1841
  setConfigInputSchema,
1394
1842
  setConfigResponseSchema,
1395
1843
  setWorkspaceConfigInputSchema,
1844
+ setWorkspaceUiStateInputSchema,
1396
1845
  skillSchema,
1397
1846
  skillsUpdateScopeStateSchema,
1398
1847
  skillsUpdateStateSchema,
@@ -1403,6 +1852,7 @@ export {
1403
1852
  stepStatusSchema,
1404
1853
  todoItemSchema,
1405
1854
  uiStateSchema,
1855
+ updateAgentProfileInputSchema,
1406
1856
  updateAutomationInputSchema,
1407
1857
  updateProjectInputSchema,
1408
1858
  updateProjectResponseSchema,