@amoree-code/ocean 0.0.0-stage → 1.1.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 (304) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +284 -2
  3. package/dist/application/auth/auth-orchestrator.js +77 -0
  4. package/dist/application/clients/clients.js +646 -0
  5. package/dist/application/clients/editors.js +398 -0
  6. package/dist/application/clients/hooks.js +335 -0
  7. package/dist/application/clients/native.js +410 -0
  8. package/dist/application/clients/opencode-plugin.js +158 -0
  9. package/dist/application/clients/registry.js +188 -0
  10. package/dist/application/gateway/webhook-gateway.js +137 -0
  11. package/dist/application/install/provider-installer.js +184 -0
  12. package/dist/application/integrations/charter-copies.js +76 -0
  13. package/dist/application/integrations/claude-vscode.js +106 -0
  14. package/dist/application/integrations/engine-entry-repair.js +105 -0
  15. package/dist/application/integrations/skill-filter.js +254 -0
  16. package/dist/application/layout/layout-apply.js +443 -0
  17. package/dist/application/layout/layout-plan.js +236 -0
  18. package/dist/application/layout/workspace-template.js +34 -0
  19. package/dist/application/onboarding/state.js +23 -0
  20. package/dist/application/onboarding/steps.js +249 -0
  21. package/dist/application/profiles/profile-distribution.js +53 -0
  22. package/dist/application/profiles/profile-suggestion.js +39 -0
  23. package/dist/application/profiles/profile-upgrade-service.js +208 -0
  24. package/dist/application/pull/history-index.js +476 -0
  25. package/dist/application/pull/project-match.js +132 -0
  26. package/dist/application/pull/pull.js +202 -0
  27. package/dist/application/pull/server-capture.js +307 -0
  28. package/dist/application/scheduler/local-scheduler.js +210 -0
  29. package/dist/composition/runtime.js +64 -0
  30. package/dist/engine-root.js +9 -0
  31. package/dist/infrastructure/filesystem/profile-loader.js +46 -0
  32. package/dist/infrastructure/filesystem/runtime-config-loader.js +29 -0
  33. package/dist/infrastructure/filesystem/skill-loader.js +84 -0
  34. package/dist/infrastructure/filesystem/workspace-capability.js +37 -0
  35. package/dist/infrastructure/observability/runtime-logger.js +16 -0
  36. package/dist/infrastructure/process/agent-tool-executor.js +99 -0
  37. package/dist/infrastructure/process/cli-process.js +49 -0
  38. package/dist/infrastructure/process/interactive-process.js +145 -0
  39. package/dist/infrastructure/process/process-supervisor.js +194 -0
  40. package/dist/infrastructure/process/service.js +252 -0
  41. package/dist/infrastructure/providers/browser-provider.js +2 -0
  42. package/dist/infrastructure/providers/claude-sdk.js +137 -0
  43. package/dist/infrastructure/providers/client-home.js +14 -0
  44. package/dist/infrastructure/providers/fake-browser-provider.js +146 -0
  45. package/dist/infrastructure/providers/ollama-embedder.js +74 -0
  46. package/dist/infrastructure/providers/openai-compatible.js +268 -0
  47. package/dist/infrastructure/providers/playwright-browser-provider.js +380 -0
  48. package/dist/infrastructure/providers/provider-capabilities.js +50 -0
  49. package/dist/infrastructure/providers/provider-invocation.js +184 -0
  50. package/dist/infrastructure/providers/provider-registry.js +77 -0
  51. package/dist/infrastructure/providers/providers.js +134 -0
  52. package/dist/infrastructure/wrappers/wrapper-manager.js +374 -0
  53. package/dist/interfaces/cli/auth-command.js +54 -0
  54. package/dist/interfaces/cli/browser-bridge-command.js +93 -0
  55. package/dist/interfaces/cli/browser-command.js +119 -0
  56. package/dist/interfaces/cli/capture-command.js +125 -0
  57. package/dist/interfaces/cli/client-test-command.js +133 -0
  58. package/dist/interfaces/cli/clients-command.js +129 -0
  59. package/dist/interfaces/cli/command-registry.js +1211 -0
  60. package/dist/interfaces/cli/context-command.js +172 -0
  61. package/dist/interfaces/cli/daily-command.js +131 -0
  62. package/dist/interfaces/cli/governance-command.js +55 -0
  63. package/dist/interfaces/cli/handoff-command.js +35 -0
  64. package/dist/interfaces/cli/help-command.js +207 -0
  65. package/dist/interfaces/cli/idea-command.js +47 -0
  66. package/dist/interfaces/cli/intercept-command.js +317 -0
  67. package/dist/interfaces/cli/layout-command.js +27 -0
  68. package/dist/interfaces/cli/market-command.js +52 -0
  69. package/dist/interfaces/cli/mcp-gateway-command.js +30 -0
  70. package/dist/interfaces/cli/memory-command.js +317 -0
  71. package/dist/interfaces/cli/migrate-command.js +26 -0
  72. package/dist/interfaces/cli/observe-command.js +78 -0
  73. package/dist/interfaces/cli/onboard-command.js +123 -0
  74. package/dist/interfaces/cli/operate-command.js +59 -0
  75. package/dist/interfaces/cli/profiles-command.js +70 -0
  76. package/dist/interfaces/cli/pull-command.js +54 -0
  77. package/dist/interfaces/cli/setup-command.js +143 -0
  78. package/dist/interfaces/cli/tasks-command.js +249 -0
  79. package/dist/main.js +49 -0
  80. package/dist/node-warnings.js +17 -0
  81. package/dist/version.js +8 -0
  82. package/market/mcp/chrome-devtools/ocean.capability.json +28 -0
  83. package/market/mcp/gateway/ocean.capability.json +21 -0
  84. package/market/mcp/obsidian/ocean.capability.json +21 -0
  85. package/market/mcp/ocean/ocean.capability.json +21 -0
  86. package/market/mcp/playwright/ocean.capability.json +23 -0
  87. package/node_modules/@ocean/brain/dist/brain/brain-eval.js +29 -0
  88. package/node_modules/@ocean/brain/dist/brain/brain-markdown.js +226 -0
  89. package/node_modules/@ocean/brain/dist/brain/brain-reindex.js +247 -0
  90. package/node_modules/@ocean/brain/dist/brain/brain-service.js +320 -0
  91. package/node_modules/@ocean/brain/dist/capture/inbox-sync.js +22 -0
  92. package/node_modules/@ocean/brain/dist/evidence/verification-report.js +13 -0
  93. package/node_modules/@ocean/brain/dist/infrastructure/brain/brain-index.js +285 -0
  94. package/node_modules/@ocean/brain/dist/memory/brain-dump.js +145 -0
  95. package/node_modules/@ocean/brain/dist/memory/daily-narrative.js +142 -0
  96. package/node_modules/@ocean/brain/dist/memory/index-sync.js +124 -0
  97. package/node_modules/@ocean/brain/dist/memory/lesson-activation.js +93 -0
  98. package/node_modules/@ocean/brain/dist/memory/lesson-learning.js +188 -0
  99. package/node_modules/@ocean/brain/dist/memory/lessons.js +321 -0
  100. package/node_modules/@ocean/brain/dist/memory/memory-audit.js +100 -0
  101. package/node_modules/@ocean/brain/dist/memory/memory-digest.js +49 -0
  102. package/node_modules/@ocean/brain/dist/memory/memory-harvest.js +345 -0
  103. package/node_modules/@ocean/brain/dist/memory/memory-paths.js +174 -0
  104. package/node_modules/@ocean/brain/dist/memory/memory-review.js +278 -0
  105. package/node_modules/@ocean/brain/dist/memory/memory-trash.js +152 -0
  106. package/node_modules/@ocean/brain/dist/memory/memory-write.js +216 -0
  107. package/node_modules/@ocean/brain/dist/memory/model-narrative.js +129 -0
  108. package/node_modules/@ocean/brain/dist/memory/profile-facts.js +103 -0
  109. package/node_modules/@ocean/brain/dist/memory/session-promotion.js +61 -0
  110. package/node_modules/@ocean/brain/dist/memory/session-summary.js +113 -0
  111. package/node_modules/@ocean/brain/dist/memory/signal-detection.js +66 -0
  112. package/node_modules/@ocean/brain/package.json +11 -0
  113. package/node_modules/@ocean/context/dist/context/context-compression.js +66 -0
  114. package/node_modules/@ocean/context/dist/context/context-cost.js +587 -0
  115. package/node_modules/@ocean/context/dist/context/context-ladder.js +363 -0
  116. package/node_modules/@ocean/context/dist/context/context-packet.js +213 -0
  117. package/node_modules/@ocean/context/dist/context/context-references.js +255 -0
  118. package/node_modules/@ocean/context/dist/context/intent-router.js +259 -0
  119. package/node_modules/@ocean/context/dist/context/resource-injection.js +36 -0
  120. package/node_modules/@ocean/context/package.json +11 -0
  121. package/node_modules/@ocean/core/dist/domain/brain/brain-record.js +22 -0
  122. package/node_modules/@ocean/core/dist/domain/brain/record-scope.js +22 -0
  123. package/node_modules/@ocean/core/dist/domain/capabilities/browser-contract.js +64 -0
  124. package/node_modules/@ocean/core/dist/domain/capabilities/capability-contract.js +16 -0
  125. package/node_modules/@ocean/core/dist/domain/capabilities/capability-manifest.js +72 -0
  126. package/node_modules/@ocean/core/dist/domain/context/context-validator.js +5 -0
  127. package/node_modules/@ocean/core/dist/domain/context/context.js +34 -0
  128. package/node_modules/@ocean/core/dist/domain/context/project-id.js +30 -0
  129. package/node_modules/@ocean/core/dist/domain/evidence/evidence.js +16 -0
  130. package/node_modules/@ocean/core/dist/domain/mcp/mcp-contract.js +36 -0
  131. package/node_modules/@ocean/core/dist/domain/mcp/memory-contract.js +41 -0
  132. package/node_modules/@ocean/core/dist/domain/ports/brain-index-port.js +7 -0
  133. package/node_modules/@ocean/core/dist/domain/ports/browser-port.js +8 -0
  134. package/node_modules/@ocean/core/dist/domain/ports/embedder-port.js +2 -0
  135. package/node_modules/@ocean/core/dist/domain/ports/platform-ports.js +2 -0
  136. package/node_modules/@ocean/core/dist/domain/ports/runtime-ports.js +2 -0
  137. package/node_modules/@ocean/core/dist/domain/ports/session-store-port.js +2 -0
  138. package/node_modules/@ocean/core/dist/domain/process/process-events.js +5 -0
  139. package/node_modules/@ocean/core/dist/domain/profiles/profile-distribution.js +19 -0
  140. package/node_modules/@ocean/core/dist/domain/profiles/profile-policy.js +34 -0
  141. package/node_modules/@ocean/core/dist/domain/profiles/profile-selection.js +73 -0
  142. package/node_modules/@ocean/core/dist/domain/profiles/profile-upgrade.js +123 -0
  143. package/node_modules/@ocean/core/dist/domain/profiles/profile-validator.js +5 -0
  144. package/node_modules/@ocean/core/dist/domain/profiles/profile.js +218 -0
  145. package/node_modules/@ocean/core/dist/domain/profiles/runtime-config.js +30 -0
  146. package/node_modules/@ocean/core/dist/domain/providers/provider-capability.js +28 -0
  147. package/node_modules/@ocean/core/dist/domain/providers/provider.js +2 -0
  148. package/node_modules/@ocean/core/dist/domain/redaction/redaction.js +86 -0
  149. package/node_modules/@ocean/core/dist/domain/runs/agent-tools.js +92 -0
  150. package/node_modules/@ocean/core/dist/domain/runs/execution-plan.js +71 -0
  151. package/node_modules/@ocean/core/dist/domain/runs/run-contract.js +38 -0
  152. package/node_modules/@ocean/core/dist/domain/sessions/entry-contract.js +31 -0
  153. package/node_modules/@ocean/core/dist/domain/sessions/handoff.js +78 -0
  154. package/node_modules/@ocean/core/dist/domain/sessions/session.js +58 -0
  155. package/node_modules/@ocean/core/dist/domain/skills/default-skills.js +29 -0
  156. package/node_modules/@ocean/core/dist/domain/skills/skill-validator.js +5 -0
  157. package/node_modules/@ocean/core/dist/domain/skills/skill.js +11 -0
  158. package/node_modules/@ocean/core/dist/domain/tasks/task-id.js +85 -0
  159. package/node_modules/@ocean/core/dist/shared/fs-utils.js +212 -0
  160. package/node_modules/@ocean/core/dist/shared/local-date.js +16 -0
  161. package/node_modules/@ocean/core/dist/shared/paths.js +324 -0
  162. package/node_modules/@ocean/core/dist/shared/project-resolution.js +1065 -0
  163. package/node_modules/@ocean/core/dist/shared/task-reference.js +133 -0
  164. package/node_modules/@ocean/core/package.json +14 -0
  165. package/node_modules/@ocean/loop/dist/handoff/handoff-service.js +133 -0
  166. package/node_modules/@ocean/loop/dist/hooks/lifecycle-hooks.js +15 -0
  167. package/node_modules/@ocean/loop/dist/hooks/session-end-hook.js +183 -0
  168. package/node_modules/@ocean/loop/dist/hooks/session-start-hook.js +237 -0
  169. package/node_modules/@ocean/loop/dist/infrastructure/persistence/session-store.js +690 -0
  170. package/node_modules/@ocean/loop/dist/infrastructure/persistence/session-validator.js +5 -0
  171. package/node_modules/@ocean/loop/dist/loops/iteration-graph.js +147 -0
  172. package/node_modules/@ocean/loop/dist/loops/task-loop-record.js +2 -0
  173. package/node_modules/@ocean/loop/dist/loops/task-loop.js +281 -0
  174. package/node_modules/@ocean/loop/dist/operations/memory-knowledge-operations.js +263 -0
  175. package/node_modules/@ocean/loop/dist/operations/operation-contract.js +227 -0
  176. package/node_modules/@ocean/loop/dist/operations/operation-scope.js +28 -0
  177. package/node_modules/@ocean/loop/dist/operations/project-operations.js +93 -0
  178. package/node_modules/@ocean/loop/dist/operations/record-io.js +65 -0
  179. package/node_modules/@ocean/loop/dist/operations/record-operations.js +45 -0
  180. package/node_modules/@ocean/loop/dist/operations/task-linker.js +40 -0
  181. package/node_modules/@ocean/loop/dist/operations/task-operations.js +279 -0
  182. package/node_modules/@ocean/loop/dist/operations/write-guard.js +157 -0
  183. package/node_modules/@ocean/loop/dist/runs/prompt-assembly.js +112 -0
  184. package/node_modules/@ocean/loop/dist/runs/run-agent.js +425 -0
  185. package/node_modules/@ocean/loop/dist/runs/run-authorization.js +24 -0
  186. package/node_modules/@ocean/loop/dist/runs/tool-loop.js +173 -0
  187. package/node_modules/@ocean/loop/dist/sessions/session-closeout.js +150 -0
  188. package/node_modules/@ocean/loop/dist/sessions/session-pointer.js +133 -0
  189. package/node_modules/@ocean/loop/dist/sessions/session-projects.js +26 -0
  190. package/node_modules/@ocean/loop/dist/sessions/session-retention.js +132 -0
  191. package/node_modules/@ocean/loop/dist/tasks/archive-tasks.js +210 -0
  192. package/node_modules/@ocean/loop/dist/tasks/checkpoint-task.js +31 -0
  193. package/node_modules/@ocean/loop/dist/tasks/claim-task.js +126 -0
  194. package/node_modules/@ocean/loop/dist/tasks/list-tasks.js +113 -0
  195. package/node_modules/@ocean/loop/dist/tasks/new-task.js +42 -0
  196. package/node_modules/@ocean/loop/dist/tasks/renumber-tasks.js +134 -0
  197. package/node_modules/@ocean/loop/dist/tasks/verification-readiness.js +78 -0
  198. package/node_modules/@ocean/loop/dist/tasks/verify-task.js +234 -0
  199. package/node_modules/@ocean/loop/package.json +11 -0
  200. package/node_modules/@ocean/market/dist/adapters/mcp-adapter.js +64 -0
  201. package/node_modules/@ocean/market/dist/adapters/owned-directory.js +89 -0
  202. package/node_modules/@ocean/market/dist/adapters/plugin-adapter.js +39 -0
  203. package/node_modules/@ocean/market/dist/adapters/skill-adapter.js +32 -0
  204. package/node_modules/@ocean/market/dist/capability/adapter.js +2 -0
  205. package/node_modules/@ocean/market/dist/capability/catalog.js +63 -0
  206. package/node_modules/@ocean/market/dist/capability/content-digest.js +40 -0
  207. package/node_modules/@ocean/market/dist/capability/registry.js +81 -0
  208. package/node_modules/@ocean/market/dist/install/default-marketplace.js +47 -0
  209. package/node_modules/@ocean/market/dist/install/lock.js +34 -0
  210. package/node_modules/@ocean/market/dist/install/marketplace-service.js +165 -0
  211. package/node_modules/@ocean/market/dist/mcp/browser-bridge.js +263 -0
  212. package/node_modules/@ocean/market/dist/mcp/mcp-connection.js +67 -0
  213. package/node_modules/@ocean/market/dist/mcp/mcp-gateway.js +317 -0
  214. package/node_modules/@ocean/market/dist/mcp/mcp-launch.js +102 -0
  215. package/node_modules/@ocean/market/dist/mcp/mcp-runner.js +32 -0
  216. package/node_modules/@ocean/market/dist/security/description-scan.js +45 -0
  217. package/node_modules/@ocean/market/dist/security/permissions.js +57 -0
  218. package/node_modules/@ocean/market/dist/security/sandbox.js +74 -0
  219. package/node_modules/@ocean/market/dist/skills/core-skill-sync.js +113 -0
  220. package/node_modules/@ocean/market/dist/skills/signal-detection.js +84 -0
  221. package/node_modules/@ocean/market/dist/skills/skill-curation.js +123 -0
  222. package/node_modules/@ocean/market/dist/skills/skill-hub.js +220 -0
  223. package/node_modules/@ocean/market/dist/skills/task-observer.js +165 -0
  224. package/node_modules/@ocean/market/package.json +11 -0
  225. package/node_modules/@ocean/services/dist/browser/browser-service.js +124 -0
  226. package/node_modules/@ocean/services/dist/browser/browser-session.js +287 -0
  227. package/node_modules/@ocean/services/dist/browser/browser-task-runner.js +70 -0
  228. package/node_modules/@ocean/services/dist/doctor/workspace-doctor.js +547 -0
  229. package/node_modules/@ocean/services/dist/infrastructure/mcp/call-ledger.js +114 -0
  230. package/node_modules/@ocean/services/dist/infrastructure/mcp/mcp-client.js +162 -0
  231. package/node_modules/@ocean/services/dist/infrastructure/mcp/obsidian-server.js +251 -0
  232. package/node_modules/@ocean/services/dist/infrastructure/mcp/ocean-server.js +880 -0
  233. package/node_modules/@ocean/services/dist/infrastructure/mcp/server-version.js +20 -0
  234. package/node_modules/@ocean/services/dist/infrastructure/mcp/tool-registry.js +29 -0
  235. package/node_modules/@ocean/services/dist/obsidian/conflict-log.js +68 -0
  236. package/node_modules/@ocean/services/dist/obsidian/inbox-promotion.js +80 -0
  237. package/node_modules/@ocean/services/dist/obsidian/vault-discovery.js +113 -0
  238. package/node_modules/@ocean/services/dist/obsidian/vault-ingestion.js +77 -0
  239. package/node_modules/@ocean/services/dist/obsidian/vault-sync.js +73 -0
  240. package/node_modules/@ocean/services/dist/obsidian/vault-writer.js +75 -0
  241. package/node_modules/@ocean/services/package.json +11 -0
  242. package/ocean-marketplace.json +415 -0
  243. package/package.json +67 -4
  244. package/skills/core/business-logic/SKILL.md +22 -0
  245. package/skills/core/catch-up/SKILL.md +17 -0
  246. package/skills/core/core-thinking/SKILL.md +11 -0
  247. package/skills/core/design-thinking/SKILL.md +19 -0
  248. package/skills/core/graft/SKILL.md +156 -0
  249. package/skills/core/loop/SKILL.md +20 -0
  250. package/skills/core/session-handoff/SKILL.md +15 -0
  251. package/skills/core/use-browser/SKILL.md +69 -0
  252. package/skills/core/verification/SKILL.md +11 -0
  253. package/skills/index.json +56 -0
  254. package/templates/README.md +4 -0
  255. package/templates/profiles/default.json +51 -0
  256. package/templates/profiles/developer.json +51 -0
  257. package/templates/profiles/reviewer.json +51 -0
  258. package/templates/profiles/strategist.json +51 -0
  259. package/templates/workspace/00-inbox/INBOX.md +7 -0
  260. package/templates/workspace/00-inbox/candidates/.gitkeep +0 -0
  261. package/templates/workspace/00-inbox/native/.gitkeep +0 -0
  262. package/templates/workspace/01-daily/.gitkeep +0 -0
  263. package/templates/workspace/02-personal/CONFLICTS.md +7 -0
  264. package/templates/workspace/02-personal/MEMORY.md +15 -0
  265. package/templates/workspace/02-personal/goals/.gitkeep +0 -0
  266. package/templates/workspace/02-personal/identity/.gitkeep +0 -0
  267. package/templates/workspace/02-personal/preferences/.gitkeep +0 -0
  268. package/templates/workspace/03-professional/.gitkeep +0 -0
  269. package/templates/workspace/04-projects/PROJECTS.md +5 -0
  270. package/templates/workspace/04-projects/_template/docs/.gitkeep +0 -0
  271. package/templates/workspace/04-projects/_template/memory/.gitkeep +0 -0
  272. package/templates/workspace/04-projects/_template/tasks/.gitkeep +0 -0
  273. package/templates/workspace/05-knowledge/KNOWLEDGE.md +8 -0
  274. package/templates/workspace/05-knowledge/decisions/.gitkeep +0 -0
  275. package/templates/workspace/05-knowledge/lessons/.gitkeep +0 -0
  276. package/templates/workspace/06-templates/TEMPLATES.md +25 -0
  277. package/templates/workspace/06-templates/decision.md +8 -0
  278. package/templates/workspace/06-templates/intelligence.md +32 -0
  279. package/templates/workspace/06-templates/project-claude.md +48 -0
  280. package/templates/workspace/06-templates/session.md +38 -0
  281. package/templates/workspace/06-templates/task.md +42 -0
  282. package/templates/workspace/MANIFEST.json +51 -0
  283. package/templates/workspace/bridge/config/CONFIG.md +21 -0
  284. package/templates/workspace/bridge/config/runtime.json +4 -0
  285. package/templates/workspace/charter/core.md +104 -0
  286. package/templates/workspace/charter/policies/README.md +31 -0
  287. package/templates/workspace/charter/policies/claude-code-context.md +90 -0
  288. package/templates/workspace/charter/policies/concise-output.md +29 -0
  289. package/templates/workspace/charter/policies/context.md +91 -0
  290. package/templates/workspace/charter/policies/contracts/task.md +189 -0
  291. package/templates/workspace/charter/policies/git.md +60 -0
  292. package/templates/workspace/charter/policies/graph.md +47 -0
  293. package/templates/workspace/charter/policies/knowledge.md +33 -0
  294. package/templates/workspace/charter/policies/lifecycle.md +119 -0
  295. package/templates/workspace/charter/policies/memory.md +67 -0
  296. package/templates/workspace/charter/policies/minimal-change.md +43 -0
  297. package/templates/workspace/charter/policies/models.md +57 -0
  298. package/templates/workspace/charter/policies/privacy-terms.txt +3 -0
  299. package/templates/workspace/charter/policies/response.md +39 -0
  300. package/templates/workspace/charter/policies/skill-observer.md +44 -0
  301. package/templates/workspace/charter/policies/stack.md +23 -0
  302. package/templates/workspace/charter/policies/task.md +139 -0
  303. package/templates/workspace/charter/policies/verification.md +29 -0
  304. package/templates/workspace/sessions/.gitkeep +0 -0
