@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,257 @@
1
+ /**
2
+ * Git diff analysis functions for computing touched set.
3
+ *
4
+ * Used by Judge phase to compute the touched set (all files modified by builder)
5
+ * based on git reality, not builder's self-report.
6
+ */
7
+ import { execSync } from 'node:child_process';
8
+ /**
9
+ * Gets tracked files that have changed since a base commit.
10
+ *
11
+ * Uses `git diff --name-status` to get all tracked changes.
12
+ * Parses status codes: A=added, M=modified, D=deleted, R=renamed.
13
+ *
14
+ * @param baseCommit - The base commit SHA to diff against
15
+ * @returns Array of file paths that have changed
16
+ * @throws {Error} If the diff operation fails
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const paths = getTouchedTracked('abc123');
21
+ * console.log(`${paths.length} tracked files changed`);
22
+ * ```
23
+ */
24
+ export function getTouchedTracked(baseCommit) {
25
+ try {
26
+ const output = execSync(`git diff --name-status ${baseCommit}..HEAD`, {
27
+ encoding: 'utf-8',
28
+ stdio: ['pipe', 'pipe', 'pipe'],
29
+ });
30
+ if (!output.trim()) {
31
+ return [];
32
+ }
33
+ return output
34
+ .trim()
35
+ .split('\n')
36
+ .map((line) => {
37
+ // Parse format: STATUS\tpath or STATUS\told_path\tnew_path (for renames)
38
+ const parts = line.split('\t');
39
+ if (parts.length >= 2) {
40
+ // For renames (R), return the new path
41
+ // For others, return the path
42
+ return parts.length === 3 ? parts[2] : parts[1];
43
+ }
44
+ return '';
45
+ })
46
+ .filter((path) => path.length > 0);
47
+ }
48
+ catch (error) {
49
+ throw new Error(`Failed to get touched tracked files from ${baseCommit}: ${error instanceof Error ? error.message : String(error)}`);
50
+ }
51
+ }
52
+ /**
53
+ * Gets untracked files that are new or modified.
54
+ *
55
+ * Uses `git status --porcelain` and filters for:
56
+ * - Lines starting with `??` (untracked files)
57
+ * - Lines starting with `A` (added files in index, but also catches untracked)
58
+ *
59
+ * @returns Array of untracked file paths
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * const untracked = getTouchedUntracked();
64
+ * console.log(`${untracked.length} untracked files`);
65
+ * ```
66
+ */
67
+ export function getTouchedUntracked() {
68
+ try {
69
+ const output = execSync('git status --porcelain', {
70
+ encoding: 'utf-8',
71
+ stdio: ['pipe', 'pipe', 'pipe'],
72
+ });
73
+ if (!output.trim()) {
74
+ return [];
75
+ }
76
+ return output
77
+ .trim()
78
+ .split('\n')
79
+ .filter((line) => {
80
+ // Filter for untracked files (??) or added files (A)
81
+ const status = line.substring(0, 2);
82
+ return status === '??' || status.startsWith('A');
83
+ })
84
+ .map((line) => {
85
+ // Remove status prefix (2 chars + space)
86
+ return line.substring(3);
87
+ })
88
+ .filter((path) => path.length > 0);
89
+ }
90
+ catch {
91
+ // If git status fails, return empty array
92
+ return [];
93
+ }
94
+ }
95
+ /**
96
+ * Gets line statistics (added/deleted) for changes since a base commit.
97
+ *
98
+ * Uses `git diff --numstat` to get line counts.
99
+ * Handles binary files which show `- -` instead of numbers.
100
+ *
101
+ * @param baseCommit - The base commit SHA to diff against
102
+ * @returns Object with lines_added and lines_deleted totals
103
+ * @throws {Error} If the diff operation fails
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * const stats = getDiffStats('abc123');
108
+ * console.log(`Added: ${stats.lines_added}, Deleted: ${stats.lines_deleted}`);
109
+ * ```
110
+ */
111
+ export function getDiffStats(baseCommit) {
112
+ try {
113
+ const output = execSync(`git diff --numstat ${baseCommit}..HEAD`, {
114
+ encoding: 'utf-8',
115
+ stdio: ['pipe', 'pipe', 'pipe'],
116
+ });
117
+ if (!output.trim()) {
118
+ return { lines_added: 0, lines_deleted: 0 };
119
+ }
120
+ let lines_added = 0;
121
+ let lines_deleted = 0;
122
+ output
123
+ .trim()
124
+ .split('\n')
125
+ .forEach((line) => {
126
+ const parts = line.split('\t');
127
+ if (parts.length >= 2) {
128
+ const added = parts[0];
129
+ const deleted = parts[1];
130
+ // Handle binary files which show "-" instead of numbers
131
+ if (added !== '-' && !isNaN(Number(added))) {
132
+ lines_added += Number(added);
133
+ }
134
+ if (deleted !== '-' && !isNaN(Number(deleted))) {
135
+ lines_deleted += Number(deleted);
136
+ }
137
+ }
138
+ });
139
+ return { lines_added, lines_deleted };
140
+ }
141
+ catch (error) {
142
+ throw new Error(`Failed to get diff stats from ${baseCommit}: ${error instanceof Error ? error.message : String(error)}`);
143
+ }
144
+ }
145
+ /**
146
+ * Analyzes git diff to compute the complete touched set.
147
+ *
148
+ * Combines tracked changes, untracked files, and line statistics
149
+ * into a complete DiffAnalysis object.
150
+ *
151
+ * @param baseCommit - The base commit SHA to diff against
152
+ * @returns Complete DiffAnalysis with all metrics
153
+ * @throws {Error} If any git operation fails
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * const analysis = analyzeDiff('abc123');
158
+ * console.log(`Touched ${analysis.files_touched} files`);
159
+ * console.log(`Added ${analysis.lines_added} lines`);
160
+ * ```
161
+ */
162
+ export function analyzeDiff(baseCommit) {
163
+ const trackedPaths = getTouchedTracked(baseCommit);
164
+ const untrackedPaths = getTouchedUntracked();
165
+ const stats = getDiffStats(baseCommit);
166
+ // Combine all touched paths
167
+ const allPaths = [...new Set([...trackedPaths, ...untrackedPaths])];
168
+ // Count new files: files that are added (A) in tracked changes
169
+ // plus all untracked files
170
+ let newFilesCount = untrackedPaths.length;
171
+ try {
172
+ const nameStatusOutput = execSync(`git diff --name-status ${baseCommit}..HEAD`, {
173
+ encoding: 'utf-8',
174
+ stdio: ['pipe', 'pipe', 'pipe'],
175
+ });
176
+ if (nameStatusOutput.trim()) {
177
+ const addedFiles = nameStatusOutput
178
+ .trim()
179
+ .split('\n')
180
+ .filter((line) => line.startsWith('A\t') || line.startsWith('A\t'))
181
+ .length;
182
+ newFilesCount += addedFiles;
183
+ }
184
+ }
185
+ catch {
186
+ // If this fails, we already have untracked count
187
+ }
188
+ return {
189
+ files_touched: allPaths.length,
190
+ lines_added: stats.lines_added,
191
+ lines_deleted: stats.lines_deleted,
192
+ new_files: newFilesCount,
193
+ touched_paths: allPaths.sort(),
194
+ };
195
+ }
196
+ /**
197
+ * Checks if diff analysis exceeds task diff limits.
198
+ *
199
+ * Compares files_touched against max_files_touched and lines_changed
200
+ * (added + deleted) against max_lines_changed.
201
+ *
202
+ * @param analysis - The diff analysis result
203
+ * @param limits - The diff limits from the task
204
+ * @returns DiffLimitCheckResult with ok status and violation details
205
+ *
206
+ * @example
207
+ * ```typescript
208
+ * const analysis = analyzeDiff('abc123');
209
+ * const limits = { max_files_touched: 10, max_lines_changed: 100 };
210
+ * const result = checkDiffLimits(analysis, limits);
211
+ * if (!result.ok) {
212
+ * console.error(`Violation: ${result.violation}`);
213
+ * }
214
+ * ```
215
+ */
216
+ export function checkDiffLimits(analysis, limits) {
217
+ const lines_changed = analysis.lines_added + analysis.lines_deleted;
218
+ const filesExceeded = analysis.files_touched > limits.max_files_touched;
219
+ const linesExceeded = lines_changed > limits.max_lines_changed;
220
+ let violation = null;
221
+ if (filesExceeded && linesExceeded) {
222
+ violation = `Files touched (${analysis.files_touched}) exceeds limit (${limits.max_files_touched}) and lines changed (${lines_changed}) exceeds limit (${limits.max_lines_changed})`;
223
+ }
224
+ else if (filesExceeded) {
225
+ violation = `Files touched (${analysis.files_touched}) exceeds limit (${limits.max_files_touched})`;
226
+ }
227
+ else if (linesExceeded) {
228
+ violation = `Lines changed (${lines_changed}) exceeds limit (${limits.max_lines_changed})`;
229
+ }
230
+ return {
231
+ ok: !filesExceeded && !linesExceeded,
232
+ files_touched: analysis.files_touched,
233
+ lines_changed,
234
+ max_files: limits.max_files_touched,
235
+ max_lines: limits.max_lines_changed,
236
+ violation,
237
+ };
238
+ }
239
+ /**
240
+ * Formats blast radius summary string from diff analysis.
241
+ *
242
+ * Format: "<files_touched> files, +<lines_added>/-<lines_deleted>, <new_files> new"
243
+ *
244
+ * @param analysis - The diff analysis result
245
+ * @returns Formatted blast radius summary string
246
+ *
247
+ * @example
248
+ * ```typescript
249
+ * const analysis = analyzeDiff('abc123');
250
+ * const summary = formatBlastRadius(analysis);
251
+ * // "5 files, +120/-30, 2 new"
252
+ * ```
253
+ */
254
+ export function formatBlastRadius(analysis) {
255
+ return `${analysis.files_touched} files, +${analysis.lines_added}/-${analysis.lines_deleted}, ${analysis.new_files} new`;
256
+ }
257
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/lib/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Doctor checks for Envoi configuration and environment.
3
+ *
4
+ * Provides functions to verify system health and configuration correctness.
5
+ */
6
+ import type { EnvoiConfig } from '../types/config.js';
7
+ /**
8
+ * Result of Codex CLI reviewer doctor check.
9
+ */
10
+ export interface ReviewerDoctorResult {
11
+ /** Whether the Codex CLI is available */
12
+ cli_available: boolean;
13
+ /** Authentication status: 'api_key_present' if CODEX_API_KEY is set, 'unknown' otherwise */
14
+ auth_status: 'api_key_present' | 'unknown';
15
+ /** Version string from codex --version, if available */
16
+ version?: string;
17
+ /** Reviewer mode: 'enabled' if reviewer.enabled is true, 'disabled' otherwise */
18
+ reviewer_mode: 'enabled' | 'disabled';
19
+ /** Auth mode from config: reviewer.auth.mode, or 'unknown' if not configured */
20
+ auth_mode: 'auto' | 'api_key' | 'login' | 'unknown';
21
+ }
22
+ /**
23
+ * Result of Cursor Agent doctor check.
24
+ */
25
+ export interface CursorAgentDoctorResult {
26
+ /** Whether the Cursor CLI command is available */
27
+ cli_available: boolean;
28
+ /** Cursor CLI version output, if available */
29
+ version?: string;
30
+ /** Whether `cursor agent` subcommand appears available */
31
+ agent_available: boolean;
32
+ /** Auth status for Cursor Agent */
33
+ auth_status: 'authenticated' | 'unauthenticated' | 'api_key_present' | 'unknown';
34
+ /** Optional details for debugging auth / CLI failures */
35
+ details?: string;
36
+ /** The command that was checked (e.g. "cursor") */
37
+ command: string;
38
+ }
39
+ /**
40
+ * Checks Codex CLI availability and authentication status.
41
+ *
42
+ * Performs the following checks:
43
+ * 1. Spawns 'codex --version' to verify CLI is available
44
+ * 2. Checks CODEX_API_KEY environment variable presence
45
+ * 3. Reads reviewer configuration from config (enabled, auth.mode)
46
+ *
47
+ * @param config - Envoi configuration (optional, for reading reviewer settings)
48
+ * @returns Promise resolving to ReviewerDoctorResult with check results
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const result = await checkCodexCli(config);
53
+ * if (result.cli_available) {
54
+ * console.log(`Codex CLI available: ${result.version}`);
55
+ * }
56
+ * ```
57
+ */
58
+ export declare function checkCodexCli(config?: EnvoiConfig): Promise<ReviewerDoctorResult>;
59
+ /**
60
+ * Checks Cursor CLI + Cursor Agent availability and basic authentication status.
61
+ *
62
+ * Heuristics:
63
+ * - If CURSOR_API_KEY is set, treat as "api_key_present" (preferred: do not store secrets in config)
64
+ * - Otherwise, attempt `cursor agent whoami` to detect authenticated vs unauthenticated
65
+ */
66
+ export declare function checkCursorAgent(config?: EnvoiConfig): Promise<CursorAgentDoctorResult>;
67
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/lib/doctor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,yCAAyC;IACzC,aAAa,EAAE,OAAO,CAAC;IACvB,4FAA4F;IAC5F,WAAW,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC3C,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,aAAa,EAAE,SAAS,GAAG,UAAU,CAAC;IACtC,gFAAgF;IAChF,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,kDAAkD;IAClD,aAAa,EAAE,OAAO,CAAC;IACvB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,eAAe,EAAE,OAAO,CAAC;IACzB,mCAAmC;IACnC,WAAW,EAAE,eAAe,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,SAAS,CAAC;IACjF,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;CACjB;AA8DD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,aAAa,CACjC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,oBAAoB,CAAC,CA8D/B;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,uBAAuB,CAAC,CA4E7F"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Doctor checks for Envoi configuration and environment.
3
+ *
4
+ * Provides functions to verify system health and configuration correctness.
5
+ */
6
+ import { spawn } from 'node:child_process';
7
+ async function spawnAndCapture(command, args, timeoutMs) {
8
+ return await new Promise((resolve) => {
9
+ let child = null;
10
+ const stdoutChunks = [];
11
+ const stderrChunks = [];
12
+ let timeout = null;
13
+ try {
14
+ child = spawn(command, args, { shell: false, stdio: ['ignore', 'pipe', 'pipe'] });
15
+ }
16
+ catch (error) {
17
+ resolve({
18
+ ok: false,
19
+ code: null,
20
+ stdout: '',
21
+ stderr: '',
22
+ error: error instanceof Error ? error.message : String(error),
23
+ });
24
+ return;
25
+ }
26
+ child.stdout?.on('data', (chunk) => stdoutChunks.push(chunk));
27
+ child.stderr?.on('data', (chunk) => stderrChunks.push(chunk));
28
+ timeout = setTimeout(() => {
29
+ try {
30
+ child?.kill('SIGTERM');
31
+ }
32
+ catch {
33
+ // ignore
34
+ }
35
+ }, timeoutMs);
36
+ const finish = (result) => {
37
+ if (timeout)
38
+ clearTimeout(timeout);
39
+ resolve(result);
40
+ };
41
+ child.on('error', (error) => {
42
+ finish({
43
+ ok: false,
44
+ code: null,
45
+ stdout: Buffer.concat(stdoutChunks).toString('utf-8'),
46
+ stderr: Buffer.concat(stderrChunks).toString('utf-8'),
47
+ error: error.message,
48
+ });
49
+ });
50
+ child.on('exit', (code) => {
51
+ const stdout = Buffer.concat(stdoutChunks).toString('utf-8').trim();
52
+ const stderr = Buffer.concat(stderrChunks).toString('utf-8').trim();
53
+ finish({ ok: code === 0, code, stdout, stderr });
54
+ });
55
+ });
56
+ }
57
+ /**
58
+ * Checks Codex CLI availability and authentication status.
59
+ *
60
+ * Performs the following checks:
61
+ * 1. Spawns 'codex --version' to verify CLI is available
62
+ * 2. Checks CODEX_API_KEY environment variable presence
63
+ * 3. Reads reviewer configuration from config (enabled, auth.mode)
64
+ *
65
+ * @param config - Envoi configuration (optional, for reading reviewer settings)
66
+ * @returns Promise resolving to ReviewerDoctorResult with check results
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * const result = await checkCodexCli(config);
71
+ * if (result.cli_available) {
72
+ * console.log(`Codex CLI available: ${result.version}`);
73
+ * }
74
+ * ```
75
+ */
76
+ export async function checkCodexCli(config) {
77
+ let cli_available = false;
78
+ let version;
79
+ // Check CLI availability by spawning 'codex --version'
80
+ try {
81
+ const child = spawn('codex', ['--version'], {
82
+ shell: false,
83
+ stdio: ['ignore', 'pipe', 'pipe'],
84
+ });
85
+ const stdoutChunks = [];
86
+ const stderrChunks = [];
87
+ child.stdout?.on('data', (chunk) => {
88
+ stdoutChunks.push(chunk);
89
+ });
90
+ child.stderr?.on('data', (chunk) => {
91
+ stderrChunks.push(chunk);
92
+ });
93
+ await new Promise((resolve, reject) => {
94
+ child.on('error', (error) => {
95
+ reject(error);
96
+ });
97
+ child.on('exit', (code) => {
98
+ if (code === 0) {
99
+ cli_available = true;
100
+ const output = Buffer.concat(stdoutChunks).toString('utf-8').trim();
101
+ // Extract version from output (e.g., "codex 1.2.3" or just "1.2.3")
102
+ version = output || undefined;
103
+ resolve();
104
+ }
105
+ else {
106
+ reject(new Error(`codex --version exited with code ${code}`));
107
+ }
108
+ });
109
+ });
110
+ }
111
+ catch {
112
+ // CLI not available or failed to execute
113
+ cli_available = false;
114
+ }
115
+ // Check auth status: look for CODEX_API_KEY environment variable
116
+ const apiKey = process.env.CODEX_API_KEY;
117
+ const auth_status = apiKey && apiKey.trim().length > 0
118
+ ? 'api_key_present'
119
+ : 'unknown';
120
+ // Read reviewer configuration
121
+ const reviewer_enabled = config?.reviewer?.enabled ?? false;
122
+ const reviewer_mode = reviewer_enabled ? 'enabled' : 'disabled';
123
+ const auth_mode = config?.reviewer?.auth?.mode ?? 'unknown';
124
+ return {
125
+ cli_available,
126
+ auth_status,
127
+ version,
128
+ reviewer_mode,
129
+ auth_mode,
130
+ };
131
+ }
132
+ /**
133
+ * Checks Cursor CLI + Cursor Agent availability and basic authentication status.
134
+ *
135
+ * Heuristics:
136
+ * - If CURSOR_API_KEY is set, treat as "api_key_present" (preferred: do not store secrets in config)
137
+ * - Otherwise, attempt `cursor agent whoami` to detect authenticated vs unauthenticated
138
+ */
139
+ export async function checkCursorAgent(config) {
140
+ const command = config?.builder?.cursor?.command ?? 'cursor';
141
+ // 1) Cursor CLI availability + version
142
+ let version;
143
+ let cli_available = false;
144
+ const versionTry1 = await spawnAndCapture(command, ['--version'], 2000);
145
+ if (versionTry1.ok) {
146
+ cli_available = true;
147
+ version = versionTry1.stdout || undefined;
148
+ }
149
+ else {
150
+ const versionTry2 = await spawnAndCapture(command, ['-v'], 2000);
151
+ if (versionTry2.ok) {
152
+ cli_available = true;
153
+ version = versionTry2.stdout || undefined;
154
+ }
155
+ }
156
+ if (!cli_available) {
157
+ const details = versionTry1.error ?? versionTry1.stderr ?? versionTry1.stdout;
158
+ return {
159
+ cli_available: false,
160
+ version: undefined,
161
+ agent_available: false,
162
+ auth_status: 'unknown',
163
+ details: details ? String(details).trim() : undefined,
164
+ command,
165
+ };
166
+ }
167
+ // 2) Agent subcommand availability
168
+ const agentHelp = await spawnAndCapture(command, ['agent', '--help'], 2000);
169
+ const agent_available = agentHelp.ok;
170
+ if (!agent_available) {
171
+ return {
172
+ cli_available: true,
173
+ version,
174
+ agent_available: false,
175
+ auth_status: 'unknown',
176
+ details: [agentHelp.stderr, agentHelp.stdout].filter(Boolean).join('\n').trim() || undefined,
177
+ command,
178
+ };
179
+ }
180
+ // 3) Auth status
181
+ const apiKey = process.env.CURSOR_API_KEY;
182
+ if (apiKey && apiKey.trim().length > 0) {
183
+ return {
184
+ cli_available: true,
185
+ version,
186
+ agent_available: true,
187
+ auth_status: 'api_key_present',
188
+ command,
189
+ };
190
+ }
191
+ const whoami = await spawnAndCapture(command, ['agent', 'whoami'], 5000);
192
+ if (whoami.ok) {
193
+ return {
194
+ cli_available: true,
195
+ version,
196
+ agent_available: true,
197
+ auth_status: 'authenticated',
198
+ command,
199
+ };
200
+ }
201
+ const details = [whoami.stderr, whoami.stdout, whoami.error].filter(Boolean).join('\n').trim();
202
+ return {
203
+ cli_available: true,
204
+ version,
205
+ agent_available: true,
206
+ auth_status: 'unauthenticated',
207
+ details: details || undefined,
208
+ command,
209
+ };
210
+ }
211
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/lib/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Task fingerprinting utilities.
3
+ *
4
+ * Task fingerprint is used to detect identical re-dispatch loops.
5
+ * If orchestrator 'retries' without changing the plan, fingerprint stays same and runner stops.
6
+ */
7
+ /**
8
+ * Canonicalizes a task object to a stable JSON string.
9
+ *
10
+ * The canonical form:
11
+ * - Has sorted keys (alphabetical order)
12
+ * - Has trimmed strings
13
+ * - Excludes task_id, id, v, milestone, and context fields
14
+ * - Only includes fingerprint-relevant fields
15
+ *
16
+ * @param task - The task object to canonicalize
17
+ * @returns A canonical JSON string representation
18
+ */
19
+ export declare function canonicalizeTask(task: Record<string, unknown>): string;
20
+ /**
21
+ * Computes a SHA-256 fingerprint of a task.
22
+ *
23
+ * @param task - The task object to fingerprint
24
+ * @returns A 64-character hexadecimal SHA-256 hash string
25
+ */
26
+ export declare function computeFingerprint(task: Record<string, unknown>): string;
27
+ //# sourceMappingURL=fingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/lib/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2FH;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAUtE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAKxE"}