@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,1211 @@
1
+ import { spawn } from "node:child_process";
2
+ import { readFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { learnFromSession } from "@ocean/brain/memory/lesson-learning.js";
5
+ import { addLesson, effectiveConfidence, listLessons, migrateLegacyLessons, readLesson, setLessonStatus, } from "@ocean/brain/memory/lessons.js";
6
+ import { promoteSessionToKnowledge } from "@ocean/brain/memory/session-promotion.js";
7
+ import { classifyIntent } from "@ocean/context/context/intent-router.js";
8
+ import { resolveProfileName } from "@ocean/core/domain/profiles/runtime-config.js";
9
+ import { oceanEnv, oceanPath, oceanRoot, SYSTEM_DIR, } from "@ocean/core/shared/paths.js";
10
+ import { autoRegisterProject, bindProject, findGitRoot, knownTaskPrefixes, listProjectBindings, migrateProjectBindings, moveProject, PROJECT_CATEGORIES, projectCategory, renameProject, renderProjectIndex, resolveProject, scanProjectManifests, unbindProjectPath, writeProjectIndex, } from "@ocean/core/shared/project-resolution.js";
11
+ import { claudeSessionEndHook, isSessionEndClient, SESSION_END_CLIENTS, } from "@ocean/loop/hooks/session-end-hook.js";
12
+ import { isSessionStartClient, readBoundedStdin, SESSION_START_CLIENTS, sessionStartHookForClient, } from "@ocean/loop/hooks/session-start-hook.js";
13
+ import { openSessionStore } from "@ocean/loop/infrastructure/persistence/session-store.js";
14
+ import { listTaskLoops, runTaskLoopsOnce, runTaskLoopWorker, startTaskLoop, stopTaskLoop, } from "@ocean/loop/loops/task-loop.js";
15
+ import { resumeAgent, runAgent } from "@ocean/loop/runs/run-agent.js";
16
+ import { applyRetention, DEFAULT_KEEP_DAYS, planRetention, simulateRetention, } from "@ocean/loop/sessions/session-retention.js";
17
+ import { browserBridgeConfig } from "@ocean/market/mcp/browser-bridge.js";
18
+ import { mcpClientConfig, oceanMcpConfig, playwrightMcpConfig, } from "@ocean/market/mcp/mcp-connection.js";
19
+ import { GATEWAY_CAPABILITY } from "@ocean/market/mcp/mcp-gateway.js";
20
+ import { coreSkillReports, syncCoreSkills, } from "@ocean/market/skills/core-skill-sync.js";
21
+ import { copyClientSkills, linkClientSkills, populateSkillHub, } from "@ocean/market/skills/skill-hub.js";
22
+ import { hasFailures, repairWorkspace, workspaceReport, } from "@ocean/services/doctor/workspace-doctor.js";
23
+ import { runObsidianMcpServer } from "@ocean/services/infrastructure/mcp/obsidian-server.js";
24
+ import { runOceanMcpServer } from "@ocean/services/infrastructure/mcp/ocean-server.js";
25
+ import { parseConflictSide, resolveConflict, } from "@ocean/services/obsidian/conflict-log.js";
26
+ import { listInboxCandidates, promoteInboxNote, } from "@ocean/services/obsidian/inbox-promotion.js";
27
+ import { connectObsidianVault, discoverObsidianVault, loadObsidianConnection, } from "@ocean/services/obsidian/vault-discovery.js";
28
+ import { syncObsidianVault, watchObsidianVault, } from "@ocean/services/obsidian/vault-sync.js";
29
+ import { writeObsidianNote } from "@ocean/services/obsidian/vault-writer.js";
30
+ import { clientFindings, repairClients, } from "../../application/clients/clients.js";
31
+ import { nativeFindings } from "../../application/clients/native.js";
32
+ import { createWebhookGateway } from "../../application/gateway/webhook-gateway.js";
33
+ import { findInstallSpec, installPlan, installProvider, listInstallSpecs, removeInstalledProvider, updateProvider, } from "../../application/install/provider-installer.js";
34
+ import { syncCharterCopies } from "../../application/integrations/charter-copies.js";
35
+ import { configureClaudeCodeWrapper } from "../../application/integrations/claude-vscode.js";
36
+ import { repairEngineEntries } from "../../application/integrations/engine-entry-repair.js";
37
+ import { syncSkillFilter } from "../../application/integrations/skill-filter.js";
38
+ import { selectProfileForTask } from "../../application/profiles/profile-suggestion.js";
39
+ import { listSchedules, runDueSchedules, runSchedule, runSchedulerWorker, runSchedulerWorkerOnce, saveSchedule, setScheduleEnabled, } from "../../application/scheduler/local-scheduler.js";
40
+ import { defaultAgentRuntime, defaultBrainIndexPort, defaultProviderRegistry, defaultSessionStoreFactory, defaultSessionStoreOpener, defaultWrapperManager, } from "../../composition/runtime.js";
41
+ import { loadRuntimeConfig } from "../../infrastructure/filesystem/runtime-config-loader.js";
42
+ import { ensureService, restartService, runService, startBackgroundPull, } from "../../infrastructure/process/service.js";
43
+ import { createOllamaEmbedder } from "../../infrastructure/providers/ollama-embedder.js";
44
+ import { loadProviderRegistry } from "../../infrastructure/providers/provider-registry.js";
45
+ import { installShellPath, registerProvider, setProviderEnabled, syncProviderWrappers, wrapperDoctor, wrapperStatus, } from "../../infrastructure/wrappers/wrapper-manager.js";
46
+ import { runAuthCommand } from "./auth-command.js";
47
+ import { browserBridgeFindings, runBrowserBridgeCommand, runBrowserServiceCommand, } from "./browser-bridge-command.js";
48
+ import { runBrowserCommand } from "./browser-command.js";
49
+ import { runCaptureCommand } from "./capture-command.js";
50
+ import { runClientTestCommand } from "./client-test-command.js";
51
+ import { runClientsCommand } from "./clients-command.js";
52
+ import { runContextCommand, runContextCostCommand } from "./context-command.js";
53
+ import { runDailyCommand } from "./daily-command.js";
54
+ import { runLifecycleCommand, runPolicyCommand } from "./governance-command.js";
55
+ import { runHandoffCommand } from "./handoff-command.js";
56
+ import { runIdeaCommand } from "./idea-command.js";
57
+ import { intercept } from "./intercept-command.js";
58
+ import { runLayoutCommand } from "./layout-command.js";
59
+ import { runMarketCommand } from "./market-command.js";
60
+ import { runMcpGatewayCommand } from "./mcp-gateway-command.js";
61
+ import { runMemoryCommand } from "./memory-command.js";
62
+ import { runMigrateCommand } from "./migrate-command.js";
63
+ import { runObserveCommand } from "./observe-command.js";
64
+ import { manageClients, runOnboardCommand } from "./onboard-command.js";
65
+ import { runOperateCommand } from "./operate-command.js";
66
+ import { runProfilesCommand } from "./profiles-command.js";
67
+ import { runPullCommand } from "./pull-command.js";
68
+ import { parseSetupArgs, SETUP_USAGE, setup } from "./setup-command.js";
69
+ import { runTasksCommand } from "./tasks-command.js";
70
+ // brain_search over MCP uses vectors when the local embedder answers (T-307), and full text when
71
+ // it does not; a working embedder is kept, a failure is retried on the next search.
72
+ function mcpEmbedder() {
73
+ let ready = null;
74
+ return async () => {
75
+ if (!ready)
76
+ ready = await createOllamaEmbedder().catch(() => null);
77
+ return ready;
78
+ };
79
+ }
80
+ async function commandSetup() {
81
+ const parsed = parseSetupArgs(process.argv.slice(3));
82
+ if (parsed.kind === "help")
83
+ console.log(SETUP_USAGE);
84
+ else if (parsed.kind === "error") {
85
+ console.error(`${parsed.message}\n${SETUP_USAGE}`);
86
+ process.exitCode = 1;
87
+ }
88
+ else
89
+ await setup(parsed.options);
90
+ }
91
+ async function commandService() {
92
+ // `ocean service restart` (T-307): a new build reaches the service without unloading it.
93
+ if (process.argv[3] === "restart") {
94
+ const restarted = await restartService({ reload: false });
95
+ console.log(JSON.stringify({ service: restarted }, null, 2));
96
+ if (typeof restarted === "object")
97
+ process.exitCode = 1;
98
+ return;
99
+ }
100
+ const shutdownAfterMs = Number(oceanEnv("SERVICE_TEST_SHUTDOWN_MS"));
101
+ await runService(Number.isFinite(shutdownAfterMs) && shutdownAfterMs > 0
102
+ ? shutdownAfterMs
103
+ : undefined);
104
+ }
105
+ async function commandIntercept() {
106
+ const clientIndex = process.argv.indexOf("--client");
107
+ const executableIndex = process.argv.indexOf("--executable");
108
+ const separatorIndex = process.argv.indexOf("--");
109
+ const client = clientIndex >= 0 ? process.argv[clientIndex + 1] : "";
110
+ const args = separatorIndex >= 0 ? process.argv.slice(separatorIndex + 1) : [];
111
+ if (!client) {
112
+ console.error("Usage: ocean intercept --client <provider> -- [args]");
113
+ process.exitCode = 1;
114
+ }
115
+ else {
116
+ process.exitCode = await intercept(client, args, executableIndex >= 0
117
+ ? {
118
+ originalExecutable: process.argv[executableIndex + 1],
119
+ entryPoint: "desktop-wrapper",
120
+ controlLevel: "managed-partial",
121
+ }
122
+ : undefined);
123
+ }
124
+ }
125
+ async function commandClient() {
126
+ const action = process.argv[3] ?? "list";
127
+ if (action === "list") {
128
+ console.log(JSON.stringify(loadProviderRegistry(), null, 2));
129
+ }
130
+ else if (action === "open") {
131
+ const provider = process.argv[4];
132
+ if (!provider) {
133
+ console.error("Usage: ocean client open <provider> [provider-args]");
134
+ process.exitCode = 1;
135
+ }
136
+ else {
137
+ // After `--`, arguments go to the provider untouched (a help flag before it is Ocean's).
138
+ const rest = process.argv.slice(5);
139
+ const separator = rest.indexOf("--");
140
+ const providerArgs = separator >= 0 ? rest.slice(0, separator) : rest;
141
+ const passed = separator >= 0 ? rest.slice(separator + 1) : [];
142
+ const taskIndex = providerArgs.indexOf("--task");
143
+ const handoffIndex = providerArgs.indexOf("--handoff");
144
+ const taskId = taskIndex >= 0 ? providerArgs[taskIndex + 1] : undefined;
145
+ const handoffId = handoffIndex >= 0 ? providerArgs[handoffIndex + 1] : undefined;
146
+ const metadataFlags = new Set();
147
+ if (taskIndex >= 0) {
148
+ metadataFlags.add(taskIndex);
149
+ metadataFlags.add(taskIndex + 1);
150
+ }
151
+ if (handoffIndex >= 0) {
152
+ metadataFlags.add(handoffIndex);
153
+ metadataFlags.add(handoffIndex + 1);
154
+ }
155
+ process.exitCode = await intercept(provider, [
156
+ ...providerArgs.filter((_, index) => !metadataFlags.has(index)),
157
+ ...passed,
158
+ ], {
159
+ entryPoint: "interactive-managed",
160
+ controlLevel: "managed-partial",
161
+ taskId,
162
+ handoffId,
163
+ });
164
+ }
165
+ }
166
+ else if (action === "sync") {
167
+ const result = await syncProviderWrappers();
168
+ // Runs at every session start (the SessionStart hook calls `client sync`), so an edit
169
+ // to core.md reaches the clients that carry a copy without a manual step.
170
+ const charter = await syncCharterCopies();
171
+ const skillFilter = await syncSkillFilter();
172
+ const engineEntries = await repairEngineEntries();
173
+ // T-305: a repointed service start file only takes effect once the service restarts.
174
+ const service = engineEntries.some((repair) => repair.kind === "service" && repair.status === "updated")
175
+ ? await restartService()
176
+ : await ensureService();
177
+ // T-296: re-applies the `ocean` entry only for clients the owner approved with
178
+ // `ocean clients apply --yes`; never a client that was not approved.
179
+ const clients = await repairClients().catch((error) => ({
180
+ error: error instanceof Error ? error.message : String(error),
181
+ }));
182
+ console.log(JSON.stringify({
183
+ directory: result.directory,
184
+ providers: result.providers,
185
+ charter,
186
+ skillFilter,
187
+ engineEntries,
188
+ service,
189
+ clients,
190
+ }, null, 2));
191
+ }
192
+ else if (action === "register") {
193
+ const id = process.argv[4];
194
+ const provider = await registerProvider(id ?? "", process.argv[5] ?? id ?? "");
195
+ console.log(JSON.stringify(provider, null, 2));
196
+ }
197
+ else if (action === "enable" || action === "disable") {
198
+ const id = process.argv[4];
199
+ if (!id) {
200
+ console.error(`Usage: ocean client ${action} <provider>`);
201
+ process.exitCode = 1;
202
+ }
203
+ else {
204
+ const provider = await setProviderEnabled(id, action === "enable");
205
+ console.log(JSON.stringify(provider, null, 2));
206
+ }
207
+ }
208
+ else if (action === "manage") {
209
+ await manageClients();
210
+ }
211
+ else if (action === "doctor") {
212
+ const findings = await wrapperDoctor(process.argv[4]);
213
+ if (findings.length) {
214
+ findings.forEach((finding) => {
215
+ console.error(`NOT READY: ${finding}`);
216
+ });
217
+ process.exitCode = 1;
218
+ }
219
+ else {
220
+ console.log("PROVEN: Ocean wrappers are configured and provider binaries resolve outside the shim directory.");
221
+ }
222
+ }
223
+ else if (action === "status") {
224
+ console.log(JSON.stringify(await wrapperStatus(), null, 2));
225
+ }
226
+ else if (action === "vscode-wrapper") {
227
+ const settingsIndex = process.argv.indexOf("--settings");
228
+ const settingsPath = settingsIndex >= 0 ? process.argv[settingsIndex + 1] : undefined;
229
+ console.log(JSON.stringify(await configureClaudeCodeWrapper(defaultWrapperManager, settingsPath, process.argv.includes("--apply")), null, 2));
230
+ }
231
+ else if (action === "test") {
232
+ const provider = process.argv[4] === "--json" ? "" : (process.argv[4] ?? "");
233
+ await runClientTestCommand(provider, process.argv.includes("--json"));
234
+ }
235
+ else {
236
+ console.error("Usage: ocean client list|status|test [provider] [--json]|open <provider> [provider-args]|vscode-wrapper [--settings <path>] [--apply]|sync|register <id> [command]|enable <id>|disable <id>|manage|doctor [absolute-provider-path]");
237
+ process.exitCode = 1;
238
+ }
239
+ }
240
+ async function commandInstall() {
241
+ const id = process.argv[3];
242
+ if (!id) {
243
+ console.error("Usage: ocean install <client> [--yes]");
244
+ process.exitCode = 1;
245
+ }
246
+ else {
247
+ try {
248
+ const spec = findInstallSpec(id);
249
+ if (!process.argv.includes("--yes")) {
250
+ console.log(JSON.stringify({ approvalRequired: true, plan: installPlan(spec.provider.id) }, null, 2));
251
+ process.exitCode = 2;
252
+ }
253
+ else {
254
+ const result = await installProvider(spec.provider.id, true, defaultWrapperManager, defaultProviderRegistry);
255
+ console.log(JSON.stringify({
256
+ installed: true,
257
+ provider: result.provider,
258
+ executable: result.executable,
259
+ }, null, 2));
260
+ }
261
+ }
262
+ catch (error) {
263
+ console.error(error instanceof Error ? error.message : String(error));
264
+ process.exitCode = 1;
265
+ }
266
+ }
267
+ }
268
+ async function commandAuth() {
269
+ await runAuthCommand(process.argv[3] ?? "", process.argv[4] ?? "");
270
+ }
271
+ async function commandTasks() {
272
+ await runTasksCommand(process.argv[3] ?? "", process.argv.slice(4));
273
+ }
274
+ async function commandPolicy() {
275
+ try {
276
+ await runPolicyCommand(process.argv[3] ?? "list");
277
+ }
278
+ catch (error) {
279
+ console.error(error instanceof Error ? error.message : String(error));
280
+ process.exitCode = 1;
281
+ }
282
+ }
283
+ async function commandMarket() {
284
+ try {
285
+ await runMarketCommand(process.argv[3] ?? "", process.argv.slice(4));
286
+ }
287
+ catch (error) {
288
+ console.error(error instanceof Error ? error.message : String(error));
289
+ process.exitCode = 1;
290
+ }
291
+ }
292
+ async function commandLifecycle() {
293
+ await runLifecycleCommand(process.argv.slice(3));
294
+ }
295
+ async function commandObserve() {
296
+ try {
297
+ await runObserveCommand(process.argv.slice(3));
298
+ }
299
+ catch (error) {
300
+ console.error(error instanceof Error ? error.message : String(error));
301
+ process.exitCode = 1;
302
+ }
303
+ }
304
+ async function commandLayout() {
305
+ try {
306
+ await runLayoutCommand(process.argv.slice(3));
307
+ }
308
+ catch (error) {
309
+ console.error(error instanceof Error ? error.message : String(error));
310
+ process.exitCode = 1;
311
+ }
312
+ }
313
+ async function commandMigrate() {
314
+ await runMigrateCommand(process.argv.includes("--apply"));
315
+ }
316
+ async function commandMemory() {
317
+ await runMemoryCommand(process.argv[3] ?? "", process.argv.slice(4));
318
+ }
319
+ async function commandMcp() {
320
+ const action = process.argv[3] ?? "config";
321
+ if (action === "config")
322
+ console.log(JSON.stringify(oceanMcpConfig(), null, 2));
323
+ else if (action === "playwright-config")
324
+ console.log(JSON.stringify(playwrightMcpConfig(), null, 2));
325
+ else if (action === "gateway-config")
326
+ console.log(JSON.stringify(mcpClientConfig(GATEWAY_CAPABILITY), null, 2));
327
+ else if (action === "serve")
328
+ await runOceanMcpServer({
329
+ brainIndex: defaultBrainIndexPort,
330
+ sessionStoreFactory: defaultSessionStoreFactory,
331
+ wrapperManager: defaultWrapperManager,
332
+ embedder: mcpEmbedder(),
333
+ });
334
+ else if (action === "gateway")
335
+ await runMcpGatewayCommand();
336
+ else if (action === "browser-config")
337
+ console.log(JSON.stringify(browserBridgeConfig(), null, 2));
338
+ else if (action === "browser-bridge")
339
+ await runBrowserBridgeCommand();
340
+ else if (action === "browser-service")
341
+ await runBrowserServiceCommand(process.argv[4] ?? "");
342
+ else {
343
+ console.error("Usage: ocean mcp config|playwright-config|gateway-config|browser-config|browser-bridge|browser-service install|uninstall|serve|gateway");
344
+ process.exitCode = 1;
345
+ }
346
+ }
347
+ async function commandObsidian() {
348
+ const action = process.argv[3] ?? "discover";
349
+ if (action === "mcp")
350
+ await runObsidianMcpServer();
351
+ else if (![
352
+ "connect",
353
+ "discover",
354
+ "sync",
355
+ "watch",
356
+ "inbox",
357
+ "write",
358
+ "conflicts",
359
+ ].includes(action)) {
360
+ console.error("Usage: ocean obsidian connect <vault-path> [--read-write]|discover|sync|watch|inbox|write|conflicts resolve <id> --keep=vault|ocean");
361
+ process.exitCode = 1;
362
+ }
363
+ else {
364
+ try {
365
+ if (action === "connect") {
366
+ const vaultPath = process.argv[4];
367
+ if (!vaultPath)
368
+ throw new Error("Usage: ocean obsidian connect <vault-path> [--read-write]");
369
+ const readWrite = process.argv.includes("--read-write");
370
+ const mode = readWrite
371
+ ? "read-write"
372
+ : "read-only";
373
+ const result = await connectObsidianVault(vaultPath, mode);
374
+ const synced = await syncObsidianVault(await loadObsidianConnection());
375
+ console.log(JSON.stringify({
376
+ connected: true,
377
+ mode,
378
+ vaultPath: result.vaultPath,
379
+ noteCount: synced.noteCount,
380
+ added: synced.added,
381
+ changed: synced.changed,
382
+ removed: synced.removed,
383
+ issues: synced.issues,
384
+ }, null, 2));
385
+ }
386
+ else {
387
+ const connection = await loadObsidianConnection();
388
+ if (action === "conflicts") {
389
+ if (process.argv[4] !== "resolve")
390
+ throw new Error("Usage: ocean obsidian conflicts resolve <id> --keep=vault|ocean");
391
+ const id = process.argv[5];
392
+ const keepArg = process.argv.find((arg) => arg.startsWith("--keep="));
393
+ const keep = keepArg?.slice("--keep=".length);
394
+ if (!id || !keep || !parseConflictSide(keep))
395
+ throw new Error("Usage: ocean obsidian conflicts resolve <id> --keep=vault|ocean");
396
+ console.log(JSON.stringify(await resolveConflict(id, keep), null, 2));
397
+ }
398
+ else if (action === "write") {
399
+ const relative = process.argv[4];
400
+ const content = process.argv[5];
401
+ const expectedSha256 = process.argv[6] ?? null;
402
+ if (!relative || content === undefined)
403
+ throw new Error("Usage: ocean obsidian write <relative.md> <content> [expected-sha256] [--apply]");
404
+ console.log(JSON.stringify(await writeObsidianNote(connection, relative, content, expectedSha256 === "-" ? null : expectedSha256, process.argv.includes("--apply")), null, 2));
405
+ }
406
+ else if (action === "inbox") {
407
+ const inboxAction = process.argv[4] ?? "list";
408
+ if (inboxAction === "list")
409
+ console.log(JSON.stringify(await listInboxCandidates(connection), null, 2));
410
+ else if (inboxAction === "promote") {
411
+ const source = process.argv[5];
412
+ const target = process.argv[6];
413
+ if (!source || !target)
414
+ throw new Error("Usage: ocean obsidian inbox promote <source.md> <target-directory> [--apply]");
415
+ console.log(JSON.stringify(await promoteInboxNote(connection, source, target, process.argv.includes("--apply")), null, 2));
416
+ }
417
+ else
418
+ throw new Error("Usage: ocean obsidian inbox list|promote <source.md> <target-directory> [--apply]");
419
+ }
420
+ else if (action === "discover")
421
+ console.log(JSON.stringify(await discoverObsidianVault(connection), null, 2));
422
+ else if (action === "sync")
423
+ console.log(JSON.stringify(await syncObsidianVault(connection), null, 2));
424
+ else {
425
+ const controller = new AbortController();
426
+ process.once("SIGINT", () => controller.abort());
427
+ process.once("SIGTERM", () => controller.abort());
428
+ await watchObsidianVault(connection, undefined, controller.signal);
429
+ }
430
+ }
431
+ }
432
+ catch (error) {
433
+ console.error(error instanceof Error ? error.message : String(error));
434
+ process.exitCode = 1;
435
+ }
436
+ }
437
+ }
438
+ async function commandCapture() {
439
+ await runCaptureCommand(process.argv[3] ?? "", process.argv.slice(4));
440
+ }
441
+ async function commandHandoff() {
442
+ try {
443
+ await runHandoffCommand(process.argv[3] ?? "list", process.argv.slice(4));
444
+ }
445
+ catch (error) {
446
+ console.error(error instanceof Error ? error.message : String(error));
447
+ process.exitCode = 1;
448
+ }
449
+ }
450
+ async function commandContext() {
451
+ if (process.argv[3] === "cost") {
452
+ await runContextCostCommand(process.argv.slice(4));
453
+ return;
454
+ }
455
+ await runContextCommand(process.argv.includes("--json"));
456
+ }
457
+ async function commandProject() {
458
+ const action = process.argv[3] ?? "resolve";
459
+ if (action === "resolve") {
460
+ console.log(JSON.stringify(await resolveProject(process.argv[4] ?? process.cwd()), null, 2));
461
+ }
462
+ else if (action === "bind") {
463
+ const args = process.argv.slice(4);
464
+ const addPath = args.includes("--add");
465
+ const [name, targetPath] = args.filter((arg) => arg !== "--add");
466
+ if (!name || !targetPath) {
467
+ console.error("Usage: ocean project bind <name> <path> [--add]");
468
+ process.exitCode = 1;
469
+ }
470
+ else {
471
+ const result = await bindProject(name, targetPath, { addPath });
472
+ console.log(JSON.stringify(result, null, 2));
473
+ if (result.conflict)
474
+ process.exitCode = 2;
475
+ }
476
+ }
477
+ else if (action === "list") {
478
+ const flag = process.argv.indexOf("--category");
479
+ const wanted = flag >= 0 ? process.argv[flag + 1] : undefined;
480
+ if (flag >= 0 &&
481
+ !PROJECT_CATEGORIES.includes(wanted ?? "")) {
482
+ console.error(`Usage: ocean project list [--category ${PROJECT_CATEGORIES.join("|")}]`);
483
+ process.exitCode = 1;
484
+ return;
485
+ }
486
+ const { manifests, errors } = await scanProjectManifests();
487
+ for (const { file, error } of errors)
488
+ console.error(`skipped invalid ${file}: ${error}`);
489
+ const categories = new Map();
490
+ for (const manifest of manifests) {
491
+ try {
492
+ const category = projectCategory(manifest);
493
+ if (category)
494
+ categories.set(manifest.id, category);
495
+ }
496
+ catch (error) {
497
+ console.error(`${manifest.id}: ${error instanceof Error ? error.message : String(error)}`);
498
+ }
499
+ }
500
+ const bindings = (await listProjectBindings())
501
+ .map((binding) => ({
502
+ ...binding,
503
+ gitRoot: binding.gitRoot ?? findGitRoot(binding.path),
504
+ ...(categories.has(binding.id)
505
+ ? { category: categories.get(binding.id) }
506
+ : {}),
507
+ }))
508
+ .filter((binding) => !wanted || binding.category === wanted);
509
+ console.log(JSON.stringify(bindings, null, 2));
510
+ if (errors.length)
511
+ process.exitCode = 2;
512
+ }
513
+ else if (action === "register") {
514
+ const result = await autoRegisterProject(process.argv[4] ?? process.cwd(), {
515
+ explicit: true,
516
+ });
517
+ console.log(JSON.stringify(result, null, 2));
518
+ if (result.status !== "registered")
519
+ process.exitCode = 2;
520
+ }
521
+ else if (action === "unbind") {
522
+ const target = process.argv[4];
523
+ if (!target) {
524
+ console.error("Usage: ocean project unbind <path>");
525
+ process.exitCode = 1;
526
+ }
527
+ else {
528
+ const result = await unbindProjectPath(target);
529
+ console.log(JSON.stringify(result, null, 2));
530
+ if (!result.removed)
531
+ process.exitCode = 2;
532
+ }
533
+ }
534
+ else if (action === "rename") {
535
+ const [from, to] = process.argv.slice(4);
536
+ if (!from || !to) {
537
+ console.error("Usage: ocean project rename <id> <new-id>");
538
+ process.exitCode = 1;
539
+ }
540
+ else {
541
+ try {
542
+ console.log(JSON.stringify(await renameProject(from, to), null, 2));
543
+ }
544
+ catch (error) {
545
+ console.error(error instanceof Error ? error.message : String(error));
546
+ process.exitCode = 2;
547
+ }
548
+ }
549
+ }
550
+ else if (action === "move") {
551
+ const args = process.argv.slice(4);
552
+ const [id, category] = args.filter((arg) => arg !== "--write");
553
+ if (!id || !category) {
554
+ console.error(`Usage: ocean project move <id> <${PROJECT_CATEGORIES.join("|")}> [--write]`);
555
+ process.exitCode = 1;
556
+ }
557
+ else {
558
+ try {
559
+ console.log(JSON.stringify(await moveProject(id, category, args.includes("--write")), null, 2));
560
+ }
561
+ catch (error) {
562
+ console.error(error instanceof Error ? error.message : String(error));
563
+ process.exitCode = 2;
564
+ }
565
+ }
566
+ }
567
+ else if (action === "migrate") {
568
+ const result = await migrateProjectBindings(process.argv.includes("--write"));
569
+ console.log(JSON.stringify(result, null, 2));
570
+ }
571
+ else if (action === "index") {
572
+ if (process.argv.includes("--write"))
573
+ console.log(JSON.stringify(await writeProjectIndex(), null, 2));
574
+ else
575
+ console.log(await renderProjectIndex());
576
+ }
577
+ else {
578
+ console.error("Usage: ocean project resolve [path]|bind <name> <path> [--add]|register [path]|unbind <path>|rename <id> <new-id>|move <id> <category> [--write]|list [--category <name>]|migrate [--write]|index [--write]");
579
+ process.exitCode = 1;
580
+ }
581
+ }
582
+ // `--repair` (the hook entries `ocean clients` writes, T-296): `client sync` in the background,
583
+ // as the Claude Code bootstrap script does; it never delays or fails the session.
584
+ function startBackgroundSync() {
585
+ try {
586
+ spawn(process.execPath, [process.argv[1], "client", "sync"], {
587
+ detached: true,
588
+ stdio: "ignore",
589
+ })
590
+ .on("error", () => { })
591
+ .unref();
592
+ }
593
+ catch {
594
+ // no repair this time; the next session start tries again
595
+ }
596
+ }
597
+ async function commandHook() {
598
+ const action = process.argv[3] ?? "";
599
+ if (action === "session-start") {
600
+ const flags = process.argv.slice(4);
601
+ if (flags.includes("--repair"))
602
+ startBackgroundSync();
603
+ startBackgroundPull();
604
+ const inline = flags.find((arg) => arg.startsWith("--client="));
605
+ const clientIndex = flags.indexOf("--client");
606
+ const client = inline
607
+ ? inline.slice("--client=".length)
608
+ : clientIndex >= 0
609
+ ? (flags[clientIndex + 1] ?? "")
610
+ : "claude";
611
+ if (!isSessionStartClient(client)) {
612
+ console.error(sessionStartUsage);
613
+ process.exitCode = 1;
614
+ return;
615
+ }
616
+ try {
617
+ const raw = await readBoundedStdin();
618
+ const parsed = raw.trim() ? JSON.parse(raw) : {};
619
+ const payload = parsed && typeof parsed === "object" && !Array.isArray(parsed)
620
+ ? parsed
621
+ : {};
622
+ console.log(JSON.stringify(await sessionStartHookForClient(client, payload)));
623
+ }
624
+ catch (error) {
625
+ console.error(error instanceof Error ? error.message : String(error));
626
+ process.exitCode = 1;
627
+ }
628
+ }
629
+ else if (action === "session-end") {
630
+ const flags = process.argv.slice(4);
631
+ const inline = flags.find((arg) => arg.startsWith("--client="));
632
+ const clientIndex = flags.indexOf("--client");
633
+ const client = inline
634
+ ? inline.slice("--client=".length)
635
+ : clientIndex >= 0
636
+ ? (flags[clientIndex + 1] ?? "")
637
+ : "claude";
638
+ if (!isSessionEndClient(client)) {
639
+ console.error(sessionEndUsage);
640
+ process.exitCode = 1;
641
+ return;
642
+ }
643
+ try {
644
+ const raw = await readBoundedStdin();
645
+ const payload = raw.trim() ? JSON.parse(raw) : {};
646
+ await claudeSessionEndHook(payload, defaultSessionStoreFactory, client);
647
+ }
648
+ catch (error) {
649
+ console.error(error instanceof Error ? error.message : String(error));
650
+ process.exitCode = 1;
651
+ }
652
+ }
653
+ else {
654
+ console.error(`${sessionStartUsage}|${sessionEndUsage.slice("Usage: ocean hook ".length)}`);
655
+ process.exitCode = 1;
656
+ }
657
+ }
658
+ const sessionEndUsage = `Usage: ocean hook session-end [--client ${SESSION_END_CLIENTS.join("|")}] (reads a hook payload from stdin)`;
659
+ const sessionStartUsage = `Usage: ocean hook session-start [--client ${SESSION_START_CLIENTS.join("|")}] [--repair]`;
660
+ async function commandIntent() {
661
+ const action = process.argv[3] ?? "classify";
662
+ if (action !== "classify") {
663
+ console.error("Usage: ocean intent classify <text>");
664
+ process.exitCode = 1;
665
+ }
666
+ else {
667
+ const text = process.argv.slice(4).join(" ");
668
+ console.log(JSON.stringify(classifyIntent(text, await knownTaskPrefixes())));
669
+ }
670
+ }
671
+ async function commandOperate() {
672
+ const args = process.argv.slice(3);
673
+ const text = (args[0] === "--" ? args.slice(1) : args).join(" ");
674
+ await runOperateCommand(text);
675
+ }
676
+ async function commandIdea() {
677
+ try {
678
+ await runIdeaCommand(process.argv[3] ?? "list", process.argv.slice(4));
679
+ }
680
+ catch (error) {
681
+ console.error(error instanceof Error ? error.message : String(error));
682
+ process.exitCode = 1;
683
+ }
684
+ }
685
+ async function commandDaily() {
686
+ try {
687
+ await runDailyCommand(process.argv[3] ?? "start", process.argv.slice(4));
688
+ }
689
+ catch (error) {
690
+ console.error(error instanceof Error ? error.message : String(error));
691
+ process.exitCode = 1;
692
+ }
693
+ }
694
+ async function commandSchedule() {
695
+ const action = process.argv[3] ?? "list";
696
+ if (action === "list")
697
+ console.log(JSON.stringify(await listSchedules(), null, 2));
698
+ else if (action === "add") {
699
+ const [id, profile, intervalMs, ...prompt] = process.argv.slice(4);
700
+ if (!id || !profile || !intervalMs || !prompt.length) {
701
+ console.error("Usage: ocean schedule add <id> <profile> <interval-ms> <prompt>");
702
+ process.exitCode = 1;
703
+ }
704
+ else
705
+ await saveSchedule({
706
+ id,
707
+ profile,
708
+ prompt: prompt.join(" "),
709
+ intervalMs: Number(intervalMs),
710
+ nextRunAt: new Date().toISOString(),
711
+ enabled: true,
712
+ });
713
+ }
714
+ else if (action === "run-due")
715
+ console.log(JSON.stringify({ ran: await runDueSchedules(oceanRoot(), defaultAgentRuntime) }, null, 2));
716
+ else if (action === "worker-once")
717
+ console.log(JSON.stringify({ ran: await runSchedulerWorkerOnce(oceanRoot(), defaultAgentRuntime) }, null, 2));
718
+ else if (action === "worker") {
719
+ const controller = new AbortController();
720
+ const stop = () => controller.abort();
721
+ process.once("SIGINT", stop);
722
+ process.once("SIGTERM", stop);
723
+ await runSchedulerWorker(oceanRoot(), defaultAgentRuntime, {
724
+ signal: controller.signal,
725
+ pollMs: Number(oceanEnv("SCHEDULER_POLL_MS") ?? 30_000),
726
+ });
727
+ process.off("SIGINT", stop);
728
+ process.off("SIGTERM", stop);
729
+ }
730
+ else if (action === "enable" || action === "disable")
731
+ console.log(JSON.stringify(await setScheduleEnabled(process.argv[4] ?? "", action === "enable"), null, 2));
732
+ else if (action === "run-now")
733
+ await runSchedule(process.argv[4] ?? "", oceanRoot(), defaultAgentRuntime);
734
+ else {
735
+ console.error("Usage: ocean schedule list|add|enable|disable|run-due|run-now|worker-once|worker");
736
+ process.exitCode = 1;
737
+ }
738
+ }
739
+ async function commandLoop() {
740
+ const action = process.argv[3] ?? "status";
741
+ if (action === "status")
742
+ console.log(JSON.stringify(await listTaskLoops(), null, 2));
743
+ else if (action === "start") {
744
+ const taskId = process.argv[4];
745
+ const profile = process.argv[5] ?? "developer";
746
+ const promptIndex = process.argv.indexOf("--prompt");
747
+ const prompt = promptIndex >= 0 ? process.argv.slice(promptIndex + 1).join(" ") : "";
748
+ if (!taskId || !prompt || !process.argv.includes("--approve")) {
749
+ console.error("Usage: ocean loop start <task-id> <profile> --prompt <text> --approve [--max-iterations N] [--interval-ms N] [--max-attempts N]");
750
+ process.exitCode = 1;
751
+ }
752
+ else {
753
+ const value = (flag, fallback) => {
754
+ const index = process.argv.indexOf(flag);
755
+ return index >= 0 ? Number(process.argv[index + 1]) : fallback;
756
+ };
757
+ console.log(JSON.stringify(await startTaskLoop({
758
+ taskId,
759
+ profile,
760
+ prompt,
761
+ cwd: oceanRoot(),
762
+ approved: true,
763
+ maxIterations: value("--max-iterations", 10),
764
+ intervalMs: value("--interval-ms", 60_000),
765
+ maxAttempts: value("--max-attempts", 2),
766
+ }), null, 2));
767
+ }
768
+ }
769
+ else if (action === "worker-once") {
770
+ console.log(JSON.stringify({ ran: await runTaskLoopsOnce(oceanRoot(), defaultAgentRuntime) }, null, 2));
771
+ }
772
+ else if (action === "worker") {
773
+ const controller = new AbortController();
774
+ const stop = () => controller.abort();
775
+ process.once("SIGINT", stop);
776
+ process.once("SIGTERM", stop);
777
+ await runTaskLoopWorker(oceanRoot(), defaultAgentRuntime, {
778
+ signal: controller.signal,
779
+ pollMs: Number(oceanEnv("LOOP_POLL_MS") ?? 30_000),
780
+ });
781
+ process.off("SIGINT", stop);
782
+ process.off("SIGTERM", stop);
783
+ }
784
+ else if (action === "stop") {
785
+ const id = process.argv[4];
786
+ if (!id) {
787
+ console.error("Usage: ocean loop stop <loop-id>");
788
+ process.exitCode = 1;
789
+ }
790
+ else
791
+ console.log(JSON.stringify(await stopTaskLoop(id), null, 2));
792
+ }
793
+ else {
794
+ console.error("Usage: ocean loop start|status|stop|worker-once|worker");
795
+ process.exitCode = 1;
796
+ }
797
+ }
798
+ async function commandGateway() {
799
+ const port = Number(oceanEnv("GATEWAY_PORT") ?? 8787);
800
+ const token = oceanEnv("GATEWAY_TOKEN");
801
+ if (!token) {
802
+ console.error("OCEAN_GATEWAY_TOKEN is required");
803
+ process.exitCode = 1;
804
+ }
805
+ else {
806
+ const server = createWebhookGateway(oceanRoot(), token, defaultAgentRuntime);
807
+ server.listen(port, "127.0.0.1", () => console.log(`Ocean webhook gateway listening on 127.0.0.1:${port}`));
808
+ }
809
+ }
810
+ async function commandSkill() {
811
+ const action = process.argv[3] ?? "list";
812
+ if (action === "sync")
813
+ console.log(JSON.stringify(await syncCoreSkills(), null, 2));
814
+ else if (action === "hub") {
815
+ const sources = process.argv
816
+ .slice(4)
817
+ .filter((arg) => !arg.startsWith("--"));
818
+ console.log(JSON.stringify(await populateSkillHub(sources), null, 2));
819
+ }
820
+ else if (action === "copy") {
821
+ console.log(JSON.stringify(await copyClientSkills({ apply: process.argv.includes("--apply") }), null, 2));
822
+ }
823
+ else if (action === "link") {
824
+ console.log(JSON.stringify(await linkClientSkills({
825
+ apply: process.argv.includes("--apply"),
826
+ all: process.argv.includes("--all"),
827
+ }), null, 2));
828
+ }
829
+ else if (action === "doctor")
830
+ console.log(JSON.stringify(await coreSkillReports(), null, 2));
831
+ else if (action === "list") {
832
+ // [status] filters; any other argument is a lesson id (what a truncated lesson points at).
833
+ const filter = process.argv[4];
834
+ const isStatus = filter === "candidate" || filter === "active" || filter === "retired";
835
+ const lessons = filter && !isStatus
836
+ ? [await readLesson(filter)].filter((lesson) => lesson !== null)
837
+ : await listLessons(isStatus ? { status: filter } : {});
838
+ if (filter && !isStatus && !lessons.length) {
839
+ console.error(`Lesson not found: ${filter}`);
840
+ process.exitCode = 1;
841
+ }
842
+ else
843
+ console.log(JSON.stringify(lessons.map((lesson) => ({
844
+ ...lesson,
845
+ effectiveConfidence: Number(effectiveConfidence(lesson).toFixed(4)),
846
+ })), null, 2));
847
+ }
848
+ else if (action === "observe" || action === "learn") {
849
+ // Scores one closed session into the lessons store (the same step closeout runs).
850
+ const sessionId = process.argv[4];
851
+ if (!sessionId && action === "observe")
852
+ console.log(JSON.stringify(await listLessons({ status: "candidate" }), null, 2));
853
+ else if (!sessionId) {
854
+ console.error("Usage: ocean skill learn <session-id>");
855
+ process.exitCode = 1;
856
+ }
857
+ else {
858
+ const store = await defaultSessionStoreFactory();
859
+ try {
860
+ console.log(JSON.stringify(await learnFromSession(store, sessionId), null, 2));
861
+ }
862
+ finally {
863
+ store.close();
864
+ }
865
+ }
866
+ }
867
+ else if (action === "add") {
868
+ const [id, name, ...instructions] = process.argv.slice(4);
869
+ if (!id || !name || !instructions.length) {
870
+ console.error("Usage: ocean skill add <id> <name> <instructions>");
871
+ process.exitCode = 1;
872
+ }
873
+ else
874
+ console.log(JSON.stringify(await addLesson({ id, title: name, body: instructions.join(" ") }), null, 2));
875
+ }
876
+ else if (action === "review") {
877
+ // The owner's call: promoted activates a lesson without waiting for the replay eval,
878
+ // rejected retires it. Run `ocean memory reindex` afterwards so runs can find it.
879
+ const [id, status] = process.argv.slice(4);
880
+ if (!id || (status !== "promoted" && status !== "rejected")) {
881
+ console.error("Usage: ocean skill review <id> promoted|rejected");
882
+ process.exitCode = 1;
883
+ }
884
+ else
885
+ console.log(JSON.stringify(await setLessonStatus(id, status === "promoted" ? "active" : "retired"), null, 2));
886
+ }
887
+ else if (action === "migrate") {
888
+ console.log(JSON.stringify(await migrateLegacyLessons(), null, 2));
889
+ }
890
+ else {
891
+ console.error("Usage: ocean skill sync|doctor|list [status|id]|observe [session-id]|add|review <id> promoted|rejected|migrate");
892
+ process.exitCode = 1;
893
+ }
894
+ }
895
+ async function commandCatalog() {
896
+ console.log(JSON.stringify(listInstallSpecs().map((spec) => ({
897
+ id: spec.provider.id,
898
+ command: spec.provider.command,
899
+ installer: installPlan(spec.provider.id),
900
+ })), null, 2));
901
+ }
902
+ async function commandEnv() {
903
+ console.log(await installShellPath());
904
+ }
905
+ async function commandUpdateOrRemove(command) {
906
+ const id = process.argv[3];
907
+ if (!id || !process.argv.includes("--yes")) {
908
+ console.error(`Usage: ocean ${command} <client> --yes`);
909
+ process.exitCode = 2;
910
+ }
911
+ else {
912
+ try {
913
+ const result = command === "update"
914
+ ? await updateProvider(id, true, defaultWrapperManager, defaultProviderRegistry)
915
+ : await removeInstalledProvider(id, true, defaultWrapperManager);
916
+ console.log(JSON.stringify({
917
+ [command === "update" ? "updated" : "removed"]: true,
918
+ provider: result,
919
+ }, null, 2));
920
+ }
921
+ catch (error) {
922
+ console.error(error instanceof Error ? error.message : String(error));
923
+ process.exitCode = 1;
924
+ }
925
+ }
926
+ }
927
+ async function commandDoctor() {
928
+ const report = await workspaceReport(defaultWrapperManager);
929
+ // T-296: every installed AI client's `ocean` entry (supported fail, unknown warn).
930
+ report.findings.push(...(await clientFindings()), ...(await nativeFindings()), ...(await browserBridgeFindings()));
931
+ if (process.argv.includes("--json"))
932
+ console.log(JSON.stringify(report, null, 2));
933
+ else
934
+ report.findings.forEach((finding) => {
935
+ console.log(`${finding.severity}: ${finding.code} — ${finding.message}`);
936
+ });
937
+ if (hasFailures(report.findings))
938
+ process.exitCode = 1;
939
+ }
940
+ async function commandRepair() {
941
+ const apply = process.argv.includes("--apply");
942
+ if (!apply) {
943
+ const report = await workspaceReport(defaultWrapperManager);
944
+ console.log(JSON.stringify({
945
+ dryRun: true,
946
+ fixable: report.findings.filter((finding) => finding.fixable),
947
+ findings: report.findings,
948
+ }, null, 2));
949
+ }
950
+ else {
951
+ const result = await repairWorkspace(defaultWrapperManager);
952
+ console.log(JSON.stringify({ applied: result.changes, findings: result.findings }, null, 2));
953
+ if (hasFailures(result.findings))
954
+ process.exitCode = 1;
955
+ }
956
+ }
957
+ async function commandBrowser() {
958
+ await runBrowserCommand(process.argv[3] ?? "", process.argv.slice(4));
959
+ }
960
+ async function commandRun() {
961
+ const profileIndex = process.argv.indexOf("--profile");
962
+ const promptIndex = process.argv.indexOf("--prompt");
963
+ const clientIndex = process.argv.indexOf("--client");
964
+ const taskIndex = process.argv.indexOf("--task");
965
+ const handoffIndex = process.argv.indexOf("--handoff");
966
+ // --profile, then runtime.json's defaultProfile, then the historical "default" while no
967
+ // runtime.json exists. A named profile that does not exist fails; nothing falls back.
968
+ const explicitProfile = profileIndex >= 0 ? process.argv[profileIndex + 1] : undefined;
969
+ if (profileIndex >= 0 &&
970
+ (!explicitProfile || explicitProfile.startsWith("--"))) {
971
+ console.error("Usage: ocean run --profile <name> ... --prompt <text>");
972
+ process.exitCode = 1;
973
+ return;
974
+ }
975
+ // runtime.json is read only when it is needed, so a broken one cannot block an explicit run.
976
+ const runtimeConfig = explicitProfile ? null : await loadRuntimeConfig();
977
+ const client = clientIndex >= 0 ? process.argv[clientIndex + 1] : undefined;
978
+ const taskId = taskIndex >= 0 ? process.argv[taskIndex + 1] : undefined;
979
+ // T-296: with `autoProfile` on, a run for a task without --profile takes the suggested one.
980
+ const profileName = runtimeConfig?.autoProfile && taskId
981
+ ? (await selectProfileForTask(taskId, { cwd: process.cwd() })).profile
982
+ : resolveProfileName(explicitProfile, runtimeConfig);
983
+ const handoffId = handoffIndex >= 0 ? process.argv[handoffIndex + 1] : undefined;
984
+ const prompt = promptIndex >= 0 ? process.argv.slice(promptIndex + 1).join(" ") : "";
985
+ if (!profileName || !prompt) {
986
+ console.error("Usage: ocean run --profile <name> [--client <client>] [--task <id>] [--handoff <id>] --prompt <text>");
987
+ process.exitCode = 1;
988
+ }
989
+ else {
990
+ const session = await runAgent({ profileName, client, taskId, handoffId, prompt, cwd: oceanRoot() }, defaultAgentRuntime);
991
+ console.log(JSON.stringify({ sessionId: session.sessionId, status: session.status }));
992
+ }
993
+ }
994
+ async function commandSession() {
995
+ const action = process.argv[3] ?? "list";
996
+ const store = await openSessionStore();
997
+ if (action === "list") {
998
+ console.log(JSON.stringify(store.list()));
999
+ store.close();
1000
+ }
1001
+ else if (action === "show") {
1002
+ const sessionId = process.argv[4] ?? "";
1003
+ const session = store.get(sessionId);
1004
+ const entryEvent = session
1005
+ ? store
1006
+ .listEvents(sessionId)
1007
+ .find((event) => event.type === "session_entry_contract")
1008
+ : undefined;
1009
+ store.close();
1010
+ if (!session) {
1011
+ console.error("Session not found");
1012
+ process.exitCode = 1;
1013
+ }
1014
+ else
1015
+ console.log(JSON.stringify({
1016
+ ...session,
1017
+ entryContract: entryEvent ? JSON.parse(entryEvent.data) : null,
1018
+ }));
1019
+ }
1020
+ else if (action === "summary") {
1021
+ const sessionId = process.argv[4] ?? "";
1022
+ const session = store.get(sessionId);
1023
+ store.close();
1024
+ if (!session) {
1025
+ console.error("Session not found");
1026
+ process.exitCode = 1;
1027
+ }
1028
+ else if (!session.summaryPath) {
1029
+ console.error("Session summary not available");
1030
+ process.exitCode = 1;
1031
+ }
1032
+ else {
1033
+ try {
1034
+ console.log(await readFile(path.resolve(oceanRoot(), session.summaryPath), "utf8"));
1035
+ }
1036
+ catch {
1037
+ console.error("Session summary file is missing");
1038
+ process.exitCode = 1;
1039
+ }
1040
+ }
1041
+ }
1042
+ else if (action === "events") {
1043
+ const sessionId = process.argv[4] ?? "";
1044
+ const session = store.get(sessionId);
1045
+ const events = session ? store.listEvents(sessionId) : [];
1046
+ store.close();
1047
+ if (!session) {
1048
+ console.error("Session not found");
1049
+ process.exitCode = 1;
1050
+ }
1051
+ else
1052
+ console.log(JSON.stringify(events, null, 2));
1053
+ }
1054
+ else if (action === "resume") {
1055
+ const sessionId = process.argv[4];
1056
+ const prompt = process.argv.slice(5).join(" ");
1057
+ store.close();
1058
+ if (!sessionId || !prompt) {
1059
+ console.error("Usage: ocean session resume <session-id> <prompt>");
1060
+ process.exitCode = 1;
1061
+ }
1062
+ else {
1063
+ const session = await resumeAgent(sessionId, prompt, defaultAgentRuntime);
1064
+ console.log(JSON.stringify({
1065
+ sessionId: session.sessionId,
1066
+ status: session.status,
1067
+ }));
1068
+ }
1069
+ }
1070
+ else if (action === "promote") {
1071
+ const sessionId = process.argv[4];
1072
+ const target = process.argv[5] ?? "knowledge/results";
1073
+ store.close();
1074
+ if (!sessionId) {
1075
+ console.error("Usage: ocean session promote <session-id> [knowledge/<kind>] --approve");
1076
+ process.exitCode = 1;
1077
+ }
1078
+ else {
1079
+ try {
1080
+ console.log(JSON.stringify(await promoteSessionToKnowledge(sessionId, defaultSessionStoreFactory, target, process.argv.includes("--approve")), null, 2));
1081
+ }
1082
+ catch (error) {
1083
+ console.error(error instanceof Error ? error.message : String(error));
1084
+ process.exitCode = 1;
1085
+ }
1086
+ }
1087
+ }
1088
+ else if (action === "doctor") {
1089
+ const thresholdHours = Number(process.argv[4] ?? "24");
1090
+ const apply = process.argv.includes("--apply");
1091
+ if (!Number.isFinite(thresholdHours) || thresholdHours <= 0) {
1092
+ store.close();
1093
+ console.error("Usage: ocean session doctor [hours] [--apply]");
1094
+ process.exitCode = 1;
1095
+ }
1096
+ else {
1097
+ const thresholdMs = thresholdHours * 60 * 60 * 1000;
1098
+ const stale = apply
1099
+ ? store.reconcileStaleRunning(thresholdMs)
1100
+ : store.listStaleRunning(thresholdMs);
1101
+ console.log(JSON.stringify({
1102
+ apply,
1103
+ thresholdHours,
1104
+ stale: stale.map((session) => ({
1105
+ sessionId: session.sessionId,
1106
+ provider: session.provider,
1107
+ updatedAt: session.updatedAt,
1108
+ })),
1109
+ integrity: store.integrityCheck(),
1110
+ }));
1111
+ store.close();
1112
+ }
1113
+ }
1114
+ else if (action === "compact") {
1115
+ const keepDaysIndex = process.argv.indexOf("--keep-days");
1116
+ const keepDays = keepDaysIndex >= 0
1117
+ ? Number(process.argv[keepDaysIndex + 1])
1118
+ : DEFAULT_KEEP_DAYS;
1119
+ const simulate = process.argv.includes("--simulate");
1120
+ const apply = process.argv.includes("--apply");
1121
+ const beforeIndex = process.argv.indexOf("--before");
1122
+ const before = beforeIndex >= 0 ? process.argv[beforeIndex + 1] : undefined;
1123
+ const planIndex = process.argv.indexOf("--plan");
1124
+ const fingerprint = planIndex >= 0 ? process.argv[planIndex + 1] : undefined;
1125
+ if (!Number.isFinite(keepDays) || keepDays <= 0) {
1126
+ store.close();
1127
+ console.error("Usage: ocean session compact [--keep-days N] [--simulate|--apply --before <iso> --plan <fingerprint>] [--json]");
1128
+ process.exitCode = 1;
1129
+ return;
1130
+ }
1131
+ const plan = planRetention(store, { keepDays, before });
1132
+ if (apply) {
1133
+ if (!before || !fingerprint) {
1134
+ store.close();
1135
+ console.error("ocean session compact --apply requires --before <iso> and --plan <fingerprint> from a prior plan/--simulate run");
1136
+ process.exitCode = 1;
1137
+ return;
1138
+ }
1139
+ try {
1140
+ const result = await applyRetention(store, oceanPath(SYSTEM_DIR, "sessions", "sessions.sqlite"), plan, fingerprint);
1141
+ console.log(JSON.stringify({ apply: true, plan, result }, null, 2));
1142
+ }
1143
+ catch (error) {
1144
+ console.error(error instanceof Error ? error.message : String(error));
1145
+ process.exitCode = 1;
1146
+ }
1147
+ finally {
1148
+ store.close();
1149
+ }
1150
+ return;
1151
+ }
1152
+ if (simulate) {
1153
+ const result = await simulateRetention(store, oceanPath(SYSTEM_DIR, "sessions", "sessions.sqlite"), plan, defaultSessionStoreOpener);
1154
+ store.close();
1155
+ console.log(JSON.stringify({ simulate: true, plan, result }, null, 2));
1156
+ return;
1157
+ }
1158
+ store.close();
1159
+ console.log(JSON.stringify({ dryRun: true, plan }, null, 2));
1160
+ }
1161
+ else {
1162
+ store.close();
1163
+ console.error("Usage: ocean session list|show <session-id>|summary <session-id>|events <session-id>|resume <session-id> <prompt>|promote <session-id> [knowledge/<kind>] --approve|doctor [hours] [--apply]|compact [--keep-days N] [--simulate]|compact --apply --before <iso> --plan <fingerprint>");
1164
+ process.exitCode = 1;
1165
+ }
1166
+ }
1167
+ export const commandRegistry = {
1168
+ setup: commandSetup,
1169
+ onboard: () => runOnboardCommand(process.argv.slice(3)),
1170
+ service: commandService,
1171
+ intercept: commandIntercept,
1172
+ client: commandClient,
1173
+ clients: () => runClientsCommand(process.argv.slice(3)),
1174
+ install: commandInstall,
1175
+ auth: commandAuth,
1176
+ tasks: commandTasks,
1177
+ policy: commandPolicy,
1178
+ lifecycle: commandLifecycle,
1179
+ observe: commandObserve,
1180
+ migrate: commandMigrate,
1181
+ layout: commandLayout,
1182
+ memory: commandMemory,
1183
+ pull: () => runPullCommand(process.argv.slice(3)),
1184
+ mcp: commandMcp,
1185
+ market: commandMarket,
1186
+ obsidian: commandObsidian,
1187
+ capture: commandCapture,
1188
+ handoff: commandHandoff,
1189
+ context: commandContext,
1190
+ project: commandProject,
1191
+ hook: commandHook,
1192
+ intent: commandIntent,
1193
+ operate: commandOperate,
1194
+ idea: commandIdea,
1195
+ daily: commandDaily,
1196
+ schedule: commandSchedule,
1197
+ loop: commandLoop,
1198
+ gateway: commandGateway,
1199
+ skill: commandSkill,
1200
+ catalog: commandCatalog,
1201
+ env: commandEnv,
1202
+ update: () => commandUpdateOrRemove("update"),
1203
+ remove: () => commandUpdateOrRemove("remove"),
1204
+ doctor: commandDoctor,
1205
+ repair: commandRepair,
1206
+ browser: commandBrowser,
1207
+ run: commandRun,
1208
+ profiles: () => runProfilesCommand(process.argv.slice(3)),
1209
+ session: commandSession,
1210
+ };
1211
+ //# sourceMappingURL=command-registry.js.map