@cmetech/otto 1.1.1 → 1.2.5

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 (433) 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-artifacts/artifacts-command.js +31 -0
  7. package/dist/resources/extensions/coworker-artifacts/artifacts-singleton.js +17 -0
  8. package/dist/resources/extensions/coworker-artifacts/extension-manifest.json +13 -0
  9. package/dist/resources/extensions/coworker-artifacts/index.js +125 -0
  10. package/dist/resources/extensions/coworker-artifacts/list-tool.js +27 -0
  11. package/dist/resources/extensions/coworker-artifacts/open-tool.js +25 -0
  12. package/dist/resources/extensions/coworker-memory/extension-manifest.json +13 -0
  13. package/dist/resources/extensions/coworker-memory/index.js +219 -0
  14. package/dist/resources/extensions/coworker-memory/memorize-tool.js +10 -0
  15. package/dist/resources/extensions/coworker-memory/memory-command.js +157 -0
  16. package/dist/resources/extensions/coworker-memory/memory-singleton.js +55 -0
  17. package/dist/resources/extensions/coworker-memory/recall-tool.js +18 -0
  18. package/dist/resources/extensions/coworker-memory/session-hooks.js +45 -0
  19. package/dist/resources/extensions/coworker-scratchpad/attach-banners.js +53 -0
  20. package/dist/resources/extensions/coworker-scratchpad/extension-manifest.json +13 -0
  21. package/dist/resources/extensions/coworker-scratchpad/format-age.js +9 -0
  22. package/dist/resources/extensions/coworker-scratchpad/helpers.js +38 -0
  23. package/dist/resources/extensions/coworker-scratchpad/index.js +199 -0
  24. package/dist/resources/extensions/coworker-scratchpad/mime-bundle.js +20 -0
  25. package/dist/resources/extensions/coworker-scratchpad/scratchpad-tool.js +118 -0
  26. package/dist/resources/extensions/coworker-scratchpad/session-sidecar.js +60 -0
  27. package/dist/resources/extensions/coworker-scratchpad/sp-command.js +597 -0
  28. package/dist/resources/extensions/coworker-scratchpad/workspace-pointer.js +41 -0
  29. package/dist/resources/extensions/coworker-scratchpad/workspace-root.js +17 -0
  30. package/dist/resources/extensions/coworker-vault/audit-command.js +35 -0
  31. package/dist/resources/extensions/coworker-vault/connect-command.js +42 -0
  32. package/dist/resources/extensions/coworker-vault/datasource-command.js +50 -0
  33. package/dist/resources/extensions/coworker-vault/extension-manifest.json +12 -0
  34. package/dist/resources/extensions/coworker-vault/index.js +171 -0
  35. package/dist/resources/extensions/coworker-vault/test-helpers.js +86 -0
  36. package/dist/resources/extensions/coworker-vault/vault-singleton.js +24 -0
  37. package/dist/resources/extensions/otto/commands/release-notes/_data.js +83 -0
  38. package/dist/resources/extensions/otto/commands/release-notes/command.js +15 -4
  39. package/dist/resources/extensions/otto/index.js +31 -6
  40. package/dist/resources/extensions/shared/coworker-paths.js +8 -0
  41. package/dist/resources/extensions/slash-commands/{audit.js → audit-codebase.js} +4 -4
  42. package/dist/resources/extensions/slash-commands/extension-manifest.json +1 -1
  43. package/dist/resources/extensions/slash-commands/index.js +2 -2
  44. package/dist/resources/extensions/subagent/index.js +8 -1
  45. package/dist/resources/extensions/subagent/launch.js +37 -5
  46. package/dist/resources/extensions/subagent/run-store.js +1 -0
  47. package/dist/resources/extensions/workflow/bootstrap/register-extension.js +2 -0
  48. package/dist/resources/extensions/workflow/bootstrap/register-hooks.js +10 -0
  49. package/dist/resources/extensions/workflow/health-widget-core.js +1 -1
  50. package/dist/resources/extensions/workflow/persona-status.js +87 -0
  51. package/package.json +26 -10
  52. package/packages/contracts/package.json +1 -1
  53. package/packages/coworker-artifacts/dist/artifact-store.d.ts +25 -0
  54. package/packages/coworker-artifacts/dist/artifact-store.js +187 -0
  55. package/packages/coworker-artifacts/dist/dir-snapshot.d.ts +7 -0
  56. package/packages/coworker-artifacts/dist/dir-snapshot.js +54 -0
  57. package/packages/coworker-artifacts/dist/errors.d.ts +18 -0
  58. package/packages/coworker-artifacts/dist/errors.js +37 -0
  59. package/packages/coworker-artifacts/dist/index.d.ts +7 -0
  60. package/packages/coworker-artifacts/dist/index.js +7 -0
  61. package/packages/coworker-artifacts/dist/readme-renderer.d.ts +5 -0
  62. package/packages/coworker-artifacts/dist/readme-renderer.js +47 -0
  63. package/packages/coworker-artifacts/dist/resolve-uri.d.ts +3 -0
  64. package/packages/coworker-artifacts/dist/resolve-uri.js +29 -0
  65. package/packages/coworker-artifacts/dist/slug.d.ts +4 -0
  66. package/packages/coworker-artifacts/dist/slug.js +32 -0
  67. package/packages/coworker-artifacts/dist/types.d.ts +52 -0
  68. package/packages/coworker-artifacts/dist/types.js +1 -0
  69. package/packages/coworker-artifacts/package.json +20 -0
  70. package/packages/coworker-artifacts/src/artifact-store.test.ts +188 -0
  71. package/packages/coworker-artifacts/src/artifact-store.ts +206 -0
  72. package/packages/coworker-artifacts/src/artifacts-integration.test.ts +109 -0
  73. package/packages/coworker-artifacts/src/dir-snapshot.test.ts +71 -0
  74. package/packages/coworker-artifacts/src/dir-snapshot.ts +52 -0
  75. package/packages/coworker-artifacts/src/errors.test.ts +37 -0
  76. package/packages/coworker-artifacts/src/errors.ts +28 -0
  77. package/packages/coworker-artifacts/src/index.test.ts +22 -0
  78. package/packages/coworker-artifacts/src/index.ts +7 -0
  79. package/packages/coworker-artifacts/src/readme-renderer.test.ts +72 -0
  80. package/packages/coworker-artifacts/src/readme-renderer.ts +56 -0
  81. package/packages/coworker-artifacts/src/resolve-uri.test.ts +46 -0
  82. package/packages/coworker-artifacts/src/resolve-uri.ts +29 -0
  83. package/packages/coworker-artifacts/src/slug.test.ts +47 -0
  84. package/packages/coworker-artifacts/src/slug.ts +31 -0
  85. package/packages/coworker-artifacts/src/types.ts +61 -0
  86. package/packages/coworker-artifacts/tsconfig.json +15 -0
  87. package/packages/coworker-artifacts/tsconfig.publish.json +4 -0
  88. package/packages/coworker-memory/dist/context-injection.d.ts +9 -0
  89. package/packages/coworker-memory/dist/context-injection.js +41 -0
  90. package/packages/coworker-memory/dist/errors.d.ts +25 -0
  91. package/packages/coworker-memory/dist/errors.js +51 -0
  92. package/packages/coworker-memory/dist/index.d.ts +12 -0
  93. package/packages/coworker-memory/dist/index.js +12 -0
  94. package/packages/coworker-memory/dist/layer-a-store.d.ts +16 -0
  95. package/packages/coworker-memory/dist/layer-a-store.js +78 -0
  96. package/packages/coworker-memory/dist/local-sqlite-backend.d.ts +28 -0
  97. package/packages/coworker-memory/dist/local-sqlite-backend.js +167 -0
  98. package/packages/coworker-memory/dist/memory-backend.d.ts +14 -0
  99. package/packages/coworker-memory/dist/memory-backend.js +1 -0
  100. package/packages/coworker-memory/dist/memory-recorder.d.ts +50 -0
  101. package/packages/coworker-memory/dist/memory-recorder.js +69 -0
  102. package/packages/coworker-memory/dist/migrations/001-init.sql +38 -0
  103. package/packages/coworker-memory/dist/migrations/002-artifact-kind.sql +50 -0
  104. package/packages/coworker-memory/dist/paste-detector.d.ts +5 -0
  105. package/packages/coworker-memory/dist/paste-detector.js +14 -0
  106. package/packages/coworker-memory/dist/persona-seed.d.ts +10 -0
  107. package/packages/coworker-memory/dist/persona-seed.js +38 -0
  108. package/packages/coworker-memory/dist/recall-formatter.d.ts +2 -0
  109. package/packages/coworker-memory/dist/recall-formatter.js +14 -0
  110. package/packages/coworker-memory/dist/scope-resolver.d.ts +9 -0
  111. package/packages/coworker-memory/dist/scope-resolver.js +10 -0
  112. package/packages/coworker-memory/dist/types.d.ts +51 -0
  113. package/packages/coworker-memory/dist/types.js +2 -0
  114. package/packages/coworker-memory/dist/workspace-id.d.ts +3 -0
  115. package/packages/coworker-memory/dist/workspace-id.js +54 -0
  116. package/packages/coworker-memory/package.json +35 -0
  117. package/packages/coworker-memory/src/activator-integration.test.ts +141 -0
  118. package/packages/coworker-memory/src/context-injection.test.ts +72 -0
  119. package/packages/coworker-memory/src/context-injection.ts +57 -0
  120. package/packages/coworker-memory/src/errors.test.ts +45 -0
  121. package/packages/coworker-memory/src/errors.ts +42 -0
  122. package/packages/coworker-memory/src/index.test.ts +21 -0
  123. package/packages/coworker-memory/src/index.ts +12 -0
  124. package/packages/coworker-memory/src/layer-a-store.test.ts +85 -0
  125. package/packages/coworker-memory/src/layer-a-store.ts +88 -0
  126. package/packages/coworker-memory/src/local-sqlite-backend.test.ts +110 -0
  127. package/packages/coworker-memory/src/local-sqlite-backend.ts +185 -0
  128. package/packages/coworker-memory/src/memory-backend.ts +10 -0
  129. package/packages/coworker-memory/src/memory-integration.test.ts +89 -0
  130. package/packages/coworker-memory/src/memory-recorder.test.ts +101 -0
  131. package/packages/coworker-memory/src/memory-recorder.ts +95 -0
  132. package/packages/coworker-memory/src/migrations/001-init.sql +38 -0
  133. package/packages/coworker-memory/src/migrations/002-artifact-kind.sql +50 -0
  134. package/packages/coworker-memory/src/paste-detector.test.ts +23 -0
  135. package/packages/coworker-memory/src/paste-detector.ts +18 -0
  136. package/packages/coworker-memory/src/persona-seed.test.ts +57 -0
  137. package/packages/coworker-memory/src/persona-seed.ts +46 -0
  138. package/packages/coworker-memory/src/recall-formatter.test.ts +34 -0
  139. package/packages/coworker-memory/src/recall-formatter.ts +15 -0
  140. package/packages/coworker-memory/src/scope-resolver.test.ts +23 -0
  141. package/packages/coworker-memory/src/scope-resolver.ts +18 -0
  142. package/packages/coworker-memory/src/types.ts +61 -0
  143. package/packages/coworker-memory/src/workspace-id.test.ts +48 -0
  144. package/packages/coworker-memory/src/workspace-id.ts +56 -0
  145. package/packages/coworker-memory/tsconfig.json +15 -0
  146. package/packages/coworker-memory/tsconfig.publish.json +4 -0
  147. package/packages/coworker-persona/dist/commands.d.ts +7 -0
  148. package/packages/coworker-persona/dist/commands.js +35 -0
  149. package/packages/coworker-persona/dist/defaults/manifest.yaml +12 -0
  150. package/packages/coworker-persona/dist/defaults/steering/identity.md +3 -0
  151. package/packages/coworker-persona/dist/index.d.ts +3 -0
  152. package/packages/coworker-persona/dist/index.js +3 -0
  153. package/packages/coworker-persona/dist/manifest.d.ts +24 -0
  154. package/packages/coworker-persona/dist/manifest.js +21 -0
  155. package/packages/coworker-persona/dist/registry.d.ts +22 -0
  156. package/packages/coworker-persona/dist/registry.js +142 -0
  157. package/packages/coworker-persona/package.json +28 -0
  158. package/packages/coworker-persona/scripts/copy-defaults.cjs +17 -0
  159. package/packages/coworker-persona/src/commands.ts +47 -0
  160. package/packages/coworker-persona/src/defaults/manifest.yaml +12 -0
  161. package/packages/coworker-persona/src/defaults/steering/identity.md +3 -0
  162. package/packages/coworker-persona/src/index.ts +3 -0
  163. package/packages/coworker-persona/src/manifest.test.ts +67 -0
  164. package/packages/coworker-persona/src/manifest.ts +49 -0
  165. package/packages/coworker-persona/src/registry.test.ts +89 -0
  166. package/packages/coworker-persona/src/registry.ts +147 -0
  167. package/packages/coworker-persona/tsconfig.json +15 -0
  168. package/packages/coworker-persona/tsconfig.publish.json +4 -0
  169. package/packages/coworker-scratchpad/dist/cell-archive.d.ts +39 -0
  170. package/packages/coworker-scratchpad/dist/cell-archive.js +77 -0
  171. package/packages/coworker-scratchpad/dist/cell-tree.d.ts +14 -0
  172. package/packages/coworker-scratchpad/dist/cell-tree.js +72 -0
  173. package/packages/coworker-scratchpad/dist/child-process-runtime.d.ts +129 -0
  174. package/packages/coworker-scratchpad/dist/child-process-runtime.js +427 -0
  175. package/packages/coworker-scratchpad/dist/collector-registry.d.ts +12 -0
  176. package/packages/coworker-scratchpad/dist/collector-registry.js +29 -0
  177. package/packages/coworker-scratchpad/dist/detect-kind.d.ts +3 -0
  178. package/packages/coworker-scratchpad/dist/detect-kind.js +19 -0
  179. package/packages/coworker-scratchpad/dist/file-collector.d.ts +15 -0
  180. package/packages/coworker-scratchpad/dist/file-collector.js +99 -0
  181. package/packages/coworker-scratchpad/dist/index.d.ts +13 -0
  182. package/packages/coworker-scratchpad/dist/index.js +13 -0
  183. package/packages/coworker-scratchpad/dist/kernel-bindings.d.ts +49 -0
  184. package/packages/coworker-scratchpad/dist/kernel-bindings.js +220 -0
  185. package/packages/coworker-scratchpad/dist/kernel-entry.d.ts +1 -0
  186. package/packages/coworker-scratchpad/dist/kernel-entry.js +355 -0
  187. package/packages/coworker-scratchpad/dist/kernel-protocol.d.ts +171 -0
  188. package/packages/coworker-scratchpad/dist/kernel-protocol.js +48 -0
  189. package/packages/coworker-scratchpad/dist/kernel-spawn.d.ts +3 -0
  190. package/packages/coworker-scratchpad/dist/kernel-spawn.js +54 -0
  191. package/packages/coworker-scratchpad/dist/namespace-codec.d.ts +22 -0
  192. package/packages/coworker-scratchpad/dist/namespace-codec.js +61 -0
  193. package/packages/coworker-scratchpad/dist/scratchpad-lock.d.ts +24 -0
  194. package/packages/coworker-scratchpad/dist/scratchpad-lock.js +86 -0
  195. package/packages/coworker-scratchpad/dist/scratchpad-manager.d.ts +193 -0
  196. package/packages/coworker-scratchpad/dist/scratchpad-manager.js +866 -0
  197. package/packages/coworker-scratchpad/dist/staleness-banner.d.ts +12 -0
  198. package/packages/coworker-scratchpad/dist/staleness-banner.js +27 -0
  199. package/packages/coworker-scratchpad/package.json +31 -0
  200. package/packages/coworker-scratchpad/src/cell-archive.test.ts +150 -0
  201. package/packages/coworker-scratchpad/src/cell-archive.ts +97 -0
  202. package/packages/coworker-scratchpad/src/cell-tree.test.ts +105 -0
  203. package/packages/coworker-scratchpad/src/cell-tree.ts +90 -0
  204. package/packages/coworker-scratchpad/src/child-process-runtime.test.ts +413 -0
  205. package/packages/coworker-scratchpad/src/child-process-runtime.ts +493 -0
  206. package/packages/coworker-scratchpad/src/collector-registry.test.ts +69 -0
  207. package/packages/coworker-scratchpad/src/collector-registry.ts +33 -0
  208. package/packages/coworker-scratchpad/src/detect-kind.test.ts +33 -0
  209. package/packages/coworker-scratchpad/src/detect-kind.ts +22 -0
  210. package/packages/coworker-scratchpad/src/file-collector.test.ts +109 -0
  211. package/packages/coworker-scratchpad/src/file-collector.ts +114 -0
  212. package/packages/coworker-scratchpad/src/index.ts +74 -0
  213. package/packages/coworker-scratchpad/src/kernel-bindings.test.ts +188 -0
  214. package/packages/coworker-scratchpad/src/kernel-bindings.ts +279 -0
  215. package/packages/coworker-scratchpad/src/kernel-entry.test.ts +123 -0
  216. package/packages/coworker-scratchpad/src/kernel-entry.ts +390 -0
  217. package/packages/coworker-scratchpad/src/kernel-protocol.test.ts +105 -0
  218. package/packages/coworker-scratchpad/src/kernel-protocol.ts +230 -0
  219. package/packages/coworker-scratchpad/src/kernel-spawn.test.ts +60 -0
  220. package/packages/coworker-scratchpad/src/kernel-spawn.ts +54 -0
  221. package/packages/coworker-scratchpad/src/namespace-codec.test.ts +102 -0
  222. package/packages/coworker-scratchpad/src/namespace-codec.ts +90 -0
  223. package/packages/coworker-scratchpad/src/scratchpad-lock.test.ts +98 -0
  224. package/packages/coworker-scratchpad/src/scratchpad-lock.ts +102 -0
  225. package/packages/coworker-scratchpad/src/scratchpad-manager.test.ts +1343 -0
  226. package/packages/coworker-scratchpad/src/scratchpad-manager.ts +891 -0
  227. package/packages/coworker-scratchpad/src/staleness-banner.test.ts +53 -0
  228. package/packages/coworker-scratchpad/src/staleness-banner.ts +33 -0
  229. package/packages/coworker-scratchpad/src/vault-integration.test.ts +221 -0
  230. package/packages/coworker-scratchpad/tsconfig.json +15 -0
  231. package/packages/coworker-scratchpad/tsconfig.publish.json +4 -0
  232. package/packages/coworker-types/dist/artifacts.d.ts +31 -0
  233. package/packages/coworker-types/dist/artifacts.js +2 -0
  234. package/packages/coworker-types/dist/contracts.d.ts +32 -0
  235. package/packages/coworker-types/dist/contracts.js +1 -0
  236. package/packages/coworker-types/dist/index.d.ts +5 -0
  237. package/packages/coworker-types/dist/index.js +5 -0
  238. package/packages/coworker-types/dist/memory.d.ts +61 -0
  239. package/packages/coworker-types/dist/memory.js +3 -0
  240. package/packages/coworker-types/dist/scratchpad.d.ts +43 -0
  241. package/packages/coworker-types/dist/scratchpad.js +2 -0
  242. package/packages/coworker-types/dist/vault.d.ts +34 -0
  243. package/packages/coworker-types/dist/vault.js +2 -0
  244. package/packages/coworker-types/package.json +24 -0
  245. package/packages/coworker-types/src/artifacts.test.ts +52 -0
  246. package/packages/coworker-types/src/artifacts.ts +35 -0
  247. package/packages/coworker-types/src/contracts.test.ts +43 -0
  248. package/packages/coworker-types/src/contracts.ts +36 -0
  249. package/packages/coworker-types/src/index.ts +5 -0
  250. package/packages/coworker-types/src/memory.test.ts +50 -0
  251. package/packages/coworker-types/src/memory.ts +79 -0
  252. package/packages/coworker-types/src/scratchpad.test.ts +46 -0
  253. package/packages/coworker-types/src/scratchpad.ts +51 -0
  254. package/packages/coworker-types/src/smoke.test.ts +34 -0
  255. package/packages/coworker-types/src/vault.test.ts +49 -0
  256. package/packages/coworker-types/src/vault.ts +40 -0
  257. package/packages/coworker-types/tsconfig.json +15 -0
  258. package/packages/coworker-types/tsconfig.publish.json +4 -0
  259. package/packages/coworker-utils/dist/audit-log.d.ts +34 -0
  260. package/packages/coworker-utils/dist/audit-log.js +88 -0
  261. package/packages/coworker-utils/dist/index.d.ts +6 -0
  262. package/packages/coworker-utils/dist/index.js +6 -0
  263. package/packages/coworker-utils/dist/lease.d.ts +7 -0
  264. package/packages/coworker-utils/dist/lease.js +67 -0
  265. package/packages/coworker-utils/dist/logger.d.ts +13 -0
  266. package/packages/coworker-utils/dist/logger.js +26 -0
  267. package/packages/coworker-utils/dist/migration-runner.d.ts +7 -0
  268. package/packages/coworker-utils/dist/migration-runner.js +36 -0
  269. package/packages/coworker-utils/dist/ndjson-channel.d.ts +3 -0
  270. package/packages/coworker-utils/dist/ndjson-channel.js +38 -0
  271. package/packages/coworker-utils/dist/secret-scanner.d.ts +10 -0
  272. package/packages/coworker-utils/dist/secret-scanner.js +42 -0
  273. package/packages/coworker-utils/package.json +24 -0
  274. package/packages/coworker-utils/src/audit-log.test.ts +140 -0
  275. package/packages/coworker-utils/src/audit-log.ts +107 -0
  276. package/packages/coworker-utils/src/index.ts +6 -0
  277. package/packages/coworker-utils/src/lease.test.ts +64 -0
  278. package/packages/coworker-utils/src/lease.ts +76 -0
  279. package/packages/coworker-utils/src/logger.test.ts +50 -0
  280. package/packages/coworker-utils/src/logger.ts +45 -0
  281. package/packages/coworker-utils/src/migration-runner.test.ts +65 -0
  282. package/packages/coworker-utils/src/migration-runner.ts +50 -0
  283. package/packages/coworker-utils/src/ndjson-channel.test.ts +76 -0
  284. package/packages/coworker-utils/src/ndjson-channel.ts +41 -0
  285. package/packages/coworker-utils/src/secret-scanner.test.ts +61 -0
  286. package/packages/coworker-utils/src/secret-scanner.ts +56 -0
  287. package/packages/coworker-utils/tsconfig.json +15 -0
  288. package/packages/coworker-utils/tsconfig.publish.json +4 -0
  289. package/packages/coworker-vault/dist/data-vault.d.ts +41 -0
  290. package/packages/coworker-vault/dist/data-vault.js +223 -0
  291. package/packages/coworker-vault/dist/engine-registry.d.ts +34 -0
  292. package/packages/coworker-vault/dist/engine-registry.js +90 -0
  293. package/packages/coworker-vault/dist/engines/jira.yaml +17 -0
  294. package/packages/coworker-vault/dist/errors.d.ts +28 -0
  295. package/packages/coworker-vault/dist/errors.js +57 -0
  296. package/packages/coworker-vault/dist/index.d.ts +6 -0
  297. package/packages/coworker-vault/dist/index.js +6 -0
  298. package/packages/coworker-vault/dist/injector.d.ts +19 -0
  299. package/packages/coworker-vault/dist/injector.js +77 -0
  300. package/packages/coworker-vault/dist/types.d.ts +28 -0
  301. package/packages/coworker-vault/dist/types.js +1 -0
  302. package/packages/coworker-vault/dist/vault-keep.d.ts +4 -0
  303. package/packages/coworker-vault/dist/vault-keep.js +21 -0
  304. package/packages/coworker-vault/package.json +29 -0
  305. package/packages/coworker-vault/src/data-vault.test.ts +199 -0
  306. package/packages/coworker-vault/src/data-vault.ts +257 -0
  307. package/packages/coworker-vault/src/engine-registry.test.ts +120 -0
  308. package/packages/coworker-vault/src/engine-registry.ts +107 -0
  309. package/packages/coworker-vault/src/engines/jira.yaml +17 -0
  310. package/packages/coworker-vault/src/errors.test.ts +58 -0
  311. package/packages/coworker-vault/src/errors.ts +50 -0
  312. package/packages/coworker-vault/src/index.test.ts +24 -0
  313. package/packages/coworker-vault/src/index.ts +6 -0
  314. package/packages/coworker-vault/src/injector.test.ts +109 -0
  315. package/packages/coworker-vault/src/injector.ts +98 -0
  316. package/packages/coworker-vault/src/types.ts +33 -0
  317. package/packages/coworker-vault/src/vault-keep.test.ts +49 -0
  318. package/packages/coworker-vault/src/vault-keep.ts +31 -0
  319. package/packages/coworker-vault/tsconfig.json +15 -0
  320. package/packages/coworker-vault/tsconfig.publish.json +4 -0
  321. package/packages/daemon/package.json +3 -3
  322. package/packages/mcp-server/package.json +3 -3
  323. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  324. package/packages/native/package.json +1 -1
  325. package/packages/native/tsconfig.tsbuildinfo +1 -1
  326. package/packages/pi-agent-core/package.json +1 -1
  327. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  328. package/packages/pi-ai/package.json +1 -1
  329. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  330. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +6 -1
  331. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  332. package/packages/pi-coding-agent/dist/core/extensions/runner.js +22 -3
  333. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  334. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +11 -0
  335. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  336. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.d.ts +47 -0
  337. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.d.ts.map +1 -0
  338. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.js +107 -0
  339. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.js.map +1 -0
  340. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.regression.test.d.ts +19 -0
  341. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.regression.test.d.ts.map +1 -0
  342. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.regression.test.js +121 -0
  343. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.regression.test.js.map +1 -0
  344. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  345. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +17 -1
  346. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  347. package/packages/pi-coding-agent/package.json +2 -2
  348. package/packages/pi-coding-agent/src/core/extensions/runner.ts +22 -3
  349. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +11 -0
  350. package/packages/pi-coding-agent/src/modes/rpc/raw-stdout.regression.test.ts +129 -0
  351. package/packages/pi-coding-agent/src/modes/rpc/raw-stdout.ts +117 -0
  352. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +18 -1
  353. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  354. package/packages/pi-tui/package.json +1 -1
  355. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  356. package/packages/rpc-client/package.json +2 -2
  357. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  358. package/pkg/package.json +1 -1
  359. package/scripts/install.js +6 -5
  360. package/src/resources/extensions/coworker-artifacts/artifacts-command.test.ts +54 -0
  361. package/src/resources/extensions/coworker-artifacts/artifacts-command.ts +43 -0
  362. package/src/resources/extensions/coworker-artifacts/artifacts-singleton.test.ts +25 -0
  363. package/src/resources/extensions/coworker-artifacts/artifacts-singleton.ts +29 -0
  364. package/src/resources/extensions/coworker-artifacts/extension-manifest.json +13 -0
  365. package/src/resources/extensions/coworker-artifacts/index.test.ts +46 -0
  366. package/src/resources/extensions/coworker-artifacts/index.ts +154 -0
  367. package/src/resources/extensions/coworker-artifacts/list-tool.test.ts +29 -0
  368. package/src/resources/extensions/coworker-artifacts/list-tool.ts +53 -0
  369. package/src/resources/extensions/coworker-artifacts/open-tool.test.ts +30 -0
  370. package/src/resources/extensions/coworker-artifacts/open-tool.ts +43 -0
  371. package/src/resources/extensions/coworker-memory/extension-manifest.json +13 -0
  372. package/src/resources/extensions/coworker-memory/index.test.ts +137 -0
  373. package/src/resources/extensions/coworker-memory/index.ts +257 -0
  374. package/src/resources/extensions/coworker-memory/memorize-tool.test.ts +41 -0
  375. package/src/resources/extensions/coworker-memory/memorize-tool.ts +20 -0
  376. package/src/resources/extensions/coworker-memory/memory-command.test.ts +134 -0
  377. package/src/resources/extensions/coworker-memory/memory-command.ts +131 -0
  378. package/src/resources/extensions/coworker-memory/memory-singleton.test.ts +41 -0
  379. package/src/resources/extensions/coworker-memory/memory-singleton.ts +89 -0
  380. package/src/resources/extensions/coworker-memory/recall-tool.test.ts +50 -0
  381. package/src/resources/extensions/coworker-memory/recall-tool.ts +35 -0
  382. package/src/resources/extensions/coworker-memory/session-hooks.test.ts +77 -0
  383. package/src/resources/extensions/coworker-memory/session-hooks.ts +61 -0
  384. package/src/resources/extensions/coworker-scratchpad/attach-banners.test.ts +124 -0
  385. package/src/resources/extensions/coworker-scratchpad/attach-banners.ts +67 -0
  386. package/src/resources/extensions/coworker-scratchpad/extension-manifest.json +13 -0
  387. package/src/resources/extensions/coworker-scratchpad/format-age.test.ts +30 -0
  388. package/src/resources/extensions/coworker-scratchpad/format-age.ts +6 -0
  389. package/src/resources/extensions/coworker-scratchpad/helpers.test.ts +93 -0
  390. package/src/resources/extensions/coworker-scratchpad/helpers.ts +42 -0
  391. package/src/resources/extensions/coworker-scratchpad/index.test.ts +514 -0
  392. package/src/resources/extensions/coworker-scratchpad/index.ts +207 -0
  393. package/src/resources/extensions/coworker-scratchpad/mime-bundle.test.ts +61 -0
  394. package/src/resources/extensions/coworker-scratchpad/mime-bundle.ts +23 -0
  395. package/src/resources/extensions/coworker-scratchpad/scratchpad-tool.test.ts +137 -0
  396. package/src/resources/extensions/coworker-scratchpad/scratchpad-tool.ts +165 -0
  397. package/src/resources/extensions/coworker-scratchpad/session-sidecar.test.ts +133 -0
  398. package/src/resources/extensions/coworker-scratchpad/session-sidecar.ts +68 -0
  399. package/src/resources/extensions/coworker-scratchpad/sp-command.test.ts +836 -0
  400. package/src/resources/extensions/coworker-scratchpad/sp-command.ts +602 -0
  401. package/src/resources/extensions/coworker-scratchpad/workspace-pointer.test.ts +74 -0
  402. package/src/resources/extensions/coworker-scratchpad/workspace-pointer.ts +55 -0
  403. package/src/resources/extensions/coworker-scratchpad/workspace-root.test.ts +51 -0
  404. package/src/resources/extensions/coworker-scratchpad/workspace-root.ts +16 -0
  405. package/src/resources/extensions/coworker-vault/audit-command.test.ts +109 -0
  406. package/src/resources/extensions/coworker-vault/audit-command.ts +56 -0
  407. package/src/resources/extensions/coworker-vault/connect-command.test.ts +103 -0
  408. package/src/resources/extensions/coworker-vault/connect-command.ts +69 -0
  409. package/src/resources/extensions/coworker-vault/datasource-command.test.ts +80 -0
  410. package/src/resources/extensions/coworker-vault/datasource-command.ts +81 -0
  411. package/src/resources/extensions/coworker-vault/extension-manifest.json +12 -0
  412. package/src/resources/extensions/coworker-vault/index.test.ts +82 -0
  413. package/src/resources/extensions/coworker-vault/index.ts +181 -0
  414. package/src/resources/extensions/coworker-vault/test-helpers.ts +120 -0
  415. package/src/resources/extensions/coworker-vault/vault-singleton.test.ts +27 -0
  416. package/src/resources/extensions/coworker-vault/vault-singleton.ts +40 -0
  417. package/src/resources/extensions/otto/commands/release-notes/_data.ts +97 -0
  418. package/src/resources/extensions/otto/commands/release-notes/command.ts +16 -3
  419. package/src/resources/extensions/otto/index.ts +29 -6
  420. package/src/resources/extensions/shared/coworker-paths.test.ts +40 -0
  421. package/src/resources/extensions/shared/coworker-paths.ts +10 -0
  422. package/src/resources/extensions/slash-commands/{audit.ts → audit-codebase.ts} +4 -4
  423. package/src/resources/extensions/slash-commands/extension-manifest.json +1 -1
  424. package/src/resources/extensions/slash-commands/index.ts +2 -2
  425. package/src/resources/extensions/subagent/index.ts +9 -0
  426. package/src/resources/extensions/subagent/launch.test.ts +97 -0
  427. package/src/resources/extensions/subagent/launch.ts +42 -5
  428. package/src/resources/extensions/subagent/run-store.ts +3 -1
  429. package/src/resources/extensions/workflow/bootstrap/register-extension.ts +2 -0
  430. package/src/resources/extensions/workflow/bootstrap/register-hooks.ts +10 -0
  431. package/src/resources/extensions/workflow/health-widget-core.ts +1 -1
  432. package/src/resources/extensions/workflow/persona-status.ts +109 -0
  433. package/src/resources/extensions/workflow/tests/auto-recovery.test.ts +34 -0
