@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,390 @@
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 type { DataSource, DataSourceRef } from '@otto/coworker-types';
8
+ import { DefaultCollectorRegistry } from './collector-registry.js';
9
+ import { FileCollector } from './file-collector.js';
10
+ import type {
11
+ KernelEvent,
12
+ KernelRequest,
13
+ ResultResponse,
14
+ SnapshotResult,
15
+ RecoveryNote,
16
+ SkippedKey,
17
+ ArtifactCreateRequest,
18
+ ArtifactCreateResponse,
19
+ ArtifactUpdateRequest,
20
+ ArtifactUpdateResponse,
21
+ KernelRpcRequest,
22
+ } from './kernel-protocol.js';
23
+ import { isKernelRpcResponse } from './kernel-protocol.js';
24
+ import { buildDataLibBindings, attachRegisterDf } from './kernel-bindings.js';
25
+ import { encodeNamespace, decodeNamespace } from './namespace-codec.js';
26
+
27
+ const workspace = argv[2] ?? process.cwd();
28
+ const scratchpadDir: string | undefined = argv[3];
29
+ const trace = process.env.OTTO_SCRATCHPAD_IPC_TRACE === '1';
30
+
31
+ const KNOWN_BOUND_KEYS = new Set([
32
+ 'otto',
33
+ 'console',
34
+ 'progress',
35
+ 'setTimeout',
36
+ 'clearTimeout',
37
+ 'setInterval',
38
+ 'clearInterval',
39
+ 'polars',
40
+ 'DuckDB',
41
+ 'ExcelJS',
42
+ 'dateFns',
43
+ 'lodash',
44
+ 'zod',
45
+ 'axios',
46
+ 'Date',
47
+ // Phase 2 Task 13: process is bound so cells can read OTTO_DS_* env vars
48
+ // injected by CredentialInjector. Filtered from namespace snapshots.
49
+ 'process',
50
+ 'Buffer',
51
+ ]);
52
+
53
+ const registry = new DefaultCollectorRegistry();
54
+ registry.register(new FileCollector({ workspace }));
55
+
56
+ process.on('SIGINT', () => {
57
+ // Ignored on purpose. A stray cancel between cells must not tear down a healthy
58
+ // kernel; the parent escalates to SIGTERM/SIGKILL to actually stop a hung kernel.
59
+ });
60
+
61
+ function send(frame: KernelEvent | ResultResponse | SnapshotResult | KernelRpcRequest): void {
62
+ if (trace) process.stderr.write(`[kernel→] ${JSON.stringify(frame)}\n`);
63
+ void writeNdjson(stdout, frame);
64
+ }
65
+
66
+ // Phase 4 Task 9 — RPC plumbing for otto.artifact.
67
+ // The kernel sends `{type:'request',...}` frames over stdout and awaits the
68
+ // matching `{type:'response',...}` frame on stdin. The main loop routes
69
+ // response frames to this pending map before falling through to the
70
+ // existing run/snapshot request handling.
71
+ interface PendingRpc {
72
+ resolve: (value: unknown) => void;
73
+ reject: (err: Error) => void;
74
+ }
75
+ const pendingRpc = new Map<string, PendingRpc>();
76
+ let nextRpcId = 1;
77
+
78
+ function newRpcId(): string {
79
+ return `art-${process.pid}-${nextRpcId++}`;
80
+ }
81
+
82
+ function rpcRequest<TResp>(payload: KernelRpcRequest): Promise<TResp> {
83
+ return new Promise<TResp>((resolve, reject) => {
84
+ pendingRpc.set(payload.id, {
85
+ resolve: resolve as (value: unknown) => void,
86
+ reject,
87
+ });
88
+ send(payload);
89
+ });
90
+ }
91
+
92
+ // Returns true when the frame was consumed as an RPC response.
93
+ function tryRouteRpcResponse(frame: unknown): boolean {
94
+ if (!isKernelRpcResponse(frame)) return false;
95
+ const p = pendingRpc.get(frame.id);
96
+ if (!p) return true; // unknown id — silently drop; nothing to do
97
+ pendingRpc.delete(frame.id);
98
+ if (frame.ok === false) p.reject(new Error(frame.error));
99
+ else p.resolve(frame);
100
+ return true;
101
+ }
102
+
103
+ const ottoCollectors = {
104
+ async list(): Promise<DataSourceRef[]> {
105
+ const refs: DataSourceRef[] = [];
106
+ for (const collector of registry.list()) {
107
+ for await (const ref of collector.list()) refs.push(ref);
108
+ }
109
+ return refs;
110
+ },
111
+ async open(uri: string): Promise<DataSource> {
112
+ const hit = await registry.resolve(uri);
113
+ if (!hit) throw new Error(`no collector resolves uri: ${uri}`);
114
+ const source = await hit.collector.open(hit.ref);
115
+ return {
116
+ ref: source.ref,
117
+ async load(): Promise<Buffer | string | object> {
118
+ const value = await source.load();
119
+ send({
120
+ type: 'event',
121
+ event: 'data_load',
122
+ drawer: {
123
+ kind: 'data_load',
124
+ collector: source.ref.collector,
125
+ uri: source.ref.uri,
126
+ bytes: source.ref.bytes ?? null,
127
+ rows_loaded: Array.isArray(value) ? value.length : null,
128
+ loaded_at: new Date().toISOString(),
129
+ schema: null,
130
+ },
131
+ });
132
+ return value;
133
+ },
134
+ };
135
+ },
136
+ };
137
+
138
+ // Phase 4 Task 9 — otto.artifact binding (RPC over stdio).
139
+ // `create` and `update` block the cell on a parent-side response; the manager
140
+ // handles the FS work and writes the artifact_create event back to memory.
141
+ interface ArtifactHandleProxy {
142
+ slug: string;
143
+ uri: string;
144
+ primaryPath: string;
145
+ update(files: Array<{ path: string; content: string }>): Promise<{ files_touched: string[] }>;
146
+ }
147
+
148
+ function makeArtifactProxy(args: { slug: string; uri: string; primaryPath: string }): ArtifactHandleProxy {
149
+ return {
150
+ slug: args.slug,
151
+ uri: args.uri,
152
+ primaryPath: args.primaryPath,
153
+ async update(files): Promise<{ files_touched: string[] }> {
154
+ const req: ArtifactUpdateRequest = {
155
+ type: 'request',
156
+ request: 'artifact_update',
157
+ id: newRpcId(),
158
+ slug: args.slug,
159
+ files,
160
+ };
161
+ const resp = await rpcRequest<ArtifactUpdateResponse>(req);
162
+ if (resp.ok === false) throw new Error(`artifact_update failed: ${resp.error}`);
163
+ return { files_touched: resp.files_touched };
164
+ },
165
+ };
166
+ }
167
+
168
+ const ottoArtifact = {
169
+ async create(kind: string, name: string): Promise<ArtifactHandleProxy> {
170
+ if (kind !== 'report') {
171
+ throw new Error(`unsupported artifact kind: ${kind}. v1 ships only 'report'.`);
172
+ }
173
+ const req: ArtifactCreateRequest = {
174
+ type: 'request',
175
+ request: 'artifact_create',
176
+ id: newRpcId(),
177
+ kind,
178
+ name,
179
+ };
180
+ const resp = await rpcRequest<ArtifactCreateResponse>(req);
181
+ if (resp.ok === false) throw new Error(`artifact_create failed: ${resp.error}`);
182
+ // Broadcast artifact_create event so the manager can call recordArtifact
183
+ // into memory (Phase 4 Task 12 closure: getMemoryRecorder()?.recordArtifact).
184
+ // Without this, Layer B is silent for artifacts.
185
+ send({
186
+ type: 'event',
187
+ event: 'artifact_create',
188
+ drawer: {
189
+ kind: 'artifact',
190
+ slug: resp.slug,
191
+ artifact_kind: kind,
192
+ uri: resp.uri,
193
+ primary_path: resp.primary_path,
194
+ created_at: new Date().toISOString(),
195
+ },
196
+ });
197
+ return makeArtifactProxy({
198
+ slug: resp.slug,
199
+ uri: resp.uri,
200
+ primaryPath: resp.primary_path,
201
+ });
202
+ },
203
+
204
+ async spillIfLarge(
205
+ value: unknown,
206
+ opts?: { thresholdBytes?: number; name?: string },
207
+ ): Promise<ArtifactHandleProxy | null> {
208
+ const threshold = opts?.thresholdBytes ?? 10_240;
209
+ let serialized: string;
210
+ try {
211
+ serialized = typeof value === 'string' ? value : JSON.stringify(value, null, 2);
212
+ } catch {
213
+ serialized = String(value);
214
+ }
215
+ if (Buffer.byteLength(serialized, 'utf8') < threshold) return null;
216
+ const name =
217
+ opts?.name ??
218
+ `cell-output-${new Date().toISOString().slice(0, 19).replace(/[T:]/g, '-')}`;
219
+ const handle = await ottoArtifact.create('report', name);
220
+ await handle.update([{ path: 'report.md', content: serialized }]);
221
+ return handle;
222
+ },
223
+ };
224
+
225
+ const otto: Record<string, unknown> = { collectors: ottoCollectors, artifact: ottoArtifact };
226
+ const sandbox: Record<string, unknown> = {
227
+ otto,
228
+ ...buildDataLibBindings(),
229
+ // Timers are not part of a fresh vm context; bind the host ones so async cells
230
+ // (await new Promise((r) => setTimeout(r, ...))) and progress() heartbeats work.
231
+ setTimeout,
232
+ clearTimeout,
233
+ setInterval,
234
+ clearInterval,
235
+ // Bind the host Date so that v8-deserialized Date objects (from namespace restore)
236
+ // pass `instanceof Date` checks inside the vm context (cross-realm fix).
237
+ Date,
238
+ // Phase 2 Task 13: cells need process.env to read OTTO_DS_* vault-injected
239
+ // env vars. Bind the host process directly; vm sandbox isolation otherwise
240
+ // hides Node globals. Buffer is bound alongside since cells frequently
241
+ // base64-encode credentials (e.g. Basic auth from env vars).
242
+ process,
243
+ Buffer,
244
+ };
245
+ const context = vm.createContext(sandbox);
246
+
247
+ async function runCell(code: string): Promise<{ value: unknown; stdout: string }> {
248
+ const logs: string[] = [];
249
+ sandbox.console = {
250
+ log: (...args: unknown[]) => logs.push(args.map((a) => String(a)).join(' ')),
251
+ error: (...args: unknown[]) => logs.push(args.map((a) => String(a)).join(' ')),
252
+ };
253
+ sandbox.progress = (message?: unknown): void => {
254
+ send({
255
+ type: 'event',
256
+ event: 'progress',
257
+ message: message === undefined ? undefined : String(message),
258
+ });
259
+ };
260
+ const wrapped = `(async () => {\n${code}\n})()`;
261
+ const value: unknown = await vm.runInContext(wrapped, context, { filename: 'cell.js' });
262
+ return { value, stdout: logs.join('\n') };
263
+ }
264
+
265
+ function toSerializable(value: unknown): unknown {
266
+ try {
267
+ return JSON.parse(JSON.stringify(value ?? null));
268
+ } catch {
269
+ return { valuePreview: String(value) };
270
+ }
271
+ }
272
+
273
+ async function openKernelDb(dir: string): Promise<void> {
274
+ try {
275
+ const instance = await DuckDBInstance.create(join(dir, 'kernel.db'));
276
+ attachRegisterDf(instance);
277
+ otto.duckdb = instance;
278
+ } catch (err) {
279
+ const e = err as Error;
280
+ await writeNdjson(stdout, {
281
+ type: 'event',
282
+ event: 'startup_error',
283
+ kind: 'duckdb_open',
284
+ error: { name: e.name, message: e.message },
285
+ });
286
+ process.exit(1);
287
+ }
288
+ }
289
+
290
+ function restoreNamespace(dir: string): RecoveryNote[] {
291
+ const path = join(dir, 'namespace.json');
292
+ if (!existsSync(path)) return [{ kind: 'namespace-absent' }];
293
+ let raw: string;
294
+ try {
295
+ raw = readFileSync(path, 'utf8');
296
+ } catch (err) {
297
+ return [{ kind: 'namespace-corrupt', message: (err as Error).message }];
298
+ }
299
+ try {
300
+ const { values } = decodeNamespace(raw);
301
+ for (const key of Object.keys(values)) {
302
+ if (KNOWN_BOUND_KEYS.has(key)) continue; // never let a tampered namespace.json overwrite host bindings
303
+ sandbox[key] = values[key];
304
+ }
305
+ return [];
306
+ } catch (err) {
307
+ return [{ kind: 'namespace-corrupt', message: (err as Error).message }];
308
+ }
309
+ }
310
+
311
+ function writeNamespaceSnapshot(dir: string): { skipped: SkippedKey[]; snapshotted_at: string } {
312
+ // Enumerate live globalThis additions, excluding the known-bound surface.
313
+ const live: Record<string, unknown> = {};
314
+ for (const key of Object.keys(sandbox)) {
315
+ if (KNOWN_BOUND_KEYS.has(key)) continue;
316
+ live[key] = sandbox[key];
317
+ }
318
+ const { envelope, skipped } = encodeNamespace(live, () => Date.now());
319
+ const nsPath = join(dir, 'namespace.json');
320
+ const tmp = `${nsPath}.tmp`;
321
+ writeFileSync(tmp, JSON.stringify(envelope));
322
+ renameSync(tmp, nsPath);
323
+ return { skipped, snapshotted_at: envelope.ts };
324
+ }
325
+
326
+ async function main(): Promise<void> {
327
+ const recoveryNotes: RecoveryNote[] = [];
328
+ if (scratchpadDir !== undefined) {
329
+ await openKernelDb(scratchpadDir);
330
+ recoveryNotes.push(...restoreNamespace(scratchpadDir));
331
+ }
332
+ send({ type: 'event', event: 'ready', recovery_notes: recoveryNotes });
333
+
334
+ try {
335
+ for await (const raw of readNdjson(stdin)) {
336
+ if (trace) process.stderr.write(`[kernel←] ${JSON.stringify(raw)}\n`);
337
+ // Phase 4 Task 9 — route artifact RPC responses to the pending map before
338
+ // falling through to the existing run/snapshot request dispatch.
339
+ if (tryRouteRpcResponse(raw)) continue;
340
+ const req = raw as KernelRequest;
341
+ if (req.type === 'snapshot') {
342
+ if (scratchpadDir === undefined) {
343
+ send({ id: req.id, type: 'snapshot_result', ok: true, skipped: [], snapshotted_at: new Date().toISOString() });
344
+ continue;
345
+ }
346
+ try {
347
+ const { skipped, snapshotted_at } = writeNamespaceSnapshot(scratchpadDir);
348
+ send({ id: req.id, type: 'snapshot_result', ok: true, skipped, snapshotted_at });
349
+ } catch (err) {
350
+ const e = err as Error;
351
+ send({ id: req.id, type: 'snapshot_result', ok: false, error: { name: e.name, message: e.message } });
352
+ }
353
+ continue;
354
+ }
355
+ if (req.type !== 'run') continue;
356
+ // Phase 4 Task 10 fix — `runCell` may issue an artifact RPC and await its
357
+ // response. The response arrives over stdin, which means the main loop
358
+ // MUST keep iterating to route it via tryRouteRpcResponse. Awaiting
359
+ // runCell inline would deadlock the kernel against its own RPC. Fire it
360
+ // off; runCell sends its own result frame. The manager already serializes
361
+ // cell submissions, so there's no concurrency to worry about.
362
+ void (async (): Promise<void> => {
363
+ let res: ResultResponse;
364
+ try {
365
+ const { value, stdout: out } = await runCell(req.code);
366
+ res = { id: req.id, type: 'result', ok: true, value: toSerializable(value), stdout: out };
367
+ } catch (err) {
368
+ const e = err as Error;
369
+ res = {
370
+ id: req.id,
371
+ type: 'result',
372
+ ok: false,
373
+ error: { name: e.name, message: e.message, stack: e.stack },
374
+ };
375
+ }
376
+ send(res);
377
+ })();
378
+ }
379
+ } finally {
380
+ // Phase 4 Task 9 review fix — if stdin closes (manager died / EOF) while
381
+ // RPCs are still in flight, reject them so awaiting cells fail fast
382
+ // instead of hanging until SIGKILL.
383
+ for (const [, p] of pendingRpc) {
384
+ p.reject(new Error('kernel: stdin closed with pending RPC'));
385
+ }
386
+ pendingRpc.clear();
387
+ }
388
+ }
389
+
390
+ void main();
@@ -0,0 +1,105 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { isDataLoadEvent, isProgressEvent, isStartupErrorEvent, isSnapshotResult } from './kernel-protocol.js';
4
+ import type { DataLoadEvent, ProgressEvent, ReadyEvent, ResultOk, KernelFrame } from './kernel-protocol.js';
5
+
6
+ describe('isDataLoadEvent', () => {
7
+ it('returns true for a data_load event frame', () => {
8
+ const frame: DataLoadEvent = {
9
+ type: 'event',
10
+ event: 'data_load',
11
+ drawer: {
12
+ kind: 'data_load',
13
+ collector: 'file',
14
+ uri: 'file:///x/a.csv',
15
+ bytes: 8,
16
+ rows_loaded: null,
17
+ loaded_at: '2026-05-31T00:00:00.000Z',
18
+ schema: null,
19
+ },
20
+ };
21
+ assert.equal(isDataLoadEvent(frame), true);
22
+ });
23
+
24
+ it('returns false for the ready event frame', () => {
25
+ const frame: ReadyEvent = { type: 'event', event: 'ready' };
26
+ assert.equal(isDataLoadEvent(frame), false);
27
+ });
28
+
29
+ it('returns false for a result frame', () => {
30
+ const frame: ResultOk = { id: 1, type: 'result', ok: true, value: 42, stdout: '' };
31
+ assert.equal(isDataLoadEvent(frame), false);
32
+ });
33
+ });
34
+
35
+ describe('isProgressEvent', () => {
36
+ it('returns true for a progress frame', () => {
37
+ const frame: ProgressEvent = { type: 'event', event: 'progress', message: 'halfway' };
38
+ assert.equal(isProgressEvent(frame), true);
39
+ });
40
+
41
+ it('returns false for ready and data_load and result frames', () => {
42
+ const ready: ReadyEvent = { type: 'event', event: 'ready' };
43
+ const dl: DataLoadEvent = {
44
+ type: 'event',
45
+ event: 'data_load',
46
+ drawer: {
47
+ kind: 'data_load', collector: 'file', uri: 'file:///x', bytes: 1,
48
+ rows_loaded: null, loaded_at: '2026-05-31T00:00:00.000Z', schema: null,
49
+ },
50
+ };
51
+ const res: ResultOk = { id: 1, type: 'result', ok: true, value: 0, stdout: '' };
52
+ assert.equal(isProgressEvent(ready), false);
53
+ assert.equal(isProgressEvent(dl), false);
54
+ assert.equal(isProgressEvent(res), false);
55
+ });
56
+ });
57
+
58
+ describe('kernel-protocol type guards (1d2 additions)', () => {
59
+ it('isStartupErrorEvent recognises the startup_error event', () => {
60
+ const f: KernelFrame = {
61
+ type: 'event',
62
+ event: 'startup_error',
63
+ kind: 'duckdb_open',
64
+ error: { name: 'Error', message: 'cannot open db' },
65
+ };
66
+ assert.equal(isStartupErrorEvent(f), true);
67
+ assert.equal(isDataLoadEvent(f), false);
68
+ assert.equal(isProgressEvent(f), false);
69
+ });
70
+
71
+ it('isSnapshotResult recognises a successful snapshot_result', () => {
72
+ const f: KernelFrame = {
73
+ id: 1,
74
+ type: 'snapshot_result',
75
+ ok: true,
76
+ skipped: [],
77
+ snapshotted_at: '2026-05-31T00:00:00.000Z',
78
+ };
79
+ assert.equal(isSnapshotResult(f), true);
80
+ });
81
+
82
+ it('isSnapshotResult recognises a failed snapshot_result', () => {
83
+ const f: KernelFrame = {
84
+ id: 1,
85
+ type: 'snapshot_result',
86
+ ok: false,
87
+ error: { name: 'Error', message: 'disk full' },
88
+ };
89
+ assert.equal(isSnapshotResult(f), true);
90
+ });
91
+
92
+ it('a ready event may carry recovery_notes', () => {
93
+ const f: ReadyEvent = {
94
+ type: 'event',
95
+ event: 'ready',
96
+ recovery_notes: [{ kind: 'namespace-absent' }],
97
+ };
98
+ assert.equal(f.recovery_notes?.[0]?.kind, 'namespace-absent');
99
+ });
100
+
101
+ it('isStartupErrorEvent returns false for a ready event', () => {
102
+ const f: KernelFrame = { type: 'event', event: 'ready' };
103
+ assert.equal(isStartupErrorEvent(f), false);
104
+ });
105
+ });