issue-flow 0.12.0 → 0.14.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 (197) hide show
  1. package/README.md +79 -274
  2. package/dist/agent-OX3KPHE4.js +30 -0
  3. package/dist/{analyze-OEET7KGE.js → analyze-WIND2SEB.js} +31 -16
  4. package/dist/analyze-WIND2SEB.js.map +1 -0
  5. package/dist/{apply-ZIA3C52S.js → apply-JNOI2LR4.js} +18 -7
  6. package/dist/{apply-ZIA3C52S.js.map → apply-JNOI2LR4.js.map} +1 -1
  7. package/dist/bench-B4VZON7E.js +910 -0
  8. package/dist/bench-B4VZON7E.js.map +1 -0
  9. package/dist/{chunk-FADTCQGM.js → chunk-2IQ6M4ZE.js} +94 -32
  10. package/dist/chunk-2IQ6M4ZE.js.map +1 -0
  11. package/dist/chunk-3BWZO4YI.js +141 -0
  12. package/dist/chunk-3BWZO4YI.js.map +1 -0
  13. package/dist/chunk-3WFZETIM.js +163 -0
  14. package/dist/chunk-3WFZETIM.js.map +1 -0
  15. package/dist/chunk-67YIU2VB.js +362 -0
  16. package/dist/chunk-67YIU2VB.js.map +1 -0
  17. package/dist/{chunk-QCPGHBSZ.js → chunk-6BENHR2I.js} +63 -21
  18. package/dist/chunk-6BENHR2I.js.map +1 -0
  19. package/dist/{chunk-BYZDPR7N.js → chunk-6QYMSNVA.js} +194 -235
  20. package/dist/chunk-6QYMSNVA.js.map +1 -0
  21. package/dist/{chunk-Y5ZDJ4PJ.js → chunk-76MMPJ53.js} +20 -10
  22. package/dist/chunk-76MMPJ53.js.map +1 -0
  23. package/dist/chunk-7Z4Y3VKM.js +26 -0
  24. package/dist/chunk-7Z4Y3VKM.js.map +1 -0
  25. package/dist/{chunk-3QHK4YQA.js → chunk-B72RQZBV.js} +346 -119
  26. package/dist/chunk-B72RQZBV.js.map +1 -0
  27. package/dist/chunk-BEZ5BA5U.js +625 -0
  28. package/dist/chunk-BEZ5BA5U.js.map +1 -0
  29. package/dist/chunk-BRCNQXYQ.js +74 -0
  30. package/dist/chunk-BRCNQXYQ.js.map +1 -0
  31. package/dist/chunk-CGKLE6WR.js +1203 -0
  32. package/dist/chunk-CGKLE6WR.js.map +1 -0
  33. package/dist/chunk-CRGIQFUQ.js +83 -0
  34. package/dist/chunk-CRGIQFUQ.js.map +1 -0
  35. package/dist/{chunk-NS6R37II.js → chunk-F6TOYSYY.js} +141 -12
  36. package/dist/chunk-F6TOYSYY.js.map +1 -0
  37. package/dist/chunk-G5EK2XRN.js +25 -0
  38. package/dist/chunk-G5EK2XRN.js.map +1 -0
  39. package/dist/chunk-HAKDLR6N.js +134 -0
  40. package/dist/chunk-HAKDLR6N.js.map +1 -0
  41. package/dist/chunk-J3SOTUVI.js +298 -0
  42. package/dist/chunk-J3SOTUVI.js.map +1 -0
  43. package/dist/chunk-JN6D3MY6.js +30 -0
  44. package/dist/chunk-JN6D3MY6.js.map +1 -0
  45. package/dist/{chunk-LAFNLLQP.js → chunk-KMRFRXIT.js} +5 -5
  46. package/dist/chunk-KT7JKOXB.js +72 -0
  47. package/dist/chunk-KT7JKOXB.js.map +1 -0
  48. package/dist/chunk-L6HSKTQE.js +77 -0
  49. package/dist/chunk-L6HSKTQE.js.map +1 -0
  50. package/dist/chunk-LBGHI4S2.js +1264 -0
  51. package/dist/chunk-LBGHI4S2.js.map +1 -0
  52. package/dist/chunk-LEW4QM74.js +180 -0
  53. package/dist/chunk-LEW4QM74.js.map +1 -0
  54. package/dist/{chunk-FJP3UQGD.js → chunk-LFEQIZLB.js} +115 -20
  55. package/dist/chunk-LFEQIZLB.js.map +1 -0
  56. package/dist/chunk-OOVG2KBY.js +77 -0
  57. package/dist/chunk-OOVG2KBY.js.map +1 -0
  58. package/dist/{chunk-56KS3TFQ.js → chunk-OR43364P.js} +115 -160
  59. package/dist/chunk-OR43364P.js.map +1 -0
  60. package/dist/chunk-P3LRUNC6.js +16 -0
  61. package/dist/chunk-P3LRUNC6.js.map +1 -0
  62. package/dist/{chunk-TSOLWK7Y.js → chunk-PBTA3QQX.js} +8 -7
  63. package/dist/{chunk-TSOLWK7Y.js.map → chunk-PBTA3QQX.js.map} +1 -1
  64. package/dist/{chunk-MJULIKQU.js → chunk-PHW2YV6N.js} +23 -47
  65. package/dist/chunk-PHW2YV6N.js.map +1 -0
  66. package/dist/{chunk-73ATPIYX.js → chunk-PZTWU277.js} +36 -71
  67. package/dist/chunk-PZTWU277.js.map +1 -0
  68. package/dist/{chunk-M5UCXTIT.js → chunk-QD4VOILZ.js} +22 -18
  69. package/dist/chunk-QD4VOILZ.js.map +1 -0
  70. package/dist/chunk-QJ5UZAH5.js +2718 -0
  71. package/dist/chunk-QJ5UZAH5.js.map +1 -0
  72. package/dist/chunk-QK7WUO7A.js +283 -0
  73. package/dist/chunk-QK7WUO7A.js.map +1 -0
  74. package/dist/{chunk-A4SLHOW7.js → chunk-QZVKRDJY.js} +27 -19
  75. package/dist/chunk-QZVKRDJY.js.map +1 -0
  76. package/dist/chunk-REO3PXXO.js +71 -0
  77. package/dist/chunk-REO3PXXO.js.map +1 -0
  78. package/dist/{chunk-EZATO3DW.js → chunk-RVO7L4FX.js} +594 -17
  79. package/dist/chunk-RVO7L4FX.js.map +1 -0
  80. package/dist/{chunk-XQUSIEKA.js → chunk-SZMHCEYV.js} +63 -14
  81. package/dist/chunk-SZMHCEYV.js.map +1 -0
  82. package/dist/chunk-TYRNTSPJ.js +243 -0
  83. package/dist/chunk-TYRNTSPJ.js.map +1 -0
  84. package/dist/chunk-UJ3L2MS7.js +238 -0
  85. package/dist/chunk-UJ3L2MS7.js.map +1 -0
  86. package/dist/chunk-V7MO5EDS.js +120 -0
  87. package/dist/chunk-V7MO5EDS.js.map +1 -0
  88. package/dist/chunk-WB2X37MO.js +415 -0
  89. package/dist/chunk-WB2X37MO.js.map +1 -0
  90. package/dist/{chunk-NTMMF5UD.js → chunk-X44FKNKP.js} +525 -252
  91. package/dist/chunk-X44FKNKP.js.map +1 -0
  92. package/dist/chunk-XEYH6ZZI.js +289 -0
  93. package/dist/chunk-XEYH6ZZI.js.map +1 -0
  94. package/dist/cli.js +267 -44
  95. package/dist/cli.js.map +1 -1
  96. package/dist/{config-PRJGWW7J.js → config-HMFMCY2M.js} +31 -5
  97. package/dist/contract-JH2WBIO6.js +8 -0
  98. package/dist/conventions-NJF2OPVQ.js +146 -0
  99. package/dist/conventions-NJF2OPVQ.js.map +1 -0
  100. package/dist/diagnostics-THH42ZMP.js +23 -0
  101. package/dist/execute-KFNNZZHI.js +35 -0
  102. package/dist/{generate-EGB4KV2B.js → generate-FW5C6NP7.js} +37 -20
  103. package/dist/{generate-EGB4KV2B.js.map → generate-FW5C6NP7.js.map} +1 -1
  104. package/dist/git-W72QQ6GT.js +33 -0
  105. package/dist/init-HTN4V67Q.js +24 -0
  106. package/dist/{operations-BYT626KQ.js → operations-BCFOBH42.js} +27 -15
  107. package/dist/{operations-BYT626KQ.js.map → operations-BCFOBH42.js.map} +1 -1
  108. package/dist/permissions-4AKNQZHK.js +18 -0
  109. package/dist/plan-SIZLGA4V.js +34 -0
  110. package/dist/{policy-6S4GFC76.js → policy-DT6Q6ZVM.js} +20 -6
  111. package/dist/policy-DT6Q6ZVM.js.map +1 -0
  112. package/dist/pr-OMWCGUOW.js +39 -0
  113. package/dist/pr-review-N24CZPKR.js +32 -0
  114. package/dist/pr-review-N24CZPKR.js.map +1 -0
  115. package/dist/prd-5OFTZAHJ.js +33 -0
  116. package/dist/prd-5OFTZAHJ.js.map +1 -0
  117. package/dist/ps-RFORTCUD.js +93 -0
  118. package/dist/ps-RFORTCUD.js.map +1 -0
  119. package/dist/recorder-KCCPMKQG.js +32 -0
  120. package/dist/recorder-KCCPMKQG.js.map +1 -0
  121. package/dist/registry-GLPXOMFG.js +15 -0
  122. package/dist/registry-GLPXOMFG.js.map +1 -0
  123. package/dist/{resume-PPCNQVVV.js → resume-M5RLKP4I.js} +55 -34
  124. package/dist/{resume-PPCNQVVV.js.map → resume-M5RLKP4I.js.map} +1 -1
  125. package/dist/review-YM4JAABY.js +35 -0
  126. package/dist/review-YM4JAABY.js.map +1 -0
  127. package/dist/routing-NNT5WKGX.js +94 -0
  128. package/dist/routing-NNT5WKGX.js.map +1 -0
  129. package/dist/run-PZUKHPQK.js +54 -0
  130. package/dist/run-PZUKHPQK.js.map +1 -0
  131. package/dist/session-publisher-T7EI3CIP.js +11 -0
  132. package/dist/session-publisher-T7EI3CIP.js.map +1 -0
  133. package/dist/{state-manager-2EDVDBAR.js → state-manager-GQH32C44.js} +4 -2
  134. package/dist/state-manager-GQH32C44.js.map +1 -0
  135. package/dist/usage-V2CHE5PY.js +177 -0
  136. package/dist/usage-V2CHE5PY.js.map +1 -0
  137. package/dist/{web-EF5WIIGG.js → web-EA3KGNFN.js} +45 -30
  138. package/dist/web-EA3KGNFN.js.map +1 -0
  139. package/package.json +6 -2
  140. package/prompts/execute.md +7 -8
  141. package/prompts/plan.md +4 -5
  142. package/prompts/pr.md +2 -2
  143. package/web/AGENTS.md +152 -13
  144. package/web/public/app.css +380 -109
  145. package/web/public/app.js +525 -25
  146. package/web/public/index.html +68 -1
  147. package/dist/analyze-OEET7KGE.js.map +0 -1
  148. package/dist/chunk-3QHK4YQA.js.map +0 -1
  149. package/dist/chunk-42PJFMAR.js +0 -605
  150. package/dist/chunk-42PJFMAR.js.map +0 -1
  151. package/dist/chunk-4JSOYE4G.js +0 -368
  152. package/dist/chunk-4JSOYE4G.js.map +0 -1
  153. package/dist/chunk-56KS3TFQ.js.map +0 -1
  154. package/dist/chunk-73ATPIYX.js.map +0 -1
  155. package/dist/chunk-A4SLHOW7.js.map +0 -1
  156. package/dist/chunk-BAUPQXPE.js +0 -173
  157. package/dist/chunk-BAUPQXPE.js.map +0 -1
  158. package/dist/chunk-BYZDPR7N.js.map +0 -1
  159. package/dist/chunk-CD5ULRVC.js +0 -615
  160. package/dist/chunk-CD5ULRVC.js.map +0 -1
  161. package/dist/chunk-DIDUVL6O.js +0 -1365
  162. package/dist/chunk-DIDUVL6O.js.map +0 -1
  163. package/dist/chunk-EZATO3DW.js.map +0 -1
  164. package/dist/chunk-FADTCQGM.js.map +0 -1
  165. package/dist/chunk-FJP3UQGD.js.map +0 -1
  166. package/dist/chunk-LWRSMTTZ.js +0 -18
  167. package/dist/chunk-LWRSMTTZ.js.map +0 -1
  168. package/dist/chunk-M5UCXTIT.js.map +0 -1
  169. package/dist/chunk-M66SJHQQ.js +0 -206
  170. package/dist/chunk-M66SJHQQ.js.map +0 -1
  171. package/dist/chunk-MJULIKQU.js.map +0 -1
  172. package/dist/chunk-NS6R37II.js.map +0 -1
  173. package/dist/chunk-NTMMF5UD.js.map +0 -1
  174. package/dist/chunk-QCPGHBSZ.js.map +0 -1
  175. package/dist/chunk-XQUSIEKA.js.map +0 -1
  176. package/dist/chunk-Y5ZDJ4PJ.js.map +0 -1
  177. package/dist/execute-XBNVL753.js +0 -18
  178. package/dist/init-AJHCXJBP.js +0 -10
  179. package/dist/plan-QOZ3RIO6.js +0 -21
  180. package/dist/policy-6S4GFC76.js.map +0 -1
  181. package/dist/pr-EBBHD2ZX.js +0 -26
  182. package/dist/pr-review-VVMW5PO4.js +0 -20
  183. package/dist/prd-JQSZF7PR.js +0 -21
  184. package/dist/review-3F6MARWH.js +0 -19
  185. package/dist/run-RXE5GDQO.js +0 -36
  186. package/dist/web-EF5WIIGG.js.map +0 -1
  187. /package/dist/{config-PRJGWW7J.js.map → agent-OX3KPHE4.js.map} +0 -0
  188. /package/dist/{chunk-LAFNLLQP.js.map → chunk-KMRFRXIT.js.map} +0 -0
  189. /package/dist/{execute-XBNVL753.js.map → config-HMFMCY2M.js.map} +0 -0
  190. /package/dist/{init-AJHCXJBP.js.map → contract-JH2WBIO6.js.map} +0 -0
  191. /package/dist/{plan-QOZ3RIO6.js.map → diagnostics-THH42ZMP.js.map} +0 -0
  192. /package/dist/{pr-EBBHD2ZX.js.map → execute-KFNNZZHI.js.map} +0 -0
  193. /package/dist/{pr-review-VVMW5PO4.js.map → git-W72QQ6GT.js.map} +0 -0
  194. /package/dist/{prd-JQSZF7PR.js.map → init-HTN4V67Q.js.map} +0 -0
  195. /package/dist/{review-3F6MARWH.js.map → permissions-4AKNQZHK.js.map} +0 -0
  196. /package/dist/{run-RXE5GDQO.js.map → plan-SIZLGA4V.js.map} +0 -0
  197. /package/dist/{state-manager-2EDVDBAR.js.map → pr-OMWCGUOW.js.map} +0 -0
