@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,78 @@
1
+ import { z } from "zod";
2
+ const handoffSchema = z.object({
3
+ handoffId: z.string().min(1),
4
+ taskId: z.string().nullable(),
5
+ title: z.string().min(1),
6
+ objective: z.string().default(""),
7
+ state: z.string().min(1),
8
+ profileId: z.string().default(""),
9
+ profileIdentity: z.string().default(""),
10
+ sourceSessionId: z.string().nullable(),
11
+ projectId: z.string().nullable().default(null),
12
+ provider: z.string().default(""),
13
+ parentSessionId: z.string().nullable(),
14
+ decisions: z.array(z.string()).default([]),
15
+ changedFiles: z.array(z.string()).default([]),
16
+ commit: z.string().nullable(),
17
+ verification: z.array(z.string()).default([]),
18
+ notProven: z.array(z.string()).default([]),
19
+ blocked: z.array(z.string()).default([]),
20
+ permissions: z.record(z.string(), z.unknown()).default({}),
21
+ contextManifest: z.record(z.string(), z.unknown()).default({}),
22
+ nextAction: z.string().default(""),
23
+ sourceSummaryPath: z.string().nullable().default(null),
24
+ content: z.string().max(16_000).default(""),
25
+ contentBytes: z.number().int().nonnegative().default(0),
26
+ createdAt: z.string().min(1),
27
+ updatedAt: z.string().min(1),
28
+ });
29
+ export function validateHandoff(input) {
30
+ return handoffSchema.parse(input);
31
+ }
32
+ export function compactHandoff(handoff, maxBytes = 8_000) {
33
+ const value = {
34
+ handoffId: handoff.handoffId,
35
+ taskId: handoff.taskId,
36
+ title: handoff.title,
37
+ objective: handoff.objective,
38
+ state: handoff.state,
39
+ profileId: handoff.profileId,
40
+ provider: handoff.provider,
41
+ commit: handoff.commit,
42
+ decisions: handoff.decisions,
43
+ changedFiles: handoff.changedFiles,
44
+ verification: handoff.verification,
45
+ notProven: handoff.notProven,
46
+ blocked: handoff.blocked,
47
+ permissions: handoff.permissions,
48
+ contextManifest: handoff.contextManifest,
49
+ nextAction: handoff.nextAction,
50
+ sourceSummaryPath: handoff.sourceSummaryPath,
51
+ };
52
+ const serialize = (candidate) => JSON.stringify(candidate);
53
+ let serialized = serialize(value);
54
+ if (Buffer.byteLength(serialized) <= maxBytes)
55
+ return serialized;
56
+ const compact = {
57
+ ...value,
58
+ decisions: value.decisions.slice(0, 8),
59
+ changedFiles: value.changedFiles.slice(0, 24),
60
+ verification: value.verification.slice(0, 8),
61
+ notProven: value.notProven.slice(0, 8),
62
+ blocked: value.blocked.slice(0, 8),
63
+ permissions: {},
64
+ contextManifest: {},
65
+ };
66
+ serialized = serialize(compact);
67
+ if (Buffer.byteLength(serialized) <= maxBytes)
68
+ return serialized;
69
+ return JSON.stringify({
70
+ handoffId: handoff.handoffId,
71
+ taskId: handoff.taskId,
72
+ title: handoff.title,
73
+ state: handoff.state,
74
+ nextAction: handoff.nextAction,
75
+ truncated: true,
76
+ });
77
+ }
78
+ //# sourceMappingURL=handoff.js.map
@@ -0,0 +1,58 @@
1
+ import { z } from "zod";
2
+ const sessionStatusSchema = z.enum([
3
+ "created",
4
+ "running",
5
+ "completed",
6
+ "failed",
7
+ "cancelled",
8
+ ]);
9
+ export const sessionSchema = z.object({
10
+ sessionId: z.string().min(1),
11
+ title: z.string().default(""),
12
+ taskId: z.string().nullable().default(null),
13
+ handoffId: z.string().nullable().default(null),
14
+ provider: z.string().min(1),
15
+ providerSessionId: z.string().nullable(),
16
+ parentSessionId: z.string().nullable(),
17
+ profile: z.string().min(1),
18
+ profileIdentity: z.string().default(""),
19
+ workingDirectory: z.string().min(1),
20
+ status: sessionStatusSchema,
21
+ createdAt: z.string().min(1),
22
+ updatedAt: z.string().min(1),
23
+ resumeData: z.string().nullable(),
24
+ contextHash: z.string().nullable().default(null),
25
+ contextBytes: z.number().int().nonnegative().default(0),
26
+ nextAction: z.string().default(""),
27
+ verificationStatus: z
28
+ .enum(["unknown", "proven", "not_proven", "blocked"])
29
+ .default("unknown"),
30
+ summaryPath: z.string().nullable().default(null),
31
+ summaryHash: z.string().nullable().default(null),
32
+ summaryBytes: z.number().int().nonnegative().default(0),
33
+ closeoutStatus: z.enum(["pending", "completed", "failed"]).default("pending"),
34
+ closeoutVersion: z.string().default("1"),
35
+ closedAt: z.string().nullable().default(null),
36
+ projectId: z.string().nullable().default(null),
37
+ });
38
+ // created: a session has been persisted but has not been sent to a provider yet.
39
+ // running: a headless provider run is in progress for this session.
40
+ // completed / failed: the most recent run finished; the session can still be resumed
41
+ // (running is reachable again) because "completed"/"failed" describe the last run,
42
+ // not the session's availability.
43
+ // cancelled: terminal. A cancelled session is never resumed.
44
+ const allowedTransitions = {
45
+ created: ["running"],
46
+ running: ["completed", "failed", "cancelled"],
47
+ completed: ["running"],
48
+ failed: ["running"],
49
+ cancelled: [],
50
+ };
51
+ export function assertValidStatusTransition(from, to) {
52
+ if (from === to)
53
+ return;
54
+ if (!allowedTransitions[from].includes(to)) {
55
+ throw new Error(`Invalid session status transition: ${from} -> ${to}`);
56
+ }
57
+ }
58
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1,29 @@
1
+ const DEFAULT_SKILLS = [
2
+ "design-thinking",
3
+ "business-logic",
4
+ "core-thinking",
5
+ "verification",
6
+ "loop",
7
+ ];
8
+ export function defaultSkillNames(_role) {
9
+ const role = _role.toLowerCase();
10
+ if (role.includes("research"))
11
+ return [
12
+ "design-thinking",
13
+ "business-logic",
14
+ "core-thinking",
15
+ "verification",
16
+ ];
17
+ if (role.includes("test"))
18
+ return [
19
+ "design-thinking",
20
+ "business-logic",
21
+ "verification",
22
+ "use-browser",
23
+ "loop",
24
+ ];
25
+ if (role.includes("developer") || role.includes("engineer"))
26
+ return [...DEFAULT_SKILLS, "use-browser"];
27
+ return [...DEFAULT_SKILLS, "use-browser"];
28
+ }
29
+ //# sourceMappingURL=default-skills.js.map
@@ -0,0 +1,5 @@
1
+ import { skillSchema } from "./skill.js";
2
+ export function validateSkill(input) {
3
+ return skillSchema.parse(input);
4
+ }
5
+ //# sourceMappingURL=skill-validator.js.map
@@ -0,0 +1,11 @@
1
+ import { z } from "zod";
2
+ export const skillMetadataSchema = z.object({
3
+ name: z.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
4
+ description: z.string().min(1),
5
+ version: z.string().min(1),
6
+ category: z.enum(["core", "role", "project", "personal"]),
7
+ });
8
+ export const skillSchema = skillMetadataSchema.extend({
9
+ instructions: z.string().min(1),
10
+ });
11
+ //# sourceMappingURL=skill.js.map
@@ -0,0 +1,85 @@
1
+ // Task identifiers: <PREFIX>-<number> (T-256). Pure — no I/O. Every place that used to hard-code
2
+ // `T-\d+` goes through here, so the legacy `T` namespace and per-project prefixes (OL-001) are
3
+ // one rule.
4
+ // The namespace every task had before prefixes existed; it stays valid forever.
5
+ export const LEGACY_PREFIX = "T";
6
+ export const PREFIX_SHAPE = /^[A-Z][A-Z0-9]{0,5}$/;
7
+ export const TASK_ID = /^[A-Z][A-Z0-9]{0,5}-\d{1,6}$/;
8
+ // Real-world tokens shaped like an id ("UTF-8", "SHA-256", "ISO-8601", "GPT-5"): a project
9
+ // may never claim one, or free text would turn every mention into a task reference.
10
+ export const RESERVED_PREFIXES = [
11
+ "CVE",
12
+ "GPT",
13
+ "HTTP",
14
+ "ISO",
15
+ "PR",
16
+ "RFC",
17
+ "SHA",
18
+ "TLS",
19
+ "UTF",
20
+ ];
21
+ export function isValidPrefix(value) {
22
+ return PREFIX_SHAPE.test(value) && !RESERVED_PREFIXES.includes(value);
23
+ }
24
+ // Case-insensitive on input (`t-45`, `ol-1`), canonical upper-case prefix on output.
25
+ export function parseTaskId(value) {
26
+ const match = /^([A-Za-z][A-Za-z0-9]{0,5})-(\d{1,6})$/.exec(value);
27
+ if (!match)
28
+ return null;
29
+ return { prefix: match[1].toUpperCase(), number: Number(match[2]) };
30
+ }
31
+ export function formatTaskId(prefix, number) {
32
+ return `${prefix}-${String(number).padStart(3, "0")}`;
33
+ }
34
+ // A task folder may be spelled T-3 or T-003; both name the same task.
35
+ export function taskIdSpellings(id) {
36
+ const parsed = parseTaskId(id);
37
+ if (!parsed)
38
+ return [id];
39
+ return [
40
+ ...new Set([
41
+ id,
42
+ formatTaskId(parsed.prefix, parsed.number),
43
+ `${parsed.prefix}-${parsed.number}`,
44
+ ]),
45
+ ];
46
+ }
47
+ // Ids mentioned in free text. `T-<n>` stays case-insensitive as it always was; any other prefix
48
+ // matches only when registered and written upper-case, so "utf-8" or "sha-256" never match.
49
+ export function extractTaskIds(text, prefixes = [LEGACY_PREFIX]) {
50
+ const ids = new Set();
51
+ for (const match of text.matchAll(/\bT-(\d+)\b/gi))
52
+ ids.add(`${LEGACY_PREFIX}-${match[1]}`);
53
+ // Filtered to [A-Z0-9] by isValidPrefix, so joining into a pattern needs no escaping.
54
+ const others = [...new Set(prefixes)].filter((prefix) => prefix !== LEGACY_PREFIX && isValidPrefix(prefix));
55
+ if (others.length)
56
+ for (const match of text.matchAll(new RegExp(`\\b(${others.join("|")})-(\\d+)\\b`, "g")))
57
+ ids.add(`${match[1]}-${match[2]}`);
58
+ return [...ids];
59
+ }
60
+ // A short prefix from a project id: initials of a multi-part id (ocean-language -> OL), else the
61
+ // first three letters (dashboard -> DAS). Taken or reserved candidates get a numeric suffix.
62
+ export function derivePrefix(projectId, taken = []) {
63
+ const used = new Set([...taken, LEGACY_PREFIX].map((prefix) => prefix.toUpperCase()));
64
+ const segments = projectId
65
+ .toUpperCase()
66
+ .split(/[-._]/)
67
+ .map((segment) => segment.replace(/[^A-Z0-9]/g, "").replace(/^[0-9]+/, ""))
68
+ .filter(Boolean);
69
+ const base = segments.length > 1
70
+ ? segments
71
+ .map((segment) => segment[0])
72
+ .join("")
73
+ .slice(0, 6)
74
+ : (segments[0] ?? "P").slice(0, 3);
75
+ const free = (candidate) => isValidPrefix(candidate) && !used.has(candidate);
76
+ if (free(base))
77
+ return base;
78
+ for (let suffix = 2;; suffix += 1) {
79
+ const tail = String(suffix);
80
+ const candidate = `${base.slice(0, 6 - tail.length)}${tail}`;
81
+ if (free(candidate))
82
+ return candidate;
83
+ }
84
+ }
85
+ //# sourceMappingURL=task-id.js.map
@@ -0,0 +1,212 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { existsSync, mkdirSync, renameSync } from "node:fs";
3
+ import { chmod, link, mkdir, readFile, realpath, rename, rm, stat, writeFile, } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { StringDecoder } from "node:string_decoder";
6
+ import { LEGACY_REGISTRY_DIR, oceanPath, REGISTRY_DIR } from "./paths.js";
7
+ // Small filesystem/parsing helpers shared across layers, kept alongside paths.ts rather than
8
+ // under any single layer since both application and infrastructure code use them directly.
9
+ // Atomic write: content lands in a sibling temp file and is renamed into place, so a failure
10
+ // (disk full, OOM kill, thrown error) never leaves the target truncated or partially written.
11
+ // A symlinked target is written through to the file it names, so the link survives, and an
12
+ // existing file keeps its permission bits unless a mode is given (T-296): renaming a fresh
13
+ // temp over a 0600 client config used to leave it at the umask default.
14
+ export async function atomicWrite(target, content, mode) {
15
+ let destination = target;
16
+ let keep = mode;
17
+ try {
18
+ destination = await realpath(target);
19
+ if (keep === undefined)
20
+ keep = (await stat(destination)).mode & 0o7777;
21
+ }
22
+ catch (error) {
23
+ if (error.code !== "ENOENT")
24
+ throw error;
25
+ }
26
+ const temp = `${destination}.ocean-tmp-${process.pid}-${Date.now()}`;
27
+ try {
28
+ await writeFile(temp, content, { encoding: "utf8", mode: keep });
29
+ // writeFile's mode is masked by the umask; chmod sets the exact bits.
30
+ if (keep !== undefined)
31
+ await chmod(temp, keep);
32
+ await rename(temp, destination);
33
+ return Buffer.byteLength(content, "utf8");
34
+ }
35
+ catch (error) {
36
+ await rm(temp, { force: true });
37
+ throw error;
38
+ }
39
+ }
40
+ // Exclusive cross-process lock around a read-modify-write of `target` (T-257): concurrent
41
+ // session closeouts each read a shared file, edit it and write it back, and without a lock
42
+ // the later write drops the earlier one's changes. The lock is `<target>.lock`, holding a
43
+ // token unique to this acquisition. It is created by linking a fully written temp file into
44
+ // place, so it is never seen empty, and released only while it still holds our token.
45
+ const LOCK_WAIT_MS = 10_000;
46
+ const LOCK_RETRY_MS = 20;
47
+ // The sections this guards take milliseconds. A lock older than this belongs to a writer that
48
+ // died or whose pid was reused, and is stale whoever it appears to belong to.
49
+ const LOCK_STALE_MS = 60_000;
50
+ // The takeover guard is only ever held for a read and an unlink.
51
+ const TAKEOVER_STALE_MS = 5_000;
52
+ async function createLockFile(lock, token) {
53
+ const temp = `${lock}.ocean-tmp-${randomUUID()}`;
54
+ await writeFile(temp, token, "utf8");
55
+ try {
56
+ await link(temp, lock);
57
+ return true;
58
+ }
59
+ catch (error) {
60
+ if (error.code === "EEXIST")
61
+ return false;
62
+ throw error;
63
+ }
64
+ finally {
65
+ await rm(temp, { force: true });
66
+ }
67
+ }
68
+ function ownerIsGone(token) {
69
+ const pid = Number.parseInt(token, 10);
70
+ if (!Number.isInteger(pid) || pid <= 0)
71
+ return true;
72
+ try {
73
+ process.kill(pid, 0);
74
+ return false;
75
+ }
76
+ catch (error) {
77
+ return error.code !== "EPERM";
78
+ }
79
+ }
80
+ async function staleLockToken(lock) {
81
+ const token = await readFile(lock, "utf8").catch(() => null);
82
+ const info = await stat(lock).catch(() => null);
83
+ if (token === null || info === null)
84
+ return null;
85
+ return Date.now() - info.mtimeMs > LOCK_STALE_MS || ownerIsGone(token)
86
+ ? token
87
+ : null;
88
+ }
89
+ // Removes a stale lock, but only under a takeover guard and only if the lock still holds the
90
+ // token judged stale: two waiters that both saw the same stale lock can never end up deleting
91
+ // a live lock one of them has just created. Returns whether the stale lock was removed.
92
+ async function removeStaleLock(lock, stale) {
93
+ const guard = `${lock}.takeover`;
94
+ if (!(await createLockFile(guard, `${process.pid} ${randomUUID()}`))) {
95
+ const info = await stat(guard).catch(() => null);
96
+ if (info && Date.now() - info.mtimeMs > TAKEOVER_STALE_MS)
97
+ await rm(guard, { force: true });
98
+ return false;
99
+ }
100
+ try {
101
+ if ((await readFile(lock, "utf8").catch(() => null)) !== stale)
102
+ return false;
103
+ await rm(lock, { force: true });
104
+ return true;
105
+ }
106
+ finally {
107
+ await rm(guard, { force: true });
108
+ }
109
+ }
110
+ export async function withFileLock(target, run) {
111
+ const lock = `${target}.lock`;
112
+ const token = `${process.pid} ${randomUUID()}`;
113
+ const deadline = Date.now() + LOCK_WAIT_MS;
114
+ await mkdir(path.dirname(lock), { recursive: true });
115
+ for (;;) {
116
+ if (await createLockFile(lock, token))
117
+ break;
118
+ const stale = await staleLockToken(lock);
119
+ if (stale !== null && (await removeStaleLock(lock, stale)))
120
+ continue;
121
+ if (Date.now() > deadline)
122
+ throw new Error(`Lock ${lock} still held after ${LOCK_WAIT_MS} ms`);
123
+ await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_MS));
124
+ }
125
+ try {
126
+ return await run();
127
+ }
128
+ finally {
129
+ if ((await readFile(lock, "utf8").catch(() => null)) === token)
130
+ await rm(lock, { force: true });
131
+ }
132
+ }
133
+ // Truncates text to at most `maxBytes` UTF-8 bytes without splitting a code point: a partial
134
+ // trailing sequence is dropped rather than rendered as U+FFFD. Callers compare lengths to
135
+ // detect truncation and append their own marker.
136
+ export function truncateUtf8(text, maxBytes) {
137
+ if (Buffer.byteLength(text) <= maxBytes)
138
+ return text;
139
+ if (maxBytes <= 0)
140
+ return "";
141
+ return new StringDecoder("utf8").write(Buffer.from(text).subarray(0, maxBytes));
142
+ }
143
+ // Parses JSON that may be malformed or may not be an object (e.g. a bare string/number) —
144
+ // returns null instead of throwing, so a caller reading an untrusted or legacy field never
145
+ // needs its own try/catch.
146
+ export function safeJsonParse(value) {
147
+ try {
148
+ const parsed = JSON.parse(value);
149
+ return parsed && typeof parsed === "object"
150
+ ? parsed
151
+ : null;
152
+ }
153
+ catch {
154
+ return null;
155
+ }
156
+ }
157
+ // Parses a `---\n...\n---` frontmatter block into a flat field map. First occurrence of a
158
+ // key wins; values are trimmed and stripped of one layer of surrounding quotes. Exported for
159
+ // the brain markdown layer (application/brain/brain-markdown.ts), which needs the raw block
160
+ // text too (for nested `metadata:` and block-list `tags:`), not just the flattened map this
161
+ // function returns.
162
+ export function parseFrontmatter(source) {
163
+ // Normalized up front: a per-line regex below anchors on `$` (end of string), which a
164
+ // trailing `\r` from CRLF-checked-out files (e.g. a Windows git checkout) defeats — `.`
165
+ // excludes line terminators, so the line never reaches `$` and silently fails to match.
166
+ const normalized = source.replace(/\r\n/g, "\n");
167
+ if (!normalized.startsWith("---"))
168
+ return {};
169
+ const end = normalized.indexOf("\n---", 3);
170
+ const block = end < 0 ? normalized.slice(3) : normalized.slice(3, end);
171
+ const fields = {};
172
+ for (const line of block.split("\n")) {
173
+ const match = /^\s{0,2}([A-Za-z_][\w-]*):\s*(.*)$/.exec(line);
174
+ if (!match)
175
+ continue;
176
+ if (fields[match[1]] === undefined)
177
+ fields[match[1]] = match[2].trim().replace(/^["']|["']$/g, "");
178
+ }
179
+ return fields;
180
+ }
181
+ // Frontmatter of a record fits in its first 4 KiB; reads stop there.
182
+ export const FRONTMATTER_READ_BYTES = 4_096;
183
+ export async function readFrontmatterFile(file, readBytes) {
184
+ try {
185
+ const info = await stat(file);
186
+ if (!info.isFile())
187
+ return null;
188
+ const handle = await readFile(file, "utf8");
189
+ return {
190
+ fields: parseFrontmatter(handle.slice(0, readBytes)),
191
+ mtimeMs: info.mtimeMs,
192
+ size: info.size,
193
+ };
194
+ }
195
+ catch {
196
+ return null;
197
+ }
198
+ }
199
+ // Registry files moved out of control-plane/; each one is carried over the first time anything
200
+ // touches it, so no command can create an empty registry that strands the old one.
201
+ export function registryFile(name) {
202
+ const current = oceanPath(REGISTRY_DIR, name);
203
+ if (existsSync(current))
204
+ return current;
205
+ const legacy = oceanPath(LEGACY_REGISTRY_DIR, name);
206
+ if (existsSync(legacy)) {
207
+ mkdirSync(path.dirname(current), { recursive: true });
208
+ renameSync(legacy, current);
209
+ }
210
+ return current;
211
+ }
212
+ //# sourceMappingURL=fs-utils.js.map
@@ -0,0 +1,16 @@
1
+ // The calendar date on the machine's own clock, as YYYY-MM-DD. `toISOString()` gives the UTC
2
+ // date instead, which filed anything written 00:00–03:00 in Baghdad under the day before.
3
+ const pad = (value) => String(value).padStart(2, "0");
4
+ export function localDate(now = new Date()) {
5
+ return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
6
+ }
7
+ // HH:MM on the same clock, for stamps that sit next to a localDate.
8
+ export function localTime(now = new Date()) {
9
+ return `${pad(now.getHours())}:${pad(now.getMinutes())}`;
10
+ }
11
+ // A stored ISO timestamp read back on the local clock; now when it is empty or invalid.
12
+ export function localMoment(iso) {
13
+ const parsed = new Date(iso ?? "");
14
+ return Number.isNaN(parsed.getTime()) ? new Date() : parsed;
15
+ }
16
+ //# sourceMappingURL=local-date.js.map