@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
@@ -1,21 +1,53 @@
1
1
  // OTTO + Subagent launch contract and child process safety helpers.
2
+ import * as crypto from "node:crypto";
2
3
  import * as fs from "node:fs";
3
4
  import * as path from "node:path";
4
5
  import { SessionManager } from "@otto/pi-coding-agent";
5
6
  export const SUBAGENT_CHILD_ENV_VAR = "OTTO_SUBAGENT_CHILD";
6
7
  export const SUBAGENT_CHILD_ENV_VALUE = "1";
8
+ export const SUBAGENT_SCRATCHPAD_ENV_VAR = "OTTO_SUBAGENT_SCRATCHPAD";
9
+ const MAX_SCRATCHPAD_AGENT_PART = 32;
10
+ export function mintSubagentScratchpadName(agentName) {
11
+ const hex = crypto.randomBytes(3).toString("hex");
12
+ // Sanitize: NFKD + strip combining marks + lowercase + non-[a-z0-9] → '-' + collapse + trim.
13
+ let sanitized = agentName
14
+ .normalize("NFKD")
15
+ .replace(/[̀-ͯ]/g, "")
16
+ .toLowerCase()
17
+ .replace(/[^a-z0-9]+/g, "-")
18
+ .replace(/-+/g, "-")
19
+ .replace(/^-+|-+$/g, "");
20
+ if (sanitized.length > MAX_SCRATCHPAD_AGENT_PART) {
21
+ sanitized = sanitized.slice(0, MAX_SCRATCHPAD_AGENT_PART).replace(/-+$/, "");
22
+ }
23
+ if (!sanitized)
24
+ return `subagent-${hex}`;
25
+ return `subagent-${sanitized}-${hex}`;
26
+ }
7
27
  export function isSubagentChildProcess(env = process.env) {
8
28
  return env[SUBAGENT_CHILD_ENV_VAR] === SUBAGENT_CHILD_ENV_VALUE;
9
29
  }
