@selesai/code 0.13.0 → 0.13.1

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 (461) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/core/agent-session.d.ts +1 -1
  3. package/dist/core/agent-session.js +1 -1
  4. package/dist/core/sdk.d.ts +2 -2
  5. package/dist/core/sdk.js +1 -1
  6. package/dist/core/system-prompt.d.ts +1 -1
  7. package/dist/core/system-prompt.js +1 -1
  8. package/dist/extensions/ascii.txt +9 -0
  9. package/dist/extensions/package.json +1 -2
  10. package/dist/extensions/pi-hermes-memory/CHANGELOG.md +371 -0
  11. package/dist/extensions/pi-hermes-memory/LICENSE +21 -0
  12. package/dist/extensions/pi-hermes-memory/README.md +643 -0
  13. package/dist/extensions/pi-hermes-memory/docs/0.1/TASKS.md +197 -0
  14. package/dist/extensions/pi-hermes-memory/docs/0.2/PLAN.md +290 -0
  15. package/dist/extensions/pi-hermes-memory/docs/0.2/TASKS.md +134 -0
  16. package/dist/extensions/pi-hermes-memory/docs/0.2/TEST-PLAN.md +216 -0
  17. package/dist/extensions/pi-hermes-memory/docs/0.3/PLAN.md +330 -0
  18. package/dist/extensions/pi-hermes-memory/docs/0.3/TASKS.md +125 -0
  19. package/dist/extensions/pi-hermes-memory/docs/0.4/PLAN.md +160 -0
  20. package/dist/extensions/pi-hermes-memory/docs/0.4/TASKS.md +113 -0
  21. package/dist/extensions/pi-hermes-memory/docs/0.6/CHANGELOG.md +57 -0
  22. package/dist/extensions/pi-hermes-memory/docs/0.6/PLAN.md +202 -0
  23. package/dist/extensions/pi-hermes-memory/docs/0.6/TASKS.md +144 -0
  24. package/dist/extensions/pi-hermes-memory/docs/0.7/PLAN.md +349 -0
  25. package/dist/extensions/pi-hermes-memory/docs/0.7/TASKS.md +110 -0
  26. package/dist/extensions/pi-hermes-memory/docs/PUBLISHING.md +149 -0
  27. package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +468 -0
  28. package/dist/extensions/pi-hermes-memory/docs/images/memory-architecture.svg +1 -0
  29. package/dist/extensions/pi-hermes-memory/docs/images/pi-logo.svg +22 -0
  30. package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.png +0 -0
  31. package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.svg +19 -0
  32. package/dist/extensions/pi-hermes-memory/docs/images/security-flow.svg +1 -0
  33. package/dist/extensions/pi-hermes-memory/docs/images/session-lifecycle.svg +1 -0
  34. package/dist/extensions/pi-hermes-memory/docs/images/source-architecture.svg +1 -0
  35. package/dist/extensions/pi-hermes-memory/docs/mermaid/memory-architecture.mmd +49 -0
  36. package/dist/extensions/pi-hermes-memory/docs/mermaid/security-flow.mmd +40 -0
  37. package/dist/extensions/pi-hermes-memory/docs/mermaid/session-lifecycle.mmd +56 -0
  38. package/dist/extensions/pi-hermes-memory/docs/mermaid/source-architecture.mmd +54 -0
  39. package/dist/extensions/pi-hermes-memory/package-lock.json +3799 -0
  40. package/dist/extensions/pi-hermes-memory/package.json +66 -0
  41. package/dist/extensions/pi-hermes-memory/scripts/check-min-sdk.mjs +99 -0
  42. package/dist/extensions/pi-hermes-memory/scripts/ensure-dev.mjs +57 -0
  43. package/dist/extensions/pi-hermes-memory/src/auto-consolidation-warning.ts +6 -0
  44. package/dist/extensions/pi-hermes-memory/src/config.ts +178 -0
  45. package/dist/extensions/pi-hermes-memory/src/constants.ts +424 -0
  46. package/dist/extensions/pi-hermes-memory/src/extension-root-migration.ts +639 -0
  47. package/dist/extensions/pi-hermes-memory/src/handlers/auto-consolidate.ts +401 -0
  48. package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +297 -0
  49. package/dist/extensions/pi-hermes-memory/src/handlers/child-process-watchdog.mjs +90 -0
  50. package/dist/extensions/pi-hermes-memory/src/handlers/correction-detector.ts +300 -0
  51. package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +86 -0
  52. package/dist/extensions/pi-hermes-memory/src/handlers/insights.ts +78 -0
  53. package/dist/extensions/pi-hermes-memory/src/handlers/interview.ts +37 -0
  54. package/dist/extensions/pi-hermes-memory/src/handlers/learn-memory.ts +186 -0
  55. package/dist/extensions/pi-hermes-memory/src/handlers/message-parts.ts +27 -0
  56. package/dist/extensions/pi-hermes-memory/src/handlers/pi-child-process.ts +485 -0
  57. package/dist/extensions/pi-hermes-memory/src/handlers/preview-context.ts +105 -0
  58. package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +506 -0
  59. package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +145 -0
  60. package/dist/extensions/pi-hermes-memory/src/handlers/session-flush.ts +151 -0
  61. package/dist/extensions/pi-hermes-memory/src/handlers/session-live-index.ts +94 -0
  62. package/dist/extensions/pi-hermes-memory/src/handlers/skills-command.ts +1334 -0
  63. package/dist/extensions/pi-hermes-memory/src/handlers/standing-pin.ts +111 -0
  64. package/dist/extensions/pi-hermes-memory/src/handlers/switch-project.ts +75 -0
  65. package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +266 -0
  66. package/dist/extensions/pi-hermes-memory/src/index.ts +378 -0
  67. package/dist/extensions/pi-hermes-memory/src/lifecycle-timing.ts +54 -0
  68. package/dist/extensions/pi-hermes-memory/src/paths.ts +61 -0
  69. package/dist/extensions/pi-hermes-memory/src/project-context.ts +13 -0
  70. package/dist/extensions/pi-hermes-memory/src/project-memory-migration.ts +93 -0
  71. package/dist/extensions/pi-hermes-memory/src/project.ts +157 -0
  72. package/dist/extensions/pi-hermes-memory/src/prompt-context.ts +55 -0
  73. package/dist/extensions/pi-hermes-memory/src/store/atomic-lock-coordinator.ts +375 -0
  74. package/dist/extensions/pi-hermes-memory/src/store/canonical-storage-path.ts +54 -0
  75. package/dist/extensions/pi-hermes-memory/src/store/content-scanner.ts +101 -0
  76. package/dist/extensions/pi-hermes-memory/src/store/db.ts +1180 -0
  77. package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +101 -0
  78. package/dist/extensions/pi-hermes-memory/src/store/markdown-mutation-lock.ts +38 -0
  79. package/dist/extensions/pi-hermes-memory/src/store/memory-lookup.ts +24 -0
  80. package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +1191 -0
  81. package/dist/extensions/pi-hermes-memory/src/store/recovery-maintenance.ts +66 -0
  82. package/dist/extensions/pi-hermes-memory/src/store/schema.ts +118 -0
  83. package/dist/extensions/pi-hermes-memory/src/store/session-anchor-search.ts +472 -0
  84. package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +511 -0
  85. package/dist/extensions/pi-hermes-memory/src/store/session-parser.ts +213 -0
  86. package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +234 -0
  87. package/dist/extensions/pi-hermes-memory/src/store/skill-store.ts +950 -0
  88. package/dist/extensions/pi-hermes-memory/src/store/skill-utils.ts +133 -0
  89. package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +1002 -0
  90. package/dist/extensions/pi-hermes-memory/src/store/sqlite-native.ts +241 -0
  91. package/dist/extensions/pi-hermes-memory/src/store/standing-instructions.ts +247 -0
  92. package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +95 -0
  93. package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +469 -0
  94. package/dist/extensions/pi-hermes-memory/src/tools/session-search-tool.ts +246 -0
  95. package/dist/extensions/pi-hermes-memory/src/tools/shared-output-view.ts +170 -0
  96. package/dist/extensions/pi-hermes-memory/src/tools/skill-tool.ts +333 -0
  97. package/dist/extensions/pi-hermes-memory/src/tools/tool-result-views.ts +105 -0
  98. package/dist/extensions/pi-hermes-memory/src/types.ts +214 -0
  99. package/dist/extensions/pi-hermes-memory/tests/config.test.ts +434 -0
  100. package/dist/extensions/pi-hermes-memory/tests/extension-root-migration.test.ts +368 -0
  101. package/dist/extensions/pi-hermes-memory/tests/handlers/auto-consolidate.test.ts +984 -0
  102. package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +950 -0
  103. package/dist/extensions/pi-hermes-memory/tests/handlers/correction-detector.test.ts +671 -0
  104. package/dist/extensions/pi-hermes-memory/tests/handlers/insights.test.ts +157 -0
  105. package/dist/extensions/pi-hermes-memory/tests/handlers/interview.test.ts +127 -0
  106. package/dist/extensions/pi-hermes-memory/tests/handlers/pi-child-process.test.ts +905 -0
  107. package/dist/extensions/pi-hermes-memory/tests/handlers/preview-context.test.ts +152 -0
  108. package/dist/extensions/pi-hermes-memory/tests/handlers/prompt-context.test.ts +166 -0
  109. package/dist/extensions/pi-hermes-memory/tests/handlers/resources-discover.test.ts +71 -0
  110. package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +614 -0
  111. package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +192 -0
  112. package/dist/extensions/pi-hermes-memory/tests/handlers/session-flush.test.ts +677 -0
  113. package/dist/extensions/pi-hermes-memory/tests/handlers/session-live-index.test.ts +225 -0
  114. package/dist/extensions/pi-hermes-memory/tests/handlers/skills-command.test.ts +827 -0
  115. package/dist/extensions/pi-hermes-memory/tests/handlers/standing-pin.test.ts +134 -0
  116. package/dist/extensions/pi-hermes-memory/tests/handlers/sync-markdown-memories.test.ts +491 -0
  117. package/dist/extensions/pi-hermes-memory/tests/handlers/system-prompt.test.ts +199 -0
  118. package/dist/extensions/pi-hermes-memory/tests/handlers/thinking-max.test.ts +64 -0
  119. package/dist/extensions/pi-hermes-memory/tests/index.test.ts +30 -0
  120. package/dist/extensions/pi-hermes-memory/tests/integration/flow.test.ts +126 -0
  121. package/dist/extensions/pi-hermes-memory/tests/lifecycle-timing.test.ts +76 -0
  122. package/dist/extensions/pi-hermes-memory/tests/paths.test.ts +23 -0
  123. package/dist/extensions/pi-hermes-memory/tests/project-memory-migration.test.ts +80 -0
  124. package/dist/extensions/pi-hermes-memory/tests/project-rebinding.test.ts +115 -0
  125. package/dist/extensions/pi-hermes-memory/tests/project.test.ts +120 -0
  126. package/dist/extensions/pi-hermes-memory/tests/run-all-timeout.test.ts +107 -0
  127. package/dist/extensions/pi-hermes-memory/tests/run-all.sh +45 -0
  128. package/dist/extensions/pi-hermes-memory/tests/store/atomic-lock-coordinator.test.ts +381 -0
  129. package/dist/extensions/pi-hermes-memory/tests/store/content-scanner.test.ts +388 -0
  130. package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +1046 -0
  131. package/dist/extensions/pi-hermes-memory/tests/store/markdown-mutation-lock.test.ts +34 -0
  132. package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +2150 -0
  133. package/dist/extensions/pi-hermes-memory/tests/store/recovery-maintenance.test.ts +170 -0
  134. package/dist/extensions/pi-hermes-memory/tests/store/session-anchor-search.test.ts +210 -0
  135. package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +643 -0
  136. package/dist/extensions/pi-hermes-memory/tests/store/session-parser.test.ts +282 -0
  137. package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +287 -0
  138. package/dist/extensions/pi-hermes-memory/tests/store/skill-store.test.ts +678 -0
  139. package/dist/extensions/pi-hermes-memory/tests/store/skill-utils.test.ts +21 -0
  140. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-lazy-load.test.ts +78 -0
  141. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +543 -0
  142. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +164 -0
  143. package/dist/extensions/pi-hermes-memory/tests/store/standing-instructions.test.ts +171 -0
  144. package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +84 -0
  145. package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +709 -0
  146. package/dist/extensions/pi-hermes-memory/tests/tools/session-search-tool.test.ts +345 -0
  147. package/dist/extensions/pi-hermes-memory/tests/tools/shared-output-view.test.ts +362 -0
  148. package/dist/extensions/pi-hermes-memory/tests/tools/skill-tool.test.ts +478 -0
  149. package/dist/extensions/pi-hermes-memory/tests/tools/tool-result-renderer-wiring.test.ts +40 -0
  150. package/dist/extensions/pi-hermes-memory/tsconfig.json +19 -0
  151. package/dist/extensions/pi-subagents/.oxlintrc.json +43 -0
  152. package/dist/extensions/pi-subagents/AGENTS.md +5 -0
  153. package/dist/extensions/pi-subagents/CHANGELOG.md +157 -0
  154. package/dist/extensions/pi-subagents/README.md +12 -6
  155. package/dist/extensions/pi-subagents/VISION.md +81 -0
  156. package/dist/extensions/pi-subagents/agents/claude-code-writer.md +15 -0
  157. package/dist/extensions/pi-subagents/agents/claude-code.md +15 -0
  158. package/dist/extensions/pi-subagents/agents/codex-exec-writer.md +15 -0
  159. package/dist/extensions/pi-subagents/agents/codex-exec.md +15 -0
  160. package/dist/extensions/pi-subagents/agents/cursor-agent-writer.md +14 -0
  161. package/dist/extensions/pi-subagents/agents/cursor-agent.md +14 -0
  162. package/dist/extensions/pi-subagents/agents/reviewer.md +1 -3
  163. package/dist/extensions/pi-subagents/docs/agents.md +488 -0
  164. package/dist/extensions/pi-subagents/docs/configuration.md +46 -9
  165. package/dist/extensions/pi-subagents/docs/extension-api.md +42 -3
  166. package/dist/extensions/pi-subagents/docs/models.md +27 -4
  167. package/dist/extensions/pi-subagents/docs/observability.md +10 -9
  168. package/dist/extensions/pi-subagents/docs/tool-reference.md +102 -6
  169. package/dist/extensions/pi-subagents/docs/workflows.md +135 -0
  170. package/dist/extensions/pi-subagents/package-lock.json +389 -2
  171. package/dist/extensions/pi-subagents/package.json +3 -1
  172. package/dist/extensions/pi-subagents/prompts/review-loop.md +2 -2
  173. package/dist/extensions/pi-subagents/skills/council-mode/SKILL.md +1 -1
  174. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +3 -1
  175. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +7 -3
  176. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
  177. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +26 -5
  178. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +41 -22
  179. package/dist/extensions/pi-subagents/src/agents/agent-refinements.ts +4 -4
  180. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +9 -2
  181. package/dist/extensions/pi-subagents/src/agents/agents.ts +322 -75
  182. package/dist/extensions/pi-subagents/src/agents/builtin-names.ts +6 -0
  183. package/dist/extensions/pi-subagents/src/agents/runtime-agent-events.ts +70 -0
  184. package/dist/extensions/pi-subagents/src/agents/runtime-agent-registry.ts +27 -20
  185. package/dist/extensions/pi-subagents/src/api/agents.ts +10 -5
  186. package/dist/extensions/pi-subagents/src/api/background-work.ts +5 -1
  187. package/dist/extensions/pi-subagents/src/api/delegation.ts +0 -7
  188. package/dist/extensions/pi-subagents/src/api/preflight.ts +34 -12
  189. package/dist/extensions/pi-subagents/src/extension/config.ts +70 -0
  190. package/dist/extensions/pi-subagents/src/extension/doctor.ts +3 -3
  191. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +5 -3
  192. package/dist/extensions/pi-subagents/src/extension/index.ts +83 -30
  193. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +44 -15
  194. package/dist/extensions/pi-subagents/src/extension/rpc.ts +55 -19
  195. package/dist/extensions/pi-subagents/src/extension/schemas.ts +41 -15
  196. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -31
  197. package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +2 -1
  198. package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +2 -10
  199. package/dist/extensions/pi-subagents/src/inspectors/herdr/session-roots-codec.ts +42 -0
  200. package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +51 -3
  201. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +2 -0
  202. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +5 -6
  203. package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +77 -10
  204. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +176 -53
  205. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +19 -12
  206. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +29 -27
  207. package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +20 -3
  208. package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +23 -261
  209. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +73 -7
  210. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +8 -3
  211. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +74 -8
  212. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +37 -21
  213. package/dist/extensions/pi-subagents/src/runs/background/inspect-rpc.ts +8 -8
  214. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +184 -9
  215. package/dist/extensions/pi-subagents/src/runs/background/result-delivery-ownership.ts +45 -0
  216. package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +28 -14
  217. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +38 -15
  218. package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +1 -1
  219. package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +1 -1
  220. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +50 -13
  221. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +93 -8
  222. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +10 -4
  223. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +4 -14
  224. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +549 -377
  225. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +58 -10
  226. package/dist/extensions/pi-subagents/src/runs/background/terminal-run-index.ts +1 -1
  227. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +26 -1
  228. package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +23 -9
  229. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +9 -2
  230. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +2 -2
  231. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +204 -129
  232. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +9 -0
  233. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +23 -1
  234. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +773 -311
  235. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +140 -115
  236. package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +119 -0
  237. package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +463 -0
  238. package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +19 -4
  239. package/dist/extensions/pi-subagents/src/runs/shared/child-launch-plan.ts +151 -0
  240. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +21 -7
  241. package/dist/extensions/pi-subagents/src/runs/shared/claude-code-adapter.ts +129 -0
  242. package/dist/extensions/pi-subagents/src/runs/shared/codex-exec-adapter.ts +129 -0
  243. package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +89 -0
  244. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +5 -4
  245. package/dist/extensions/pi-subagents/src/runs/shared/cursor-agent-adapter.ts +114 -0
  246. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +3 -3
  247. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-contract.ts +167 -0
  248. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +122 -0
  249. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +348 -55
  250. package/dist/extensions/pi-subagents/src/runs/shared/fast-mode-extension.ts +5 -5
  251. package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +230 -0
  252. package/dist/extensions/pi-subagents/src/runs/shared/lane-metadata.ts +105 -0
  253. package/dist/extensions/pi-subagents/src/runs/shared/launch-cwd.ts +16 -0
  254. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +2 -1
  255. package/dist/extensions/pi-subagents/src/runs/shared/mcp-config-sources.ts +422 -0
  256. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +221 -158
  257. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-grant.ts +197 -0
  258. package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +69 -7
  259. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +47 -6
  260. package/dist/extensions/pi-subagents/src/runs/shared/mutation-evidence.ts +7 -2
  261. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +9 -3
  262. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +9 -5
  263. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +419 -7
  264. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +15 -1
  265. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +81 -8
  266. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +13 -0
  267. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +21 -1
  268. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +44 -4
  269. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +98 -13
  270. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +1 -1
  271. package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +847 -0
  272. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +18 -0
  273. package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +46 -0
  274. package/dist/extensions/pi-subagents/src/shared/extension-context.ts +24 -0
  275. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +21 -0
  276. package/dist/extensions/pi-subagents/src/shared/formatters.ts +18 -3
  277. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +5 -1
  278. package/dist/extensions/pi-subagents/src/shared/pruned-fork.ts +450 -0
  279. package/dist/extensions/pi-subagents/src/shared/session-file-trust.ts +19 -0
  280. package/dist/extensions/pi-subagents/src/shared/session-tokens.ts +14 -3
  281. package/dist/extensions/pi-subagents/src/shared/settings.ts +19 -105
  282. package/dist/extensions/pi-subagents/src/shared/shortcuts.ts +17 -0
  283. package/dist/extensions/pi-subagents/src/shared/types.ts +359 -40
  284. package/dist/extensions/pi-subagents/src/shared/utils.ts +41 -84
  285. package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +116 -0
  286. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +1 -9
  287. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +0 -4
  288. package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +1 -2
  289. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +378 -88
  290. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +22 -11
  291. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +3 -0
  292. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +147 -79
  293. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +11 -5
  294. package/dist/extensions/pi-subagents/src/tui/fleet.ts +39 -18
  295. package/dist/extensions/pi-subagents/src/tui/render.ts +369 -46
  296. package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +1 -1
  297. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +6 -3
  298. package/dist/extensions/pi-subagents/src/workflows/host-command.ts +230 -0
  299. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +740 -58
  300. package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +121 -0
  301. package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +270 -0
  302. package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +195 -6
  303. package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +246 -0
  304. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
  305. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1114 -260
  306. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +34 -0
  307. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +150 -3
  308. package/dist/extensions/pi-subagents/test/integration/claude-code-smoke.test.ts +52 -0
  309. package/dist/extensions/pi-subagents/test/integration/claude-code-writer-smoke.test.ts +55 -0
  310. package/dist/extensions/pi-subagents/test/integration/codex-exec-smoke.test.ts +53 -0
  311. package/dist/extensions/pi-subagents/test/integration/codex-exec-writer-smoke.test.ts +57 -0
  312. package/dist/extensions/pi-subagents/test/integration/cursor-agent-smoke.test.ts +59 -0
  313. package/dist/extensions/pi-subagents/test/integration/cursor-agent-writer-smoke.test.ts +62 -0
  314. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +57 -1
  315. package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +1 -0
  316. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +20 -0
  317. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +4 -3
  318. package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +2 -2
  319. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +54 -4
  320. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +482 -4
  321. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +157 -9
  322. package/dist/extensions/pi-subagents/test/integration/session-tokens.test.ts +5 -5
  323. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1508 -291
  324. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +423 -1
  325. package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +8 -0
  326. package/dist/extensions/pi-subagents/test/support/cursor-smoke-inputs.ts +51 -0
  327. package/dist/extensions/pi-subagents/test/support/helpers.ts +2 -0
  328. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +5 -5
  329. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +6 -6
  330. package/dist/extensions/pi-subagents/test/unit/abort-recovery.test.ts +152 -0
  331. package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +48 -0
  332. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +184 -6
  333. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +66 -6
  334. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +77 -0
  335. package/dist/extensions/pi-subagents/test/unit/agent-refinements.test.ts +18 -0
  336. package/dist/extensions/pi-subagents/test/unit/anti-slop-oxlint.test.ts +86 -0
  337. package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +1 -1
  338. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +101 -1
  339. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +121 -0
  340. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +28 -0
  341. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +14 -7
  342. package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +53 -0
  343. package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +190 -0
  344. package/dist/extensions/pi-subagents/test/unit/async-status-snapshot.test.ts +42 -0
  345. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +8 -4
  346. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +23 -0
  347. package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +78 -1
  348. package/dist/extensions/pi-subagents/test/unit/child-launch-plan.test.ts +94 -0
  349. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +21 -0
  350. package/dist/extensions/pi-subagents/test/unit/child-session-name.test.ts +50 -0
  351. package/dist/extensions/pi-subagents/test/unit/claude-code-adapter.test.ts +245 -0
  352. package/dist/extensions/pi-subagents/test/unit/codex-exec-adapter.test.ts +192 -0
  353. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +27 -0
  354. package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +150 -0
  355. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +21 -0
  356. package/dist/extensions/pi-subagents/test/unit/cursor-agent-adapter.test.ts +259 -0
  357. package/dist/extensions/pi-subagents/test/unit/cursor-smoke-inputs.test.ts +77 -0
  358. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +1 -4
  359. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +1 -1
  360. package/dist/extensions/pi-subagents/test/unit/extension-context.test.ts +27 -0
  361. package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +223 -0
  362. package/dist/extensions/pi-subagents/test/unit/fast-mode-extension.test.ts +27 -0
  363. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +208 -2
  364. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +29 -1
  365. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +110 -1
  366. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +10 -0
  367. package/dist/extensions/pi-subagents/test/unit/formatters.test.ts +14 -0
  368. package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +18 -9
  369. package/dist/extensions/pi-subagents/test/unit/herdr-session-roots-codec.test.ts +63 -0
  370. package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +2 -2
  371. package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +132 -0
  372. package/dist/extensions/pi-subagents/test/unit/host-command.test.ts +156 -0
  373. package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +98 -0
  374. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +178 -26
  375. package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +2 -1
  376. package/dist/extensions/pi-subagents/test/unit/inspect-rpc.test.ts +21 -0
  377. package/dist/extensions/pi-subagents/test/unit/mcp-direct-tool-grant.test.ts +138 -0
  378. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +1 -1
  379. package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +91 -0
  380. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +72 -7
  381. package/dist/extensions/pi-subagents/test/unit/mutation-evidence.test.ts +21 -0
  382. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +1 -0
  383. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +20 -2
  384. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +129 -1
  385. package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +2 -2
  386. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +4 -0
  387. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +358 -0
  388. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +574 -21
  389. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +109 -1
  390. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +71 -1
  391. package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +7 -7
  392. package/dist/extensions/pi-subagents/test/unit/pruned-fork.test.ts +214 -0
  393. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +29 -8
  394. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +53 -0
  395. package/dist/extensions/pi-subagents/test/unit/result-delivery-ownership.test.ts +34 -0
  396. package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +101 -3
  397. package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +1 -0
  398. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +10 -8
  399. package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +71 -1
  400. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +41 -7
  401. package/dist/extensions/pi-subagents/test/unit/runtime-agent-registration.test.ts +136 -2
  402. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +137 -0
  403. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +33 -12
  404. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +504 -1
  405. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +8 -0
  406. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
  407. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +12 -1
  408. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +3 -5
  409. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +5 -6
  410. package/dist/extensions/pi-subagents/test/unit/subagent-action-recovery.test.ts +0 -8
  411. package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +5 -0
  412. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +157 -2
  413. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +1 -1
  414. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +63 -4
  415. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +27 -23
  416. package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +44 -0
  417. package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +1 -0
  418. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +7 -5
  419. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +106 -0
  420. package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +484 -9
  421. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +38 -4
  422. package/dist/extensions/pi-subagents/test/unit/workflow-preflight.test.ts +155 -0
  423. package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +318 -0
  424. package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +365 -0
  425. package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +349 -0
  426. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +21 -0
  427. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +2 -7
  428. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/index.ts +13 -0
  429. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/rules/no-service-constructor-imports.ts +52 -0
  430. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/index.ts +41 -0
  431. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-chained-type-assertions.ts +77 -0
  432. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-conditional-empty-object-spread.ts +49 -0
  433. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-known-value-widening.ts +247 -0
  434. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-module-mocking.ts +91 -0
  435. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-object-parameters.ts +126 -0
  436. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-apply.ts +28 -0
  437. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-get.ts +28 -0
  438. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-runtime-typeof.ts +67 -0
  439. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-shape-in-symbol-names.ts +39 -0
  440. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-parameters.ts +83 -0
  441. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-returns.ts +115 -0
  442. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-type-aliases.ts +72 -0
  443. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unsafe-dictionary-type.ts +134 -0
  444. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-widen-then-assert.ts +366 -0
  445. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/require-safety-comment-for-type-assertion.ts +62 -0
  446. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/dictionary-types.ts +502 -0
  447. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/lexical-type-parameters.ts +60 -0
  448. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/reflect-method.ts +35 -0
  449. package/dist/extensions/pi-tool-display/tests/capabilities.test.ts +1 -1
  450. package/dist/extensions/pi-tool-display/tests/settings-inspector.test.ts +2 -2
  451. package/dist/extensions/pi-tool-display/tests/tool-overrides-mcp.test.ts +1 -1
  452. package/dist/modes/interactive/interactive-mode.js +7 -7
  453. package/dist/skills/workflow/SKILL.md +65 -50
  454. package/package.json +112 -110
  455. package/dist/extensions/enable-readonly-tools.test.ts +0 -63
  456. package/dist/extensions/enable-readonly-tools.ts +0 -24
  457. package/dist/extensions/model-prompt-injector/config.json +0 -16
  458. package/dist/extensions/model-prompt-injector/index.test.ts +0 -102
  459. package/dist/extensions/model-prompt-injector/index.ts +0 -148
  460. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +0 -98
  461. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +0 -250
