@haystackeditor/cli 0.8.0 → 0.9.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 (76) hide show
  1. package/README.md +105 -12
  2. package/dist/assets/hooks/agent-context/detect.ts +136 -0
  3. package/dist/assets/hooks/agent-context/format.ts +99 -0
  4. package/dist/assets/hooks/agent-context/index.ts +39 -0
  5. package/dist/assets/hooks/agent-context/parsers/claude.ts +253 -0
  6. package/dist/assets/hooks/agent-context/parsers/gemini.ts +155 -0
  7. package/dist/assets/hooks/agent-context/parsers/opencode.ts +174 -0
  8. package/dist/assets/hooks/agent-context/tsconfig.json +13 -0
  9. package/dist/assets/hooks/agent-context/types.ts +58 -0
  10. package/dist/assets/hooks/llm-rules-template.md +56 -0
  11. package/dist/assets/hooks/package.json +11 -0
  12. package/dist/assets/hooks/scripts/commit-msg.sh +4 -0
  13. package/dist/assets/hooks/scripts/post-commit.sh +4 -0
  14. package/dist/assets/hooks/scripts/pre-commit.sh +92 -0
  15. package/dist/assets/hooks/scripts/pre-push.sh +25 -0
  16. package/dist/assets/hooks/scripts/prepare-commit-msg.sh +3 -0
  17. package/dist/assets/hooks/truncation-checker/ast-analyzer.ts +528 -0
  18. package/dist/assets/hooks/truncation-checker/index.ts +595 -0
  19. package/dist/assets/hooks/truncation-checker/tsconfig.json +13 -0
  20. package/dist/assets/skills/prepare-haystack.md +323 -0
  21. package/dist/assets/skills/secrets.md +164 -0
  22. package/dist/assets/skills/setup-external-sandbox.md +243 -0
  23. package/dist/assets/skills/setup-haystack.md +639 -0
  24. package/dist/assets/skills/submit.md +154 -0
  25. package/dist/assets/templates/CLAUDE.md.snippet +42 -0
  26. package/dist/assets/templates/haystack.yml +193 -0
  27. package/dist/commands/check-pending.d.ts +19 -0
  28. package/dist/commands/check-pending.js +217 -0
  29. package/dist/commands/config.d.ts +18 -12
  30. package/dist/commands/config.js +327 -52
  31. package/dist/commands/hooks.d.ts +17 -0
  32. package/dist/commands/hooks.js +269 -0
  33. package/dist/commands/install-session-hooks.d.ts +16 -0
  34. package/dist/commands/install-session-hooks.js +302 -0
  35. package/dist/commands/login.js +1 -1
  36. package/dist/commands/policy.d.ts +31 -0
  37. package/dist/commands/policy.js +365 -0
  38. package/dist/commands/skills.d.ts +8 -0
  39. package/dist/commands/skills.js +80 -0
  40. package/dist/commands/submit.d.ts +22 -0
  41. package/dist/commands/submit.js +428 -0
  42. package/dist/commands/triage.d.ts +16 -0
  43. package/dist/commands/triage.js +354 -0
  44. package/dist/index.d.ts +3 -0
  45. package/dist/index.js +317 -2
  46. package/dist/tools/detect.d.ts +50 -0
  47. package/dist/tools/detect.js +853 -0
  48. package/dist/tools/fixtures.d.ts +38 -0
  49. package/dist/tools/fixtures.js +199 -0
  50. package/dist/tools/setup.d.ts +43 -0
  51. package/dist/tools/setup.js +597 -0
  52. package/dist/triage/prompts.d.ts +31 -0
  53. package/dist/triage/prompts.js +266 -0
  54. package/dist/triage/runner.d.ts +21 -0
  55. package/dist/triage/runner.js +325 -0
  56. package/dist/triage/traces.d.ts +20 -0
  57. package/dist/triage/traces.js +305 -0
  58. package/dist/triage/types.d.ts +47 -0
  59. package/dist/triage/types.js +7 -0
  60. package/dist/types.d.ts +1387 -191
  61. package/dist/types.js +254 -2
  62. package/dist/utils/analysis-api.d.ts +108 -0
  63. package/dist/utils/analysis-api.js +194 -0
  64. package/dist/utils/config.js +1 -1
  65. package/dist/utils/git.d.ts +80 -0
  66. package/dist/utils/git.js +302 -0
  67. package/dist/utils/github-api.d.ts +83 -0
  68. package/dist/utils/github-api.js +266 -0
  69. package/dist/utils/hooks.d.ts +26 -0
  70. package/dist/utils/hooks.js +226 -0
  71. package/dist/utils/pending-state.d.ts +38 -0
  72. package/dist/utils/pending-state.js +86 -0
  73. package/dist/utils/secrets.js +3 -3
  74. package/dist/utils/skill.d.ts +1 -1
  75. package/dist/utils/skill.js +658 -1
  76. package/package.json +5 -3
