@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,49 @@
1
+ import type { DuckDBInstance } from '@duckdb/node-api';
2
+ import { type AuditLog } from '@otto/coworker-utils';
3
+ /**
4
+ * The data libraries pre-bound into every scratchpad cell's vm sandbox.
5
+ * DuckDB is bound as an in-memory-capable lib here; on-disk kernel.db wiring is 1d2.
6
+ */
7
+ export declare function buildDataLibBindings(): Record<string, unknown>;
8
+ /** SQL column type string passed straight into CREATE TABLE (e.g. VARCHAR, BIGINT). */
9
+ export type DuckDBColumnType = string;
10
+ export interface RegisterDfOptions {
11
+ /**
12
+ * Explicit per-column SQL types. When omitted, the schema is inferred from
13
+ * the first non-null value of each column in the first 10 rows.
14
+ */
15
+ schema?: Record<string, DuckDBColumnType> | Array<[string, DuckDBColumnType]>;
16
+ }
17
+ /**
18
+ * Patches a DuckDBInstance with a `registerDf(name, input, opts?)` method
19
+ * so the LLM can drop a polars DataFrame / Arrow Table / array of records
20
+ * into DuckDB in one call instead of discovering the appender API.
21
+ *
22
+ * The method opens a fresh connection on each call (cheap — DuckDB connections
23
+ * share the underlying instance/db) and CREATE-TABLE-then-appends.
24
+ */
25
+ export declare function attachRegisterDf(instance: DuckDBInstance): void;
26
+ /**
27
+ * Context passed to `redactForJournal`. The audit instance is the same one
28
+ * held by the CredentialInjector — supplied by the manager so secret-redaction
29
+ * audit records land alongside vault inject/inject-skipped records.
30
+ */
31
+ export interface RedactionContext {
32
+ audit: AuditLog;
33
+ sessionId: string;
34
+ scratchpadName: string;
35
+ pid: number;
36
+ cellId: string;
37
+ }
38
+ /**
39
+ * Scans `raw` for known secret patterns; for each hit, appends a
40
+ * `producer: 'secret-scanner', action: 'redact'` audit record (severity warn)
41
+ * with `detail = { cell_id, kind, offset, length }` — NEVER the secret value
42
+ * or `SecretHit.preview`. Returns the redacted text (`[REDACTED:<kind>]` per
43
+ * hit). If no hits, returns the input verbatim with no audit emission.
44
+ *
45
+ * Backward compatibility: callers that don't have an AuditLog should skip this
46
+ * helper entirely (pass-through). Audit is required here because the redaction
47
+ * MUST be observable.
48
+ */
49
+ export declare function redactForJournal(raw: string, ctx: RedactionContext): string;
@@ -0,0 +1,220 @@
1
+ import pl from 'nodejs-polars';
2
+ import ExcelJS from 'exceljs';
3
+ import lodash from 'lodash';
4
+ import axios from 'axios';
5
+ import { z } from 'zod';
6
+ import * as dateFns from 'date-fns';
7
+ import * as DuckDB from '@duckdb/node-api';
8
+ import { SecretScanner } from '@otto/coworker-utils';
9
+ /**
10
+ * The data libraries pre-bound into every scratchpad cell's vm sandbox.
11
+ * DuckDB is bound as an in-memory-capable lib here; on-disk kernel.db wiring is 1d2.
12
+ */
13
+ export function buildDataLibBindings() {
14
+ return {
15
+ polars: pl,
16
+ DuckDB,
17
+ ExcelJS,
18
+ dateFns,
19
+ lodash,
20
+ zod: z,
21
+ axios,
22
+ };
23
+ }
24
+ function isPolarsDataFrame(x) {
25
+ return (!!x &&
26
+ typeof x === 'object' &&
27
+ typeof x.toRecords === 'function' &&
28
+ typeof x.width === 'number' &&
29
+ typeof x.height === 'number');
30
+ }
31
+ function isArrowTable(x) {
32
+ return (!!x &&
33
+ typeof x === 'object' &&
34
+ typeof x.toArray === 'function' &&
35
+ typeof x.numRows === 'number' &&
36
+ 'schema' in x);
37
+ }
38
+ function coerceToRecords(input) {
39
+ if (isPolarsDataFrame(input))
40
+ return input.toRecords();
41
+ if (isArrowTable(input))
42
+ return input.toArray();
43
+ if (Array.isArray(input))
44
+ return input;
45
+ throw new TypeError('registerDf: input must be a polars DataFrame, Arrow Table, or array of records');
46
+ }
47
+ function inferSchema(records) {
48
+ if (records.length === 0) {
49
+ throw new Error('registerDf: cannot infer schema from empty input. Provide opts.schema or pass at least one row.');
50
+ }
51
+ const cols = Object.keys(records[0]);
52
+ const out = {};
53
+ for (const col of cols) {
54
+ // Null-walk: scan up to the first 10 rows for the first non-null value of this column.
55
+ // Defaults to VARCHAR for all-null columns (safe — DuckDB will accept NULL into a VARCHAR).
56
+ out[col] = 'VARCHAR';
57
+ const walk = Math.min(10, records.length);
58
+ for (let i = 0; i < walk; i++) {
59
+ const v = records[i][col];
60
+ if (v === null || v === undefined)
61
+ continue;
62
+ if (typeof v === 'string') {
63
+ out[col] = 'VARCHAR';
64
+ break;
65
+ }
66
+ if (typeof v === 'bigint') {
67
+ out[col] = 'BIGINT';
68
+ break;
69
+ }
70
+ if (typeof v === 'number') {
71
+ out[col] = 'DOUBLE';
72
+ break;
73
+ }
74
+ if (typeof v === 'boolean') {
75
+ out[col] = 'BOOLEAN';
76
+ break;
77
+ }
78
+ if (v instanceof Date) {
79
+ out[col] = 'TIMESTAMP';
80
+ break;
81
+ }
82
+ out[col] = 'VARCHAR'; // unknown object → store as VARCHAR
83
+ break;
84
+ }
85
+ }
86
+ return out;
87
+ }
88
+ function normalizeSchema(schema) {
89
+ if (Array.isArray(schema))
90
+ return schema;
91
+ return Object.entries(schema);
92
+ }
93
+ function quoteIdent(name) {
94
+ // DuckDB identifier quoting: wrap in double quotes, escape embedded double quotes.
95
+ return `"${name.replace(/"/g, '""')}"`;
96
+ }
97
+ async function registerViaAppender(conn, name, records, schema, sourceHint) {
98
+ const ddl = `CREATE TABLE ${quoteIdent(name)} (${schema
99
+ .map(([c, t]) => `${quoteIdent(c)} ${t}`)
100
+ .join(', ')})`;
101
+ await conn.run(ddl);
102
+ // All-or-nothing semantic: on any failure we drop the table so the caller
103
+ // can retry the same name without hitting "Table already exists." On the
104
+ // success path we flip this flag and the finally becomes a no-op.
105
+ let createdTable = true;
106
+ const app = await conn.createAppender(name);
107
+ try {
108
+ for (let i = 0; i < records.length; i++) {
109
+ let failingColIdx = -1;
110
+ try {
111
+ for (let colIdx = 0; colIdx < schema.length; colIdx++) {
112
+ failingColIdx = colIdx;
113
+ const col = schema[colIdx][0];
114
+ const v = records[i][col];
115
+ if (v === null || v === undefined) {
116
+ app.appendNull();
117
+ }
118
+ else {
119
+ // appendValue accepts DuckDBValue (null | boolean | number | bigint | string | ...)
120
+ // and lets the engine coerce based on the declared column type.
121
+ app.appendValue(v);
122
+ }
123
+ }
124
+ // endRow() may itself reject the row on a type mismatch detected at
125
+ // end-of-row; in that case we can't attribute to a single column so
126
+ // we fall back to '<column>' literally rather than blame col 0.
127
+ failingColIdx = -1;
128
+ app.endRow();
129
+ }
130
+ catch (e) {
131
+ const failingCol = failingColIdx >= 0 ? schema[failingColIdx][0] : '<column>';
132
+ const hint = sourceHint === 'inferred'
133
+ ? ` Pass an explicit schema via the third argument: registerDf(name, df, { schema: { ${failingCol}: 'VARCHAR' } })`
134
+ : '';
135
+ throw new Error(`registerDf row ${i}: append failed for column '${failingCol}' (${e.message}).${hint}`);
136
+ }
137
+ }
138
+ // Success path: close the appender to commit the rows, then disarm cleanup.
139
+ app.closeSync();
140
+ createdTable = false;
141
+ }
142
+ finally {
143
+ if (createdTable) {
144
+ // Failure path: close the appender (may already be closed; best-effort)
145
+ // then drop the partially-populated table.
146
+ try {
147
+ app.closeSync();
148
+ }
149
+ catch { /* already closed or errored */ }
150
+ try {
151
+ await conn.run(`DROP TABLE IF EXISTS ${quoteIdent(name)}`);
152
+ }
153
+ catch { /* best-effort */ }
154
+ }
155
+ }
156
+ }
157
+ /**
158
+ * Patches a DuckDBInstance with a `registerDf(name, input, opts?)` method
159
+ * so the LLM can drop a polars DataFrame / Arrow Table / array of records
160
+ * into DuckDB in one call instead of discovering the appender API.
161
+ *
162
+ * The method opens a fresh connection on each call (cheap — DuckDB connections
163
+ * share the underlying instance/db) and CREATE-TABLE-then-appends.
164
+ */
165
+ export function attachRegisterDf(instance) {
166
+ const patched = instance;
167
+ patched.registerDf = async function registerDf(name, input, opts = {}) {
168
+ const conn = await instance.connect();
169
+ try {
170
+ const records = coerceToRecords(input);
171
+ const sourceHint = opts.schema ? 'explicit' : 'inferred';
172
+ const schemaObj = opts.schema ?? inferSchema(records);
173
+ const schema = normalizeSchema(schemaObj);
174
+ await registerViaAppender(conn, name, records, schema, sourceHint);
175
+ }
176
+ finally {
177
+ // Release the connection — DuckDBConnection exposes closeSync(): void.
178
+ // Without this, every registerDf call leaks one connection over the
179
+ // lifetime of the scratchpad session.
180
+ conn.closeSync();
181
+ }
182
+ };
183
+ }
184
+ const journalScanner = new SecretScanner();
185
+ /**
186
+ * Scans `raw` for known secret patterns; for each hit, appends a
187
+ * `producer: 'secret-scanner', action: 'redact'` audit record (severity warn)
188
+ * with `detail = { cell_id, kind, offset, length }` — NEVER the secret value
189
+ * or `SecretHit.preview`. Returns the redacted text (`[REDACTED:<kind>]` per
190
+ * hit). If no hits, returns the input verbatim with no audit emission.
191
+ *
192
+ * Backward compatibility: callers that don't have an AuditLog should skip this
193
+ * helper entirely (pass-through). Audit is required here because the redaction
194
+ * MUST be observable.
195
+ */
196
+ export function redactForJournal(raw, ctx) {
197
+ const hits = journalScanner.scan(raw);
198
+ if (hits.length === 0)
199
+ return raw;
200
+ const ts = new Date().toISOString();
201
+ for (const h of hits) {
202
+ ctx.audit.append({
203
+ _schema: 1,
204
+ ts,
205
+ producer: 'secret-scanner',
206
+ action: 'redact',
207
+ severity: 'warn',
208
+ sessionId: ctx.sessionId,
209
+ scratchpadName: ctx.scratchpadName,
210
+ pid: ctx.pid,
211
+ detail: {
212
+ cell_id: ctx.cellId,
213
+ kind: h.kind,
214
+ offset: h.start,
215
+ length: h.end - h.start,
216
+ },
217
+ });
218
+ }
219
+ return journalScanner.redact(raw);
220
+ }
@@ -0,0 +1,355 @@
1
+ import process, { argv, stdin, stdout } from 'node:process';
2
+ import vm from 'node:vm';
3
+ import { existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { DuckDBInstance } from '@duckdb/node-api';
6
+ import { writeNdjson, readNdjson } from '@otto/coworker-utils';
7
+ import { DefaultCollectorRegistry } from './collector-registry.js';
8
+ import { FileCollector } from './file-collector.js';
9
+ import { isKernelRpcResponse } from './kernel-protocol.js';
10
+ import { buildDataLibBindings, attachRegisterDf } from './kernel-bindings.js';
11
+ import { encodeNamespace, decodeNamespace } from './namespace-codec.js';
12
+ const workspace = argv[2] ?? process.cwd();
13
+ const scratchpadDir = argv[3];
14
+ const trace = process.env.OTTO_SCRATCHPAD_IPC_TRACE === '1';
15
+ const KNOWN_BOUND_KEYS = new Set([
16
+ 'otto',
17
+ 'console',
18
+ 'progress',
19
+ 'setTimeout',
20
+ 'clearTimeout',
21
+ 'setInterval',
22
+ 'clearInterval',
23
+ 'polars',
24
+ 'DuckDB',
25
+ 'ExcelJS',
26
+ 'dateFns',
27
+ 'lodash',
28
+ 'zod',
29
+ 'axios',
30
+ 'Date',
31
+ // Phase 2 Task 13: process is bound so cells can read OTTO_DS_* env vars
32
+ // injected by CredentialInjector. Filtered from namespace snapshots.
33
+ 'process',
34
+ 'Buffer',
35
+ ]);
36
+ const registry = new DefaultCollectorRegistry();
37
+ registry.register(new FileCollector({ workspace }));
38
+ process.on('SIGINT', () => {
39
+ // Ignored on purpose. A stray cancel between cells must not tear down a healthy
40
+ // kernel; the parent escalates to SIGTERM/SIGKILL to actually stop a hung kernel.
41
+ });
42
+ function send(frame) {
43
+ if (trace)
44
+ process.stderr.write(`[kernel→] ${JSON.stringify(frame)}\n`);
45
+ void writeNdjson(stdout, frame);
46
+ }
47
+ const pendingRpc = new Map();
48
+ let nextRpcId = 1;
49
+ function newRpcId() {
50
+ return `art-${process.pid}-${nextRpcId++}`;
51
+ }
52
+ function rpcRequest(payload) {
53
+ return new Promise((resolve, reject) => {
54
+ pendingRpc.set(payload.id, {
55
+ resolve: resolve,
56
+ reject,
57
+ });
58
+ send(payload);
59
+ });
60
+ }
61
+ // Returns true when the frame was consumed as an RPC response.
62
+ function tryRouteRpcResponse(frame) {
63
+ if (!isKernelRpcResponse(frame))
64
+ return false;
65
+ const p = pendingRpc.get(frame.id);
66
+ if (!p)
67
+ return true; // unknown id — silently drop; nothing to do
68
+ pendingRpc.delete(frame.id);
69
+ if (frame.ok === false)
70
+ p.reject(new Error(frame.error));
71
+ else
72
+ p.resolve(frame);
73
+ return true;
74
+ }
75
+ const ottoCollectors = {
76
+ async list() {
77
+ const refs = [];
78
+ for (const collector of registry.list()) {
79
+ for await (const ref of collector.list())
80
+ refs.push(ref);
81
+ }
82
+ return refs;
83
+ },
84
+ async open(uri) {
85
+ const hit = await registry.resolve(uri);
86
+ if (!hit)
87
+ throw new Error(`no collector resolves uri: ${uri}`);
88
+ const source = await hit.collector.open(hit.ref);
89
+ return {
90
+ ref: source.ref,
91
+ async load() {
92
+ const value = await source.load();
93
+ send({
94
+ type: 'event',
95
+ event: 'data_load',
96
+ drawer: {
97
+ kind: 'data_load',
98
+ collector: source.ref.collector,
99
+ uri: source.ref.uri,
100
+ bytes: source.ref.bytes ?? null,
101
+ rows_loaded: Array.isArray(value) ? value.length : null,
102
+ loaded_at: new Date().toISOString(),
103
+ schema: null,
104
+ },
105
+ });
106
+ return value;
107
+ },
108
+ };
109
+ },
110
+ };
111
+ function makeArtifactProxy(args) {
112
+ return {
113
+ slug: args.slug,
114
+ uri: args.uri,
115
+ primaryPath: args.primaryPath,
116
+ async update(files) {
117
+ const req = {
118
+ type: 'request',
119
+ request: 'artifact_update',
120
+ id: newRpcId(),
121
+ slug: args.slug,
122
+ files,
123
+ };
124
+ const resp = await rpcRequest(req);
125
+ if (resp.ok === false)
126
+ throw new Error(`artifact_update failed: ${resp.error}`);
127
+ return { files_touched: resp.files_touched };
128
+ },
129
+ };
130
+ }
131
+ const ottoArtifact = {
132
+ async create(kind, name) {
133
+ if (kind !== 'report') {
134
+ throw new Error(`unsupported artifact kind: ${kind}. v1 ships only 'report'.`);
135
+ }
136
+ const req = {
137
+ type: 'request',
138
+ request: 'artifact_create',
139
+ id: newRpcId(),
140
+ kind,
141
+ name,
142
+ };
143
+ const resp = await rpcRequest(req);
144
+ if (resp.ok === false)
145
+ throw new Error(`artifact_create failed: ${resp.error}`);
146
+ // Broadcast artifact_create event so the manager can call recordArtifact
147
+ // into memory (Phase 4 Task 12 closure: getMemoryRecorder()?.recordArtifact).
148
+ // Without this, Layer B is silent for artifacts.
149
+ send({
150
+ type: 'event',
151
+ event: 'artifact_create',
152
+ drawer: {
153
+ kind: 'artifact',
154
+ slug: resp.slug,
155
+ artifact_kind: kind,
156
+ uri: resp.uri,
157
+ primary_path: resp.primary_path,
158
+ created_at: new Date().toISOString(),
159
+ },
160
+ });
161
+ return makeArtifactProxy({
162
+ slug: resp.slug,
163
+ uri: resp.uri,
164
+ primaryPath: resp.primary_path,
165
+ });
166
+ },
167
+ async spillIfLarge(value, opts) {
168
+ const threshold = opts?.thresholdBytes ?? 10_240;
169
+ let serialized;
170
+ try {
171
+ serialized = typeof value === 'string' ? value : JSON.stringify(value, null, 2);
172
+ }
173
+ catch {
174
+ serialized = String(value);
175
+ }
176
+ if (Buffer.byteLength(serialized, 'utf8') < threshold)
177
+ return null;
178
+ const name = opts?.name ??
179
+ `cell-output-${new Date().toISOString().slice(0, 19).replace(/[T:]/g, '-')}`;
180
+ const handle = await ottoArtifact.create('report', name);
181
+ await handle.update([{ path: 'report.md', content: serialized }]);
182
+ return handle;
183
+ },
184
+ };
185
+ const otto = { collectors: ottoCollectors, artifact: ottoArtifact };
186
+ const sandbox = {
187
+ otto,
188
+ ...buildDataLibBindings(),
189
+ // Timers are not part of a fresh vm context; bind the host ones so async cells
190
+ // (await new Promise((r) => setTimeout(r, ...))) and progress() heartbeats work.
191
+ setTimeout,
192
+ clearTimeout,
193
+ setInterval,
194
+ clearInterval,
195
+ // Bind the host Date so that v8-deserialized Date objects (from namespace restore)
196
+ // pass `instanceof Date` checks inside the vm context (cross-realm fix).
197
+ Date,
198
+ // Phase 2 Task 13: cells need process.env to read OTTO_DS_* vault-injected
199
+ // env vars. Bind the host process directly; vm sandbox isolation otherwise
200
+ // hides Node globals. Buffer is bound alongside since cells frequently
201
+ // base64-encode credentials (e.g. Basic auth from env vars).
202
+ process,
203
+ Buffer,
204
+ };
205
+ const context = vm.createContext(sandbox);
206
+ async function runCell(code) {
207
+ const logs = [];
208
+ sandbox.console = {
209
+ log: (...args) => logs.push(args.map((a) => String(a)).join(' ')),
210
+ error: (...args) => logs.push(args.map((a) => String(a)).join(' ')),
211
+ };
212
+ sandbox.progress = (message) => {
213
+ send({
214
+ type: 'event',
215
+ event: 'progress',
216
+ message: message === undefined ? undefined : String(message),
217
+ });
218
+ };
219
+ const wrapped = `(async () => {\n${code}\n})()`;
220
+ const value = await vm.runInContext(wrapped, context, { filename: 'cell.js' });
221
+ return { value, stdout: logs.join('\n') };
222
+ }
223
+ function toSerializable(value) {
224
+ try {
225
+ return JSON.parse(JSON.stringify(value ?? null));
226
+ }
227
+ catch {
228
+ return { valuePreview: String(value) };
229
+ }
230
+ }
231
+ async function openKernelDb(dir) {
232
+ try {
233
+ const instance = await DuckDBInstance.create(join(dir, 'kernel.db'));
234
+ attachRegisterDf(instance);
235
+ otto.duckdb = instance;
236
+ }
237
+ catch (err) {
238
+ const e = err;
239
+ await writeNdjson(stdout, {
240
+ type: 'event',
241
+ event: 'startup_error',
242
+ kind: 'duckdb_open',
243
+ error: { name: e.name, message: e.message },
244
+ });
245
+ process.exit(1);
246
+ }
247
+ }
248
+ function restoreNamespace(dir) {
249
+ const path = join(dir, 'namespace.json');
250
+ if (!existsSync(path))
251
+ return [{ kind: 'namespace-absent' }];
252
+ let raw;
253
+ try {
254
+ raw = readFileSync(path, 'utf8');
255
+ }
256
+ catch (err) {
257
+ return [{ kind: 'namespace-corrupt', message: err.message }];
258
+ }
259
+ try {
260
+ const { values } = decodeNamespace(raw);
261
+ for (const key of Object.keys(values)) {
262
+ if (KNOWN_BOUND_KEYS.has(key))
263
+ continue; // never let a tampered namespace.json overwrite host bindings
264
+ sandbox[key] = values[key];
265
+ }
266
+ return [];
267
+ }
268
+ catch (err) {
269
+ return [{ kind: 'namespace-corrupt', message: err.message }];
270
+ }
271
+ }
272
+ function writeNamespaceSnapshot(dir) {
273
+ // Enumerate live globalThis additions, excluding the known-bound surface.
274
+ const live = {};
275
+ for (const key of Object.keys(sandbox)) {
276
+ if (KNOWN_BOUND_KEYS.has(key))
277
+ continue;
278
+ live[key] = sandbox[key];
279
+ }
280
+ const { envelope, skipped } = encodeNamespace(live, () => Date.now());
281
+ const nsPath = join(dir, 'namespace.json');
282
+ const tmp = `${nsPath}.tmp`;
283
+ writeFileSync(tmp, JSON.stringify(envelope));
284
+ renameSync(tmp, nsPath);
285
+ return { skipped, snapshotted_at: envelope.ts };
286
+ }
287
+ async function main() {
288
+ const recoveryNotes = [];
289
+ if (scratchpadDir !== undefined) {
290
+ await openKernelDb(scratchpadDir);
291
+ recoveryNotes.push(...restoreNamespace(scratchpadDir));
292
+ }
293
+ send({ type: 'event', event: 'ready', recovery_notes: recoveryNotes });
294
+ try {
295
+ for await (const raw of readNdjson(stdin)) {
296
+ if (trace)
297
+ process.stderr.write(`[kernel←] ${JSON.stringify(raw)}\n`);
298
+ // Phase 4 Task 9 — route artifact RPC responses to the pending map before
299
+ // falling through to the existing run/snapshot request dispatch.
300
+ if (tryRouteRpcResponse(raw))
301
+ continue;
302
+ const req = raw;
303
+ if (req.type === 'snapshot') {
304
+ if (scratchpadDir === undefined) {
305
+ send({ id: req.id, type: 'snapshot_result', ok: true, skipped: [], snapshotted_at: new Date().toISOString() });
306
+ continue;
307
+ }
308
+ try {
309
+ const { skipped, snapshotted_at } = writeNamespaceSnapshot(scratchpadDir);
310
+ send({ id: req.id, type: 'snapshot_result', ok: true, skipped, snapshotted_at });
311
+ }
312
+ catch (err) {
313
+ const e = err;
314
+ send({ id: req.id, type: 'snapshot_result', ok: false, error: { name: e.name, message: e.message } });
315
+ }
316
+ continue;
317
+ }
318
+ if (req.type !== 'run')
319
+ continue;
320
+ // Phase 4 Task 10 fix — `runCell` may issue an artifact RPC and await its
321
+ // response. The response arrives over stdin, which means the main loop
322
+ // MUST keep iterating to route it via tryRouteRpcResponse. Awaiting
323
+ // runCell inline would deadlock the kernel against its own RPC. Fire it
324
+ // off; runCell sends its own result frame. The manager already serializes
325
+ // cell submissions, so there's no concurrency to worry about.
326
+ void (async () => {
327
+ let res;
328
+ try {
329
+ const { value, stdout: out } = await runCell(req.code);
330
+ res = { id: req.id, type: 'result', ok: true, value: toSerializable(value), stdout: out };
331
+ }
332
+ catch (err) {
333
+ const e = err;
334
+ res = {
335
+ id: req.id,
336
+ type: 'result',
337
+ ok: false,
338
+ error: { name: e.name, message: e.message, stack: e.stack },
339
+ };
340
+ }
341
+ send(res);
342
+ })();
343
+ }
344
+ }
345
+ finally {
346
+ // Phase 4 Task 9 review fix — if stdin closes (manager died / EOF) while
347
+ // RPCs are still in flight, reject them so awaiting cells fail fast
348
+ // instead of hanging until SIGKILL.
349
+ for (const [, p] of pendingRpc) {
350
+ p.reject(new Error('kernel: stdin closed with pending RPC'));
351
+ }
352
+ pendingRpc.clear();
353
+ }
354
+ }
355
+ void main();