@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.
Files changed (109) hide show
  1. package/README.md +39 -463
  2. package/dist/capture/app-config.js +30 -6
  3. package/dist/commands/capture-brief.js +45 -35
  4. package/dist/commands/capture-contract.js +4 -4
  5. package/dist/commands/crawl-report.js +196 -0
  6. package/dist/commands/db-profile-upload.js +3 -3
  7. package/dist/commands/feedback.js +66 -0
  8. package/dist/commands/init-telemetry.js +55 -9
  9. package/dist/commands/init.js +8 -3
  10. package/dist/commands/lockfile-pin.js +307 -0
  11. package/dist/commands/telemetry-token.js +3 -3
  12. package/dist/commands/tokens.js +4 -4
  13. package/dist/commands/verify-explore.js +3 -3
  14. package/dist/commands/verify-history.js +2 -2
  15. package/dist/commands/verify-onboarding.js +13 -16
  16. package/dist/commands/verify-precompute.js +3 -4
  17. package/dist/commands/verify.js +31 -118
  18. package/dist/index.js +55 -968
  19. package/dist/schema.js +4 -10
  20. package/dist/utils/haystack-api.js +8 -36
  21. package/package.json +1 -5
  22. package/schemas/feedback.v1.json +13 -0
  23. package/schemas/pre-verify.v2.json +240 -0
  24. package/schemas/verify-raw.v1.json +1132 -0
  25. package/schemas/verify.v2.json +655 -0
  26. package/dist/assets/hooks/agent-context/detect.ts +0 -316
  27. package/dist/assets/hooks/agent-context/format.ts +0 -100
  28. package/dist/assets/hooks/agent-context/index.ts +0 -41
  29. package/dist/assets/hooks/agent-context/parsers/claude.ts +0 -262
  30. package/dist/assets/hooks/agent-context/parsers/codex.ts +0 -416
  31. package/dist/assets/hooks/agent-context/parsers/gemini.ts +0 -155
  32. package/dist/assets/hooks/agent-context/parsers/opencode.ts +0 -174
  33. package/dist/assets/hooks/agent-context/tsconfig.json +0 -14
  34. package/dist/assets/hooks/agent-context/types.ts +0 -58
  35. package/dist/assets/hooks/llm-rules-template.md +0 -59
  36. package/dist/assets/hooks/package-lock.json +0 -598
  37. package/dist/assets/hooks/package.json +0 -12
  38. package/dist/assets/hooks/scripts/commit-msg.sh +0 -5
  39. package/dist/assets/hooks/scripts/post-commit.sh +0 -5
  40. package/dist/assets/hooks/scripts/pre-commit.sh +0 -175
  41. package/dist/assets/hooks/scripts/pre-push.sh +0 -25
  42. package/dist/assets/hooks/scripts/prepare-commit-msg.sh +0 -5
  43. package/dist/assets/hooks/truncation-checker/ast-analyzer.ts +0 -528
  44. package/dist/assets/hooks/truncation-checker/index.ts +0 -595
  45. package/dist/assets/hooks/truncation-checker/tsconfig.json +0 -13
  46. package/dist/assets/skills/map-cloud-verifier-universe/SKILL.md +0 -2051
  47. package/dist/assets/skills/map-cloud-verifier-universe/agents/openai.yaml +0 -4
  48. package/dist/assets/skills/map-cloud-verifier-universe/references/output-contract.md +0 -3411
  49. package/dist/assets/skills/map-your-system.md +0 -143
  50. package/dist/assets/skills/submit.md +0 -200
  51. package/dist/commands/ask.js +0 -20
  52. package/dist/commands/cloud-verifier-behaviors.js +0 -218
  53. package/dist/commands/cloud-verifier-data-store-census.js +0 -539
  54. package/dist/commands/cloud-verifier-data-store-drift.js +0 -158
  55. package/dist/commands/cloud-verifier-identity-census.js +0 -4060
  56. package/dist/commands/cloud-verifier-materialization.js +0 -704
  57. package/dist/commands/cloud-verifier-pascal-selector-census.js +0 -1382
  58. package/dist/commands/cloud-verifier-python-manifest-selector-census.js +0 -2015
  59. package/dist/commands/cloud-verifier-specialized-operational-census.js +0 -11432
  60. package/dist/commands/cloud-verifier-universe.js +0 -10178
  61. package/dist/commands/config.js +0 -549
  62. package/dist/commands/design-verify.js +0 -311
  63. package/dist/commands/dismiss.js +0 -159
  64. package/dist/commands/hooks.js +0 -226
  65. package/dist/commands/inbox.js +0 -137
  66. package/dist/commands/mcp.js +0 -201
  67. package/dist/commands/policy.js +0 -371
  68. package/dist/commands/pr-status.js +0 -207
  69. package/dist/commands/pr.js +0 -105
  70. package/dist/commands/prepare-universe-review.js +0 -1092
  71. package/dist/commands/production-source-deny-policy.js +0 -100
  72. package/dist/commands/request-review.js +0 -74
  73. package/dist/commands/review.js +0 -191
  74. package/dist/commands/rules.js +0 -98
  75. package/dist/commands/scaffold-provisional-universe.js +0 -806
  76. package/dist/commands/setup.js +0 -1170
  77. package/dist/commands/skills.js +0 -447
  78. package/dist/commands/status.js +0 -35
  79. package/dist/commands/submit.js +0 -745
  80. package/dist/commands/system-map.js +0 -228
  81. package/dist/commands/triage.js +0 -598
  82. package/dist/commands/webhooks.js +0 -241
  83. package/dist/states.js +0 -46
  84. package/dist/tools/detect.js +0 -832
  85. package/dist/triage/astra.js +0 -202
  86. package/dist/triage/prompts.js +0 -188
  87. package/dist/triage/runner.js +0 -200
  88. package/dist/triage/types.js +0 -7
  89. package/dist/types.js +0 -326
  90. package/dist/utils/action-output.js +0 -26
  91. package/dist/utils/analysis-api.js +0 -416
  92. package/dist/utils/config.js +0 -54
  93. package/dist/utils/design-verifier-api.js +0 -294
  94. package/dist/utils/design-verifier-history.js +0 -79
  95. package/dist/utils/design-verifier-result.js +0 -424
  96. package/dist/utils/github-api.js +0 -324
  97. package/dist/utils/pending-state.js +0 -86
  98. package/dist/utils/pr-ref.js +0 -56
  99. package/dist/utils/prompter.js +0 -328
  100. package/schemas/action.v1.json +0 -22
  101. package/schemas/ask.v1.json +0 -40
  102. package/schemas/inbox.v1.json +0 -27
  103. package/schemas/pr-status.v1.json +0 -61
  104. package/schemas/pr.v1.json +0 -97
  105. package/schemas/pr.v3.json +0 -45
  106. package/schemas/setup.v1.json +0 -75
  107. package/schemas/submit.v1.json +0 -90
  108. package/schemas/triage.v1.json +0 -103
  109. package/schemas/triage.v2.json +0 -64
@@ -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
- }
@@ -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
- }
@@ -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
- }
@@ -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
- }
@@ -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
- }
@@ -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
- }