@haystackeditor/cli 0.10.3 → 0.12.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 (42) hide show
  1. package/README.md +15 -16
  2. package/dist/assets/hooks/agent-context/detect.ts +180 -0
  3. package/dist/assets/hooks/agent-context/format.ts +1 -0
  4. package/dist/assets/hooks/agent-context/index.ts +2 -0
  5. package/dist/assets/hooks/agent-context/parsers/claude.ts +14 -5
  6. package/dist/assets/hooks/agent-context/parsers/codex.ts +416 -0
  7. package/dist/assets/hooks/agent-context/tsconfig.json +1 -0
  8. package/dist/assets/hooks/agent-context/types.ts +1 -1
  9. package/dist/assets/hooks/package.json +2 -1
  10. package/dist/assets/hooks/scripts/pre-commit.sh +80 -2
  11. package/dist/assets/hooks/scripts/pre-push.sh +1 -1
  12. package/dist/assets/skills/submit.md +20 -0
  13. package/dist/commands/config.d.ts +4 -0
  14. package/dist/commands/config.js +94 -69
  15. package/dist/commands/dismiss.js +2 -1
  16. package/dist/commands/install-session-hooks.d.ts +3 -2
  17. package/dist/commands/install-session-hooks.js +27 -11
  18. package/dist/commands/pr-status.d.ts +5 -0
  19. package/dist/commands/pr-status.js +2 -2
  20. package/dist/commands/request-review.d.ts +15 -0
  21. package/dist/commands/request-review.js +95 -0
  22. package/dist/commands/setup.d.ts +1 -0
  23. package/dist/commands/setup.js +285 -2
  24. package/dist/commands/submit.d.ts +1 -0
  25. package/dist/commands/submit.js +12 -19
  26. package/dist/commands/triage.d.ts +16 -4
  27. package/dist/commands/triage.js +278 -179
  28. package/dist/index.d.ts +2 -1
  29. package/dist/index.js +73 -50
  30. package/dist/triage/prompts.js +13 -5
  31. package/dist/triage/runner.js +1 -1
  32. package/dist/triage/traces.js +9 -3
  33. package/dist/triage/types.d.ts +1 -1
  34. package/dist/types.d.ts +146 -26
  35. package/dist/types.js +44 -5
  36. package/dist/utils/analysis-api.d.ts +16 -0
  37. package/dist/utils/analysis-api.js +23 -5
  38. package/dist/utils/telemetry.d.ts +17 -0
  39. package/dist/utils/telemetry.js +109 -0
  40. package/package.json +1 -1
  41. package/dist/commands/check-pending.d.ts +0 -19
  42. package/dist/commands/check-pending.js +0 -217
package/dist/index.js CHANGED
@@ -11,10 +11,11 @@
11
11
  * npx @haystackeditor/cli status # Check configuration
12
12
  * npx @haystackeditor/cli login # Authenticate with GitHub
13
13
  * npx @haystackeditor/cli submit # Create a PR (auto-merge or review)
14
- * npx @haystackeditor/cli check-pending # Check analysis status
14
+ * npx @haystackeditor/cli triage # Check last submitted PR
15
15
  * npx @haystackeditor/cli triage 123 # View analysis results for a PR
16
16
  * npx @haystackeditor/cli dismiss 123 # Dismiss findings for a PR
17
17
  * npx @haystackeditor/cli mark-reviewed 123 # Mark review as not needed
18
+ * npx @haystackeditor/cli request-review 123 # Tag a PR as needing human review
18
19
  * npx @haystackeditor/cli pr-status 123 # Show PR status in Haystack pipeline
19
20
  * npx @haystackeditor/cli config # Manage preferences
20
21
  */
@@ -22,22 +23,22 @@ import { Command } from 'commander';
22
23
  import { statusCommand } from './commands/status.js';
23
24
  import { initCommand } from './commands/init.js';
24
25
  import { loginCommand, logoutCommand } from './commands/login.js';
25
- import { handleAgenticTool, handleAutoMerge, handleWaitForReviewers } from './commands/config.js';
26
+ import { handleAgenticTool, handleAutoMerge, handleWaitForReviewers, isAutoMergeEnabled } from './commands/config.js';
26
27
  import { installSkills, listSkills } from './commands/skills.js';
27
28
  import { hooksInstall, hooksStatus, hooksUpdate } from './commands/hooks.js';
28
29
  import { submitCommand } from './commands/submit.js';
29
- import { checkPendingCommand } from './commands/check-pending.js';
30
30
  import { installSessionHooks, sessionHooksStatus } from './commands/install-session-hooks.js';
31
31
  import { listPolicies, addPolicy, removePolicy, initPolicies, addInstruction } from './commands/policy.js';
32
32
  import { triageCommand } from './commands/triage.js';