@@ -0,0 +1,639 @@
1
+ import fs from "node:fs/promises";
2
+ import { existsSync } from "node:fs";
3
+ import { randomUUID } from "node:crypto";
4
+ import path from "node:path";
5
+ import { AtomicLockCoordinator, type AtomicLockLease } from "./store/atomic-lock-coordinator.js";
6
+ import { canonicalStoragePathSync } from "./store/canonical-storage-path.js";
7
+ import { createRequire } from "node:module";
8
+ import { isBunRuntime, loadBetterSqlite3 } from "./store/sqlite-native.js";
9
+
10
+ type MigrationDatabase = {
11
+ exec: (sql: string) => void;
12
+ prepare: (sql: string) => { get: (...args: unknown[]) => unknown; run: (...args: unknown[]) => unknown };
13
+ close: () => void;
14
+ pragma: (query: string, options?: { simple?: boolean }) => unknown;
15
+ backup: (
16
+ destination: string,
17
+ options?: { progress?: () => void },
18
+ ) => Promise<void> | void;
19
+ };
20
+
21
+ type MigrationDatabaseCtor = new (
22
+ dbPath: string,
23
+ options?: { readonly?: boolean; fileMustExist?: boolean; timeout?: number },
24
+ ) => MigrationDatabase;
25
+
26
+ type BunDatabaseInstance = {
27
+ exec: (sql: string) => void;
28
+ prepare: (sql: string) => { get: (...args: unknown[]) => unknown; run: (...args: unknown[]) => unknown };
29
+ close: () => void;
30
+ };
31
+
32
+ /**
33
+ * bun:sqlite shim covering the slice of the better-sqlite3 API this migration
34
+ * uses. Compiled Pi cannot resolve better-sqlite3 at all, so under Bun this is
35
+ * the only way the legacy-root migration can touch sessions.db.
36
+ */
37
+ function createBunMigrationDatabaseCtor(): MigrationDatabaseCtor {
38
+ const require = createRequire(import.meta.url);
39
+ const bunSqlite = require("bun:sqlite") as {
40
+ Database: new (
41
+ dbPath: string,
42
+ options?: { readonly?: boolean; readwrite?: boolean; create?: boolean },
43
+ ) => BunDatabaseInstance;
44
+ };
45
+
46
+ return class BunMigrationDatabase implements MigrationDatabase {
47
+ private readonly db: BunDatabaseInstance;
48
+
49
+ constructor(
50
+ dbPath: string,
51
+ options: { readonly?: boolean; fileMustExist?: boolean; timeout?: number } = {},
52
+ ) {
53
+ const readonly = options.readonly === true;
54
+ this.db = new bunSqlite.Database(dbPath, {
55
+ readonly,
56
+ readwrite: !readonly,
57
+ create: !readonly && options.fileMustExist !== true,
58
+ });
59
+ if (typeof options.timeout === "number") {
60
+ this.db.exec(`PRAGMA busy_timeout = ${Math.max(0, Math.trunc(options.timeout))}`);
61
+ }
62
+ }
63
+
64
+ exec(sql: string): void {
65
+ this.db.exec(sql);
66
+ }
67
+
68
+ prepare(sql: string): { get: (...args: unknown[]) => unknown; run: (...args: unknown[]) => unknown } {
69
+ return this.db.prepare(sql);
70
+ }
71
+
72
+ close(): void {
73
+ this.db.close();
74
+ }
75
+
76
+ pragma(query: string, options?: { simple?: boolean }): unknown {
77
+ if (query.includes("=")) {
78
+ this.db.exec(`PRAGMA ${query}`);
79
+ return undefined;
80
+ }
81
+ const row = this.db.prepare(`PRAGMA ${query}`).get();
82
+ if (typeof row !== "object" || row === null) return options?.simple ? row : [];
83
+ return options?.simple ? Object.values(row)[0] : [row];
84
+ }
85
+
86
+ /**
87
+ * bun:sqlite exposes no online backup API. `VACUUM INTO` writes an
88
+ * equivalent consistent snapshot under a read transaction, but has no
89
+ * incremental callback, so the heartbeat only fires either side of it.
90
+ */
91
+ async backup(destination: string, options?: { progress?: () => void }): Promise<void> {
92
+ options?.progress?.();
93
+ this.db.prepare("VACUUM INTO ?").run(destination);
94
+ options?.progress?.();
95
+ }
96
+ };
97
+ }
98
+
99
+ let cachedDatabaseCtor: MigrationDatabaseCtor | null = null;
100
+
101
+ /**
102
+ * Resolved on first use, never at import time: this module is pulled in by
103
+ * src/index.ts at extension load, and a module-scope native load turns any
104
+ * SQLite resolve/ABI failure into "Failed to load extension" (issue #117).
105
+ */
106
+ function getDatabaseCtor(): MigrationDatabaseCtor {
107
+ if (!cachedDatabaseCtor) {
108
+ cachedDatabaseCtor = isBunRuntime()
109
+ ? createBunMigrationDatabaseCtor()
110
+ : (loadBetterSqlite3() as MigrationDatabaseCtor);
111
+ }
112
+ return cachedDatabaseCtor;
113
+ }
114
+ const DATABASE_FILES = ["sessions.db", "sessions.db-wal", "sessions.db-shm"] as const;
115
+ const DATABASE_MIGRATION_PENDING_FILE = ".sessions-db-migration-pending";
116
+
117
+ export interface ExtensionRootMigrationResult {
118
+ moved: number;
119
+ merged: number;
120
+ skipped: number;
121
+ warnings: string[];
122
+ criticalFailures: Array<{
123
+ name: string;
124
+ source: string;
125
+ target: string;
126
+ message: string;
127
+ }>;
128
+ }
129
+
130
+ export interface ExtensionRootMigrationOptions {
131
+ moveFile?: (source: string, target: string) => Promise<void>;
132
+ publishDatabaseFile?: (source: string, target: string) => Promise<void>;
133
+ retireDatabaseFile?: (source: string, target: string) => Promise<void>;
134
+ backupDatabase?: (source: string, staged: string, onProgress?: () => void) => Promise<void>;
135
+ onDatabaseBackupProgress?: () => void;
136
+ }
137
+
138
+ const MIGRATION_LOCK_WAIT_MS = 5000;
139
+ const MIGRATION_LOCK_POLL_MS = 50;
140
+
141
+ export function isDatabaseMigrationPending(legacyRoot: string, targetRoot: string): boolean {
142
+ return existsSync(path.join(targetRoot, DATABASE_MIGRATION_PENDING_FILE))
143
+ || (existsSync(path.join(legacyRoot, "sessions.db")) && !existsSync(path.join(targetRoot, "sessions.db")));
144
+ }
145
+
146
+ async function pathExists(filePath: string): Promise<boolean> {
147
+ try {
148
+ await fs.access(filePath);
149
+ return true;
150
+ } catch {
151
+ return false;
152
+ }
153
+ }
154
+
155
+ async function pathEntryExists(filePath: string): Promise<boolean> {
156
+ try {
157
+ await fs.lstat(filePath);
158
+ return true;
159
+ } catch (error) {
160
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return false;
161
+ throw error;
162
+ }
163
+ }
164
+
165
+ async function databaseFilesAt(root: string): Promise<string[]> {
166
+ const names: string[] = [];
167
+ for (const name of DATABASE_FILES) {
168
+ if (await pathEntryExists(path.join(root, name))) names.push(name);
169
+ }
170
+ return names;
171
+ }
172
+
173
+ async function moveFileSafe(source: string, target: string): Promise<void> {
174
+ await fs.mkdir(path.dirname(target), { recursive: true });
175
+
176
+ try {
177
+ await fs.rename(source, target);
178
+ return;
179
+ } catch (error) {
180
+ const code = (error as NodeJS.ErrnoException)?.code;
181
+ if (code !== "EXDEV") throw error;
182
+ }
183
+
184
+ await fs.copyFile(source, target);
185
+ await fs.unlink(source);
186
+ }
187
+
188
+ async function stageDatabaseSnapshot(
189
+ source: string,
190
+ staged: string,
191
+ onProgress?: () => void,
192
+ ): Promise<void> {
193
+ const Database = getDatabaseCtor();
194
+ const sourceDb = new Database(source, { readonly: true, fileMustExist: true });
195
+ try {
196
+ await sourceDb.backup(staged, {
197
+ progress: () => {
198
+ onProgress?.();
199
+ return 64;
200
+ },
201
+ });
202
+ } finally {
203
+ sourceDb.close();
204
+ }
205
+
206
+ const stagedDb = new Database(staged, { readonly: true, fileMustExist: true });
207
+ try {
208
+ const check = stagedDb.pragma("integrity_check", { simple: true });
209
+ if (check !== "ok") throw new Error(`staged SQLite snapshot failed integrity_check: ${String(check)}`);
210
+ } finally {
211
+ stagedDb.close();
212
+ }
213
+ }
214
+
215
+ function isDatabaseCorruption(error: unknown): boolean {
216
+ const code = typeof error === "object" && error && "code" in error
217
+ ? String((error as { code?: unknown }).code)
218
+ : "";
219
+ if (code === "SQLITE_CORRUPT" || code === "SQLITE_NOTADB") return true;
220
+ const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
221
+ return message.includes("database disk image is malformed")
222
+ || message.includes("file is not a database")
223
+ || message.includes("database schema is corrupt")
224
+ || message.includes("malformed database schema")
225
+ || message.includes("failed integrity_check");
226
+ }
227
+
228
+ async function acquireMigrationLease(legacyRoot: string, targetRoot: string): Promise<AtomicLockLease> {
229
+ const coordinator = AtomicLockCoordinator.shared(path.join(targetRoot, ".pi-hermes-locks.sqlite"));
230
+ const sourceIdentity = canonicalStoragePathSync(path.join(legacyRoot, "sessions.db"));
231
+ const targetIdentity = canonicalStoragePathSync(path.join(targetRoot, "sessions.db"));
232
+ const key = `extension-root-migration:${sourceIdentity}:${targetIdentity}`;
233
+ const deadline = Date.now() + MIGRATION_LOCK_WAIT_MS;
234
+
235
+ while (true) {
236
+ const lease = coordinator.tryAcquire(key, { staleMs: 300_000 });
237
+ if (lease) return lease;
238
+ if (Date.now() >= deadline) {
239
+ throw new Error(`SQLite extension-root migration already in progress for ${targetIdentity}`);
240
+ }
241
+ await new Promise<void>((resolve) => setTimeout(resolve, MIGRATION_LOCK_POLL_MS));
242
+ }
243
+ }
244
+
245
+ class DatabaseGenerationMoveError extends Error {
246
+ constructor(message: string, readonly moved: string[], options: { cause: unknown }) {
247
+ super(message, options);
248
+ }
249
+ }
250
+
251
+ async function moveDatabaseGeneration(
252
+ names: string[],
253
+ sourceRoot: string,
254
+ holdingRoot: string,
255
+ move: (source: string, target: string) => Promise<void>,
256
+ ): Promise<string[]> {
257
+ const moved: string[] = [];
258
+ await fs.mkdir(holdingRoot, { mode: 0o700 });
259
+ const orderedNames = [...names].sort((left, right) => Number(left === "sessions.db") - Number(right === "sessions.db"));
260
+ try {
261
+ for (const name of orderedNames) {
262
+ const source = path.join(sourceRoot, name);
263
+ const target = path.join(holdingRoot, name);
264
+ try {
265
+ await move(source, target);
266
+ moved.push(name);
267
+ } catch (error) {
268
+ if (await pathEntryExists(target)) moved.push(name);
269
+ throw error;
270
+ }
271
+ }
272
+ return moved;
273
+ } catch (error) {
274
+ throw new DatabaseGenerationMoveError(
275
+ error instanceof Error ? error.message : String(error),
276
+ moved,
277
+ { cause: error },
278
+ );
279
+ }
280
+ }
281
+
282
+ async function restoreDatabaseGeneration(names: string[], holdingRoot: string, sourceRoot: string): Promise<string[]> {
283
+ const failures: string[] = [];
284
+ for (const name of [...names].reverse()) {
285
+ const held = path.join(holdingRoot, name);
286
+ if (!await pathEntryExists(held)) continue;
287
+ try {
288
+ await fs.link(held, path.join(sourceRoot, name));
289
+ await fs.unlink(held);
290
+ } catch (error) {
291
+ failures.push(`${name}: ${error instanceof Error ? error.message : String(error)}`);
292
+ }
293
+ }
294
+ return failures;
295
+ }
296
+
297
+ interface FileIdentity {
298
+ dev: number;
299
+ ino: number;
300
+ }
301
+
302
+ async function fileIdentity(filePath: string): Promise<FileIdentity> {
303
+ const stat = await fs.lstat(filePath);
304
+ return { dev: stat.dev, ino: stat.ino };
305
+ }
306
+
307
+ async function unlinkIfOwned(filePath: string, identity: FileIdentity): Promise<void> {
308
+ try {
309
+ const current = await fileIdentity(filePath);
310
+ if (current.dev === identity.dev && current.ino === identity.ino) await fs.unlink(filePath);
311
+ } catch (error) {
312
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
313
+ }
314
+ }
315
+
316
+ async function stageDatabaseSymlink(source: string, staged: string): Promise<void> {
317
+ const before = await fs.readlink(source);
318
+ await fs.symlink(path.resolve(path.dirname(source), before), staged);
319
+ const after = await fs.readlink(source);
320
+ if (before !== after) throw new Error("sessions.db symlink changed while staging");
321
+ }
322
+
323
+ async function moveDirContents(
324
+ sourceDir: string,
325
+ targetDir: string,
326
+ result: ExtensionRootMigrationResult,
327
+ moveFile: (source: string, target: string) => Promise<void>,
328
+ relativeDir = "",
329
+ ): Promise<void> {
330
+ await fs.mkdir(targetDir, { recursive: true });
331
+
332
+ const entries = await fs.readdir(sourceDir, { withFileTypes: true });
333
+ for (const entry of entries) {
334
+ if (!relativeDir && DATABASE_FILES.includes(entry.name as typeof DATABASE_FILES[number])) {
335
+ continue;
336
+ }
337
+ const sourcePath = path.join(sourceDir, entry.name);
338
+ const targetPath = path.join(targetDir, entry.name);
339
+
340
+ if (!await pathExists(targetPath)) {
341
+ try {
342
+ await moveFile(sourcePath, targetPath);
343
+ result.moved++;
344
+ } catch (error) {
345
+ const message = error instanceof Error ? error.message : String(error);
346
+ result.warnings.push(`${sourcePath}: ${message}`);
347
+ }
348
+ continue;
349
+ }
350
+
351
+ if (entry.isDirectory()) {
352
+ await moveDirContents(
353
+ sourcePath,
354
+ targetPath,
355
+ result,
356
+ moveFile,
357
+ path.join(relativeDir, entry.name),
358
+ );
359
+ result.merged++;
360
+ try {
361
+ const remaining = await fs.readdir(sourcePath);
362
+ if (remaining.length === 0) await fs.rmdir(sourcePath);
363
+ } catch {
364
+ // best effort
365
+ }
366
+ continue;
367
+ }
368
+
369
+ result.skipped++;
370
+ }
371
+ }
372
+
373
+ async function publishDatabaseFile(source: string, target: string): Promise<void> {
374
+ if ((await fs.lstat(source)).isSymbolicLink()) {
375
+ await fs.symlink(await fs.readlink(source), target);
376
+ return;
377
+ }
378
+ await fs.link(source, target);
379
+ }
380
+
381
+ async function migrateDatabaseGeneration(
382
+ legacyRoot: string,
383
+ targetRoot: string,
384
+ result: ExtensionRootMigrationResult,
385
+ publish: (source: string, target: string) => Promise<void>,
386
+ retire: (source: string, target: string) => Promise<void>,
387
+ backup: (source: string, staged: string, onProgress?: () => void) => Promise<void>,
388
+ onBackupProgress?: () => void,
389
+ ): Promise<void> {
390
+ let lease: AtomicLockLease | null = null;
391
+ try {
392
+ lease = await acquireMigrationLease(legacyRoot, targetRoot);
393
+ } catch (error) {
394
+ const message = error instanceof Error ? error.message : String(error);
395
+ result.warnings.push(`${path.join(legacyRoot, "sessions.db")}: ${message}`);
396
+ result.criticalFailures.push({
397
+ name: "sessions.db",
398
+ source: path.join(legacyRoot, "sessions.db"),
399
+ target: path.join(targetRoot, "sessions.db"),
400
+ message,
401
+ });
402
+ return;
403
+ }
404
+
405
+ try {
406
+ const pendingMarker = path.join(targetRoot, DATABASE_MIGRATION_PENDING_FILE);
407
+ const hadPendingMarker = await pathEntryExists(pendingMarker);
408
+ const sourceNames = await databaseFilesAt(legacyRoot);
409
+ const targetNames = await databaseFilesAt(targetRoot);
410
+ if (sourceNames.length === 0) {
411
+ if (!hadPendingMarker) return;
412
+ if (targetNames.includes("sessions.db")) {
413
+ await fs.unlink(pendingMarker);
414
+ return;
415
+ }
416
+ const retirementDirs = (await fs.readdir(legacyRoot))
417
+ .filter((name) => name.startsWith(".sessions-db-retirement-"));
418
+ const message = retirementDirs.length > 0
419
+ ? `an interrupted migration preserved recovery artifacts at ${retirementDirs.map((name) => path.join(legacyRoot, name)).join(", ")}`
420
+ : "an interrupted migration has no complete source or destination SQLite generation";
421
+ result.warnings.push(`${path.join(legacyRoot, "sessions.db")}: ${message}`);
422
+ result.criticalFailures.push({
423
+ name: "sessions.db",
424
+ source: path.join(legacyRoot, "sessions.db"),
425
+ target: path.join(targetRoot, "sessions.db"),
426
+ message,
427
+ });
428
+ return;
429
+ }
430
+
431
+ if (targetNames.includes("sessions.db")) {
432
+ if (hadPendingMarker) {
433
+ const message = "an incomplete migration left both legacy and destination SQLite generations; manual recovery is required";
434
+ result.warnings.push(`${path.join(legacyRoot, "sessions.db")}: ${message}`);
435
+ result.criticalFailures.push({
436
+ name: "sessions.db",
437
+ source: path.join(legacyRoot, "sessions.db"),
438
+ target: path.join(targetRoot, "sessions.db"),
439
+ message,
440
+ });
441
+ return;
442
+ }
443
+ result.skipped += sourceNames.length;
444
+ return;
445
+ }
446
+
447
+ if (!sourceNames.includes("sessions.db") || targetNames.length > 0) {
448
+ const message = targetNames.length > 0
449
+ ? `destination contains a partial SQLite generation: ${targetNames.join(", ")}`
450
+ : "legacy SQLite sidecars exist without sessions.db";
451
+ result.warnings.push(`${path.join(legacyRoot, "sessions.db")}: ${message}`);
452
+ result.criticalFailures.push({
453
+ name: "sessions.db",
454
+ source: path.join(legacyRoot, "sessions.db"),
455
+ target: path.join(targetRoot, "sessions.db"),
456
+ message,
457
+ });
458
+ return;
459
+ }
460
+
461
+ await fs.mkdir(targetRoot, { recursive: true });
462
+ const stagingDir = path.join(targetRoot, `.sessions-db-migration-${randomUUID()}`);
463
+ const retirementDir = path.join(legacyRoot, `.sessions-db-retirement-${randomUUID()}`);
464
+ const published = new Map<string, FileIdentity>();
465
+ let retired: string[] = [];
466
+ let preserveRetirement = false;
467
+ let keepPendingMarker = false;
468
+ let writeLock: {
469
+ pragma: (query: string) => unknown;
470
+ exec: (sql: string) => void;
471
+ close: () => void;
472
+ } | null = null;
473
+ let corruptGeneration = false;
474
+ let generationNames = sourceNames;
475
+ try {
476
+ await fs.writeFile(pendingMarker, `${process.pid}:${randomUUID()}\n`, { mode: 0o600 });
477
+ await fs.mkdir(stagingDir, { mode: 0o700 });
478
+ const source = path.join(legacyRoot, "sessions.db");
479
+ const staged = path.join(stagingDir, "sessions.db");
480
+ const sourceState = await fs.lstat(source);
481
+ try {
482
+ writeLock = new (getDatabaseCtor())(source, { fileMustExist: true, timeout: 0 });
483
+ writeLock.pragma("busy_timeout = 0");
484
+ writeLock.exec("BEGIN IMMEDIATE");
485
+ } catch (error) {
486
+ if (!isDatabaseCorruption(error)) throw error;
487
+ if (writeLock) {
488
+ try { writeLock.close(); } catch {}
489
+ writeLock = null;
490
+ }
491
+ corruptGeneration = true;
492
+ }
493
+ generationNames = await databaseFilesAt(legacyRoot);
494
+
495
+ if (sourceState.isSymbolicLink()) {
496
+ if (sourceNames.length !== 1) {
497
+ throw new Error("symlinked sessions.db cannot be combined with legacy SQLite sidecars");
498
+ }
499
+ await stageDatabaseSymlink(source, staged);
500
+ corruptGeneration = false;
501
+ } else if (sourceState.isFile()) {
502
+ if (!corruptGeneration) {
503
+ try {
504
+ await backup(source, staged, onBackupProgress);
505
+ } catch (error) {
506
+ if (!isDatabaseCorruption(error)) throw error;
507
+ corruptGeneration = true;
508
+ try { await fs.unlink(staged); } catch {}
509
+ }
510
+ }
511
+ if (corruptGeneration) {
512
+ try {
513
+ retired = await moveDatabaseGeneration(generationNames, legacyRoot, retirementDir, retire);
514
+ } catch (error) {
515
+ if (error instanceof DatabaseGenerationMoveError) retired = error.moved;
516
+ throw error;
517
+ }
518
+ for (const name of retired) {
519
+ const target = path.join(targetRoot, name);
520
+ await publish(path.join(retirementDir, name), target);
521
+ published.set(target, await fileIdentity(target));
522
+ }
523
+ }
524
+ } else {
525
+ throw new Error("sessions.db is not a regular file or symlink");
526
+ }
527
+
528
+ if (!corruptGeneration) {
529
+ try {
530
+ retired = await moveDatabaseGeneration(generationNames, legacyRoot, retirementDir, retire);
531
+ } catch (error) {
532
+ if (error instanceof DatabaseGenerationMoveError) retired = error.moved;
533
+ throw error;
534
+ }
535
+ const target = path.join(targetRoot, "sessions.db");
536
+ await publish(staged, target);
537
+ published.set(target, await fileIdentity(target));
538
+ }
539
+
540
+ if (writeLock) {
541
+ // Every generation file has already been moved out of legacyRoot, so this
542
+ // transaction can no longer guard anything and its database no longer
543
+ // exists at this path. bun:sqlite reports SQLITE_IOERR here where
544
+ // better-sqlite3 succeeds; either way a failed cleanup COMMIT must not
545
+ // roll back an otherwise completed migration.
546
+ // The connection is closed in `finally` either way.
547
+ try { writeLock.exec("COMMIT"); } catch {}
548
+ }
549
+ result.moved += generationNames.length;
550
+ } catch (error) {
551
+ for (const [target, identity] of [...published.entries()].reverse()) {
552
+ try { await unlinkIfOwned(target, identity); } catch {}
553
+ }
554
+ let restoreFailures: string[] = [];
555
+ if (retired.length > 0) {
556
+ restoreFailures = await restoreDatabaseGeneration(retired, retirementDir, legacyRoot);
557
+ preserveRetirement = restoreFailures.length > 0;
558
+ keepPendingMarker = preserveRetirement;
559
+ }
560
+ const destinationPreserved = await pathEntryExists(path.join(targetRoot, "sessions.db"));
561
+ if (destinationPreserved) keepPendingMarker = true;
562
+ if (writeLock) {
563
+ try { writeLock.exec("ROLLBACK"); } catch {}
564
+ }
565
+ const baseMessage = error instanceof Error ? error.message : String(error);
566
+ let message = restoreFailures.length > 0
567
+ ? `${baseMessage}; recovery artifacts preserved at ${retirementDir} (${restoreFailures.join("; ")})`
568
+ : baseMessage;
569
+ if (destinationPreserved) {
570
+ message += `; an unowned destination generation was preserved at ${path.join(targetRoot, "sessions.db")}`;
571
+ }
572
+ result.warnings.push(`${path.join(legacyRoot, "sessions.db")}: ${message}`);
573
+ result.criticalFailures.push({
574
+ name: "sessions.db",
575
+ source: path.join(legacyRoot, "sessions.db"),
576
+ target: path.join(targetRoot, "sessions.db"),
577
+ message,
578
+ });
579
+ } finally {
580
+ if (writeLock) {
581
+ try { writeLock.close(); } catch {}
582
+ }
583
+ try { await fs.rm(stagingDir, { recursive: true, force: true }); } catch {}
584
+ if (!preserveRetirement) {
585
+ try { await fs.rm(retirementDir, { recursive: true, force: true }); } catch {}
586
+ }
587
+ if (!keepPendingMarker) {
588
+ try { await fs.unlink(pendingMarker); } catch {}
589
+ }
590
+ }
591
+ } finally {
592
+ lease.release();
593
+ }
594
+ }
595
+
596
+ /**
597
+ * Move legacy extension assets from ~/.selesai/agent/memory into
598
+ * ~/.selesai/agent/pi-hermes-memory. Existing destination files win.
599
+ */
600
+ export async function migrateExtensionRoot(
601
+ legacyRoot: string,
602
+ targetRoot: string,
603
+ options: ExtensionRootMigrationOptions = {},
604
+ ): Promise<ExtensionRootMigrationResult> {
605
+ const result: ExtensionRootMigrationResult = {
606
+ moved: 0,
607
+ merged: 0,
608
+ skipped: 0,
609
+ warnings: [],
610
+ criticalFailures: [],
611
+ };
612
+
613
+ if (path.resolve(legacyRoot) === path.resolve(targetRoot)) return result;
614
+ if (!existsSync(legacyRoot)) return result;
615
+
616
+ await fs.mkdir(targetRoot, { recursive: true });
617
+ await migrateDatabaseGeneration(
618
+ legacyRoot,
619
+ targetRoot,
620
+ result,
621
+ options.publishDatabaseFile ?? options.moveFile ?? publishDatabaseFile,
622
+ options.retireDatabaseFile ?? moveFileSafe,
623
+ options.backupDatabase ?? stageDatabaseSnapshot,
624
+ options.onDatabaseBackupProgress,
625
+ );
626
+ if (result.criticalFailures.some((failure) => failure.name === "sessions.db")) return result;
627
+ await moveDirContents(legacyRoot, targetRoot, result, options.moveFile ?? moveFileSafe);
628
+
629
+ try {
630
+ const remaining = await fs.readdir(legacyRoot);
631
+ if (remaining.length === 0) {
632
+ await fs.rmdir(legacyRoot);
633
+ }
634
+ } catch {
635
+ // best effort
636
+ }
637
+
638
+ return result;
639
+ }