@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,1739 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ createEngineAgent,
4
+ createLoopGuardRegistration,
5
+ createProtectedArtifactsRegistration,
6
+ describeCallTarget,
7
+ isLoopGuardSynthesisBackstopReason,
8
+ isReserveAdmittedTool,
9
+ patchWorkerRequestPayload,
10
+ resolveDeliveryTools,
11
+ sanitizeLockedSynthesisMessage,
12
+ workerLoopBlockBudget
13
+ } from "../chunk-BYEU76JP.js";
14
+ import {
15
+ DEFAULT_ESCALATION_FALLBACK,
16
+ DEFAULT_ESCALATION_TIMEOUT_MS,
17
+ WORKER_EXIT_PERMISSION_REQUIRED,
18
+ agentSkillToolPolicy,
19
+ attestedToolSignature,
20
+ claudeToolsOutsideProfile,
21
+ coerceToolInput,
22
+ createMiddlewareToolChoiceControl,
23
+ createRunEffectsRecorder,
24
+ createWorkerSafety,
25
+ createWorkerToolRegistry,
26
+ emitClaudeToolPermissionDecision,
27
+ isClaudeCodeSessionId,
28
+ parseWorkerSpec,
29
+ resolveAgentTools,
30
+ runtimeSpeaksResponseSchemaDialect,
31
+ shouldRequestStalledTurnContinuation,
32
+ startAntigravityWorkerRun,
33
+ startClaudeCodeWorkerRun,
34
+ validateRehydratedWorkerRuntime
35
+ } from "../chunk-GNGDQYDU.js";
36
+ import "../chunk-2J63S4SF.js";
37
+ import "../chunk-RQDWMVRB.js";
38
+ import "../chunk-7BHLZB3A.js";
39
+ import "../chunk-TPOCL34A.js";
40
+ import "../chunk-E3NYWENM.js";
41
+ import {
42
+ RESULT_CONTRACT_REPAIR_LIMIT,
43
+ parseResultContract,
44
+ resultContractRepairMessage,
45
+ validateResultContract
46
+ } from "../chunk-XV4ZJ6ZM.js";
47
+ import "../chunk-26BZQOAD.js";
48
+ import "../chunk-WD6AJM35.js";
49
+ import {
50
+ ToolNames
51
+ } from "../chunk-QV47YRF4.js";
52
+ import "../chunk-CLJ5HLUD.js";
53
+ import {
54
+ UNKNOWN_RESOURCE,
55
+ WORKER_PROTOCOL_VERSION,
56
+ WORKER_RESOURCE_LABEL_MAX,
57
+ WORKER_STDIN_FRAME_MAX_BYTES,
58
+ encodeControlFrame,
59
+ endpointIdentityHash,
60
+ knownResource,
61
+ parseAgentLedgerBody,
62
+ parseAgentLedgerEntry,
63
+ withinFrameBudget,
64
+ workerSpecDigest
65
+ } from "../chunk-BBUH4VAA.js";
66
+ import "../chunk-GOTUR54M.js";
67
+ import {
68
+ FileKnowledgeBase,
69
+ applyModelCapabilityPatch,
70
+ disposeLmStudioClients,
71
+ getRuntimeRegistry,
72
+ loadPluginRuntimes,
73
+ registerBuiltinRuntimes,
74
+ registerClioApiProviders,
75
+ registerFauxFromEnv,
76
+ resolveModelRuntimeCapabilitiesForModel,
77
+ resolveProviderKnowledgeBaseRoots,
78
+ setGlobalDefaultMaxOutputTokens,
79
+ setProtectedModelsProvider,
80
+ setResidencyNoticeSink
81
+ } from "../chunk-TKHQ4DGZ.js";
82
+ import "../chunk-D5YD55AR.js";
83
+ import {
84
+ readSettings,
85
+ validateSettingsFile
86
+ } from "../chunk-JWHCJDCI.js";
87
+ import {
88
+ configureGuardrails,
89
+ isWorkerToolCallCapExceededReason,
90
+ isWorkerToolCallCapSynthesisReason
91
+ } from "../chunk-UHTSULZS.js";
92
+ import "../chunk-5LDRNKX2.js";
93
+ import "../chunk-UGYAX5YI.js";
94
+ import "../chunk-5N2FG33Q.js";
95
+ import "../chunk-VPAWTYLY.js";
96
+ import "../chunk-X3NE4WVW.js";
97
+ import {
98
+ readClioVersion
99
+ } from "../chunk-DXQNI4PC.js";
100
+
101
+ // src/engine/worker-runtime.ts
102
+ import { existsSync, readFileSync } from "node:fs";
103
+ import path from "node:path";
104
+
105
+ // src/engine/claude/sdk-runtime.ts
106
+ import {
107
+ query
108
+ } from "@anthropic-ai/claude-agent-sdk";
109
+ var DEFAULT_CLAUDE_TOOLS = { type: "preset", preset: "claude_code" };
110
+ function sdkUserTextMessage(text, shouldQuery) {
111
+ return {
112
+ type: "user",
113
+ message: { role: "user", content: [{ type: "text", text }] },
114
+ parent_tool_use_id: null,
115
+ shouldQuery,
116
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
117
+ };
118
+ }
119
+ function buildClaudeSdkPrompt(input) {
120
+ const parts = (input.dynamicPromptMessages ?? []).map((message) => message.body.trim()).filter(Boolean);
121
+ parts.push(input.task);
122
+ return parts.join("\n\n");
123
+ }
124
+ async function* oneSdkUserMessage(message) {
125
+ yield message;
126
+ }
127
+ function claudeSdkPermissionModeForAutonomy(_level) {
128
+ return "default";
129
+ }
130
+ function claudeSdkToolsForAutonomy(_level) {
131
+ return DEFAULT_CLAUDE_TOOLS;
132
+ }
133
+ function effortForThinking(level) {
134
+ switch (level) {
135
+ case "minimal":
136
+ case "low":
137
+ return "low";
138
+ case "medium":
139
+ return "medium";
140
+ case "high":
141
+ return "high";
142
+ case "xhigh":
143
+ return "xhigh";
144
+ default:
145
+ return void 0;
146
+ }
147
+ }
148
+ function thinkingForInput(input) {
149
+ const level = input.runtimeResolution?.effectiveThinkingLevel ?? input.thinkingLevel ?? "off";
150
+ if (level === "off") return { type: "disabled" };
151
+ const budgetTokens = input.runtimeResolution?.request.budgetTokens;
152
+ if (typeof budgetTokens === "number" && Number.isFinite(budgetTokens) && budgetTokens > 0) {
153
+ return { type: "enabled", budgetTokens, display: "summarized" };
154
+ }
155
+ return { type: "adaptive", display: "summarized" };
156
+ }
157
+ function systemPromptForInput(input) {
158
+ const append = input.systemPrompt.trim();
159
+ if (append.length === 0) return { type: "preset", preset: "claude_code" };
160
+ return { type: "preset", preset: "claude_code", append };
161
+ }
162
+ function finite(value) {
163
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
164
+ }
165
+ function nestedRecord(record, key) {
166
+ const value = record[key];
167
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
168
+ }
169
+ function normalizeUsage(raw, totalCostUsd = 0) {
170
+ const record = typeof raw === "object" && raw !== null ? raw : {};
171
+ const cacheCreation = finite(record.cache_creation_input_tokens) + finite(record.cacheCreationInputTokens) + finite(record.cacheWrite) + finite(record.cacheWriteTokens);
172
+ const cacheRead = finite(record.cache_read_input_tokens) + finite(record.cacheReadInputTokens) + finite(record.cacheRead) + finite(record.cacheReadTokens);
173
+ const input = finite(record.input_tokens) + finite(record.inputTokens) + finite(record.input) + finite(record.prompt_tokens) + finite(record.promptTokens);
174
+ const output = finite(record.output_tokens) + finite(record.outputTokens) + finite(record.output) + finite(record.completion_tokens) + finite(record.completionTokens);
175
+ const totalTokens = input + output + cacheRead + cacheCreation;
176
+ const cost = finite(totalCostUsd) + finite(record.costUSD) + finite(record.cost_usd);
177
+ return {
178
+ input,
179
+ output,
180
+ cacheRead,
181
+ cacheWrite: cacheCreation,
182
+ totalTokens,
183
+ cost: {
184
+ input: 0,
185
+ output: 0,
186
+ cacheRead: 0,
187
+ cacheWrite: 0,
188
+ total: cost
189
+ }
190
+ };
191
+ }
192
+ function textFromUnknownBlock(block) {
193
+ if (typeof block !== "object" || block === null) return "";
194
+ const record = block;
195
+ if (record.type === "text" && typeof record.text === "string") return record.text;
196
+ if (record.type === "thinking" && typeof record.thinking === "string") return "";
197
+ return "";
198
+ }
199
+ function thinkingFromUnknownBlock(block) {
200
+ if (typeof block !== "object" || block === null) return "";
201
+ const record = block;
202
+ if (record.type === "thinking" && typeof record.thinking === "string") return record.thinking;
203
+ return "";
204
+ }
205
+ function contentFromSdkMessage(message) {
206
+ const content = [];
207
+ const record = typeof message === "object" && message !== null ? message : {};
208
+ const blocks = Array.isArray(record.content) ? record.content : [];
209
+ for (const block of blocks) {
210
+ const text = textFromUnknownBlock(block);
211
+ if (text.length > 0) {
212
+ content.push({ type: "text", text });
213
+ continue;
214
+ }
215
+ const thinking = thinkingFromUnknownBlock(block);
216
+ if (thinking.length > 0) {
217
+ content.push({ type: "thinking", thinking });
218
+ continue;
219
+ }
220
+ if (typeof block === "object" && block !== null) {
221
+ const tool = block;
222
+ if (tool.type === "tool_use" && typeof tool.name === "string" && typeof tool.id === "string") {
223
+ content.push({
224
+ type: "toolCall",
225
+ id: tool.id,
226
+ name: tool.name,
227
+ arguments: nestedRecord(tool, "input") ?? {}
228
+ });
229
+ }
230
+ }
231
+ }
232
+ if (content.length === 0) content.push({ type: "text", text: "" });
233
+ return {
234
+ role: "assistant",
235
+ content,
236
+ api: "claude-agent-sdk",
237
+ provider: "anthropic",
238
+ model: "",
239
+ usage: normalizeUsage(null),
240
+ stopReason: "stop",
241
+ timestamp: Date.now()
242
+ };
243
+ }
244
+ function extractAssistantText(message) {
245
+ if (message.type !== "assistant") return "";
246
+ const record = message;
247
+ const assistant = contentFromSdkMessage(record.message);
248
+ return assistant.content.map((block) => block.type === "text" ? block.text : "").filter(Boolean).join("");
249
+ }
250
+ function extractStreamDelta(message) {
251
+ if (message.type !== "stream_event") return "";
252
+ const event = message.event;
253
+ if (typeof event !== "object" || event === null) return "";
254
+ const record = event;
255
+ const delta = nestedRecord(record, "delta");
256
+ if (delta && typeof delta.text === "string") return delta.text;
257
+ if (delta && typeof delta.thinking === "string") return "";
258
+ const contentBlock = nestedRecord(record, "content_block");
259
+ if (contentBlock && contentBlock.type === "text" && typeof contentBlock.text === "string") return contentBlock.text;
260
+ return "";
261
+ }
262
+ function resultText(message) {
263
+ if (message?.subtype !== "success") return "";
264
+ return typeof message.result === "string" ? message.result : "";
265
+ }
266
+ function resultError(message) {
267
+ if (!message || message.subtype === "success") return "";
268
+ return Array.isArray(message.errors) ? message.errors.join("; ") : "Claude Agent SDK run failed";
269
+ }
270
+ function stopReasonFor(result, aborted) {
271
+ if (aborted) return "aborted";
272
+ if (!result) return "stop";
273
+ if (result.subtype !== "success") return "error";
274
+ if (result.stop_reason === "max_tokens") return "length";
275
+ return "stop";
276
+ }
277
+ function buildAssistantMessage(input) {
278
+ const usage = normalizeUsage(input.result?.usage, input.result?.total_cost_usd ?? 0);
279
+ const message = {
280
+ role: "assistant",
281
+ content: [{ type: "text", text: input.text }],
282
+ api: "claude-agent-sdk",
283
+ provider: "anthropic",
284
+ model: input.model,
285
+ usage,
286
+ stopReason: stopReasonFor(input.result, input.aborted),
287
+ timestamp: Date.now()
288
+ };
289
+ if (input.responseModel !== void 0) message.responseModel = input.responseModel;
290
+ if (input.responseId !== void 0) message.responseId = input.responseId;
291
+ if (input.errorMessage !== void 0 && input.errorMessage.length > 0) message.errorMessage = input.errorMessage;
292
+ return message;
293
+ }
294
+ function emitTextDelta(emit, state, delta) {
295
+ if (delta.length === 0) return;
296
+ state.text += delta;
297
+ const message = buildAssistantMessage({ model: state.model, text: state.text, result: null, aborted: false });
298
+ if (!state.started) {
299
+ state.started = true;
300
+ emit({ type: "message_start", message });
301
+ }
302
+ emit({
303
+ type: "message_update",
304
+ message,
305
+ assistantMessageEvent: {
306
+ type: "text_delta",
307
+ contentIndex: 0,
308
+ delta,
309
+ partial: message
310
+ }
311
+ });
312
+ }
313
+ function createClaudeWorkerBudgetGate(budget, onBoundary, onHardCap, deliveryTools = []) {
314
+ let attempts = 0;
315
+ let admitted = 0;
316
+ let locked = false;
317
+ const phaseDecision = (canonicalToolName) => {
318
+ const reserveAdmits = isReserveAdmittedTool(canonicalToolName, deliveryTools);
319
+ if (locked || admitted >= budget.toolCalls) {
320
+ if (deliveryTools.length > 0 && !locked) {
321
+ if (reserveAdmits) return { kind: "allow" };
322
+ return {
323
+ kind: "deny",
324
+ reason: `worker discovery budget reached (${budget.toolCalls}); only read and ${deliveryTools.join("/")} are admitted for the rest of this run`
325
+ };
326
+ }
327
+ return {
328
+ kind: "deny",
329
+ reason: budget.synthesis ? `worker agent budget reached (${budget.toolCalls}); tool calls are disabled for final synthesis` : `worker agent budget reached (${budget.toolCalls}); synthesis is disabled`
330
+ };
331
+ }
332
+ const reserveStart = budget.toolCalls - budget.readReserve;
333
+ if (budget.readReserve > 0 && admitted >= reserveStart && !reserveAdmits) {
334
+ const admittedNames = deliveryTools.length > 0 ? `read and ${deliveryTools.join("/")} are` : "only read is";
335
+ return {
336
+ kind: "deny",
337
+ reason: `worker read reserve: ${budget.toolCalls - admitted} admitted calls remain and ${admittedNames} allowed`
338
+ };
339
+ }
340
+ return { kind: "allow" };
341
+ };
342
+ return {
343
+ attempt(canonicalToolName) {
344
+ attempts += 1;
345
+ if (attempts > budget.hardCap) {
346
+ onHardCap();
347
+ return { kind: "deny", reason: `workerToolCallCap reached (${budget.hardCap}); abort run` };
348
+ }
349
+ return phaseDecision(canonicalToolName);
350
+ },
351
+ admit(canonicalToolName) {
352
+ const phase = phaseDecision(canonicalToolName);
353
+ if (phase.kind === "deny") return phase;
354
+ admitted += 1;
355
+ if (admitted >= budget.toolCalls && deliveryTools.length === 0) {
356
+ locked = true;
357
+ onBoundary();
358
+ }
359
+ return { kind: "allow" };
360
+ },
361
+ phaseReached: () => locked
362
+ };
363
+ }
364
+ function permissionResultForDecision(decision, toolUseID, input) {
365
+ if (decision.kind === "allow") {
366
+ const result2 = {
367
+ behavior: "allow",
368
+ decisionClassification: "user_temporary"
369
+ };
370
+ if (toolUseID !== void 0) result2.toolUseID = toolUseID;
371
+ return result2;
372
+ }
373
+ if (decision.permissionRequired && input.onPermission === "fail") {
374
+ input.onPermissionFailure();
375
+ }
376
+ const result = {
377
+ behavior: "deny",
378
+ message: decision.reason,
379
+ interrupt: decision.permissionRequired && input.onPermission === "fail",
380
+ decisionClassification: "user_reject"
381
+ };
382
+ if (toolUseID !== void 0) result.toolUseID = toolUseID;
383
+ return result;
384
+ }
385
+ function decideToolUse(input, toolName, toolInput) {
386
+ return emitClaudeToolPermissionDecision({
387
+ toolName,
388
+ input: coerceToolInput(toolInput),
389
+ safety: input.safety,
390
+ cwd: input.cwd,
391
+ ...input.autonomy !== void 0 ? { autonomy: input.autonomy } : {},
392
+ onPermission: input.onPermission,
393
+ emit: input.emit,
394
+ allowedTools: input.allowedTools,
395
+ ...input.budgetGate ? { budgetGate: input.budgetGate } : {}
396
+ });
397
+ }
398
+ function decideClaudeSdkToolUseOnce(handled, toolUseID, decide) {
399
+ const cached = toolUseID ? handled.get(toolUseID) : void 0;
400
+ if (cached) return cached;
401
+ const decision = decide();
402
+ if (toolUseID) handled.set(toolUseID, decision);
403
+ return decision;
404
+ }
405
+ function decideToolUseOnce(input, toolUseID, toolName, toolInput) {
406
+ return decideClaudeSdkToolUseOnce(
407
+ input.handledToolDecisions,
408
+ toolUseID,
409
+ () => decideToolUse(input, toolName, toolInput)
410
+ );
411
+ }
412
+ function buildCanUseTool(input) {
413
+ return async (toolName, toolInput, options) => {
414
+ const decision = decideToolUseOnce(input, options.toolUseID, toolName, toolInput);
415
+ return permissionResultForDecision(decision, options.toolUseID, input);
416
+ };
417
+ }
418
+ function buildPreToolUseHook(input) {
419
+ return async (hookInput, toolUseID) => {
420
+ if (hookInput.hook_event_name !== "PreToolUse") return { continue: true };
421
+ const id = hookInput.tool_use_id || toolUseID;
422
+ const decision = decideToolUseOnce(input, id, hookInput.tool_name, hookInput.tool_input);
423
+ if (decision.kind === "allow") {
424
+ return {
425
+ continue: true,
426
+ hookSpecificOutput: {
427
+ hookEventName: "PreToolUse",
428
+ permissionDecision: "allow",
429
+ permissionDecisionReason: decision.reason
430
+ }
431
+ };
432
+ }
433
+ if (decision.permissionRequired && input.onPermission === "fail") input.onPermissionFailure();
434
+ return {
435
+ continue: true,
436
+ hookSpecificOutput: {
437
+ hookEventName: "PreToolUse",
438
+ permissionDecision: "deny",
439
+ permissionDecisionReason: decision.reason
440
+ }
441
+ };
442
+ };
443
+ }
444
+ function startClaudeSdkWorkerRun(input, emit) {
445
+ const abortController = new AbortController();
446
+ let queryHandle = null;
447
+ let aborted = false;
448
+ let permissionFailure = false;
449
+ let budgetFailure = false;
450
+ const abort = () => {
451
+ aborted = true;
452
+ abortController.abort();
453
+ void queryHandle?.interrupt().catch(() => {
454
+ });
455
+ queryHandle?.close();
456
+ };
457
+ if (input.signal) {
458
+ if (input.signal.aborted) abort();
459
+ else input.signal.addEventListener("abort", abort, { once: true });
460
+ }
461
+ const safety = createWorkerSafety({
462
+ cwd: process.cwd(),
463
+ ...input.writeRoots !== void 0 ? { writeRoots: input.writeRoots } : {},
464
+ ...input.protectedArtifactState !== void 0 ? { protectedArtifactState: { artifacts: [...input.protectedArtifactState.artifacts] } } : {}
465
+ });
466
+ const onPermission = input.onPermission === "fail" ? "fail" : "deny";
467
+ const allowedToolSet = new Set(input.allowedTools);
468
+ const budgetGate = input.budget ? createClaudeWorkerBudgetGate(
469
+ input.budget,
470
+ () => {
471
+ },
472
+ () => {
473
+ budgetFailure = true;
474
+ emit({ type: "clio_run_outcome", payload: { outcomeCode: "worker_tool_call_cap_exhausted" } });
475
+ abort();
476
+ },
477
+ resolveDeliveryTools(allowedToolSet, input.product)
478
+ ) : void 0;
479
+ const permissionGate = {
480
+ safety,
481
+ cwd: process.cwd(),
482
+ ...input.autonomy !== void 0 ? { autonomy: input.autonomy } : {},
483
+ onPermission,
484
+ emit,
485
+ handledToolDecisions: /* @__PURE__ */ new Map(),
486
+ onPermissionFailure() {
487
+ permissionFailure = true;
488
+ abort();
489
+ },
490
+ allowedTools: allowedToolSet,
491
+ ...budgetGate ? { budgetGate } : {}
492
+ };
493
+ const canUseTool = buildCanUseTool(permissionGate);
494
+ const preToolUseHook = buildPreToolUseHook(permissionGate);
495
+ const postToolBatchHook = async (hookInput) => {
496
+ if (hookInput.hook_event_name !== "PostToolBatch" || !budgetGate?.phaseReached()) return { continue: true };
497
+ if (input.budget?.synthesis === false) {
498
+ budgetFailure = true;
499
+ emit({ type: "clio_run_outcome", payload: { outcomeCode: "worker_tool_call_cap_exhausted" } });
500
+ return { continue: false, stopReason: `worker agent budget reached (${input.budget.toolCalls})` };
501
+ }
502
+ return {
503
+ continue: true,
504
+ hookSpecificOutput: {
505
+ hookEventName: "PostToolBatch",
506
+ additionalContext: "The admitted tool-call phase is complete. Tools are now disabled. Return the final answer in plain text from evidence already gathered."
507
+ }
508
+ };
509
+ };
510
+ const options = {
511
+ abortController,
512
+ cwd: process.cwd(),
513
+ model: input.wireModelId,
514
+ systemPrompt: systemPromptForInput(input),
515
+ tools: claudeSdkToolsForAutonomy(input.autonomy),
516
+ permissionMode: claudeSdkPermissionModeForAutonomy(input.autonomy),
517
+ canUseTool,
518
+ hooks: {
519
+ PreToolUse: [{ hooks: [preToolUseHook] }],
520
+ ...budgetGate ? { PostToolBatch: [{ hooks: [postToolBatchHook] }] } : {}
521
+ },
522
+ includePartialMessages: true,
523
+ persistSession: false,
524
+ settingSources: [],
525
+ env: { ...process.env, CLAUDE_AGENT_SDK_CLIENT_APP: `@iowarp/clio-coder/${readClioVersion()}` }
526
+ };
527
+ const disallowedTools = claudeToolsOutsideProfile(allowedToolSet);
528
+ if (disallowedTools.length > 0) options.disallowedTools = disallowedTools;
529
+ const thinking = thinkingForInput(input);
530
+ if (thinking !== void 0) options.thinking = thinking;
531
+ const effort = input.runtimeResolution?.request.reasoningEffort ?? effortForThinking(input.runtimeResolution?.effectiveThinkingLevel ?? input.thinkingLevel);
532
+ if (effort !== void 0) options.effort = effort;
533
+ if (isClaudeCodeSessionId(input.sessionId)) options.sessionId = input.sessionId.trim();
534
+ const promise = (async () => {
535
+ const messages = [];
536
+ const streamState = { started: false, text: "", model: input.wireModelId };
537
+ let result = null;
538
+ let responseModel;
539
+ let responseId;
540
+ emit({ type: "agent_start" });
541
+ try {
542
+ queryHandle = query({ prompt: buildClaudeSdkPrompt(input), options });
543
+ for await (const sdkMessage of queryHandle) {
544
+ if (sdkMessage.type === "system" && sdkMessage.subtype === "init") {
545
+ const init = sdkMessage;
546
+ if (typeof init.model === "string" && init.model.length > 0) streamState.model = init.model;
547
+ if (typeof init.uuid === "string") responseId = init.uuid;
548
+ continue;
549
+ }
550
+ if (sdkMessage.type === "stream_event") {
551
+ emitTextDelta(emit, streamState, extractStreamDelta(sdkMessage));
552
+ continue;
553
+ }
554
+ if (sdkMessage.type === "assistant") {
555
+ const text = extractAssistantText(sdkMessage);
556
+ if (text.length > 0 && text.length >= streamState.text.length) {
557
+ streamState.text = text;
558
+ }
559
+ const assistant = sdkMessage;
560
+ if (typeof assistant.message?.model === "string") responseModel = assistant.message.model;
561
+ if (typeof assistant.request_id === "string") responseId = assistant.request_id;
562
+ else if (typeof assistant.uuid === "string") responseId = assistant.uuid;
563
+ continue;
564
+ }
565
+ if (sdkMessage.type === "result") {
566
+ result = sdkMessage;
567
+ }
568
+ }
569
+ const error = resultError(result);
570
+ const finalText = streamState.text || resultText(result) || error;
571
+ const finalMessage = buildAssistantMessage({
572
+ model: streamState.model,
573
+ responseModel,
574
+ responseId,
575
+ text: finalText,
576
+ result,
577
+ aborted,
578
+ errorMessage: error
579
+ });
580
+ if (!streamState.started) emit({ type: "message_start", message: finalMessage });
581
+ emit({ type: "message_end", message: finalMessage });
582
+ messages.push(finalMessage);
583
+ emit({ type: "agent_end", messages });
584
+ if (permissionFailure) return { messages, exitCode: WORKER_EXIT_PERMISSION_REQUIRED };
585
+ if (budgetFailure) return { messages, exitCode: 1 };
586
+ return { messages, exitCode: finalMessage.stopReason === "error" ? 1 : 0 };
587
+ } catch (error) {
588
+ const messageText = error instanceof Error ? error.message : String(error);
589
+ const finalMessage = buildAssistantMessage({
590
+ model: streamState.model,
591
+ text: messageText,
592
+ result,
593
+ aborted,
594
+ errorMessage: messageText
595
+ });
596
+ emit({ type: "message_end", message: finalMessage });
597
+ messages.push(finalMessage);
598
+ emit({ type: "agent_end", messages });
599
+ if (permissionFailure) return { messages, exitCode: WORKER_EXIT_PERMISSION_REQUIRED };
600
+ if (budgetFailure) return { messages, exitCode: 1 };
601
+ if (!aborted) process.stderr.write(`[worker:claude-sdk] ${messageText}
602
+ `);
603
+ return { messages, exitCode: 1 };
604
+ } finally {
605
+ queryHandle?.close();
606
+ }
607
+ })();
608
+ return {
609
+ promise,
610
+ abort,
611
+ async steer(text) {
612
+ const trimmed = text.trim();
613
+ const activeQuery = queryHandle;
614
+ if (trimmed.length === 0 || activeQuery === null) return false;
615
+ try {
616
+ await activeQuery.streamInput(oneSdkUserMessage(sdkUserTextMessage(trimmed, true)));
617
+ return true;
618
+ } catch {
619
+ return false;
620
+ }
621
+ }
622
+ };
623
+ }
624
+
625
+ // src/engine/worker-runtime.ts
626
+ function isAssistantMessage(message) {
627
+ if (typeof message !== "object" || message === null) return false;
628
+ return "role" in message && message.role === "assistant";
629
+ }
630
+ function getTerminalAgentError(messages) {
631
+ for (let i = messages.length - 1; i >= 0; i--) {
632
+ const message = messages[i];
633
+ if (!isAssistantMessage(message)) continue;
634
+ if (message.stopReason !== "error") return null;
635
+ return typeof message.errorMessage === "string" ? message.errorMessage : "";
636
+ }
637
+ return null;
638
+ }
639
+ function assistantMessageText(message) {
640
+ if (!isAssistantMessage(message) || !Array.isArray(message.content)) return null;
641
+ return message.content.filter((block) => block.type === "text" && typeof block.text === "string").map((block) => block.text).join("").trim();
642
+ }
643
+ function isTerminalAssistantMessage(message) {
644
+ if (!isAssistantMessage(message)) return false;
645
+ return message.stopReason !== "toolUse" && message.stopReason !== "error";
646
+ }
647
+ function terminalContractViolation(contract, message, cwd, observedReadRanges, observedRunEffects) {
648
+ if (!isAssistantMessage(message)) return null;
649
+ const text = assistantMessageText(message);
650
+ if (text === null || text.length === 0) return "missing final result";
651
+ const stopReason = message.stopReason;
652
+ if (shouldRequestStalledTurnContinuation({
653
+ hook: "turn_end",
654
+ text,
655
+ metadata: { turnToolCalls: 0, ...typeof stopReason === "string" ? { stopReason } : {} }
656
+ })) {
657
+ return "the response announced further work instead of stating the final result";
658
+ }
659
+ const validation = validateResultContract({
660
+ contract,
661
+ output: text,
662
+ cwd,
663
+ observedReadRanges,
664
+ observedRunEffects,
665
+ // Repair rounds judge shape and grounding only. Network posture belongs to
666
+ // the orchestrator's sealed validation, which runs again on the receipt.
667
+ networkAllowed: true,
668
+ filesystem: {
669
+ readFile(filePath) {
670
+ try {
671
+ return readFileSync(filePath, "utf8");
672
+ } catch {
673
+ return null;
674
+ }
675
+ },
676
+ pathExists(filePath) {
677
+ return existsSync(filePath);
678
+ }
679
+ }
680
+ });
681
+ return validation.conformance === "pass" ? null : validation.reason ?? "invalid result";
682
+ }
683
+ var NullKnowledgeBase = class {
684
+ lookup(_modelId) {
685
+ return null;
686
+ }
687
+ entries() {
688
+ return [];
689
+ }
690
+ };
691
+ var kbSingleton = null;
692
+ function getKnowledgeBase() {
693
+ if (kbSingleton) return kbSingleton;
694
+ try {
695
+ const roots = resolveProviderKnowledgeBaseRoots(import.meta.url);
696
+ kbSingleton = roots.length > 0 ? new FileKnowledgeBase(roots) : new NullKnowledgeBase();
697
+ } catch {
698
+ kbSingleton = new NullKnowledgeBase();
699
+ }
700
+ return kbSingleton;
701
+ }
702
+ function clampThinkingLevelForModel(model, requested) {
703
+ const level = requested ?? "off";
704
+ return resolveModelRuntimeCapabilitiesForModel(model, level).thinking.effectiveLevel;
705
+ }
706
+ function promptMessage(fragment) {
707
+ return {
708
+ role: "user",
709
+ content: [{ type: "text", text: fragment.body }],
710
+ timestamp: Date.now()
711
+ };
712
+ }
713
+ function taskMessage(task) {
714
+ return {
715
+ role: "user",
716
+ content: [{ type: "text", text: task }],
717
+ timestamp: Date.now()
718
+ };
719
+ }
720
+ function promptMessagesForWorker(input) {
721
+ const messages = (input.dynamicPromptMessages ?? []).map(promptMessage);
722
+ messages.push(taskMessage(input.task));
723
+ return messages;
724
+ }
725
+ function workerProviderSupportsTools(input) {
726
+ const runtimeDecision = input.runtimeResolution?.capabilities.tools;
727
+ if (runtimeDecision !== void 0) return runtimeDecision === true;
728
+ if (typeof input.modelCapabilities?.tools === "boolean") return input.modelCapabilities.tools;
729
+ return input.runtime.defaultCapabilities.tools === true;
730
+ }
731
+ function assertResponseSchemaRuntime(input) {
732
+ if (input.responseSchema === void 0) return;
733
+ if (runtimeSpeaksResponseSchemaDialect(input.runtime) && input.modelCapabilities?.structuredOutputs === "json-schema") {
734
+ return;
735
+ }
736
+ throw new Error(
737
+ `responseSchema requires a native llamacpp runtime with resolved JSON-schema support; received '${input.runtime.id}'`
738
+ );
739
+ }
740
+ function resolveWorkerRuntimeBudget(input) {
741
+ return input.budget;
742
+ }
743
+ function startWorkerRun(input, emit) {
744
+ assertResponseSchemaRuntime(input);
745
+ if (input.resultContract !== void 0) parseResultContract(input.resultContract, "WorkerSpec.resultContract");
746
+ if (input.runtime.id === "claude-sdk") {
747
+ return startClaudeSdkWorkerRun(input, emit);
748
+ }
749
+ if (input.runtime.id === "claude-code") {
750
+ return startClaudeCodeWorkerRun(input, emit);
751
+ }
752
+ if (input.runtime.id === "antigravity-code") {
753
+ return startAntigravityWorkerRun(input, emit);
754
+ }
755
+ registerClioApiProviders();
756
+ const workerSettings = validateSettingsFile().settings;
757
+ setGlobalDefaultMaxOutputTokens(workerSettings.defaults.maxTokens);
758
+ configureGuardrails(workerSettings.guardrails);
759
+ const fauxModel = registerFauxFromEnv();
760
+ const agentSkillPolicy = input.allowedTools.includes(ToolNames.Context) && input.noSkills !== true ? agentSkillToolPolicy(input.agentSkills ?? []) : void 0;
761
+ const activeWorkerTools = workerProviderSupportsTools(input) ? input.allowedTools : [];
762
+ const kb = getKnowledgeBase();
763
+ const kbHit = kb.lookup(input.wireModelId);
764
+ const synthesized = input.runtime.synthesizeModel(input.target, input.wireModelId, kbHit);
765
+ const model = applyModelCapabilityPatch(
766
+ input.target.runtime === "faux" && fauxModel ? fauxModel : synthesized,
767
+ input.modelCapabilities
768
+ );
769
+ const safety = createWorkerSafety({
770
+ cwd: process.cwd(),
771
+ ...input.writeRoots !== void 0 ? { writeRoots: input.writeRoots } : {},
772
+ ...input.protectedArtifactState !== void 0 ? { protectedArtifactState: { artifacts: [...input.protectedArtifactState.artifacts] } } : {}
773
+ });
774
+ let synthesisToolLock = false;
775
+ let workerBoundFailure = null;
776
+ let workerBoundAborted = false;
777
+ let abortWorkerForBound = null;
778
+ let stopAfterToolResultCallId = null;
779
+ const workerBudget = resolveWorkerRuntimeBudget(input);
780
+ const readReserve = input.allowedTools.includes(ToolNames.Read) ? workerBudget.readReserve : 0;
781
+ const deliveryTools = resolveDeliveryTools(input.allowedTools, input.product);
782
+ const middlewareToolChoice = createMiddlewareToolChoiceControl();
783
+ let workerModelRound = 0;
784
+ const registry = createWorkerToolRegistry(
785
+ input.middlewareSnapshot,
786
+ safety,
787
+ {
788
+ ...input.noSkills !== void 0 ? { noSkills: input.noSkills } : {},
789
+ ...input.skillPaths !== void 0 ? { skillPaths: [...input.skillPaths] } : {},
790
+ ...input.trustProjectCompatRoots !== void 0 ? { trustProjectCompatRoots: input.trustProjectCompatRoots } : {}
791
+ },
792
+ // Workers run unattended, so the loop guard carries the hard tool-call
793
+ // cap in addition to repetition blocking, plus the synthesis lockout:
794
+ // after the loop-block budget the worker is told to report from what it
795
+ // gathered instead of burning the lifetime cap on a retry spiral, and
796
+ // the bounded backstop reason is watched in telemetry.onFinish below to
797
+ // abort a worker that keeps calling tools anyway.
798
+ // The protected-artifacts guard starts from the parent-session snapshot
799
+ // and has no persistence sink. It can still absorb worker-local
800
+ // protect_path effects from snapshot rules for the rest of this run.
801
+ [
802
+ createLoopGuardRegistration({
803
+ safety,
804
+ toolCallCap: workerBudget.hardCap,
805
+ toolCallSoftLimit: workerBudget.toolCalls,
806
+ // A worker's blocks all land in one run-long bucket, so the bound on
807
+ // them is a statement about this run's length, not about a turn.
808
+ turnBlockBudget: workerLoopBlockBudget(workerBudget.toolCalls),
809
+ toolCallSoftReadReserve: readReserve,
810
+ ...deliveryTools.length > 0 ? { deliveryTools } : {},
811
+ turnSynthesisLockout: workerBudget.synthesis,
812
+ // Once locked, the next model round is forced text-only at the
813
+ // request level (tool_choice none in onPayload below): the lockout
814
+ // directive alone relies on model compliance, and measured local
815
+ // models kept calling tools until the backstop aborted the run.
816
+ onSynthesisLockout: () => {
817
+ if (workerBudget.synthesis) {
818
+ synthesisToolLock = true;
819
+ }
820
+ },
821
+ ...!workerBudget.synthesis ? {
822
+ onSoftLimitFinalCallAdmitted: (toolCallId) => {
823
+ if (workerBoundFailure === null) {
824
+ workerBoundFailure = `worker agent budget reached (${workerBudget.toolCalls}); synthesis is disabled`;
825
+ }
826
+ stopAfterToolResultCallId = toolCallId ?? "";
827
+ }
828
+ } : {},
829
+ // Forcing the next round to `read` is only correct when reading is
830
+ // the whole reserve. An agent with delivery tools must be able to
831
+ // write in its own reserve window, so it gets the steering directive
832
+ // without the request-level lock.
833
+ ...readReserve > 0 && deliveryTools.length === 0 ? {
834
+ onSoftReadReserve: () => {
835
+ middlewareToolChoice.apply([{ kind: "require_tool", toolName: ToolNames.Read }]);
836
+ }
837
+ } : {}
838
+ }),
839
+ createProtectedArtifactsRegistration({
840
+ ...input.protectedArtifactState !== void 0 ? { initialState: { artifacts: [...input.protectedArtifactState.artifacts] } } : {}
841
+ })
842
+ ],
843
+ input.autonomy,
844
+ (effects) => middlewareToolChoice.apply(effects),
845
+ input.agentLedger
846
+ );
847
+ const contractCwd = input.cwd ?? process.cwd();
848
+ let resultContractRepairsQueued = 0;
849
+ const pendingReadCitations = /* @__PURE__ */ new Map();
850
+ const observedReadRanges = /* @__PURE__ */ new Map();
851
+ const runEffects = createRunEffectsRecorder(contractCwd);
852
+ const recordObservedRead = (request, result) => {
853
+ const observation = result?.details?.observation;
854
+ if (!observation) return;
855
+ const shown = observation.shownCount;
856
+ const total = observation.totalCount;
857
+ if (typeof shown !== "number" || !Number.isFinite(shown) || shown <= 0) return;
858
+ let start;
859
+ if (request.tail) {
860
+ if (typeof total !== "number" || !Number.isFinite(total)) return;
861
+ start = Math.max(1, Math.floor(total) - shown + 1);
862
+ } else {
863
+ start = request.offset ?? 1;
864
+ }
865
+ const key = path.resolve(contractCwd, request.path);
866
+ const spans = observedReadRanges.get(key) ?? [];
867
+ spans.push([start, start + shown - 1]);
868
+ observedReadRanges.set(key, spans);
869
+ };
870
+ const observedReadAnchors = () => [...observedReadRanges.entries()].flatMap(
871
+ ([key, spans]) => spans.map(([start, end]) => `${path.relative(contractCwd, key) || key}:${start}-${end}`)
872
+ );
873
+ const telemetry = {
874
+ onStart(event) {
875
+ emit({ type: "clio_tool_start", payload: event });
876
+ },
877
+ onFinish(event) {
878
+ emit({ type: "clio_tool_finish", payload: event });
879
+ if (event.outcome !== "blocked" || typeof event.reason !== "string") return;
880
+ if (isWorkerToolCallCapSynthesisReason(event.reason)) {
881
+ emit({ type: "clio_run_outcome", payload: { outcomeCode: "worker_tool_call_cap_exhausted" } });
882
+ if (workerBoundFailure === null) {
883
+ workerBoundFailure = event.reason;
884
+ process.stderr.write(`[worker] ${event.reason}
885
+ `);
886
+ }
887
+ return;
888
+ }
889
+ if (isWorkerToolCallCapExceededReason(event.reason) || isLoopGuardSynthesisBackstopReason(event.reason)) {
890
+ emit({
891
+ type: "clio_run_outcome",
892
+ payload: {
893
+ outcomeCode: isLoopGuardSynthesisBackstopReason(event.reason) ? "loop_guard_tools_disabled_exhausted" : "worker_tool_call_cap_exhausted"
894
+ }
895
+ });
896
+ if (workerBoundAborted) return;
897
+ workerBoundAborted = true;
898
+ if (workerBoundFailure === null) workerBoundFailure = event.reason;
899
+ process.stderr.write(`[worker] ${event.reason}
900
+ `);
901
+ abortWorkerForBound?.();
902
+ }
903
+ }
904
+ };
905
+ const tools = resolveAgentTools({
906
+ registry,
907
+ telemetry,
908
+ allowedTools: activeWorkerTools,
909
+ agentId: input.agentId,
910
+ task: input.task,
911
+ includeInteractiveTools: false,
912
+ invokeOptions: () => ({
913
+ correlationId: `worker-model-round-${workerModelRound}`,
914
+ ...agentSkillPolicy ? { pendingSkillPolicy: agentSkillPolicy } : {}
915
+ })
916
+ });
917
+ if (tools.length === 0 && activeWorkerTools.length > 0) {
918
+ process.stderr.write(`[worker] warning: no tools resolved for allowed=[${activeWorkerTools.join(",")}]
919
+ `);
920
+ }
921
+ const effectiveThinkingLevel = clampThinkingLevelForModel(
922
+ model,
923
+ input.runtimeResolution?.effectiveThinkingLevel ?? input.thinkingLevel
924
+ );
925
+ const options = {
926
+ initialState: {
927
+ systemPrompt: input.systemPrompt,
928
+ model,
929
+ thinkingLevel: effectiveThinkingLevel,
930
+ tools,
931
+ messages: []
932
+ },
933
+ onPayload: async (payload, currentModel) => {
934
+ const middlewareChoice = middlewareToolChoice.current();
935
+ return patchWorkerRequestPayload(payload, currentModel, {
936
+ runtimeId: input.runtime.id,
937
+ thinkingLevel: effectiveThinkingLevel,
938
+ ...input.responseSchema !== void 0 ? { responseSchema: input.responseSchema } : {},
939
+ toolChoiceNone: synthesisToolLock || middlewareChoice.kind === "none",
940
+ ...middlewareChoice.kind === "required" ? { toolChoiceName: middlewareChoice.toolName } : {}
941
+ });
942
+ },
943
+ getApiKey: async () => input.apiKey
944
+ };
945
+ if (input.sessionId) options.sessionId = input.sessionId;
946
+ const { agent } = createEngineAgent(options);
947
+ abortWorkerForBound = () => agent.abort();
948
+ const unsubscribe = agent.subscribe(async (event) => {
949
+ if (event.type === "turn_start") workerModelRound += 1;
950
+ if (event.type === "tool_execution_start") middlewareToolChoice.toolStarted(event.toolName);
951
+ if (event.type === "tool_execution_start") {
952
+ runEffects.start(event.toolCallId, event.toolName, event.args);
953
+ }
954
+ if (event.type === "tool_execution_end") {
955
+ runEffects.finish(event.toolCallId, event.isError === true);
956
+ }
957
+ if (event.type === "tool_execution_start" && event.toolName === ToolNames.Read) {
958
+ const args = event.args;
959
+ const readPath = typeof args.path === "string" ? args.path.trim() : "";
960
+ const offset = typeof args.offset === "number" && Number.isFinite(args.offset) && args.offset > 0 ? Math.floor(args.offset) : null;
961
+ if (readPath.length > 0) {
962
+ pendingReadCitations.set(event.toolCallId, { path: readPath, offset, tail: args.tail !== void 0 });
963
+ }
964
+ }
965
+ if (event.type === "tool_execution_end" && event.toolName === ToolNames.Read) {
966
+ const request = pendingReadCitations.get(event.toolCallId);
967
+ pendingReadCitations.delete(event.toolCallId);
968
+ if (request !== void 0 && event.isError !== true) recordObservedRead(request, event.result);
969
+ }
970
+ if (synthesisToolLock && event.type === "message_end") {
971
+ sanitizeLockedSynthesisMessage(event.message);
972
+ }
973
+ const contract = input.resultContract;
974
+ if (contract && event.type === "message_end" && isTerminalAssistantMessage(event.message)) {
975
+ const violation = terminalContractViolation(
976
+ contract,
977
+ event.message,
978
+ contractCwd,
979
+ observedReadRanges,
980
+ runEffects.snapshot()
981
+ );
982
+ if (violation !== null) {
983
+ if (resultContractRepairsQueued < RESULT_CONTRACT_REPAIR_LIMIT) {
984
+ resultContractRepairsQueued += 1;
985
+ synthesisToolLock = true;
986
+ agent.followUp(
987
+ taskMessage(
988
+ resultContractRepairMessage({
989
+ contract,
990
+ reason: violation,
991
+ attempt: resultContractRepairsQueued,
992
+ anchors: observedReadAnchors()
993
+ })
994
+ )
995
+ );
996
+ } else if (workerBoundFailure === null) {
997
+ workerBoundFailure = `result contract failed after ${RESULT_CONTRACT_REPAIR_LIMIT} bounded repair rounds: ${violation}`;
998
+ emit({ type: "clio_run_outcome", payload: { outcomeCode: "result_contract_exhausted" } });
999
+ process.stderr.write(`[worker] ${workerBoundFailure}
1000
+ `);
1001
+ }
1002
+ }
1003
+ }
1004
+ emit(event);
1005
+ if (stopAfterToolResultCallId !== null && event.type === "message_end" && event.message.role === "toolResult" && (stopAfterToolResultCallId.length === 0 || event.message.toolCallId === stopAfterToolResultCallId)) {
1006
+ stopAfterToolResultCallId = null;
1007
+ workerBoundAborted = true;
1008
+ abortWorkerForBound?.();
1009
+ }
1010
+ });
1011
+ const onPermission = input.onPermission ?? "deny";
1012
+ const escalationConfig = onPermission === "escalate" ? {
1013
+ timeoutMs: input.escalation?.timeoutMs ?? DEFAULT_ESCALATION_TIMEOUT_MS,
1014
+ fallback: input.escalation?.fallback ?? DEFAULT_ESCALATION_FALLBACK
1015
+ } : null;
1016
+ let permissionFailure = false;
1017
+ const denyReason = (tool, actionClass) => `permission denied by policy: dispatched workers run non-interactively (workers.onPermission=deny); ${tool} requires ${actionClass} confirmation`;
1018
+ const failReason = (tool, actionClass) => `permission required for ${tool} (${actionClass}); workers.onPermission=fail ends this run`;
1019
+ let activeEscalation = null;
1020
+ const clearActiveEscalation = () => {
1021
+ if (activeEscalation) {
1022
+ clearTimeout(activeEscalation.timer);
1023
+ activeEscalation = null;
1024
+ }
1025
+ };
1026
+ const resolveEscalation = (requestId, decision, source) => {
1027
+ const active = activeEscalation;
1028
+ if (!active || active.requestId !== requestId) return false;
1029
+ clearActiveEscalation();
1030
+ if (decision === "approve") {
1031
+ emit({
1032
+ type: "clio_permission_resolved",
1033
+ payload: {
1034
+ tool: active.tool,
1035
+ actionClass: active.actionClass,
1036
+ mode: "escalate",
1037
+ source,
1038
+ requestId,
1039
+ decision: "approved",
1040
+ reason: `operator approved permission escalation for ${active.tool} (${active.actionClass})`
1041
+ }
1042
+ });
1043
+ void registry.resumeParkedCalls({
1044
+ actionClass: active.actionClass,
1045
+ requestId,
1046
+ requestedBy: `escalation:${source}`
1047
+ });
1048
+ return true;
1049
+ }
1050
+ const effectiveFail = source === "timeout" && escalationConfig?.fallback === "fail";
1051
+ const mode = effectiveFail ? "fail" : "deny";
1052
+ const denialContext = source === "timeout" ? "escalation timed out with no operator decision" : "operator denied";
1053
+ const reason = effectiveFail ? `permission required for ${active.tool} (${active.actionClass}); ${denialContext} and workers fallback=fail ends this run` : `permission denied by ${source === "timeout" ? "escalation timeout fallback" : "operator"}: ${active.tool} requires ${active.actionClass} confirmation`;
1054
+ emit({
1055
+ type: "clio_permission_resolved",
1056
+ payload: {
1057
+ tool: active.tool,
1058
+ actionClass: active.actionClass,
1059
+ mode,
1060
+ source,
1061
+ requestId,
1062
+ decision: "denied",
1063
+ reason
1064
+ }
1065
+ });
1066
+ if (effectiveFail) {
1067
+ permissionFailure = true;
1068
+ registry.cancelParkedCalls(reason);
1069
+ agent.abort();
1070
+ return true;
1071
+ }
1072
+ if (source === "operator") registry.cancelParkedCall(requestId, reason);
1073
+ else registry.cancelParkedCalls(reason);
1074
+ return true;
1075
+ };
1076
+ const denyActiveEscalationOnAbort = (reason) => {
1077
+ const active = activeEscalation;
1078
+ if (!active) return;
1079
+ emit({
1080
+ type: "clio_permission_resolved",
1081
+ payload: {
1082
+ tool: active.tool,
1083
+ actionClass: active.actionClass,
1084
+ mode: "escalate",
1085
+ source: "operator",
1086
+ requestId: active.requestId,
1087
+ decision: "denied",
1088
+ reason
1089
+ }
1090
+ });
1091
+ clearActiveEscalation();
1092
+ };
1093
+ const unsubscribePermission = registry.onPermissionRequired((call, decision, meta) => {
1094
+ const actionClass = decision.classification.actionClass;
1095
+ if (escalationConfig) {
1096
+ if (activeEscalation !== null) return;
1097
+ const requestId = meta.requestId;
1098
+ const timer = setTimeout(() => resolveEscalation(requestId, "deny", "timeout"), escalationConfig.timeoutMs);
1099
+ activeEscalation = { requestId, tool: call.tool, actionClass, timer };
1100
+ const target = describeCallTarget(call.args).slice(0, 200);
1101
+ emit({
1102
+ type: "clio_permission_escalated",
1103
+ payload: {
1104
+ requestId,
1105
+ tool: call.tool,
1106
+ summary: `${call.tool} requires ${actionClass} confirmation`,
1107
+ ...target.length > 0 ? { target } : {},
1108
+ axis: meta.axis,
1109
+ decision: {
1110
+ actionClass,
1111
+ reasons: decision.classification.reasons,
1112
+ ...decision.policy?.reasonCode ? { reasonCode: decision.policy.reasonCode } : {},
1113
+ ...decision.policy?.ruleId ? { ruleId: decision.policy.ruleId } : {},
1114
+ ...decision.policy?.policySource ? { policySource: decision.policy.policySource } : {}
1115
+ },
1116
+ timeoutMs: escalationConfig.timeoutMs
1117
+ }
1118
+ });
1119
+ return;
1120
+ }
1121
+ const reason = onPermission === "fail" ? failReason(call.tool, actionClass) : denyReason(call.tool, actionClass);
1122
+ emit({
1123
+ type: "clio_permission_resolved",
1124
+ payload: {
1125
+ tool: call.tool,
1126
+ actionClass,
1127
+ mode: onPermission,
1128
+ source: "policy",
1129
+ requestId: meta.requestId,
1130
+ reason
1131
+ }
1132
+ });
1133
+ if (onPermission === "fail") {
1134
+ permissionFailure = true;
1135
+ registry.cancelParkedCalls(reason);
1136
+ agent.abort();
1137
+ return;
1138
+ }
1139
+ registry.cancelParkedCalls(reason);
1140
+ });
1141
+ const promise = (async () => {
1142
+ try {
1143
+ await agent.prompt(promptMessagesForWorker(input));
1144
+ await agent.waitForIdle();
1145
+ unsubscribe();
1146
+ if (workerBoundFailure !== null) {
1147
+ return { messages: agent.state.messages, exitCode: 1 };
1148
+ }
1149
+ if (permissionFailure) {
1150
+ return { messages: agent.state.messages, exitCode: WORKER_EXIT_PERMISSION_REQUIRED };
1151
+ }
1152
+ const messages = agent.state.messages;
1153
+ const errorMessage = getTerminalAgentError(messages);
1154
+ if (errorMessage !== null) {
1155
+ if (errorMessage.length > 0) {
1156
+ process.stderr.write(`[worker] agent ended with stopReason=error: ${errorMessage}
1157
+ `);
1158
+ }
1159
+ return { messages, exitCode: 1 };
1160
+ }
1161
+ return { messages, exitCode: 0 };
1162
+ } catch (err) {
1163
+ unsubscribe();
1164
+ if (workerBoundFailure !== null) {
1165
+ return { messages: agent.state.messages, exitCode: 1 };
1166
+ }
1167
+ if (permissionFailure) {
1168
+ return { messages: agent.state.messages, exitCode: WORKER_EXIT_PERMISSION_REQUIRED };
1169
+ }
1170
+ const msg = err instanceof Error ? err.message : String(err);
1171
+ emit({ type: "agent_end", messages: agent.state.messages });
1172
+ process.stderr.write(`[worker] agent error: ${msg}
1173
+ `);
1174
+ return { messages: agent.state.messages, exitCode: 1 };
1175
+ } finally {
1176
+ clearActiveEscalation();
1177
+ unsubscribePermission();
1178
+ }
1179
+ })();
1180
+ return {
1181
+ promise,
1182
+ abort: () => {
1183
+ if (escalationConfig) {
1184
+ const reason = "run aborted while a permission escalation was pending";
1185
+ denyActiveEscalationOnAbort(reason);
1186
+ registry.cancelParkedCalls(reason);
1187
+ }
1188
+ agent.abort();
1189
+ },
1190
+ steer: (text) => {
1191
+ const trimmed = text.trim();
1192
+ if (trimmed.length === 0) return false;
1193
+ agent.steer(taskMessage(trimmed));
1194
+ return true;
1195
+ },
1196
+ resolvePermission: (requestId, decision) => resolveEscalation(requestId, decision, "operator")
1197
+ };
1198
+ }
1199
+
1200
+ // src/worker/control-lane.ts
1201
+ function emitControlFrame(frame) {
1202
+ try {
1203
+ process.stderr.write(encodeControlFrame(frame));
1204
+ } catch {
1205
+ }
1206
+ }
1207
+
1208
+ // src/worker/event-projection.ts
1209
+ function isRecord(value) {
1210
+ return typeof value === "object" && value !== null;
1211
+ }
1212
+ function projectWorkerEventForStdout(event) {
1213
+ if (!isRecord(event) || event.type !== "message_update") return event;
1214
+ const { message: _message, assistantMessageEvent, ...rest } = event;
1215
+ if (!isRecord(assistantMessageEvent)) return rest;
1216
+ const { partial: _partial, ...slimAssistantMessageEvent } = assistantMessageEvent;
1217
+ return { ...rest, assistantMessageEvent: slimAssistantMessageEvent };
1218
+ }
1219
+
1220
+ // src/worker/heartbeat.ts
1221
+ function startWorkerHeartbeat(intervalMs = 1e3) {
1222
+ emitControlFrame({ kind: "heartbeat", at: Date.now() });
1223
+ const id = setInterval(() => emitControlFrame({ kind: "heartbeat", at: Date.now() }), intervalMs);
1224
+ id.unref?.();
1225
+ return () => clearInterval(id);
1226
+ }
1227
+
1228
+ // src/worker/ledger-mirror.ts
1229
+ var WORKER_AGENT_LEDGER_POST_CAP = 20;
1230
+ function createWorkerAgentLedgerMirror() {
1231
+ const bySequence = /* @__PURE__ */ new Map();
1232
+ let watermark = 0;
1233
+ return {
1234
+ apply(entries) {
1235
+ for (const entry of entries) {
1236
+ bySequence.set(entry.sequence, entry);
1237
+ if (entry.sequence > watermark) watermark = entry.sequence;
1238
+ }
1239
+ },
1240
+ entries() {
1241
+ return [...bySequence.values()].sort((left, right) => left.sequence - right.sequence);
1242
+ },
1243
+ watermark() {
1244
+ return watermark;
1245
+ }
1246
+ };
1247
+ }
1248
+ function createWorkerAgentLedgerPort(deps) {
1249
+ const mirror = deps.mirror ?? createWorkerAgentLedgerMirror();
1250
+ const { ledger, emitControlFrame: emitControlFrame2 } = deps;
1251
+ let posted = 0;
1252
+ return {
1253
+ post(body) {
1254
+ if (ledger === void 0) return { ok: false, reason: "no-ledger" };
1255
+ const parsed = parseAgentLedgerBody(body);
1256
+ if (!parsed.ok) return { ok: false, reason: "invalid-body" };
1257
+ if (posted >= WORKER_AGENT_LEDGER_POST_CAP) return { ok: false, reason: "per-run-cap" };
1258
+ posted += 1;
1259
+ emitControlFrame2({ kind: "ledger_post", body: parsed.body });
1260
+ return { ok: true };
1261
+ },
1262
+ read() {
1263
+ if (ledger === void 0) return null;
1264
+ return { open: true, watermark: mirror.watermark(), entries: mirror.entries() };
1265
+ },
1266
+ acceptDelta(entries) {
1267
+ mirror.apply(entries);
1268
+ }
1269
+ };
1270
+ }
1271
+
1272
+ // src/worker/ndjson.ts
1273
+ function emitEvent(event) {
1274
+ try {
1275
+ process.stdout.write(`${JSON.stringify(event)}
1276
+ `);
1277
+ } catch (err) {
1278
+ const msg = err instanceof Error ? err.message : String(err);
1279
+ process.stderr.write(`[worker] failed to emit event: ${msg}
1280
+ `);
1281
+ }
1282
+ }
1283
+ function drainStdout(timeoutMs = 2e3) {
1284
+ return new Promise((resolve) => {
1285
+ let done = false;
1286
+ const finish = () => {
1287
+ if (done) return;
1288
+ done = true;
1289
+ clearTimeout(timer);
1290
+ resolve();
1291
+ };
1292
+ const timer = setTimeout(finish, timeoutMs);
1293
+ try {
1294
+ process.stdout.write("", finish);
1295
+ } catch {
1296
+ finish();
1297
+ }
1298
+ });
1299
+ }
1300
+
1301
+ // src/worker/resource-facts.ts
1302
+ import { execFileSync } from "node:child_process";
1303
+ import { cpus, freemem, hostname, totalmem } from "node:os";
1304
+ var GPU_PROBE_TIMEOUT_MS = 1e3;
1305
+ function probeNvidiaGpus() {
1306
+ try {
1307
+ const stdout = execFileSync("nvidia-smi", ["--query-gpu=memory.total", "--format=csv,noheader,nounits"], {
1308
+ timeout: GPU_PROBE_TIMEOUT_MS,
1309
+ encoding: "utf8",
1310
+ stdio: ["ignore", "pipe", "ignore"]
1311
+ });
1312
+ const megabytes = stdout.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => Number.parseInt(line, 10)).filter((value) => Number.isFinite(value) && value > 0);
1313
+ if (megabytes.length === 0) return { gpuCount: UNKNOWN_RESOURCE, vramBytes: UNKNOWN_RESOURCE };
1314
+ const totalBytes = megabytes.reduce((sum, value) => sum + value, 0) * 1024 * 1024;
1315
+ return { gpuCount: knownResource(megabytes.length), vramBytes: knownResource(totalBytes) };
1316
+ } catch {
1317
+ return { gpuCount: UNKNOWN_RESOURCE, vramBytes: UNKNOWN_RESOURCE };
1318
+ }
1319
+ }
1320
+ function observeCpuCount() {
1321
+ const count = cpus().length;
1322
+ return count > 0 ? knownResource(count) : UNKNOWN_RESOURCE;
1323
+ }
1324
+ function observeMemory(read) {
1325
+ const bytes = read();
1326
+ return Number.isFinite(bytes) && bytes > 0 ? knownResource(bytes) : UNKNOWN_RESOURCE;
1327
+ }
1328
+ function observeWorkerResourceFacts(labels = []) {
1329
+ const gpu = probeNvidiaGpus();
1330
+ return {
1331
+ labels: [...labels].slice(0, WORKER_RESOURCE_LABEL_MAX),
1332
+ cpuCount: observeCpuCount(),
1333
+ totalMemoryBytes: observeMemory(totalmem),
1334
+ freeMemoryBytes: observeMemory(freemem),
1335
+ gpuCount: gpu.gpuCount,
1336
+ vramBytes: gpu.vramBytes,
1337
+ residentModels: UNKNOWN_RESOURCE
1338
+ };
1339
+ }
1340
+ function observeHostIdentity() {
1341
+ const name = hostname();
1342
+ return name.length > 0 ? name : "unknown-host";
1343
+ }
1344
+
1345
+ // src/worker/runtime-registry.ts
1346
+ async function resolveWorkerRuntime(runtimeId) {
1347
+ const registry = getRuntimeRegistry();
1348
+ registerBuiltinRuntimes(registry);
1349
+ await loadPluginRuntimes(registry, readSettings());
1350
+ return registry.get(runtimeId);
1351
+ }
1352
+
1353
+ // src/worker/stdin-demux.ts
1354
+ function createOrderedSteerHandler(deliver, onAccepted, onRejected) {
1355
+ let tail = Promise.resolve();
1356
+ return (steer) => {
1357
+ tail = tail.then(async () => {
1358
+ let rejection = null;
1359
+ try {
1360
+ if (await deliver(steer.text)) onAccepted(steer);
1361
+ else rejection = "runtime does not accept live guidance";
1362
+ } catch (error) {
1363
+ rejection = error instanceof Error ? error.message : String(error);
1364
+ }
1365
+ if (rejection !== null) {
1366
+ try {
1367
+ onRejected(rejection);
1368
+ } catch {
1369
+ }
1370
+ }
1371
+ });
1372
+ return tail;
1373
+ };
1374
+ }
1375
+ function createWorkerStdinDemux() {
1376
+ let buffer = "";
1377
+ let specResolve = null;
1378
+ let specReject = null;
1379
+ let specValue = null;
1380
+ let specError = null;
1381
+ let specReceived = false;
1382
+ let closed = false;
1383
+ let steerHandler = null;
1384
+ const pendingSteers = [];
1385
+ let permissionHandler = null;
1386
+ const pendingPermissionDecisions = [];
1387
+ let ledgerDeltaHandler = null;
1388
+ const pendingLedgerDeltas = [];
1389
+ let droppedLines = 0;
1390
+ let channelCloseHandler = null;
1391
+ let channelCloseDelivered = false;
1392
+ let channelClosedAfterSpec = false;
1393
+ function deliverChannelClose() {
1394
+ if (channelCloseDelivered || channelCloseHandler === null) return;
1395
+ channelCloseDelivered = true;
1396
+ channelCloseHandler();
1397
+ }
1398
+ function resolveSpec(spec) {
1399
+ specValue = spec;
1400
+ specResolve?.(spec);
1401
+ }
1402
+ function rejectSpec(err) {
1403
+ specError = err;
1404
+ specReject?.(err);
1405
+ }
1406
+ function deliverSteer(steer) {
1407
+ if (steerHandler) {
1408
+ steerHandler(steer);
1409
+ return;
1410
+ }
1411
+ pendingSteers.push(steer);
1412
+ }
1413
+ function deliverPermissionDecision(requestId, decision) {
1414
+ if (permissionHandler) {
1415
+ permissionHandler({ requestId, decision });
1416
+ return;
1417
+ }
1418
+ pendingPermissionDecisions.push({ requestId, decision });
1419
+ }
1420
+ function deliverLedgerDelta(entries) {
1421
+ if (ledgerDeltaHandler) {
1422
+ ledgerDeltaHandler(entries);
1423
+ return;
1424
+ }
1425
+ pendingLedgerDeltas.push(entries);
1426
+ }
1427
+ function processPostSpecLine(line) {
1428
+ let value;
1429
+ try {
1430
+ value = JSON.parse(line);
1431
+ } catch {
1432
+ droppedLines += 1;
1433
+ return;
1434
+ }
1435
+ if (typeof value === "object" && value !== null && value.type === "steer" && typeof value.text === "string" && value.text.trim().length > 0 && Number.isSafeInteger(value.sequence) && Number(value.sequence) > 0) {
1436
+ deliverSteer({
1437
+ text: value.text,
1438
+ sequence: value.sequence
1439
+ });
1440
+ return;
1441
+ }
1442
+ if (typeof value === "object" && value !== null && value.type === "permission_decision" && typeof value.requestId === "string" && value.requestId.length > 0 && (value.decision === "approve" || value.decision === "deny")) {
1443
+ deliverPermissionDecision(
1444
+ value.requestId,
1445
+ value.decision
1446
+ );
1447
+ return;
1448
+ }
1449
+ if (typeof value === "object" && value !== null && value.type === "ledger_delta") {
1450
+ const raw = value.entries;
1451
+ if (!Array.isArray(raw)) {
1452
+ droppedLines += 1;
1453
+ return;
1454
+ }
1455
+ const entries = [];
1456
+ for (const candidate of raw) {
1457
+ const entry = parseAgentLedgerEntry(candidate);
1458
+ if (entry !== null) entries.push(entry);
1459
+ }
1460
+ if (entries.length === 0) {
1461
+ droppedLines += 1;
1462
+ return;
1463
+ }
1464
+ deliverLedgerDelta(entries);
1465
+ return;
1466
+ }
1467
+ droppedLines += 1;
1468
+ }
1469
+ function processLine(line) {
1470
+ if (line.length === 0) return;
1471
+ if (!withinFrameBudget(line, WORKER_STDIN_FRAME_MAX_BYTES)) {
1472
+ if (!specReceived) {
1473
+ specReceived = true;
1474
+ rejectSpec(new Error(`WorkerSpec line exceeds the ${WORKER_STDIN_FRAME_MAX_BYTES} byte stdin frame limit`));
1475
+ return;
1476
+ }
1477
+ droppedLines += 1;
1478
+ return;
1479
+ }
1480
+ if (!specReceived) {
1481
+ specReceived = true;
1482
+ try {
1483
+ resolveSpec(parseWorkerSpec(JSON.parse(line)));
1484
+ } catch (err) {
1485
+ rejectSpec(err instanceof Error ? err : new Error(String(err)));
1486
+ }
1487
+ return;
1488
+ }
1489
+ processPostSpecLine(line);
1490
+ }
1491
+ let discardingOversizedLine = false;
1492
+ return {
1493
+ feed(chunk) {
1494
+ if (closed) return;
1495
+ buffer += chunk;
1496
+ let idx = buffer.indexOf("\n");
1497
+ while (idx >= 0) {
1498
+ const line = buffer.slice(0, idx);
1499
+ buffer = buffer.slice(idx + 1);
1500
+ if (discardingOversizedLine) {
1501
+ discardingOversizedLine = false;
1502
+ droppedLines += 1;
1503
+ } else {
1504
+ processLine(line);
1505
+ }
1506
+ idx = buffer.indexOf("\n");
1507
+ }
1508
+ if (!withinFrameBudget(buffer, WORKER_STDIN_FRAME_MAX_BYTES)) {
1509
+ if (!specReceived) {
1510
+ specReceived = true;
1511
+ rejectSpec(new Error(`WorkerSpec line exceeds the ${WORKER_STDIN_FRAME_MAX_BYTES} byte stdin frame limit`));
1512
+ }
1513
+ buffer = "";
1514
+ discardingOversizedLine = true;
1515
+ }
1516
+ },
1517
+ eof() {
1518
+ if (closed) return;
1519
+ closed = true;
1520
+ if (buffer.length > 0) {
1521
+ processLine(buffer);
1522
+ buffer = "";
1523
+ }
1524
+ if (!specReceived) {
1525
+ rejectSpec(new Error("worker stdin closed before spec received"));
1526
+ return;
1527
+ }
1528
+ channelClosedAfterSpec = true;
1529
+ deliverChannelClose();
1530
+ },
1531
+ readSpec() {
1532
+ if (specValue) return Promise.resolve(specValue);
1533
+ if (specError) return Promise.reject(specError);
1534
+ if (closed && !specReceived) return Promise.reject(new Error("worker stdin closed before spec received"));
1535
+ return new Promise((resolve, reject) => {
1536
+ specResolve = resolve;
1537
+ specReject = reject;
1538
+ });
1539
+ },
1540
+ onSteer(handler) {
1541
+ steerHandler = handler;
1542
+ while (pendingSteers.length > 0) {
1543
+ const steer = pendingSteers.shift();
1544
+ if (steer !== void 0) handler(steer);
1545
+ }
1546
+ },
1547
+ onPermissionDecision(handler) {
1548
+ permissionHandler = handler;
1549
+ while (pendingPermissionDecisions.length > 0) {
1550
+ const entry = pendingPermissionDecisions.shift();
1551
+ if (entry !== void 0) handler(entry);
1552
+ }
1553
+ },
1554
+ onLedgerDelta(handler) {
1555
+ ledgerDeltaHandler = handler;
1556
+ while (pendingLedgerDeltas.length > 0) {
1557
+ const batch = pendingLedgerDeltas.shift();
1558
+ if (batch !== void 0) handler(batch);
1559
+ }
1560
+ },
1561
+ droppedLineCount() {
1562
+ return droppedLines;
1563
+ },
1564
+ onChannelClose(handler) {
1565
+ channelCloseHandler = handler;
1566
+ if (channelClosedAfterSpec) deliverChannelClose();
1567
+ }
1568
+ };
1569
+ }
1570
+
1571
+ // src/worker/entry.ts
1572
+ var CHANNEL_CLOSE_EXIT_GRACE_MS = 5e3;
1573
+ function configuredNodeLabels() {
1574
+ return (process.env.CLIO_CODER_WORKER_LABELS ?? "").split(",").map((label) => label.trim()).filter((label) => label.length > 0);
1575
+ }
1576
+ function announcedProcessGroupId() {
1577
+ const declared = Number.parseInt(process.env.CLIO_CODER_WORKER_PGID ?? "", 10);
1578
+ if (Number.isSafeInteger(declared) && declared > 0) return declared;
1579
+ return process.platform === "win32" ? null : process.pid;
1580
+ }
1581
+ function announceWorker(spec, input) {
1582
+ emitControlFrame({
1583
+ kind: "announce",
1584
+ attestation: {
1585
+ protocolVersion: WORKER_PROTOCOL_VERSION,
1586
+ specVersion: spec.specVersion,
1587
+ pid: process.pid,
1588
+ processGroupId: announcedProcessGroupId(),
1589
+ host: observeHostIdentity(),
1590
+ settingsFingerprint: spec.settingsFingerprint,
1591
+ specDigest: workerSpecDigest(spec),
1592
+ runtimeId: spec.runtimeId,
1593
+ targetId: spec.target.id,
1594
+ endpointIdentityHash: endpointIdentityHash(spec.target.url),
1595
+ wireModelId: spec.wireModelId,
1596
+ toolSignature: attestedToolSignature({
1597
+ allowedTools: spec.allowedTools,
1598
+ toolsSupported: workerProviderSupportsTools(input),
1599
+ ...spec.toolProfile !== void 0 ? { toolProfile: spec.toolProfile } : {},
1600
+ agentId: spec.agentId,
1601
+ task: spec.task
1602
+ }),
1603
+ resources: observeWorkerResourceFacts(configuredNodeLabels())
1604
+ }
1605
+ });
1606
+ }
1607
+ async function main() {
1608
+ setResidencyNoticeSink((notice) => {
1609
+ process.stderr.write(`[worker] residency ${notice.kind}: ${notice.message}
1610
+ `);
1611
+ if (notice.kind === "will-not-fit") {
1612
+ emitEvent({ type: "clio_run_outcome", payload: { outcomeCode: "vram_capacity_fit_failure" } });
1613
+ }
1614
+ });
1615
+ const demux = createWorkerStdinDemux();
1616
+ process.stdin.setEncoding("utf8");
1617
+ process.stdin.on("data", (chunk) => demux.feed(chunk));
1618
+ process.stdin.on("end", () => demux.eof());
1619
+ process.stdin.on("error", () => demux.eof());
1620
+ process.stdin.resume();
1621
+ const spec = await demux.readSpec();
1622
+ setProtectedModelsProvider(() => spec.protectedModels ?? []);
1623
+ const stopHeartbeat = startWorkerHeartbeat();
1624
+ const runtime = await resolveWorkerRuntime(spec.runtimeId);
1625
+ if (!runtime) {
1626
+ process.stderr.write(`[worker] runtime '${spec.runtimeId}' not registered
1627
+ `);
1628
+ stopHeartbeat();
1629
+ return 2;
1630
+ }
1631
+ try {
1632
+ validateRehydratedWorkerRuntime(spec, runtime);
1633
+ } catch (err) {
1634
+ process.stderr.write(`[worker] ${err instanceof Error ? err.message : String(err)}
1635
+ `);
1636
+ stopHeartbeat();
1637
+ return 2;
1638
+ }
1639
+ const ledgerPort = createWorkerAgentLedgerPort({
1640
+ ...spec.ledger !== void 0 ? { ledger: spec.ledger } : {},
1641
+ emitControlFrame
1642
+ });
1643
+ demux.onLedgerDelta((entries) => ledgerPort.acceptDelta(entries));
1644
+ const input = {
1645
+ systemPrompt: spec.systemPrompt,
1646
+ dynamicPromptMessages: spec.dynamicPromptMessages ?? [],
1647
+ agentId: spec.agentId,
1648
+ task: spec.task,
1649
+ target: spec.target,
1650
+ runtime,
1651
+ wireModelId: spec.wireModelId,
1652
+ allowedTools: spec.allowedTools,
1653
+ budget: spec.budget,
1654
+ ...spec.noSkills !== void 0 ? { noSkills: spec.noSkills } : {},
1655
+ ...spec.skillPaths !== void 0 ? { skillPaths: [...spec.skillPaths] } : {},
1656
+ ...spec.agentSkills !== void 0 ? { agentSkills: [...spec.agentSkills] } : {},
1657
+ ...spec.trustProjectCompatRoots !== void 0 ? { trustProjectCompatRoots: spec.trustProjectCompatRoots } : {},
1658
+ ...spec.onPermission !== void 0 ? { onPermission: spec.onPermission } : {},
1659
+ ...spec.escalation !== void 0 ? { escalation: spec.escalation } : {},
1660
+ ...spec.toolProfile !== void 0 ? { toolProfile: spec.toolProfile } : {},
1661
+ ...spec.autonomy !== void 0 ? { autonomy: spec.autonomy } : {},
1662
+ ...spec.writeRoots !== void 0 ? { writeRoots: [...spec.writeRoots] } : {},
1663
+ ...spec.protectedArtifactState !== void 0 ? {
1664
+ protectedArtifactState: {
1665
+ version: spec.protectedArtifactState.version,
1666
+ artifacts: structuredClone(spec.protectedArtifactState.artifacts)
1667
+ }
1668
+ } : {},
1669
+ ...spec.responseSchema !== void 0 ? { responseSchema: spec.responseSchema } : {},
1670
+ ...spec.resultContract !== void 0 ? { resultContract: spec.resultContract } : {},
1671
+ ...spec.product !== void 0 ? { product: spec.product } : {},
1672
+ agentLedger: ledgerPort,
1673
+ cwd: process.cwd()
1674
+ };
1675
+ if (spec.modelCapabilities) input.modelCapabilities = spec.modelCapabilities;
1676
+ if (spec.sessionId) input.sessionId = spec.sessionId;
1677
+ if (spec.apiKey) input.apiKey = spec.apiKey;
1678
+ if (spec.thinkingLevel) input.thinkingLevel = spec.thinkingLevel;
1679
+ if (spec.runtimeResolution) input.runtimeResolution = spec.runtimeResolution;
1680
+ if (spec.middlewareSnapshot) input.middlewareSnapshot = spec.middlewareSnapshot;
1681
+ announceWorker(spec, input);
1682
+ const handle = startWorkerRun(input, (event) => emitEvent(projectWorkerEventForStdout(event)));
1683
+ demux.onSteer(
1684
+ createOrderedSteerHandler(
1685
+ (text) => handle.steer?.(text) ?? false,
1686
+ ({ text, sequence }) => emitEvent({ type: "clio_steer_received", payload: { chars: text.trim().length, sequence } }),
1687
+ (reason) => process.stderr.write(`[worker] dropped steer: ${reason}
1688
+ `)
1689
+ )
1690
+ );
1691
+ demux.onPermissionDecision(({ requestId, decision }) => {
1692
+ const resolved = handle.resolvePermission?.(requestId, decision) ?? false;
1693
+ if (!resolved) {
1694
+ process.stderr.write(`[worker] dropped permission_decision for unknown request '${requestId}'
1695
+ `);
1696
+ }
1697
+ });
1698
+ demux.onChannelClose(() => {
1699
+ process.stderr.write("[worker] control channel closed; aborting run\n");
1700
+ emitControlFrame({ kind: "cancel_ack", at: Date.now() });
1701
+ handle.abort();
1702
+ const forceExit = setTimeout(() => process.exit(1), CHANNEL_CLOSE_EXIT_GRACE_MS);
1703
+ forceExit.unref?.();
1704
+ });
1705
+ const onSignal = () => {
1706
+ emitControlFrame({ kind: "cancel_ack", at: Date.now() });
1707
+ handle.abort();
1708
+ };
1709
+ process.on("SIGINT", onSignal);
1710
+ process.on("SIGTERM", onSignal);
1711
+ try {
1712
+ const result = await handle.promise;
1713
+ return result.exitCode;
1714
+ } finally {
1715
+ stopHeartbeat();
1716
+ process.off("SIGINT", onSignal);
1717
+ process.off("SIGTERM", onSignal);
1718
+ const dropped = demux.droppedLineCount();
1719
+ if (dropped > 0) {
1720
+ process.stderr.write(`[worker] dropped ${dropped} unrecognized stdin line(s) after the spec
1721
+ `);
1722
+ }
1723
+ await disposeLmStudioClients();
1724
+ }
1725
+ }
1726
+ main().then(
1727
+ async (code) => {
1728
+ await drainStdout();
1729
+ process.exit(code);
1730
+ },
1731
+ async (err) => {
1732
+ const msg = err instanceof Error ? err.message : String(err);
1733
+ process.stderr.write(`[worker] fatal: ${msg}
1734
+ `);
1735
+ await drainStdout();
1736
+ process.exit(2);
1737
+ }
1738
+ );
1739
+ //# sourceMappingURL=entry.js.map