package/dist/index.js CHANGED
@@ -9,6 +9,9 @@
9
9
  * npx @haystackeditor/cli init # Set up .haystack.json
10
10
  * npx @haystackeditor/cli status # Check configuration
11
11
  * npx @haystackeditor/cli login # Authenticate with GitHub
12
+ * npx @haystackeditor/cli submit # Create a PR (auto-merge or review)
13
+ * npx @haystackeditor/cli check-pending # Check analysis status
14
+ * npx @haystackeditor/cli triage 123 # View analysis results for a PR
12
15
  * npx @haystackeditor/cli secrets list # List stored secrets
13
16
  */
14
17
  import { Command } from 'commander';
@@ -16,12 +19,19 @@ import { statusCommand } from './commands/status.js';
16
19
  import { initCommand } from './commands/init.js';
17
20
  import { loginCommand, logoutCommand } from './commands/login.js';
18
21
  import { listSecrets, setSecret, getSecret, getSecretsForRepo, deleteSecret } from './commands/secrets.js';
19
- import { handleSandbox } from './commands/config.js';
22
+ import { handleSandbox, handleAgenticTool, handleAutoMerge, handleWaitForReviewers } from './commands/config.js';
23
+ import { installSkills, listSkills } from './commands/skills.js';
24
+ import { hooksInstall, hooksStatus, hooksUpdate } from './commands/hooks.js';
25
+ import { submitCommand } from './commands/submit.js';
26
+ import { checkPendingCommand } from './commands/check-pending.js';
27
+ import { installSessionHooks, sessionHooksStatus } from './commands/install-session-hooks.js';
28
+ import { listPolicies, addPolicy, removePolicy, initPolicies, addInstruction } from './commands/policy.js';
29
+ import { triageCommand } from './commands/triage.js';
20
30
  const program = new Command();
21
31
  program
22
32
  .name('haystack')
23
33
  .description('Set up Haystack verification for your project')
24
- .version('0.3.0');
34
+ .version('0.9.0');
25
35
  program
26
36
  .command('init')
27
37
  .description('Create .haystack.json configuration')
@@ -48,6 +58,107 @@ program
48
58
  .command('logout')
49
59
  .description('Remove stored credentials')
50
60
  .action(logoutCommand);
