agent-dealer 0.2.0 → 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 (276) hide show
  1. package/bundle/server/dist/adapters/agent-deck-bind.js +443 -0
  2. package/bundle/server/dist/adapters/agent-deck-bind.test.js +454 -0
  3. package/bundle/server/dist/adapters/agent-deck.js +38 -50
  4. package/bundle/server/dist/adapters/agent-deck.test.js +63 -0
  5. package/bundle/server/dist/adapters/agent-health.js +230 -33
  6. package/bundle/server/dist/adapters/agent-health.test.js +237 -0
  7. package/bundle/server/dist/adapters/authority-lifecycle.js +289 -0
  8. package/bundle/server/dist/adapters/codex-scoped-config.js +103 -0
  9. package/bundle/server/dist/adapters/execution-authority.js +103 -0
  10. package/bundle/server/dist/adapters/execution-authority.test.js +166 -0
  11. package/bundle/server/dist/adapters/external.js +0 -1
  12. package/bundle/server/dist/adapters/git-worktree.js +514 -0
  13. package/bundle/server/dist/adapters/git-worktree.test.js +502 -0
  14. package/bundle/server/dist/adapters/github.js +170 -0
  15. package/bundle/server/dist/adapters/github.test.js +205 -0
  16. package/bundle/server/dist/adapters/linear-inbox.js +199 -30
  17. package/bundle/server/dist/adapters/linear-inbox.test.js +35 -0
  18. package/bundle/server/dist/adapters/linear-sync.js +3 -101
  19. package/bundle/server/dist/adapters/managed-repo.js +168 -0
  20. package/bundle/server/dist/adapters/managed-repo.test.js +63 -0
  21. package/bundle/server/dist/adapters/outbound-delivery.js +83 -0
  22. package/bundle/server/dist/adapters/outbound-delivery.test.js +53 -0
  23. package/bundle/server/dist/adapters/reflect-authority.js +43 -0
  24. package/bundle/server/dist/cli-env.js +26 -0
  25. package/bundle/server/dist/cli-env.test.js +14 -1
  26. package/bundle/server/dist/coordinator/abort.integration.test.js +74 -0
  27. package/bundle/server/dist/coordinator/admission.js +330 -0
  28. package/bundle/server/dist/coordinator/admission.test.js +338 -0
  29. package/bundle/server/dist/coordinator/args.js +128 -0
  30. package/bundle/server/dist/coordinator/args.test.js +132 -0
  31. package/bundle/server/dist/coordinator/authority-recovery.integration.test.js +661 -0
  32. package/bundle/server/dist/coordinator/auto-merge.integration.test.js +363 -0
  33. package/bundle/server/dist/coordinator/auto-merge.js +286 -0
  34. package/bundle/server/dist/coordinator/auto-merge.timeout.test.js +14 -0
  35. package/bundle/server/dist/coordinator/branch-progress.js +81 -0
  36. package/bundle/server/dist/coordinator/clock-jump.js +98 -0
  37. package/bundle/server/dist/coordinator/commands.js +1088 -0
  38. package/bundle/server/dist/coordinator/commands.test.js +554 -0
  39. package/bundle/server/dist/coordinator/deck-outage-config.js +32 -0
  40. package/bundle/server/dist/coordinator/deck-outage.integration.test.js +200 -0
  41. package/bundle/server/dist/coordinator/dependencies.js +242 -0
  42. package/bundle/server/dist/coordinator/dependency-readiness.integration.test.js +535 -0
  43. package/bundle/server/dist/coordinator/developer-effect.js +959 -0
  44. package/bundle/server/dist/coordinator/developer-effect.test.js +1143 -0
  45. package/bundle/server/dist/coordinator/dispatcher.js +58 -0
  46. package/bundle/server/dist/coordinator/dispatcher.test.js +81 -0
  47. package/bundle/server/dist/coordinator/effect-registry.js +17 -0
  48. package/bundle/server/dist/coordinator/execution-env.integration.test.js +122 -0
  49. package/bundle/server/dist/coordinator/failure-reason.js +273 -0
  50. package/bundle/server/dist/coordinator/failure-reason.test.js +234 -0
  51. package/bundle/server/dist/coordinator/guidance.js +33 -0
  52. package/bundle/server/dist/coordinator/guidance.test.js +110 -0
  53. package/bundle/server/dist/coordinator/human-resolution.js +88 -0
  54. package/bundle/server/dist/coordinator/human-resolution.test.js +72 -0
  55. package/bundle/server/dist/coordinator/intent-forecast.js +13 -0
  56. package/bundle/server/dist/coordinator/intent-forecast.test.js +34 -0
  57. package/bundle/server/dist/coordinator/latest-failure.js +100 -0
  58. package/bundle/server/dist/coordinator/latest-failure.test.js +125 -0
  59. package/bundle/server/dist/coordinator/metrics.js +35 -0
  60. package/bundle/server/dist/coordinator/metrics.test.js +52 -0
  61. package/bundle/server/dist/coordinator/permissions.js +127 -0
  62. package/bundle/server/dist/coordinator/permissions.test.js +184 -0
  63. package/bundle/server/dist/coordinator/presumed-dead-budget.integration.test.js +146 -0
  64. package/bundle/server/dist/coordinator/process-liveness.js +191 -0
  65. package/bundle/server/dist/coordinator/profile-snapshot.js +20 -0
  66. package/bundle/server/dist/coordinator/profile-snapshot.test.js +118 -0
  67. package/bundle/server/dist/coordinator/projection.js +147 -0
  68. package/bundle/server/dist/coordinator/projection.test.js +121 -0
  69. package/bundle/server/dist/coordinator/prompts.js +164 -0
  70. package/bundle/server/dist/coordinator/prompts.test.js +177 -0
  71. package/bundle/server/dist/coordinator/queue-by-default.integration.test.js +271 -0
  72. package/bundle/server/dist/coordinator/reclaim-republish.integration.test.js +372 -0
  73. package/bundle/server/dist/coordinator/recovery.js +466 -0
  74. package/bundle/server/dist/coordinator/recovery.test.js +164 -0
  75. package/bundle/server/dist/coordinator/reflect-trigger.js +218 -0
  76. package/bundle/server/dist/coordinator/reflect-trigger.test.js +324 -0
  77. package/bundle/server/dist/coordinator/repair-cycle.integration.test.js +234 -0
  78. package/bundle/server/dist/coordinator/restart-recovery.integration.test.js +363 -0
  79. package/bundle/server/dist/coordinator/reviewer-effect.js +507 -0
  80. package/bundle/server/dist/coordinator/reviewer-effect.test.js +612 -0
  81. package/bundle/server/dist/coordinator/reviewer-result.js +38 -0
  82. package/bundle/server/dist/coordinator/reviewer-result.test.js +45 -0
  83. package/bundle/server/dist/coordinator/routing.js +160 -0
  84. package/bundle/server/dist/coordinator/routing.test.js +336 -0
  85. package/bundle/server/dist/coordinator/session-lifecycle.integration.test.js +127 -0
  86. package/bundle/server/dist/coordinator/session-lifecycle.js +280 -0
  87. package/bundle/server/dist/coordinator/session-lifecycle.test.js +121 -0
  88. package/bundle/server/dist/coordinator/session-progress.js +351 -0
  89. package/bundle/server/dist/coordinator/session-progress.test.js +190 -0
  90. package/bundle/server/dist/coordinator/session-timeouts.js +33 -0
  91. package/bundle/server/dist/coordinator/sleep-recovery.integration.test.js +233 -0
  92. package/bundle/server/dist/coordinator/spawn.js +49 -0
  93. package/bundle/server/dist/coordinator/sync-issue-base-branch.js +18 -0
  94. package/bundle/server/dist/coordinator/usage-cap-config.js +10 -0
  95. package/bundle/server/dist/coordinator/usage-cap-defer.js +189 -0
  96. package/bundle/server/dist/coordinator/usage-cap.integration.test.js +193 -0
  97. package/bundle/server/dist/coordinator/usage.js +40 -0
  98. package/bundle/server/dist/coordinator/usage.test.js +69 -0
  99. package/bundle/server/dist/coordinator/verification-receipt.js +333 -0
  100. package/bundle/server/dist/coordinator/verification-receipt.test.js +382 -0
  101. package/bundle/server/dist/coordinator/worker-loop.js +363 -0
  102. package/bundle/server/dist/coordinator/worker-loop.test.js +327 -0
  103. package/bundle/server/dist/coordinator/workflow-instances.test.js +45 -0
  104. package/bundle/server/dist/coordinator/worktree-owner-liveness.js +82 -0
  105. package/bundle/server/dist/coordinator/worktree-owner-liveness.test.js +199 -0
  106. package/bundle/server/dist/db/artifacts-issue-columns.test.js +18 -0
  107. package/bundle/server/dist/db/authority-attempts-stale-at-migration.test.js +65 -0
  108. package/bundle/server/dist/db/idempotency-index-migration.test.js +57 -0
  109. package/bundle/server/dist/db/index.js +359 -7
  110. package/bundle/server/dist/db/linear-inbox-unlock.test.js +67 -0
  111. package/bundle/server/dist/db/migrate-to-issues.js +824 -0
  112. package/bundle/server/dist/db/migrate-to-issues.test.js +842 -0
  113. package/bundle/server/dist/db/schema.sql +311 -1
  114. package/bundle/server/dist/db/schema.test.js +66 -0
  115. package/bundle/server/dist/db/worker-session-pid-migration.test.js +112 -0
  116. package/bundle/server/dist/dev-review-cli-happy-path.integration.test.js +338 -0
  117. package/bundle/server/dist/direct-start-liveness.integration.test.js +350 -0
  118. package/bundle/server/dist/index.js +58 -5
  119. package/bundle/server/dist/paths.js +40 -4
  120. package/bundle/server/dist/paths.test.js +42 -0
  121. package/bundle/server/dist/pid-marker-claim-child.js +18 -0
  122. package/bundle/server/dist/pid-marker-hold-arbiter-child.js +24 -0
  123. package/bundle/server/dist/pid-marker.js +141 -0
  124. package/bundle/server/dist/pid-marker.test.js +208 -0
  125. package/bundle/server/dist/queue/approve-deliver.js +128 -28
  126. package/bundle/server/dist/queue/reflect-schedule.js +25 -0
  127. package/bundle/server/dist/queue/result-qa.js +1 -1
  128. package/bundle/server/dist/queue/send-gate.test.js +172 -36
  129. package/bundle/server/dist/repository/agents.js +55 -18
  130. package/bundle/server/dist/repository/artifacts-for-issue.js +42 -0
  131. package/bundle/server/dist/repository/artifacts-for-issue.test.js +48 -0
  132. package/bundle/server/dist/repository/artifacts.js +47 -0
  133. package/bundle/server/dist/repository/artifacts.test.js +48 -0
  134. package/bundle/server/dist/repository/authority-attempts.js +189 -0
  135. package/bundle/server/dist/repository/findings.js +70 -0
  136. package/bundle/server/dist/repository/findings.test.js +68 -0
  137. package/bundle/server/dist/repository/human-actions.js +142 -0
  138. package/bundle/server/dist/repository/human-actions.test.js +123 -0
  139. package/bundle/server/dist/repository/intake-settings.js +5 -59
  140. package/bundle/server/dist/repository/issues.js +305 -0
  141. package/bundle/server/dist/repository/issues.test.js +69 -0
  142. package/bundle/server/dist/repository/outbound-drafts.js +28 -0
  143. package/bundle/server/dist/repository/queue-entries.js +162 -0
  144. package/bundle/server/dist/repository/review-publications.js +153 -0
  145. package/bundle/server/dist/repository/review-publications.test.js +78 -0
  146. package/bundle/server/dist/repository/runs-external-id.test.js +5 -3
  147. package/bundle/server/dist/repository/runs.js +4 -211
  148. package/bundle/server/dist/repository/runtime-availability.js +54 -0
  149. package/bundle/server/dist/repository/usage-events.js +60 -0
  150. package/bundle/server/dist/repository/usage-events.test.js +56 -0
  151. package/bundle/server/dist/repository/work-items.js +305 -0
  152. package/bundle/server/dist/repository/work-items.test.js +142 -0
  153. package/bundle/server/dist/repository/worker-sessions.js +219 -0
  154. package/bundle/server/dist/repository/worker-sessions.test.js +60 -0
  155. package/bundle/server/dist/repository/workflow-events.js +193 -0
  156. package/bundle/server/dist/repository/workflow-events.test.js +89 -0
  157. package/bundle/server/dist/resolve-tsx-bin.js +19 -0
  158. package/bundle/server/dist/routes/human-actions.js +68 -0
  159. package/bundle/server/dist/routes/human-actions.test.js +284 -0
  160. package/bundle/server/dist/routes/index.js +29 -496
  161. package/bundle/server/dist/routes/issues.js +240 -0
  162. package/bundle/server/dist/routes/issues.test.js +451 -0
  163. package/bundle/server/dist/routes/queue.js +41 -0
  164. package/bundle/server/dist/routes/queue.test.js +78 -0
  165. package/bundle/server/dist/runners/claude-args.js +18 -30
  166. package/bundle/server/dist/runners/claude.js +19 -163
  167. package/bundle/server/dist/runners/claude.test.js +15 -70
  168. package/bundle/server/dist/runners/codex-args.js +59 -0
  169. package/bundle/server/dist/runners/codex-args.test.js +72 -0
  170. package/bundle/server/dist/runners/codex-jsonl.js +150 -0
  171. package/bundle/server/dist/runners/codex-jsonl.test.js +36 -0
  172. package/bundle/server/dist/runners/codex-resume.test.js +19 -0
  173. package/bundle/server/dist/runners/codex.js +46 -0
  174. package/bundle/server/dist/runners/models-codex.test.js +14 -0
  175. package/bundle/server/dist/runners/models.js +53 -1
  176. package/bundle/server/dist/runners/persist.js +4 -1
  177. package/bundle/server/dist/runners/process-registry.js +11 -0
  178. package/bundle/server/dist/runners/prompts.js +13 -280
  179. package/bundle/server/dist/runners/prompts.test.js +22 -153
  180. package/bundle/server/dist/runners/qa.js +17 -1
  181. package/bundle/server/dist/runners/reflect.js +4 -16
  182. package/bundle/server/dist/runners/spawn-cli.js +197 -0
  183. package/bundle/server/dist/runners/spawn-cli.test.js +130 -0
  184. package/bundle/server/dist/runners/stream-json.js +0 -141
  185. package/bundle/server/dist/runners/usage-cap.js +242 -0
  186. package/bundle/server/dist/runners/usage-cap.test.js +97 -0
  187. package/bundle/server/dist/server-liveness.js +37 -0
  188. package/bundle/server/dist/server-liveness.test.js +82 -0
  189. package/bundle/server/dist/static-ui.test.js +44 -0
  190. package/bundle/server/package.json +4 -2
  191. package/bundle/server/static-ui/assets/index-BTtPGYpY.js +60 -0
  192. package/bundle/server/static-ui/assets/index-BxTx4b1d.css +1 -0
  193. package/bundle/server/static-ui/index.html +2 -2
  194. package/bundle/shared/dist/agents.d.ts +262 -133
  195. package/bundle/shared/dist/agents.js +85 -19
  196. package/bundle/shared/dist/cursor-auth-health.d.ts +12 -0
  197. package/bundle/shared/dist/cursor-auth-health.js +36 -0
  198. package/bundle/shared/dist/cursor-auth-health.test.d.ts +1 -0
  199. package/bundle/shared/dist/cursor-auth-health.test.js +40 -0
  200. package/bundle/shared/dist/findings.d.ts +46 -0
  201. package/bundle/shared/dist/findings.js +17 -0
  202. package/bundle/shared/dist/findings.test.d.ts +1 -0
  203. package/bundle/shared/dist/findings.test.js +20 -0
  204. package/bundle/shared/dist/github-repo.d.ts +28 -0
  205. package/bundle/shared/dist/github-repo.js +98 -0
  206. package/bundle/shared/dist/github-repo.test.d.ts +1 -0
  207. package/bundle/shared/dist/github-repo.test.js +32 -0
  208. package/bundle/shared/dist/human-actions.d.ts +66 -0
  209. package/bundle/shared/dist/human-actions.js +51 -0
  210. package/bundle/shared/dist/human-actions.test.d.ts +1 -0
  211. package/bundle/shared/dist/human-actions.test.js +57 -0
  212. package/bundle/shared/dist/index.d.ts +567 -757
  213. package/bundle/shared/dist/index.js +22 -36
  214. package/bundle/shared/dist/issues.d.ts +385 -0
  215. package/bundle/shared/dist/issues.js +169 -0
  216. package/bundle/shared/dist/issues.test.d.ts +1 -0
  217. package/bundle/shared/dist/issues.test.js +72 -0
  218. package/bundle/shared/dist/outbound-draft.d.ts +6 -0
  219. package/bundle/shared/dist/outbound-draft.js +4 -0
  220. package/bundle/shared/dist/plan-triage.d.ts +6 -6
  221. package/bundle/shared/dist/profile-snapshot.d.ts +154 -0
  222. package/bundle/shared/dist/profile-snapshot.js +145 -0
  223. package/bundle/shared/dist/profile-snapshot.test.d.ts +1 -0
  224. package/bundle/shared/dist/profile-snapshot.test.js +67 -0
  225. package/bundle/shared/dist/queue-entries.d.ts +89 -0
  226. package/bundle/shared/dist/queue-entries.js +19 -0
  227. package/bundle/shared/dist/result-qa.d.ts +2 -2
  228. package/bundle/shared/dist/runtime-auth-health.d.ts +66 -0
  229. package/bundle/shared/dist/runtime-auth-health.js +186 -0
  230. package/bundle/shared/dist/runtime-auth-health.test.d.ts +1 -0
  231. package/bundle/shared/dist/runtime-auth-health.test.js +200 -0
  232. package/bundle/shared/dist/runtime-availability.d.ts +51 -0
  233. package/bundle/shared/dist/runtime-availability.js +13 -0
  234. package/bundle/shared/dist/runtime.d.ts +1 -1
  235. package/bundle/shared/dist/runtime.js +1 -1
  236. package/bundle/shared/dist/usage-events.d.ts +36 -0
  237. package/bundle/shared/dist/usage-events.js +13 -0
  238. package/bundle/shared/dist/worker-sessions.d.ts +140 -0
  239. package/bundle/shared/dist/worker-sessions.js +70 -0
  240. package/bundle/shared/dist/worker-sessions.test.d.ts +1 -0
  241. package/bundle/shared/dist/worker-sessions.test.js +39 -0
  242. package/bundle/shared/dist/workflow.d.ts +78 -0
  243. package/bundle/shared/dist/workflow.js +59 -0
  244. package/bundle/shared/dist/workflow.test.d.ts +1 -0
  245. package/bundle/shared/dist/workflow.test.js +61 -0
  246. package/bundle/shared/package.json +1 -1
  247. package/dist/action.d.ts +1 -0
  248. package/dist/action.js +50 -0
  249. package/dist/action.test.d.ts +1 -0
  250. package/dist/action.test.js +70 -0
  251. package/dist/agent.d.ts +1 -0
  252. package/dist/agent.js +17 -0
  253. package/dist/agent.test.d.ts +1 -0
  254. package/dist/agent.test.js +19 -0
  255. package/dist/cli-check.d.ts +7 -0
  256. package/dist/cli-check.js +40 -0
  257. package/dist/doctor.js +59 -1
  258. package/dist/http.d.ts +5 -0
  259. package/dist/http.js +19 -0
  260. package/dist/index.js +28 -0
  261. package/dist/issue.d.ts +35 -0
  262. package/dist/issue.js +143 -0
  263. package/dist/issue.test.d.ts +1 -0
  264. package/dist/issue.test.js +240 -0
  265. package/dist/lifecycle.contract.test.d.ts +1 -0
  266. package/dist/lifecycle.contract.test.js +135 -0
  267. package/dist/queue.d.ts +11 -0
  268. package/dist/queue.js +60 -0
  269. package/dist/queue.test.d.ts +1 -0
  270. package/dist/queue.test.js +46 -0
  271. package/dist/test-fetch-stub.d.ts +6 -0
  272. package/dist/test-fetch-stub.js +31 -0
  273. package/package.json +2 -1
  274. package/templates/prod.env.example +1 -1
  275. package/bundle/server/static-ui/assets/index-B_7S7xJb.js +0 -79
  276. package/bundle/server/static-ui/assets/index-QYv3zmE6.css +0 -1
