@haystackeditor/cli 0.15.10 → 0.15.12
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/dist/commands/mcp.d.ts +1 -0
- package/dist/commands/mcp.js +185 -0
- package/dist/commands/pr.d.ts +10 -0
- package/dist/commands/pr.js +103 -0
- package/dist/commands/rules.d.ts +4 -0
- package/dist/commands/rules.js +98 -0
- package/dist/commands/schema-cmd.d.ts +2 -0
- package/dist/commands/schema-cmd.js +41 -0
- package/dist/commands/setup.js +62 -7
- package/dist/commands/submit.js +32 -4
- package/dist/commands/tokens.d.ts +14 -0
- package/dist/commands/tokens.js +184 -0
- package/dist/commands/triage.js +3 -2
- package/dist/commands/webhooks.d.ts +18 -0
- package/dist/commands/webhooks.js +210 -0
- package/dist/index.js +223 -4
- package/dist/schema.d.ts +21 -0
- package/dist/schema.js +20 -0
- package/dist/triage/runner.js +15 -5
- package/dist/utils/analysis-api.d.ts +12 -5
- package/dist/utils/analysis-api.js +155 -82
- package/dist/utils/auth.d.ts +29 -0
- package/dist/utils/auth.js +70 -2
- package/dist/utils/git.d.ts +36 -0
- package/dist/utils/git.js +113 -2
- package/dist/utils/prompter.js +4 -1
- package/package.json +6 -3
- package/schemas/pr.v1.json +34 -0
- package/schemas/setup.v1.json +21 -0
- package/schemas/triage.v1.json +50 -0
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
import { readFileSync } from 'node:fs';
|
|
23
23
|
import { fileURLToPath } from 'node:url';
|
|
24
24
|
import { dirname, join } from 'node:path';
|
|
25
|
+
import chalk from 'chalk';
|
|
25
26
|
import { Command } from 'commander';
|
|
26
27
|
import { statusCommand } from './commands/status.js';
|
|
27
28
|
import { initCommand } from './commands/init.js';
|
|
@@ -37,6 +38,16 @@ import { dismissCommand, markReviewedCommand, undismissCommand } from './command
|
|
|
37
38
|
import { requestReviewCommand } from './commands/request-review.js';
|
|
38
39
|
import { prStatusCommand } from './commands/pr-status.js';
|
|
39
40
|
import { setupCommand } from './commands/setup.js';
|
|
41
|
+
import { schemaCommand, listSchemas } from './commands/schema-cmd.js';
|
|
42
|
+
import { registerWebhook, listWebhooks, rotateWebhookSecret, setWebhookEnabled, listDeliveries, replayDelivery, } from './commands/webhooks.js';
|
|
43
|
+
import { editRulesCommand, validateRulesCommand } from './commands/rules.js';
|
|
44
|
+
import { headlessLoginCommand, headlessLogoutCommand, listTokensCommand, revokeTokenCommand, } from './commands/tokens.js';
|
|
45
|
+
import { runMcpServer } from './commands/mcp.js';
|
|
46
|
+
// pr-state read helpers (parsePrRef, prReadCommand) are imported by the MCP
|
|
47
|
+
// server directly from ./commands/pr.js; no top-level CLI command is wired
|
|
48
|
+
// here. The previous `pr <ref> [show|merge|snooze|dismiss]` and `fix <ref>`
|
|
49
|
+
// surfaces were scope creep on the CLI-as-platform spec; `haystack pr-status`
|
|
50
|
+
// already covered the read use case.
|
|
40
51
|
/** Read the published version from package.json (dist/index.js → ../package.json)
|
|
41
52
|
* so `haystack --version` can't drift from the package version. Falls back
|
|
42
53
|
* gracefully so the flag never throws if the file can't be read. */
|
|
@@ -58,6 +69,16 @@ program
|
|
|
58
69
|
.name('haystack')
|
|
59
70
|
.description('Haystack CLI — automated PR review, triage, and merge queue')
|
|
60
71
|
.version(getVersion());
|
|
72
|
+
program
|
|
73
|
+
.command('schema [name]')
|
|
74
|
+
.description('Print the JSON Schema for a command\'s --json output (triage, setup, inbox, pr, chat)')
|
|
75
|
+
.action((name) => {
|
|
76
|
+
if (!name) {
|
|
77
|
+
listSchemas();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
schemaCommand(name);
|
|
81
|
+
});
|
|
61
82
|
program
|
|
62
83
|
.command('init')
|
|
63
84
|
.description('Create .haystack.json configuration')
|
|
@@ -122,12 +143,68 @@ program
|
|
|
122
143
|
.action(statusCommand);
|
|
123
144
|
program
|
|
124
145
|
.command('login')
|
|
125
|
-
.description('Add or refresh a saved GitHub account')
|
|
126
|
-
.
|
|
146
|
+
.description('Add or refresh a saved GitHub account (use --headless for CI tokens)')
|
|
147
|
+
.option('--headless', 'Mint a long-lived hsk_live_* token instead of an interactive OAuth session')
|
|
148
|
+
.option('--label <name>', '(--headless) Label to display in the dashboard for this token')
|
|
149
|
+
.option('--scope <repos>', '(--headless) Comma-separated repos to scope the token to (or "all")', (val) => val.split(',').map((s) => s.trim()).filter(Boolean))
|
|
150
|
+
.option('--token <hsk_live_...>', '(--headless) Skip the browser handshake — paste a token minted in the dashboard')
|
|
151
|
+
.action(async (opts) => {
|
|
152
|
+
if (opts.headless) {
|
|
153
|
+
try {
|
|
154
|
+
await headlessLoginCommand({ label: opts.label, scope: opts.scope, token: opts.token });
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
console.error(chalk.red('headless login failed:'), err instanceof Error ? err.message : err);
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
return loginCommand();
|
|
163
|
+
});
|
|
127
164
|
program
|
|
128
165
|
.command('logout [login]')
|
|
129
|
-
.description('Remove a saved GitHub account (
|
|
130
|
-
.
|
|
166
|
+
.description('Remove a saved GitHub account (use --headless to remove the local CLI token)')
|
|
167
|
+
.option('--headless', 'Remove the local hsk_live_* token file (does not revoke server-side — use `haystack tokens revoke <id>`)')
|
|
168
|
+
.action(async (login, opts) => {
|
|
169
|
+
if (opts.headless) {
|
|
170
|
+
try {
|
|
171
|
+
await headlessLogoutCommand();
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
console.error(chalk.red('headless logout failed:'), err instanceof Error ? err.message : err);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
return logoutCommand(login);
|
|
180
|
+
});
|
|
181
|
+
// ─── tokens (server-side hsk_live_*) ─────────────────────────────────────────
|
|
182
|
+
const tokens = program.command('tokens').description('Manage server-side hsk_live_* tokens');
|
|
183
|
+
tokens
|
|
184
|
+
.command('list')
|
|
185
|
+
.description('List your CLI tokens')
|
|
186
|
+
.option('--json', 'Machine-readable output')
|
|
187
|
+
.action(async (opts) => {
|
|
188
|
+
try {
|
|
189
|
+
await listTokensCommand(opts);
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
console.error(chalk.red('list failed:'), err instanceof Error ? err.message : err);
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
tokens
|
|
197
|
+
.command('revoke <id>')
|
|
198
|
+
.description('Revoke a token by id (cannot be undone)')
|
|
199
|
+
.action(async (id) => {
|
|
200
|
+
try {
|
|
201
|
+
await revokeTokenCommand(id);
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
console.error(chalk.red('revoke failed:'), err instanceof Error ? err.message : err);
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
131
208
|
program
|
|
132
209
|
.command('whoami')
|
|
133
210
|
.description('Show the active Haystack GitHub account')
|
|
@@ -606,6 +683,148 @@ The generated policies appear in Haystack's "Human Review Needed"
|
|
|
606
683
|
section when a PR touches matching files.
|
|
607
684
|
`)
|
|
608
685
|
.action(initPolicies);
|
|
686
|
+
// ─── webhooks ────────────────────────────────────────────────────────────────
|
|
687
|
+
//
|
|
688
|
+
// `haystack webhooks ...` — register outbound webhook subscriptions and inspect
|
|
689
|
+
// delivery status. Talks to the haystack-webhooks worker.
|
|
690
|
+
//
|
|
691
|
+
// See docs/SPEC-CLI-FIRST-CLASS.md §1 for the wire protocol (HMAC, retries,
|
|
692
|
+
// idempotency).
|
|
693
|
+
const webhooks = program
|
|
694
|
+
.command('webhooks')
|
|
695
|
+
.description('Manage outbound webhooks (events: triage.completed, fixer.completed, ...)');
|
|
696
|
+
webhooks
|
|
697
|
+
.command('register')
|
|
698
|
+
.description('Register a webhook URL for the current repo and mint a fresh HMAC secret')
|
|
699
|
+
.requiredOption('-u, --url <url>', 'Receiver URL (https only)')
|
|
700
|
+
.option('-e, --events <events>', 'Comma-separated event list', (val) => val.split(',').map((s) => s.trim()).filter(Boolean))
|
|
701
|
+
.option('--secret-env <name>', 'Environment-variable name where you\'ll stash the secret (recorded in .haystack.json)')
|
|
702
|
+
.option('--repo <owner/name>', 'Override the inferred repo')
|
|
703
|
+
.action(async (opts) => {
|
|
704
|
+
try {
|
|
705
|
+
await registerWebhook(opts);
|
|
706
|
+
}
|
|
707
|
+
catch (err) {
|
|
708
|
+
console.error(chalk.red('register failed:'), err instanceof Error ? err.message : err);
|
|
709
|
+
process.exit(1);
|
|
710
|
+
}
|
|
711
|
+
});
|
|
712
|
+
webhooks
|
|
713
|
+
.command('list')
|
|
714
|
+
.description('List active webhook registrations for the current repo')
|
|
715
|
+
.option('--repo <owner/name>', 'Override the inferred repo')
|
|
716
|
+
.option('--json', 'Machine-readable JSON output')
|
|
717
|
+
.action(async (opts) => {
|
|
718
|
+
try {
|
|
719
|
+
await listWebhooks(opts);
|
|
720
|
+
}
|
|
721
|
+
catch (err) {
|
|
722
|
+
console.error(chalk.red('list failed:'), err instanceof Error ? err.message : err);
|
|
723
|
+
process.exit(1);
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
webhooks
|
|
727
|
+
.command('rotate-secret <id>')
|
|
728
|
+
.description('Rotate the HMAC secret for a registration (prints the new secret once)')
|
|
729
|
+
.action(async (id) => {
|
|
730
|
+
try {
|
|
731
|
+
await rotateWebhookSecret(id);
|
|
732
|
+
}
|
|
733
|
+
catch (err) {
|
|
734
|
+
console.error(chalk.red('rotate-secret failed:'), err instanceof Error ? err.message : err);
|
|
735
|
+
process.exit(1);
|
|
736
|
+
}
|
|
737
|
+
});
|
|
738
|
+
webhooks
|
|
739
|
+
.command('disable <id>')
|
|
740
|
+
.description('Disable a registration (stops delivery; existing in-flight retries continue)')
|
|
741
|
+
.action(async (id) => {
|
|
742
|
+
try {
|
|
743
|
+
await setWebhookEnabled(id, false);
|
|
744
|
+
}
|
|
745
|
+
catch (err) {
|
|
746
|
+
console.error(chalk.red('disable failed:'), err instanceof Error ? err.message : err);
|
|
747
|
+
process.exit(1);
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
webhooks
|
|
751
|
+
.command('enable <id>')
|
|
752
|
+
.description('Re-enable a previously disabled registration')
|
|
753
|
+
.action(async (id) => {
|
|
754
|
+
try {
|
|
755
|
+
await setWebhookEnabled(id, true);
|
|
756
|
+
}
|
|
757
|
+
catch (err) {
|
|
758
|
+
console.error(chalk.red('enable failed:'), err instanceof Error ? err.message : err);
|
|
759
|
+
process.exit(1);
|
|
760
|
+
}
|
|
761
|
+
});
|
|
762
|
+
webhooks
|
|
763
|
+
.command('deliveries')
|
|
764
|
+
.description('Show recent webhook delivery attempts for the current repo')
|
|
765
|
+
.option('--repo <owner/name>', 'Override the inferred repo')
|
|
766
|
+
.option('--limit <n>', 'Number of deliveries (default 20)', (v) => parseInt(v, 10))
|
|
767
|
+
.option('--json', 'Machine-readable JSON output')
|
|
768
|
+
.action(async (opts) => {
|
|
769
|
+
try {
|
|
770
|
+
await listDeliveries(opts);
|
|
771
|
+
}
|
|
772
|
+
catch (err) {
|
|
773
|
+
console.error(chalk.red('deliveries failed:'), err instanceof Error ? err.message : err);
|
|
774
|
+
process.exit(1);
|
|
775
|
+
}
|
|
776
|
+
});
|
|
777
|
+
webhooks
|
|
778
|
+
.command('replay <id>')
|
|
779
|
+
.description('Replay a previous delivery (idempotent via X-Haystack-Delivery)')
|
|
780
|
+
.action(async (id) => {
|
|
781
|
+
try {
|
|
782
|
+
await replayDelivery(id);
|
|
783
|
+
}
|
|
784
|
+
catch (err) {
|
|
785
|
+
console.error(chalk.red('replay failed:'), err instanceof Error ? err.message : err);
|
|
786
|
+
process.exit(1);
|
|
787
|
+
}
|
|
788
|
+
});
|
|
789
|
+
// ─── rules ───────────────────────────────────────────────────────────────────
|
|
790
|
+
const rules = program.command('rules').description('Manage .haystack/pr-rules.yml');
|
|
791
|
+
rules
|
|
792
|
+
.command('edit')
|
|
793
|
+
.description('Open .haystack/pr-rules.yml in $EDITOR (creates a starter if missing)')
|
|
794
|
+
.action(async () => {
|
|
795
|
+
try {
|
|
796
|
+
await editRulesCommand();
|
|
797
|
+
}
|
|
798
|
+
catch (err) {
|
|
799
|
+
console.error(chalk.red('edit failed:'), err instanceof Error ? err.message : err);
|
|
800
|
+
process.exit(1);
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
rules
|
|
804
|
+
.command('validate')
|
|
805
|
+
.description('Parse pr-rules.yml with the same parser the server uses')
|
|
806
|
+
.action(async () => {
|
|
807
|
+
try {
|
|
808
|
+
await validateRulesCommand();
|
|
809
|
+
}
|
|
810
|
+
catch (err) {
|
|
811
|
+
console.error(chalk.red('validate failed:'), err instanceof Error ? err.message : err);
|
|
812
|
+
process.exit(1);
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
// ─── mcp ─────────────────────────────────────────────────────────────────────
|
|
816
|
+
program
|
|
817
|
+
.command('mcp')
|
|
818
|
+
.description('Run a stdio MCP server exposing Haystack tools to Claude Code, Cursor, etc.')
|
|
819
|
+
.action(async () => {
|
|
820
|
+
try {
|
|
821
|
+
await runMcpServer();
|
|
822
|
+
}
|
|
823
|
+
catch (err) {
|
|
824
|
+
console.error(chalk.red('mcp server failed:'), err instanceof Error ? err.message : err);
|
|
825
|
+
process.exit(1);
|
|
826
|
+
}
|
|
827
|
+
});
|
|
609
828
|
// Show help if no command provided
|
|
610
829
|
if (process.argv.length === 2) {
|
|
611
830
|
program.help();
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable machine-readable schema versions for each `--json` output.
|
|
3
|
+
*
|
|
4
|
+
* Bump semantics (per docs/SPEC-CLI-FIRST-CLASS.md):
|
|
5
|
+
* patch — additive fields only
|
|
6
|
+
* minor — field deprecated (kept emitting for one minor with _deprecated: true)
|
|
7
|
+
* major — removal / rename
|
|
8
|
+
*
|
|
9
|
+
* One schema, two transports: every webhook payload for the corresponding noun
|
|
10
|
+
* uses the same envelope as the `--json` output, byte-for-byte.
|
|
11
|
+
*/
|
|
12
|
+
export declare const SCHEMA_VERSIONS: {
|
|
13
|
+
readonly triage: "1.0.0";
|
|
14
|
+
readonly setup: "1.0.0";
|
|
15
|
+
readonly pr: "1.0.0";
|
|
16
|
+
};
|
|
17
|
+
export type SchemaName = keyof typeof SCHEMA_VERSIONS;
|
|
18
|
+
/** Wrap a payload with the `schema_version` envelope. */
|
|
19
|
+
export declare function withSchema<T extends Record<string, unknown>>(name: SchemaName, payload: T): T & {
|
|
20
|
+
schema_version: string;
|
|
21
|
+
};
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable machine-readable schema versions for each `--json` output.
|
|
3
|
+
*
|
|
4
|
+
* Bump semantics (per docs/SPEC-CLI-FIRST-CLASS.md):
|
|
5
|
+
* patch — additive fields only
|
|
6
|
+
* minor — field deprecated (kept emitting for one minor with _deprecated: true)
|
|
7
|
+
* major — removal / rename
|
|
8
|
+
*
|
|
9
|
+
* One schema, two transports: every webhook payload for the corresponding noun
|
|
10
|
+
* uses the same envelope as the `--json` output, byte-for-byte.
|
|
11
|
+
*/
|
|
12
|
+
export const SCHEMA_VERSIONS = {
|
|
13
|
+
triage: '1.0.0',
|
|
14
|
+
setup: '1.0.0',
|
|
15
|
+
pr: '1.0.0',
|
|
16
|
+
};
|
|
17
|
+
/** Wrap a payload with the `schema_version` envelope. */
|
|
18
|
+
export function withSchema(name, payload) {
|
|
19
|
+
return { schema_version: SCHEMA_VERSIONS[name], ...payload };
|
|
20
|
+
}
|
package/dist/triage/runner.js
CHANGED
|
@@ -10,6 +10,7 @@ import { join } from 'path';
|
|
|
10
10
|
import chalk from 'chalk';
|
|
11
11
|
import { buildCodeReviewPrompt, buildRulesValidatorPrompt, buildIntentDriftPrompt } from './prompts.js';
|
|
12
12
|
import { findRelevantTraces } from './traces.js';
|
|
13
|
+
import { resolveDiffBaseRef } from '../utils/git.js';
|
|
13
14
|
import { trackError } from '../utils/telemetry.js';
|
|
14
15
|
// ============================================================================
|
|
15
16
|
// Constants
|
|
@@ -272,11 +273,20 @@ export async function runTriage(gitRoot, baseBranch, options = {}) {
|
|
|
272
273
|
rmSync(triageDir, { recursive: true });
|
|
273
274
|
}
|
|
274
275
|
mkdirSync(triageDir, { recursive: true });
|
|
276
|
+
// Resolve the ref to diff against once. Prefers origin/<base> over the bare
|
|
277
|
+
// local <base> ref (which is often stale and balloons the diff with already-
|
|
278
|
+
// merged code). Every git read below — the precomputed diff, the agent diff
|
|
279
|
+
// commands in the prompts, and the changed-file scan in findRelevantTraces —
|
|
280
|
+
// uses this single resolved ref so they all see the same fork point.
|
|
281
|
+
const diffBaseRef = resolveDiffBaseRef(baseBranch);
|
|
282
|
+
if (diffBaseRef !== baseBranch) {
|
|
283
|
+
console.log(chalk.dim(` Diff base: ${diffBaseRef}`));
|
|
284
|
+
}
|
|
275
285
|
// Pre-compute the diff once so sub-agents don't waste turns running git diff.
|
|
276
286
|
// Includes 10 lines of context around each hunk for reviewability.
|
|
277
287
|
let precomputedDiff = null;
|
|
278
288
|
try {
|
|
279
|
-
const diffOutput = execSync(`git diff ${
|
|
289
|
+
const diffOutput = execSync(`git diff ${diffBaseRef}...HEAD -U10`, { cwd: gitRoot, encoding: 'utf-8', maxBuffer: 5 * 1024 * 1024 }).trim();
|
|
280
290
|
// Only inline if the diff is under 100K chars — beyond that, let the agent
|
|
281
291
|
// run git diff itself (it can paginate or review file-by-file).
|
|
282
292
|
if (diffOutput.length > 0 && diffOutput.length <= 100_000) {
|
|
@@ -292,7 +302,7 @@ export async function runTriage(gitRoot, baseBranch, options = {}) {
|
|
|
292
302
|
const codeReviewOutput = join(triageDir, 'code-review.json');
|
|
293
303
|
checkers.push({
|
|
294
304
|
name: 'code-review',
|
|
295
|
-
prompt: buildCodeReviewPrompt(
|
|
305
|
+
prompt: buildCodeReviewPrompt(diffBaseRef, codeReviewOutput, maxTurns['code-review'], timeoutMs, precomputedDiff),
|
|
296
306
|
outputFile: codeReviewOutput,
|
|
297
307
|
maxTurns: maxTurns['code-review'],
|
|
298
308
|
});
|
|
@@ -303,7 +313,7 @@ export async function runTriage(gitRoot, baseBranch, options = {}) {
|
|
|
303
313
|
const agentPolicyFiles = discoverAgentPolicyFiles(gitRoot);
|
|
304
314
|
if (hasRulesYaml || agentPolicyFiles.length > 0) {
|
|
305
315
|
const rulesValidatorOutput = join(triageDir, 'rules-validator.json');
|
|
306
|
-
const rulesPrompt = buildRulesValidatorPrompt(
|
|
316
|
+
const rulesPrompt = buildRulesValidatorPrompt(diffBaseRef, rulesYaml, rulesValidatorOutput, maxTurns['rules-validator'], timeoutMs, agentPolicyFiles, precomputedDiff);
|
|
307
317
|
if (rulesPrompt) {
|
|
308
318
|
checkers.push({
|
|
309
319
|
name: 'rules-validator',
|
|
@@ -314,10 +324,10 @@ export async function runTriage(gitRoot, baseBranch, options = {}) {
|
|
|
314
324
|
}
|
|
315
325
|
}
|
|
316
326
|
// 3. Intent drift (only if relevant trace files exist)
|
|
317
|
-
const traceFiles = findRelevantTraces(gitRoot,
|
|
327
|
+
const traceFiles = findRelevantTraces(gitRoot, diffBaseRef);
|
|
318
328
|
if (traceFiles.length > 0) {
|
|
319
329
|
const intentDriftOutput = join(triageDir, 'intent-drift.json');
|
|
320
|
-
const driftPrompt = buildIntentDriftPrompt(
|
|
330
|
+
const driftPrompt = buildIntentDriftPrompt(diffBaseRef, traceFiles, intentDriftOutput, maxTurns['intent-drift'], timeoutMs, precomputedDiff);
|
|
321
331
|
if (driftPrompt) {
|
|
322
332
|
checkers.push({
|
|
323
333
|
name: 'intent-drift',
|
|
@@ -15,8 +15,18 @@ export interface AnalysisVerdict {
|
|
|
15
15
|
summary: string;
|
|
16
16
|
issues: AnalysisIssue[];
|
|
17
17
|
reviewUrl: string;
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Whether the PR has actually been merged on GitHub. Read from the GH
|
|
20
|
+
* REST PR endpoint — NOT inferred from review policy / canAutoMerge /
|
|
21
|
+
* haystackRating, all of which mean "eligible", not "merged".
|
|
22
|
+
*/
|
|
19
23
|
autoMerged?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Whether the rating synthesis flagged that a human reviewer is required
|
|
26
|
+
* (review policy, security-sensitive paths, etc.). Distinct from
|
|
27
|
+
* `state === 'needs-input'` — analysis can be clean AND still need a human.
|
|
28
|
+
*/
|
|
29
|
+
needsHumanReview?: boolean;
|
|
20
30
|
}
|
|
21
31
|
export interface AnalysisIssue {
|
|
22
32
|
file: string;
|
|
@@ -55,7 +65,7 @@ export interface HumanReviewReason {
|
|
|
55
65
|
}
|
|
56
66
|
export interface RatingSynthesis {
|
|
57
67
|
haystackRating: 1 | 2 | 3 | 4 | 5;
|
|
58
|
-
analysisVerdict?: 'clean' | 'has-issues';
|
|
68
|
+
analysisVerdict?: 'clean' | 'has-issues' | 'needs-review';
|
|
59
69
|
synthesis: string;
|
|
60
70
|
synthesisDisplay?: SynthesisDisplayIssue[];
|
|
61
71
|
verifiedBugs: VerifiedBug[];
|
|
@@ -99,9 +109,6 @@ export type AnalysisReadyResult = {
|
|
|
99
109
|
* Returns 'ready' if complete, 'pending' if not yet available, or 'error' for server failures.
|
|
100
110
|
*/
|
|
101
111
|
export declare function checkAnalysisReady(owner: string, repo: string, prNumber: number, token?: string): Promise<AnalysisReadyResult>;
|
|
102
|
-
/**
|
|
103
|
-
* Fetch analysis results once complete. Combines bug detection and rule violations.
|
|
104
|
-
*/
|
|
105
112
|
export declare function fetchAnalysisResults(owner: string, repo: string, prNumber: number, token?: string): Promise<AnalysisVerdict>;
|
|
106
113
|
/**
|
|
107
114
|
* Fetch the full rating synthesis for a PR.
|