10
- export function buildSubagentProcessEnv(env = process.env) {
11
- return {
30
+ export function buildSubagentProcessEnv(env = process.env, scratchpadName) {
31
+ const next = {
12
32
  ...env,
13
33
  [SUBAGENT_CHILD_ENV_VAR]: SUBAGENT_CHILD_ENV_VALUE,
14
34
  };
35
+ if (scratchpadName) {
36
+ next[SUBAGENT_SCRATCHPAD_ENV_VAR] = scratchpadName;
37
+ }
38
+ return next;
15
39
  }
16
40
  export function buildShellEnvAssignments(env = process.env) {
17
- const value = env[SUBAGENT_CHILD_ENV_VAR];
18
- return value ? [`${SUBAGENT_CHILD_ENV_VAR}=${JSON.stringify(value)}`] : [];
41
+ const out = [];
42
+ const childValue = env[SUBAGENT_CHILD_ENV_VAR];
43
+ if (childValue) {
44
+ out.push(`${SUBAGENT_CHILD_ENV_VAR}=${JSON.stringify(childValue)}`);
45
+ }
46
+ const scratchpadValue = env[SUBAGENT_SCRATCHPAD_ENV_VAR];
47
+ if (scratchpadValue) {
48
+ out.push(`${SUBAGENT_SCRATCHPAD_ENV_VAR}=${JSON.stringify(scratchpadValue)}`);
49
+ }
50
+ return out;
19
51
  }
20
52
  export function buildSubagentProcessArgs(agent, task, tmpPromptPath, modelOverride, session = { mode: "fresh" }) {
21
53
  const args = ["--mode", "json", "-p"];
@@ -70,7 +102,7 @@ export function createSubagentLaunchPlan(input) {
70
102
  const session = input.session ?? resolveSubagentSessionArgs(input.contextMode ?? "fresh", input.parentSessionManager);
71
103
  return {
72
104
  args: buildSubagentProcessArgs(input.agent, input.task, input.tmpPromptPath, input.modelOverride, session),
73
- env: buildSubagentProcessEnv(),
105
+ env: buildSubagentProcessEnv(process.env, input.scratchpadName),
74
106
  cwd: input.cwd ?? input.defaultCwd,
75
107
  session,
76
108
  };
@@ -131,6 +131,7 @@ export function createInitialRunRecord(input) {
131
131
  index,
132
132
  agent: child.agent,
133
133
  trackingName: child.trackingName,
134
+ scratchpadName: child.scratchpadName,
134
135
  task: child.task,
135
136
  cwd: child.cwd,
136
137
  status: "queued",
@@ -19,6 +19,7 @@ import { logWarning } from "../workflow-logger.js";
19
19
  // session hook calling startAuto) would be silently dropped because Node's
20
20
  // EventEmitter does not buffer events for late subscribers.
21
21
  import { initCmuxEventListeners } from "../../cmux/index.js";
22
+ import { registerPersonaCommands } from "../persona-status.js";
22
23
  import { BRAND } from "../strings.js";
23
24
  export { writeCrashLog } from "./crash-log.js";
24
25
  export function handleRecoverableExtensionProcessError(err) {
@@ -110,6 +111,7 @@ export function registerWorkflowExtension(pi) {
110
111
  ["memory-tools", () => registerMemoryTools(pi)],
111
112
  ["exec-tools", () => registerExecTools(pi)],
112
113
  ["schedule-wakeup-tool", () => registerScheduleWakeupTool(pi)],
114
+ ["persona-commands", () => registerPersonaCommands(pi)],
113
115
  ["shortcuts", () => registerShortcuts(pi)],
114
116
  // cmux is a library (no pi), so gsd sets up the event listeners on its
115
117
  // behalf using the shared event channel contract. Registration is
@@ -299,6 +299,15 @@ async function resetAskUserQuestionsTurnCache() {
299
299
  const { resetAskUserQuestionsCache } = await import("../../ask-user-questions.js");
300
300
  resetAskUserQuestionsCache();
301
301
  }
302
+ async function initPersonaStatusChip(ctx) {
303
+ try {
304
+ const { initPersonaWidget } = await import("../persona-status.js");
305
+ await initPersonaWidget(ctx);
306
+ }
307
+ catch {
308
+ // Non-fatal: persona chip simply won't render if the registry is unavailable.
309
+ }
310
+ }
302
311
  async function syncServiceTierStatus(ctx) {
303
312
  const { getEffectiveServiceTier, formatServiceTierFooterStatus } = await import("../service-tier.js");
304
313
  ctx.ui.setStatus("gsd-fast", formatServiceTierFooterStatus(getEffectiveServiceTier(), ctx.model?.id));
@@ -424,6 +433,7 @@ export function registerHooks(pi, ecosystemHandlers) {
424
433
  approvalQuestionAbortInFlight = false;
425
434
  clearDeferredApprovalGate();
426
435
  await resetAskUserQuestionsTurnCache();
436
+ await initPersonaStatusChip(ctx);
427
437
  await syncServiceTierStatus(ctx);
428
438
  await applyDisabledModelProviderPolicy(ctx);
429
439
  await applyCompactionThresholdOverride(ctx);
@@ -0,0 +1,87 @@
1
+ // Wires /persona slash commands + the persona status-bar chip into Otto.
2
+ // Spec §2.5 + §5.2. Lives inside the src/resources extension boundary, so it
3
+ // imports only the @otto/coworker-persona package (never src/ modules).
4
+ import { homedir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { PersonaRegistry, handleList, handleCurrent, handleSwitch, handleReset, handleInstall, handleUninstall, } from "@otto/coworker-persona";
7
+ // Sorts ahead of alphabetic extension status keys so the chip lands leftmost
8
+ // in the footer's extension-status block.
9
+ const STATUS_KEY = "00-persona";
10
+ const SUBCOMMANDS = ["list", "current", "switch", "install", "uninstall", "reset"];
11
+ function ottoHome() {
12
+ return process.env.OTTO_HOME || join(homedir(), ".otto");
13
+ }
14
+ function getRegistry() {
15
+ return new PersonaRegistry({ ottoHome: ottoHome() });
16
+ }
17
+ function formatPersonaChip(persona) {
18
+ const { icon, label } = persona.status_line;
19
+ return `${icon} ${label}`.trim();
20
+ }
21
+ async function refreshPersonaChip(ctx, registry) {
22
+ if (!ctx.hasUI)
23
+ return;
24
+ try {
25
+ const active = await registry.activeInWorkspace(ctx.cwd);
26
+ ctx.ui.setStatus(STATUS_KEY, formatPersonaChip(active));
27
+ }
28
+ catch {
29
+ ctx.ui.setStatus(STATUS_KEY, undefined);
30
+ }
31
+ }
32
+ // Called on session_start to seed the default persona and render the chip.
33
+ export async function initPersonaWidget(ctx) {
34
+ const registry = getRegistry();
35
+ try {
36
+ await registry.ensureDefaultInstalled();
37
+ }
38
+ catch {
39
+ // Non-fatal: chip simply won't render if the default can't be installed.
40
+ }
41
+ await refreshPersonaChip(ctx, registry);
42
+ }
43
+ export function registerPersonaCommands(pi) {
44
+ pi.registerCommand("persona", {
45
+ description: "Manage Otto co-worker personas (list, current, switch, install, uninstall, reset)",
46
+ getArgumentCompletions: (prefix) => SUBCOMMANDS.filter((s) => s.startsWith(prefix)).map((s) => ({ value: s, label: s })),
47
+ handler: async (args, ctx) => {
48
+ const registry = getRegistry();
49
+ await registry.ensureDefaultInstalled();
50
+ const [sub, ...rest] = args.trim().split(/\s+/).filter(Boolean);
51
+ const ws = ctx.cwd;
52
+ try {
53
+ let lines;
54
+ switch (sub ?? "current") {
55
+ case "list":
56
+ lines = await handleList(registry, ws);
57
+ break;
58
+ case "current":
59
+ lines = await handleCurrent(registry, ws);
60
+ break;
61
+ case "switch":
62
+ lines = await handleSwitch(registry, ws, rest[0]);
63
+ await refreshPersonaChip(ctx, registry);
64
+ break;
65
+ case "reset":
66
+ lines = await handleReset(registry, ws);
67
+ await refreshPersonaChip(ctx, registry);
68
+ break;
69
+ case "install":
70
+ lines = await handleInstall(registry, rest[0]);
71
+ break;
72
+ case "uninstall":
73
+ lines = await handleUninstall(registry, rest[0], [ws]);
74
+ await refreshPersonaChip(ctx, registry);
75
+ break;
76
+ default:
77
+ ctx.ui.notify(`Unknown subcommand: ${sub}. Try: ${SUBCOMMANDS.join(", ")}`, "warning");
78
+ return;
79
+ }
80
+ ctx.ui.notify(lines.join("\n"), "info");
81
+ }
82
+ catch (err) {
83
+ ctx.ui.notify(err instanceof Error ? err.message : String(err), "error");
84
+ }
85
+ },
86
+ });
87
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmetech/otto",
3
- "version": "1.1.1",
3
+ "version": "1.2.4",
4
4
  "description": "Terminal-based developer chat assistant. Permanent hard fork of gsd-pi with LangFlow flow triggers, a flow builder, and optional gateway routing for compliance environments.",
5
5
  "keywords": [
6
6
  "ai",
@@ -65,10 +65,18 @@
65
65
  "build:pi-coding-agent": "npm run build:contracts && npm run build -w @otto/pi-coding-agent",
66
66
  "build:native-pkg": "npm run build -w @otto/native",
67
67
  "build:contracts": "npm run build -w @otto-build/contracts",
68
+ "build:coworker-types": "npm run build -w @otto/coworker-types",
69
+ "build:coworker-utils": "npm run build -w @otto/coworker-utils",
70
+ "build:coworker-memory": "npm run build -w @otto/coworker-memory",
71
+ "build:coworker-vault": "npm run build -w @otto/coworker-vault",
72
+ "build:coworker-artifacts": "npm run build -w @otto/coworker-artifacts",
73
+ "build:coworker-scratchpad": "npm run build -w @otto/coworker-scratchpad",
74
+ "build:coworker-persona": "npm run build -w @otto/coworker-persona",
75
+ "build:coworker": "npm run build:coworker-types && npm run build:coworker-utils && npm run build:coworker-memory && npm run build:coworker-vault && npm run build:coworker-artifacts && npm run build:coworker-scratchpad && npm run build:coworker-persona",
68
76
  "build:rpc-client": "npm run build -w @otto-build/rpc-client",
69
77
  "build:pi": "npm run build:contracts && npm run build:native-pkg && npm run build:pi-tui && npm run build:pi-ai && npm run build:pi-agent-core && npm run build:pi-coding-agent",
70
78
  "build:mcp-server": "npm run build -w @otto-build/mcp-server",
71
- "build:core": "npm run build:contracts && npm run build:pi && npm run build:rpc-client && npm run build:mcp-server && tsc && npm run copy-resources && npm run copy-themes && npm run copy-export-html",
79
+ "build:core": "npm run build:contracts && npm run build:coworker && npm run build:pi && npm run build:rpc-client && npm run build:mcp-server && tsc && npm run copy-resources && npm run copy-themes && npm run copy-export-html",
72
80
  "prebuild": "node scripts/sync-brand-colors.mjs && node scripts/sync-piconfig.mjs && node scripts/sync-release-notes.mjs && node scripts/generate-theme-const.mjs",
73
81
  "build": "npm run build:core",
74
82
  "sync-brand-colors": "node scripts/sync-brand-colors.mjs",
@@ -86,7 +94,7 @@
86
94
  "baseline:refactor:phase0": "npm run baseline:refactor:gate && node --import ./src/resources/extensions/workflow/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/workflow/tests/derive-state-db.test.ts src/resources/extensions/workflow/tests/single-writer-invariant.test.ts src/resources/extensions/workflow/tests/auto-recovery.test.ts src/resources/extensions/workflow/tests/auto-worktree-registry.test.ts",
87
95
  "legacy:cleanup:gate": "node scripts/legacy-cleanup-gate.mjs",
88
96
  "legacy:cleanup:evidence": "node scripts/legacy-cleanup-evidence.mjs",
89
- "test:unit:compiled": "node --import ./scripts/dist-test-resolve.mjs --experimental-test-isolation=process --test-reporter=./scripts/test-reporter-compact.mjs --test \"dist-test/src/tests/*.test.js\" \"dist-test/src/resources/extensions/workflow/tests/*.test.js\" \"dist-test/src/resources/extensions/workflow/tests/*.test.mjs\" \"dist-test/src/resources/extensions/shared/tests/*.test.js\" \"dist-test/src/resources/extensions/subagent/tests/*.test.js\" \"dist-test/src/resources/extensions/claude-code-cli/tests/*.test.js\" \"dist-test/src/resources/extensions/github-sync/tests/*.test.js\" \"dist-test/src/resources/extensions/universal-config/tests/*.test.js\" \"dist-test/src/resources/extensions/visual-brief/tests/*.test.js\" \"dist-test/src/resources/extensions/voice/tests/*.test.js\" \"dist-test/src/resources/extensions/mcp-client/tests/*.test.js\" \"dist-test/src/resources/extensions/remote-questions/tests/*.test.js\"",
97
+ "test:unit:compiled": "node --import ./scripts/dist-test-resolve.mjs --experimental-test-isolation=process --test-reporter=./scripts/test-reporter-compact.mjs --test \"dist-test/src/tests/*.test.js\" \"dist-test/src/resources/extensions/workflow/tests/*.test.js\" \"dist-test/src/resources/extensions/workflow/tests/*.test.mjs\" \"dist-test/src/resources/extensions/shared/tests/*.test.js\" \"dist-test/src/resources/extensions/subagent/tests/*.test.js\" \"dist-test/src/resources/extensions/claude-code-cli/tests/*.test.js\" \"dist-test/src/resources/extensions/github-sync/tests/*.test.js\" \"dist-test/src/resources/extensions/universal-config/tests/*.test.js\" \"dist-test/src/resources/extensions/visual-brief/tests/*.test.js\" \"dist-test/src/resources/extensions/voice/tests/*.test.js\" \"dist-test/src/resources/extensions/mcp-client/tests/*.test.js\" \"dist-test/src/resources/extensions/remote-questions/tests/*.test.js\" \"dist-test/src/resources/extensions/coworker-memory/*.test.js\" \"dist-test/src/resources/extensions/coworker-vault/*.test.js\" \"dist-test/src/resources/extensions/coworker-scratchpad/*.test.js\" \"dist-test/src/resources/extensions/coworker-artifacts/*.test.js\"",
90
98
  "test:unit": "npm run test:compile && npm run test:unit:compiled",
91
99
  "test:changed:src": "node scripts/verify-changed-src-tests.mjs",
92
100
  "test:packages": "npm run test:compile && npm run test:packages:compiled",
@@ -147,17 +155,22 @@
147
155
  "@sinclair/typebox": "^0.34.41",
148
156
  "ajv": "^8.17.1",
149
157
  "ajv-formats": "^3.0.1",
158
+ "axios": "^1.16.1",
150
159
  "chalk": "^5.6.2",
151
160
  "chokidar": "^5.0.0",
161
+ "date-fns": "^4.4.0",
152
162
  "diff": "^8.0.2",
153
163
  "echarts": "^5.6.0",
164
+ "exceljs": "^4.4.0",
154
165
  "extract-zip": "^2.0.1",
155
166
  "file-type": "^21.1.1",
156
167
  "glob": "^13.0.1",
157
168
  "hosted-git-info": "^9.0.2",
158
169
  "ignore": "^7.0.5",
170
+ "lodash": "^4.18.1",
159
171
  "marked": "^15.0.12",
160
172
  "minimatch": "^10.2.3",
173
+ "nodejs-polars": "^0.24.1",
161
174
  "openai": "^6.26.0",
162
175
  "picomatch": "^4.0.3",
163
176
  "playwright": "^1.58.2",
@@ -167,9 +180,11 @@
167
180
  "sql.js": "^1.14.1",
168
181
  "strip-ansi": "^7.1.0",
169
182
  "undici": "^7.24.2",
170
- "yaml": "^2.8.2"
183
+ "yaml": "^2.8.2",
184
+ "zod": "^4.4.3"
171
185
  },
172
186
  "devDependencies": {
187
+ "@types/lodash": "^4.17.24",
173
188
  "@types/node": "^24.12.0",
174
189
  "@types/picomatch": "^4.0.2",
175
190
  "@types/proper-lockfile": "^4.1.4",
@@ -181,13 +196,13 @@
181
196
  },
182
197
  "optionalDependencies": {
183
198
  "@anthropic-ai/claude-agent-sdk": "0.2.83",
199
+ "@cmetech/otto-engine-darwin-arm64": "1.2.4",
200
+ "@cmetech/otto-engine-darwin-x64": "1.2.4",
201
+ "@cmetech/otto-engine-linux-arm64-gnu": "1.2.4",
202
+ "@cmetech/otto-engine-linux-x64-gnu": "1.2.4",
203
+ "@cmetech/otto-engine-win32-x64-msvc": "1.2.4",
184
204
  "fsevents": "~2.3.3",
185
- "koffi": "^2.9.0",
186
- "@cmetech/otto-engine-darwin-arm64": "1.1.1",
187
- "@cmetech/otto-engine-darwin-x64": "1.1.1",
188
- "@cmetech/otto-engine-linux-arm64-gnu": "1.1.1",
189
- "@cmetech/otto-engine-linux-x64-gnu": "1.1.1",
190
- "@cmetech/otto-engine-win32-x64-msvc": "1.1.1"
205
+ "koffi": "^2.9.0"
191
206
  },
192
207
  "overrides": {
193
208
  "gaxios": "7.1.4",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otto-build/contracts",
3
- "version": "1.1.1",
3
+ "version": "1.2.4",
4
4
  "description": "Shared public contracts for OTTO workspace boundaries",
5
5
  "license": "MIT",
6
6
  "otto": {
@@ -0,0 +1,25 @@
1
+ import type { ArtifactHandle, ArtifactKind, FileWrite, TurnEntry } from './types.js';
2
+ export interface ArtifactStoreOptions {
3
+ workspaceDir: string;
4
+ now?: () => string;
5
+ }
6
+ export declare class ArtifactStore {
7
+ private readonly workspaceDir;
8
+ private readonly now;
9
+ constructor(opts: ArtifactStoreOptions);
10
+ private rootDir;
11
+ private existingSlugs;
12
+ private handleFor;
13
+ private atomicWrite;
14
+ private readMetadata;
15
+ private readProvenance;
16
+ private fileStats;
17
+ create(kind: ArtifactKind, name: string): Promise<ArtifactHandle>;
18
+ update(handle: ArtifactHandle, files: FileWrite[]): Promise<{
19
+ files_touched: string[];
20
+ }>;
21
+ recordTurn(handle: ArtifactHandle, entry: Omit<TurnEntry, '_schema' | 'ts'> & Partial<Pick<TurnEntry, 'ts'>>): Promise<void>;
22
+ list(): Promise<ArtifactHandle[]>;
23
+ get(slug: string): Promise<ArtifactHandle | null>;
24
+ remove(slug: string, confirm: true): Promise<void>;
25
+ }
@@ -0,0 +1,187 @@
1
+ // packages/coworker-artifacts/src/artifact-store.ts
2
+ import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync, } from 'node:fs';
3
+ import { join, normalize } from 'node:path';
4
+ import { ARTIFACT_KINDS } from './types.js';
5
+ import { ArtifactKindRejected, ArtifactNotFound, } from './errors.js';
6
+ import { deriveSlug, nextCollisionSlug } from './slug.js';
7
+ import { takeSnapshot, diffSnapshots } from './dir-snapshot.js';
8
+ import { renderReadme } from './readme-renderer.js';
9
+ const ARTIFACTS_DIR_NAME = '.otto/artifacts';
10
+ const PRIMARY_FILE = 'report.md';
11
+ export class ArtifactStore {
12
+ workspaceDir;
13
+ now;
14
+ constructor(opts) {
15
+ this.workspaceDir = opts.workspaceDir;
16
+ this.now = opts.now ?? (() => new Date().toISOString());
17
+ }
18
+ rootDir() {
19
+ return join(this.workspaceDir, ARTIFACTS_DIR_NAME);
20
+ }
21
+ existingSlugs() {
22
+ const root = this.rootDir();
23
+ if (!existsSync(root))
24
+ return new Set();
25
+ return new Set(readdirSync(root, { withFileTypes: true })
26
+ .filter(e => e.isDirectory())
27
+ .map(e => e.name));
28
+ }
29
+ handleFor(slug, kind, name) {
30
+ const dir = join(this.rootDir(), slug);
31
+ return {
32
+ slug, kind, name, dir,
33
+ uri: `artifact://${slug}`,
34
+ primaryPath: join(dir, PRIMARY_FILE),
35
+ metadataPath: join(dir, 'metadata.json'),
36
+ provenancePath: join(dir, 'provenance.json'),
37
+ readmePath: join(dir, 'README.md'),
38
+ };
39
+ }
40
+ atomicWrite(path, content, mode = 0o600) {
41
+ const tmp = `${path}.tmp`;
42
+ writeFileSync(tmp, content, { mode });
43
+ chmodSync(tmp, mode);
44
+ renameSync(tmp, path);
45
+ }
46
+ readMetadata(path) {
47
+ return JSON.parse(readFileSync(path, 'utf8'));
48
+ }
49
+ readProvenance(path) {
50
+ if (!existsSync(path))
51
+ return [];
52
+ try {
53
+ return JSON.parse(readFileSync(path, 'utf8'));
54
+ }
55
+ catch {
56
+ return [];
57
+ }
58
+ }
59
+ fileStats(dir) {
60
+ const snap = takeSnapshot(dir);
61
+ return [...snap.entries()]
62
+ .filter(([p]) => p !== 'metadata.json' && p !== 'provenance.json' && p !== 'README.md')
63
+ .map(([path, { sizeBytes }]) => ({ path, sizeBytes }));
64
+ }
65
+ async create(kind, name) {
66
+ if (!ARTIFACT_KINDS.includes(kind))
67
+ throw new ArtifactKindRejected(kind);
68
+ mkdirSync(this.rootDir(), { recursive: true, mode: 0o700 });
69
+ const base = deriveSlug(name);
70
+ const slug = nextCollisionSlug(base, this.existingSlugs());
71
+ const handle = this.handleFor(slug, kind, name);
72
+ // Use mkdirSync (non-recursive) on the artifact dir for race detection,
73
+ // but the parent is created above; if this throws EEXIST, retry with bumped slug.
74
+ try {
75
+ mkdirSync(handle.dir, { mode: 0o700 });
76
+ }
77
+ catch (err) {
78
+ if (err.code === 'EEXIST') {
79
+ // Race — recurse with refreshed slug set
80
+ return this.create(kind, name);
81
+ }
82
+ throw err;
83
+ }
84
+ const ts = this.now();
85
+ const meta = {
86
+ _schema: 1, slug, kind, name,
87
+ created_at: ts, last_updated_at: ts,
88
+ turn_count: 0, primary_file: PRIMARY_FILE,
89
+ uri: handle.uri,
90
+ };
91
+ this.atomicWrite(handle.metadataPath, JSON.stringify(meta, null, 2));
92
+ this.atomicWrite(handle.primaryPath, '');
93
+ this.atomicWrite(handle.provenancePath, '[]');
94
+ this.atomicWrite(handle.readmePath, renderReadme(meta, [], this.fileStats(handle.dir)));
95
+ return handle;
96
+ }
97
+ async update(handle, files) {
98
+ if (!existsSync(handle.dir))
99
+ throw new ArtifactNotFound(handle.slug);
100
+ for (const f of files) {
101
+ const normalized = normalize(f.path);
102
+ if (!f.path || !normalized || normalized === '.' ||
103
+ normalized.startsWith('..') || normalized.startsWith('/') ||
104
+ normalized.includes('\0')) {
105
+ throw new Error(`Bad FileWrite path: ${f.path}`);
106
+ }
107
+ }
108
+ const before = takeSnapshot(handle.dir);
109
+ for (const f of files) {
110
+ const abs = join(handle.dir, f.path);
111
+ mkdirSync(join(abs, '..'), { recursive: true, mode: 0o700 });
112
+ this.atomicWrite(abs, f.content);
113
+ }
114
+ const after = takeSnapshot(handle.dir);
115
+ const diff = diffSnapshots(before, after);
116
+ const filesTouched = [...new Set([...diff.added, ...diff.modified])]
117
+ .filter(p => p !== 'metadata.json' && p !== 'provenance.json' && p !== 'README.md')
118
+ .sort();
119
+ // Bump metadata (last_updated_at; turn_count incremented by recordTurn)
120
+ const meta = this.readMetadata(handle.metadataPath);
121
+ meta.last_updated_at = this.now();
122
+ this.atomicWrite(handle.metadataPath, JSON.stringify(meta, null, 2));
123
+ const prov = this.readProvenance(handle.provenancePath);
124
+ this.atomicWrite(handle.readmePath, renderReadme(meta, prov, this.fileStats(handle.dir)));
125
+ return { files_touched: filesTouched };
126
+ }
127
+ async recordTurn(handle, entry) {
128
+ if (!existsSync(handle.dir))
129
+ throw new ArtifactNotFound(handle.slug);
130
+ const prov = this.readProvenance(handle.provenancePath);
131
+ const ts = entry.ts ?? this.now();
132
+ const fullEntry = {
133
+ _schema: 1, ts,
134
+ action: entry.action,
135
+ turn_id: entry.turn_id,
136
+ user_prompt: entry.user_prompt,
137
+ files_touched: entry.files_touched,
138
+ ...(entry.agent_turn_id !== undefined ? { agent_turn_id: entry.agent_turn_id } : {}),
139
+ ...(entry.scratchpad_name !== undefined ? { scratchpad_name: entry.scratchpad_name } : {}),
140
+ };
141
+ prov.push(fullEntry);
142
+ this.atomicWrite(handle.provenancePath, JSON.stringify(prov, null, 2));
143
+ // Bump metadata
144
+ const meta = this.readMetadata(handle.metadataPath);
145
+ meta.turn_count = prov.length;
146
+ meta.last_updated_at = ts;
147
+ this.atomicWrite(handle.metadataPath, JSON.stringify(meta, null, 2));
148
+ this.atomicWrite(handle.readmePath, renderReadme(meta, prov, this.fileStats(handle.dir)));
149
+ }
150
+ async list() {
151
+ const root = this.rootDir();
152
+ if (!existsSync(root))
153
+ return [];
154
+ const handles = [];
155
+ for (const slug of this.existingSlugs()) {
156
+ const metaPath = join(root, slug, 'metadata.json');
157
+ if (!existsSync(metaPath))
158
+ continue;
159
+ try {
160
+ const meta = this.readMetadata(metaPath);
161
+ const h = this.handleFor(meta.slug, meta.kind, meta.name);
162
+ handles.push({ handle: h, created_at: meta.created_at });
163
+ }
164
+ catch { /* skip malformed */ }
165
+ }
166
+ handles.sort((a, b) => b.created_at.localeCompare(a.created_at));
167
+ return handles.map(x => x.handle);
168
+ }
169
+ async get(slug) {
170
+ const metaPath = join(this.rootDir(), slug, 'metadata.json');
171
+ if (!existsSync(metaPath))
172
+ return null;
173
+ const meta = this.readMetadata(metaPath);
174
+ return this.handleFor(meta.slug, meta.kind, meta.name);
175
+ }
176
+ async remove(slug, confirm) {
177
+ if (confirm !== true)
178
+ throw new Error(`/artifacts remove requires --confirm`);
179
+ if (!slug || slug.includes('/') || slug.includes('..') || slug === '.') {
180
+ throw new ArtifactNotFound(slug);
181
+ }
182
+ const dir = join(this.rootDir(), slug);
183
+ if (!existsSync(dir))
184
+ throw new ArtifactNotFound(slug);
185
+ rmSync(dir, { recursive: true, force: true });
186
+ }
187
+ }
@@ -0,0 +1,7 @@
1
+ import type { DirSnapshot } from './types.js';
2
+ export declare function takeSnapshot(dir: string): DirSnapshot;
3
+ export declare function diffSnapshots(before: DirSnapshot, after: DirSnapshot): {
4
+ added: string[];
5
+ modified: string[];
6
+ removed: string[];
7
+ };
@@ -0,0 +1,54 @@
1
+ // packages/coworker-artifacts/src/dir-snapshot.ts
2
+ import { existsSync, readdirSync, statSync } from 'node:fs';
3
+ import { join, relative, sep } from 'node:path';
4
+ export function takeSnapshot(dir) {
5
+ const out = new Map();
6
+ if (!existsSync(dir))
7
+ return out;
8
+ walk(dir, dir, out);
9
+ return out;
10
+ }
11
+ function walk(root, current, out) {
12
+ let entries;
13
+ try {
14
+ entries = readdirSync(current, { withFileTypes: true });
15
+ }
16
+ catch {
17
+ return;
18
+ }
19
+ for (const entry of entries) {
20
+ const abs = join(current, entry.name);
21
+ if (entry.isDirectory()) {
22
+ walk(root, abs, out);
23
+ }
24
+ else if (entry.isFile()) {
25
+ const stat = statSync(abs, { bigint: true });
26
+ const rel = relative(root, abs).split(sep).join('/');
27
+ out.set(rel, {
28
+ mtimeNs: stat.mtimeNs,
29
+ sizeBytes: Number(stat.size),
30
+ });
31
+ }
32
+ }
33
+ }
34
+ export function diffSnapshots(before, after) {
35
+ const added = [];
36
+ const modified = [];
37
+ const removed = [];
38
+ for (const [path, a] of after) {
39
+ const b = before.get(path);
40
+ if (!b)
41
+ added.push(path);
42
+ else if (b.mtimeNs !== a.mtimeNs || b.sizeBytes !== a.sizeBytes)
43
+ modified.push(path);
44
+ }
45
+ for (const path of before.keys()) {
46
+ if (!after.has(path))
47
+ removed.push(path);
48
+ }
49
+ return {
50
+ added: added.sort(),
51
+ modified: modified.sort(),
52
+ removed: removed.sort(),
53
+ };
54
+ }
@@ -0,0 +1,18 @@
1
+ export declare class ArtifactNotFound extends Error {
2
+ readonly slug: string;
3
+ constructor(slug: string);
4
+ }
5
+ export declare class ArtifactKindRejected extends Error {
6
+ readonly kind: string;
7
+ constructor(kind: string);
8
+ }
9
+ export declare class ArtifactUriMalformed extends Error {
10
+ readonly uri: string;
11
+ readonly reason: string;
12
+ constructor(uri: string, reason: string);
13
+ }
14
+ export declare class ArtifactSlugCollision extends Error {
15
+ readonly base: string;
16
+ readonly attempts: number;
17
+ constructor(base: string, attempts: number);
18
+ }
@@ -0,0 +1,37 @@
1
+ // packages/coworker-artifacts/src/errors.ts
2
+ export class ArtifactNotFound extends Error {
3
+ slug;
4
+ constructor(slug) {
5
+ super(`Artifact not found: ${slug}. /artifacts list to see available.`);
6
+ this.slug = slug;
7
+ this.name = 'ArtifactNotFound';
8
+ }
9
+ }
10
+ export class ArtifactKindRejected extends Error {
11
+ kind;
12
+ constructor(kind) {
13
+ super(`Artifact kind '${kind}' is not supported. v1 ships only 'report'.`);
14
+ this.kind = kind;
15
+ this.name = 'ArtifactKindRejected';
16
+ }
17
+ }
18
+ export class ArtifactUriMalformed extends Error {
19
+ uri;
20
+ reason;
21
+ constructor(uri, reason) {
22
+ super(`Bad artifact URI ${uri}: ${reason}.`);
23
+ this.uri = uri;
24
+ this.reason = reason;
25
+ this.name = 'ArtifactUriMalformed';
26
+ }
27
+ }
28
+ export class ArtifactSlugCollision extends Error {
29
+ base;
30
+ attempts;
31
+ constructor(base, attempts) {
32
+ super(`Slug collision: '${base}' has ${attempts} colliding suffixes (-2…-${attempts + 1}). Pick a different name.`);
33
+ this.base = base;
34
+ this.attempts = attempts;
35
+ this.name = 'ArtifactSlugCollision';
36
+ }
37
+ }
@@ -0,0 +1,7 @@
1
+ export * from './types.js';
2
+ export * from './errors.js';
3
+ export * from './slug.js';
4
+ export * from './dir-snapshot.js';
5
+ export * from './resolve-uri.js';
6
+ export * from './readme-renderer.js';
7
+ export * from './artifact-store.js';
@@ -0,0 +1,7 @@
1
+ export * from './types.js';
2
+ export * from './errors.js';
3
+ export * from './slug.js';
4
+ export * from './dir-snapshot.js';
5
+ export * from './resolve-uri.js';
6
+ export * from './readme-renderer.js';
7
+ export * from './artifact-store.js';