@diff-review-system/drs 1.0.0 → 2.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 (287) hide show
  1. package/.opencode/agent/describe/pr-describer.md +221 -0
  2. package/.opencode/agent/review/documentation.md +56 -0
  3. package/.opencode/agent/review/performance.md +32 -130
  4. package/.opencode/agent/review/quality.md +36 -104
  5. package/.opencode/agent/review/security.md +32 -94
  6. package/.opencode/agent/review/style.md +26 -10
  7. package/.opencode/agent/review/unified-reviewer.md +74 -0
  8. package/.opencode/opencode.jsonc +4 -41
  9. package/.opencode/tool/write_json_output.ts +24 -0
  10. package/README.md +215 -82
  11. package/dist/ci/runner.d.ts.map +1 -1
  12. package/dist/ci/runner.js +4 -4
  13. package/dist/ci/runner.js.map +1 -1
  14. package/dist/cli/describe-mr.d.ts +11 -0
  15. package/dist/cli/describe-mr.d.ts.map +1 -0
  16. package/dist/cli/describe-mr.js +104 -0
  17. package/dist/cli/describe-mr.js.map +1 -0
  18. package/dist/cli/describe-pr.d.ts +12 -0
  19. package/dist/cli/describe-pr.d.ts.map +1 -0
  20. package/dist/cli/describe-pr.js +105 -0
  21. package/dist/cli/describe-pr.js.map +1 -0
  22. package/dist/cli/index.js +234 -20
  23. package/dist/cli/index.js.map +1 -1
  24. package/dist/cli/init.d.ts +1 -1
  25. package/dist/cli/init.d.ts.map +1 -1
  26. package/dist/cli/init.js +337 -120
  27. package/dist/cli/init.js.map +1 -1
  28. package/dist/cli/post-comments.d.ts +15 -0
  29. package/dist/cli/post-comments.d.ts.map +1 -0
  30. package/dist/cli/post-comments.js +216 -0
  31. package/dist/cli/post-comments.js.map +1 -0
  32. package/dist/cli/review-local.d.ts +3 -0
  33. package/dist/cli/review-local.d.ts.map +1 -1
  34. package/dist/cli/review-local.js +46 -63
  35. package/dist/cli/review-local.js.map +1 -1
  36. package/dist/cli/review-mr.d.ts +7 -0
  37. package/dist/cli/review-mr.d.ts.map +1 -1
  38. package/dist/cli/review-mr.js +88 -117
  39. package/dist/cli/review-mr.js.map +1 -1
  40. package/dist/cli/review-pr.d.ts +6 -0
  41. package/dist/cli/review-pr.d.ts.map +1 -1
  42. package/dist/cli/review-pr.js +81 -114
  43. package/dist/cli/review-pr.js.map +1 -1
  44. package/dist/cli/show-changes.d.ts +15 -0
  45. package/dist/cli/show-changes.d.ts.map +1 -0
  46. package/dist/cli/show-changes.js +184 -0
  47. package/dist/cli/show-changes.js.map +1 -0
  48. package/dist/github/client.d.ts +199 -4
  49. package/dist/github/client.d.ts.map +1 -1
  50. package/dist/github/client.js +37 -2
  51. package/dist/github/client.js.map +1 -1
  52. package/dist/github/client.test.d.ts +2 -0
  53. package/dist/github/client.test.d.ts.map +1 -0
  54. package/dist/github/client.test.js +206 -0
  55. package/dist/github/client.test.js.map +1 -0
  56. package/dist/github/platform-adapter.d.ts +31 -0
  57. package/dist/github/platform-adapter.d.ts.map +1 -0
  58. package/dist/github/platform-adapter.js +129 -0
  59. package/dist/github/platform-adapter.js.map +1 -0
  60. package/dist/github/platform-adapter.test.d.ts +2 -0
  61. package/dist/github/platform-adapter.test.d.ts.map +1 -0
  62. package/dist/github/platform-adapter.test.js +40 -0
  63. package/dist/github/platform-adapter.test.js.map +1 -0
  64. package/dist/gitlab/client.d.ts +12 -0
  65. package/dist/gitlab/client.d.ts.map +1 -1
  66. package/dist/gitlab/client.js +19 -1
  67. package/dist/gitlab/client.js.map +1 -1
  68. package/dist/gitlab/diff-parser.test.d.ts +2 -0
  69. package/dist/gitlab/diff-parser.test.d.ts.map +1 -0
  70. package/dist/gitlab/diff-parser.test.js +315 -0
  71. package/dist/gitlab/diff-parser.test.js.map +1 -0
  72. package/dist/gitlab/platform-adapter.d.ts +27 -0
  73. package/dist/gitlab/platform-adapter.d.ts.map +1 -0
  74. package/dist/gitlab/platform-adapter.js +121 -0
  75. package/dist/gitlab/platform-adapter.js.map +1 -0
  76. package/dist/gitlab/platform-adapter.test.d.ts +2 -0
  77. package/dist/gitlab/platform-adapter.test.d.ts.map +1 -0
  78. package/dist/gitlab/platform-adapter.test.js +21 -0
  79. package/dist/gitlab/platform-adapter.test.js.map +1 -0
  80. package/dist/index.test.d.ts +2 -0
  81. package/dist/index.test.d.ts.map +1 -0
  82. package/dist/index.test.js +7 -0
  83. package/dist/index.test.js.map +1 -0
  84. package/dist/lib/change-summary.d.ts +8 -0
  85. package/dist/lib/change-summary.d.ts.map +1 -0
  86. package/dist/lib/change-summary.js +2 -0
  87. package/dist/lib/change-summary.js.map +1 -0
  88. package/dist/lib/code-quality-report.d.ts +44 -0
  89. package/dist/lib/code-quality-report.d.ts.map +1 -0
  90. package/dist/lib/code-quality-report.js +62 -0
  91. package/dist/lib/code-quality-report.js.map +1 -0
  92. package/dist/lib/code-quality-report.test.d.ts +2 -0
  93. package/dist/lib/code-quality-report.test.d.ts.map +1 -0
  94. package/dist/lib/code-quality-report.test.js +327 -0
  95. package/dist/lib/code-quality-report.test.js.map +1 -0
  96. package/dist/{gitlab → lib}/comment-formatter.d.ts +6 -3
  97. package/dist/lib/comment-formatter.d.ts.map +1 -0
  98. package/dist/{gitlab → lib}/comment-formatter.js +63 -16
  99. package/dist/lib/comment-formatter.js.map +1 -0
  100. package/dist/lib/comment-formatter.test.d.ts +2 -0
  101. package/dist/lib/comment-formatter.test.d.ts.map +1 -0
  102. package/dist/lib/comment-formatter.test.js +607 -0
  103. package/dist/lib/comment-formatter.test.js.map +1 -0
  104. package/dist/lib/comment-manager.d.ts +61 -0
  105. package/dist/lib/comment-manager.d.ts.map +1 -0
  106. package/dist/lib/comment-manager.js +91 -0
  107. package/dist/lib/comment-manager.js.map +1 -0
  108. package/dist/lib/comment-manager.test.d.ts +2 -0
  109. package/dist/lib/comment-manager.test.d.ts.map +1 -0
  110. package/dist/lib/comment-manager.test.js +618 -0
  111. package/dist/lib/comment-manager.test.js.map +1 -0
  112. package/dist/lib/comment-poster.d.ts +21 -0
  113. package/dist/lib/comment-poster.d.ts.map +1 -0
  114. package/dist/lib/comment-poster.js +96 -0
  115. package/dist/lib/comment-poster.js.map +1 -0
  116. package/dist/lib/comment-poster.test.d.ts +5 -0
  117. package/dist/lib/comment-poster.test.d.ts.map +1 -0
  118. package/dist/lib/comment-poster.test.js +215 -0
  119. package/dist/lib/comment-poster.test.js.map +1 -0
  120. package/dist/lib/config-model-overrides.test.d.ts +12 -0
  121. package/dist/lib/config-model-overrides.test.d.ts.map +1 -0
  122. package/dist/lib/config-model-overrides.test.js +254 -0
  123. package/dist/lib/config-model-overrides.test.js.map +1 -0
  124. package/dist/lib/config.d.ts +93 -8
  125. package/dist/lib/config.d.ts.map +1 -1
  126. package/dist/lib/config.js +178 -25
  127. package/dist/lib/config.js.map +1 -1
  128. package/dist/lib/config.test.d.ts +2 -0
  129. package/dist/lib/config.test.d.ts.map +1 -0
  130. package/dist/lib/config.test.js +36 -0
  131. package/dist/lib/config.test.js.map +1 -0
  132. package/dist/lib/context-compression.d.ts +19 -0
  133. package/dist/lib/context-compression.d.ts.map +1 -0
  134. package/dist/lib/context-compression.js +170 -0
  135. package/dist/lib/context-compression.js.map +1 -0
  136. package/dist/lib/context-compression.test.d.ts +2 -0
  137. package/dist/lib/context-compression.test.d.ts.map +1 -0
  138. package/dist/lib/context-compression.test.js +33 -0
  139. package/dist/lib/context-compression.test.js.map +1 -0
  140. package/dist/lib/context-loader.d.ts +29 -0
  141. package/dist/lib/context-loader.d.ts.map +1 -0
  142. package/dist/lib/context-loader.js +75 -0
  143. package/dist/lib/context-loader.js.map +1 -0
  144. package/dist/lib/context-loader.test.d.ts +2 -0
  145. package/dist/lib/context-loader.test.d.ts.map +1 -0
  146. package/dist/lib/context-loader.test.js +207 -0
  147. package/dist/lib/context-loader.test.js.map +1 -0
  148. package/dist/lib/describe-core.d.ts +9 -0
  149. package/dist/lib/describe-core.d.ts.map +1 -0
  150. package/dist/lib/describe-core.js +71 -0
  151. package/dist/lib/describe-core.js.map +1 -0
  152. package/dist/lib/describe-core.test.d.ts +2 -0
  153. package/dist/lib/describe-core.test.d.ts.map +1 -0
  154. package/dist/lib/describe-core.test.js +208 -0
  155. package/dist/lib/describe-core.test.js.map +1 -0
  156. package/dist/lib/describe-output-path.test.d.ts +2 -0
  157. package/dist/lib/describe-output-path.test.d.ts.map +1 -0
  158. package/dist/lib/describe-output-path.test.js +51 -0
  159. package/dist/lib/describe-output-path.test.js.map +1 -0
  160. package/dist/lib/describe-parser.d.ts +3 -0
  161. package/dist/lib/describe-parser.d.ts.map +1 -0
  162. package/dist/lib/describe-parser.js +163 -0
  163. package/dist/lib/describe-parser.js.map +1 -0
  164. package/dist/lib/describe-parser.test.d.ts +2 -0
  165. package/dist/lib/describe-parser.test.d.ts.map +1 -0
  166. package/dist/lib/describe-parser.test.js +282 -0
  167. package/dist/lib/describe-parser.test.js.map +1 -0
  168. package/dist/lib/description-executor.d.ts +22 -0
  169. package/dist/lib/description-executor.d.ts.map +1 -0
  170. package/dist/lib/description-executor.js +72 -0
  171. package/dist/lib/description-executor.js.map +1 -0
  172. package/dist/lib/description-formatter.d.ts +37 -0
  173. package/dist/lib/description-formatter.d.ts.map +1 -0
  174. package/dist/lib/description-formatter.js +219 -0
  175. package/dist/lib/description-formatter.js.map +1 -0
  176. package/dist/{gitlab → lib}/diff-parser.d.ts +11 -0
  177. package/dist/lib/diff-parser.d.ts.map +1 -0
  178. package/dist/{gitlab → lib}/diff-parser.js +40 -3
  179. package/dist/lib/diff-parser.js.map +1 -0
  180. package/dist/lib/issue-parser.d.ts +29 -0
  181. package/dist/lib/issue-parser.d.ts.map +1 -0
  182. package/dist/lib/issue-parser.js +153 -0
  183. package/dist/lib/issue-parser.js.map +1 -0
  184. package/dist/lib/issue-parser.test.d.ts +2 -0
  185. package/dist/lib/issue-parser.test.d.ts.map +1 -0
  186. package/dist/lib/issue-parser.test.js +281 -0
  187. package/dist/lib/issue-parser.test.js.map +1 -0
  188. package/dist/lib/json-output-schema.d.ts +207 -0
  189. package/dist/lib/json-output-schema.d.ts.map +1 -0
  190. package/dist/lib/json-output-schema.js +124 -0
  191. package/dist/lib/json-output-schema.js.map +1 -0
  192. package/dist/lib/json-output-schema.test.d.ts +2 -0
  193. package/dist/lib/json-output-schema.test.d.ts.map +1 -0
  194. package/dist/lib/json-output-schema.test.js +92 -0
  195. package/dist/lib/json-output-schema.test.js.map +1 -0
  196. package/dist/lib/json-output.d.ts +43 -0
  197. package/dist/lib/json-output.d.ts.map +1 -0
  198. package/dist/lib/json-output.js +34 -0
  199. package/dist/lib/json-output.js.map +1 -0
  200. package/dist/lib/output-paths.d.ts +6 -0
  201. package/dist/lib/output-paths.d.ts.map +1 -0
  202. package/dist/lib/output-paths.js +5 -0
  203. package/dist/lib/output-paths.js.map +1 -0
  204. package/dist/lib/platform-client.d.ts +130 -0
  205. package/dist/lib/platform-client.d.ts.map +1 -0
  206. package/dist/lib/platform-client.js +8 -0
  207. package/dist/lib/platform-client.js.map +1 -0
  208. package/dist/lib/position-validator.d.ts +36 -0
  209. package/dist/lib/position-validator.d.ts.map +1 -0
  210. package/dist/lib/position-validator.js +43 -0
  211. package/dist/lib/position-validator.js.map +1 -0
  212. package/dist/lib/repository-validator.d.ts +52 -0
  213. package/dist/lib/repository-validator.d.ts.map +1 -0
  214. package/dist/lib/repository-validator.js +219 -0
  215. package/dist/lib/repository-validator.js.map +1 -0
  216. package/dist/lib/repository-validator.test.d.ts +5 -0
  217. package/dist/lib/repository-validator.test.d.ts.map +1 -0
  218. package/dist/lib/repository-validator.test.js +341 -0
  219. package/dist/lib/repository-validator.test.js.map +1 -0
  220. package/dist/lib/review-core.d.ts +66 -0
  221. package/dist/lib/review-core.d.ts.map +1 -0
  222. package/dist/lib/review-core.js +449 -0
  223. package/dist/lib/review-core.js.map +1 -0
  224. package/dist/lib/review-core.test.d.ts +2 -0
  225. package/dist/lib/review-core.test.d.ts.map +1 -0
  226. package/dist/lib/review-core.test.js +552 -0
  227. package/dist/lib/review-core.test.js.map +1 -0
  228. package/dist/lib/review-orchestrator.d.ts +77 -0
  229. package/dist/lib/review-orchestrator.d.ts.map +1 -0
  230. package/dist/lib/review-orchestrator.js +124 -0
  231. package/dist/lib/review-orchestrator.js.map +1 -0
  232. package/dist/lib/review-orchestrator.test.d.ts +2 -0
  233. package/dist/lib/review-orchestrator.test.d.ts.map +1 -0
  234. package/dist/lib/review-orchestrator.test.js +413 -0
  235. package/dist/lib/review-orchestrator.test.js.map +1 -0
  236. package/dist/lib/review-output-path.test.d.ts +2 -0
  237. package/dist/lib/review-output-path.test.d.ts.map +1 -0
  238. package/dist/lib/review-output-path.test.js +83 -0
  239. package/dist/lib/review-output-path.test.js.map +1 -0
  240. package/dist/lib/review-parser.d.ts +2 -0
  241. package/dist/lib/review-parser.d.ts.map +1 -0
  242. package/dist/lib/review-parser.js +100 -0
  243. package/dist/lib/review-parser.js.map +1 -0
  244. package/dist/lib/unified-review-executor.d.ts +49 -0
  245. package/dist/lib/unified-review-executor.d.ts.map +1 -0
  246. package/dist/lib/unified-review-executor.js +158 -0
  247. package/dist/lib/unified-review-executor.js.map +1 -0
  248. package/dist/lib/unified-review-executor.test.d.ts +5 -0
  249. package/dist/lib/unified-review-executor.test.d.ts.map +1 -0
  250. package/dist/lib/unified-review-executor.test.js +344 -0
  251. package/dist/lib/unified-review-executor.test.js.map +1 -0
  252. package/dist/lib/write-json-output.d.ts +13 -0
  253. package/dist/lib/write-json-output.d.ts.map +1 -0
  254. package/dist/lib/write-json-output.js +37 -0
  255. package/dist/lib/write-json-output.js.map +1 -0
  256. package/dist/opencode/agent-loader.d.ts +3 -4
  257. package/dist/opencode/agent-loader.d.ts.map +1 -1
  258. package/dist/opencode/agent-loader.js +51 -42
  259. package/dist/opencode/agent-loader.js.map +1 -1
  260. package/dist/opencode/agent-skill-overlay.d.ts +11 -0
  261. package/dist/opencode/agent-skill-overlay.d.ts.map +1 -0
  262. package/dist/opencode/agent-skill-overlay.js +164 -0
  263. package/dist/opencode/agent-skill-overlay.js.map +1 -0
  264. package/dist/opencode/client.d.ts +14 -5
  265. package/dist/opencode/client.d.ts.map +1 -1
  266. package/dist/opencode/client.js +311 -32
  267. package/dist/opencode/client.js.map +1 -1
  268. package/dist/opencode/client.test.d.ts +2 -0
  269. package/dist/opencode/client.test.d.ts.map +1 -0
  270. package/dist/opencode/client.test.js +317 -0
  271. package/dist/opencode/client.test.js.map +1 -0
  272. package/dist/opencode/opencode-paths.d.ts +2 -0
  273. package/dist/opencode/opencode-paths.d.ts.map +1 -0
  274. package/dist/opencode/opencode-paths.js +7 -0
  275. package/dist/opencode/opencode-paths.js.map +1 -0
  276. package/dist/opencode/skill-loader.d.ts +6 -0
  277. package/dist/opencode/skill-loader.d.ts.map +1 -0
  278. package/dist/opencode/skill-loader.js +36 -0
  279. package/dist/opencode/skill-loader.js.map +1 -0
  280. package/package.json +29 -20
  281. package/.opencode/agent/github-reviewer.md +0 -62
  282. package/.opencode/agent/gitlab-reviewer.md +0 -62
  283. package/.opencode/agent/local-reviewer.md +0 -71
  284. package/dist/gitlab/comment-formatter.d.ts.map +0 -1
  285. package/dist/gitlab/comment-formatter.js.map +0 -1
  286. package/dist/gitlab/diff-parser.d.ts.map +0 -1
  287. package/dist/gitlab/diff-parser.js.map +0 -1
