@haystackeditor/cli 0.25.1 → 0.27.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 +39 -463
- package/dist/capture/app-config.js +30 -6
- package/dist/commands/capture-brief.js +45 -35
- package/dist/commands/capture-contract.js +4 -4
- package/dist/commands/crawl-report.js +196 -0
- package/dist/commands/db-profile-upload.js +3 -3
- package/dist/commands/feedback.js +66 -0
- package/dist/commands/init-telemetry.js +55 -9
- package/dist/commands/init.js +8 -3
- package/dist/commands/lockfile-pin.js +307 -0
- package/dist/commands/telemetry-token.js +3 -3
- package/dist/commands/tokens.js +4 -4
- package/dist/commands/verify-explore.js +3 -3
- package/dist/commands/verify-history.js +2 -2
- package/dist/commands/verify-onboarding.js +13 -16
- package/dist/commands/verify-precompute.js +3 -4
- package/dist/commands/verify.js +31 -118
- package/dist/index.js +55 -968
- package/dist/schema.js +4 -10
- package/dist/utils/haystack-api.js +8 -36
- package/package.json +1 -5
- package/schemas/feedback.v1.json +13 -0
- package/schemas/pre-verify.v2.json +240 -0
- package/schemas/verify-raw.v1.json +1132 -0
- package/schemas/verify.v2.json +655 -0
- package/dist/assets/hooks/agent-context/detect.ts +0 -316
- package/dist/assets/hooks/agent-context/format.ts +0 -100
- package/dist/assets/hooks/agent-context/index.ts +0 -41
- package/dist/assets/hooks/agent-context/parsers/claude.ts +0 -262
- package/dist/assets/hooks/agent-context/parsers/codex.ts +0 -416
- package/dist/assets/hooks/agent-context/parsers/gemini.ts +0 -155
- package/dist/assets/hooks/agent-context/parsers/opencode.ts +0 -174
- package/dist/assets/hooks/agent-context/tsconfig.json +0 -14
- package/dist/assets/hooks/agent-context/types.ts +0 -58
- package/dist/assets/hooks/llm-rules-template.md +0 -59
- package/dist/assets/hooks/package-lock.json +0 -598
- package/dist/assets/hooks/package.json +0 -12
- package/dist/assets/hooks/scripts/commit-msg.sh +0 -5
- package/dist/assets/hooks/scripts/post-commit.sh +0 -5
- package/dist/assets/hooks/scripts/pre-commit.sh +0 -175
- package/dist/assets/hooks/scripts/pre-push.sh +0 -25
- package/dist/assets/hooks/scripts/prepare-commit-msg.sh +0 -5
- package/dist/assets/hooks/truncation-checker/ast-analyzer.ts +0 -528
- package/dist/assets/hooks/truncation-checker/index.ts +0 -595
- package/dist/assets/hooks/truncation-checker/tsconfig.json +0 -13
- package/dist/assets/skills/map-cloud-verifier-universe/SKILL.md +0 -2051
- package/dist/assets/skills/map-cloud-verifier-universe/agents/openai.yaml +0 -4
- package/dist/assets/skills/map-cloud-verifier-universe/references/output-contract.md +0 -3411
- package/dist/assets/skills/map-your-system.md +0 -143
- package/dist/assets/skills/submit.md +0 -200
- package/dist/commands/ask.js +0 -20
- package/dist/commands/cloud-verifier-behaviors.js +0 -218
- package/dist/commands/cloud-verifier-data-store-census.js +0 -539
- package/dist/commands/cloud-verifier-data-store-drift.js +0 -158
- package/dist/commands/cloud-verifier-identity-census.js +0 -4060
- package/dist/commands/cloud-verifier-materialization.js +0 -704
- package/dist/commands/cloud-verifier-pascal-selector-census.js +0 -1382
- package/dist/commands/cloud-verifier-python-manifest-selector-census.js +0 -2015
- package/dist/commands/cloud-verifier-specialized-operational-census.js +0 -11432
- package/dist/commands/cloud-verifier-universe.js +0 -10178
- package/dist/commands/config.js +0 -549
- package/dist/commands/design-verify.js +0 -311
- package/dist/commands/dismiss.js +0 -159
- package/dist/commands/hooks.js +0 -226
- package/dist/commands/inbox.js +0 -137
- package/dist/commands/mcp.js +0 -201
- package/dist/commands/policy.js +0 -371
- package/dist/commands/pr-status.js +0 -207
- package/dist/commands/pr.js +0 -105
- package/dist/commands/prepare-universe-review.js +0 -1092
- package/dist/commands/production-source-deny-policy.js +0 -100
- package/dist/commands/request-review.js +0 -74
- package/dist/commands/review.js +0 -191
- package/dist/commands/rules.js +0 -98
- package/dist/commands/scaffold-provisional-universe.js +0 -806
- package/dist/commands/setup.js +0 -1170
- package/dist/commands/skills.js +0 -447
- package/dist/commands/status.js +0 -35
- package/dist/commands/submit.js +0 -745
- package/dist/commands/system-map.js +0 -228
- package/dist/commands/triage.js +0 -598
- package/dist/commands/webhooks.js +0 -241
- package/dist/states.js +0 -46
- package/dist/tools/detect.js +0 -832
- package/dist/triage/astra.js +0 -202
- package/dist/triage/prompts.js +0 -188
- package/dist/triage/runner.js +0 -200
- package/dist/triage/types.js +0 -7
- package/dist/types.js +0 -326
- package/dist/utils/action-output.js +0 -26
- package/dist/utils/analysis-api.js +0 -416
- package/dist/utils/config.js +0 -54
- package/dist/utils/design-verifier-api.js +0 -294
- package/dist/utils/design-verifier-history.js +0 -79
- package/dist/utils/design-verifier-result.js +0 -424
- package/dist/utils/github-api.js +0 -324
- package/dist/utils/pending-state.js +0 -86
- package/dist/utils/pr-ref.js +0 -56
- package/dist/utils/prompter.js +0 -328
- package/schemas/action.v1.json +0 -22
- package/schemas/ask.v1.json +0 -40
- package/schemas/inbox.v1.json +0 -27
- package/schemas/pr-status.v1.json +0 -61
- package/schemas/pr.v1.json +0 -97
- package/schemas/pr.v3.json +0 -45
- package/schemas/setup.v1.json +0 -75
- package/schemas/submit.v1.json +0 -90
- package/schemas/triage.v1.json +0 -103
- package/schemas/triage.v2.json +0 -64
package/dist/utils/prompter.js
DELETED
|
@@ -1,328 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Prompter — decouples a wizard's *decisions* from *how they're answered*.
|
|
3
|
-
*
|
|
4
|
-
* `haystack setup` historically welded every decision to inquirer/TTY, so it
|
|
5
|
-
* couldn't run headless, in CI, or under a coding agent. The Prompter is the
|
|
6
|
-
* seam: step code calls `confirm` / `multiselect` / `action`, and the
|
|
7
|
-
* implementation decides how to source the answer.
|
|
8
|
-
*
|
|
9
|
-
* Three modes, one mechanism:
|
|
10
|
-
* - TtyPrompter — humans in a terminal (inquirer). Default.
|
|
11
|
-
* - JsonPrompter — a coding agent: NDJSON events on stdout, answers on stdin.
|
|
12
|
-
* The agent can relay a `question` to the user OR auto-answer.
|
|
13
|
-
* - Pre-supplied answers (flags / --answers file) short-circuit any question
|
|
14
|
-
* by id, so the same code runs fully autonomously when every answer is known.
|
|
15
|
-
*
|
|
16
|
-
* Human-facing chrome stays as `console.*`; in JSON mode the JsonPrompter
|
|
17
|
-
* redirects `console.*` to stderr so stdout carries only NDJSON.
|
|
18
|
-
*/
|
|
19
|
-
import chalk from 'chalk';
|
|
20
|
-
import { Separator, checkbox, confirm } from '@inquirer/prompts';
|
|
21
|
-
import * as readline from 'node:readline';
|
|
22
|
-
import { readFileSync } from 'node:fs';
|
|
23
|
-
function isSeparator(c) {
|
|
24
|
-
return c.separator !== undefined;
|
|
25
|
-
}
|
|
26
|
-
/** Thrown when an agent explicitly rejects/cancels a prompt (vs. answering it),
|
|
27
|
-
* so callers can distinguish a cancellation from a valid empty answer. */
|
|
28
|
-
export class PromptCancelledError extends Error {
|
|
29
|
-
requestID;
|
|
30
|
-
constructor(requestID) {
|
|
31
|
-
super(`Prompt "${requestID}" was cancelled.`);
|
|
32
|
-
this.requestID = requestID;
|
|
33
|
-
this.name = 'PromptCancelledError';
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
export function loadAnswersFile(path) {
|
|
37
|
-
const raw = readFileSync(path, 'utf8');
|
|
38
|
-
const parsed = JSON.parse(raw);
|
|
39
|
-
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
40
|
-
throw new Error(`--answers file must be a JSON object of {questionId: value}`);
|
|
41
|
-
}
|
|
42
|
-
return parsed;
|
|
43
|
-
}
|
|
44
|
-
// ---------------------------------------------------------------------------
|
|
45
|
-
// TTY (human) prompter
|
|
46
|
-
// ---------------------------------------------------------------------------
|
|
47
|
-
/**
|
|
48
|
-
* Await an @inquirer/prompts prompt, keeping the Ctrl+C behaviour the CLI had
|
|
49
|
-
* under inquirer 9: that version answered Ctrl+C by re-sending SIGINT to the
|
|
50
|
-
* process (which terminates it) and never settled the prompt. @inquirer/prompts
|
|
51
|
-
* instead rejects with an ExitPromptError, which would surface as an uncaught
|
|
52
|
-
* error with a stack trace, so translate it back.
|
|
53
|
-
*/
|
|
54
|
-
export async function runPrompt(prompt) {
|
|
55
|
-
try {
|
|
56
|
-
return await prompt;
|
|
57
|
-
}
|
|
58
|
-
catch (err) {
|
|
59
|
-
if (err instanceof Error && err.name === 'ExitPromptError') {
|
|
60
|
-
process.kill(process.pid, 'SIGINT');
|
|
61
|
-
console.log('');
|
|
62
|
-
return new Promise(() => { });
|
|
63
|
-
}
|
|
64
|
-
throw err;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
// ---------------------------------------------------------------------------
|
|
68
|
-
class TtyPrompter {
|
|
69
|
-
answers;
|
|
70
|
-
interactive = true;
|
|
71
|
-
constructor(answers) {
|
|
72
|
-
this.answers = answers;
|
|
73
|
-
}
|
|
74
|
-
hasPreset(id) {
|
|
75
|
-
return id in this.answers;
|
|
76
|
-
}
|
|
77
|
-
async confirm(q) {
|
|
78
|
-
if (q.id in this.answers)
|
|
79
|
-
return toBool(this.answers[q.id]);
|
|
80
|
-
return runPrompt(confirm({ message: q.message, default: q.default ?? true }));
|
|
81
|
-
}
|
|
82
|
-
async multiselect(q) {
|
|
83
|
-
if (q.id in this.answers)
|
|
84
|
-
return asArray(this.answers[q.id], q.id);
|
|
85
|
-
const choices = q.choices.map((c) => isSeparator(c) ? new Separator(c.separator) : { name: c.name, value: c.value, checked: c.checked });
|
|
86
|
-
return runPrompt(checkbox({ message: q.message, choices, pageSize: 20 }));
|
|
87
|
-
}
|
|
88
|
-
async action(q) {
|
|
89
|
-
if (this.answers[q.id] === 'skip')
|
|
90
|
-
return 'skip';
|
|
91
|
-
if (await q.check())
|
|
92
|
-
return 'ok';
|
|
93
|
-
console.log(chalk.yellow(` ${q.message}`));
|
|
94
|
-
if (q.url)
|
|
95
|
-
console.log(` ${chalk.cyan(q.url)}`);
|
|
96
|
-
console.log(chalk.dim(' Waiting...'));
|
|
97
|
-
const started = Date.now();
|
|
98
|
-
const timeout = q.timeoutMs ?? 10 * 60 * 1000;
|
|
99
|
-
const interval = q.pollIntervalMs ?? 3000;
|
|
100
|
-
while (Date.now() - started < timeout) {
|
|
101
|
-
await sleep(interval);
|
|
102
|
-
if (await q.check())
|
|
103
|
-
return 'ok';
|
|
104
|
-
}
|
|
105
|
-
return 'timeout';
|
|
106
|
-
}
|
|
107
|
-
progress(message, detail) {
|
|
108
|
-
// Only emit carriage-return / clear-line ANSI to a real TTY; piped to a file
|
|
109
|
-
// or CI log (non-interactive, no --json) those sequences corrupt the output,
|
|
110
|
-
// so stay silent there.
|
|
111
|
-
if (!process.stdout.isTTY)
|
|
112
|
-
return;
|
|
113
|
-
process.stdout.write(`\r${chalk.dim(' ' + message)}${detail ? chalk.dim(' — ' + detail) : ''}\x1b[K`);
|
|
114
|
-
}
|
|
115
|
-
clearProgress() {
|
|
116
|
-
if (!process.stdout.isTTY)
|
|
117
|
-
return;
|
|
118
|
-
process.stdout.write('\r\x1b[K');
|
|
119
|
-
}
|
|
120
|
-
result(_data) {
|
|
121
|
-
// Human output is rendered inline by the step code; nothing structured to emit.
|
|
122
|
-
}
|
|
123
|
-
close() {
|
|
124
|
-
/* nothing to release */
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
// ---------------------------------------------------------------------------
|
|
128
|
-
// JSON (coding-agent) prompter
|
|
129
|
-
// ---------------------------------------------------------------------------
|
|
130
|
-
class JsonPrompter {
|
|
131
|
-
answers;
|
|
132
|
-
interactive = false;
|
|
133
|
-
rl = null;
|
|
134
|
-
pending = new Map();
|
|
135
|
-
buffered = new Map();
|
|
136
|
-
restoreConsole = null;
|
|
137
|
-
constructor(answers) {
|
|
138
|
-
this.answers = answers;
|
|
139
|
-
// Keep stdout pure NDJSON: route human chrome to stderr.
|
|
140
|
-
const origLog = console.log;
|
|
141
|
-
const origWarn = console.warn;
|
|
142
|
-
const origError = console.error;
|
|
143
|
-
const toErr = (...args) => process.stderr.write(args.map(stringifyArg).join(' ') + '\n');
|
|
144
|
-
console.log = toErr;
|
|
145
|
-
console.warn = toErr;
|
|
146
|
-
console.error = toErr;
|
|
147
|
-
this.restoreConsole = () => {
|
|
148
|
-
console.log = origLog;
|
|
149
|
-
console.warn = origWarn;
|
|
150
|
-
console.error = origError;
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
hasPreset(id) {
|
|
154
|
-
return id in this.answers;
|
|
155
|
-
}
|
|
156
|
-
emit(event) {
|
|
157
|
-
// Stamp every NDJSON event with the setup schema version so agent
|
|
158
|
-
// consumers can pin a contract. See docs/SPEC-CLI-FIRST-CLASS.md.
|
|
159
|
-
const stamped = { schema_version: '1.0.0', ...event };
|
|
160
|
-
process.stdout.write(JSON.stringify(stamped) + '\n');
|
|
161
|
-
}
|
|
162
|
-
/** Lazily open stdin only when we actually need an answer the agent must send. */
|
|
163
|
-
ensureStdin() {
|
|
164
|
-
if (this.rl)
|
|
165
|
-
return;
|
|
166
|
-
this.rl = readline.createInterface({ input: process.stdin });
|
|
167
|
-
this.rl.on('line', (line) => {
|
|
168
|
-
const trimmed = line.trim();
|
|
169
|
-
if (!trimmed)
|
|
170
|
-
return;
|
|
171
|
-
let obj;
|
|
172
|
-
try {
|
|
173
|
-
obj = JSON.parse(trimmed);
|
|
174
|
-
}
|
|
175
|
-
catch (err) {
|
|
176
|
-
// Surface malformed input on stderr (PR001: no silent swallow) so an
|
|
177
|
-
// agent can tell its line was rejected and resend, instead of the
|
|
178
|
-
// prompt hanging on input that never parsed. stderr keeps stdout NDJSON.
|
|
179
|
-
process.stderr.write(`haystack setup: ignoring unparseable stdin line: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
if (!obj || typeof obj !== 'object')
|
|
183
|
-
return;
|
|
184
|
-
// Mirror OpenCode: question replies are keyed by `requestID`, permission
|
|
185
|
-
// replies by `permissionID`.
|
|
186
|
-
const key = (obj.requestID ?? obj.permissionID);
|
|
187
|
-
if (typeof key !== 'string')
|
|
188
|
-
return;
|
|
189
|
-
const resolve = this.pending.get(key);
|
|
190
|
-
if (resolve) {
|
|
191
|
-
this.pending.delete(key);
|
|
192
|
-
resolve(obj);
|
|
193
|
-
}
|
|
194
|
-
else {
|
|
195
|
-
this.buffered.set(key, obj);
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
/** Wait for the agent's reply object, keyed by the request/permission id. */
|
|
200
|
-
awaitReply(id) {
|
|
201
|
-
if (this.buffered.has(id)) {
|
|
202
|
-
const v = this.buffered.get(id);
|
|
203
|
-
this.buffered.delete(id);
|
|
204
|
-
return Promise.resolve(v);
|
|
205
|
-
}
|
|
206
|
-
this.ensureStdin();
|
|
207
|
-
return new Promise((resolve) => this.pending.set(id, resolve));
|
|
208
|
-
}
|
|
209
|
-
async confirm(q) {
|
|
210
|
-
if (q.id in this.answers)
|
|
211
|
-
return toBool(this.answers[q.id]);
|
|
212
|
-
// A confirm is a single-choice question; emit OpenCode's `question` envelope.
|
|
213
|
-
// Reply: {requestID, answers: <bool>}; reject: {requestID, reject: true}.
|
|
214
|
-
this.emit({ type: 'question', requestID: q.id, kind: 'confirm', prompt: q.message, default: q.default ?? true });
|
|
215
|
-
const reply = await this.awaitReply(q.id);
|
|
216
|
-
// Reject = cancellation (distinct from "No"); parse the answer robustly so a
|
|
217
|
-
// string "false" isn't coerced truthy.
|
|
218
|
-
if (reply.reject)
|
|
219
|
-
throw new PromptCancelledError(q.id);
|
|
220
|
-
return toBool(reply.answers);
|
|
221
|
-
}
|
|
222
|
-
async multiselect(q) {
|
|
223
|
-
if (q.id in this.answers)
|
|
224
|
-
return asArray(this.answers[q.id], q.id);
|
|
225
|
-
const options = q.choices
|
|
226
|
-
.filter((c) => !isSeparator(c))
|
|
227
|
-
.map((c) => ({ value: c.value, label: c.name, default: c.checked ?? false }));
|
|
228
|
-
// Reply: {requestID, answers: <value[]>}; reject: {requestID, reject: true}.
|
|
229
|
-
this.emit({ type: 'question', requestID: q.id, kind: 'multiselect', prompt: q.message, options });
|
|
230
|
-
const reply = await this.awaitReply(q.id);
|
|
231
|
-
// Surface a rejection as a distinct cancellation rather than masking it as an
|
|
232
|
-
// empty selection, and surface a non-array reply as a protocol error rather
|
|
233
|
-
// than silently coercing to [] (PR001: no silent fallback).
|
|
234
|
-
if (reply.reject)
|
|
235
|
-
throw new PromptCancelledError(q.id);
|
|
236
|
-
return asArray(reply.answers, q.id);
|
|
237
|
-
}
|
|
238
|
-
async action(q) {
|
|
239
|
-
if (this.answers[q.id] === 'skip')
|
|
240
|
-
return 'skip';
|
|
241
|
-
if (await q.check())
|
|
242
|
-
return 'ok';
|
|
243
|
-
// An out-of-band action maps to OpenCode's `permission` request. Reply:
|
|
244
|
-
// {permissionID, response: "once"|"always"|"reject"}. We also keep polling
|
|
245
|
-
// check() so it resolves on its own once the action completes.
|
|
246
|
-
this.emit({ type: 'permission', permissionID: q.id, prompt: q.message, url: q.url, poll: true });
|
|
247
|
-
const started = Date.now();
|
|
248
|
-
const timeout = q.timeoutMs ?? 10 * 60 * 1000;
|
|
249
|
-
const interval = q.pollIntervalMs ?? 3000;
|
|
250
|
-
let override = null;
|
|
251
|
-
this.ensureStdin();
|
|
252
|
-
const answerPromise = this.awaitReply(q.id).then((reply) => {
|
|
253
|
-
const r = reply.response;
|
|
254
|
-
override = r === 'reject' ? 'skip' : 'done';
|
|
255
|
-
});
|
|
256
|
-
try {
|
|
257
|
-
while (Date.now() - started < timeout) {
|
|
258
|
-
if (await q.check())
|
|
259
|
-
return 'ok';
|
|
260
|
-
if (override === 'skip')
|
|
261
|
-
return 'skip';
|
|
262
|
-
// 'done' means the agent reports the action complete — but completion may
|
|
263
|
-
// be eventually-consistent, so keep polling check() at the interval until
|
|
264
|
-
// it confirms or we time out (matching TTY behavior), rather than failing
|
|
265
|
-
// on a single immediate check.
|
|
266
|
-
if (override === 'done') {
|
|
267
|
-
await sleep(interval);
|
|
268
|
-
continue;
|
|
269
|
-
}
|
|
270
|
-
await Promise.race([sleep(interval), answerPromise]);
|
|
271
|
-
}
|
|
272
|
-
return 'timeout';
|
|
273
|
-
}
|
|
274
|
-
finally {
|
|
275
|
-
// If polling or the timeout won before any stdin reply arrived, drop the
|
|
276
|
-
// dangling resolver so it doesn't accumulate across action() calls.
|
|
277
|
-
this.pending.delete(q.id);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
progress(message, detail) {
|
|
281
|
-
this.emit({ type: 'progress', message, ...(detail ? { detail } : {}) });
|
|
282
|
-
}
|
|
283
|
-
clearProgress() {
|
|
284
|
-
/* no ephemeral line in JSON mode */
|
|
285
|
-
}
|
|
286
|
-
result(data) {
|
|
287
|
-
this.emit({ type: 'result', ...data });
|
|
288
|
-
}
|
|
289
|
-
close() {
|
|
290
|
-
this.rl?.close();
|
|
291
|
-
this.rl = null;
|
|
292
|
-
this.restoreConsole?.();
|
|
293
|
-
this.restoreConsole = null;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
export function createPrompter(options = {}) {
|
|
297
|
-
const answers = options.answers ?? {};
|
|
298
|
-
return options.json ? new JsonPrompter(answers) : new TtyPrompter(answers);
|
|
299
|
-
}
|
|
300
|
-
function sleep(ms) {
|
|
301
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
302
|
-
}
|
|
303
|
-
/** Coerce an answer to a boolean without the `Boolean("false") === true` trap:
|
|
304
|
-
* recognizes string forms ("true"/"false", "yes"/"no", "1"/"0") explicitly. */
|
|
305
|
-
function toBool(v) {
|
|
306
|
-
if (typeof v === 'boolean')
|
|
307
|
-
return v;
|
|
308
|
-
if (typeof v === 'string') {
|
|
309
|
-
const s = v.trim().toLowerCase();
|
|
310
|
-
if (['true', 'yes', 'y', '1'].includes(s))
|
|
311
|
-
return true;
|
|
312
|
-
if (['false', 'no', 'n', '0', ''].includes(s))
|
|
313
|
-
return false;
|
|
314
|
-
}
|
|
315
|
-
return Boolean(v);
|
|
316
|
-
}
|
|
317
|
-
/** Validate a pre-supplied multiselect answer is actually an array before use,
|
|
318
|
-
* so a bad --answers value (e.g. a string) fails fast with a clear message
|
|
319
|
-
* instead of crashing downstream array operations. */
|
|
320
|
-
function asArray(value, id) {
|
|
321
|
-
if (!Array.isArray(value)) {
|
|
322
|
-
throw new Error(`Answer for "${id}" must be a JSON array, got ${typeof value}.`);
|
|
323
|
-
}
|
|
324
|
-
return value;
|
|
325
|
-
}
|
|
326
|
-
function stringifyArg(a) {
|
|
327
|
-
return typeof a === 'string' ? a : String(a);
|
|
328
|
-
}
|
package/schemas/action.v1.json
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://docs.haystackeditor.com/cli/schemas/action.v1.json",
|
|
4
|
-
"title": "haystack <dismiss|mark-reviewed|undismiss|request-review|review> --json",
|
|
5
|
-
"description": "Shared envelope for every mutating command. Exactly one document on stdout; progress on stderr. status 'error' payloads accompany exit code 1.",
|
|
6
|
-
"type": "object",
|
|
7
|
-
"required": ["schema_version", "action", "status"],
|
|
8
|
-
"properties": {
|
|
9
|
-
"schema_version": { "type": "string", "const": "1.0.0" },
|
|
10
|
-
"action": { "type": "string", "enum": ["dismiss", "mark_reviewed", "undismiss", "request_review", "trigger_review", "clear_pending"] },
|
|
11
|
-
"status": { "type": "string", "enum": ["ok", "error"] },
|
|
12
|
-
"ref": { "type": ["string", "null"], "description": "owner/repo#number. Null on errors that happen before the ref resolves." },
|
|
13
|
-
"error": { "type": "string", "description": "Present only when status is 'error'. Actionable message including the remediation." },
|
|
14
|
-
"detail": { "type": "string", "description": "Human-readable statement of what changed." },
|
|
15
|
-
"head_sha": { "type": "string", "description": "dismiss/mark_reviewed: the head commit the override is tied to. A new commit invalidates the override." },
|
|
16
|
-
"reviewer": { "type": ["string", "null"], "description": "request_review: the GitHub user review was requested from, or null for the needs-assignment queue." },
|
|
17
|
-
"reviewer_request_failed": { "type": ["string", "null"], "description": "request_review: set when the label was applied but the specific-reviewer request failed (partial success)." },
|
|
18
|
-
"request_id": { "type": "string", "description": "trigger_review: the analysis run id." },
|
|
19
|
-
"run_status": { "type": "string", "enum": ["started", "already_processing", "completed", "superseded", "running"], "description": "trigger_review: state of the triggered run when the command returned." },
|
|
20
|
-
"next": { "type": ["string", "null"], "description": "Follow-up command to read results (e.g. `haystack triage <ref> --json`)." }
|
|
21
|
-
}
|
|
22
|
-
}
|
package/schemas/ask.v1.json
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://docs.haystackeditor.com/cli/schemas/ask.v1.json",
|
|
4
|
-
"title": "haystack ask <ref> <question> --json",
|
|
5
|
-
"type": "object",
|
|
6
|
-
"additionalProperties": false,
|
|
7
|
-
"required": ["schema_version", "ref", "head_sha", "answer", "evidence", "session_id"],
|
|
8
|
-
"properties": {
|
|
9
|
-
"schema_version": { "type": "string", "const": "1.0.0" },
|
|
10
|
-
"ref": { "type": "string" },
|
|
11
|
-
"head_sha": { "type": "string" },
|
|
12
|
-
"answer": { "type": "string" },
|
|
13
|
-
"session_id": { "type": "string" },
|
|
14
|
-
"evidence": {
|
|
15
|
-
"type": "array",
|
|
16
|
-
"items": {
|
|
17
|
-
"type": "object",
|
|
18
|
-
"required": ["evidence_id", "type"],
|
|
19
|
-
"propertyNames": {
|
|
20
|
-
"enum": [
|
|
21
|
-
"evidence_id", "type", "title", "body", "author", "state", "isDraft", "labels", "reviewers", "requestedReviewers", "sha",
|
|
22
|
-
"section_number", "summary", "explanation", "changes", "path", "base_sha", "head_sha", "patch", "start_line", "end_line", "content",
|
|
23
|
-
"query", "file_pattern", "matches", "files", "totalMatches", "truncated", "scope", "result", "locations", "functions", "change_key", "nodes", "caller", "context",
|
|
24
|
-
"finding_id", "category", "detail", "suggested_fix", "source", "severity", "source_changes", "test_changes", "changeKey", "testFiles",
|
|
25
|
-
"uncoveredScenarios", "coverageDescription", "assessment", "id", "filePath", "line", "side", "comments", "isResolved", "isOutdated",
|
|
26
|
-
"checks", "status", "reason", "blockingChecks", "action", "checkpointId", "commitSha", "commitMessage", "overviewSummary", "userPrompt",
|
|
27
|
-
"filesTouched", "branch", "checkpoint_id", "chunks", "total_chars", "users", "teams", "result_sha"
|
|
28
|
-
]
|
|
29
|
-
},
|
|
30
|
-
"properties": {
|
|
31
|
-
"evidence_id": { "type": "string" },
|
|
32
|
-
"type": {
|
|
33
|
-
"type": "string",
|
|
34
|
-
"enum": ["pr_context", "change_summary", "diff", "source", "search", "call_relationship", "finding", "test_coverage", "review_thread", "ci", "merge", "trace", "suggested_reviewers", "fixer"]
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
package/schemas/inbox.v1.json
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://docs.haystackeditor.com/cli/schemas/inbox.v1.json",
|
|
4
|
-
"title": "haystack inbox list --json",
|
|
5
|
-
"type": "object",
|
|
6
|
-
"additionalProperties": false,
|
|
7
|
-
"required": ["schema_version", "pull_requests"],
|
|
8
|
-
"properties": {
|
|
9
|
-
"schema_version": { "type": "string", "const": "1.0.0" },
|
|
10
|
-
"pull_requests": {
|
|
11
|
-
"type": "array",
|
|
12
|
-
"items": {
|
|
13
|
-
"type": "object",
|
|
14
|
-
"additionalProperties": false,
|
|
15
|
-
"required": ["ref", "title", "head_sha", "bucket", "reason", "action"],
|
|
16
|
-
"properties": {
|
|
17
|
-
"ref": { "type": "string" },
|
|
18
|
-
"title": { "type": "string" },
|
|
19
|
-
"head_sha": { "type": "string" },
|
|
20
|
-
"bucket": { "type": "string", "enum": ["analyzing", "needs_shepherding", "needs_review", "good_to_merge"] },
|
|
21
|
-
"reason": { "type": "string" },
|
|
22
|
-
"action": { "type": "string" }
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://docs.haystackeditor.com/cli/schemas/pr-status.v1.json",
|
|
4
|
-
"title": "haystack pr-status <ref> --json",
|
|
5
|
-
"description": "Which Haystack feed bucket a PR is in, and why. All state tokens are snake_case — the same vocabulary as `haystack triage --json` and `haystack pr get --json`.",
|
|
6
|
-
"type": "object",
|
|
7
|
-
"additionalProperties": false,
|
|
8
|
-
"required": ["schema_version", "ref", "bucket", "in_feed", "feed_priority", "reason", "analysis", "needs_human_review", "labels", "overrides", "author", "is_author", "is_open", "state_synced_at", "stale_warning"],
|
|
9
|
-
"properties": {
|
|
10
|
-
"schema_version": { "type": "string", "const": "1.0.0" },
|
|
11
|
-
"ref": { "type": "string", "description": "owner/repo#number" },
|
|
12
|
-
"bucket": {
|
|
13
|
-
"type": ["string", "null"],
|
|
14
|
-
"description": "Feed bucket in snake_case. Known values are enumerated below; new buckets may appear (always snake_case). Null when the PR is unclassified (closed or not yet analyzed).",
|
|
15
|
-
"examples": ["analyzing", "auto_fixing", "good_to_merge", "failed_when_merging", "issues", "needs_assignment", "needs_shepherding", "needs_fixing", "awaiting_review", "review_requested", "snoozed"]
|
|
16
|
-
},
|
|
17
|
-
"in_feed": { "type": ["boolean", "null"], "description": "Null when the PR is unclassified (e.g. closed)." },
|
|
18
|
-
"feed_priority": { "type": ["number", "null"] },
|
|
19
|
-
"reason": { "type": "string", "description": "Human-readable explanation of the classification." },
|
|
20
|
-
"analysis": {
|
|
21
|
-
"type": "object",
|
|
22
|
-
"additionalProperties": false,
|
|
23
|
-
"required": ["status", "verdict", "rating"],
|
|
24
|
-
"properties": {
|
|
25
|
-
"status": { "type": "string", "enum": ["pending", "in_queue", "ready", "error"] },
|
|
26
|
-
"verdict": {
|
|
27
|
-
"anyOf": [
|
|
28
|
-
{ "type": "string", "enum": ["good_to_merge", "needs_review", "needs_input"] },
|
|
29
|
-
{ "type": "null" }
|
|
30
|
-
],
|
|
31
|
-
"description": "Null until analysis is ready."
|
|
32
|
-
},
|
|
33
|
-
"rating": {
|
|
34
|
-
"anyOf": [
|
|
35
|
-
{ "type": "integer", "minimum": 1, "maximum": 5 },
|
|
36
|
-
{ "type": "null" }
|
|
37
|
-
]
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
"needs_human_review": { "type": ["boolean", "null"] },
|
|
42
|
-
"labels": { "type": "array", "items": { "type": "string" } },
|
|
43
|
-
"overrides": {
|
|
44
|
-
"type": "object",
|
|
45
|
-
"additionalProperties": false,
|
|
46
|
-
"required": ["snoozed", "dismissed", "dismissed_agent_alerts", "dismissed_needs_assignment", "manually_good_to_merge"],
|
|
47
|
-
"properties": {
|
|
48
|
-
"snoozed": { "type": "boolean" },
|
|
49
|
-
"dismissed": { "type": "boolean" },
|
|
50
|
-
"dismissed_agent_alerts": { "type": "boolean" },
|
|
51
|
-
"dismissed_needs_assignment": { "type": "boolean" },
|
|
52
|
-
"manually_good_to_merge": { "type": "boolean" }
|
|
53
|
-
}
|
|
54
|
-
},
|
|
55
|
-
"author": { "type": ["string", "null"], "description": "Null when the server could not resolve PR metadata." },
|
|
56
|
-
"is_author": { "type": ["boolean", "null"] },
|
|
57
|
-
"is_open": { "type": ["boolean", "null"] },
|
|
58
|
-
"state_synced_at": { "type": ["string", "null"] },
|
|
59
|
-
"stale_warning": { "type": ["string", "null"] }
|
|
60
|
-
}
|
|
61
|
-
}
|
package/schemas/pr.v1.json
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://docs.haystackeditor.com/cli/schemas/pr.v1.json",
|
|
4
|
-
"title": "haystack pr <ref> --json",
|
|
5
|
-
"deprecated": true,
|
|
6
|
-
"description": "HISTORICAL: superseded by pr.v2.json. The CLI no longer emits this shape; this file is retained immutably for consumers pinned to the v1 contract.",
|
|
7
|
-
"type": "object",
|
|
8
|
-
"required": [
|
|
9
|
-
"schema_version",
|
|
10
|
-
"owner",
|
|
11
|
-
"repo",
|
|
12
|
-
"prNumber",
|
|
13
|
-
"bucket",
|
|
14
|
-
"state"
|
|
15
|
-
],
|
|
16
|
-
"properties": {
|
|
17
|
-
"schema_version": {
|
|
18
|
-
"type": "string",
|
|
19
|
-
"const": "1.0.0"
|
|
20
|
-
},
|
|
21
|
-
"owner": {
|
|
22
|
-
"type": "string"
|
|
23
|
-
},
|
|
24
|
-
"repo": {
|
|
25
|
-
"type": "string"
|
|
26
|
-
},
|
|
27
|
-
"prNumber": {
|
|
28
|
-
"type": "integer"
|
|
29
|
-
},
|
|
30
|
-
"bucket": {
|
|
31
|
-
"type": "string"
|
|
32
|
-
},
|
|
33
|
-
"state": {
|
|
34
|
-
"type": "string",
|
|
35
|
-
"enum": [
|
|
36
|
-
"open",
|
|
37
|
-
"closed",
|
|
38
|
-
"merged"
|
|
39
|
-
]
|
|
40
|
-
},
|
|
41
|
-
"title": {
|
|
42
|
-
"type": "string"
|
|
43
|
-
},
|
|
44
|
-
"headSha": {
|
|
45
|
-
"type": "string"
|
|
46
|
-
},
|
|
47
|
-
"haystackUrl": {
|
|
48
|
-
"type": "string"
|
|
49
|
-
},
|
|
50
|
-
"mergeQueue": {
|
|
51
|
-
"type": "object",
|
|
52
|
-
"properties": {
|
|
53
|
-
"state": {
|
|
54
|
-
"type": "string",
|
|
55
|
-
"enum": [
|
|
56
|
-
"not-enrolled",
|
|
57
|
-
"eligible",
|
|
58
|
-
"grace",
|
|
59
|
-
"queued",
|
|
60
|
-
"merging",
|
|
61
|
-
"merged",
|
|
62
|
-
"blocked"
|
|
63
|
-
]
|
|
64
|
-
},
|
|
65
|
-
"graceEndsAt": {
|
|
66
|
-
"type": [
|
|
67
|
-
"string",
|
|
68
|
-
"null"
|
|
69
|
-
]
|
|
70
|
-
},
|
|
71
|
-
"blockedReason": {
|
|
72
|
-
"type": [
|
|
73
|
-
"string",
|
|
74
|
-
"null"
|
|
75
|
-
]
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
"lastTriage": {
|
|
80
|
-
"type": [
|
|
81
|
-
"object",
|
|
82
|
-
"null"
|
|
83
|
-
],
|
|
84
|
-
"properties": {
|
|
85
|
-
"rating": {
|
|
86
|
-
"type": "integer"
|
|
87
|
-
},
|
|
88
|
-
"completedAt": {
|
|
89
|
-
"type": "string"
|
|
90
|
-
},
|
|
91
|
-
"headSha": {
|
|
92
|
-
"type": "string"
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
package/schemas/pr.v3.json
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://docs.haystackeditor.com/cli/schemas/pr.v3.json",
|
|
4
|
-
"title": "haystack pr get <ref> --json",
|
|
5
|
-
"type": "object",
|
|
6
|
-
"additionalProperties": false,
|
|
7
|
-
"required": ["schema_version", "ref", "title", "head_sha", "triage", "merge"],
|
|
8
|
-
"properties": {
|
|
9
|
-
"schema_version": { "type": "string", "const": "3.0.0" },
|
|
10
|
-
"ref": { "type": "string" },
|
|
11
|
-
"title": { "type": "string" },
|
|
12
|
-
"head_sha": { "type": "string" },
|
|
13
|
-
"triage": {
|
|
14
|
-
"type": "object",
|
|
15
|
-
"additionalProperties": false,
|
|
16
|
-
"required": ["status", "verdict", "findings_count"],
|
|
17
|
-
"properties": {
|
|
18
|
-
"status": { "type": "string", "enum": ["pending", "complete", "failed", "stale", "unavailable"] },
|
|
19
|
-
"verdict": { "type": ["string", "null"], "enum": ["good_to_merge", "needs_review", "needs_input", null] },
|
|
20
|
-
"findings_count": { "type": "integer", "minimum": 0 }
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
"merge": {
|
|
24
|
-
"type": "object",
|
|
25
|
-
"additionalProperties": false,
|
|
26
|
-
"required": ["status", "reason", "blocking_checks", "action"],
|
|
27
|
-
"properties": {
|
|
28
|
-
"status": { "type": "string" },
|
|
29
|
-
"reason": { "type": "string" },
|
|
30
|
-
"blocking_checks": { "type": "array", "items": { "type": "string" } },
|
|
31
|
-
"action": { "type": ["string", "null"] }
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
"fixer": {
|
|
35
|
-
"type": "object",
|
|
36
|
-
"additionalProperties": false,
|
|
37
|
-
"required": ["status", "result_sha", "summary"],
|
|
38
|
-
"properties": {
|
|
39
|
-
"status": { "type": "string", "enum": ["completed", "failed"] },
|
|
40
|
-
"result_sha": { "type": "string" },
|
|
41
|
-
"summary": { "type": "string" }
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|