@haystackeditor/cli 0.9.0 → 0.10.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.
- package/README.md +51 -91
- package/dist/assets/hooks/package.json +2 -2
- package/dist/commands/dismiss.d.ts +17 -0
- package/dist/commands/dismiss.js +201 -0
- package/dist/commands/init.js +25 -28
- package/dist/commands/pr-status.d.ts +16 -0
- package/dist/commands/pr-status.js +188 -0
- package/dist/commands/setup.d.ts +13 -0
- package/dist/commands/setup.js +496 -0
- package/dist/commands/submit.d.ts +1 -0
- package/dist/commands/submit.js +29 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +113 -3
- package/dist/triage/prompts.d.ts +3 -3
- package/dist/triage/prompts.js +46 -16
- package/dist/triage/runner.js +21 -7
- package/dist/utils/pending-state.d.ts +2 -0
- package/package.json +11 -11
package/dist/commands/submit.js
CHANGED
|
@@ -287,6 +287,19 @@ export async function submitCommand(options) {
|
|
|
287
287
|
}
|
|
288
288
|
}
|
|
289
289
|
// -------------------------------------------------------------------------
|
|
290
|
+
// Step 6b: Apply auto-fix label if --auto-fix
|
|
291
|
+
// -------------------------------------------------------------------------
|
|
292
|
+
if (options.autoFix) {
|
|
293
|
+
try {
|
|
294
|
+
await ensureHaystackLabels(remoteInfo.owner, remoteInfo.repo, ['haystack:auto-fix']);
|
|
295
|
+
await addLabelsToIssue(remoteInfo.owner, remoteInfo.repo, prNumber, ['haystack:auto-fix']);
|
|
296
|
+
console.log(chalk.green('✓ Auto-fix enabled for this PR'));
|
|
297
|
+
}
|
|
298
|
+
catch (err) {
|
|
299
|
+
console.log(chalk.yellow(`⚠ Could not set auto-fix label: ${err.message}`));
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
// -------------------------------------------------------------------------
|
|
290
303
|
// Step 7: Request review if --review
|
|
291
304
|
// -------------------------------------------------------------------------
|
|
292
305
|
if (options.review) {
|
|
@@ -318,6 +331,9 @@ export async function submitCommand(options) {
|
|
|
318
331
|
if (autoMergeEnabled) {
|
|
319
332
|
console.log(` ${chalk.dim('Merge:')} ${chalk.green('Auto-merge if safe')}`);
|
|
320
333
|
}
|
|
334
|
+
if (options.autoFix) {
|
|
335
|
+
console.log(` ${chalk.dim('Fix:')} ${chalk.cyan('Auto-fix issues before Feed')}`);
|
|
336
|
+
}
|
|
321
337
|
if (options.review) {
|
|
322
338
|
const reviewer = typeof options.review === 'string' ? options.review : 'needs assignment';
|
|
323
339
|
console.log(` ${chalk.dim('Review:')} ${chalk.yellow(reviewer)}`);
|
|
@@ -388,6 +404,16 @@ export async function submitCommand(options) {
|
|
|
388
404
|
console.log(chalk.dim(` ${verdict.summary}`));
|
|
389
405
|
}
|
|
390
406
|
}
|
|
407
|
+
else if (options.autoFix) {
|
|
408
|
+
// Auto-fix flow: agent fixes straightforward issues in the background.
|
|
409
|
+
// Issues appear in Feed immediately — user can review while agent works.
|
|
410
|
+
console.log(chalk.cyan.bold(' ⚙ Auto-fix triggered\n'));
|
|
411
|
+
console.log(chalk.dim(` ${verdict.summary}\n`));
|
|
412
|
+
console.log(chalk.dim(' Coding agent is fixing straightforward issues in the background.'));
|
|
413
|
+
console.log(chalk.dim(' Issues that need your judgment are in the Feed now.\n'));
|
|
414
|
+
const reviewUrl = `https://haystackeditor.com/review/${remoteInfo.owner}/${remoteInfo.repo}/${prNumber}`;
|
|
415
|
+
console.log(` ${chalk.dim('Feed:')} ${chalk.cyan(reviewUrl)}\n`);
|
|
416
|
+
}
|
|
391
417
|
else {
|
|
392
418
|
console.log(chalk.yellow.bold(' ⚠ Needs your input\n'));
|
|
393
419
|
console.log(chalk.dim(` ${verdict.summary}\n`));
|
|
@@ -397,7 +423,9 @@ export async function submitCommand(options) {
|
|
|
397
423
|
console.log(` ${icon} ${chalk.dim(loc)} ${issue.message}`);
|
|
398
424
|
}
|
|
399
425
|
}
|
|
400
|
-
|
|
426
|
+
if (!options.autoFix || verdict.state === 'good-to-merge') {
|
|
427
|
+
console.log(`\n ${chalk.dim('Review:')} ${chalk.cyan(verdict.reviewUrl)}\n`);
|
|
428
|
+
}
|
|
401
429
|
}
|
|
402
430
|
catch {
|
|
403
431
|
console.log(chalk.yellow('⚠ Analysis complete but could not fetch results.'));
|
package/dist/index.d.ts
CHANGED
|
@@ -7,11 +7,15 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
9
|
* npx @haystackeditor/cli init # Set up .haystack.json
|
|
10
|
+
* npx @haystackeditor/cli setup # Interactive onboarding wizard
|
|
10
11
|
* npx @haystackeditor/cli status # Check configuration
|
|
11
12
|
* npx @haystackeditor/cli login # Authenticate with GitHub
|
|
12
13
|
* npx @haystackeditor/cli submit # Create a PR (auto-merge or review)
|
|
13
14
|
* npx @haystackeditor/cli check-pending # Check analysis status
|
|
14
15
|
* npx @haystackeditor/cli triage 123 # View analysis results for a PR
|
|
16
|
+
* npx @haystackeditor/cli dismiss 123 # Dismiss findings for a PR
|
|
17
|
+
* npx @haystackeditor/cli mark-reviewed 123 # Mark review as not needed
|
|
18
|
+
* npx @haystackeditor/cli pr-status 123 # Show PR status in Haystack pipeline
|
|
15
19
|
* npx @haystackeditor/cli secrets list # List stored secrets
|
|
16
20
|
*/
|
|
17
21
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -7,11 +7,15 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
9
|
* npx @haystackeditor/cli init # Set up .haystack.json
|
|
10
|
+
* npx @haystackeditor/cli setup # Interactive onboarding wizard
|
|
10
11
|
* npx @haystackeditor/cli status # Check configuration
|
|
11
12
|
* npx @haystackeditor/cli login # Authenticate with GitHub
|
|
12
13
|
* npx @haystackeditor/cli submit # Create a PR (auto-merge or review)
|
|
13
14
|
* npx @haystackeditor/cli check-pending # Check analysis status
|
|
14
15
|
* npx @haystackeditor/cli triage 123 # View analysis results for a PR
|
|
16
|
+
* npx @haystackeditor/cli dismiss 123 # Dismiss findings for a PR
|
|
17
|
+
* npx @haystackeditor/cli mark-reviewed 123 # Mark review as not needed
|
|
18
|
+
* npx @haystackeditor/cli pr-status 123 # Show PR status in Haystack pipeline
|
|
15
19
|
* npx @haystackeditor/cli secrets list # List stored secrets
|
|
16
20
|
*/
|
|
17
21
|
import { Command } from 'commander';
|
|
@@ -27,6 +31,9 @@ import { checkPendingCommand } from './commands/check-pending.js';
|
|
|
27
31
|
import { installSessionHooks, sessionHooksStatus } from './commands/install-session-hooks.js';
|
|
28
32
|
import { listPolicies, addPolicy, removePolicy, initPolicies, addInstruction } from './commands/policy.js';
|
|
29
33
|
import { triageCommand } from './commands/triage.js';
|
|
34
|
+
import { dismissCommand, markReviewedCommand, undismissCommand } from './commands/dismiss.js';
|
|
35
|
+
import { prStatusCommand } from './commands/pr-status.js';
|
|
36
|
+
import { setupCommand } from './commands/setup.js';
|
|
30
37
|
const program = new Command();
|
|
31
38
|
program
|
|
32
39
|
.name('haystack')
|
|
@@ -42,10 +49,29 @@ This creates a .haystack.json file with auto-detected settings:
|
|
|
42
49
|
• Services (for monorepos)
|
|
43
50
|
• Auth bypass for sandbox environments
|
|
44
51
|
|
|
45
|
-
After running, use
|
|
46
|
-
|
|
52
|
+
After running, use \`haystack setup\` to scan your repos for rules,
|
|
53
|
+
CI signals, and review policies.
|
|
47
54
|
`)
|
|
48
55
|
.action(initCommand);
|
|
56
|
+
program
|
|
57
|
+
.command('setup')
|
|
58
|
+
.description('Interactive onboarding wizard — scan repos for rules, signals, and policies')
|
|
59
|
+
.addHelpText('after', `
|
|
60
|
+
This walks you through Haystack setup step by step:
|
|
61
|
+
|
|
62
|
+
1. Select GitHub repositories to configure
|
|
63
|
+
2. Scan for coding rules (conventions your team follows)
|
|
64
|
+
3. Scan for CI/bot signals (checks to wait for before merging)
|
|
65
|
+
4. Scan for review policies (who should review what)
|
|
66
|
+
5. Review and toggle discovered items
|
|
67
|
+
6. Write .haystack.json to your repos
|
|
68
|
+
|
|
69
|
+
Requires authentication — run \`haystack login\` first.
|
|
70
|
+
|
|
71
|
+
Examples:
|
|
72
|
+
haystack setup
|
|
73
|
+
`)
|
|
74
|
+
.action(setupCommand);
|
|
49
75
|
program
|
|
50
76
|
.command('status')
|
|
51
77
|
.description('Check if .haystack.json exists and is valid')
|
|
@@ -68,6 +94,7 @@ program
|
|
|
68
94
|
.option('--draft', 'Create as draft PR')
|
|
69
95
|
.option('--review [reviewer]', 'Request human review (BLOCKS auto-merge — only use when explicitly asked)')
|
|
70
96
|
.option('--force', 'Skip pre-PR triage checks')
|
|
97
|
+
.option('--auto-fix', 'Auto-fix analysis issues in a sandbox before surfacing to Feed')
|
|
71
98
|
.option('--no-wait', 'Skip waiting for analysis results')
|
|
72
99
|
.addHelpText('after', `
|
|
73
100
|
This command is designed for AI coding agents to submit PRs.
|
|
@@ -85,6 +112,7 @@ Pre-PR Triage:
|
|
|
85
112
|
|
|
86
113
|
Use --force to skip triage entirely.
|
|
87
114
|
Use --no-wait to skip waiting for analysis results.
|
|
115
|
+
Use --auto-fix to auto-fix analysis issues before surfacing to Feed.
|
|
88
116
|
|
|
89
117
|
Review Routing:
|
|
90
118
|
By default, PRs enter the auto-merge queue and merge automatically once
|
|
@@ -99,7 +127,8 @@ Review Routing:
|
|
|
99
127
|
• --review <username> Same label, plus requests review from that GitHub user
|
|
100
128
|
|
|
101
129
|
Examples:
|
|
102
|
-
haystack submit
|
|
130
|
+
haystack submit --auto-fix # Recommended: triage, create PR, auto-fix issues
|
|
131
|
+
haystack submit # Triage, create PR, auto-merge queue (no auto-fix)
|
|
103
132
|
haystack submit --force # Skip triage
|
|
104
133
|
haystack submit --no-wait # Don't wait for analysis
|
|
105
134
|
haystack submit --title "Fix auth" # Custom PR title
|
|
@@ -159,6 +188,87 @@ Examples:
|
|
|
159
188
|
haystack triage 42 --no-wait # Don't wait if pending
|
|
160
189
|
`)
|
|
161
190
|
.action(triageCommand);
|
|
191
|
+
program
|
|
192
|
+
.command('dismiss <pr>')
|
|
193
|
+
.description('Dismiss analysis findings for a PR')
|
|
194
|
+
.addHelpText('after', `
|
|
195
|
+
Dismiss analysis findings for a PR, moving it from "Issues Found" to
|
|
196
|
+
"Good to Merge" in the Haystack feed.
|
|
197
|
+
|
|
198
|
+
The override is tied to the PR's current HEAD commit. If a new commit is
|
|
199
|
+
pushed, the override is invalidated and you'll need to dismiss again.
|
|
200
|
+
|
|
201
|
+
PR identifier formats:
|
|
202
|
+
123 PR number (uses current repo)
|
|
203
|
+
#123 PR number with hash
|
|
204
|
+
owner/repo#123 Fully qualified
|
|
205
|
+
https://github.com/owner/repo/pull/123 GitHub URL
|
|
206
|
+
|
|
207
|
+
Examples:
|
|
208
|
+
haystack dismiss 42 # Dismiss findings for PR #42
|
|
209
|
+
haystack dismiss acme/widgets#99 # Dismiss for specific repo
|
|
210
|
+
`)
|
|
211
|
+
.action(dismissCommand);
|
|
212
|
+
program
|
|
213
|
+
.command('mark-reviewed <pr>')
|
|
214
|
+
.description('Mark human review as not needed for a PR')
|
|
215
|
+
.addHelpText('after', `
|
|
216
|
+
Mark human review as not needed for a PR, moving it from "Needs Review"
|
|
217
|
+
to "Good to Merge" in the Haystack feed.
|
|
218
|
+
|
|
219
|
+
The override is tied to the PR's current HEAD commit. If a new commit is
|
|
220
|
+
pushed, the override is invalidated and you'll need to mark it again.
|
|
221
|
+
|
|
222
|
+
PR identifier formats:
|
|
223
|
+
123 PR number (uses current repo)
|
|
224
|
+
#123 PR number with hash
|
|
225
|
+
owner/repo#123 Fully qualified
|
|
226
|
+
https://github.com/owner/repo/pull/123 GitHub URL
|
|
227
|
+
|
|
228
|
+
Examples:
|
|
229
|
+
haystack mark-reviewed 42 # Mark review not needed for PR #42
|
|
230
|
+
haystack mark-reviewed acme/widgets#99 # Mark for specific repo
|
|
231
|
+
`)
|
|
232
|
+
.action(markReviewedCommand);
|
|
233
|
+
program
|
|
234
|
+
.command('undismiss <pr>')
|
|
235
|
+
.description('Undo a dismiss or mark-reviewed override for a PR')
|
|
236
|
+
.addHelpText('after', `
|
|
237
|
+
Clear all overrides (dismissed findings and/or review-not-needed) for a PR,
|
|
238
|
+
returning it to its original feed bucket.
|
|
239
|
+
|
|
240
|
+
PR identifier formats:
|
|
241
|
+
123 PR number (uses current repo)
|
|
242
|
+
#123 PR number with hash
|
|
243
|
+
owner/repo#123 Fully qualified
|
|
244
|
+
https://github.com/owner/repo/pull/123 GitHub URL
|
|
245
|
+
|
|
246
|
+
Examples:
|
|
247
|
+
haystack undismiss 42 # Undo overrides for PR #42
|
|
248
|
+
haystack undismiss acme/widgets#99 # Undo for specific repo
|
|
249
|
+
`)
|
|
250
|
+
.action(undismissCommand);
|
|
251
|
+
program
|
|
252
|
+
.command('pr-status <pr>')
|
|
253
|
+
.description('Show the current Haystack status of a PR')
|
|
254
|
+
.option('--json', 'Output as JSON')
|
|
255
|
+
.addHelpText('after', `
|
|
256
|
+
Show what bucket a PR is in within the Haystack pipeline:
|
|
257
|
+
analyzing, auto-fixing, good-to-merge, issues, needs-assignment, etc.
|
|
258
|
+
|
|
259
|
+
PR identifier formats:
|
|
260
|
+
123 PR number (uses current repo)
|
|
261
|
+
#123 PR number with hash
|
|
262
|
+
owner/repo#123 Fully qualified
|
|
263
|
+
https://github.com/owner/repo/pull/123 GitHub URL
|
|
264
|
+
|
|
265
|
+
Examples:
|
|
266
|
+
haystack pr-status 42 # Current repo, PR #42
|
|
267
|
+
haystack pr-status acme/widgets#99 # Specific repo
|
|
268
|
+
haystack pr-status https://github.com/o/r/pull/1 # From URL
|
|
269
|
+
haystack pr-status 42 --json # Machine-readable output
|
|
270
|
+
`)
|
|
271
|
+
.action(prStatusCommand);
|
|
162
272
|
// Secrets subcommands
|
|
163
273
|
const secrets = program
|
|
164
274
|
.command('secrets')
|
package/dist/triage/prompts.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* Build the code review prompt.
|
|
12
12
|
* Always runs — looks for objective bugs in the diff.
|
|
13
13
|
*/
|
|
14
|
-
export declare function buildCodeReviewPrompt(baseBranch: string, outputPath: string): string;
|
|
14
|
+
export declare function buildCodeReviewPrompt(baseBranch: string, outputPath: string, precomputedDiff?: string | null): string;
|
|
15
15
|
/**
|
|
16
16
|
* Build the rules validator prompt.
|
|
17
17
|
* Runs if .haystack/pr-rules.yml exists OR agent instruction files are found.
|
|
@@ -21,11 +21,11 @@ export declare function buildCodeReviewPrompt(baseBranch: string, outputPath: st
|
|
|
21
21
|
export declare function buildRulesValidatorPrompt(baseBranch: string, rulesYaml: string, outputPath: string, agentPolicies?: {
|
|
22
22
|
filename: string;
|
|
23
23
|
content: string;
|
|
24
|
-
}[]): string | null;
|
|
24
|
+
}[], precomputedDiff?: string | null): string | null;
|
|
25
25
|
/**
|
|
26
26
|
* Build the intent drift prompt.
|
|
27
27
|
* Only runs if relevant trace files exist.
|
|
28
28
|
*
|
|
29
29
|
* @returns The prompt string, or null if no trace files provided.
|
|
30
30
|
*/
|
|
31
|
-
export declare function buildIntentDriftPrompt(baseBranch: string, traceFiles: string[], outputPath: string): string | null;
|
|
31
|
+
export declare function buildIntentDriftPrompt(baseBranch: string, traceFiles: string[], outputPath: string, precomputedDiff?: string | null): string | null;
|
package/dist/triage/prompts.js
CHANGED
|
@@ -59,15 +59,27 @@ const INTENT_DRIFT_SCHEMA = `{
|
|
|
59
59
|
* Build the code review prompt.
|
|
60
60
|
* Always runs — looks for objective bugs in the diff.
|
|
61
61
|
*/
|
|
62
|
-
export function buildCodeReviewPrompt(baseBranch, outputPath) {
|
|
63
|
-
|
|
62
|
+
export function buildCodeReviewPrompt(baseBranch, outputPath, precomputedDiff) {
|
|
63
|
+
const diffSection = precomputedDiff
|
|
64
|
+
? `## Diff (precomputed)
|
|
65
|
+
|
|
66
|
+
\`\`\`diff
|
|
67
|
+
${precomputedDiff}
|
|
68
|
+
\`\`\`
|
|
64
69
|
|
|
65
70
|
## Instructions
|
|
66
71
|
|
|
67
|
-
1.
|
|
68
|
-
2.
|
|
69
|
-
3.
|
|
70
|
-
|
|
72
|
+
1. Review the diff above.
|
|
73
|
+
2. If you need more context for a specific function, read just that section of the file — do NOT read entire large files.
|
|
74
|
+
3. Identify only REAL BUGS — things that will definitely crash, produce wrong results, or corrupt data.`
|
|
75
|
+
: `## Instructions
|
|
76
|
+
|
|
77
|
+
1. Run \`git diff ${baseBranch}...HEAD\` to see the full diff.
|
|
78
|
+
2. If you need more context for a specific function, read just that section of the file — do NOT read entire large files.
|
|
79
|
+
3. Identify only REAL BUGS — things that will definitely crash, produce wrong results, or corrupt data.`;
|
|
80
|
+
return `You are a pre-PR code reviewer. Your job is to find OBJECTIVE BUGS in the code changes that will cause incorrect runtime behavior.
|
|
81
|
+
|
|
82
|
+
${diffSection}
|
|
71
83
|
|
|
72
84
|
## What to flag
|
|
73
85
|
|
|
@@ -110,7 +122,7 @@ Be extremely conservative. False positives waste the developer's time. Only flag
|
|
|
110
122
|
*
|
|
111
123
|
* @returns The prompt string, or null if no rules content or agent policies provided.
|
|
112
124
|
*/
|
|
113
|
-
export function buildRulesValidatorPrompt(baseBranch, rulesYaml, outputPath, agentPolicies) {
|
|
125
|
+
export function buildRulesValidatorPrompt(baseBranch, rulesYaml, outputPath, agentPolicies, precomputedDiff) {
|
|
114
126
|
const hasRules = rulesYaml.trim().length > 0;
|
|
115
127
|
const hasPolicies = agentPolicies && agentPolicies.length > 0;
|
|
116
128
|
if (!hasRules && !hasPolicies)
|
|
@@ -165,14 +177,26 @@ For each extracted policy violation:
|
|
|
165
177
|
|
|
166
178
|
`;
|
|
167
179
|
}
|
|
168
|
-
|
|
180
|
+
const diffInstructions = precomputedDiff
|
|
181
|
+
? `## Diff (precomputed)
|
|
169
182
|
|
|
170
|
-
|
|
183
|
+
\`\`\`diff
|
|
184
|
+
${precomputedDiff}
|
|
185
|
+
\`\`\`
|
|
171
186
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
187
|
+
## Instructions
|
|
188
|
+
|
|
189
|
+
1. Review the diff above.
|
|
190
|
+
2. Check ONLY the changed code (lines added or modified in the diff), not pre-existing code.
|
|
191
|
+
3. If you need more context, read just the relevant section of the file — do NOT read entire large files.`
|
|
192
|
+
: `## Instructions
|
|
193
|
+
|
|
194
|
+
1. Run \`git diff ${baseBranch}...HEAD\` to see the full diff.
|
|
195
|
+
2. Check ONLY the changed code (lines added or modified in the diff), not pre-existing code.
|
|
196
|
+
3. If you need more context, read just the relevant section of the file — do NOT read entire large files.`;
|
|
197
|
+
return `You are a PR rules validator. Your job is to check the code changes against project rules and policies, then flag violations.
|
|
198
|
+
|
|
199
|
+
${rulesSection}${policiesSection}${diffInstructions}
|
|
176
200
|
|
|
177
201
|
## Important
|
|
178
202
|
|
|
@@ -199,7 +223,7 @@ ${RULES_VALIDATOR_SCHEMA}
|
|
|
199
223
|
*
|
|
200
224
|
* @returns The prompt string, or null if no trace files provided.
|
|
201
225
|
*/
|
|
202
|
-
export function buildIntentDriftPrompt(baseBranch, traceFiles, outputPath) {
|
|
226
|
+
export function buildIntentDriftPrompt(baseBranch, traceFiles, outputPath, precomputedDiff) {
|
|
203
227
|
if (traceFiles.length === 0)
|
|
204
228
|
return null;
|
|
205
229
|
const traceFileList = traceFiles.map(f => `- \`${f}\``).join('\n');
|
|
@@ -218,7 +242,7 @@ ${traceFileList}
|
|
|
218
242
|
- The user's original instruction/prompt (the first message)
|
|
219
243
|
- Any follow-up instructions or corrections from the user
|
|
220
244
|
|
|
221
|
-
3. Run \`git diff ${baseBranch}...HEAD
|
|
245
|
+
3. ${precomputedDiff ? 'Review the diff below' : `Run \`git diff ${baseBranch}...HEAD\``} to see what was actually implemented.
|
|
222
246
|
|
|
223
247
|
4. Compare the user's intent against the actual implementation. Look for:
|
|
224
248
|
|
|
@@ -262,5 +286,11 @@ ${INTENT_DRIFT_SCHEMA}
|
|
|
262
286
|
|
|
263
287
|
- **error**: Core user intent violated — the main thing they asked for is wrong or missing
|
|
264
288
|
- **warning**: Secondary requirement missed or approximated
|
|
265
|
-
- **info**: Minor simplification that mostly still works as intended
|
|
289
|
+
- **info**: Minor simplification that mostly still works as intended${precomputedDiff ? `
|
|
290
|
+
|
|
291
|
+
## Diff (precomputed)
|
|
292
|
+
|
|
293
|
+
\`\`\`diff
|
|
294
|
+
${precomputedDiff}
|
|
295
|
+
\`\`\`` : ''}`;
|
|
266
296
|
}
|
package/dist/triage/runner.js
CHANGED
|
@@ -15,11 +15,11 @@ import { findRelevantTraces } from './traces.js';
|
|
|
15
15
|
// ============================================================================
|
|
16
16
|
const TRIAGE_DIR = '.haystack/triage';
|
|
17
17
|
const TIMEOUT_MS = 300_000; // 5 minutes per checker
|
|
18
|
-
/** Max agentic turns per checker */
|
|
18
|
+
/** Max agentic turns per checker — kept tight since these are read-only tasks */
|
|
19
19
|
const MAX_TURNS = {
|
|
20
|
-
'code-review':
|
|
21
|
-
'rules-validator':
|
|
22
|
-
'intent-drift':
|
|
20
|
+
'code-review': 10,
|
|
21
|
+
'rules-validator': 10,
|
|
22
|
+
'intent-drift': 10,
|
|
23
23
|
};
|
|
24
24
|
// ============================================================================
|
|
25
25
|
// Agent policy file discovery
|
|
@@ -232,13 +232,27 @@ export async function runTriage(gitRoot, baseBranch) {
|
|
|
232
232
|
rmSync(triageDir, { recursive: true });
|
|
233
233
|
}
|
|
234
234
|
mkdirSync(triageDir, { recursive: true });
|
|
235
|
+
// Pre-compute the diff once so sub-agents don't waste turns running git diff.
|
|
236
|
+
// Includes 10 lines of context around each hunk for reviewability.
|
|
237
|
+
let precomputedDiff = null;
|
|
238
|
+
try {
|
|
239
|
+
const diffOutput = execSync(`git diff ${baseBranch}...HEAD -U10`, { cwd: gitRoot, encoding: 'utf-8', maxBuffer: 5 * 1024 * 1024 }).trim();
|
|
240
|
+
// Only inline if the diff is under 100K chars — beyond that, let the agent
|
|
241
|
+
// run git diff itself (it can paginate or review file-by-file).
|
|
242
|
+
if (diffOutput.length > 0 && diffOutput.length <= 100_000) {
|
|
243
|
+
precomputedDiff = diffOutput;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
// git diff failed — agents will run it themselves
|
|
248
|
+
}
|
|
235
249
|
// Build checker configs
|
|
236
250
|
const checkers = [];
|
|
237
251
|
// 1. Code review (always runs)
|
|
238
252
|
const codeReviewOutput = join(triageDir, 'code-review.json');
|
|
239
253
|
checkers.push({
|
|
240
254
|
name: 'code-review',
|
|
241
|
-
prompt: buildCodeReviewPrompt(baseBranch, codeReviewOutput),
|
|
255
|
+
prompt: buildCodeReviewPrompt(baseBranch, codeReviewOutput, precomputedDiff),
|
|
242
256
|
outputFile: codeReviewOutput,
|
|
243
257
|
maxTurns: MAX_TURNS['code-review'],
|
|
244
258
|
});
|
|
@@ -249,7 +263,7 @@ export async function runTriage(gitRoot, baseBranch) {
|
|
|
249
263
|
const agentPolicyFiles = discoverAgentPolicyFiles(gitRoot);
|
|
250
264
|
if (hasRulesYaml || agentPolicyFiles.length > 0) {
|
|
251
265
|
const rulesValidatorOutput = join(triageDir, 'rules-validator.json');
|
|
252
|
-
const rulesPrompt = buildRulesValidatorPrompt(baseBranch, rulesYaml, rulesValidatorOutput, agentPolicyFiles);
|
|
266
|
+
const rulesPrompt = buildRulesValidatorPrompt(baseBranch, rulesYaml, rulesValidatorOutput, agentPolicyFiles, precomputedDiff);
|
|
253
267
|
if (rulesPrompt) {
|
|
254
268
|
checkers.push({
|
|
255
269
|
name: 'rules-validator',
|
|
@@ -263,7 +277,7 @@ export async function runTriage(gitRoot, baseBranch) {
|
|
|
263
277
|
const traceFiles = findRelevantTraces(gitRoot, baseBranch);
|
|
264
278
|
if (traceFiles.length > 0) {
|
|
265
279
|
const intentDriftOutput = join(triageDir, 'intent-drift.json');
|
|
266
|
-
const driftPrompt = buildIntentDriftPrompt(baseBranch, traceFiles, intentDriftOutput);
|
|
280
|
+
const driftPrompt = buildIntentDriftPrompt(baseBranch, traceFiles, intentDriftOutput, precomputedDiff);
|
|
267
281
|
if (driftPrompt) {
|
|
268
282
|
checkers.push({
|
|
269
283
|
name: 'intent-drift',
|
|
@@ -18,6 +18,8 @@ export interface PendingSubmit {
|
|
|
18
18
|
status: 'polling' | 'completed' | 'failed' | 'stale';
|
|
19
19
|
analysisResult?: AnalysisVerdict;
|
|
20
20
|
resolvedAt?: string;
|
|
21
|
+
autoFix?: boolean;
|
|
22
|
+
autoFixStatus?: 'pending' | 'fixing' | 'fixed' | 'failed' | 'timed_out';
|
|
21
23
|
}
|
|
22
24
|
/**
|
|
23
25
|
* Save pending submit state to disk.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haystackeditor/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Set up Haystack verification for your project",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -32,18 +32,18 @@
|
|
|
32
32
|
"url": "https://github.com/haystackeditor/haystack-review/issues"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"chalk": "
|
|
36
|
-
"commander": "
|
|
37
|
-
"fast-glob": "
|
|
38
|
-
"glob": "
|
|
39
|
-
"inquirer": "
|
|
40
|
-
"yaml": "
|
|
41
|
-
"zod": "
|
|
35
|
+
"chalk": "5.6.2",
|
|
36
|
+
"commander": "12.1.0",
|
|
37
|
+
"fast-glob": "3.3.3",
|
|
38
|
+
"glob": "10.5.0",
|
|
39
|
+
"inquirer": "9.3.8",
|
|
40
|
+
"yaml": "2.8.2",
|
|
41
|
+
"zod": "3.25.76"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@types/inquirer": "
|
|
45
|
-
"@types/node": "
|
|
46
|
-
"typescript": "
|
|
44
|
+
"@types/inquirer": "9.0.9",
|
|
45
|
+
"@types/node": "20.19.30",
|
|
46
|
+
"typescript": "5.9.3"
|
|
47
47
|
},
|
|
48
48
|
"files": [
|
|
49
49
|
"dist"
|