@cmetech/otto 1.1.0 → 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 (425) 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 +82 -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/dist/update-cmd.d.ts +19 -0
  47. package/dist/update-cmd.js +177 -6
  48. package/package.json +25 -10
  49. package/packages/contracts/package.json +1 -1
  50. package/packages/coworker-artifacts/dist/artifact-store.d.ts +25 -0
  51. package/packages/coworker-artifacts/dist/artifact-store.js +187 -0
  52. package/packages/coworker-artifacts/dist/dir-snapshot.d.ts +7 -0
  53. package/packages/coworker-artifacts/dist/dir-snapshot.js +54 -0
  54. package/packages/coworker-artifacts/dist/errors.d.ts +18 -0
  55. package/packages/coworker-artifacts/dist/errors.js +37 -0
  56. package/packages/coworker-artifacts/dist/index.d.ts +7 -0
  57. package/packages/coworker-artifacts/dist/index.js +7 -0
  58. package/packages/coworker-artifacts/dist/readme-renderer.d.ts +5 -0
  59. package/packages/coworker-artifacts/dist/readme-renderer.js +47 -0
  60. package/packages/coworker-artifacts/dist/resolve-uri.d.ts +3 -0
  61. package/packages/coworker-artifacts/dist/resolve-uri.js +29 -0
  62. package/packages/coworker-artifacts/dist/slug.d.ts +4 -0
  63. package/packages/coworker-artifacts/dist/slug.js +32 -0
  64. package/packages/coworker-artifacts/dist/types.d.ts +52 -0
  65. package/packages/coworker-artifacts/dist/types.js +1 -0
  66. package/packages/coworker-artifacts/package.json +20 -0
  67. package/packages/coworker-artifacts/src/artifact-store.test.ts +188 -0
  68. package/packages/coworker-artifacts/src/artifact-store.ts +206 -0
  69. package/packages/coworker-artifacts/src/artifacts-integration.test.ts +109 -0
  70. package/packages/coworker-artifacts/src/dir-snapshot.test.ts +71 -0
  71. package/packages/coworker-artifacts/src/dir-snapshot.ts +52 -0
  72. package/packages/coworker-artifacts/src/errors.test.ts +37 -0
  73. package/packages/coworker-artifacts/src/errors.ts +28 -0
  74. package/packages/coworker-artifacts/src/index.test.ts +22 -0
  75. package/packages/coworker-artifacts/src/index.ts +7 -0
  76. package/packages/coworker-artifacts/src/readme-renderer.test.ts +72 -0
  77. package/packages/coworker-artifacts/src/readme-renderer.ts +56 -0
  78. package/packages/coworker-artifacts/src/resolve-uri.test.ts +46 -0
  79. package/packages/coworker-artifacts/src/resolve-uri.ts +29 -0
  80. package/packages/coworker-artifacts/src/slug.test.ts +47 -0
  81. package/packages/coworker-artifacts/src/slug.ts +31 -0
  82. package/packages/coworker-artifacts/src/types.ts +61 -0
  83. package/packages/coworker-artifacts/tsconfig.json +15 -0
  84. package/packages/coworker-artifacts/tsconfig.publish.json +4 -0
  85. package/packages/coworker-memory/dist/context-injection.d.ts +9 -0
  86. package/packages/coworker-memory/dist/context-injection.js +41 -0
  87. package/packages/coworker-memory/dist/errors.d.ts +25 -0
  88. package/packages/coworker-memory/dist/errors.js +51 -0
  89. package/packages/coworker-memory/dist/index.d.ts +12 -0
  90. package/packages/coworker-memory/dist/index.js +12 -0
  91. package/packages/coworker-memory/dist/layer-a-store.d.ts +16 -0
  92. package/packages/coworker-memory/dist/layer-a-store.js +78 -0
  93. package/packages/coworker-memory/dist/local-sqlite-backend.d.ts +28 -0
  94. package/packages/coworker-memory/dist/local-sqlite-backend.js +167 -0
  95. package/packages/coworker-memory/dist/memory-backend.d.ts +14 -0
  96. package/packages/coworker-memory/dist/memory-backend.js +1 -0
  97. package/packages/coworker-memory/dist/memory-recorder.d.ts +50 -0
  98. package/packages/coworker-memory/dist/memory-recorder.js +69 -0
  99. package/packages/coworker-memory/dist/migrations/001-init.sql +38 -0
  100. package/packages/coworker-memory/dist/migrations/002-artifact-kind.sql +50 -0
  101. package/packages/coworker-memory/dist/paste-detector.d.ts +5 -0
  102. package/packages/coworker-memory/dist/paste-detector.js +14 -0
  103. package/packages/coworker-memory/dist/persona-seed.d.ts +10 -0
  104. package/packages/coworker-memory/dist/persona-seed.js +38 -0
  105. package/packages/coworker-memory/dist/recall-formatter.d.ts +2 -0
  106. package/packages/coworker-memory/dist/recall-formatter.js +14 -0
  107. package/packages/coworker-memory/dist/scope-resolver.d.ts +9 -0
  108. package/packages/coworker-memory/dist/scope-resolver.js +10 -0
  109. package/packages/coworker-memory/dist/types.d.ts +51 -0
  110. package/packages/coworker-memory/dist/types.js +2 -0
  111. package/packages/coworker-memory/dist/workspace-id.d.ts +3 -0
  112. package/packages/coworker-memory/dist/workspace-id.js +54 -0
  113. package/packages/coworker-memory/package.json +35 -0
  114. package/packages/coworker-memory/src/activator-integration.test.ts +141 -0
  115. package/packages/coworker-memory/src/context-injection.test.ts +72 -0
  116. package/packages/coworker-memory/src/context-injection.ts +57 -0
  117. package/packages/coworker-memory/src/errors.test.ts +45 -0
  118. package/packages/coworker-memory/src/errors.ts +42 -0
  119. package/packages/coworker-memory/src/index.test.ts +21 -0
  120. package/packages/coworker-memory/src/index.ts +12 -0
  121. package/packages/coworker-memory/src/layer-a-store.test.ts +85 -0
  122. package/packages/coworker-memory/src/layer-a-store.ts +88 -0
  123. package/packages/coworker-memory/src/local-sqlite-backend.test.ts +110 -0
  124. package/packages/coworker-memory/src/local-sqlite-backend.ts +185 -0
  125. package/packages/coworker-memory/src/memory-backend.ts +10 -0
  126. package/packages/coworker-memory/src/memory-integration.test.ts +89 -0
  127. package/packages/coworker-memory/src/memory-recorder.test.ts +101 -0
  128. package/packages/coworker-memory/src/memory-recorder.ts +95 -0
  129. package/packages/coworker-memory/src/migrations/001-init.sql +38 -0
  130. package/packages/coworker-memory/src/migrations/002-artifact-kind.sql +50 -0
  131. package/packages/coworker-memory/src/paste-detector.test.ts +23 -0
  132. package/packages/coworker-memory/src/paste-detector.ts +18 -0
  133. package/packages/coworker-memory/src/persona-seed.test.ts +57 -0
  134. package/packages/coworker-memory/src/persona-seed.ts +46 -0
  135. package/packages/coworker-memory/src/recall-formatter.test.ts +34 -0
  136. package/packages/coworker-memory/src/recall-formatter.ts +15 -0
  137. package/packages/coworker-memory/src/scope-resolver.test.ts +23 -0
  138. package/packages/coworker-memory/src/scope-resolver.ts +18 -0
  139. package/packages/coworker-memory/src/types.ts +61 -0
  140. package/packages/coworker-memory/src/workspace-id.test.ts +48 -0
  141. package/packages/coworker-memory/src/workspace-id.ts +56 -0
  142. package/packages/coworker-memory/tsconfig.json +15 -0
  143. package/packages/coworker-memory/tsconfig.publish.json +4 -0
  144. package/packages/coworker-persona/dist/commands.d.ts +7 -0
  145. package/packages/coworker-persona/dist/commands.js +35 -0
  146. package/packages/coworker-persona/dist/defaults/manifest.yaml +12 -0
  147. package/packages/coworker-persona/dist/defaults/steering/identity.md +3 -0
  148. package/packages/coworker-persona/dist/index.d.ts +3 -0
  149. package/packages/coworker-persona/dist/index.js +3 -0
  150. package/packages/coworker-persona/dist/manifest.d.ts +24 -0
  151. package/packages/coworker-persona/dist/manifest.js +21 -0
  152. package/packages/coworker-persona/dist/registry.d.ts +22 -0
  153. package/packages/coworker-persona/dist/registry.js +142 -0
  154. package/packages/coworker-persona/package.json +28 -0
  155. package/packages/coworker-persona/scripts/copy-defaults.cjs +17 -0
  156. package/packages/coworker-persona/src/commands.ts +47 -0
  157. package/packages/coworker-persona/src/defaults/manifest.yaml +12 -0
  158. package/packages/coworker-persona/src/defaults/steering/identity.md +3 -0
  159. package/packages/coworker-persona/src/index.ts +3 -0
  160. package/packages/coworker-persona/src/manifest.test.ts +67 -0
  161. package/packages/coworker-persona/src/manifest.ts +49 -0
  162. package/packages/coworker-persona/src/registry.test.ts +89 -0
  163. package/packages/coworker-persona/src/registry.ts +147 -0
  164. package/packages/coworker-persona/tsconfig.json +15 -0
  165. package/packages/coworker-persona/tsconfig.publish.json +4 -0
  166. package/packages/coworker-scratchpad/dist/cell-archive.d.ts +39 -0
  167. package/packages/coworker-scratchpad/dist/cell-archive.js +77 -0
  168. package/packages/coworker-scratchpad/dist/cell-tree.d.ts +14 -0
  169. package/packages/coworker-scratchpad/dist/cell-tree.js +72 -0
  170. package/packages/coworker-scratchpad/dist/child-process-runtime.d.ts +129 -0
  171. package/packages/coworker-scratchpad/dist/child-process-runtime.js +427 -0
  172. package/packages/coworker-scratchpad/dist/collector-registry.d.ts +12 -0
  173. package/packages/coworker-scratchpad/dist/collector-registry.js +29 -0
  174. package/packages/coworker-scratchpad/dist/detect-kind.d.ts +3 -0
  175. package/packages/coworker-scratchpad/dist/detect-kind.js +19 -0
  176. package/packages/coworker-scratchpad/dist/file-collector.d.ts +15 -0
  177. package/packages/coworker-scratchpad/dist/file-collector.js +99 -0
  178. package/packages/coworker-scratchpad/dist/index.d.ts +13 -0
  179. package/packages/coworker-scratchpad/dist/index.js +13 -0
  180. package/packages/coworker-scratchpad/dist/kernel-bindings.d.ts +49 -0
  181. package/packages/coworker-scratchpad/dist/kernel-bindings.js +220 -0
  182. package/packages/coworker-scratchpad/dist/kernel-entry.d.ts +1 -0
  183. package/packages/coworker-scratchpad/dist/kernel-entry.js +355 -0
  184. package/packages/coworker-scratchpad/dist/kernel-protocol.d.ts +171 -0
  185. package/packages/coworker-scratchpad/dist/kernel-protocol.js +48 -0
  186. package/packages/coworker-scratchpad/dist/kernel-spawn.d.ts +3 -0
  187. package/packages/coworker-scratchpad/dist/kernel-spawn.js +54 -0
  188. package/packages/coworker-scratchpad/dist/namespace-codec.d.ts +22 -0
  189. package/packages/coworker-scratchpad/dist/namespace-codec.js +61 -0
  190. package/packages/coworker-scratchpad/dist/scratchpad-lock.d.ts +24 -0
  191. package/packages/coworker-scratchpad/dist/scratchpad-lock.js +86 -0
  192. package/packages/coworker-scratchpad/dist/scratchpad-manager.d.ts +193 -0
  193. package/packages/coworker-scratchpad/dist/scratchpad-manager.js +866 -0
  194. package/packages/coworker-scratchpad/dist/staleness-banner.d.ts +12 -0
  195. package/packages/coworker-scratchpad/dist/staleness-banner.js +27 -0
  196. package/packages/coworker-scratchpad/package.json +31 -0
  197. package/packages/coworker-scratchpad/src/cell-archive.test.ts +150 -0
  198. package/packages/coworker-scratchpad/src/cell-archive.ts +97 -0
  199. package/packages/coworker-scratchpad/src/cell-tree.test.ts +105 -0
  200. package/packages/coworker-scratchpad/src/cell-tree.ts +90 -0
  201. package/packages/coworker-scratchpad/src/child-process-runtime.test.ts +413 -0
  202. package/packages/coworker-scratchpad/src/child-process-runtime.ts +493 -0
  203. package/packages/coworker-scratchpad/src/collector-registry.test.ts +69 -0
  204. package/packages/coworker-scratchpad/src/collector-registry.ts +33 -0
  205. package/packages/coworker-scratchpad/src/detect-kind.test.ts +33 -0
  206. package/packages/coworker-scratchpad/src/detect-kind.ts +22 -0
  207. package/packages/coworker-scratchpad/src/file-collector.test.ts +109 -0
  208. package/packages/coworker-scratchpad/src/file-collector.ts +114 -0
  209. package/packages/coworker-scratchpad/src/index.ts +74 -0
  210. package/packages/coworker-scratchpad/src/kernel-bindings.test.ts +188 -0
  211. package/packages/coworker-scratchpad/src/kernel-bindings.ts +279 -0
  212. package/packages/coworker-scratchpad/src/kernel-entry.test.ts +123 -0
  213. package/packages/coworker-scratchpad/src/kernel-entry.ts +390 -0
  214. package/packages/coworker-scratchpad/src/kernel-protocol.test.ts +105 -0
  215. package/packages/coworker-scratchpad/src/kernel-protocol.ts +230 -0
  216. package/packages/coworker-scratchpad/src/kernel-spawn.test.ts +60 -0
  217. package/packages/coworker-scratchpad/src/kernel-spawn.ts +54 -0
  218. package/packages/coworker-scratchpad/src/namespace-codec.test.ts +102 -0
  219. package/packages/coworker-scratchpad/src/namespace-codec.ts +90 -0
  220. package/packages/coworker-scratchpad/src/scratchpad-lock.test.ts +98 -0
  221. package/packages/coworker-scratchpad/src/scratchpad-lock.ts +102 -0
  222. package/packages/coworker-scratchpad/src/scratchpad-manager.test.ts +1343 -0
  223. package/packages/coworker-scratchpad/src/scratchpad-manager.ts +891 -0
  224. package/packages/coworker-scratchpad/src/staleness-banner.test.ts +53 -0
  225. package/packages/coworker-scratchpad/src/staleness-banner.ts +33 -0
  226. package/packages/coworker-scratchpad/src/vault-integration.test.ts +221 -0
  227. package/packages/coworker-scratchpad/tsconfig.json +15 -0
  228. package/packages/coworker-scratchpad/tsconfig.publish.json +4 -0
  229. package/packages/coworker-types/dist/artifacts.d.ts +31 -0
  230. package/packages/coworker-types/dist/artifacts.js +2 -0
  231. package/packages/coworker-types/dist/contracts.d.ts +32 -0
  232. package/packages/coworker-types/dist/contracts.js +1 -0
  233. package/packages/coworker-types/dist/index.d.ts +5 -0
  234. package/packages/coworker-types/dist/index.js +5 -0
  235. package/packages/coworker-types/dist/memory.d.ts +61 -0
  236. package/packages/coworker-types/dist/memory.js +3 -0
  237. package/packages/coworker-types/dist/scratchpad.d.ts +43 -0
  238. package/packages/coworker-types/dist/scratchpad.js +2 -0
  239. package/packages/coworker-types/dist/vault.d.ts +34 -0
  240. package/packages/coworker-types/dist/vault.js +2 -0
  241. package/packages/coworker-types/package.json +24 -0
  242. package/packages/coworker-types/src/artifacts.test.ts +52 -0
  243. package/packages/coworker-types/src/artifacts.ts +35 -0
  244. package/packages/coworker-types/src/contracts.test.ts +43 -0
  245. package/packages/coworker-types/src/contracts.ts +36 -0
  246. package/packages/coworker-types/src/index.ts +5 -0
  247. package/packages/coworker-types/src/memory.test.ts +50 -0
  248. package/packages/coworker-types/src/memory.ts +79 -0
  249. package/packages/coworker-types/src/scratchpad.test.ts +46 -0
  250. package/packages/coworker-types/src/scratchpad.ts +51 -0
  251. package/packages/coworker-types/src/smoke.test.ts +34 -0
  252. package/packages/coworker-types/src/vault.test.ts +49 -0
  253. package/packages/coworker-types/src/vault.ts +40 -0
  254. package/packages/coworker-types/tsconfig.json +15 -0
  255. package/packages/coworker-types/tsconfig.publish.json +4 -0
  256. package/packages/coworker-utils/dist/audit-log.d.ts +34 -0
  257. package/packages/coworker-utils/dist/audit-log.js +88 -0
  258. package/packages/coworker-utils/dist/index.d.ts +6 -0
  259. package/packages/coworker-utils/dist/index.js +6 -0
  260. package/packages/coworker-utils/dist/lease.d.ts +7 -0
  261. package/packages/coworker-utils/dist/lease.js +67 -0
  262. package/packages/coworker-utils/dist/logger.d.ts +13 -0
  263. package/packages/coworker-utils/dist/logger.js +26 -0
  264. package/packages/coworker-utils/dist/migration-runner.d.ts +7 -0
  265. package/packages/coworker-utils/dist/migration-runner.js +36 -0
  266. package/packages/coworker-utils/dist/ndjson-channel.d.ts +3 -0
  267. package/packages/coworker-utils/dist/ndjson-channel.js +38 -0
  268. package/packages/coworker-utils/dist/secret-scanner.d.ts +10 -0
  269. package/packages/coworker-utils/dist/secret-scanner.js +42 -0
  270. package/packages/coworker-utils/package.json +24 -0
  271. package/packages/coworker-utils/src/audit-log.test.ts +140 -0
  272. package/packages/coworker-utils/src/audit-log.ts +107 -0
  273. package/packages/coworker-utils/src/index.ts +6 -0
  274. package/packages/coworker-utils/src/lease.test.ts +64 -0
  275. package/packages/coworker-utils/src/lease.ts +76 -0
  276. package/packages/coworker-utils/src/logger.test.ts +50 -0
  277. package/packages/coworker-utils/src/logger.ts +45 -0
  278. package/packages/coworker-utils/src/migration-runner.test.ts +65 -0
  279. package/packages/coworker-utils/src/migration-runner.ts +50 -0
  280. package/packages/coworker-utils/src/ndjson-channel.test.ts +76 -0
  281. package/packages/coworker-utils/src/ndjson-channel.ts +41 -0
  282. package/packages/coworker-utils/src/secret-scanner.test.ts +61 -0
  283. package/packages/coworker-utils/src/secret-scanner.ts +56 -0
  284. package/packages/coworker-utils/tsconfig.json +15 -0
  285. package/packages/coworker-utils/tsconfig.publish.json +4 -0
  286. package/packages/coworker-vault/dist/data-vault.d.ts +41 -0
  287. package/packages/coworker-vault/dist/data-vault.js +223 -0
  288. package/packages/coworker-vault/dist/engine-registry.d.ts +34 -0
  289. package/packages/coworker-vault/dist/engine-registry.js +90 -0
  290. package/packages/coworker-vault/dist/engines/jira.yaml +17 -0
  291. package/packages/coworker-vault/dist/errors.d.ts +28 -0
  292. package/packages/coworker-vault/dist/errors.js +57 -0
  293. package/packages/coworker-vault/dist/index.d.ts +6 -0
  294. package/packages/coworker-vault/dist/index.js +6 -0
  295. package/packages/coworker-vault/dist/injector.d.ts +19 -0
  296. package/packages/coworker-vault/dist/injector.js +77 -0
  297. package/packages/coworker-vault/dist/types.d.ts +28 -0
  298. package/packages/coworker-vault/dist/types.js +1 -0
  299. package/packages/coworker-vault/dist/vault-keep.d.ts +4 -0
  300. package/packages/coworker-vault/dist/vault-keep.js +21 -0
  301. package/packages/coworker-vault/package.json +29 -0
  302. package/packages/coworker-vault/src/data-vault.test.ts +199 -0
  303. package/packages/coworker-vault/src/data-vault.ts +257 -0
  304. package/packages/coworker-vault/src/engine-registry.test.ts +120 -0
  305. package/packages/coworker-vault/src/engine-registry.ts +107 -0
  306. package/packages/coworker-vault/src/engines/jira.yaml +17 -0
  307. package/packages/coworker-vault/src/errors.test.ts +58 -0
  308. package/packages/coworker-vault/src/errors.ts +50 -0
  309. package/packages/coworker-vault/src/index.test.ts +24 -0
  310. package/packages/coworker-vault/src/index.ts +6 -0
  311. package/packages/coworker-vault/src/injector.test.ts +109 -0
  312. package/packages/coworker-vault/src/injector.ts +98 -0
  313. package/packages/coworker-vault/src/types.ts +33 -0
  314. package/packages/coworker-vault/src/vault-keep.test.ts +49 -0
  315. package/packages/coworker-vault/src/vault-keep.ts +31 -0
  316. package/packages/coworker-vault/tsconfig.json +15 -0
  317. package/packages/coworker-vault/tsconfig.publish.json +4 -0
  318. package/packages/daemon/package.json +3 -3
  319. package/packages/mcp-server/package.json +3 -3
  320. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  321. package/packages/native/package.json +1 -1
  322. package/packages/native/tsconfig.tsbuildinfo +1 -1
  323. package/packages/pi-agent-core/package.json +1 -1
  324. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  325. package/packages/pi-ai/package.json +1 -1
  326. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  327. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +6 -1
  328. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  329. package/packages/pi-coding-agent/dist/core/extensions/runner.js +22 -3
  330. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  331. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +11 -0
  332. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  333. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.d.ts +47 -0
  334. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.d.ts.map +1 -0
  335. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.js +107 -0
  336. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.js.map +1 -0
  337. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.regression.test.d.ts +19 -0
  338. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.regression.test.d.ts.map +1 -0
  339. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.regression.test.js +121 -0
  340. package/packages/pi-coding-agent/dist/modes/rpc/raw-stdout.regression.test.js.map +1 -0
  341. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  342. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +17 -1
  343. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  344. package/packages/pi-coding-agent/package.json +2 -2
  345. package/packages/pi-coding-agent/src/core/extensions/runner.ts +22 -3
  346. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +11 -0
  347. package/packages/pi-coding-agent/src/modes/rpc/raw-stdout.regression.test.ts +129 -0
  348. package/packages/pi-coding-agent/src/modes/rpc/raw-stdout.ts +117 -0
  349. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +18 -1
  350. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  351. package/packages/pi-tui/package.json +1 -1
  352. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  353. package/packages/rpc-client/package.json +2 -2
  354. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  355. package/pkg/package.json +1 -1
  356. package/scripts/install.js +6 -5
  357. package/src/resources/extensions/_coworker-paths.test.ts +40 -0
  358. package/src/resources/extensions/_coworker-paths.ts +10 -0
  359. package/src/resources/extensions/coworker-artifacts/artifacts-command.test.ts +54 -0
  360. package/src/resources/extensions/coworker-artifacts/artifacts-command.ts +43 -0
  361. package/src/resources/extensions/coworker-artifacts/artifacts-singleton.test.ts +25 -0
  362. package/src/resources/extensions/coworker-artifacts/artifacts-singleton.ts +29 -0
  363. package/src/resources/extensions/coworker-artifacts/extension-manifest.json +13 -0
  364. package/src/resources/extensions/coworker-artifacts/index.test.ts +46 -0
  365. package/src/resources/extensions/coworker-artifacts/index.ts +154 -0
  366. package/src/resources/extensions/coworker-artifacts/list-tool.test.ts +29 -0
  367. package/src/resources/extensions/coworker-artifacts/list-tool.ts +53 -0
  368. package/src/resources/extensions/coworker-artifacts/open-tool.test.ts +30 -0
  369. package/src/resources/extensions/coworker-artifacts/open-tool.ts +43 -0
  370. package/src/resources/extensions/coworker-memory/extension-manifest.json +13 -0
  371. package/src/resources/extensions/coworker-memory/index.test.ts +137 -0
  372. package/src/resources/extensions/coworker-memory/index.ts +257 -0
  373. package/src/resources/extensions/coworker-memory/memorize-tool.test.ts +41 -0
  374. package/src/resources/extensions/coworker-memory/memorize-tool.ts +20 -0
  375. package/src/resources/extensions/coworker-memory/memory-command.test.ts +134 -0
  376. package/src/resources/extensions/coworker-memory/memory-command.ts +131 -0
  377. package/src/resources/extensions/coworker-memory/memory-singleton.test.ts +41 -0
  378. package/src/resources/extensions/coworker-memory/memory-singleton.ts +89 -0
  379. package/src/resources/extensions/coworker-memory/recall-tool.test.ts +50 -0
  380. package/src/resources/extensions/coworker-memory/recall-tool.ts +35 -0
  381. package/src/resources/extensions/coworker-memory/session-hooks.test.ts +77 -0
  382. package/src/resources/extensions/coworker-memory/session-hooks.ts +61 -0
  383. package/src/resources/extensions/coworker-scratchpad/attach-banners.test.ts +124 -0
  384. package/src/resources/extensions/coworker-scratchpad/attach-banners.ts +67 -0
  385. package/src/resources/extensions/coworker-scratchpad/extension-manifest.json +13 -0
  386. package/src/resources/extensions/coworker-scratchpad/format-age.test.ts +30 -0
  387. package/src/resources/extensions/coworker-scratchpad/format-age.ts +6 -0
  388. package/src/resources/extensions/coworker-scratchpad/helpers.test.ts +93 -0
  389. package/src/resources/extensions/coworker-scratchpad/helpers.ts +42 -0
  390. package/src/resources/extensions/coworker-scratchpad/index.test.ts +514 -0
  391. package/src/resources/extensions/coworker-scratchpad/index.ts +207 -0
  392. package/src/resources/extensions/coworker-scratchpad/mime-bundle.test.ts +61 -0
  393. package/src/resources/extensions/coworker-scratchpad/mime-bundle.ts +23 -0
  394. package/src/resources/extensions/coworker-scratchpad/scratchpad-tool.test.ts +137 -0
  395. package/src/resources/extensions/coworker-scratchpad/scratchpad-tool.ts +165 -0
  396. package/src/resources/extensions/coworker-scratchpad/session-sidecar.test.ts +133 -0
  397. package/src/resources/extensions/coworker-scratchpad/session-sidecar.ts +68 -0
  398. package/src/resources/extensions/coworker-scratchpad/sp-command.test.ts +836 -0
  399. package/src/resources/extensions/coworker-scratchpad/sp-command.ts +602 -0
  400. package/src/resources/extensions/coworker-scratchpad/workspace-pointer.test.ts +74 -0
  401. package/src/resources/extensions/coworker-scratchpad/workspace-pointer.ts +55 -0
  402. package/src/resources/extensions/coworker-scratchpad/workspace-root.test.ts +51 -0
  403. package/src/resources/extensions/coworker-scratchpad/workspace-root.ts +16 -0
  404. package/src/resources/extensions/coworker-vault/audit-command.test.ts +109 -0
  405. package/src/resources/extensions/coworker-vault/audit-command.ts +56 -0
  406. package/src/resources/extensions/coworker-vault/connect-command.test.ts +103 -0
  407. package/src/resources/extensions/coworker-vault/connect-command.ts +69 -0
  408. package/src/resources/extensions/coworker-vault/datasource-command.test.ts +80 -0
  409. package/src/resources/extensions/coworker-vault/datasource-command.ts +81 -0
  410. package/src/resources/extensions/coworker-vault/extension-manifest.json +12 -0
  411. package/src/resources/extensions/coworker-vault/index.test.ts +82 -0
  412. package/src/resources/extensions/coworker-vault/index.ts +181 -0
  413. package/src/resources/extensions/coworker-vault/test-helpers.ts +120 -0
  414. package/src/resources/extensions/coworker-vault/vault-singleton.test.ts +27 -0
  415. package/src/resources/extensions/coworker-vault/vault-singleton.ts +40 -0
  416. package/src/resources/extensions/otto/commands/release-notes/_data.ts +96 -0
  417. package/src/resources/extensions/otto/commands/release-notes/command.ts +16 -3
  418. package/src/resources/extensions/subagent/index.ts +9 -0
  419. package/src/resources/extensions/subagent/launch.test.ts +97 -0
  420. package/src/resources/extensions/subagent/launch.ts +42 -5
  421. package/src/resources/extensions/subagent/run-store.ts +3 -1
  422. package/src/resources/extensions/workflow/bootstrap/register-extension.ts +2 -0
  423. package/src/resources/extensions/workflow/bootstrap/register-hooks.ts +10 -0
  424. package/src/resources/extensions/workflow/persona-status.ts +109 -0
  425. package/src/resources/extensions/workflow/tests/auto-recovery.test.ts +34 -0
