@claudexor/schema 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +16 -0
  3. package/dist/agent-capabilities.d.ts +366 -0
  4. package/dist/agent-capabilities.d.ts.map +1 -0
  5. package/dist/agent-capabilities.js +125 -0
  6. package/dist/agent-capabilities.js.map +1 -0
  7. package/dist/apply-eligibility.d.ts +76 -0
  8. package/dist/apply-eligibility.d.ts.map +1 -0
  9. package/dist/apply-eligibility.js +37 -0
  10. package/dist/apply-eligibility.js.map +1 -0
  11. package/dist/attachment.d.ts +69 -0
  12. package/dist/attachment.d.ts.map +1 -0
  13. package/dist/attachment.js +54 -0
  14. package/dist/attachment.js.map +1 -0
  15. package/dist/budget.d.ts +75 -0
  16. package/dist/budget.d.ts.map +1 -0
  17. package/dist/budget.js +54 -0
  18. package/dist/budget.js.map +1 -0
  19. package/dist/config.d.ts +743 -0
  20. package/dist/config.d.ts.map +1 -0
  21. package/dist/config.js +194 -0
  22. package/dist/config.js.map +1 -0
  23. package/dist/context.d.ts +222 -0
  24. package/dist/context.d.ts.map +1 -0
  25. package/dist/context.js +70 -0
  26. package/dist/context.js.map +1 -0
  27. package/dist/control-run-detail.d.ts +1686 -0
  28. package/dist/control-run-detail.d.ts.map +1 -0
  29. package/dist/control-run-detail.js +107 -0
  30. package/dist/control-run-detail.js.map +1 -0
  31. package/dist/control-trust.d.ts +79 -0
  32. package/dist/control-trust.d.ts.map +1 -0
  33. package/dist/control-trust.js +39 -0
  34. package/dist/control-trust.js.map +1 -0
  35. package/dist/control.d.ts +4226 -0
  36. package/dist/control.d.ts.map +1 -0
  37. package/dist/control.js +1022 -0
  38. package/dist/control.js.map +1 -0
  39. package/dist/decision.d.ts +208 -0
  40. package/dist/decision.d.ts.map +1 -0
  41. package/dist/decision.js +98 -0
  42. package/dist/decision.js.map +1 -0
  43. package/dist/events.d.ts +70 -0
  44. package/dist/events.d.ts.map +1 -0
  45. package/dist/events.js +105 -0
  46. package/dist/events.js.map +1 -0
  47. package/dist/gate.d.ts +37 -0
  48. package/dist/gate.d.ts.map +1 -0
  49. package/dist/gate.js +20 -0
  50. package/dist/gate.js.map +1 -0
  51. package/dist/harness.d.ts +1418 -0
  52. package/dist/harness.d.ts.map +1 -0
  53. package/dist/harness.js +552 -0
  54. package/dist/harness.js.map +1 -0
  55. package/dist/index.d.ts +32 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +32 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/orchestrate.d.ts +428 -0
  60. package/dist/orchestrate.d.ts.map +1 -0
  61. package/dist/orchestrate.js +246 -0
  62. package/dist/orchestrate.js.map +1 -0
  63. package/dist/primitives.d.ts +71 -0
  64. package/dist/primitives.d.ts.map +1 -0
  65. package/dist/primitives.js +114 -0
  66. package/dist/primitives.js.map +1 -0
  67. package/dist/review.d.ts +220 -0
  68. package/dist/review.d.ts.map +1 -0
  69. package/dist/review.js +91 -0
  70. package/dist/review.js.map +1 -0
  71. package/dist/route.d.ts +67 -0
  72. package/dist/route.d.ts.map +1 -0
  73. package/dist/route.js +33 -0
  74. package/dist/route.js.map +1 -0
  75. package/dist/spec.d.ts +561 -0
  76. package/dist/spec.d.ts.map +1 -0
  77. package/dist/spec.js +133 -0
  78. package/dist/spec.js.map +1 -0
  79. package/dist/surface-run-controls.d.ts +14 -0
  80. package/dist/surface-run-controls.d.ts.map +1 -0
  81. package/dist/surface-run-controls.js +142 -0
  82. package/dist/surface-run-controls.js.map +1 -0
  83. package/dist/task.d.ts +565 -0
  84. package/dist/task.d.ts.map +1 -0
  85. package/dist/task.js +186 -0
  86. package/dist/task.js.map +1 -0
  87. package/dist/telemetry.d.ts +660 -0
  88. package/dist/telemetry.d.ts.map +1 -0
  89. package/dist/telemetry.js +140 -0
  90. package/dist/telemetry.js.map +1 -0
  91. package/dist/thread.d.ts +348 -0
  92. package/dist/thread.d.ts.map +1 -0
  93. package/dist/thread.js +194 -0
  94. package/dist/thread.js.map +1 -0
  95. package/dist/workproduct.d.ts +31 -0
  96. package/dist/workproduct.d.ts.map +1 -0
  97. package/dist/workproduct.js +25 -0
  98. package/dist/workproduct.js.map +1 -0
  99. package/dist/workspace.d.ts +53 -0
  100. package/dist/workspace.d.ts.map +1 -0
  101. package/dist/workspace.js +30 -0
  102. package/dist/workspace.js.map +1 -0
  103. package/generated/AgentCapabilityCatalog.schema.json +389 -0
  104. package/generated/ApplyEligibility.schema.json +44 -0
  105. package/generated/BudgetLease.schema.json +95 -0
  106. package/generated/BudgetObservation.schema.json +76 -0
  107. package/generated/ConformanceReport.schema.json +107 -0
  108. package/generated/ContextPack.schema.json +186 -0
  109. package/generated/ControlApplyCheckRequest.schema.json +54 -0
  110. package/generated/ControlApplyRequest.schema.json +74 -0
  111. package/generated/ControlHarnessListResponse.schema.json +498 -0
  112. package/generated/ControlHarnessModelsResponse.schema.json +78 -0
  113. package/generated/ControlHarnessSettingsPatch.schema.json +130 -0
  114. package/generated/ControlInteractionAnswerRequest.schema.json +48 -0
  115. package/generated/ControlInteractionAnswerResponse.schema.json +35 -0
  116. package/generated/ControlPendingInteraction.schema.json +129 -0
  117. package/generated/ControlQueuedRunInfo.schema.json +44 -0
  118. package/generated/ControlRunControlRequest.schema.json +61 -0
  119. package/generated/ControlRunControlResponse.schema.json +40 -0
  120. package/generated/ControlRunDecisionRequest.schema.json +98 -0
  121. package/generated/ControlRunDecisionResponse.schema.json +40 -0
  122. package/generated/ControlRunDetail.schema.json +1925 -0
  123. package/generated/ControlRunStartInfo.schema.json +33 -0
  124. package/generated/ControlRunStartRequest.schema.json +429 -0
  125. package/generated/ControlRunSummary.schema.json +666 -0
  126. package/generated/ControlSecretListResponse.schema.json +57 -0
  127. package/generated/ControlSettingsSnapshot.schema.json +281 -0
  128. package/generated/ControlSettingsUpdateRequest.schema.json +212 -0
  129. package/generated/ControlSetupJob.schema.json +148 -0
  130. package/generated/ControlSetupJobConfirmRequest.schema.json +18 -0
  131. package/generated/ControlSetupJobCreateRequest.schema.json +38 -0
  132. package/generated/ControlSetupJobEvent.schema.json +58 -0
  133. package/generated/ControlSetupJobListResponse.schema.json +162 -0
  134. package/generated/ControlSpecFreezeRequest.schema.json +83 -0
  135. package/generated/ControlSpecQuestionsRequest.schema.json +80 -0
  136. package/generated/ControlThread.schema.json +129 -0
  137. package/generated/ControlThreadApplyRequest.schema.json +32 -0
  138. package/generated/ControlThreadApplyResponse.schema.json +47 -0
  139. package/generated/ControlThreadCreateRequest.schema.json +107 -0
  140. package/generated/ControlThreadDetail.schema.json +515 -0
  141. package/generated/ControlThreadListResponse.schema.json +141 -0
  142. package/generated/ControlThreadUpdateRequest.schema.json +46 -0
  143. package/generated/ControlTrustListResponse.schema.json +59 -0
  144. package/generated/ControlTrustState.schema.json +45 -0
  145. package/generated/ControlTrustUpdateRequest.schema.json +26 -0
  146. package/generated/DecisionRecord.schema.json +232 -0
  147. package/generated/GateResult.schema.json +81 -0
  148. package/generated/GlobalConfig.schema.json +313 -0
  149. package/generated/HarnessEvent.schema.json +360 -0
  150. package/generated/HarnessManifest.schema.json +350 -0
  151. package/generated/HarnessModel.schema.json +41 -0
  152. package/generated/HarnessStatusDto.schema.json +486 -0
  153. package/generated/McpRunToolResult.schema.json +91 -0
  154. package/generated/OrchestrateContract.schema.json +93 -0
  155. package/generated/OrchestratePlan.schema.json +244 -0
  156. package/generated/OrchestratePlanProgress.schema.json +103 -0
  157. package/generated/ProjectConfig.schema.json +95 -0
  158. package/generated/ReviewFinding.schema.json +226 -0
  159. package/generated/RouteFallbackPayload.schema.json +79 -0
  160. package/generated/RouteProof.schema.json +111 -0
  161. package/generated/RunControl.schema.json +51 -0
  162. package/generated/RunEvent.schema.json +103 -0
  163. package/generated/RunFailure.schema.json +98 -0
  164. package/generated/RunTelemetry.schema.json +433 -0
  165. package/generated/SecretMetadata.schema.json +34 -0
  166. package/generated/Session.schema.json +80 -0
  167. package/generated/SessionReboundLineage.schema.json +73 -0
  168. package/generated/SpecPack.schema.json +372 -0
  169. package/generated/TaskContract.schema.json +501 -0
  170. package/generated/Thread.schema.json +176 -0
  171. package/generated/ThreadTurn.schema.json +172 -0
  172. package/generated/TrustConfig.schema.json +44 -0
  173. package/generated/WorkProduct.schema.json +60 -0
  174. package/generated/WorkspaceEnvelope.schema.json +94 -0
  175. package/package.json +43 -0
