@haystackeditor/cli 0.15.27 → 0.15.29
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 +13 -20
- package/dist/assets/hooks/agent-context/detect.ts +7 -7
- package/dist/assets/hooks/agent-context/parsers/claude.ts +1 -1
- package/dist/assets/hooks/scripts/commit-msg.sh +1 -3
- package/dist/assets/hooks/scripts/post-commit.sh +1 -3
- package/dist/assets/hooks/scripts/pre-push.sh +1 -4
- package/dist/assets/hooks/scripts/prepare-commit-msg.sh +1 -2
- package/dist/assets/telemetry/browser-runtime.js +668 -43
- package/dist/assets/telemetry/runtime.cjs +62 -68
- package/dist/commands/design-verify.d.ts +11 -3
- package/dist/commands/design-verify.js +147 -4
- package/dist/commands/hooks.d.ts +1 -5
- package/dist/commands/hooks.js +10 -112
- package/dist/commands/install-session-hooks.d.ts +2 -2
- package/dist/commands/install-session-hooks.js +71 -21
- package/dist/commands/mcp.js +1 -34
- package/dist/commands/pr.js +2 -7
- package/dist/commands/setup.d.ts +1 -2
- package/dist/commands/setup.js +18 -272
- package/dist/commands/submit.js +1 -2
- package/dist/commands/verify-hosted-mcp.js +12 -2
- package/dist/commands/verify-hosted-reproducibility.d.ts +1 -0
- package/dist/commands/verify-hosted-reproducibility.js +4 -1
- package/dist/commands/verify-hosted.d.ts +20 -0
- package/dist/commands/verify-hosted.js +119 -11
- package/dist/commands/verify-precompute.d.ts +19 -0
- package/dist/commands/verify-precompute.js +328 -0
- package/dist/index.js +45 -44
- package/dist/schema.d.ts +1 -2
- package/dist/schema.js +1 -2
- package/dist/triage/prompts.d.ts +0 -7
- package/dist/triage/prompts.js +0 -145
- package/dist/triage/runner.js +3 -22
- package/dist/triage/types.d.ts +1 -8
- package/dist/types.d.ts +8 -8
- package/dist/types.js +1 -1
- package/dist/utils/design-verifier-api.d.ts +71 -0
- package/dist/utils/design-verifier-api.js +96 -0
- package/dist/utils/design-verifier-result.d.ts +7 -2
- package/dist/utils/design-verifier-result.js +67 -21
- package/dist/utils/git.d.ts +5 -1
- package/dist/utils/git.js +19 -9
- package/dist/utils/github-api.js +11 -14
- package/dist/utils/hooks.d.ts +1 -15
- package/dist/utils/hooks.js +1 -127
- package/dist/utils/telemetry.d.ts +2 -0
- package/dist/utils/telemetry.js +81 -8
- package/package.json +2 -1
- package/schemas/cloud-verifier.v1.json +69 -3
- package/schemas/{pr.v2.json → pr.v3.json} +3 -12
- package/dist/commands/traces.d.ts +0 -48
- package/dist/commands/traces.js +0 -92
- package/dist/triage/traces.d.ts +0 -20
- package/dist/triage/traces.js +0 -311
- package/schemas/traces.v1.json +0 -53
package/dist/commands/hooks.js
CHANGED
|
@@ -2,15 +2,14 @@
|
|
|
2
2
|
* haystack hooks - Install and manage git hooks for AI agent quality checks
|
|
3
3
|
*
|
|
4
4
|
* Installs:
|
|
5
|
-
* - Entire CLI binary (session tracking, powered by https://entire.dev)
|
|
6
5
|
* - Pre-commit hook (agent detection, truncation checking, LLM rules review)
|
|
7
|
-
* - Git hooks for
|
|
6
|
+
* - Git hooks for Haystack quality checks and workflow guidance
|
|
8
7
|
*/
|
|
9
8
|
import chalk from 'chalk';
|
|
10
9
|
import { existsSync, accessSync, constants } from 'fs';
|
|
11
10
|
import * as path from 'path';
|
|
12
11
|
import { execSync } from 'child_process';
|
|
13
|
-
import { findGitRoot,
|
|
12
|
+
import { findGitRoot, copyHookFiles, installHookDeps, copyLlmRulesTemplate, } from '../utils/hooks.js';
|
|
14
13
|
export async function hooksInstall(options) {
|
|
15
14
|
console.log(chalk.cyan('\nHaystack Hooks Setup\n'));
|
|
16
15
|
// Step 1: Validate git repo
|
|
@@ -28,30 +27,7 @@ export async function hooksInstall(options) {
|
|
|
28
27
|
if (existsSync(hooksDir) && options.force) {
|
|
29
28
|
console.log(chalk.yellow('Overwriting existing hooks...'));
|
|
30
29
|
}
|
|
31
|
-
// Step 3:
|
|
32
|
-
if (!options.skipEntire) {
|
|
33
|
-
const version = options.version || ENTIRE_DEFAULT_VERSION;
|
|
34
|
-
const installedVersion = await getInstalledEntireVersion();
|
|
35
|
-
if (installedVersion === version) {
|
|
36
|
-
console.log(chalk.green(`✓ Entire CLI v${version} already installed`));
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
console.log(chalk.dim(`Downloading Entire CLI v${version}...`));
|
|
40
|
-
try {
|
|
41
|
-
await downloadEntireBinary(version);
|
|
42
|
-
console.log(chalk.green(`✓ Entire CLI v${version} installed to ~/.haystack/bin/entire`));
|
|
43
|
-
}
|
|
44
|
-
catch (err) {
|
|
45
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
46
|
-
console.error(chalk.red(`Failed to download Entire CLI: ${message}\n`));
|
|
47
|
-
process.exit(1);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
console.log(chalk.dim('Skipping Entire CLI download (--skip-entire)'));
|
|
53
|
-
}
|
|
54
|
-
// Step 4: Copy hook files
|
|
30
|
+
// Step 3: Copy hook files
|
|
55
31
|
try {
|
|
56
32
|
await copyHookFiles(hooksDir);
|
|
57
33
|
console.log(chalk.green('✓ Hook scripts installed to hooks/'));
|
|
@@ -61,7 +37,7 @@ export async function hooksInstall(options) {
|
|
|
61
37
|
console.error(chalk.red(`Failed to copy hook files: ${message}\n`));
|
|
62
38
|
process.exit(1);
|
|
63
39
|
}
|
|
64
|
-
// Step
|
|
40
|
+
// Step 4: Install hook dependencies
|
|
65
41
|
console.log(chalk.dim('Installing hook dependencies (tree-sitter)...'));
|
|
66
42
|
try {
|
|
67
43
|
await installHookDeps(hooksDir);
|
|
@@ -70,7 +46,7 @@ export async function hooksInstall(options) {
|
|
|
70
46
|
catch {
|
|
71
47
|
console.log(chalk.yellow('⚠ Failed to install hook dependencies. Run `npm ci` in hooks/ manually.'));
|
|
72
48
|
}
|
|
73
|
-
// Step
|
|
49
|
+
// Step 5: Configure git hooks path
|
|
74
50
|
try {
|
|
75
51
|
execSync('git config core.hooksPath hooks', { cwd: gitRoot, stdio: 'pipe' });
|
|
76
52
|
console.log(chalk.green('✓ Git configured to use hooks/ directory'));
|
|
@@ -80,15 +56,7 @@ export async function hooksInstall(options) {
|
|
|
80
56
|
console.error(chalk.red(`Failed to set git hooks path: ${message}\n`));
|
|
81
57
|
process.exit(1);
|
|
82
58
|
}
|
|
83
|
-
// Step
|
|
84
|
-
try {
|
|
85
|
-
await createEntireConfig(gitRoot);
|
|
86
|
-
console.log(chalk.green('✓ Created .entire/settings.json'));
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
console.log(chalk.yellow('⚠ Failed to create .entire/ configuration'));
|
|
90
|
-
}
|
|
91
|
-
// Step 8: Create LLM_RULES.md if needed
|
|
59
|
+
// Step 6: Create LLM_RULES.md if needed
|
|
92
60
|
try {
|
|
93
61
|
const created = await copyLlmRulesTemplate(gitRoot);
|
|
94
62
|
if (created) {
|
|
@@ -101,29 +69,17 @@ export async function hooksInstall(options) {
|
|
|
101
69
|
catch {
|
|
102
70
|
console.log(chalk.yellow('⚠ Failed to create LLM_RULES.md'));
|
|
103
71
|
}
|
|
104
|
-
// Step 9: Update .gitignore
|
|
105
|
-
try {
|
|
106
|
-
const updated = await updateGitignore(gitRoot);
|
|
107
|
-
if (updated) {
|
|
108
|
-
console.log(chalk.green('✓ Updated .gitignore'));
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
console.log(chalk.yellow('⚠ Failed to update .gitignore'));
|
|
113
|
-
}
|
|
114
72
|
// Summary
|
|
115
73
|
console.log(chalk.green('\n✓ Haystack hooks installed!\n'));
|
|
116
74
|
console.log(chalk.dim('Hooks installed:'));
|
|
117
75
|
console.log(chalk.dim(' pre-commit Agent detection, truncation check, LLM rules review'));
|
|
118
|
-
console.log(chalk.dim(' commit-msg
|
|
119
|
-
console.log(chalk.dim(' post-commit
|
|
120
|
-
console.log(chalk.dim(' pre-push
|
|
121
|
-
console.log(chalk.dim(' prepare-commit-msg
|
|
76
|
+
console.log(chalk.dim(' commit-msg Haystack commit checks'));
|
|
77
|
+
console.log(chalk.dim(' post-commit Haystack post-commit checks'));
|
|
78
|
+
console.log(chalk.dim(' pre-push Haystack workflow guidance'));
|
|
79
|
+
console.log(chalk.dim(' prepare-commit-msg Haystack commit preparation'));
|
|
122
80
|
console.log('');
|
|
123
81
|
console.log(chalk.dim('Files to commit:'));
|
|
124
82
|
console.log(chalk.dim(' hooks/ Hook scripts and TypeScript modules'));
|
|
125
|
-
console.log(chalk.dim(' .entire/settings.json'));
|
|
126
|
-
console.log(chalk.dim(' .entire/.gitignore'));
|
|
127
83
|
console.log(chalk.dim(' LLM_RULES.md Customize this for your project'));
|
|
128
84
|
console.log('');
|
|
129
85
|
}
|
|
@@ -199,25 +155,6 @@ export async function hooksStatus() {
|
|
|
199
155
|
catch {
|
|
200
156
|
console.log(chalk.red('✗ Git core.hooksPath not set'));
|
|
201
157
|
}
|
|
202
|
-
// Check Entire binary
|
|
203
|
-
const installedVersion = await getInstalledEntireVersion();
|
|
204
|
-
if (installedVersion) {
|
|
205
|
-
console.log(chalk.green(`✓ Entire CLI v${installedVersion}`));
|
|
206
|
-
}
|
|
207
|
-
else if (existsSync(ENTIRE_BIN_PATH)) {
|
|
208
|
-
console.log(chalk.yellow('⚠ Entire CLI binary exists but failed to run'));
|
|
209
|
-
}
|
|
210
|
-
else {
|
|
211
|
-
console.log(chalk.yellow('⚠ Entire CLI not installed (~/.haystack/bin/entire)'));
|
|
212
|
-
}
|
|
213
|
-
// Check .entire/settings.json
|
|
214
|
-
const settingsPath = path.join(gitRoot, '.entire', 'settings.json');
|
|
215
|
-
if (existsSync(settingsPath)) {
|
|
216
|
-
console.log(chalk.green('✓ .entire/settings.json'));
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
console.log(chalk.yellow('⚠ .entire/settings.json not found'));
|
|
220
|
-
}
|
|
221
158
|
// Check LLM_RULES.md
|
|
222
159
|
const rulesPath = path.join(gitRoot, 'LLM_RULES.md');
|
|
223
160
|
if (existsSync(rulesPath)) {
|
|
@@ -228,42 +165,3 @@ export async function hooksStatus() {
|
|
|
228
165
|
}
|
|
229
166
|
console.log('');
|
|
230
167
|
}
|
|
231
|
-
// ============================================================================
|
|
232
|
-
// haystack hooks update
|
|
233
|
-
// ============================================================================
|
|
234
|
-
export async function hooksUpdate() {
|
|
235
|
-
console.log(chalk.cyan('\nUpdating Entire CLI...\n'));
|
|
236
|
-
// Check current version
|
|
237
|
-
const currentVersion = await getInstalledEntireVersion();
|
|
238
|
-
if (currentVersion) {
|
|
239
|
-
console.log(chalk.dim(`Current version: v${currentVersion}`));
|
|
240
|
-
}
|
|
241
|
-
else {
|
|
242
|
-
console.log(chalk.dim('Entire CLI not currently installed.'));
|
|
243
|
-
}
|
|
244
|
-
// Fetch latest version
|
|
245
|
-
let latestVersion;
|
|
246
|
-
try {
|
|
247
|
-
latestVersion = await getLatestEntireVersion();
|
|
248
|
-
}
|
|
249
|
-
catch (err) {
|
|
250
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
251
|
-
console.error(chalk.red(`Failed to check for updates: ${message}\n`));
|
|
252
|
-
process.exit(1);
|
|
253
|
-
}
|
|
254
|
-
console.log(chalk.dim(`Latest version: v${latestVersion}`));
|
|
255
|
-
if (currentVersion === latestVersion) {
|
|
256
|
-
console.log(chalk.green('\n✓ Already up to date.\n'));
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
// Download and install
|
|
260
|
-
try {
|
|
261
|
-
await downloadEntireBinary(latestVersion);
|
|
262
|
-
console.log(chalk.green(`\n✓ Updated Entire CLI to v${latestVersion}\n`));
|
|
263
|
-
}
|
|
264
|
-
catch (err) {
|
|
265
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
266
|
-
console.error(chalk.red(`Failed to update: ${message}\n`));
|
|
267
|
-
process.exit(1);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* install-session-hooks — Wire up session-start hooks for coding CLIs.
|
|
2
|
+
* install-session-hooks — Wire up session-start and Stop hooks for coding CLIs.
|
|
3
3
|
*
|
|
4
4
|
* When a CLI session starts, `haystack triage --hook` runs automatically
|
|
5
5
|
* and shows the user whether their last submitted PR is "Good to merge" or
|
|
6
6
|
* "Needs input", with the Haystack rating and auto-fixer status.
|
|
7
7
|
*
|
|
8
8
|
* Supported CLIs:
|
|
9
|
-
* - Claude Code: Native SessionStart
|
|
9
|
+
* - Claude Code: Native SessionStart and Stop hooks in .claude/settings.json
|
|
10
10
|
* - Codex CLI: AGENTS.md instructions (no native hook support)
|
|
11
11
|
* - Gemini CLI: GEMINI.md instructions (no native hook support)
|
|
12
12
|
*/
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* install-session-hooks — Wire up session-start hooks for coding CLIs.
|
|
2
|
+
* install-session-hooks — Wire up session-start and Stop hooks for coding CLIs.
|
|
3
3
|
*
|
|
4
4
|
* When a CLI session starts, `haystack triage --hook` runs automatically
|
|
5
5
|
* and shows the user whether their last submitted PR is "Good to merge" or
|
|
6
6
|
* "Needs input", with the Haystack rating and auto-fixer status.
|
|
7
7
|
*
|
|
8
8
|
* Supported CLIs:
|
|
9
|
-
* - Claude Code: Native SessionStart
|
|
9
|
+
* - Claude Code: Native SessionStart and Stop hooks in .claude/settings.json
|
|
10
10
|
* - Codex CLI: AGENTS.md instructions (no native hook support)
|
|
11
11
|
* - Gemini CLI: GEMINI.md instructions (no native hook support)
|
|
12
12
|
*/
|
|
@@ -43,6 +43,7 @@ function detectInstalledCLIs() {
|
|
|
43
43
|
// Claude Code: Native SessionStart hook
|
|
44
44
|
// ============================================================================
|
|
45
45
|
const HAYSTACK_HOOK_COMMAND = 'haystack triage --hook';
|
|
46
|
+
const HAYSTACK_PRECOMPUTE_HOOK_COMMAND = 'haystack verify precompute --hook';
|
|
46
47
|
function installClaudeHook(gitRoot) {
|
|
47
48
|
const settingsDir = join(gitRoot, '.claude');
|
|
48
49
|
const settingsPath = join(settingsDir, 'settings.json');
|
|
@@ -65,6 +66,8 @@ function installClaudeHook(gitRoot) {
|
|
|
65
66
|
// Check if haystack hook already installed (current or legacy)
|
|
66
67
|
const isHaystackHook = (h) => h.command?.includes('haystack triage') || h.command?.includes('haystack check-pending');
|
|
67
68
|
const existingIndex = sessionStart.findIndex(entry => entry.hooks?.some(h => isHaystackHook(h)));
|
|
69
|
+
let changed = false;
|
|
70
|
+
let migrated = false;
|
|
68
71
|
if (existingIndex !== -1) {
|
|
69
72
|
const entry = sessionStart[existingIndex];
|
|
70
73
|
const isLegacy = entry.hooks?.some(h => h.command?.includes('haystack check-pending'));
|
|
@@ -73,27 +76,51 @@ function installClaudeHook(gitRoot) {
|
|
|
73
76
|
for (const h of entry.hooks || []) {
|
|
74
77
|
if (h.command?.includes('haystack check-pending')) {
|
|
75
78
|
h.command = HAYSTACK_HOOK_COMMAND;
|
|
79
|
+
changed = true;
|
|
80
|
+
migrated = true;
|
|
76
81
|
}
|
|
77
82
|
}
|
|
78
|
-
writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
79
|
-
console.log(chalk.green(' Claude Code hook migrated from check-pending to triage.'));
|
|
80
83
|
}
|
|
81
|
-
|
|
82
|
-
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Add the session-start hook (fresh install).
|
|
87
|
+
sessionStart.push({
|
|
88
|
+
matcher: '',
|
|
89
|
+
hooks: [
|
|
90
|
+
{
|
|
91
|
+
type: 'command',
|
|
92
|
+
command: HAYSTACK_HOOK_COMMAND,
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
});
|
|
96
|
+
changed = true;
|
|
97
|
+
}
|
|
98
|
+
// Stop precompute is independent of SessionStart. Preserve every unrelated
|
|
99
|
+
// entry and add the exact command only when no matching command exists.
|
|
100
|
+
const stop = (hooks.Stop || []);
|
|
101
|
+
hooks.Stop = stop;
|
|
102
|
+
const hasPrecomputeHook = stop.some(entry => entry.hooks?.some(h => h.command?.includes(HAYSTACK_PRECOMPUTE_HOOK_COMMAND)));
|
|
103
|
+
if (!hasPrecomputeHook) {
|
|
104
|
+
stop.push({
|
|
105
|
+
matcher: '',
|
|
106
|
+
hooks: [
|
|
107
|
+
{
|
|
108
|
+
type: 'command',
|
|
109
|
+
command: HAYSTACK_PRECOMPUTE_HOOK_COMMAND,
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
});
|
|
113
|
+
changed = true;
|
|
114
|
+
}
|
|
115
|
+
if (changed) {
|
|
116
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
117
|
+
if (migrated) {
|
|
118
|
+
console.log(chalk.green(' Claude Code hook migrated from check-pending to triage.'));
|
|
83
119
|
}
|
|
84
|
-
return true;
|
|
85
120
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
hooks: [
|
|
90
|
-
{
|
|
91
|
-
type: 'command',
|
|
92
|
-
command: HAYSTACK_HOOK_COMMAND,
|
|
93
|
-
},
|
|
94
|
-
],
|
|
95
|
-
});
|
|
96
|
-
writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
121
|
+
else {
|
|
122
|
+
console.log(chalk.dim(' Claude Code session and Stop hooks already installed.'));
|
|
123
|
+
}
|
|
97
124
|
return true;
|
|
98
125
|
}
|
|
99
126
|
catch (err) {
|
|
@@ -101,6 +128,19 @@ function installClaudeHook(gitRoot) {
|
|
|
101
128
|
return false;
|
|
102
129
|
}
|
|
103
130
|
}
|
|
131
|
+
function checkClaudePrecomputeHook(gitRoot) {
|
|
132
|
+
const settingsPath = join(gitRoot, '.claude', 'settings.json');
|
|
133
|
+
if (!existsSync(settingsPath))
|
|
134
|
+
return false;
|
|
135
|
+
try {
|
|
136
|
+
const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
137
|
+
const stop = settings?.hooks?.Stop || [];
|
|
138
|
+
return stop.some((entry) => entry.hooks?.some(h => h.command?.includes(HAYSTACK_PRECOMPUTE_HOOK_COMMAND)));
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
104
144
|
function checkClaudeHook(gitRoot) {
|
|
105
145
|
const settingsPath = join(gitRoot, '.claude', 'settings.json');
|
|
106
146
|
if (!existsSync(settingsPath))
|
|
@@ -220,6 +260,7 @@ const CLI_HOOKS = {
|
|
|
220
260
|
hasNativeHook: true,
|
|
221
261
|
install: installClaudeHook,
|
|
222
262
|
check: checkClaudeHook,
|
|
263
|
+
checkStop: checkClaudePrecomputeHook,
|
|
223
264
|
},
|
|
224
265
|
codex: {
|
|
225
266
|
name: 'codex',
|
|
@@ -286,6 +327,9 @@ export async function installSessionHooks(options) {
|
|
|
286
327
|
}
|
|
287
328
|
}
|
|
288
329
|
console.log(chalk.green('\n✓ Session hooks installed!\n'));
|
|
330
|
+
if (targets.includes('claude')) {
|
|
331
|
+
console.log(chalk.dim('Claude Code will also precompute verification inputs when a session stops.'));
|
|
332
|
+
}
|
|
289
333
|
console.log(chalk.dim('When you start a new session, you\'ll see:'));
|
|
290
334
|
console.log(chalk.green(' [Haystack] ✓ PR #42 "Fix auth": Good to merge'));
|
|
291
335
|
console.log(chalk.yellow(' [Haystack] ⚠ PR #37 "Refactor API": Needs your input (2 bugs)'));
|
|
@@ -306,11 +350,17 @@ export async function sessionHooksStatus() {
|
|
|
306
350
|
const cliIcon = isInstalled ? chalk.green('✓') : chalk.dim('-');
|
|
307
351
|
const hookIcon = hookConfigured ? chalk.green('✓') : chalk.red('✗');
|
|
308
352
|
console.log(` ${cliIcon} ${config.displayName} ${isInstalled ? '(installed)' : '(not found)'}`);
|
|
309
|
-
|
|
310
|
-
|
|
353
|
+
console.log(` ${hookIcon} Session hook ${hookConfigured ? 'configured' : 'not configured'}`);
|
|
354
|
+
if (config.checkStop) {
|
|
355
|
+
const stopConfigured = config.checkStop(gitRoot);
|
|
356
|
+
const stopIcon = stopConfigured ? chalk.green('✓') : chalk.red('✗');
|
|
357
|
+
console.log(` ${stopIcon} Stop precompute hook ${stopConfigured ? 'configured' : 'not configured'}`);
|
|
311
358
|
}
|
|
312
359
|
}
|
|
313
|
-
const anyMissing = installed.some(cli =>
|
|
360
|
+
const anyMissing = installed.some(cli => {
|
|
361
|
+
const config = CLI_HOOKS[cli];
|
|
362
|
+
return !config.check(gitRoot) || (config.checkStop ? !config.checkStop(gitRoot) : false);
|
|
363
|
+
});
|
|
314
364
|
if (anyMissing) {
|
|
315
365
|
console.log(chalk.dim('\nRun: haystack hooks install-session'));
|
|
316
366
|
}
|
package/dist/commands/mcp.js
CHANGED
|
@@ -9,7 +9,6 @@ import { fetchPrStatePayload } from './pr.js';
|
|
|
9
9
|
import { fetchPrStatusPayload } from './pr-status.js';
|
|
10
10
|
import { fetchTriagePayload, fetchTriageHeadSha } from './triage.js';
|
|
11
11
|
import { fetchAskPayload } from './ask.js';
|
|
12
|
-
import { fetchTracesGetPayload, fetchTracesListPayload } from './traces.js';
|
|
13
12
|
import { performOverride, performUndismiss } from './dismiss.js';
|
|
14
13
|
import { performRequestReview } from './request-review.js';
|
|
15
14
|
import { loadToken } from '../utils/auth.js';
|
|
@@ -29,7 +28,7 @@ const TOOLS = [
|
|
|
29
28
|
},
|
|
30
29
|
{
|
|
31
30
|
name: 'pr_get',
|
|
32
|
-
description: 'Get useful state for one PR: triage, minimal merge blockers,
|
|
31
|
+
description: 'Get useful state for one PR: triage, minimal merge blockers, and conditional fixer outcome.',
|
|
33
32
|
inputSchema: { type: 'object', properties: { ref: refInput }, required: ['ref'] },
|
|
34
33
|
},
|
|
35
34
|
{
|
|
@@ -50,25 +49,6 @@ const TOOLS = [
|
|
|
50
49
|
required: ['ref', 'question'],
|
|
51
50
|
},
|
|
52
51
|
},
|
|
53
|
-
{
|
|
54
|
-
name: 'traces_list',
|
|
55
|
-
description: 'List retained customer-owned Entire checkpoints for one PR.',
|
|
56
|
-
inputSchema: { type: 'object', properties: { ref: refInput }, required: ['ref'] },
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
name: 'traces_get',
|
|
60
|
-
description: 'Get a page of retained customer-owned transcript chunks for one checkpoint.',
|
|
61
|
-
inputSchema: {
|
|
62
|
-
type: 'object',
|
|
63
|
-
properties: {
|
|
64
|
-
ref: refInput,
|
|
65
|
-
checkpoint_id: { type: 'string' },
|
|
66
|
-
cursor: { type: 'string' },
|
|
67
|
-
limit: { type: 'integer', minimum: 1, maximum: 100 },
|
|
68
|
-
},
|
|
69
|
-
required: ['ref', 'checkpoint_id'],
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
52
|
{
|
|
73
53
|
name: 'pr_status',
|
|
74
54
|
description: 'Get which Haystack feed bucket a PR is in (analyzing, good_to_merge, issues, needs_assignment, ...) and why.',
|
|
@@ -153,19 +133,6 @@ export async function runMcpServer() {
|
|
|
153
133
|
session: typeof input.session_id === 'string' ? input.session_id : undefined,
|
|
154
134
|
}));
|
|
155
135
|
}
|
|
156
|
-
if (name === 'traces_list') {
|
|
157
|
-
if (typeof input.ref !== 'string')
|
|
158
|
-
return fail('ref required');
|
|
159
|
-
return ok(await fetchTracesListPayload(input.ref));
|
|
160
|
-
}
|
|
161
|
-
if (name === 'traces_get') {
|
|
162
|
-
if (typeof input.ref !== 'string' || typeof input.checkpoint_id !== 'string')
|
|
163
|
-
return fail('ref and checkpoint_id required');
|
|
164
|
-
return ok(await fetchTracesGetPayload(input.ref, input.checkpoint_id, {
|
|
165
|
-
cursor: typeof input.cursor === 'string' ? input.cursor : undefined,
|
|
166
|
-
limit: typeof input.limit === 'number' ? String(input.limit) : undefined,
|
|
167
|
-
}));
|
|
168
|
-
}
|
|
169
136
|
if (name === 'pr_status') {
|
|
170
137
|
if (typeof input.ref !== 'string')
|
|
171
138
|
return fail('ref required');
|
package/dist/commands/pr.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { loadToken } from '../utils/auth.js';
|
|
3
3
|
import { fetchAutoFixManifest, fetchRatingSynthesis } from '../utils/analysis-api.js';
|
|
4
|
-
import {
|
|
4
|
+
import { fetchGitHubJson, haystackJson, HaystackApiError } from '../utils/haystack-api.js';
|
|
5
5
|
import { parsePrRef } from '../utils/pr-ref.js';
|
|
6
6
|
import { toPublicVerdict } from '../states.js';
|
|
7
7
|
import { withSchema } from '../schema.js';
|
|
@@ -59,10 +59,9 @@ export async function fetchPrStatePayload(ref) {
|
|
|
59
59
|
if (!token)
|
|
60
60
|
throw new Error('Not authenticated. Run `haystack login` first.');
|
|
61
61
|
const meta = await fetchGitHubJson(`/repos/${pr.owner}/${pr.repo}/pulls/${pr.prNumber}`, token);
|
|
62
|
-
const [synthesis, manifest,
|
|
62
|
+
const [synthesis, manifest, merge] = await Promise.all([
|
|
63
63
|
fetchRatingSynthesis(pr.owner, pr.repo, pr.prNumber, token),
|
|
64
64
|
fetchAutoFixManifest(pr.owner, pr.repo, pr.prNumber, token),
|
|
65
|
-
fetchAnalysisArtifact(pr.owner, pr.repo, pr.prNumber, 'entire_traces.json', token),
|
|
66
65
|
fetchMergePublicState(meta, pr.prNumber, pr.owner, pr.repo, token),
|
|
67
66
|
]);
|
|
68
67
|
const payload = {
|
|
@@ -77,10 +76,6 @@ export async function fetchPrStatePayload(ref) {
|
|
|
77
76
|
}
|
|
78
77
|
: { status: 'pending', verdict: null, findings_count: 0 },
|
|
79
78
|
merge,
|
|
80
|
-
traces: {
|
|
81
|
-
available: traces?.hasTraces === true,
|
|
82
|
-
count: traces?.traces?.length ?? 0,
|
|
83
|
-
},
|
|
84
79
|
};
|
|
85
80
|
if (manifest) {
|
|
86
81
|
const fixed = manifest.fixedItems.length;
|
package/dist/commands/setup.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* 5. Scan for review policies
|
|
10
10
|
* 6. Review discovered items (toggle on/off)
|
|
11
11
|
* 7. Confirm & write .haystack.json to selected repos
|
|
12
|
-
* 8.
|
|
12
|
+
* 8. Offer to install local Haystack hooks
|
|
13
13
|
*/
|
|
14
14
|
/**
|
|
15
15
|
* Flags accepted by `haystack setup`. With none, it runs the interactive TTY
|
|
@@ -23,7 +23,6 @@ export interface SetupOptions {
|
|
|
23
23
|
repos?: string[];
|
|
24
24
|
yes?: boolean;
|
|
25
25
|
autoMerge?: boolean;
|
|
26
|
-
skipEntire?: boolean;
|
|
27
26
|
answersFile?: string;
|
|
28
27
|
}
|
|
29
28
|
export declare function setupCommand(options?: SetupOptions): Promise<void>;
|