@@ -4,12 +4,21 @@ import { AgentWithHealth } from "./agents.js";
4
4
  import { PhaseBudget, RunBudget } from "./budget.js";
5
5
  export * from "./runtime.js";
6
6
  export * from "./agents.js";
7
+ export * from "./runtime-auth-health.js";
7
8
  export * from "./budget.js";
8
9
  export * from "./execution.js";
9
- export * from "./plan-triage.js";
10
10
  export * from "./outbound-draft.js";
11
- export * from "./result-qa.js";
12
11
  export * from "./playbook-reflect.js";
12
+ export * from "./issues.js";
13
+ export * from "./github-repo.js";
14
+ export * from "./worker-sessions.js";
15
+ export * from "./profile-snapshot.js";
16
+ export * from "./workflow.js";
17
+ export * from "./human-actions.js";
18
+ export * from "./findings.js";
19
+ export * from "./usage-events.js";
20
+ export * from "./runtime-availability.js";
21
+ export * from "./queue-entries.js";
13
22
  export const RunStatus = z.enum([
14
23
  "queued",
15
24
  "plan_pending",
@@ -248,51 +257,26 @@ export const LinearCandidate = z.object({
248
257
  labels: z.array(z.string()).optional(),
249
258
  teamId: z.string().optional(),
250
259
  });
251
- export const LinearRoutingRule = z.object({
252
- label: z.string().min(1),
253
- agentId: z.string().uuid(),
254
- });
260
+ // NOT-71: defaultAgentId and routingRules (label -> agent `autoAgent` routing) are gone
261
+ // with intake/agent-routing.ts and the promote endpoint that consumed them. The persisted
262
+ // `linear.defaultAgentId` / `linear.routingRules` rows are left in intake_settings — this
263
+ // ticket removes no user data — but nothing reads them into the config any more.
255
264
  export const LinearIntakeConfig = z.object({
256
265
  stateFilter: z.array(z.string()),
257
266
  teamId: z.string().nullable(),
258
267
  assigneeMe: z.boolean(),
259
- defaultAgentId: z.string().uuid().nullable(),
260
268
  syncEnabled: z.boolean(),
261
- routingRules: z.array(LinearRoutingRule),
262
- });
263
- /** GET /api/intake/linear/config — effective config plus persistence hints for the UI */
264
- export const LinearIntakeConfigView = LinearIntakeConfig.extend({
265
- persisted: LinearIntakeConfig,
266
- envOverrides: z.object({
267
- stateFilter: z.boolean(),
268
- teamId: z.boolean(),
269
- }),
270
- });
271
- export const LinearIntakeConfigPatch = LinearIntakeConfig.partial();
272
- export const LinearConnectionStatus = z.object({
273
- connected: z.boolean(),
274
- viewer: z
275
- .object({
276
- id: z.string(),
277
- name: z.string(),
278
- email: z.string().optional(),
279
- })
280
- .optional(),
281
- error: z.string().optional(),
282
- });
283
- export const ResolveAgentResult = z.object({
284
- agentId: z.string().uuid(),
285
- reason: z.string(),
286
269
  });
287
270
  export const AgentDeckConfig = z.object({
288
271
  host: z.string(),
289
272
  port: z.number().int().min(1).max(65535),
290
273
  envOverride: z.boolean(),
291
274
  });
292
- export const AgentDeckConfigPatch = z.object({
293
- host: z.string().min(1).optional(),
294
- port: z.number().int().min(1).max(65535).optional(),
295
- });
275
+ /** Typed outcomes for deck-metadata discovery — never collapse to an empty list. */
276
+ export const DeckAccessErrorCode = z.enum([
277
+ "UNAUTHORIZED",
278
+ "DECK_UNAVAILABLE",
279
+ ]);
296
280
  export const AgentDeckStatus = z.object({
297
281
  connected: z.boolean(),
298
282
  apiUrl: z.string(),
@@ -300,6 +284,8 @@ export const AgentDeckStatus = z.object({
300
284
  deckCount: z.number().optional(),
301
285
  envOverride: z.boolean(),
302
286
  error: z.string().optional(),
287
+ deckAccessError: DeckAccessErrorCode.optional(),
288
+ deckAccessErrorMessage: z.string().optional(),
303
289
  });
304
290
  export const PromoteLinearInput = z
305
291
  .object({
@@ -0,0 +1,385 @@
1
+ import { z } from "zod";
2
+ export declare const IssueStatus: z.ZodEnum<["ready", "developing", "reviewing", "repairing", "final_review", "needs_human", "done", "closed"]>;
3
+ export type IssueStatus = z.infer<typeof IssueStatus>;
4
+ export declare const IssueOwner: z.ZodEnum<["human", "developer", "reviewer", "system"]>;
5
+ export type IssueOwner = z.infer<typeof IssueOwner>;
6
+ /** "agent" covers an issue a coding agent created via the API/CLI (PRD §5). */
7
+ export declare const IssueSource: z.ZodEnum<["manual", "linear", "agent"]>;
8
+ export type IssueSource = z.infer<typeof IssueSource>;
9
+ export declare const Issue: z.ZodObject<{
10
+ id: z.ZodString;
11
+ source: z.ZodEnum<["manual", "linear", "agent"]>;
12
+ externalId: z.ZodNullable<z.ZodString>;
13
+ externalLabel: z.ZodNullable<z.ZodString>;
14
+ externalUrl: z.ZodNullable<z.ZodString>;
15
+ title: z.ZodString;
16
+ description: z.ZodNullable<z.ZodString>;
17
+ acceptanceCriteria: z.ZodNullable<z.ZodString>;
18
+ /**
19
+ * Portable GitHub identity (`github.com/owner/repo`) for new issues (NOT-149).
20
+ * Legacy rows may still hold a local filesystem path until explicitly migrated —
21
+ * the coordinator resolves those via an explicit compatibility path, never by guessing.
22
+ */
23
+ repo: z.ZodString;
24
+ baseBranch: z.ZodString;
25
+ status: z.ZodEnum<["ready", "developing", "reviewing", "repairing", "final_review", "needs_human", "done", "closed"]>;
26
+ currentOwner: z.ZodEnum<["human", "developer", "reviewer", "system"]>;
27
+ currentIntent: z.ZodNullable<z.ZodString>;
28
+ developerAgentId: z.ZodNullable<z.ZodString>;
29
+ reviewerAgentId: z.ZodNullable<z.ZodString>;
30
+ maxReviewRounds: z.ZodNumber;
31
+ currentRound: z.ZodNumber;
32
+ /** 0 is a valid policy: no automatic infra retry, escalate to a human immediately. */
33
+ maxInfraAttempts: z.ZodNumber;
34
+ infraAttempts: z.ZodNumber;
35
+ branch: z.ZodNullable<z.ZodString>;
36
+ baseSha: z.ZodNullable<z.ZodString>;
37
+ headSha: z.ZodNullable<z.ZodString>;
38
+ prNumber: z.ZodNullable<z.ZodNumber>;
39
+ prUrl: z.ZodNullable<z.ZodString>;
40
+ /**
41
+ * When true, reviewer `approved` merges the PR and marks the issue done (skips
42
+ * `final_review`). Kick UI defaults this on; API/CLI omit → false so existing
43
+ * callers keep the human final-review path.
44
+ */
45
+ autoMerge: z.ZodBoolean;
46
+ createdAt: z.ZodString;
47
+ updatedAt: z.ZodString;
48
+ }, "strip", z.ZodTypeAny, {
49
+ status: "done" | "final_review" | "ready" | "developing" | "reviewing" | "repairing" | "needs_human" | "closed";
50
+ id: string;
51
+ createdAt: string;
52
+ updatedAt: string;
53
+ title: string;
54
+ source: "manual" | "linear" | "agent";
55
+ externalId: string | null;
56
+ externalLabel: string | null;
57
+ externalUrl: string | null;
58
+ description: string | null;
59
+ acceptanceCriteria: string | null;
60
+ repo: string;
61
+ baseBranch: string;
62
+ currentOwner: "developer" | "reviewer" | "human" | "system";
63
+ currentIntent: string | null;
64
+ developerAgentId: string | null;
65
+ reviewerAgentId: string | null;
66
+ maxReviewRounds: number;
67
+ currentRound: number;
68
+ maxInfraAttempts: number;
69
+ infraAttempts: number;
70
+ branch: string | null;
71
+ baseSha: string | null;
72
+ headSha: string | null;
73
+ prNumber: number | null;
74
+ prUrl: string | null;
75
+ autoMerge: boolean;
76
+ }, {
77
+ status: "done" | "final_review" | "ready" | "developing" | "reviewing" | "repairing" | "needs_human" | "closed";
78
+ id: string;
79
+ createdAt: string;
80
+ updatedAt: string;
81
+ title: string;
82
+ source: "manual" | "linear" | "agent";
83
+ externalId: string | null;
84
+ externalLabel: string | null;
85
+ externalUrl: string | null;
86
+ description: string | null;
87
+ acceptanceCriteria: string | null;
88
+ repo: string;
89
+ baseBranch: string;
90
+ currentOwner: "developer" | "reviewer" | "human" | "system";
91
+ currentIntent: string | null;
92
+ developerAgentId: string | null;
93
+ reviewerAgentId: string | null;
94
+ maxReviewRounds: number;
95
+ currentRound: number;
96
+ maxInfraAttempts: number;
97
+ infraAttempts: number;
98
+ branch: string | null;
99
+ baseSha: string | null;
100
+ headSha: string | null;
101
+ prNumber: number | null;
102
+ prUrl: string | null;
103
+ autoMerge: boolean;
104
+ }>;
105
+ export type Issue = z.infer<typeof Issue>;
106
+ export declare const CreateIssueInput: z.ZodObject<{
107
+ title: z.ZodString;
108
+ description: z.ZodOptional<z.ZodString>;
109
+ acceptanceCriteria: z.ZodOptional<z.ZodString>;
110
+ /** GitHub URL or `owner/repo` — normalized to `github.com/owner/repo` on parse. */
111
+ repo: z.ZodEffects<z.ZodString, string, string>;
112
+ baseBranch: z.ZodDefault<z.ZodString>;
113
+ developerAgentId: z.ZodString;
114
+ reviewerAgentId: z.ZodString;
115
+ maxReviewRounds: z.ZodDefault<z.ZodNumber>;
116
+ maxInfraAttempts: z.ZodDefault<z.ZodNumber>;
117
+ /** Kick UI sends true; omit/false preserves final_review after approve. */
118
+ autoMerge: z.ZodDefault<z.ZodBoolean>;
119
+ source: z.ZodDefault<z.ZodEnum<["manual", "linear", "agent"]>>;
120
+ externalId: z.ZodOptional<z.ZodString>;
121
+ externalLabel: z.ZodOptional<z.ZodString>;
122
+ externalUrl: z.ZodOptional<z.ZodString>;
123
+ /**
124
+ * NOT-118: a create directive, not an issue field — the route enqueues the new issue for
125
+ * admission by default so creating one never starts a workflow behind the queue's back.
126
+ * `false` creates a draft that sits outside the queue until someone adds or starts it.
127
+ */
128
+ enqueue: z.ZodDefault<z.ZodBoolean>;
129
+ }, "strip", z.ZodTypeAny, {
130
+ title: string;
131
+ source: "manual" | "linear" | "agent";
132
+ repo: string;
133
+ baseBranch: string;
134
+ developerAgentId: string;
135
+ reviewerAgentId: string;
136
+ maxReviewRounds: number;
137
+ maxInfraAttempts: number;
138
+ autoMerge: boolean;
139
+ enqueue: boolean;
140
+ externalId?: string | undefined;
141
+ externalLabel?: string | undefined;
142
+ externalUrl?: string | undefined;
143
+ description?: string | undefined;
144
+ acceptanceCriteria?: string | undefined;
145
+ }, {
146
+ title: string;
147
+ repo: string;
148
+ developerAgentId: string;
149
+ reviewerAgentId: string;
150
+ source?: "manual" | "linear" | "agent" | undefined;
151
+ externalId?: string | undefined;
152
+ externalLabel?: string | undefined;
153
+ externalUrl?: string | undefined;
154
+ description?: string | undefined;
155
+ acceptanceCriteria?: string | undefined;
156
+ baseBranch?: string | undefined;
157
+ maxReviewRounds?: number | undefined;
158
+ maxInfraAttempts?: number | undefined;
159
+ autoMerge?: boolean | undefined;
160
+ enqueue?: boolean | undefined;
161
+ }>;
162
+ /** Wire/API body shape — defaults applied by `CreateIssueInput.parse` / repository. */
163
+ export type CreateIssueInput = z.input<typeof CreateIssueInput>;
164
+ /** Pre-start (or parked-on-`needs_human`) edits only — the route enforces no active
165
+ * workflow instance; status/owner/intent/branch/SHA/PR stay coordinator-owned. */
166
+ export declare const UpdateIssueInput: z.ZodObject<{
167
+ title: z.ZodOptional<z.ZodString>;
168
+ description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
169
+ acceptanceCriteria: z.ZodOptional<z.ZodNullable<z.ZodString>>;
170
+ repo: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
171
+ baseBranch: z.ZodOptional<z.ZodString>;
172
+ developerAgentId: z.ZodOptional<z.ZodString>;
173
+ reviewerAgentId: z.ZodOptional<z.ZodString>;
174
+ maxReviewRounds: z.ZodOptional<z.ZodNumber>;
175
+ maxInfraAttempts: z.ZodOptional<z.ZodNumber>;
176
+ autoMerge: z.ZodOptional<z.ZodBoolean>;
177
+ }, "strip", z.ZodTypeAny, {
178
+ title?: string | undefined;
179
+ description?: string | null | undefined;
180
+ acceptanceCriteria?: string | null | undefined;
181
+ repo?: string | undefined;
182
+ baseBranch?: string | undefined;
183
+ developerAgentId?: string | undefined;
184
+ reviewerAgentId?: string | undefined;
185
+ maxReviewRounds?: number | undefined;
186
+ maxInfraAttempts?: number | undefined;
187
+ autoMerge?: boolean | undefined;
188
+ }, {
189
+ title?: string | undefined;
190
+ description?: string | null | undefined;
191
+ acceptanceCriteria?: string | null | undefined;
192
+ repo?: string | undefined;
193
+ baseBranch?: string | undefined;
194
+ developerAgentId?: string | undefined;
195
+ reviewerAgentId?: string | undefined;
196
+ maxReviewRounds?: number | undefined;
197
+ maxInfraAttempts?: number | undefined;
198
+ autoMerge?: boolean | undefined;
199
+ }>;
200
+ export type UpdateIssueInput = z.infer<typeof UpdateIssueInput>;
201
+ /**
202
+ * Guard rails only — which status the coordinator may move an issue to next.
203
+ * The *specific* target within an allowed set (e.g. which needs_human resolution
204
+ * leads where) is coordinator business logic, not encoded here, mirroring how
205
+ * VALID_TRANSITIONS works for the legacy RunStatus table today.
206
+ */
207
+ export declare const ISSUE_STATUS_TRANSITIONS: Record<IssueStatus, IssueStatus[]>;
208
+ export declare function canTransitionIssue(from: IssueStatus, to: IssueStatus): boolean;
209
+ /**
210
+ * The statuses a pass can never leave — derived from the transition table so the two cannot
211
+ * drift. "Terminal" is a property of the *local* issue row, not of the upstream ticket: a
212
+ * closed dealer issue for a still-open Linear ticket is the normal case a re-import serves
213
+ * (NOT-141).
214
+ */
215
+ export declare const TERMINAL_ISSUE_STATUSES: readonly IssueStatus[];
216
+ /** Membership test for {@link TERMINAL_ISSUE_STATUSES} — false means the pass can still move. */
217
+ export declare function isTerminalIssueStatus(status: IssueStatus): boolean;
218
+ /**
219
+ * What the request did to the admission queue — the *mutation*, not the intent. `enqueue`
220
+ * is idempotent, so a re-import of an already-queued issue changes nothing; reporting that
221
+ * as "queued" is how the CLI came to announce a queue action for a request that queued
222
+ * nothing (NOT-141).
223
+ */
224
+ export declare const QueueOutcome: z.ZodEnum<["enqueued", "already_queued", "not_queued"]>;
225
+ export type QueueOutcome = z.infer<typeof QueueOutcome>;
226
+ /**
227
+ * NOT-141: `POST /api/issues` answers with the issue *plus* what the server did with it.
228
+ * `created: false` means the request matched a live issue for the same `(source,
229
+ * externalId)` and re-enqueued it instead of making a second row — without these flags a
230
+ * caller cannot tell an import from a no-op, and the CLI printed "Queued for admission" for
231
+ * requests that queued nothing.
232
+ */
233
+ export declare const CreateIssueResult: z.ZodObject<{
234
+ id: z.ZodString;
235
+ source: z.ZodEnum<["manual", "linear", "agent"]>;
236
+ externalId: z.ZodNullable<z.ZodString>;
237
+ externalLabel: z.ZodNullable<z.ZodString>;
238
+ externalUrl: z.ZodNullable<z.ZodString>;
239
+ title: z.ZodString;
240
+ description: z.ZodNullable<z.ZodString>;
241
+ acceptanceCriteria: z.ZodNullable<z.ZodString>;
242
+ /**
243
+ * Portable GitHub identity (`github.com/owner/repo`) for new issues (NOT-149).
244
+ * Legacy rows may still hold a local filesystem path until explicitly migrated —
245
+ * the coordinator resolves those via an explicit compatibility path, never by guessing.
246
+ */
247
+ repo: z.ZodString;
248
+ baseBranch: z.ZodString;
249
+ status: z.ZodEnum<["ready", "developing", "reviewing", "repairing", "final_review", "needs_human", "done", "closed"]>;
250
+ currentOwner: z.ZodEnum<["human", "developer", "reviewer", "system"]>;
251
+ currentIntent: z.ZodNullable<z.ZodString>;
252
+ developerAgentId: z.ZodNullable<z.ZodString>;
253
+ reviewerAgentId: z.ZodNullable<z.ZodString>;
254
+ maxReviewRounds: z.ZodNumber;
255
+ currentRound: z.ZodNumber;
256
+ /** 0 is a valid policy: no automatic infra retry, escalate to a human immediately. */
257
+ maxInfraAttempts: z.ZodNumber;
258
+ infraAttempts: z.ZodNumber;
259
+ branch: z.ZodNullable<z.ZodString>;
260
+ baseSha: z.ZodNullable<z.ZodString>;
261
+ headSha: z.ZodNullable<z.ZodString>;
262
+ prNumber: z.ZodNullable<z.ZodNumber>;
263
+ prUrl: z.ZodNullable<z.ZodString>;
264
+ /**
265
+ * When true, reviewer `approved` merges the PR and marks the issue done (skips
266
+ * `final_review`). Kick UI defaults this on; API/CLI omit → false so existing
267
+ * callers keep the human final-review path.
268
+ */
269
+ autoMerge: z.ZodBoolean;
270
+ createdAt: z.ZodString;
271
+ updatedAt: z.ZodString;
272
+ } & {
273
+ created: z.ZodBoolean;
274
+ queue: z.ZodEnum<["enqueued", "already_queued", "not_queued"]>;
275
+ /**
276
+ * How many issues already existed for this `(source, externalId)` before the request (0
277
+ * for a manual create). With `created: true` they are all terminal, so a non-zero count
278
+ * means this import opened a *second* pass on a ticket dealer has already finished once —
279
+ * callers should say that out loud instead of presenting it as a first import.
280
+ */
281
+ priorPasses: z.ZodNumber;
282
+ }, "strip", z.ZodTypeAny, {
283
+ status: "done" | "final_review" | "ready" | "developing" | "reviewing" | "repairing" | "needs_human" | "closed";
284
+ id: string;
285
+ createdAt: string;
286
+ updatedAt: string;
287
+ title: string;
288
+ source: "manual" | "linear" | "agent";
289
+ externalId: string | null;
290
+ externalLabel: string | null;
291
+ externalUrl: string | null;
292
+ description: string | null;
293
+ acceptanceCriteria: string | null;
294
+ repo: string;
295
+ baseBranch: string;
296
+ currentOwner: "developer" | "reviewer" | "human" | "system";
297
+ currentIntent: string | null;
298
+ developerAgentId: string | null;
299
+ reviewerAgentId: string | null;
300
+ maxReviewRounds: number;
301
+ currentRound: number;
302
+ maxInfraAttempts: number;
303
+ infraAttempts: number;
304
+ branch: string | null;
305
+ baseSha: string | null;
306
+ headSha: string | null;
307
+ prNumber: number | null;
308
+ prUrl: string | null;
309
+ autoMerge: boolean;
310
+ created: boolean;
311
+ queue: "enqueued" | "already_queued" | "not_queued";
312
+ priorPasses: number;
313
+ }, {
314
+ status: "done" | "final_review" | "ready" | "developing" | "reviewing" | "repairing" | "needs_human" | "closed";
315
+ id: string;
316
+ createdAt: string;
317
+ updatedAt: string;
318
+ title: string;
319
+ source: "manual" | "linear" | "agent";
320
+ externalId: string | null;
321
+ externalLabel: string | null;
322
+ externalUrl: string | null;
323
+ description: string | null;
324
+ acceptanceCriteria: string | null;
325
+ repo: string;
326
+ baseBranch: string;
327
+ currentOwner: "developer" | "reviewer" | "human" | "system";
328
+ currentIntent: string | null;
329
+ developerAgentId: string | null;
330
+ reviewerAgentId: string | null;
331
+ maxReviewRounds: number;
332
+ currentRound: number;
333
+ maxInfraAttempts: number;
334
+ infraAttempts: number;
335
+ branch: string | null;
336
+ baseSha: string | null;
337
+ headSha: string | null;
338
+ prNumber: number | null;
339
+ prUrl: string | null;
340
+ autoMerge: boolean;
341
+ created: boolean;
342
+ queue: "enqueued" | "already_queued" | "not_queued";
343
+ priorPasses: number;
344
+ }>;
345
+ export type CreateIssueResult = z.infer<typeof CreateIssueResult>;
346
+ /** 409 body when a re-import collides with a live issue — mirrors the runs promote path. */
347
+ export interface ExistingIssueConflict {
348
+ error: string;
349
+ existingIssueId: string;
350
+ existingIssueStatus: IssueStatus;
351
+ }
352
+ /**
353
+ * Issue-scoped artifact. Distinct from the legacy run-scoped `Artifact`: it is keyed
354
+ * by `issueId` (+ optional `workerSessionId`), never a `runId`, so it validates on its
355
+ * own terms rather than failing `Artifact.runId`'s UUID check.
356
+ */
357
+ export declare const IssueArtifact: z.ZodObject<{
358
+ id: z.ZodString;
359
+ issueId: z.ZodNullable<z.ZodString>;
360
+ workerSessionId: z.ZodNullable<z.ZodString>;
361
+ kind: z.ZodString;
362
+ contentJson: z.ZodNullable<z.ZodString>;
363
+ blobPath: z.ZodNullable<z.ZodString>;
364
+ author: z.ZodEnum<["human", "agent", "system"]>;
365
+ createdAt: z.ZodString;
366
+ }, "strip", z.ZodTypeAny, {
367
+ id: string;
368
+ issueId: string | null;
369
+ createdAt: string;
370
+ workerSessionId: string | null;
371
+ kind: string;
372
+ contentJson: string | null;
373
+ blobPath: string | null;
374
+ author: "human" | "system" | "agent";
375
+ }, {
376
+ id: string;
377
+ issueId: string | null;
378
+ createdAt: string;
379
+ workerSessionId: string | null;
380
+ kind: string;
381
+ contentJson: string | null;
382
+ blobPath: string | null;
383
+ author: "human" | "system" | "agent";
384
+ }>;
385
+ export type IssueArtifact = z.infer<typeof IssueArtifact>;
@@ -0,0 +1,169 @@
1
+ import { z } from "zod";
2
+ import { GitHubRepoInput } from "./github-repo.js";
3
+ export const IssueStatus = z.enum([
4
+ "ready",
5
+ "developing",
6
+ "reviewing",
7
+ "repairing",
8
+ "final_review",
9
+ "needs_human",
10
+ "done",
11
+ "closed",
12
+ ]);
13
+ export const IssueOwner = z.enum(["human", "developer", "reviewer", "system"]);
14
+ /** "agent" covers an issue a coding agent created via the API/CLI (PRD §5). */
15
+ export const IssueSource = z.enum(["manual", "linear", "agent"]);
16
+ export const Issue = z.object({
17
+ id: z.string().uuid(),
18
+ source: IssueSource,
19
+ externalId: z.string().nullable(),
20
+ externalLabel: z.string().nullable(),
21
+ externalUrl: z.string().nullable(),
22
+ title: z.string(),
23
+ description: z.string().nullable(),
24
+ acceptanceCriteria: z.string().nullable(),
25
+ /**
26
+ * Portable GitHub identity (`github.com/owner/repo`) for new issues (NOT-149).
27
+ * Legacy rows may still hold a local filesystem path until explicitly migrated —
28
+ * the coordinator resolves those via an explicit compatibility path, never by guessing.
29
+ */
30
+ repo: z.string(),
31
+ baseBranch: z.string(),
32
+ status: IssueStatus,
33
+ currentOwner: IssueOwner,
34
+ currentIntent: z.string().nullable(),
35
+ developerAgentId: z.string().uuid().nullable(),
36
+ reviewerAgentId: z.string().uuid().nullable(),
37
+ maxReviewRounds: z.number().int().min(1),
38
+ currentRound: z.number().int().min(1),
39
+ /** 0 is a valid policy: no automatic infra retry, escalate to a human immediately. */
40
+ maxInfraAttempts: z.number().int().min(0),
41
+ infraAttempts: z.number().int().min(0),
42
+ branch: z.string().nullable(),
43
+ baseSha: z.string().nullable(),
44
+ headSha: z.string().nullable(),
45
+ prNumber: z.number().int().nullable(),
46
+ prUrl: z.string().nullable(),
47
+ /**
48
+ * When true, reviewer `approved` merges the PR and marks the issue done (skips
49
+ * `final_review`). Kick UI defaults this on; API/CLI omit → false so existing
50
+ * callers keep the human final-review path.
51
+ */
52
+ autoMerge: z.boolean(),
53
+ createdAt: z.string(),
54
+ updatedAt: z.string(),
55
+ });
56
+ export const CreateIssueInput = z.object({
57
+ title: z.string().min(1),
58
+ description: z.string().optional(),
59
+ acceptanceCriteria: z.string().optional(),
60
+ /** GitHub URL or `owner/repo` — normalized to `github.com/owner/repo` on parse. */
61
+ repo: GitHubRepoInput,
62
+ baseBranch: z.string().min(1).default("main"),
63
+ developerAgentId: z.string().uuid(),
64
+ reviewerAgentId: z.string().uuid(),
65
+ maxReviewRounds: z.number().int().min(1).default(3),
66
+ maxInfraAttempts: z.number().int().min(0).default(3),
67
+ /** Kick UI sends true; omit/false preserves final_review after approve. */
68
+ autoMerge: z.boolean().default(false),
69
+ source: IssueSource.default("manual"),
70
+ externalId: z.string().optional(),
71
+ externalLabel: z.string().optional(),
72
+ externalUrl: z.string().optional(),
73
+ /**
74
+ * NOT-118: a create directive, not an issue field — the route enqueues the new issue for
75
+ * admission by default so creating one never starts a workflow behind the queue's back.
76
+ * `false` creates a draft that sits outside the queue until someone adds or starts it.
77
+ */
78
+ enqueue: z.boolean().default(true),
79
+ });
80
+ /** Pre-start (or parked-on-`needs_human`) edits only — the route enforces no active
81
+ * workflow instance; status/owner/intent/branch/SHA/PR stay coordinator-owned. */
82
+ export const UpdateIssueInput = z.object({
83
+ title: z.string().min(1).optional(),
84
+ description: z.string().nullable().optional(),
85
+ acceptanceCriteria: z.string().nullable().optional(),
86
+ repo: GitHubRepoInput.optional(),
87
+ baseBranch: z.string().min(1).optional(),
88
+ developerAgentId: z.string().uuid().optional(),
89
+ reviewerAgentId: z.string().uuid().optional(),
90
+ maxReviewRounds: z.number().int().min(1).optional(),
91
+ maxInfraAttempts: z.number().int().min(0).optional(),
92
+ autoMerge: z.boolean().optional(),
93
+ });
94
+ /**
95
+ * Guard rails only — which status the coordinator may move an issue to next.
96
+ * The *specific* target within an allowed set (e.g. which needs_human resolution
97
+ * leads where) is coordinator business logic, not encoded here, mirroring how
98
+ * VALID_TRANSITIONS works for the legacy RunStatus table today.
99
+ */
100
+ export const ISSUE_STATUS_TRANSITIONS = {
101
+ ready: ["developing", "closed"],
102
+ developing: ["developing", "reviewing", "needs_human", "closed"],
103
+ // Self-loop matches developing/repairing below: a stale-review retry re-queues a fresh
104
+ // reviewer at a newly verified head without leaving the "reviewing" stage.
105
+ reviewing: ["reviewing", "repairing", "final_review", "needs_human", "closed"],
106
+ repairing: ["repairing", "reviewing", "needs_human", "closed"],
107
+ // "reviewing" lets a reviewer-side infra escalation (session_failed/publish_failed
108
+ // exhausted) resume with a fresh reviewer session at the still-valid pinned head,
109
+ // instead of always routing back through the developer.
110
+ needs_human: ["developing", "reviewing", "repairing", "final_review", "done", "closed"],
111
+ // Self-loop: human complete parks owner/intent for undraft+merge without leaving the stage.
112
+ final_review: ["final_review", "done", "repairing", "needs_human", "closed"],
113
+ done: [],
114
+ closed: [],
115
+ };
116
+ export function canTransitionIssue(from, to) {
117
+ return ISSUE_STATUS_TRANSITIONS[from].includes(to);
118
+ }
119
+ /**
120
+ * The statuses a pass can never leave — derived from the transition table so the two cannot
121
+ * drift. "Terminal" is a property of the *local* issue row, not of the upstream ticket: a
122
+ * closed dealer issue for a still-open Linear ticket is the normal case a re-import serves
123
+ * (NOT-141).
124
+ */
125
+ export const TERMINAL_ISSUE_STATUSES = Object.keys(ISSUE_STATUS_TRANSITIONS).filter((status) => ISSUE_STATUS_TRANSITIONS[status].length === 0);
126
+ /** Membership test for {@link TERMINAL_ISSUE_STATUSES} — false means the pass can still move. */
127
+ export function isTerminalIssueStatus(status) {
128
+ return TERMINAL_ISSUE_STATUSES.includes(status);
129
+ }
130
+ /**
131
+ * What the request did to the admission queue — the *mutation*, not the intent. `enqueue`
132
+ * is idempotent, so a re-import of an already-queued issue changes nothing; reporting that
133
+ * as "queued" is how the CLI came to announce a queue action for a request that queued
134
+ * nothing (NOT-141).
135
+ */
136
+ export const QueueOutcome = z.enum(["enqueued", "already_queued", "not_queued"]);
137
+ /**
138
+ * NOT-141: `POST /api/issues` answers with the issue *plus* what the server did with it.
139
+ * `created: false` means the request matched a live issue for the same `(source,
140
+ * externalId)` and re-enqueued it instead of making a second row — without these flags a
141
+ * caller cannot tell an import from a no-op, and the CLI printed "Queued for admission" for
142
+ * requests that queued nothing.
143
+ */
144
+ export const CreateIssueResult = Issue.extend({
145
+ created: z.boolean(),
146
+ queue: QueueOutcome,
147
+ /**
148
+ * How many issues already existed for this `(source, externalId)` before the request (0
149
+ * for a manual create). With `created: true` they are all terminal, so a non-zero count
150
+ * means this import opened a *second* pass on a ticket dealer has already finished once —
151
+ * callers should say that out loud instead of presenting it as a first import.
152
+ */
153
+ priorPasses: z.number().int().min(0),
154
+ });
155
+ /**
156
+ * Issue-scoped artifact. Distinct from the legacy run-scoped `Artifact`: it is keyed
157
+ * by `issueId` (+ optional `workerSessionId`), never a `runId`, so it validates on its
158
+ * own terms rather than failing `Artifact.runId`'s UUID check.
159
+ */
160
+ export const IssueArtifact = z.object({
161
+ id: z.string(),
162
+ issueId: z.string().nullable(),
163
+ workerSessionId: z.string().nullable(),
164
+ kind: z.string(),
165
+ contentJson: z.string().nullable(),
166
+ blobPath: z.string().nullable(),
167
+ author: z.enum(["human", "agent", "system"]),
168
+ createdAt: z.string(),
169
+ });
@@ -0,0 +1 @@
1
+ export {};