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