@claudexor/cli 1.0.1

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 (131) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +22 -0
  3. package/dist/args.d.ts +12 -0
  4. package/dist/args.d.ts.map +1 -0
  5. package/dist/args.js +88 -0
  6. package/dist/args.js.map +1 -0
  7. package/dist/attachment-resolver.d.ts +11 -0
  8. package/dist/attachment-resolver.d.ts.map +1 -0
  9. package/dist/attachment-resolver.js +61 -0
  10. package/dist/attachment-resolver.js.map +1 -0
  11. package/dist/capabilities.d.ts +13 -0
  12. package/dist/capabilities.d.ts.map +1 -0
  13. package/dist/capabilities.js +90 -0
  14. package/dist/capabilities.js.map +1 -0
  15. package/dist/claudexord.d.ts +3 -0
  16. package/dist/claudexord.d.ts.map +1 -0
  17. package/dist/claudexord.js +564 -0
  18. package/dist/claudexord.js.map +1 -0
  19. package/dist/cli-io.d.ts +28 -0
  20. package/dist/cli-io.d.ts.map +1 -0
  21. package/dist/cli-io.js +37 -0
  22. package/dist/cli-io.js.map +1 -0
  23. package/dist/cli.d.ts +3 -0
  24. package/dist/cli.d.ts.map +1 -0
  25. package/dist/cli.js +1459 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/command-registry.d.ts +105 -0
  28. package/dist/command-registry.d.ts.map +1 -0
  29. package/dist/command-registry.js +516 -0
  30. package/dist/command-registry.js.map +1 -0
  31. package/dist/daemon-lifecycle.d.ts +18 -0
  32. package/dist/daemon-lifecycle.d.ts.map +1 -0
  33. package/dist/daemon-lifecycle.js +62 -0
  34. package/dist/daemon-lifecycle.js.map +1 -0
  35. package/dist/daemon-run.d.ts +86 -0
  36. package/dist/daemon-run.d.ts.map +1 -0
  37. package/dist/daemon-run.js +269 -0
  38. package/dist/daemon-run.js.map +1 -0
  39. package/dist/decision.d.ts +18 -0
  40. package/dist/decision.d.ts.map +1 -0
  41. package/dist/decision.js +46 -0
  42. package/dist/decision.js.map +1 -0
  43. package/dist/live.d.ts +26 -0
  44. package/dist/live.d.ts.map +1 -0
  45. package/dist/live.js +311 -0
  46. package/dist/live.js.map +1 -0
  47. package/dist/mcp-runner.d.ts +41 -0
  48. package/dist/mcp-runner.d.ts.map +1 -0
  49. package/dist/mcp-runner.js +306 -0
  50. package/dist/mcp-runner.js.map +1 -0
  51. package/dist/ops-commands.d.ts +11 -0
  52. package/dist/ops-commands.d.ts.map +1 -0
  53. package/dist/ops-commands.js +358 -0
  54. package/dist/ops-commands.js.map +1 -0
  55. package/dist/orchestrate-options.d.ts +9 -0
  56. package/dist/orchestrate-options.d.ts.map +1 -0
  57. package/dist/orchestrate-options.js +16 -0
  58. package/dist/orchestrate-options.js.map +1 -0
  59. package/dist/orphan-reaper.d.ts +9 -0
  60. package/dist/orphan-reaper.d.ts.map +1 -0
  61. package/dist/orphan-reaper.js +97 -0
  62. package/dist/orphan-reaper.js.map +1 -0
  63. package/dist/orphan-sweeper.d.ts +7 -0
  64. package/dist/orphan-sweeper.d.ts.map +1 -0
  65. package/dist/orphan-sweeper.js +289 -0
  66. package/dist/orphan-sweeper.js.map +1 -0
  67. package/dist/plugins.d.ts +44 -0
  68. package/dist/plugins.d.ts.map +1 -0
  69. package/dist/plugins.js +1383 -0
  70. package/dist/plugins.js.map +1 -0
  71. package/dist/primary-output.d.ts +14 -0
  72. package/dist/primary-output.d.ts.map +1 -0
  73. package/dist/primary-output.js +34 -0
  74. package/dist/primary-output.js.map +1 -0
  75. package/dist/registry.d.ts +26 -0
  76. package/dist/registry.d.ts.map +1 -0
  77. package/dist/registry.js +71 -0
  78. package/dist/registry.js.map +1 -0
  79. package/dist/release.d.ts +14 -0
  80. package/dist/release.d.ts.map +1 -0
  81. package/dist/release.js +49 -0
  82. package/dist/release.js.map +1 -0
  83. package/dist/repl.d.ts +26 -0
  84. package/dist/repl.d.ts.map +1 -0
  85. package/dist/repl.js +277 -0
  86. package/dist/repl.js.map +1 -0
  87. package/dist/review-command.d.ts +3 -0
  88. package/dist/review-command.d.ts.map +1 -0
  89. package/dist/review-command.js +83 -0
  90. package/dist/review-command.js.map +1 -0
  91. package/dist/reviewer-options.d.ts +18 -0
  92. package/dist/reviewer-options.d.ts.map +1 -0
  93. package/dist/reviewer-options.js +110 -0
  94. package/dist/reviewer-options.js.map +1 -0
  95. package/dist/run-options.d.ts +8 -0
  96. package/dist/run-options.d.ts.map +1 -0
  97. package/dist/run-options.js +50 -0
  98. package/dist/run-options.js.map +1 -0
  99. package/dist/run-secret-scan.d.ts +2 -0
  100. package/dist/run-secret-scan.d.ts.map +1 -0
  101. package/dist/run-secret-scan.js +5 -0
  102. package/dist/run-secret-scan.js.map +1 -0
  103. package/dist/settings-command.d.ts +3 -0
  104. package/dist/settings-command.d.ts.map +1 -0
  105. package/dist/settings-command.js +202 -0
  106. package/dist/settings-command.js.map +1 -0
  107. package/dist/settings-display.d.ts +3 -0
  108. package/dist/settings-display.d.ts.map +1 -0
  109. package/dist/settings-display.js +33 -0
  110. package/dist/settings-display.js.map +1 -0
  111. package/dist/settings-service.d.ts +15 -0
  112. package/dist/settings-service.d.ts.map +1 -0
  113. package/dist/settings-service.js +91 -0
  114. package/dist/settings-service.js.map +1 -0
  115. package/dist/setup-jobs.d.ts +28 -0
  116. package/dist/setup-jobs.d.ts.map +1 -0
  117. package/dist/setup-jobs.js +477 -0
  118. package/dist/setup-jobs.js.map +1 -0
  119. package/dist/spec.d.ts +84 -0
  120. package/dist/spec.d.ts.map +1 -0
  121. package/dist/spec.js +438 -0
  122. package/dist/spec.js.map +1 -0
  123. package/dist/trust-command.d.ts +3 -0
  124. package/dist/trust-command.d.ts.map +1 -0
  125. package/dist/trust-command.js +80 -0
  126. package/dist/trust-command.js.map +1 -0
  127. package/dist/trust-services.d.ts +7 -0
  128. package/dist/trust-services.d.ts.map +1 -0
  129. package/dist/trust-services.js +35 -0
  130. package/dist/trust-services.js.map +1 -0
  131. package/package.json +59 -0