@@ -44,6 +44,7 @@ import {
44
44
  buildSubagentProcessArgs,
45
45
  createSubagentLaunchPlan,
46
46
  isSubagentChildProcess,
47
+ mintSubagentScratchpadName,
47
48
  type SubagentContextMode,
48
49
  type SubagentSessionArgs,
49
50
  } from "./launch.js";
@@ -208,6 +209,7 @@ interface UsageStats {
208
209
  interface SingleResult {
209
210
  agent: string;
210
211
  trackingName?: string;
212
+ scratchpadName?: string;
211
213
  agentSource: "user" | "project" | "unknown";
212
214
  task: string;
213
215
  exitCode: number;
@@ -359,6 +361,7 @@ function resultToChildArtifact(result: SingleResult, index: number, cwd?: string
359
361
  index,
360
362
  agent: result.agent,
361
363
  trackingName: result.trackingName,
364
+ scratchpadName: result.scratchpadName,
362
365
  task: result.task,
363
366
  status: running ? "running" : resultStatus(result),
364
367
  exitCode: result.exitCode,
@@ -486,6 +489,8 @@ async function runSingleAgent(
486
489
  tmpPromptDir = tmp.dir;
487
490
  tmpPromptPath = tmp.filePath;
488
491
  }
492
+ const scratchpadName = mintSubagentScratchpadName(agent.name);
493
+ currentResult.scratchpadName = scratchpadName;
489
494
  const launch = createSubagentLaunchPlan({
490
495
  agent,
491
496
  task,
@@ -496,6 +501,7 @@ async function runSingleAgent(
496
501
  session: sessionOverride,
497
502
  cwd,
498
503
  defaultCwd,
504
+ scratchpadName,
499
505
  });
500
506
  if (launch.session.mode === "fork") currentResult.sessionFile = launch.session.sessionFile;
501
507
  let wasAborted = false;
@@ -638,6 +644,8 @@ async function runSingleAgentInCmuxSplit(
638
644
 
639
645
  const bundledPaths = ((process.env.OTTO_BUNDLED_EXTENSION_PATHS ?? process.env.OTTO_BUNDLED_EXTENSION_PATHS) ?? "").split(path.delimiter).map((s) => s.trim()).filter(Boolean);
640
646
  const extensionArgs = bundledPaths.flatMap((p) => ["--extension", p]);
647
+ const scratchpadName = mintSubagentScratchpadName(agent.name);
648
+ currentResult.scratchpadName = scratchpadName;
641
649
  const launch = createSubagentLaunchPlan({
642
650
  agent,
643
651
  task,
@@ -648,6 +656,7 @@ async function runSingleAgentInCmuxSplit(
648
656
  session: sessionOverride,
649
657
  cwd,
650
658
  defaultCwd,
659
+ scratchpadName,
651
660
  });
652
661
  if (launch.session.mode === "fork") currentResult.sessionFile = launch.session.sessionFile;
653
662
  const processArgs = [(process.env.OTTO_BIN_PATH ?? process.env.OTTO_BIN_PATH)!, ...extensionArgs, ...launch.args];
@@ -0,0 +1,97 @@
1
+ // src/resources/extensions/subagent/launch.test.ts
2
+ import { describe, it } from 'node:test';
3
+ import assert from 'node:assert/strict';
4
+ import {
5
+ buildShellEnvAssignments,
6
+ buildSubagentProcessEnv,
7
+ createSubagentLaunchPlan,
8
+ mintSubagentScratchpadName,
9
+ SUBAGENT_CHILD_ENV_VAR,
10
+ SUBAGENT_SCRATCHPAD_ENV_VAR,
11
+ } from './launch.js';
12
+ import type { AgentConfig } from './agents.js';
13
+
14
+ const STUB_AGENT: AgentConfig = {
15
+ name: 'rca-analyst',
16
+ description: '',
17
+ systemPrompt: 'x',
18
+ source: 'project',
19
+ filePath: '/tmp/rca-analyst.md',
20
+ };
21
+
22
+ describe('mintSubagentScratchpadName', () => {
23
+ it('produces subagent-<agent>-<6hex> for simple input', () => {
24
+ const name = mintSubagentScratchpadName('rca-analyst');
25
+ assert.match(name, /^subagent-rca-analyst-[0-9a-f]{6}$/);
26
+ });
27
+ it('sanitizes uppercase + punctuation to kebab', () => {
28
+ const name = mintSubagentScratchpadName('UPPER & weird!! chars');
29
+ assert.match(name, /^subagent-upper-weird-chars-[0-9a-f]{6}$/);
30
+ });
31
+ it('falls back to subagent-<hex> for empty input', () => {
32
+ const name = mintSubagentScratchpadName('');
33
+ assert.match(name, /^subagent-[0-9a-f]{6}$/);
34
+ });
35
+ it('truncates agent portion to fit reasonable length', () => {
36
+ const long = 'a'.repeat(100);
37
+ const name = mintSubagentScratchpadName(long);
38
+ // subagent- (9) + max 32 chars agent + - + 6 hex = max 48
39
+ assert.ok(name.length <= 48);
40
+ assert.match(name, /^subagent-a+-[0-9a-f]{6}$/);
41
+ });
42
+ it('strips diacritics', () => {
43
+ const name = mintSubagentScratchpadName('résumé');
44
+ assert.match(name, /^subagent-resume-[0-9a-f]{6}$/);
45
+ });
46
+ });
47
+
48
+ describe('buildSubagentProcessEnv', () => {
49
+ it('without scratchpad name preserves existing OTTO_SUBAGENT_CHILD only', () => {
50
+ const env = buildSubagentProcessEnv({ FOO: 'bar' });
51
+ assert.equal(env[SUBAGENT_CHILD_ENV_VAR], '1');
52
+ assert.equal(env.FOO, 'bar');
53
+ assert.equal(env[SUBAGENT_SCRATCHPAD_ENV_VAR], undefined);
54
+ });
55
+ it('with scratchpad name injects OTTO_SUBAGENT_SCRATCHPAD', () => {
56
+ const env = buildSubagentProcessEnv({ FOO: 'bar' }, 'subagent-foo-abc123');
57
+ assert.equal(env[SUBAGENT_CHILD_ENV_VAR], '1');
58
+ assert.equal(env[SUBAGENT_SCRATCHPAD_ENV_VAR], 'subagent-foo-abc123');
59
+ });
60
+ });
61
+
62
+ describe('buildShellEnvAssignments', () => {
63
+ it('includes scratchpad assignment when var is set', () => {
64
+ const out = buildShellEnvAssignments({
65
+ [SUBAGENT_CHILD_ENV_VAR]: '1',
66
+ [SUBAGENT_SCRATCHPAD_ENV_VAR]: 'subagent-foo-abc123',
67
+ });
68
+ assert.ok(out.some((s) => s.startsWith(`${SUBAGENT_CHILD_ENV_VAR}=`)));
69
+ assert.ok(out.some((s) => s.startsWith(`${SUBAGENT_SCRATCHPAD_ENV_VAR}=`)));
70
+ });
71
+ it('omits scratchpad assignment when var is unset', () => {
72
+ const out = buildShellEnvAssignments({ [SUBAGENT_CHILD_ENV_VAR]: '1' });
73
+ assert.equal(out.some((s) => s.startsWith(`${SUBAGENT_SCRATCHPAD_ENV_VAR}=`)), false);
74
+ });
75
+ });
76
+
77
+ describe('createSubagentLaunchPlan', () => {
78
+ it('threads scratchpadName into env', () => {
79
+ const plan = createSubagentLaunchPlan({
80
+ agent: STUB_AGENT,
81
+ task: 'do thing',
82
+ tmpPromptPath: null,
83
+ defaultCwd: '/tmp',
84
+ scratchpadName: 'subagent-rca-analyst-abc123',
85
+ });
86
+ assert.equal(plan.env[SUBAGENT_SCRATCHPAD_ENV_VAR], 'subagent-rca-analyst-abc123');
87
+ });
88
+ it('without scratchpadName leaves env var unset', () => {
89
+ const plan = createSubagentLaunchPlan({
90
+ agent: STUB_AGENT,
91
+ task: 'do thing',
92
+ tmpPromptPath: null,
93
+ defaultCwd: '/tmp',
94
+ });
95
+ assert.equal(plan.env[SUBAGENT_SCRATCHPAD_ENV_VAR], undefined);
96
+ });
97
+ });
@@ -1,5 +1,6 @@
1
1
  // OTTO + Subagent launch contract and child process safety helpers.
2
2
 
3
+ import * as crypto from "node:crypto";
3
4
  import * as fs from "node:fs";
4
5
  import * as path from "node:path";
5
6
  import { SessionManager } from "@otto/pi-coding-agent";
@@ -7,6 +8,26 @@ import type { AgentConfig } from "./agents.js";
7
8
 
8
9
  export const SUBAGENT_CHILD_ENV_VAR = "OTTO_SUBAGENT_CHILD";
9
10
  export const SUBAGENT_CHILD_ENV_VALUE = "1";
11
+ export const SUBAGENT_SCRATCHPAD_ENV_VAR = "OTTO_SUBAGENT_SCRATCHPAD";
12
+
13
+ const MAX_SCRATCHPAD_AGENT_PART = 32;
14
+
15
+ export function mintSubagentScratchpadName(agentName: string): string {
16
+ const hex = crypto.randomBytes(3).toString("hex");
17
+ // Sanitize: NFKD + strip combining marks + lowercase + non-[a-z0-9] → '-' + collapse + trim.
18
+ let sanitized = agentName
19
+ .normalize("NFKD")
20
+ .replace(/[̀-ͯ]/g, "")
21
+ .toLowerCase()
22
+ .replace(/[^a-z0-9]+/g, "-")
23
+ .replace(/-+/g, "-")
24
+ .replace(/^-+|-+$/g, "");
25
+ if (sanitized.length > MAX_SCRATCHPAD_AGENT_PART) {
26
+ sanitized = sanitized.slice(0, MAX_SCRATCHPAD_AGENT_PART).replace(/-+$/, "");
27
+ }
28
+ if (!sanitized) return `subagent-${hex}`;
29
+ return `subagent-${sanitized}-${hex}`;
30
+ }
10
31
 
11
32
  export type SubagentContextMode = "fresh" | "fork";
12
33
 
@@ -30,6 +51,7 @@ export interface SubagentLaunchInput {
30
51
  session?: SubagentSessionArgs;
31
52
  cwd?: string;
32
53
  defaultCwd: string;
54
+ scratchpadName?: string;
33
55
  }
34
56
 
35
57
  export interface SubagentLaunchPlan {
@@ -43,16 +65,31 @@ export function isSubagentChildProcess(env: NodeJS.ProcessEnv = process.env): bo
43
65
  return env[SUBAGENT_CHILD_ENV_VAR] === SUBAGENT_CHILD_ENV_VALUE;
44
66
  }
45
67
 
46
- export function buildSubagentProcessEnv(env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv {
47
- return {
68
+ export function buildSubagentProcessEnv(
69
+ env: NodeJS.ProcessEnv = process.env,
70
+ scratchpadName?: string,
71
+ ): NodeJS.ProcessEnv {
72
+ const next: NodeJS.ProcessEnv = {
48
73
  ...env,
49
74
  [SUBAGENT_CHILD_ENV_VAR]: SUBAGENT_CHILD_ENV_VALUE,
50
75
  };
76
+ if (scratchpadName) {
77
+ next[SUBAGENT_SCRATCHPAD_ENV_VAR] = scratchpadName;
78
+ }
79
+ return next;
51
80
  }
52
81
 
53
82
  export function buildShellEnvAssignments(env: NodeJS.ProcessEnv = process.env): string[] {
54
- const value = env[SUBAGENT_CHILD_ENV_VAR];
55
- return value ? [`${SUBAGENT_CHILD_ENV_VAR}=${JSON.stringify(value)}`] : [];
83
+ const out: string[] = [];
84
+ const childValue = env[SUBAGENT_CHILD_ENV_VAR];
85
+ if (childValue) {
86
+ out.push(`${SUBAGENT_CHILD_ENV_VAR}=${JSON.stringify(childValue)}`);
87
+ }
88
+ const scratchpadValue = env[SUBAGENT_SCRATCHPAD_ENV_VAR];
89
+ if (scratchpadValue) {
90
+ out.push(`${SUBAGENT_SCRATCHPAD_ENV_VAR}=${JSON.stringify(scratchpadValue)}`);
91
+ }
92
+ return out;
56
93
  }
57
94
 
58
95
  export function buildSubagentProcessArgs(
@@ -124,7 +161,7 @@ export function createSubagentLaunchPlan(input: SubagentLaunchInput): SubagentLa
124
161
  input.modelOverride,
125
162
  session,
126
163
  ),
127
- env: buildSubagentProcessEnv(),
164
+ env: buildSubagentProcessEnv(process.env, input.scratchpadName),
128
165
  cwd: input.cwd ?? input.defaultCwd,
129
166
  session,
130
167
  };
@@ -12,6 +12,7 @@ export interface SubagentChildArtifact {
12
12
  index: number;
13
13
  agent: string;
14
14
  trackingName?: string;
15
+ scratchpadName?: string;
15
16
  task: string;
16
17
  status: SubagentRunStatus;
17
18
  exitCode?: number;
@@ -186,7 +187,7 @@ export function createInitialRunRecord(input: {
186
187
  mode: SubagentRunMode;
187
188
  contextMode: "fresh" | "fork";
188
189
  cwd: string;
189
- children: Array<{ agent: string; trackingName?: string; task: string; cwd?: string }>;
190
+ children: Array<{ agent: string; trackingName?: string; scratchpadName?: string; task: string; cwd?: string }>;
190
191
  now?: string;
191
192
  }): SubagentRunRecord {
192
193
  const now = input.now ?? new Date().toISOString();
@@ -203,6 +204,7 @@ export function createInitialRunRecord(input: {
203
204
  index,
204
205
  agent: child.agent,
205
206
  trackingName: child.trackingName,
207
+ scratchpadName: child.scratchpadName,
206
208
  task: child.task,
207
209
  cwd: child.cwd,
208
210
  status: "queued",
@@ -23,6 +23,7 @@ import { logWarning } from "../workflow-logger.js";
23
23
  // session hook calling startAuto) would be silently dropped because Node's
24
24
  // EventEmitter does not buffer events for late subscribers.
25
25
  import { initCmuxEventListeners } from "../../cmux/index.js";
26
+ import { registerPersonaCommands } from "../persona-status.js";
26
27
  import { BRAND } from "../strings.js";
27
28
 
28
29
  export { writeCrashLog } from "./crash-log.js";
@@ -126,6 +127,7 @@ export function registerWorkflowExtension(pi: ExtensionAPI): void {
126
127
  ["memory-tools", () => registerMemoryTools(pi)],
127
128
  ["exec-tools", () => registerExecTools(pi)],
128
129
  ["schedule-wakeup-tool", () => registerScheduleWakeupTool(pi)],
130
+ ["persona-commands", () => registerPersonaCommands(pi)],
129
131
  ["shortcuts", () => registerShortcuts(pi)],
130
132
  // cmux is a library (no pi), so gsd sets up the event listeners on its
131
133
  // behalf using the shared event channel contract. Registration is
@@ -357,6 +357,15 @@ async function resetAskUserQuestionsTurnCache(): Promise<void> {
357
357
  resetAskUserQuestionsCache();
358
358
  }
359
359
 
360
+ async function initPersonaStatusChip(ctx: ExtensionContext): Promise<void> {
361
+ try {
362
+ const { initPersonaWidget } = await import("../persona-status.js");
363
+ await initPersonaWidget(ctx);
364
+ } catch {
365
+ // Non-fatal: persona chip simply won't render if the registry is unavailable.
366
+ }
367
+ }
368
+
360
369
  async function syncServiceTierStatus(ctx: ExtensionContext): Promise<void> {
361
370
  const { getEffectiveServiceTier, formatServiceTierFooterStatus } = await import("../service-tier.js");
362
371
  ctx.ui.setStatus("gsd-fast", formatServiceTierFooterStatus(getEffectiveServiceTier(), ctx.model?.id));
@@ -498,6 +507,7 @@ export function registerHooks(
498
507
  approvalQuestionAbortInFlight = false;
499
508
  clearDeferredApprovalGate();
500
509
  await resetAskUserQuestionsTurnCache();
510
+ await initPersonaStatusChip(ctx);
501
511
  await syncServiceTierStatus(ctx);
502
512
  await applyDisabledModelProviderPolicy(ctx);
503
513
  await applyCompactionThresholdOverride(ctx);
@@ -0,0 +1,109 @@
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 type {
7
+ ExtensionAPI,
8
+ ExtensionCommandContext,
9
+ ExtensionContext,
10
+ } from "@otto/pi-coding-agent";
11
+ import {
12
+ PersonaRegistry,
13
+ type PersonaManifest,
14
+ handleList,
15
+ handleCurrent,
16
+ handleSwitch,
17
+ handleReset,
18
+ handleInstall,
19
+ handleUninstall,
20
+ } from "@otto/coworker-persona";
21
+
22
+ // Sorts ahead of alphabetic extension status keys so the chip lands leftmost
23
+ // in the footer's extension-status block.
24
+ const STATUS_KEY = "00-persona";
25
+
26
+ const SUBCOMMANDS = ["list", "current", "switch", "install", "uninstall", "reset"] as const;
27
+
28
+ function ottoHome(): string {
29
+ return process.env.OTTO_HOME || join(homedir(), ".otto");
30
+ }
31
+
32
+ function getRegistry(): PersonaRegistry {
33
+ return new PersonaRegistry({ ottoHome: ottoHome() });
34
+ }
35
+
36
+ function formatPersonaChip(persona: PersonaManifest): string {
37
+ const { icon, label } = persona.status_line;
38
+ return `${icon} ${label}`.trim();
39
+ }
40
+
41
+ async function refreshPersonaChip(ctx: ExtensionContext, registry: PersonaRegistry): Promise<void> {
42
+ if (!ctx.hasUI) return;
43
+ try {
44
+ const active = await registry.activeInWorkspace(ctx.cwd);
45
+ ctx.ui.setStatus(STATUS_KEY, formatPersonaChip(active));
46
+ } catch {
47
+ ctx.ui.setStatus(STATUS_KEY, undefined);
48
+ }
49
+ }
50
+
51
+ // Called on session_start to seed the default persona and render the chip.
52
+ export async function initPersonaWidget(ctx: ExtensionContext): Promise<void> {
53
+ const registry = getRegistry();
54
+ try {
55
+ await registry.ensureDefaultInstalled();
56
+ } catch {
57
+ // Non-fatal: chip simply won't render if the default can't be installed.
58
+ }
59
+ await refreshPersonaChip(ctx, registry);
60
+ }
61
+
62
+ export function registerPersonaCommands(pi: ExtensionAPI): void {
63
+ pi.registerCommand("persona", {
64
+ description: "Manage Otto co-worker personas (list, current, switch, install, uninstall, reset)",
65
+ getArgumentCompletions: (prefix: string) =>
66
+ SUBCOMMANDS.filter((s) => s.startsWith(prefix)).map((s) => ({ value: s, label: s })),
67
+ handler: async (args: string, ctx: ExtensionCommandContext) => {
68
+ const registry = getRegistry();
69
+ await registry.ensureDefaultInstalled();
70
+ const [sub, ...rest] = args.trim().split(/\s+/).filter(Boolean);
71
+ const ws = ctx.cwd;
72
+ try {
73
+ let lines: string[];
74
+ switch (sub ?? "current") {
75
+ case "list":
76
+ lines = await handleList(registry, ws);
77
+ break;
78
+ case "current":
79
+ lines = await handleCurrent(registry, ws);
80
+ break;
81
+ case "switch":
82
+ lines = await handleSwitch(registry, ws, rest[0]);
83
+ await refreshPersonaChip(ctx, registry);
84
+ break;
85
+ case "reset":
86
+ lines = await handleReset(registry, ws);
87
+ await refreshPersonaChip(ctx, registry);
88
+ break;
89
+ case "install":
90
+ lines = await handleInstall(registry, rest[0]);
91
+ break;
92
+ case "uninstall":
93
+ lines = await handleUninstall(registry, rest[0], [ws]);
94
+ await refreshPersonaChip(ctx, registry);
95
+ break;
96
+ default:
97
+ ctx.ui.notify(
98
+ `Unknown subcommand: ${sub}. Try: ${SUBCOMMANDS.join(", ")}`,
99
+ "warning",
100
+ );
101
+ return;
102
+ }
103
+ ctx.ui.notify(lines.join("\n"), "info");
104
+ } catch (err) {
105
+ ctx.ui.notify(err instanceof Error ? err.message : String(err), "error");
106
+ }
107
+ },
108
+ });
109
+ }
@@ -16,6 +16,40 @@ import { invalidateAllCaches } from "../cache.ts";
16
16
  import { deriveState, invalidateStateCache } from "../state.ts";
17
17
  import { writeIntegrationBranch } from "../git-service.ts";
18
18
 
19
+ // Hermetic git environment for the whole test process.
20
+ //
21
+ // These tests create throwaway repos and run tight add/commit loops (some 200+
22
+ // commits). Git's background auto-maintenance (detached `gc --auto`) would fire
23
+ // mid-loop and repack/prune loose objects while the next `git add`/`commit` is
24
+ // still referencing them, producing intermittent, load-dependent failures like
25
+ // "error: invalid object … / Error building trees" or "unable to create
26
+ // temporary file … / failed to write commit object" under a busy `npm test`.
27
+ // Disabling gc/maintenance is the actual fix; isolating global/system config and
28
+ // pinning identity/signing is defense-in-depth so the suite never depends on (or
29
+ // is perturbed by) the developer's git setup.
30
+ {
31
+ const gitConfig: Array<[string, string]> = [
32
+ ["user.name", "OTTO Test"],
33
+ ["user.email", "test@otto.invalid"],
34
+ ["commit.gpgsign", "false"],
35
+ ["tag.gpgsign", "false"],
36
+ ["gc.auto", "0"],
37
+ ["gc.autoDetach", "false"],
38
+ ["maintenance.auto", "false"],
39
+ ["core.hooksPath", "/dev/null"],
40
+ ["core.fsmonitor", "false"],
41
+ ];
42
+ process.env.GIT_CONFIG_GLOBAL = "/dev/null";
43
+ process.env.GIT_CONFIG_SYSTEM = "/dev/null";
44
+ process.env.GIT_CONFIG_NOSYSTEM = "1";
45
+ process.env.GIT_TERMINAL_PROMPT = "0";
46
+ process.env.GIT_CONFIG_COUNT = String(gitConfig.length);
47
+ gitConfig.forEach(([key, value], i) => {
48
+ process.env[`GIT_CONFIG_KEY_${i}`] = key;
49
+ process.env[`GIT_CONFIG_VALUE_${i}`] = value;
50
+ });
51
+ }
52
+
19
53
  const tmpDirs: string[] = [];
20
54
 
21
55
  function makeTmpBase(): string {