@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,279 @@
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 type { DuckDBInstance, DuckDBConnection } from '@duckdb/node-api';
9
+ import { SecretScanner, type AuditLog, type AuditRecord } from '@otto/coworker-utils';
10
+
11
+ /**
12
+ * The data libraries pre-bound into every scratchpad cell's vm sandbox.
13
+ * DuckDB is bound as an in-memory-capable lib here; on-disk kernel.db wiring is 1d2.
14
+ */
15
+ export function buildDataLibBindings(): Record<string, unknown> {
16
+ return {
17
+ polars: pl,
18
+ DuckDB,
19
+ ExcelJS,
20
+ dateFns,
21
+ lodash,
22
+ zod: z,
23
+ axios,
24
+ };
25
+ }
26
+
27
+ // ---------------------------------------------------------------------------
28
+ // Task F: otto.duckdb.registerDf — single-call polars/Arrow/records → DuckDB
29
+ // ---------------------------------------------------------------------------
30
+
31
+ /** SQL column type string passed straight into CREATE TABLE (e.g. VARCHAR, BIGINT). */
32
+ export type DuckDBColumnType = string;
33
+
34
+ export interface RegisterDfOptions {
35
+ /**
36
+ * Explicit per-column SQL types. When omitted, the schema is inferred from
37
+ * the first non-null value of each column in the first 10 rows.
38
+ */
39
+ schema?: Record<string, DuckDBColumnType> | Array<[string, DuckDBColumnType]>;
40
+ }
41
+
42
+ interface PolarsDataFrameShape {
43
+ toRecords: () => Record<string, unknown>[];
44
+ width: number;
45
+ height: number;
46
+ }
47
+
48
+ interface ArrowTableShape {
49
+ toArray: () => Record<string, unknown>[];
50
+ numRows: number;
51
+ schema: unknown;
52
+ }
53
+
54
+ function isPolarsDataFrame(x: unknown): x is PolarsDataFrameShape {
55
+ return (
56
+ !!x &&
57
+ typeof x === 'object' &&
58
+ typeof (x as { toRecords?: unknown }).toRecords === 'function' &&
59
+ typeof (x as { width?: unknown }).width === 'number' &&
60
+ typeof (x as { height?: unknown }).height === 'number'
61
+ );
62
+ }
63
+
64
+ function isArrowTable(x: unknown): x is ArrowTableShape {
65
+ return (
66
+ !!x &&
67
+ typeof x === 'object' &&
68
+ typeof (x as { toArray?: unknown }).toArray === 'function' &&
69
+ typeof (x as { numRows?: unknown }).numRows === 'number' &&
70
+ 'schema' in (x as object)
71
+ );
72
+ }
73
+
74
+ function coerceToRecords(input: unknown): Record<string, unknown>[] {
75
+ if (isPolarsDataFrame(input)) return input.toRecords();
76
+ if (isArrowTable(input)) return input.toArray();
77
+ if (Array.isArray(input)) return input as Record<string, unknown>[];
78
+ throw new TypeError(
79
+ 'registerDf: input must be a polars DataFrame, Arrow Table, or array of records',
80
+ );
81
+ }
82
+
83
+ function inferSchema(records: Record<string, unknown>[]): Record<string, DuckDBColumnType> {
84
+ if (records.length === 0) {
85
+ throw new Error(
86
+ 'registerDf: cannot infer schema from empty input. Provide opts.schema or pass at least one row.',
87
+ );
88
+ }
89
+ const cols = Object.keys(records[0]!);
90
+ const out: Record<string, DuckDBColumnType> = {};
91
+ for (const col of cols) {
92
+ // Null-walk: scan up to the first 10 rows for the first non-null value of this column.
93
+ // Defaults to VARCHAR for all-null columns (safe — DuckDB will accept NULL into a VARCHAR).
94
+ out[col] = 'VARCHAR';
95
+ const walk = Math.min(10, records.length);
96
+ for (let i = 0; i < walk; i++) {
97
+ const v = records[i]![col];
98
+ if (v === null || v === undefined) continue;
99
+ if (typeof v === 'string') { out[col] = 'VARCHAR'; break; }
100
+ if (typeof v === 'bigint') { out[col] = 'BIGINT'; break; }
101
+ if (typeof v === 'number') { out[col] = 'DOUBLE'; break; }
102
+ if (typeof v === 'boolean') { out[col] = 'BOOLEAN'; break; }
103
+ if (v instanceof Date) { out[col] = 'TIMESTAMP'; break; }
104
+ out[col] = 'VARCHAR'; // unknown object → store as VARCHAR
105
+ break;
106
+ }
107
+ }
108
+ return out;
109
+ }
110
+
111
+ function normalizeSchema(
112
+ schema: Record<string, DuckDBColumnType> | Array<[string, DuckDBColumnType]>,
113
+ ): Array<[string, DuckDBColumnType]> {
114
+ if (Array.isArray(schema)) return schema;
115
+ return Object.entries(schema);
116
+ }
117
+
118
+ function quoteIdent(name: string): string {
119
+ // DuckDB identifier quoting: wrap in double quotes, escape embedded double quotes.
120
+ return `"${name.replace(/"/g, '""')}"`;
121
+ }
122
+
123
+ async function registerViaAppender(
124
+ conn: DuckDBConnection,
125
+ name: string,
126
+ records: Record<string, unknown>[],
127
+ schema: Array<[string, DuckDBColumnType]>,
128
+ sourceHint: 'inferred' | 'explicit',
129
+ ): Promise<void> {
130
+ const ddl = `CREATE TABLE ${quoteIdent(name)} (${schema
131
+ .map(([c, t]) => `${quoteIdent(c)} ${t}`)
132
+ .join(', ')})`;
133
+ await conn.run(ddl);
134
+ // All-or-nothing semantic: on any failure we drop the table so the caller
135
+ // can retry the same name without hitting "Table already exists." On the
136
+ // success path we flip this flag and the finally becomes a no-op.
137
+ let createdTable = true;
138
+ const app = await conn.createAppender(name);
139
+ try {
140
+ for (let i = 0; i < records.length; i++) {
141
+ let failingColIdx = -1;
142
+ try {
143
+ for (let colIdx = 0; colIdx < schema.length; colIdx++) {
144
+ failingColIdx = colIdx;
145
+ const col = schema[colIdx]![0];
146
+ const v = records[i]![col];
147
+ if (v === null || v === undefined) {
148
+ app.appendNull();
149
+ } else {
150
+ // appendValue accepts DuckDBValue (null | boolean | number | bigint | string | ...)
151
+ // and lets the engine coerce based on the declared column type.
152
+ app.appendValue(v as never);
153
+ }
154
+ }
155
+ // endRow() may itself reject the row on a type mismatch detected at
156
+ // end-of-row; in that case we can't attribute to a single column so
157
+ // we fall back to '<column>' literally rather than blame col 0.
158
+ failingColIdx = -1;
159
+ app.endRow();
160
+ } catch (e) {
161
+ const failingCol =
162
+ failingColIdx >= 0 ? schema[failingColIdx]![0] : '<column>';
163
+ const hint =
164
+ sourceHint === 'inferred'
165
+ ? ` Pass an explicit schema via the third argument: registerDf(name, df, { schema: { ${failingCol}: 'VARCHAR' } })`
166
+ : '';
167
+ throw new Error(
168
+ `registerDf row ${i}: append failed for column '${failingCol}' (${(e as Error).message}).${hint}`,
169
+ );
170
+ }
171
+ }
172
+ // Success path: close the appender to commit the rows, then disarm cleanup.
173
+ app.closeSync();
174
+ createdTable = false;
175
+ } finally {
176
+ if (createdTable) {
177
+ // Failure path: close the appender (may already be closed; best-effort)
178
+ // then drop the partially-populated table.
179
+ try { app.closeSync(); } catch { /* already closed or errored */ }
180
+ try { await conn.run(`DROP TABLE IF EXISTS ${quoteIdent(name)}`); } catch { /* best-effort */ }
181
+ }
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Patches a DuckDBInstance with a `registerDf(name, input, opts?)` method
187
+ * so the LLM can drop a polars DataFrame / Arrow Table / array of records
188
+ * into DuckDB in one call instead of discovering the appender API.
189
+ *
190
+ * The method opens a fresh connection on each call (cheap — DuckDB connections
191
+ * share the underlying instance/db) and CREATE-TABLE-then-appends.
192
+ */
193
+ export function attachRegisterDf(instance: DuckDBInstance): void {
194
+ const patched = instance as unknown as {
195
+ registerDf: (
196
+ name: string,
197
+ input: unknown,
198
+ opts?: RegisterDfOptions,
199
+ ) => Promise<void>;
200
+ };
201
+ patched.registerDf = async function registerDf(
202
+ name: string,
203
+ input: unknown,
204
+ opts: RegisterDfOptions = {},
205
+ ): Promise<void> {
206
+ const conn = await instance.connect();
207
+ try {
208
+ const records = coerceToRecords(input);
209
+ const sourceHint: 'inferred' | 'explicit' = opts.schema ? 'explicit' : 'inferred';
210
+ const schemaObj = opts.schema ?? inferSchema(records);
211
+ const schema = normalizeSchema(schemaObj);
212
+ await registerViaAppender(conn, name, records, schema, sourceHint);
213
+ } finally {
214
+ // Release the connection — DuckDBConnection exposes closeSync(): void.
215
+ // Without this, every registerDf call leaks one connection over the
216
+ // lifetime of the scratchpad session.
217
+ conn.closeSync();
218
+ }
219
+ };
220
+ }
221
+
222
+ // ---------------------------------------------------------------------------
223
+ // Phase 2 Task 14: SecretScanner gate on cell-output journal writes.
224
+ // Live TUI output is UPSTREAM of the journal write (the runtime returns the
225
+ // raw stdout, then the manager forks: the same string is returned to the tool
226
+ // for live display AND passed through redactForJournal before archive.append).
227
+ // Only the journal copy is redacted; the TUI copy is untouched.
228
+ // ---------------------------------------------------------------------------
229
+
230
+ /**
231
+ * Context passed to `redactForJournal`. The audit instance is the same one
232
+ * held by the CredentialInjector — supplied by the manager so secret-redaction
233
+ * audit records land alongside vault inject/inject-skipped records.
234
+ */
235
+ export interface RedactionContext {
236
+ audit: AuditLog;
237
+ sessionId: string;
238
+ scratchpadName: string;
239
+ pid: number;
240
+ cellId: string;
241
+ }
242
+
243
+ const journalScanner = new SecretScanner();
244
+
245
+ /**
246
+ * Scans `raw` for known secret patterns; for each hit, appends a
247
+ * `producer: 'secret-scanner', action: 'redact'` audit record (severity warn)
248
+ * with `detail = { cell_id, kind, offset, length }` — NEVER the secret value
249
+ * or `SecretHit.preview`. Returns the redacted text (`[REDACTED:<kind>]` per
250
+ * hit). If no hits, returns the input verbatim with no audit emission.
251
+ *
252
+ * Backward compatibility: callers that don't have an AuditLog should skip this
253
+ * helper entirely (pass-through). Audit is required here because the redaction
254
+ * MUST be observable.
255
+ */
256
+ export function redactForJournal(raw: string, ctx: RedactionContext): string {
257
+ const hits = journalScanner.scan(raw);
258
+ if (hits.length === 0) return raw;
259
+ const ts = new Date().toISOString();
260
+ for (const h of hits) {
261
+ ctx.audit.append({
262
+ _schema: 1,
263
+ ts,
264
+ producer: 'secret-scanner',
265
+ action: 'redact',
266
+ severity: 'warn',
267
+ sessionId: ctx.sessionId,
268
+ scratchpadName: ctx.scratchpadName,
269
+ pid: ctx.pid,
270
+ detail: {
271
+ cell_id: ctx.cellId,
272
+ kind: h.kind,
273
+ offset: h.start,
274
+ length: h.end - h.start,
275
+ },
276
+ } satisfies AuditRecord);
277
+ }
278
+ return journalScanner.redact(raw);
279
+ }
@@ -0,0 +1,123 @@
1
+ import { describe, it, beforeEach, afterEach } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process';
4
+ import { existsSync } from 'node:fs';
5
+ import { mkdtemp, mkdir, writeFile, rm } from 'node:fs/promises';
6
+ import { tmpdir } from 'node:os';
7
+ import { join } from 'node:path';
8
+ import { pathToFileURL } from 'node:url';
9
+ import process from 'node:process';
10
+ import { writeNdjson, readNdjson } from '@otto/coworker-utils';
11
+ import { ChildProcessRuntime } from './child-process-runtime.js';
12
+ import { resolveKernelEntry, kernelExecArgv, filterEnv } from './kernel-spawn.js';
13
+ import type { KernelFrame, ProgressEvent, ResultResponse } from './kernel-protocol.js';
14
+
15
+ let workspace: string;
16
+ let inputs: string;
17
+ let child: ChildProcessWithoutNullStreams;
18
+
19
+ function startKernel(ws: string): ChildProcessWithoutNullStreams {
20
+ return spawn(
21
+ process.execPath,
22
+ [...kernelExecArgv(), resolveKernelEntry(), ws],
23
+ { stdio: ['pipe', 'pipe', 'inherit'], cwd: process.cwd(), env: filterEnv(process.env) },
24
+ ) as unknown as ChildProcessWithoutNullStreams;
25
+ }
26
+
27
+ // Drain frames until `count` result frames have arrived; ignore events.
28
+ async function collectResults(c: ChildProcessWithoutNullStreams, count: number): Promise<ResultResponse[]> {
29
+ const results: ResultResponse[] = [];
30
+ for await (const raw of readNdjson(c.stdout)) {
31
+ const frame = raw as KernelFrame;
32
+ if (frame.type === 'result') {
33
+ results.push(frame);
34
+ if (results.length === count) break;
35
+ }
36
+ }
37
+ return results;
38
+ }
39
+
40
+ describe('kernel-entry (child process)', () => {
41
+ beforeEach(async () => {
42
+ workspace = await mkdtemp(join(tmpdir(), 'ke-ws-'));
43
+ inputs = join(workspace, '.otto', 'inputs');
44
+ await mkdir(inputs, { recursive: true });
45
+ });
46
+
47
+ afterEach(async () => {
48
+ child?.kill('SIGKILL');
49
+ await rm(workspace, { recursive: true, force: true });
50
+ });
51
+
52
+ it('evaluates a cell and returns its value + captured stdout', async () => {
53
+ child = startKernel(workspace);
54
+ await writeNdjson(child.stdin, { id: 1, type: 'run', code: "console.log('hi'); return 1 + 1;" });
55
+ const [res] = await collectResults(child, 1);
56
+ assert.equal(res.ok, true);
57
+ assert.equal((res as { value: unknown }).value, 2);
58
+ assert.equal((res as { stdout: string }).stdout, 'hi');
59
+ });
60
+
61
+ it('persists globalThis across cells', async () => {
62
+ child = startKernel(workspace);
63
+ await writeNdjson(child.stdin, { id: 1, type: 'run', code: 'globalThis.counter = 41; return globalThis.counter;' });
64
+ await writeNdjson(child.stdin, { id: 2, type: 'run', code: 'return globalThis.counter + 1;' });
65
+ const results = await collectResults(child, 2);
66
+ assert.equal(results[0].ok, true);
67
+ assert.equal((results[0] as { value: unknown }).value, 41);
68
+ assert.equal((results[1] as { value: unknown }).value, 42);
69
+ });
70
+
71
+ it('binds otto.collectors.list() to the workspace inputs dir', async () => {
72
+ await writeFile(join(inputs, 'cmdb.csv'), 'a,b\n1,2\n');
73
+ child = startKernel(workspace);
74
+ await writeNdjson(child.stdin, { id: 1, type: 'run', code: 'return (await otto.collectors.list()).map((r) => r.uri);' });
75
+ const [res] = await collectResults(child, 1);
76
+ assert.equal(res.ok, true);
77
+ assert.deepEqual((res as { value: string[] }).value, [pathToFileURL(join(inputs, 'cmdb.csv')).href]);
78
+ });
79
+
80
+ it('returns ok:false with the error message when a cell throws', async () => {
81
+ child = startKernel(workspace);
82
+ await writeNdjson(child.stdin, { id: 1, type: 'run', code: "throw new Error('boom');" });
83
+ const [res] = await collectResults(child, 1);
84
+ assert.equal(res.ok, false);
85
+ assert.match((res as { error: { message: string } }).error.message, /boom/);
86
+ });
87
+
88
+ it('emits a progress event when a cell calls progress()', async () => {
89
+ child = startKernel(workspace);
90
+ await writeNdjson(child.stdin, { id: 1, type: 'run', code: "progress('halfway'); return 1;" });
91
+ const frames: KernelFrame[] = [];
92
+ for await (const raw of readNdjson(child.stdout)) {
93
+ const f = raw as KernelFrame;
94
+ frames.push(f);
95
+ if (f.type === 'result') break;
96
+ }
97
+ const prog = frames.find((f) => f.type === 'event' && f.event === 'progress');
98
+ assert.ok(prog, 'expected a progress event before the result');
99
+ assert.equal((prog as ProgressEvent).message, 'halfway');
100
+ });
101
+
102
+ it('snapshot writes namespace.json via tmp + rename (no .tmp leak — 1g3)', async () => {
103
+ // Strategy: drive the kernel via ChildProcessRuntime, run a cell, snapshot,
104
+ // confirm namespace.json exists and namespace.json.tmp does NOT.
105
+ // (kernel-entry's snapshot handler is exercised through a real subprocess
106
+ // in the existing tests; this just adds the .tmp absence assertion.)
107
+ const ws = await mkdtemp(join(tmpdir(), 'ke-ws-'));
108
+ const dir = await mkdtemp(join(tmpdir(), 'ke-dir-'));
109
+ try {
110
+ const rt = new ChildProcessRuntime({ workspace: ws, scratchpadDir: dir });
111
+ await rt.start();
112
+ await rt.runCell('globalThis.x = 1;');
113
+ const res = await rt.snapshot();
114
+ assert.equal(res.ok, true, 'snapshot acked');
115
+ assert.ok(existsSync(join(dir, 'namespace.json')), 'namespace.json present');
116
+ assert.equal(existsSync(join(dir, 'namespace.json.tmp')), false, 'no .tmp leak');
117
+ await rt.dispose();
118
+ } finally {
119
+ await rm(ws, { recursive: true, force: true });
120
+ await rm(dir, { recursive: true, force: true });
121
+ }
122
+ });
123
+ });