@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,192 @@
1
+ /**
2
+ * Risk scoring and reviewer trigger logic.
3
+ *
4
+ * Determines when the reviewer should be invoked based on deterministic
5
+ * risk signals: high-risk file paths, diff fraction thresholds, repeated
6
+ * stops, verification failures, and budget warnings.
7
+ */
8
+ import micromatch from 'micromatch';
9
+ /**
10
+ * Checks if any paths match high-risk glob patterns.
11
+ *
12
+ * Uses micromatch to check paths against high_risk_globs patterns.
13
+ *
14
+ * @param paths - Array of file paths to check
15
+ * @param highRiskGlobs - Array of glob patterns for high-risk files
16
+ * @returns Array of paths that match high-risk patterns
17
+ *
18
+ * @example
19
+ * const riskyPaths = checkHighRiskGlobs(
20
+ * ['src/auth.ts', 'src/utils.ts'],
21
+ * ['src/auth*.ts', 'src/*secret*']
22
+ * );
23
+ */
24
+ export function checkHighRiskGlobs(paths, highRiskGlobs) {
25
+ if (highRiskGlobs.length === 0) {
26
+ return [];
27
+ }
28
+ // Check if any paths match high-risk globs
29
+ return paths.filter((path) => micromatch.isMatch(path, highRiskGlobs));
30
+ }
31
+ /**
32
+ * Checks if diff fraction exceeds threshold.
33
+ *
34
+ * Calculates files_touched/max_files_touched or lines_changed/max_lines_changed
35
+ * and checks if either fraction >= threshold.
36
+ *
37
+ * @param analysis - Diff analysis result
38
+ * @param limits - Diff limits from task
39
+ * @param threshold - Fraction threshold (0.0 to 1.0)
40
+ * @returns True if diff fraction >= threshold
41
+ *
42
+ * @example
43
+ * const analysis = { files_touched: 8, lines_changed: 300, ... };
44
+ * const limits = { max_files_touched: 10, max_lines_changed: 400 };
45
+ * const nearCap = checkDiffFraction(analysis, limits, 0.8);
46
+ */
47
+ export function checkDiffFraction(analysis, limits, threshold) {
48
+ if (threshold <= 0) {
49
+ return false;
50
+ }
51
+ const lines_changed = analysis.lines_added + analysis.lines_deleted;
52
+ // Calculate fractions
53
+ const filesFraction = limits.max_files_touched > 0
54
+ ? analysis.files_touched / limits.max_files_touched
55
+ : 0;
56
+ const linesFraction = limits.max_lines_changed > 0 ? lines_changed / limits.max_lines_changed : 0;
57
+ // Check if either fraction exceeds threshold
58
+ return filesFraction >= threshold || linesFraction >= threshold;
59
+ }
60
+ /**
61
+ * Checks if there are repeated stops within a time window.
62
+ *
63
+ * Counts STOP verdicts in stop_history within the specified window
64
+ * and checks if count >= maxStops.
65
+ *
66
+ * @param stopHistory - Array of stop history entries
67
+ * @param window - Time window in ticks
68
+ * @param maxStops - Maximum number of stops allowed in window
69
+ * @param currentTick - Current tick number
70
+ * @returns True if repeated stops detected
71
+ *
72
+ * @example
73
+ * const history = [
74
+ * { tick: 5, verdict: 'stop' },
75
+ * { tick: 8, verdict: 'stop' },
76
+ * { tick: 12, verdict: 'stop' }
77
+ * ];
78
+ * const repeated = checkRepeatedStops(history, 10, 2, 12);
79
+ */
80
+ export function checkRepeatedStops(stopHistory, window, maxStops, currentTick) {
81
+ if (window <= 0 || maxStops <= 0) {
82
+ return false;
83
+ }
84
+ // Filter stops within the window (from currentTick - window to currentTick)
85
+ const windowStart = Math.max(0, currentTick - window);
86
+ const stopsInWindow = stopHistory.filter((entry) => entry.verdict === 'stop' && entry.tick >= windowStart && entry.tick <= currentTick);
87
+ return stopsInWindow.length >= maxStops;
88
+ }
89
+ /**
90
+ * Computes risk flags based on various risk signals.
91
+ *
92
+ * Returns an array of risk flag strings indicating which risk conditions
93
+ * have been triggered.
94
+ *
95
+ * @param params - Parameters for risk computation
96
+ * @param params.analysis - Diff analysis result
97
+ * @param params.limits - Diff limits from task
98
+ * @param params.scope - Task scope configuration
99
+ * @param params.trigger - Reviewer trigger configuration
100
+ * @param params.stopHistory - Array of stop history entries
101
+ * @param params.currentTick - Current tick number
102
+ * @param params.verifyFailed - Whether verification failed
103
+ * @param params.budgetWarning - Whether budget warning threshold reached
104
+ * @returns Array of risk flag strings
105
+ *
106
+ * @example
107
+ * const flags = computeRiskFlags({
108
+ * analysis,
109
+ * limits,
110
+ * scope,
111
+ * trigger,
112
+ * stopHistory: [],
113
+ * currentTick: 10,
114
+ * verifyFailed: false,
115
+ * budgetWarning: false
116
+ * });
117
+ */
118
+ export function computeRiskFlags(params) {
119
+ const { analysis, limits, scope, trigger, stopHistory, currentTick, verifyFailed, budgetWarning, } = params;
120
+ const flags = [];
121
+ // Check high-risk paths
122
+ if (trigger.on_high_risk_paths && trigger.high_risk_globs.length > 0) {
123
+ const riskyPaths = checkHighRiskGlobs(analysis.touched_paths, trigger.high_risk_globs);
124
+ if (riskyPaths.length > 0) {
125
+ flags.push('high_risk_path');
126
+ }
127
+ // Also check if allowed_globs overlap with high_risk_globs (pattern-level check)
128
+ // This is mentioned in the PRD as a risk trigger
129
+ const hasOverlap = scope.allowed_globs.some((allowedGlob) => trigger.high_risk_globs.some((riskGlob) => {
130
+ // Check if patterns overlap by testing if they could match similar paths
131
+ // Simple heuristic: check if one pattern could match the other
132
+ try {
133
+ return micromatch.isMatch(allowedGlob, [riskGlob]) ||
134
+ micromatch.isMatch(riskGlob, [allowedGlob]);
135
+ }
136
+ catch {
137
+ // If pattern matching fails, skip this comparison
138
+ return false;
139
+ }
140
+ }));
141
+ if (hasOverlap && riskyPaths.length === 0) {
142
+ // Pattern overlap detected even if no paths match yet
143
+ flags.push('high_risk_path');
144
+ }
145
+ }
146
+ // Check diff fraction threshold
147
+ if (trigger.diff_fraction_threshold > 0) {
148
+ const nearCap = checkDiffFraction(analysis, limits, trigger.diff_fraction_threshold);
149
+ if (nearCap) {
150
+ flags.push('diff_near_cap');
151
+ }
152
+ }
153
+ // Check verification failure
154
+ if (trigger.on_verify_fail && verifyFailed) {
155
+ flags.push('verify_failed');
156
+ }
157
+ // Check repeated stops
158
+ if (trigger.on_repeated_stop &&
159
+ trigger.stop_window_ticks > 0 &&
160
+ trigger.max_stops_in_window > 0) {
161
+ const repeated = checkRepeatedStops(stopHistory, trigger.stop_window_ticks, trigger.max_stops_in_window, currentTick);
162
+ if (repeated) {
163
+ flags.push('repeated_stop');
164
+ }
165
+ }
166
+ // Check budget warning
167
+ if (budgetWarning) {
168
+ flags.push('budget_warning');
169
+ }
170
+ return flags;
171
+ }
172
+ /**
173
+ * Determines if reviewer should be triggered based on risk flags and config.
174
+ *
175
+ * Returns true if reviewer is enabled and any trigger condition is met.
176
+ *
177
+ * @param config - Reviewer configuration
178
+ * @param riskFlags - Array of risk flags from computeRiskFlags
179
+ * @returns True if reviewer should be triggered
180
+ *
181
+ * @example
182
+ * const shouldTrigger = shouldTriggerReviewer(config, ['high_risk_path', 'diff_near_cap']);
183
+ */
184
+ export function shouldTriggerReviewer(config, riskFlags) {
185
+ // Reviewer must be enabled
186
+ if (!config.enabled) {
187
+ return false;
188
+ }
189
+ // At least one risk flag must be present
190
+ return riskFlags.length > 0;
191
+ }
192
+ //# sourceMappingURL=risk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"risk.js","sourceRoot":"","sources":["../../src/lib/risk.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Rollback utilities to restore repository to base_commit state.
3
+ *
4
+ * Used when Judge detects violations (scope, diff limits, etc.) to reset
5
+ * tracked files and remove only the untracked files that were touched by the builder.
6
+ */
7
+ /**
8
+ * Result of a rollback operation.
9
+ */
10
+ export interface RollbackResult {
11
+ /**
12
+ * True if rollback completed successfully.
13
+ */
14
+ success: boolean;
15
+ /**
16
+ * Whether git reset succeeded.
17
+ */
18
+ tracked_reset: boolean;
19
+ /**
20
+ * Untracked paths that were removed.
21
+ */
22
+ paths_removed: string[];
23
+ /**
24
+ * Any errors encountered during rollback.
25
+ */
26
+ errors: string[];
27
+ }
28
+ /**
29
+ * Result of a rollback operation (new format for STOP code handling).
30
+ */
31
+ export interface RollbackResultNew {
32
+ /**
33
+ * True if rollback completed successfully.
34
+ */
35
+ ok: boolean;
36
+ /**
37
+ * The commit SHA that was restored to.
38
+ */
39
+ restoredCommit: string;
40
+ /**
41
+ * Files that were removed during rollback.
42
+ */
43
+ removedFiles: string[];
44
+ /**
45
+ * Error message if rollback failed, null otherwise.
46
+ */
47
+ error: string | null;
48
+ }
49
+ /**
50
+ * Resets tracked files to a specific base commit using git reset --hard.
51
+ *
52
+ * @param baseCommit - The commit SHA to reset to
53
+ * @returns Object indicating success and any errors
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * const result = rollbackTracked('abc123');
58
+ * if (!result.tracked_reset) {
59
+ * console.error('Failed to reset tracked files');
60
+ * }
61
+ * ```
62
+ */
63
+ export declare function rollbackTracked(baseCommit: string): {
64
+ tracked_reset: boolean;
65
+ errors: string[];
66
+ };
67
+ /**
68
+ * Removes specific untracked files and directories.
69
+ *
70
+ * Handles errors gracefully (file already removed, permission issues, etc.)
71
+ * and continues removing other paths even if some fail.
72
+ *
73
+ * @param paths - Array of file or directory paths to remove
74
+ * @returns Object with list of successfully removed paths and any errors
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * const result = await removeUntrackedPaths(['temp.txt', 'build/']);
79
+ * console.log(`Removed ${result.paths_removed.length} paths`);
80
+ * ```
81
+ */
82
+ export declare function removeUntrackedPaths(paths: string[]): Promise<{
83
+ paths_removed: string[];
84
+ errors: string[];
85
+ }>;
86
+ /**
87
+ * Performs a full rollback operation: resets tracked files to base_commit
88
+ * and removes specified untracked paths.
89
+ *
90
+ * @param baseCommit - The commit SHA to reset tracked files to
91
+ * @param untrackedPaths - Array of untracked file/directory paths to remove
92
+ * @returns RollbackResult with complete status of the operation
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * const result = await rollback('abc123', ['temp.txt', 'build/']);
97
+ * if (result.success) {
98
+ * console.log('Rollback completed successfully');
99
+ * }
100
+ * ```
101
+ */
102
+ export declare function rollback(baseCommit: string, untrackedPaths: string[]): Promise<RollbackResult>;
103
+ /**
104
+ * Resets to base commit and removes untracked files created by builder.
105
+ *
106
+ * This is the synchronous version used for STOP code handling.
107
+ * It resets tracked files to the base commit and removes specified untracked files.
108
+ *
109
+ * @param baseCommit - The commit SHA to reset to
110
+ * @param untrackedToRemove - Optional array of untracked file/directory paths to remove
111
+ * @returns RollbackResultNew with success status and details
112
+ *
113
+ * @example
114
+ * ```typescript
115
+ * const result = rollbackToCommit('abc123', ['temp.txt', 'build/']);
116
+ * if (result.ok) {
117
+ * console.log(`Rolled back to ${result.restoredCommit}`);
118
+ * console.log(`Removed ${result.removedFiles.length} files`);
119
+ * } else {
120
+ * console.error(`Rollback failed: ${result.error}`);
121
+ * }
122
+ * ```
123
+ */
124
+ export declare function rollbackToCommit(baseCommit: string, untrackedToRemove?: string[]): RollbackResultNew;
125
+ /**
126
+ * Verifies that the git worktree is clean.
127
+ *
128
+ * Uses `git diff --exit-code` to check for uncommitted tracked changes.
129
+ * Also checks that there are no untracked files (via git status --porcelain).
130
+ *
131
+ * @returns true if worktree is clean (no uncommitted changes and no untracked files), false otherwise
132
+ *
133
+ * @example
134
+ * ```typescript
135
+ * if (verifyCleanWorktree()) {
136
+ * console.log('Worktree is clean');
137
+ * } else {
138
+ * console.log('Worktree has uncommitted changes');
139
+ * }
140
+ * ```
141
+ */
142
+ export declare function verifyCleanWorktree(): boolean;
143
+ //# sourceMappingURL=rollback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rollback.d.ts","sourceRoot":"","sources":["../../src/lib/rollback.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,aAAa,EAAE,OAAO,CAAC;IAEvB;;OAEG;IACH,aAAa,EAAE,MAAM,EAAE,CAAC;IAExB;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,EAAE,EAAE,OAAO,CAAC;IAEZ;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,YAAY,EAAE,MAAM,EAAE,CAAC;IAEvB;;OAEG;IACH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG;IACnD,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAgBA;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACnE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC,CAqCD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,QAAQ,CAC5B,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,cAAc,CAAC,CAqBzB;AA8CD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,iBAAiB,GAAE,MAAM,EAAO,GAC/B,iBAAiB,CAkCnB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAqB7C"}
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Rollback utilities to restore repository to base_commit state.
3
+ *
4
+ * Used when Judge detects violations (scope, diff limits, etc.) to reset
5
+ * tracked files and remove only the untracked files that were touched by the builder.
6
+ */
7
+ import { execSync } from 'node:child_process';
8
+ import { unlink, rm } from 'node:fs/promises';
9
+ import { stat } from 'node:fs/promises';
10
+ import { unlinkSync, rmSync, statSync } from 'node:fs';
11
+ /**
12
+ * Resets tracked files to a specific base commit using git reset --hard.
13
+ *
14
+ * @param baseCommit - The commit SHA to reset to
15
+ * @returns Object indicating success and any errors
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const result = rollbackTracked('abc123');
20
+ * if (!result.tracked_reset) {
21
+ * console.error('Failed to reset tracked files');
22
+ * }
23
+ * ```
24
+ */
25
+ export function rollbackTracked(baseCommit) {
26
+ const errors = [];
27
+ try {
28
+ execSync(`git reset --hard ${baseCommit}`, {
29
+ encoding: 'utf-8',
30
+ stdio: ['pipe', 'pipe', 'pipe'],
31
+ });
32
+ return { tracked_reset: true, errors: [] };
33
+ }
34
+ catch (error) {
35
+ const errorMsg = `Failed to reset tracked files to ${baseCommit}: ${error instanceof Error ? error.message : String(error)}`;
36
+ errors.push(errorMsg);
37
+ return { tracked_reset: false, errors };
38
+ }
39
+ }
40
+ /**
41
+ * Removes specific untracked files and directories.
42
+ *
43
+ * Handles errors gracefully (file already removed, permission issues, etc.)
44
+ * and continues removing other paths even if some fail.
45
+ *
46
+ * @param paths - Array of file or directory paths to remove
47
+ * @returns Object with list of successfully removed paths and any errors
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * const result = await removeUntrackedPaths(['temp.txt', 'build/']);
52
+ * console.log(`Removed ${result.paths_removed.length} paths`);
53
+ * ```
54
+ */
55
+ export async function removeUntrackedPaths(paths) {
56
+ const paths_removed = [];
57
+ const errors = [];
58
+ for (const path of paths) {
59
+ try {
60
+ // Check if path exists and is a directory
61
+ const stats = await stat(path);
62
+ const isDirectory = stats.isDirectory();
63
+ if (isDirectory) {
64
+ // Use rm with recursive for directories
65
+ await rm(path, { recursive: true, force: true });
66
+ }
67
+ else {
68
+ // Use unlink for files
69
+ await unlink(path);
70
+ }
71
+ paths_removed.push(path);
72
+ }
73
+ catch (error) {
74
+ // Handle errors gracefully - file may already be removed, permission issues, etc.
75
+ const errorMsg = `Failed to remove ${path}: ${error instanceof Error ? error.message : String(error)}`;
76
+ // Check if it's a "file not found" error (ENOENT) - this is acceptable
77
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
78
+ // File/directory doesn't exist - consider it already removed, but don't add to paths_removed
79
+ // since we didn't actually remove it
80
+ continue;
81
+ }
82
+ errors.push(errorMsg);
83
+ }
84
+ }
85
+ return { paths_removed, errors };
86
+ }
87
+ /**
88
+ * Performs a full rollback operation: resets tracked files to base_commit
89
+ * and removes specified untracked paths.
90
+ *
91
+ * @param baseCommit - The commit SHA to reset tracked files to
92
+ * @param untrackedPaths - Array of untracked file/directory paths to remove
93
+ * @returns RollbackResult with complete status of the operation
94
+ *
95
+ * @example
96
+ * ```typescript
97
+ * const result = await rollback('abc123', ['temp.txt', 'build/']);
98
+ * if (result.success) {
99
+ * console.log('Rollback completed successfully');
100
+ * }
101
+ * ```
102
+ */
103
+ export async function rollback(baseCommit, untrackedPaths) {
104
+ const errors = [];
105
+ // Step 1: Reset tracked files
106
+ const trackedResult = rollbackTracked(baseCommit);
107
+ errors.push(...trackedResult.errors);
108
+ // Step 2: Remove untracked paths
109
+ const untrackedResult = await removeUntrackedPaths(untrackedPaths);
110
+ errors.push(...untrackedResult.errors);
111
+ // Rollback is considered successful if tracked files were reset
112
+ // (untracked removal errors are less critical)
113
+ const success = trackedResult.tracked_reset && errors.length === 0;
114
+ return {
115
+ success,
116
+ tracked_reset: trackedResult.tracked_reset,
117
+ paths_removed: untrackedResult.paths_removed,
118
+ errors,
119
+ };
120
+ }
121
+ /**
122
+ * Synchronous version of removeUntrackedPaths for use in rollbackToCommit.
123
+ */
124
+ function removeUntrackedPathsSync(paths) {
125
+ const paths_removed = [];
126
+ const errors = [];
127
+ for (const path of paths) {
128
+ try {
129
+ // Check if path exists and is a directory
130
+ const stats = statSync(path);
131
+ const isDirectory = stats.isDirectory();
132
+ if (isDirectory) {
133
+ // Use rmSync with recursive for directories
134
+ rmSync(path, { recursive: true, force: true });
135
+ }
136
+ else {
137
+ // Use unlinkSync for files
138
+ unlinkSync(path);
139
+ }
140
+ paths_removed.push(path);
141
+ }
142
+ catch (error) {
143
+ // Handle errors gracefully - file may already be removed, permission issues, etc.
144
+ const errorMsg = `Failed to remove ${path}: ${error instanceof Error ? error.message : String(error)}`;
145
+ // Check if it's a "file not found" error (ENOENT) - this is acceptable
146
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
147
+ // File/directory doesn't exist - consider it already removed
148
+ continue;
149
+ }
150
+ errors.push(errorMsg);
151
+ }
152
+ }
153
+ return { paths_removed, errors };
154
+ }
155
+ /**
156
+ * Resets to base commit and removes untracked files created by builder.
157
+ *
158
+ * This is the synchronous version used for STOP code handling.
159
+ * It resets tracked files to the base commit and removes specified untracked files.
160
+ *
161
+ * @param baseCommit - The commit SHA to reset to
162
+ * @param untrackedToRemove - Optional array of untracked file/directory paths to remove
163
+ * @returns RollbackResultNew with success status and details
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * const result = rollbackToCommit('abc123', ['temp.txt', 'build/']);
168
+ * if (result.ok) {
169
+ * console.log(`Rolled back to ${result.restoredCommit}`);
170
+ * console.log(`Removed ${result.removedFiles.length} files`);
171
+ * } else {
172
+ * console.error(`Rollback failed: ${result.error}`);
173
+ * }
174
+ * ```
175
+ */
176
+ export function rollbackToCommit(baseCommit, untrackedToRemove = []) {
177
+ try {
178
+ // Step 1: Reset tracked files
179
+ execSync(`git reset --hard ${baseCommit}`, {
180
+ encoding: 'utf-8',
181
+ stdio: ['pipe', 'pipe', 'pipe'],
182
+ });
183
+ // Step 2: Remove untracked files
184
+ const untrackedResult = removeUntrackedPathsSync(untrackedToRemove);
185
+ // If there were errors removing untracked files, still consider it successful
186
+ // as long as git reset succeeded (untracked removal errors are less critical)
187
+ const ok = untrackedResult.errors.length === 0;
188
+ const error = untrackedResult.errors.length > 0 ? untrackedResult.errors.join('; ') : null;
189
+ return {
190
+ ok,
191
+ restoredCommit: baseCommit,
192
+ removedFiles: untrackedResult.paths_removed,
193
+ error,
194
+ };
195
+ }
196
+ catch (error) {
197
+ const errorMsg = `Failed to rollback to ${baseCommit}: ${error instanceof Error ? error.message : String(error)}`;
198
+ return {
199
+ ok: false,
200
+ restoredCommit: baseCommit,
201
+ removedFiles: [],
202
+ error: errorMsg,
203
+ };
204
+ }
205
+ }
206
+ /**
207
+ * Verifies that the git worktree is clean.
208
+ *
209
+ * Uses `git diff --exit-code` to check for uncommitted tracked changes.
210
+ * Also checks that there are no untracked files (via git status --porcelain).
211
+ *
212
+ * @returns true if worktree is clean (no uncommitted changes and no untracked files), false otherwise
213
+ *
214
+ * @example
215
+ * ```typescript
216
+ * if (verifyCleanWorktree()) {
217
+ * console.log('Worktree is clean');
218
+ * } else {
219
+ * console.log('Worktree has uncommitted changes');
220
+ * }
221
+ * ```
222
+ */
223
+ export function verifyCleanWorktree() {
224
+ try {
225
+ // Check for uncommitted tracked changes
226
+ execSync('git diff --exit-code', {
227
+ encoding: 'utf-8',
228
+ stdio: ['pipe', 'pipe', 'pipe'],
229
+ });
230
+ // Check for untracked files
231
+ const status = execSync('git status --porcelain', {
232
+ encoding: 'utf-8',
233
+ stdio: ['pipe', 'pipe', 'pipe'],
234
+ });
235
+ // Worktree is clean if status is empty (no uncommitted changes and no untracked files)
236
+ return status.trim() === '';
237
+ }
238
+ catch {
239
+ // git diff --exit-code exits with non-zero if there are changes
240
+ // git status might fail in some edge cases
241
+ return false;
242
+ }
243
+ }
244
+ //# sourceMappingURL=rollback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rollback.js","sourceRoot":"","sources":["../../src/lib/rollback.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * JSON Schema validation utilities using Ajv.
3
+ *
4
+ * Provides functions to load and validate data against JSON schemas.
5
+ */
6
+ /**
7
+ * Raw AJV error object (subset of fields we care about).
8
+ */
9
+ export interface RawAjvError {
10
+ instancePath: string;
11
+ schemaPath: string;
12
+ keyword: string;
13
+ params: Record<string, unknown>;
14
+ message?: string;
15
+ }
16
+ /**
17
+ * Result of schema validation.
18
+ */
19
+ export interface ValidationResult<T> {
20
+ /** Whether the data is valid */
21
+ valid: boolean;
22
+ /** Typed data if valid, null otherwise */
23
+ data: T | null;
24
+ /** Validation error messages if invalid */
25
+ errors: string[];
26
+ /** Raw AJV error objects for diagnostics */
27
+ rawErrors?: RawAjvError[];
28
+ }
29
+ /**
30
+ * Loads and parses a JSON schema file.
31
+ *
32
+ * @param schemaPath - Path to the JSON schema file
33
+ * @returns Parsed schema object
34
+ * @throws Error if the schema file cannot be read or parsed
35
+ */
36
+ export declare function loadSchema(schemaPath: string): Promise<object>;
37
+ /**
38
+ * Validates data against a JSON schema using Ajv.
39
+ *
40
+ * Uses draft-2020-12 schema support and caches compiled schemas for performance.
41
+ *
42
+ * @param data - Data to validate
43
+ * @param schema - JSON schema object
44
+ * @returns ValidationResult with typed data or error messages
45
+ */
46
+ export declare function validateWithSchema<T>(data: unknown, schema: object): ValidationResult<T>;
47
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/lib/schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,gCAAgC;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,0CAA0C;IAC1C,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACf,2CAA2C;IAC3C,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,WAAW,EAAE,CAAC;CAC3B;AAKD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CASpE;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAAC,CAAC,CAAC,CA6DxF"}