@diff-review-system/drs 2.2.1 → 3.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 (240) hide show
  1. package/README.md +228 -92
  2. package/dist/ci/runner.d.ts.map +1 -1
  3. package/dist/ci/runner.js +19 -22
  4. package/dist/ci/runner.js.map +1 -1
  5. package/dist/cli/describe-mr.d.ts.map +1 -1
  6. package/dist/cli/describe-mr.js +39 -20
  7. package/dist/cli/describe-mr.js.map +1 -1
  8. package/dist/cli/describe-pr.d.ts.map +1 -1
  9. package/dist/cli/describe-pr.js +39 -20
  10. package/dist/cli/describe-pr.js.map +1 -1
  11. package/dist/cli/index.js +11 -7
  12. package/dist/cli/index.js.map +1 -1
  13. package/dist/cli/init.d.ts.map +1 -1
  14. package/dist/cli/init.js +30 -2
  15. package/dist/cli/init.js.map +1 -1
  16. package/dist/cli/post-comments.d.ts.map +1 -1
  17. package/dist/cli/post-comments.js +5 -5
  18. package/dist/cli/post-comments.js.map +1 -1
  19. package/dist/cli/review-local.d.ts.map +1 -1
  20. package/dist/cli/review-local.integration.test.d.ts +2 -0
  21. package/dist/cli/review-local.integration.test.d.ts.map +1 -0
  22. package/dist/cli/review-local.integration.test.js +343 -0
  23. package/dist/cli/review-local.integration.test.js.map +1 -0
  24. package/dist/cli/review-local.js +5 -4
  25. package/dist/cli/review-local.js.map +1 -1
  26. package/dist/cli/review-local.live.e2e.test.d.ts +2 -0
  27. package/dist/cli/review-local.live.e2e.test.d.ts.map +1 -0
  28. package/dist/cli/review-local.live.e2e.test.js +154 -0
  29. package/dist/cli/review-local.live.e2e.test.js.map +1 -0
  30. package/dist/cli/review-local.test.d.ts +2 -0
  31. package/dist/cli/review-local.test.d.ts.map +1 -0
  32. package/dist/cli/review-local.test.js +164 -0
  33. package/dist/cli/review-local.test.js.map +1 -0
  34. package/dist/cli/review-mr.d.ts +1 -1
  35. package/dist/cli/review-mr.d.ts.map +1 -1
  36. package/dist/cli/review-mr.js +92 -17
  37. package/dist/cli/review-mr.js.map +1 -1
  38. package/dist/cli/review-mr.test.d.ts +2 -0
  39. package/dist/cli/review-mr.test.d.ts.map +1 -0
  40. package/dist/cli/review-mr.test.js +142 -0
  41. package/dist/cli/review-mr.test.js.map +1 -0
  42. package/dist/cli/review-pr.d.ts +1 -1
  43. package/dist/cli/review-pr.d.ts.map +1 -1
  44. package/dist/cli/review-pr.js +96 -13
  45. package/dist/cli/review-pr.js.map +1 -1
  46. package/dist/cli/review-pr.test.d.ts +2 -0
  47. package/dist/cli/review-pr.test.d.ts.map +1 -0
  48. package/dist/cli/review-pr.test.js +137 -0
  49. package/dist/cli/review-pr.test.js.map +1 -0
  50. package/dist/cli/show-changes.js +4 -4
  51. package/dist/github/platform-adapter.js +2 -2
  52. package/dist/gitlab/client.js +1 -1
  53. package/dist/lib/code-quality-report.js +1 -1
  54. package/dist/lib/comment-formatter.d.ts +2 -1
  55. package/dist/lib/comment-formatter.d.ts.map +1 -1
  56. package/dist/lib/comment-formatter.js +33 -1
  57. package/dist/lib/comment-formatter.js.map +1 -1
  58. package/dist/lib/comment-formatter.test.js +43 -0
  59. package/dist/lib/comment-formatter.test.js.map +1 -1
  60. package/dist/lib/comment-manager.d.ts.map +1 -1
  61. package/dist/lib/comment-manager.js +4 -3
  62. package/dist/lib/comment-manager.js.map +1 -1
  63. package/dist/lib/comment-poster.d.ts +2 -1
  64. package/dist/lib/comment-poster.d.ts.map +1 -1
  65. package/dist/lib/comment-poster.js +2 -2
  66. package/dist/lib/comment-poster.js.map +1 -1
  67. package/dist/lib/comment-poster.test.js +27 -11
  68. package/dist/lib/comment-poster.test.js.map +1 -1
  69. package/dist/lib/config-model-overrides.test.d.ts +1 -1
  70. package/dist/lib/config-model-overrides.test.js +2 -2
  71. package/dist/lib/config-model-overrides.test.js.map +1 -1
  72. package/dist/lib/config.d.ts +34 -7
  73. package/dist/lib/config.d.ts.map +1 -1
  74. package/dist/lib/config.js +35 -13
  75. package/dist/lib/config.js.map +1 -1
  76. package/dist/lib/config.test.js +16 -0
  77. package/dist/lib/config.test.js.map +1 -1
  78. package/dist/lib/context-compression.d.ts +27 -1
  79. package/dist/lib/context-compression.d.ts.map +1 -1
  80. package/dist/lib/context-compression.js +106 -4
  81. package/dist/lib/context-compression.js.map +1 -1
  82. package/dist/lib/context-compression.test.js +305 -1
  83. package/dist/lib/context-compression.test.js.map +1 -1
  84. package/dist/lib/context-loader.d.ts +3 -2
  85. package/dist/lib/context-loader.d.ts.map +1 -1
  86. package/dist/lib/context-loader.js +11 -11
  87. package/dist/lib/context-loader.js.map +1 -1
  88. package/dist/lib/description-executor.d.ts +19 -2
  89. package/dist/lib/description-executor.d.ts.map +1 -1
  90. package/dist/lib/description-executor.js +52 -21
  91. package/dist/lib/description-executor.js.map +1 -1
  92. package/dist/lib/description-executor.test.d.ts +2 -0
  93. package/dist/lib/description-executor.test.d.ts.map +1 -0
  94. package/dist/lib/description-executor.test.js +120 -0
  95. package/dist/lib/description-executor.test.js.map +1 -0
  96. package/dist/lib/description-formatter.d.ts +8 -3
  97. package/dist/lib/description-formatter.d.ts.map +1 -1
  98. package/dist/lib/description-formatter.js +88 -13
  99. package/dist/lib/description-formatter.js.map +1 -1
  100. package/dist/lib/description-formatter.test.d.ts +2 -0
  101. package/dist/lib/description-formatter.test.d.ts.map +1 -0
  102. package/dist/lib/description-formatter.test.js +57 -0
  103. package/dist/lib/description-formatter.test.js.map +1 -0
  104. package/dist/lib/diff-parser.test.d.ts +2 -0
  105. package/dist/lib/diff-parser.test.d.ts.map +1 -0
  106. package/dist/lib/diff-parser.test.js +335 -0
  107. package/dist/lib/diff-parser.test.js.map +1 -0
  108. package/dist/lib/exit.d.ts +35 -0
  109. package/dist/lib/exit.d.ts.map +1 -0
  110. package/dist/lib/exit.js +53 -0
  111. package/dist/lib/exit.js.map +1 -0
  112. package/dist/lib/exit.test.d.ts +2 -0
  113. package/dist/lib/exit.test.d.ts.map +1 -0
  114. package/dist/lib/exit.test.js +120 -0
  115. package/dist/lib/exit.test.js.map +1 -0
  116. package/dist/lib/format-utils.d.ts +3 -0
  117. package/dist/lib/format-utils.d.ts.map +1 -0
  118. package/dist/lib/format-utils.js +7 -0
  119. package/dist/lib/format-utils.js.map +1 -0
  120. package/dist/lib/json-output.d.ts +4 -1
  121. package/dist/lib/json-output.d.ts.map +1 -1
  122. package/dist/lib/json-output.js +2 -1
  123. package/dist/lib/json-output.js.map +1 -1
  124. package/dist/lib/json-output.test.d.ts +2 -0
  125. package/dist/lib/json-output.test.d.ts.map +1 -0
  126. package/dist/lib/json-output.test.js +135 -0
  127. package/dist/lib/json-output.test.js.map +1 -0
  128. package/dist/lib/logger.d.ts +10 -2
  129. package/dist/lib/logger.d.ts.map +1 -1
  130. package/dist/lib/logger.js +22 -4
  131. package/dist/lib/logger.js.map +1 -1
  132. package/dist/lib/logger.test.d.ts +2 -0
  133. package/dist/lib/logger.test.d.ts.map +1 -0
  134. package/dist/lib/logger.test.js +324 -0
  135. package/dist/lib/logger.test.js.map +1 -0
  136. package/dist/lib/position-validator.test.d.ts +2 -0
  137. package/dist/lib/position-validator.test.d.ts.map +1 -0
  138. package/dist/lib/position-validator.test.js +128 -0
  139. package/dist/lib/position-validator.test.js.map +1 -0
  140. package/dist/lib/repository-validator.js +1 -1
  141. package/dist/lib/review-core.d.ts +9 -4
  142. package/dist/lib/review-core.d.ts.map +1 -1
  143. package/dist/lib/review-core.js +207 -112
  144. package/dist/lib/review-core.js.map +1 -1
  145. package/dist/lib/review-core.test.js +76 -30
  146. package/dist/lib/review-core.test.js.map +1 -1
  147. package/dist/lib/review-orchestrator.d.ts +12 -7
  148. package/dist/lib/review-orchestrator.d.ts.map +1 -1
  149. package/dist/lib/review-orchestrator.js +78 -22
  150. package/dist/lib/review-orchestrator.js.map +1 -1
  151. package/dist/lib/review-orchestrator.test.js +160 -42
  152. package/dist/lib/review-orchestrator.test.js.map +1 -1
  153. package/dist/lib/review-parser.test.d.ts +2 -0
  154. package/dist/lib/review-parser.test.d.ts.map +1 -0
  155. package/dist/lib/review-parser.test.js +130 -0
  156. package/dist/lib/review-parser.test.js.map +1 -0
  157. package/dist/lib/review-usage.d.ts +32 -0
  158. package/dist/lib/review-usage.d.ts.map +1 -0
  159. package/dist/lib/review-usage.js +72 -0
  160. package/dist/lib/review-usage.js.map +1 -0
  161. package/dist/lib/review-usage.test.d.ts +2 -0
  162. package/dist/lib/review-usage.test.d.ts.map +1 -0
  163. package/dist/lib/review-usage.test.js +83 -0
  164. package/dist/lib/review-usage.test.js.map +1 -0
  165. package/dist/lib/unified-review-executor.d.ts +6 -2
  166. package/dist/lib/unified-review-executor.d.ts.map +1 -1
  167. package/dist/lib/unified-review-executor.js +54 -28
  168. package/dist/lib/unified-review-executor.js.map +1 -1
  169. package/dist/lib/unified-review-executor.test.js +138 -16
  170. package/dist/lib/unified-review-executor.test.js.map +1 -1
  171. package/dist/lib/write-json-output.test.d.ts +2 -0
  172. package/dist/lib/write-json-output.test.d.ts.map +1 -0
  173. package/dist/lib/write-json-output.test.js +259 -0
  174. package/dist/lib/write-json-output.test.js.map +1 -0
  175. package/dist/pi/sdk.d.ts +94 -0
  176. package/dist/pi/sdk.d.ts.map +1 -0
  177. package/dist/pi/sdk.js +486 -0
  178. package/dist/pi/sdk.js.map +1 -0
  179. package/dist/pi/sdk.test.d.ts +2 -0
  180. package/dist/pi/sdk.test.d.ts.map +1 -0
  181. package/dist/pi/sdk.test.js +331 -0
  182. package/dist/pi/sdk.test.js.map +1 -0
  183. package/dist/{opencode → runtime}/agent-loader.d.ts +7 -5
  184. package/dist/runtime/agent-loader.d.ts.map +1 -0
  185. package/dist/{opencode → runtime}/agent-loader.js +24 -19
  186. package/dist/runtime/agent-loader.js.map +1 -0
  187. package/dist/runtime/agent-loader.test.d.ts +2 -0
  188. package/dist/runtime/agent-loader.test.d.ts.map +1 -0
  189. package/dist/runtime/agent-loader.test.js +280 -0
  190. package/dist/runtime/agent-loader.test.js.map +1 -0
  191. package/dist/runtime/built-in-paths.d.ts +2 -0
  192. package/dist/runtime/built-in-paths.d.ts.map +1 -0
  193. package/dist/runtime/built-in-paths.js +14 -0
  194. package/dist/runtime/built-in-paths.js.map +1 -0
  195. package/dist/{opencode → runtime}/client.d.ts +35 -18
  196. package/dist/runtime/client.d.ts.map +1 -0
  197. package/dist/runtime/client.js +486 -0
  198. package/dist/runtime/client.js.map +1 -0
  199. package/dist/{opencode → runtime}/client.test.d.ts.map +1 -1
  200. package/dist/runtime/client.test.js +392 -0
  201. package/dist/runtime/client.test.js.map +1 -0
  202. package/dist/runtime/path-config.d.ts +8 -0
  203. package/dist/runtime/path-config.d.ts.map +1 -0
  204. package/dist/runtime/path-config.js +68 -0
  205. package/dist/runtime/path-config.js.map +1 -0
  206. package/dist/runtime/path-config.test.d.ts +2 -0
  207. package/dist/runtime/path-config.test.d.ts.map +1 -0
  208. package/dist/runtime/path-config.test.js +103 -0
  209. package/dist/runtime/path-config.test.js.map +1 -0
  210. package/package.json +5 -5
  211. package/.opencode/opencode.jsonc +0 -15
  212. package/.opencode/tool/write_json_output.ts +0 -24
  213. package/.opencode/tools/drs_skill.ts +0 -67
  214. package/dist/lib/skills-prompt.d.ts +0 -3
  215. package/dist/lib/skills-prompt.d.ts.map +0 -1
  216. package/dist/lib/skills-prompt.js +0 -70
  217. package/dist/lib/skills-prompt.js.map +0 -1
  218. package/dist/opencode/agent-loader.d.ts.map +0 -1
  219. package/dist/opencode/agent-loader.js.map +0 -1
  220. package/dist/opencode/client.d.ts.map +0 -1
  221. package/dist/opencode/client.js +0 -456
  222. package/dist/opencode/client.js.map +0 -1
  223. package/dist/opencode/client.test.js +0 -317
  224. package/dist/opencode/client.test.js.map +0 -1
  225. package/dist/opencode/opencode-paths.d.ts +0 -2
  226. package/dist/opencode/opencode-paths.d.ts.map +0 -1
  227. package/dist/opencode/opencode-paths.js +0 -7
  228. package/dist/opencode/opencode-paths.js.map +0 -1
  229. package/dist/opencode/skill-loader.d.ts +0 -15
  230. package/dist/opencode/skill-loader.d.ts.map +0 -1
  231. package/dist/opencode/skill-loader.js +0 -88
  232. package/dist/opencode/skill-loader.js.map +0 -1
  233. /package/{.opencode/agent → .pi/agents}/describe/pr-describer.md +0 -0
  234. /package/{.opencode/agent → .pi/agents}/review/documentation.md +0 -0
  235. /package/{.opencode/agent → .pi/agents}/review/performance.md +0 -0
  236. /package/{.opencode/agent → .pi/agents}/review/quality.md +0 -0
  237. /package/{.opencode/agent → .pi/agents}/review/security.md +0 -0
  238. /package/{.opencode/agent → .pi/agents}/review/style.md +0 -0
  239. /package/{.opencode/agent → .pi/agents}/review/unified-reviewer.md +0 -0
  240. /package/dist/{opencode → runtime}/client.test.d.ts +0 -0