@@ -0,0 +1,58 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {
4
+ EngineNotFound,
5
+ EngineValidationError,
6
+ VaultEntryNotFound,
7
+ VaultEntryMalformed,
8
+ BindingRefMalformed,
9
+ BindingNotFound,
10
+ } from './errors.js';
11
+
12
+ describe('vault errors', () => {
13
+ it('EngineNotFound carries id and is named', () => {
14
+ const e = new EngineNotFound('servicenow');
15
+ assert.equal(e.id, 'servicenow');
16
+ assert.equal(e.name, 'EngineNotFound');
17
+ assert.ok(e.message.includes('servicenow'));
18
+ });
19
+
20
+ it('VaultEntryNotFound carries engine, entryName, and searched paths', () => {
21
+ const searched = ['/ws/.otto/vault/jira', '/home/u/.otto/vault/jira'];
22
+ const e = new VaultEntryNotFound('jira', 'prod', searched);
23
+ assert.equal(e.name, 'VaultEntryNotFound');
24
+ assert.equal(e.engine, 'jira');
25
+ assert.equal(e.entryName, 'prod');
26
+ assert.deepEqual(e.searched, searched);
27
+ });
28
+
29
+ it('BindingRefMalformed carries input and hints at jira:prod', () => {
30
+ const e = new BindingRefMalformed('jira-prod');
31
+ assert.equal(e.name, 'BindingRefMalformed');
32
+ assert.equal(e.input, 'jira-prod');
33
+ assert.ok(e.message.includes('jira:prod'));
34
+ });
35
+
36
+ it('BindingNotFound carries ref', () => {
37
+ const e = new BindingNotFound('jira:prod');
38
+ assert.equal(e.name, 'BindingNotFound');
39
+ assert.equal(e.ref, 'jira:prod');
40
+ assert.ok(e.message.includes('jira:prod'));
41
+ });
42
+
43
+ it('EngineValidationError carries yamlPath and issue', () => {
44
+ const e = new EngineValidationError('/engines/jira.yaml', 'missing field "label"');
45
+ assert.equal(e.name, 'EngineValidationError');
46
+ assert.equal(e.yamlPath, '/engines/jira.yaml');
47
+ assert.equal(e.issue, 'missing field "label"');
48
+ assert.ok(e.message.includes('/engines/jira.yaml'));
49
+ assert.ok(e.message.includes('missing field "label"'));
50
+ });
51
+
52
+ it('VaultEntryMalformed carries path', () => {
53
+ const e = new VaultEntryMalformed('/ws/.otto/vault/jira/prod.yaml', 'invalid YAML');
54
+ assert.equal(e.name, 'VaultEntryMalformed');
55
+ assert.equal(e.path, '/ws/.otto/vault/jira/prod.yaml');
56
+ assert.ok(e.message.includes('/ws/.otto/vault/jira/prod.yaml'));
57
+ });
58
+ });
@@ -0,0 +1,50 @@
1
+ // packages/coworker-vault/src/errors.ts
2
+ export class EngineNotFound extends Error {
3
+ constructor(public readonly id: string) {
4
+ super(`Unknown engine: ${id}. Available engines can be listed with /datasource list.`);
5
+ this.name = 'EngineNotFound';
6
+ }
7
+ }
8
+
9
+ export class EngineValidationError extends Error {
10
+ constructor(public readonly yamlPath: string, public readonly issue: string) {
11
+ super(`Engine ${yamlPath}: ${issue}`);
12
+ this.name = 'EngineValidationError';
13
+ }
14
+ }
15
+
16
+ export class VaultEntryNotFound extends Error {
17
+ constructor(
18
+ public readonly engine: string,
19
+ public readonly entryName: string,
20
+ public readonly searched: string[],
21
+ ) {
22
+ super(
23
+ `Vault entry not found: ${engine}:${entryName}. Searched: ${searched.join(', ')}. Use /connect ${engine} ${entryName} to create.`,
24
+ );
25
+ this.name = 'VaultEntryNotFound';
26
+ }
27
+ }
28
+
29
+ export class VaultEntryMalformed extends Error {
30
+ constructor(public readonly path: string, public readonly reason: string) {
31
+ super(`Vault entry corrupt: ${path} (${reason}). Move it aside and re-create with /connect.`);
32
+ this.name = 'VaultEntryMalformed';
33
+ }
34
+ }
35
+
36
+ export class BindingRefMalformed extends Error {
37
+ constructor(public readonly input: string) {
38
+ super(`Bad binding: ${input}. Expected <engine>:<name>, e.g., jira:prod.`);
39
+ this.name = 'BindingRefMalformed';
40
+ }
41
+ }
42
+
43
+ export class BindingNotFound extends Error {
44
+ constructor(public readonly ref: string) {
45
+ super(
46
+ `Vault binding not resolvable: ${ref}. The entry may have been removed. Use /datasource list to inspect.`,
47
+ );
48
+ this.name = 'BindingNotFound';
49
+ }
50
+ }
@@ -0,0 +1,24 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+
4
+ describe('coworker-vault barrel', () => {
5
+ it('barrel imports without throwing', async () => {
6
+ const mod = await import('./index.js');
7
+ assert.ok(mod, 'module namespace should load');
8
+ });
9
+
10
+ it('exposes expected public API', async () => {
11
+ const mod = await import('./index.js');
12
+ // Spot-check key exports from each submodule.
13
+ assert.equal(typeof mod.LocalDataVault, 'function', 'LocalDataVault class exported');
14
+ assert.equal(typeof mod.EngineRegistry, 'function', 'EngineRegistry class exported');
15
+ assert.equal(typeof mod.CredentialInjector, 'function', 'CredentialInjector class exported');
16
+ assert.equal(typeof mod.clearEnv, 'function', 'clearEnv function exported');
17
+ assert.equal(typeof mod.envVarName, 'function', 'envVarName helper exported');
18
+ assert.equal(typeof mod.BindingNotFound, 'function', 'BindingNotFound error exported');
19
+ assert.equal(typeof mod.BindingRefMalformed, 'function', 'BindingRefMalformed error exported');
20
+ assert.equal(typeof mod.VaultEntryNotFound, 'function', 'VaultEntryNotFound error exported');
21
+ assert.equal(typeof mod.mergeWithSentinel, 'function', 'mergeWithSentinel helper exported');
22
+ assert.equal(typeof mod.VAULT_KEEP, 'string', 'VAULT_KEEP sentinel exported');
23
+ });
24
+ });
@@ -0,0 +1,6 @@
1
+ export * from './types.js';
2
+ export * from './errors.js';
3
+ export * from './vault-keep.js';
4
+ export * from './engine-registry.js';
5
+ export * from './data-vault.js';
6
+ export * from './injector.js';
@@ -0,0 +1,109 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { mkdtempSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import { AuditLog } from '@otto/coworker-utils';
7
+ import { LocalDataVault } from './data-vault.js';
8
+ import { CredentialInjector, clearEnv } from './injector.js';
9
+ import { BindingNotFound, BindingRefMalformed } from './errors.js';
10
+
11
+ function ctx() {
12
+ const root = mkdtempSync(join(tmpdir(), 'vault-inj-'));
13
+ const audit = new AuditLog({ path: join(root, 'audit.jsonl') });
14
+ const vault = new LocalDataVault({ globalDir: join(root, 'global'), workspaceDir: undefined, audit });
15
+ return { root, audit, vault };
16
+ }
17
+
18
+ function injCtx() {
19
+ return { scratchpadName: 'sp-test', sessionId: 'sess-test', pid: 1234 };
20
+ }
21
+
22
+ describe('CredentialInjector', () => {
23
+ it('returns OTTO_DS_<ENGINE>_<NAME>__<FIELD> for each field', async () => {
24
+ const { vault, audit } = ctx();
25
+ await vault.set({ engine: 'jira', name: 'prod' }, { url: 'https://x', email: 'a@b', token: 't' });
26
+ const injector = new CredentialInjector({ vault, audit });
27
+ const out = await injector.injectEnv({ PATH: '/bin' }, ['jira:prod'], injCtx());
28
+ assert.equal(out['OTTO_DS_JIRA_PROD__URL'], 'https://x');
29
+ assert.equal(out['OTTO_DS_JIRA_PROD__EMAIL'], 'a@b');
30
+ assert.equal(out['OTTO_DS_JIRA_PROD__TOKEN'], 't');
31
+ assert.equal(out['PATH'], '/bin');
32
+ });
33
+
34
+ it('uppercases entry name and replaces hyphens with underscores in env var name', async () => {
35
+ const { vault, audit } = ctx();
36
+ await vault.set({ engine: 'jira', name: 'prod-east-1' }, { url: 'https://x' });
37
+ const injector = new CredentialInjector({ vault, audit });
38
+ const out = await injector.injectEnv({}, ['jira:prod-east-1'], injCtx());
39
+ assert.equal(out['OTTO_DS_JIRA_PROD_EAST_1__URL'], 'https://x');
40
+ });
41
+
42
+ it('does not mutate baseEnv', async () => {
43
+ const { vault, audit } = ctx();
44
+ await vault.set({ engine: 'jira', name: 'prod' }, { url: 'https://x' });
45
+ const injector = new CredentialInjector({ vault, audit });
46
+ const baseEnv = { PATH: '/bin' };
47
+ const snapshot = { ...baseEnv };
48
+ await injector.injectEnv(baseEnv, ['jira:prod'], injCtx());
49
+ assert.deepEqual(baseEnv, snapshot);
50
+ });
51
+
52
+ it('strict mode (default) throws BindingNotFound for missing binding', async () => {
53
+ const { vault, audit } = ctx();
54
+ const injector = new CredentialInjector({ vault, audit });
55
+ await assert.rejects(
56
+ () => injector.injectEnv({}, ['jira:missing'], injCtx()),
57
+ (err: unknown) => err instanceof BindingNotFound,
58
+ );
59
+ });
60
+
61
+ it('loose mode (OTTO_VAULT_MISSING_OK=1) skips missing binding and warns', async () => {
62
+ const { vault, audit } = ctx();
63
+ await vault.set({ engine: 'jira', name: 'prod' }, { url: 'https://x' });
64
+ const injector = new CredentialInjector({ vault, audit });
65
+ const prev = process.env.OTTO_VAULT_MISSING_OK;
66
+ process.env.OTTO_VAULT_MISSING_OK = '1';
67
+ try {
68
+ const out = await injector.injectEnv({}, ['jira:prod', 'jira:missing'], injCtx());
69
+ assert.equal(out['OTTO_DS_JIRA_PROD__URL'], 'https://x');
70
+ assert.equal(out['OTTO_DS_JIRA_MISSING__URL'], undefined);
71
+ } finally {
72
+ if (prev === undefined) delete process.env.OTTO_VAULT_MISSING_OK;
73
+ else process.env.OTTO_VAULT_MISSING_OK = prev;
74
+ }
75
+ });
76
+
77
+ it('throws BindingRefMalformed on bad ref', async () => {
78
+ const { vault, audit } = ctx();
79
+ const injector = new CredentialInjector({ vault, audit });
80
+ await assert.rejects(
81
+ () => injector.injectEnv({}, ['jira/prod'], injCtx()),
82
+ (err: unknown) => err instanceof BindingRefMalformed,
83
+ );
84
+ });
85
+
86
+ it("emits one audit 'inject' record per binding with fields_injected (names only)", async () => {
87
+ const { vault, audit } = ctx();
88
+ await vault.set({ engine: 'jira', name: 'prod' }, { url: 'https://x', token: 't' });
89
+ const injector = new CredentialInjector({ vault, audit });
90
+ await injector.injectEnv({}, ['jira:prod'], injCtx());
91
+ const records: { action: string; detail: { fields_injected?: string[] } }[] = [];
92
+ for await (const r of audit.read({ producer: 'vault', action: 'inject' })) {
93
+ records.push(r as never);
94
+ }
95
+ assert.equal(records.length, 1);
96
+ assert.deepEqual(records[0]!.detail.fields_injected!.slice().sort(), ['token', 'url']);
97
+ });
98
+ });
99
+
100
+ describe('clearEnv', () => {
101
+ it('removes OTTO_DS_* keys, preserves others, returns count', () => {
102
+ const env: NodeJS.ProcessEnv = { PATH: '/bin', OTTO_DS_JIRA_PROD__URL: 'x', FOO: 'bar' };
103
+ const n = clearEnv(env);
104
+ assert.equal(n, 1);
105
+ assert.equal(env['OTTO_DS_JIRA_PROD__URL'], undefined);
106
+ assert.equal(env['PATH'], '/bin');
107
+ assert.equal(env['FOO'], 'bar');
108
+ });
109
+ });
@@ -0,0 +1,98 @@
1
+ // packages/coworker-vault/src/injector.ts
2
+ import { AuditLog } from '@otto/coworker-utils';
3
+ import { LocalDataVault } from './data-vault.js';
4
+ import { BindingNotFound, VaultEntryNotFound } from './errors.js';
5
+ import type { VaultEntry } from './types.js';
6
+
7
+ export interface CredentialInjectorOptions {
8
+ vault: LocalDataVault;
9
+ audit: AuditLog;
10
+ }
11
+
12
+ export interface InjectionContext {
13
+ scratchpadName: string;
14
+ sessionId: string;
15
+ pid: number;
16
+ }
17
+
18
+ export class CredentialInjector {
19
+ constructor(private readonly opts: CredentialInjectorOptions) {}
20
+
21
+ async injectEnv(
22
+ baseEnv: NodeJS.ProcessEnv,
23
+ bindings: string[],
24
+ ctx: InjectionContext,
25
+ ): Promise<NodeJS.ProcessEnv> {
26
+ const out: NodeJS.ProcessEnv = { ...baseEnv };
27
+ const loose = process.env.OTTO_VAULT_MISSING_OK === '1';
28
+ for (const refStr of bindings) {
29
+ const ref = LocalDataVault.parseRef(refStr);
30
+ let entry: VaultEntry;
31
+ try {
32
+ entry = await this.opts.vault.get(ref);
33
+ } catch (err) {
34
+ if (err instanceof VaultEntryNotFound) {
35
+ if (loose) {
36
+ process.stderr.write(
37
+ `vault: binding ${refStr} missing — skipped (OTTO_VAULT_MISSING_OK=1)\n`,
38
+ );
39
+ this.opts.audit.append({
40
+ _schema: 1,
41
+ ts: new Date().toISOString(),
42
+ producer: 'vault',
43
+ action: 'inject-skipped',
44
+ severity: 'warn',
45
+ sessionId: ctx.sessionId,
46
+ scratchpadName: ctx.scratchpadName,
47
+ pid: ctx.pid,
48
+ detail: { ref: refStr, reason: 'not-found' },
49
+ });
50
+ continue;
51
+ }
52
+ throw new BindingNotFound(refStr);
53
+ }
54
+ throw err;
55
+ }
56
+ for (const [field, value] of Object.entries(entry.fields)) {
57
+ out[envVarName(ref.engine, ref.name, field)] = value;
58
+ }
59
+ this.opts.audit.append({
60
+ _schema: 1,
61
+ ts: new Date().toISOString(),
62
+ producer: 'vault',
63
+ action: 'inject',
64
+ sessionId: ctx.sessionId,
65
+ scratchpadName: ctx.scratchpadName,
66
+ pid: ctx.pid,
67
+ detail: {
68
+ engine: ref.engine,
69
+ name: ref.name,
70
+ fields_injected: Object.keys(entry.fields),
71
+ },
72
+ });
73
+ }
74
+ return out;
75
+ }
76
+
77
+ async loadForBinding(_serviceName: string): Promise<null> {
78
+ return null; // Phase 3+
79
+ }
80
+ }
81
+
82
+ export function envVarName(engineId: string, entryName: string, fieldName: string): string {
83
+ const e = engineId.replace(/-/g, '_').toUpperCase();
84
+ const n = entryName.replace(/-/g, '_').toUpperCase();
85
+ const f = fieldName.toUpperCase();
86
+ return `OTTO_DS_${e}_${n}__${f}`;
87
+ }
88
+
89
+ export function clearEnv(env: NodeJS.ProcessEnv = process.env): number {
90
+ let n = 0;
91
+ for (const key of Object.keys(env)) {
92
+ if (key.startsWith('OTTO_DS_')) {
93
+ delete env[key];
94
+ n++;
95
+ }
96
+ }
97
+ return n;
98
+ }
@@ -0,0 +1,33 @@
1
+ // packages/coworker-vault/src/types.ts
2
+ export interface EntryRef {
3
+ engine: string;
4
+ name: string;
5
+ }
6
+
7
+ export interface EngineField {
8
+ name: string;
9
+ label: string;
10
+ secret: boolean;
11
+ required: boolean;
12
+ default?: string;
13
+ }
14
+
15
+ export interface EngineDefinition {
16
+ schema_version: 1;
17
+ id: string;
18
+ label: string;
19
+ description?: string;
20
+ fields: EngineField[];
21
+ }
22
+
23
+ export interface VaultEntry {
24
+ _schema: 1;
25
+ engine: string;
26
+ name: string;
27
+ fields: Record<string, string>;
28
+ created_at: string;
29
+ last_modified_at: string;
30
+ }
31
+
32
+ export type EngineSource = 'builtin' | 'user' | 'workspace';
33
+ export type VaultScope = 'global' | 'workspace';
@@ -0,0 +1,49 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { VAULT_KEEP, mergeWithSentinel, assertNoSentinelInCreate } from './vault-keep.js';
4
+ import type { EngineField } from './types.js';
5
+
6
+ const FIELDS: EngineField[] = [
7
+ { name: 'url', label: 'URL', secret: false, required: true },
8
+ { name: 'token', label: 'Token', secret: true, required: true },
9
+ { name: 'email', label: 'Email', secret: false, required: false },
10
+ ];
11
+
12
+ describe('VAULT_KEEP', () => {
13
+ it('is the literal string "[VAULT_KEEP]"', () => {
14
+ assert.equal(VAULT_KEEP, '[VAULT_KEEP]');
15
+ });
16
+
17
+ describe('mergeWithSentinel (edit mode)', () => {
18
+ it('preserves stored secret when submitted value is the sentinel', () => {
19
+ const stored = { url: 'https://old', token: 'SECRET', email: 'a@b' };
20
+ const submitted = { url: 'https://new', token: VAULT_KEEP, email: 'c@d' };
21
+ const out = mergeWithSentinel(FIELDS, stored, submitted);
22
+ assert.deepEqual(out, { url: 'https://new', token: 'SECRET', email: 'c@d' });
23
+ });
24
+
25
+ it('replaces stored secret when submitted value differs from the sentinel', () => {
26
+ const stored = { url: 'u', token: 'OLD', email: 'e' };
27
+ const submitted = { url: 'u', token: 'NEW', email: 'e' };
28
+ const out = mergeWithSentinel(FIELDS, stored, submitted);
29
+ assert.equal(out.token, 'NEW');
30
+ });
31
+
32
+ it('ignores sentinel for non-secret fields (treats it as literal new value)', () => {
33
+ const stored = { url: 'u', token: 't', email: 'e' };
34
+ const submitted = { url: VAULT_KEEP, token: 't', email: 'e' };
35
+ const out = mergeWithSentinel(FIELDS, stored, submitted);
36
+ assert.equal(out.url, VAULT_KEEP);
37
+ });
38
+ });
39
+
40
+ describe('assertNoSentinelInCreate', () => {
41
+ it('throws when a secret field input equals the sentinel', () => {
42
+ assert.throws(() => assertNoSentinelInCreate(FIELDS, { url: 'u', token: VAULT_KEEP, email: 'e' }), /VAULT_KEEP is reserved/);
43
+ });
44
+
45
+ it('passes when no secret field equals the sentinel', () => {
46
+ assert.doesNotThrow(() => assertNoSentinelInCreate(FIELDS, { url: 'u', token: 'real', email: 'e' }));
47
+ });
48
+ });
49
+ });
@@ -0,0 +1,31 @@
1
+ import type { EngineField } from './types.js';
2
+
3
+ export const VAULT_KEEP = '[VAULT_KEEP]' as const;
4
+
5
+ export function mergeWithSentinel(
6
+ fields: EngineField[],
7
+ stored: Record<string, string>,
8
+ submitted: Record<string, string>,
9
+ ): Record<string, string> {
10
+ const out: Record<string, string> = {};
11
+ for (const f of fields) {
12
+ const sub = submitted[f.name];
13
+ if (f.secret && sub === VAULT_KEEP) {
14
+ out[f.name] = stored[f.name] ?? '';
15
+ } else {
16
+ out[f.name] = sub ?? '';
17
+ }
18
+ }
19
+ return out;
20
+ }
21
+
22
+ export function assertNoSentinelInCreate(
23
+ fields: EngineField[],
24
+ submitted: Record<string, string>,
25
+ ): void {
26
+ for (const f of fields) {
27
+ if (f.secret && submitted[f.name] === VAULT_KEEP) {
28
+ throw new Error(`VAULT_KEEP is reserved; pick a real value for field "${f.name}".`);
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "NodeNext",
4
+ "moduleResolution": "NodeNext",
5
+ "target": "ES2022",
6
+ "outDir": "dist",
7
+ "rootDir": "src",
8
+ "strict": true,
9
+ "declaration": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true
12
+ },
13
+ "include": ["src"],
14
+ "exclude": ["src/**/*.test.ts"]
15
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": { "incremental": false }
4
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otto-build/daemon",
3
- "version": "1.1.1",
3
+ "version": "1.2.5",
4
4
  "description": "OTTO daemon — background process for project monitoring and Discord integration",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -29,8 +29,8 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@anthropic-ai/sdk": "^0.52.0",
32
- "@otto-build/contracts": "^1.1.1",
33
- "@otto-build/rpc-client": "^1.1.1",
32
+ "@otto-build/contracts": "^1.2.5",
33
+ "@otto-build/rpc-client": "^1.2.5",
34
34
  "discord.js": "^14.25.1",
35
35
  "yaml": "^2.8.0",
36
36
  "zod": "^3.24.0"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@otto-build/mcp-server",
3
- "version": "1.1.1",
3
+ "version": "1.2.5",
4
4
  "description": "MCP server exposing OTTO orchestration tools for compatible clients",
5
5
  "license": "MIT",
6
6
  "otto": {
@@ -34,8 +34,8 @@
34
34
  "test": "npm run build:test && node --test dist/mcp-server.test.js dist/remote-questions.test.js"
35
35
  },
36
36
  "dependencies": {
37
- "@otto-build/contracts": "^1.1.1",
38
- "@otto-build/rpc-client": "^1.1.1",
37
+ "@otto-build/contracts": "^1.2.5",
38
+ "@otto-build/rpc-client": "^1.2.5",
39
39
  "@modelcontextprotocol/sdk": "^1.27.1",
40
40
  "zod": "^4.0.0"
41
41
  },