@cmetech/otto 1.1.1 → 1.2.4

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 (423) hide show
  1. package/dist/coworker/persona-commands.d.ts +1 -0
  2. package/dist/coworker/persona-commands.js +5 -0
  3. package/dist/coworker/persona-commands.test.d.ts +1 -0
  4. package/dist/coworker/persona-commands.test.js +45 -0
  5. package/dist/resources/.managed-resources-content-hash +1 -1
  6. package/dist/resources/extensions/_coworker-paths.js +8 -0
  7. package/dist/resources/extensions/coworker-artifacts/artifacts-command.js +31 -0
  8. package/dist/resources/extensions/coworker-artifacts/artifacts-singleton.js +17 -0
  9. package/dist/resources/extensions/coworker-artifacts/extension-manifest.json +13 -0
  10. package/dist/resources/extensions/coworker-artifacts/index.js +125 -0
  11. package/dist/resources/extensions/coworker-artifacts/list-tool.js +27 -0
  12. package/dist/resources/extensions/coworker-artifacts/open-tool.js +25 -0
  13. package/dist/resources/extensions/coworker-memory/extension-manifest.json +13 -0
  14. package/dist/resources/extensions/coworker-memory/index.js +219 -0
  15. package/dist/resources/extensions/coworker-memory/memorize-tool.js +10 -0
  16. package/dist/resources/extensions/coworker-memory/memory-command.js +157 -0
  17. package/dist/resources/extensions/coworker-memory/memory-singleton.js +55 -0
  18. package/dist/resources/extensions/coworker-memory/recall-tool.js +18 -0
  19. package/dist/resources/extensions/coworker-memory/session-hooks.js +45 -0
  20. package/dist/resources/extensions/coworker-scratchpad/attach-banners.js +53 -0
  21. package/dist/resources/extensions/coworker-scratchpad/extension-manifest.json +13 -0
  22. package/dist/resources/extensions/coworker-scratchpad/format-age.js +9 -0
  23. package/dist/resources/extensions/coworker-scratchpad/helpers.js +38 -0
  24. package/dist/resources/extensions/coworker-scratchpad/index.js +199 -0
  25. package/dist/resources/extensions/coworker-scratchpad/mime-bundle.js +20 -0
  26. package/dist/resources/extensions/coworker-scratchpad/scratchpad-tool.js +118 -0
  27. package/dist/resources/extensions/coworker-scratchpad/session-sidecar.js +60 -0
  28. package/dist/resources/extensions/coworker-scratchpad/sp-command.js +597 -0
  29. package/dist/resources/extensions/coworker-scratchpad/workspace-pointer.js +41 -0
  30. package/dist/resources/extensions/coworker-scratchpad/workspace-root.js +17 -0
  31. package/dist/resources/extensions/coworker-vault/audit-command.js +35 -0
  32. package/dist/resources/extensions/coworker-vault/connect-command.js +42 -0
  33. package/dist/resources/extensions/coworker-vault/datasource-command.js +50 -0
  34. package/dist/resources/extensions/coworker-vault/extension-manifest.json +12 -0
  35. package/dist/resources/extensions/coworker-vault/index.js +171 -0
  36. package/dist/resources/extensions/coworker-vault/test-helpers.js +86 -0
  37. package/dist/resources/extensions/coworker-vault/vault-singleton.js +24 -0
  38. package/dist/resources/extensions/otto/commands/release-notes/_data.js +71 -0
  39. package/dist/resources/extensions/otto/commands/release-notes/command.js +15 -4
  40. package/dist/resources/extensions/subagent/index.js +8 -1
  41. package/dist/resources/extensions/subagent/launch.js +37 -5
  42. package/dist/resources/extensions/subagent/run-store.js +1 -0
  43. package/dist/resources/extensions/workflow/bootstrap/register-extension.js +2 -0
  44. package/dist/resources/extensions/workflow/bootstrap/register-hooks.js +10 -0
  45. package/dist/resources/extensions/workflow/persona-status.js +87 -0
  46. package/package.json +25 -10
  47. package/packages/contracts/package.json +1 -1
  48. package/packages/coworker-artifacts/dist/artifact-store.d.ts +25 -0
  49. package/packages/coworker-artifacts/dist/artifact-store.js +187 -0
  50. package/packages/coworker-artifacts/dist/dir-snapshot.d.ts +7 -0
  51. package/packages/coworker-artifacts/dist/dir-snapshot.js +54 -0
  52. package/packages/coworker-artifacts/dist/errors.d.ts +18 -0
  53. package/packages/coworker-artifacts/dist/errors.js +37 -0
  54. package/packages/coworker-artifacts/dist/index.d.ts +7 -0
  55. package/packages/coworker-artifacts/dist/index.js +7 -0
  56. package/packages/coworker-artifacts/dist/readme-renderer.d.ts +5 -0
  57. package/packages/coworker-artifacts/dist/readme-renderer.js +47 -0
  58. package/packages/coworker-artifacts/dist/resolve-uri.d.ts +3 -0
  59. package/packages/coworker-artifacts/dist/resolve-uri.js +29 -0
  60. package/packages/coworker-artifacts/dist/slug.d.ts +4 -0
  61. package/packages/coworker-artifacts/dist/slug.js +32 -0
  62. package/packages/coworker-artifacts/dist/types.d.ts +52 -0
  63. package/packages/coworker-artifacts/dist/types.js +1 -0
  64. package/packages/coworker-artifacts/package.json +20 -0
  65. package/packages/coworker-artifacts/src/artifact-store.test.ts +188 -0
  66. package/packages/coworker-artifacts/src/artifact-store.ts +206 -0
  67. package/packages/coworker-artifacts/src/artifacts-integration.test.ts +109 -0
  68. package/packages/coworker-artifacts/src/dir-snapshot.test.ts +71 -0
  69. package/packages/coworker-artifacts/src/dir-snapshot.ts +52 -0
  70. package/packages/coworker-artifacts/src/errors.test.ts +37 -0
  71. package/packages/coworker-artifacts/src/errors.ts +28 -0
  72. package/packages/coworker-artifacts/src/index.test.ts +22 -0
  73. package/packages/coworker-artifacts/src/index.ts +7 -0
  74. package/packages/coworker-artifacts/src/readme-renderer.test.ts +72 -0
  75. package/packages/coworker-artifacts/src/readme-renderer.ts +56 -0
  76. package/packages/coworker-artifacts/src/resolve-uri.test.ts +46 -0
  77. package/packages/coworker-artifacts/src/resolve-uri.ts +29 -0
  78. package/packages/coworker-artifacts/src/slug.test.ts +47 -0
  79. package/packages/coworker-artifacts/src/slug.ts +31 -0
  80. package/packages/coworker-artifacts/src/types.ts +61 -0
  81. package/packages/coworker-artifacts/tsconfig.json +15 -0
  82. package/packages/coworker-artifacts/tsconfig.publish.json +4 -0
  83. package/packages/coworker-memory/dist/context-injection.d.ts +9 -0
  84. package/packages/coworker-memory/dist/context-injection.js +41 -0
  85. package/packages/coworker-memory/dist/errors.d.ts +25 -0
  86. package/packages/coworker-memory/dist/errors.js +51 -0
  87. package/packages/coworker-memory/dist/index.d.ts +12 -0
  88. package/packages/coworker-memory/dist/index.js +12 -0
  89. package/packages/coworker-memory/dist/layer-a-store.d.ts +16 -0
  90. package/packages/coworker-memory/dist/layer-a-store.js +78 -0
  91. package/packages/coworker-memory/dist/local-sqlite-backend.d.ts +28 -0
  92. package/packages/coworker-memory/dist/local-sqlite-backend.js +167 -0
  93. package/packages/coworker-memory/dist/memory-backend.d.ts +14 -0
  94. package/packages/coworker-memory/dist/memory-backend.js +1 -0
  95. package/packages/coworker-memory/dist/memory-recorder.d.ts +50 -0
  96. package/packages/coworker-memory/dist/memory-recorder.js +69 -0
  97. package/packages/coworker-memory/dist/migrations/001-init.sql +38 -0
  98. package/packages/coworker-memory/dist/migrations/002-artifact-kind.sql +50 -0
  99. package/packages/coworker-memory/dist/paste-detector.d.ts +5 -0
  100. package/packages/coworker-memory/dist/paste-detector.js +14 -0
  101. package/packages/coworker-memory/dist/persona-seed.d.ts +10 -0
  102. package/packages/coworker-memory/dist/persona-seed.js +38 -0
  103. package/packages/coworker-memory/dist/recall-formatter.d.ts +2 -0
  104. package/packages/coworker-memory/dist/recall-formatter.js +14 -0
  105. package/packages/coworker-memory/dist/scope-resolver.d.ts +9 -0
  106. package/packages/coworker-memory/dist/scope-resolver.js +10 -0
  107. package/packages/coworker-memory/dist/types.d.ts +51 -0
  108. package/packages/coworker-memory/dist/types.js +2 -0
  109. package/packages/coworker-memory/dist/workspace-id.d.ts +3 -0
  110. package/packages/coworker-memory/dist/workspace-id.js +54 -0
  111. package/packages/coworker-memory/package.json +35 -0
  112. package/packages/coworker-memory/src/activator-integration.test.ts +141 -0
  113. package/packages/coworker-memory/src/context-injection.test.ts +72 -0
  114. package/packages/coworker-memory/src/context-injection.ts +57 -0
  115. package/packages/coworker-memory/src/errors.test.ts +45 -0
  116. package/packages/coworker-memory/src/errors.ts +42 -0
  117. package/packages/coworker-memory/src/index.test.ts +21 -0
  118. package/packages/coworker-memory/src/index.ts +12 -0
  119. package/packages/coworker-memory/src/layer-a-store.test.ts +85 -0
  120. package/packages/coworker-memory/src/layer-a-store.ts +88 -0
  121. package/packages/coworker-memory/src/local-sqlite-backend.test.ts +110 -0
  122. package/packages/coworker-memory/src/local-sqlite-backend.ts +185 -0
  123. package/packages/coworker-memory/src/memory-backend.ts +10 -0
  124. package/packages/coworker-memory/src/memory-integration.test.ts +89 -0
  125. package/packages/coworker-memory/src/memory-recorder.test.ts +101 -0
  126. package/packages/coworker-memory/src/memory-recorder.ts +95 -0
  127. package/packages/coworker-memory/src/migrations/001-init.sql +38 -0
  128. package/packages/coworker-memory/src/migrations/002-artifact-kind.sql +50 -0
  129. package/packages/coworker-memory/src/paste-detector.test.ts +23 -0
  130. package/packages/coworker-memory/src/paste-detector.ts +18 -0
  131. package/packages/coworker-memory/src/persona-seed.test.ts +57 -0
  132. package/packages/coworker-memory/src/persona-seed.ts +46 -0
  133. package/packages/coworker-memory/src/recall-formatter.test.ts +34 -0
  134. package/packages/coworker-memory/src/recall-formatter.ts +15 -0
  135. package/packages/coworker-memory/src/scope-resolver.test.ts +23 -0
  136. package/packages/coworker-memory/src/scope-resolver.ts +18 -0
  137. package/packages/coworker-memory/src/types.ts +61 -0
  138. package/packages/coworker-memory/src/workspace-id.test.ts +48 -0
  139. package/packages/coworker-memory/src/workspace-id.ts +56 -0
  140. package/packages/coworker-memory/tsconfig.json +15 -0
  141. package/packages/coworker-memory/tsconfig.publish.json +4 -0
  142. package/packages/coworker-persona/dist/commands.d.ts +7 -0
  143. package/packages/coworker-persona/dist/commands.js +35 -0
  144. package/packages/coworker-persona/dist/defaults/manifest.yaml +12 -0
  145. package/packages/coworker-persona/dist/defaults/steering/identity.md +3 -0
  146. package/packages/coworker-persona/dist/index.d.ts +3 -0
  147. package/packages/coworker-persona/dist/index.js +3 -0
  148. package/packages/coworker-persona/dist/manifest.d.ts +24 -0
  149. package/packages/coworker-persona/dist/manifest.js +21 -0
  150. package/packages/coworker-persona/dist/registry.d.ts +22 -0
  151. package/packages/coworker-persona/dist/registry.js +142 -0
  152. package/packages/coworker-persona/package.json +28 -0
  153. package/packages/coworker-persona/scripts/copy-defaults.cjs +17 -0
  154. package/packages/coworker-persona/src/commands.ts +47 -0
  155. package/packages/coworker-persona/src/defaults/manifest.yaml +12 -0
  156. package/packages/coworker-persona/src/defaults/steering/identity.md +3 -0
  157. package/packages/coworker-persona/src/index.ts +3 -0
  158. package/packages/coworker-persona/src/manifest.test.ts +67 -0
  159. package/packages/coworker-persona/src/manifest.ts +49 -0
  160. package/packages/coworker-persona/src/registry.test.ts +89 -0
  161. package/packages/coworker-persona/src/registry.ts +147 -0
  162. package/packages/coworker-persona/tsconfig.json +15 -0
  163. package/packages/coworker-persona/tsconfig.publish.json +4 -0
  164. package/packages/coworker-scratchpad/dist/cell-archive.d.ts +39 -0
  165. package/packages/coworker-scratchpad/dist/cell-archive.js +77 -0
  166. package/packages/coworker-scratchpad/dist/cell-tree.d.ts +14 -0
  167. package/packages/coworker-scratchpad/dist/cell-tree.js +72 -0
  168. package/packages/coworker-scratchpad/dist/child-process-runtime.d.ts +129 -0
  169. package/packages/coworker-scratchpad/dist/child-process-runtime.js +427 -0
  170. package/packages/coworker-scratchpad/dist/collector-registry.d.ts +12 -0
  171. package/packages/coworker-scratchpad/dist/collector-registry.js +29 -0
  172. package/packages/coworker-scratchpad/dist/detect-kind.d.ts +3 -0
  173. package/packages/coworker-scratchpad/dist/detect-kind.js +19 -0
  174. package/packages/coworker-scratchpad/dist/file-collector.d.ts +15 -0
  175. package/packages/coworker-scratchpad/dist/file-collector.js +99 -0
  176. package/packages/coworker-scratchpad/dist/index.d.ts +13 -0
  177. package/packages/coworker-scratchpad/dist/index.js +13 -0
  178. package/packages/coworker-scratchpad/dist/kernel-bindings.d.ts +49 -0
  179. package/packages/coworker-scratchpad/dist/kernel-bindings.js +220 -0
  180. package/packages/coworker-scratchpad/dist/kernel-entry.d.ts +1 -0
  181. package/packages/coworker-scratchpad/dist/kernel-entry.js +355 -0
  182. package/packages/coworker-scratchpad/dist/kernel-protocol.d.ts +171 -0
  183. package/packages/coworker-scratchpad/dist/kernel-protocol.js +48 -0
  184. package/packages/coworker-scratchpad/dist/kernel-spawn.d.ts +3 -0
  185. package/packages/coworker-scratchpad/dist/kernel-spawn.js +54 -0
  186. package/packages/coworker-scratchpad/dist/namespace-codec.d.ts +22 -0
  187. package/packages/coworker-scratchpad/dist/namespace-codec.js +61 -0
  188. package/packages/coworker-scratchpad/dist/scratchpad-lock.d.ts +24 -0
  189. package/packages/coworker-scratchpad/dist/scratchpad-lock.js +86 -0
  190. package/packages/coworker-scratchpad/dist/scratchpad-manager.d.ts +193 -0
  191. package/packages/coworker-scratchpad/dist/scratchpad-manager.js +866 -0
  192. package/packages/coworker-scratchpad/dist/staleness-banner.d.ts +12 -0
  193. package/packages/coworker-scratchpad/dist/staleness-banner.js +27 -0
  194. package/packages/coworker-scratchpad/package.json +31 -0
  195. package/packages/coworker-scratchpad/src/cell-archive.test.ts +150 -0
  196. package/packages/coworker-scratchpad/src/cell-archive.ts +97 -0
  197. package/packages/coworker-scratchpad/src/cell-tree.test.ts +105 -0
  198. package/packages/coworker-scratchpad/src/cell-tree.ts +90 -0
  199. package/packages/coworker-scratchpad/src/child-process-runtime.test.ts +413 -0
  200. package/packages/coworker-scratchpad/src/child-process-runtime.ts +493 -0
  201. package/packages/coworker-scratchpad/src/collector-registry.test.ts +69 -0
  202. package/packages/coworker-scratchpad/src/collector-registry.ts +33 -0
  203. package/packages/coworker-scratchpad/src/detect-kind.test.ts +33 -0
  204. package/packages/coworker-scratchpad/src/detect-kind.ts +22 -0
  205. package/packages/coworker-scratchpad/src/file-collector.test.ts +109 -0
  206. package/packages/coworker-scratchpad/src/file-collector.ts +114 -0
  207. package/packages/coworker-scratchpad/src/index.ts +74 -0
  208. package/packages/coworker-scratchpad/src/kernel-bindings.test.ts +188 -0
  209. package/packages/coworker-scratchpad/src/kernel-bindings.ts +279 -0
  210. package/packages/coworker-scratchpad/src/kernel-entry.test.ts +123 -0
  211. package/packages/coworker-scratchpad/src/kernel-entry.ts +390 -0
  212. package/packages/coworker-scratchpad/src/kernel-protocol.test.ts +105 -0
  213. package/packages/coworker-scratchpad/src/kernel-protocol.ts +230 -0
  214. package/packages/coworker-scratchpad/src/kernel-spawn.test.ts +60 -0
  215. package/packages/coworker-scratchpad/src/kernel-spawn.ts +54 -0
  216. package/packages/coworker-scratchpad/src/namespace-codec.test.ts +102 -0
  217. package/packages/coworker-scratchpad/src/namespace-codec.ts +90 -0
  218. package/packages/coworker-scratchpad/src/scratchpad-lock.test.ts +98 -0
  219. package/packages/coworker-scratchpad/src/scratchpad-lock.ts +102 -0
  220. package/packages/coworker-scratchpad/src/scratchpad-manager.test.ts +1343 -0
  221. package/packages/coworker-scratchpad/src/scratchpad-manager.ts +891 -0
  222. package/packages/coworker-scratchpad/src/staleness-banner.test.ts +53 -0
  223. package/packages/coworker-scratchpad/src/staleness-banner.ts +33 -0
  224. package/packages/coworker-scratchpad/src/vault-integration.test.ts +221 -0
  225. package/packages/coworker-scratchpad/tsconfig.json +15 -0
  226. package/packages/coworker-scratchpad/tsconfig.publish.json +4 -0
  227. package/packages/coworker-types/dist/artifacts.d.ts +31 -0
  228. package/packages/coworker-types/dist/artifacts.js +2 -0
  229. package/packages/coworker-types/dist/contracts.d.ts +32 -0
  230. package/packages/coworker-types/dist/contracts.js +1 -0
  231. package/packages/coworker-types/dist/index.d.ts +5 -0
  232. package/packages/coworker-types/dist/index.js +5 -0
  233. package/packages/coworker-types/dist/memory.d.ts +61 -0
  234. package/packages/coworker-types/dist/memory.js +3 -0
  235. package/packages/coworker-types/dist/scratchpad.d.ts +43 -0
  236. package/packages/coworker-types/dist/scratchpad.js +2 -0
  237. package/packages/coworker-types/dist/vault.d.ts +34 -0
  238. package/packages/coworker-types/dist/vault.js +2 -0
  239. package/packages/coworker-types/package.json +24 -0
  240. package/packages/coworker-types/src/artifacts.test.ts +52 -0
  241. package/packages/coworker-types/src/artifacts.ts +35 -0
  242. package/packages/coworker-types/src/contracts.test.ts +43 -0
  243. package/packages/coworker-types/src/contracts.ts +36 -0
  244. package/packages/coworker-types/src/index.ts +5 -0
  245. package/packages/coworker-types/src/memory.test.ts +50 -0
  246. package/packages/coworker-types/src/memory.ts +79 -0
  247. package/packages/coworker-types/src/scratchpad.test.ts +46 -0
  248. package/packages/coworker-types/src/scratchpad.ts +51 -0
  249. package/packages/coworker-types/src/smoke.test.ts +34 -0
  250. package/packages/coworker-types/src/vault.test.ts +49 -0
  251. package/packages/coworker-types/src/vault.ts +40 -0
  252. package/packages/coworker-types/tsconfig.json +15 -0
  253. package/packages/coworker-types/tsconfig.publish.json +4 -0
  254. package/packages/coworker-utils/dist/audit-log.d.ts +34 -0
  255. package/packages/coworker-utils/dist/audit-log.js +88 -0
  256. package/packages/coworker-utils/dist/index.d.ts +6 -0
  257. package/packages/coworker-utils/dist/index.js +6 -0
  258. package/packages/coworker-utils/dist/lease.d.ts +7 -0
  259. package/packages/coworker-utils/dist/lease.js +67 -0
  260. package/packages/coworker-utils/dist/logger.d.ts +13 -0
  261. package/packages/coworker-utils/dist/logger.js +26 -0
  262. package/packages/coworker-utils/dist/migration-runner.d.ts +7 -0
  263. package/packages/coworker-utils/dist/migration-runner.js +36 -0
  264. package/packages/coworker-utils/dist/ndjson-channel.d.ts +3 -0
  265. package/packages/coworker-utils/dist/ndjson-channel.js +38 -0
  266. package/packages/coworker-utils/dist/secret-scanner.d.ts +10 -0
  267. package/packages/coworker-utils/dist/secret-scanner.js +42 -0
  268. package/packages/coworker-utils/package.json +24 -0
  269. package/packages/coworker-utils/src/audit-log.test.ts +140 -0
  270. package/packages/coworker-utils/src/audit-log.ts +107 -0
  271. package/packages/coworker-utils/src/index.ts +6 -0
  272. package/packages/coworker-utils/src/lease.test.ts +64 -0
  273. package/packages/coworker-utils/src/lease.ts +76 -0
  274. package/packages/coworker-utils/src/logger.test.ts +50 -0
  275. package/packages/coworker-utils/src/logger.ts +45 -0
  276. package/packages/coworker-utils/src/migration-runner.test.ts +65 -0
  277. package/packages/coworker-utils/src/migration-runner.ts +50 -0
  278. package/packages/coworker-utils/src/ndjson-channel.test.ts +76 -0
  279. package/packages/coworker-utils/src/ndjson-channel.ts +41 -0
  280. package/packages/coworker-utils/src/secret-scanner.test.ts +61 -0
  281. package/packages/coworker-utils/src/secret-scanner.ts +56 -0
  282. package/packages/coworker-utils/tsconfig.json +15 -0
  283. package/packages/coworker-utils/tsconfig.publish.json +4 -0
  284. package/packages/coworker-vault/dist/data-vault.d.ts +41 -0
  285. package/packages/coworker-vault/dist/data-vault.js +223 -0
  286. package/packages/coworker-vault/dist/engine-registry.d.ts +34 -0
  287. package/packages/coworker-vault/dist/engine-registry.js +90 -0
  288. package/packages/coworker-vault/dist/engines/jira.yaml +17 -0
  289. package/packages/coworker-vault/dist/errors.d.ts +28 -0
  290. package/packages/coworker-vault/dist/errors.js +57 -0
  291. package/packages/coworker-vault/dist/index.d.ts +6 -0
  292. package/packages/coworker-vault/dist/index.js +6 -0
  293. package/packages/coworker-vault/dist/injector.d.ts +19 -0
  294. package/packages/coworker-vault/dist/injector.js +77 -0
  295. package/packages/coworker-vault/dist/types.d.ts +28 -0
  296. package/packages/coworker-vault/dist/types.js +1 -0
  297. package/packages/coworker-vault/dist/vault-keep.d.ts +4 -0
  298. package/packages/coworker-vault/dist/vault-keep.js +21 -0
  299. package/packages/coworker-vault/package.json +29 -0
  300. package/packages/coworker-vault/src/data-vault.test.ts +199 -0
  301. package/packages/coworker-vault/src/data-vault.ts +257 -0
  302. package/packages/coworker-vault/src/engine-registry.test.ts +120 -0
  303. package/packages/coworker-vault/src/engine-registry.ts +107 -0
  304. package/packages/coworker-vault/src/engines/jira.yaml +17 -0
  305. package/packages/coworker-vault/src/errors.test.ts +58 -0
  306. package/packages/coworker-vault/src/errors.ts +50 -0
  307. package/packages/coworker-vault/src/index.test.ts +24 -0
  308. package/packages/coworker-vault/src/index.ts +6 -0
  309. package/packages/coworker-vault/src/injector.test.ts +109 -0
  310. package/packages/coworker-vault/src/injector.ts +98 -0
  311. package/packages/coworker-vault/src/types.ts +33 -0
  312. package/packages/coworker-vault/src/vault-keep.test.ts +49 -0
  313. package/packages/coworker-vault/src/vault-keep.ts +31 -0
  314. package/packages/coworker-vault/tsconfig.json +15 -0
  315. package/packages/coworker-vault/tsconfig.publish.json +4 -0
  316. package/packages/daemon/package.json +3 -3
  317. package/packages/mcp-server/package.json +3 -3
  318. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  319. package/packages/native/package.json +1 -1
  320. package/packages/native/tsconfig.tsbuildinfo +1 -1
  321. package/packages/pi-agent-core/package.json +1 -1
  322. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  323. package/packages/pi-ai/package.json +1 -1
  324. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  325. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +6 -1
  326. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  327. package/packages/pi-coding-agent/dist/core/extensions/runner.js +22 -3
  328. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  329. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +11 -0
  330. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  331. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.d.ts +47 -0
  332. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.d.ts.map +1 -0
  333. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.js +107 -0
  334. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.js.map +1 -0
  335. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.regression.test.d.ts +19 -0
  336. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.regression.test.d.ts.map +1 -0
  337. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.regression.test.js +121 -0
  338. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.regression.test.js.map +1 -0
  339. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  340. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +17 -1
  341. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  342. package/packages/pi-coding-agent/package.json +2 -2
  343. package/packages/pi-coding-agent/src/core/extensions/runner.ts +22 -3
  344. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +11 -0
  345. package/packages/pi-coding-agent/src/modes/rpc/raw-stdout.regression.test.ts +129 -0
  346. package/packages/pi-coding-agent/src/modes/rpc/raw-stdout.ts +117 -0
  347. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +18 -1
  348. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  349. package/packages/pi-tui/package.json +1 -1
  350. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  351. package/packages/rpc-client/package.json +2 -2
  352. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  353. package/pkg/package.json +1 -1
  354. package/scripts/install.js +6 -5
  355. package/src/resources/extensions/_coworker-paths.test.ts +40 -0
  356. package/src/resources/extensions/_coworker-paths.ts +10 -0
  357. package/src/resources/extensions/coworker-artifacts/artifacts-command.test.ts +54 -0
  358. package/src/resources/extensions/coworker-artifacts/artifacts-command.ts +43 -0
  359. package/src/resources/extensions/coworker-artifacts/artifacts-singleton.test.ts +25 -0
  360. package/src/resources/extensions/coworker-artifacts/artifacts-singleton.ts +29 -0
  361. package/src/resources/extensions/coworker-artifacts/extension-manifest.json +13 -0
  362. package/src/resources/extensions/coworker-artifacts/index.test.ts +46 -0
  363. package/src/resources/extensions/coworker-artifacts/index.ts +154 -0
  364. package/src/resources/extensions/coworker-artifacts/list-tool.test.ts +29 -0
  365. package/src/resources/extensions/coworker-artifacts/list-tool.ts +53 -0
  366. package/src/resources/extensions/coworker-artifacts/open-tool.test.ts +30 -0
  367. package/src/resources/extensions/coworker-artifacts/open-tool.ts +43 -0
  368. package/src/resources/extensions/coworker-memory/extension-manifest.json +13 -0
  369. package/src/resources/extensions/coworker-memory/index.test.ts +137 -0
  370. package/src/resources/extensions/coworker-memory/index.ts +257 -0
  371. package/src/resources/extensions/coworker-memory/memorize-tool.test.ts +41 -0
  372. package/src/resources/extensions/coworker-memory/memorize-tool.ts +20 -0
  373. package/src/resources/extensions/coworker-memory/memory-command.test.ts +134 -0
  374. package/src/resources/extensions/coworker-memory/memory-command.ts +131 -0
  375. package/src/resources/extensions/coworker-memory/memory-singleton.test.ts +41 -0
  376. package/src/resources/extensions/coworker-memory/memory-singleton.ts +89 -0
  377. package/src/resources/extensions/coworker-memory/recall-tool.test.ts +50 -0
  378. package/src/resources/extensions/coworker-memory/recall-tool.ts +35 -0
  379. package/src/resources/extensions/coworker-memory/session-hooks.test.ts +77 -0
  380. package/src/resources/extensions/coworker-memory/session-hooks.ts +61 -0
  381. package/src/resources/extensions/coworker-scratchpad/attach-banners.test.ts +124 -0
  382. package/src/resources/extensions/coworker-scratchpad/attach-banners.ts +67 -0
  383. package/src/resources/extensions/coworker-scratchpad/extension-manifest.json +13 -0
  384. package/src/resources/extensions/coworker-scratchpad/format-age.test.ts +30 -0
  385. package/src/resources/extensions/coworker-scratchpad/format-age.ts +6 -0
  386. package/src/resources/extensions/coworker-scratchpad/helpers.test.ts +93 -0
  387. package/src/resources/extensions/coworker-scratchpad/helpers.ts +42 -0
  388. package/src/resources/extensions/coworker-scratchpad/index.test.ts +514 -0
  389. package/src/resources/extensions/coworker-scratchpad/index.ts +207 -0
  390. package/src/resources/extensions/coworker-scratchpad/mime-bundle.test.ts +61 -0
  391. package/src/resources/extensions/coworker-scratchpad/mime-bundle.ts +23 -0
  392. package/src/resources/extensions/coworker-scratchpad/scratchpad-tool.test.ts +137 -0
  393. package/src/resources/extensions/coworker-scratchpad/scratchpad-tool.ts +165 -0
  394. package/src/resources/extensions/coworker-scratchpad/session-sidecar.test.ts +133 -0
  395. package/src/resources/extensions/coworker-scratchpad/session-sidecar.ts +68 -0
  396. package/src/resources/extensions/coworker-scratchpad/sp-command.test.ts +836 -0
  397. package/src/resources/extensions/coworker-scratchpad/sp-command.ts +602 -0
  398. package/src/resources/extensions/coworker-scratchpad/workspace-pointer.test.ts +74 -0
  399. package/src/resources/extensions/coworker-scratchpad/workspace-pointer.ts +55 -0
  400. package/src/resources/extensions/coworker-scratchpad/workspace-root.test.ts +51 -0
  401. package/src/resources/extensions/coworker-scratchpad/workspace-root.ts +16 -0
  402. package/src/resources/extensions/coworker-vault/audit-command.test.ts +109 -0
  403. package/src/resources/extensions/coworker-vault/audit-command.ts +56 -0
  404. package/src/resources/extensions/coworker-vault/connect-command.test.ts +103 -0
  405. package/src/resources/extensions/coworker-vault/connect-command.ts +69 -0
  406. package/src/resources/extensions/coworker-vault/datasource-command.test.ts +80 -0
  407. package/src/resources/extensions/coworker-vault/datasource-command.ts +81 -0
  408. package/src/resources/extensions/coworker-vault/extension-manifest.json +12 -0
  409. package/src/resources/extensions/coworker-vault/index.test.ts +82 -0
  410. package/src/resources/extensions/coworker-vault/index.ts +181 -0
  411. package/src/resources/extensions/coworker-vault/test-helpers.ts +120 -0
  412. package/src/resources/extensions/coworker-vault/vault-singleton.test.ts +27 -0
  413. package/src/resources/extensions/coworker-vault/vault-singleton.ts +40 -0
  414. package/src/resources/extensions/otto/commands/release-notes/_data.ts +85 -0
  415. package/src/resources/extensions/otto/commands/release-notes/command.ts +16 -3
  416. package/src/resources/extensions/subagent/index.ts +9 -0
  417. package/src/resources/extensions/subagent/launch.test.ts +97 -0
  418. package/src/resources/extensions/subagent/launch.ts +42 -5
  419. package/src/resources/extensions/subagent/run-store.ts +3 -1
  420. package/src/resources/extensions/workflow/bootstrap/register-extension.ts +2 -0
  421. package/src/resources/extensions/workflow/bootstrap/register-hooks.ts +10 -0
  422. package/src/resources/extensions/workflow/persona-status.ts +109 -0
  423. package/src/resources/extensions/workflow/tests/auto-recovery.test.ts +34 -0