@@ -0,0 +1,335 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { parseDiff, getChangedFiles, getAddedLines, diffContainsPattern, diffToPatch, getFilesWithDiffs, } from './diff-parser.js';
3
+ // ── Fixtures ──────────────────────────────────────────────────────
4
+ const SIMPLE_DIFF = `diff --git a/src/app.ts b/src/app.ts
5
+ --- a/src/app.ts
6
+ +++ b/src/app.ts
7
+ @@ -1,5 +1,6 @@
8
+ import express from 'express';
9
+
10
+ const app = express();
11
+ +app.use(express.json());
12
+
13
+ export default app;
14
+ `;
15
+ const MULTI_FILE_DIFF = `diff --git a/src/app.ts b/src/app.ts
16
+ --- a/src/app.ts
17
+ +++ b/src/app.ts
18
+ @@ -1,3 +1,4 @@
19
+ import express from 'express';
20
+ +import cors from 'cors';
21
+
22
+ const app = express();
23
+ diff --git a/src/utils.ts b/src/utils.ts
24
+ --- a/src/utils.ts
25
+ +++ b/src/utils.ts
26
+ @@ -5,7 +5,7 @@
27
+ export function add(a: number, b: number): number {
28
+ - return a + b + 0;
29
+ + return a + b;
30
+ }
31
+ `;
32
+ const NEW_FILE_DIFF = `diff --git a/src/new-file.ts b/src/new-file.ts
33
+ --- /dev/null
34
+ +++ b/src/new-file.ts
35
+ @@ -0,0 +1,3 @@
36
+ +export const greeting = 'hello';
37
+ +
38
+ +export default greeting;
39
+ `;
40
+ const DELETED_FILE_DIFF = `diff --git a/src/old-file.ts b/src/old-file.ts
41
+ --- a/src/old-file.ts
42
+ +++ /dev/null
43
+ @@ -1,3 +0,0 @@
44
+ -export const legacy = true;
45
+ -
46
+ -export default legacy;
47
+ `;
48
+ const RENAMED_FILE_DIFF = `diff --git a/src/old-name.ts b/src/new-name.ts
49
+ --- a/src/old-name.ts
50
+ +++ b/src/new-name.ts
51
+ @@ -1,3 +1,3 @@
52
+ -export const name = 'old';
53
+ +export const name = 'new';
54
+
55
+ export default name;
56
+ `;
57
+ const MULTI_HUNK_DIFF = `diff --git a/src/big.ts b/src/big.ts
58
+ --- a/src/big.ts
59
+ +++ b/src/big.ts
60
+ @@ -1,4 +1,5 @@
61
+ // header
62
+ +import { log } from './log';
63
+
64
+ function first() {
65
+ return 1;
66
+ @@ -20,4 +21,5 @@
67
+ function second() {
68
+ return 2;
69
+ }
70
+ +// end of file
71
+ `;
72
+ // ── parseDiff ──────────────────────────────────────────────────────
73
+ describe('parseDiff', () => {
74
+ it('parses a simple single-file diff', () => {
75
+ const result = parseDiff(SIMPLE_DIFF);
76
+ expect(result).toHaveLength(1);
77
+ expect(result[0].oldPath).toBe('src/app.ts');
78
+ expect(result[0].newPath).toBe('src/app.ts');
79
+ expect(result[0].isNew).toBe(false);
80
+ expect(result[0].isDeleted).toBe(false);
81
+ expect(result[0].isRenamed).toBe(false);
82
+ expect(result[0].hunks).toHaveLength(1);
83
+ });
84
+ it('extracts correct line numbers and types', () => {
85
+ const [file] = parseDiff(SIMPLE_DIFF);
86
+ const hunk = file.hunks[0];
87
+ expect(hunk.oldStart).toBe(1);
88
+ expect(hunk.oldLines).toBe(5);
89
+ expect(hunk.newStart).toBe(1);
90
+ expect(hunk.newLines).toBe(6);
91
+ const added = hunk.lines.filter((l) => l.type === 'add');
92
+ expect(added).toHaveLength(1);
93
+ expect(added[0].content).toBe('app.use(express.json());');
94
+ expect(added[0].newLineNumber).toBeDefined();
95
+ const context = hunk.lines.filter((l) => l.type === 'context');
96
+ expect(context.length).toBeGreaterThan(0);
97
+ expect(context[0].oldLineNumber).toBeDefined();
98
+ expect(context[0].newLineNumber).toBeDefined();
99
+ });
100
+ it('parses multi-file diffs', () => {
101
+ const result = parseDiff(MULTI_FILE_DIFF);
102
+ expect(result).toHaveLength(2);
103
+ expect(result[0].newPath).toBe('src/app.ts');
104
+ expect(result[1].newPath).toBe('src/utils.ts');
105
+ // First file: one addition
106
+ const firstAdded = result[0].hunks[0].lines.filter((l) => l.type === 'add');
107
+ expect(firstAdded).toHaveLength(1);
108
+ expect(firstAdded[0].content).toBe("import cors from 'cors';");
109
+ // Second file: one delete, one add
110
+ const secondHunk = result[1].hunks[0];
111
+ const deleted = secondHunk.lines.filter((l) => l.type === 'delete');
112
+ const added = secondHunk.lines.filter((l) => l.type === 'add');
113
+ expect(deleted).toHaveLength(1);
114
+ expect(added).toHaveLength(1);
115
+ expect(deleted[0].content).toBe(' return a + b + 0;');
116
+ expect(added[0].content).toBe(' return a + b;');
117
+ });
118
+ it('detects new files', () => {
119
+ const [file] = parseDiff(NEW_FILE_DIFF);
120
+ expect(file.isNew).toBe(true);
121
+ expect(file.isDeleted).toBe(false);
122
+ expect(file.oldPath).toBe('/dev/null');
123
+ expect(file.newPath).toBe('src/new-file.ts');
124
+ const added = file.hunks[0].lines.filter((l) => l.type === 'add');
125
+ expect(added).toHaveLength(3);
126
+ });
127
+ it('detects deleted files', () => {
128
+ const [file] = parseDiff(DELETED_FILE_DIFF);
129
+ expect(file.isDeleted).toBe(true);
130
+ expect(file.isNew).toBe(false);
131
+ expect(file.oldPath).toBe('src/old-file.ts');
132
+ expect(file.newPath).toBe('/dev/null');
133
+ const deleted = file.hunks[0].lines.filter((l) => l.type === 'delete');
134
+ expect(deleted).toHaveLength(3);
135
+ });
136
+ it('parses renamed files with changes', () => {
137
+ const [file] = parseDiff(RENAMED_FILE_DIFF);
138
+ expect(file.oldPath).toBe('src/old-name.ts');
139
+ expect(file.newPath).toBe('src/new-name.ts');
140
+ });
141
+ it('handles multiple hunks in a single file', () => {
142
+ const [file] = parseDiff(MULTI_HUNK_DIFF);
143
+ expect(file.hunks).toHaveLength(2);
144
+ expect(file.hunks[0].oldStart).toBe(1);
145
+ expect(file.hunks[0].newStart).toBe(1);
146
+ expect(file.hunks[1].oldStart).toBe(20);
147
+ expect(file.hunks[1].newStart).toBe(21);
148
+ });
149
+ it('returns empty array for empty input', () => {
150
+ expect(parseDiff('')).toEqual([]);
151
+ });
152
+ it('returns empty array for non-diff text', () => {
153
+ expect(parseDiff('just some random text\nwith multiple lines\n')).toEqual([]);
154
+ });
155
+ it('handles hunk header without line count (single-line hunks)', () => {
156
+ const diff = `diff --git a/file.ts b/file.ts
157
+ --- a/file.ts
158
+ +++ b/file.ts
159
+ @@ -1 +1 @@
160
+ -old
161
+ +new
162
+ `;
163
+ const [file] = parseDiff(diff);
164
+ const hunk = file.hunks[0];
165
+ expect(hunk.oldLines).toBe(1);
166
+ expect(hunk.newLines).toBe(1);
167
+ });
168
+ it('tracks line numbers correctly across adds and deletes', () => {
169
+ const diff = `diff --git a/f.ts b/f.ts
170
+ --- a/f.ts
171
+ +++ b/f.ts
172
+ @@ -10,5 +10,6 @@
173
+ context line
174
+ -deleted line
175
+ +added line 1
176
+ +added line 2
177
+ another context
178
+ final line
179
+ `;
180
+ const [file] = parseDiff(diff);
181
+ const lines = file.hunks[0].lines;
182
+ // context at old:10, new:10
183
+ expect(lines[0]).toMatchObject({ type: 'context', oldLineNumber: 10, newLineNumber: 10 });
184
+ // delete at old:11
185
+ expect(lines[1]).toMatchObject({ type: 'delete', oldLineNumber: 11 });
186
+ // adds at new:11, new:12
187
+ expect(lines[2]).toMatchObject({ type: 'add', newLineNumber: 11 });
188
+ expect(lines[3]).toMatchObject({ type: 'add', newLineNumber: 12 });
189
+ // context resumes at old:12, new:13
190
+ expect(lines[4]).toMatchObject({ type: 'context', oldLineNumber: 12, newLineNumber: 13 });
191
+ expect(lines[5]).toMatchObject({ type: 'context', oldLineNumber: 13, newLineNumber: 14 });
192
+ });
193
+ });
194
+ // ── getChangedFiles ──────────────────────────────────────────────
195
+ describe('getChangedFiles', () => {
196
+ it('returns new-side paths for modified files', () => {
197
+ const diffs = parseDiff(MULTI_FILE_DIFF);
198
+ expect(getChangedFiles(diffs)).toEqual(['src/app.ts', 'src/utils.ts']);
199
+ });
200
+ it('excludes deleted files', () => {
201
+ const diffs = parseDiff(DELETED_FILE_DIFF);
202
+ expect(getChangedFiles(diffs)).toEqual([]);
203
+ });
204
+ it('includes new files', () => {
205
+ const diffs = parseDiff(NEW_FILE_DIFF);
206
+ expect(getChangedFiles(diffs)).toEqual(['src/new-file.ts']);
207
+ });
208
+ it('handles mixed new/modified/deleted', () => {
209
+ const diffs = parseDiff(NEW_FILE_DIFF + SIMPLE_DIFF + DELETED_FILE_DIFF);
210
+ const changed = getChangedFiles(diffs);
211
+ expect(changed).toContain('src/new-file.ts');
212
+ expect(changed).toContain('src/app.ts');
213
+ expect(changed).not.toContain('/dev/null');
214
+ // deleted file should be excluded
215
+ expect(changed).not.toContain('src/old-file.ts');
216
+ });
217
+ it('returns empty for empty input', () => {
218
+ expect(getChangedFiles([])).toEqual([]);
219
+ });
220
+ });
221
+ // ── getAddedLines ────────────────────────────────────────────────
222
+ describe('getAddedLines', () => {
223
+ it('returns added lines with line numbers', () => {
224
+ const [file] = parseDiff(SIMPLE_DIFF);
225
+ const added = getAddedLines(file);
226
+ expect(added).toHaveLength(1);
227
+ expect(added[0].content).toBe('app.use(express.json());');
228
+ expect(added[0].line).toBeGreaterThan(0);
229
+ });
230
+ it('returns all added lines for a new file', () => {
231
+ const [file] = parseDiff(NEW_FILE_DIFF);
232
+ const added = getAddedLines(file);
233
+ // 3 lines added (blank line between them is also an add with content '')
234
+ expect(added).toHaveLength(3);
235
+ expect(added[0].content).toBe("export const greeting = 'hello';");
236
+ expect(added[1].content).toBe('');
237
+ expect(added[2].content).toBe('export default greeting;');
238
+ });
239
+ it('returns added lines across multiple hunks', () => {
240
+ const [file] = parseDiff(MULTI_HUNK_DIFF);
241
+ const added = getAddedLines(file);
242
+ expect(added).toHaveLength(2);
243
+ expect(added[0].content).toBe("import { log } from './log';");
244
+ expect(added[1].content).toBe('// end of file');
245
+ });
246
+ it('returns empty for a deleted file', () => {
247
+ const [file] = parseDiff(DELETED_FILE_DIFF);
248
+ const added = getAddedLines(file);
249
+ expect(added).toEqual([]);
250
+ });
251
+ });
252
+ // ── diffContainsPattern ──────────────────────────────────────────
253
+ describe('diffContainsPattern', () => {
254
+ it('matches pattern in added lines', () => {
255
+ const [file] = parseDiff(SIMPLE_DIFF);
256
+ expect(diffContainsPattern(file, /express\.json/)).toBe(true);
257
+ });
258
+ it('does not match pattern in context lines', () => {
259
+ const [file] = parseDiff(SIMPLE_DIFF);
260
+ // 'import express' is a context line, not an add
261
+ expect(diffContainsPattern(file, /^import express/)).toBe(false);
262
+ });
263
+ it('does not match pattern in deleted lines', () => {
264
+ const [, file] = parseDiff(MULTI_FILE_DIFF);
265
+ // 'a + b + 0' is in a deleted line
266
+ expect(diffContainsPattern(file, /a \+ b \+ 0/)).toBe(false);
267
+ });
268
+ it('returns false when no match', () => {
269
+ const [file] = parseDiff(SIMPLE_DIFF);
270
+ expect(diffContainsPattern(file, /nonexistent_pattern/)).toBe(false);
271
+ });
272
+ it('returns false for file with no hunks', () => {
273
+ expect(diffContainsPattern({ oldPath: '', newPath: '', hunks: [], isNew: false, isDeleted: false, isRenamed: false }, /anything/)).toBe(false);
274
+ });
275
+ });
276
+ // ── diffToPatch ──────────────────────────────────────────────────
277
+ describe('diffToPatch', () => {
278
+ it('reconstructs hunk header and lines', () => {
279
+ const [file] = parseDiff(SIMPLE_DIFF);
280
+ const patch = diffToPatch(file);
281
+ expect(patch).toContain('@@ -1,5 +1,6 @@');
282
+ expect(patch).toContain('+app.use(express.json());');
283
+ expect(patch).toContain(" import express from 'express';");
284
+ });
285
+ it('preserves delete and add lines', () => {
286
+ const [, file] = parseDiff(MULTI_FILE_DIFF);
287
+ const patch = diffToPatch(file);
288
+ expect(patch).toContain('- return a + b + 0;');
289
+ expect(patch).toContain('+ return a + b;');
290
+ });
291
+ it('handles multiple hunks', () => {
292
+ const [file] = parseDiff(MULTI_HUNK_DIFF);
293
+ const patch = diffToPatch(file);
294
+ // Both hunk headers
295
+ expect(patch).toContain('@@ -1,4 +1,5 @@');
296
+ expect(patch).toContain('@@ -20,4 +21,5 @@');
297
+ });
298
+ it('returns empty string for file with no hunks', () => {
299
+ expect(diffToPatch({
300
+ oldPath: '',
301
+ newPath: '',
302
+ hunks: [],
303
+ isNew: false,
304
+ isDeleted: false,
305
+ isRenamed: false,
306
+ })).toBe('');
307
+ });
308
+ });
309
+ // ── getFilesWithDiffs ────────────────────────────────────────────
310
+ describe('getFilesWithDiffs', () => {
311
+ it('returns filename and patch for modified files', () => {
312
+ const diffs = parseDiff(MULTI_FILE_DIFF);
313
+ const files = getFilesWithDiffs(diffs);
314
+ expect(files).toHaveLength(2);
315
+ expect(files[0].filename).toBe('src/app.ts');
316
+ expect(files[0].patch).toContain('+import cors');
317
+ expect(files[1].filename).toBe('src/utils.ts');
318
+ });
319
+ it('excludes deleted files', () => {
320
+ const diffs = parseDiff(DELETED_FILE_DIFF);
321
+ const files = getFilesWithDiffs(diffs);
322
+ expect(files).toEqual([]);
323
+ });
324
+ it('includes new files', () => {
325
+ const diffs = parseDiff(NEW_FILE_DIFF);
326
+ const files = getFilesWithDiffs(diffs);
327
+ expect(files).toHaveLength(1);
328
+ expect(files[0].filename).toBe('src/new-file.ts');
329
+ expect(files[0].patch).toContain("+export const greeting = 'hello';");
330
+ });
331
+ it('returns empty for empty input', () => {
332
+ expect(getFilesWithDiffs([])).toEqual([]);
333
+ });
334
+ });
335
+ //# sourceMappingURL=diff-parser.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-parser.test.js","sourceRoot":"","sources":["../../src/lib/diff-parser.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,SAAS,EACT,eAAe,EACf,aAAa,EACb,mBAAmB,EACnB,WAAW,EACX,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAE1B,qEAAqE;AAErE,MAAM,WAAW,GAAG;;;;;;;;;;CAUnB,CAAC;AAEF,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;CAgBvB,CAAC;AAEF,MAAM,aAAa,GAAG;;;;;;;CAOrB,CAAC;AAEF,MAAM,iBAAiB,GAAG;;;;;;;CAOzB,CAAC;AAEF,MAAM,iBAAiB,GAAG;;;;;;;;CAQzB,CAAC;AAEF,MAAM,eAAe,GAAG;;;;;;;;;;;;;;CAcvB,CAAC;AAEF,sEAAsE;AAEtE,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,MAAM,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;QAEtC,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAE3B,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAE9B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;QACzD,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QAC1D,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,WAAW,EAAE,CAAC;QAE7C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;QAC/D,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,WAAW,EAAE,CAAC;QAC/C,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,MAAM,GAAG,SAAS,CAAC,eAAe,CAAC,CAAC;QAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAE/C,2BAA2B;QAC3B,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;QAC5E,MAAM,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QAE/D,mCAAmC;QACnC,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;QACpE,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;QAC/D,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QACvD,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC3B,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC;QAExC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAE7C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;QAClE,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAE5C,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAEvC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;QACvE,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAE5C,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,eAAe,CAAC,CAAC;QAE1C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,SAAS,CAAC,8CAA8C,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,IAAI,GAAG;;;;;;CAMhB,CAAC;QACE,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3B,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,IAAI,GAAG;;;;;;;;;;CAUhB,CAAC;QACE,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAElC,4BAA4B;QAC5B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1F,mBAAmB;QACnB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,CAAC;QACtE,yBAAyB;QACzB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,CAAC;QACnE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,CAAC;QACnE,oCAAoC;QACpC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,CAAC;IAC5F,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,oEAAoE;AAEpE,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,KAAK,GAAG,SAAS,CAAC,eAAe,CAAC,CAAC;QACzC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,KAAK,GAAG,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC3C,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAC5B,MAAM,KAAK,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC;QACvC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,KAAK,GAAG,SAAS,CAAC,aAAa,GAAG,WAAW,GAAG,iBAAiB,CAAC,CAAC;QACzE,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC7C,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACxC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAC3C,kCAAkC;QAClC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,oEAAoE;AAEpE,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QAElC,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QAC1D,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC;QACxC,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QAElC,yEAAyE;QACzE,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;QAClE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAClC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,eAAe,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QAElC,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;QAC9D,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,oEAAoE;AAEpE,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;QACtC,iDAAiD;QACjD,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,SAAS,CAAC,eAAe,CAAC,CAAC;QAC5C,mCAAmC;QACnC,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CACJ,mBAAmB,CACjB,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,EACzF,UAAU,CACX,CACF,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,oEAAoE;AAEpE,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QAEhC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAC;QACrD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,iCAAiC,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,SAAS,CAAC,eAAe,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QAEhC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,eAAe,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QAEhC,oBAAoB;QACpB,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CACJ,WAAW,CAAC;YACV,OAAO,EAAE,EAAE;YACX,OAAO,EAAE,EAAE;YACX,KAAK,EAAE,EAAE;YACT,KAAK,EAAE,KAAK;YACZ,SAAS,EAAE,KAAK;YAChB,SAAS,EAAE,KAAK;SACjB,CAAC,CACH,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,oEAAoE;AAEpE,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,KAAK,GAAG,SAAS,CAAC,eAAe,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAEvC,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,KAAK,GAAG,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAC5B,MAAM,KAAK,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC;QACvC,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAEvC,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,mCAAmC,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Process exit abstraction for testability.
3
+ *
4
+ * Library code should call `exitProcess(code)` instead of `process.exit(code)`.
5
+ * In tests the handler can be replaced with `setExitHandler()` to capture
6
+ * the exit code without terminating the process.
7
+ */
8
+ export type ExitHandler = (code: number) => never;
9
+ /**
10
+ * Exit the process (or trigger the installed handler in tests).
11
+ */
12
+ export declare function exitProcess(code: number): never;
13
+ /**
14
+ * Replace the exit handler. Returns a restore function.
15
+ *
16
+ * ```ts
17
+ * const restore = setExitHandler((code) => { throw new ExitError(code); });
18
+ * try { ... } finally { restore(); }
19
+ * ```
20
+ */
21
+ export declare function setExitHandler(handler: ExitHandler): () => void;
22
+ /**
23
+ * Error thrown by the test exit handler so callers can
24
+ * assert on the exit code.
25
+ */
26
+ export declare class ExitError extends Error {
27
+ readonly code: number;
28
+ constructor(code: number);
29
+ }
30
+ /**
31
+ * Install a test exit handler that throws `ExitError`.
32
+ * Returns a restore function.
33
+ */
34
+ export declare function installTestExitHandler(): () => void;
35
+ //# sourceMappingURL=exit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit.d.ts","sourceRoot":"","sources":["../../src/lib/exit.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC;AAMlD;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAE/C;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,IAAI,CAM/D;AAED;;;GAGG;AACH,qBAAa,SAAU,SAAQ,KAAK;aACN,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;CAIzC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,IAAI,CAInD"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Process exit abstraction for testability.
3
+ *
4
+ * Library code should call `exitProcess(code)` instead of `process.exit(code)`.
5
+ * In tests the handler can be replaced with `setExitHandler()` to capture
6
+ * the exit code without terminating the process.
7
+ */
8
+ let currentHandler = ((code) => {
9
+ process.exit(code);
10
+ });
11
+ /**
12
+ * Exit the process (or trigger the installed handler in tests).
13
+ */
14
+ export function exitProcess(code) {
15
+ return currentHandler(code);
16
+ }
17
+ /**
18
+ * Replace the exit handler. Returns a restore function.
19
+ *
20
+ * ```ts
21
+ * const restore = setExitHandler((code) => { throw new ExitError(code); });
22
+ * try { ... } finally { restore(); }
23
+ * ```
24
+ */
25
+ export function setExitHandler(handler) {
26
+ const previous = currentHandler;
27
+ currentHandler = handler;
28
+ return () => {
29
+ currentHandler = previous;
30
+ };
31
+ }
32
+ /**
33
+ * Error thrown by the test exit handler so callers can
34
+ * assert on the exit code.
35
+ */
36
+ export class ExitError extends Error {
37
+ code;
38
+ constructor(code) {
39
+ super(`process.exit(${code})`);
40
+ this.code = code;
41
+ this.name = 'ExitError';
42
+ }
43
+ }
44
+ /**
45
+ * Install a test exit handler that throws `ExitError`.
46
+ * Returns a restore function.
47
+ */
48
+ export function installTestExitHandler() {
49
+ return setExitHandler(((code) => {
50
+ throw new ExitError(code);
51
+ }));
52
+ }
53
+ //# sourceMappingURL=exit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit.js","sourceRoot":"","sources":["../../src/lib/exit.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,IAAI,cAAc,GAAgB,CAAC,CAAC,IAAY,EAAE,EAAE;IAClD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC,CAAgB,CAAC;AAElB;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,OAAoB;IACjD,MAAM,QAAQ,GAAG,cAAc,CAAC;IAChC,cAAc,GAAG,OAAO,CAAC;IACzB,OAAO,GAAG,EAAE;QACV,cAAc,GAAG,QAAQ,CAAC;IAC5B,CAAC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IACN;IAA5B,YAA4B,IAAY;QACtC,KAAK,CAAC,gBAAgB,IAAI,GAAG,CAAC,CAAC;QADL,SAAI,GAAJ,IAAI,CAAQ;QAEtC,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,cAAc,CAAC,CAAC,CAAC,IAAY,EAAE,EAAE;QACtC,MAAM,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAgB,CAAC,CAAC;AACrB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=exit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit.test.d.ts","sourceRoot":"","sources":["../../src/lib/exit.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,120 @@
1
+ import { describe, it, expect, afterEach } from 'vitest';
2
+ import { exitProcess, setExitHandler, installTestExitHandler, ExitError } from './exit.js';
3
+ describe('exit', () => {
4
+ let restore;
5
+ afterEach(() => {
6
+ restore?.();
7
+ restore = undefined;
8
+ });
9
+ describe('exitProcess', () => {
10
+ it('calls the installed handler with the exit code', () => {
11
+ let capturedCode;
12
+ restore = setExitHandler(((code) => {
13
+ capturedCode = code;
14
+ }));
15
+ try {
16
+ exitProcess(1);
17
+ }
18
+ catch {
19
+ // handler may not actually be `never` in test
20
+ }
21
+ expect(capturedCode).toBe(1);
22
+ });
23
+ it('passes exit code 0 for success', () => {
24
+ let capturedCode;
25
+ restore = setExitHandler(((code) => {
26
+ capturedCode = code;
27
+ }));
28
+ try {
29
+ exitProcess(0);
30
+ }
31
+ catch {
32
+ // handler may not actually be `never` in test
33
+ }
34
+ expect(capturedCode).toBe(0);
35
+ });
36
+ });
37
+ describe('setExitHandler', () => {
38
+ it('returns a restore function that reverts to previous handler', () => {
39
+ const codes = [];
40
+ const first = setExitHandler(((code) => {
41
+ codes.push(code);
42
+ }));
43
+ const second = setExitHandler(((code) => {
44
+ codes.push(code * 10);
45
+ }));
46
+ try {
47
+ exitProcess(1);
48
+ }
49
+ catch {
50
+ /* noop */
51
+ }
52
+ expect(codes).toEqual([10]); // second handler
53
+ second(); // restore to first
54
+ try {
55
+ exitProcess(2);
56
+ }
57
+ catch {
58
+ /* noop */
59
+ }
60
+ expect(codes).toEqual([10, 2]); // first handler
61
+ first(); // restore to original
62
+ restore = undefined; // already cleaned up
63
+ });
64
+ });
65
+ describe('installTestExitHandler', () => {
66
+ it('throws ExitError with the exit code', () => {
67
+ restore = installTestExitHandler();
68
+ expect(() => exitProcess(1)).toThrow(ExitError);
69
+ expect(() => exitProcess(1)).toThrow('process.exit(1)');
70
+ });
71
+ it('captures exit code 0', () => {
72
+ restore = installTestExitHandler();
73
+ try {
74
+ exitProcess(0);
75
+ }
76
+ catch (e) {
77
+ expect(e).toBeInstanceOf(ExitError);
78
+ expect(e.code).toBe(0);
79
+ }
80
+ });
81
+ it('restore function reverts the handler', () => {
82
+ const restoreFn = installTestExitHandler();
83
+ // Should throw while installed
84
+ expect(() => exitProcess(1)).toThrow(ExitError);
85
+ restoreFn();
86
+ restore = undefined;
87
+ // After restore, we can't easily test it calls process.exit
88
+ // without actually exiting. Just verify no ExitError.
89
+ let capturedCode;
90
+ restore = setExitHandler(((code) => {
91
+ capturedCode = code;
92
+ }));
93
+ try {
94
+ exitProcess(42);
95
+ }
96
+ catch {
97
+ /* noop */
98
+ }
99
+ expect(capturedCode).toBe(42);
100
+ });
101
+ });
102
+ describe('ExitError', () => {
103
+ it('has name ExitError', () => {
104
+ const err = new ExitError(1);
105
+ expect(err.name).toBe('ExitError');
106
+ });
107
+ it('has code property', () => {
108
+ expect(new ExitError(0).code).toBe(0);
109
+ expect(new ExitError(1).code).toBe(1);
110
+ expect(new ExitError(127).code).toBe(127);
111
+ });
112
+ it('has descriptive message', () => {
113
+ expect(new ExitError(1).message).toBe('process.exit(1)');
114
+ });
115
+ it('is instanceof Error', () => {
116
+ expect(new ExitError(1)).toBeInstanceOf(Error);
117
+ });
118
+ });
119
+ });
120
+ //# sourceMappingURL=exit.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit.test.js","sourceRoot":"","sources":["../../src/lib/exit.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function formatCount(value: number): string;
2
+ export declare function formatCost(value: number): string;
3
+ //# sourceMappingURL=format-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-utils.d.ts","sourceRoot":"","sources":["../../src/lib/format-utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD"}
@@ -0,0 +1,7 @@
1
+ export function formatCount(value) {
2
+ return new Intl.NumberFormat('en-US').format(Math.round(value));
3
+ }
4
+ export function formatCost(value) {
5
+ return `$${value.toFixed(4)}`;
6
+ }
7
+ //# sourceMappingURL=format-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-utils.js","sourceRoot":"","sources":["../../src/lib/format-utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;AAChC,CAAC"}
@@ -5,6 +5,7 @@
5
5
  * not posting comments or generating code quality reports.