61
+ program
62
+ .command('submit')
63
+ .description('Create a PR from current changes')
64
+ .option('--title <title>', 'PR title (default: last commit message)')
65
+ .option('--body <body>', 'PR body (default: commit messages since base)')
66
+ .option('--body-file <path>', 'Read PR body from file (use "-" for stdin)')
67
+ .option('--base <branch>', 'Base branch (default: main or master)')
68
+ .option('--draft', 'Create as draft PR')
69
+ .option('--review [reviewer]', 'Request human review (BLOCKS auto-merge — only use when explicitly asked)')
70
+ .option('--force', 'Skip pre-PR triage checks')
71
+ .option('--no-wait', 'Skip waiting for analysis results')
72
+ .addHelpText('after', `
73
+ This command is designed for AI coding agents to submit PRs.
74
+
75
+ 1. Runs pre-PR triage (code review, rules, intent drift) via sub-agents
76
+ 2. Pushes the current branch to origin
77
+ 3. Creates a pull request on GitHub
78
+ 4. Waits for Haystack analysis results (triggered via GitHub App webhook)
79
+
80
+ Pre-PR Triage:
81
+ Before creating the PR, haystack spawns parallel sub-agents to check for:
82
+ • Code review bugs (logic errors, null crashes, security issues)
83
+ • Rule violations (from .haystack/pr-rules.yml)
84
+ • Intent drift (AI agent deviations from user instructions)
85
+
86
+ Use --force to skip triage entirely.
87
+ Use --no-wait to skip waiting for analysis results.
88
+
89
+ Review Routing:
90
+ By default, PRs enter the auto-merge queue and merge automatically once
91
+ Haystack analysis passes. This is the correct default for most PRs.
92
+
93
+ ⚠ Only use --review when the user EXPLICITLY asks for human review.
94
+ --review BLOCKS auto-merge — the PR will NOT merge until a human approves,
95
+ which delays merging. Do not add --review "just to be safe".
96
+
97
+ • --review Labels the PR "haystack:needs-review" for the
98
+ needs-assignment queue (a teammate will pick it up)
99
+ • --review <username> Same label, plus requests review from that GitHub user
100
+
101
+ Examples:
102
+ haystack submit # Triage, create PR, auto-merge queue
103
+ haystack submit --force # Skip triage
104
+ haystack submit --no-wait # Don't wait for analysis
105
+ haystack submit --title "Fix auth" # Custom PR title
106
+ haystack submit --body "## Summary" # Custom PR body (inline)
107
+ haystack submit --body-file body.md # Read body from file (supports markdown)
108
+ echo "## Summary" | haystack submit --body-file - # Read body from stdin
109
+ haystack submit --base develop # Target a different base branch
110
+ haystack submit --draft # Create as draft PR
111
+ haystack submit --review # ⚠ Blocks auto-merge, needs human approval
112
+ haystack submit --review octocat # ⚠ Blocks auto-merge, requests review from octocat
113
+ `)
114
+ .action(submitCommand);
115
+ program
116
+ .command('check-pending')
117
+ .description('Check status of pending Haystack analysis')
118
+ .option('--json', 'Output as JSON')
119
+ .option('--hook', 'Minimal output for session-start hooks')
120
+ .option('--clear', 'Clear pending submit state')
121
+ .addHelpText('after', `
122
+ After \`haystack submit\`, this checks whether the analysis finished
123
+ and shows a two-state verdict:
124
+
125
+ Good to merge — No issues found, safe to merge
126
+ Needs your input — Bugs or rule violations found
127
+
128
+ This runs automatically on CLI session start if session hooks are installed.
129
+
130
+ Examples:
131
+ haystack check-pending # Rich terminal output
132
+ haystack check-pending --hook # Minimal output (for hooks)
133
+ haystack check-pending --json # Machine-readable JSON
134
+ haystack check-pending --clear # Clear pending state
135
+ `)
136
+ .action(checkPendingCommand);
137
+ program
138
+ .command('triage <pr>')
139
+ .description('View Haystack analysis results for a PR')
140
+ .option('--json', 'Output as JSON')
141
+ .option('--no-wait', 'Exit immediately if analysis is still pending')
142
+ .addHelpText('after', `
143
+ Look up triage results (bugs, rule violations, verdict) for any PR.
144
+
145
+ PR identifier formats:
146
+ 123 PR number (uses current repo)
147
+ #123 PR number with hash
148
+ owner/repo#123 Fully qualified
149
+ https://github.com/owner/repo/pull/123 GitHub URL
150
+
151
+ By default, if analysis is still in progress, the command will poll
152
+ for up to 5 minutes. Use --no-wait to exit immediately instead.
153
+
154
+ Examples:
155
+ haystack triage 42 # Current repo, PR #42
156
+ haystack triage acme/widgets#99 # Specific repo
157
+ haystack triage https://github.com/o/r/pull/1 # From URL
158
+ haystack triage 42 --json # Machine-readable output
159
+ haystack triage 42 --no-wait # Don't wait if pending
160
+ `)
161
+ .action(triageCommand);
51
162
  // Secrets subcommands