@@ -0,0 +1,427 @@
1
+ import { spawn } from 'node:child_process';
2
+ import process from 'node:process';
3
+ import { writeNdjson, readNdjson } from '@otto/coworker-utils';
4
+ import { filterEnv, kernelExecArgv, resolveKernelEntry } from './kernel-spawn.js';
5
+ import { isDataLoadEvent, isProgressEvent, isStartupErrorEvent, isSnapshotResult, isArtifactCreateEvent, isArtifactCreateRequest, isArtifactUpdateRequest, } from './kernel-protocol.js';
6
+ const DEFAULT_CELL_TIMEOUT_MS = 120_000;
7
+ const DEFAULT_INACTIVITY_MS = 30_000;
8
+ const DEFAULT_INACTIVITY_AFTER_PROGRESS_MS = 60_000;
9
+ const DEFAULT_CANCEL_GRACE_MS = 2_000;
10
+ const MAX_RESTARTS_BEFORE_SUCCESS = 1;
11
+ export class ChildProcessRuntime {
12
+ options;
13
+ child = null;
14
+ pending = new Map();
15
+ pendingSnapshots = new Map();
16
+ activeId = null;
17
+ nextId = 1;
18
+ alive = false;
19
+ childReady = false;
20
+ disposed = false;
21
+ restartsSinceSuccess = 0;
22
+ recoveryNotes_ = [];
23
+ resolveReady = () => { };
24
+ rejectReady = () => { };
25
+ ready = Promise.resolve();
26
+ /**
27
+ * Phase 2 Task 13: timestamp of the most recent successful spawn(). Used by
28
+ * higher-level staleness checks (Task 15) to decide whether a warm kernel's
29
+ * env-injected credentials need to be refreshed. Pre-start() value is epoch
30
+ * so callers can distinguish "never spawned" without nullable juggling.
31
+ */
32
+ spawnTime = new Date(0);
33
+ constructor(options) {
34
+ this.options = options;
35
+ }
36
+ async start() {
37
+ if (this.disposed)
38
+ throw new Error('runtime disposed');
39
+ await this.spawnChild();
40
+ }
41
+ /**
42
+ * Phase 2 Task 13: env construction split out so the injector hop has a clean
43
+ * seam to extend. Existing semantics unchanged: filterEnv applies the kernel's
44
+ * allowlist/denylist, then (when configured) the injector overlays OTTO_DS_*
45
+ * vars from vault entries. Only the spawned child sees the result; the parent
46
+ * process.env is never mutated.
47
+ */
48
+ async buildBaseEnv() {
49
+ const base = filterEnv(process.env);
50
+ const { injector, bindings } = this.options;
51
+ if (!injector || !bindings || bindings.length === 0)
52
+ return base;
53
+ return injector.injectEnv(base, bindings, {
54
+ scratchpadName: this.options.scratchpadName ?? '',
55
+ sessionId: this.options.sessionId ?? '',
56
+ pid: process.pid,
57
+ });
58
+ }
59
+ async spawnChild() {
60
+ this.ready = new Promise((resolve, reject) => {
61
+ this.resolveReady = resolve;
62
+ this.rejectReady = reject;
63
+ });
64
+ const entry = this.options.entryPath ?? resolveKernelEntry();
65
+ const args = [...kernelExecArgv(), entry, this.options.workspace];
66
+ if (this.options.scratchpadDir !== undefined)
67
+ args.push(this.options.scratchpadDir);
68
+ const env = await this.buildBaseEnv();
69
+ const child = spawn(process.execPath, args, { stdio: ['pipe', 'pipe', 'inherit'], cwd: process.cwd(), env });
70
+ this.child = child;
71
+ this.alive = true;
72
+ this.childReady = false;
73
+ // Phase 2 Task 13: stamp spawnTime immediately after a successful spawn.
74
+ // Done synchronously so the ready promise (which the caller awaits) reflects
75
+ // a non-epoch spawnTime by the time start() returns.
76
+ this.spawnTime = new Date();
77
+ child.on('exit', (code, signal) => {
78
+ if (this.child !== child)
79
+ return; // superseded by a restart
80
+ this.alive = false;
81
+ this.childReady = false;
82
+ if (this.disposed)
83
+ return;
84
+ const err = new Error(`kernel exited (code=${code ?? 'null'}, signal=${signal ?? 'null'})`);
85
+ this.rejectReady(err); // no-op if ready already resolved
86
+ this.failAllPending(err);
87
+ });
88
+ void this.readLoop(child);
89
+ return this.ready;
90
+ }
91
+ async readLoop(child) {
92
+ try {
93
+ for await (const raw of readNdjson(child.stdout)) {
94
+ if (this.child !== child)
95
+ break; // superseded by a restart
96
+ const frame = raw;
97
+ if (frame.type === 'event') {
98
+ if (frame.event === 'ready') {
99
+ if (frame.recovery_notes)
100
+ this.recoveryNotes_ = [...frame.recovery_notes];
101
+ this.childReady = true;
102
+ this.resolveReady();
103
+ }
104
+ else if (isStartupErrorEvent(frame)) {
105
+ const err = new Error(frame.error.message);
106
+ err.name = `startup_error/${frame.kind}`;
107
+ this.rejectReady(err);
108
+ }
109
+ else if (isDataLoadEvent(frame))
110
+ this.options.onDataLoad?.(frame.drawer);
111
+ else if (isArtifactCreateEvent(frame))
112
+ this.options.onArtifactCreate?.(frame.drawer);
113
+ else if (isProgressEvent(frame))
114
+ this.resetInactivity();
115
+ continue;
116
+ }
117
+ if (isSnapshotResult(frame)) {
118
+ const resolver = this.pendingSnapshots.get(frame.id);
119
+ if (resolver) {
120
+ this.pendingSnapshots.delete(frame.id);
121
+ resolver(frame);
122
+ }
123
+ continue;
124
+ }
125
+ // Phase 4 Task 10: artifact RPC requests originate from the kernel and
126
+ // are serviced by the manager via handleArtifactCreate/Update. Handle
127
+ // before the result-fallthrough — these frames carry a string `id`
128
+ // (kernel mints `art-<pid>-<seq>`) and would otherwise be miskeyed
129
+ // against the numeric `pending` map.
130
+ if (isArtifactCreateRequest(frame)) {
131
+ void this.handleArtifactCreateRpc(frame);
132
+ continue;
133
+ }
134
+ if (isArtifactUpdateRequest(frame)) {
135
+ void this.handleArtifactUpdateRpc(frame);
136
+ continue;
137
+ }
138
+ if (frame.type !== 'result')
139
+ continue; // defensive: unknown frame shape
140
+ const p = this.pending.get(frame.id);
141
+ if (!p)
142
+ continue;
143
+ clearTimeout(p.totalTimer);
144
+ clearTimeout(p.inactivityTimer);
145
+ this.pending.delete(frame.id);
146
+ if (this.activeId === frame.id)
147
+ this.activeId = null;
148
+ this.restartsSinceSuccess = 0; // a completed cell proves the kernel is healthy
149
+ if (frame.ok) {
150
+ p.resolve({ value: frame.value, stdout: frame.stdout });
151
+ }
152
+ else {
153
+ const err = new Error(frame.error.message);
154
+ err.name = frame.error.name;
155
+ if (frame.error.stack)
156
+ err.stack = frame.error.stack;
157
+ p.reject(err);
158
+ }
159
+ }
160
+ }
161
+ catch (err) {
162
+ this.failAllPending(err);
163
+ }
164
+ }
165
+ resetInactivity() {
166
+ if (this.activeId === null)
167
+ return;
168
+ const id = this.activeId;
169
+ const p = this.pending.get(id);
170
+ if (!p)
171
+ return;
172
+ p.inactivityWindowMs =
173
+ this.options.inactivityAfterProgressMs ?? DEFAULT_INACTIVITY_AFTER_PROGRESS_MS;
174
+ clearTimeout(p.inactivityTimer);
175
+ p.inactivityTimer = setTimeout(() => this.onInactivityTimeout(id), p.inactivityWindowMs);
176
+ }
177
+ onInactivityTimeout(id) {
178
+ const p = this.pending.get(id);
179
+ if (!p)
180
+ return;
181
+ clearTimeout(p.totalTimer);
182
+ this.pending.delete(id);
183
+ if (this.activeId === id)
184
+ this.activeId = null;
185
+ this.markDead();
186
+ p.reject(new Error(`cell ${id} timed out after ${p.inactivityWindowMs}ms of inactivity`));
187
+ }
188
+ onTotalTimeout(id, totalMs) {
189
+ const p = this.pending.get(id);
190
+ if (!p)
191
+ return;
192
+ clearTimeout(p.inactivityTimer);
193
+ this.pending.delete(id);
194
+ if (this.activeId === id)
195
+ this.activeId = null;
196
+ this.markDead();
197
+ p.reject(new Error(`cell ${id} timed out after ${totalMs}ms (total wall-clock)`));
198
+ }
199
+ async runCell(code) {
200
+ if (this.disposed)
201
+ throw new Error('runtime disposed');
202
+ if (!this.alive) {
203
+ if (this.restartsSinceSuccess >= MAX_RESTARTS_BEFORE_SUCCESS) {
204
+ throw new Error(`kernel repeatedly crashed (${this.restartsSinceSuccess} restart(s) without a successful cell); giving up`);
205
+ }
206
+ this.restartsSinceSuccess++;
207
+ this.spawnChild(); // start a fresh kernel; the write below waits for its ready
208
+ }
209
+ const id = this.nextId++;
210
+ const totalMs = this.options.cellTimeoutMs ?? DEFAULT_CELL_TIMEOUT_MS;
211
+ const inactivityMs = this.options.inactivityTimeoutMs ?? DEFAULT_INACTIVITY_MS;
212
+ const result = new Promise((resolve, reject) => {
213
+ const totalTimer = setTimeout(() => this.onTotalTimeout(id, totalMs), totalMs);
214
+ const inactivityTimer = setTimeout(() => this.onInactivityTimeout(id), inactivityMs);
215
+ this.pending.set(id, { resolve, reject, totalTimer, inactivityTimer, inactivityWindowMs: inactivityMs });
216
+ });
217
+ // Register the active cell synchronously so cancel()/timeouts can act on it even
218
+ // while a restarted kernel is still starting up. Send the code once it's ready.
219
+ this.activeId = id;
220
+ const ready = this.ready;
221
+ void ready
222
+ .then(() => {
223
+ const child = this.child;
224
+ if (child && this.pending.has(id))
225
+ return writeNdjson(child.stdin, { id, type: 'run', code });
226
+ })
227
+ .catch(() => {
228
+ // ready rejected (kernel died during startup); the exit handler/cancel rejects this cell.
229
+ });
230
+ return result;
231
+ }
232
+ async cancel() {
233
+ const child = this.child;
234
+ if (!child || !this.alive)
235
+ return;
236
+ const id = this.activeId;
237
+ if (!this.childReady) {
238
+ // The kernel is still starting (e.g. a fresh restart). SIGINT would race the
239
+ // child's SIG_IGN handler install and could kill it before it's installed, so
240
+ // escalate straight to a hard kill and reject the active cell as cancelled.
241
+ this.rejectActive(id, `cell ${id} cancelled`);
242
+ this.markDead();
243
+ return;
244
+ }
245
+ child.kill('SIGINT'); // child ignores SIGINT between cells; no-op for sync vm code mid-cell
246
+ if (id === null)
247
+ return; // nothing running: the gentle signal is harmless
248
+ await new Promise((r) => setTimeout(r, this.options.cancelGraceMs ?? DEFAULT_CANCEL_GRACE_MS));
249
+ const p = this.pending.get(id);
250
+ if (!p)
251
+ return; // settled within the grace window
252
+ clearTimeout(p.totalTimer);
253
+ clearTimeout(p.inactivityTimer);
254
+ this.pending.delete(id);
255
+ if (this.activeId === id)
256
+ this.activeId = null;
257
+ this.markDead(); // escalate: SIGTERM -> SIGKILL
258
+ p.reject(new Error(`cell ${id} cancelled`));
259
+ }
260
+ async snapshot() {
261
+ if (this.disposed) {
262
+ return { id: 0, type: 'snapshot_result', ok: false, error: { name: 'RuntimeDisposed', message: 'runtime disposed' } };
263
+ }
264
+ if (!this.alive || !this.child) {
265
+ return { id: 0, type: 'snapshot_result', ok: false, error: { name: 'RuntimeDead', message: 'kernel is not alive' } };
266
+ }
267
+ const id = this.nextId++;
268
+ const result = new Promise((resolve) => {
269
+ this.pendingSnapshots.set(id, resolve);
270
+ });
271
+ try {
272
+ await this.ready;
273
+ const child = this.child;
274
+ if (!child) {
275
+ this.pendingSnapshots.delete(id);
276
+ return { id, type: 'snapshot_result', ok: false, error: { name: 'RuntimeDead', message: 'kernel died before snapshot' } };
277
+ }
278
+ await writeNdjson(child.stdin, { id, type: 'snapshot' });
279
+ }
280
+ catch (err) {
281
+ this.pendingSnapshots.delete(id);
282
+ const e = err;
283
+ return { id, type: 'snapshot_result', ok: false, error: { name: e.name, message: e.message } };
284
+ }
285
+ return result;
286
+ }
287
+ /**
288
+ * Phase 4 Task 10: service an `artifact_create` RPC request from the kernel.
289
+ * Calls the manager-supplied handler (if any), serializes the result into a
290
+ * `{type:'response', request:'artifact_create'}` frame, and writes it back
291
+ * to the child's stdin. Errors are surfaced to the kernel as `ok:false`
292
+ * frames so the awaiting cell rejects cleanly rather than hanging.
293
+ */
294
+ async handleArtifactCreateRpc(req) {
295
+ const child = this.child;
296
+ if (!child)
297
+ return;
298
+ let resp;
299
+ try {
300
+ const handler = this.options.handleArtifactCreate;
301
+ if (!handler)
302
+ throw new Error('artifacts unavailable');
303
+ const result = await handler({ kind: req.kind, name: req.name });
304
+ resp = {
305
+ type: 'response',
306
+ request: 'artifact_create',
307
+ id: req.id,
308
+ ok: true,
309
+ slug: result.slug,
310
+ uri: result.uri,
311
+ primary_path: result.primary_path,
312
+ };
313
+ }
314
+ catch (err) {
315
+ const e = err;
316
+ resp = {
317
+ type: 'response',
318
+ request: 'artifact_create',
319
+ id: req.id,
320
+ ok: false,
321
+ error: e.message,
322
+ };
323
+ }
324
+ try {
325
+ await writeNdjson(child.stdin, resp);
326
+ }
327
+ catch {
328
+ // child died between request and response — exit handler fails pending cells.
329
+ }
330
+ }
331
+ /**
332
+ * Phase 4 Task 10: service an `artifact_update` RPC request. Mirror of
333
+ * handleArtifactCreateRpc for the update path.
334
+ */
335
+ async handleArtifactUpdateRpc(req) {
336
+ const child = this.child;
337
+ if (!child)
338
+ return;
339
+ let resp;
340
+ try {
341
+ const handler = this.options.handleArtifactUpdate;
342
+ if (!handler)
343
+ throw new Error('artifacts unavailable');
344
+ const result = await handler({ slug: req.slug, files: req.files });
345
+ resp = {
346
+ type: 'response',
347
+ request: 'artifact_update',
348
+ id: req.id,
349
+ ok: true,
350
+ files_touched: result.files_touched,
351
+ };
352
+ }
353
+ catch (err) {
354
+ const e = err;
355
+ resp = {
356
+ type: 'response',
357
+ request: 'artifact_update',
358
+ id: req.id,
359
+ ok: false,
360
+ error: e.message,
361
+ };
362
+ }
363
+ try {
364
+ await writeNdjson(child.stdin, resp);
365
+ }
366
+ catch {
367
+ // child died between request and response — exit handler fails pending cells.
368
+ }
369
+ }
370
+ rejectActive(id, message) {
371
+ if (id === null)
372
+ return;
373
+ const p = this.pending.get(id);
374
+ if (!p)
375
+ return;
376
+ clearTimeout(p.totalTimer);
377
+ clearTimeout(p.inactivityTimer);
378
+ this.pending.delete(id);
379
+ if (this.activeId === id)
380
+ this.activeId = null;
381
+ p.reject(new Error(message));
382
+ }
383
+ failAllPending(err) {
384
+ for (const p of this.pending.values()) {
385
+ clearTimeout(p.totalTimer);
386
+ clearTimeout(p.inactivityTimer);
387
+ p.reject(err);
388
+ }
389
+ this.pending.clear();
390
+ this.activeId = null;
391
+ for (const resolve of this.pendingSnapshots.values()) {
392
+ resolve({ id: 0, type: 'snapshot_result', ok: false, error: { name: err.name, message: err.message } });
393
+ }
394
+ this.pendingSnapshots.clear();
395
+ }
396
+ markDead() {
397
+ const child = this.child;
398
+ if (!child)
399
+ return;
400
+ this.alive = false;
401
+ this.childReady = false;
402
+ child.kill('SIGTERM');
403
+ child.kill('SIGKILL');
404
+ // child stays referenced until its 'exit' fires; identity guards in readLoop/exit
405
+ // ignore the dead child once a restart reassigns this.child.
406
+ }
407
+ get hasActiveCell() {
408
+ return this.activeId !== null;
409
+ }
410
+ get recoveryNotes() {
411
+ return this.recoveryNotes_;
412
+ }
413
+ async dispose() {
414
+ if (this.disposed)
415
+ return;
416
+ this.disposed = true;
417
+ this.alive = false;
418
+ this.childReady = false;
419
+ this.failAllPending(new Error('runtime disposed'));
420
+ const child = this.child;
421
+ this.child = null;
422
+ if (child) {
423
+ child.stdin.end();
424
+ child.kill('SIGTERM');
425
+ }
426
+ }
427
+ }
@@ -0,0 +1,12 @@
1
+ import type { Collector, CollectorRegistry, DataSourceRef } from '@otto/coworker-types';
2
+ export declare function uriMatchesPattern(uri: string, pattern: string): boolean;
3
+ export declare class DefaultCollectorRegistry implements CollectorRegistry {
4
+ private readonly collectors;
5
+ register(collector: Collector): void;
6
+ list(): Collector[];
7
+ get(id: string): Collector | null;
8
+ resolve(uri: string): Promise<{
9
+ collector: Collector;
10
+ ref: DataSourceRef;
11
+ } | null>;
12
+ }
@@ -0,0 +1,29 @@
1
+ export function uriMatchesPattern(uri, pattern) {
2
+ if (pattern.endsWith('*'))
3
+ return uri.startsWith(pattern.slice(0, -1));
4
+ return uri === pattern;
5
+ }
6
+ export class DefaultCollectorRegistry {
7
+ collectors = new Map();
8
+ register(collector) {
9
+ this.collectors.set(collector.id, collector);
10
+ }
11
+ list() {
12
+ return [...this.collectors.values()];
13
+ }
14
+ get(id) {
15
+ return this.collectors.get(id) ?? null;
16
+ }
17
+ async resolve(uri) {
18
+ for (const collector of this.collectors.values()) {
19
+ const patterns = collector.describe().supports_uris;
20
+ if (!patterns.some((p) => uriMatchesPattern(uri, p)))
21
+ continue;
22
+ for await (const ref of collector.list()) {
23
+ if (ref.uri === uri)
24
+ return { collector, ref };
25
+ }
26
+ }
27
+ return null;
28
+ }
29
+ }
@@ -0,0 +1,3 @@
1
+ import type { DataKind } from '@otto/coworker-types';
2
+ export declare const FILE_COLLECTOR_KINDS: readonly DataKind[];
3
+ export declare function detectKind(pathOrUri: string): DataKind | null;
@@ -0,0 +1,19 @@
1
+ const EXT_TO_KIND = {
2
+ '.csv': 'csv',
3
+ '.xlsx': 'xlsx',
4
+ '.json': 'json',
5
+ '.parquet': 'parquet',
6
+ '.txt': 'txt',
7
+ '.md': 'md',
8
+ };
9
+ // The six file kinds FileCollector enumerates. (DataKind also includes
10
+ // rest/mcp-resource/acp-stream, which belong to future non-file collectors.)
11
+ export const FILE_COLLECTOR_KINDS = ['csv', 'xlsx', 'json', 'parquet', 'txt', 'md'];
12
+ export function detectKind(pathOrUri) {
13
+ const clean = pathOrUri.split('?')[0].split('#')[0];
14
+ const dot = clean.lastIndexOf('.');
15
+ if (dot === -1)
16
+ return null;
17
+ const ext = clean.slice(dot).toLowerCase();
18
+ return EXT_TO_KIND[ext] ?? null;
19
+ }
@@ -0,0 +1,15 @@
1
+ import type { Collector, CollectorCapabilities, DataSource, DataSourceRef, ListOpts, Unsubscribe } from '@otto/coworker-types';
2
+ export interface FileCollectorOptions {
3
+ /** Absolute path to the workspace root. inputs/ resolves to <workspace>/.otto/inputs. */
4
+ workspace: string;
5
+ }
6
+ export declare class FileCollector implements Collector {
7
+ readonly id = "file";
8
+ readonly kind: "file";
9
+ private readonly inputsDir;
10
+ constructor(opts: FileCollectorOptions);
11
+ describe(): CollectorCapabilities;
12
+ list(opts?: ListOpts): AsyncIterable<DataSourceRef>;
13
+ open(ref: DataSourceRef): Promise<DataSource>;
14
+ watch(ref: DataSourceRef, onChange: (ref: DataSourceRef) => void): Unsubscribe;
15
+ }
@@ -0,0 +1,99 @@
1
+ import { readdir, readFile, stat } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { pathToFileURL, fileURLToPath } from 'node:url';
4
+ import { watch as chokidarWatch } from 'chokidar';
5
+ import { detectKind, FILE_COLLECTOR_KINDS } from './detect-kind.js';
6
+ const TEXT_KINDS = new Set(['csv', 'txt', 'md']);
7
+ export class FileCollector {
8
+ id = 'file';
9
+ kind = 'file';
10
+ inputsDir;
11
+ constructor(opts) {
12
+ this.inputsDir = join(opts.workspace, '.otto', 'inputs');
13
+ }
14
+ describe() {
15
+ return {
16
+ supports_uris: ['file://*'],
17
+ supports_kinds: [...FILE_COLLECTOR_KINDS],
18
+ supports_streaming: false,
19
+ supports_watching: true,
20
+ };
21
+ }
22
+ async *list(opts) {
23
+ let remaining = opts?.limit ?? Number.POSITIVE_INFINITY;
24
+ if (remaining <= 0)
25
+ return;
26
+ const prefixDir = opts?.prefix ? join(this.inputsDir, opts.prefix) : this.inputsDir;
27
+ for await (const abs of walk(this.inputsDir)) {
28
+ if (opts?.prefix && !abs.startsWith(prefixDir))
29
+ continue;
30
+ const kind = detectKind(abs);
31
+ if (!kind)
32
+ continue;
33
+ const st = await stat(abs);
34
+ yield {
35
+ collector: this.id,
36
+ uri: pathToFileURL(abs).href,
37
+ kind,
38
+ bytes: st.size,
39
+ modified: st.mtime.toISOString(),
40
+ metadata: {},
41
+ };
42
+ remaining -= 1;
43
+ if (remaining <= 0)
44
+ return;
45
+ }
46
+ }
47
+ async open(ref) {
48
+ const abs = fileURLToPath(ref.uri);
49
+ const kind = ref.kind;
50
+ return {
51
+ ref,
52
+ async load() {
53
+ if (kind === 'json') {
54
+ return JSON.parse(await readFile(abs, 'utf8'));
55
+ }
56
+ if (TEXT_KINDS.has(kind)) {
57
+ return readFile(abs, 'utf8');
58
+ }
59
+ return readFile(abs); // Buffer for xlsx/parquet
60
+ },
61
+ };
62
+ }
63
+ watch(ref, onChange) {
64
+ const abs = fileURLToPath(ref.uri);
65
+ const watcher = chokidarWatch(abs, { ignoreInitial: true });
66
+ const handler = async () => {
67
+ try {
68
+ const st = await stat(abs);
69
+ onChange({ ...ref, bytes: st.size, modified: st.mtime.toISOString() });
70
+ }
71
+ catch {
72
+ onChange(ref);
73
+ }
74
+ };
75
+ watcher.on('change', () => void handler());
76
+ watcher.on('add', () => void handler());
77
+ return () => {
78
+ void watcher.close();
79
+ };
80
+ }
81
+ }
82
+ async function* walk(dir) {
83
+ let entries;
84
+ try {
85
+ entries = await readdir(dir, { withFileTypes: true });
86
+ }
87
+ catch {
88
+ return; // inputs/ may not exist yet — yield nothing
89
+ }
90
+ for (const entry of entries) {
91
+ const full = join(dir, entry.name);
92
+ if (entry.isDirectory()) {
93
+ yield* walk(full);
94
+ }
95
+ else if (entry.isFile()) {
96
+ yield full;
97
+ }
98
+ }
99
+ }
@@ -0,0 +1,13 @@
1
+ export { detectKind, FILE_COLLECTOR_KINDS } from './detect-kind.js';
2
+ export { FileCollector, type FileCollectorOptions } from './file-collector.js';
3
+ export { DefaultCollectorRegistry, uriMatchesPattern } from './collector-registry.js';
4
+ export { isDataLoadEvent, isProgressEvent, isStartupErrorEvent, isSnapshotResult, type RunRequest, type SnapshotRequest, type KernelRequest, type ResultOk, type ResultErr, type ResultResponse, type SnapshotResultOk, type SnapshotResultErr, type SnapshotResult, type SkippedKey, type RecoveryNote, type StartupErrorEvent, type DataLoadDrawer, type ArtifactCreateDrawer, type ReadyEvent, type DataLoadEvent, type ProgressEvent, type KernelEvent, type KernelFrame, } from './kernel-protocol.js';
5
+ export { filterEnv, kernelExecArgv, resolveKernelEntry } from './kernel-spawn.js';
6
+ export { ChildProcessRuntime, type CellResult, type ChildProcessRuntimeOptions, } from './child-process-runtime.js';
7
+ export { ScratchpadManager, ForkKernelHangError, type ScratchpadManagerOptions, type AttachOptions, type ScratchpadInfo, } from './scratchpad-manager.js';
8
+ export { acquireLock, releaseLock, readLock, isStaleLock, ScratchpadBusyError, type LockInfo, type AcquireOptions, } from './scratchpad-lock.js';
9
+ export { CellArchive, CELLS_SCHEMA_VERSION, type CellEntry, type AppendInput, } from './cell-archive.js';
10
+ export { buildDataLibBindings } from './kernel-bindings.js';
11
+ export { NAMESPACE_SCHEMA_VERSION, encodeNamespace, decodeNamespace, type NamespaceEnvelope, type EncodeResult, type DecodeResult, } from './namespace-codec.js';
12
+ export { projectTree, findLeaves, validateLeafId, formatTreeText, type TreeNode, type CellTree, } from './cell-tree.js';
13
+ export { StalenessBanner, type StalenessCheck } from './staleness-banner.js';
@@ -0,0 +1,13 @@
1
+ export { detectKind, FILE_COLLECTOR_KINDS } from './detect-kind.js';
2
+ export { FileCollector } from './file-collector.js';
3
+ export { DefaultCollectorRegistry, uriMatchesPattern } from './collector-registry.js';
4
+ export { isDataLoadEvent, isProgressEvent, isStartupErrorEvent, isSnapshotResult, } from './kernel-protocol.js';
5
+ export { filterEnv, kernelExecArgv, resolveKernelEntry } from './kernel-spawn.js';
6
+ export { ChildProcessRuntime, } from './child-process-runtime.js';
7
+ export { ScratchpadManager, ForkKernelHangError, } from './scratchpad-manager.js';
8
+ export { acquireLock, releaseLock, readLock, isStaleLock, ScratchpadBusyError, } from './scratchpad-lock.js';
9
+ export { CellArchive, CELLS_SCHEMA_VERSION, } from './cell-archive.js';
10
+ export { buildDataLibBindings } from './kernel-bindings.js';
11
+ export { NAMESPACE_SCHEMA_VERSION, encodeNamespace, decodeNamespace, } from './namespace-codec.js';
12
+ export { projectTree, findLeaves, validateLeafId, formatTreeText, } from './cell-tree.js';
13
+ export { StalenessBanner } from './staleness-banner.js';