6
6
  */
7
7
  import type { ReviewIssue, ReviewSummary } from './comment-formatter.js';
8
+ import type { ReviewUsageSummary } from './review-usage.js';
8
9
  /**
9
10
  * JSON output structure for review results
10
11
  */
@@ -15,6 +16,8 @@ export interface ReviewJsonOutput {
15
16
  summary: ReviewSummary;
16
17
  /** All issues found */
17
18
  issues: ReviewIssue[];
19
+ /** Token usage and cost breakdown */
20
+ usage?: ReviewUsageSummary;
18
21
  /** Metadata about the review */
19
22
  metadata?: {
20
23
  /** Source of the review (PR number, MR iid, or local) */
@@ -31,7 +34,7 @@ export interface ReviewJsonOutput {
31
34
  /**
32
35
  * Format review results as JSON output
33
36
  */
34
- export declare function formatReviewJson(summary: ReviewSummary, issues: ReviewIssue[], metadata?: ReviewJsonOutput['metadata']): ReviewJsonOutput;
37
+ export declare function formatReviewJson(summary: ReviewSummary, issues: ReviewIssue[], metadata?: ReviewJsonOutput['metadata'], usage?: ReviewUsageSummary): ReviewJsonOutput;
35
38
  /**
36
39
  * Write review results to a JSON file
37
40
  */
@@ -1 +1 @@
1
- {"version":3,"file":"json-output.d.ts","sourceRoot":"","sources":["../../src/lib/json-output.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,gCAAgC;IAChC,OAAO,EAAE,aAAa,CAAC;IACvB,uBAAuB;IACvB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,gCAAgC;IAChC,QAAQ,CAAC,EAAE;QACT,yDAAyD;QACzD,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,yBAAyB;QACzB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,yBAAyB;QACzB,MAAM,CAAC,EAAE;YACP,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,MAAM,CAAC,EAAE,MAAM,CAAC;SACjB,CAAC;KACH,CAAC;CACH;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,WAAW,EAAE,EACrB,QAAQ,CAAC,EAAE,gBAAgB,CAAC,UAAU,CAAC,GACtC,gBAAgB,CAOlB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,gBAAgB,EACxB,UAAU,EAAE,MAAM,EAClB,UAAU,GAAE,MAAsB,GACjC,OAAO,CAAC,IAAI,CAAC,CAIf;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAE9D"}
1
+ {"version":3,"file":"json-output.d.ts","sourceRoot":"","sources":["../../src/lib/json-output.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,gCAAgC;IAChC,OAAO,EAAE,aAAa,CAAC;IACvB,uBAAuB;IACvB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,qCAAqC;IACrC,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,gCAAgC;IAChC,QAAQ,CAAC,EAAE;QACT,yDAAyD;QACzD,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,yBAAyB;QACzB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,yBAAyB;QACzB,MAAM,CAAC,EAAE;YACP,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,MAAM,CAAC,EAAE,MAAM,CAAC;SACjB,CAAC;KACH,CAAC;CACH;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,WAAW,EAAE,EACrB,QAAQ,CAAC,EAAE,gBAAgB,CAAC,UAAU,CAAC,EACvC,KAAK,CAAC,EAAE,kBAAkB,GACzB,gBAAgB,CAQlB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,gBAAgB,EACxB,UAAU,EAAE,MAAM,EAClB,UAAU,GAAE,MAAsB,GACjC,OAAO,CAAC,IAAI,CAAC,CAIf;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAE9D"}