@claudexor/cli 1.0.1 → 2.1.2

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 (213) hide show
  1. package/dist/acp-surface-runner.d.ts +17 -0
  2. package/dist/acp-surface-runner.d.ts.map +1 -0
  3. package/dist/acp-surface-runner.js +187 -0
  4. package/dist/acp-surface-runner.js.map +1 -0
  5. package/dist/args.d.ts.map +1 -1
  6. package/dist/args.js.map +1 -1
  7. package/dist/bridge-serve.d.ts +3 -0
  8. package/dist/bridge-serve.d.ts.map +1 -0
  9. package/dist/bridge-serve.js +39 -0
  10. package/dist/bridge-serve.js.map +1 -0
  11. package/dist/capabilities.d.ts.map +1 -1
  12. package/dist/capabilities.js +12 -3
  13. package/dist/capabilities.js.map +1 -1
  14. package/dist/claude-oauth-usage.d.ts +33 -0
  15. package/dist/claude-oauth-usage.d.ts.map +1 -0
  16. package/dist/claude-oauth-usage.js +190 -0
  17. package/dist/claude-oauth-usage.js.map +1 -0
  18. package/dist/claude-statusline.d.ts +25 -0
  19. package/dist/claude-statusline.d.ts.map +1 -0
  20. package/dist/claude-statusline.js +259 -0
  21. package/dist/claude-statusline.js.map +1 -0
  22. package/dist/claudexord.js +346 -543
  23. package/dist/claudexord.js.map +1 -1
  24. package/dist/cli-io.d.ts +8 -9
  25. package/dist/cli-io.d.ts.map +1 -1
  26. package/dist/cli-io.js +11 -7
  27. package/dist/cli-io.js.map +1 -1
  28. package/dist/cli.js +475 -516
  29. package/dist/cli.js.map +1 -1
  30. package/dist/codex-quota-source.d.ts +11 -0
  31. package/dist/codex-quota-source.d.ts.map +1 -0
  32. package/dist/codex-quota-source.js +181 -0
  33. package/dist/codex-quota-source.js.map +1 -0
  34. package/dist/command-flags.d.ts +18 -0
  35. package/dist/command-flags.d.ts.map +1 -0
  36. package/dist/command-flags.js +124 -0
  37. package/dist/command-flags.js.map +1 -0
  38. package/dist/command-registry.d.ts +2 -40
  39. package/dist/command-registry.d.ts.map +1 -1
  40. package/dist/command-registry.js +74 -164
  41. package/dist/command-registry.js.map +1 -1
  42. package/dist/control-services.d.ts +2483 -0
  43. package/dist/control-services.d.ts.map +1 -0
  44. package/dist/control-services.js +437 -0
  45. package/dist/control-services.js.map +1 -0
  46. package/dist/credential-commands.d.ts +9 -0
  47. package/dist/credential-commands.d.ts.map +1 -0
  48. package/dist/credential-commands.js +224 -0
  49. package/dist/credential-commands.js.map +1 -0
  50. package/dist/daemon-lifecycle.d.ts +7 -3
  51. package/dist/daemon-lifecycle.d.ts.map +1 -1
  52. package/dist/daemon-lifecycle.js +40 -12
  53. package/dist/daemon-lifecycle.js.map +1 -1
  54. package/dist/daemon-run.d.ts +2 -0
  55. package/dist/daemon-run.d.ts.map +1 -1
  56. package/dist/daemon-run.js +62 -14
  57. package/dist/daemon-run.js.map +1 -1
  58. package/dist/daemon-runtime-shutdown.d.ts +58 -0
  59. package/dist/daemon-runtime-shutdown.d.ts.map +1 -0
  60. package/dist/daemon-runtime-shutdown.js +142 -0
  61. package/dist/daemon-runtime-shutdown.js.map +1 -0
  62. package/dist/decision.d.ts.map +1 -1
  63. package/dist/decision.js +12 -3
  64. package/dist/decision.js.map +1 -1
  65. package/dist/live.d.ts +29 -0
  66. package/dist/live.d.ts.map +1 -1
  67. package/dist/live.js +117 -6
  68. package/dist/live.js.map +1 -1
  69. package/dist/local-attachment.d.ts +14 -0
  70. package/dist/local-attachment.d.ts.map +1 -0
  71. package/dist/local-attachment.js +67 -0
  72. package/dist/local-attachment.js.map +1 -0
  73. package/dist/mcp-runner.d.ts +4 -15
  74. package/dist/mcp-runner.d.ts.map +1 -1
  75. package/dist/mcp-runner.js +273 -145
  76. package/dist/mcp-runner.js.map +1 -1
  77. package/dist/native-login.d.ts +21 -0
  78. package/dist/native-login.d.ts.map +1 -0
  79. package/dist/native-login.js +111 -0
  80. package/dist/native-login.js.map +1 -0
  81. package/dist/ops-commands.d.ts +8 -6
  82. package/dist/ops-commands.d.ts.map +1 -1
  83. package/dist/ops-commands.js +250 -168
  84. package/dist/ops-commands.js.map +1 -1
  85. package/dist/orchestrate-options.d.ts.map +1 -1
  86. package/dist/orchestrate-options.js +1 -1
  87. package/dist/orchestrate-options.js.map +1 -1
  88. package/dist/orphan-reaper.d.ts +4 -5
  89. package/dist/orphan-reaper.d.ts.map +1 -1
  90. package/dist/orphan-reaper.js +29 -56
  91. package/dist/orphan-reaper.js.map +1 -1
  92. package/dist/orphan-sweeper.d.ts +1 -2
  93. package/dist/orphan-sweeper.d.ts.map +1 -1
  94. package/dist/orphan-sweeper.js +29 -48
  95. package/dist/orphan-sweeper.js.map +1 -1
  96. package/dist/plugins.d.ts.map +1 -1
  97. package/dist/plugins.js +196 -64
  98. package/dist/plugins.js.map +1 -1
  99. package/dist/primary-output.d.ts.map +1 -1
  100. package/dist/primary-output.js.map +1 -1
  101. package/dist/profile-registration.d.ts +15 -0
  102. package/dist/profile-registration.d.ts.map +1 -0
  103. package/dist/profile-registration.js +68 -0
  104. package/dist/profile-registration.js.map +1 -0
  105. package/dist/project-command.d.ts +3 -0
  106. package/dist/project-command.d.ts.map +1 -0
  107. package/dist/project-command.js +87 -0
  108. package/dist/project-command.js.map +1 -0
  109. package/dist/quota-command.d.ts +3 -0
  110. package/dist/quota-command.d.ts.map +1 -0
  111. package/dist/quota-command.js +59 -0
  112. package/dist/quota-command.js.map +1 -0
  113. package/dist/registry.d.ts +1 -1
  114. package/dist/registry.d.ts.map +1 -1
  115. package/dist/registry.js +16 -4
  116. package/dist/registry.js.map +1 -1
  117. package/dist/release.d.ts.map +1 -1
  118. package/dist/release.js +15 -3
  119. package/dist/release.js.map +1 -1
  120. package/dist/repl.d.ts +3 -8
  121. package/dist/repl.d.ts.map +1 -1
  122. package/dist/repl.js +23 -122
  123. package/dist/repl.js.map +1 -1
  124. package/dist/request-preflight.d.ts +13 -0
  125. package/dist/request-preflight.d.ts.map +1 -0
  126. package/dist/request-preflight.js +81 -0
  127. package/dist/request-preflight.js.map +1 -0
  128. package/dist/retention-service.d.ts +24 -0
  129. package/dist/retention-service.d.ts.map +1 -0
  130. package/dist/retention-service.js +100 -0
  131. package/dist/retention-service.js.map +1 -0
  132. package/dist/retry-command-specs.d.ts +3 -0
  133. package/dist/retry-command-specs.d.ts.map +1 -0
  134. package/dist/retry-command-specs.js +21 -0
  135. package/dist/retry-command-specs.js.map +1 -0
  136. package/dist/retry-command.d.ts +4 -0
  137. package/dist/retry-command.d.ts.map +1 -0
  138. package/dist/retry-command.js +57 -0
  139. package/dist/retry-command.js.map +1 -0
  140. package/dist/review-command.d.ts.map +1 -1
  141. package/dist/review-command.js +47 -12
  142. package/dist/review-command.js.map +1 -1
  143. package/dist/run-options.d.ts +2 -2
  144. package/dist/run-options.d.ts.map +1 -1
  145. package/dist/run-options.js +27 -5
  146. package/dist/run-options.js.map +1 -1
  147. package/dist/settings-command.d.ts.map +1 -1
  148. package/dist/settings-command.js +143 -188
  149. package/dist/settings-command.js.map +1 -1
  150. package/dist/settings-service.d.ts +50 -0
  151. package/dist/settings-service.d.ts.map +1 -1
  152. package/dist/settings-service.js +67 -1
  153. package/dist/settings-service.js.map +1 -1
  154. package/dist/setup-job-reducer.d.ts +9 -0
  155. package/dist/setup-job-reducer.d.ts.map +1 -0
  156. package/dist/setup-job-reducer.js +290 -0
  157. package/dist/setup-job-reducer.js.map +1 -0
  158. package/dist/setup-job-store.d.ts +250 -0
  159. package/dist/setup-job-store.d.ts.map +1 -0
  160. package/dist/setup-job-store.js +359 -0
  161. package/dist/setup-job-store.js.map +1 -0
  162. package/dist/setup-job-support.d.ts +27 -0
  163. package/dist/setup-job-support.d.ts.map +1 -0
  164. package/dist/setup-job-support.js +141 -0
  165. package/dist/setup-job-support.js.map +1 -0
  166. package/dist/setup-jobs.d.ts +437 -22
  167. package/dist/setup-jobs.d.ts.map +1 -1
  168. package/dist/setup-jobs.js +813 -423
  169. package/dist/setup-jobs.js.map +1 -1
  170. package/dist/setup-lifecycle-binding.d.ts +40 -0
  171. package/dist/setup-lifecycle-binding.d.ts.map +1 -0
  172. package/dist/setup-lifecycle-binding.js +159 -0
  173. package/dist/setup-lifecycle-binding.js.map +1 -0
  174. package/dist/setup-login-protocol.d.ts +13 -0
  175. package/dist/setup-login-protocol.d.ts.map +1 -0
  176. package/dist/setup-login-protocol.js +179 -0
  177. package/dist/setup-login-protocol.js.map +1 -0
  178. package/dist/setup-login-runner.d.ts +20 -0
  179. package/dist/setup-login-runner.d.ts.map +1 -0
  180. package/dist/setup-login-runner.js +225 -0
  181. package/dist/setup-login-runner.js.map +1 -0
  182. package/dist/setup-supervisor.d.ts +53 -0
  183. package/dist/setup-supervisor.d.ts.map +1 -0
  184. package/dist/setup-supervisor.js +177 -0
  185. package/dist/setup-supervisor.js.map +1 -0
  186. package/dist/spec.d.ts +9 -20
  187. package/dist/spec.d.ts.map +1 -1
  188. package/dist/spec.js +49 -21
  189. package/dist/spec.js.map +1 -1
  190. package/dist/thread-delivery.d.ts +18 -0
  191. package/dist/thread-delivery.d.ts.map +1 -0
  192. package/dist/thread-delivery.js +67 -0
  193. package/dist/thread-delivery.js.map +1 -0
  194. package/dist/thread-select.d.ts +9 -0
  195. package/dist/thread-select.d.ts.map +1 -0
  196. package/dist/thread-select.js +12 -0
  197. package/dist/thread-select.js.map +1 -0
  198. package/dist/trust-command.d.ts.map +1 -1
  199. package/dist/trust-command.js +69 -61
  200. package/dist/trust-command.js.map +1 -1
  201. package/dist/trust-services.d.ts +5 -6
  202. package/dist/trust-services.d.ts.map +1 -1
  203. package/dist/trust-services.js +42 -13
  204. package/dist/trust-services.js.map +1 -1
  205. package/package.json +24 -22
  206. package/dist/attachment-resolver.d.ts +0 -11
  207. package/dist/attachment-resolver.d.ts.map +0 -1
  208. package/dist/attachment-resolver.js +0 -61
  209. package/dist/attachment-resolver.js.map +0 -1
  210. package/dist/settings-display.d.ts +0 -3
  211. package/dist/settings-display.d.ts.map +0 -1
  212. package/dist/settings-display.js +0 -33
  213. package/dist/settings-display.js.map +0 -1
