@haystackeditor/cli 0.15.18 → 0.15.20
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 +86 -1
- package/dist/assets/skills/map-your-system.md +143 -0
- package/dist/commands/ask.js +2 -2
- package/dist/commands/config.d.ts +9 -0
- package/dist/commands/config.js +46 -14
- package/dist/commands/dismiss.d.ts +15 -3
- package/dist/commands/dismiss.js +66 -116
- package/dist/commands/mcp.js +96 -1
- package/dist/commands/policy.js +31 -12
- package/dist/commands/pr-status.d.ts +125 -2
- package/dist/commands/pr-status.js +88 -73
- package/dist/commands/pr.d.ts +1 -7
- package/dist/commands/pr.js +10 -21
- package/dist/commands/request-review.d.ts +12 -1
- package/dist/commands/request-review.js +42 -65
- package/dist/commands/review.d.ts +25 -0
- package/dist/commands/review.js +191 -0
- package/dist/commands/setup.js +4 -1
- package/dist/commands/skills.js +4 -0
- package/dist/commands/submit.d.ts +3 -0
- package/dist/commands/submit.js +178 -38
- package/dist/commands/system-map.d.ts +42 -0
- package/dist/commands/system-map.js +228 -0
- package/dist/commands/tokens.js +3 -2
- package/dist/commands/traces.js +2 -2
- package/dist/commands/triage.d.ts +1 -6
- package/dist/commands/triage.js +51 -55
- package/dist/index.js +116 -19
- package/dist/schema.d.ts +4 -0
- package/dist/schema.js +4 -0
- package/dist/states.d.ts +29 -0
- package/dist/states.js +46 -0
- package/dist/triage/runner.d.ts +7 -0
- package/dist/triage/runner.js +2 -2
- package/dist/utils/action-output.d.ts +24 -0
- package/dist/utils/action-output.js +26 -0
- package/dist/utils/analysis-api.d.ts +44 -0
- package/dist/utils/analysis-api.js +137 -6
- package/dist/utils/auth.js +7 -0
- package/dist/utils/git.d.ts +4 -1
- package/dist/utils/git.js +17 -7
- package/dist/utils/haystack-api.d.ts +15 -0
- package/dist/utils/haystack-api.js +58 -7
- package/dist/utils/pr-ref.d.ts +27 -0
- package/dist/utils/pr-ref.js +56 -0
- package/package.json +1 -1
- package/schemas/action.v1.json +22 -0
- package/schemas/error.v1.json +14 -0
- package/schemas/pr-status.v1.json +61 -0
- package/schemas/pr.v1.json +80 -17
- package/schemas/setup.v1.json +66 -12
- package/schemas/submit.v1.json +88 -0
- package/schemas/triage.v1.json +71 -18
|
@@ -12,4 +12,15 @@
|
|
|
12
12
|
* owner/repo#123 # Fully qualified
|
|
13
13
|
* https://github.com/owner/repo/pull/123 # GitHub URL
|
|
14
14
|
*/
|
|
15
|
-
|
|
15
|
+
import { type ActionPayload } from '../utils/action-output.js';
|
|
16
|
+
export interface RequestReviewPayload extends ActionPayload {
|
|
17
|
+
reviewer: string | null;
|
|
18
|
+
/** Set when the label was applied but the specific-reviewer request failed. */
|
|
19
|
+
reviewer_request_failed: string | null;
|
|
20
|
+
}
|
|
21
|
+
/** Apply the needs-review label (and optional reviewer). Throws on failure. */
|
|
22
|
+
export declare function performRequestReview(identifier: string, reviewer?: string): Promise<RequestReviewPayload>;
|
|
23
|
+
export interface RequestReviewOptions {
|
|
24
|
+
json?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare function requestReviewCommand(identifier: string, reviewer?: string, options?: RequestReviewOptions): Promise<void>;
|
|
@@ -13,85 +13,62 @@
|
|
|
13
13
|
* https://github.com/owner/repo/pull/123 # GitHub URL
|
|
14
14
|
*/
|
|
15
15
|
import chalk from 'chalk';
|
|
16
|
+
import { emitActionPayload, failAction } from '../utils/action-output.js';
|
|
16
17
|
import { resolveAuthContext } from '../utils/auth.js';
|
|
17
|
-
import {
|
|
18
|
+
import { parsePrRef } from '../utils/pr-ref.js';
|
|
18
19
|
import { ensureHaystackLabels, addLabelsToIssue, requestReviewers, } from '../utils/github-api.js';
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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);
|
|
20
|
+
/** Apply the needs-review label (and optional reviewer). Throws on failure. */
|
|
21
|
+
export async function performRequestReview(identifier, reviewer) {
|
|
22
|
+
const pr = parsePrRef(identifier, 'request-review');
|
|
23
|
+
const authContext = await resolveAuthContext({ owner: pr.owner, repo: pr.repo });
|
|
24
|
+
const ref = `${pr.owner}/${pr.repo}#${pr.prNumber}`;
|
|
25
|
+
await ensureHaystackLabels(pr.owner, pr.repo, ['haystack:needs-review'], authContext.token);
|
|
26
|
+
await addLabelsToIssue(pr.owner, pr.repo, pr.prNumber, ['haystack:needs-review'], authContext.token);
|
|
27
|
+
let reviewerRequestFailed = null;
|
|
28
|
+
if (reviewer) {
|
|
34
29
|
try {
|
|
35
|
-
|
|
36
|
-
return { owner: remote.owner, repo: remote.repo, prNumber };
|
|
30
|
+
await requestReviewers(pr.owner, pr.repo, pr.prNumber, [reviewer], authContext.token);
|
|
37
31
|
}
|
|
38
|
-
catch {
|
|
39
|
-
|
|
40
|
-
|
|
32
|
+
catch (err) {
|
|
33
|
+
// Label was added successfully, just the reviewer request failed —
|
|
34
|
+
// report the partial outcome instead of failing the whole action.
|
|
35
|
+
reviewerRequestFailed = err.message;
|
|
41
36
|
}
|
|
42
37
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
return {
|
|
39
|
+
action: 'request_review',
|
|
40
|
+
status: 'ok',
|
|
41
|
+
ref,
|
|
42
|
+
reviewer: reviewer && !reviewerRequestFailed ? reviewer : null,
|
|
43
|
+
reviewer_request_failed: reviewerRequestFailed,
|
|
44
|
+
detail: reviewer && !reviewerRequestFailed
|
|
45
|
+
? `Review requested from ${reviewer}; the PR moves to the "Needs Assignment" queue.`
|
|
46
|
+
: 'PR marked for human review; it moves to the "Needs Assignment" queue.',
|
|
47
|
+
};
|
|
48
48
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// Parse PR identifier
|
|
54
|
-
let pr;
|
|
49
|
+
export async function requestReviewCommand(identifier, reviewer, options = {}) {
|
|
50
|
+
if (!options.json)
|
|
51
|
+
console.log(chalk.dim(`\nRequesting review for ${identifier}...`));
|
|
52
|
+
let payload;
|
|
55
53
|
try {
|
|
56
|
-
|
|
54
|
+
payload = await performRequestReview(identifier, reviewer);
|
|
57
55
|
}
|
|
58
56
|
catch (err) {
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
failAction(options.json, 'request_review', null, err.message);
|
|
58
|
+
return; // unreachable — satisfies TS narrowing
|
|
61
59
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
if (options.json) {
|
|
61
|
+
emitActionPayload(payload);
|
|
62
|
+
return;
|
|
65
63
|
}
|
|
66
|
-
|
|
67
|
-
console.
|
|
68
|
-
process.exit(1);
|
|
69
|
-
}
|
|
70
|
-
const prLabel = `${pr.owner}/${pr.repo}#${pr.prNumber}`;
|
|
71
|
-
console.log(chalk.dim(`\nRequesting review for ${prLabel}...`));
|
|
72
|
-
// Ensure the label exists in the repo, then add it to the PR
|
|
73
|
-
try {
|
|
74
|
-
await ensureHaystackLabels(pr.owner, pr.repo, ['haystack:needs-review'], authContext.token);
|
|
75
|
-
await addLabelsToIssue(pr.owner, pr.repo, pr.prNumber, ['haystack:needs-review'], authContext.token);
|
|
76
|
-
}
|
|
77
|
-
catch (err) {
|
|
78
|
-
console.error(chalk.red(`\nFailed to add label: ${err.message}\n`));
|
|
79
|
-
process.exit(1);
|
|
80
|
-
}
|
|
81
|
-
// Request specific reviewer if provided
|
|
82
|
-
if (reviewer) {
|
|
83
|
-
try {
|
|
84
|
-
await requestReviewers(pr.owner, pr.repo, pr.prNumber, [reviewer], authContext.token);
|
|
85
|
-
console.log(chalk.green(`\n Review requested from ${reviewer} on ${prLabel}`));
|
|
86
|
-
}
|
|
87
|
-
catch (err) {
|
|
88
|
-
// Label was added successfully, just the reviewer request failed
|
|
89
|
-
console.log(chalk.green(`\n Marked ${prLabel} for review`));
|
|
90
|
-
console.log(chalk.yellow(` Could not request reviewer "${reviewer}": ${err.message}`));
|
|
91
|
-
}
|
|
64
|
+
if (payload.reviewer) {
|
|
65
|
+
console.log(chalk.green(`\n Review requested from ${payload.reviewer} on ${payload.ref}`));
|
|
92
66
|
}
|
|
93
67
|
else {
|
|
94
|
-
console.log(chalk.green(`\n Marked ${
|
|
68
|
+
console.log(chalk.green(`\n Marked ${payload.ref} for human review`));
|
|
69
|
+
if (payload.reviewer_request_failed) {
|
|
70
|
+
console.log(chalk.yellow(` Could not request reviewer "${reviewer}": ${payload.reviewer_request_failed}`));
|
|
71
|
+
}
|
|
95
72
|
}
|
|
96
73
|
console.log(chalk.dim(' The PR will appear in the "Needs Assignment" queue in the feed.\n'));
|
|
97
74
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* review command — Trigger a fresh Haystack analysis for a PR.
|
|
3
|
+
*
|
|
4
|
+
* haystack review [pr] [--no-wait]
|
|
5
|
+
*
|
|
6
|
+
* Haystack runs a full analysis when a PR is opened (or marked ready);
|
|
7
|
+
* later pushes only get a resolution check against the existing findings.
|
|
8
|
+
* This command is the explicit escape hatch: it re-runs full detection on
|
|
9
|
+
* the PR's current head — use it after substantial new commits, or any
|
|
10
|
+
* time you want a fresh second opinion.
|
|
11
|
+
*
|
|
12
|
+
* When called without a PR identifier, reads the last submitted PR from
|
|
13
|
+
* `.haystack/pending-submit.json` (written by `haystack submit`).
|
|
14
|
+
*
|
|
15
|
+
* Accepts a PR identifier in several formats:
|
|
16
|
+
* haystack review # Last submitted PR
|
|
17
|
+
* haystack review 123 # Uses current repo's owner/repo
|
|
18
|
+
* haystack review owner/repo#123 # Fully qualified
|
|
19
|
+
* haystack review https://github.com/owner/repo/pull/123
|
|
20
|
+
*/
|
|
21
|
+
export interface ReviewOptions {
|
|
22
|
+
wait?: boolean;
|
|
23
|
+
json?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare function reviewCommand(identifier: string | undefined, options: ReviewOptions): Promise<void>;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* review command — Trigger a fresh Haystack analysis for a PR.
|
|
3
|
+
*
|
|
4
|
+
* haystack review [pr] [--no-wait]
|
|
5
|
+
*
|
|
6
|
+
* Haystack runs a full analysis when a PR is opened (or marked ready);
|
|
7
|
+
* later pushes only get a resolution check against the existing findings.
|
|
8
|
+
* This command is the explicit escape hatch: it re-runs full detection on
|
|
9
|
+
* the PR's current head — use it after substantial new commits, or any
|
|
10
|
+
* time you want a fresh second opinion.
|
|
11
|
+
*
|
|
12
|
+
* When called without a PR identifier, reads the last submitted PR from
|
|
13
|
+
* `.haystack/pending-submit.json` (written by `haystack submit`).
|
|
14
|
+
*
|
|
15
|
+
* Accepts a PR identifier in several formats:
|
|
16
|
+
* haystack review # Last submitted PR
|
|
17
|
+
* haystack review 123 # Uses current repo's owner/repo
|
|
18
|
+
* haystack review owner/repo#123 # Fully qualified
|
|
19
|
+
* haystack review https://github.com/owner/repo/pull/123
|
|
20
|
+
*/
|
|
21
|
+
import chalk from 'chalk';
|
|
22
|
+
import { emitActionPayload, failAction } from '../utils/action-output.js';
|
|
23
|
+
import { triggerAnalysis, fetchTriggerStatus } from '../utils/analysis-api.js';
|
|
24
|
+
import { fetchTriageHeadSha } from './triage.js';
|
|
25
|
+
import { loadToken } from '../utils/auth.js';
|
|
26
|
+
import { loadPendingSubmit } from '../utils/pending-state.js';
|
|
27
|
+
import { parsePrRef } from '../utils/pr-ref.js';
|
|
28
|
+
import { triageCommand } from './triage.js';
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// Constants
|
|
31
|
+
// ============================================================================
|
|
32
|
+
const STATUS_POLL_INTERVAL_MS = 10_000;
|
|
33
|
+
// Full analyses regularly take 10+ minutes on large PRs; this bounds the
|
|
34
|
+
// CLI's wait, not the analysis itself (results land on the feed regardless).
|
|
35
|
+
const STATUS_POLL_TIMEOUT_MS = 25 * 60 * 1000;
|
|
36
|
+
function resolvePR(identifier, json) {
|
|
37
|
+
if (identifier) {
|
|
38
|
+
try {
|
|
39
|
+
return parsePrRef(identifier, 'review');
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
failAction(json, 'trigger_review', null, err.message);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const pending = loadPendingSubmit();
|
|
46
|
+
if (!pending) {
|
|
47
|
+
console.log(chalk.dim('No pending submits. Pass a PR number to review a specific PR.\n'));
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
return { owner: pending.owner, repo: pending.repo, prNumber: pending.prNumber };
|
|
51
|
+
}
|
|
52
|
+
// ============================================================================
|
|
53
|
+
// Waiting
|
|
54
|
+
// ============================================================================
|
|
55
|
+
async function waitForRun(requestId, token) {
|
|
56
|
+
const deadline = Date.now() + STATUS_POLL_TIMEOUT_MS;
|
|
57
|
+
let consecutiveErrors = 0;
|
|
58
|
+
while (Date.now() < deadline) {
|
|
59
|
+
const result = await fetchTriggerStatus(requestId, token);
|
|
60
|
+
if (result.status === 'COMPLETED')
|
|
61
|
+
return 'completed';
|
|
62
|
+
if (result.status === 'FAILED')
|
|
63
|
+
return 'failed';
|
|
64
|
+
if (result.status === 'SUPERSEDED')
|
|
65
|
+
return 'superseded';
|
|
66
|
+
if (result.status === 'error') {
|
|
67
|
+
consecutiveErrors++;
|
|
68
|
+
if (consecutiveErrors >= 5)
|
|
69
|
+
return 'failed';
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
consecutiveErrors = 0;
|
|
73
|
+
}
|
|
74
|
+
process.stderr.write(`\r ${chalk.dim('Analysis in progress...')}${' '.repeat(5)}`);
|
|
75
|
+
// Deliberately NOT unref'd: during the wait this timer can be the only
|
|
76
|
+
// live handle, and an unref'd timer lets Node exit mid-wait.
|
|
77
|
+
await new Promise((resolve) => {
|
|
78
|
+
setTimeout(resolve, STATUS_POLL_INTERVAL_MS);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return 'timeout';
|
|
82
|
+
}
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// Main command
|
|
85
|
+
// ============================================================================
|
|
86
|
+
export async function reviewCommand(identifier, options) {
|
|
87
|
+
if (options.json && identifier === undefined && !loadPendingSubmit()) {
|
|
88
|
+
failAction(true, 'trigger_review', null, 'No pending submit to review. Pass a PR identifier: haystack review owner/repo#123 --json');
|
|
89
|
+
}
|
|
90
|
+
const pr = resolvePR(identifier, options.json);
|
|
91
|
+
if (!pr)
|
|
92
|
+
return;
|
|
93
|
+
const prLabel = `${pr.owner}/${pr.repo}#${pr.prNumber}`;
|
|
94
|
+
let token = null;
|
|
95
|
+
try {
|
|
96
|
+
token = await loadToken({ owner: pr.owner, repo: pr.repo });
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
failAction(options.json, 'trigger_review', prLabel, `Could not load Haystack credentials: ${err.message}`);
|
|
100
|
+
}
|
|
101
|
+
if (!token) {
|
|
102
|
+
failAction(options.json, 'trigger_review', prLabel, 'Triggering an analysis requires authentication. Run `haystack login` first.');
|
|
103
|
+
return; // unreachable — satisfies TS narrowing
|
|
104
|
+
}
|
|
105
|
+
if (!options.json)
|
|
106
|
+
console.log(chalk.dim(`\nRequesting a fresh analysis for ${prLabel}...`));
|
|
107
|
+
// Resolve the current head so ingestion's dedup compares commits — an
|
|
108
|
+
// in-flight run for an OLDER head must be superseded, not reused. A
|
|
109
|
+
// failed metadata fetch degrades to a head-less trigger (the dedup is a
|
|
110
|
+
// freshness aid, not a correctness requirement) instead of crashing.
|
|
111
|
+
let headSha;
|
|
112
|
+
try {
|
|
113
|
+
headSha = await fetchTriageHeadSha(pr, token) ?? undefined;
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
console.error(chalk.dim(` Could not resolve the PR head (${err.message}) — continuing without it.`));
|
|
117
|
+
}
|
|
118
|
+
const trigger = await triggerAnalysis(pr.owner, pr.repo, pr.prNumber, token, headSha);
|
|
119
|
+
if (trigger.status === 'rate_limited') {
|
|
120
|
+
const retryHint = trigger.retryAfterSeconds
|
|
121
|
+
? ` Try again in ~${Math.ceil(trigger.retryAfterSeconds / 60)} minute(s).`
|
|
122
|
+
: '';
|
|
123
|
+
failAction(options.json, 'trigger_review', prLabel, `${trigger.message}${retryHint}`);
|
|
124
|
+
}
|
|
125
|
+
if (trigger.status === 'denied') {
|
|
126
|
+
failAction(options.json, 'trigger_review', prLabel, trigger.message);
|
|
127
|
+
}
|
|
128
|
+
if (trigger.status === 'error') {
|
|
129
|
+
failAction(options.json, 'trigger_review', prLabel, `Failed to trigger analysis: ${trigger.message}`);
|
|
130
|
+
return; // unreachable — satisfies TS narrowing
|
|
131
|
+
}
|
|
132
|
+
if (!options.json) {
|
|
133
|
+
if (trigger.status === 'already_processing') {
|
|
134
|
+
console.log(chalk.yellow(' An analysis for this PR is already running — waiting on it instead.'));
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
console.log(chalk.green(' Analysis started.'));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/** One envelope for every terminal state of the trigger. */
|
|
141
|
+
const emitJson = (runStatus, detail, done) => {
|
|
142
|
+
emitActionPayload({
|
|
143
|
+
action: 'trigger_review',
|
|
144
|
+
status: 'ok',
|
|
145
|
+
ref: prLabel,
|
|
146
|
+
detail,
|
|
147
|
+
request_id: trigger.requestId,
|
|
148
|
+
run_status: runStatus,
|
|
149
|
+
next: done ? `haystack triage ${prLabel} --json` : null,
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
if (options.wait === false) {
|
|
153
|
+
if (options.json) {
|
|
154
|
+
emitJson(trigger.status, 'Analysis triggered; not waiting for completion.', true);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
console.log(chalk.dim(' Check results later with: ') + chalk.cyan(`haystack triage ${prLabel}`));
|
|
158
|
+
console.log(chalk.dim(' Or view the review: ') + chalk.cyan(`https://haystackeditor.com/review/${pr.owner}/${pr.repo}/${pr.prNumber}\n`));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const outcome = await waitForRun(trigger.requestId, token);
|
|
162
|
+
process.stderr.write('\r' + ' '.repeat(60) + '\r');
|
|
163
|
+
if (outcome === 'failed') {
|
|
164
|
+
failAction(options.json, 'trigger_review', prLabel, `Analysis run failed. Check the review page: https://haystackeditor.com/review/${pr.owner}/${pr.repo}/${pr.prNumber}`);
|
|
165
|
+
}
|
|
166
|
+
if (outcome === 'superseded') {
|
|
167
|
+
if (options.json) {
|
|
168
|
+
emitJson('superseded', 'This run was superseded by a newer analysis (a push likely landed meanwhile). The latest results stand.', true);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
console.log(chalk.yellow('\n This run was superseded by a newer analysis (a push likely landed meanwhile).'));
|
|
172
|
+
console.log(chalk.dim(' Showing the latest results instead.'));
|
|
173
|
+
await triageCommand(prLabel, { wait: false });
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (outcome === 'timeout') {
|
|
177
|
+
if (options.json) {
|
|
178
|
+
emitJson('running', 'Still running after 25 minutes; the analysis continues server-side.', true);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
console.log(chalk.yellow('\n Still running after 25 minutes — giving up on waiting.'));
|
|
182
|
+
console.log(chalk.dim(' Check results later with: ') + chalk.cyan(`haystack triage ${prLabel}\n`));
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
// Completed — render results through the triage view (no extra wait).
|
|
186
|
+
if (options.json) {
|
|
187
|
+
emitJson('completed', 'Analysis completed.', true);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
await triageCommand(prLabel, { wait: false });
|
|
191
|
+
}
|
package/dist/commands/setup.js
CHANGED
|
@@ -48,8 +48,11 @@ function buildAnswerMap(options) {
|
|
|
48
48
|
answers.want_to_toggle = false;
|
|
49
49
|
if (!('confirm_write' in answers))
|
|
50
50
|
answers.confirm_write = true;
|
|
51
|
-
if (!('auto_merge' in answers))
|
|
51
|
+
if (!('auto_merge' in answers)) {
|
|
52
52
|
answers.auto_merge = true;
|
|
53
|
+
// Consequential default applied without an interactive prompt — say so.
|
|
54
|
+
console.error('--yes: enabling auto-merge (the wizard default). Pass --no-auto-merge to opt out.');
|
|
55
|
+
}
|
|
53
56
|
if (!('install_entire' in answers))
|
|
54
57
|
answers.install_entire = true;
|
|
55
58
|
if (!('upgrade_entire' in answers))
|
package/dist/commands/skills.js
CHANGED
|
@@ -15,6 +15,7 @@ function getSkillsSourceDir() {
|
|
|
15
15
|
const SKILL_FILES = [
|
|
16
16
|
'setup-haystack.md',
|
|
17
17
|
'submit.md',
|
|
18
|
+
'map-your-system.md',
|
|
18
19
|
];
|
|
19
20
|
function installSkillFiles(targetDir) {
|
|
20
21
|
const sourceDir = getSkillsSourceDir();
|
|
@@ -55,6 +56,7 @@ export async function installSkills(options) {
|
|
|
55
56
|
}
|
|
56
57
|
const claudeCommandPath = join(claudeCommandsDir, 'setup-haystack.md');
|
|
57
58
|
writeFileSync(claudeCommandPath, '# Set Up Haystack\n\nFollow .agents/skills/setup-haystack.md to set up Haystack for this repo.\n');
|
|
59
|
+
writeFileSync(join(claudeCommandsDir, 'map-your-system.md'), '# Map Your System for Haystack QA\n\nFollow .agents/skills/map-your-system.md to create .haystack/system.yml — verified facts about how this system builds, boots, seeds data, and logs in, so Haystack QA can run it.\n');
|
|
58
60
|
showSuccessMessage();
|
|
59
61
|
}
|
|
60
62
|
function showSuccessMessage() {
|
|
@@ -62,6 +64,7 @@ function showSuccessMessage() {
|
|
|
62
64
|
console.log(chalk.white('Available skills:'));
|
|
63
65
|
console.log(chalk.cyan(' /setup-haystack ') + chalk.gray('- Create .haystack.json with AI assistance'));
|
|
64
66
|
console.log(chalk.cyan(' /submit ') + chalk.gray('- Submit a PR via Haystack'));
|
|
67
|
+
console.log(chalk.cyan(' /map-your-system ') + chalk.gray('- Write .haystack/system.yml so Haystack QA can run this system'));
|
|
65
68
|
console.log();
|
|
66
69
|
console.log(chalk.white('Run in your coding CLI:'));
|
|
67
70
|
console.log(chalk.cyan(' /setup-haystack'));
|
|
@@ -71,5 +74,6 @@ export async function listSkills() {
|
|
|
71
74
|
console.log(chalk.white('\nAvailable Haystack skills:\n'));
|
|
72
75
|
console.log(chalk.cyan(' /setup-haystack ') + chalk.gray('- Master setup - creates .haystack.json'));
|
|
73
76
|
console.log(chalk.cyan(' /submit ') + chalk.gray('- Submit a PR via Haystack'));
|
|
77
|
+
console.log(chalk.cyan(' /map-your-system ') + chalk.gray('- Write .haystack/system.yml so Haystack QA can run this system'));
|
|
74
78
|
console.log();
|
|
75
79
|
}
|
|
@@ -19,8 +19,11 @@ export interface SubmitOptions {
|
|
|
19
19
|
review?: string | true;
|
|
20
20
|
force?: boolean;
|
|
21
21
|
wait?: boolean;
|
|
22
|
+
json?: boolean;
|
|
22
23
|
autoFix?: boolean;
|
|
23
24
|
autoMerge?: boolean;
|
|
25
|
+
autoMergeSource?: 'flag' | 'config';
|
|
26
|
+
autoFixSource?: 'flag' | 'config';
|
|
24
27
|
maxTurns?: number;
|
|
25
28
|
triageTimeout?: number;
|
|
26
29
|
}
|