@@ -0,0 +1,137 @@
1
+ import { spawn } from "node:child_process";
2
+ import path from "node:path";
3
+ import { DEFAULT_MAX_OUTPUT_BYTES } from "../process/cli-process.js";
4
+ import { ownsGroup, superviseProcess } from "../process/process-supervisor.js";
5
+ import { resolveOriginalExecutable } from "./provider-registry.js";
6
+ // The plan's model, unless it leaves the client's own default ("provider-managed" or absent).
7
+ export function explicitModel(model) {
8
+ return model && model !== "provider-managed" ? model : undefined;
9
+ }
10
+ // A Claude request as Claude Agent SDK options. The SDK turns them into Claude Code's own flags
11
+ // (--resume, --model, --permission-mode, --add-dir) and speaks its stream protocol, so Ocean no
12
+ // longer builds `claude -p` arguments or parses its output itself.
13
+ export function claudeSdkOptions(request, executable) {
14
+ const model = explicitModel(request.model);
15
+ return {
16
+ // The user's own Claude Code, past Ocean's shims, never the SDK's bundled copy.
17
+ pathToClaudeCodeExecutable: executable,
18
+ cwd: path.resolve(request.cwd),
19
+ // Built fresh for every run, as for every provider: the plan's variables over this process's.
20
+ env: { ...process.env, ...request.env },
21
+ // Claude Code's own system prompt, as `claude -p` has it. Left unset, the SDK sends an empty one.
22
+ // Settings and CLAUDE.md need nothing: an unset settingSources loads every source, as the CLI does.
23
+ systemPrompt: { type: "preset", preset: "claude_code" },
24
+ ...(request.resumeId ? { resume: request.resumeId } : {}),
25
+ ...(model ? { model } : {}),
26
+ // Read-only is enforced with Claude Code's own controls, never only asked for in the prompt.
27
+ ...(request.readOnly
28
+ ? { permissionMode: "plan", extraArgs: { restricted: null } }
29
+ : {}),
30
+ ...(request.readDirectories?.length
31
+ ? { additionalDirectories: request.readDirectories }
32
+ : {}),
33
+ };
34
+ }
35
+ function exited(child) {
36
+ if (child.exitCode !== null || child.signalCode !== null)
37
+ return Promise.resolve(child.exitCode);
38
+ return new Promise((resolve) => child.once("exit", resolve));
39
+ }
40
+ // One headless Claude turn through the Agent SDK, with the same contract as every CLI provider:
41
+ // Ocean spawns the process (so the session store gets its pid and its environment is the
42
+ // plan's), every SDK message becomes a `json` event, and the run's timeout (124) and output
43
+ // budget (125) end it exactly as they end any other provider, through the same supervisor.
44
+ export async function runClaudeSdk(request) {
45
+ const executable = resolveOriginalExecutable("claude");
46
+ // The SDK loads only when Claude actually runs, not on every `ocean` command.
47
+ const { query } = await import("@anthropic-ai/claude-agent-sdk");
48
+ const abortController = new AbortController();
49
+ const events = [];
50
+ let terminating = false;
51
+ const supervision = superviseProcess({
52
+ timeoutMs: request.timeoutMs ?? 60_000,
53
+ maxOutputBytes: request.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES,
54
+ onTerminate: () => {
55
+ terminating = true;
56
+ abortController.abort();
57
+ },
58
+ // JSON lines reach us as the SDK's messages; lines that are not JSON never do (a crash
59
+ // notice, a plain-text warning), so keep those as text events, as the CLI runner does.
60
+ onLine: (line) => {
61
+ try {
62
+ JSON.parse(line);
63
+ }
64
+ catch {
65
+ const event = { type: "text", data: line };
66
+ events.push(event);
67
+ request.onEvent?.(event);
68
+ }
69
+ },
70
+ });
71
+ let child;
72
+ let failure;
73
+ let errorResult = false;
74
+ let code = null;
75
+ try {
76
+ const consumed = (async () => {
77
+ const messages = query({
78
+ prompt: request.prompt,
79
+ options: {
80
+ ...claudeSdkOptions(request, executable),
81
+ abortController,
82
+ spawnClaudeCodeProcess: (options) => {
83
+ const spawned = spawn(options.command, options.args, {
84
+ cwd: options.cwd,
85
+ env: options.env,
86
+ signal: options.signal,
87
+ stdio: ["pipe", "pipe", "pipe"],
88
+ detached: ownsGroup,
89
+ windowsHide: true,
90
+ });
91
+ child = spawned;
92
+ supervision.attach(spawned);
93
+ if (spawned.pid)
94
+ request.onSpawn?.(spawned.pid);
95
+ return spawned;
96
+ },
97
+ },
98
+ });
99
+ for await (const message of messages) {
100
+ if (terminating)
101
+ break;
102
+ const event = { type: "json", data: message };
103
+ events.push(event);
104
+ request.onEvent?.(event);
105
+ if (message.type === "result" && message.is_error)
106
+ errorResult = true;
107
+ }
108
+ })().catch((error) => {
109
+ failure = error instanceof Error ? error.message : String(error);
110
+ });
111
+ // After a forced stop the run no longer waits on the SDK, whose message stream may never
112
+ // settle once its process and pipes are gone.
113
+ await Promise.race([consumed, supervision.released]);
114
+ if (!supervision.spawnError && child)
115
+ code = await exited(child);
116
+ }
117
+ finally {
118
+ supervision.finish();
119
+ }
120
+ if (supervision.spawnError && !supervision.timedOut)
121
+ throw supervision.spawnError;
122
+ supervision.flush();
123
+ const stopped = supervision.timedOut || supervision.outputLimitExceeded;
124
+ return {
125
+ exitCode: stopped || !child || code === null
126
+ ? supervision.exitCode(child ? code : null)
127
+ : code !== 0
128
+ ? code
129
+ : failure || errorResult
130
+ ? 1
131
+ : 0,
132
+ events,
133
+ stderr: supervision.stderr +
134
+ (stopped ? supervision.stopNote : failure ? `${failure}\n` : ""),
135
+ };
136
+ }
137
+ //# sourceMappingURL=claude-sdk.js.map
@@ -0,0 +1,14 @@
1
+ import path from "node:path";
2
+ import { oceanPath, SYSTEM_DIR } from "@ocean/core/shared/paths.js";
3
+ export function resolveClientHome(profile) {
4
+ const configured = profile.clients[profile.provider]?.home;
5
+ if (!configured)
6
+ return undefined;
7
+ const root = path.resolve(oceanPath(SYSTEM_DIR, "clients"));
8
+ const resolved = path.resolve(oceanPath(configured));
9
+ if (resolved !== root && !resolved.startsWith(`${root}${path.sep}`)) {
10
+ throw new Error(`Client home must stay under Ocean system/clients: ${configured}`);
11
+ }
12
+ return resolved;
13
+ }
14
+ //# sourceMappingURL=client-home.js.map
@@ -0,0 +1,146 @@
1
+ // An in-memory BrowserProvider used by tests to exercise application-layer policy
2
+ // (authority, approval, verification) without launching a real browser.
3
+ function nthIndex(value, needle, occurrence) {
4
+ let from = 0;
5
+ for (let current = 1; current <= occurrence; current += 1) {
6
+ const index = value.indexOf(needle, from);
7
+ if (index < 0)
8
+ return -1;
9
+ if (current === occurrence)
10
+ return index;
11
+ from = index + needle.length;
12
+ }
13
+ return -1;
14
+ }
15
+ class FakePage {
16
+ url = "about:blank";
17
+ title = "";
18
+ inputs = new Map();
19
+ elements = [];
20
+ scrollY = 0;
21
+ clickTargets = new Map();
22
+ }
23
+ class FakeHandle {
24
+ page;
25
+ constructor(page) {
26
+ this.page = page;
27
+ }
28
+ // Test-only configuration hooks, not part of the BrowserHandle contract: they let a
29
+ // test script a scenario (a click that navigates, or a selector's current element
30
+ // count) for the application layer to verify against, without a real browser.
31
+ setElements(elements) {
32
+ this.page.elements = elements;
33
+ }
34
+ setClickTarget(selector, url) {
35
+ this.page.clickTargets.set(selector, url);
36
+ }
37
+ async state() {
38
+ return { url: this.page.url, title: this.page.title };
39
+ }
40
+ async navigate(url) {
41
+ this.page.url = url;
42
+ this.page.title = `Title for ${url}`;
43
+ return this.state();
44
+ }
45
+ async readText() {
46
+ return {
47
+ ...(await this.state()),
48
+ text: this.page.elements.map((element) => element.text).join(" "),
49
+ };
50
+ }
51
+ async observe() {
52
+ return { ...(await this.state()), elements: this.page.elements };
53
+ }
54
+ async extract(selector, attribute) {
55
+ const values = this.page.elements
56
+ .filter((element) => element.id === selector || element.name === selector)
57
+ .map((element) => (attribute ? null : element.text));
58
+ return { selector, count: values.length, values };
59
+ }
60
+ async click(selector) {
61
+ const urlBefore = this.page.url;
62
+ const target = this.page.clickTargets.get(selector);
63
+ if (target) {
64
+ this.page.url = target;
65
+ this.page.title = `Title for ${target}`;
66
+ }
67
+ return { ...(await this.state()), urlBefore };
68
+ }
69
+ async type(selector, text, clear = true) {
70
+ const current = clear ? "" : (this.page.inputs.get(selector) ?? "");
71
+ const value = current + text;
72
+ this.page.inputs.set(selector, value);
73
+ return { selector, typed: text.length, value };
74
+ }
75
+ async replaceText(selector, oldText, newText, occurrence = 1) {
76
+ const value = this.page.inputs.get(selector) ?? "";
77
+ const index = nthIndex(value, oldText, occurrence);
78
+ if (index < 0)
79
+ throw new Error(`Text occurrence not found: ${occurrence}`);
80
+ const next = value.slice(0, index) + newText + value.slice(index + oldText.length);
81
+ this.page.inputs.set(selector, next);
82
+ return { selector, oldText, newText, occurrence, value: next };
83
+ }
84
+ async select(selector, value) {
85
+ this.page.inputs.set(selector, value);
86
+ return { selector, value };
87
+ }
88
+ async scroll(deltaY = 0) {
89
+ this.page.scrollY = Math.max(0, this.page.scrollY + deltaY);
90
+ return { scrollY: this.page.scrollY };
91
+ }
92
+ async wait() {
93
+ return this.state();
94
+ }
95
+ async upload(selector, paths) {
96
+ this.page.inputs.set(selector, paths.join(","));
97
+ return {
98
+ selector,
99
+ attached: paths.map((filePath) => filePath.split("/").pop() ?? filePath),
100
+ };
101
+ }
102
+ async download(selector, destinationDir) {
103
+ return { selector, path: `${destinationDir}/fake-download.txt`, size: 0 };
104
+ }
105
+ async submit(_selector) {
106
+ const urlBefore = this.page.url;
107
+ const bodyBefore = this.page.elements
108
+ .map((element) => element.text)
109
+ .join(" ");
110
+ return {
111
+ ...(await this.state()),
112
+ urlBefore,
113
+ bodyBefore,
114
+ bodyAfter: bodyBefore,
115
+ };
116
+ }
117
+ async release() { }
118
+ }
119
+ export class FakeBrowserProvider {
120
+ pages = new Map();
121
+ launchCount = 0;
122
+ async detect() {
123
+ return { ok: true, detail: "fake provider always available" };
124
+ }
125
+ async launch(profileDir, port = 0) {
126
+ this.launchCount += 1;
127
+ const launch = {
128
+ pid: this.launchCount,
129
+ port,
130
+ endpoint: `fake://${profileDir}`,
131
+ profileDir,
132
+ };
133
+ this.pages.set(launch.endpoint, new FakePage());
134
+ return launch;
135
+ }
136
+ async connect(launch) {
137
+ const page = this.pages.get(launch.endpoint);
138
+ if (!page)
139
+ throw new Error(`No fake session for endpoint: ${launch.endpoint}`);
140
+ return new FakeHandle(page);
141
+ }
142
+ async close(launch) {
143
+ this.pages.delete(launch.endpoint);
144
+ }
145
+ }
146
+ //# sourceMappingURL=fake-browser-provider.js.map
@@ -0,0 +1,74 @@
1
+ import { oceanEnv } from "@ocean/core/shared/paths.js";
2
+ // Local-only embedder for the brain index (T-228). Talks to a local Ollama daemon over
3
+ // loopback only — never a remote host, never a `:cloud` model (Ollama's proxy to
4
+ // ollama.com). This is a hard privacy boundary, not a convenience default: brain/02-personal
5
+ // and brain/05-knowledge content must never leave the machine to be embedded.
6
+ const LOOPBACK_HOSTNAMES = new Set(["127.0.0.1", "localhost", "::1", "[::1]"]);
7
+ export class RemoteEmbedderRefusedError extends Error {
8
+ }
9
+ function assertLoopback(rawUrl) {
10
+ let url;
11
+ try {
12
+ url = new URL(rawUrl);
13
+ }
14
+ catch {
15
+ throw new RemoteEmbedderRefusedError(`OCEAN_OLLAMA_URL is not a valid URL: ${rawUrl}`);
16
+ }
17
+ if (!LOOPBACK_HOSTNAMES.has(url.hostname)) {
18
+ throw new RemoteEmbedderRefusedError(`refusing non-loopback embedder host '${url.hostname}' — only 127.0.0.1/localhost/::1 are allowed`);
19
+ }
20
+ return url;
21
+ }
22
+ function assertNotCloudModel(model) {
23
+ if (model.toLowerCase().includes("cloud")) {
24
+ throw new RemoteEmbedderRefusedError(`refusing ':cloud'-style model '${model}' — it proxies to a remote host`);
25
+ }
26
+ }
27
+ const DEFAULT_BATCH_SIZE = 32;
28
+ // Creates and validates an embedder against the live Ollama daemon: confirms loopback host,
29
+ // confirms the model name and `/api/show` report neither name a remote model, and probes
30
+ // dimensions with a single embed call. Throws (does not silently fall back) on any refusal —
31
+ // reindex is expected to fail loudly unless the caller explicitly passed --no-vectors.
32
+ export async function createOllamaEmbedder(options = {}) {
33
+ const baseUrl = options.baseUrl ?? oceanEnv("OLLAMA_URL") ?? "http://127.0.0.1:11434";
34
+ const model = options.model ?? oceanEnv("EMBED_MODEL") ?? "embeddinggemma";
35
+ const batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE;
36
+ const doFetch = options.fetchImpl ?? fetch;
37
+ const url = assertLoopback(baseUrl);
38
+ assertNotCloudModel(model);
39
+ const showResponse = await doFetch(new URL("/api/show", url), {
40
+ method: "POST",
41
+ headers: { "content-type": "application/json" },
42
+ body: JSON.stringify({ model }),
43
+ });
44
+ if (showResponse.ok) {
45
+ const show = (await showResponse.json());
46
+ if (show.remote_host || show.remote_model) {
47
+ throw new RemoteEmbedderRefusedError(`refusing model '${model}' — Ollama reports it as remote (${show.remote_host ?? show.remote_model})`);
48
+ }
49
+ }
50
+ const embed = async (texts) => {
51
+ const out = [];
52
+ for (let start = 0; start < texts.length; start += batchSize) {
53
+ const batch = texts.slice(start, start + batchSize);
54
+ const response = await doFetch(new URL("/api/embed", url), {
55
+ method: "POST",
56
+ headers: { "content-type": "application/json" },
57
+ body: JSON.stringify({ model, input: batch }),
58
+ });
59
+ if (!response.ok) {
60
+ throw new Error(`Ollama /api/embed failed with status ${response.status}: ${await response.text()}`);
61
+ }
62
+ const body = (await response.json());
63
+ for (const embedding of body.embeddings)
64
+ out.push(new Float32Array(embedding));
65
+ }
66
+ return out;
67
+ };
68
+ const probe = await embed(["dimension probe"]);
69
+ const dimensions = probe[0]?.length ?? 0;
70
+ if (dimensions <= 0)
71
+ throw new Error(`Ollama returned an empty embedding for model '${model}'`);
72
+ return { model, dimensions, embed };
73
+ }
74
+ //# sourceMappingURL=ollama-embedder.js.map
@@ -0,0 +1,268 @@
1
+ import { redactRuntimeText } from "@ocean/core/domain/redaction/redaction.js";
2
+ import { DEFAULT_MAX_OUTPUT_BYTES } from "../process/cli-process.js";
3
+ // OpenAI-compatible chat completions over built-in fetch (T-245 Phase 4). Endpoints and
4
+ // credential variable names are fixed here, never taken from a profile, so a profile cannot
5
+ // send a credential to another host or read another provider's credential. Checked against
6
+ // the providers' docs on 2026-10-05 (see the T-245 plan).
7
+ export const completionEndpoints = {
8
+ deepseek: "https://api.deepseek.com/chat/completions",
9
+ openrouter: "https://openrouter.ai/api/v1/chat/completions",
10
+ };
11
+ export const completionCredentialEnv = {
12
+ deepseek: "DEEPSEEK_API_KEY",
13
+ openrouter: "OPENROUTER_API_KEY",
14
+ };
15
+ const DEFAULT_TIMEOUT_MS = 60_000;
16
+ const MAX_COMPLETION_TOKENS = 8_192;
17
+ const BACKOFF_BASE_MS = 500;
18
+ const BACKOFF_MAX_MS = 8_000;
19
+ class CompletionFailure extends Error {
20
+ exitCode;
21
+ constructor(message, exitCode) {
22
+ super(message);
23
+ this.exitCode = exitCode;
24
+ }
25
+ }
26
+ function abortableSleep(ms, signal) {
27
+ return new Promise((resolve, reject) => {
28
+ if (signal.aborted)
29
+ return reject(signal.reason);
30
+ const timer = setTimeout(() => {
31
+ signal.removeEventListener("abort", onAbort);
32
+ resolve();
33
+ }, ms);
34
+ const onAbort = () => {
35
+ clearTimeout(timer);
36
+ reject(signal.reason);
37
+ };
38
+ signal.addEventListener("abort", onAbort, { once: true });
39
+ });
40
+ }
41
+ // Reads at most `maxBytes` of the body; a larger body is cancelled, never buffered whole.
42
+ async function readBounded(response, maxBytes) {
43
+ if (!response.body)
44
+ return "";
45
+ const reader = response.body.getReader();
46
+ const chunks = [];
47
+ let total = 0;
48
+ for (;;) {
49
+ const { done, value } = await reader.read();
50
+ if (done)
51
+ break;
52
+ total += value.byteLength;
53
+ if (total > maxBytes) {
54
+ await reader.cancel();
55
+ throw new CompletionFailure("Output budget exceeded.", 125);
56
+ }
57
+ chunks.push(value);
58
+ }
59
+ return Buffer.concat(chunks).toString("utf8");
60
+ }
61
+ function retryDelay(response, attempt) {
62
+ const header = Number(response.headers.get("retry-after"));
63
+ const backoff = BACKOFF_BASE_MS * 2 ** (attempt - 1);
64
+ return Math.min(BACKOFF_MAX_MS, Number.isFinite(header) && header > 0 ? header * 1_000 : backoff);
65
+ }
66
+ function rateLimit(response) {
67
+ return Object.fromEntries([...response.headers].filter(([name]) => name.startsWith("x-ratelimit-") || name === "retry-after"));
68
+ }
69
+ const MAX_TOOL_CALLS_PER_REPLY = 16;
70
+ function parseToolCalls(value) {
71
+ if (value === undefined || value === null)
72
+ return undefined;
73
+ if (!Array.isArray(value) || value.length > MAX_TOOL_CALLS_PER_REPLY)
74
+ throw new CompletionFailure("Malformed completion response: tool_calls", 1);
75
+ return value.map((call) => {
76
+ const { id, function: fn } = (call ?? {});
77
+ if (typeof id !== "string" ||
78
+ typeof fn?.name !== "string" ||
79
+ typeof fn.arguments !== "string")
80
+ throw new CompletionFailure("Malformed completion response: tool_calls", 1);
81
+ return {
82
+ id,
83
+ type: "function",
84
+ function: { name: fn.name, arguments: fn.arguments },
85
+ };
86
+ });
87
+ }
88
+ function parseReply(source, fallbackModel) {
89
+ let body;
90
+ try {
91
+ body = JSON.parse(source);
92
+ }
93
+ catch {
94
+ throw new CompletionFailure("Malformed completion response: not JSON", 1);
95
+ }
96
+ const message = body?.choices?.[0]?.message;
97
+ const toolCalls = parseToolCalls(message?.tool_calls);
98
+ const content = message?.content ?? null;
99
+ if (typeof content !== "string" && !(content === null && toolCalls?.length))
100
+ throw new CompletionFailure("Malformed completion response: no choices[0].message.content", 1);
101
+ return {
102
+ message: {
103
+ role: "assistant",
104
+ content,
105
+ ...(toolCalls?.length ? { tool_calls: toolCalls } : {}),
106
+ },
107
+ model: typeof body.model === "string" ? body.model : fallbackModel,
108
+ usage: body.usage ?? null,
109
+ id: typeof body.id === "string" ? body.id : null,
110
+ };
111
+ }
112
+ // One chat turn: credential check, request, bounded read, transient retries. Throws a
113
+ // CompletionFailure (with its exit code) on anything else.
114
+ async function chat(request, deps, emit, signal) {
115
+ const endpoint = deps.endpoints[request.provider];
116
+ const credentialName = completionCredentialEnv[request.provider];
117
+ if (!endpoint)
118
+ throw new CompletionFailure(`Unsupported completion provider: ${request.provider}`, 1);
119
+ // Fails before any request is made; names the variable, never its value.
120
+ const credential = deps.env[credentialName];
121
+ if (!credential)
122
+ throw new CompletionFailure(`Missing credential: set ${credentialName} in the environment`, 1);
123
+ const maxBytes = request.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
124
+ const attempts = Math.max(1, request.maxAttempts ?? 1);
125
+ for (let attempt = 1;; attempt += 1) {
126
+ const response = await deps.fetch(endpoint, {
127
+ method: "POST",
128
+ headers: {
129
+ authorization: `Bearer ${credential}`,
130
+ "content-type": "application/json",
131
+ },
132
+ body: JSON.stringify({
133
+ model: request.model,
134
+ messages: request.messages,
135
+ max_tokens: MAX_COMPLETION_TOKENS,
136
+ stream: false,
137
+ ...(request.temperature === undefined
138
+ ? {}
139
+ : { temperature: request.temperature }),
140
+ ...(request.tools.length ? { tools: request.tools } : {}),
141
+ }),
142
+ // A redirect could carry the credential to another host; it is an error instead.
143
+ redirect: "error",
144
+ signal,
145
+ });
146
+ const meta = {
147
+ provider: request.provider,
148
+ status: response.status,
149
+ requestId: response.headers.get("x-request-id"),
150
+ rateLimit: rateLimit(response),
151
+ attempt,
152
+ };
153
+ if (response.ok)
154
+ return {
155
+ ...parseReply(await readBounded(response, maxBytes), request.model),
156
+ meta,
157
+ };
158
+ // Only 429 and 5xx are transient. Authentication, validation and policy failures are
159
+ // never retried.
160
+ const transient = response.status === 429 || response.status >= 500;
161
+ // An upstream error body is untrusted: it could echo the request back, so the credential
162
+ // is removed before it reaches stderr or the session.
163
+ const detail = redactRuntimeText((await readBounded(response, 4_096).catch(() => ""))
164
+ .split(credential)
165
+ .join("[REDACTED]")
166
+ .slice(0, 500));
167
+ if (!transient || attempt >= attempts) {
168
+ await response.body?.cancel().catch(() => undefined);
169
+ throw new CompletionFailure(`Completion request failed: HTTP ${response.status}${detail ? ` ${detail}` : ""}`, 1);
170
+ }
171
+ const delayMs = retryDelay(response, attempt);
172
+ emit({
173
+ type: "json",
174
+ data: { type: "completion_retry", ...meta, delayMs },
175
+ });
176
+ await deps.sleep(delayMs, signal);
177
+ }
178
+ }
179
+ async function complete(request, deps, emit, signal) {
180
+ const started = Date.now();
181
+ const reply = await chat({
182
+ provider: request.provider,
183
+ model: request.model,
184
+ temperature: request.temperature,
185
+ messages: [{ role: "user", content: request.prompt }],
186
+ tools: [],
187
+ maxOutputBytes: request.maxOutputBytes,
188
+ maxAttempts: request.maxAttempts,
189
+ }, deps, emit, signal);
190
+ if (typeof reply.message.content !== "string")
191
+ throw new CompletionFailure("Malformed completion response: no choices[0].message.content", 1);
192
+ emit({
193
+ type: "json",
194
+ data: {
195
+ type: "completion",
196
+ ...reply.meta,
197
+ id: reply.id,
198
+ model: reply.model,
199
+ usage: reply.usage,
200
+ durationMs: Date.now() - started,
201
+ text: reply.message.content,
202
+ },
203
+ });
204
+ }
205
+ function defaultDeps(overrides) {
206
+ return {
207
+ // Resolved per call, so a fetch installed after import is the one used.
208
+ fetch: (...args) => globalThis.fetch(...args),
209
+ endpoints: completionEndpoints,
210
+ env: process.env,
211
+ sleep: abortableSleep,
212
+ ...overrides,
213
+ };
214
+ }
215
+ // The tool loop's transport: one turn per call, under the caller's signal. A failure is
216
+ // thrown with an `exitCode` (124 when the caller's deadline aborted it).
217
+ export function createChatTransport(overrides = {}) {
218
+ const deps = defaultDeps(overrides);
219
+ return async ({ signal, onEvent, ...request }) => {
220
+ try {
221
+ const { meta: _meta, ...reply } = await chat(request, deps, (event) => onEvent?.(event), signal);
222
+ return reply;
223
+ }
224
+ catch (error) {
225
+ if (error instanceof CompletionFailure)
226
+ throw error;
227
+ if (signal.aborted)
228
+ throw signal.reason;
229
+ throw new CompletionFailure(`Completion request failed: ${error.message}`, 1);
230
+ }
231
+ };
232
+ }
233
+ export const chatTransport = createChatTransport();
234
+ export function createCompletionExecutor(overrides = {}) {
235
+ const deps = defaultDeps(overrides);
236
+ return async (request) => {
237
+ const events = [];
238
+ const emit = (event) => {
239
+ events.push(event);
240
+ request.onEvent?.(event);
241
+ };
242
+ // One deadline covers every attempt and every backoff.
243
+ const controller = new AbortController();
244
+ const timer = setTimeout(() => controller.abort(new CompletionFailure("Process timed out.", 124)), request.timeoutMs ?? DEFAULT_TIMEOUT_MS);
245
+ try {
246
+ await complete(request, deps, emit, controller.signal);
247
+ return { exitCode: 0, events, stderr: "" };
248
+ }
249
+ catch (error) {
250
+ const failure = error instanceof CompletionFailure
251
+ ? error
252
+ : controller.signal.aborted &&
253
+ controller.signal.reason instanceof CompletionFailure
254
+ ? controller.signal.reason
255
+ : new CompletionFailure(`Completion request failed: ${error.message}`, 1);
256
+ return {
257
+ exitCode: failure.exitCode,
258
+ events,
259
+ stderr: `${failure.message}\n`,
260
+ };
261
+ }
262
+ finally {
263
+ clearTimeout(timer);
264
+ }
265
+ };
266
+ }
267
+ export const runCompletion = createCompletionExecutor();
268
+ //# sourceMappingURL=openai-compatible.js.map