33
33
  import { dismissCommand, markReviewedCommand, undismissCommand } from './commands/dismiss.js';
34
+ import { requestReviewCommand } from './commands/request-review.js';
34
35
  import { prStatusCommand } from './commands/pr-status.js';
35
36
  import { setupCommand } from './commands/setup.js';
36
37
  const program = new Command();
37
38
  program
38
39
  .name('haystack')
39
40
  .description('Haystack CLI — automated PR review, triage, and merge queue')
40
- .version('0.10.3');
41
+ .version('0.11.0');
41
42
  program
42
43
  .command('init')
43
44
  .description('Create .haystack.json configuration')
@@ -93,12 +94,13 @@ program
93
94
  .option('--draft', 'Create as draft PR')
94
95
  .option('--review [reviewer]', 'Request human review (BLOCKS auto-merge — only use when explicitly asked)')
95
96
  .option('--force', 'Skip pre-PR triage checks')
96
- .option('--auto-fix', 'Auto-fix analysis issues before surfacing to Feed')
97
+ .option('--auto-fix', 'Alpha auto-fix for straightforward mechanical issues (discouraged)')
98
+ .option('--auto-merge', 'Apply auto-merge label (default: from .haystack.json, --no-auto-merge to disable)')
97
99
  .option('--no-wait', 'Skip waiting for analysis results')
98
100
  .addHelpText('after', `
99
101
  This command is designed for AI coding agents to submit PRs.
100
102
 
101
- 1. Runs pre-PR triage (code review, rules, intent drift) via sub-agents
103
+ 1. Runs pre-PR triage (code review, rules, instruction drift) via sub-agents
102
104
  2. Pushes the current branch to origin
103
105
  3. Creates a pull request on GitHub
104
106
  4. Waits for Haystack analysis results (triggered via GitHub App webhook)
@@ -107,16 +109,21 @@ Pre-PR Triage:
107
109
  Before creating the PR, haystack spawns parallel sub-agents to check for:
108
110
  • Code review bugs (logic errors, null crashes, security issues)
109
111
  • Rule violations (from .haystack/pr-rules.yml)
110
- Intent drift (AI agent deviations from user instructions)
112
+ Instruction drift (AI agent deviations from user instructions)
111
113
 
112
114
  Use --force to skip triage entirely.
113
115
  Use --no-wait to skip waiting for analysis results.
114
- Use --auto-fix to auto-fix analysis issues before surfacing to Feed.
116
+ Use --auto-fix only when explicitly opting into the alpha fixer for
117
+ straightforward mechanical issues.
115
118
 
116
119
  Review Routing:
117
120
  By default, PRs enter the auto-merge queue and merge automatically once
118
121
  Haystack analysis passes. This is the correct default for most PRs.
119
122
 
123
+ ⚠ --auto-fix is currently alpha and discouraged by default. Prefer plain
124
+ haystack submit unless you explicitly want the sandbox fixer to attempt
125
+ straightforward mechanical fixes before issues hit the Feed.
126
+
120
127
  ⚠ Only use --review when the user EXPLICITLY asks for human review.
121
128
  --review BLOCKS auto-merge — the PR will NOT merge until a human approves,
122
129
  which delays merging. Do not add --review "just to be safe".
@@ -126,8 +133,8 @@ Review Routing:
126
133
  • --review <username> Same label, plus requests review from that GitHub user
127
134
 
128
135
  Examples:
129
- haystack submit --auto-fix # Recommended: triage, create PR, auto-fix issues
130
- haystack submit # Triage, create PR, auto-merge queue (no auto-fix)
136
+ haystack submit # Recommended: triage, create PR, auto-merge queue
137
+ haystack submit --auto-fix # Discouraged alpha: auto-fix straightforward mechanical issues
131
138
  haystack submit --force # Skip triage
132
139
  haystack submit --no-wait # Don't wait for analysis
133
140
  haystack submit --title "Fix auth" # Custom PR title
@@ -139,38 +146,28 @@ Examples:
139
146
  haystack submit --review # ⚠ Blocks auto-merge, needs human approval
140
147
  haystack submit --review octocat # ⚠ Blocks auto-merge, requests review from octocat
141
148
  `)