52
163
  const secrets = program
53
164
  .command('secrets')
@@ -101,6 +212,210 @@ Examples:
101
212
  haystack config sandbox off # Disable sandbox mode
102
213
  `)
103
214
  .action(handleSandbox);
215
+ config
216
+ .command('agentic-tool [tool]')
217
+ .description('Set agentic tool (opencode|claude-code|codex|status)')
218
+ .addHelpText('after', `
219
+ Tools:
220
+ opencode OpenCode (Haystack billing) - default
221
+ claude-code Claude Code (your Claude Max subscription)
222
+ codex Codex CLI (your ChatGPT subscription)
223
+ status Show current setting (default)
224
+
225
+ This sets your account-level default. Projects can override
226
+ this in .haystack.json under agentic.tool.
227
+
228
+ Examples:
229
+ haystack config agentic-tool # Show current setting
230
+ haystack config agentic-tool opencode # Use Haystack billing
231
+ haystack config agentic-tool claude-code # Use your Claude Max
232
+ haystack config agentic-tool codex # Use your ChatGPT
233
+ `)
234
+ .action(handleAgenticTool);
235
+ config
236
+ .command('auto-merge [action]')
237
+ .description('Auto-merge safe PRs submitted via haystack submit (on|off|status)')
238
+ .addHelpText('after', `
239
+ Actions:
240
+ on, enable Enable auto-merge for safe PRs
241
+ off, disable Disable auto-merge
242
+ status Show current status (default)
243
+
244
+ When enabled, PRs submitted via \`haystack submit\` will be
245
+ automatically merged if Haystack analysis finds no issues
246
+ (safe to merge). PRs with bugs or rule violations still
247
+ require manual review.
248
+
249
+ Examples:
250
+ haystack config auto-merge # Show current status
251
+ haystack config auto-merge on # Enable auto-merge
252
+ haystack config auto-merge off # Disable auto-merge
253
+ `)
254
+ .action(handleAutoMerge);
255
+ config
256
+ .command('wait-for-reviewers [action] [reviewers...]')
257
+ .description('Configure which AI reviewers the merge queue waits for')
258
+ .addHelpText('after', `
259
+ Actions:
260
+ list Show current expected reviewers (default)
261
+ add <names> Add one or more AI reviewer sources
262
+ remove <names> Remove one or more AI reviewer sources
263
+ clear Remove all expected reviewers
264
+
265
+ AI reviewer sources are stored in .haystack.json under
266
+ babysitter.expected_ai_reviewers. The merge queue will
267
+ wait for these reviewers to post before starting the
268
+ grace period.
269
+
270
+ Run \`haystack config wait-for-reviewers list\` to see
271
+ all available reviewer sources and which are enabled.
272
+
273
+ Examples:
274
+ haystack config wait-for-reviewers # Show status
275
+ haystack config wait-for-reviewers add cursor # Wait for Cursor BugBot
276
+ haystack config wait-for-reviewers add cursor coderabbit # Add multiple
277
+ haystack config wait-for-reviewers remove cursor # Stop waiting for Cursor
278
+ haystack config wait-for-reviewers clear # Wait for none
279
+ `)
280
+ .action(handleWaitForReviewers);
281
+ // Skills subcommands
282
+ const skills = program
283
+ .command('skills')
284
+ .description('Manage AI skills for Claude Code');
285
+ skills
286
+ .command('install')
287
+ .description('Install Haystack skills into your coding CLI')
288
+ .option('--cli <name>', 'Target CLI: claude, codex, cursor, or manual')
289
+ .addHelpText('after', `
290
+ This registers the Haystack MCP server with your coding CLI, enabling:
291
+ /setup-haystack - AI-assisted project setup
292
+ /prepare-haystack - Add accessibility attributes
293
+ /setup-haystack-secrets - Configure secrets
294
+
295
+ Supported CLIs:
296
+ claude Claude Code (auto-detected)
297
+ codex Codex CLI (auto-detected)
298
+ cursor Cursor IDE (auto-detected)
299
+ manual Show manual setup instructions
300
+
301
+ Examples:
302
+ haystack skills install # Auto-detect and install
303
+ haystack skills install --cli codex # Install for Codex only
304
+ haystack skills install --cli manual # Show manual instructions
305
+ `)
306
+ .action(installSkills);
307
+ skills
308
+ .command('list')
309
+ .description('List available Haystack skills')
310
+ .action(listSkills);
311
+ // Hooks subcommands
312
+ const hooks = program
313
+ .command('hooks')
314
+ .description('Manage git hooks for AI agent quality checks');
315
+ hooks
316
+ .command('install')
317
+ .description('Install Haystack git hooks and Entire CLI')
318
+ .option('--version <version>', 'Entire CLI version (default: pinned)')
319
+ .option('-f, --force', 'Overwrite existing hooks')
320
+ .option('--skip-entire', 'Skip Entire binary download')
321
+ .addHelpText('after', `
322
+ This installs:
323
+ • Git hooks for AI agent quality checks (pre-commit, commit-msg, etc.)
324
+ • Agent context detector (identifies AI agent sessions)
325
+ • Truncation checker (prevents code truncation by LLMs)
326
+ • Entire CLI binary for session tracking (powered by https://entire.dev)
327
+
328
+ Hooks are installed to <repo>/hooks/ and git is configured to use them.
329
+
330
+ Examples:
331
+ haystack hooks install # Install with pinned Entire version
332
+ haystack hooks install --force # Overwrite existing hooks
333
+ haystack hooks install --skip-entire # Only install Haystack hooks
334
+ `)
335
+ .action(hooksInstall);
336
+ hooks
337
+ .command('status')
338
+ .description('Check hooks installation status')
339
+ .action(hooksStatus);
340
+ hooks
341
+ .command('update')
342
+ .description('Update Entire CLI to the latest version')
343
+ .action(hooksUpdate);
344
+ hooks
345
+ .command('install-session')
346
+ .description('Install session-start hooks for coding CLIs')
347
+ .option('--cli <name>', 'Target CLI: claude, codex, gemini, or all')
348
+ .addHelpText('after', `
349
+ Configures your coding CLI to run \`haystack check-pending\` on session start.
350
+ This shows pending PR analysis results when you open a new terminal session.
351
+
352
+ Claude Code: Native SessionStart hook (.claude/settings.json)
353
+ Codex CLI: AGENTS.md instructions
354
+ Gemini CLI: GEMINI.md instructions
355
+
356
+ Examples:
357
+ haystack hooks install-session # Auto-detect CLIs
358
+ haystack hooks install-session --cli claude # Claude Code only
359
+ haystack hooks install-session --cli all # All detected CLIs
360
+ `)
361
+ .action(installSessionHooks);
362
+ hooks
363
+ .command('session-status')
364
+ .description('Check session hook installation status')
365
+ .action(sessionHooksStatus);
366
+ // Policy subcommands
367
+ const policy = program
368
+ .command('policy')
369
+ .description('Manage review policies (.haystack/review-policy.md)');
370
+ policy
371
+ .command('list')
372
+ .description('List all review policies')
373
+ .action(listPolicies);
374
+ policy
375
+ .command('add [name]')
376
+ .description('Add a new review policy interactively')
377
+ .addHelpText('after', `
378
+ This command prompts for:
379
+ • Policy name (e.g., "Infrastructure changes")
380
+ • File patterns (comma-separated globs, e.g., "terraform/**,*.tf")
381
+ • Severity (critical, high, medium, low)
382
+ • Reason (why this requires human review)
383
+
384
+ Examples:
385
+ haystack policy add # Interactive add
386
+ haystack policy add "Database changes" # Start with name
387
+ `)
388
+ .action(addPolicy);
389
+ policy
390
+ .command('remove <name>')
391
+ .description('Remove a review policy by name')
392
+ .action(removePolicy);
393
+ policy
394
+ .command('add-instruction [text]')
395
+ .description('Add a semantic review instruction')
396
+ .addHelpText('after', `
397
+ Instructions are natural language directives that override default review behavior.
398
+ They apply to all PRs (not file-pattern-gated).
399
+
400
+ Examples:
401
+ haystack policy add-instruction "Never flag weak test coverage as needing review"
402
+ haystack policy add-instruction # Interactive prompt
403
+ `)
404
+ .action(addInstruction);
405
+ policy
406
+ .command('init')
407
+ .description('Create initial review-policy.md with example policies')
408
+ .option('-f, --force', 'Overwrite existing file')
409
+ .addHelpText('after', `
410
+ Creates .haystack/review-policy.md with sensible defaults:
411
+ • Infrastructure changes (terraform, pulumi, cdk)
412
+ • Secret files (*.secret*, *.env*, credentials)
413
+ • CI/CD pipelines (GitHub Actions, GitLab CI, etc.)
414
+
415
+ The generated policies appear in Haystack's "Human Review Needed"
416
+ section when a PR touches matching files.
417
+ `)
418
+ .action(initPolicies);
104
419
  // Show help if no command provided
