@iowarp/clio-coder 0.3.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 (226) hide show
  1. package/CHANGELOG.md +407 -0
  2. package/CODE_OF_CONDUCT.md +21 -0
  3. package/CONTRIBUTING.md +224 -0
  4. package/LICENSE +202 -0
  5. package/NOTICE +9 -0
  6. package/README.md +798 -0
  7. package/SECURITY.md +72 -0
  8. package/assets/clio-coder-logo-128.webp +0 -0
  9. package/damage-control-rules.yaml +419 -0
  10. package/dist/acp-UMLFVA3F.js +92 -0
  11. package/dist/agents-Q4MYPMUW.js +91 -0
  12. package/dist/auth-O6HYIJ6J.js +521 -0
  13. package/dist/chunk-262G75JS.js +35 -0
  14. package/dist/chunk-26BZQOAD.js +1281 -0
  15. package/dist/chunk-2J63S4SF.js +508 -0
  16. package/dist/chunk-3DANZDGR.js +717 -0
  17. package/dist/chunk-4UQA7NCT.js +29 -0
  18. package/dist/chunk-527KG6XR.js +497 -0
  19. package/dist/chunk-5LDRNKX2.js +1063 -0
  20. package/dist/chunk-5N2FG33Q.js +25 -0
  21. package/dist/chunk-67MTHP2E.js +135 -0
  22. package/dist/chunk-6CWDTGUC.js +20 -0
  23. package/dist/chunk-7BHLZB3A.js +2115 -0
  24. package/dist/chunk-7RBKDI66.js +348 -0
  25. package/dist/chunk-AMFR5YA3.js +541 -0
  26. package/dist/chunk-BBUH4VAA.js +1224 -0
  27. package/dist/chunk-BYEU76JP.js +899 -0
  28. package/dist/chunk-CLJ5HLUD.js +458 -0
  29. package/dist/chunk-D5YD55AR.js +116 -0
  30. package/dist/chunk-DXQNI4PC.js +61 -0
  31. package/dist/chunk-E3NYWENM.js +1004 -0
  32. package/dist/chunk-GNGDQYDU.js +34688 -0
  33. package/dist/chunk-GOTUR54M.js +9 -0
  34. package/dist/chunk-HBU5MTAM.js +41 -0
  35. package/dist/chunk-HMYNFFY4.js +28 -0
  36. package/dist/chunk-JPOWPFCU.js +1010 -0
  37. package/dist/chunk-JWHCJDCI.js +1215 -0
  38. package/dist/chunk-KBR4MZZR.js +41 -0
  39. package/dist/chunk-KKKPTZLM.js +93 -0
  40. package/dist/chunk-ME6DNWIU.js +66 -0
  41. package/dist/chunk-NI4DEJMC.js +88 -0
  42. package/dist/chunk-O4EJEDHO.js +659 -0
  43. package/dist/chunk-PIDUD6M2.js +31 -0
  44. package/dist/chunk-PS4PFJQP.js +29459 -0
  45. package/dist/chunk-QV47YRF4.js +48 -0
  46. package/dist/chunk-RQDWMVRB.js +279 -0
  47. package/dist/chunk-TFSSEXL6.js +136 -0
  48. package/dist/chunk-TKHQ4DGZ.js +8290 -0
  49. package/dist/chunk-TPOCL34A.js +2876 -0
  50. package/dist/chunk-UGYAX5YI.js +565 -0
  51. package/dist/chunk-UHTSULZS.js +461 -0
  52. package/dist/chunk-UU3R62TT.js +128 -0
  53. package/dist/chunk-UWIJNAOB.js +3906 -0
  54. package/dist/chunk-VOO7NYPP.js +914 -0
  55. package/dist/chunk-VPAWTYLY.js +117 -0
  56. package/dist/chunk-WD6AJM35.js +1216 -0
  57. package/dist/chunk-X3BR7HWV.js +115 -0
  58. package/dist/chunk-X3NE4WVW.js +120 -0
  59. package/dist/chunk-XNISANGE.js +1395 -0
  60. package/dist/chunk-XV4ZJ6ZM.js +3177 -0
  61. package/dist/cli/index.js +236 -0
  62. package/dist/clio-KIQ5SNDS.js +53 -0
  63. package/dist/components-JVHMUBEB.js +653 -0
  64. package/dist/config-ZFCDBMDC.js +372 -0
  65. package/dist/configure-G4E3A2PG.js +27 -0
  66. package/dist/context-CDXTP2MP.js +293 -0
  67. package/dist/context-E3KIFVXI.js +185 -0
  68. package/dist/context-clear-3F4PLXOS.js +102 -0
  69. package/dist/context-index-Q7YSYTR3.js +106 -0
  70. package/dist/docs-YIETIWZI.js +280 -0
  71. package/dist/doctor-M5HJJZOL.js +61 -0
  72. package/dist/domains/agents/builtins/architect.md +33 -0
  73. package/dist/domains/agents/builtins/coder.md +31 -0
  74. package/dist/domains/agents/builtins/context-bootstrap.md +38 -0
  75. package/dist/domains/agents/builtins/debugger.md +30 -0
  76. package/dist/domains/agents/builtins/documenter.md +31 -0
  77. package/dist/domains/agents/builtins/git-master.md +30 -0
  78. package/dist/domains/agents/builtins/provenance.md +30 -0
  79. package/dist/domains/agents/builtins/researcher.md +71 -0
  80. package/dist/domains/agents/builtins/scout.md +42 -0
  81. package/dist/domains/agents/builtins/tester.md +31 -0
  82. package/dist/domains/agents/builtins/verifier.md +30 -0
  83. package/dist/domains/agents/builtins/wiki-writer.md +41 -0
  84. package/dist/eval-B3KZZESM.js +2674 -0
  85. package/dist/evidence-V67CHM35.js +233 -0
  86. package/dist/evolve-YDZSUQYA.js +518 -0
  87. package/dist/extensions-SRG7XCAH.js +207 -0
  88. package/dist/fleet-CA2CRTVG.js +760 -0
  89. package/dist/fleet-preflight-CLIAX7YR.js +21 -0
  90. package/dist/init-2OZDJE2D.js +227 -0
  91. package/dist/memory-3PIQQAKX.js +207 -0
  92. package/dist/models-DY35XI7Y.js +237 -0
  93. package/dist/paths-5OMXW7Z4.js +57 -0
  94. package/dist/preload-KZVHET2B.js +11 -0
  95. package/dist/reset-PIFYNOS3.js +216 -0
  96. package/dist/run-3VSPP24F.js +735 -0
  97. package/dist/share-D36RQCXM.js +241 -0
  98. package/dist/skills-F2MRLELY.js +445 -0
  99. package/dist/skills-eval-E2ZTW4PL.js +932 -0
  100. package/dist/targets-DZMEZAH4.js +977 -0
  101. package/dist/trace-7NYCUI2J.js +250 -0
  102. package/dist/uninstall-AD3JWHBB.js +322 -0
  103. package/dist/upgrade-WYYBKGDY.js +301 -0
  104. package/dist/usage-ULIDAGFF.js +755 -0
  105. package/dist/version-ROZ6CZKH.js +16 -0
  106. package/dist/wiki-generate-PKFIX6OB.js +377 -0
  107. package/dist/worker/entry.js +1739 -0
  108. package/docs/README.md +93 -0
  109. package/docs/acp.md +120 -0
  110. package/docs/alcf-provider.md +72 -0
  111. package/docs/architecture.md +172 -0
  112. package/docs/artifact-versions.md +54 -0
  113. package/docs/built-in-agents.md +265 -0
  114. package/docs/capacity-and-scheduling.md +97 -0
  115. package/docs/commands-and-modes.md +554 -0
  116. package/docs/config-knobs-audit.md +115 -0
  117. package/docs/configuration-and-targets.md +812 -0
  118. package/docs/context-engine.md +236 -0
  119. package/docs/dispatch-architecture-rationale.md +126 -0
  120. package/docs/documentation-coverage.md +46 -0
  121. package/docs/documentation-guide.md +166 -0
  122. package/docs/environment-variables.md +105 -0
  123. package/docs/eval-runner.md +205 -0
  124. package/docs/evals-internal.md +298 -0
  125. package/docs/evidence-and-memory.md +243 -0
  126. package/docs/evolution.md +143 -0
  127. package/docs/exit-codes-and-output.md +74 -0
  128. package/docs/extensions-and-sharing.md +306 -0
  129. package/docs/fleet-demo-runbook.md +179 -0
  130. package/docs/fleet-dispatch.md +591 -0
  131. package/docs/glossary.md +75 -0
  132. package/docs/html/agents_blueprint.html +936 -0
  133. package/docs/html/alcf_blueprint.html +324 -0
  134. package/docs/html/architecture_blueprint.html +850 -0
  135. package/docs/html/commands_blueprint.html +794 -0
  136. package/docs/html/config_knobs_audit_blueprint.html +178 -0
  137. package/docs/html/configuration_blueprint.html +1080 -0
  138. package/docs/html/context_blueprint.html +603 -0
  139. package/docs/html/documentation_blueprint.html +832 -0
  140. package/docs/html/environment_blueprint.html +404 -0
  141. package/docs/html/eval_blueprint.html +743 -0
  142. package/docs/html/evals_internal_blueprint.html +190 -0
  143. package/docs/html/evolution_blueprint.html +674 -0
  144. package/docs/html/extensions_blueprint.html +2065 -0
  145. package/docs/html/fleet_dispatch_blueprint.html +286 -0
  146. package/docs/html/index.html +919 -0
  147. package/docs/html/lifecycle_blueprint.html +723 -0
  148. package/docs/html/memory_blueprint.html +699 -0
  149. package/docs/html/middleware_blueprint.html +664 -0
  150. package/docs/html/models_blueprint.html +2366 -0
  151. package/docs/html/observability_blueprint.html +683 -0
  152. package/docs/html/provider_adapter_blueprint.html +245 -0
  153. package/docs/html/safety_blueprint.html +1386 -0
  154. package/docs/html/shared.css +571 -0
  155. package/docs/html/shared.js +143 -0
  156. package/docs/html/skills_blueprint.html +671 -0
  157. package/docs/html/soak_blueprint.html +182 -0
  158. package/docs/html/tool_usage_blueprint.html +350 -0
  159. package/docs/html/tools_blueprint.html +2249 -0
  160. package/docs/html/trace_blueprint.html +235 -0
  161. package/docs/html/tui_design_blueprint.html +314 -0
  162. package/docs/html/validation_blueprint.html +961 -0
  163. package/docs/html/worker_dispatch_blueprint.html +231 -0
  164. package/docs/installation-and-lifecycle.md +308 -0
  165. package/docs/middleware-and-components.md +148 -0
  166. package/docs/model-catalog.md +189 -0
  167. package/docs/observability.md +233 -0
  168. package/docs/proactive-memory.md +452 -0
  169. package/docs/prompt-envelope-and-tools.md +142 -0
  170. package/docs/provider-adapter-cookbook.md +148 -0
  171. package/docs/release-cut-checklist.md +138 -0
  172. package/docs/safety-model.md +357 -0
  173. package/docs/scientific-validation.md +105 -0
  174. package/docs/session-lifecycle.md +156 -0
  175. package/docs/skills-marketplace.md +46 -0
  176. package/docs/tool-usage.md +527 -0
  177. package/docs/trace-store.md +132 -0
  178. package/docs/troubleshooting.md +33 -0
  179. package/docs/tui-design.md +239 -0
  180. package/docs/worker-dispatch-mechanics.md +242 -0
  181. package/package.json +132 -0
  182. package/skills/README.md +408 -0
  183. package/skills/git/commit-crafting/SKILL.md +79 -0
  184. package/skills/git/commit-crafting/evals.md +92 -0
  185. package/skills/git/create-pr/SKILL.md +116 -0
  186. package/skills/git/create-pr/evals.md +114 -0
  187. package/skills/git/investigate-issue/SKILL.md +139 -0
  188. package/skills/git/investigate-issue/evals.md +94 -0
  189. package/skills/git/resolve-merge-conflicts/SKILL.md +96 -0
  190. package/skills/git/resolve-merge-conflicts/evals.md +58 -0
  191. package/skills/git/review-changes/SKILL.md +103 -0
  192. package/skills/git/review-changes/evals.md +85 -0
  193. package/skills/git/worktree-create/SKILL.md +92 -0
  194. package/skills/git/worktree-create/evals.md +97 -0
  195. package/skills/git/worktree-create/references/worktree-setup.md +66 -0
  196. package/skills/git/worktree-merge/SKILL.md +95 -0
  197. package/skills/git/worktree-merge/evals.md +114 -0
  198. package/skills/skill-marketplace.json +261 -0
  199. package/skills/workflow/cut-it/SKILL.md +86 -0
  200. package/skills/workflow/cut-it/evals.md +42 -0
  201. package/src/domains/agents/builtins/architect.md +33 -0
  202. package/src/domains/agents/builtins/coder.md +31 -0
  203. package/src/domains/agents/builtins/context-bootstrap.md +38 -0
  204. package/src/domains/agents/builtins/debugger.md +30 -0
  205. package/src/domains/agents/builtins/documenter.md +31 -0
  206. package/src/domains/agents/builtins/git-master.md +30 -0
  207. package/src/domains/agents/builtins/provenance.md +30 -0
  208. package/src/domains/agents/builtins/researcher.md +71 -0
  209. package/src/domains/agents/builtins/scout.md +42 -0
  210. package/src/domains/agents/builtins/tester.md +31 -0
  211. package/src/domains/agents/builtins/verifier.md +30 -0
  212. package/src/domains/agents/builtins/wiki-writer.md +41 -0
  213. package/src/domains/agents/fleets/build-review.md +34 -0
  214. package/src/domains/agents/fleets/build-test.md +35 -0
  215. package/src/domains/agents/fleets/sdlc.md +86 -0
  216. package/src/domains/prompts/fragments/identity/clio-worker.md +11 -0
  217. package/src/domains/prompts/fragments/identity/clio.md +26 -0
  218. package/src/domains/prompts/fragments/operating/contract.md +64 -0
  219. package/src/domains/prompts/fragments/safety/auto-edit.md +14 -0
  220. package/src/domains/prompts/fragments/safety/full-auto.md +14 -0
  221. package/src/domains/prompts/fragments/safety/read-only.md +13 -0
  222. package/src/domains/prompts/fragments/safety/suggest.md +13 -0
  223. package/src/domains/prompts/fragments/wiki/page.md +75 -0
  224. package/src/domains/prompts/fragments/wiki/plan.md +48 -0
  225. package/src/domains/providers/models/cloud-models/alcf.yaml +40 -0
  226. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +993 -0