142
- .action(submitCommand);
143
- program
144
- .command('check-pending')
145
- .description('Check status of pending Haystack analysis')
146
- .option('--json', 'Output as JSON')
147
- .option('--hook', 'Minimal output for session-start hooks')
148
- .option('--clear', 'Clear pending submit state')
149
- .addHelpText('after', `
150
- After \`haystack submit\`, this checks whether the analysis finished
151
- and shows a two-state verdict:
152
-
153
- Good to merge — No issues found, safe to merge
154
- Needs your input — Bugs or rule violations found
155
-
156
- This runs automatically on CLI session start if session hooks are installed.
157
-
158
- Examples:
159
- haystack check-pending # Rich terminal output
160
- haystack check-pending --hook # Minimal output (for hooks)
161
- haystack check-pending --json # Machine-readable JSON
162
- haystack check-pending --clear # Clear pending state
163
- `)
164
- .action(checkPendingCommand);
149
+ .action(async (options) => {
150
+ // Resolve --auto-merge default from .haystack.json when not explicitly set
151
+ if (options.autoMerge === undefined) {
152
+ options.autoMerge = await isAutoMergeEnabled();
153
+ }
154
+ return submitCommand(options);
155
+ });
165
156
  program
166
- .command('triage <pr>')
157
+ .command('triage [pr]')
167
158
  .description('View Haystack analysis results for a PR')
168
159
  .option('--json', 'Output as JSON')
160
+ .option('--hook', 'Minimal single-line output for session-start hooks')
161
+ .option('--clear', 'Clear pending submit state')
169
162
  .option('--no-wait', 'Exit immediately if analysis is still pending')
170
163
  .addHelpText('after', `
171
164
  Look up triage results (bugs, rule violations, verdict) for any PR.
165
+ When called without a PR identifier, checks the last submitted PR.
166
+
167
+ Runs automatically on CLI session start if session hooks are installed.
172
168
 
173
169
  PR identifier formats:
170
+ (none) Last submitted PR
174
171
  123 PR number (uses current repo)
175
172
  #123 PR number with hash
176
173
  owner/repo#123 Fully qualified
@@ -180,11 +177,14 @@ By default, if analysis is still in progress, the command will poll
180
177
  for up to 5 minutes. Use --no-wait to exit immediately instead.
181
178
 
182
179
  Examples:
180
+ haystack triage # Last submitted PR
183
181
  haystack triage 42 # Current repo, PR #42
184
182
  haystack triage acme/widgets#99 # Specific repo
185
183
  haystack triage https://github.com/o/r/pull/1 # From URL
186
184
  haystack triage 42 --json # Machine-readable output
187
185
  haystack triage 42 --no-wait # Don't wait if pending
186
+ haystack triage --hook # Session-start hook output
187
+ haystack triage --clear # Clear pending state
188
188
  `)
189
189
  .action(triageCommand);
190
190
  program
@@ -247,6 +247,29 @@ Examples:
247
247
  haystack undismiss acme/widgets#99 # Undo for specific repo
248
248
  `)
249
249
  .action(undismissCommand);
250
+ program
251
+ .command('request-review <pr> [reviewer]')
252
+ .description('Tag a PR as needing human review')
253
+ .addHelpText('after', `
254
+ Tag any PR with "needs human review", even after it was created.
255
+ Adds the haystack:needs-review label to the PR, moving it from
256
+ "Good to Merge" to the "Needs Assignment" queue in the feed.
257
+
258
+ Optionally specify a reviewer to request review from a specific
259
+ GitHub user.
260
+
261
+ PR identifier formats:
262
+ 123 PR number (uses current repo)
263
+ #123 PR number with hash
264
+ owner/repo#123 Fully qualified
265
+ https://github.com/owner/repo/pull/123 GitHub URL
266
+
267
+ Examples:
268
+ haystack request-review 42 # Tag PR #42 for human review
269
+ haystack request-review 42 octocat # Tag and request review from octocat
270
+ haystack request-review acme/widgets#99 # Specific repo
271
+ `)
272
+ .action(requestReviewCommand);
250
273
  program
251
274
  .command('pr-status <pr>')
252
275
  .description('Show the current Haystack status of a PR')
@@ -317,25 +340,25 @@ config
317
340
  .description('Configure which AI reviewers the merge queue waits for')
318
341
  .addHelpText('after', `
319
342
  Actions:
320
- list Show current expected reviewers (default)
321
- add <names> Add one or more AI reviewer sources
322
- remove <names> Remove one or more AI reviewer sources
323
- clear Remove all expected reviewers
343
+ list Show configured reviewer bots (default)
344
+ add <names> Add one or more reviewer bots
345
+ remove <names> Remove one or more reviewer bots
346
+ clear Remove all reviewer bots
324
347
 
325
- AI reviewer sources are stored in .haystack.json under
326
- babysitter.expected_ai_reviewers. The merge queue will
327
- wait for these reviewers to post before starting the
328
- grace period.
348
+ Accepts friendly names (cursor, coderabbit) or exact
349
+ GitHub bot usernames (cursor-bugbot[bot]).
329
350
 
