@amoree-code/ocean 0.0.0-stage → 1.2.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 (300) 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/package.json +11 -0
  112. package/node_modules/@ocean/context/dist/context/context-compression.js +66 -0
  113. package/node_modules/@ocean/context/dist/context/context-cost.js +587 -0
  114. package/node_modules/@ocean/context/dist/context/context-ladder.js +363 -0
  115. package/node_modules/@ocean/context/dist/context/context-packet.js +213 -0
  116. package/node_modules/@ocean/context/dist/context/context-references.js +255 -0
  117. package/node_modules/@ocean/context/dist/context/intent-router.js +259 -0
  118. package/node_modules/@ocean/context/dist/context/resource-injection.js +36 -0
  119. package/node_modules/@ocean/context/package.json +11 -0
  120. package/node_modules/@ocean/core/dist/domain/brain/brain-record.js +22 -0
  121. package/node_modules/@ocean/core/dist/domain/brain/record-scope.js +22 -0
  122. package/node_modules/@ocean/core/dist/domain/capabilities/browser-contract.js +64 -0
  123. package/node_modules/@ocean/core/dist/domain/capabilities/capability-contract.js +16 -0
  124. package/node_modules/@ocean/core/dist/domain/capabilities/capability-manifest.js +72 -0
  125. package/node_modules/@ocean/core/dist/domain/context/context-validator.js +5 -0
  126. package/node_modules/@ocean/core/dist/domain/context/context.js +34 -0
  127. package/node_modules/@ocean/core/dist/domain/context/project-id.js +30 -0
  128. package/node_modules/@ocean/core/dist/domain/evidence/evidence.js +16 -0
  129. package/node_modules/@ocean/core/dist/domain/mcp/mcp-contract.js +36 -0
  130. package/node_modules/@ocean/core/dist/domain/mcp/memory-contract.js +41 -0
  131. package/node_modules/@ocean/core/dist/domain/ports/brain-index-port.js +7 -0
  132. package/node_modules/@ocean/core/dist/domain/ports/browser-port.js +8 -0
  133. package/node_modules/@ocean/core/dist/domain/ports/embedder-port.js +2 -0
  134. package/node_modules/@ocean/core/dist/domain/ports/platform-ports.js +2 -0
  135. package/node_modules/@ocean/core/dist/domain/ports/runtime-ports.js +2 -0
  136. package/node_modules/@ocean/core/dist/domain/ports/session-store-port.js +2 -0
  137. package/node_modules/@ocean/core/dist/domain/process/process-events.js +5 -0
  138. package/node_modules/@ocean/core/dist/domain/profiles/profile-distribution.js +19 -0
  139. package/node_modules/@ocean/core/dist/domain/profiles/profile-policy.js +34 -0
  140. package/node_modules/@ocean/core/dist/domain/profiles/profile-selection.js +73 -0
  141. package/node_modules/@ocean/core/dist/domain/profiles/profile-upgrade.js +123 -0
  142. package/node_modules/@ocean/core/dist/domain/profiles/profile-validator.js +5 -0
  143. package/node_modules/@ocean/core/dist/domain/profiles/profile.js +218 -0
  144. package/node_modules/@ocean/core/dist/domain/profiles/runtime-config.js +30 -0
  145. package/node_modules/@ocean/core/dist/domain/providers/provider-capability.js +28 -0
  146. package/node_modules/@ocean/core/dist/domain/providers/provider.js +2 -0
  147. package/node_modules/@ocean/core/dist/domain/redaction/redaction.js +86 -0
  148. package/node_modules/@ocean/core/dist/domain/runs/agent-tools.js +92 -0
  149. package/node_modules/@ocean/core/dist/domain/runs/execution-plan.js +71 -0
  150. package/node_modules/@ocean/core/dist/domain/runs/run-contract.js +38 -0
  151. package/node_modules/@ocean/core/dist/domain/sessions/entry-contract.js +31 -0
  152. package/node_modules/@ocean/core/dist/domain/sessions/handoff.js +78 -0
  153. package/node_modules/@ocean/core/dist/domain/sessions/session.js +58 -0
  154. package/node_modules/@ocean/core/dist/domain/skills/default-skills.js +29 -0
  155. package/node_modules/@ocean/core/dist/domain/skills/skill-validator.js +5 -0
  156. package/node_modules/@ocean/core/dist/domain/skills/skill.js +11 -0
  157. package/node_modules/@ocean/core/dist/domain/tasks/task-id.js +85 -0
  158. package/node_modules/@ocean/core/dist/shared/fs-utils.js +212 -0
  159. package/node_modules/@ocean/core/dist/shared/local-date.js +16 -0
  160. package/node_modules/@ocean/core/dist/shared/paths.js +324 -0
  161. package/node_modules/@ocean/core/dist/shared/project-resolution.js +1065 -0
  162. package/node_modules/@ocean/core/dist/shared/task-reference.js +133 -0
  163. package/node_modules/@ocean/core/package.json +14 -0
  164. package/node_modules/@ocean/loop/dist/handoff/handoff-service.js +133 -0
  165. package/node_modules/@ocean/loop/dist/hooks/lifecycle-hooks.js +15 -0
  166. package/node_modules/@ocean/loop/dist/hooks/session-end-hook.js +183 -0
  167. package/node_modules/@ocean/loop/dist/hooks/session-start-hook.js +237 -0
  168. package/node_modules/@ocean/loop/dist/infrastructure/persistence/session-store.js +690 -0
  169. package/node_modules/@ocean/loop/dist/infrastructure/persistence/session-validator.js +5 -0
  170. package/node_modules/@ocean/loop/dist/loops/iteration-graph.js +147 -0
  171. package/node_modules/@ocean/loop/dist/loops/task-loop-record.js +2 -0
  172. package/node_modules/@ocean/loop/dist/loops/task-loop.js +281 -0
  173. package/node_modules/@ocean/loop/dist/operations/memory-knowledge-operations.js +263 -0
  174. package/node_modules/@ocean/loop/dist/operations/operation-contract.js +227 -0
  175. package/node_modules/@ocean/loop/dist/operations/operation-scope.js +28 -0
  176. package/node_modules/@ocean/loop/dist/operations/project-operations.js +93 -0
  177. package/node_modules/@ocean/loop/dist/operations/record-io.js +65 -0
  178. package/node_modules/@ocean/loop/dist/operations/record-operations.js +45 -0
  179. package/node_modules/@ocean/loop/dist/operations/task-linker.js +40 -0
  180. package/node_modules/@ocean/loop/dist/operations/task-operations.js +279 -0
  181. package/node_modules/@ocean/loop/dist/operations/write-guard.js +157 -0
  182. package/node_modules/@ocean/loop/dist/runs/prompt-assembly.js +112 -0
  183. package/node_modules/@ocean/loop/dist/runs/run-agent.js +425 -0
  184. package/node_modules/@ocean/loop/dist/runs/run-authorization.js +24 -0
  185. package/node_modules/@ocean/loop/dist/runs/tool-loop.js +173 -0
  186. package/node_modules/@ocean/loop/dist/sessions/session-closeout.js +150 -0
  187. package/node_modules/@ocean/loop/dist/sessions/session-pointer.js +133 -0
  188. package/node_modules/@ocean/loop/dist/sessions/session-projects.js +26 -0
  189. package/node_modules/@ocean/loop/dist/sessions/session-retention.js +132 -0
  190. package/node_modules/@ocean/loop/dist/tasks/archive-tasks.js +210 -0
  191. package/node_modules/@ocean/loop/dist/tasks/checkpoint-task.js +31 -0
  192. package/node_modules/@ocean/loop/dist/tasks/claim-task.js +126 -0
  193. package/node_modules/@ocean/loop/dist/tasks/list-tasks.js +113 -0
  194. package/node_modules/@ocean/loop/dist/tasks/new-task.js +42 -0
  195. package/node_modules/@ocean/loop/dist/tasks/renumber-tasks.js +134 -0
  196. package/node_modules/@ocean/loop/dist/tasks/verification-readiness.js +78 -0
  197. package/node_modules/@ocean/loop/dist/tasks/verify-task.js +234 -0
  198. package/node_modules/@ocean/loop/package.json +11 -0
  199. package/node_modules/@ocean/market/dist/adapters/mcp-adapter.js +64 -0
  200. package/node_modules/@ocean/market/dist/adapters/owned-directory.js +89 -0
  201. package/node_modules/@ocean/market/dist/adapters/plugin-adapter.js +39 -0
  202. package/node_modules/@ocean/market/dist/adapters/skill-adapter.js +32 -0
  203. package/node_modules/@ocean/market/dist/capability/adapter.js +2 -0
  204. package/node_modules/@ocean/market/dist/capability/catalog.js +63 -0
  205. package/node_modules/@ocean/market/dist/capability/content-digest.js +40 -0
  206. package/node_modules/@ocean/market/dist/capability/registry.js +81 -0
  207. package/node_modules/@ocean/market/dist/install/default-marketplace.js +47 -0
  208. package/node_modules/@ocean/market/dist/install/lock.js +34 -0
  209. package/node_modules/@ocean/market/dist/install/marketplace-service.js +165 -0
  210. package/node_modules/@ocean/market/dist/mcp/browser-bridge.js +263 -0
  211. package/node_modules/@ocean/market/dist/mcp/mcp-connection.js +67 -0
  212. package/node_modules/@ocean/market/dist/mcp/mcp-gateway.js +317 -0
  213. package/node_modules/@ocean/market/dist/mcp/mcp-launch.js +102 -0
  214. package/node_modules/@ocean/market/dist/mcp/mcp-runner.js +32 -0
  215. package/node_modules/@ocean/market/dist/security/description-scan.js +45 -0
  216. package/node_modules/@ocean/market/dist/security/permissions.js +57 -0
  217. package/node_modules/@ocean/market/dist/skills/core-skill-sync.js +113 -0
  218. package/node_modules/@ocean/market/dist/skills/signal-detection.js +84 -0
  219. package/node_modules/@ocean/market/dist/skills/skill-hub.js +220 -0
  220. package/node_modules/@ocean/market/package.json +11 -0
  221. package/node_modules/@ocean/services/dist/browser/browser-service.js +124 -0
  222. package/node_modules/@ocean/services/dist/browser/browser-session.js +287 -0
  223. package/node_modules/@ocean/services/dist/browser/browser-task-runner.js +70 -0
  224. package/node_modules/@ocean/services/dist/doctor/workspace-doctor.js +547 -0
  225. package/node_modules/@ocean/services/dist/infrastructure/mcp/call-ledger.js +114 -0
  226. package/node_modules/@ocean/services/dist/infrastructure/mcp/mcp-client.js +162 -0
  227. package/node_modules/@ocean/services/dist/infrastructure/mcp/obsidian-server.js +251 -0
  228. package/node_modules/@ocean/services/dist/infrastructure/mcp/ocean-server.js +880 -0
  229. package/node_modules/@ocean/services/dist/infrastructure/mcp/server-version.js +20 -0
  230. package/node_modules/@ocean/services/dist/infrastructure/mcp/tool-registry.js +29 -0
  231. package/node_modules/@ocean/services/dist/obsidian/conflict-log.js +68 -0
  232. package/node_modules/@ocean/services/dist/obsidian/inbox-promotion.js +80 -0
  233. package/node_modules/@ocean/services/dist/obsidian/vault-discovery.js +113 -0
  234. package/node_modules/@ocean/services/dist/obsidian/vault-ingestion.js +77 -0
  235. package/node_modules/@ocean/services/dist/obsidian/vault-sync.js +73 -0
  236. package/node_modules/@ocean/services/dist/obsidian/vault-writer.js +75 -0
  237. package/node_modules/@ocean/services/package.json +11 -0
  238. package/ocean-marketplace.json +415 -0
  239. package/package.json +67 -4
  240. package/skills/core/business-logic/SKILL.md +22 -0
  241. package/skills/core/catch-up/SKILL.md +17 -0
  242. package/skills/core/core-thinking/SKILL.md +11 -0
  243. package/skills/core/design-thinking/SKILL.md +19 -0
  244. package/skills/core/graft/SKILL.md +156 -0
  245. package/skills/core/loop/SKILL.md +20 -0
  246. package/skills/core/session-handoff/SKILL.md +15 -0
  247. package/skills/core/use-browser/SKILL.md +69 -0
  248. package/skills/core/verification/SKILL.md +11 -0
  249. package/skills/index.json +56 -0
  250. package/templates/README.md +4 -0
  251. package/templates/profiles/default.json +51 -0
  252. package/templates/profiles/developer.json +51 -0
  253. package/templates/profiles/reviewer.json +51 -0
  254. package/templates/profiles/strategist.json +51 -0
  255. package/templates/workspace/00-inbox/INBOX.md +7 -0
  256. package/templates/workspace/00-inbox/candidates/.gitkeep +0 -0
  257. package/templates/workspace/00-inbox/native/.gitkeep +0 -0
  258. package/templates/workspace/01-daily/.gitkeep +0 -0
  259. package/templates/workspace/02-personal/CONFLICTS.md +7 -0
  260. package/templates/workspace/02-personal/MEMORY.md +15 -0
  261. package/templates/workspace/02-personal/goals/.gitkeep +0 -0
  262. package/templates/workspace/02-personal/identity/.gitkeep +0 -0
  263. package/templates/workspace/02-personal/preferences/.gitkeep +0 -0
  264. package/templates/workspace/03-professional/.gitkeep +0 -0
  265. package/templates/workspace/04-projects/PROJECTS.md +5 -0
  266. package/templates/workspace/04-projects/_template/docs/.gitkeep +0 -0
  267. package/templates/workspace/04-projects/_template/memory/.gitkeep +0 -0
  268. package/templates/workspace/04-projects/_template/tasks/.gitkeep +0 -0
  269. package/templates/workspace/05-knowledge/KNOWLEDGE.md +8 -0
  270. package/templates/workspace/05-knowledge/decisions/.gitkeep +0 -0
  271. package/templates/workspace/05-knowledge/lessons/.gitkeep +0 -0
  272. package/templates/workspace/06-templates/TEMPLATES.md +25 -0
  273. package/templates/workspace/06-templates/decision.md +8 -0
  274. package/templates/workspace/06-templates/intelligence.md +32 -0
  275. package/templates/workspace/06-templates/project-claude.md +48 -0
  276. package/templates/workspace/06-templates/session.md +38 -0
  277. package/templates/workspace/06-templates/task.md +42 -0
  278. package/templates/workspace/MANIFEST.json +51 -0
  279. package/templates/workspace/bridge/config/CONFIG.md +21 -0
  280. package/templates/workspace/bridge/config/runtime.json +4 -0
  281. package/templates/workspace/charter/core.md +104 -0
  282. package/templates/workspace/charter/policies/README.md +31 -0
  283. package/templates/workspace/charter/policies/claude-code-context.md +90 -0
  284. package/templates/workspace/charter/policies/concise-output.md +29 -0
  285. package/templates/workspace/charter/policies/context.md +91 -0
  286. package/templates/workspace/charter/policies/contracts/task.md +189 -0
  287. package/templates/workspace/charter/policies/git.md +60 -0
  288. package/templates/workspace/charter/policies/graph.md +47 -0
  289. package/templates/workspace/charter/policies/knowledge.md +33 -0
  290. package/templates/workspace/charter/policies/lifecycle.md +119 -0
  291. package/templates/workspace/charter/policies/memory.md +67 -0
  292. package/templates/workspace/charter/policies/minimal-change.md +43 -0
  293. package/templates/workspace/charter/policies/models.md +57 -0
  294. package/templates/workspace/charter/policies/privacy-terms.txt +3 -0
  295. package/templates/workspace/charter/policies/response.md +39 -0
  296. package/templates/workspace/charter/policies/skill-observer.md +44 -0
  297. package/templates/workspace/charter/policies/stack.md +23 -0
  298. package/templates/workspace/charter/policies/task.md +139 -0
  299. package/templates/workspace/charter/policies/verification.md +29 -0
  300. package/templates/workspace/sessions/.gitkeep +0 -0