@@ -0,0 +1,1215 @@
1
+ import {
2
+ ACTIVE_AGENT_AUTOMATION_ROLES,
3
+ ACTIVE_ROUTING_POSTURES,
4
+ ACTIVE_ROUTING_ROLES,
5
+ DEFAULT_SETTINGS,
6
+ THINKING_LEVELS
7
+ } from "./chunk-UHTSULZS.js";
8
+ import {
9
+ safeResourceWrite
10
+ } from "./chunk-VPAWTYLY.js";
11
+ import {
12
+ clioConfigDir,
13
+ resolveClioDirs
14
+ } from "./chunk-X3NE4WVW.js";
15
+
16
+ // src/core/config.ts
17
+ import { existsSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
18
+ import { join } from "node:path";
19
+ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
20
+
21
+ // src/core/timers.ts
22
+ var MAX_TIMER_DELAY_MS = 2147483647;
23
+ function clampTimerDelayMs(value) {
24
+ if (Number.isNaN(value) || value <= 0) return 0;
25
+ return value >= MAX_TIMER_DELAY_MS ? MAX_TIMER_DELAY_MS : Math.floor(value);
26
+ }
27
+ function sleep(ms) {
28
+ return new Promise((resolve) => setTimeout(resolve, ms));
29
+ }
30
+
31
+ // src/core/config.ts
32
+ function settingsPath() {
33
+ return join(clioConfigDir(), "settings.yaml");
34
+ }
35
+ function issuesKind(issues) {
36
+ return issues[0]?.kind ?? "schema";
37
+ }
38
+ function settingsRemedy(kind, path) {
39
+ if (kind === "unreadable") return `Restore read access to ${path}, then run \`clio-coder doctor\` to re-check.`;
40
+ if (kind === "syntax") return `Fix the YAML in ${path}, then run \`clio-coder doctor\` to re-check.`;
41
+ return `Fix the keys above in ${path}, then run \`clio-coder doctor\` to re-check.`;
42
+ }
43
+ function settingsRemedyInline(kind, path) {
44
+ if (kind === "unreadable") return `restore read access to ${path}`;
45
+ if (kind === "syntax") return `fix the YAML in ${path}`;
46
+ return `edit the named keys in ${path}`;
47
+ }
48
+ var SettingsValidationError = class extends Error {
49
+ issues;
50
+ /**
51
+ * The headline and the remedy both follow the failure kind. A file that
52
+ * cannot be read has no key at fault, so telling its reader to "fix the keys
53
+ * above" named a repair that does not exist for the problem they have.
54
+ */
55
+ constructor(issues) {
56
+ const path = join(resolveClioDirs().config, "settings.yaml");
57
+ const kind = issuesKind(issues);
58
+ const lines = kind === "schema" ? issues.map((issue) => ` ${issue.path}: ${issue.message}`) : issues.map((issue) => ` ${issue.message}`);
59
+ const headline = kind === "schema" ? "settings.yaml failed validation:" : "settings.yaml cannot be loaded:";
60
+ super(
61
+ `${headline}
62
+ ${lines.join("\n")}
63
+
64
+ ${settingsRemedy(kind, path)}
65
+ \`clio-coder doctor --fix\` repairs directories and credential permissions; it never rewrites settings.
66
+ To discard these settings and start from defaults instead, run \`clio-coder reset --config --force\`.`
67
+ );
68
+ this.name = "SettingsValidationError";
69
+ this.issues = issues;
70
+ }
71
+ };
72
+ function foldToOneLine(text) {
73
+ return text.replace(/\s*\n\s*/g, " ").trim();
74
+ }
75
+ function yamlErrorSummary(error) {
76
+ const raw = error instanceof Error ? error.message : String(error);
77
+ return (raw.split("\n")[0] ?? raw).trim().replace(/:$/u, "");
78
+ }
79
+ function settingsFailureHeadline(kind) {
80
+ if (kind === "unreadable") return "settings.yaml cannot be read";
81
+ if (kind === "syntax") return "settings.yaml is not valid YAML";
82
+ return "settings.yaml failed validation";
83
+ }
84
+ function formatSettingsIssues(issues) {
85
+ if (issues.length === 0) return "";
86
+ const path = join(resolveClioDirs().config, "settings.yaml");
87
+ const kind = issuesKind(issues);
88
+ const detail = kind === "schema" ? issues.map((issue) => `${issue.path}: ${issue.message}`).join("; ") : issues.map((issue) => issue.message.replace(/^(?:invalid YAML|unreadable): /u, "")).join("; ");
89
+ const discard = "`clio-coder reset --config --force` to start from defaults";
90
+ return foldToOneLine(
91
+ `${settingsFailureHeadline(kind)}: ${settingsRemedyInline(kind, path)}, or ${discard}. ${detail}`
92
+ );
93
+ }
94
+ function formatSettingsFailure(error) {
95
+ if (error instanceof SettingsValidationError && error.issues.length > 0) return formatSettingsIssues(error.issues);
96
+ return foldToOneLine(error instanceof Error ? error.message : String(error));
97
+ }
98
+ function isPlainObject(value) {
99
+ return typeof value === "object" && value !== null && !Array.isArray(value);
100
+ }
101
+ function cloneValue(value) {
102
+ return structuredClone(value);
103
+ }
104
+ var Issues = class {
105
+ list = [];
106
+ add(path, message) {
107
+ this.list.push({ path, message });
108
+ }
109
+ unknownKeys(path, raw, known) {
110
+ const knownSet = new Set(known);
111
+ for (const key of Object.keys(raw)) {
112
+ if (!knownSet.has(key)) this.add(path ? `${path}.${key}` : key, "unknown key");
113
+ }
114
+ }
115
+ };
116
+ function expectString(issues, path, value) {
117
+ if (typeof value !== "string") {
118
+ issues.add(path, `expected a string, got ${describe(value)}`);
119
+ return void 0;
120
+ }
121
+ const trimmed = value.trim();
122
+ if (trimmed.length === 0) {
123
+ issues.add(path, "expected a non-empty string");
124
+ return void 0;
125
+ }
126
+ return trimmed;
127
+ }
128
+ function expectBoolean(issues, path, value) {
129
+ if (typeof value !== "boolean") {
130
+ issues.add(path, `expected a boolean, got ${describe(value)}`);
131
+ return void 0;
132
+ }
133
+ return value;
134
+ }
135
+ function expectNumber(issues, path, value, opts) {
136
+ if (typeof value !== "number" || !Number.isFinite(value)) {
137
+ issues.add(path, `expected a number, got ${describe(value)}`);
138
+ return void 0;
139
+ }
140
+ if (opts?.min !== void 0 && value < opts.min) {
141
+ issues.add(path, `expected a number >= ${opts.min}, got ${value}`);
142
+ return void 0;
143
+ }
144
+ if (opts?.max !== void 0 && value > opts.max) {
145
+ issues.add(path, `expected a number <= ${opts.max}, got ${value}`);
146
+ return void 0;
147
+ }
148
+ return value;
149
+ }
150
+ function expectInteger(issues, path, value, opts) {
151
+ if (typeof value !== "number" || !Number.isInteger(value)) {
152
+ issues.add(path, `expected an integer, got ${describe(value)}`);
153
+ return void 0;
154
+ }
155
+ if (opts?.min !== void 0 && value < opts.min) {
156
+ issues.add(path, `expected an integer >= ${opts.min}, got ${value}`);
157
+ return void 0;
158
+ }
159
+ if (opts?.max !== void 0 && value > opts.max) {
160
+ issues.add(path, `expected an integer <= ${opts.max}, got ${value}`);
161
+ return void 0;
162
+ }
163
+ return value;
164
+ }
165
+ function expectEnum(issues, path, value, allowed) {
166
+ if (typeof value === "string" && allowed.includes(value)) return value;
167
+ issues.add(path, `expected one of ${allowed.join(" | ")}, got ${describe(value)}`);
168
+ return void 0;
169
+ }
170
+ function expectStringArray(issues, path, value) {
171
+ if (!Array.isArray(value)) {
172
+ issues.add(path, `expected a list of strings, got ${describe(value)}`);
173
+ return void 0;
174
+ }
175
+ const seen = /* @__PURE__ */ new Set();
176
+ const out = [];
177
+ for (let i = 0; i < value.length; i += 1) {
178
+ const entry = expectString(issues, `${path}[${i}]`, value[i]);
179
+ if (entry === void 0) continue;
180
+ if (seen.has(entry)) continue;
181
+ seen.add(entry);
182
+ out.push(entry);
183
+ }
184
+ return out;
185
+ }
186
+ function expectStringRecord(issues, path, value) {
187
+ if (!isPlainObject(value)) {
188
+ issues.add(path, `expected a string map, got ${describe(value)}`);
189
+ return void 0;
190
+ }
191
+ const out = {};
192
+ for (const [key, raw] of Object.entries(value)) {
193
+ const entry = expectString(issues, `${path}.${key}`, raw);
194
+ if (entry !== void 0) out[key] = entry;
195
+ }
196
+ return out;
197
+ }
198
+ function describe(value) {
199
+ if (value === null) return "null";
200
+ if (Array.isArray(value)) return "a list";
201
+ if (typeof value === "object") return "a map";
202
+ if (typeof value === "string") return value.trim().length === 0 ? "an empty string" : JSON.stringify(value);
203
+ return String(value);
204
+ }
205
+ var TOOL_CALL_FORMATS = ["openai", "anthropic", "hermes", "llama3-json", "mistral", "qwen", "xml"];
206
+ var THINKING_FORMATS = [
207
+ "qwen-chat-template",
208
+ "openrouter",
209
+ "zai",
210
+ "anthropic-extended",
211
+ "deepseek-r1",
212
+ "openai-codex",
213
+ "harmony"
214
+ ];
215
+ var STRUCTURED_OUTPUTS = ["json-schema", "gbnf", "xgrammar", "none"];
216
+ var AUTONOMY_LEVELS = ["read-only", "suggest", "auto-edit", "full-auto"];
217
+ var TOOL_GOVERNANCE = ["clio-policy", "agent-managed", "deny-all"];
218
+ function validateCapabilities(issues, path, value) {
219
+ if (!isPlainObject(value)) {
220
+ issues.add(path, `expected a map, got ${describe(value)}`);
221
+ return void 0;
222
+ }
223
+ issues.unknownKeys(path, value, [
224
+ "chat",
225
+ "tools",
226
+ "toolCallFormat",
227
+ "reasoning",
228
+ "thinkingFormat",
229
+ "structuredOutputs",
230
+ "vision",
231
+ "audio",
232
+ "embeddings",
233
+ "rerank",
234
+ "fim",
235
+ "contextWindow",
236
+ "maxTokens"
237
+ ]);
238
+ const out = {};
239
+ for (const key of ["chat", "tools", "reasoning", "vision", "audio", "embeddings", "rerank", "fim"]) {
240
+ if (key in value) {
241
+ const v = expectBoolean(issues, `${path}.${key}`, value[key]);
242
+ if (v !== void 0) out[key] = v;
243
+ }
244
+ }
245
+ if ("toolCallFormat" in value) {
246
+ const v = expectEnum(issues, `${path}.toolCallFormat`, value.toolCallFormat, TOOL_CALL_FORMATS);
247
+ if (v !== void 0) out.toolCallFormat = v;
248
+ }
249
+ if ("thinkingFormat" in value) {
250
+ const v = expectEnum(issues, `${path}.thinkingFormat`, value.thinkingFormat, THINKING_FORMATS);
251
+ if (v !== void 0) out.thinkingFormat = v;
252
+ }
253
+ if ("structuredOutputs" in value) {
254
+ const v = expectEnum(issues, `${path}.structuredOutputs`, value.structuredOutputs, STRUCTURED_OUTPUTS);
255
+ if (v !== void 0) out.structuredOutputs = v;
256
+ }
257
+ if ("contextWindow" in value) {
258
+ const v = expectInteger(issues, `${path}.contextWindow`, value.contextWindow, { min: 0 });
259
+ if (v !== void 0) out.contextWindow = v;
260
+ }
261
+ if ("maxTokens" in value) {
262
+ const v = expectInteger(issues, `${path}.maxTokens`, value.maxTokens, { min: 0 });
263
+ if (v !== void 0) out.maxTokens = v;
264
+ }
265
+ return Object.keys(out).length > 0 ? out : void 0;
266
+ }
267
+ function validateAuth(issues, path, value) {
268
+ if (!isPlainObject(value)) {
269
+ issues.add(path, `expected a map, got ${describe(value)}`);
270
+ return void 0;
271
+ }
272
+ issues.unknownKeys(path, value, ["apiKeyEnvVar", "apiKeyRef", "oauthProfile", "headers"]);
273
+ const out = {};
274
+ for (const key of ["apiKeyEnvVar", "apiKeyRef", "oauthProfile"]) {
275
+ if (key in value) {
276
+ const v = expectString(issues, `${path}.${key}`, value[key]);
277
+ if (v !== void 0) out[key] = v;
278
+ }
279
+ }
280
+ if ("headers" in value) {
281
+ const v = expectStringRecord(issues, `${path}.headers`, value.headers);
282
+ if (v !== void 0 && Object.keys(v).length > 0) out.headers = v;
283
+ }
284
+ return Object.keys(out).length > 0 ? out : void 0;
285
+ }
286
+ function validatePricing(issues, path, value) {
287
+ if (!isPlainObject(value)) {
288
+ issues.add(path, `expected a map, got ${describe(value)}`);
289
+ return void 0;
290
+ }
291
+ issues.unknownKeys(path, value, ["input", "output", "cacheRead", "cacheWrite"]);
292
+ const input = expectNumber(issues, `${path}.input`, value.input, { min: 0 });
293
+ const output = expectNumber(issues, `${path}.output`, value.output, { min: 0 });
294
+ if (input === void 0 || output === void 0) return void 0;
295
+ const out = { input, output };
296
+ if ("cacheRead" in value) {
297
+ const v = expectNumber(issues, `${path}.cacheRead`, value.cacheRead, { min: 0 });
298
+ if (v !== void 0) out.cacheRead = v;
299
+ }
300
+ if ("cacheWrite" in value) {
301
+ const v = expectNumber(issues, `${path}.cacheWrite`, value.cacheWrite, { min: 0 });
302
+ if (v !== void 0) out.cacheWrite = v;
303
+ }
304
+ return out;
305
+ }
306
+ function validateTarget(issues, path, value) {
307
+ if (!isPlainObject(value)) {
308
+ issues.add(path, `expected a map, got ${describe(value)}`);
309
+ return null;
310
+ }
311
+ issues.unknownKeys(path, value, [
312
+ "id",
313
+ "runtime",
314
+ "url",
315
+ "auth",
316
+ "defaultModel",
317
+ "wireModels",
318
+ "capabilities",
319
+ "lifecycle",
320
+ "gateway",
321
+ "pricing"
322
+ ]);
323
+ const id = "id" in value ? expectString(issues, `${path}.id`, value.id) : void 0;
324
+ const runtime = "runtime" in value ? expectString(issues, `${path}.runtime`, value.runtime) : void 0;
325
+ if (!("id" in value)) issues.add(`${path}.id`, "required");
326
+ if (!("runtime" in value)) issues.add(`${path}.runtime`, "required");
327
+ if (id === void 0 || runtime === void 0) return null;
328
+ const target = { id, runtime };
329
+ if ("url" in value) {
330
+ const v = expectString(issues, `${path}.url`, value.url);
331
+ if (v !== void 0) target.url = v;
332
+ }
333
+ if ("auth" in value) {
334
+ const v = validateAuth(issues, `${path}.auth`, value.auth);
335
+ if (v !== void 0) target.auth = v;
336
+ }
337
+ if ("wireModels" in value) {
338
+ const v = expectStringArray(issues, `${path}.wireModels`, value.wireModels);
339
+ if (v !== void 0 && v.length > 0) target.wireModels = v;
340
+ }
341
+ if ("defaultModel" in value) {
342
+ const v = expectString(issues, `${path}.defaultModel`, value.defaultModel);
343
+ if (v !== void 0) target.defaultModel = v;
344
+ } else if (target.wireModels?.[0]) {
345
+ target.defaultModel = target.wireModels[0];
346
+ }
347
+ if ("capabilities" in value) {
348
+ const v = validateCapabilities(issues, `${path}.capabilities`, value.capabilities);
349
+ if (v !== void 0) target.capabilities = v;
350
+ }
351
+ if ("lifecycle" in value) {
352
+ const v = expectEnum(issues, `${path}.lifecycle`, value.lifecycle, ["user-managed", "clio-managed"]);
353
+ if (v !== void 0) target.lifecycle = v;
354
+ }
355
+ if ("gateway" in value) {
356
+ const v = expectBoolean(issues, `${path}.gateway`, value.gateway);
357
+ if (v !== void 0) target.gateway = v;
358
+ }
359
+ if ("pricing" in value) {
360
+ const v = validatePricing(issues, `${path}.pricing`, value.pricing);
361
+ if (v !== void 0) target.pricing = v;
362
+ }
363
+ return target;
364
+ }
365
+ function validateWorkerTarget(issues, path, value, defaults, targets, options) {
366
+ const out = cloneValue(defaults);
367
+ if (!isPlainObject(value)) {
368
+ issues.add(path, `expected a map, got ${describe(value)}`);
369
+ return out;
370
+ }
371
+ const allowNode = options?.nodeIds !== void 0;
372
+ issues.unknownKeys(
373
+ path,
374
+ value,
375
+ allowNode ? ["target", "model", "thinkingLevel", "node"] : ["target", "model", "thinkingLevel"]
376
+ );
377
+ if ("target" in value && value.target !== null) {
378
+ const v = expectString(issues, `${path}.target`, value.target);
379
+ if (v !== void 0) out.target = targets.some((entry) => entry.id === v) ? v : null;
380
+ }
381
+ if ("thinkingLevel" in value) {
382
+ const v = expectEnum(issues, `${path}.thinkingLevel`, value.thinkingLevel, THINKING_LEVELS);
383
+ if (v !== void 0) out.thinkingLevel = v;
384
+ }
385
+ if ("model" in value && value.model !== null) {
386
+ const v = expectString(issues, `${path}.model`, value.model);
387
+ if (v !== void 0) out.model = v;
388
+ }
389
+ if (allowNode && "node" in value && value.node !== null) {
390
+ const v = expectString(issues, `${path}.node`, value.node);
391
+ if (v !== void 0) {
392
+ const id = v.trim();
393
+ if (id.length > 0 && (id === "local" || options?.nodeIds?.has(id) === true)) out.node = id;
394
+ }
395
+ }
396
+ if (!out.target) {
397
+ out.model = null;
398
+ } else if (out.model === null) {
399
+ out.model = targets.find((entry) => entry.id === out.target)?.defaultModel ?? null;
400
+ }
401
+ return out;
402
+ }
403
+ function normalizeModelRefs(refs, targets) {
404
+ const byId = new Set(targets.map((target) => target.id));
405
+ const out = [];
406
+ for (const ref of refs) {
407
+ const [targetId, ...modelParts] = ref.split("/");
408
+ if (!targetId || !byId.has(targetId) || modelParts.length === 0) continue;
409
+ const model = modelParts.join("/").trim();
410
+ if (!model) continue;
411
+ const normalized = `${targetId}/${model}`;
412
+ if (!out.includes(normalized)) out.push(normalized);
413
+ }
414
+ return out;
415
+ }
416
+ function normalizeScope(refs, targets) {
417
+ const byId = new Set(targets.map((target) => target.id));
418
+ const out = [];
419
+ for (const ref of refs) {
420
+ const [targetId] = ref.split("/");
421
+ if (!targetId || !byId.has(targetId)) continue;
422
+ if (!out.includes(ref)) out.push(ref);
423
+ }
424
+ return out;
425
+ }
426
+ function validateDelegationAgent(issues, path, value, defaults, seen) {
427
+ if (!isPlainObject(value)) {
428
+ issues.add(path, `expected a map, got ${describe(value)}`);
429
+ return null;
430
+ }
431
+ issues.unknownKeys(path, value, [
432
+ "id",
433
+ "command",
434
+ "args",
435
+ "cwd",
436
+ "env",
437
+ "connectTimeoutMs",
438
+ "turnTimeoutMs",
439
+ "permissionTimeoutMs",
440
+ "stallTimeoutMs",
441
+ "toolGovernance",
442
+ "projectContext",
443
+ "labels"
444
+ ]);
445
+ const id = "id" in value ? expectString(issues, `${path}.id`, value.id) : void 0;
446
+ const command = "command" in value ? expectString(issues, `${path}.command`, value.command) : void 0;
447
+ if (!("id" in value)) issues.add(`${path}.id`, "required");
448
+ if (!("command" in value)) issues.add(`${path}.command`, "required");
449
+ if (id === void 0 || command === void 0) return null;
450
+ if (id === "auto") {
451
+ issues.add(`${path}.id`, "'auto' is reserved for coordinator-owned agent selection");
452
+ return null;
453
+ }
454
+ if (seen.has(id)) {
455
+ issues.add(`${path}.id`, `duplicate delegation agent id '${id}'`);
456
+ return null;
457
+ }
458
+ seen.add(id);
459
+ const agent = {
460
+ id,
461
+ command,
462
+ args: [],
463
+ connectTimeoutMs: defaults.connectTimeoutMs,
464
+ turnTimeoutMs: defaults.turnTimeoutMs,
465
+ permissionTimeoutMs: defaults.permissionTimeoutMs,
466
+ toolGovernance: defaults.toolGovernance
467
+ };
468
+ if ("args" in value) {
469
+ const v = expectStringArray(issues, `${path}.args`, value.args);
470
+ if (v !== void 0) agent.args = v;
471
+ }
472
+ for (const key of ["connectTimeoutMs", "turnTimeoutMs", "permissionTimeoutMs"]) {
473
+ if (key in value) {
474
+ const v = expectInteger(issues, `${path}.${key}`, value[key], { min: 1, max: MAX_TIMER_DELAY_MS });
475
+ if (v !== void 0) agent[key] = v;
476
+ }
477
+ }
478
+ if ("stallTimeoutMs" in value) {
479
+ const v = expectInteger(issues, `${path}.stallTimeoutMs`, value.stallTimeoutMs);
480
+ if (v !== void 0) agent.stallTimeoutMs = v;
481
+ }
482
+ if ("toolGovernance" in value) {
483
+ const v = expectEnum(issues, `${path}.toolGovernance`, value.toolGovernance, TOOL_GOVERNANCE);
484
+ if (v !== void 0) agent.toolGovernance = v;
485
+ }
486
+ if ("projectContext" in value) {
487
+ const v = expectEnum(issues, `${path}.projectContext`, value.projectContext, ["none", "bounded"]);
488
+ if (v !== void 0) agent.projectContext = v;
489
+ }
490
+ if ("cwd" in value) {
491
+ const v = expectString(issues, `${path}.cwd`, value.cwd);
492
+ if (v !== void 0) agent.cwd = v;
493
+ }
494
+ if ("env" in value) {
495
+ const v = expectStringRecord(issues, `${path}.env`, value.env);
496
+ if (v !== void 0 && Object.keys(v).length > 0) agent.env = v;
497
+ }
498
+ if ("labels" in value) {
499
+ const v = expectStringRecord(issues, `${path}.labels`, value.labels);
500
+ if (v !== void 0 && Object.keys(v).length > 0) agent.labels = v;
501
+ }
502
+ return agent;
503
+ }
504
+ function validateDelegation(issues, value) {
505
+ const out = cloneValue(DEFAULT_SETTINGS.delegation);
506
+ if (!isPlainObject(value)) {
507
+ issues.add("delegation", `expected a map, got ${describe(value)}`);
508
+ return out;
509
+ }
510
+ issues.unknownKeys("delegation", value, ["agents", "defaults"]);
511
+ if ("defaults" in value) {
512
+ if (!isPlainObject(value.defaults)) {
513
+ issues.add("delegation.defaults", `expected a map, got ${describe(value.defaults)}`);
514
+ } else {
515
+ issues.unknownKeys("delegation.defaults", value.defaults, [
516
+ "connectTimeoutMs",
517
+ "turnTimeoutMs",
518
+ "permissionTimeoutMs",
519
+ "toolGovernance"
520
+ ]);
521
+ for (const key of ["connectTimeoutMs", "turnTimeoutMs", "permissionTimeoutMs"]) {
522
+ if (key in value.defaults) {
523
+ const v = expectInteger(issues, `delegation.defaults.${key}`, value.defaults[key], {
524
+ min: 1,
525
+ max: MAX_TIMER_DELAY_MS
526
+ });
527
+ if (v !== void 0) out.defaults[key] = v;
528
+ }
529
+ }
530
+ if ("toolGovernance" in value.defaults) {
531
+ const v = expectEnum(issues, "delegation.defaults.toolGovernance", value.defaults.toolGovernance, TOOL_GOVERNANCE);
532
+ if (v !== void 0) out.defaults.toolGovernance = v;
533
+ }
534
+ }
535
+ }
536
+ if ("agents" in value) {
537
+ if (!Array.isArray(value.agents)) {
538
+ issues.add("delegation.agents", `expected a list, got ${describe(value.agents)}`);
539
+ } else {
540
+ const seen = /* @__PURE__ */ new Set();
541
+ out.agents = value.agents.map((entry, i) => validateDelegationAgent(issues, `delegation.agents[${i}]`, entry, out.defaults, seen)).filter((entry) => entry !== null);
542
+ }
543
+ }
544
+ return out;
545
+ }
546
+ function validateFleetNode(issues, path, value, seen) {
547
+ if (!isPlainObject(value)) {
548
+ issues.add(path, `expected a map, got ${describe(value)}`);
549
+ return null;
550
+ }
551
+ issues.unknownKeys(path, value, [
552
+ "id",
553
+ "host",
554
+ "user",
555
+ "port",
556
+ "identityFile",
557
+ "clioEntry",
558
+ "labels",
559
+ "maxWorkers",
560
+ "residency"
561
+ ]);
562
+ const id = "id" in value ? expectString(issues, `${path}.id`, value.id) : void 0;
563
+ const host = "host" in value ? expectString(issues, `${path}.host`, value.host) : void 0;
564
+ if (!("id" in value)) issues.add(`${path}.id`, "required");
565
+ if (!("host" in value)) issues.add(`${path}.host`, "required");
566
+ if (id === void 0 || host === void 0) return null;
567
+ const trimmedId = id.trim();
568
+ if (trimmedId.length === 0) {
569
+ issues.add(`${path}.id`, "must not be blank");
570
+ return null;
571
+ }
572
+ if (trimmedId === "local") {
573
+ issues.add(`${path}.id`, "'local' is reserved for the implicit local node");
574
+ return null;
575
+ }
576
+ if (seen.has(trimmedId)) {
577
+ issues.add(`${path}.id`, `duplicate fleet node id '${trimmedId}'`);
578
+ return null;
579
+ }
580
+ seen.add(trimmedId);
581
+ const node = { id: trimmedId, host, maxWorkers: 2 };
582
+ if ("user" in value) {
583
+ const v = expectString(issues, `${path}.user`, value.user);
584
+ if (v !== void 0) node.user = v;
585
+ }
586
+ if ("port" in value) {
587
+ const v = expectInteger(issues, `${path}.port`, value.port, { min: 1 });
588
+ if (v !== void 0) node.port = v;
589
+ }
590
+ if ("identityFile" in value) {
591
+ const v = expectString(issues, `${path}.identityFile`, value.identityFile);
592
+ if (v !== void 0) node.identityFile = v;
593
+ }
594
+ if ("clioEntry" in value) {
595
+ const v = expectString(issues, `${path}.clioEntry`, value.clioEntry);
596
+ if (v !== void 0) node.clioEntry = v;
597
+ }
598
+ if ("labels" in value) {
599
+ const v = expectStringArray(issues, `${path}.labels`, value.labels);
600
+ if (v !== void 0) node.labels = v;
601
+ }
602
+ if ("maxWorkers" in value) {
603
+ const v = expectInteger(issues, `${path}.maxWorkers`, value.maxWorkers, { min: 1 });
604
+ if (v !== void 0) node.maxWorkers = v;
605
+ }
606
+ if ("residency" in value) {
607
+ const v = expectEnum(issues, `${path}.residency`, value.residency, ["observe", "manage"]);
608
+ if (v !== void 0) node.residency = v;
609
+ }
610
+ return node;
611
+ }
612
+ function validateFleet(issues, value) {
613
+ const out = cloneValue(DEFAULT_SETTINGS.fleet);
614
+ if (!isPlainObject(value)) {
615
+ issues.add("fleet", `expected a map, got ${describe(value)}`);
616
+ return out;
617
+ }
618
+ issues.unknownKeys("fleet", value, ["nodes"]);
619
+ if ("nodes" in value) {
620
+ if (!Array.isArray(value.nodes)) {
621
+ issues.add("fleet.nodes", `expected a list, got ${describe(value.nodes)}`);
622
+ } else {
623
+ const seen = /* @__PURE__ */ new Set();
624
+ out.nodes = value.nodes.map((entry, i) => validateFleetNode(issues, `fleet.nodes[${i}]`, entry, seen)).filter((entry) => entry !== null);
625
+ }
626
+ }
627
+ return out;
628
+ }
629
+ function validateMemorySettings(issues, value) {
630
+ const out = cloneValue(DEFAULT_SETTINGS.memory);
631
+ if (!isPlainObject(value)) {
632
+ issues.add("memory", `expected a map, got ${describe(value)}`);
633
+ return out;
634
+ }
635
+ issues.unknownKeys("memory", value, ["intervention"]);
636
+ if (!("intervention" in value)) return out;
637
+ if (!isPlainObject(value.intervention)) {
638
+ issues.add("memory.intervention", `expected a map, got ${describe(value.intervention)}`);
639
+ return out;
640
+ }
641
+ const raw = value.intervention;
642
+ issues.unknownKeys("memory.intervention", raw, ["enabled", "everyNTools", "windowSteps", "maxTokens", "timeoutMs"]);
643
+ if ("enabled" in raw) {
644
+ const enabled = expectBoolean(issues, "memory.intervention.enabled", raw.enabled);
645
+ if (enabled !== void 0) out.intervention.enabled = enabled;
646
+ }
647
+ for (const key of ["everyNTools", "windowSteps", "maxTokens", "timeoutMs"]) {
648
+ if (!(key in raw)) continue;
649
+ const parsed = expectInteger(issues, `memory.intervention.${key}`, raw[key], {
650
+ min: key === "everyNTools" ? 2 : 1
651
+ });
652
+ if (parsed !== void 0) out.intervention[key] = parsed;
653
+ }
654
+ return out;
655
+ }
656
+ function validateKeybindings(issues, value) {
657
+ if (!isPlainObject(value)) {
658
+ issues.add("keybindings", `expected a map, got ${describe(value)}`);
659
+ return {};
660
+ }
661
+ const next = {};
662
+ for (const [rawKey, rawValue] of Object.entries(value)) {
663
+ const id = rawKey.trim();
664
+ if (!id) {
665
+ issues.add("keybindings", "empty keybinding id");
666
+ continue;
667
+ }
668
+ if (typeof rawValue === "string") {
669
+ const v = expectString(issues, `keybindings.${id}`, rawValue);
670
+ if (v !== void 0) next[id] = v;
671
+ continue;
672
+ }
673
+ if (Array.isArray(rawValue)) {
674
+ const v = expectStringArray(issues, `keybindings.${id}`, rawValue);
675
+ if (v !== void 0 && v.length > 0) next[id] = v;
676
+ continue;
677
+ }
678
+ issues.add(`keybindings.${id}`, `expected a string or list of strings, got ${describe(rawValue)}`);
679
+ }
680
+ return next;
681
+ }
682
+ var TOP_LEVEL_KEYS = [
683
+ "version",
684
+ "identity",
685
+ "autonomy",
686
+ "targets",
687
+ "runtimePlugins",
688
+ "orchestrator",
689
+ "background",
690
+ "memory",
691
+ "workers",
692
+ "fleet",
693
+ "routing",
694
+ "scope",
695
+ "modelSelector",
696
+ "budget",
697
+ "defaults",
698
+ "theme",
699
+ "terminal",
700
+ "skills",
701
+ "delegation",
702
+ "keybindings",
703
+ "compaction",
704
+ "retry",
705
+ "guardrails"
706
+ ];
707
+ function validateSettings(raw) {
708
+ const issues = new Issues();
709
+ const settings = cloneValue(DEFAULT_SETTINGS);
710
+ if (!isPlainObject(raw)) {
711
+ issues.add("(root)", `expected a map, got ${describe(raw)}`);
712
+ return { settings, issues: issues.list };
713
+ }
714
+ issues.unknownKeys("", raw, TOP_LEVEL_KEYS);
715
+ if ("version" in raw && raw.version !== 1) {
716
+ issues.add("version", `expected 1, got ${describe(raw.version)}`);
717
+ }
718
+ if ("identity" in raw) {
719
+ const v = expectString(issues, "identity", raw.identity);
720
+ if (v !== void 0) settings.identity = v;
721
+ }
722
+ if ("autonomy" in raw) {
723
+ const v = expectEnum(issues, "autonomy", raw.autonomy, AUTONOMY_LEVELS);
724
+ if (v !== void 0) settings.autonomy = v;
725
+ }
726
+ if ("targets" in raw) {
727
+ if (!Array.isArray(raw.targets)) {
728
+ issues.add("targets", `expected a list, got ${describe(raw.targets)}`);
729
+ } else {
730
+ const seen = /* @__PURE__ */ new Set();
731
+ const out = [];
732
+ for (let i = 0; i < raw.targets.length; i += 1) {
733
+ const target = validateTarget(issues, `targets[${i}]`, raw.targets[i]);
734
+ if (!target) continue;
735
+ if (seen.has(target.id)) {
736
+ issues.add(`targets[${i}].id`, `duplicate target id '${target.id}'`);
737
+ continue;
738
+ }
739
+ seen.add(target.id);
740
+ out.push(target);
741
+ }
742
+ settings.targets = out;
743
+ }
744
+ }
745
+ if ("runtimePlugins" in raw) {
746
+ const v = expectStringArray(issues, "runtimePlugins", raw.runtimePlugins);
747
+ if (v !== void 0) settings.runtimePlugins = v;
748
+ }
749
+ if ("orchestrator" in raw) {
750
+ settings.orchestrator = validateWorkerTarget(
751
+ issues,
752
+ "orchestrator",
753
+ raw.orchestrator,
754
+ settings.orchestrator,
755
+ settings.targets
756
+ );
757
+ }
758
+ if ("background" in raw) {
759
+ settings.background = validateWorkerTarget(
760
+ issues,
761
+ "background",
762
+ raw.background,
763
+ settings.background,
764
+ settings.targets
765
+ );
766
+ }
767
+ if ("memory" in raw) settings.memory = validateMemorySettings(issues, raw.memory);
768
+ if ("fleet" in raw) {
769
+ settings.fleet = validateFleet(issues, raw.fleet);
770
+ }
771
+ const fleetNodeIds = new Set(settings.fleet.nodes.map((node) => node.id));
772
+ if ("routing" in raw) {
773
+ if (!isPlainObject(raw.routing)) {
774
+ issues.add("routing", `expected a map, got ${describe(raw.routing)}`);
775
+ } else {
776
+ issues.unknownKeys("routing", raw.routing, ["activeRoles", "activePostures", "agentAutomation"]);
777
+ const activeRoles = expectStringArray(issues, "routing.activeRoles", raw.routing.activeRoles);
778
+ if (activeRoles !== void 0) {
779
+ const allowed = new Set(ACTIVE_ROUTING_ROLES);
780
+ const rawRoles = raw.routing.activeRoles;
781
+ const stringRoles = rawRoles.filter((role) => typeof role === "string");
782
+ const complete = activeRoles.length === rawRoles.length;
783
+ for (const role of activeRoles) {
784
+ if (!allowed.has(role)) issues.add("routing.activeRoles", `unsupported active role '${role}'`);
785
+ }
786
+ if (new Set(stringRoles).size !== stringRoles.length) {
787
+ issues.add("routing.activeRoles", "expected unique roles");
788
+ }
789
+ if (complete && activeRoles.every((role) => allowed.has(role))) {
790
+ settings.routing.activeRoles = activeRoles;
791
+ }
792
+ }
793
+ const activePostures = expectStringArray(issues, "routing.activePostures", raw.routing.activePostures);
794
+ if (activePostures !== void 0) {
795
+ const allowed = new Set(ACTIVE_ROUTING_POSTURES);
796
+ const rawPostures = raw.routing.activePostures;
797
+ const stringPostures = rawPostures.filter((posture) => typeof posture === "string");
798
+ const complete = activePostures.length === rawPostures.length;
799
+ for (const posture of activePostures) {
800
+ if (!allowed.has(posture)) issues.add("routing.activePostures", `unsupported active posture '${posture}'`);
801
+ }
802
+ if (new Set(stringPostures).size !== stringPostures.length) {
803
+ issues.add("routing.activePostures", "expected unique postures");
804
+ }
805
+ if (complete && activePostures.every((posture) => allowed.has(posture))) {
806
+ settings.routing.activePostures = activePostures;
807
+ }
808
+ }
809
+ if (!isPlainObject(raw.routing.agentAutomation)) {
810
+ issues.add("routing.agentAutomation", "expected a map");
811
+ } else {
812
+ const automation = raw.routing.agentAutomation;
813
+ issues.unknownKeys("routing.agentAutomation", automation, ["activeAgentRoles"]);
814
+ if (!Array.isArray(automation.activeAgentRoles)) {
815
+ issues.add("routing.agentAutomation.activeAgentRoles", "expected a list");
816
+ } else {
817
+ const pairs = [];
818
+ const seen = /* @__PURE__ */ new Set();
819
+ for (const [index, value] of automation.activeAgentRoles.entries()) {
820
+ const path = `routing.agentAutomation.activeAgentRoles[${index}]`;
821
+ if (!isPlainObject(value)) {
822
+ issues.add(path, "expected a map");
823
+ continue;
824
+ }
825
+ issues.unknownKeys(path, value, ["agentId", "executionRole"]);
826
+ const agentId = expectString(issues, `${path}.agentId`, value.agentId);
827
+ const executionRole = expectEnum(
828
+ issues,
829
+ `${path}.executionRole`,
830
+ value.executionRole,
831
+ ACTIVE_AGENT_AUTOMATION_ROLES
832
+ );
833
+ if (agentId === "auto") {
834
+ issues.add(`${path}.agentId`, "'auto' is reserved for coordinator-owned agent selection");
835
+ }
836
+ if (agentId === void 0 || agentId === "auto" || executionRole === void 0) continue;
837
+ const key = `${agentId}\0${executionRole}`;
838
+ if (seen.has(key)) {
839
+ issues.add(path, "duplicate agent and execution-role pair");
840
+ continue;
841
+ }
842
+ seen.add(key);
843
+ pairs.push({ agentId, executionRole });
844
+ }
845
+ if (pairs.length === automation.activeAgentRoles.length) {
846
+ settings.routing.agentAutomation.activeAgentRoles = pairs;
847
+ }
848
+ }
849
+ }
850
+ }
851
+ }
852
+ if ("workers" in raw) {
853
+ if (!isPlainObject(raw.workers)) {
854
+ issues.add("workers", `expected a map, got ${describe(raw.workers)}`);
855
+ } else {
856
+ issues.unknownKeys("workers", raw.workers, [
857
+ "default",
858
+ "profiles",
859
+ "agentBindings",
860
+ "maxRetries",
861
+ "onPermission",
862
+ "escalation",
863
+ "resilienceCooldownMs"
864
+ ]);
865
+ if ("default" in raw.workers) {
866
+ settings.workers.default = validateWorkerTarget(
867
+ issues,
868
+ "workers.default",
869
+ raw.workers.default,
870
+ settings.workers.default,
871
+ settings.targets,
872
+ { nodeIds: fleetNodeIds }
873
+ );
874
+ }
875
+ if ("profiles" in raw.workers) {
876
+ if (!isPlainObject(raw.workers.profiles)) {
877
+ issues.add("workers.profiles", `expected a map, got ${describe(raw.workers.profiles)}`);
878
+ } else {
879
+ const profiles = {};
880
+ for (const [rawName, rawProfile] of Object.entries(raw.workers.profiles)) {
881
+ const name = rawName.trim();
882
+ if (!name) {
883
+ issues.add("workers.profiles", "empty profile name");
884
+ continue;
885
+ }
886
+ const profile = validateWorkerTarget(
887
+ issues,
888
+ `workers.profiles.${name}`,
889
+ rawProfile,
890
+ DEFAULT_SETTINGS.workers.default,
891
+ settings.targets,
892
+ { nodeIds: fleetNodeIds }
893
+ );
894
+ if (!profile.target) continue;
895
+ profiles[name] = profile;
896
+ }
897
+ settings.workers.profiles = profiles;
898
+ }
899
+ }
900
+ if ("agentBindings" in raw.workers) {
901
+ if (!isPlainObject(raw.workers.agentBindings)) {
902
+ issues.add("workers.agentBindings", `expected a map, got ${describe(raw.workers.agentBindings)}`);
903
+ } else {
904
+ const agentBindings = {};
905
+ for (const [rawAgentId, rawProfileName] of Object.entries(raw.workers.agentBindings)) {
906
+ const agentId = rawAgentId.trim();
907
+ if (!agentId) {
908
+ issues.add("workers.agentBindings", "empty agent id");
909
+ continue;
910
+ }
911
+ if (agentId === "auto") {
912
+ issues.add("workers.agentBindings", "'auto' is reserved for coordinator-owned agent selection");
913
+ continue;
914
+ }
915
+ const profileName = expectString(issues, `workers.agentBindings.${agentId}`, rawProfileName);
916
+ if (profileName !== void 0) agentBindings[agentId] = profileName;
917
+ }
918
+ settings.workers.agentBindings = agentBindings;
919
+ }
920
+ }
921
+ if ("maxRetries" in raw.workers) {
922
+ const v = expectInteger(issues, "workers.maxRetries", raw.workers.maxRetries, { min: 0 });
923
+ if (v !== void 0) settings.workers.maxRetries = v;
924
+ }
925
+ if ("onPermission" in raw.workers) {
926
+ const v = expectEnum(issues, "workers.onPermission", raw.workers.onPermission, [
927
+ "deny",
928
+ "fail",
929
+ "escalate"
930
+ ]);
931
+ if (v !== void 0) settings.workers.onPermission = v;
932
+ }
933
+ if ("escalation" in raw.workers) {
934
+ if (!isPlainObject(raw.workers.escalation)) {
935
+ issues.add("workers.escalation", `expected a map, got ${describe(raw.workers.escalation)}`);
936
+ } else {
937
+ const base = settings.workers.escalation ?? DEFAULT_SETTINGS.workers.escalation;
938
+ const escalation = { timeoutMs: base?.timeoutMs ?? 12e4, fallback: base?.fallback ?? "deny" };
939
+ issues.unknownKeys("workers.escalation", raw.workers.escalation, ["timeoutMs", "fallback"]);
940
+ if ("timeoutMs" in raw.workers.escalation) {
941
+ const v = expectInteger(issues, "workers.escalation.timeoutMs", raw.workers.escalation.timeoutMs, {
942
+ min: 1
943
+ });
944
+ if (v !== void 0) escalation.timeoutMs = v;
945
+ }
946
+ if ("fallback" in raw.workers.escalation) {
947
+ const v = expectEnum(issues, "workers.escalation.fallback", raw.workers.escalation.fallback, [
948
+ "deny",
949
+ "fail"
950
+ ]);
951
+ if (v !== void 0) escalation.fallback = v;
952
+ }
953
+ settings.workers.escalation = escalation;
954
+ }
955
+ }
956
+ if ("resilienceCooldownMs" in raw.workers) {
957
+ const v = expectInteger(issues, "workers.resilienceCooldownMs", raw.workers.resilienceCooldownMs, { min: 0 });
958
+ if (v !== void 0) settings.workers.resilienceCooldownMs = v;
959
+ }
960
+ }
961
+ }
962
+ if ("scope" in raw) {
963
+ const v = expectStringArray(issues, "scope", raw.scope);
964
+ if (v !== void 0) settings.scope = normalizeScope(v, settings.targets);
965
+ }
966
+ if ("modelSelector" in raw) {
967
+ if (!isPlainObject(raw.modelSelector)) {
968
+ issues.add("modelSelector", `expected a map, got ${describe(raw.modelSelector)}`);
969
+ } else {
970
+ issues.unknownKeys("modelSelector", raw.modelSelector, ["favorites", "recentLimit"]);
971
+ if ("favorites" in raw.modelSelector) {
972
+ const v = expectStringArray(issues, "modelSelector.favorites", raw.modelSelector.favorites);
973
+ if (v !== void 0) settings.modelSelector.favorites = normalizeModelRefs(v, settings.targets);
974
+ }
975
+ if ("recentLimit" in raw.modelSelector) {
976
+ const v = expectInteger(issues, "modelSelector.recentLimit", raw.modelSelector.recentLimit, { min: 1 });
977
+ if (v !== void 0) settings.modelSelector.recentLimit = v;
978
+ }
979
+ }
980
+ }
981
+ if ("budget" in raw) {
982
+ if (!isPlainObject(raw.budget)) {
983
+ issues.add("budget", `expected a map, got ${describe(raw.budget)}`);
984
+ } else {
985
+ issues.unknownKeys("budget", raw.budget, ["sessionCeilingUsd", "concurrency"]);
986
+ if ("sessionCeilingUsd" in raw.budget) {
987
+ const v = expectNumber(issues, "budget.sessionCeilingUsd", raw.budget.sessionCeilingUsd, { min: 0 });
988
+ if (v !== void 0) settings.budget.sessionCeilingUsd = v;
989
+ }
990
+ if ("concurrency" in raw.budget) {
991
+ if (raw.budget.concurrency === "auto") {
992
+ settings.budget.concurrency = "auto";
993
+ } else {
994
+ const v = expectInteger(issues, "budget.concurrency", raw.budget.concurrency, { min: 1 });
995
+ if (v !== void 0) settings.budget.concurrency = v;
996
+ }
997
+ }
998
+ }
999
+ }
1000
+ if ("defaults" in raw) {
1001
+ if (!isPlainObject(raw.defaults)) {
1002
+ issues.add("defaults", `expected a map, got ${describe(raw.defaults)}`);
1003
+ } else {
1004
+ issues.unknownKeys("defaults", raw.defaults, ["maxTokens"]);
1005
+ if ("maxTokens" in raw.defaults) {
1006
+ const v = expectInteger(issues, "defaults.maxTokens", raw.defaults.maxTokens, { min: 0 });
1007
+ if (v !== void 0) settings.defaults.maxTokens = v;
1008
+ }
1009
+ }
1010
+ }
1011
+ if ("theme" in raw) {
1012
+ const v = expectString(issues, "theme", raw.theme);
1013
+ if (v !== void 0) settings.theme = v;
1014
+ }
1015
+ if ("terminal" in raw) {
1016
+ if (!isPlainObject(raw.terminal)) {
1017
+ issues.add("terminal", `expected a map, got ${describe(raw.terminal)}`);
1018
+ } else {
1019
+ issues.unknownKeys("terminal", raw.terminal, ["showTerminalProgress", "outputVerbosity"]);
1020
+ if ("showTerminalProgress" in raw.terminal) {
1021
+ const v = expectBoolean(issues, "terminal.showTerminalProgress", raw.terminal.showTerminalProgress);
1022
+ if (v !== void 0) settings.terminal.showTerminalProgress = v;
1023
+ }
1024
+ if ("outputVerbosity" in raw.terminal) {
1025
+ const v = expectString(issues, "terminal.outputVerbosity", raw.terminal.outputVerbosity);
1026
+ if (v === "minimal" || v === "default" || v === "verbose") settings.terminal.outputVerbosity = v;
1027
+ else if (v !== void 0) issues.add("terminal.outputVerbosity", "expected minimal, default, or verbose");
1028
+ }
1029
+ }
1030
+ }
1031
+ if ("skills" in raw) {
1032
+ if (!isPlainObject(raw.skills)) {
1033
+ issues.add("skills", `expected a map, got ${describe(raw.skills)}`);
1034
+ } else {
1035
+ issues.unknownKeys("skills", raw.skills, ["trustProjectCompatRoots"]);
1036
+ if ("trustProjectCompatRoots" in raw.skills) {
1037
+ const v = expectBoolean(issues, "skills.trustProjectCompatRoots", raw.skills.trustProjectCompatRoots);
1038
+ if (v !== void 0) settings.skills.trustProjectCompatRoots = v;
1039
+ }
1040
+ }
1041
+ }
1042
+ if ("delegation" in raw) {
1043
+ settings.delegation = validateDelegation(issues, raw.delegation);
1044
+ }
1045
+ if ("keybindings" in raw) {
1046
+ settings.keybindings = validateKeybindings(issues, raw.keybindings);
1047
+ }
1048
+ if ("compaction" in raw) {
1049
+ if (!isPlainObject(raw.compaction)) {
1050
+ issues.add("compaction", `expected a map, got ${describe(raw.compaction)}`);
1051
+ } else {
1052
+ issues.unknownKeys("compaction", raw.compaction, ["auto", "threshold", "excludeLastTurns", "model", "systemPrompt"]);
1053
+ if ("auto" in raw.compaction) {
1054
+ const v = expectBoolean(issues, "compaction.auto", raw.compaction.auto);
1055
+ if (v !== void 0) settings.compaction.auto = v;
1056
+ }
1057
+ if ("threshold" in raw.compaction) {
1058
+ const v = expectNumber(issues, "compaction.threshold", raw.compaction.threshold, { min: 0, max: 1 });
1059
+ if (v !== void 0) settings.compaction.threshold = v;
1060
+ }
1061
+ if ("excludeLastTurns" in raw.compaction) {
1062
+ const v = expectInteger(issues, "compaction.excludeLastTurns", raw.compaction.excludeLastTurns, { min: 1 });
1063
+ if (v !== void 0) settings.compaction.excludeLastTurns = v;
1064
+ }
1065
+ if ("model" in raw.compaction) {
1066
+ const v = expectString(issues, "compaction.model", raw.compaction.model);
1067
+ if (v !== void 0) settings.compaction.model = v;
1068
+ }
1069
+ if ("systemPrompt" in raw.compaction) {
1070
+ const v = expectString(issues, "compaction.systemPrompt", raw.compaction.systemPrompt);
1071
+ if (v !== void 0) settings.compaction.systemPrompt = v;
1072
+ }
1073
+ }
1074
+ }
1075
+ if ("retry" in raw) {
1076
+ if (!isPlainObject(raw.retry)) {
1077
+ issues.add("retry", `expected a map, got ${describe(raw.retry)}`);
1078
+ } else {
1079
+ issues.unknownKeys("retry", raw.retry, ["enabled", "maxRetries", "baseDelayMs", "maxDelayMs"]);
1080
+ if ("enabled" in raw.retry) {
1081
+ const v = expectBoolean(issues, "retry.enabled", raw.retry.enabled);
1082
+ if (v !== void 0) settings.retry.enabled = v;
1083
+ }
1084
+ for (const key of ["maxRetries", "baseDelayMs", "maxDelayMs"]) {
1085
+ if (key in raw.retry) {
1086
+ const v = expectInteger(issues, `retry.${key}`, raw.retry[key], { min: 0 });
1087
+ if (v !== void 0) settings.retry[key] = v;
1088
+ }
1089
+ }
1090
+ }
1091
+ }
1092
+ if ("guardrails" in raw) {
1093
+ if (!isPlainObject(raw.guardrails)) {
1094
+ issues.add("guardrails", `expected a map, got ${describe(raw.guardrails)}`);
1095
+ } else {
1096
+ const keys = [
1097
+ "turnToolCallBudget",
1098
+ "workerToolCallCap",
1099
+ "maxDispatchRuns",
1100
+ "readMaxBytes",
1101
+ "observationTurnBudgetBytes",
1102
+ "internalDispatchTimeoutMs"
1103
+ ];
1104
+ issues.unknownKeys("guardrails", raw.guardrails, keys);
1105
+ for (const key of keys) {
1106
+ if (key in raw.guardrails) {
1107
+ const v = expectInteger(issues, `guardrails.${key}`, raw.guardrails[key], { min: 1 });
1108
+ if (v !== void 0) settings.guardrails[key] = v;
1109
+ }
1110
+ }
1111
+ }
1112
+ }
1113
+ return { settings, issues: issues.list };
1114
+ }
1115
+ function validateSettingsFile() {
1116
+ const path = join(resolveClioDirs().config, "settings.yaml");
1117
+ if (!existsSync(path)) return { settings: cloneValue(DEFAULT_SETTINGS), issues: [] };
1118
+ let text;
1119
+ try {
1120
+ text = readFileSync(path, "utf8");
1121
+ } catch (err) {
1122
+ return {
1123
+ settings: cloneValue(DEFAULT_SETTINGS),
1124
+ issues: [
1125
+ { path: "(root)", message: `unreadable: ${err instanceof Error ? err.message : String(err)}`, kind: "unreadable" }
1126
+ ]
1127
+ };
1128
+ }
1129
+ let parsed;
1130
+ try {
1131
+ parsed = parseYaml(text);
1132
+ } catch (err) {
1133
+ return {
1134
+ settings: cloneValue(DEFAULT_SETTINGS),
1135
+ issues: [{ path: "(root)", message: `invalid YAML: ${yamlErrorSummary(err)}`, kind: "syntax" }]
1136
+ };
1137
+ }
1138
+ return validateSettings(parsed);
1139
+ }
1140
+ function readSettings() {
1141
+ const result = validateSettingsFile();
1142
+ if (result.issues.length > 0) throw new SettingsValidationError(result.issues);
1143
+ return result.settings;
1144
+ }
1145
+ function persistSettings(settings) {
1146
+ safeResourceWrite(settingsPath(), stringifyYaml(settings), { encoding: "utf8", mode: 420 });
1147
+ }
1148
+ function settingsLockPath() {
1149
+ return `${settingsPath()}.lock`;
1150
+ }
1151
+ function sleepSync(ms) {
1152
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, Math.max(1, ms));
1153
+ }
1154
+ function tryAcquireSettingsLock(lockPath, staleLockMs) {
1155
+ try {
1156
+ writeFileSync(lockPath, `${JSON.stringify({ pid: process.pid, at: (/* @__PURE__ */ new Date()).toISOString() })}
1157
+ `, {
1158
+ encoding: "utf8",
1159
+ flag: "wx",
1160
+ mode: 420
1161
+ });
1162
+ return true;
1163
+ } catch (err) {
1164
+ if (err.code !== "EEXIST") throw err;
1165
+ }
1166
+ try {
1167
+ if (Date.now() - statSync(lockPath).mtimeMs > staleLockMs) rmSync(lockPath, { force: true });
1168
+ } catch {
1169
+ }
1170
+ return false;
1171
+ }
1172
+ function withSettingsLock(fn, options = {}) {
1173
+ const timeoutMs = options.timeoutMs ?? 1e4;
1174
+ const staleLockMs = options.staleLockMs ?? 5e3;
1175
+ const pollIntervalMs = options.pollIntervalMs ?? 25;
1176
+ const lockPath = settingsLockPath();
1177
+ const deadline = Date.now() + timeoutMs;
1178
+ while (!tryAcquireSettingsLock(lockPath, staleLockMs)) {
1179
+ if (Date.now() >= deadline) {
1180
+ throw new Error(
1181
+ `timed out after ${timeoutMs}ms waiting for ${lockPath}; delete it if no other clio process is running`
1182
+ );
1183
+ }
1184
+ sleepSync(pollIntervalMs);
1185
+ }
1186
+ try {
1187
+ return fn();
1188
+ } finally {
1189
+ rmSync(lockPath, { force: true });
1190
+ }
1191
+ }
1192
+ function updateSettings(mutate, options = {}) {
1193
+ return withSettingsLock(() => {
1194
+ const current = readSettings();
1195
+ const next = mutate(current) ?? current;
1196
+ const revalidated = validateSettings(JSON.parse(JSON.stringify(next)));
1197
+ if (revalidated.issues.length > 0) throw new SettingsValidationError(revalidated.issues);
1198
+ persistSettings(revalidated.settings);
1199
+ return revalidated.settings;
1200
+ }, options);
1201
+ }
1202
+
1203
+ export {
1204
+ MAX_TIMER_DELAY_MS,
1205
+ clampTimerDelayMs,
1206
+ sleep,
1207
+ settingsPath,
1208
+ formatSettingsIssues,
1209
+ formatSettingsFailure,
1210
+ validateSettings,
1211
+ validateSettingsFile,
1212
+ readSettings,
1213
+ updateSettings
1214
+ };
1215
+ //# sourceMappingURL=chunk-JWHCJDCI.js.map