@@ -0,0 +1,282 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import { parseJsonFromAgentOutput, parseDescribeOutput } from './describe-parser.js';
3
+ import { mkdir, writeFile, rm } from 'fs/promises';
4
+ import { join } from 'path';
5
+ import { tmpdir } from 'os';
6
+ describe('describe-parser', () => {
7
+ describe('parseJsonFromAgentOutput', () => {
8
+ it('should parse JSON from code fence', () => {
9
+ const raw = '```json\n{"type": "feature", "title": "Test"}\n```';
10
+ const result = parseJsonFromAgentOutput(raw);
11
+ expect(result).toEqual({ type: 'feature', title: 'Test' });
12
+ });
13
+ it('should parse JSON from code fence with extra whitespace', () => {
14
+ const raw = '```json\n\n {"type": "feature", "title": "Test"} \n\n```';
15
+ const result = parseJsonFromAgentOutput(raw);
16
+ expect(result).toEqual({ type: 'feature', title: 'Test' });
17
+ });
18
+ it('should parse JSON from code fence with case-insensitive marker', () => {
19
+ const raw = '```JSON\n{"type": "feature", "title": "Test"}\n```';
20
+ const result = parseJsonFromAgentOutput(raw);
21
+ expect(result).toEqual({ type: 'feature', title: 'Test' });
22
+ });
23
+ it('should parse embedded JSON from mixed text', () => {
24
+ const raw = 'Here is the output: {"outputType":"describe_output","outputPath":".drs/describe-output.json"} Done!';
25
+ const result = parseJsonFromAgentOutput(raw);
26
+ expect(result).toEqual({
27
+ outputType: 'describe_output',
28
+ outputPath: '.drs/describe-output.json',
29
+ });
30
+ });
31
+ it('should parse pure JSON string', () => {
32
+ const raw = '{"type": "feature", "title": "Test"}';
33
+ const result = parseJsonFromAgentOutput(raw);
34
+ expect(result).toEqual({ type: 'feature', title: 'Test' });
35
+ });
36
+ it('should handle nested JSON objects', () => {
37
+ const raw = `{"type": "feature", "title": "Test"}`;
38
+ const result = parseJsonFromAgentOutput(raw);
39
+ expect(result).toEqual({
40
+ type: 'feature',
41
+ title: 'Test',
42
+ });
43
+ });
44
+ it('should handle JSON with arrays', () => {
45
+ const raw = '{"items": [1, 2, 3]}';
46
+ const result = parseJsonFromAgentOutput(raw);
47
+ expect(result).toEqual({
48
+ items: [1, 2, 3],
49
+ });
50
+ });
51
+ it('should handle JSON with escaped quotes', () => {
52
+ const raw = '{"message": "This is a \\"quoted\\" string"}';
53
+ const result = parseJsonFromAgentOutput(raw);
54
+ expect(result).toEqual({
55
+ message: 'This is a "quoted" string',
56
+ });
57
+ });
58
+ it('should prefer last JSON candidate when multiple exist', () => {
59
+ const raw = 'First: {"id": 1} Second: {"id": 2}';
60
+ const result = parseJsonFromAgentOutput(raw);
61
+ // Should return the last valid JSON found
62
+ expect(result).toEqual({ id: 2 });
63
+ });
64
+ it('should prefer code fence over embedded JSON', () => {
65
+ const raw = `
66
+ {"id": 1}
67
+ \`\`\`json
68
+ {"id": 2}
69
+ \`\`\`
70
+ `;
71
+ const result = parseJsonFromAgentOutput(raw);
72
+ expect(result).toEqual({ id: 2 });
73
+ });
74
+ it('should throw error for invalid JSON', () => {
75
+ const raw = 'This is not JSON at all';
76
+ expect(() => parseJsonFromAgentOutput(raw)).toThrow();
77
+ });
78
+ it('should throw error for incomplete JSON', () => {
79
+ const raw = '{"type": "feature", "title":';
80
+ expect(() => parseJsonFromAgentOutput(raw)).toThrow();
81
+ });
82
+ it('should handle empty string', () => {
83
+ const raw = '';
84
+ expect(() => parseJsonFromAgentOutput(raw)).toThrow();
85
+ });
86
+ it('should handle JSON with null values', () => {
87
+ const raw = '{"value": null, "name": "test"}';
88
+ const result = parseJsonFromAgentOutput(raw);
89
+ expect(result).toEqual({ value: null, name: 'test' });
90
+ });
91
+ it('should handle JSON with boolean values', () => {
92
+ const raw = '{"enabled": true, "disabled": false}';
93
+ const result = parseJsonFromAgentOutput(raw);
94
+ expect(result).toEqual({ enabled: true, disabled: false });
95
+ });
96
+ it('should handle JSON with numbers', () => {
97
+ const raw = '{"integer": 42, "float": 3.14, "negative": -10}';
98
+ const result = parseJsonFromAgentOutput(raw);
99
+ expect(result).toEqual({ integer: 42, float: 3.14, negative: -10 });
100
+ });
101
+ it('should handle markdown text with embedded JSON', () => {
102
+ const raw = `
103
+ # Title
104
+
105
+ Here is some explanation text.
106
+
107
+ {"outputType":"describe_output","outputPath":".drs/output.json"}
108
+
109
+ More text after.
110
+ `;
111
+ const result = parseJsonFromAgentOutput(raw);
112
+ expect(result).toEqual({
113
+ outputType: 'describe_output',
114
+ outputPath: '.drs/output.json',
115
+ });
116
+ });
117
+ it('should handle JSON with escaped characters', () => {
118
+ const raw = '{"pattern": "function() with \\"quotes\\""}';
119
+ const result = parseJsonFromAgentOutput(raw);
120
+ expect(result).toEqual({
121
+ pattern: 'function() with "quotes"',
122
+ });
123
+ });
124
+ });
125
+ describe('parseDescribeOutput', () => {
126
+ let testDir;
127
+ beforeEach(async () => {
128
+ // Create a unique temporary directory for each test
129
+ testDir = join(tmpdir(), `drs-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
130
+ await mkdir(testDir, { recursive: true });
131
+ await mkdir(join(testDir, '.drs'), { recursive: true });
132
+ });
133
+ afterEach(async () => {
134
+ // Clean up test directory
135
+ try {
136
+ await rm(testDir, { recursive: true, force: true });
137
+ }
138
+ catch {
139
+ // Ignore cleanup errors
140
+ }
141
+ });
142
+ it('should read describe output from default path', async () => {
143
+ const describeData = {
144
+ type: 'feature',
145
+ title: 'Add new feature',
146
+ summary: ['Added authentication', 'Updated database schema'],
147
+ };
148
+ await writeFile(join(testDir, '.drs/describe-output.json'), JSON.stringify(describeData));
149
+ const result = await parseDescribeOutput(testDir, false);
150
+ expect(result).toEqual(describeData);
151
+ });
152
+ it('should read describe output from pointer path', async () => {
153
+ const describeData = {
154
+ type: 'bugfix',
155
+ title: 'Fix authentication bug',
156
+ summary: ['Fixed login issue'],
157
+ };
158
+ await writeFile(join(testDir, '.drs/custom-output.json'), JSON.stringify(describeData));
159
+ const rawOutput = JSON.stringify({
160
+ outputType: 'describe_output',
161
+ outputPath: '.drs/custom-output.json',
162
+ });
163
+ const result = await parseDescribeOutput(testDir, false, rawOutput);
164
+ expect(result).toEqual(describeData);
165
+ });
166
+ it('should fall back to default path if pointer path not found', async () => {
167
+ const describeData = {
168
+ type: 'refactor',
169
+ title: 'Refactor code',
170
+ summary: ['Improved code quality'],
171
+ };
172
+ await writeFile(join(testDir, '.drs/describe-output.json'), JSON.stringify(describeData));
173
+ const rawOutput = JSON.stringify({
174
+ outputType: 'describe_output',
175
+ outputPath: '.drs/nonexistent.json',
176
+ });
177
+ const result = await parseDescribeOutput(testDir, false, rawOutput);
178
+ expect(result).toEqual(describeData);
179
+ });
180
+ it('should throw error if no describe output found', async () => {
181
+ await expect(parseDescribeOutput(testDir, false)).rejects.toThrow('Describe output file not found');
182
+ });
183
+ it('should throw error for invalid output type in pointer', async () => {
184
+ const rawOutput = JSON.stringify({
185
+ outputType: 'invalid_type',
186
+ outputPath: '.drs/output.json',
187
+ });
188
+ await expect(parseDescribeOutput(testDir, false, rawOutput)).rejects.toThrow('Unexpected output type for describe output: invalid_type');
189
+ });
190
+ it('should handle pointer with only outputType field', async () => {
191
+ const describeData = {
192
+ type: 'docs',
193
+ title: 'Update documentation',
194
+ };
195
+ await writeFile(join(testDir, '.drs/describe-output.json'), JSON.stringify(describeData));
196
+ const rawOutput = JSON.stringify({
197
+ outputType: 'describe_output',
198
+ });
199
+ const result = await parseDescribeOutput(testDir, false, rawOutput);
200
+ expect(result).toEqual(describeData);
201
+ });
202
+ it('should log debug messages when debug=true', async () => {
203
+ const logSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
204
+ const describeData = { type: 'test' };
205
+ await writeFile(join(testDir, '.drs/describe-output.json'), JSON.stringify(describeData));
206
+ await parseDescribeOutput(testDir, true);
207
+ expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('Describe output loaded from'));
208
+ logSpy.mockRestore();
209
+ });
210
+ it('should not log debug messages when debug=false', async () => {
211
+ const logSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
212
+ const describeData = { type: 'test' };
213
+ await writeFile(join(testDir, '.drs/describe-output.json'), JSON.stringify(describeData));
214
+ await parseDescribeOutput(testDir, false);
215
+ expect(logSpy).not.toHaveBeenCalled();
216
+ logSpy.mockRestore();
217
+ });
218
+ it('should refuse to read outside working directory', async () => {
219
+ const rawOutput = JSON.stringify({
220
+ outputType: 'describe_output',
221
+ outputPath: '../../../etc/passwd',
222
+ });
223
+ await expect(parseDescribeOutput(testDir, false, rawOutput)).rejects.toThrow('Refusing to read outside working directory');
224
+ });
225
+ it('should handle absolute paths within working directory', async () => {
226
+ const describeData = { type: 'feature' };
227
+ const outputPath = join(testDir, '.drs/describe-output.json');
228
+ await writeFile(outputPath, JSON.stringify(describeData));
229
+ const rawOutput = JSON.stringify({
230
+ outputType: 'describe_output',
231
+ outputPath: outputPath,
232
+ });
233
+ const result = await parseDescribeOutput(testDir, false, rawOutput);
234
+ expect(result).toEqual(describeData);
235
+ });
236
+ it('should handle invalid JSON in describe output file', async () => {
237
+ await writeFile(join(testDir, '.drs/describe-output.json'), 'not valid json');
238
+ await expect(parseDescribeOutput(testDir, false)).rejects.toThrow();
239
+ });
240
+ it('should use process.cwd() as default working directory', async () => {
241
+ // This test verifies the default parameter works
242
+ // We can't easily test the actual cwd behavior in isolation
243
+ const rawOutput = 'invalid pointer';
244
+ // Should attempt to use cwd and likely fail (unless file exists there)
245
+ await expect(parseDescribeOutput(undefined, false, rawOutput)).rejects.toThrow();
246
+ });
247
+ it('should handle pointer with invalid JSON format', async () => {
248
+ const logSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
249
+ const describeData = { type: 'test' };
250
+ await writeFile(join(testDir, '.drs/describe-output.json'), JSON.stringify(describeData));
251
+ const rawOutput = 'not valid json at all';
252
+ // Should fall back to default path since pointer parsing fails
253
+ const result = await parseDescribeOutput(testDir, true, rawOutput);
254
+ expect(result).toEqual(describeData);
255
+ expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('Describe output pointer parse failed'));
256
+ logSpy.mockRestore();
257
+ });
258
+ it('should handle complex describe output structure', async () => {
259
+ const describeData = {
260
+ type: 'feature',
261
+ title: 'Complex feature',
262
+ summary: ['Point 1', 'Point 2', 'Point 3'],
263
+ walkthrough: [
264
+ {
265
+ file: 'src/app.ts',
266
+ changeType: 'modified',
267
+ semanticLabel: 'feature',
268
+ title: 'Added new function',
269
+ changes: ['Added authentication', 'Updated routes'],
270
+ significance: 'major',
271
+ },
272
+ ],
273
+ labels: ['enhancement', 'security'],
274
+ recommendations: ['Add tests', 'Update docs'],
275
+ };
276
+ await writeFile(join(testDir, '.drs/describe-output.json'), JSON.stringify(describeData));
277
+ const result = await parseDescribeOutput(testDir, false);
278
+ expect(result).toEqual(describeData);
279
+ });
280
+ });
281
+ });
282
+ //# sourceMappingURL=describe-parser.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"describe-parser.test.js","sourceRoot":"","sources":["../../src/lib/describe-parser.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * PR/MR description generation executor
3
+ *
4
+ * This module handles generating descriptions for pull requests and merge requests
5
+ * using the describe agent.
6
+ */
7
+ import type { DRSConfig } from './config.js';
8
+ import type { FileWithDiff } from './review-core.js';
9
+ import type { PlatformClient, PullRequest } from './platform-client.js';
10
+ import { type Description, type Platform } from './description-formatter.js';
11
+ import type { OpencodeClient } from '../opencode/client.js';
12
+ /**
13
+ * Detect platform type from PR/MR platform data
14
+ */
15
+ export declare function detectPlatform(pr: PullRequest): Platform;
16
+ /**
17
+ * Generate and optionally post a PR/MR description
18
+ *
19
+ * @returns The generated description, or null if description generation is disabled
20
+ */
21
+ export declare function runDescribeIfEnabled(opencode: OpencodeClient, config: DRSConfig, platformClient: PlatformClient, projectId: string, pr: PullRequest, files: FileWithDiff[], shouldPostDescription: boolean, workingDir: string, debug?: boolean): Promise<Description | null>;
22
+ //# sourceMappingURL=description-executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"description-executor.d.ts","sourceRoot":"","sources":["../../src/lib/description-executor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,QAAQ,EACd,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,WAAW,GAAG,QAAQ,CAMxD;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,SAAS,EACjB,cAAc,EAAE,cAAc,EAC9B,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,WAAW,EACf,KAAK,EAAE,YAAY,EAAE,EACrB,qBAAqB,EAAE,OAAO,EAC9B,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,OAAO,GACd,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAyD7B"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * PR/MR description generation executor
3
+ *
4
+ * This module handles generating descriptions for pull requests and merge requests
5
+ * using the describe agent.
6
+ */
7
+ import chalk from 'chalk';
8
+ import { buildDescribeInstructions } from './describe-core.js';
9
+ import { compressFilesWithDiffs, formatCompressionSummary } from './context-compression.js';
10
+ import { displayDescription, normalizeDescription, postDescription, } from './description-formatter.js';
11
+ import { parseDescribeOutput } from './describe-parser.js';
12
+ /**
13
+ * Detect platform type from PR/MR platform data
14
+ */
15
+ export function detectPlatform(pr) {
16
+ const platformData = pr.platformData;
17
+ if (platformData && ('iid' in platformData || 'diff_refs' in platformData)) {
18
+ return 'MR';
19
+ }
20
+ return 'PR';
21
+ }
22
+ /**
23
+ * Generate and optionally post a PR/MR description
24
+ *
25
+ * @returns The generated description, or null if description generation is disabled
26
+ */
27
+ export async function runDescribeIfEnabled(opencode, config, platformClient, projectId, pr, files, shouldPostDescription, workingDir, debug) {
28
+ console.log(chalk.bold.blue('\nšŸ” Generating PR/MR Description\n'));
29
+ const label = `${detectPlatform(pr)} #${pr.number}`;
30
+ const compression = compressFilesWithDiffs(files, config.contextCompression);
31
+ const compressionSummary = formatCompressionSummary(compression);
32
+ if (compressionSummary) {
33
+ console.log(chalk.yellow('⚠ Diff content trimmed to fit token budget.\n'));
34
+ }
35
+ const instructions = buildDescribeInstructions(label, compression.files, compressionSummary);
36
+ if (debug) {
37
+ console.log(chalk.yellow('\n=== Describe Agent Instructions ==='));
38
+ console.log(instructions);
39
+ console.log(chalk.yellow('=== End Instructions ===\n'));
40
+ }
41
+ // Run describe agent
42
+ const session = await opencode.createSession({
43
+ agent: 'describe/pr-describer',
44
+ message: instructions,
45
+ });
46
+ let fullResponse = '';
47
+ for await (const message of opencode.streamMessages(session.id)) {
48
+ if (message.role === 'assistant') {
49
+ fullResponse += message.content;
50
+ }
51
+ }
52
+ // Parse agent output
53
+ let descriptionPayload;
54
+ try {
55
+ descriptionPayload = (await parseDescribeOutput(workingDir, debug, fullResponse));
56
+ }
57
+ catch (parseError) {
58
+ console.error(chalk.red('Failed to parse agent output as JSON'));
59
+ console.log(chalk.dim('Agent output:'), fullResponse);
60
+ const reason = parseError instanceof Error ? `: ${parseError.message}` : '';
61
+ throw new Error(`Describe agent did not return valid JSON output${reason}`);
62
+ }
63
+ // Display and optionally post description
64
+ const description = normalizeDescription(descriptionPayload);
65
+ const platform = detectPlatform(pr);
66
+ displayDescription(description, platform);
67
+ if (shouldPostDescription) {
68
+ await postDescription(platformClient, projectId, pr.number, description, platform);
69
+ }
70
+ return description;
71
+ }
72
+ //# sourceMappingURL=description-executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"description-executor.js","sourceRoot":"","sources":["../../src/lib/description-executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { PlatformClient } from './platform-client.js';
2
+ export interface DescriptionWalkthroughEntry {
3
+ file: string;
4
+ changeType: string;
5
+ semanticLabel: string;
6
+ title: string;
7
+ changes?: string[];
8
+ significance?: string;
9
+ }
10
+ export interface Description {
11
+ type: string;
12
+ title: string;
13
+ summary: string[];
14
+ walkthrough?: DescriptionWalkthroughEntry[];
15
+ labels?: string[];
16
+ recommendations?: string[];
17
+ }
18
+ export declare function normalizeDescription(description: unknown): Description;
19
+ export type Platform = 'PR' | 'MR';
20
+ /**
21
+ * Display description to console
22
+ */
23
+ export declare function displayDescription(description: Description, platform?: Platform): void;
24
+ /**
25
+ * Get colored terminal icon for change type
26
+ */
27
+ export declare function getChangeIcon(changeType: string): string;
28
+ /**
29
+ * Get markdown emoji icon for change type
30
+ */
31
+ export declare function getMarkdownChangeIcon(changeType: string): string;
32
+ export declare function formatDescriptionAsMarkdown(description: Description, platform?: Platform): string;
33
+ /**
34
+ * Post description to PR/MR as comment
35
+ */
36
+ export declare function postDescription(platformAdapter: PlatformClient, projectId: string, prNumber: number, description: Description, platform?: Platform): Promise<void>;
37
+ //# sourceMappingURL=description-formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"description-formatter.d.ts","sourceRoot":"","sources":["../../src/lib/description-formatter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,2BAA2B,EAAE,CAAC;IAC5C,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAsBD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,OAAO,GAAG,WAAW,CAwEtE;AAED,MAAM,MAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;AAEnC;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,GAAE,QAAe,QAmDrF;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAaxD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAahE;AAeD,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,WAAW,EACxB,QAAQ,GAAE,QAAe,GACxB,MAAM,CA+CR;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,eAAe,EAAE,cAAc,EAC/B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,WAAW,EACxB,QAAQ,GAAE,QAAe,iBAe1B"}