@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,1010 @@
1
+ import {
2
+ assertAgentIdNamespace
3
+ } from "./chunk-527KG6XR.js";
4
+ import {
5
+ CONFIRMED_SCOPE,
6
+ READONLY_SCOPE,
7
+ WORKSPACE_SCOPE,
8
+ createLoopState,
9
+ createSafetyPolicyEngine,
10
+ isSubset,
11
+ observe,
12
+ parseFrontmatter,
13
+ parseResultContract
14
+ } from "./chunk-XV4ZJ6ZM.js";
15
+ import {
16
+ loadSkills
17
+ } from "./chunk-26BZQOAD.js";
18
+ import {
19
+ assertAgentSpecPolicy,
20
+ classify,
21
+ isAgentAudience,
22
+ isAgentCapabilityClass,
23
+ isAgentCategory,
24
+ isAgentLatencyClass,
25
+ isAgentProduct,
26
+ isAgentProjectContextTier,
27
+ isShadowAgent,
28
+ normalizeAgentSpec
29
+ } from "./chunk-WD6AJM35.js";
30
+ import {
31
+ BusChannels,
32
+ isRunAbortedPayload
33
+ } from "./chunk-D5YD55AR.js";
34
+ import {
35
+ clioConfigDir,
36
+ clioStateDir,
37
+ stateRootRemoved
38
+ } from "./chunk-X3NE4WVW.js";
39
+ import {
40
+ resolvePackageRoot
41
+ } from "./chunk-DXQNI4PC.js";
42
+
43
+ // src/domains/agents/extension.ts
44
+ import path3 from "node:path";
45
+
46
+ // src/domains/agents/registry.ts
47
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
48
+ import path2 from "node:path";
49
+
50
+ // src/domains/agents/recipe.ts
51
+ import path from "node:path";
52
+ var AGENT_BUDGET_KEYS = ["toolCalls", "readReserve", "synthesis"];
53
+ function parseAgentBudget(value, sourcePath) {
54
+ if (value === void 0) return void 0;
55
+ const prefix = `agent budget: ${sourcePath}: budget`;
56
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
57
+ throw new Error(`${prefix} must be a non-null YAML object`);
58
+ }
59
+ const record = value;
60
+ for (const key of Object.keys(record)) {
61
+ if (!AGENT_BUDGET_KEYS.includes(key)) {
62
+ throw new Error(`${prefix}.${key} is unknown`);
63
+ }
64
+ }
65
+ for (const key of AGENT_BUDGET_KEYS) {
66
+ if (!Object.hasOwn(record, key)) throw new Error(`${prefix}.${key} is required`);
67
+ }
68
+ const toolCalls = record.toolCalls;
69
+ if (typeof toolCalls !== "number" || !Number.isSafeInteger(toolCalls)) {
70
+ throw new Error(`${prefix}.toolCalls must be a finite safe integer`);
71
+ }
72
+ if (toolCalls <= 0) throw new Error(`${prefix}.toolCalls must be greater than 0`);
73
+ const readReserve = record.readReserve;
74
+ if (typeof readReserve !== "number" || !Number.isSafeInteger(readReserve)) {
75
+ throw new Error(`${prefix}.readReserve must be a finite safe integer`);
76
+ }
77
+ if (readReserve < 0) throw new Error(`${prefix}.readReserve must be greater than or equal to 0`);
78
+ if (readReserve >= toolCalls) throw new Error(`${prefix}.readReserve must be less than budget.toolCalls`);
79
+ const synthesis = record.synthesis;
80
+ if (typeof synthesis !== "boolean") throw new Error(`${prefix}.synthesis must be a boolean`);
81
+ return { toolCalls, readReserve, synthesis };
82
+ }
83
+ function recipeIdFromPath(absPath, rootDir) {
84
+ const resolvedRoot = path.resolve(rootDir);
85
+ const resolvedPath = path.resolve(absPath);
86
+ const relPath = path.relative(resolvedRoot, resolvedPath);
87
+ if (relPath === "" || relPath.startsWith("..") || path.isAbsolute(relPath)) {
88
+ throw new Error(`recipe: path must live under rootDir (${resolvedPath} not under ${resolvedRoot})`);
89
+ }
90
+ if (path.dirname(relPath) !== ".") {
91
+ throw new Error(`recipe: recipes must live directly under rootDir (${resolvedPath})`);
92
+ }
93
+ if (path.extname(relPath) !== ".md") {
94
+ throw new Error(`recipe: recipe files must end in .md (${resolvedPath})`);
95
+ }
96
+ const id = path.basename(relPath, ".md");
97
+ if (id === "") {
98
+ throw new Error(`recipe: recipe filename must not be empty (${resolvedPath})`);
99
+ }
100
+ return id;
101
+ }
102
+
103
+ // src/domains/agents/recipe-schema.ts
104
+ var RECIPE_KEYS = [
105
+ "version",
106
+ "name",
107
+ "description",
108
+ "tools",
109
+ "skills",
110
+ "audience",
111
+ "category",
112
+ "capabilityClass",
113
+ "latencyClass",
114
+ "projectContextTier",
115
+ "budget",
116
+ "resultContract",
117
+ "tags"
118
+ ];
119
+ var OPTIONAL_RECIPE_KEYS = ["product"];
120
+ var ALL_RECIPE_KEYS = [...RECIPE_KEYS, ...OPTIONAL_RECIPE_KEYS];
121
+ function requiredString(value, path4) {
122
+ if (typeof value !== "string" || value.trim().length === 0)
123
+ throw new Error(`agent recipe: ${path4} must be a non-empty string`);
124
+ return value;
125
+ }
126
+ function requiredStringArray(value, path4) {
127
+ if (!Array.isArray(value)) throw new Error(`agent recipe: ${path4} must be an array of strings`);
128
+ const entries = value.map((entry, index) => requiredString(entry, `${path4}[${index}]`));
129
+ if (new Set(entries).size !== entries.length) throw new Error(`agent recipe: ${path4} must not contain duplicates`);
130
+ return entries;
131
+ }
132
+ function enumValue(value, path4, predicate) {
133
+ if (!predicate(value)) throw new Error(`agent recipe: ${path4} has an unsupported value`);
134
+ return value;
135
+ }
136
+ function parseAudience(value, source, filepath) {
137
+ const audience = enumValue(value, `${filepath}: audience`, isAgentAudience);
138
+ if (source === "builtin") {
139
+ if (audience === "custom") {
140
+ throw new Error(`agent recipe: ${filepath}: a builtin recipe must not declare audience 'custom'`);
141
+ }
142
+ return audience;
143
+ }
144
+ if (audience !== "custom") {
145
+ throw new Error(
146
+ `agent recipe: ${filepath}: a ${source} recipe must declare audience 'custom', not '${audience}'; audience follows where the recipe was discovered and cannot be claimed in frontmatter`
147
+ );
148
+ }
149
+ return audience;
150
+ }
151
+ function parseTools(value, filepath) {
152
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
153
+ throw new Error(`agent recipe: ${filepath}: tools must be a { required, optional } object`);
154
+ }
155
+ const record = value;
156
+ if (Object.keys(record).some((key) => key !== "required" && key !== "optional")) {
157
+ throw new Error(`agent recipe: ${filepath}: tools has an unknown key`);
158
+ }
159
+ if (!("required" in record) || !("optional" in record)) {
160
+ throw new Error(`agent recipe: ${filepath}: tools.required and tools.optional are required`);
161
+ }
162
+ if (!Array.isArray(record.required) || !Array.isArray(record.optional)) {
163
+ throw new Error(`agent recipe: ${filepath}: tools.required and tools.optional must be arrays`);
164
+ }
165
+ const required = record.required.map((entry, index) => {
166
+ const entryPath = `${filepath}: tools.required[${index}]`;
167
+ if (typeof entry === "string") return requiredString(entry, entryPath);
168
+ if (entry === null || typeof entry !== "object" || Array.isArray(entry)) {
169
+ throw new Error(`agent recipe: ${entryPath} must be a tool name or { anyOf: [...] }`);
170
+ }
171
+ const group = entry;
172
+ if (Object.keys(group).length !== 1 || !("anyOf" in group)) {
173
+ throw new Error(`agent recipe: ${entryPath} must contain only anyOf`);
174
+ }
175
+ const anyOf = requiredStringArray(group.anyOf, `${entryPath}.anyOf`);
176
+ if (anyOf.length === 0) throw new Error(`agent recipe: ${entryPath}.anyOf must not be empty`);
177
+ return { anyOf };
178
+ });
179
+ const optional = requiredStringArray(record.optional, `${filepath}: tools.optional`);
180
+ const tools = [
181
+ ...required.flatMap((requirement) => typeof requirement === "string" ? [requirement] : requirement.anyOf),
182
+ ...optional
183
+ ];
184
+ if (new Set(tools).size !== tools.length)
185
+ throw new Error(`agent recipe: ${filepath}: tools contains duplicate requirements`);
186
+ return { tools, toolRequirements: { required, optional } };
187
+ }
188
+ function parseAgentRecipeSchema(input) {
189
+ const { frontmatter, filepath } = input;
190
+ for (const key of Object.keys(frontmatter)) {
191
+ if (!ALL_RECIPE_KEYS.includes(key)) {
192
+ throw new Error(`agent recipe: ${filepath}: unknown key '${key}'`);
193
+ }
194
+ }
195
+ for (const key of RECIPE_KEYS) {
196
+ if (!(key in frontmatter)) throw new Error(`agent recipe: ${filepath}: ${key} is required`);
197
+ }
198
+ if (frontmatter.version !== 1) throw new Error(`agent recipe: ${filepath}: version must be the supported integer 1`);
199
+ if (input.body.trim().length === 0) throw new Error(`agent recipe: ${filepath}: persona body must not be empty`);
200
+ const parsedTools = parseTools(frontmatter.tools, filepath);
201
+ const budget = parseAgentBudget(frontmatter.budget, filepath);
202
+ if (budget === void 0) throw new Error(`agent recipe: ${filepath}: budget is required`);
203
+ return {
204
+ version: 1,
205
+ id: input.id,
206
+ name: requiredString(frontmatter.name, `${filepath}: name`),
207
+ description: requiredString(frontmatter.description, `${filepath}: description`),
208
+ tools: parsedTools.tools,
209
+ toolRequirements: parsedTools.toolRequirements,
210
+ skills: requiredStringArray(frontmatter.skills, `${filepath}: skills`),
211
+ boundSkillPaths: [],
212
+ audience: parseAudience(frontmatter.audience, input.source, filepath),
213
+ category: enumValue(frontmatter.category, `${filepath}: category`, isAgentCategory),
214
+ capabilityClass: enumValue(
215
+ frontmatter.capabilityClass,
216
+ `${filepath}: capabilityClass`,
217
+ isAgentCapabilityClass
218
+ ),
219
+ latencyClass: enumValue(
220
+ frontmatter.latencyClass,
221
+ `${filepath}: latencyClass`,
222
+ isAgentLatencyClass
223
+ ),
224
+ projectContextTier: enumValue(
225
+ frontmatter.projectContextTier,
226
+ `${filepath}: projectContextTier`,
227
+ isAgentProjectContextTier
228
+ ),
229
+ budget,
230
+ resultContract: parseResultContract(frontmatter.resultContract, filepath),
231
+ // Optional, but not lenient. A misspelled product silently costs the run
232
+ // the delivery tools its reserve window was supposed to keep, and the
233
+ // only symptom is a blocked tool call deep in a dispatch log.
234
+ ...frontmatter.product === void 0 ? {} : { product: enumValue(frontmatter.product, `${filepath}: product`, isAgentProduct) },
235
+ tags: requiredStringArray(frontmatter.tags, `${filepath}: tags`),
236
+ source: input.source,
237
+ filepath,
238
+ body: input.body
239
+ };
240
+ }
241
+
242
+ // src/domains/agents/registry.ts
243
+ var RESERVED_CUSTOM_AGENT_IDS = /* @__PURE__ */ new Set(["worker", "delegate", "auto"]);
244
+ function resolveBoundSkills(recipe, source) {
245
+ if (recipe.skills.length === 0) return { ...recipe, boundSkillPaths: [] };
246
+ const packageSkills = path2.resolve(source.dir, "..", "..", "..", "..", "skills");
247
+ const skills = loadSkills({
248
+ cwd: process.cwd(),
249
+ ...source.source === "builtin" && existsSync(packageSkills) ? { explicitSkillPaths: [packageSkills] } : {}
250
+ });
251
+ const byName = new Map(skills.items.map((skill) => [skill.name, skill.filePath]));
252
+ const missing = recipe.skills.filter((skill) => !byName.has(skill));
253
+ if (missing.length > 0) {
254
+ throw new Error(`agent recipe: ${recipe.filepath}: bound skill(s) unavailable: ${missing.join(", ")}`);
255
+ }
256
+ const boundSkillPaths = recipe.skills.map((skill) => {
257
+ const filePath = byName.get(skill);
258
+ if (filePath === void 0) throw new Error(`agent recipe: ${recipe.filepath}: bound skill unavailable: ${skill}`);
259
+ return filePath;
260
+ });
261
+ return { ...recipe, boundSkillPaths };
262
+ }
263
+ function loadRecipesFromDir(source, diagnostics = []) {
264
+ let entries;
265
+ try {
266
+ entries = readdirSync(source.dir, { withFileTypes: true });
267
+ } catch (err) {
268
+ const error = err;
269
+ if (error.code === "ENOENT" || error.code === "ENOTDIR") return [];
270
+ throw err;
271
+ }
272
+ const recipes = [];
273
+ for (const entry of entries) {
274
+ if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
275
+ const filepath = path2.join(source.dir, entry.name);
276
+ try {
277
+ const id = recipeIdFromPath(filepath, source.dir);
278
+ const raw = readFileSync(filepath, "utf8");
279
+ const { frontmatter, body } = parseFrontmatter(raw, filepath);
280
+ const parsedRecipe = parseAgentRecipeSchema({ id, source: source.source, filepath, body, frontmatter });
281
+ const recipe = resolveBoundSkills(parsedRecipe, source);
282
+ assertAgentSpecPolicy(normalizeAgentSpec(recipe));
283
+ recipes.push(recipe);
284
+ } catch (error) {
285
+ if (source.source === "builtin") throw error;
286
+ const message = error instanceof Error ? error.message : String(error);
287
+ diagnostics.push({ source: source.source, filepath, message });
288
+ process.stderr.write(`[clio:agents] quarantine path=${filepath} source=${source.source} reason=${message}
289
+ `);
290
+ }
291
+ }
292
+ recipes.sort((left, right) => left.id.localeCompare(right.id));
293
+ return recipes;
294
+ }
295
+ function mergeRecipes(...sources) {
296
+ const byId = /* @__PURE__ */ new Map();
297
+ const builtinById = /* @__PURE__ */ new Map();
298
+ for (const group of sources) {
299
+ for (const recipe of group) {
300
+ if (recipe.source === "builtin") builtinById.set(recipe.id, recipe);
301
+ }
302
+ }
303
+ for (const group of sources) {
304
+ for (const recipe of group) {
305
+ if (recipe.source !== "builtin" && RESERVED_CUSTOM_AGENT_IDS.has(recipe.id)) {
306
+ process.stderr.write(`[clio:agents] ignore id=${recipe.id} by=${recipe.source} reason=reserved-agent-id
307
+ `);
308
+ continue;
309
+ }
310
+ const builtin = builtinById.get(recipe.id);
311
+ if (recipe.source === "user" && builtin && isShadowAgent(normalizeAgentSpec(builtin))) {
312
+ process.stderr.write(`[clio:agents] ignore override id=${recipe.id} by=user reason=reserved-shadow
313
+ `);
314
+ continue;
315
+ }
316
+ if (recipe.source === "project" && builtin) {
317
+ process.stderr.write(`[clio:agents] ignore override id=${recipe.id} by=project reason=reserved-builtin
318
+ `);
319
+ continue;
320
+ }
321
+ if (byId.has(recipe.id)) process.stderr.write(`[clio:agents] override id=${recipe.id} by=${recipe.source}
322
+ `);
323
+ byId.set(recipe.id, recipe);
324
+ }
325
+ }
326
+ return Array.from(byId.values()).sort((left, right) => left.id.localeCompare(right.id));
327
+ }
328
+
329
+ // src/domains/agents/extension.ts
330
+ function createAgentsBundle(_context) {
331
+ let recipes = [];
332
+ let specs = [];
333
+ let diagnostics = [];
334
+ function discover() {
335
+ const builtinDir = path3.join(resolvePackageRoot(), "src", "domains", "agents", "builtins");
336
+ const userDir = path3.join(clioConfigDir(), "agents");
337
+ const projectDir = path3.join(process.cwd(), ".clio-coder", "agents");
338
+ const nextDiagnostics = [];
339
+ const builtin = loadRecipesFromDir({ dir: builtinDir, source: "builtin" }, nextDiagnostics);
340
+ const user = loadRecipesFromDir({ dir: userDir, source: "user" }, nextDiagnostics);
341
+ const project = loadRecipesFromDir({ dir: projectDir, source: "project" }, nextDiagnostics);
342
+ const merged = mergeRecipes(builtin, user, project);
343
+ const config = _context.getContract("config");
344
+ assertAgentIdNamespace(merged, config?.get()?.delegation?.agents ?? []);
345
+ recipes = merged;
346
+ specs = recipes.map(normalizeAgentSpec);
347
+ diagnostics = nextDiagnostics;
348
+ }
349
+ const extension = {
350
+ async start() {
351
+ discover();
352
+ },
353
+ async stop() {
354
+ }
355
+ };
356
+ const contract = {
357
+ list() {
358
+ return recipes;
359
+ },
360
+ get(id) {
361
+ return recipes.find((r) => r.id === id) ?? null;
362
+ },
363
+ diagnostics() {
364
+ return diagnostics.map((diagnostic) => ({ ...diagnostic }));
365
+ },
366
+ listSpecs() {
367
+ const config = _context.getContract("config");
368
+ const delegationAgents = config?.get()?.delegation?.agents ?? [];
369
+ const delegationSpecs = delegationAgents.map((agent) => ({
370
+ version: 1,
371
+ id: agent.id,
372
+ name: agent.id,
373
+ description: `External ACP delegation agent: ${agent.command} ${(agent.args ?? []).join(" ")}`,
374
+ source: "custom",
375
+ filepath: "settings.yaml",
376
+ tools: [],
377
+ toolRequirements: { required: [], optional: [] },
378
+ category: "explore",
379
+ capabilityClass: "orchestration",
380
+ latencyClass: "deep",
381
+ projectContextTier: "none",
382
+ audience: "custom",
383
+ tags: ["delegation", "acp"],
384
+ skills: [],
385
+ resultContract: { kind: "external-delegation" },
386
+ budget: { toolCalls: 1, readReserve: 0, synthesis: false },
387
+ body: "External ACP delegation."
388
+ }));
389
+ return [...specs, ...delegationSpecs];
390
+ },
391
+ getSpec(id) {
392
+ const found = specs.find((r) => r.id === id);
393
+ if (found) return found;
394
+ const config = _context.getContract("config");
395
+ const agent = config?.get()?.delegation?.agents?.find((entry) => entry.id === id);
396
+ if (agent) {
397
+ return {
398
+ version: 1,
399
+ id: agent.id,
400
+ name: agent.id,
401
+ description: `External ACP delegation agent: ${agent.command} ${(agent.args ?? []).join(" ")}`,
402
+ source: "custom",
403
+ filepath: "settings.yaml",
404
+ tools: [],
405
+ toolRequirements: { required: [], optional: [] },
406
+ category: "explore",
407
+ capabilityClass: "orchestration",
408
+ latencyClass: "deep",
409
+ projectContextTier: "none",
410
+ audience: "custom",
411
+ tags: ["delegation", "acp"],
412
+ skills: [],
413
+ resultContract: { kind: "external-delegation" },
414
+ budget: { toolCalls: 1, readReserve: 0, synthesis: false },
415
+ body: "External ACP delegation."
416
+ };
417
+ }
418
+ return null;
419
+ },
420
+ reload() {
421
+ discover();
422
+ }
423
+ };
424
+ return { extension, contract };
425
+ }
426
+
427
+ // src/domains/agents/manifest.ts
428
+ var AgentsManifest = {
429
+ name: "agents",
430
+ dependsOn: ["config"]
431
+ };
432
+
433
+ // src/domains/agents/index.ts
434
+ var AgentsDomainModule = {
435
+ manifest: AgentsManifest,
436
+ createExtension: createAgentsBundle
437
+ };
438
+
439
+ // src/domains/safety/audit.ts
440
+ import { randomBytes } from "node:crypto";
441
+ import { closeSync, fsyncSync, mkdirSync, openSync, writeSync } from "node:fs";
442
+ import { join } from "node:path";
443
+ var REDACT_KEY_RE = /(password|token|secret|key|auth|credential)/i;
444
+ var MAX_STRING_LEN = 200;
445
+ function localDateString(d) {
446
+ const fmt = new Intl.DateTimeFormat("en-CA", {
447
+ year: "numeric",
448
+ month: "2-digit",
449
+ day: "2-digit"
450
+ });
451
+ return fmt.format(d);
452
+ }
453
+ function newCorrelationId() {
454
+ const n = BigInt(`0x${randomBytes(8).toString("hex")}`);
455
+ const raw = n.toString(36);
456
+ if (raw.length >= 12) return raw.slice(0, 12);
457
+ return raw.padStart(12, "0");
458
+ }
459
+ function redactString(s) {
460
+ if (s.length <= MAX_STRING_LEN) return s;
461
+ const truncated = s.length - MAX_STRING_LEN;
462
+ return `${s.slice(0, MAX_STRING_LEN)}\u2026 [truncated ${truncated} chars]`;
463
+ }
464
+ function redactArgs(value, depth = 0) {
465
+ if (depth > 8) return "[redacted:depth]";
466
+ if (value == null) return value;
467
+ if (typeof value === "string") return redactString(value);
468
+ if (typeof value === "number" || typeof value === "boolean") return value;
469
+ if (Array.isArray(value)) return value.map((item) => redactArgs(item, depth + 1));
470
+ if (typeof value === "object") {
471
+ const out = {};
472
+ for (const [k, v] of Object.entries(value)) {
473
+ if (REDACT_KEY_RE.test(k)) {
474
+ out[k] = "[redacted]";
475
+ continue;
476
+ }
477
+ out[k] = redactArgs(v, depth + 1);
478
+ }
479
+ return out;
480
+ }
481
+ return String(value);
482
+ }
483
+ function buildAuditRecord(input) {
484
+ const now = input.now ?? /* @__PURE__ */ new Date();
485
+ const record = {
486
+ kind: "tool_call",
487
+ ts: now.toISOString(),
488
+ correlationId: newCorrelationId(),
489
+ tool: input.tool,
490
+ actionClass: input.classification.actionClass,
491
+ decision: input.decision,
492
+ reasons: input.reasons ?? input.policy?.reasons ?? input.classification.reasons
493
+ };
494
+ if (input.requestId !== void 0) record.requestId = input.requestId;
495
+ if (input.posture !== void 0) record.posture = input.posture;
496
+ if (input.policy?.ruleId !== void 0) record.ruleId = input.policy.ruleId;
497
+ const reasonCode = input.reasonCode ?? input.policy?.reasonCode;
498
+ if (reasonCode !== void 0) record.reasonCode = reasonCode;
499
+ if (input.policy?.policySource !== void 0) record.policySource = input.policy.policySource;
500
+ if (input.policy?.policyHash !== void 0) record.policyHash = input.policy.policyHash;
501
+ if (input.policy?.command !== void 0) record.command = redactString(input.policy.command);
502
+ if (input.policy?.cwd !== void 0) record.cwd = input.policy.cwd;
503
+ if (input.args !== void 0) record.args = redactArgs(input.args);
504
+ return record;
505
+ }
506
+ function buildAbortAuditRecord(input) {
507
+ const now = input.now ?? /* @__PURE__ */ new Date();
508
+ const record = {
509
+ kind: "abort",
510
+ ts: now.toISOString(),
511
+ correlationId: newCorrelationId(),
512
+ source: input.source,
513
+ runId: input.runId,
514
+ startedAt: input.startedAt,
515
+ elapsedMs: input.elapsedMs
516
+ };
517
+ if (input.reason !== void 0) record.reason = input.reason;
518
+ return record;
519
+ }
520
+ function buildSessionParkAuditRecord(input) {
521
+ const now = input.now ?? /* @__PURE__ */ new Date();
522
+ return {
523
+ kind: "session_park",
524
+ ts: now.toISOString(),
525
+ correlationId: newCorrelationId(),
526
+ sessionId: input.sessionId,
527
+ reason: input.reason
528
+ };
529
+ }
530
+ function buildSessionResumeAuditRecord(input) {
531
+ const now = input.now ?? /* @__PURE__ */ new Date();
532
+ return {
533
+ kind: "session_resume",
534
+ ts: now.toISOString(),
535
+ correlationId: newCorrelationId(),
536
+ sessionId: input.sessionId,
537
+ via: input.via
538
+ };
539
+ }
540
+ function buildPermissionAuditRecord(input) {
541
+ const now = input.now ?? /* @__PURE__ */ new Date();
542
+ const record = {
543
+ kind: "permission",
544
+ ts: now.toISOString(),
545
+ correlationId: newCorrelationId(),
546
+ status: input.status
547
+ };
548
+ if (input.tool !== void 0) record.tool = input.tool;
549
+ if (input.requestId !== void 0) record.requestId = input.requestId;
550
+ if (input.origin !== void 0) record.origin = input.origin;
551
+ if (input.decidedBy !== void 0) record.decidedBy = input.decidedBy;
552
+ if (input.actionClass !== void 0) record.actionClass = input.actionClass;
553
+ if (input.reason !== void 0) record.reason = input.reason;
554
+ if (input.requestedBy !== void 0) record.requestedBy = input.requestedBy;
555
+ return record;
556
+ }
557
+ function buildAgentStatusChangeAuditRecord(input) {
558
+ const now = input.now ?? /* @__PURE__ */ new Date();
559
+ const record = {
560
+ kind: "agent_status_change",
561
+ ts: now.toISOString(),
562
+ correlationId: newCorrelationId(),
563
+ runId: input.runId,
564
+ phase: input.phase,
565
+ prevPhase: input.prevPhase,
566
+ elapsedFromStart: Math.max(0, Math.floor(input.elapsedFromStart)),
567
+ watchdogTier: Math.max(0, Math.floor(input.watchdogTier))
568
+ };
569
+ if (input.metadata !== void 0) record.metadata = redactArgs(input.metadata);
570
+ return record;
571
+ }
572
+ function buildCompletionContractAuditRecord(input) {
573
+ const now = input.now ?? /* @__PURE__ */ new Date();
574
+ const record = {
575
+ kind: "completion_contract",
576
+ ts: now.toISOString(),
577
+ correlationId: newCorrelationId(),
578
+ turnId: input.turnId,
579
+ decision: input.decision,
580
+ reason: input.reason,
581
+ rigor: input.rigor,
582
+ mutatedPaths: input.mutatedPaths.map((path4) => redactString(path4)),
583
+ evidenceKinds: [...input.evidenceKinds]
584
+ };
585
+ if (input.runId !== void 0) record.runId = input.runId;
586
+ if (input.sessionId !== void 0) record.sessionId = input.sessionId;
587
+ return record;
588
+ }
589
+ function logAuditError(err, path4) {
590
+ const msg = err instanceof Error ? err.message : String(err);
591
+ const where = path4 ? ` (${path4})` : "";
592
+ process.stderr.write(`[clio:audit] ${msg}${where}
593
+ `);
594
+ }
595
+ var AUDIT_FLUSH_INTERVAL_MS = 5e3;
596
+ function openAuditWriter(opts) {
597
+ const dateFn = opts?.dateFn ?? (() => /* @__PURE__ */ new Date());
598
+ let current = null;
599
+ let closed = false;
600
+ let dirty = false;
601
+ function flushCurrent() {
602
+ if (current === null || !dirty) return;
603
+ try {
604
+ fsyncSync(current.fd);
605
+ dirty = false;
606
+ } catch (err) {
607
+ logAuditError(err, current.path);
608
+ }
609
+ }
610
+ const flushTimer = setInterval(flushCurrent, AUDIT_FLUSH_INTERVAL_MS);
611
+ flushTimer.unref();
612
+ function closeCurrent() {
613
+ if (current === null) return;
614
+ flushCurrent();
615
+ try {
616
+ closeSync(current.fd);
617
+ } catch (err) {
618
+ logAuditError(err, current.path);
619
+ }
620
+ current = null;
621
+ dirty = false;
622
+ }
623
+ function ensureFor(date) {
624
+ if (current !== null && current.date === date) return current;
625
+ if (current !== null) closeCurrent();
626
+ if (stateRootRemoved()) return null;
627
+ try {
628
+ const dir = join(clioStateDir(), "audit");
629
+ mkdirSync(dir, { recursive: true });
630
+ const filePath = join(dir, `${date}.jsonl`);
631
+ const fd = openSync(filePath, "a");
632
+ current = { fd, date, path: filePath };
633
+ return current;
634
+ } catch (err) {
635
+ logAuditError(err);
636
+ return null;
637
+ }
638
+ }
639
+ return {
640
+ write(record) {
641
+ if (closed) return;
642
+ try {
643
+ const date = localDateString(dateFn());
644
+ const handle = ensureFor(date);
645
+ if (handle === null) return;
646
+ const line = `${JSON.stringify(record)}
647
+ `;
648
+ writeSync(handle.fd, line);
649
+ dirty = true;
650
+ } catch (err) {
651
+ logAuditError(err, current?.path);
652
+ }
653
+ },
654
+ flush() {
655
+ flushCurrent();
656
+ },
657
+ async close() {
658
+ if (closed) return;
659
+ closed = true;
660
+ clearInterval(flushTimer);
661
+ closeCurrent();
662
+ }
663
+ };
664
+ }
665
+
666
+ // src/domains/safety/extension.ts
667
+ function isPermissionResolvedPayload(value) {
668
+ if (!value || typeof value !== "object") return false;
669
+ const p = value;
670
+ if (p.status !== "granted" && p.status !== "denied") return false;
671
+ if (p.tool !== void 0 && typeof p.tool !== "string") return false;
672
+ if (p.actionClass !== void 0 && typeof p.actionClass !== "string") return false;
673
+ if (p.reason !== void 0 && typeof p.reason !== "string") return false;
674
+ if (p.requestedBy !== void 0 && typeof p.requestedBy !== "string") return false;
675
+ if (p.requestId !== void 0 && typeof p.requestId !== "string") return false;
676
+ if (p.origin !== void 0 && typeof p.origin !== "string") return false;
677
+ if (p.decidedBy !== void 0 && typeof p.decidedBy !== "string") return false;
678
+ return true;
679
+ }
680
+ function isPermissionRequestedPayload(value) {
681
+ if (!value || typeof value !== "object") return false;
682
+ const p = value;
683
+ if (typeof p.tool !== "string" || p.tool.length === 0) return false;
684
+ if (typeof p.actionClass !== "string" || p.actionClass.length === 0) return false;
685
+ if (p.origin !== void 0 && typeof p.origin !== "string") return false;
686
+ if (p.requestId !== void 0 && typeof p.requestId !== "string") return false;
687
+ if (p.requestedBy !== void 0 && typeof p.requestedBy !== "string") return false;
688
+ if (p.summary !== void 0 && typeof p.summary !== "string") return false;
689
+ if (p.rejection !== void 0) {
690
+ const rejection = p.rejection;
691
+ if (!rejection || typeof rejection !== "object" || Array.isArray(rejection)) return false;
692
+ if (typeof rejection.short !== "string") return false;
693
+ }
694
+ return true;
695
+ }
696
+ var PARK_REASONS = /* @__PURE__ */ new Set([
697
+ "create_new",
698
+ "resume_other",
699
+ "fork",
700
+ "switch_branch",
701
+ "close",
702
+ "shutdown"
703
+ ]);
704
+ var RESUME_VIAS = /* @__PURE__ */ new Set(["resume", "switch_branch"]);
705
+ var MAX_REQUESTED_PERMISSION_AUDIT_IDS = 4096;
706
+ function isSessionParkedPayload(value) {
707
+ if (!value || typeof value !== "object") return false;
708
+ const p = value;
709
+ if (typeof p.sessionId !== "string") return false;
710
+ if (typeof p.reason !== "string" || !PARK_REASONS.has(p.reason)) return false;
711
+ return true;
712
+ }
713
+ function isSessionResumedPayload(value) {
714
+ if (!value || typeof value !== "object") return false;
715
+ const p = value;
716
+ if (typeof p.sessionId !== "string") return false;
717
+ if (typeof p.via !== "string" || !RESUME_VIAS.has(p.via)) return false;
718
+ return true;
719
+ }
720
+ function isAgentStatusChangedPayload(value) {
721
+ if (!value || typeof value !== "object") return false;
722
+ const p = value;
723
+ if (p.runId !== null && typeof p.runId !== "string") return false;
724
+ if (typeof p.phase !== "string" || typeof p.prevPhase !== "string") return false;
725
+ if (typeof p.elapsedFromStart !== "number" || !Number.isFinite(p.elapsedFromStart)) return false;
726
+ if (typeof p.watchdogTier !== "number" || !Number.isFinite(p.watchdogTier)) return false;
727
+ if (p.metadata !== void 0 && (!p.metadata || typeof p.metadata !== "object" || Array.isArray(p.metadata)))
728
+ return false;
729
+ return true;
730
+ }
731
+ function isAlarmableStatus(payload) {
732
+ if (payload.phase === "stuck" || payload.phase === "tool_blocked" || payload.phase === "retrying") return true;
733
+ return payload.phase === "ended" && payload.metadata?.reason === "cancelled";
734
+ }
735
+ function createSafetyBundle(context) {
736
+ let writer = null;
737
+ let policyEngine = null;
738
+ let loopState = createLoopState();
739
+ let recordCount = 0;
740
+ let unsubscribePermissionRequested = null;
741
+ let unsubscribePermissionResolved = null;
742
+ let unsubscribeRunAborted = null;
743
+ let unsubscribeSessionParked = null;
744
+ let unsubscribeSessionResumed = null;
745
+ let unsubscribeAgentStatusChanged = null;
746
+ let unsubscribeDispatchCompleted = null;
747
+ let unsubscribeDispatchFailed = null;
748
+ const recordedRequestedPermissionIds = /* @__PURE__ */ new Set();
749
+ function writeAudit(rec) {
750
+ if (writer === null) return;
751
+ writer.write(rec);
752
+ recordCount += 1;
753
+ }
754
+ function recordToolCallAudit(input) {
755
+ writeAudit(buildAuditRecord(input));
756
+ }
757
+ function recordCompletionContractAudit(input) {
758
+ writeAudit(buildCompletionContractAuditRecord(input));
759
+ }
760
+ const extension = {
761
+ async start() {
762
+ policyEngine = createSafetyPolicyEngine();
763
+ writer = openAuditWriter();
764
+ unsubscribePermissionRequested = context.bus.on(BusChannels.PermissionRequested, (payload) => {
765
+ if (!isPermissionRequestedPayload(payload)) return;
766
+ if (payload.origin === void 0 || payload.origin === "main") return;
767
+ if (payload.requestId === void 0) return;
768
+ if (recordedRequestedPermissionIds.has(payload.requestId)) return;
769
+ recordedRequestedPermissionIds.add(payload.requestId);
770
+ if (recordedRequestedPermissionIds.size > MAX_REQUESTED_PERMISSION_AUDIT_IDS) {
771
+ const oldest = recordedRequestedPermissionIds.values().next().value;
772
+ if (oldest !== void 0) recordedRequestedPermissionIds.delete(oldest);
773
+ }
774
+ const reason = payload.rejection?.short ?? payload.summary;
775
+ writeAudit(
776
+ buildPermissionAuditRecord({
777
+ status: "requested",
778
+ requestId: payload.requestId,
779
+ origin: payload.origin,
780
+ tool: payload.tool,
781
+ actionClass: payload.actionClass,
782
+ ...reason !== void 0 ? { reason } : {},
783
+ ...payload.requestedBy !== void 0 ? { requestedBy: payload.requestedBy } : {}
784
+ })
785
+ );
786
+ });
787
+ unsubscribePermissionResolved = context.bus.on(BusChannels.PermissionResolved, (payload) => {
788
+ if (!isPermissionResolvedPayload(payload)) return;
789
+ writeAudit(
790
+ buildPermissionAuditRecord({
791
+ status: payload.status,
792
+ ...payload.requestId !== void 0 ? { requestId: payload.requestId } : {},
793
+ ...payload.origin !== void 0 ? { origin: payload.origin } : {},
794
+ ...payload.decidedBy !== void 0 ? { decidedBy: payload.decidedBy } : {},
795
+ ...payload.tool !== void 0 ? { tool: payload.tool } : {},
796
+ ...payload.actionClass !== void 0 ? { actionClass: payload.actionClass } : {},
797
+ ...payload.reason !== void 0 ? { reason: payload.reason } : {},
798
+ ...payload.requestedBy !== void 0 ? { requestedBy: payload.requestedBy } : {}
799
+ })
800
+ );
801
+ });
802
+ unsubscribeRunAborted = context.bus.on(BusChannels.RunAborted, (payload) => {
803
+ if (!isRunAbortedPayload(payload)) return;
804
+ const recordInput = {
805
+ source: payload.source,
806
+ runId: payload.runId,
807
+ startedAt: payload.startedAt,
808
+ elapsedMs: payload.elapsedMs
809
+ };
810
+ if (payload.reason !== void 0) recordInput.reason = payload.reason;
811
+ writeAudit(buildAbortAuditRecord(recordInput));
812
+ });
813
+ unsubscribeSessionParked = context.bus.on(BusChannels.SessionParked, (payload) => {
814
+ if (!isSessionParkedPayload(payload)) return;
815
+ writeAudit(buildSessionParkAuditRecord({ sessionId: payload.sessionId, reason: payload.reason }));
816
+ });
817
+ unsubscribeSessionResumed = context.bus.on(BusChannels.SessionResumed, (payload) => {
818
+ if (!isSessionResumedPayload(payload)) return;
819
+ writeAudit(buildSessionResumeAuditRecord({ sessionId: payload.sessionId, via: payload.via }));
820
+ });
821
+ unsubscribeAgentStatusChanged = context.bus.on(BusChannels.AgentStatusChanged, (payload) => {
822
+ if (!isAgentStatusChangedPayload(payload) || !isAlarmableStatus(payload)) return;
823
+ writeAudit(
824
+ buildAgentStatusChangeAuditRecord({
825
+ runId: payload.runId,
826
+ phase: payload.phase,
827
+ prevPhase: payload.prevPhase,
828
+ elapsedFromStart: payload.elapsedFromStart,
829
+ watchdogTier: payload.watchdogTier,
830
+ ...payload.metadata ? { metadata: payload.metadata } : {}
831
+ })
832
+ );
833
+ });
834
+ const auditDispatchTerminal = (raw) => {
835
+ if (!raw || typeof raw !== "object") return;
836
+ const payload = raw;
837
+ if (typeof payload.runId !== "string" || typeof payload.outcome !== "string") return;
838
+ const lineage = payload.lineage && typeof payload.lineage === "object" && !Array.isArray(payload.lineage) ? payload.lineage : null;
839
+ const durationMs = typeof payload.durationMs === "number" ? payload.durationMs : 0;
840
+ writeAudit(
841
+ buildAgentStatusChangeAuditRecord({
842
+ runId: payload.runId,
843
+ phase: payload.outcome,
844
+ prevPhase: "running",
845
+ elapsedFromStart: durationMs,
846
+ watchdogTier: 0,
847
+ metadata: {
848
+ outcome: payload.outcome,
849
+ ...payload.outcomeDetail !== void 0 && payload.outcomeDetail !== null ? { outcomeDetail: payload.outcomeDetail } : {},
850
+ ...typeof payload.agentId === "string" ? { agentId: payload.agentId } : {},
851
+ ...lineage !== null ? {
852
+ parentRunId: lineage.parentRunId ?? null,
853
+ rootRunId: lineage.rootRunId ?? null,
854
+ attempt: lineage.attempt ?? 0,
855
+ depth: lineage.depth ?? 0
856
+ } : {}
857
+ }
858
+ })
859
+ );
860
+ };
861
+ unsubscribeDispatchCompleted = context.bus.on(BusChannels.DispatchCompleted, auditDispatchTerminal);
862
+ unsubscribeDispatchFailed = context.bus.on(BusChannels.DispatchFailed, auditDispatchTerminal);
863
+ },
864
+ async stop() {
865
+ unsubscribePermissionRequested?.();
866
+ unsubscribePermissionRequested = null;
867
+ unsubscribePermissionResolved?.();
868
+ unsubscribePermissionResolved = null;
869
+ unsubscribeRunAborted?.();
870
+ unsubscribeRunAborted = null;
871
+ unsubscribeSessionParked?.();
872
+ unsubscribeSessionParked = null;
873
+ unsubscribeSessionResumed?.();
874
+ unsubscribeSessionResumed = null;
875
+ unsubscribeAgentStatusChanged?.();
876
+ unsubscribeAgentStatusChanged = null;
877
+ unsubscribeDispatchCompleted?.();
878
+ unsubscribeDispatchCompleted = null;
879
+ unsubscribeDispatchFailed?.();
880
+ unsubscribeDispatchFailed = null;
881
+ recordedRequestedPermissionIds.clear();
882
+ await writer?.close();
883
+ writer = null;
884
+ }
885
+ };
886
+ const contract = {
887
+ classify(call) {
888
+ return classify(call);
889
+ },
890
+ evaluate(call, posture) {
891
+ const policy = (policyEngine ?? createSafetyPolicyEngine()).evaluate(call, posture);
892
+ const classification = policy.classification;
893
+ context.bus.emit(BusChannels.SafetyClassified, {
894
+ tool: call.tool,
895
+ actionClass: classification.actionClass,
896
+ reasons: classification.reasons,
897
+ ruleId: policy.ruleId,
898
+ posture,
899
+ policySource: policy.policySource,
900
+ reasonCode: policy.reasonCode
901
+ });
902
+ if (policy.kind === "block") {
903
+ const auditInput2 = {
904
+ tool: call.tool,
905
+ classification,
906
+ decision: "blocked",
907
+ args: call.args,
908
+ policy
909
+ };
910
+ if (posture !== void 0) auditInput2.posture = posture;
911
+ recordToolCallAudit(auditInput2);
912
+ context.bus.emit(BusChannels.SafetyBlocked, {
913
+ tool: call.tool,
914
+ actionClass: classification.actionClass,
915
+ ruleId: policy.ruleId,
916
+ posture,
917
+ rejection: policy.rejection,
918
+ policySource: policy.policySource,
919
+ reasonCode: policy.reasonCode
920
+ });
921
+ const decision = {
922
+ kind: "block",
923
+ classification,
924
+ rejection: policy.rejection ?? fallbackRejection(policy),
925
+ policy
926
+ };
927
+ if (policy.match) decision.match = policy.match;
928
+ return decision;
929
+ }
930
+ if (policy.kind === "ask") {
931
+ const auditInput2 = {
932
+ tool: call.tool,
933
+ classification,
934
+ decision: "classified",
935
+ args: call.args,
936
+ policy
937
+ };
938
+ if (posture !== void 0) auditInput2.posture = posture;
939
+ recordToolCallAudit(auditInput2);
940
+ const decision = {
941
+ kind: "ask",
942
+ classification,
943
+ rejection: policy.rejection ?? fallbackRejection(policy),
944
+ policy
945
+ };
946
+ if (policy.match) decision.match = policy.match;
947
+ return decision;
948
+ }
949
+ const auditInput = {
950
+ tool: call.tool,
951
+ classification,
952
+ // Non-confirmed net passes are not final: registry admission still
953
+ // applies autonomy and writes the resolved allowed/park/denied row.
954
+ decision: posture === "confirmed" ? "allowed" : "classified",
955
+ args: call.args,
956
+ policy
957
+ };
958
+ if (posture !== void 0) auditInput.posture = posture;
959
+ recordToolCallAudit(auditInput);
960
+ context.bus.emit(BusChannels.SafetyAllowed, {
961
+ tool: call.tool,
962
+ actionClass: classification.actionClass,
963
+ posture,
964
+ ruleId: policy.ruleId,
965
+ policySource: policy.policySource,
966
+ reasonCode: policy.reasonCode
967
+ });
968
+ return { kind: "allow", classification, policy };
969
+ },
970
+ observeLoop(key, now) {
971
+ const [next, verdict] = observe(loopState, key, now ?? Date.now());
972
+ loopState = next;
973
+ return verdict;
974
+ },
975
+ scopes: { readonly: READONLY_SCOPE, workspace: WORKSPACE_SCOPE, confirmed: CONFIRMED_SCOPE },
976
+ isSubset,
977
+ policy: { metadata: (posture) => (policyEngine ?? createSafetyPolicyEngine()).metadata(posture) },
978
+ audit: {
979
+ recordCount: () => recordCount,
980
+ recordToolCall: recordToolCallAudit,
981
+ recordCompletionContract: recordCompletionContractAudit
982
+ }
983
+ };
984
+ return { extension, contract };
985
+ }
986
+ function fallbackRejection(policy) {
987
+ return {
988
+ short: `${policy.tool} blocked: ${policy.actionClass}`,
989
+ detail: policy.reasons.join("\n"),
990
+ hints: []
991
+ };
992
+ }
993
+
994
+ // src/domains/safety/manifest.ts
995
+ var SafetyManifest = {
996
+ name: "safety",
997
+ dependsOn: ["config"]
998
+ };
999
+
1000
+ // src/domains/safety/index.ts
1001
+ var SafetyDomainModule = {
1002
+ manifest: SafetyManifest,
1003
+ createExtension: createSafetyBundle
1004
+ };
1005
+
1006
+ export {
1007
+ AgentsDomainModule,
1008
+ SafetyDomainModule
1009
+ };
1010
+ //# sourceMappingURL=chunk-JPOWPFCU.js.map