@@ -0,0 +1,145 @@
1
+ import { spawn } from "node:child_process";
2
+ import { accessSync, chmodSync, constants } from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import path from "node:path";
5
+ // node-pty is optional: it has no Linux prebuild, so npm compiles it there and skips it when no
6
+ // compiler toolchain is present. Without it, a provider still runs, attached to this terminal
7
+ // directly, but its terminal output is not recorded.
8
+ let ptyModule;
9
+ const loadPty = () => (ptyModule ??= import("node-pty").catch(() => undefined));
10
+ // node-pty's npm tarball ships its macOS spawn-helper without the executable bit, so every pty
11
+ // spawn fails after a plain `npm install`. Restore the bit once, before the first spawn.
12
+ let spawnHelperChecked = false;
13
+ function ensureSpawnHelperExecutable() {
14
+ if (spawnHelperChecked || process.platform === "win32")
15
+ return;
16
+ spawnHelperChecked = true;
17
+ const root = path.resolve(path.dirname(createRequire(import.meta.url).resolve("node-pty")), "..");
18
+ for (const helper of [
19
+ path.join(root, "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper"),
20
+ path.join(root, "build", "Release", "spawn-helper"),
21
+ ]) {
22
+ try {
23
+ accessSync(helper, constants.X_OK);
24
+ }
25
+ catch {
26
+ try {
27
+ chmodSync(helper, 0o755);
28
+ }
29
+ catch {
30
+ // Missing (a native build provides its own) or not ours to change: the spawn reports it.
31
+ }
32
+ }
33
+ }
34
+ }
35
+ export async function runInteractive(request) {
36
+ const pty = await loadPty();
37
+ if (!pty) {
38
+ process.stderr.write("ocean: node-pty is not installed, so this session's terminal output is not recorded (see docs/troubleshooting.md)\n");
39
+ return await runPassthrough(request);
40
+ }
41
+ return await new Promise((resolve, reject) => {
42
+ let terminal;
43
+ try {
44
+ ensureSpawnHelperExecutable();
45
+ terminal = pty.spawn(request.command, request.args, {
46
+ name: process.env.TERM || "xterm-256color",
47
+ cols: process.stdout.columns || 120,
48
+ rows: process.stdout.rows || 40,
49
+ cwd: request.cwd,
50
+ env: { ...process.env, ...request.env },
51
+ });
52
+ }
53
+ catch (error) {
54
+ reject(error);
55
+ return;
56
+ }
57
+ let output = "";
58
+ let timedOut = false;
59
+ let cancelled = false;
60
+ let timer;
61
+ let forceKillTimer;
62
+ const maxCapture = 64_000;
63
+ const onData = (data) => {
64
+ if (output.length < maxCapture)
65
+ output += data.slice(0, maxCapture - output.length);
66
+ process.stdout.write(data);
67
+ request.onData?.(data.slice(0, 64_000));
68
+ };
69
+ terminal.onData(onData);
70
+ const stdinIsTTY = Boolean(process.stdin.isTTY && process.stdin.setRawMode);
71
+ const onStdin = (data) => {
72
+ const input = data.toString();
73
+ request.onInput?.(input);
74
+ terminal.write(input);
75
+ };
76
+ if (stdinIsTTY) {
77
+ process.stdin.setRawMode?.(true);
78
+ process.stdin.resume();
79
+ process.stdin.on("data", onStdin);
80
+ }
81
+ const onResize = () => terminal.resize(process.stdout.columns || 120, process.stdout.rows || 40);
82
+ process.stdout.on("resize", onResize);
83
+ const stop = (reason) => {
84
+ if (reason === "timeout")
85
+ timedOut = true;
86
+ else
87
+ cancelled = true;
88
+ terminal.kill("SIGTERM");
89
+ forceKillTimer = setTimeout(() => terminal.kill("SIGKILL"), 100);
90
+ };
91
+ const onAbort = () => stop("cancel");
92
+ if (request.timeoutMs !== undefined)
93
+ timer = setTimeout(() => stop("timeout"), request.timeoutMs);
94
+ request.signal?.addEventListener("abort", onAbort, { once: true });
95
+ if (request.signal?.aborted)
96
+ onAbort();
97
+ terminal.onExit(({ exitCode }) => {
98
+ if (timer)
99
+ clearTimeout(timer);
100
+ if (forceKillTimer)
101
+ clearTimeout(forceKillTimer);
102
+ request.signal?.removeEventListener("abort", onAbort);
103
+ if (stdinIsTTY) {
104
+ process.stdin.off("data", onStdin);
105
+ process.stdin.setRawMode?.(false);
106
+ process.stdin.pause();
107
+ }
108
+ process.stdout.off("resize", onResize);
109
+ resolve({ exitCode, output, timedOut, cancelled });
110
+ });
111
+ });
112
+ }
113
+ export function runPassthrough(request) {
114
+ return new Promise((resolve, reject) => {
115
+ const child = spawn(request.command, request.args, {
116
+ cwd: request.cwd,
117
+ env: { ...process.env, ...request.env },
118
+ stdio: "inherit",
119
+ });
120
+ const timer = request.timeoutMs === undefined
121
+ ? undefined
122
+ : setTimeout(() => child.kill("SIGTERM"), request.timeoutMs);
123
+ const onAbort = () => {
124
+ child.kill("SIGTERM");
125
+ };
126
+ request.signal?.addEventListener("abort", onAbort, { once: true });
127
+ child.once("error", (error) => {
128
+ if (timer)
129
+ clearTimeout(timer);
130
+ request.signal?.removeEventListener("abort", onAbort);
131
+ reject(error);
132
+ });
133
+ child.once("close", (exitCode) => {
134
+ if (timer)
135
+ clearTimeout(timer);
136
+ request.signal?.removeEventListener("abort", onAbort);
137
+ resolve({
138
+ exitCode: exitCode ?? 1,
139
+ output: "",
140
+ cancelled: request.signal?.aborted,
141
+ });
142
+ });
143
+ });
144
+ }
145
+ //# sourceMappingURL=interactive-process.js.map
@@ -0,0 +1,194 @@
1
+ import { StringDecoder } from "node:string_decoder";
2
+ // The one place that decides how a headless run ends, for every provider that runs a process: the
3
+ // run's timeout (124), its output budget (125), the process group it runs in, the signals passed
4
+ // on to it, and how stdout becomes lines. `runHeadless` (CLI providers) and the Claude Agent SDK
5
+ // runner both use it, so a fix to any of these lands once.
6
+ // A process run in its own group is stopped as a whole, so a timeout or budget stop ends
7
+ // everything it started (a tool's subprocess too), not just the leader: a surviving descendant
8
+ // would hold the output pipe open and keep the run waiting.
9
+ export const ownsGroup = process.platform !== "win32";
10
+ const forwardedSignals = ["SIGINT", "SIGTERM", "SIGHUP"];
11
+ // How long output still in the pipe gets, once the process itself has exited, before whatever
12
+ // else holds the pipe open (a background process it left behind) is stopped and no longer awaited.
13
+ const LINGER_MS = 500;
14
+ export function signalTree(child, signal) {
15
+ if (!child?.pid)
16
+ return;
17
+ try {
18
+ if (ownsGroup)
19
+ process.kill(-child.pid, signal);
20
+ else
21
+ child.kill(signal);
22
+ }
23
+ catch {
24
+ // Already gone.
25
+ }
26
+ }
27
+ // Out of the terminal's process group, a run no longer receives this process's Ctrl+C or kill
28
+ // directly; pass them on, then let the signal do what it would have done here. One set of
29
+ // listeners serves every run in flight, so many concurrent runs never trip Node's listener warning.
30
+ const active = new Set();
31
+ let listening = false;
32
+ const onExit = () => {
33
+ for (const child of active)
34
+ signalTree(child, "SIGTERM");
35
+ };
36
+ const onSignal = (signal) => {
37
+ onExit();
38
+ unlisten();
39
+ if (process.listenerCount(signal) === 0)
40
+ process.kill(process.pid, signal);
41
+ };
42
+ function unlisten() {
43
+ if (!listening)
44
+ return;
45
+ listening = false;
46
+ process.off("exit", onExit);
47
+ for (const signal of forwardedSignals)
48
+ process.off(signal, onSignal);
49
+ }
50
+ function endWithThisProcess(child) {
51
+ if (!listening) {
52
+ listening = true;
53
+ process.once("exit", onExit);
54
+ for (const signal of forwardedSignals)
55
+ process.on(signal, onSignal);
56
+ }
57
+ active.add(child);
58
+ return () => {
59
+ active.delete(child);
60
+ if (active.size === 0)
61
+ unlisten();
62
+ };
63
+ }
64
+ export function superviseProcess(options) {
65
+ let child;
66
+ let release = () => { };
67
+ let spawnError;
68
+ let stderr = "";
69
+ let outputBytes = 0;
70
+ let timedOut = false;
71
+ let outputLimitExceeded = false;
72
+ let terminating = false;
73
+ let killTimer;
74
+ let lingerTimer;
75
+ let letGoNow = () => { };
76
+ const released = new Promise((resolve) => {
77
+ letGoNow = resolve;
78
+ });
79
+ let closedNow = () => { };
80
+ const closed = new Promise((resolve) => {
81
+ closedNow = resolve;
82
+ });
83
+ // Whatever still holds the pipes (a descendant that left the group) no longer holds the run.
84
+ const letGo = () => {
85
+ child?.stdout?.destroy();
86
+ child?.stderr?.destroy();
87
+ letGoNow();
88
+ };
89
+ const terminate = () => {
90
+ if (terminating)
91
+ return;
92
+ terminating = true;
93
+ options.onTerminate?.();
94
+ signalTree(child, "SIGTERM");
95
+ // Not unref'd: this timer keeps the process alive until the run has been let go.
96
+ killTimer = setTimeout(() => {
97
+ signalTree(child, "SIGKILL");
98
+ letGo();
99
+ }, 100);
100
+ };
101
+ // Armed until the process has closed, not just until the output stops.
102
+ const timer = setTimeout(() => {
103
+ timedOut = true;
104
+ terminate();
105
+ }, options.timeoutMs);
106
+ // Raw stdout and stderr bytes count against one budget as they arrive, before anything buffers
107
+ // a line, so a huge or unterminated line cannot grow past the cap.
108
+ const withinBudget = (bytes) => {
109
+ if (outputLimitExceeded)
110
+ return false;
111
+ if (outputBytes + bytes > options.maxOutputBytes) {
112
+ outputLimitExceeded = true;
113
+ terminate();
114
+ return false;
115
+ }
116
+ outputBytes += bytes;
117
+ return true;
118
+ };
119
+ const decoder = new StringDecoder("utf8");
120
+ let pending = "";
121
+ const emit = (line) => {
122
+ if (line)
123
+ options.onLine?.(line);
124
+ };
125
+ return {
126
+ attach(spawned) {
127
+ child = spawned;
128
+ if (ownsGroup)
129
+ release = endWithThisProcess(spawned);
130
+ // A failed start (no such executable) is a failed run; the abort of a stop we asked for is not.
131
+ spawned.once("error", (error) => {
132
+ if (terminating)
133
+ return;
134
+ spawnError = error;
135
+ letGo();
136
+ });
137
+ spawned.once("exit", () => {
138
+ if (!terminating)
139
+ lingerTimer = setTimeout(letGo, LINGER_MS);
140
+ });
141
+ spawned.once("close", closedNow);
142
+ spawned.stdout?.on("data", (chunk) => {
143
+ if (!withinBudget(chunk.byteLength))
144
+ return;
145
+ pending += decoder.write(chunk);
146
+ const lines = pending.split(/\r?\n/);
147
+ pending = lines.pop() ?? "";
148
+ for (const line of lines)
149
+ emit(line);
150
+ });
151
+ spawned.stderr?.on("data", (chunk) => {
152
+ if (withinBudget(chunk.byteLength))
153
+ stderr += chunk.toString("utf8");
154
+ });
155
+ },
156
+ closed,
157
+ released,
158
+ get spawnError() {
159
+ return spawnError;
160
+ },
161
+ get timedOut() {
162
+ return timedOut;
163
+ },
164
+ get outputLimitExceeded() {
165
+ return outputLimitExceeded;
166
+ },
167
+ get stderr() {
168
+ return stderr;
169
+ },
170
+ get stopNote() {
171
+ return timedOut
172
+ ? "Process timed out.\n"
173
+ : outputLimitExceeded
174
+ ? "Output budget exceeded.\n"
175
+ : "";
176
+ },
177
+ exitCode(code) {
178
+ return timedOut ? 124 : outputLimitExceeded ? 125 : (code ?? 1);
179
+ },
180
+ flush() {
181
+ emit(pending + decoder.end());
182
+ pending = "";
183
+ },
184
+ finish() {
185
+ clearTimeout(timer);
186
+ clearTimeout(lingerTimer);
187
+ clearTimeout(killTimer);
188
+ // The leader is gone; end anything it left in the group, then stop watching it.
189
+ signalTree(child, "SIGKILL");
190
+ release();
191
+ },
192
+ };
193
+ }
194
+ //# sourceMappingURL=process-supervisor.js.map
@@ -0,0 +1,252 @@
1
+ import { execFile, spawn } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { promisify } from "node:util";
6
+ import { reindexBrain } from "@ocean/brain/brain/brain-reindex.js";
7
+ import { brainIndexState } from "@ocean/brain/brain/brain-service.js";
8
+ import { brainIndexPort } from "@ocean/brain/infrastructure/brain/brain-index.js";
9
+ import { loadObsidianConnection } from "@ocean/services/obsidian/vault-discovery.js";
10
+ import { watchObsidianVault } from "@ocean/services/obsidian/vault-sync.js";
11
+ import { refreshClaudeProjects } from "../../application/pull/server-capture.js";
12
+ import { createOllamaEmbedder } from "../providers/ollama-embedder.js";
13
+ const HOUR_MS = 60 * 60 * 1000;
14
+ const REINDEX_CHECK_MS = 2 * 60 * 1000;
15
+ const CLAUDE_PROJECTS_MS = 15 * 60 * 1000;
16
+ let reindexing = false;
17
+ // Keeps the brain index current (T-307): a record written over MCP, an approval or a hand edit is
18
+ // searchable within minutes, without `ocean memory reindex`. The build goes to a temp file renamed
19
+ // into place, so a search never reads half an index. Vectors when the local embedder answers;
20
+ // without one, an index that has vectors waits for it rather than losing them, and one without is
21
+ // rebuilt as full text. OCEAN_NO_AUTO_REINDEX=1 turns it off.
22
+ export async function reindexWhenStale(options = {}) {
23
+ if (process.env.OCEAN_NO_AUTO_REINDEX === "1")
24
+ return "off";
25
+ if (reindexing)
26
+ return "busy";
27
+ reindexing = true;
28
+ try {
29
+ const state = await brainIndexState({
30
+ root: options.root,
31
+ indexPort: brainIndexPort,
32
+ });
33
+ if (!state.stale)
34
+ return "fresh";
35
+ const embedder = await (options.embedder ?? (() => createOllamaEmbedder()))().catch(() => null);
36
+ if (!embedder && state.hasVectors)
37
+ return "waiting";
38
+ await reindexBrain({
39
+ root: options.root,
40
+ embedder,
41
+ indexPort: brainIndexPort,
42
+ });
43
+ return "rebuilt";
44
+ }
45
+ finally {
46
+ reindexing = false;
47
+ }
48
+ }
49
+ // The owner's Claude project names, so a conversation in a new Claude project can register it
50
+ // (T-307). Reading the caches takes tens of seconds, so it runs here, never in a tool call.
51
+ function startClaudeProjectsRefresh() {
52
+ if (process.env.OCEAN_NO_PULL_ON_START === "1")
53
+ return;
54
+ refreshClaudeProjects(os.homedir()).catch((error) => {
55
+ console.error(`Claude project names not refreshed: ${error instanceof Error ? error.message : String(error)}`);
56
+ });
57
+ }
58
+ function startAutoReindex() {
59
+ reindexWhenStale().catch((error) => {
60
+ console.error(`brain reindex failed: ${error instanceof Error ? error.message : String(error)}`);
61
+ });
62
+ }
63
+ // The daily `ocean pull --yes` (T-305) in a detached child; it returns at once when the last pull
64
+ // is under a day old. Session starts run it, and so does the always-on service, so a user who only
65
+ // opens Claude Desktop is pulled too. OCEAN_NO_PULL_ON_START=1 turns both off.
66
+ export function startBackgroundPull() {
67
+ if (process.env.OCEAN_NO_PULL_ON_START === "1")
68
+ return;
69
+ try {
70
+ spawn(process.execPath, [process.argv[1], "pull", "--yes", "--daily"], {
71
+ detached: true,
72
+ stdio: "ignore",
73
+ })
74
+ .on("error", () => { })
75
+ .unref();
76
+ }
77
+ catch {
78
+ // no pull this time; the next try runs it
79
+ }
80
+ }
81
+ const runCommand = (command, args) => promisify(execFile)(command, args);
82
+ function serviceContext(options) {
83
+ const home = options.home ?? os.homedir();
84
+ const domain = `gui/${process.getuid?.() ?? ""}`;
85
+ return {
86
+ home,
87
+ platform: options.platform ?? process.platform,
88
+ run: options.run ?? runCommand,
89
+ wait: options.wait ??
90
+ ((ms) => new Promise((resolve) => setTimeout(resolve, ms))),
91
+ plist: path.join(home, "Library", "LaunchAgents", "com.ocean.runtime.plist"),
92
+ unit: path.join(home, ".config", "systemd", "user", "ocean.service"),
93
+ domain,
94
+ label: `${domain}/com.ocean.runtime`,
95
+ };
96
+ }
97
+ const loaded = (context) => context.run("launchctl", ["print", context.label]).then(() => true, () => false);
98
+ // Loads the launchd job: three tries a second apart, then the error names the command that
99
+ // starts it, since nothing else would retry it.
100
+ async function bootstrap(context) {
101
+ let failure;
102
+ for (let attempt = 0; attempt < 3; attempt += 1) {
103
+ if (attempt)
104
+ await context.wait(1000);
105
+ try {
106
+ await context.run("launchctl", [
107
+ "bootstrap",
108
+ context.domain,
109
+ context.plist,
110
+ ]);
111
+ return;
112
+ }
113
+ catch (error) {
114
+ failure = error;
115
+ }
116
+ }
117
+ throw new Error(`${failure instanceof Error ? failure.message : String(failure)} — the service is stopped; start it with: launchctl bootstrap ${context.domain} ${context.plist}`);
118
+ }
119
+ // A running service keeps the engine it started with, whatever `current` or its start file now
120
+ // say (T-305), so a new build or a repointed start file restarts it. With the start file
121
+ // unchanged (`reload: false`), launchd's kickstart restarts the process while the job stays
122
+ // loaded, so KeepAlive covers it throughout (T-307). A changed file needs the job unloaded and
123
+ // loaded again: bootout returns before launchd has removed the job, and a bootstrap while it is
124
+ // still there fails ("Bootstrap failed: 5: Input/output error"), so it waits until `print` no
125
+ // longer finds it (up to 5 s) and retries. systemd re-reads the unit on reload; the Windows
126
+ // startup script has no manager and takes effect at next login. Never throws: it runs inside
127
+ // session starts, which must not fail on it.
128
+ export async function restartService(options = {}) {
129
+ const context = serviceContext(options);
130
+ const { run, wait } = context;
131
+ try {
132
+ if (context.platform === "darwin") {
133
+ if (!existsSync(context.plist))
134
+ return "not-installed";
135
+ if (options.reload === false) {
136
+ const kicked = await run("launchctl", [
137
+ "kickstart",
138
+ "-k",
139
+ context.label,
140
+ ]).then(() => true, () => false);
141
+ if (!kicked)
142
+ await bootstrap(context);
143
+ return "restarted";
144
+ }
145
+ await run("launchctl", ["bootout", context.label]).catch(() => { });
146
+ for (let poll = 0; poll < 20 && (await loaded(context)); poll += 1)
147
+ await wait(250);
148
+ await bootstrap(context);
149
+ return "restarted";
150
+ }
151
+ if (context.platform === "linux") {
152
+ if (!existsSync(context.unit))
153
+ return "not-installed";
154
+ await run("systemctl", ["--user", "daemon-reload"]);
155
+ await run("systemctl", ["--user", "try-restart", "ocean.service"]);
156
+ return "restarted";
157
+ }
158
+ const startup = path.join(process.env.APPDATA ?? path.join(context.home, "AppData", "Roaming"), "Microsoft", "Windows", "Start Menu", "Programs", "Startup", "ocean.cmd");
159
+ return context.platform === "win32" && existsSync(startup)
160
+ ? "next-login"
161
+ : "not-installed";
162
+ }
163
+ catch (error) {
164
+ return { failed: error instanceof Error ? error.message : String(error) };
165
+ }
166
+ }
167
+ // The safety net (T-307): every session start makes sure an installed service is loaded and
168
+ // running, so nothing — a failed restart, a manual bootout — leaves it stopped past the next
169
+ // session. Windows has no service manager to ask. Never throws.
170
+ export async function ensureService(options = {}) {
171
+ const context = serviceContext(options);
172
+ try {
173
+ if (context.platform === "darwin") {
174
+ if (!existsSync(context.plist))
175
+ return "not-installed";
176
+ if (await loaded(context))
177
+ return "running";
178
+ await bootstrap(context);
179
+ return "started";
180
+ }
181
+ if (context.platform === "linux") {
182
+ if (!existsSync(context.unit))
183
+ return "not-installed";
184
+ const active = await context
185
+ .run("systemctl", ["--user", "is-active", "--quiet", "ocean.service"])
186
+ .then(() => true, () => false);
187
+ if (active)
188
+ return "running";
189
+ await context.run("systemctl", ["--user", "start", "ocean.service"]);
190
+ return "started";
191
+ }
192
+ return "unchecked";
193
+ }
194
+ catch (error) {
195
+ return { failed: error instanceof Error ? error.message : String(error) };
196
+ }
197
+ }
198
+ export async function runService(shutdownAfterMs) {
199
+ const controller = new AbortController();
200
+ let watcher;
201
+ try {
202
+ const connection = await loadObsidianConnection();
203
+ watcher = watchObsidianVault(connection, undefined, controller.signal).catch((error) => {
204
+ console.error(`Obsidian watcher stopped: ${error instanceof Error ? error.message : String(error)}`);
205
+ });
206
+ console.log(`Obsidian watcher enabled: ${connection.vaultPath}`);
207
+ }
208
+ catch (error) {
209
+ if (error.code !== "ENOENT") {
210
+ console.error(`Obsidian watcher unavailable: ${error instanceof Error ? error.message : String(error)}`);
211
+ }
212
+ }
213
+ const heartbeat = setInterval(() => undefined, 60_000);
214
+ startBackgroundPull();
215
+ const dailyPull = setInterval(startBackgroundPull, HOUR_MS);
216
+ startAutoReindex();
217
+ const autoReindex = setInterval(startAutoReindex, REINDEX_CHECK_MS);
218
+ startClaudeProjectsRefresh();
219
+ const claudeProjects = setInterval(startClaudeProjectsRefresh, CLAUDE_PROJECTS_MS);
220
+ await new Promise((resolve) => {
221
+ let testShutdown;
222
+ const shutdown = (signal) => {
223
+ console.log(`Ocean runtime received ${signal}, shutting down.`);
224
+ clearInterval(heartbeat);
225
+ clearInterval(dailyPull);
226
+ clearInterval(autoReindex);
227
+ clearInterval(claudeProjects);
228
+ controller.abort();
229
+ process.off("SIGINT", shutdown);
230
+ process.off("SIGTERM", shutdown);
231
+ process.off("message", onMessage);
232
+ if (testShutdown)
233
+ clearTimeout(testShutdown);
234
+ resolve();
235
+ };
236
+ const onMessage = (message) => {
237
+ if (message === "shutdown")
238
+ shutdown("IPC");
239
+ };
240
+ process.on("SIGINT", shutdown);
241
+ process.on("SIGTERM", shutdown);
242
+ process.on("message", onMessage);
243
+ // Only now is a SIGTERM handled gracefully; announcing earlier lets a signal that
244
+ // arrives during startup kill the process before it can shut down cleanly.
245
+ console.log("Ocean runtime is running.");
246
+ if (shutdownAfterMs !== undefined)
247
+ testShutdown = setTimeout(() => shutdown("timer"), shutdownAfterMs);
248
+ });
249
+ await watcher;
250
+ console.log("Ocean runtime stopped.");
251
+ }
252
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=browser-provider.js.map