@ttfw/envoi 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 (283) hide show
  1. package/README.md +238 -0
  2. package/dist/commands/app.d.ts +2 -0
  3. package/dist/commands/app.d.ts.map +1 -0
  4. package/dist/commands/app.js +31 -0
  5. package/dist/commands/app.js.map +1 -0
  6. package/dist/commands/autonomy.d.ts +6 -0
  7. package/dist/commands/autonomy.d.ts.map +1 -0
  8. package/dist/commands/autonomy.js +89 -0
  9. package/dist/commands/autonomy.js.map +1 -0
  10. package/dist/commands/builder.d.ts +13 -0
  11. package/dist/commands/builder.d.ts.map +1 -0
  12. package/dist/commands/builder.js +142 -0
  13. package/dist/commands/builder.js.map +1 -0
  14. package/dist/commands/idea.d.ts +12 -0
  15. package/dist/commands/idea.d.ts.map +1 -0
  16. package/dist/commands/idea.js +79 -0
  17. package/dist/commands/idea.js.map +1 -0
  18. package/dist/commands/init.d.ts +18 -0
  19. package/dist/commands/init.d.ts.map +1 -0
  20. package/dist/commands/init.js +423 -0
  21. package/dist/commands/init.js.map +1 -0
  22. package/dist/commands/mode.d.ts +13 -0
  23. package/dist/commands/mode.d.ts.map +1 -0
  24. package/dist/commands/mode.js +96 -0
  25. package/dist/commands/mode.js.map +1 -0
  26. package/dist/commands/onboard.d.ts +37 -0
  27. package/dist/commands/onboard.d.ts.map +1 -0
  28. package/dist/commands/onboard.js +743 -0
  29. package/dist/commands/onboard.js.map +1 -0
  30. package/dist/commands/pr-note.d.ts +8 -0
  31. package/dist/commands/pr-note.d.ts.map +1 -0
  32. package/dist/commands/pr-note.js +27 -0
  33. package/dist/commands/pr-note.js.map +1 -0
  34. package/dist/commands/undo.d.ts +7 -0
  35. package/dist/commands/undo.d.ts.map +1 -0
  36. package/dist/commands/undo.js +59 -0
  37. package/dist/commands/undo.js.map +1 -0
  38. package/dist/commands/update.d.ts +24 -0
  39. package/dist/commands/update.d.ts.map +1 -0
  40. package/dist/commands/update.js +248 -0
  41. package/dist/commands/update.js.map +1 -0
  42. package/dist/constants/report_codes.d.ts +29 -0
  43. package/dist/constants/report_codes.d.ts.map +1 -0
  44. package/dist/constants/report_codes.js +69 -0
  45. package/dist/constants/report_codes.js.map +1 -0
  46. package/dist/index.d.ts +3 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +675 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/lib/autonomy.d.ts +16 -0
  51. package/dist/lib/autonomy.d.ts.map +1 -0
  52. package/dist/lib/autonomy.js +38 -0
  53. package/dist/lib/autonomy.js.map +1 -0
  54. package/dist/lib/blocked.d.ts +87 -0
  55. package/dist/lib/blocked.d.ts.map +1 -0
  56. package/dist/lib/blocked.js +134 -0
  57. package/dist/lib/blocked.js.map +1 -0
  58. package/dist/lib/branding.d.ts +13 -0
  59. package/dist/lib/branding.d.ts.map +1 -0
  60. package/dist/lib/branding.js +19 -0
  61. package/dist/lib/branding.js.map +1 -0
  62. package/dist/lib/claude.d.ts +42 -0
  63. package/dist/lib/claude.d.ts.map +1 -0
  64. package/dist/lib/claude.js +291 -0
  65. package/dist/lib/claude.js.map +1 -0
  66. package/dist/lib/config.d.ts +71 -0
  67. package/dist/lib/config.d.ts.map +1 -0
  68. package/dist/lib/config.js +410 -0
  69. package/dist/lib/config.js.map +1 -0
  70. package/dist/lib/diff.d.ts +150 -0
  71. package/dist/lib/diff.d.ts.map +1 -0
  72. package/dist/lib/diff.js +257 -0
  73. package/dist/lib/diff.js.map +1 -0
  74. package/dist/lib/doctor.d.ts +67 -0
  75. package/dist/lib/doctor.d.ts.map +1 -0
  76. package/dist/lib/doctor.js +211 -0
  77. package/dist/lib/doctor.js.map +1 -0
  78. package/dist/lib/fingerprint.d.ts +27 -0
  79. package/dist/lib/fingerprint.d.ts.map +1 -0
  80. package/dist/lib/fingerprint.js +116 -0
  81. package/dist/lib/fingerprint.js.map +1 -0
  82. package/dist/lib/fs.d.ts +93 -0
  83. package/dist/lib/fs.d.ts.map +1 -0
  84. package/dist/lib/fs.js +179 -0
  85. package/dist/lib/fs.js.map +1 -0
  86. package/dist/lib/git.d.ts +177 -0
  87. package/dist/lib/git.d.ts.map +1 -0
  88. package/dist/lib/git.js +355 -0
  89. package/dist/lib/git.js.map +1 -0
  90. package/dist/lib/git_branching.d.ts +84 -0
  91. package/dist/lib/git_branching.d.ts.map +1 -0
  92. package/dist/lib/git_branching.js +327 -0
  93. package/dist/lib/git_branching.js.map +1 -0
  94. package/dist/lib/gitignore.d.ts +26 -0
  95. package/dist/lib/gitignore.d.ts.map +1 -0
  96. package/dist/lib/gitignore.js +119 -0
  97. package/dist/lib/gitignore.js.map +1 -0
  98. package/dist/lib/guardrails.d.ts +232 -0
  99. package/dist/lib/guardrails.d.ts.map +1 -0
  100. package/dist/lib/guardrails.js +323 -0
  101. package/dist/lib/guardrails.js.map +1 -0
  102. package/dist/lib/history.d.ts +110 -0
  103. package/dist/lib/history.d.ts.map +1 -0
  104. package/dist/lib/history.js +236 -0
  105. package/dist/lib/history.js.map +1 -0
  106. package/dist/lib/index.d.ts +29 -0
  107. package/dist/lib/index.d.ts.map +1 -0
  108. package/dist/lib/index.js +29 -0
  109. package/dist/lib/index.js.map +1 -0
  110. package/dist/lib/json-extract.d.ts +42 -0
  111. package/dist/lib/json-extract.d.ts.map +1 -0
  112. package/dist/lib/json-extract.js +201 -0
  113. package/dist/lib/json-extract.js.map +1 -0
  114. package/dist/lib/judge.d.ts +237 -0
  115. package/dist/lib/judge.d.ts.map +1 -0
  116. package/dist/lib/judge.js +501 -0
  117. package/dist/lib/judge.js.map +1 -0
  118. package/dist/lib/lock.d.ts +79 -0
  119. package/dist/lib/lock.d.ts.map +1 -0
  120. package/dist/lib/lock.js +254 -0
  121. package/dist/lib/lock.js.map +1 -0
  122. package/dist/lib/migration.d.ts +9 -0
  123. package/dist/lib/migration.d.ts.map +1 -0
  124. package/dist/lib/migration.js +74 -0
  125. package/dist/lib/migration.js.map +1 -0
  126. package/dist/lib/paths.d.ts +18 -0
  127. package/dist/lib/paths.d.ts.map +1 -0
  128. package/dist/lib/paths.js +27 -0
  129. package/dist/lib/paths.js.map +1 -0
  130. package/dist/lib/preflight.d.ts +33 -0
  131. package/dist/lib/preflight.d.ts.map +1 -0
  132. package/dist/lib/preflight.js +177 -0
  133. package/dist/lib/preflight.js.map +1 -0
  134. package/dist/lib/prompt_budget.d.ts +18 -0
  135. package/dist/lib/prompt_budget.d.ts.map +1 -0
  136. package/dist/lib/prompt_budget.js +36 -0
  137. package/dist/lib/prompt_budget.js.map +1 -0
  138. package/dist/lib/report.d.ts +102 -0
  139. package/dist/lib/report.d.ts.map +1 -0
  140. package/dist/lib/report.js +347 -0
  141. package/dist/lib/report.js.map +1 -0
  142. package/dist/lib/reviewer-flow.d.ts +80 -0
  143. package/dist/lib/reviewer-flow.d.ts.map +1 -0
  144. package/dist/lib/reviewer-flow.js +138 -0
  145. package/dist/lib/reviewer-flow.js.map +1 -0
  146. package/dist/lib/reviewer.d.ts +53 -0
  147. package/dist/lib/reviewer.d.ts.map +1 -0
  148. package/dist/lib/reviewer.js +199 -0
  149. package/dist/lib/reviewer.js.map +1 -0
  150. package/dist/lib/risk.d.ts +127 -0
  151. package/dist/lib/risk.d.ts.map +1 -0
  152. package/dist/lib/risk.js +192 -0
  153. package/dist/lib/risk.js.map +1 -0
  154. package/dist/lib/rollback.d.ts +143 -0
  155. package/dist/lib/rollback.d.ts.map +1 -0
  156. package/dist/lib/rollback.js +244 -0
  157. package/dist/lib/rollback.js.map +1 -0
  158. package/dist/lib/schema.d.ts +47 -0
  159. package/dist/lib/schema.d.ts.map +1 -0
  160. package/dist/lib/schema.js +91 -0
  161. package/dist/lib/schema.js.map +1 -0
  162. package/dist/lib/scope.d.ts +89 -0
  163. package/dist/lib/scope.d.ts.map +1 -0
  164. package/dist/lib/scope.js +135 -0
  165. package/dist/lib/scope.js.map +1 -0
  166. package/dist/lib/self_update.d.ts +13 -0
  167. package/dist/lib/self_update.d.ts.map +1 -0
  168. package/dist/lib/self_update.js +172 -0
  169. package/dist/lib/self_update.js.map +1 -0
  170. package/dist/lib/state.d.ts +143 -0
  171. package/dist/lib/state.d.ts.map +1 -0
  172. package/dist/lib/state.js +258 -0
  173. package/dist/lib/state.js.map +1 -0
  174. package/dist/lib/tick.d.ts +310 -0
  175. package/dist/lib/tick.d.ts.map +1 -0
  176. package/dist/lib/tick.js +424 -0
  177. package/dist/lib/tick.js.map +1 -0
  178. package/dist/lib/transport.d.ts +145 -0
  179. package/dist/lib/transport.d.ts.map +1 -0
  180. package/dist/lib/transport.js +237 -0
  181. package/dist/lib/transport.js.map +1 -0
  182. package/dist/lib/verdict_labels.d.ts +5 -0
  183. package/dist/lib/verdict_labels.d.ts.map +1 -0
  184. package/dist/lib/verdict_labels.js +25 -0
  185. package/dist/lib/verdict_labels.js.map +1 -0
  186. package/dist/lib/verify-safety.d.ts +63 -0
  187. package/dist/lib/verify-safety.d.ts.map +1 -0
  188. package/dist/lib/verify-safety.js +123 -0
  189. package/dist/lib/verify-safety.js.map +1 -0
  190. package/dist/lib/verify.d.ts +139 -0
  191. package/dist/lib/verify.d.ts.map +1 -0
  192. package/dist/lib/verify.js +311 -0
  193. package/dist/lib/verify.js.map +1 -0
  194. package/dist/lib/workspace_state.d.ts +79 -0
  195. package/dist/lib/workspace_state.d.ts.map +1 -0
  196. package/dist/lib/workspace_state.js +283 -0
  197. package/dist/lib/workspace_state.js.map +1 -0
  198. package/dist/runner/builder.d.ts +58 -0
  199. package/dist/runner/builder.d.ts.map +1 -0
  200. package/dist/runner/builder.js +775 -0
  201. package/dist/runner/builder.js.map +1 -0
  202. package/dist/runner/builder_parse.d.ts +37 -0
  203. package/dist/runner/builder_parse.d.ts.map +1 -0
  204. package/dist/runner/builder_parse.js +76 -0
  205. package/dist/runner/builder_parse.js.map +1 -0
  206. package/dist/runner/index.d.ts +9 -0
  207. package/dist/runner/index.d.ts.map +1 -0
  208. package/dist/runner/index.js +7 -0
  209. package/dist/runner/index.js.map +1 -0
  210. package/dist/runner/loop.d.ts +51 -0
  211. package/dist/runner/loop.d.ts.map +1 -0
  212. package/dist/runner/loop.js +221 -0
  213. package/dist/runner/loop.js.map +1 -0
  214. package/dist/runner/orchestrator.d.ts +67 -0
  215. package/dist/runner/orchestrator.d.ts.map +1 -0
  216. package/dist/runner/orchestrator.js +376 -0
  217. package/dist/runner/orchestrator.js.map +1 -0
  218. package/dist/runner/tick.d.ts +10 -0
  219. package/dist/runner/tick.d.ts.map +1 -0
  220. package/dist/runner/tick.js +1639 -0
  221. package/dist/runner/tick.js.map +1 -0
  222. package/dist/types/blocked.d.ts +52 -0
  223. package/dist/types/blocked.d.ts.map +1 -0
  224. package/dist/types/blocked.js +8 -0
  225. package/dist/types/blocked.js.map +1 -0
  226. package/dist/types/builder.d.ts +25 -0
  227. package/dist/types/builder.d.ts.map +1 -0
  228. package/dist/types/builder.js +7 -0
  229. package/dist/types/builder.js.map +1 -0
  230. package/dist/types/claude.d.ts +86 -0
  231. package/dist/types/claude.d.ts.map +1 -0
  232. package/dist/types/claude.js +48 -0
  233. package/dist/types/claude.js.map +1 -0
  234. package/dist/types/config.d.ts +384 -0
  235. package/dist/types/config.d.ts.map +1 -0
  236. package/dist/types/config.js +7 -0
  237. package/dist/types/config.js.map +1 -0
  238. package/dist/types/index.d.ts +18 -0
  239. package/dist/types/index.d.ts.map +1 -0
  240. package/dist/types/index.js +8 -0
  241. package/dist/types/index.js.map +1 -0
  242. package/dist/types/lock.d.ts +21 -0
  243. package/dist/types/lock.d.ts.map +1 -0
  244. package/dist/types/lock.js +8 -0
  245. package/dist/types/lock.js.map +1 -0
  246. package/dist/types/preflight.d.ts +49 -0
  247. package/dist/types/preflight.d.ts.map +1 -0
  248. package/dist/types/preflight.js +8 -0
  249. package/dist/types/preflight.js.map +1 -0
  250. package/dist/types/report.d.ts +161 -0
  251. package/dist/types/report.d.ts.map +1 -0
  252. package/dist/types/report.js +8 -0
  253. package/dist/types/report.js.map +1 -0
  254. package/dist/types/reviewer.d.ts +66 -0
  255. package/dist/types/reviewer.d.ts.map +1 -0
  256. package/dist/types/reviewer.js +5 -0
  257. package/dist/types/reviewer.js.map +1 -0
  258. package/dist/types/state.d.ts +124 -0
  259. package/dist/types/state.d.ts.map +1 -0
  260. package/dist/types/state.js +20 -0
  261. package/dist/types/state.js.map +1 -0
  262. package/dist/types/task.d.ts +117 -0
  263. package/dist/types/task.d.ts.map +1 -0
  264. package/dist/types/task.js +7 -0
  265. package/dist/types/task.js.map +1 -0
  266. package/dist/types/workspace_state.d.ts +125 -0
  267. package/dist/types/workspace_state.d.ts.map +1 -0
  268. package/dist/types/workspace_state.js +10 -0
  269. package/dist/types/workspace_state.js.map +1 -0
  270. package/envoi.config.json +191 -0
  271. package/package.json +52 -0
  272. package/relais/prompts/.gitkeep +0 -0
  273. package/relais/prompts/builder.system.txt +13 -0
  274. package/relais/prompts/builder.user.txt +15 -0
  275. package/relais/prompts/orchestrator.system.txt +37 -0
  276. package/relais/prompts/orchestrator.user.txt +34 -0
  277. package/relais/prompts/reviewer.system.txt +33 -0
  278. package/relais/prompts/reviewer.user.txt +35 -0
  279. package/relais/schemas/.gitkeep +0 -0
  280. package/relais/schemas/builder_result.schema.json +29 -0
  281. package/relais/schemas/report.schema.json +195 -0
  282. package/relais/schemas/reviewer_result.schema.json +70 -0
  283. package/relais/schemas/task.schema.json +155 -0
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Guardrail preflight checks for verifying state before running verify commands.
3
+ *
4
+ * These checks validate:
5
+ * - Branch match: git branch must equal STATE.branch
6
+ * - Fingerprint match: TASK fingerprint must match STATE.task_fingerprint
7
+ * - Worktree clean: git worktree must be clean
8
+ *
9
+ * If any check fails, returns a STOP code to prevent unsafe execution.
10
+ */
11
+ import type { ReportCode } from '../types/report.js';
12
+ import type { Task } from '../types/task.js';
13
+ import type { TickState } from '../types/state.js';
14
+ import type { EnvoiConfig } from '../types/config.js';
15
+ /**
16
+ * Verify result type classification.
17
+ */
18
+ export type VerifyResultType = 'PASS' | 'FAIL' | 'TIMEOUT';
19
+ /**
20
+ * Classification result for a verify command execution.
21
+ */
22
+ export interface VerifyClassification {
23
+ /** Result type: PASS, FAIL, or TIMEOUT */
24
+ resultType: VerifyResultType;
25
+ /** STOP code if verification failed or timed out, null if passed */
26
+ stopCode: ReportCode | null;
27
+ /** Whether this result should increment the failure streak */
28
+ shouldIncrementFailureStreak: boolean;
29
+ }
30
+ /**
31
+ * State structure required for guardrail preflight checks.
32
+ */
33
+ export interface GuardrailState {
34
+ /** Expected branch name */
35
+ branch: string;
36
+ /** Current task fingerprint (SHA256) */
37
+ task_fingerprint?: string;
38
+ /** Fingerprint of last failed task */
39
+ last_failed_fingerprint?: string;
40
+ }
41
+ /**
42
+ * Result of guardrail preflight checks.
43
+ */
44
+ export interface PreflightResult {
45
+ /** Whether all checks passed */
46
+ ok: boolean;
47
+ /** Stop code if check failed */
48
+ stopCode?: ReportCode;
49
+ /** Human-readable reason for failure */
50
+ reason?: string;
51
+ }
52
+ /**
53
+ * Checks if the current git branch matches the expected branch from state.
54
+ *
55
+ * @param state - State containing expected branch name
56
+ * @returns PreflightResult with ok=true if match, or STOP_BRANCH_MISMATCH if mismatch
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * const result = checkBranchMatch({ branch: 'task/wp-001' });
61
+ * if (!result.ok) {
62
+ * console.error(`Branch mismatch: ${result.reason}`);
63
+ * }
64
+ * ```
65
+ */
66
+ export declare function checkBranchMatch(state: GuardrailState): PreflightResult;
67
+ /**
68
+ * Checks if the task fingerprint matches state expectations.
69
+ *
70
+ * Compares the computed task fingerprint with:
71
+ * - STATE.task_fingerprint (must match if present)
72
+ * - STATE.last_failed_fingerprint (must not match - prevents re-dispatch of identical failed task)
73
+ *
74
+ * @param state - State containing fingerprint information
75
+ * @param task - Task to compute fingerprint for
76
+ * @returns PreflightResult with ok=true if checks pass, or STOP_REDISPATCH_IDENTICAL_TASK if fingerprint matches last failed
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const result = checkFingerprintMatch(state, task);
81
+ * if (!result.ok) {
82
+ * console.error(`Fingerprint check failed: ${result.reason}`);
83
+ * }
84
+ * ```
85
+ */
86
+ export declare function checkFingerprintMatch(state: GuardrailState, task: Task): PreflightResult;
87
+ /**
88
+ * Checks if the git worktree is clean (no uncommitted changes).
89
+ *
90
+ * @returns PreflightResult with ok=true if clean, or STOP_MERGE_DIRTY_WORKTREE if dirty
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * const result = checkWorktreeClean();
95
+ * if (!result.ok) {
96
+ * console.error(`Worktree is dirty: ${result.reason}`);
97
+ * }
98
+ * ```
99
+ */
100
+ export declare function checkWorktreeClean(): PreflightResult;
101
+ /**
102
+ * Runs all guardrail preflight checks before verify commands.
103
+ *
104
+ * Checks are run in order, returning immediately on first failure:
105
+ * 1. Branch match check
106
+ * 2. Fingerprint match check
107
+ * 3. Worktree clean check
108
+ *
109
+ * @param state - State containing branch and fingerprint information
110
+ * @param task - Task to validate fingerprint for
111
+ * @returns PreflightResult indicating if all checks passed or which check failed
112
+ *
113
+ * @example
114
+ * ```typescript
115
+ * const result = runGuardrailPreflight(state, task);
116
+ * if (!result.ok) {
117
+ * console.error(`Preflight failed: ${result.stopCode}: ${result.reason}`);
118
+ * process.exit(1);
119
+ * }
120
+ * ```
121
+ */
122
+ export declare function runGuardrailPreflight(state: GuardrailState, task: Task): PreflightResult;
123
+ /**
124
+ * Escalation decision result.
125
+ */
126
+ export interface EscalationDecision {
127
+ /** Escalation mode: 'none' (no escalation), 'reviewer' (escalate to reviewer), or 'human' (escalate to human) */
128
+ mode: 'none' | 'reviewer' | 'human';
129
+ /** Human-readable reason explaining why escalation was triggered (or why it wasn't) */
130
+ reason: string;
131
+ }
132
+ /**
133
+ * Determines if escalation should be triggered based on failure streak and stop history.
134
+ *
135
+ * Escalation triggers:
136
+ * - failure_streak >= 2: After 2 consecutive failures, escalate instead of allowing a third normal retry
137
+ * - stop_history window: If STOPs in last stop_window_ticks >= max_stops_in_window, escalate
138
+ * - Risk level: MED/HIGH tasks with verify failures may have stricter thresholds (not yet implemented - requires risk field in Task)
139
+ *
140
+ * Escalation mode selection:
141
+ * - If reviewer is enabled in config → mode is 'reviewer'
142
+ * - Otherwise → mode is 'human'
143
+ *
144
+ * @param state - Current tick state containing failure_streak and stop_history
145
+ * @param config - Envoi configuration containing escalation settings
146
+ * @param currentTick - Current tick number (for stop window calculation)
147
+ * @returns EscalationDecision with mode and reason
148
+ *
149
+ * @example
150
+ * ```typescript
151
+ * const decision = shouldEscalate(state, config, 10);
152
+ * if (decision.mode !== 'none') {
153
+ * console.log(`Escalation required: ${decision.mode} - ${decision.reason}`);
154
+ * }
155
+ * ```
156
+ */
157
+ export declare function shouldEscalate(state: TickState, config: EnvoiConfig, currentTick: number): EscalationDecision;
158
+ /**
159
+ * Classifies a verify command result into PASS, FAIL, or TIMEOUT.
160
+ *
161
+ * Classification rules:
162
+ * - PASS: exitCode === 0 && !timedOut
163
+ * - FAIL: exitCode !== 0 && !timedOut
164
+ * - TIMEOUT: timedOut === true
165
+ *
166
+ * STOP code mapping:
167
+ * - PASS: null (no stop)
168
+ * - FAIL: STOP_VERIFY_FAILED_FAST (if phase === 'fast') or STOP_VERIFY_FAILED_SLOW (if phase === 'slow')
169
+ * - TIMEOUT: STOP_VERIFY_FLAKY_OR_TIMEOUT
170
+ *
171
+ * Failure streak increment:
172
+ * - TIMEOUT: always increments failure_streak
173
+ * - FAIL: may increment based on config (default: true)
174
+ * - PASS: never increments
175
+ *
176
+ * @param exitCode - Process exit code
177
+ * @param timedOut - Whether the command timed out
178
+ * @param durationMs - Duration in milliseconds (used for logging/debugging)
179
+ * @param phase - Verification phase ('fast' or 'slow') to determine correct STOP code for FAIL
180
+ * @returns VerifyClassification with result type, stop code, and failure streak flag
181
+ *
182
+ * @example
183
+ * ```typescript
184
+ * const classification = classifyVerifyResult(0, false, 1500, 'fast');
185
+ * // Returns: { resultType: 'PASS', stopCode: null, shouldIncrementFailureStreak: false }
186
+ *
187
+ * const classification = classifyVerifyResult(1, false, 2000, 'slow');
188
+ * // Returns: { resultType: 'FAIL', stopCode: 'STOP_VERIFY_FAILED_SLOW', shouldIncrementFailureStreak: true }
189
+ *
190
+ * const classification = classifyVerifyResult(124, true, 30000, 'fast');
191
+ * // Returns: { resultType: 'TIMEOUT', stopCode: 'STOP_VERIFY_FLAKY_OR_TIMEOUT', shouldIncrementFailureStreak: true }
192
+ * ```
193
+ */
194
+ export declare function classifyVerifyResult(exitCode: number, timedOut: boolean, durationMs: number, phase: 'fast' | 'slow'): VerifyClassification;
195
+ /**
196
+ * Merge eligibility result indicating whether a merge can proceed.
197
+ */
198
+ export interface MergeEligibility {
199
+ /** Whether merge is eligible to proceed */
200
+ eligible: boolean;
201
+ /** List of reasons explaining eligibility status */
202
+ reasons: string[];
203
+ }
204
+ /**
205
+ * Report structure with git_diff_files field for merge eligibility checks.
206
+ */
207
+ export interface MergeEligibilityReport {
208
+ /** List of files changed (from git diff --name-only main...HEAD) */
209
+ git_diff_files?: string[];
210
+ }
211
+ /**
212
+ * Checks if merge is eligible based on verification history, diff evidence, and worktree state.
213
+ *
214
+ * Merge eligibility requirements:
215
+ * - verify_history must contain at least one PASS result
216
+ * - git_diff_files must be non-empty (evidence of changes)
217
+ * - worktree must be clean (no uncommitted changes)
218
+ *
219
+ * @param state - Tick state containing verify_history
220
+ * @param report - Report containing git_diff_files array
221
+ * @returns MergeEligibility with eligible status and reasons
222
+ *
223
+ * @example
224
+ * ```typescript
225
+ * const eligibility = checkMergeEligibility(state, report);
226
+ * if (!eligibility.eligible) {
227
+ * console.error(`Merge not eligible: ${eligibility.reasons.join(', ')}`);
228
+ * }
229
+ * ```
230
+ */
231
+ export declare function checkMergeEligibility(state: TickState, report: MergeEligibilityReport): MergeEligibility;
232
+ //# sourceMappingURL=guardrails.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guardrails.d.ts","sourceRoot":"","sources":["../../src/lib/guardrails.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAItD;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,0CAA0C;IAC1C,UAAU,EAAE,gBAAgB,CAAC;IAC7B,oEAAoE;IACpE,QAAQ,EAAE,UAAU,GAAG,IAAI,CAAC;IAC5B,8DAA8D;IAC9D,4BAA4B,EAAE,OAAO,CAAC;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sCAAsC;IACtC,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,gCAAgC;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,gCAAgC;IAChC,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,GAAG,eAAe,CAkBvE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,IAAI,GACT,eAAe,CAkBjB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,CASpD;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,IAAI,GACT,eAAe,CAqBjB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,iHAAiH;IACjH,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC;IACpC,uFAAuF;IACvF,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,MAAM,GAClB,kBAAkB,CAwDpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,GAAG,MAAM,GACrB,oBAAoB,CA4BtB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2CAA2C;IAC3C,QAAQ,EAAE,OAAO,CAAC;IAClB,oDAAoD;IACpD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,sBAAsB,GAC7B,gBAAgB,CA0BlB"}
@@ -0,0 +1,323 @@
1
+ /**
2
+ * Guardrail preflight checks for verifying state before running verify commands.
3
+ *
4
+ * These checks validate:
5
+ * - Branch match: git branch must equal STATE.branch
6
+ * - Fingerprint match: TASK fingerprint must match STATE.task_fingerprint
7
+ * - Worktree clean: git worktree must be clean
8
+ *
9
+ * If any check fails, returns a STOP code to prevent unsafe execution.
10
+ */
11
+ import { getCurrentBranch, isWorktreeClean } from './git.js';
12
+ import { computeFingerprint } from './fingerprint.js';
13
+ /**
14
+ * Checks if the current git branch matches the expected branch from state.
15
+ *
16
+ * @param state - State containing expected branch name
17
+ * @returns PreflightResult with ok=true if match, or STOP_BRANCH_MISMATCH if mismatch
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const result = checkBranchMatch({ branch: 'task/wp-001' });
22
+ * if (!result.ok) {
23
+ * console.error(`Branch mismatch: ${result.reason}`);
24
+ * }
25
+ * ```
26
+ */
27
+ export function checkBranchMatch(state) {
28
+ try {
29
+ const currentBranch = getCurrentBranch();
30
+ if (currentBranch !== state.branch) {
31
+ return {
32
+ ok: false,
33
+ stopCode: 'STOP_BRANCH_MISMATCH',
34
+ reason: `Current branch '${currentBranch}' does not match expected branch '${state.branch}'`,
35
+ };
36
+ }
37
+ return { ok: true };
38
+ }
39
+ catch (error) {
40
+ return {
41
+ ok: false,
42
+ stopCode: 'STOP_BRANCH_MISMATCH',
43
+ reason: `Failed to get current branch: ${error instanceof Error ? error.message : String(error)}`,
44
+ };
45
+ }
46
+ }
47
+ /**
48
+ * Checks if the task fingerprint matches state expectations.
49
+ *
50
+ * Compares the computed task fingerprint with:
51
+ * - STATE.task_fingerprint (must match if present)
52
+ * - STATE.last_failed_fingerprint (must not match - prevents re-dispatch of identical failed task)
53
+ *
54
+ * @param state - State containing fingerprint information
55
+ * @param task - Task to compute fingerprint for
56
+ * @returns PreflightResult with ok=true if checks pass, or STOP_REDISPATCH_IDENTICAL_TASK if fingerprint matches last failed
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * const result = checkFingerprintMatch(state, task);
61
+ * if (!result.ok) {
62
+ * console.error(`Fingerprint check failed: ${result.reason}`);
63
+ * }
64
+ * ```
65
+ */
66
+ export function checkFingerprintMatch(state, task) {
67
+ const taskFingerprint = computeFingerprint(task);
68
+ // Check if fingerprint matches last failed task (prevent re-dispatch)
69
+ if (state.last_failed_fingerprint && taskFingerprint === state.last_failed_fingerprint) {
70
+ return {
71
+ ok: false,
72
+ stopCode: 'STOP_REDISPATCH_IDENTICAL_TASK',
73
+ reason: `Task fingerprint matches last failed fingerprint - identical task re-dispatch detected`,
74
+ };
75
+ }
76
+ // If state has a task_fingerprint, it should match (for consistency check)
77
+ // Note: This is a guardrail, so we're lenient - if state.task_fingerprint exists but doesn't match,
78
+ // it might indicate state inconsistency, but we don't stop on this (fingerprint is updated during tick)
79
+ // The main check is preventing re-dispatch of identical failed tasks
80
+ return { ok: true };
81
+ }
82
+ /**
83
+ * Checks if the git worktree is clean (no uncommitted changes).
84
+ *
85
+ * @returns PreflightResult with ok=true if clean, or STOP_MERGE_DIRTY_WORKTREE if dirty
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * const result = checkWorktreeClean();
90
+ * if (!result.ok) {
91
+ * console.error(`Worktree is dirty: ${result.reason}`);
92
+ * }
93
+ * ```
94
+ */
95
+ export function checkWorktreeClean() {
96
+ if (!isWorktreeClean()) {
97
+ return {
98
+ ok: false,
99
+ stopCode: 'STOP_MERGE_DIRTY_WORKTREE',
100
+ reason: 'Git worktree has uncommitted changes or untracked files',
101
+ };
102
+ }
103
+ return { ok: true };
104
+ }
105
+ /**
106
+ * Runs all guardrail preflight checks before verify commands.
107
+ *
108
+ * Checks are run in order, returning immediately on first failure:
109
+ * 1. Branch match check
110
+ * 2. Fingerprint match check
111
+ * 3. Worktree clean check
112
+ *
113
+ * @param state - State containing branch and fingerprint information
114
+ * @param task - Task to validate fingerprint for
115
+ * @returns PreflightResult indicating if all checks passed or which check failed
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * const result = runGuardrailPreflight(state, task);
120
+ * if (!result.ok) {
121
+ * console.error(`Preflight failed: ${result.stopCode}: ${result.reason}`);
122
+ * process.exit(1);
123
+ * }
124
+ * ```
125
+ */
126
+ export function runGuardrailPreflight(state, task) {
127
+ // 1. Check branch match
128
+ const branchResult = checkBranchMatch(state);
129
+ if (!branchResult.ok) {
130
+ return branchResult;
131
+ }
132
+ // 2. Check fingerprint match
133
+ const fingerprintResult = checkFingerprintMatch(state, task);
134
+ if (!fingerprintResult.ok) {
135
+ return fingerprintResult;
136
+ }
137
+ // 3. Check worktree clean
138
+ const worktreeResult = checkWorktreeClean();
139
+ if (!worktreeResult.ok) {
140
+ return worktreeResult;
141
+ }
142
+ // All checks passed
143
+ return { ok: true };
144
+ }
145
+ /**
146
+ * Determines if escalation should be triggered based on failure streak and stop history.
147
+ *
148
+ * Escalation triggers:
149
+ * - failure_streak >= 2: After 2 consecutive failures, escalate instead of allowing a third normal retry
150
+ * - stop_history window: If STOPs in last stop_window_ticks >= max_stops_in_window, escalate
151
+ * - Risk level: MED/HIGH tasks with verify failures may have stricter thresholds (not yet implemented - requires risk field in Task)
152
+ *
153
+ * Escalation mode selection:
154
+ * - If reviewer is enabled in config → mode is 'reviewer'
155
+ * - Otherwise → mode is 'human'
156
+ *
157
+ * @param state - Current tick state containing failure_streak and stop_history
158
+ * @param config - Envoi configuration containing escalation settings
159
+ * @param currentTick - Current tick number (for stop window calculation)
160
+ * @returns EscalationDecision with mode and reason
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * const decision = shouldEscalate(state, config, 10);
165
+ * if (decision.mode !== 'none') {
166
+ * console.log(`Escalation required: ${decision.mode} - ${decision.reason}`);
167
+ * }
168
+ * ```
169
+ */
170
+ export function shouldEscalate(state, config, currentTick) {
171
+ const failureStreak = state.failure_streak ?? 0;
172
+ const stopHistory = state.guardrail?.stop_history ?? [];
173
+ // Check failure streak >= 2
174
+ if (failureStreak >= 2) {
175
+ const reviewerEnabled = config.reviewer?.enabled ?? false;
176
+ const mode = reviewerEnabled ? 'reviewer' : 'human';
177
+ return {
178
+ mode,
179
+ reason: `Failure streak is ${failureStreak} (>= 2). Escalating to prevent infinite retry loops.`,
180
+ };
181
+ }
182
+ // Check stop history window
183
+ const reviewerConfig = config.reviewer;
184
+ if (reviewerConfig?.trigger?.on_repeated_stop &&
185
+ reviewerConfig.trigger.stop_window_ticks > 0 &&
186
+ reviewerConfig.trigger.max_stops_in_window > 0) {
187
+ const windowTicks = reviewerConfig.trigger.stop_window_ticks;
188
+ const maxStops = reviewerConfig.trigger.max_stops_in_window;
189
+ // Count stops in recent history
190
+ // Since stop_history entries don't have tick numbers, we count the last N entries
191
+ // where N = windowTicks (approximating ticks with entries)
192
+ // This is a reasonable approximation: if we have >= maxStops entries in the window,
193
+ // we've exceeded the threshold
194
+ const recentStops = stopHistory.slice(-windowTicks);
195
+ if (recentStops.length >= maxStops) {
196
+ const reviewerEnabled = reviewerConfig.enabled ?? false;
197
+ const mode = reviewerEnabled ? 'reviewer' : 'human';
198
+ return {
199
+ mode,
200
+ reason: `Found ${recentStops.length} stops in last ${windowTicks} entries (>= ${maxStops}). Escalating to prevent repeated failures.`,
201
+ };
202
+ }
203
+ }
204
+ // Risk level check (MED/HIGH with verify failure)
205
+ // Note: This requires a risk field in Task which is not yet in the schema.
206
+ // For now, we skip this check. When risk is added to Task, we can check:
207
+ // if (task.risk === 'MED' || task.risk === 'HIGH') {
208
+ // const verifyFailed = state.verify_history?.some(e => e.result === 'FAIL') ?? false;
209
+ // if (verifyFailed) {
210
+ // return { mode: reviewerEnabled ? 'reviewer' : 'human', reason: 'MED/HIGH risk task with verify failure' };
211
+ // }
212
+ // }
213
+ // No escalation needed
214
+ return {
215
+ mode: 'none',
216
+ reason: 'No escalation triggers detected. Failure streak and stop history are within acceptable limits.',
217
+ };
218
+ }
219
+ /**
220
+ * Classifies a verify command result into PASS, FAIL, or TIMEOUT.
221
+ *
222
+ * Classification rules:
223
+ * - PASS: exitCode === 0 && !timedOut
224
+ * - FAIL: exitCode !== 0 && !timedOut
225
+ * - TIMEOUT: timedOut === true
226
+ *
227
+ * STOP code mapping:
228
+ * - PASS: null (no stop)
229
+ * - FAIL: STOP_VERIFY_FAILED_FAST (if phase === 'fast') or STOP_VERIFY_FAILED_SLOW (if phase === 'slow')
230
+ * - TIMEOUT: STOP_VERIFY_FLAKY_OR_TIMEOUT
231
+ *
232
+ * Failure streak increment:
233
+ * - TIMEOUT: always increments failure_streak
234
+ * - FAIL: may increment based on config (default: true)
235
+ * - PASS: never increments
236
+ *
237
+ * @param exitCode - Process exit code
238
+ * @param timedOut - Whether the command timed out
239
+ * @param durationMs - Duration in milliseconds (used for logging/debugging)
240
+ * @param phase - Verification phase ('fast' or 'slow') to determine correct STOP code for FAIL
241
+ * @returns VerifyClassification with result type, stop code, and failure streak flag
242
+ *
243
+ * @example
244
+ * ```typescript
245
+ * const classification = classifyVerifyResult(0, false, 1500, 'fast');
246
+ * // Returns: { resultType: 'PASS', stopCode: null, shouldIncrementFailureStreak: false }
247
+ *
248
+ * const classification = classifyVerifyResult(1, false, 2000, 'slow');
249
+ * // Returns: { resultType: 'FAIL', stopCode: 'STOP_VERIFY_FAILED_SLOW', shouldIncrementFailureStreak: true }
250
+ *
251
+ * const classification = classifyVerifyResult(124, true, 30000, 'fast');
252
+ * // Returns: { resultType: 'TIMEOUT', stopCode: 'STOP_VERIFY_FLAKY_OR_TIMEOUT', shouldIncrementFailureStreak: true }
253
+ * ```
254
+ */
255
+ export function classifyVerifyResult(exitCode, timedOut, durationMs, phase) {
256
+ // TIMEOUT takes precedence - if timed out, it's always TIMEOUT
257
+ if (timedOut) {
258
+ return {
259
+ resultType: 'TIMEOUT',
260
+ stopCode: 'STOP_VERIFY_FLAKY_OR_TIMEOUT',
261
+ shouldIncrementFailureStreak: true,
262
+ };
263
+ }
264
+ // PASS: exit code 0 and not timed out
265
+ if (exitCode === 0) {
266
+ return {
267
+ resultType: 'PASS',
268
+ stopCode: null,
269
+ shouldIncrementFailureStreak: false,
270
+ };
271
+ }
272
+ // FAIL: non-zero exit code and not timed out
273
+ const stopCode = phase === 'fast' ? 'STOP_VERIFY_FAILED_FAST' : 'STOP_VERIFY_FAILED_SLOW';
274
+ return {
275
+ resultType: 'FAIL',
276
+ stopCode,
277
+ shouldIncrementFailureStreak: true, // Default to true, caller can override based on config
278
+ };
279
+ }
280
+ /**
281
+ * Checks if merge is eligible based on verification history, diff evidence, and worktree state.
282
+ *
283
+ * Merge eligibility requirements:
284
+ * - verify_history must contain at least one PASS result
285
+ * - git_diff_files must be non-empty (evidence of changes)
286
+ * - worktree must be clean (no uncommitted changes)
287
+ *
288
+ * @param state - Tick state containing verify_history
289
+ * @param report - Report containing git_diff_files array
290
+ * @returns MergeEligibility with eligible status and reasons
291
+ *
292
+ * @example
293
+ * ```typescript
294
+ * const eligibility = checkMergeEligibility(state, report);
295
+ * if (!eligibility.eligible) {
296
+ * console.error(`Merge not eligible: ${eligibility.reasons.join(', ')}`);
297
+ * }
298
+ * ```
299
+ */
300
+ export function checkMergeEligibility(state, report) {
301
+ const reasons = [];
302
+ // Check 1: verify_history must contain at least one PASS
303
+ const verifyHistory = state.verify_history ?? [];
304
+ const hasPass = verifyHistory.some((entry) => entry.result === 'PASS');
305
+ if (!hasPass) {
306
+ reasons.push('verify_history does not contain any PASS results');
307
+ }
308
+ // Check 2: git_diff_files must be non-empty
309
+ const gitDiffFiles = report.git_diff_files ?? [];
310
+ if (gitDiffFiles.length === 0) {
311
+ reasons.push('git_diff_files is empty (no evidence of changes)');
312
+ }
313
+ // Check 3: worktree must be clean
314
+ const worktreeResult = checkWorktreeClean();
315
+ if (!worktreeResult.ok) {
316
+ reasons.push(worktreeResult.reason || 'Git worktree has uncommitted changes');
317
+ }
318
+ return {
319
+ eligible: reasons.length === 0,
320
+ reasons: reasons.length > 0 ? reasons : ['All merge eligibility checks passed'],
321
+ };
322
+ }
323
+ //# sourceMappingURL=guardrails.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guardrails.js","sourceRoot":"","sources":["../../src/lib/guardrails.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * History management utilities for preserving tick run artifacts.
3
+ *
4
+ * Each tick's artifacts (report.json, report.md, diff.patch, verify.log) are
5
+ * preserved in history/<run_id>/ to enable debugging and audit trails.
6
+ */
7
+ import type { EnvoiConfig } from '../types/config.js';
8
+ import type { ReportData } from '../types/report.js';
9
+ import type { RawAjvError } from './schema.js';
10
+ /**
11
+ * Creates the history snapshot directory for a run.
12
+ *
13
+ * @param runId - Run ID
14
+ * @param config - Envoi configuration
15
+ * @returns Promise that resolves when directory is created
16
+ * @throws {Error} If directory creation fails
17
+ */
18
+ export declare function createHistorySnapshot(runId: string, config: EnvoiConfig): Promise<void>;
19
+ /**
20
+ * Writes an artifact file to the history directory for a run.
21
+ *
22
+ * @param runId - Run ID
23
+ * @param filename - Name of the artifact file (e.g., 'report.json', 'diff.patch')
24
+ * @param content - Content to write (string for text files, object for JSON)
25
+ * @param config - Envoi configuration
26
+ * @returns Promise that resolves when write completes
27
+ * @throws {Error} If the write operation fails
28
+ */
29
+ export declare function writeHistoryArtifact(runId: string, filename: string, content: string | object, config: EnvoiConfig): Promise<void>;
30
+ /**
31
+ * Creates a complete history snapshot for a tick run.
32
+ *
33
+ * Saves all artifacts (meta.json, report.json, report.md, and optionally
34
+ * diff.patch and verify.log) to history/<run_id>/.
35
+ *
36
+ * @param runId - Run ID
37
+ * @param report - Report data
38
+ * @param markdown - Markdown rendering of the report
39
+ * @param diffPatch - Optional diff patch content
40
+ * @param verifyLog - Optional verification log content
41
+ * @param config - Envoi configuration
42
+ * @returns Promise that resolves when all artifacts are saved
43
+ * @throws {Error} If any write operation fails
44
+ */
45
+ export declare function snapshotRun(runId: string, report: ReportData, markdown: string, diffPatch: string | null, verifyLog: string | null, config: EnvoiConfig): Promise<void>;
46
+ /**
47
+ * Counts the number of existing history entries.
48
+ *
49
+ * @param config - Envoi configuration
50
+ * @returns Promise that resolves to the count of history entries
51
+ * @throws {Error} If reading the history directory fails
52
+ */
53
+ /**
54
+ * Error information for builder failures.
55
+ */
56
+ export interface BuilderErrorInfo {
57
+ /** Error kind matching BuilderParseErrorKind or 'cli_error' */
58
+ kind: 'json_parse' | 'schema' | 'shape' | 'cli_error';
59
+ /** Human-readable error message */
60
+ message: string;
61
+ /** Additional error details */
62
+ details?: unknown;
63
+ }
64
+ /**
65
+ * Persists builder failure artifacts to history for debugging.
66
+ *
67
+ * Writes raw stdout, stderr (if available), and error info to
68
+ * history/<run_id>/ for post-mortem analysis.
69
+ *
70
+ * @param runId - Run ID
71
+ * @param stdout - Raw stdout from builder invocation
72
+ * @param stderr - Raw stderr from builder invocation (may be null)
73
+ * @param errorInfo - Structured error information
74
+ * @param config - Envoi configuration
75
+ * @returns Promise that resolves when all artifacts are saved
76
+ * @throws {Error} If any write operation fails
77
+ */
78
+ export declare function persistBuilderFailure(runId: string, stdout: string, stderr: string | null, errorInfo: BuilderErrorInfo, config: EnvoiConfig): Promise<void>;
79
+ /**
80
+ * Metadata for orchestrator failure artifacts.
81
+ */
82
+ export interface OrchestratorFailureMeta {
83
+ run_id: string;
84
+ phase: 'orchestrator';
85
+ model: string;
86
+ timeout_ms: number;
87
+ prompt_chars: number;
88
+ system_prompt_chars: number;
89
+ cwd: string;
90
+ args_summary_redacted: string;
91
+ }
92
+ /**
93
+ * Persists orchestrator failure artifacts to history for debugging.
94
+ *
95
+ * Writes stdout, stderr, extracted JSON, schema errors, and meta to
96
+ * history/<run_id>/orchestrator/ for post-mortem analysis.
97
+ *
98
+ * @param runId - Run ID
99
+ * @param stdout - Raw stdout from orchestrator invocation
100
+ * @param stderr - Raw stderr from orchestrator invocation
101
+ * @param extractedJson - Extracted JSON candidate if extraction succeeded
102
+ * @param schemaErrors - Ajv errors array when validation fails
103
+ * @param meta - Invocation metadata
104
+ * @param config - Envoi configuration
105
+ * @returns Promise that resolves when all artifacts are saved
106
+ * @throws {Error} If any write operation fails
107
+ */
108
+ export declare function persistOrchestratorFailure(runId: string, stdout: string, stderr: string, extractedJson: unknown | null, schemaErrors: RawAjvError[] | null, meta: OrchestratorFailureMeta, config: EnvoiConfig): Promise<void>;
109
+ export declare function getHistoryCount(config: EnvoiConfig): Promise<number>;
110
+ //# sourceMappingURL=history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/lib/history.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAuB,MAAM,oBAAoB,CAAC;AAE1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAuE/C;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAG7F;AAED;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,IAAI,CAAC,CASf;AAYD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAED;;;;;;GAMG;AACH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,+DAA+D;IAC/D,IAAI,EAAE,YAAY,GAAG,QAAQ,GAAG,OAAO,GAAG,WAAW,CAAC;IACtD,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,SAAS,EAAE,gBAAgB,EAC3B,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,IAAI,CAAC,CAcf;AAeD;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,OAAO,GAAG,IAAI,EAC7B,YAAY,EAAE,WAAW,EAAE,GAAG,IAAI,EAClC,IAAI,EAAE,uBAAuB,EAC7B,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,IAAI,CAAC,CAiCf;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAc1E"}