package/dist/spec.js ADDED
@@ -0,0 +1,438 @@
1
+ import { readFileSync, realpathSync, renameSync, rmSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { ArtifactStore } from "@claudexor/artifact-store";
4
+ import { InterviewEngine, diffSpecPacks, } from "@claudexor/interview";
5
+ import { SpecPack as SpecPackSchema } from "@claudexor/schema";
6
+ import { assertNoInlineSecretValues, ensureDir, hashJson, readJsonSafe, redactSecrets, writeJson, writeText } from "@claudexor/util";
7
+ const INTERVIEW_KINDS = new Set(["single", "multi", "text"]);
8
+ export function loadFrozenSpec(path) {
9
+ let raw;
10
+ try {
11
+ raw = readFileSync(path, "utf8");
12
+ }
13
+ catch (err) {
14
+ throw new Error(`cannot read --spec '${path}': ${err instanceof Error ? err.message : String(err)}`);
15
+ }
16
+ let parsed;
17
+ try {
18
+ parsed = JSON.parse(raw);
19
+ }
20
+ catch (err) {
21
+ throw new Error(`invalid --spec '${path}' JSON: ${err instanceof Error ? err.message : String(err)}`);
22
+ }
23
+ const result = SpecPackSchema.safeParse(parsed);
24
+ if (!result.success) {
25
+ const issue = result.error.issues[0];
26
+ const where = issue?.path.length ? issue.path.join(".") : "root";
27
+ const what = issue?.message ?? "schema validation failed";
28
+ throw new Error(`invalid --spec '${path}' schema at ${where}: ${what}`);
29
+ }
30
+ let resolved;
31
+ try {
32
+ resolved = realpathSync(path);
33
+ }
34
+ catch (err) {
35
+ throw new Error(`cannot resolve --spec '${path}': ${err instanceof Error ? err.message : String(err)}`);
36
+ }
37
+ return { spec: result.data, specPath: resolved, specHash: hashJson(result.data) };
38
+ }
39
+ export function resolveRunTestCommands(cliTests, spec) {
40
+ if (cliTests && cliTests.length > 0)
41
+ return cliTests;
42
+ const specTests = spec?.tests.map((test) => test.command) ?? [];
43
+ return specTests.length > 0 ? specTests : undefined;
44
+ }
45
+ export function buildGroundingPrompt(prompt, priorDecisions = []) {
46
+ const deeper = priorDecisions.length > 0;
47
+ const priorSection = deeper
48
+ ? `\n\nDECISIONS ALREADY MADE (the user answered these — do NOT re-ask them; treat them as fixed and surface the NEXT, deeper layer of decisions these answers unlock):\n${priorDecisions
49
+ .map((d) => `- ${d.question} => ${d.answer}`)
50
+ .join("\n")}`
51
+ : "";
52
+ const countLine = deeper
53
+ ? "List the next 3–6 DEEPER open decisions that the answers above now make relevant"
54
+ : "List 4–8 of the MOST important open decisions";
55
+ const noneLine = deeper
56
+ ? "If the spec is now unambiguous and there are genuinely no FURTHER open decisions, write a single bullet: - (none)"
57
+ : "If there are genuinely no open decisions, write a single bullet: - (none)";
58
+ return `${prompt}${priorSection}
59
+
60
+ ---
61
+ GROUNDING INSTRUCTION (for Claudexor's spec interview — do this in addition to your plan):
62
+ Identify the material decisions a developer must make BEFORE implementing this${deeper ? ", GIVEN the decisions already made above" : ""}, then
63
+ end your response with a section titled exactly:
64
+
65
+ ## Open Questions
66
+
67
+ ${countLine}, one per bullet, in EXACTLY this format:
68
+
69
+ - [single] <question> :: <option A> :: <option B> :: <option C>
70
+ - [multi] <question> :: <option A> :: <option B> :: <option C>
71
+ - [text] <question that has no good fixed options>
72
+
73
+ Rules:
74
+ - [single] = pick exactly one; [multi] = pick one or more; [text] = free-form (no "::" options).
75
+ - For [single], make options MUTUALLY EXCLUSIVE; for [multi], make options concrete
76
+ INDEPENDENT selections that can be combined. Ground every option in THIS repository.
77
+ - Prefer [single]/[multi] with real options over [text] whenever sensible choices exist.
78
+ - Do NOT repeat any decision already made above; each question must open NEW ground.
79
+ - ${noneLine}`;
80
+ }
81
+ /** A real markdown ATX heading: 1–6 leading `#` then a space. Used as the
82
+ * open-questions block terminator so an inline `#`-prefixed bullet body (e.g. a
83
+ * shell `#comment`) does not cut the block short. */
84
+ function isMarkdownHeading(line) {
85
+ let i = 0;
86
+ while (i < line.length && line[i] === "#")
87
+ i++;
88
+ return i >= 1 && i <= 6 && line[i] === " ";
89
+ }
90
+ function markdownHeadingText(line) {
91
+ let i = 0;
92
+ while (i < line.length && line[i] === "#")
93
+ i++;
94
+ return line.slice(i).trim().replace(/\s+#+\s*$/, "");
95
+ }
96
+ /** A "no open decisions" sentinel bullet body, e.g. `(none)` / `(none — ...)`. */
97
+ function isNoneBullet(body) {
98
+ return !body || body.toLowerCase().startsWith("(none");
99
+ }
100
+ /**
101
+ * A leaked grounding-prompt format placeholder — ONLY the exact templates this
102
+ * module's buildGroundingPrompt emits (`<question>`, `<question that ...>`,
103
+ * `<option A>`…). Narrow on purpose so legitimate angle-bracket options a harness
104
+ * may produce (e.g. `<stdio.h>`, `<Button>`, `<input>`) are NOT dropped.
105
+ */
106
+ function isPlaceholder(text) {
107
+ const t = text.trim().toLowerCase();
108
+ if (t === "<question>" || t === "<question that has no good fixed options>")
109
+ return true;
110
+ return t.startsWith("<option ") && t.endsWith(">");
111
+ }
112
+ /**
113
+ * Parse the grounding plan's "Open Questions" section into an interactive interview.
114
+ *
115
+ * The grounding prompt (see claudexord.specQuestions) asks the harness to end its
116
+ * plan with an `## Open Questions` section, one bullet per decision, in the format:
117
+ *
118
+ * - [single] Which auth flow? :: OAuth :: API key :: Both
119
+ * - [multi] Which platforms? :: iOS :: Android :: Web
120
+ * - [text] Any naming constraints?
121
+ *
122
+ * `[single|multi|text]` is the answer kind; `::` separates the question from each
123
+ * option. Parsing is TOLERANT so the quiz degrades gracefully and old plans still
124
+ * work: an untagged bullet with no `::` becomes a free-text question (the previous
125
+ * behavior); an untagged bullet WITH options defaults to single-choice; a tagged
126
+ * choice question with no options falls back to text. `(none)` is skipped. This is
127
+ * plain delimiter parsing of the harness's own structured output (a data shape we
128
+ * instructed), not a governance signal — it does not infer risk/success/etc.
129
+ */
130
+ export function extractQuestionsFromPlan(plan) {
131
+ const lines = plan.split("\n");
132
+ // A grounding plan can contain SEVERAL "open questions" headings:
133
+ // 1. the echoed grounding INSTRUCTION (placeholder template + "Rules:"),
134
+ // 2. the harness's REAL interview section (what we want),
135
+ // 3. an orchestrator-appended REVIEW-findings "Open questions" (e.g. a
136
+ // NEEDS_HUMAN patch-identity error) — NOT interview questions.
137
+ // So we can't take the first or the last block. Parse EVERY block and pick the
138
+ // one with the most STRUCTURED (tagged single/multi) questions; the echoed
139
+ // instruction block is skipped outright by its signature. (Heading match is a
140
+ // REAL markdown heading whose text mentions the section, so a stray
141
+ // `#open questions` non-heading line can't start a block.)
142
+ const blocks = [];
143
+ let afterReviewFindings = false;
144
+ for (let i = 0; i < lines.length; i++) {
145
+ const t = (lines[i] ?? "").trim();
146
+ if (!isMarkdownHeading(t))
147
+ continue;
148
+ const heading = markdownHeadingText(t).toLowerCase();
149
+ if (!heading.includes("open questions")) {
150
+ afterReviewFindings ||= heading.includes("review findings");
151
+ continue;
152
+ }
153
+ const blockLines = [];
154
+ for (const raw of lines.slice(i + 1)) {
155
+ if (isMarkdownHeading(raw.trim()))
156
+ break; // next real heading ends the block
157
+ blockLines.push(raw);
158
+ }
159
+ // Skip the echoed grounding instruction itself (it carries the format spec, not
160
+ // real questions). Its placeholder bullets would be dropped anyway, but the
161
+ // "Rules:" lines could otherwise parse as junk questions.
162
+ if (blockLines.some((l) => {
163
+ const low = l.toLowerCase();
164
+ return low.includes("in exactly this format") || low.includes("[single] = pick exactly one");
165
+ }))
166
+ continue;
167
+ blocks.push({ questions: parseQuestionBullets(blockLines), afterReviewFindings });
168
+ }
169
+ // Best block: most tagged (single/multi) questions, tie-broken by total count.
170
+ // Prefer blocks before a review-findings section so a legacy free-text interview
171
+ // is not displaced by an appended review error block.
172
+ let best = [];
173
+ let bestScore = [-1, -1];
174
+ const candidates = blocks.some((b) => !b.afterReviewFindings) ? blocks.filter((b) => !b.afterReviewFindings) : blocks;
175
+ for (const { questions: qs } of candidates) {
176
+ const tagged = qs.filter((q) => q.kind === "single" || q.kind === "multi").length;
177
+ const score = [tagged, qs.length];
178
+ if (score[0] > bestScore[0] || (score[0] === bestScore[0] && score[1] > bestScore[1])) {
179
+ bestScore = score;
180
+ best = qs;
181
+ }
182
+ }
183
+ return best;
184
+ }
185
+ /** Parse the bullets of ONE "open questions" block into interview questions. */
186
+ function parseQuestionBullets(blockLines) {
187
+ const questions = [];
188
+ for (const raw of blockLines) {
189
+ const line = raw.trim();
190
+ if (!line.startsWith("- ") && !line.startsWith("* "))
191
+ continue;
192
+ let body = line.slice(2).trim();
193
+ if (isNoneBullet(body))
194
+ continue;
195
+ // Optional leading kind tag: [single] | [multi] | [text].
196
+ let kind = "text";
197
+ let kindTagged = false;
198
+ if (body.startsWith("[")) {
199
+ const close = body.indexOf("]");
200
+ if (close > 0) {
201
+ const tag = body.slice(1, close).trim().toLowerCase();
202
+ if (INTERVIEW_KINDS.has(tag)) {
203
+ kind = tag;
204
+ kindTagged = true;
205
+ body = body.slice(close + 1).trim();
206
+ }
207
+ }
208
+ }
209
+ // Re-check after stripping the tag: `- [text] (none)` must still skip.
210
+ if (isNoneBullet(body))
211
+ continue;
212
+ // "question :: optA :: optB" — `::` separates the prompt from each option.
213
+ // Only treat `::` as an option delimiter when the bullet is TAGGED, or has 2+
214
+ // option segments (a real choice). An untagged legacy bullet with a single `::`
215
+ // (e.g. prose "Session store :: Redis vs Postgres?") is kept as ONE free-text
216
+ // question, not silently turned into a 1-option choice.
217
+ const segments = body.split("::").map((p) => p.trim()).filter((p) => p.length > 0);
218
+ const splitAsChoice = kindTagged ? segments.length > 1 : segments.length >= 3;
219
+ const promptText = splitAsChoice ? (segments[0] ?? "") : body;
220
+ if (!promptText)
221
+ continue;
222
+ // Skip the prompt's own format example if it ever leaks through (a pure
223
+ // angle-bracket placeholder like "<question>"), so the user never sees template text.
224
+ if (isPlaceholder(promptText))
225
+ continue;
226
+ // Drop any leaked template placeholder option labels (e.g. "<option A>") so a
227
+ // partially-echoed bullet can't show "<option A>" chips. If that empties a choice
228
+ // question's options, the normalization below degrades it to free text.
229
+ const options = (splitAsChoice ? segments.slice(1) : [])
230
+ .filter((label) => !isPlaceholder(label))
231
+ .map((label, i) => ({ id: `o${i + 1}`, label }));
232
+ // Untagged: choice when options were given, else free text. A choice with no
233
+ // options can't be picked, so degrade to text.
234
+ if (!kindTagged)
235
+ kind = options.length > 0 ? "single" : "text";
236
+ if (kind !== "text" && options.length === 0)
237
+ kind = "text";
238
+ // Normalize: text questions are free-form (NO options, accept free text);
239
+ // choice questions are choice-only. Keyed off the final kind so a tagged
240
+ // `[text] ... :: A :: B` can't end up unanswerable (options + allow_text:false).
241
+ const isText = kind === "text";
242
+ questions.push({
243
+ id: `q${questions.length + 1}`,
244
+ tier: 0,
245
+ prompt: promptText,
246
+ kind,
247
+ options: isText ? [] : options,
248
+ allow_text: isText,
249
+ rationale: "Surfaced by the grounding plan's open-questions interview.",
250
+ });
251
+ }
252
+ return questions;
253
+ }
254
+ export function readAnswers(path) {
255
+ const parsed = readJsonSafe(path);
256
+ if (!parsed)
257
+ throw new Error(`could not parse answers JSON: ${path}`);
258
+ // Same fence as the daemon spec endpoints: answers become part of the
259
+ // durable SpecPack, so secret-like values are refused at ingestion.
260
+ assertNoInlineSecretValues(parsed, "$", "spec answers file");
261
+ if (Array.isArray(parsed))
262
+ return { answers: parsed };
263
+ return { ...parsed, answers: parsed.answers ?? [] };
264
+ }
265
+ /**
266
+ * The resolved answer for a question, or null when genuinely unanswered. Counts
267
+ * BOTH selected option_ids (resolved to their labels) and free text — so a
268
+ * choice question answered only via chips (text: null) is NOT treated as missing.
269
+ * Without this, single/multi answers would freeze as unresolved clarifications.
270
+ */
271
+ function answerText(q, answers) {
272
+ const a = answers.find((x) => x.question_id === q.id);
273
+ if (!a)
274
+ return null;
275
+ const labels = (a.option_ids ?? [])
276
+ .map((id) => q.options.find((o) => o.id === id)?.label)
277
+ .filter((l) => typeof l === "string" && l.length > 0);
278
+ const text = a.text?.trim();
279
+ const parts = text ? [...labels, text] : labels;
280
+ return parts.length > 0 ? parts.join(", ") : null;
281
+ }
282
+ export function draftFromPlanAndAnswers(prompt, plan, questions, file) {
283
+ // Resolve each interview question to its answer (selected option labels + free
284
+ // text), or null when unanswered. RECORD the resolved decisions in the frozen
285
+ // SpecPack — both structurally (open_questions: status resolved + resolution) and
286
+ // human-readably (decided_tradeoffs) — so an Implement run that reads `specPath`
287
+ // knows exactly what the user chose. Unanswered questions stay `open`, which makes
288
+ // freeze fail loudly (a frozen SpecPack cannot carry open clarifications).
289
+ const resolved = questions
290
+ .map((q) => ({ q, answer: answerText(q, file.answers) }))
291
+ .filter((x) => x.answer !== null);
292
+ return {
293
+ summary: file.summary ?? `Spec for: ${prompt}`,
294
+ success_criteria: (file.success_criteria ?? []).map((text, i) => ({
295
+ id: `ac${i + 1}`,
296
+ behavior: text,
297
+ required: true,
298
+ })),
299
+ non_goals: file.non_goals ?? [],
300
+ forbidden_approaches: file.forbidden_approaches ?? [],
301
+ decided_tradeoffs: [
302
+ ...(file.decided_tradeoffs ?? []),
303
+ // Provenance lines kept first (stable position) — interview decisions follow.
304
+ "Grounding came from Claudexor plan mode: multi-harness read-only planning plus cross-family plan review.",
305
+ `Plan grounding hash: ${hashJson({ plan })}`,
306
+ ...resolved.map(({ q, answer }) => `Interview — ${q.prompt} → ${answer}`),
307
+ ],
308
+ tests: (file.tests ?? []).map((command, i) => ({ id: `gate-${i + 1}`, command, required: true })),
309
+ tasks: [
310
+ { id: "task-1", title: "Implement against the frozen SpecPack", depends_on: [], done: false },
311
+ { id: "task-2", title: "Run deterministic gates and cross-family review", depends_on: ["task-1"], done: false },
312
+ ],
313
+ clarifications: questions.map((q) => {
314
+ const answer = answerText(q, file.answers);
315
+ return {
316
+ id: `clarify-${q.id}`,
317
+ claim: q.prompt,
318
+ status: answer ? "resolved" : "open",
319
+ resolution: answer,
320
+ };
321
+ }),
322
+ // The plan grounding hash lives in decided_tradeoffs (above); native exports
323
+ // carry the full plan text. Protected-path approvals are explicit run input,
324
+ // never inferred from interview prose, so frozen specs cannot contain them.
325
+ constraints: {
326
+ protected_paths: [],
327
+ },
328
+ };
329
+ }
330
+ /**
331
+ * Validate submitted answers against the question contract BEFORE freezing — fail
332
+ * loudly (Bible §5: no silent guessing) rather than freeze a malformed SpecPack.
333
+ * Rejects an answer for an unknown question id, unknown option ids, more than one
334
+ * option on a single-choice question, and free text where the question disallows it.
335
+ */
336
+ export function validateAnswers(questions, answers) {
337
+ const byId = new Map(questions.map((q) => [q.id, q]));
338
+ const seen = new Set();
339
+ for (const a of answers) {
340
+ if (seen.has(a.question_id)) {
341
+ throw new Error(`spec answer: duplicate answer for question "${a.question_id}"`);
342
+ }
343
+ seen.add(a.question_id);
344
+ const q = byId.get(a.question_id);
345
+ if (!q)
346
+ throw new Error(`spec answer for unknown question "${a.question_id}"`);
347
+ const validIds = new Set(q.options.map((o) => o.id));
348
+ const unknown = (a.option_ids ?? []).filter((id) => !validIds.has(id));
349
+ if (unknown.length > 0) {
350
+ throw new Error(`spec answer for "${q.id}": unknown option id(s): ${unknown.join(", ")}`);
351
+ }
352
+ if (q.kind === "single" && (a.option_ids?.length ?? 0) > 1) {
353
+ throw new Error(`spec answer for "${q.id}": single-choice question accepts at most one option`);
354
+ }
355
+ if (!q.allow_text && (a.text?.trim() ?? "") !== "") {
356
+ throw new Error(`spec answer for "${q.id}": free text is not allowed for this question`);
357
+ }
358
+ }
359
+ }
360
+ export async function freezeSpecFromGrounding(prompt, plan, answers) {
361
+ const questions = extractQuestionsFromPlan(plan);
362
+ validateAnswers(questions, answers.answers);
363
+ const engine = new InterviewEngine({
364
+ intent: prompt,
365
+ generator: async (state) => (state.tier === 0 ? questions : []),
366
+ assembler: async () => draftFromPlanAndAnswers(prompt, plan, questions, answers),
367
+ });
368
+ await engine.runToConvergence((qs) => qs.map((q) => {
369
+ const a = answers.answers.find((x) => x.question_id === q.id);
370
+ return a ?? { question_id: q.id, option_ids: [], text: null };
371
+ }));
372
+ return engine.freeze();
373
+ }
374
+ function renderNativePlanProjection(spec, plan, specHash) {
375
+ return [
376
+ `# Claudexor Spec ${spec.id} v${spec.version}`,
377
+ "",
378
+ `Spec hash: \`${specHash}\``,
379
+ "",
380
+ "## Intent",
381
+ spec.intent.raw,
382
+ "",
383
+ "## Summary",
384
+ spec.summary || "(none)",
385
+ "",
386
+ "## Acceptance Criteria",
387
+ ...(spec.success_criteria.length ? spec.success_criteria.map((c) => `- [${c.id}] ${c.behavior}`) : ["- (none)"]),
388
+ "",
389
+ "## Tests",
390
+ ...(spec.tests.length ? spec.tests.map((t) => `- ${t.command}`) : ["- (none configured)"]),
391
+ "",
392
+ "## Non-goals",
393
+ ...(spec.non_goals.length ? spec.non_goals.map((x) => `- ${x}`) : ["- (none)"]),
394
+ "",
395
+ "## Forbidden approaches",
396
+ ...(spec.forbidden_approaches.length ? spec.forbidden_approaches.map((x) => `- ${x}`) : ["- (none)"]),
397
+ "",
398
+ "## Source plan grounding",
399
+ redactSecrets(plan).trim(),
400
+ "",
401
+ "> This file is a generated projection for native harnesses. The canonical SSOT",
402
+ `> is .claudexor/specs/${spec.id}/spec.json (hash above). Regenerate rather than editing this projection.`,
403
+ "",
404
+ ].join("\n");
405
+ }
406
+ export function persistSpec(repoRoot, spec, plan, previous) {
407
+ const canonical = SpecPackSchema.parse(spec);
408
+ const specDir = join(repoRoot, ".claudexor", "specs", canonical.id);
409
+ ensureDir(specDir);
410
+ const specHash = hashJson(canonical);
411
+ const changes = previous ? diffSpecPacks(previous, canonical) : [];
412
+ // Secondary artifacts first; canonical spec.json LAST and atomically
413
+ // (tmp + rename) as the commit point — downstream hash verification reads
414
+ // spec.json, so a crash mid-persist leaves either no spec or a complete
415
+ // one, never a torn multi-file state fronted by a valid-looking spec.json.
416
+ new ArtifactStore(repoRoot).writeYaml(join(specDir, "spec.yaml"), canonical);
417
+ writeText(join(specDir, "PLANS.md"), renderNativePlanProjection(canonical, plan, specHash));
418
+ writeJson(join(specDir, "changes.json"), changes);
419
+ // Atomic commit point: rename MOVES the tmp file (no leftover on success);
420
+ // a failure between write and rename must not litter the spec dir either.
421
+ const tmp = join(specDir, `spec.json.tmp-${process.pid}`);
422
+ try {
423
+ writeJson(tmp, canonical);
424
+ renameSync(tmp, join(specDir, "spec.json"));
425
+ }
426
+ catch (err) {
427
+ rmSync(tmp, { force: true });
428
+ throw err;
429
+ }
430
+ return { specDir, specHash, changes };
431
+ }
432
+ export function loadPreviousSpec(path) {
433
+ if (!path)
434
+ return null;
435
+ const raw = readFileSync(path, "utf8");
436
+ return SpecPackSchema.parse(JSON.parse(raw));
437
+ }
438
+ //# sourceMappingURL=spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.js","sourceRoot":"","sources":["../src/spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ParsedArgs } from "./args.js";
2
+ export declare function trustCommand(args: ParsedArgs, json: boolean): Promise<number>;
3
+ //# sourceMappingURL=trust-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trust-command.d.ts","sourceRoot":"","sources":["../src/trust-command.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAU5C,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAqDnF"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * `claudexor trust` — user-local trust settings for THIS repo.
3
+ *
4
+ * Sensitive powers (unsandboxed full access, write-mode default) live ONLY in
5
+ * the user-local trust file keyed by repo-root hash — versioned repo config
6
+ * can never self-grant them (Bible INV-122). This command is the missing
7
+ * WRITER for that file: before it, the full-access refusal named a file no
8
+ * tool could create.
9
+ *
10
+ * claudexor trust # show the resolved trust state + path
11
+ * claudexor trust --allow-full-access # permit access=full for this repo
12
+ * claudexor trust --revoke-full-access # revoke it
13
+ * claudexor trust --access-default workspace_write|readonly
14
+ */
15
+ import { loadConfig, trustConfigPath, updateTrustConfig } from "@claudexor/config";
16
+ import { AccessProfile } from "@claudexor/schema";
17
+ function print(s) {
18
+ process.stdout.write(s + "\n");
19
+ }
20
+ function printJson(value) {
21
+ process.stdout.write(JSON.stringify(value, null, 2) + "\n");
22
+ }
23
+ export async function trustCommand(args, json) {
24
+ const repoRoot = process.cwd();
25
+ const allow = args.flags["allow-full-access"];
26
+ const revoke = args.flags["revoke-full-access"];
27
+ const accessDefaultRaw = args.flags["access-default"];
28
+ const accessDefault = typeof accessDefaultRaw === "string" ? accessDefaultRaw : undefined;
29
+ try {
30
+ if (allow !== undefined || revoke !== undefined || accessDefaultRaw !== undefined) {
31
+ if (allow !== undefined && revoke !== undefined) {
32
+ throw new Error("--allow-full-access and --revoke-full-access are mutually exclusive");
33
+ }
34
+ let parsedDefault;
35
+ if (accessDefaultRaw !== undefined) {
36
+ const parsed = AccessProfile.safeParse(accessDefault);
37
+ // `full` as the DEFAULT for every run is not a supported trust shape —
38
+ // full access stays per-run (--access full) atop the explicit allow.
39
+ if (!parsed.success || parsed.data === "full" || parsed.data === "inherit_native") {
40
+ throw new Error("--access-default must be readonly|workspace_write");
41
+ }
42
+ parsedDefault = parsed.data;
43
+ }
44
+ const res = updateTrustConfig(repoRoot, (cfg) => ({
45
+ ...cfg,
46
+ ...(allow !== undefined ? { allow_full_access: true } : {}),
47
+ ...(revoke !== undefined ? { allow_full_access: false } : {}),
48
+ ...(parsedDefault !== undefined ? { access_default: parsedDefault } : {}),
49
+ }));
50
+ if (json)
51
+ printJson({ path: res.path, trust: res.config });
52
+ else {
53
+ print(`updated ${res.path}`);
54
+ print(`allow_full_access: ${res.config.allow_full_access}`);
55
+ print(`access_default: ${res.config.access_default}`);
56
+ }
57
+ return 0;
58
+ }
59
+ const cfg = loadConfig(repoRoot);
60
+ const path = trustConfigPath(repoRoot);
61
+ if (json)
62
+ printJson({ path, trust: cfg.trust });
63
+ else {
64
+ print(`trust file: ${path}${cfg.sources.includes(path) ? "" : " (not created yet)"}`);
65
+ print(`allow_full_access: ${cfg.trust.allow_full_access}`);
66
+ print(`access_default: ${cfg.trust.access_default}`);
67
+ print("change with: claudexor trust --allow-full-access | --revoke-full-access | --access-default readonly|workspace_write");
68
+ }
69
+ return 0;
70
+ }
71
+ catch (err) {
72
+ const msg = `claudexor trust: ${err instanceof Error ? err.message : String(err)}`;
73
+ if (json)
74
+ printJson({ error: msg });
75
+ else
76
+ process.stderr.write(`${msg}\n`);
77
+ return 1;
78
+ }
79
+ }
80
+ //# sourceMappingURL=trust-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trust-command.js","sourceRoot":"","sources":["../src/trust-command.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { ControlTrustListResponse, ControlTrustState } from "@claudexor/schema";
2
+ export declare function listTrustService(): Promise<ControlTrustListResponse>;
3
+ export declare function updateTrustService(input: {
4
+ repoRoot: string;
5
+ allowFullAccess: boolean;
6
+ }): Promise<ControlTrustState>;
7
+ //# sourceMappingURL=trust-services.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trust-services.d.ts","sourceRoot":"","sources":["../src/trust-services.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGhF,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,wBAAwB,CAAC,CAS1E;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAc1H"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * User-level trust services for the control API (narrow by design): list the
3
+ * per-repo trust files and grant/revoke ONE flag — the same file/writer
4
+ * `claudexor trust` owns. Every other trust field stays CLI-only. Shapes are
5
+ * the schema-owned ControlTrustState (no local DTO forks).
6
+ */
7
+ import { isAbsolute } from "node:path";
8
+ import { ControlTrustListResponse, ControlTrustState } from "@claudexor/schema";
9
+ import { listTrustConfigs, updateTrustConfig } from "@claudexor/config";
10
+ export async function listTrustService() {
11
+ return ControlTrustListResponse.parse({
12
+ entries: listTrustConfigs().map(({ path, config }) => ({
13
+ repoRoot: config.repo_root,
14
+ path,
15
+ allowFullAccess: config.allow_full_access,
16
+ accessDefault: config.access_default,
17
+ })),
18
+ });
19
+ }
20
+ export async function updateTrustService(input) {
21
+ if (!isAbsolute(input.repoRoot)) {
22
+ throw Object.assign(new Error(`repoRoot must be an absolute path (got ${input.repoRoot})`), { status: 400 });
23
+ }
24
+ const res = updateTrustConfig(input.repoRoot, (cfg) => ({
25
+ ...cfg,
26
+ allow_full_access: input.allowFullAccess,
27
+ }));
28
+ return ControlTrustState.parse({
29
+ repoRoot: res.config.repo_root,
30
+ path: res.path,
31
+ allowFullAccess: res.config.allow_full_access,
32
+ accessDefault: res.config.access_default,
33
+ });
34
+ }
35
+ //# sourceMappingURL=trust-services.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trust-services.js","sourceRoot":"","sources":["../src/trust-services.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAExE,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,OAAO,wBAAwB,CAAC,KAAK,CAAC;QACpC,OAAO,EAAE,gBAAgB,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;YACrD,QAAQ,EAAE,MAAM,CAAC,SAAS;YAC1B,IAAI;YACJ,eAAe,EAAE,MAAM,CAAC,iBAAiB;YACzC,aAAa,EAAE,MAAM,CAAC,cAAc;SACrC,CAAC,CAAC;KACJ,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAAqD;IAC5F,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChC,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,0CAA0C,KAAK,CAAC,QAAQ,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IAC/G,CAAC;IACD,MAAM,GAAG,GAAG,iBAAiB,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACtD,GAAG,GAAG;QACN,iBAAiB,EAAE,KAAK,CAAC,eAAe;KACzC,CAAC,CAAC,CAAC;IACJ,OAAO,iBAAiB,CAAC,KAAK,CAAC;QAC7B,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS;QAC9B,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,iBAAiB;QAC7C,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,cAAc;KACzC,CAAC,CAAC;AACL,CAAC"}