330
- Run \`haystack config wait-for-reviewers list\` to see
331
- all available reviewer sources and which are enabled.
351
+ Stored in .haystack.json under merge_queue.wait_for_reviewer.bots.
352
+ The merge queue will block merging until ALL configured
353
+ bots have posted a review or comment on the PR.
332
354
 
333
355
  Examples:
334
- haystack config wait-for-reviewers # Show status
335
- haystack config wait-for-reviewers add cursor # Wait for Cursor BugBot
336
- haystack config wait-for-reviewers add cursor coderabbit # Add multiple
337
- haystack config wait-for-reviewers remove cursor # Stop waiting for Cursor
338
- haystack config wait-for-reviewers clear # Wait for none
356
+ haystack config wait-for-reviewers # Show status
357
+ haystack config wait-for-reviewers add cursor # Wait for Cursor BugBot
358
+ haystack config wait-for-reviewers add cursor coderabbit # Add multiple
359
+ haystack config wait-for-reviewers add cursor-bugbot[bot] # Raw bot username
360
+ haystack config wait-for-reviewers remove cursor # Stop waiting
361
+ haystack config wait-for-reviewers clear # Wait for none
339
362
  `)
340
363
  .action(handleWaitForReviewers);
341
364
  // Skills subcommands
@@ -404,7 +427,7 @@ hooks
404
427
  .description('Install session-start hooks for coding CLIs')
405
428
  .option('--cli <name>', 'Target CLI: claude, codex, gemini, or all')
406
429
  .addHelpText('after', `
407
- Configures your coding CLI to run \`haystack check-pending\` on session start.
430
+ Configures your coding CLI to run \`haystack triage --hook\` on session start.
408
431
  This shows pending PR analysis results when you open a new terminal session.
409
432
 
410
433
  Claude Code: Native SessionStart hook (.claude/settings.json)
@@ -45,7 +45,7 @@ const INTENT_DRIFT_SCHEMA = `{
45
45
  "line": 42,
46
46
  "severity": "error | warning | info",
47
47
  "message": "Description of the drift or incomplete fulfillment",
48
- "pattern": "intent_drift | incomplete_fulfillment"
48
+ "pattern": "intent_drift | incomplete_fulfillment | scope_creep"
49
49
  }
50
50
  ],
51
51
  "summary": "Brief 1-sentence summary",
@@ -261,12 +261,20 @@ The agent didn't finish everything that was asked:
261
261
  - Agent said "I'll skip X for now" for something the user explicitly requested
262
262
  - Tests not written when user asked for tests
263
263
 
264
+ ### Scope Creep
265
+ The agent added functionality the user never asked for:
266
+ - User asks to fix a bug → agent also adds a cooldown, retry logic, or caching layer
267
+ - User asks to investigate → agent proactively "fixes" things beyond what was discussed
268
+ - User asks for one feature → agent bundles in extra features "while we're at it"
269
+ - Any new mechanism not traceable to a user instruction
270
+
264
271
  ## Red flags to search for in the diff
265
272
 
266
273
  - Fixed/hardcoded values where dynamic behavior was requested
267
274
  - TODO, FIXME, placeholder, stub comments in new code
268
275
  - Empty function bodies or early returns
269
276
  - Interface fields that are declared but never assigned anywhere
277
+ - New mechanisms (cooldowns, retries, caches, rate limits) not requested by the user
270
278
 
271
279
  ## Output
272
280
 
@@ -277,15 +285,15 @@ ${INTENT_DRIFT_SCHEMA}
277
285
  \`\`\`
278
286
 
279
287
  - Set \`sessionsChecked\` to the number of trace files you read
280
- - Set \`passed\` to \`true\` if no drift or incomplete fulfillment found
288
+ - Set \`passed\` to \`true\` if no drift, incomplete fulfillment, or scope creep found
281
289
  - Set \`passed\` to \`false\` if any issues with severity "error" were found
282
- - For each issue, set \`pattern\` to either "intent_drift" or "incomplete_fulfillment"
290
+ - For each issue, set \`pattern\` to "intent_drift", "incomplete_fulfillment", or "scope_creep"
283
291
  - You MUST write the result file even if no issues are found
284
292
 
285
293
  ## Severity guidelines
286
294
 
287
- - **error**: Core user intent violated — the main thing they asked for is wrong or missing
288
- - **warning**: Secondary requirement missed or approximated
295
+ - **error**: Core user intent violated — the main thing they asked for is wrong or missing, or large unrequested feature added
296
+ - **warning**: Secondary requirement missed or approximated, or small unrequested mechanism added
289
297
  - **info**: Minor simplification that mostly still works as intended${precomputedDiff ? `
290
298
 
291
299
  ## Diff (precomputed)
@@ -17,7 +17,7 @@ const TRIAGE_DIR = '.haystack/triage';
17
17
  const TIMEOUT_MS = 300_000; // 5 minutes per checker
18
18
  /** Max agentic turns per checker — kept tight since these are read-only tasks */