@@ -0,0 +1,1264 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/agents/types.ts
4
+ var AGENT_PHASES = [
5
+ "analyze",
6
+ "generate",
7
+ "prd",
8
+ "plan",
9
+ "execute",
10
+ "review",
11
+ "pr",
12
+ "pr-review"
13
+ ];
14
+ function isAgentPhase(value) {
15
+ return AGENT_PHASES.includes(value);
16
+ }
17
+ function isAgentProviderId(value) {
18
+ return value === "claude" || value === "codex" || value === "cursor" || value === "antigravity";
19
+ }
20
+ var CLAUDE_CAPABILITIES = {
21
+ extraDirectories: "flag",
22
+ addDirs: true,
23
+ toolAllowlist: true,
24
+ maxTurns: true,
25
+ osSandbox: false,
26
+ modelSelection: true,
27
+ modelDiscovery: false,
28
+ usage: "tokens-and-cost",
29
+ reportsUsage: true,
30
+ reportsCost: true,
31
+ sessionResume: false,
32
+ authProbe: "none",
33
+ bareModelAliases: true,
34
+ promptChannel: "both",
35
+ nativeTimeout: false,
36
+ contextFileName: "CLAUDE.md",
37
+ contextFileMaxBytes: null,
38
+ toolNameCase: "CamelCase",
39
+ readOnlyMode: "native"
40
+ };
41
+ var CODEX_CAPABILITIES = {
42
+ extraDirectories: "flag",
43
+ addDirs: true,
44
+ toolAllowlist: false,
45
+ maxTurns: false,
46
+ osSandbox: true,
47
+ modelSelection: true,
48
+ modelDiscovery: false,
49
+ usage: "tokens-only",
50
+ reportsUsage: true,
51
+ reportsCost: false,
52
+ sessionResume: true,
53
+ authProbe: "exit-code",
54
+ bareModelAliases: false,
55
+ promptChannel: "both",
56
+ nativeTimeout: false,
57
+ contextFileName: "AGENTS.md",
58
+ contextFileMaxBytes: 32 * 1024,
59
+ toolNameCase: "none",
60
+ readOnlyMode: "sandbox"
61
+ };
62
+ var CURSOR_CAPABILITIES = {
63
+ extraDirectories: "permission-file",
64
+ addDirs: false,
65
+ toolAllowlist: false,
66
+ maxTurns: false,
67
+ osSandbox: true,
68
+ modelSelection: true,
69
+ modelDiscovery: true,
70
+ usage: "none",
71
+ reportsUsage: false,
72
+ reportsCost: false,
73
+ sessionResume: true,
74
+ authProbe: "text",
75
+ bareModelAliases: false,
76
+ promptChannel: "argv",
77
+ nativeTimeout: false,
78
+ contextFileName: "AGENTS.md",
79
+ contextFileMaxBytes: null,
80
+ toolNameCase: "lowercase",
81
+ readOnlyMode: "native"
82
+ };
83
+ var ANTIGRAVITY_CAPABILITIES = {
84
+ extraDirectories: "flag",
85
+ addDirs: true,
86
+ toolAllowlist: false,
87
+ maxTurns: false,
88
+ osSandbox: true,
89
+ modelSelection: true,
90
+ modelDiscovery: true,
91
+ usage: "tokens-only",
92
+ reportsUsage: true,
93
+ reportsCost: false,
94
+ sessionResume: true,
95
+ authProbe: "none",
96
+ bareModelAliases: false,
97
+ promptChannel: "argv",
98
+ nativeTimeout: true,
99
+ contextFileName: "AGENTS.md",
100
+ contextFileMaxBytes: null,
101
+ toolNameCase: "CamelCase",
102
+ readOnlyMode: "native"
103
+ };
104
+ var AGENT_SCHEMA_VERSION = 1;
105
+
106
+ // src/policy/schemas.ts
107
+ import { z } from "zod";
108
+ var policyDiscoveryConfigSchema = z.object({
109
+ issueTemplates: z.boolean().default(true),
110
+ pullRequestTemplate: z.boolean().default(true),
111
+ docs: z.boolean().default(true),
112
+ codeowners: z.boolean().default(true),
113
+ labels: z.boolean().default(true),
114
+ issueTypes: z.boolean().default(true)
115
+ });
116
+ var policyIssuesDeclarationSchema = z.object({
117
+ titleConvention: z.string().min(1).optional(),
118
+ /**
119
+ * Whether Issue Flow may create a label the repository does not have.
120
+ *
121
+ * `.optional()` rather than `.default(false)`: the resolved declarations must
122
+ * stay "only what was written", or the group would always look declared and
123
+ * `sources` would report a provenance nobody asked for. The effective default
124
+ * — false — lives at the call site.
125
+ *
126
+ * That default is a deliberate change of behaviour: creating taxonomy without
127
+ * asking is the defect this exists to stop. A repository that wants the old
128
+ * behaviour opts back into it.
129
+ */
130
+ allowLabelCreation: z.boolean().optional()
131
+ });
132
+ var policyPullRequestsDeclarationSchema = z.object({
133
+ baseBranch: z.string().min(1).optional(),
134
+ titleConvention: z.string().min(1).optional()
135
+ });
136
+ var policyGitDeclarationSchema = z.object({
137
+ branchConvention: z.string().min(1).optional(),
138
+ commitConvention: z.string().min(1).optional(),
139
+ pullRequestTitleConvention: z.string().min(1).optional(),
140
+ issueReference: z.enum(["closes", "refs"]).optional(),
141
+ typeMap: z.record(z.string(), z.string().min(1)).optional()
142
+ });
143
+ var policyConfigSchema = z.object({
144
+ enabled: z.boolean().default(true),
145
+ /**
146
+ * Token budget for the `__REPO_POLICY__` projection. Sections above it are
147
+ * replaced whole by a pointer rather than truncated — see
148
+ * `policy/placeholders.ts`.
149
+ */
150
+ contextBudget: z.number().int().positive().default(1500),
151
+ discovery: policyDiscoveryConfigSchema.prefault({}),
152
+ issues: policyIssuesDeclarationSchema.prefault({}),
153
+ pullRequests: policyPullRequestsDeclarationSchema.prefault({}),
154
+ git: policyGitDeclarationSchema.prefault({})
155
+ });
156
+ var policyConfigInputSchema = z.object({
157
+ enabled: z.boolean().optional(),
158
+ contextBudget: z.number().int().positive().optional(),
159
+ // Spelled out rather than `policyDiscoveryConfigSchema.partial()`: in zod 4
160
+ // a `.default()` survives `.partial()`, so every toggle would come back
161
+ // materialized and the input layer would stop meaning "what the user wrote".
162
+ discovery: z.object({
163
+ issueTemplates: z.boolean().optional(),
164
+ pullRequestTemplate: z.boolean().optional(),
165
+ docs: z.boolean().optional(),
166
+ codeowners: z.boolean().optional(),
167
+ labels: z.boolean().optional(),
168
+ issueTypes: z.boolean().optional()
169
+ }).optional(),
170
+ issues: z.object({ titleConvention: z.string().nullish(), allowLabelCreation: z.boolean().optional() }).optional(),
171
+ pullRequests: z.object({ baseBranch: z.string().nullish(), titleConvention: z.string().nullish() }).optional(),
172
+ git: z.object({
173
+ branchConvention: z.string().nullish(),
174
+ commitConvention: z.string().nullish(),
175
+ pullRequestTitleConvention: z.string().nullish(),
176
+ issueReference: z.enum(["closes", "refs"]).nullish(),
177
+ typeMap: z.record(z.string(), z.string().min(1)).nullish()
178
+ }).optional()
179
+ });
180
+
181
+ // src/schemas.ts
182
+ import { z as z2 } from "zod";
183
+ var claudeUsageSchema = z2.object({
184
+ inputTokens: z2.number().optional(),
185
+ outputTokens: z2.number().optional(),
186
+ cacheReadTokens: z2.number().optional(),
187
+ cacheCreationTokens: z2.number().optional(),
188
+ costUsd: z2.number().optional()
189
+ });
190
+ var userStoryStatusSchema = z2.enum(["backlog", "in_progress", "in_review", "done"]);
191
+ var storyStageSchema = z2.enum([
192
+ "pending",
193
+ "executing",
194
+ "awaiting_review",
195
+ "in_review",
196
+ "in_correction",
197
+ "done",
198
+ "failed"
199
+ ]);
200
+ var userStorySchema = z2.object({
201
+ id: z2.string(),
202
+ title: z2.string(),
203
+ description: z2.string(),
204
+ acceptanceCriteria: z2.array(z2.string()),
205
+ priority: z2.number().int().positive(),
206
+ passes: z2.boolean(),
207
+ notes: z2.string(),
208
+ ...claudeUsageSchema.shape,
209
+ durationSeconds: z2.number().optional(),
210
+ status: userStoryStatusSchema.optional(),
211
+ dependencies: z2.array(z2.string()).optional(),
212
+ stage: storyStageSchema.optional(),
213
+ stageSince: z2.string().optional(),
214
+ stageDetail: z2.string().optional()
215
+ });
216
+ var pipelineStateSchema = z2.object({
217
+ analyzeCompleted: z2.boolean().optional(),
218
+ prdCompleted: z2.boolean(),
219
+ jsonCompleted: z2.boolean(),
220
+ executionCompleted: z2.boolean(),
221
+ reviewCompleted: z2.boolean(),
222
+ prCreated: z2.boolean(),
223
+ prReviewCompleted: z2.boolean().optional()
224
+ });
225
+ var pullRequestRefSchema = z2.object({
226
+ number: z2.number().int().positive(),
227
+ url: z2.string(),
228
+ headBranch: z2.string(),
229
+ createdAt: z2.string()
230
+ });
231
+ var prReviewRecommendationSchema = z2.enum([
232
+ "APPROVE",
233
+ "APPROVE_WITH_SUGGESTIONS",
234
+ "REQUEST_CHANGES"
235
+ ]);
236
+ var prReviewStateSchema = z2.object({
237
+ enabled: z2.boolean().default(false),
238
+ pullRequestNumber: z2.number().int().positive().optional(),
239
+ rounds: z2.number().int().min(0).default(0),
240
+ lastRecommendation: prReviewRecommendationSchema.optional(),
241
+ lastReviewedAt: z2.string().optional()
242
+ });
243
+ var lastErrorSchema = z2.object({
244
+ category: z2.string(),
245
+ message: z2.string(),
246
+ at: z2.string()
247
+ });
248
+ var issueMetadataSchema = z2.object({
249
+ schemaVersion: z2.literal(1),
250
+ id: z2.string().min(1),
251
+ number: z2.number().int().positive().nullable(),
252
+ source: z2.enum(["github", "local"]),
253
+ title: z2.string(),
254
+ labels: z2.array(z2.string()),
255
+ state: z2.enum(["open", "closed"]),
256
+ createdAt: z2.string(),
257
+ updatedAt: z2.string(),
258
+ contentHash: z2.string(),
259
+ remote: z2.object({
260
+ provider: z2.enum(["github", "local"]),
261
+ ref: z2.string(),
262
+ syncedAt: z2.string(),
263
+ syncedContentHash: z2.string()
264
+ }).optional()
265
+ });
266
+ var runOwnerSchema = z2.object({
267
+ pid: z2.number().int().positive(),
268
+ host: z2.string(),
269
+ startedAt: z2.string()
270
+ });
271
+ var issueRunStateSchema = z2.object({
272
+ status: z2.enum(["idle", "running", "waiting", "retrying", "paused", "blocked", "failed"]).default("idle"),
273
+ currentPhase: z2.string().nullable().default(null),
274
+ attempt: z2.number().int().min(0).default(0),
275
+ lastHeartbeatAt: z2.string().nullable().default(null),
276
+ blockedReason: z2.string().nullable().default(null),
277
+ owner: runOwnerSchema.nullable().default(null)
278
+ });
279
+ var failureKindSchema = z2.enum([
280
+ "network",
281
+ "timeout",
282
+ "stalled",
283
+ "rate_limit",
284
+ "provider_down",
285
+ "provider_crash",
286
+ "authentication",
287
+ "configuration",
288
+ "repository_state",
289
+ "task_execution",
290
+ "internal",
291
+ "unknown"
292
+ ]);
293
+ var normalizedUsageSchema = z2.object({
294
+ inputTokens: z2.number().optional(),
295
+ outputTokens: z2.number().optional(),
296
+ cacheReadTokens: z2.number().optional(),
297
+ cacheCreationTokens: z2.number().optional(),
298
+ reasoningTokens: z2.number().optional(),
299
+ details: z2.record(z2.string(), z2.number()).optional(),
300
+ source: z2.enum(["provider", "unavailable"])
301
+ });
302
+ var pricingSnapshotSchema = z2.object({
303
+ tableVersion: z2.string(),
304
+ modelKey: z2.string(),
305
+ inputPerMillion: z2.number(),
306
+ outputPerMillion: z2.number(),
307
+ cacheReadPerMillion: z2.number().optional(),
308
+ cacheWritePerMillion: z2.number().optional(),
309
+ capturedAt: z2.string()
310
+ });
311
+ var costRecordSchema = z2.discriminatedUnion("status", [
312
+ z2.object({ status: z2.literal("reported"), amount: z2.number(), currency: z2.literal("USD") }),
313
+ z2.object({
314
+ status: z2.literal("estimated"),
315
+ amount: z2.number(),
316
+ currency: z2.literal("USD"),
317
+ pricing: pricingSnapshotSchema
318
+ }),
319
+ z2.object({
320
+ status: z2.literal("unknown"),
321
+ reason: z2.enum(["not_reported", "no_pricing", "unknown_model", "subscription", "zero_rated"])
322
+ })
323
+ ]);
324
+ var executionRecordSchema = z2.object({
325
+ id: z2.string(),
326
+ sessionId: z2.string().nullable(),
327
+ purpose: z2.enum([
328
+ "analyze",
329
+ "generate",
330
+ "prd",
331
+ "plan",
332
+ "execute",
333
+ "review",
334
+ "pr",
335
+ "pr-review",
336
+ "verify"
337
+ ]),
338
+ attempt: z2.number().int().positive(),
339
+ trigger: z2.enum(["initial", "retry", "fallback", "correction", "escalation"]),
340
+ triggerReason: failureKindSchema.nullable(),
341
+ agent: z2.object({
342
+ harness: z2.string(),
343
+ provider: z2.string().nullable(),
344
+ harnessVersion: z2.string().nullable().optional(),
345
+ model: z2.object({
346
+ requested: z2.string().nullable(),
347
+ resolved: z2.string().nullable(),
348
+ source: z2.enum(["provider", "config", "unavailable"])
349
+ }),
350
+ providerSessionId: z2.string().nullable()
351
+ }),
352
+ startedAt: z2.string(),
353
+ finishedAt: z2.string().nullable(),
354
+ durationMs: z2.number().nullable(),
355
+ cliDurationMs: z2.number().nullable().optional(),
356
+ harnessStartupMs: z2.number().nullable().optional(),
357
+ apiDurationMs: z2.number().nullable().optional(),
358
+ ttftMs: z2.number().nullable().optional(),
359
+ numTurns: z2.number().nullable().optional(),
360
+ usage: normalizedUsageSchema.nullable(),
361
+ cost: costRecordSchema,
362
+ status: z2.enum(["running", "completed", "failed", "timeout", "cancelled", "interrupted"]),
363
+ failure: z2.object({
364
+ kind: failureKindSchema,
365
+ message: z2.string(),
366
+ exitCode: z2.number().nullable()
367
+ }).nullable(),
368
+ stopReason: z2.enum([
369
+ "completed",
370
+ "failed",
371
+ "timeout",
372
+ "cancelled",
373
+ "max_attempts",
374
+ "max_cost",
375
+ "max_duration"
376
+ ]).nullable().optional(),
377
+ iteration: z2.number().int().optional(),
378
+ correctionCycle: z2.number().int().min(0).optional(),
379
+ storyIds: z2.array(z2.string()).optional(),
380
+ owner: z2.object({ pid: z2.number().int(), host: z2.string() }).nullable().optional(),
381
+ routingDecision: z2.object({
382
+ selected: z2.string(),
383
+ actual: z2.string().optional(),
384
+ candidates: z2.array(z2.unknown()).optional(),
385
+ reasonCodes: z2.array(z2.string()).optional()
386
+ }).passthrough().nullable().optional(),
387
+ verdict: z2.object({
388
+ status: z2.enum(["passed", "failed", "unverified"]),
389
+ level: z2.string().nullable().optional(),
390
+ independence: z2.string().nullable().optional()
391
+ }).nullable().optional()
392
+ });
393
+ var taskPlanSchema = z2.object({
394
+ project: z2.string(),
395
+ issueNumber: z2.union([z2.number().int().positive(), z2.string().min(1)]),
396
+ issueUrl: z2.string().optional().default(""),
397
+ branchName: z2.string(),
398
+ noBranch: z2.boolean().optional().default(false),
399
+ description: z2.string(),
400
+ issueStatus: z2.enum(["pending", "in_progress", "completed"]),
401
+ completedAt: z2.string().nullable(),
402
+ lastAttemptAt: z2.string().nullable(),
403
+ lastError: lastErrorSchema.nullable(),
404
+ correctionCycle: z2.number().int().min(0),
405
+ maxCorrectionCycles: z2.number().int().min(0),
406
+ /**
407
+ * Findings from the most recent failed review, verbatim. Non-null means the
408
+ * issue has a pending correction even if every userStories[].passes is
409
+ * already true — the execute phase must address these before the field is
410
+ * cleared back to null. See core/engine.ts's early-return guards.
411
+ */
412
+ lastReviewFindings: z2.string().nullable().optional().default(null),
413
+ pipeline: pipelineStateSchema,
414
+ /**
415
+ * Where the run stands right now. Purely additive: absent in every plan
416
+ * written before it, and absent is not the same as `idle` — it means the
417
+ * plan predates the field, which is why there is no `.default()` here.
418
+ */
419
+ runState: issueRunStateSchema.optional(),
420
+ pullRequest: pullRequestRefSchema.optional(),
421
+ prReview: prReviewStateSchema.optional(),
422
+ userStories: z2.array(userStorySchema),
423
+ /**
424
+ * Per-invocation history. `.optional()` and no `.default([])`: a plan that
425
+ * predates the field must not grow an empty array just because it was saved.
426
+ */
427
+ executions: z2.array(executionRecordSchema).optional()
428
+ });
429
+ var headlessResultSchema = z2.object({
430
+ success: z2.boolean(),
431
+ result: z2.string(),
432
+ cost: claudeUsageSchema.nullable(),
433
+ error: z2.string().nullable()
434
+ });
435
+ var sessionLogEntrySchema = z2.object({
436
+ at: z2.string(),
437
+ level: z2.enum(["info", "warn", "error"]),
438
+ message: z2.string()
439
+ });
440
+ var sessionUsageShape = {
441
+ inputTokens: z2.number().nullable().default(null),
442
+ outputTokens: z2.number().nullable().default(null),
443
+ cacheReadTokens: z2.number().nullable().default(null),
444
+ cacheCreationTokens: z2.number().nullable().default(null),
445
+ costUsd: z2.number().nullable().default(null)
446
+ };
447
+ var sessionPhaseSchema = z2.object({
448
+ name: z2.string(),
449
+ status: z2.enum(["pending", "running", "completed", "failed"]),
450
+ startedAt: z2.string().nullable(),
451
+ endedAt: z2.string().nullable(),
452
+ durationSeconds: z2.number().nullable(),
453
+ error: z2.string().nullable(),
454
+ harnessExecutionMs: z2.number().nullable().default(null),
455
+ orchestrationOverheadMs: z2.number().nullable().default(null),
456
+ harnessStartupMs: z2.number().nullable().default(null),
457
+ ttftMs: z2.number().nullable().default(null),
458
+ attemptCount: z2.number().nullable().default(null),
459
+ retryDurationMs: z2.number().nullable().default(null),
460
+ ...sessionUsageShape
461
+ });
462
+ var sessionStorySchema = z2.object({
463
+ id: z2.string(),
464
+ title: z2.string(),
465
+ priority: z2.number(),
466
+ passes: z2.boolean(),
467
+ completedAt: z2.string().nullable(),
468
+ // Also introduced with the metrics, hence the same tolerant default.
469
+ durationSeconds: z2.number().nullable().default(null),
470
+ // Snapshot fields are always present on output and defaulted on input, so a
471
+ // session.json written before they existed still parses. This is the mirror
472
+ // image of userStorySchema, where the same two fields are plainly optional.
473
+ status: userStoryStatusSchema.default("backlog"),
474
+ dependencies: z2.array(z2.string()).default([]),
475
+ // Published for the panel's story detail view. Same tolerant default as the
476
+ // fields above: absent (older session.json) and empty resolve to the same
477
+ // value, so the client never has to tell them apart.
478
+ description: z2.string().default(""),
479
+ acceptanceCriteria: z2.array(z2.string()).default([]),
480
+ // Additive like the rest of this schema: a session.json written before
481
+ // `stage` existed parses into 'pending'/null, the same values a fresh
482
+ // snapshot starts a story at.
483
+ stage: storyStageSchema.default("pending"),
484
+ stageSince: z2.string().nullable().default(null),
485
+ stageDetail: z2.string().nullable().default(null),
486
+ history: z2.array(
487
+ z2.object({
488
+ at: z2.string(),
489
+ stage: storyStageSchema,
490
+ detail: z2.string().nullable()
491
+ })
492
+ ).default([]),
493
+ ...sessionUsageShape
494
+ });
495
+ var sessionConfigurationValueSchema = z2.object({
496
+ value: z2.string().nullable(),
497
+ source: z2.enum(["default", "global", "project", "env", "cli", "fallback"])
498
+ });
499
+ var sessionConfigurationSchema = z2.object({
500
+ precedence: z2.array(z2.string()),
501
+ defaultProvider: sessionConfigurationValueSchema,
502
+ defaultModel: sessionConfigurationValueSchema,
503
+ phases: z2.array(
504
+ z2.object({
505
+ phase: z2.string(),
506
+ provider: sessionConfigurationValueSchema,
507
+ model: sessionConfigurationValueSchema
508
+ })
509
+ ),
510
+ fallbacks: z2.array(z2.string()),
511
+ overrides: z2.array(z2.string())
512
+ });
513
+ var sessionSnapshotSchema = z2.object({
514
+ schemaVersion: z2.literal(1),
515
+ sessionId: z2.string().nullable(),
516
+ readOnly: z2.literal(true),
517
+ capabilities: z2.array(z2.string()),
518
+ issue: z2.object({
519
+ number: z2.number().nullable(),
520
+ url: z2.string().nullable(),
521
+ // Additive: a session.json written before the Issue section was enriched
522
+ // parses into the same "not reported" values createInitialSnapshot() uses.
523
+ title: z2.string().nullable().default(null),
524
+ description: z2.string().nullable().default(null),
525
+ labels: z2.array(z2.string()).default([]),
526
+ state: z2.string().nullable().default(null)
527
+ }),
528
+ status: z2.enum(["idle", "running", "completed", "failed"]),
529
+ startedAt: z2.string().nullable(),
530
+ updatedAt: z2.string().nullable(),
531
+ endedAt: z2.string().nullable(),
532
+ elapsedSeconds: z2.number().nullable(),
533
+ estimatedRemainingSeconds: z2.number().nullable(),
534
+ progress: z2.object({
535
+ percent: z2.number(),
536
+ phasesCompleted: z2.number(),
537
+ phasesTotal: z2.number(),
538
+ storiesCompleted: z2.number(),
539
+ storiesTotal: z2.number()
540
+ }),
541
+ currentPhase: z2.string().nullable(),
542
+ currentActivity: z2.object({
543
+ story: z2.string().nullable(),
544
+ tool: z2.string().nullable(),
545
+ detail: z2.string().nullable(),
546
+ since: z2.string()
547
+ }).nullable(),
548
+ phases: z2.array(sessionPhaseSchema),
549
+ stories: z2.array(sessionStorySchema),
550
+ // The whole aggregate is additive: a snapshot from before it existed parses
551
+ // into the same "nothing reported" object the reducer starts from.
552
+ metrics: z2.object({
553
+ totalInputTokens: z2.number().nullable().default(null),
554
+ totalOutputTokens: z2.number().nullable().default(null),
555
+ totalCacheReadTokens: z2.number().nullable().default(null),
556
+ totalCacheCreationTokens: z2.number().nullable().default(null),
557
+ totalCostUsd: z2.number().nullable().default(null)
558
+ }).default({
559
+ totalInputTokens: null,
560
+ totalOutputTokens: null,
561
+ totalCacheReadTokens: null,
562
+ totalCacheCreationTokens: null,
563
+ totalCostUsd: null
564
+ }),
565
+ execution: z2.object({
566
+ iteration: z2.number(),
567
+ retries: z2.number(),
568
+ correctionCycle: z2.number(),
569
+ maxCorrectionCycles: z2.number().nullable()
570
+ }),
571
+ executions: z2.array(executionRecordSchema).default([]),
572
+ processLogs: z2.array(
573
+ z2.object({
574
+ at: z2.string(),
575
+ phase: z2.string(),
576
+ executionId: z2.string().nullable(),
577
+ provider: z2.string(),
578
+ stream: z2.enum(["stdout", "stderr", "combined"]),
579
+ message: z2.string()
580
+ })
581
+ ).default([]),
582
+ configuration: sessionConfigurationSchema.nullable().default(null),
583
+ // Additive resilience projection. Every field defaults so session.json from
584
+ // before provider failover/observability remains readable without a schema
585
+ // version bump.
586
+ resilience: z2.object({
587
+ attempt: z2.number().int().nonnegative().default(0),
588
+ provider: z2.string().nullable().default(null),
589
+ model: z2.string().nullable().default(null),
590
+ lastFailureKind: z2.enum([
591
+ "network",
592
+ "timeout",
593
+ "stalled",
594
+ "rate_limit",
595
+ "provider_down",
596
+ "provider_crash",
597
+ "authentication",
598
+ "configuration",
599
+ "repository_state",
600
+ "task_execution",
601
+ "internal",
602
+ "unknown"
603
+ ]).nullable().default(null),
604
+ cooldownUntil: z2.string().nullable().default(null),
605
+ lastActivityAt: z2.string().nullable().default(null)
606
+ }).default({
607
+ attempt: 0,
608
+ provider: null,
609
+ model: null,
610
+ lastFailureKind: null,
611
+ cooldownUntil: null,
612
+ lastActivityAt: null
613
+ }),
614
+ git: z2.object({
615
+ branch: z2.string().nullable(),
616
+ baseBranch: z2.string().nullable(),
617
+ branchCreated: z2.boolean().nullable().default(null),
618
+ startCommit: z2.string().nullable().default(null),
619
+ commits: z2.array(
620
+ z2.object({
621
+ hash: z2.string(),
622
+ subject: z2.string(),
623
+ committedAt: z2.string().nullable().default(null),
624
+ storyId: z2.string().nullable().default(null)
625
+ })
626
+ )
627
+ }),
628
+ // Additive like the metrics aggregate: a session.json written before the
629
+ // repository section existed parses into the same all-null object
630
+ // createInitialSnapshot() starts from.
631
+ repository: z2.object({
632
+ name: z2.string().nullable().default(null),
633
+ remoteUrl: z2.string().nullable().default(null),
634
+ branch: z2.string().nullable().default(null),
635
+ headCommit: z2.string().nullable().default(null),
636
+ root: z2.string().nullable().default(null)
637
+ }).default({ name: null, remoteUrl: null, branch: null, headCommit: null, root: null }),
638
+ pullRequests: z2.array(z2.object({ number: z2.number(), url: z2.string(), title: z2.string() })),
639
+ logs: z2.array(sessionLogEntrySchema),
640
+ errors: z2.array(sessionLogEntrySchema),
641
+ warnings: z2.array(sessionLogEntrySchema),
642
+ lastError: z2.object({ message: z2.string(), at: z2.string() }).nullable(),
643
+ nextSteps: z2.array(z2.string()),
644
+ environment: z2.object({
645
+ node: z2.string(),
646
+ platform: z2.string(),
647
+ agent: z2.string().nullable().default(null),
648
+ model: z2.string().nullable().default(null)
649
+ }).nullable(),
650
+ // Additive: a session.json written before the acceptance contract existed
651
+ // parses as "not reported". schemaVersion stays 1.
652
+ verification: z2.object({
653
+ verdict: z2.enum(["passed", "failed", "unverified"]).nullable(),
654
+ level: z2.string().nullable(),
655
+ independence: z2.string().nullable()
656
+ }).nullable().default(null)
657
+ });
658
+ var webConfigSchema = z2.object({
659
+ enabled: z2.boolean().default(false),
660
+ port: z2.number().int().min(1).max(65535).default(3737),
661
+ host: z2.string().min(1).default("0.0.0.0"),
662
+ refreshSeconds: z2.number().positive().default(5),
663
+ logLimit: z2.number().int().positive().default(200),
664
+ includeLogs: z2.boolean().default(true)
665
+ });
666
+ var issuesConfigSchema = z2.object({
667
+ defaultGenerateTarget: z2.enum(["github", "local", "both"]).default("github"),
668
+ preferredProvider: z2.enum(["github", "local"]).default("github"),
669
+ conflictPolicy: z2.enum(["ask", "prefer-local", "prefer-github"]).default("ask"),
670
+ requireConfirmation: z2.boolean().default(true)
671
+ });
672
+ var prReviewConfigSchema = z2.object({
673
+ publisher: z2.enum(["local", "github"]).default("local")
674
+ });
675
+ var verifyCheckSchema = z2.object({
676
+ id: z2.string().min(1),
677
+ run: z2.string().optional(),
678
+ expectFiles: z2.array(z2.string()).optional(),
679
+ fatal: z2.boolean().optional()
680
+ });
681
+ var verifyConfigSchema = z2.object({
682
+ level: z2.enum(["L0", "L1", "L2", "L3", "L5"]).default("L1"),
683
+ triggers: z2.array(z2.string()).default([]),
684
+ pairings: z2.record(z2.string(), z2.string()).default({}),
685
+ contract: z2.array(verifyCheckSchema).optional(),
686
+ crossVerify: z2.boolean().default(true)
687
+ });
688
+ var routingConfigSchema = z2.object({
689
+ mode: z2.enum(["off", "shadow", "recommend", "active"]).default("shadow"),
690
+ profile: z2.enum(["economy", "balanced", "quality", "speed"]).default("balanced"),
691
+ escalation: z2.object({
692
+ enabled: z2.boolean().default(false),
693
+ minAttemptsBeforeEscalation: z2.number().int().positive().default(2),
694
+ maxEscalations: z2.number().int().nonnegative().default(2),
695
+ maxRungs: z2.array(z2.enum(["effort", "model", "harness", "review", "decompose"])).default(["effort", "model", "harness"])
696
+ }).default({
697
+ enabled: false,
698
+ minAttemptsBeforeEscalation: 2,
699
+ maxEscalations: 2,
700
+ maxRungs: ["effort", "model", "harness"]
701
+ }),
702
+ ceilings: z2.object({
703
+ maxCostUsdPerIssue: z2.number().nonnegative().nullable().default(null),
704
+ maxDurationMsPerIssue: z2.number().nonnegative().nullable().default(null),
705
+ maxExecutionsPerIssue: z2.number().int().nonnegative().nullable().default(null),
706
+ onCeiling: z2.literal("block").default("block")
707
+ }).default({
708
+ maxCostUsdPerIssue: null,
709
+ maxDurationMsPerIssue: null,
710
+ maxExecutionsPerIssue: null,
711
+ onCeiling: "block"
712
+ })
713
+ });
714
+
715
+ // src/agents/schemas.ts
716
+ import { z as z3 } from "zod";
717
+ var agentProviderIdSchema = z3.enum(["claude", "codex", "cursor", "antigravity"]);
718
+ var codexSandboxSchema = z3.enum(["read-only", "workspace-write", "danger-full-access"]);
719
+ var codexReasoningEffortSchema = z3.enum(["minimal", "low", "medium", "high", "xhigh"]);
720
+ var claudeSettingsSchema = z3.object({
721
+ ignoreUserConfig: z3.boolean(),
722
+ strictMcpConfig: z3.boolean()
723
+ }).partial();
724
+ var codexSettingsSchema = z3.object({
725
+ reasoningEffort: codexReasoningEffortSchema,
726
+ sandbox: codexSandboxSchema,
727
+ ignoreUserConfig: z3.boolean(),
728
+ skipGitRepoCheck: z3.boolean(),
729
+ configOverrides: z3.record(z3.string(), z3.union([z3.string(), z3.number(), z3.boolean()]))
730
+ }).partial();
731
+ var cursorSandboxSchema = z3.enum(["enabled", "disabled"]);
732
+ var cursorPermissionsFileSchema = z3.enum(["global", "project", "none"]);
733
+ var cursorSettingsSchema = z3.object({
734
+ sandbox: cursorSandboxSchema,
735
+ approveMcps: z3.boolean(),
736
+ permissionsFile: cursorPermissionsFileSchema,
737
+ minVersion: z3.string().min(1),
738
+ force: z3.boolean().refine((value) => value !== false, {
739
+ message: "agent.cursor.force cannot be false: without --force, Cursor finishes with exit 0 and writes nothing."
740
+ })
741
+ }).partial();
742
+ var antigravityEffortSchema = z3.enum(["low", "medium", "high"]);
743
+ var antigravitySettingsSchema = z3.object({
744
+ effort: antigravityEffortSchema,
745
+ sandbox: z3.boolean(),
746
+ executeTimeout: z3.union([z3.number().int(), z3.string().min(1), z3.null()]),
747
+ maxPromptBytes: z3.number().int().positive(),
748
+ minVersion: z3.string().min(1),
749
+ skipPermissions: z3.boolean().refine((value) => value !== false, {
750
+ message: "agent.antigravity.skipPermissions cannot be false: without --dangerously-skip-permissions, Antigravity finishes SUCCESS and writes nothing."
751
+ })
752
+ }).partial();
753
+ var agentBlockSchema = z3.object({
754
+ provider: agentProviderIdSchema,
755
+ model: z3.string().min(1).nullable(),
756
+ claude: claudeSettingsSchema,
757
+ codex: codexSettingsSchema,
758
+ cursor: cursorSettingsSchema,
759
+ antigravity: antigravitySettingsSchema
760
+ }).partial();
761
+ var agentPhasesSchema = z3.object({
762
+ analyze: agentBlockSchema,
763
+ generate: agentBlockSchema,
764
+ prd: agentBlockSchema,
765
+ plan: agentBlockSchema,
766
+ execute: agentBlockSchema,
767
+ review: agentBlockSchema,
768
+ pr: agentBlockSchema,
769
+ "pr-review": agentBlockSchema
770
+ }).partial();
771
+ var agentConfigInputSchema = z3.object({
772
+ provider: agentProviderIdSchema,
773
+ model: z3.string().min(1).nullable(),
774
+ claude: claudeSettingsSchema,
775
+ codex: codexSettingsSchema,
776
+ cursor: cursorSettingsSchema,
777
+ antigravity: antigravitySettingsSchema,
778
+ phases: agentPhasesSchema
779
+ }).partial();
780
+ function parsePhasesInput(value, warn) {
781
+ if (value === void 0 || value === null) return {};
782
+ if (typeof value !== "object" || Array.isArray(value)) {
783
+ warn('Ignoring "agent.phases": expected an object.');
784
+ return {};
785
+ }
786
+ const result = {};
787
+ for (const [key, raw] of Object.entries(value)) {
788
+ if (!AGENT_PHASES.includes(key)) {
789
+ warn(`Ignoring unknown agent phase "${key}".`);
790
+ continue;
791
+ }
792
+ const parsed = agentBlockSchema.safeParse(raw);
793
+ if (!parsed.success) {
794
+ warn(`Ignoring agent.phases.${key}: ${parsed.error.issues[0]?.message ?? "invalid value"}.`);
795
+ continue;
796
+ }
797
+ result[key] = parsed.data;
798
+ }
799
+ return result;
800
+ }
801
+
802
+ // src/storage/schemas.ts
803
+ import { z as z4 } from "zod";
804
+ var STORAGE_SCHEMA_VERSION = 1;
805
+ var userStoryNumberingSourceSchema = z4.enum(["history", "start-us", "none"]);
806
+ var userStoryNumberingDecisionSchema = z4.object({
807
+ /** The `US-NNN` number the `plan` prompt was told to continue from. */
808
+ nextNumber: z4.number().int().positive(),
809
+ source: userStoryNumberingSourceSchema,
810
+ /** Issue the decision was made for. */
811
+ issueNumber: z4.string().min(1),
812
+ decidedAt: z4.string().min(1),
813
+ /** Human-readable origin, e.g. the previous story id and issue it came from. */
814
+ detail: z4.string().optional()
815
+ });
816
+ var projectMetadataSchema = z4.object({
817
+ schemaVersion: z4.number().int().positive(),
818
+ projectId: z4.string().min(1),
819
+ root: z4.string().min(1),
820
+ /** Normalized remote (`host/org/repo`), or null when the project has none. */
821
+ remoteUrl: z4.string().nullable(),
822
+ createdAt: z4.string().min(1),
823
+ updatedAt: z4.string().min(1),
824
+ /** Null until the project is used by a pipeline run. */
825
+ lastAttemptAt: z4.string().nullable(),
826
+ /**
827
+ * Most recent User Story numbering decision made by `plan` (issue #36).
828
+ * Absent on a project whose `plan` never ran through the numbering
829
+ * resolver, or on a `metadata.json` written before the feature existed.
830
+ */
831
+ userStoryNumbering: userStoryNumberingDecisionSchema.optional()
832
+ });
833
+ var webShape = webConfigSchema.shape;
834
+ var globalWebConfigSchema = z4.object({
835
+ port: webShape.port.unwrap(),
836
+ host: webShape.host.unwrap(),
837
+ refreshSeconds: webShape.refreshSeconds.unwrap(),
838
+ logLimit: webShape.logLimit.unwrap()
839
+ }).partial();
840
+ var globalRetryConfigSchema = z4.object({
841
+ retryLimit: z4.number().int().nonnegative(),
842
+ retryForever: z4.boolean(),
843
+ backoffBaseSeconds: z4.number().nonnegative(),
844
+ backoffMaxSeconds: z4.number().nonnegative()
845
+ }).partial();
846
+ var resilienceProfileSchema = z4.enum([
847
+ "default",
848
+ "continuous"
849
+ ]);
850
+ var jitterSchema = z4.enum(["none", "full"]);
851
+ var failoverModeSchema = z4.enum([
852
+ "never",
853
+ "after_attempts",
854
+ "immediate"
855
+ ]);
856
+ var exhaustedActionSchema = z4.enum(["fail", "block"]);
857
+ var retryPolicyOverrideSchema = z4.object({
858
+ maxAttempts: z4.number().int().nonnegative(),
859
+ initialDelayMs: z4.number().nonnegative(),
860
+ maxDelayMs: z4.number().nonnegative(),
861
+ backoffFactor: z4.number().min(1),
862
+ jitter: jitterSchema,
863
+ retryForever: z4.boolean(),
864
+ failover: failoverModeSchema,
865
+ failoverAfterAttempts: z4.number().int().positive(),
866
+ onExhausted: exhaustedActionSchema
867
+ }).partial();
868
+ var retryOverridesByKind = {
869
+ network: retryPolicyOverrideSchema,
870
+ timeout: retryPolicyOverrideSchema,
871
+ stalled: retryPolicyOverrideSchema,
872
+ rateLimit: retryPolicyOverrideSchema,
873
+ providerDown: retryPolicyOverrideSchema,
874
+ providerCrash: retryPolicyOverrideSchema,
875
+ authentication: retryPolicyOverrideSchema,
876
+ configuration: retryPolicyOverrideSchema,
877
+ repositoryState: retryPolicyOverrideSchema,
878
+ taskExecution: retryPolicyOverrideSchema,
879
+ internal: retryPolicyOverrideSchema,
880
+ unknown: retryPolicyOverrideSchema
881
+ };
882
+ var resilienceRetryConfigSchema = z4.object(retryOverridesByKind).partial();
883
+ var resilienceProvidersConfigSchema = z4.object({
884
+ failover: z4.boolean(),
885
+ chain: z4.array(z4.string().min(1)),
886
+ cooldownMs: z4.number().nonnegative(),
887
+ maxCooldownMs: z4.number().nonnegative(),
888
+ failureWindowMs: z4.number().positive(),
889
+ failuresToTrip: z4.number().int().positive()
890
+ }).partial();
891
+ var providerHealthStatusSchema = z4.enum([
892
+ "healthy",
893
+ "degraded",
894
+ "unavailable",
895
+ "rate_limited",
896
+ "auth_failed",
897
+ "half_open"
898
+ ]);
899
+ var providerHealthRecordSchema = z4.object({
900
+ status: providerHealthStatusSchema.default("healthy"),
901
+ failures: z4.array(
902
+ z4.object({
903
+ at: z4.string(),
904
+ kind: z4.enum([
905
+ "network",
906
+ "timeout",
907
+ "stalled",
908
+ "rate_limit",
909
+ "provider_down",
910
+ "provider_crash",
911
+ "authentication",
912
+ "configuration",
913
+ "repository_state",
914
+ "task_execution",
915
+ "internal",
916
+ "unknown"
917
+ ])
918
+ })
919
+ ).default([]),
920
+ consecutiveFailures: z4.number().int().nonnegative().default(0),
921
+ cooldownLevel: z4.number().int().nonnegative().default(0),
922
+ cooldownUntil: z4.string().nullable().default(null),
923
+ lastFailureKind: z4.enum([
924
+ "network",
925
+ "timeout",
926
+ "stalled",
927
+ "rate_limit",
928
+ "provider_down",
929
+ "provider_crash",
930
+ "authentication",
931
+ "configuration",
932
+ "repository_state",
933
+ "task_execution",
934
+ "internal",
935
+ "unknown"
936
+ ]).nullable().default(null),
937
+ lastFailureAt: z4.string().nullable().default(null),
938
+ lastSuccessAt: z4.string().nullable().default(null),
939
+ probeInFlight: z4.boolean().default(false),
940
+ probeStartedAt: z4.string().nullable().default(null)
941
+ });
942
+ var providersHealthSchema = z4.object({
943
+ schemaVersion: z4.literal(1).default(1),
944
+ providers: z4.record(z4.string(), providerHealthRecordSchema).default({})
945
+ });
946
+ var resilienceQueueConfigSchema = z4.object({
947
+ onIssueFailure: z4.enum(["stop", "skip", "block"]),
948
+ maxIssueAttempts: z4.number().int().positive()
949
+ }).partial();
950
+ var resilienceWatchdogConfigSchema = z4.object({
951
+ inactivityTimeoutMs: z4.number().int().nonnegative()
952
+ }).partial();
953
+ var resilienceJournalConfigSchema = z4.object({
954
+ enabled: z4.boolean(),
955
+ maxFileBytes: z4.number().int().positive()
956
+ }).partial();
957
+ var resilienceDecomposeConfigSchema = z4.object({
958
+ auto: z4.boolean()
959
+ }).partial();
960
+ var resilienceConfigSchema = z4.object({
961
+ profile: resilienceProfileSchema,
962
+ /** Whether a credential failure may migrate to another provider. */
963
+ failoverOnAuth: z4.boolean(),
964
+ retry: resilienceRetryConfigSchema,
965
+ providers: resilienceProvidersConfigSchema,
966
+ queue: resilienceQueueConfigSchema,
967
+ watchdog: resilienceWatchdogConfigSchema,
968
+ journal: resilienceJournalConfigSchema,
969
+ decompose: resilienceDecomposeConfigSchema
970
+ }).partial();
971
+ var telemetryPricingOverrideSchema = z4.object({
972
+ inputPerMillion: z4.number(),
973
+ outputPerMillion: z4.number(),
974
+ cacheReadPerMillion: z4.number(),
975
+ cacheWritePerMillion: z4.number()
976
+ }).partial();
977
+ var telemetryConfigInputSchema = z4.object({
978
+ enabled: z4.boolean(),
979
+ maxExecutions: z4.number().int().positive(),
980
+ pricing: z4.object({
981
+ estimate: z4.boolean(),
982
+ overrides: z4.record(z4.string(), telemetryPricingOverrideSchema)
983
+ }).partial()
984
+ }).partial();
985
+ var globalCommitConfigSchema = z4.object({
986
+ signoff: z4.boolean(),
987
+ conventional: z4.boolean()
988
+ }).partial();
989
+ var globalConfigSchema = z4.object({
990
+ schemaVersion: z4.number().int().positive(),
991
+ /** Override for the directory holding `projects/`. */
992
+ storageDir: z4.string().min(1),
993
+ web: globalWebConfigSchema,
994
+ retry: globalRetryConfigSchema,
995
+ commit: globalCommitConfigSchema,
996
+ resilience: resilienceConfigSchema,
997
+ agent: agentConfigInputSchema,
998
+ telemetry: telemetryConfigInputSchema
999
+ }).partial();
1000
+ var webLockSchema = z4.object({
1001
+ pid: z4.number().int().positive(),
1002
+ port: z4.number().int().positive(),
1003
+ host: z4.string().min(1),
1004
+ startedAt: z4.string().min(1)
1005
+ });
1006
+ var runLockSchema = z4.object({
1007
+ pid: z4.number().int().positive(),
1008
+ /** `os.hostname()`. A pid only means something on the host that wrote it. */
1009
+ host: z4.string().min(1),
1010
+ /** The issue (or queue) identifier the owner is running. */
1011
+ target: z4.string().min(1),
1012
+ startedAt: z4.string().min(1),
1013
+ lastHeartbeatAt: z4.string().min(1),
1014
+ /** Absent on a foreground run written before this field existed. */
1015
+ detached: z4.boolean().optional()
1016
+ });
1017
+ var executionPlanIssueSchema = z4.object({
1018
+ id: z4.string().min(1),
1019
+ number: z4.number().int().positive().nullable(),
1020
+ title: z4.string(),
1021
+ url: z4.string().nullable(),
1022
+ source: z4.string().min(1),
1023
+ position: z4.number().int().positive(),
1024
+ // `blocked` and `skipped` are additive: no plan written before them can
1025
+ // carry one, and a reader that does not know them was never given one.
1026
+ status: z4.enum(["pending", "in_progress", "completed", "failed", "blocked", "skipped"]),
1027
+ origin: z4.enum(["requested", "discovered"]),
1028
+ role: z4.enum(["executable", "container"]).default("executable"),
1029
+ externalDependencies: z4.array(z4.string()).default([]),
1030
+ dependsOn: z4.array(z4.string()).default([]),
1031
+ parent: z4.string().nullable().default(null),
1032
+ priority: z4.enum(["high", "medium", "low"]).nullable().default(null),
1033
+ heuristic: z4.boolean().default(false),
1034
+ failedPhase: z4.string().nullable().default(null),
1035
+ lastError: z4.object({ category: z4.string(), message: z4.string(), at: z4.string() }).nullable().default(null),
1036
+ startedAt: z4.string().nullable().default(null),
1037
+ completedAt: z4.string().nullable().default(null),
1038
+ // Both default, so an execution-plan.json written by an earlier release
1039
+ // parses unchanged and reads as "never attempted, not blocked".
1040
+ attempts: z4.number().int().min(0).default(0),
1041
+ blockedReason: z4.string().nullable().default(null)
1042
+ });
1043
+ var executionPlanSchema = z4.object({
1044
+ schemaVersion: z4.literal(1),
1045
+ id: z4.string().min(1),
1046
+ project: z4.string().min(1),
1047
+ requested: z4.array(z4.string().min(1)),
1048
+ branchName: z4.string().nullable().default(null),
1049
+ noBranch: z4.boolean().default(false),
1050
+ prReview: z4.boolean().default(false),
1051
+ status: z4.enum(["pending", "in_progress", "completed", "failed"]),
1052
+ createdAt: z4.string().min(1),
1053
+ updatedAt: z4.string().min(1),
1054
+ truncated: z4.boolean().default(false),
1055
+ issues: z4.array(executionPlanIssueSchema),
1056
+ excluded: z4.array(
1057
+ z4.object({
1058
+ id: z4.string().min(1),
1059
+ number: z4.number().int().positive().nullable(),
1060
+ title: z4.string(),
1061
+ url: z4.string().nullable(),
1062
+ reason: z4.string()
1063
+ })
1064
+ ).default([]),
1065
+ pullRequest: pullRequestRefSchema.optional()
1066
+ });
1067
+
1068
+ // src/storage/lock.ts
1069
+ import { mkdir, readFile, rm, writeFile } from "fs/promises";
1070
+ import { hostname } from "os";
1071
+ import { dirname } from "path";
1072
+ var RUN_LOCK_HEARTBEAT_MS = 1e4;
1073
+ var RUN_LOCK_STALE_INTERVALS = 3;
1074
+ var CLAIM_RETRIES = 3;
1075
+ function isProcessAlive(pid) {
1076
+ try {
1077
+ process.kill(pid, 0);
1078
+ return true;
1079
+ } catch (err) {
1080
+ return err.code === "EPERM";
1081
+ }
1082
+ }
1083
+ async function readRunLock(lockFile) {
1084
+ let raw;
1085
+ try {
1086
+ raw = await readFile(lockFile, "utf-8");
1087
+ } catch {
1088
+ return null;
1089
+ }
1090
+ try {
1091
+ const result = runLockSchema.safeParse(JSON.parse(raw));
1092
+ return result.success ? result.data : null;
1093
+ } catch {
1094
+ return null;
1095
+ }
1096
+ }
1097
+ async function removeRunLock(lockFile) {
1098
+ try {
1099
+ await rm(lockFile, { force: true });
1100
+ } catch {
1101
+ }
1102
+ }
1103
+ function isRunLockStale(lock, options = {}) {
1104
+ const heartbeatMs = options.heartbeatMs ?? RUN_LOCK_HEARTBEAT_MS;
1105
+ const staleIntervals = options.staleIntervals ?? RUN_LOCK_STALE_INTERVALS;
1106
+ const now = (options.clock ?? Date.now)();
1107
+ const host = options.host ?? hostname();
1108
+ const beat = Date.parse(lock.lastHeartbeatAt);
1109
+ const silent = Number.isNaN(beat) || now - beat > heartbeatMs * staleIntervals;
1110
+ if (lock.host !== host) return silent;
1111
+ return silent || !isProcessAlive(lock.pid);
1112
+ }
1113
+ function isSelf(lock, pid, host) {
1114
+ return lock.pid === pid && lock.host === host;
1115
+ }
1116
+ function describeRunLockOwner(lock) {
1117
+ return `pid ${lock.pid} on ${lock.host} (issue ${lock.target}, started ${lock.startedAt}, last heartbeat ${lock.lastHeartbeatAt})`;
1118
+ }
1119
+ async function touchRunLock(lockFile, lock, at) {
1120
+ const next = { ...lock, lastHeartbeatAt: at };
1121
+ try {
1122
+ await writeFile(lockFile, `${JSON.stringify(next, null, 2)}
1123
+ `, "utf-8");
1124
+ } catch {
1125
+ }
1126
+ return next;
1127
+ }
1128
+ async function claim(lockFile, lock) {
1129
+ try {
1130
+ await mkdir(dirname(lockFile), { recursive: true });
1131
+ await writeFile(lockFile, `${JSON.stringify(lock, null, 2)}
1132
+ `, {
1133
+ encoding: "utf-8",
1134
+ flag: "wx"
1135
+ });
1136
+ return true;
1137
+ } catch (err) {
1138
+ if (err.code === "EEXIST") return false;
1139
+ throw err;
1140
+ }
1141
+ }
1142
+ async function acquireRunLock(lockFile, options) {
1143
+ const pid = options.pid ?? process.pid;
1144
+ const host = options.host ?? hostname();
1145
+ const heartbeatMs = options.heartbeatMs ?? RUN_LOCK_HEARTBEAT_MS;
1146
+ const clock = options.clock ?? Date.now;
1147
+ const staleness = {
1148
+ heartbeatMs,
1149
+ ...options.staleIntervals === void 0 ? {} : { staleIntervals: options.staleIntervals },
1150
+ clock,
1151
+ pid,
1152
+ host
1153
+ };
1154
+ let reclaimedFrom = null;
1155
+ for (let attempt = 0; attempt <= CLAIM_RETRIES; attempt++) {
1156
+ const at = new Date(clock()).toISOString();
1157
+ const mine = {
1158
+ pid,
1159
+ host,
1160
+ target: options.target,
1161
+ startedAt: at,
1162
+ lastHeartbeatAt: at,
1163
+ ...options.detached === true ? { detached: true } : {}
1164
+ };
1165
+ if (await claim(lockFile, mine)) {
1166
+ return { ok: true, handle: startHandle(lockFile, mine, reclaimedFrom, options) };
1167
+ }
1168
+ const existing = await readRunLock(lockFile);
1169
+ if (existing === null) {
1170
+ await removeRunLock(lockFile);
1171
+ continue;
1172
+ }
1173
+ if (isSelf(existing, pid, host)) {
1174
+ return { ok: true, handle: nestedHandle(existing) };
1175
+ }
1176
+ if (!isRunLockStale(existing, staleness)) {
1177
+ return { ok: false, owner: existing };
1178
+ }
1179
+ reclaimedFrom = existing;
1180
+ try {
1181
+ options.onTakeover?.(existing);
1182
+ } catch {
1183
+ }
1184
+ await removeRunLock(lockFile);
1185
+ }
1186
+ const owner = await readRunLock(lockFile);
1187
+ if (owner !== null) return { ok: false, owner };
1188
+ return {
1189
+ ok: false,
1190
+ owner: {
1191
+ pid: 0,
1192
+ host,
1193
+ target: options.target,
1194
+ startedAt: new Date(clock()).toISOString(),
1195
+ lastHeartbeatAt: new Date(clock()).toISOString()
1196
+ }
1197
+ };
1198
+ }
1199
+ function startHandle(lockFile, lock, reclaimedFrom, options) {
1200
+ const heartbeatMs = options.heartbeatMs ?? RUN_LOCK_HEARTBEAT_MS;
1201
+ const clock = options.clock ?? Date.now;
1202
+ let current = lock;
1203
+ let timer = null;
1204
+ if (options.heartbeat !== false) {
1205
+ timer = setInterval(() => {
1206
+ void touchRunLock(lockFile, current, new Date(clock()).toISOString()).then((next) => {
1207
+ current = next;
1208
+ });
1209
+ }, heartbeatMs);
1210
+ timer.unref();
1211
+ }
1212
+ return {
1213
+ lock,
1214
+ reclaimedFrom,
1215
+ release: async () => {
1216
+ if (timer !== null) {
1217
+ clearInterval(timer);
1218
+ timer = null;
1219
+ }
1220
+ await removeRunLock(lockFile);
1221
+ }
1222
+ };
1223
+ }
1224
+ function nestedHandle(lock) {
1225
+ return { lock, reclaimedFrom: null, release: async () => {
1226
+ } };
1227
+ }
1228
+
1229
+ export {
1230
+ AGENT_PHASES,
1231
+ isAgentPhase,
1232
+ isAgentProviderId,
1233
+ CLAUDE_CAPABILITIES,
1234
+ CODEX_CAPABILITIES,
1235
+ CURSOR_CAPABILITIES,
1236
+ ANTIGRAVITY_CAPABILITIES,
1237
+ AGENT_SCHEMA_VERSION,
1238
+ policyConfigSchema,
1239
+ policyConfigInputSchema,
1240
+ issueMetadataSchema,
1241
+ taskPlanSchema,
1242
+ sessionSnapshotSchema,
1243
+ webConfigSchema,
1244
+ issuesConfigSchema,
1245
+ prReviewConfigSchema,
1246
+ verifyConfigSchema,
1247
+ routingConfigSchema,
1248
+ agentConfigInputSchema,
1249
+ parsePhasesInput,
1250
+ STORAGE_SCHEMA_VERSION,
1251
+ projectMetadataSchema,
1252
+ providersHealthSchema,
1253
+ resilienceConfigSchema,
1254
+ telemetryConfigInputSchema,
1255
+ globalConfigSchema,
1256
+ webLockSchema,
1257
+ executionPlanSchema,
1258
+ isProcessAlive,
1259
+ readRunLock,
1260
+ isRunLockStale,
1261
+ describeRunLockOwner,
1262
+ acquireRunLock
1263
+ };
1264
+ //# sourceMappingURL=chunk-LBGHI4S2.js.map