@@ -0,0 +1,57 @@
1
+ import { print, printJson, printUsageError } from "./cli-io.js";
2
+ import { ensureDaemon } from "./daemon-run.js";
3
+ import { controlApiFetch } from "./live.js";
4
+ export async function retryCommand(args, json) {
5
+ const runId = args._[1];
6
+ if (!runId)
7
+ return printUsageError(json, "usage: claudexor retry <run_id>");
8
+ try {
9
+ const { addr } = await ensureDaemon();
10
+ const response = await controlApiFetch(addr, `/runs/${encodeURIComponent(runId)}/retry`, {
11
+ method: "POST",
12
+ headers: { Authorization: `Bearer ${addr.token}`, "content-type": "application/json" },
13
+ body: "{}",
14
+ });
15
+ const data = (await response.json());
16
+ if (!response.ok)
17
+ throw new Error(String(data["error"] ?? `HTTP ${response.status}`));
18
+ if (json)
19
+ printJson(data);
20
+ else
21
+ print(`retry ${runId}: ${String(data["state"])} (${String(data["runId"] ?? data["jobId"])})`);
22
+ return 0;
23
+ }
24
+ catch (error) {
25
+ return printUsageError(json, `claudexor retry: ${error instanceof Error ? error.message : String(error)}`);
26
+ }
27
+ }
28
+ export async function runAgainCommand(args, json) {
29
+ const runId = args._[1];
30
+ if (!runId)
31
+ return printUsageError(json, "usage: claudexor run-again <run_id>");
32
+ try {
33
+ const { addr } = await ensureDaemon();
34
+ const response = await controlApiFetch(addr, `/runs/${encodeURIComponent(runId)}/run-again`, {
35
+ headers: { Authorization: `Bearer ${addr.token}` },
36
+ });
37
+ const data = (await response.json());
38
+ if (!response.ok)
39
+ throw new Error(String(data["error"] ?? `HTTP ${response.status}`));
40
+ if (json)
41
+ printJson(data);
42
+ else {
43
+ print(`editable Run Again draft from ${runId}:`);
44
+ print(JSON.stringify(data["request"] ?? {}, null, 2));
45
+ const differences = Array.isArray(data["differences"]) ? data["differences"] : [];
46
+ for (const difference of differences) {
47
+ const row = difference;
48
+ print(` omitted ${String(row["field"])}: ${String(row["reason"])}`);
49
+ }
50
+ }
51
+ return 0;
52
+ }
53
+ catch (error) {
54
+ return printUsageError(json, `claudexor run-again: ${error instanceof Error ? error.message : String(error)}`);
55
+ }
56
+ }
57
+ //# sourceMappingURL=retry-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry-command.js","sourceRoot":"","sources":["../src/retry-command.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"review-command.d.ts","sourceRoot":"","sources":["../src/review-command.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,UAAU,EAAuB,MAAM,WAAW,CAAC;AAQjE,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAiEpF"}
1
+ {"version":3,"file":"review-command.d.ts","sourceRoot":"","sources":["../src/review-command.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,UAAU,EAAuB,MAAM,WAAW,CAAC;AAQjE,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CA4GpF"}
@@ -1,6 +1,6 @@
1
1
  /**
2
- * `claudexor review --diff <file>`: thin surface over the engine's
3
- * scoped diff review the per-commit gate's PRIMARY route. FAIL CLOSED: an
2
+ * `claudexor review`: thin surface over the engine's scoped review. It accepts
3
+ * either an ad-hoc diff or a SHA-bound sealed packet. FAIL CLOSED: an
4
4
  * inconclusive reviewer panel (unhealthy cross-family state or
5
5
  * INSUFFICIENT_EVIDENCE findings) never reads as a pass.
6
6
  */
@@ -16,15 +16,38 @@ function panelFlags(args) {
16
16
  }
17
17
  export async function reviewCommand(args, json) {
18
18
  const diffPath = flagStr(args, "diff");
19
- if (!diffPath) {
20
- return printUsageError(json, 'usage: claudexor review --diff <file> [--intent "<text>"] [--tests "<evidence>"] [--reviewer-panel <list>] [--json]');
19
+ const evidenceDir = flagStr(args, "evidence-dir");
20
+ const artifactsDir = flagStr(args, "artifacts-dir");
21
+ const candidateSha = flagStr(args, "candidate-sha");
22
+ const candidateTree = flagStr(args, "candidate-tree");
23
+ const packetManifestSha256 = flagStr(args, "packet-manifest-digest");
24
+ const frozenValues = [
25
+ evidenceDir,
26
+ artifactsDir,
27
+ candidateSha,
28
+ candidateTree,
29
+ packetManifestSha256,
30
+ ];
31
+ const frozenRequested = frozenValues.some((value) => value !== undefined);
32
+ const usage = 'usage: claudexor review --diff <file> [--intent "<text>"] [--tests "<evidence>"] [--reviewer-panel <list>] [--json]\n' +
33
+ " or: claudexor review --evidence-dir <path> --artifacts-dir <external-path> --candidate-sha <sha> --candidate-tree <tree> --packet-manifest-digest <sha256> [--reviewer-panel <list>] [--json]";
34
+ if ((!diffPath && !frozenRequested) || (frozenRequested && frozenValues.some((v) => !v))) {
35
+ return printUsageError(json, usage);
21
36
  }
22
- let diffText;
23
- try {
24
- diffText = readFileSync(diffPath, "utf8");
37
+ if (frozenRequested &&
38
+ (diffPath !== undefined ||
39
+ flagStr(args, "intent") !== undefined ||
40
+ flagStr(args, "tests") !== undefined)) {
41
+ return printUsageError(json, "claudexor review: sealed packet mode cannot be combined with --diff, --intent, or --tests");
25
42
  }
26
- catch (err) {
27
- return printUsageError(json, `claudexor review: cannot read --diff '${diffPath}': ${err instanceof Error ? err.message : String(err)}`);
43
+ let diffText;
44
+ if (diffPath) {
45
+ try {
46
+ diffText = readFileSync(diffPath, "utf8");
47
+ }
48
+ catch (err) {
49
+ return printUsageError(json, `claudexor review: cannot read --diff '${diffPath}': ${err instanceof Error ? err.message : String(err)}`);
50
+ }
28
51
  }
29
52
  try {
30
53
  const orch = new Orchestrator({
@@ -33,9 +56,21 @@ export async function reviewCommand(args, json) {
33
56
  });
34
57
  const result = await orch.reviewDiff({
35
58
  repoRoot: process.cwd(),
36
- diff: diffText,
37
- userIntent: flagStr(args, "intent"),
38
- tests: flagStr(args, "tests"),
59
+ ...(frozenRequested
60
+ ? {
61
+ frozen: {
62
+ evidenceDir: evidenceDir,
63
+ artifactsDir: artifactsDir,
64
+ candidateSha: candidateSha,
65
+ candidateTree: candidateTree,
66
+ packetManifestSha256: packetManifestSha256,
67
+ },
68
+ }
69
+ : {
70
+ diff: diffText,
71
+ userIntent: flagStr(args, "intent"),
72
+ tests: flagStr(args, "tests"),
73
+ }),
39
74
  });
40
75
  const blockers = result.findings.filter((f) => isBlocking(f));
41
76
  // FAIL CLOSED: reviewer setup/parse failures surface as
@@ -1 +1 @@
1
- {"version":3,"file":"review-command.js","sourceRoot":"","sources":["../src/review-command.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"review-command.js","sourceRoot":"","sources":["../src/review-command.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
- import type { ControlReviewerPanelEntry, EffortHint, ProtectedPathApproval, ProviderFamily } from "@claudexor/schema";
1
+ import type { ControlReviewerPanelEntry, EffortHint, ProtectedPathApproval, ProviderFamily, TestCommandInvocation } from "@claudexor/schema";
2
2
  export declare function stringFlagValues(values: Array<string | boolean>, flag: string): string[];
3
3
  export declare function parseProtectedPathApprovalFlags(values: Array<string | boolean>): ProtectedPathApproval[] | undefined;
4
- export declare function parseTestCommandFlags(values: Array<string | boolean>): string[] | undefined;
4
+ export declare function parseTestCommandFlags(values: Array<string | boolean>): TestCommandInvocation[] | undefined;
5
5
  export declare function parseReviewerPanelFlags(values: Array<string | boolean>): ControlReviewerPanelEntry[] | undefined;
6
6
  export declare function parseReviewerModelFlags(values: Array<string | boolean>): Partial<Record<ProviderFamily, string>> | undefined;
7
7
  export declare function parseReviewerEffortFlags(values: Array<string | boolean>): Partial<Record<ProviderFamily, EffortHint>> | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"run-options.d.ts","sourceRoot":"","sources":["../src/run-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,UAAU,EACV,qBAAqB,EACrB,cAAc,EACf,MAAM,mBAAmB,CAAC;AAO3B,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAKxF;AAED,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,GAC9B,qBAAqB,EAAE,GAAG,SAAS,CAYrC;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,SAAS,CAY3F;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,GAC9B,yBAAyB,EAAE,GAAG,SAAS,CAGzC;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAGrD;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC,GAAG,SAAS,CAGzD"}
1
+ {"version":3,"file":"run-options.d.ts","sourceRoot":"","sources":["../src/run-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,UAAU,EACV,qBAAqB,EACrB,cAAc,EACd,qBAAqB,EACtB,MAAM,mBAAmB,CAAC;AAO3B,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAKxF;AAED,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,GAC9B,qBAAqB,EAAE,GAAG,SAAS,CAarC;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,GAC9B,qBAAqB,EAAE,GAAG,SAAS,CAqCrC;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,GAC9B,yBAAyB,EAAE,GAAG,SAAS,CAGzC;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAGrD;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC,GAAG,SAAS,CAGzD"}
@@ -26,12 +26,34 @@ export function parseTestCommandFlags(values) {
26
26
  return undefined;
27
27
  const commands = [];
28
28
  for (const value of strings) {
29
- for (const part of value.split(";;")) {
30
- const command = part.trim();
31
- if (!command)
32
- throw new Error("invalid --test value (empty ;;-separated entry)");
33
- commands.push(command);
29
+ const command = value.trim();
30
+ if (!command)
31
+ throw new Error("invalid --test value (empty command)");
32
+ if (command.startsWith("[")) {
33
+ let argv;
34
+ try {
35
+ argv = JSON.parse(command);
36
+ }
37
+ catch {
38
+ throw new Error("invalid --test value (expected a JSON argv array)");
39
+ }
40
+ if (!Array.isArray(argv) ||
41
+ argv.length === 0 ||
42
+ !argv.every((part) => typeof part === "string") ||
43
+ !argv[0].trim()) {
44
+ throw new Error("invalid --test value (expected a non-empty JSON string argv array)");
45
+ }
46
+ commands.push({
47
+ program: argv[0],
48
+ args: argv.slice(1),
49
+ envAllowlist: [],
50
+ });
51
+ continue;
34
52
  }
53
+ if (/\s|[;&|<>$`()]/.test(command)) {
54
+ throw new Error('invalid --test value (implicit shell syntax is forbidden; use JSON argv, e.g. --test \'["pnpm","test"]\')');
55
+ }
56
+ commands.push({ program: command, args: [], envAllowlist: [] });
35
57
  }
36
58
  return commands;
37
59
  }
@@ -1 +1 @@
1
- {"version":3,"file":"run-options.js","sourceRoot":"","sources":["../src/run-options.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run-options.js","sourceRoot":"","sources":["../src/run-options.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,UAAU,gBAAgB,CAAC,MAA+B,EAAE,IAAY;IAC5E,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC;IACrF,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM;QAClC,MAAM,IAAI,KAAK,CAAC,aAAa,IAAI,2BAA2B,CAAC,CAAC;IAChE,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,+BAA+B,CAC7C,MAA+B;IAE/B,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;IACjE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI;gBACP,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;YACxF,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,qCAAqC,EAAE,CAAC,CAAC,CAAC;AACxF,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,MAA+B;IAE/B,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3C,MAAM,QAAQ,GAA4B,EAAE,CAAC;IAC7C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QACtE,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,IAAI,IAAa,CAAC;YAClB,IAAI,CAAC;gBACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC7B,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;YACvE,CAAC;YACD,IACE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;gBACpB,IAAI,CAAC,MAAM,KAAK,CAAC;gBACjB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC;gBAC/C,CAAE,IAAI,CAAC,CAAC,CAAY,CAAC,IAAI,EAAE,EAC3B,CAAC;gBACD,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;YACxF,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC;gBACZ,OAAO,EAAE,IAAI,CAAC,CAAC,CAAW;gBAC1B,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAa;gBAC/B,YAAY,EAAE,EAAE;aACjB,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CACb,2GAA2G,CAC5G,CAAC;QACJ,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,MAA+B;IAE/B,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC3D,OAAO,kBAAkB,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAChF,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,MAA+B;IAE/B,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC3D,OAAO,qBAAqB,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,MAA+B;IAE/B,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAC5D,OAAO,sBAAsB,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AACpF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"settings-command.d.ts","sourceRoot":"","sources":["../src/settings-command.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AA8B5C,wBAAsB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAoLtF"}
1
+ {"version":3,"file":"settings-command.d.ts","sourceRoot":"","sources":["../src/settings-command.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAQ5C,wBAAsB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBtF"}
@@ -1,202 +1,157 @@
1
- /**
2
- * `claudexor settings show|set` user defaults over the layered config, with
3
- * the same strict validation the daemon settings endpoint applies: model
4
- * values pass the harness truth source, effort passes the declared ladder,
5
- * and routing ids must be REAL harnesses (fakes never persist).
6
- */
7
- import { loadConfig, updateGlobalConfig } from "@claudexor/config";
8
- import { validateModel } from "@claudexor/core";
9
- import { ControlSettingsSnapshot, EffortHint, GlobalConfig, Portfolio, } from "@claudexor/schema";
1
+ /** `claudexor settings` is a thin projection of the daemon-owned /v2/settings surface. */
2
+ import { ControlSettingsSnapshot, ControlSettingsUpdateRequest, } from "@claudexor/schema";
10
3
  import { print, printJson, printUsageError } from "./cli-io.js";
11
- import { connectDaemonIfRunning } from "./daemon-run.js";
12
- import { buildRegistry, harnessModels } from "./registry.js";
13
- import { daemonRuntimeDiffLines } from "./settings-display.js";
14
- /**
15
- * A REAL harness id (fakes excluded), for `settings set` validation. A persistent
16
- * routing default is not an explicit per-run selection, so a `fake-*` fixture must
17
- * never be accepted as primary/eligible (it could route ordinary runs to a fake).
18
- */
19
- function isKnownHarness(id) {
20
- return buildRegistry({ includeFakes: false }).has(id);
4
+ import { ensureDaemon } from "./daemon-run.js";
5
+ import { controlApiFetch } from "./live.js";
6
+ const USAGE = "usage: claudexor settings set routing_goal|paid_fallback|quality_tiers|primary_harness|eligible_harnesses|harness.<id>.default_model|harness.<id>.fallback_model|harness.<id>.effort|env_inheritance|routing_policy|paid_budget_per_run|interaction_timeout_ms <value>";
7
+ export async function settingsCommand(args, json) {
8
+ const sub = args._[1] ?? "show";
9
+ if (sub !== "show" && sub !== "set")
10
+ return printUsageError(json, "usage: claudexor settings show|set");
11
+ try {
12
+ const { addr } = await ensureDaemon();
13
+ if (sub === "show") {
14
+ const snapshot = await settingsRequest(addr, "GET");
15
+ if (json)
16
+ printJson(snapshot);
17
+ else
18
+ printSettings(snapshot);
19
+ return 0;
20
+ }
21
+ const key = args._[2];
22
+ const value = args._[3];
23
+ if (!key || value === undefined)
24
+ return printUsageError(json, USAGE);
25
+ const snapshot = await settingsRequest(addr, "POST", settingPatch(key, value));
26
+ if (json)
27
+ printJson(snapshot);
28
+ else
29
+ print(`updated ${key}`);
30
+ return 0;
31
+ }
32
+ catch (error) {
33
+ const message = `claudexor settings: ${error instanceof Error ? error.message : String(error)}`;
34
+ if (json)
35
+ printJson({ ok: false, exitCode: 1, error: message });
36
+ else
37
+ process.stderr.write(`${message}\n`);
38
+ return 1;
39
+ }
21
40
  }
22
- async function daemonSettingsSnapshotIfRunning() {
23
- const conn = await connectDaemonIfRunning();
24
- if (!conn)
25
- return null;
41
+ async function settingsRequest(addr, method, body) {
42
+ const response = await controlApiFetch(addr, "/settings", {
43
+ method,
44
+ headers: {
45
+ Authorization: `Bearer ${addr.token}`,
46
+ ...(body ? { "content-type": "application/json" } : {}),
47
+ },
48
+ ...(body ? { body: JSON.stringify(body) } : {}),
49
+ });
50
+ const text = await response.text();
51
+ let value = {};
26
52
  try {
27
- const res = await fetch(`${conn.addr.baseUrl}/settings`, {
28
- headers: { Authorization: `Bearer ${conn.addr.token}` },
29
- signal: AbortSignal.timeout(1500),
30
- });
31
- if (!res.ok)
32
- return null;
33
- return ControlSettingsSnapshot.parse(await res.json());
53
+ value = text ? JSON.parse(text) : {};
34
54
  }
35
55
  catch {
36
- return null;
56
+ throw new Error(`settings endpoint returned invalid JSON (HTTP ${response.status})`);
37
57
  }
58
+ if (!response.ok) {
59
+ const detail = value;
60
+ throw new Error(typeof detail["message"] === "string"
61
+ ? detail["message"]
62
+ : typeof detail["error"] === "string"
63
+ ? detail["error"]
64
+ : `settings request failed (HTTP ${response.status})`);
65
+ }
66
+ return ControlSettingsSnapshot.parse(value);
38
67
  }
39
- export async function settingsCommand(args, json) {
40
- const sub = args._[1] ?? "show";
41
- if (sub === "show") {
42
- const cfg = loadConfig(process.cwd());
43
- if (json)
44
- printJson(cfg);
45
- else {
46
- print(`sources: ${cfg.sources.length ? cfg.sources.join(", ") : "(defaults)"}`);
47
- print(`default_portfolio: ${cfg.global.default_portfolio}`);
48
- print(`routing.default_policy: ${cfg.global.routing.default_policy}`);
49
- print(`routing.primary_harness: ${cfg.global.routing.primary_harness ?? "(none)"}`);
50
- print(`routing.eligible_harnesses: ${cfg.global.routing.eligible_harnesses.length ? cfg.global.routing.eligible_harnesses.join(", ") : "(auto)"}`);
51
- print(`routing.env_inheritance: ${cfg.global.routing.env_inheritance}`);
52
- print(`budget.max_usd_per_run: ${cfg.global.budget.max_usd_per_run ?? "(none)"}`);
53
- print(`interaction_timeout_ms: ${cfg.global.interaction_timeout_ms}`);
54
- print(`runtime.reviewer_timeout_ms: ${cfg.global.runtime.reviewer_timeout_ms}`);
55
- print(`runtime.transient_retry.max_retries: ${cfg.global.runtime.transient_retry.max_retries}`);
56
- print(`runtime.transient_retry.initial_delay_ms: ${cfg.global.runtime.transient_retry.initial_delay_ms}`);
57
- print(`runtime.transient_retry.max_delay_ms: ${cfg.global.runtime.transient_retry.max_delay_ms}`);
58
- const harnessIds = Object.keys(cfg.global.harnesses);
59
- if (harnessIds.length) {
60
- print("harnesses:");
61
- for (const id of harnessIds) {
62
- const h = cfg.global.harnesses[id];
63
- print(` ${id}: enabled=${h.enabled} model=${h.default_model ?? "(native)"} effort=${h.effort ?? "(native)"} web=${h.web} max_turns=${h.max_turns ?? "(none)"} max_usd=${h.max_usd ?? "(none)"}`);
64
- }
65
- }
66
- const daemonSettings = await daemonSettingsSnapshotIfRunning();
67
- if (daemonSettings) {
68
- const diffLines = daemonRuntimeDiffLines(cfg, daemonSettings);
69
- for (const line of diffLines)
70
- print(line);
71
- }
72
- }
73
- return 0;
68
+ function settingPatch(key, value) {
69
+ if (key === "default_model") {
70
+ throw new Error("the global default_model setting was removed (model choice is harness-scoped, INV-103); use `claudexor settings set harness.<id>.default_model <model>`");
74
71
  }
75
- if (sub === "set") {
76
- const key = args._[2];
77
- const value = args._[3];
78
- if (!key || value === undefined) {
79
- return printUsageError(json, "usage: claudexor settings set default_portfolio|primary_harness|eligible_harnesses|harness.<id>.default_model|harness.<id>.fallback_model|harness.<id>.effort|env_inheritance|routing_policy|budget_max_usd_per_run|interaction_timeout_ms <value>");
80
- }
72
+ const harness = /^harness\.([^.]+)\.(default_model|fallback_model|effort)$/.exec(key);
73
+ if (harness) {
74
+ const id = harness[1];
75
+ const field = harness[2];
76
+ const cleared = value === "none";
77
+ return ControlSettingsUpdateRequest.parse({
78
+ harnesses: {
79
+ [id]: field === "default_model"
80
+ ? { defaultModel: cleared ? null : value }
81
+ : field === "fallback_model"
82
+ ? { fallbackModel: cleared ? null : value }
83
+ : { effort: cleared ? null : value },
84
+ },
85
+ });
86
+ }
87
+ if (key === "default_portfolio") {
88
+ throw new Error("default_portfolio was removed in v2; use routing_goal");
89
+ }
90
+ if (key === "routing_goal")
91
+ return ControlSettingsUpdateRequest.parse({ routingGoal: value });
92
+ if (key === "paid_fallback")
93
+ return ControlSettingsUpdateRequest.parse({ paidFallback: value });
94
+ if (key === "quality_tiers") {
95
+ let qualityTiers;
81
96
  try {
82
- // Harness-scoped model/effort keys (INV-103: model choice is
83
- // harness-scoped — there is no global model setting). Values are
84
- // validated against the harness's truth source BEFORE persisting, the
85
- // same strict gate the daemon settings endpoint applies.
86
- const harnessKey = /^harness\.([^.]+)\.(default_model|fallback_model|effort)$/.exec(key);
87
- if (harnessKey) {
88
- const [, harnessId, field] = harnessKey;
89
- if (!isKnownHarness(harnessId))
90
- throw new Error(`unknown harness '${harnessId}' (run \`claudexor harness list --all\`)`);
91
- const cleared = value === "none";
92
- if (!cleared && (field === "default_model" || field === "fallback_model")) {
93
- const truth = await harnessModels(harnessId, process.cwd(), true);
94
- const check = validateModel(value, truth.models.map((m) => m.id), truth.source === "api" ? "api" : "manifest");
95
- if (check.status !== "ok") {
96
- throw new Error(`harness '${harnessId}' refused ${field} '${value}' (truth source: ${truth.source}): ${check.message}`);
97
- }
98
- }
99
- let effortValue = null;
100
- if (!cleared && field === "effort") {
101
- effortValue = EffortHint.parse(value);
102
- const adapter = buildRegistry({ includeFakes: true }).get(harnessId);
103
- const ladder = adapter ? (await adapter.discover()).capabilities.effort_levels : [];
104
- if (!ladder.includes(effortValue)) {
105
- throw new Error(ladder.length === 0
106
- ? `harness '${harnessId}' declares no effort ladder; leave effort unset`
107
- : `harness '${harnessId}' does not accept effort '${value}' (declared ladder: ${ladder.join(", ")})`);
108
- }
109
- }
110
- const res = updateGlobalConfig((cfg) => {
111
- const base = cfg.harnesses[harnessId] ??
112
- GlobalConfig.shape.harnesses.removeDefault().valueSchema.parse({});
113
- return {
114
- ...cfg,
115
- harnesses: {
116
- ...cfg.harnesses,
117
- [harnessId]: {
118
- ...base,
119
- ...(field === "default_model" ? { default_model: cleared ? null : value } : {}),
120
- ...(field === "fallback_model" ? { fallback_model: cleared ? null : value } : {}),
121
- ...(field === "effort" ? { effort: cleared ? null : effortValue } : {}),
122
- },
123
- },
124
- };
125
- });
126
- if (json)
127
- printJson(res);
128
- else
129
- print(`updated ${key} in ${res.path}`);
130
- return 0;
131
- }
132
- const res = updateGlobalConfig((cfg) => {
133
- if (key === "default_portfolio") {
134
- const p = Portfolio.parse(value);
135
- return { ...cfg, default_portfolio: p };
136
- }
137
- if (key === "primary_harness") {
138
- if (value !== "none" && !isKnownHarness(value))
139
- throw new Error(`unknown harness '${value}' (run \`claudexor harness list --all\`)`);
140
- return {
141
- ...cfg,
142
- routing: { ...cfg.routing, primary_harness: value === "none" ? null : value },
143
- };
144
- }
145
- if (key === "eligible_harnesses") {
146
- const list = value === "none"
147
- ? []
148
- : value
149
- .split(",")
150
- .map((s) => s.trim())
151
- .filter(Boolean);
152
- const unknown = list.filter((h) => !isKnownHarness(h));
153
- if (unknown.length)
154
- throw new Error(`unknown harness(es): ${unknown.join(", ")} (run \`claudexor harness list --all\`)`);
155
- return { ...cfg, routing: { ...cfg.routing, eligible_harnesses: list } };
156
- }
157
- if (key === "default_model") {
158
- throw new Error("the global default_model setting was removed (model choice is harness-scoped, INV-103); use `claudexor settings set harness.<id>.default_model <model>`");
159
- }
160
- if (key === "env_inheritance") {
161
- if (!["mirror_native", "clean"].includes(value))
162
- throw new Error("env_inheritance must be mirror_native|clean");
163
- return { ...cfg, routing: { ...cfg.routing, env_inheritance: value } };
164
- }
165
- if (key === "routing_policy") {
166
- if (!["auto", "primary"].includes(value))
167
- throw new Error("routing_policy must be auto|primary");
168
- return { ...cfg, routing: { ...cfg.routing, default_policy: value } };
169
- }
170
- if (key === "budget_max_usd_per_run") {
171
- // Number() parses the WHOLE string ('1abc' -> NaN), unlike parseFloat.
172
- const parsed = value === "none" ? null : Number(value.trim());
173
- if (parsed !== null && (!Number.isFinite(parsed) || parsed < 0 || value.trim() === ""))
174
- throw new Error(`${key} must be a non-negative number or none`);
175
- return { ...cfg, budget: { ...cfg.budget, max_usd_per_run: parsed } };
176
- }
177
- if (key === "interaction_timeout_ms") {
178
- const parsed = Number(value.trim());
179
- if (!Number.isInteger(parsed) || parsed <= 0)
180
- throw new Error("interaction_timeout_ms must be a positive integer (milliseconds)");
181
- return { ...cfg, interaction_timeout_ms: parsed };
182
- }
183
- throw new Error(`unknown setting: ${key}`);
184
- });
185
- if (json)
186
- printJson(res);
187
- else
188
- print(`updated ${key} in ${res.path}`);
189
- return 0;
97
+ qualityTiers = JSON.parse(value);
190
98
  }
191
- catch (err) {
192
- const message = `claudexor settings: ${err instanceof Error ? err.message : String(err)}`;
193
- if (json)
194
- printJson({ ok: false, exitCode: 1, error: message });
195
- else
196
- process.stderr.write(`${message}\n`);
197
- return 1;
99
+ catch {
100
+ throw new Error("quality_tiers must be a JSON object of per-intent ordered tiers");
198
101
  }
102
+ return ControlSettingsUpdateRequest.parse({ qualityTiers });
103
+ }
104
+ if (key === "primary_harness")
105
+ return ControlSettingsUpdateRequest.parse({ primaryHarness: value === "none" ? null : value });
106
+ if (key === "eligible_harnesses") {
107
+ const eligibleHarnesses = value === "none"
108
+ ? []
109
+ : value
110
+ .split(",")
111
+ .map((item) => item.trim())
112
+ .filter(Boolean);
113
+ return ControlSettingsUpdateRequest.parse({ eligibleHarnesses });
114
+ }
115
+ if (key === "env_inheritance")
116
+ return ControlSettingsUpdateRequest.parse({ envInheritance: value });
117
+ if (key === "routing_policy")
118
+ return ControlSettingsUpdateRequest.parse({ routingPolicy: value });
119
+ if (key === "paid_budget_per_run") {
120
+ if (value === "unlimited")
121
+ return ControlSettingsUpdateRequest.parse({ paidBudgetPerRun: { kind: "unlimited" } });
122
+ const maxUsd = Number(value.trim());
123
+ if (!Number.isFinite(maxUsd) || maxUsd < 0 || value.trim() === "")
124
+ throw new Error(`${key} must be a non-negative number or unlimited`);
125
+ return ControlSettingsUpdateRequest.parse({
126
+ paidBudgetPerRun: { kind: "finite", maxUsd },
127
+ });
128
+ }
129
+ if (key === "interaction_timeout_ms") {
130
+ const interactionTimeoutMs = Number(value.trim());
131
+ return ControlSettingsUpdateRequest.parse({ interactionTimeoutMs });
132
+ }
133
+ throw new Error(`unknown setting: ${key}`);
134
+ }
135
+ function printSettings(settings) {
136
+ print(`sources: ${settings.sources.length ? settings.sources.join(", ") : "(defaults)"}`);
137
+ print(`routing.goal: ${settings.routing.goal}`);
138
+ print(`routing.paid_fallback: ${settings.routing.paidFallback}`);
139
+ print(`routing.default_policy: ${settings.routing.defaultPolicy}`);
140
+ print(`routing.primary_harness: ${settings.routing.primaryHarness ?? "(none)"}`);
141
+ print(`routing.eligible_harnesses: ${settings.routing.eligibleHarnesses.length ? settings.routing.eligibleHarnesses.join(", ") : "(auto)"}`);
142
+ print(`routing.env_inheritance: ${settings.routing.envInheritance}`);
143
+ print(`budget.paid_budget_per_run: ${settings.budget.paidBudgetPerRun.kind === "unlimited" ? "unlimited" : settings.budget.paidBudgetPerRun.maxUsd}`);
144
+ print(`interaction_timeout_ms: ${settings.interactionTimeoutMs}`);
145
+ print(`runtime.reviewer_timeout_ms: ${settings.runtime.reviewerTimeoutMs}`);
146
+ print(`runtime.transient_retry.max_retries: ${settings.runtime.transientRetry.maxRetries}`);
147
+ print(`runtime.transient_retry.initial_delay_ms: ${settings.runtime.transientRetry.initialDelayMs}`);
148
+ print(`runtime.transient_retry.max_delay_ms: ${settings.runtime.transientRetry.maxDelayMs}`);
149
+ const harnesses = Object.entries(settings.harnesses);
150
+ if (harnesses.length === 0)
151
+ return;
152
+ print("harnesses:");
153
+ for (const [id, harness] of harnesses) {
154
+ print(` ${id}: enabled=${harness.enabled} model=${harness.defaultModel ?? "(native)"} effort=${harness.effort ?? "(native)"} web=${harness.web} max_turns=${harness.maxTurns ?? "(none)"}`);
199
155
  }
200
- return printUsageError(json, "usage: claudexor settings show|set");
201
156
  }
202
157
  //# sourceMappingURL=settings-command.js.map