19
19
  const MAX_TURNS = {
20
- 'code-review': 10,
20
+ 'code-review': 5,
21
21
  'rules-validator': 10,
22
22
  'intent-drift': 10,
23
23
  };
@@ -146,7 +146,10 @@ function extractHumanText(content) {
146
146
  return null;
147
147
  const textParts = [];
148
148
  for (const block of content) {
149
- if (block?.type !== 'text' || typeof block.text !== 'string')
149
+ // Support both old ({type: "text", text}) and new ({id, text}) content blocks
150
+ if (typeof block?.text !== 'string')
151
+ continue;
152
+ if (block.type && block.type !== 'text')
150
153
  continue;
151
154
  const stripped = stripWrappers(block.text);
152
155
  if (stripped && !isSlashCommand(stripped)) {
@@ -231,9 +234,12 @@ function extractUserMessages(tracePath) {
231
234
  }
232
235
  const entries = parseJsonl(content, tracePath);
233
236
  for (const entry of entries) {
234
- if (entry?.type !== 'user')
237
+ // Support both old format (entry.message.role === 'user') and new (entry.type === 'user')
238
+ const role = entry.message?.role ?? entry?.type;
239
+ if (role !== 'user')
235
240
  continue;
236
- const msg = entry.message?.content;
241
+ // Support both old format ({message: {content}}) and new ({content} at top level)
242
+ const msg = entry.message?.content ?? entry.content;
237
243
  if (!msg)
238
244
  continue;
239
245
  const text = extractHumanText(msg);
@@ -13,7 +13,7 @@ export interface TriageIssue {
13
13
  /** For rules validator: rule ID (e.g., PR001) */
14
14
  rule?: string;
15
15
  /** For intent drift: drift pattern */
16
- pattern?: 'intent_drift' | 'incomplete_fulfillment';
16
+ pattern?: 'intent_drift' | 'incomplete_fulfillment' | 'scope_creep';
17
17
  }
18
18
  export interface CodeReviewResult {
19
19
  checker: 'code-review';
package/dist/types.d.ts CHANGED
@@ -56,7 +56,9 @@ declare const DevServerSchema: z.ZodObject<{
56
56
  /** Valid AI reviewer source identifiers that the merge queue can wait for */
57
57
  export declare const AI_REVIEWER_SOURCES: readonly ["cursor", "coderabbit", "copilot", "greptile", "sourcery", "qodo", "codeant", "ellipsis", "korbit", "panto", "bito", "graphite", "deepsource", "snyk", "codacy", "sonarcloud", "sweep", "codeguru", "codereviewer", "codium"];
58
58
  export declare const AI_REVIEWER_DISPLAY_NAMES: Record<typeof AI_REVIEWER_SOURCES[number], string>;
59
- declare const BabysitterConfigSchema: z.ZodObject<{
59
+ /** Maps friendly source names to exact GitHub bot login usernames. */
60
+ export declare const AI_REVIEWER_BOT_USERNAMES: Record<typeof AI_REVIEWER_SOURCES[number], string>;
61
+ declare const MergeQueueConfigSchema: z.ZodObject<{
60
62
  /** Enable the Haystack auto-merge queue */
61
63
  merge_queue: z.ZodOptional<z.ZodBoolean>;
62
64
  /** Automatically rebase PRs that develop merge conflicts after pushes to the base branch */
@@ -74,8 +76,40 @@ declare const BabysitterConfigSchema: z.ZodObject<{
74
76
  default_minutes?: number | undefined;
75
77
  authors?: Record<string, number> | undefined;
76
78
  }>>;
77
- /** AI reviewer sources to wait for before starting the merge grace period */
78
- expected_ai_reviewers: z.ZodOptional<z.ZodArray<z.ZodEnum<["cursor", "coderabbit", "copilot", "greptile", "sourcery", "qodo", "codeant", "ellipsis", "korbit", "panto", "bito", "graphite", "deepsource", "snyk", "codacy", "sonarcloud", "sweep", "codeguru", "codereviewer", "codium"]>, "many">>;
79
+ /** Batch multiple PRs into one CI run */
80
+ batch_merge: z.ZodOptional<z.ZodObject<{
81
+ /** Enable batch merging */
82
+ enabled: z.ZodOptional<z.ZodBoolean>;
83
+ /** Minimum PRs to form a batch */
84
+ min_batch_size: z.ZodOptional<z.ZodNumber>;
85
+ /** Maximum PRs per batch (cap: 20) */
86
+ max_batch_size: z.ZodOptional<z.ZodNumber>;
87
+ /** Seconds to wait after grace period for more PRs to accumulate (default: 30, 0 to disable) */
88
+ batch_window_seconds: z.ZodOptional<z.ZodNumber>;
89
+ }, "strip", z.ZodTypeAny, {
90
+ enabled?: boolean | undefined;
91
+ min_batch_size?: number | undefined;
92
+ max_batch_size?: number | undefined;
93
+ batch_window_seconds?: number | undefined;
94
+ }, {
95
+ enabled?: boolean | undefined;
96
+ min_batch_size?: number | undefined;
97
+ max_batch_size?: number | undefined;
98
+ batch_window_seconds?: number | undefined;
99
+ }>>;
100
+ /** Wait for external AI code reviewers before merging — all bots must post */
101
+ wait_for_reviewer: z.ZodOptional<z.ZodObject<{
102
+ /** GitHub bot usernames to wait for (e.g. "cursor-bugbot[bot]") */
103
+ bots: z.ZodArray<z.ZodString, "many">;
104
+ /** Give up waiting after this many minutes (default: 30) */
105
+ timeout_minutes: z.ZodOptional<z.ZodNumber>;
106
+ }, "strip", z.ZodTypeAny, {
107
+ bots: string[];
108
+ timeout_minutes?: number | undefined;
109
+ }, {
110
+ bots: string[];
111
+ timeout_minutes?: number | undefined;
112
+ }>>;
79
113
  }, "strip", z.ZodTypeAny, {
80
114
  merge_queue?: boolean | undefined;
81
115
  auto_resolve_conflicts?: boolean | undefined;
@@ -83,7 +117,16 @@ declare const BabysitterConfigSchema: z.ZodObject<{
83
117
  default_minutes?: number | undefined;
84
118
  authors?: Record<string, number> | undefined;
85
119
  } | undefined;
86
- expected_ai_reviewers?: ("cursor" | "coderabbit" | "copilot" | "greptile" | "sourcery" | "qodo" | "codeant" | "ellipsis" | "korbit" | "panto" | "bito" | "graphite" | "deepsource" | "snyk" | "codacy" | "sonarcloud" | "sweep" | "codeguru" | "codereviewer" | "codium")[] | undefined;
120
+ batch_merge?: {
121
+ enabled?: boolean | undefined;
122
+ min_batch_size?: number | undefined;
123
+ max_batch_size?: number | undefined;
124
+ batch_window_seconds?: number | undefined;
125
+ } | undefined;
126
+ wait_for_reviewer?: {
127
+ bots: string[];
128
+ timeout_minutes?: number | undefined;
129
+ } | undefined;
87
130
  }, {
88
131
  merge_queue?: boolean | undefined;
89
132
  auto_resolve_conflicts?: boolean | undefined;
@@ -91,7 +134,16 @@ declare const BabysitterConfigSchema: z.ZodObject<{
91
134
  default_minutes?: number | undefined;
92
135
  authors?: Record<string, number> | undefined;
93
136
  } | undefined;
94
- expected_ai_reviewers?: ("cursor" | "coderabbit" | "copilot" | "greptile" | "sourcery" | "qodo" | "codeant" | "ellipsis" | "korbit" | "panto" | "bito" | "graphite" | "deepsource" | "snyk" | "codacy" | "sonarcloud" | "sweep" | "codeguru" | "codereviewer" | "codium")[] | undefined;
137
+ batch_merge?: {
138
+ enabled?: boolean | undefined;
139
+ min_batch_size?: number | undefined;
140
+ max_batch_size?: number | undefined;
141
+ batch_window_seconds?: number | undefined;
142
+ } | undefined;
143
+ wait_for_reviewer?: {
144
+ bots: string[];
145
+ timeout_minutes?: number | undefined;
146
+ } | undefined;
95
147
  }>;
96
148
  declare const ServiceSchema: z.ZodObject<{
97
149
  /** Root directory relative to repo root */
@@ -1109,8 +1161,8 @@ export declare const HaystackConfigSchema: z.ZodObject<{
1109
1161
  services?: string[] | undefined;
1110
1162
  description?: string | undefined;
1111
1163
  }>>>;
1112
- /** Babysitter configuration for autonomous PR maintenance */
1113
- babysitter: z.ZodOptional<z.ZodObject<{
1164
+ /** Merge queue configuration for autonomous PR maintenance */
1165
+ merge_queue: z.ZodOptional<z.ZodObject<{
1114
1166
  /** Enable the Haystack auto-merge queue */
1115
1167
  merge_queue: z.ZodOptional<z.ZodBoolean>;
1116
1168
  /** Automatically rebase PRs that develop merge conflicts after pushes to the base branch */
@@ -1128,8 +1180,40 @@ export declare const HaystackConfigSchema: z.ZodObject<{
1128
1180
  default_minutes?: number | undefined;
1129
1181
  authors?: Record<string, number> | undefined;
1130
1182
  }>>;
1131
- /** AI reviewer sources to wait for before starting the merge grace period */
1132
- expected_ai_reviewers: z.ZodOptional<z.ZodArray<z.ZodEnum<["cursor", "coderabbit", "copilot", "greptile", "sourcery", "qodo", "codeant", "ellipsis", "korbit", "panto", "bito", "graphite", "deepsource", "snyk", "codacy", "sonarcloud", "sweep", "codeguru", "codereviewer", "codium"]>, "many">>;
1183
+ /** Batch multiple PRs into one CI run */
1184
+ batch_merge: z.ZodOptional<z.ZodObject<{
1185
+ /** Enable batch merging */
1186
+ enabled: z.ZodOptional<z.ZodBoolean>;
1187
+ /** Minimum PRs to form a batch */
1188
+ min_batch_size: z.ZodOptional<z.ZodNumber>;
1189
+ /** Maximum PRs per batch (cap: 20) */
1190
+ max_batch_size: z.ZodOptional<z.ZodNumber>;
1191
+ /** Seconds to wait after grace period for more PRs to accumulate (default: 30, 0 to disable) */
1192
+ batch_window_seconds: z.ZodOptional<z.ZodNumber>;
1193
+ }, "strip", z.ZodTypeAny, {
1194
+ enabled?: boolean | undefined;
1195
+ min_batch_size?: number | undefined;
1196
+ max_batch_size?: number | undefined;
1197
+ batch_window_seconds?: number | undefined;
1198
+ }, {
1199
+ enabled?: boolean | undefined;
1200
+ min_batch_size?: number | undefined;
1201
+ max_batch_size?: number | undefined;
1202
+ batch_window_seconds?: number | undefined;
1203
+ }>>;
1204
+ /** Wait for external AI code reviewers before merging — all bots must post */
1205
+ wait_for_reviewer: z.ZodOptional<z.ZodObject<{
1206
+ /** GitHub bot usernames to wait for (e.g. "cursor-bugbot[bot]") */
1207
+ bots: z.ZodArray<z.ZodString, "many">;
1208
+ /** Give up waiting after this many minutes (default: 30) */
1209
+ timeout_minutes: z.ZodOptional<z.ZodNumber>;
1210
+ }, "strip", z.ZodTypeAny, {
1211
+ bots: string[];
1212
+ timeout_minutes?: number | undefined;
1213
+ }, {
1214
+ bots: string[];
1215
+ timeout_minutes?: number | undefined;
1216
+ }>>;
1133
1217
  }, "strip", z.ZodTypeAny, {
1134
1218
  merge_queue?: boolean | undefined;
1135
1219
  auto_resolve_conflicts?: boolean | undefined;
@@ -1137,7 +1221,16 @@ export declare const HaystackConfigSchema: z.ZodObject<{
1137
1221
  default_minutes?: number | undefined;
1138
1222
  authors?: Record<string, number> | undefined;
1139
1223
  } | undefined;
1140
- expected_ai_reviewers?: ("cursor" | "coderabbit" | "copilot" | "greptile" | "sourcery" | "qodo" | "codeant" | "ellipsis" | "korbit" | "panto" | "bito" | "graphite" | "deepsource" | "snyk" | "codacy" | "sonarcloud" | "sweep" | "codeguru" | "codereviewer" | "codium")[] | undefined;
1224
+ batch_merge?: {
1225
+ enabled?: boolean | undefined;
1226
+ min_batch_size?: number | undefined;
1227
+ max_batch_size?: number | undefined;
1228
+ batch_window_seconds?: number | undefined;
1229
+ } | undefined;
1230
+ wait_for_reviewer?: {
1231
+ bots: string[];
1232
+ timeout_minutes?: number | undefined;
1233
+ } | undefined;
1141
1234
  }, {
1142
1235
  merge_queue?: boolean | undefined;
1143
1236
  auto_resolve_conflicts?: boolean | undefined;
@@ -1145,11 +1238,38 @@ export declare const HaystackConfigSchema: z.ZodObject<{
1145
1238
  default_minutes?: number | undefined;
1146
1239
  authors?: Record<string, number> | undefined;
1147
1240
  } | undefined;
1148
- expected_ai_reviewers?: ("cursor" | "coderabbit" | "copilot" | "greptile" | "sourcery" | "qodo" | "codeant" | "ellipsis" | "korbit" | "panto" | "bito" | "graphite" | "deepsource" | "snyk" | "codacy" | "sonarcloud" | "sweep" | "codeguru" | "codereviewer" | "codium")[] | undefined;
1241
+ batch_merge?: {
1242
+ enabled?: boolean | undefined;
1243
+ min_batch_size?: number | undefined;
1244
+ max_batch_size?: number | undefined;
1245
+ batch_window_seconds?: number | undefined;
1246
+ } | undefined;
1247
+ wait_for_reviewer?: {
1248
+ bots: string[];
1249
+ timeout_minutes?: number | undefined;
1250
+ } | undefined;
1149
1251
  }>>;
1150
1252
  }, "strip", z.ZodTypeAny, {
1151
1253
  version: "1";
1152
1254
  name?: string | undefined;
1255
+ merge_queue?: {
1256
+ merge_queue?: boolean | undefined;
1257
+ auto_resolve_conflicts?: boolean | undefined;
1258
+ merge_debounce?: {
1259
+ default_minutes?: number | undefined;
1260
+ authors?: Record<string, number> | undefined;
1261
+ } | undefined;
1262
+ batch_merge?: {
1263
+ enabled?: boolean | undefined;
1264
+ min_batch_size?: number | undefined;
1265
+ max_batch_size?: number | undefined;
1266
+ batch_window_seconds?: number | undefined;
1267
+ } | undefined;
1268
+ wait_for_reviewer?: {
1269
+ bots: string[];
1270
+ timeout_minutes?: number | undefined;
1271
+ } | undefined;
1272
+ } | undefined;
1153
1273
  services?: Record<string, {
1154
1274
  command: string;
1155
1275
  type?: "server" | "batch" | undefined;
@@ -1251,18 +1371,27 @@ export declare const HaystackConfigSchema: z.ZodObject<{
1251
1371
  services?: string[] | undefined;
1252
1372
  description?: string | undefined;
1253
1373
  }> | undefined;
1254
- babysitter?: {
1374
+ }, {
1375
+ version: "1";
1376
+ name?: string | undefined;
1377
+ merge_queue?: {
1255
1378
  merge_queue?: boolean | undefined;
1256
1379
  auto_resolve_conflicts?: boolean | undefined;
1257
1380
  merge_debounce?: {
1258
1381
  default_minutes?: number | undefined;
1259
1382
  authors?: Record<string, number> | undefined;
1260
1383
  } | undefined;
1261
- expected_ai_reviewers?: ("cursor" | "coderabbit" | "copilot" | "greptile" | "sourcery" | "qodo" | "codeant" | "ellipsis" | "korbit" | "panto" | "bito" | "graphite" | "deepsource" | "snyk" | "codacy" | "sonarcloud" | "sweep" | "codeguru" | "codereviewer" | "codium")[] | undefined;
1384
+ batch_merge?: {
1385
+ enabled?: boolean | undefined;
1386
+ min_batch_size?: number | undefined;
1387
+ max_batch_size?: number | undefined;
1388
+ batch_window_seconds?: number | undefined;
1389
+ } | undefined;
1390
+ wait_for_reviewer?: {
1391
+ bots: string[];
1392
+ timeout_minutes?: number | undefined;
1393
+ } | undefined;
1262
1394
  } | undefined;
1263
- }, {
1264
- version: "1";
1265
- name?: string | undefined;
1266
1395
  services?: Record<string, {
1267
1396
  command: string;
1268
1397
  type?: "server" | "batch" | undefined;
@@ -1364,15 +1493,6 @@ export declare const HaystackConfigSchema: z.ZodObject<{
1364
1493
  services?: string[] | undefined;
1365
1494
  description?: string | undefined;
1366
1495
  }> | undefined;
1367
- babysitter?: {
1368
- merge_queue?: boolean | undefined;
1369
- auto_resolve_conflicts?: boolean | undefined;
1370
- merge_debounce?: {
1371
- default_minutes?: number | undefined;
1372
- authors?: Record<string, number> | undefined;
1373
- } | undefined;
1374
- expected_ai_reviewers?: ("cursor" | "coderabbit" | "copilot" | "greptile" | "sourcery" | "qodo" | "codeant" | "ellipsis" | "korbit" | "panto" | "bito" | "graphite" | "deepsource" | "snyk" | "codacy" | "sonarcloud" | "sweep" | "codeguru" | "codereviewer" | "codium")[] | undefined;
1375
- } | undefined;
1376
1496
  }>;
1377
1497
  export type HaystackConfig = z.infer<typeof HaystackConfigSchema>;
1378
1498
  export type VerificationCommand = z.infer<typeof VerificationCommandSchema>;
@@ -1392,7 +1512,7 @@ export type DockerService = z.infer<typeof DockerServiceSchema>;
1392
1512
  export type DatabaseConfig = z.infer<typeof DatabaseConfigSchema>;
1393
1513
  export type NetworkConfig = z.infer<typeof NetworkConfigSchema>;
1394
1514
  export type SecretDeclaration = z.infer<typeof SecretDeclarationSchema>;
1395
- export type BabysitterConfig = z.infer<typeof BabysitterConfigSchema>;
1515
+ export type MergeQueueConfig = z.infer<typeof MergeQueueConfigSchema>;
1396
1516
  /**
1397
1517
  * Project detection results
1398
1518
  */