@@ -0,0 +1,1022 @@
1
+ import { z } from "zod";
2
+ import { AccessProfile, AuthPreference, ContentHash, ExternalContextPolicy, Id, ModeKind, NonBlankString, OutputReadyState, ProviderFamily, } from "./primitives.js";
3
+ import { Portfolio } from "./budget.js";
4
+ import { AdapterStatus, ConformanceCheck, EffortHint, HarnessManifest, HarnessModel, InteractionQuestion, } from "./harness.js";
5
+ import { ThreadState, ThreadTurnKind, WorkspaceMode } from "./thread.js";
6
+ import { OrchestrateAutonomy } from "./orchestrate.js";
7
+ import { AttachmentInput } from "./attachment.js";
8
+ import { ProtectedPathApproval } from "./task.js";
9
+ /** Project context depth. The "deep" tier never shipped a distinct behavior
10
+ * (v0.15 triage): auto is the only mode; off exists solely on projections of
11
+ * no-project runs. */
12
+ export const RunScopeContext = z.enum(["auto"]).describe("Project context depth; auto is the only mode.");
13
+ export const RunScope = z
14
+ .discriminatedUnion("kind", [
15
+ z
16
+ .object({
17
+ kind: z.literal("project"),
18
+ root: z.string().describe("Absolute path of the project root."),
19
+ context: RunScopeContext.default("auto"),
20
+ })
21
+ .strict()
22
+ .describe("Run anchored to a project."),
23
+ z.object({ kind: z.literal("none") }).strict().describe("Run with no project (pure ask)."),
24
+ ])
25
+ .describe("What the run operates on: a project (with root) or nothing.");
26
+ export const RunExecution = z
27
+ .object({
28
+ isolation: z
29
+ .enum(["envelope", "live"])
30
+ .default("envelope")
31
+ .describe("Run isolation: envelope (isolated worktree under .claudexor/workspaces, the default) or live (the project tree itself)."),
32
+ })
33
+ .strict()
34
+ .describe("Execution isolation settings for a run.");
35
+ export const ControlReviewerPanelEntry = z
36
+ .object({
37
+ /** Explicit reviewer harness id. Repeated harness ids are allowed so one
38
+ * native provider can review through multiple requested models. */
39
+ harness: NonBlankString.describe("Explicit reviewer harness id; repeated harness ids are allowed so one provider can review through multiple requested models."),
40
+ /** Optional per-reviewer model hint, passed to that harness only. */
41
+ model: NonBlankString.optional().describe("Per-reviewer model hint, passed to that harness only."),
42
+ /** Optional per-reviewer effort hint, passed to that harness only. */
43
+ effort: EffortHint.optional().describe("Per-reviewer effort hint, passed to that harness only."),
44
+ })
45
+ .strict()
46
+ .describe("One reviewer of an explicit reviewer panel.");
47
+ export const ControlRunStartRequest = z
48
+ .object({
49
+ prompt: z.string().default("").describe("The user's prompt for the run."),
50
+ /** Inbound files/images for this turn; the daemon resolves each to a scoped
51
+ * on-disk Attachment before the run spec is built. */
52
+ attachments: z
53
+ .array(AttachmentInput)
54
+ .optional()
55
+ .describe("Inbound files/images for this turn; the daemon resolves each to a scoped on-disk attachment before the run spec is built."),
56
+ mode: ModeKind.default("agent"),
57
+ scope: RunScope.default({ kind: "none" }),
58
+ execution: RunExecution.default({ isolation: "envelope" }),
59
+ harnesses: z.array(NonBlankString).optional().describe("Eligible harness pool for the run; omitted = engine auto-pools."),
60
+ primaryHarness: NonBlankString.optional().describe("Primary harness the run should prefer."),
61
+ portfolio: Portfolio.optional(),
62
+ /** Scalar model convenience: expands to the RESOLVED PRIMARY harness only
63
+ * (never the pool). With a multi-harness pool and no primary it is
64
+ * rejected — use `models` instead (INV-103). */
65
+ model: NonBlankString.optional().describe("Scalar model convenience: expands to the resolved primary harness only (never the pool); rejected with a multi-harness pool and no primary — use models instead."),
66
+ /** Harness-scoped model map (harness id → model id). Specific beats
67
+ * general: an entry here wins over the scalar `model` and over the
68
+ * per-harness settings default. */
69
+ models: z
70
+ .record(NonBlankString, NonBlankString)
71
+ .optional()
72
+ .describe("Harness-scoped model map (harness id to model id); an entry here wins over the scalar model and over the per-harness settings default."),
73
+ effort: EffortHint.optional().describe("Requested reasoning effort."),
74
+ reviewerModels: z
75
+ .record(ProviderFamily, NonBlankString)
76
+ .optional()
77
+ .describe("Per-provider-family reviewer model overrides (legacy; reviewerPanel wins when present)."),
78
+ reviewerEfforts: z
79
+ .record(ProviderFamily, EffortHint)
80
+ .optional()
81
+ .describe("Per-provider-family reviewer effort overrides (legacy; reviewerPanel wins when present)."),
82
+ n: z.number().int().positive().optional().describe("Race width: number of best-of-N candidates."),
83
+ attempts: z.number().int().positive().nullable().optional().describe("Cap on convergence attempts; null = engine default."),
84
+ /** agent flag: iterate until the convergence predicate is clean (no fixed cap). */
85
+ untilClean: z.boolean().optional().describe("Agent flag: iterate until the convergence predicate is clean (no fixed cap)."),
86
+ /** audit flag: bounded read-only research swarm (the old `explore`). */
87
+ swarm: z.boolean().optional().describe("Audit flag: bounded read-only research swarm."),
88
+ /** agent flag: create-from-scratch intent (the old `create` mode). */
89
+ create: z.boolean().optional().describe("Agent flag: create-from-scratch intent."),
90
+ /** Best-of-N synthesis policy. `auto` (default) only synthesizes a 3rd
91
+ * candidate when n>=3 and candidates genuinely complement; `always`/`never`
92
+ * force it. Threaded to the orchestrator's decideSynthesis. */
93
+ synthesis: z
94
+ .enum(["auto", "always", "never"])
95
+ .optional()
96
+ .describe("Best-of-N synthesis policy: auto only synthesizes an extra candidate when n>=3 and candidates genuinely complement; always/never force it."),
97
+ maxUsd: z.number().nonnegative().nullable().optional().describe("USD cap for the run; null = no cap."),
98
+ /** Requested access profile. Effective access is derived by the engine and never client-supplied. */
99
+ access: AccessProfile.optional().describe("Requested access profile; effective access is derived by the engine and never client-supplied."),
100
+ web: ExternalContextPolicy.optional().describe("Web policy for the run (alias of externalContextPolicy; must match when both set)."),
101
+ externalContextPolicy: ExternalContextPolicy.optional().describe("External web/context policy for the run."),
102
+ /** Opt this run into the agent-driven browser (Playwright MCP). Honored only
103
+ * for browser-capable harnesses when web policy is not `off`. */
104
+ browser: z
105
+ .boolean()
106
+ .optional()
107
+ .describe("Opt this run into the agent-driven browser; honored only for browser-capable harnesses when web policy is not off."),
108
+ tests: z.array(NonBlankString).optional().describe("Test commands to run as deterministic gates."),
109
+ /** Typed per-run approval for changing auto-protected gate/test paths. This
110
+ * does not bypass built-in critical/security path human gates. */
111
+ protectedPathApprovals: z
112
+ .array(ProtectedPathApproval)
113
+ .optional()
114
+ .describe("Typed per-run approvals for changing auto-protected gate/test paths; does not bypass built-in critical/security path human gates."),
115
+ specPath: NonBlankString.optional().describe("Path to a frozen SpecPack the run is held to."),
116
+ specId: z.string().optional().describe("Id of the SpecPack the run is held to."),
117
+ specHash: ContentHash.optional().describe("Content hash of the SpecPack the run is held to."),
118
+ /** Thread/session linkage: a run is a turn inside a thread. */
119
+ threadId: Id.optional().describe("Thread this run is a turn of."),
120
+ /** INTERNAL single-writer handoff: control-api pre-creates the turn and
121
+ * passes its id to the daemon runner. REJECTED (400) when supplied by a
122
+ * client on POST /runs — a foreign turnId could rebind another thread's
123
+ * lineage; POST /threads/:id/turns is the public turn surface. */
124
+ turnId: Id.optional().describe("Internal daemon handoff only; rejected (400) when supplied by a client on POST /runs — use POST /threads/:id/turns instead."),
125
+ parentRunId: Id.optional().describe("Run this turn follows up on."),
126
+ /** When set, this turn implements an approved plan: the engine prefixes the
127
+ * parent plan run's final/plan.md into the prompt (mode is forced to agent). */
128
+ planRunId: Id.optional().describe("Internal daemon handoff only; rejected (400) on POST /runs. When set, the turn implements an approved plan from that run."),
129
+ /** Explicit reviewer panel. When present it overrides the legacy
130
+ * per-provider-family reviewerModels/reviewerEfforts maps and preserves
131
+ * duplicate harness entries for multi-model same-provider reviews. */
132
+ reviewerPanel: z
133
+ .array(ControlReviewerPanelEntry)
134
+ .min(1)
135
+ .optional()
136
+ .describe("Explicit reviewer panel; overrides the legacy reviewerModels/reviewerEfforts maps and preserves duplicate harness entries for multi-model same-provider reviews."),
137
+ /** Per-run auth route override (subscription/api_key/auto). */
138
+ authPreference: AuthPreference.optional().describe("Per-run auth route override."),
139
+ /** How much the orchestrate planner may act without confirmation
140
+ * (suggest/auto_safe/auto_full). Only meaningful for mode=orchestrate;
141
+ * consumed by the executor in runOrchestrate. */
142
+ autonomy: OrchestrateAutonomy.optional().describe("Autonomy level for the orchestrate planner; only meaningful for mode=orchestrate."),
143
+ /** Orchestrate executor: cap on plan tool calls. Only meaningful for
144
+ * mode=orchestrate; consumed by executeOrchestratePlan. */
145
+ maxToolCalls: z
146
+ .number()
147
+ .int()
148
+ .positive()
149
+ .optional()
150
+ .describe("Cap on orchestrate plan tool calls; only meaningful for mode=orchestrate."),
151
+ })
152
+ .strict()
153
+ .describe("Request body for POST /runs: prompt, mode, scope, routing, strategy flags, budget, policies, and spec/thread linkage.");
154
+ /** Harness ids that have a managed setup flow (shared by the async setup-jobs path). */
155
+ export const ControlHarnessSetupHarness = z
156
+ .enum(["codex", "claude", "cursor", "opencode", "raw"])
157
+ .describe("Harness ids that have a managed setup flow.");
158
+ export const ControlSetupJobAction = z
159
+ .enum(["install", "login", "doctor", "store_key"])
160
+ .describe("Setup action to perform: install the vendor CLI, log in, run the doctor, or store an API key.");
161
+ export const ControlSetupJobState = z
162
+ .enum(["queued", "running", "waiting_for_input", "succeeded", "failed", "cancelled", "not_supported"])
163
+ .describe("Lifecycle state of a setup job, including waiting_for_input (needs user confirmation/input) and not_supported.");
164
+ export const ControlSetupJobCreateRequest = z
165
+ .object({
166
+ harness: ControlHarnessSetupHarness,
167
+ action: ControlSetupJobAction,
168
+ })
169
+ .strict()
170
+ .describe("Request body to create a harness setup job.");
171
+ export const ControlSetupJob = z
172
+ .object({
173
+ jobId: Id.describe("Setup job id."),
174
+ harness: ControlHarnessSetupHarness,
175
+ action: ControlSetupJobAction,
176
+ state: ControlSetupJobState,
177
+ command: z.string().nullable().default(null).describe("Shell command the job runs, when applicable."),
178
+ guideUrl: z.string().url().nullable().default(null).describe("Vendor guide URL for manual steps, when applicable."),
179
+ logPath: z.string().nullable().default(null).describe("On-disk log path for the job's output."),
180
+ message: z.string().describe("Human-readable status message."),
181
+ riskFlags: z.array(z.string()).default([]).describe("Risk flags for the action (e.g. network_download, shell_pipe), surfaced before confirmation."),
182
+ requiresConfirmation: z.boolean().default(false).describe("Whether the job waits for explicit user confirmation before running."),
183
+ createdAt: z.string().describe("When the job was created."),
184
+ startedAt: z.string().nullable().default(null).describe("When the job started running."),
185
+ firstOutputAt: z.string().nullable().default(null).describe("When the job produced its first output."),
186
+ lastOutputAt: z.string().nullable().default(null).describe("When the job last produced output."),
187
+ finishedAt: z.string().nullable().default(null).describe("When the job finished."),
188
+ retryCount: z.number().int().nonnegative().default(0).describe("How many times the job was retried."),
189
+ })
190
+ .strict()
191
+ .describe("One managed harness setup job (install/login/doctor/store_key) with its lifecycle timestamps.");
192
+ export const ControlSetupJobEvent = z
193
+ .object({
194
+ jobId: Id.describe("Setup job the event belongs to."),
195
+ seq: z.number().int().nonnegative().describe("Monotonic event sequence within the job."),
196
+ time: z.string().describe("Event timestamp."),
197
+ /** Only "status" is ever produced (v0.15 triage: the log/end kinds had no
198
+ * producer; SSE stream end is a transport frame, not a payload kind). */
199
+ kind: z.enum(["status"]).describe("Event kind; only status is ever produced."),
200
+ state: ControlSetupJobState.optional(),
201
+ message: z.string().describe("Human-readable status message."),
202
+ })
203
+ .strict()
204
+ .describe("Status event on a setup job's event stream.");
205
+ export const ControlSetupJobListResponse = z
206
+ .object({
207
+ jobs: z.array(ControlSetupJob).describe("All known setup jobs."),
208
+ })
209
+ .describe("Response for listing setup jobs.");
210
+ export const ControlSetupJobConfirmRequest = z
211
+ .object({
212
+ confirmed: z.boolean().default(true).describe("Whether the user confirmed the pending action."),
213
+ })
214
+ .strict()
215
+ .describe("Request body confirming a setup job that waits for user confirmation.");
216
+ export const ControlSpecQuestionsRequest = z
217
+ .object({
218
+ prompt: z.string().describe("The user's request the interview is clarifying."),
219
+ scope: z
220
+ .object({
221
+ kind: z.literal("project"),
222
+ root: z.string().describe("Absolute path of the project root."),
223
+ context: RunScopeContext.default("auto"),
224
+ })
225
+ .strict()
226
+ .describe("Project the spec is about."),
227
+ harnesses: z.array(NonBlankString).optional().describe("Harnesses eligible to generate the questions."),
228
+ /** Already-answered decisions from prior tiers; carried so each round goes
229
+ * DEEPER instead of re-asking (multi-tier adaptive interview). */
230
+ priorDecisions: z
231
+ .array(z.object({
232
+ question: z.string().describe("Question asked in a prior tier."),
233
+ answer: z.string().describe("The user's answer."),
234
+ }))
235
+ .optional()
236
+ .describe("Already-answered decisions from prior tiers, carried so each round goes deeper instead of re-asking."),
237
+ })
238
+ .strict()
239
+ .describe("Request body to generate the next tier of spec interview questions.");
240
+ export const ControlSpecFreezeRequest = z
241
+ .object({
242
+ prompt: z.string().describe("The user's request the spec captures."),
243
+ scope: z
244
+ .object({
245
+ kind: z.literal("project"),
246
+ root: z.string().describe("Absolute path of the project root."),
247
+ context: RunScopeContext.default("auto"),
248
+ })
249
+ .strict()
250
+ .describe("Project the spec is about."),
251
+ planDir: z.string().optional().describe("Directory to write the frozen spec artifacts into."),
252
+ plan: z.string().optional().describe("Plan text to fold into the spec."),
253
+ answers: z.array(z.unknown()).optional().describe("Interview answers for the current tier."),
254
+ /** Accumulated prior-tier interview decisions. Folded into the frozen
255
+ * SpecPack's decided_tradeoffs so a MULTI-TIER spec carries every tier, not
256
+ * just the last (mirror of ControlSpecQuestionsRequest.priorDecisions). */
257
+ priorDecisions: z
258
+ .array(z.object({
259
+ question: z.string().describe("Question asked in a prior tier."),
260
+ answer: z.string().describe("The user's answer."),
261
+ }))
262
+ .optional()
263
+ .describe("Accumulated prior-tier interview decisions, folded into the frozen SpecPack's decided tradeoffs."),
264
+ })
265
+ .strict()
266
+ .describe("Request body to freeze a SpecPack from the interview.");
267
+ export const ControlRunStartInfo = z
268
+ .object({
269
+ jobId: z.string().optional().describe("Daemon job id backing the run."),
270
+ runId: z.string().describe("Run id."),
271
+ taskId: z.string().optional().describe("Task id, when already allocated."),
272
+ runDir: z.string().describe("On-disk run artifact directory."),
273
+ })
274
+ .describe("Response for a successfully enqueued run.");
275
+ export const ControlRunState = z
276
+ .enum([
277
+ "queued",
278
+ "running",
279
+ "blocked",
280
+ "succeeded",
281
+ "no_op",
282
+ "ungated",
283
+ "review_not_run",
284
+ "failed",
285
+ "cancelled",
286
+ "interrupted",
287
+ "exhausted",
288
+ "not_converged",
289
+ "stuck_no_progress",
290
+ ])
291
+ .describe("Control-plane run state: queued/running while live; blocked awaiting a human; then a terminal outcome (succeeded, no_op, ungated, review_not_run, failed, cancelled, interrupted, exhausted, not_converged, stuck_no_progress).");
292
+ export const ControlQueuedRunInfo = z
293
+ .object({
294
+ jobId: z.string().describe("Daemon job id."),
295
+ state: ControlRunState,
296
+ error: z.string().optional().describe("Error message, when the job failed."),
297
+ })
298
+ .describe("Compact state of a queued/running daemon job.");
299
+ export const RunFailure = z
300
+ .object({
301
+ phase: z.string().default("unknown").describe("Pipeline phase where the failure happened."),
302
+ category: z
303
+ .enum([
304
+ "validation",
305
+ "project",
306
+ "auth",
307
+ "harness_unavailable",
308
+ "harness_error",
309
+ "budget",
310
+ "policy",
311
+ "cancelled",
312
+ "internal",
313
+ "unknown",
314
+ ])
315
+ .default("unknown")
316
+ .describe("Typed failure category (validation, project, auth, harness, budget, policy, cancelled, internal, unknown)."),
317
+ harnessId: z.string().nullable().default(null).describe("Harness involved in the failure, when known."),
318
+ attemptId: z.string().nullable().default(null).describe("Attempt involved in the failure, when known."),
319
+ safeMessage: z.string().describe("Redacted human-readable failure message."),
320
+ rawDetailRef: z.string().nullable().default(null).describe("Artifact path holding the raw (redacted) failure detail."),
321
+ logRefs: z.array(z.string()).default([]).describe("Log artifact paths relevant to the failure."),
322
+ eventRefs: z.array(z.string()).default([]).describe("Event references relevant to the failure."),
323
+ runDir: z.string().nullable().default(null).describe("Run artifact directory."),
324
+ nextActions: z.array(z.string()).default([]).describe("Suggested operator next actions."),
325
+ })
326
+ .describe("Typed failure record for a run: phase, category, evidence references, and suggested next actions.");
327
+ export const ControlProjectMetadata = z
328
+ .object({
329
+ kind: z.enum(["project", "none"]).default("none").describe("Whether the run was anchored to a project."),
330
+ root: z.string().nullable().default(null).describe("Project root, when anchored."),
331
+ projectName: z.string().nullable().default(null).describe("Project display name, when anchored."),
332
+ context: z.enum(["off", "auto"]).default("off").describe("Project context depth used for the run."),
333
+ })
334
+ .describe("Project metadata projected onto a run summary.");
335
+ export const ControlWebEvidence = z
336
+ .object({
337
+ required: z.boolean().default(false).describe("Whether the run required web evidence."),
338
+ /** Requested external-context policy for the run. */
339
+ mode: ExternalContextPolicy.default("auto").describe("Requested external-context policy for the run."),
340
+ /** Mode the selected route actually executed (disclosed upgrades, e.g. claude cached->live). */
341
+ effectiveMode: ExternalContextPolicy.default("auto").describe("Policy the selected route actually executed (disclosed upgrades, e.g. cached to live)."),
342
+ attempted: z.boolean().default(false).describe("Whether any web activity was attempted."),
343
+ satisfied: z.boolean().default(false).describe("Whether the web-evidence requirement was satisfied."),
344
+ status: z
345
+ .enum(["none", "attempted", "satisfied", "failed", "unverified"])
346
+ .default("none")
347
+ .describe("Web-evidence verdict for the run."),
348
+ tool: z.string().nullable().default(null).describe("Web tool that produced the evidence, when any."),
349
+ target: z.string().nullable().default(null).describe("Redacted target (query/url) of the web activity, when any."),
350
+ errorSummary: z.string().nullable().default(null).describe("Redacted error detail when web activity failed."),
351
+ rawDetailRef: z.string().nullable().default(null).describe("Artifact path holding the raw (redacted) evidence detail."),
352
+ /** False when the run predates telemetry.yaml; surfaces must render "telemetry unavailable". */
353
+ available: z
354
+ .boolean()
355
+ .default(true)
356
+ .describe('False when the run predates the telemetry artifact; surfaces must render "telemetry unavailable".'),
357
+ })
358
+ .describe("Web evidence projected onto a run summary from the telemetry artifact.");
359
+ /**
360
+ * Run-level route evidence projected from telemetry (observed model per
361
+ * attempt). `verified` is true only when an observed model was actually
362
+ * reported by the harness stream — never inferred from the request.
363
+ */
364
+ export const ControlRouteInfo = z
365
+ .object({
366
+ requestedModel: z.string().nullable().default(null).describe("Model requested for the run."),
367
+ observedModel: z.string().nullable().default(null).describe("Model the harness stream actually reported."),
368
+ harnessId: z.string().nullable().default(null).describe("Harness that ran the final attempt."),
369
+ verified: z
370
+ .boolean()
371
+ .default(false)
372
+ .describe("True only when an observed model was actually reported by the harness stream — never inferred from the request."),
373
+ })
374
+ .describe("Run-level route evidence projected from telemetry (requested vs observed model).");
375
+ /**
376
+ * Honest terminal outcome of a run, projected from final/work_product.yaml and
377
+ * the presence of final/answer.md. Answers "what did this turn actually do?" so
378
+ * a chat surface never shows a green "succeeded" next to nothing (the v0.9 plan
379
+ * bug): `kind:"plan"` means a plan was produced and NO files changed; `diffStat`
380
+ * is null unless a patch exists; `adopted` is true when the live in-place tree
381
+ * was actually mutated this turn (decoupled from a clean review — see applyState).
382
+ */
383
+ export const RunApplyState = z
384
+ .enum([
385
+ /** No in-place mutation happened (envelope-only, plan/answer, or nothing produced). */
386
+ "not_applied",
387
+ /** Winner applied to the live tree AND review converged clean. */
388
+ "applied",
389
+ /** Winner applied to the live tree but review is blocked/unconverged — honest
390
+ * "Applied · review blocked"; the Revert affordance is offered. */
391
+ "applied_review_blocked",
392
+ /** A prior in-place application was reverted to its pre-turn snapshot. */
393
+ "reverted",
394
+ ])
395
+ .describe("Honest application state of a run's changes: not_applied (no in-place mutation), applied (applied and review clean), applied_review_blocked (applied but review blocked/unconverged), or reverted.");
396
+ export const ControlRunResult = z
397
+ .object({
398
+ kind: z
399
+ .enum(["patch", "answer", "plan", "report", "none"])
400
+ .default("none")
401
+ .describe("What the turn actually produced: a patch, an answer, a plan (no files changed), a report, or nothing."),
402
+ diffStat: z
403
+ .object({
404
+ files: z.number().int().nonnegative().describe("Files changed."),
405
+ additions: z.number().int().nonnegative().describe("Lines added."),
406
+ deletions: z.number().int().nonnegative().describe("Lines deleted."),
407
+ })
408
+ .nullable()
409
+ .default(null)
410
+ .describe("Diff statistics; null unless a patch exists."),
411
+ blockers: z.number().int().nonnegative().default(0).describe("Count of accepted blocking review findings."),
412
+ /** True when the live in-place tree was mutated this turn (regardless of review). */
413
+ adopted: z
414
+ .boolean()
415
+ .nullable()
416
+ .default(null)
417
+ .describe("True when the live in-place tree was mutated this turn (regardless of review); null when unknown."),
418
+ /** Honest application state (decoupled from clean-terminal). */
419
+ applyState: RunApplyState.default("not_applied"),
420
+ /** Tree SHA before this turn mutated the in-place tree (revert restore target). */
421
+ preTurnSha: z
422
+ .string()
423
+ .nullable()
424
+ .default(null)
425
+ .describe("Tree SHA before this turn mutated the in-place tree (revert restore target)."),
426
+ /** Tree SHA right after this turn's mutation (revert divergence fence: refuse
427
+ * to revert if the working tree has diverged from this since). */
428
+ postTurnSha: z
429
+ .string()
430
+ .nullable()
431
+ .default(null)
432
+ .describe("Tree SHA right after this turn's mutation; revert refuses if the working tree has diverged from this since."),
433
+ /** Revert metadata is available (the turn mutated the live tree in place and
434
+ * pre/post-turn snapshots were recorded), so a Revert affordance may be offered.
435
+ * This is NOT a live-safe guarantee: the server re-checks tree divergence at
436
+ * revert time and refuses (fail loud) if the working tree changed since. */
437
+ revertable: z
438
+ .boolean()
439
+ .default(false)
440
+ .describe("Revert metadata is available so a Revert affordance may be offered; not a live-safe guarantee — the server re-checks tree divergence at revert time."),
441
+ })
442
+ .describe("Honest terminal outcome of a run (what the turn actually did), projected from the work product and answer artifacts.");
443
+ export const ControlRunSummary = z
444
+ .object({
445
+ jobId: z.string().describe("Daemon job id backing the run."),
446
+ runId: z.string().describe("Run id."),
447
+ taskId: z.string().optional().describe("Task id, when allocated."),
448
+ state: ControlRunState,
449
+ runDir: z.string().optional().describe("On-disk run artifact directory."),
450
+ error: z.string().optional().describe("Error message, when the run failed."),
451
+ failure: RunFailure.nullable().default(null).describe("Typed failure record; null unless the run failed."),
452
+ project: ControlProjectMetadata.default({}),
453
+ mode: ModeKind.optional(),
454
+ /** v0.9 engine strategy on the mode (flags, not modes): race width / repair caps / swarm / create. */
455
+ strategy: z
456
+ .enum(["race", "attempts", "until_clean", "swarm", "create"])
457
+ .nullable()
458
+ .optional()
459
+ .describe("Engine strategy flag on the mode (race width / attempt caps / until-clean / swarm / create); flags, not modes."),
460
+ prompt: z.string().optional().describe("The user's prompt for the run."),
461
+ harnesses: z.array(z.string()).optional().describe("Harness pool the run used."),
462
+ primaryHarness: z.string().optional().describe("Primary harness the run preferred."),
463
+ portfolio: Portfolio.optional(),
464
+ model: z.string().optional().describe("Scalar model requested for the run."),
465
+ reviewerPanel: z.array(ControlReviewerPanelEntry).optional().describe("Explicit reviewer panel used for the run."),
466
+ protectedPathApprovals: z.array(ProtectedPathApproval).optional().describe("Per-run protected-path approvals supplied."),
467
+ n: z.number().int().optional().describe("Race width, when the run was a race."),
468
+ maxUsd: z.number().nullable().optional().describe("USD cap for the run; null = no cap."),
469
+ spendUsd: z.number().nullable().optional().describe("Settled spend in USD; null when unknown."),
470
+ spendEstimated: z.boolean().optional().describe("True when spend is token-derived rather than natively reported."),
471
+ access: AccessProfile.optional().describe("Access profile of the run: the effective profile when known, else the requested one (prefer requestedAccess/effectiveAccess)."),
472
+ requestedAccess: AccessProfile.optional().describe("Access profile the caller requested."),
473
+ effectiveAccess: AccessProfile.optional().describe("Access profile actually enforced by the engine."),
474
+ externalContextPolicy: ExternalContextPolicy.optional().describe("Requested web policy for the run."),
475
+ webRequired: z.boolean().optional().describe("Whether the run required web evidence."),
476
+ webMode: ExternalContextPolicy.optional().describe("Web policy actually executed by the selected route."),
477
+ webEvidence: ControlWebEvidence.default({}),
478
+ toolPermissionPolicy: z.record(z.string(), z.unknown()).optional().describe("Tool allow/deny policy applied to the run."),
479
+ outputReadyState: OutputReadyState.default("pending"),
480
+ /** Non-blocking tool warnings projected from final/telemetry.yaml. */
481
+ toolWarningsTotal: z
482
+ .number()
483
+ .int()
484
+ .nonnegative()
485
+ .default(0)
486
+ .describe("Non-blocking tool warnings projected from the telemetry artifact."),
487
+ /** Honest terminal outcome (what the turn did): patch/answer/plan/report/none. */
488
+ result: ControlRunResult.default({}),
489
+ /** True while at least one interaction.requested has no answered/timeout. */
490
+ waitingOnUser: z.boolean().default(false).describe("True while at least one interactive question is awaiting the user's answer."),
491
+ /** Route evidence from telemetry; null when no telemetry exists (legacy). */
492
+ route: ControlRouteInfo.nullable().default(null).describe("Route evidence from telemetry; null when no telemetry exists (legacy runs)."),
493
+ tests: z.array(z.string()).optional().describe("Test commands configured as gates."),
494
+ specId: z.string().optional().describe("SpecPack id the run was held to."),
495
+ specHash: ContentHash.optional().describe("Content hash of the SpecPack the run was held to."),
496
+ createdAt: z.string().optional().describe("When the run was created."),
497
+ startedAt: z.string().optional().describe("When the run started."),
498
+ finishedAt: z.string().optional().describe("When the run finished."),
499
+ })
500
+ .describe("Run summary row served by GET /runs and embedded in run detail: state, routing, budget, policies, and honest outcome.");
501
+ export const ControlPrimaryOutput = z
502
+ .object({
503
+ kind: z
504
+ .enum(["answer", "report", "plan", "summary", "patch", "diagnostic"])
505
+ .describe("What kind of output this is: answer, report, plan, summary, patch, or diagnostic."),
506
+ path: z.string().describe("Artifact path of the output."),
507
+ text: z.string().nullable().default(null).describe("Inline text content, when loaded."),
508
+ bytes: z.number().int().nonnegative().optional().describe("Size of the output in bytes."),
509
+ })
510
+ .describe("The run's primary user-facing output artifact.");
511
+ export const ControlTimelineEvent = z
512
+ .object({
513
+ type: z.string().describe("Run event type."),
514
+ ts: z.string().optional().describe("Event timestamp."),
515
+ harnessId: z.string().nullable().default(null).describe("Harness involved, when any."),
516
+ attemptId: z.string().nullable().default(null).describe("Attempt involved, when any."),
517
+ title: z.string().describe("Human-readable event title."),
518
+ detail: z.string().nullable().default(null).describe("Human-readable event detail."),
519
+ severity: z.enum(["info", "warning", "error"]).default("info").describe("Display severity of the event."),
520
+ toolName: z.string().nullable().default(null).describe("Tool name for tool events."),
521
+ target: z.string().nullable().default(null).describe("Redacted tool target for tool events."),
522
+ errorSummary: z.string().nullable().default(null).describe("Redacted error detail for error events."),
523
+ rawRef: z.string().nullable().default(null).describe("Reference to the raw underlying event/artifact."),
524
+ })
525
+ .describe("One projected timeline row of a run for display.");
526
+ export const ControlBudgetSnapshot = z
527
+ .object({
528
+ maxUsd: z.number().nullable().default(null).describe("USD cap for the run; null = no cap."),
529
+ spendUsd: z.number().nullable().default(null).describe("Spend so far in USD; null when unknown."),
530
+ remainingUsd: z.number().nullable().default(null).describe("Remaining budget in USD; null when no cap or unknown spend."),
531
+ estimated: z.boolean().default(false).describe("True when spend is token-derived rather than natively reported."),
532
+ source: z
533
+ .enum(["decision", "events", "settings", "unknown"])
534
+ .default("unknown")
535
+ .describe("Where the snapshot came from: the decision record, live events, settings, or unknown."),
536
+ })
537
+ .describe("Budget snapshot for a run: cap, spend, and provenance.");
538
+ export const ControlArtifactInfo = z
539
+ .object({
540
+ path: z.string().describe("Artifact path relative to the run directory."),
541
+ kind: z.enum(["file", "directory"]).describe("Whether the artifact is a file or a directory."),
542
+ bytes: z.number().int().nonnegative().optional().describe("Size in bytes; absent for directories."),
543
+ /** Clean MIME type derived from the extension (e.g. `image/png`, `text/plain`,
544
+ * `application/pdf`); lets a gallery render text vs image vs pdf. Absent for
545
+ * directories. */
546
+ mime: z.string().optional().describe("MIME type derived from the extension; absent for directories."),
547
+ })
548
+ .describe("One artifact in the run's artifact tree.");
549
+ /** A live interaction awaiting the user's answer (snapshot projection). */
550
+ export const ControlPendingInteraction = z
551
+ .object({
552
+ interactionId: Id.describe("Interaction id used to answer."),
553
+ runId: Id.describe("Run the interaction belongs to."),
554
+ attemptId: z.string().nullable().default(null).describe("Attempt the interaction was raised in, when known."),
555
+ harnessId: z.string().nullable().default(null).describe("Harness that raised the interaction."),
556
+ sourceTool: z.string().nullable().default(null).describe("Native tool that raised the request."),
557
+ questions: z.array(InteractionQuestion).default([]).describe("Questions awaiting answers."),
558
+ requestedAt: z.string().describe("When the interaction was requested."),
559
+ timeoutAt: z.string().nullable().default(null).describe("When the interaction times out into a benign decline; null = no timeout."),
560
+ })
561
+ .describe("A live interactive question awaiting the user's answer (snapshot projection).");
562
+ export const ControlInteractionAnswerRequest = z
563
+ .object({
564
+ answers: z
565
+ .array(z
566
+ .object({
567
+ questionId: Id.describe("Id of the question being answered."),
568
+ selectedLabels: z.array(z.string()).default([]).describe("Labels of the selected options."),
569
+ freeText: z.string().nullable().default(null).describe("Free-text answer; null when only options were selected."),
570
+ })
571
+ .strict())
572
+ .default([])
573
+ .describe("Answers, one per question."),
574
+ })
575
+ .strict()
576
+ .describe("Request body answering a pending interactive question.");
577
+ export const ControlInteractionAnswerResponse = z
578
+ .object({
579
+ accepted: z.boolean().describe("Whether the answer was accepted."),
580
+ status: z
581
+ .enum(["delivered", "not_found", "already_resolved", "rejected"])
582
+ .describe("Delivery outcome: delivered into the live session, interaction not found, already resolved, or rejected."),
583
+ message: z.string().optional().describe("Human-readable detail."),
584
+ })
585
+ .describe("Response to an interaction answer.");
586
+ export const RunControlTarget = z
587
+ .object({
588
+ attemptId: z.string().optional().describe("Attempt to target; omitted = the whole run."),
589
+ harnessId: z.string().optional().describe("Harness to target."),
590
+ sessionId: z.string().optional().describe("Session to target."),
591
+ requestId: z.string().optional().describe("Specific request to target."),
592
+ })
593
+ .describe("Optional narrowing of what a run control verb targets.");
594
+ export const RunControl = z
595
+ .object({
596
+ // `interrupt` was deleted as a fake knob: it mapped to the same daemon
597
+ // cancel (staged-field doctrine — no vocabulary without distinct behavior).
598
+ kind: z.enum(["cancel"]).describe("Control verb: cancel the run."),
599
+ target: RunControlTarget.default({}),
600
+ reason: z.string().optional().describe("Human-readable reason for the control."),
601
+ })
602
+ .describe("A control verb (cancel) aimed at a run or a narrower target inside it.");
603
+ export const ControlRunControlRequest = z
604
+ .object({
605
+ control: RunControl,
606
+ })
607
+ .describe("Request body for POST /runs/:id/control.");
608
+ export const ControlRunControlResponse = z
609
+ .object({
610
+ accepted: z.boolean().describe("Whether the control was accepted."),
611
+ status: z
612
+ .enum(["applied", "queued", "rejected", "unsupported"])
613
+ .default("queued")
614
+ .describe("Outcome: applied immediately, queued, rejected, or unsupported for this run."),
615
+ runId: Id.optional().describe("Run the control was applied to."),
616
+ message: z.string().optional().describe("Human-readable detail."),
617
+ })
618
+ .describe("Response to a run control request.");
619
+ export const ApplyTarget = z
620
+ .discriminatedUnion("kind", [
621
+ z.object({ kind: z.literal("original_project") }).strict().describe("Apply to the project the run originally came from."),
622
+ z
623
+ .object({ kind: z.literal("project"), root: z.string().describe("Absolute path of the target project root.") })
624
+ .strict()
625
+ .describe("Apply to an explicitly named project root."),
626
+ ])
627
+ .describe("Where a work product is delivered: the original project or an explicit project root.");
628
+ export const ControlApplyCheckRequest = z
629
+ .object({
630
+ target: ApplyTarget.default({ kind: "original_project" }),
631
+ })
632
+ .strict()
633
+ .describe("Request body for a dry-run apply check.");
634
+ export const ControlApplyRequest = z
635
+ .object({
636
+ target: ApplyTarget.default({ kind: "original_project" }),
637
+ mode: z
638
+ .enum(["artifact_only", "apply", "branch", "commit", "pr"])
639
+ .default("apply")
640
+ .describe("Delivery mode: artifact_only (export only), apply to the tree, or as a branch, commit, or PR."),
641
+ branch: z.string().optional().describe("Branch name for branch/pr modes."),
642
+ message: z.string().optional().describe("Commit message for commit/pr modes."),
643
+ })
644
+ .strict()
645
+ .describe("Request body applying a run's work product to a project.");
646
+ /**
647
+ * Operator decision on a NEEDS_HUMAN-blocked run (review_actions). Closes the
648
+ * v0.8 "apply: human_review" dead end: a typed, auditable unblock path instead
649
+ * of a read-only review queue.
650
+ */
651
+ export const RunDecisionAction = z
652
+ .enum([
653
+ "accept_clean_patch",
654
+ "rerun_with_feedback",
655
+ "accept_risk",
656
+ "override_needs_human",
657
+ /** Restore the live in-place tree to this turn's pre-turn snapshot (server-owned;
658
+ * refuses if the tree has diverged from the recorded post-turn state). */
659
+ "revert_run",
660
+ ])
661
+ .describe("Operator decision on a blocked run: accept_clean_patch (apply it), rerun_with_feedback, accept_risk, override_needs_human, or revert_run (restore the pre-turn snapshot).");
662
+ export const ControlRunDecisionRequest = z
663
+ .object({
664
+ action: RunDecisionAction,
665
+ /** Findings the decision targets (override/accept_risk). */
666
+ findingIds: z.array(Id).default([]).describe("Findings the decision targets (override/accept_risk)."),
667
+ /** Reviewer feedback to seed a rerun turn. */
668
+ feedback: z.string().optional().describe("Reviewer feedback to seed a rerun turn."),
669
+ /** Risk reasons being explicitly accepted (recorded, never silent). */
670
+ acceptedRisks: z.array(z.string()).default([]).describe("Risk reasons being explicitly accepted (recorded, never silent)."),
671
+ /** Apply mode + target for accept_clean_patch. */
672
+ applyMode: z
673
+ .enum(["artifact_only", "apply", "branch", "commit", "pr"])
674
+ .optional()
675
+ .describe("Delivery mode for accept_clean_patch."),
676
+ target: ApplyTarget.optional().describe("Delivery target for accept_clean_patch."),
677
+ })
678
+ .strict()
679
+ .describe("Typed, auditable operator decision on a NEEDS_HUMAN-blocked run.");
680
+ export const ControlRunDecisionResponse = z
681
+ .object({
682
+ accepted: z.boolean().describe("Whether the decision was accepted."),
683
+ status: z
684
+ .enum(["applied", "requeued", "rejected", "unsupported"])
685
+ .describe("Outcome: applied, requeued (a new turn was enqueued), rejected, or unsupported."),
686
+ /** New run id when the decision re-enqueues a turn (rerun_with_feedback). */
687
+ newRunId: Id.optional().describe("New run id when the decision re-enqueues a turn (rerun_with_feedback)."),
688
+ message: z.string().optional().describe("Human-readable detail."),
689
+ })
690
+ .describe("Response to an operator run decision.");
691
+ /* ---- Threads / Sessions (chat/session-first; camelCase control projections) ---- */
692
+ export const ControlThread = z
693
+ .object({
694
+ id: Id.describe("Thread id."),
695
+ title: z.string().nullable().default(null).describe("Thread title; null until set."),
696
+ repoRoot: z.string().nullable().default(null).describe("Project root the thread is anchored to; null for a no-project thread."),
697
+ mode: ModeKind.optional().describe("Default mode for new turns."),
698
+ /** How turns touch files (in-place live tree vs isolated worktree). */
699
+ workspaceMode: WorkspaceMode.default("in_place"),
700
+ authPreference: AuthPreference.default("auto"),
701
+ primaryHarness: z.string().nullable().default(null).describe("Sticky primary harness for the thread; null = engine routing."),
702
+ /** Sticky eligible pool for the thread (empty => engine auto-pools). */
703
+ eligibleHarnesses: z.array(z.string()).default([]).describe("Sticky eligible harness pool; empty = the engine auto-pools."),
704
+ state: ThreadState.default("active"),
705
+ runIds: z.array(Id).default([]).describe("Ordered run lineage of the thread."),
706
+ headRunId: Id.nullable().default(null).describe("Most recent run of the thread; null before the first turn runs."),
707
+ /** True when the head turn is blocked on a human decision (needs-me inbox). */
708
+ needsHuman: z.boolean().default(false).describe("True when the head turn is blocked on a human decision (needs-me inbox)."),
709
+ createdAt: z.string().describe("When the thread was created."),
710
+ updatedAt: z.string().describe("When the thread was last updated."),
711
+ })
712
+ .describe("Control-plane projection of a thread (camelCase view of the Thread artifact).");
713
+ export const ControlSession = z
714
+ .object({
715
+ id: Id.describe("Session id."),
716
+ threadId: Id.describe("Thread the session belongs to."),
717
+ harnessId: Id.describe("Harness the session is bound to."),
718
+ nativeSessionId: z.string().nullable().default(null).describe("The vendor CLI session id; null when none exists."),
719
+ observedModel: z.string().nullable().default(null).describe("Model last observed on the session's stream."),
720
+ state: z.enum(["live", "stale", "rebound"]).default("live").describe("Session cache state: live, stale, or rebound."),
721
+ })
722
+ .describe("Control-plane projection of a vendor CLI session bound to a thread.");
723
+ /**
724
+ * Compact run state embedded on a turn so a chat surface renders the whole
725
+ * conversation from one GET /threads/:id (no N+1 run-detail fetch per turn).
726
+ */
727
+ export const ControlTurnRunCard = z
728
+ .object({
729
+ state: ControlRunState,
730
+ mode: ModeKind.optional(),
731
+ strategy: z
732
+ .enum(["race", "attempts", "until_clean", "swarm", "create"])
733
+ .nullable()
734
+ .optional()
735
+ .describe("Engine strategy flag on the mode, when any."),
736
+ n: z.number().int().optional().describe("Race width, when the run was a race."),
737
+ result: ControlRunResult.default({}),
738
+ spendUsd: z.number().nullable().optional().describe("Settled spend in USD; null when unknown."),
739
+ outputReadyState: OutputReadyState.default("pending"),
740
+ waitingOnUser: z.boolean().default(false).describe("True while an interactive question is awaiting the user's answer."),
741
+ finishedAt: z.string().nullable().default(null).describe("When the run finished; null while live."),
742
+ })
743
+ .describe("Compact run state embedded on a turn so a chat surface renders the whole conversation from one thread fetch.");
744
+ export const ControlThreadTurn = z
745
+ .object({
746
+ id: Id.describe("Turn id."),
747
+ threadId: Id.describe("Thread the turn belongs to."),
748
+ runId: Id.nullable().default(null).describe("Run backing this turn; null while unbound."),
749
+ parentRunId: Id.nullable().default(null).describe("Run this turn follows up on, when any."),
750
+ /** Set when this turn implements an approved plan from an earlier run. */
751
+ planRunId: Id.nullable().default(null).describe("Set when this turn implements an approved plan from an earlier run."),
752
+ kind: ThreadTurnKind.default("followup"),
753
+ prompt: z.string().default("").describe("The user's message for this turn."),
754
+ /** Embedded run card (outcome/state) so the chat renders without N+1 fetches. */
755
+ run: ControlTurnRunCard.nullable().default(null).describe("Embedded run card (outcome/state); null while no run is bound."),
756
+ /** Why this turn has NO run (enqueue/preflight refusal, e.g. the trust
757
+ * gate) — surfaces render it as an inline failure card with the remedy;
758
+ * null once a run binds (retry clears it). `code` is the typed throw's
759
+ * machine code (remedies key on it, never on the message text);
760
+ * `retryable=false` means no recorded job exists to replay — surfaces
761
+ * offer "send a new message" instead of a doomed Retry. */
762
+ enqueueError: z
763
+ .object({
764
+ message: z.string().describe("Human-readable refusal message."),
765
+ code: z.string().nullable().default(null).describe("Machine-readable refusal code; remedies key on it, never on the message text."),
766
+ retryable: z
767
+ .boolean()
768
+ .default(true)
769
+ .describe("False when no recorded job exists to replay — surfaces offer a new message instead of a doomed retry."),
770
+ failedAt: z.string().describe("When the enqueue failed."),
771
+ })
772
+ .nullable()
773
+ .default(null)
774
+ .describe("Why this turn has no run (enqueue/preflight refusal); null once a run binds."),
775
+ createdAt: z.string().describe("When the turn was created."),
776
+ })
777
+ .describe("Control-plane projection of one thread turn with its embedded run card.");
778
+ export const ControlThreadCreateRequest = z
779
+ .object({
780
+ title: z.string().optional().describe("Initial thread title."),
781
+ scope: RunScope.default({ kind: "none" }),
782
+ mode: ModeKind.optional().describe("Default mode for new turns."),
783
+ workspace: WorkspaceMode.optional().describe("Workspace mode for the thread (in_place or isolated)."),
784
+ authPreference: AuthPreference.optional().describe("Per-thread auth preference override."),
785
+ primaryHarness: NonBlankString.optional().describe("Sticky primary harness for the thread."),
786
+ /** Sticky eligible pool for the thread; turns inherit it when unset. */
787
+ eligibleHarnesses: z.array(NonBlankString).optional().describe("Sticky eligible harness pool; turns inherit it when unset."),
788
+ })
789
+ .strict()
790
+ .describe("Request body for POST /threads.");
791
+ /** Mutate a thread's title, open/closed state, or sticky routing (rename,
792
+ * archive, switch primary/pool). primaryHarness nullable => clear back to auto. */
793
+ export const ControlThreadUpdateRequest = z
794
+ .object({
795
+ title: z.string().optional().describe("New thread title."),
796
+ state: ThreadState.optional().describe("New thread state (active/closed)."),
797
+ primaryHarness: NonBlankString.nullable().optional().describe("New sticky primary harness; null clears back to engine routing."),
798
+ eligibleHarnesses: z.array(NonBlankString).optional().describe("New sticky eligible harness pool."),
799
+ })
800
+ .strict()
801
+ .describe("Request body for PATCH /threads/:id: rename, archive, or switch sticky routing.");
802
+ /** Apply an isolated thread's accumulated worktree diff to the project. */
803
+ export const ControlThreadApplyRequest = z
804
+ .object({
805
+ mode: z
806
+ .enum(["apply", "branch", "commit", "pr"])
807
+ .default("apply")
808
+ .describe("Delivery mode: apply to the tree, or as a branch, commit, or PR."),
809
+ branch: z.string().optional().describe("Branch name for branch/pr modes."),
810
+ message: z.string().optional().describe("Commit message for commit/pr modes."),
811
+ })
812
+ .strict()
813
+ .describe("Request body applying an isolated thread's accumulated worktree diff to the project.");
814
+ export const ControlThreadApplyResponse = z
815
+ .object({
816
+ applied: z.boolean().describe("Whether anything was delivered."),
817
+ status: z
818
+ .enum(["applied", "branched", "committed", "pr_opened", "empty", "conflict", "rejected"])
819
+ .describe("Delivery outcome: applied, branched, committed, pr_opened, empty (no diff), conflict, or rejected."),
820
+ /** True when the project HEAD moved past the thread base since the thread started. */
821
+ headMoved: z.boolean().default(false).describe("True when the project HEAD moved past the thread base since the thread started."),
822
+ detail: z.string().nullable().default(null).describe("Human-readable detail."),
823
+ })
824
+ .describe("Response to a thread apply.");
825
+ export const ControlThreadListResponse = z
826
+ .object({
827
+ threads: z.array(ControlThread).default([]).describe("All threads."),
828
+ })
829
+ .describe("Response for GET /threads.");
830
+ export const ControlThreadDetail = z
831
+ .object({
832
+ thread: ControlThread,
833
+ sessions: z.array(ControlSession).default([]).describe("Vendor sessions bound to the thread."),
834
+ turns: z.array(ControlThreadTurn).default([]).describe("Turns of the conversation, in order."),
835
+ })
836
+ .describe("Full thread detail served by GET /threads/:id: the thread, its vendor sessions, and its turns.");
837
+ export const HarnessStatusDto = z
838
+ .object({
839
+ id: z.string().describe("Harness id."),
840
+ status: AdapterStatus,
841
+ manifest: HarnessManifest.nullable().optional().describe("The harness's declared manifest, when available."),
842
+ enabledIntents: z.array(z.string()).default([]).describe("Intents the gateway will route to this harness."),
843
+ disabledIntents: z.array(z.string()).default([]).describe("Intents the doctor disabled."),
844
+ checks: z.array(ConformanceCheck).default([]).describe("Doctor probe results."),
845
+ reasons: z.array(z.string()).default([]).describe("Human-readable reasons for degraded/unavailable status."),
846
+ /** The user's configured per-harness default model, if any. */
847
+ configuredModel: z.string().nullable().default(null).describe("The user's configured per-harness default model, if any."),
848
+ /** Strict truth-source check of `configuredModel`: null when no model
849
+ * is configured; a rejection carries the actionable message so UIs render
850
+ * the same honesty `claudexor doctor` prints. */
851
+ configuredModelCheck: z
852
+ .object({
853
+ status: z.enum(["ok", "rejected"]).describe("Whether the configured model passes the strict truth-source check."),
854
+ message: z.string().nullable().default(null).describe("Actionable rejection message, when rejected."),
855
+ })
856
+ .nullable()
857
+ .default(null)
858
+ .describe("Strict truth-source check of configuredModel; null when no model is configured."),
859
+ })
860
+ .describe("Doctor-backed status row for one harness: status, intents, checks, and configured-model validity.");
861
+ export const ControlHarnessListResponse = z
862
+ .object({
863
+ harnesses: z.array(HarnessStatusDto).default([]).describe("Status rows for all known harnesses."),
864
+ })
865
+ .describe("Response for GET /harnesses.");
866
+ /**
867
+ * Models enumerable for one harness. `source` is honest about provenance:
868
+ * "api" when the adapter implemented a real enumeration (raw-api / OpenAI
869
+ * `GET /v1/models`), "manifest" when the list is the manifest's known-good
870
+ * hint set, "none" when the harness has no model truth source at all (the
871
+ * list is then empty and explicit models are refused under strict model-truth validation).
872
+ */
873
+ export const ControlHarnessModelsResponse = z
874
+ .object({
875
+ harnessId: z.string().describe("Harness the models belong to."),
876
+ models: z.array(HarnessModel).default([]).describe("Enumerable models; empty when the harness has no model truth source."),
877
+ source: z
878
+ .enum(["api", "manifest", "none"])
879
+ .describe("Provenance of the list: api (a live vendor enumeration), manifest (the manifest's known-good hint set), or none (no model truth source; explicit models are refused)."),
880
+ /** Freshness note for manifest-sourced lists: the vendor CLI version the
881
+ * known-model hints were last verified against (null for api/none). */
882
+ verifiedAgainst: z
883
+ .string()
884
+ .nullable()
885
+ .default(null)
886
+ .describe("Vendor CLI version the manifest hints were last verified against; null for api/none sources."),
887
+ })
888
+ .describe("Models enumerable for one harness, with honest provenance.");
889
+ export const ControlSettingsSnapshot = z
890
+ .object({
891
+ sources: z.array(z.string()).default([]).describe("Config file paths that contributed to the snapshot."),
892
+ defaultPortfolio: Portfolio.default("subscription-first").describe("Budget portfolio used when a run does not specify one."),
893
+ /** How long a run waits for an interactive answer before a benign decline. */
894
+ interactionTimeoutMs: z
895
+ .number()
896
+ .int()
897
+ .positive()
898
+ .default(900_000)
899
+ .describe("How long a run waits for an interactive answer before a benign decline, in milliseconds."),
900
+ routing: z
901
+ .object({
902
+ defaultPolicy: z.enum(["auto", "primary"]).default("auto").describe("Default routing policy."),
903
+ primaryHarness: z.string().nullable().default(null).describe("Global default primary harness; null = engine decides."),
904
+ eligibleHarnesses: z.array(z.string()).default([]).describe("Harness pool eligible for routing/races; empty = all available."),
905
+ envInheritance: z
906
+ .enum(["mirror_native", "clean"])
907
+ .default("mirror_native")
908
+ .describe("How the child harness env is built: mirror_native inherits the shell env; clean spawns from a minimal allowlist."),
909
+ authPreference: AuthPreference.default("auto"),
910
+ })
911
+ .default({})
912
+ .describe("Global routing settings."),
913
+ budget: z
914
+ .object({
915
+ maxUsdPerRun: z.number().nullable().default(null).describe("Global USD cap per run; null = no cap."),
916
+ })
917
+ .default({})
918
+ .describe("Global budget limits."),
919
+ runtime: z
920
+ .object({
921
+ reviewerTimeoutMs: z.number().int().positive().default(600_000).describe("Wall-clock timeout for a reviewer run, in milliseconds."),
922
+ harnessInactivityTimeoutMs: z
923
+ .number()
924
+ .int()
925
+ .positive()
926
+ .default(1_200_000)
927
+ .describe("Inactivity watchdog for harness streams, in milliseconds."),
928
+ transientRetry: z
929
+ .object({
930
+ maxRetries: z.number().int().nonnegative().default(2).describe("Maximum retries for a transient failure."),
931
+ initialDelayMs: z.number().int().nonnegative().default(1_000).describe("Initial retry delay in milliseconds."),
932
+ maxDelayMs: z.number().int().nonnegative().default(10_000).describe("Maximum retry delay in milliseconds."),
933
+ })
934
+ .default({})
935
+ .describe("Bounded retry policy for transient failures."),
936
+ })
937
+ .default({})
938
+ .describe("Global runtime timeouts and retry policy."),
939
+ harnesses: z
940
+ .record(z.string(), z
941
+ .object({
942
+ enabled: z.boolean().default(true).describe("Whether the harness participates in routing."),
943
+ defaultModel: z.string().nullable().default(null).describe("Per-harness default model; null = the harness's own default."),
944
+ effort: EffortHint.nullable().default(null).describe("Default reasoning effort; null = harness default."),
945
+ maxTurns: z.number().int().positive().nullable().default(null).describe("Default max agent turns; null = no limit."),
946
+ maxRounds: z.number().int().positive().nullable().default(null).describe("Default max convergence rounds; null = engine default."),
947
+ maxUsd: z.number().nonnegative().nullable().default(null).describe("Per-harness USD cap; null = no cap."),
948
+ toolsAllow: z.array(z.string()).default([]).describe("Tool names allowed for this harness."),
949
+ toolsDeny: z.array(z.string()).default([]).describe("Tool names denied for this harness."),
950
+ fallbackModel: z.string().nullable().default(null).describe("Model to fall back to on typed fallback signals; null = none."),
951
+ web: ExternalContextPolicy.default("auto").describe("Default web policy for this harness."),
952
+ authPreference: AuthPreference.default("auto"),
953
+ })
954
+ .describe("Per-harness settings."))
955
+ .default({})
956
+ .describe("Per-harness settings keyed by harness id."),
957
+ })
958
+ .describe("Effective settings snapshot served by GET /settings.");
959
+ /**
960
+ * Partial per-harness settings patch; absent fields keep their stored value.
961
+ * STRICT: a typoed key must 400, not silently no-op (fail-loudly contract).
962
+ */
963
+ export const ControlHarnessSettingsPatch = z
964
+ .object({
965
+ enabled: z.boolean().optional().describe("Enable/disable the harness for routing."),
966
+ defaultModel: NonBlankString.nullable().optional().describe("New per-harness default model; null clears it."),
967
+ effort: EffortHint.nullable().optional().describe("New default reasoning effort; null clears it."),
968
+ maxTurns: z.number().int().positive().nullable().optional().describe("New max agent turns; null clears the limit."),
969
+ maxRounds: z.number().int().positive().nullable().optional().describe("New max convergence rounds; null clears it."),
970
+ maxUsd: z.number().nonnegative().nullable().optional().describe("New per-harness USD cap; null clears it."),
971
+ toolsAllow: z.array(NonBlankString).optional().describe("New tool allowlist."),
972
+ toolsDeny: z.array(NonBlankString).optional().describe("New tool denylist."),
973
+ fallbackModel: NonBlankString.nullable().optional().describe("New fallback model; null clears it."),
974
+ web: ExternalContextPolicy.optional().describe("New default web policy."),
975
+ authPreference: AuthPreference.optional().describe("New auth route preference."),
976
+ })
977
+ .strict()
978
+ .describe("Partial per-harness settings patch; absent fields keep their stored value, and a typoed key 400s (strict).");
979
+ export const ControlSettingsUpdateRequest = z
980
+ .object({
981
+ defaultPortfolio: Portfolio.optional(),
982
+ interactionTimeoutMs: z.number().int().positive().optional().describe("New interactive-answer timeout, in milliseconds."),
983
+ routingPolicy: z.enum(["auto", "primary"]).optional().describe("New default routing policy."),
984
+ primaryHarness: NonBlankString.nullable().optional().describe("New global primary harness; null clears back to engine routing."),
985
+ eligibleHarnesses: z.array(NonBlankString).optional().describe("New global eligible harness pool."),
986
+ envInheritance: z.enum(["mirror_native", "clean"]).optional().describe("New child harness env composition mode."),
987
+ maxUsdPerRun: z.number().nonnegative().optional().describe("New global USD cap per run (mutually exclusive with clearMaxUsdPerRun)."),
988
+ clearMaxUsdPerRun: z.boolean().optional().describe("Clear the global USD cap per run (mutually exclusive with maxUsdPerRun)."),
989
+ authPreference: AuthPreference.optional().describe("New global auth route preference."),
990
+ harnesses: z
991
+ .record(NonBlankString, ControlHarnessSettingsPatch)
992
+ .optional()
993
+ .describe("Per-harness settings patches keyed by harness id."),
994
+ })
995
+ .strict()
996
+ .superRefine((value, ctx) => {
997
+ if (value.maxUsdPerRun !== undefined && value.clearMaxUsdPerRun === true) {
998
+ ctx.addIssue({
999
+ code: z.ZodIssueCode.custom,
1000
+ path: ["maxUsdPerRun"],
1001
+ message: "maxUsdPerRun and clearMaxUsdPerRun are mutually exclusive",
1002
+ });
1003
+ }
1004
+ })
1005
+ .describe("Request body for PATCH /settings; absent fields keep their stored values.");
1006
+ /** Secret list row: exactly what the store's list() can honestly produce
1007
+ * (the never-populated harnesses/env/description fields were retired in the
1008
+ * v0.15 triage). */
1009
+ export const SecretMetadata = z
1010
+ .object({
1011
+ name: z.string().describe("Secret name/label."),
1012
+ backend: z.enum(["keychain", "file"]).describe("Where the secret is stored: the OS keychain or a file store."),
1013
+ present: z.boolean().default(true).describe("Whether a value is actually stored."),
1014
+ })
1015
+ .describe("Secret list row: name, storage backend, and presence — never the value.");
1016
+ export const ControlSecretListResponse = z
1017
+ .object({
1018
+ backend: z.enum(["keychain", "file"]).describe("Active secret store backend."),
1019
+ secrets: z.array(SecretMetadata).default([]).describe("Stored secrets (metadata only, never values)."),
1020
+ })
1021
+ .describe("Response for listing stored secrets (metadata only).");
1022
+ //# sourceMappingURL=control.js.map