@haystackeditor/cli 0.10.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/dist/commands/config.js +81 -66
- package/dist/commands/dismiss.js +2 -1
- package/dist/commands/request-review.d.ts +15 -0
- package/dist/commands/request-review.js +95 -0
- package/dist/commands/setup.d.ts +1 -0
- package/dist/commands/setup.js +274 -2
- package/dist/commands/submit.js +1 -1
- package/dist/commands/triage.js +115 -23
- package/dist/index.d.ts +1 -0
- package/dist/index.js +43 -18
- package/dist/triage/prompts.js +13 -5
- package/dist/triage/runner.js +1 -1
- package/dist/triage/types.d.ts +1 -1
- package/dist/types.d.ts +132 -26
- package/dist/types.js +42 -5
- package/dist/utils/analysis-api.d.ts +16 -0
- package/dist/utils/analysis-api.js +23 -5
- package/dist/utils/telemetry.d.ts +17 -0
- package/dist/utils/telemetry.js +109 -0
- package/package.json +1 -1
- package/dist/commands/secrets.d.ts +0 -33
- package/dist/commands/secrets.js +0 -216
- package/dist/tools/fixtures.d.ts +0 -38
- package/dist/tools/fixtures.js +0 -199
- package/dist/tools/setup.d.ts +0 -43
- package/dist/tools/setup.js +0 -597
- package/dist/utils/skill.d.ts +0 -10
- package/dist/utils/skill.js +0 -1671
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @haystackeditor/cli
|
|
2
2
|
|
|
3
|
-
Set up Haystack for your project. When PRs are opened, Haystack automatically reviews them for bugs,
|
|
3
|
+
Set up Haystack for your project. When PRs are opened, Haystack automatically reviews them for bugs, instruction drift, and rule violations — then routes them to the right place.
|
|
4
4
|
|
|
5
5
|
## Quick Start
|
|
6
6
|
|
|
@@ -65,7 +65,7 @@ haystack logout
|
|
|
65
65
|
|
|
66
66
|
### `haystack submit`
|
|
67
67
|
|
|
68
|
-
Create a PR from current changes. Runs pre-PR triage (code review, rules validation,
|
|
68
|
+
Create a PR from current changes. Runs pre-PR triage (code review, rules validation, instruction drift), pushes your branch, and opens the PR.
|
|
69
69
|
|
|
70
70
|
```bash
|
|
71
71
|
haystack submit # Triage -> create PR -> wait for analysis
|
|
@@ -163,12 +163,14 @@ haystack config auto-merge # Show current status
|
|
|
163
163
|
haystack config auto-merge on # Enable auto-merge
|
|
164
164
|
haystack config auto-merge off # Disable auto-merge
|
|
165
165
|
|
|
166
|
-
# AI reviewer wait list
|
|
166
|
+
# AI reviewer wait list (merge queue waits for ALL configured bots before merging)
|
|
167
167
|
haystack config wait-for-reviewers # Show status
|
|
168
168
|
haystack config wait-for-reviewers add cursor # Wait for Cursor BugBot
|
|
169
169
|
haystack config wait-for-reviewers add cursor coderabbit # Add multiple
|
|
170
170
|
haystack config wait-for-reviewers remove cursor # Stop waiting
|
|
171
171
|
haystack config wait-for-reviewers clear # Wait for none
|
|
172
|
+
# Also accepts raw GitHub bot usernames:
|
|
173
|
+
haystack config wait-for-reviewers add cursor-bugbot[bot]
|
|
172
174
|
```
|
|
173
175
|
|
|
174
176
|
### `haystack skills`
|
|
@@ -244,7 +246,7 @@ The `setup` wizard writes `.haystack.json` to your repos with discovered rules,
|
|
|
244
246
|
1. Run `haystack setup` to configure your repos (or `haystack init` for local-only config)
|
|
245
247
|
2. Install the [Haystack GitHub App](https://haystackeditor.com/github-app)
|
|
246
248
|
3. When PRs are opened, Haystack automatically:
|
|
247
|
-
- Analyzes the code for bugs,
|
|
249
|
+
- Analyzes the code for bugs, instruction drift, and rule violations
|
|
248
250
|
- Reports results on the PR
|
|
249
251
|
- Routes the PR to the right inbox tab (Good to Merge, Issues Found, etc.)
|
|
250
252
|
- If auto-merge is enabled, clean PRs merge automatically
|
package/dist/commands/config.js
CHANGED
|
@@ -9,7 +9,7 @@ import { readFileSync, writeFileSync } from 'fs';
|
|
|
9
9
|
import { resolve } from 'path';
|
|
10
10
|
import { execSync } from 'child_process';
|
|
11
11
|
import { loadToken } from './login.js';
|
|
12
|
-
import { AI_REVIEWER_SOURCES, AI_REVIEWER_DISPLAY_NAMES } from '../types.js';
|
|
12
|
+
import { AI_REVIEWER_SOURCES, AI_REVIEWER_DISPLAY_NAMES, AI_REVIEWER_BOT_USERNAMES } from '../types.js';
|
|
13
13
|
const API_BASE = 'https://haystackeditor.com/api/preferences';
|
|
14
14
|
const AGENTIC_TOOL_LABELS = {
|
|
15
15
|
'opencode': 'OpenCode (Haystack billing)',
|
|
@@ -228,50 +228,71 @@ export async function handleAutoMerge(action) {
|
|
|
228
228
|
// ============================================================================
|
|
229
229
|
// Wait-for-reviewers (repo-level via .haystack.json)
|
|
230
230
|
// ============================================================================
|
|
231
|
-
|
|
231
|
+
/** Reverse map: bot username → friendly source name */
|
|
232
|
+
const BOT_USERNAME_TO_SOURCE = {};
|
|
233
|
+
for (const source of AI_REVIEWER_SOURCES) {
|
|
234
|
+
BOT_USERNAME_TO_SOURCE[AI_REVIEWER_BOT_USERNAMES[source]] = source;
|
|
235
|
+
}
|
|
236
|
+
function getMergeQueueConfig() {
|
|
232
237
|
const { config, path } = loadHaystackConfig();
|
|
233
|
-
const
|
|
234
|
-
const
|
|
235
|
-
return { config, path,
|
|
238
|
+
const mergeConfig = config.merge_queue ?? {};
|
|
239
|
+
const bots = mergeConfig.wait_for_reviewer?.bots ?? [];
|
|
240
|
+
return { config, path, bots };
|
|
236
241
|
}
|
|
237
|
-
function
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
242
|
+
function saveMergeQueueBots(config, configPath, bots, timeoutMinutes) {
|
|
243
|
+
const mergeConfig = config.merge_queue ?? {};
|
|
244
|
+
if (bots.length > 0) {
|
|
245
|
+
mergeConfig.wait_for_reviewer = {
|
|
246
|
+
bots,
|
|
247
|
+
...(timeoutMinutes != null ? { timeout_minutes: timeoutMinutes } : mergeConfig.wait_for_reviewer?.timeout_minutes != null ? { timeout_minutes: mergeConfig.wait_for_reviewer.timeout_minutes } : {}),
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
delete mergeConfig.wait_for_reviewer;
|
|
252
|
+
}
|
|
253
|
+
// Always write to merge_queue (new key)
|
|
254
|
+
config.merge_queue = mergeConfig;
|
|
241
255
|
saveHaystackConfig(config, configPath);
|
|
242
256
|
}
|
|
243
|
-
function printAvailableReviewers(
|
|
244
|
-
const currentSet = new Set(
|
|
257
|
+
function printAvailableReviewers(currentBots) {
|
|
258
|
+
const currentSet = new Set(currentBots);
|
|
245
259
|
console.log(chalk.dim('Available AI reviewer sources:'));
|
|
246
260
|
for (const source of AI_REVIEWER_SOURCES) {
|
|
247
261
|
const name = AI_REVIEWER_DISPLAY_NAMES[source];
|
|
248
|
-
const
|
|
262
|
+
const botUsername = AI_REVIEWER_BOT_USERNAMES[source];
|
|
263
|
+
const active = currentSet.has(botUsername);
|
|
249
264
|
const marker = active ? chalk.green(' ✓ ') : ' ';
|
|
250
|
-
console.log(`${marker}${chalk.cyan(source)} — ${name}`);
|
|
265
|
+
console.log(`${marker}${chalk.cyan(source)} — ${name} ${chalk.dim(`(${botUsername})`)}`);
|
|
251
266
|
}
|
|
252
267
|
console.log();
|
|
253
268
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
const
|
|
257
|
-
if
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
process.exit(1);
|
|
269
|
+
/** Resolve a source name (e.g. "cursor") to its GitHub bot username. Also accepts raw bot usernames. */
|
|
270
|
+
function resolveToBot(input) {
|
|
271
|
+
const lower = input.toLowerCase();
|
|
272
|
+
// Check if it's a known friendly source name
|
|
273
|
+
if (AI_REVIEWER_SOURCES.includes(lower)) {
|
|
274
|
+
return AI_REVIEWER_BOT_USERNAMES[lower];
|
|
261
275
|
}
|
|
262
|
-
|
|
276
|
+
// Already a bot username (e.g. "cursor-bugbot[bot]")
|
|
277
|
+
return input;
|
|
278
|
+
}
|
|
279
|
+
function displayName(botUsername) {
|
|
280
|
+
const source = BOT_USERNAME_TO_SOURCE[botUsername];
|
|
281
|
+
if (source) {
|
|
282
|
+
return `${AI_REVIEWER_DISPLAY_NAMES[source]} (${botUsername})`;
|
|
283
|
+
}
|
|
284
|
+
return botUsername;
|
|
263
285
|
}
|
|
264
286
|
export async function handleWaitForReviewers(action, reviewers) {
|
|
265
287
|
const normalizedAction = action?.toLowerCase();
|
|
266
288
|
// Default: show status
|
|
267
289
|
if (!normalizedAction || normalizedAction === 'list' || normalizedAction === 'status') {
|
|
268
|
-
const {
|
|
269
|
-
console.log(chalk.bold('\nMerge queue —
|
|
270
|
-
if (
|
|
271
|
-
console.log('The merge queue will wait for these
|
|
272
|
-
for (const
|
|
273
|
-
|
|
274
|
-
console.log(` ${chalk.green(name)} ${chalk.dim(`(${source})`)}`);
|
|
290
|
+
const { bots } = getMergeQueueConfig();
|
|
291
|
+
console.log(chalk.bold('\nMerge queue — wait for reviewers\n'));
|
|
292
|
+
if (bots.length > 0) {
|
|
293
|
+
console.log('The merge queue will wait for ALL of these bots to post before merging:');
|
|
294
|
+
for (const bot of bots) {
|
|
295
|
+
console.log(` ${chalk.green(displayName(bot))}`);
|
|
275
296
|
}
|
|
276
297
|
}
|
|
277
298
|
else {
|
|
@@ -279,26 +300,28 @@ export async function handleWaitForReviewers(action, reviewers) {
|
|
|
279
300
|
console.log(chalk.dim('The merge queue will not wait for any external reviewers.'));
|
|
280
301
|
}
|
|
281
302
|
console.log();
|
|
282
|
-
printAvailableReviewers(
|
|
283
|
-
console.log(chalk.dim('Add with:
|
|
303
|
+
printAvailableReviewers(bots);
|
|
304
|
+
console.log(chalk.dim('Add with: haystack config wait-for-reviewers add cursor coderabbit'));
|
|
305
|
+
console.log(chalk.dim('Or raw bot: haystack config wait-for-reviewers add cursor-bugbot[bot]'));
|
|
284
306
|
console.log();
|
|
285
307
|
return;
|
|
286
308
|
}
|
|
287
309
|
if (normalizedAction === 'add') {
|
|
288
310
|
if (!reviewers || reviewers.length === 0) {
|
|
289
|
-
console.error(chalk.red('\nSpecify at least one reviewer
|
|
290
|
-
const {
|
|
311
|
+
console.error(chalk.red('\nSpecify at least one reviewer to add.'));
|
|
312
|
+
const { bots } = getMergeQueueConfig();
|
|
291
313
|
console.log();
|
|
292
|
-
printAvailableReviewers(
|
|
314
|
+
printAvailableReviewers(bots);
|
|
293
315
|
process.exit(1);
|
|
316
|
+
return; // unreachable — satisfies TS narrowing
|
|
294
317
|
}
|
|
295
|
-
const
|
|
296
|
-
const { config, path,
|
|
297
|
-
const merged = Array.from(new Set([...current, ...
|
|
298
|
-
|
|
299
|
-
const added =
|
|
318
|
+
const resolved = reviewers.map(resolveToBot);
|
|
319
|
+
const { config, path, bots: current } = getMergeQueueConfig();
|
|
320
|
+
const merged = Array.from(new Set([...current, ...resolved]));
|
|
321
|
+
saveMergeQueueBots(config, path, merged);
|
|
322
|
+
const added = resolved.filter(b => !current.includes(b));
|
|
300
323
|
if (added.length > 0) {
|
|
301
|
-
console.log(chalk.green(`\nAdded: ${added.map(
|
|
324
|
+
console.log(chalk.green(`\nAdded: ${added.map(displayName).join(', ')}`));
|
|
302
325
|
}
|
|
303
326
|
else {
|
|
304
327
|
console.log(chalk.dim('\nAll specified reviewers were already configured.'));
|
|
@@ -308,17 +331,18 @@ export async function handleWaitForReviewers(action, reviewers) {
|
|
|
308
331
|
}
|
|
309
332
|
if (normalizedAction === 'remove') {
|
|
310
333
|
if (!reviewers || reviewers.length === 0) {
|
|
311
|
-
console.error(chalk.red('\nSpecify at least one reviewer
|
|
334
|
+
console.error(chalk.red('\nSpecify at least one reviewer to remove.'));
|
|
312
335
|
process.exit(1);
|
|
336
|
+
return; // unreachable — satisfies TS narrowing
|
|
313
337
|
}
|
|
314
|
-
const
|
|
315
|
-
const { config, path,
|
|
316
|
-
const removeSet = new Set(
|
|
317
|
-
const remaining = current.filter(
|
|
318
|
-
|
|
319
|
-
const removed =
|
|
338
|
+
const resolved = reviewers.map(resolveToBot);
|
|
339
|
+
const { config, path, bots: current } = getMergeQueueConfig();
|
|
340
|
+
const removeSet = new Set(resolved);
|
|
341
|
+
const remaining = current.filter(b => !removeSet.has(b));
|
|
342
|
+
saveMergeQueueBots(config, path, remaining);
|
|
343
|
+
const removed = resolved.filter(b => current.includes(b));
|
|
320
344
|
if (removed.length > 0) {
|
|
321
|
-
console.log(chalk.yellow(`\nRemoved: ${removed.map(
|
|
345
|
+
console.log(chalk.yellow(`\nRemoved: ${removed.map(displayName).join(', ')}`));
|
|
322
346
|
}
|
|
323
347
|
else {
|
|
324
348
|
console.log(chalk.dim('\nNone of the specified reviewers were configured.'));
|
|
@@ -327,28 +351,19 @@ export async function handleWaitForReviewers(action, reviewers) {
|
|
|
327
351
|
return;
|
|
328
352
|
}
|
|
329
353
|
if (normalizedAction === 'clear') {
|
|
330
|
-
const { config, path } =
|
|
331
|
-
|
|
354
|
+
const { config, path } = getMergeQueueConfig();
|
|
355
|
+
saveMergeQueueBots(config, path, []);
|
|
332
356
|
console.log(chalk.yellow('\nCleared all expected AI reviewers.'));
|
|
333
357
|
console.log(chalk.dim('The merge queue will not wait for any external reviewers.'));
|
|
334
358
|
console.log(chalk.dim('Commit .haystack.json to share with your team.\n'));
|
|
335
359
|
return;
|
|
336
360
|
}
|
|
337
|
-
// Unknown action — maybe the user passed
|
|
338
|
-
|
|
339
|
-
const
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
const merged = Array.from(new Set([...current, ...validated]));
|
|
346
|
-
saveBabysitterReviewers(config, path, merged);
|
|
347
|
-
console.log(chalk.green(`\nAdded: ${validated.map(s => AI_REVIEWER_DISPLAY_NAMES[s] ?? s).join(', ')}`));
|
|
348
|
-
console.log(chalk.dim('Commit .haystack.json to share with your team.\n'));
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
console.error(chalk.red(`\nUnknown action: ${action}`));
|
|
352
|
-
console.log('\nUsage: haystack config wait-for-reviewers [list|add|remove|clear] [sources...]\n');
|
|
353
|
-
process.exit(1);
|
|
361
|
+
// Unknown action — maybe the user passed reviewer names directly (implicit 'add')
|
|
362
|
+
const allNames = [action, ...(reviewers ?? [])].filter(Boolean);
|
|
363
|
+
const resolved = allNames.map(resolveToBot);
|
|
364
|
+
const { config, path, bots: current } = getMergeQueueConfig();
|
|
365
|
+
const merged = Array.from(new Set([...current, ...resolved]));
|
|
366
|
+
saveMergeQueueBots(config, path, merged);
|
|
367
|
+
console.log(chalk.green(`\nAdded: ${resolved.map(displayName).join(', ')}`));
|
|
368
|
+
console.log(chalk.dim('Commit .haystack.json to share with your team.\n'));
|
|
354
369
|
}
|
package/dist/commands/dismiss.js
CHANGED
|
@@ -161,7 +161,8 @@ async function runOverride(identifier, type, commandName) {
|
|
|
161
161
|
console.log(chalk.green(`\n Review marked as not needed for ${prLabel}`));
|
|
162
162
|
}
|
|
163
163
|
console.log(chalk.dim(` Commit: ${headSha.slice(0, 7)}`));
|
|
164
|
-
console.log(chalk.dim(' The PR will move to "Good to Merge" in the feed
|
|
164
|
+
console.log(chalk.dim(' The PR will move to "Good to Merge" in the feed.'));
|
|
165
|
+
console.log(chalk.dim(' If a new commit introduces net-new issues, the PR will resurface.\n'));
|
|
165
166
|
}
|
|
166
167
|
// ============================================================================
|
|
167
168
|
// Exported commands
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* request-review command — Tag a PR as needing human review after creation.
|
|
3
|
+
*
|
|
4
|
+
* haystack request-review <pr> [reviewer]
|
|
5
|
+
*
|
|
6
|
+
* Adds the `haystack:needs-review` label to the PR. Optionally requests
|
|
7
|
+
* review from a specific GitHub user. The PR will move to the
|
|
8
|
+
* "Needs Assignment" or "Awaiting Review" bucket in the Haystack feed.
|
|
9
|
+
*
|
|
10
|
+
* Accepts a PR identifier in several formats:
|
|
11
|
+
* 123 # Uses current repo's owner/repo
|
|
12
|
+
* owner/repo#123 # Fully qualified
|
|
13
|
+
* https://github.com/owner/repo/pull/123 # GitHub URL
|
|
14
|
+
*/
|
|
15
|
+
export declare function requestReviewCommand(identifier: string, reviewer?: string): Promise<void>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* request-review command — Tag a PR as needing human review after creation.
|
|
3
|
+
*
|
|
4
|
+
* haystack request-review <pr> [reviewer]
|
|
5
|
+
*
|
|
6
|
+
* Adds the `haystack:needs-review` label to the PR. Optionally requests
|
|
7
|
+
* review from a specific GitHub user. The PR will move to the
|
|
8
|
+
* "Needs Assignment" or "Awaiting Review" bucket in the Haystack feed.
|
|
9
|
+
*
|
|
10
|
+
* Accepts a PR identifier in several formats:
|
|
11
|
+
* 123 # Uses current repo's owner/repo
|
|
12
|
+
* owner/repo#123 # Fully qualified
|
|
13
|
+
* https://github.com/owner/repo/pull/123 # GitHub URL
|
|
14
|
+
*/
|
|
15
|
+
import chalk from 'chalk';
|
|
16
|
+
import { loadToken } from './login.js';
|
|
17
|
+
import { parseRemoteUrl } from '../utils/git.js';
|
|
18
|
+
import { ensureHaystackLabels, addLabelsToIssue, requestReviewers, } from '../utils/github-api.js';
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// PR identifier parsing (shared pattern with dismiss.ts)
|
|
21
|
+
// ============================================================================
|
|
22
|
+
function parsePRIdentifier(identifier) {
|
|
23
|
+
const urlMatch = identifier.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)\/?$/);
|
|
24
|
+
if (urlMatch) {
|
|
25
|
+
return { owner: urlMatch[1], repo: urlMatch[2], prNumber: parseInt(urlMatch[3], 10) };
|
|
26
|
+
}
|
|
27
|
+
const qualifiedMatch = identifier.match(/^([^/]+)\/([^#]+)#(\d+)$/);
|
|
28
|
+
if (qualifiedMatch) {
|
|
29
|
+
return { owner: qualifiedMatch[1], repo: qualifiedMatch[2], prNumber: parseInt(qualifiedMatch[3], 10) };
|
|
30
|
+
}
|
|
31
|
+
const numberMatch = identifier.match(/^#?(\d+)$/);
|
|
32
|
+
if (numberMatch) {
|
|
33
|
+
const prNumber = parseInt(numberMatch[1], 10);
|
|
34
|
+
try {
|
|
35
|
+
const remote = parseRemoteUrl('origin');
|
|
36
|
+
return { owner: remote.owner, repo: remote.repo, prNumber };
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
throw new Error(`Cannot determine repository for PR #${prNumber}.\n` +
|
|
40
|
+
`Use the full format: haystack request-review owner/repo#${prNumber}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
throw new Error(`Invalid PR identifier: "${identifier}"\n\n` +
|
|
44
|
+
`Accepted formats:\n` +
|
|
45
|
+
` haystack request-review 123\n` +
|
|
46
|
+
` haystack request-review owner/repo#123\n` +
|
|
47
|
+
` haystack request-review https://github.com/owner/repo/pull/123`);
|
|
48
|
+
}
|
|
49
|
+
// ============================================================================
|
|
50
|
+
// Main command
|
|
51
|
+
// ============================================================================
|
|
52
|
+
export async function requestReviewCommand(identifier, reviewer) {
|
|
53
|
+
// Parse PR identifier
|
|
54
|
+
let pr;
|
|
55
|
+
try {
|
|
56
|
+
pr = parsePRIdentifier(identifier);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
console.error(chalk.red(`\n${err.message}\n`));
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
// Require auth
|
|
63
|
+
const token = await loadToken();
|
|
64
|
+
if (!token) {
|
|
65
|
+
console.error(chalk.red('\nNot logged in. Run `haystack login` first.\n'));
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
const prLabel = `${pr.owner}/${pr.repo}#${pr.prNumber}`;
|
|
69
|
+
console.log(chalk.dim(`\nRequesting review for ${prLabel}...`));
|
|
70
|
+
// Ensure the label exists in the repo, then add it to the PR
|
|
71
|
+
try {
|
|
72
|
+
await ensureHaystackLabels(pr.owner, pr.repo, ['haystack:needs-review']);
|
|
73
|
+
await addLabelsToIssue(pr.owner, pr.repo, pr.prNumber, ['haystack:needs-review']);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
console.error(chalk.red(`\nFailed to add label: ${err.message}\n`));
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
// Request specific reviewer if provided
|
|
80
|
+
if (reviewer) {
|
|
81
|
+
try {
|
|
82
|
+
await requestReviewers(pr.owner, pr.repo, pr.prNumber, [reviewer]);
|
|
83
|
+
console.log(chalk.green(`\n Review requested from ${reviewer} on ${prLabel}`));
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
// Label was added successfully, just the reviewer request failed
|
|
87
|
+
console.log(chalk.green(`\n Marked ${prLabel} for review`));
|
|
88
|
+
console.log(chalk.yellow(` Could not request reviewer "${reviewer}": ${err.message}`));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
console.log(chalk.green(`\n Marked ${prLabel} for human review`));
|
|
93
|
+
}
|
|
94
|
+
console.log(chalk.dim(' The PR will appear in the "Needs Assignment" queue in the feed.\n'));
|
|
95
|
+
}
|
package/dist/commands/setup.d.ts
CHANGED
|
@@ -9,5 +9,6 @@
|
|
|
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. Install session tracking (Entire CLI + .entire/settings.json + local hooks)
|
|
12
13
|
*/
|
|
13
14
|
export declare function setupCommand(): Promise<void>;
|