105
420
  if (process.argv.length === 2) {
106
421
  program.help();
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Auto-detection utilities for framework, monorepo, and service configuration.
3
+ * Used by the setup wizard to provide smart defaults.
4
+ */
5
+ export interface DetectedFramework {
6
+ name: string;
7
+ devCommand: string;
8
+ port: number;
9
+ readyPattern: string;
10
+ configFile: string;
11
+ }
12
+ export interface DetectedService {
13
+ name: string;
14
+ root: string;
15
+ type: 'server' | 'batch';
16
+ framework?: DetectedFramework;
17
+ /** Services this service depends on (detected from proxy config) */
18
+ depends_on?: string[];
19
+ }
20
+ export interface ProxyTarget {
21
+ /** Path pattern being proxied (e.g., "/api") */
22
+ path: string;
23
+ /** Target URL (e.g., "http://localhost:8787") */
24
+ target: string;
25
+ /** Port extracted from target */
26
+ port: number;
27
+ }
28
+ export interface ProjectDetection {
29
+ isMonorepo: boolean;
30
+ packageManager: 'npm' | 'pnpm' | 'yarn' | 'bun';
31
+ frameworks: DetectedFramework[];
32
+ services: DetectedService[];
33
+ /** Proxy targets detected from config files */
34
+ proxyTargets: ProxyTarget[];
35
+ suggestions: {
36
+ projectName: string;
37
+ devCommand: string;
38
+ port: number;
39
+ readyPattern: string;
40
+ authBypassEnv?: string;
41
+ };
42
+ }
43
+ /**
44
+ * Main detection function - analyzes a project directory
45
+ */
46
+ export declare function detectProject(rootDir?: string): ProjectDetection;
47
+ /**
48
+ * Format detection results for display to user
49
+ */
50
+ export declare function formatDetectionSummary(detection: ProjectDetection): string;