@selesai/code 0.12.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 (466) hide show
  1. package/CHANGELOG.md +17 -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/core/usage-totals.d.ts +2 -0
  9. package/dist/core/usage-totals.js +10 -0
  10. package/dist/extensions/ascii.txt +9 -0
  11. package/dist/extensions/package.json +1 -2
  12. package/dist/extensions/pi-hermes-memory/CHANGELOG.md +371 -0
  13. package/dist/extensions/pi-hermes-memory/LICENSE +21 -0
  14. package/dist/extensions/pi-hermes-memory/README.md +643 -0
  15. package/dist/extensions/pi-hermes-memory/docs/0.1/TASKS.md +197 -0
  16. package/dist/extensions/pi-hermes-memory/docs/0.2/PLAN.md +290 -0
  17. package/dist/extensions/pi-hermes-memory/docs/0.2/TASKS.md +134 -0
  18. package/dist/extensions/pi-hermes-memory/docs/0.2/TEST-PLAN.md +216 -0
  19. package/dist/extensions/pi-hermes-memory/docs/0.3/PLAN.md +330 -0
  20. package/dist/extensions/pi-hermes-memory/docs/0.3/TASKS.md +125 -0
  21. package/dist/extensions/pi-hermes-memory/docs/0.4/PLAN.md +160 -0
  22. package/dist/extensions/pi-hermes-memory/docs/0.4/TASKS.md +113 -0
  23. package/dist/extensions/pi-hermes-memory/docs/0.6/CHANGELOG.md +57 -0
  24. package/dist/extensions/pi-hermes-memory/docs/0.6/PLAN.md +202 -0
  25. package/dist/extensions/pi-hermes-memory/docs/0.6/TASKS.md +144 -0
  26. package/dist/extensions/pi-hermes-memory/docs/0.7/PLAN.md +349 -0
  27. package/dist/extensions/pi-hermes-memory/docs/0.7/TASKS.md +110 -0
  28. package/dist/extensions/pi-hermes-memory/docs/PUBLISHING.md +149 -0
  29. package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +468 -0
  30. package/dist/extensions/pi-hermes-memory/docs/images/memory-architecture.svg +1 -0
  31. package/dist/extensions/pi-hermes-memory/docs/images/pi-logo.svg +22 -0
  32. package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.png +0 -0
  33. package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.svg +19 -0
  34. package/dist/extensions/pi-hermes-memory/docs/images/security-flow.svg +1 -0
  35. package/dist/extensions/pi-hermes-memory/docs/images/session-lifecycle.svg +1 -0
  36. package/dist/extensions/pi-hermes-memory/docs/images/source-architecture.svg +1 -0
  37. package/dist/extensions/pi-hermes-memory/docs/mermaid/memory-architecture.mmd +49 -0
  38. package/dist/extensions/pi-hermes-memory/docs/mermaid/security-flow.mmd +40 -0
  39. package/dist/extensions/pi-hermes-memory/docs/mermaid/session-lifecycle.mmd +56 -0
  40. package/dist/extensions/pi-hermes-memory/docs/mermaid/source-architecture.mmd +54 -0
  41. package/dist/extensions/pi-hermes-memory/package-lock.json +3799 -0
  42. package/dist/extensions/pi-hermes-memory/package.json +66 -0
  43. package/dist/extensions/pi-hermes-memory/scripts/check-min-sdk.mjs +99 -0
  44. package/dist/extensions/pi-hermes-memory/scripts/ensure-dev.mjs +57 -0
  45. package/dist/extensions/pi-hermes-memory/src/auto-consolidation-warning.ts +6 -0
  46. package/dist/extensions/pi-hermes-memory/src/config.ts +178 -0
  47. package/dist/extensions/pi-hermes-memory/src/constants.ts +424 -0
  48. package/dist/extensions/pi-hermes-memory/src/extension-root-migration.ts +639 -0
  49. package/dist/extensions/pi-hermes-memory/src/handlers/auto-consolidate.ts +401 -0
  50. package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +297 -0
  51. package/dist/extensions/pi-hermes-memory/src/handlers/child-process-watchdog.mjs +90 -0
  52. package/dist/extensions/pi-hermes-memory/src/handlers/correction-detector.ts +300 -0
  53. package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +86 -0
  54. package/dist/extensions/pi-hermes-memory/src/handlers/insights.ts +78 -0
  55. package/dist/extensions/pi-hermes-memory/src/handlers/interview.ts +37 -0
  56. package/dist/extensions/pi-hermes-memory/src/handlers/learn-memory.ts +186 -0
  57. package/dist/extensions/pi-hermes-memory/src/handlers/message-parts.ts +27 -0
  58. package/dist/extensions/pi-hermes-memory/src/handlers/pi-child-process.ts +485 -0
  59. package/dist/extensions/pi-hermes-memory/src/handlers/preview-context.ts +105 -0
  60. package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +506 -0
  61. package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +145 -0
  62. package/dist/extensions/pi-hermes-memory/src/handlers/session-flush.ts +151 -0
  63. package/dist/extensions/pi-hermes-memory/src/handlers/session-live-index.ts +94 -0
  64. package/dist/extensions/pi-hermes-memory/src/handlers/skills-command.ts +1334 -0
  65. package/dist/extensions/pi-hermes-memory/src/handlers/standing-pin.ts +111 -0
  66. package/dist/extensions/pi-hermes-memory/src/handlers/switch-project.ts +75 -0
  67. package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +266 -0
  68. package/dist/extensions/pi-hermes-memory/src/index.ts +378 -0
  69. package/dist/extensions/pi-hermes-memory/src/lifecycle-timing.ts +54 -0
  70. package/dist/extensions/pi-hermes-memory/src/paths.ts +61 -0
  71. package/dist/extensions/pi-hermes-memory/src/project-context.ts +13 -0
  72. package/dist/extensions/pi-hermes-memory/src/project-memory-migration.ts +93 -0
  73. package/dist/extensions/pi-hermes-memory/src/project.ts +157 -0
  74. package/dist/extensions/pi-hermes-memory/src/prompt-context.ts +55 -0
  75. package/dist/extensions/pi-hermes-memory/src/store/atomic-lock-coordinator.ts +375 -0
  76. package/dist/extensions/pi-hermes-memory/src/store/canonical-storage-path.ts +54 -0
  77. package/dist/extensions/pi-hermes-memory/src/store/content-scanner.ts +101 -0
  78. package/dist/extensions/pi-hermes-memory/src/store/db.ts +1180 -0
  79. package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +101 -0
  80. package/dist/extensions/pi-hermes-memory/src/store/markdown-mutation-lock.ts +38 -0
  81. package/dist/extensions/pi-hermes-memory/src/store/memory-lookup.ts +24 -0
  82. package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +1191 -0
  83. package/dist/extensions/pi-hermes-memory/src/store/recovery-maintenance.ts +66 -0
  84. package/dist/extensions/pi-hermes-memory/src/store/schema.ts +118 -0
  85. package/dist/extensions/pi-hermes-memory/src/store/session-anchor-search.ts +472 -0
  86. package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +511 -0
  87. package/dist/extensions/pi-hermes-memory/src/store/session-parser.ts +213 -0
  88. package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +234 -0
  89. package/dist/extensions/pi-hermes-memory/src/store/skill-store.ts +950 -0
  90. package/dist/extensions/pi-hermes-memory/src/store/skill-utils.ts +133 -0
  91. package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +1002 -0
  92. package/dist/extensions/pi-hermes-memory/src/store/sqlite-native.ts +241 -0
  93. package/dist/extensions/pi-hermes-memory/src/store/standing-instructions.ts +247 -0
  94. package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +95 -0
  95. package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +469 -0
  96. package/dist/extensions/pi-hermes-memory/src/tools/session-search-tool.ts +246 -0
  97. package/dist/extensions/pi-hermes-memory/src/tools/shared-output-view.ts +170 -0
  98. package/dist/extensions/pi-hermes-memory/src/tools/skill-tool.ts +333 -0
  99. package/dist/extensions/pi-hermes-memory/src/tools/tool-result-views.ts +105 -0
  100. package/dist/extensions/pi-hermes-memory/src/types.ts +214 -0
  101. package/dist/extensions/pi-hermes-memory/tests/config.test.ts +434 -0
  102. package/dist/extensions/pi-hermes-memory/tests/extension-root-migration.test.ts +368 -0
  103. package/dist/extensions/pi-hermes-memory/tests/handlers/auto-consolidate.test.ts +984 -0
  104. package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +950 -0
  105. package/dist/extensions/pi-hermes-memory/tests/handlers/correction-detector.test.ts +671 -0
  106. package/dist/extensions/pi-hermes-memory/tests/handlers/insights.test.ts +157 -0
  107. package/dist/extensions/pi-hermes-memory/tests/handlers/interview.test.ts +127 -0
  108. package/dist/extensions/pi-hermes-memory/tests/handlers/pi-child-process.test.ts +905 -0
  109. package/dist/extensions/pi-hermes-memory/tests/handlers/preview-context.test.ts +152 -0
  110. package/dist/extensions/pi-hermes-memory/tests/handlers/prompt-context.test.ts +166 -0
  111. package/dist/extensions/pi-hermes-memory/tests/handlers/resources-discover.test.ts +71 -0
  112. package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +614 -0
  113. package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +192 -0
  114. package/dist/extensions/pi-hermes-memory/tests/handlers/session-flush.test.ts +677 -0
  115. package/dist/extensions/pi-hermes-memory/tests/handlers/session-live-index.test.ts +225 -0
  116. package/dist/extensions/pi-hermes-memory/tests/handlers/skills-command.test.ts +827 -0
  117. package/dist/extensions/pi-hermes-memory/tests/handlers/standing-pin.test.ts +134 -0
  118. package/dist/extensions/pi-hermes-memory/tests/handlers/sync-markdown-memories.test.ts +491 -0
  119. package/dist/extensions/pi-hermes-memory/tests/handlers/system-prompt.test.ts +199 -0
  120. package/dist/extensions/pi-hermes-memory/tests/handlers/thinking-max.test.ts +64 -0
  121. package/dist/extensions/pi-hermes-memory/tests/index.test.ts +30 -0
  122. package/dist/extensions/pi-hermes-memory/tests/integration/flow.test.ts +126 -0
  123. package/dist/extensions/pi-hermes-memory/tests/lifecycle-timing.test.ts +76 -0
  124. package/dist/extensions/pi-hermes-memory/tests/paths.test.ts +23 -0
  125. package/dist/extensions/pi-hermes-memory/tests/project-memory-migration.test.ts +80 -0
  126. package/dist/extensions/pi-hermes-memory/tests/project-rebinding.test.ts +115 -0
  127. package/dist/extensions/pi-hermes-memory/tests/project.test.ts +120 -0
  128. package/dist/extensions/pi-hermes-memory/tests/run-all-timeout.test.ts +107 -0
  129. package/dist/extensions/pi-hermes-memory/tests/run-all.sh +45 -0
  130. package/dist/extensions/pi-hermes-memory/tests/store/atomic-lock-coordinator.test.ts +381 -0
  131. package/dist/extensions/pi-hermes-memory/tests/store/content-scanner.test.ts +388 -0
  132. package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +1046 -0
  133. package/dist/extensions/pi-hermes-memory/tests/store/markdown-mutation-lock.test.ts +34 -0
  134. package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +2150 -0
  135. package/dist/extensions/pi-hermes-memory/tests/store/recovery-maintenance.test.ts +170 -0
  136. package/dist/extensions/pi-hermes-memory/tests/store/session-anchor-search.test.ts +210 -0
  137. package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +643 -0
  138. package/dist/extensions/pi-hermes-memory/tests/store/session-parser.test.ts +282 -0
  139. package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +287 -0
  140. package/dist/extensions/pi-hermes-memory/tests/store/skill-store.test.ts +678 -0
  141. package/dist/extensions/pi-hermes-memory/tests/store/skill-utils.test.ts +21 -0
  142. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-lazy-load.test.ts +78 -0
  143. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +543 -0
  144. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +164 -0
  145. package/dist/extensions/pi-hermes-memory/tests/store/standing-instructions.test.ts +171 -0
  146. package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +84 -0
  147. package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +709 -0
  148. package/dist/extensions/pi-hermes-memory/tests/tools/session-search-tool.test.ts +345 -0
  149. package/dist/extensions/pi-hermes-memory/tests/tools/shared-output-view.test.ts +362 -0
  150. package/dist/extensions/pi-hermes-memory/tests/tools/skill-tool.test.ts +478 -0
  151. package/dist/extensions/pi-hermes-memory/tests/tools/tool-result-renderer-wiring.test.ts +40 -0
  152. package/dist/extensions/pi-hermes-memory/tsconfig.json +19 -0
  153. package/dist/extensions/pi-subagents/.oxlintrc.json +43 -0
  154. package/dist/extensions/pi-subagents/AGENTS.md +5 -0
  155. package/dist/extensions/pi-subagents/CHANGELOG.md +157 -0
  156. package/dist/extensions/pi-subagents/README.md +12 -6
  157. package/dist/extensions/pi-subagents/VISION.md +81 -0
  158. package/dist/extensions/pi-subagents/agents/claude-code-writer.md +15 -0
  159. package/dist/extensions/pi-subagents/agents/claude-code.md +15 -0
  160. package/dist/extensions/pi-subagents/agents/codex-exec-writer.md +15 -0
  161. package/dist/extensions/pi-subagents/agents/codex-exec.md +15 -0
  162. package/dist/extensions/pi-subagents/agents/cursor-agent-writer.md +14 -0
  163. package/dist/extensions/pi-subagents/agents/cursor-agent.md +14 -0
  164. package/dist/extensions/pi-subagents/agents/reviewer.md +1 -3
  165. package/dist/extensions/pi-subagents/docs/agents.md +488 -0
  166. package/dist/extensions/pi-subagents/docs/configuration.md +46 -9
  167. package/dist/extensions/pi-subagents/docs/extension-api.md +42 -3
  168. package/dist/extensions/pi-subagents/docs/models.md +27 -4
  169. package/dist/extensions/pi-subagents/docs/observability.md +10 -9
  170. package/dist/extensions/pi-subagents/docs/tool-reference.md +102 -6
  171. package/dist/extensions/pi-subagents/docs/workflows.md +135 -0
  172. package/dist/extensions/pi-subagents/package-lock.json +389 -2
  173. package/dist/extensions/pi-subagents/package.json +3 -1
  174. package/dist/extensions/pi-subagents/prompts/review-loop.md +2 -2
  175. package/dist/extensions/pi-subagents/skills/council-mode/SKILL.md +1 -1
  176. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +3 -1
  177. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +7 -3
  178. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
  179. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +26 -5
  180. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +41 -22
  181. package/dist/extensions/pi-subagents/src/agents/agent-refinements.ts +4 -4
  182. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +9 -2
  183. package/dist/extensions/pi-subagents/src/agents/agents.ts +322 -75
  184. package/dist/extensions/pi-subagents/src/agents/builtin-names.ts +6 -0
  185. package/dist/extensions/pi-subagents/src/agents/runtime-agent-events.ts +70 -0
  186. package/dist/extensions/pi-subagents/src/agents/runtime-agent-registry.ts +27 -20
  187. package/dist/extensions/pi-subagents/src/api/agents.ts +10 -5
  188. package/dist/extensions/pi-subagents/src/api/background-work.ts +5 -1
  189. package/dist/extensions/pi-subagents/src/api/delegation.ts +0 -7
  190. package/dist/extensions/pi-subagents/src/api/preflight.ts +34 -12
  191. package/dist/extensions/pi-subagents/src/extension/config.ts +70 -0
  192. package/dist/extensions/pi-subagents/src/extension/doctor.ts +3 -3
  193. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +5 -3
  194. package/dist/extensions/pi-subagents/src/extension/index.ts +83 -30
  195. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +44 -15
  196. package/dist/extensions/pi-subagents/src/extension/rpc.ts +55 -19
  197. package/dist/extensions/pi-subagents/src/extension/schemas.ts +41 -15
  198. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -31
  199. package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +2 -1
  200. package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +2 -10
  201. package/dist/extensions/pi-subagents/src/inspectors/herdr/session-roots-codec.ts +42 -0
  202. package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +51 -3
  203. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +2 -0
  204. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +5 -6
  205. package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +77 -10
  206. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +176 -53
  207. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +19 -12
  208. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +29 -27
  209. package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +20 -3
  210. package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +23 -261
  211. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +73 -7
  212. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +8 -3
  213. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +74 -8
  214. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +37 -21
  215. package/dist/extensions/pi-subagents/src/runs/background/inspect-rpc.ts +8 -8
  216. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +184 -9
  217. package/dist/extensions/pi-subagents/src/runs/background/result-delivery-ownership.ts +45 -0
  218. package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +28 -14
  219. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +38 -15
  220. package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +1 -1
  221. package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +1 -1
  222. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +50 -13
  223. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +93 -8
  224. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +10 -4
  225. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +4 -14
  226. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +549 -377
  227. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +58 -10
  228. package/dist/extensions/pi-subagents/src/runs/background/terminal-run-index.ts +1 -1
  229. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +26 -1
  230. package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +23 -9
  231. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +9 -2
  232. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +2 -2
  233. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +204 -129
  234. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +9 -0
  235. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +23 -1
  236. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +773 -311
  237. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +140 -115
  238. package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +119 -0
  239. package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +463 -0
  240. package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +19 -4
  241. package/dist/extensions/pi-subagents/src/runs/shared/child-launch-plan.ts +151 -0
  242. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +21 -7
  243. package/dist/extensions/pi-subagents/src/runs/shared/claude-code-adapter.ts +129 -0
  244. package/dist/extensions/pi-subagents/src/runs/shared/codex-exec-adapter.ts +129 -0
  245. package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +89 -0
  246. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +5 -4
  247. package/dist/extensions/pi-subagents/src/runs/shared/cursor-agent-adapter.ts +114 -0
  248. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +3 -3
  249. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-contract.ts +167 -0
  250. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +122 -0
  251. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +348 -55
  252. package/dist/extensions/pi-subagents/src/runs/shared/fast-mode-extension.ts +5 -5
  253. package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +230 -0
  254. package/dist/extensions/pi-subagents/src/runs/shared/lane-metadata.ts +105 -0
  255. package/dist/extensions/pi-subagents/src/runs/shared/launch-cwd.ts +16 -0
  256. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +2 -1
  257. package/dist/extensions/pi-subagents/src/runs/shared/mcp-config-sources.ts +422 -0
  258. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +221 -158
  259. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-grant.ts +197 -0
  260. package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +69 -7
  261. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +47 -6
  262. package/dist/extensions/pi-subagents/src/runs/shared/mutation-evidence.ts +7 -2
  263. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +9 -3
  264. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +9 -5
  265. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +419 -7
  266. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +15 -1
  267. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +81 -8
  268. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +13 -0
  269. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +21 -1
  270. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +44 -4
  271. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +98 -13
  272. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +1 -1
  273. package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +847 -0
  274. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +18 -0
  275. package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +46 -0
  276. package/dist/extensions/pi-subagents/src/shared/extension-context.ts +24 -0
  277. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +21 -0
  278. package/dist/extensions/pi-subagents/src/shared/formatters.ts +18 -3
  279. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +5 -1
  280. package/dist/extensions/pi-subagents/src/shared/pruned-fork.ts +450 -0
  281. package/dist/extensions/pi-subagents/src/shared/session-file-trust.ts +19 -0
  282. package/dist/extensions/pi-subagents/src/shared/session-tokens.ts +14 -3
  283. package/dist/extensions/pi-subagents/src/shared/settings.ts +19 -105
  284. package/dist/extensions/pi-subagents/src/shared/shortcuts.ts +17 -0
  285. package/dist/extensions/pi-subagents/src/shared/types.ts +359 -40
  286. package/dist/extensions/pi-subagents/src/shared/utils.ts +41 -84
  287. package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +116 -0
  288. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +1 -9
  289. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +0 -4
  290. package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +1 -2
  291. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +378 -88
  292. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +22 -11
  293. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +3 -0
  294. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +147 -79
  295. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +11 -5
  296. package/dist/extensions/pi-subagents/src/tui/fleet.ts +39 -18
  297. package/dist/extensions/pi-subagents/src/tui/render.ts +369 -46
  298. package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +1 -1
  299. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +6 -3
  300. package/dist/extensions/pi-subagents/src/workflows/host-command.ts +230 -0
  301. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +740 -58
  302. package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +121 -0
  303. package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +270 -0
  304. package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +195 -6
  305. package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +246 -0
  306. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
  307. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1114 -260
  308. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +34 -0
  309. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +150 -3
  310. package/dist/extensions/pi-subagents/test/integration/claude-code-smoke.test.ts +52 -0
  311. package/dist/extensions/pi-subagents/test/integration/claude-code-writer-smoke.test.ts +55 -0
  312. package/dist/extensions/pi-subagents/test/integration/codex-exec-smoke.test.ts +53 -0
  313. package/dist/extensions/pi-subagents/test/integration/codex-exec-writer-smoke.test.ts +57 -0
  314. package/dist/extensions/pi-subagents/test/integration/cursor-agent-smoke.test.ts +59 -0
  315. package/dist/extensions/pi-subagents/test/integration/cursor-agent-writer-smoke.test.ts +62 -0
  316. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +57 -1
  317. package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +1 -0
  318. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +20 -0
  319. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +4 -3
  320. package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +2 -2
  321. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +54 -4
  322. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +482 -4
  323. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +157 -9
  324. package/dist/extensions/pi-subagents/test/integration/session-tokens.test.ts +5 -5
  325. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1508 -291
  326. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +423 -1
  327. package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +8 -0
  328. package/dist/extensions/pi-subagents/test/support/cursor-smoke-inputs.ts +51 -0
  329. package/dist/extensions/pi-subagents/test/support/helpers.ts +2 -0
  330. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +5 -5
  331. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +6 -6
  332. package/dist/extensions/pi-subagents/test/unit/abort-recovery.test.ts +152 -0
  333. package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +48 -0
  334. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +184 -6
  335. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +66 -6
  336. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +77 -0
  337. package/dist/extensions/pi-subagents/test/unit/agent-refinements.test.ts +18 -0
  338. package/dist/extensions/pi-subagents/test/unit/anti-slop-oxlint.test.ts +86 -0
  339. package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +1 -1
  340. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +101 -1
  341. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +121 -0
  342. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +28 -0
  343. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +14 -7
  344. package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +53 -0
  345. package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +190 -0
  346. package/dist/extensions/pi-subagents/test/unit/async-status-snapshot.test.ts +42 -0
  347. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +8 -4
  348. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +23 -0
  349. package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +78 -1
  350. package/dist/extensions/pi-subagents/test/unit/child-launch-plan.test.ts +94 -0
  351. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +21 -0
  352. package/dist/extensions/pi-subagents/test/unit/child-session-name.test.ts +50 -0
  353. package/dist/extensions/pi-subagents/test/unit/claude-code-adapter.test.ts +245 -0
  354. package/dist/extensions/pi-subagents/test/unit/codex-exec-adapter.test.ts +192 -0
  355. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +27 -0
  356. package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +150 -0
  357. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +21 -0
  358. package/dist/extensions/pi-subagents/test/unit/cursor-agent-adapter.test.ts +259 -0
  359. package/dist/extensions/pi-subagents/test/unit/cursor-smoke-inputs.test.ts +77 -0
  360. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +1 -4
  361. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +1 -1
  362. package/dist/extensions/pi-subagents/test/unit/extension-context.test.ts +27 -0
  363. package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +223 -0
  364. package/dist/extensions/pi-subagents/test/unit/fast-mode-extension.test.ts +27 -0
  365. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +208 -2
  366. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +29 -1
  367. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +110 -1
  368. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +10 -0
  369. package/dist/extensions/pi-subagents/test/unit/formatters.test.ts +14 -0
  370. package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +18 -9
  371. package/dist/extensions/pi-subagents/test/unit/herdr-session-roots-codec.test.ts +63 -0
  372. package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +2 -2
  373. package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +132 -0
  374. package/dist/extensions/pi-subagents/test/unit/host-command.test.ts +156 -0
  375. package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +98 -0
  376. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +178 -26
  377. package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +2 -1
  378. package/dist/extensions/pi-subagents/test/unit/inspect-rpc.test.ts +21 -0
  379. package/dist/extensions/pi-subagents/test/unit/mcp-direct-tool-grant.test.ts +138 -0
  380. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +1 -1
  381. package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +91 -0
  382. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +72 -7
  383. package/dist/extensions/pi-subagents/test/unit/mutation-evidence.test.ts +21 -0
  384. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +1 -0
  385. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +20 -2
  386. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +129 -1
  387. package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +2 -2
  388. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +4 -0
  389. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +358 -0
  390. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +574 -21
  391. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +109 -1
  392. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +71 -1
  393. package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +7 -7
  394. package/dist/extensions/pi-subagents/test/unit/pruned-fork.test.ts +214 -0
  395. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +29 -8
  396. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +53 -0
  397. package/dist/extensions/pi-subagents/test/unit/result-delivery-ownership.test.ts +34 -0
  398. package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +101 -3
  399. package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +1 -0
  400. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +10 -8
  401. package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +71 -1
  402. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +41 -7
  403. package/dist/extensions/pi-subagents/test/unit/runtime-agent-registration.test.ts +136 -2
  404. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +137 -0
  405. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +33 -12
  406. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +504 -1
  407. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +8 -0
  408. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
  409. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +12 -1
  410. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +3 -5
  411. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +5 -6
  412. package/dist/extensions/pi-subagents/test/unit/subagent-action-recovery.test.ts +0 -8
  413. package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +5 -0
  414. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +157 -2
  415. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +1 -1
  416. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +63 -4
  417. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +27 -23
  418. package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +44 -0
  419. package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +1 -0
  420. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +7 -5
  421. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +106 -0
  422. package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +484 -9
  423. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +38 -4
  424. package/dist/extensions/pi-subagents/test/unit/workflow-preflight.test.ts +155 -0
  425. package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +318 -0
  426. package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +365 -0
  427. package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +349 -0
  428. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +21 -0
  429. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +2 -7
  430. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/index.ts +13 -0
  431. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/rules/no-service-constructor-imports.ts +52 -0
  432. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/index.ts +41 -0
  433. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-chained-type-assertions.ts +77 -0
  434. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-conditional-empty-object-spread.ts +49 -0
  435. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-known-value-widening.ts +247 -0
  436. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-module-mocking.ts +91 -0
  437. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-object-parameters.ts +126 -0
  438. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-apply.ts +28 -0
  439. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-get.ts +28 -0
  440. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-runtime-typeof.ts +67 -0
  441. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-shape-in-symbol-names.ts +39 -0
  442. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-parameters.ts +83 -0
  443. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-returns.ts +115 -0
  444. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-type-aliases.ts +72 -0
  445. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unsafe-dictionary-type.ts +134 -0
  446. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-widen-then-assert.ts +366 -0
  447. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/require-safety-comment-for-type-assertion.ts +62 -0
  448. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/dictionary-types.ts +502 -0
  449. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/lexical-type-parameters.ts +60 -0
  450. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/reflect-method.ts +35 -0
  451. package/dist/extensions/pi-tool-display/tests/capabilities.test.ts +1 -1
  452. package/dist/extensions/pi-tool-display/tests/settings-inspector.test.ts +2 -2
  453. package/dist/extensions/pi-tool-display/tests/tool-overrides-mcp.test.ts +1 -1
  454. package/dist/extensions/pi-zentui/extensions/zentui/format.ts +2 -1
  455. package/dist/extensions/pi-zentui/test/format.test.ts +15 -1
  456. package/dist/modes/interactive/components/footer.js +2 -2
  457. package/dist/modes/interactive/interactive-mode.js +11 -11
  458. package/dist/skills/workflow/SKILL.md +65 -50
  459. package/package.json +112 -110
  460. package/dist/extensions/enable-readonly-tools.test.ts +0 -63
  461. package/dist/extensions/enable-readonly-tools.ts +0 -24
  462. package/dist/extensions/model-prompt-injector/config.json +0 -16
  463. package/dist/extensions/model-prompt-injector/index.test.ts +0 -102
  464. package/dist/extensions/model-prompt-injector/index.ts +0 -148
  465. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +0 -98
  466. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +0 -250
@@ -0,0 +1,671 @@
1
+ /**
2
+ * Unit tests for correction detection — isCorrection() pattern matching
3
+ * and handler behavior (rate limiting, pi.exec trigger).
4
+ */
5
+
6
+ import { describe, it, beforeEach, afterEach } from "node:test";
7
+ import assert from "node:assert/strict";
8
+ import fs from "node:fs";
9
+ import os from "node:os";
10
+ import path from "node:path";
11
+ import { DatabaseManager } from "../../src/store/db.js";
12
+ import { getMemories } from "../../src/store/sqlite-memory-store.js";
13
+ import { MemoryStore } from "../../src/store/memory-store.js";
14
+ import { registerMemoryTool } from "../../src/tools/memory-tool.js";
15
+ import { isCorrection, setupCorrectionDetector } from "../../src/handlers/correction-detector.js";
16
+ import { resolveWatchedChildPiInvocation } from "../../src/handlers/pi-child-process.js";
17
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
18
+ import type { MemoryConfig } from "../../src/types.js";
19
+
20
+ // ─── Pattern matching tests ───
21
+
22
+ describe("isCorrection", () => {
23
+ // ── Strong patterns (always trigger) ──
24
+
25
+ describe("strong patterns (always trigger)", () => {
26
+ it("matches 'don't do that'", () => {
27
+ assert.strictEqual(isCorrection("don't do that"), true);
28
+ });
29
+
30
+ it("matches 'not like that'", () => {
31
+ assert.strictEqual(isCorrection("not like that"), true);
32
+ });
33
+
34
+ it("matches 'I said use yarn'", () => {
35
+ assert.strictEqual(isCorrection("I said use yarn"), true);
36
+ });
37
+
38
+ it("matches 'I told you already'", () => {
39
+ assert.strictEqual(isCorrection("I told you already"), true);
40
+ });
41
+
42
+ it("matches 'we already discussed this'", () => {
43
+ assert.strictEqual(isCorrection("we already discussed this"), true);
44
+ });
45
+
46
+ it("matches 'please don't commit yet'", () => {
47
+ assert.strictEqual(isCorrection("please don't commit yet"), true);
48
+ });
49
+
50
+ it("matches \"that's not what I asked for\"", () => {
51
+ assert.strictEqual(isCorrection("that's not what I asked for"), true);
52
+ });
53
+ });
54
+
55
+ // ── Weak patterns (need directive clause) ──
56
+
57
+ describe("weak patterns (need directive clause)", () => {
58
+ it("matches 'no, use yarn instead' (has directive 'use')", () => {
59
+ assert.strictEqual(isCorrection("no, use yarn instead"), true);
60
+ });
61
+
62
+ it("matches 'wrong, the file is in src/' (has directive 'the')", () => {
63
+ assert.strictEqual(isCorrection("wrong, the file is in src/"), true);
64
+ });
65
+
66
+ it("matches 'actually, don't use that' (has directive 'don't')", () => {
67
+ assert.strictEqual(isCorrection("actually, don't use that"), true);
68
+ });
69
+
70
+ it("matches 'stop, fix the test first' (has directive 'fix')", () => {
71
+ assert.strictEqual(isCorrection("stop, fix the test first"), true);
72
+ });
73
+
74
+ it("matches 'no! delete that file' (has directive 'delete')", () => {
75
+ assert.strictEqual(isCorrection("no! delete that file"), true);
76
+ });
77
+
78
+ it("does NOT match 'no just kidding' (no directive clause)", () => {
79
+ assert.strictEqual(isCorrection("no just kidding"), false);
80
+ });
81
+ });
82
+
83
+ // ── Negative patterns (suppress even if positive matches) ──
84
+
85
+ describe("negative patterns (suppress false positives)", () => {
86
+ it("suppresses 'no worries, I'll handle it'", () => {
87
+ assert.strictEqual(isCorrection("no worries, I'll handle it"), false);
88
+ });
89
+
90
+ it("suppresses 'no problem'", () => {
91
+ assert.strictEqual(isCorrection("no problem"), false);
92
+ });
93
+
94
+ it("suppresses 'no thanks'", () => {
95
+ assert.strictEqual(isCorrection("no thanks"), false);
96
+ });
97
+
98
+ it("suppresses 'no need to change that'", () => {
99
+ assert.strictEqual(isCorrection("no need to change that"), false);
100
+ });
101
+
102
+ it("suppresses 'actually, that looks great'", () => {
103
+ assert.strictEqual(isCorrection("actually, that looks great"), false);
104
+ });
105
+
106
+ it("suppresses 'actually, perfect'", () => {
107
+ assert.strictEqual(isCorrection("actually, perfect"), false);
108
+ });
109
+
110
+ it("suppresses 'actually, that's correct'", () => {
111
+ assert.strictEqual(isCorrection("actually, that's correct"), false);
112
+ });
113
+
114
+ it("suppresses 'stop there'", () => {
115
+ assert.strictEqual(isCorrection("stop there"), false);
116
+ });
117
+
118
+ it("suppresses 'stop here'", () => {
119
+ assert.strictEqual(isCorrection("stop here"), false);
120
+ });
121
+
122
+ it("suppresses 'stop for now'", () => {
123
+ assert.strictEqual(isCorrection("stop for now"), false);
124
+ });
125
+ });
126
+
127
+ // ── Non-corrections (should NOT trigger) ──
128
+
129
+ describe("non-corrections (should NOT trigger)", () => {
130
+ it("does NOT match 'yes, do that'", () => {
131
+ assert.strictEqual(isCorrection("yes, do that"), false);
132
+ });
133
+
134
+ it("does NOT match 'looks good'", () => {
135
+ assert.strictEqual(isCorrection("looks good"), false);
136
+ });
137
+
138
+ it("does NOT match 'can you also check the tests?'", () => {
139
+ assert.strictEqual(isCorrection("can you also check the tests?"), false);
140
+ });
141
+
142
+ it("does NOT match empty string", () => {
143
+ assert.strictEqual(isCorrection(""), false);
144
+ });
145
+
146
+ it("does NOT match 'thanks'", () => {
147
+ assert.strictEqual(isCorrection("thanks"), false);
148
+ });
149
+
150
+ it("does NOT match 'great, that works'", () => {
151
+ assert.strictEqual(isCorrection("great, that works"), false);
152
+ });
153
+
154
+ it("does NOT match 'please continue'", () => {
155
+ assert.strictEqual(isCorrection("please continue"), false);
156
+ });
157
+ });
158
+
159
+ // ── Case insensitivity ──
160
+
161
+ describe("case insensitivity", () => {
162
+ it("matches 'DON'T DO THAT' (uppercase)", () => {
163
+ assert.strictEqual(isCorrection("DON'T DO THAT"), true);
164
+ });
165
+
166
+ it("matches 'I Told You Already' (mixed case)", () => {
167
+ assert.strictEqual(isCorrection("I Told You Already"), true);
168
+ });
169
+
170
+ it("suppresses 'No Worries' (uppercase negative)", () => {
171
+ assert.strictEqual(isCorrection("No Worries"), false);
172
+ });
173
+ });
174
+
175
+ describe("custom pattern config", () => {
176
+ it("matches custom strong patterns", () => {
177
+ assert.strictEqual(
178
+ isCorrection("custom correction", { correctionStrongPatterns: ["^custom correction$"] }),
179
+ true,
180
+ );
181
+ });
182
+
183
+ it("uses custom negative patterns to suppress matches", () => {
184
+ assert.strictEqual(
185
+ isCorrection("custom correction", {
186
+ correctionStrongPatterns: ["^custom"],
187
+ correctionNegativePatterns: ["^custom correction$"],
188
+ }),
189
+ false,
190
+ );
191
+ });
192
+
193
+ it("uses custom directive words for weak patterns", () => {
194
+ assert.strictEqual(
195
+ isCorrection("no, shipit now", { correctionDirectiveWords: ["shipit"] }),
196
+ true,
197
+ );
198
+ assert.strictEqual(
199
+ isCorrection("no, use yarn", { correctionDirectiveWords: ["shipit"] }),
200
+ false,
201
+ );
202
+ });
203
+
204
+ it("ignores invalid custom regex entries and keeps valid entries", () => {
205
+ assert.strictEqual(
206
+ isCorrection("custom correction", { correctionStrongPatterns: ["bad(", "^custom"] }),
207
+ true,
208
+ );
209
+ });
210
+
211
+ it("treats explicit empty or all-invalid pattern arrays as empty", () => {
212
+ assert.strictEqual(
213
+ isCorrection("don't do that", { correctionStrongPatterns: [] }),
214
+ false,
215
+ );
216
+ assert.strictEqual(
217
+ isCorrection("don't do that", { correctionStrongPatterns: ["bad("] }),
218
+ false,
219
+ );
220
+ });
221
+ });
222
+ });
223
+
224
+ // ─── Handler behavior tests ───
225
+
226
+ describe("setupCorrectionDetector handler", () => {
227
+ let handlers: Record<string, Function[]>;
228
+ let execCalls: any[];
229
+ let notifyCalls: any[];
230
+ let tmpDir: string;
231
+ let dbManager: DatabaseManager;
232
+
233
+ function createMockPi(execReturn?: { code: number; stdout: string; stderr: string }) {
234
+ const ret = execReturn ?? { code: 0, stdout: "Saved correction", stderr: "" };
235
+ return {
236
+ on: (event: string, handler: Function) => {
237
+ handlers[event] = handlers[event] || [];
238
+ handlers[event].push(handler);
239
+ },
240
+ exec: async (...args: any[]) => {
241
+ execCalls.push(args);
242
+ return ret;
243
+ },
244
+ registerTool: () => {},
245
+ registerCommand: () => {},
246
+ } as any;
247
+ }
248
+
249
+ let directCalls: unknown[][];
250
+
251
+ function makeDirectDeps(
252
+ result: { ok: boolean; appliedCount: number } | "throw",
253
+ ): { runDirectMemoryCompletion: (...args: unknown[]) => Promise<{ ok: boolean; appliedCount: number }> } {
254
+ return {
255
+ runDirectMemoryCompletion: async (...args: unknown[]) => {
256
+ directCalls.push(args);
257
+ if (result === "throw") throw new Error("injected direct correction failure");
258
+ return result;
259
+ },
260
+ };
261
+ }
262
+
263
+
264
+ function correctionBranch(userText = "don't do that") {
265
+ return [
266
+ { type: "message", message: { role: "user", content: [{ type: "text", text: userText }] } },
267
+ { type: "message", message: { role: "assistant", content: [{ type: "text", text: "I used npm" }] } },
268
+ ];
269
+ }
270
+
271
+ function storeWithFailureTracking() {
272
+ let failureCount = 0;
273
+ return {
274
+ store: {
275
+ getMemoryEntries: () => ["existing entry"],
276
+ getUserEntries: () => [],
277
+ addFailure: async () => {
278
+ failureCount += 1;
279
+ },
280
+ getFailureCount: () => failureCount,
281
+ },
282
+ };
283
+ }
284
+
285
+ function logicalChildArgs(call: any[]): string[] {
286
+ const [cmd, args] = call;
287
+ const underlying = { command: args[3], args: args.slice(4) };
288
+ const expected = resolveWatchedChildPiInvocation(underlying, Number(args[1]), args[2]);
289
+ assert.strictEqual(cmd, expected.command);
290
+ assert.deepStrictEqual(args, expected.args);
291
+ return underlying.command === "selesai" ? underlying.args : underlying.args.slice(1);
292
+ }
293
+
294
+ const mockStore = {
295
+ getMemoryEntries: () => ["existing entry"],
296
+ getUserEntries: () => [],
297
+ } as any;
298
+
299
+ const config = {
300
+ correctionDetection: true,
301
+ nudgeInterval: 10,
302
+ reviewEnabled: false,
303
+ memoryCharLimit: 5000,
304
+ userCharLimit: 5000,
305
+ projectCharLimit: 5000,
306
+ flushOnCompact: false,
307
+ flushOnShutdown: false,
308
+ flushMinTurns: 6,
309
+ nudgeToolCalls: 15,
310
+ consolidationTimeoutMs: 60_000,
311
+ };
312
+
313
+ const directTransportConfig: MemoryConfig = { ...config, reviewTransport: "direct" };
314
+
315
+ function makeCtx(branch: any[] = []) {
316
+ return {
317
+ sessionManager: { getBranch: () => branch },
318
+ signal: undefined,
319
+ cwd: "/tmp/active-project",
320
+ model: { provider: "local-llama", id: "local-9b" },
321
+ modelRegistry: {},
322
+ ui: {
323
+ notify: (msg: string, level: string) => {
324
+ notifyCalls.push({ msg, level });
325
+ },
326
+ },
327
+ };
328
+ }
329
+
330
+ function fireMessageEnd(role: string, text: string) {
331
+ const h = handlers["message_end"];
332
+ if (!h) throw new Error("No message_end handler registered");
333
+ for (const fn of h) {
334
+ fn({ message: { role, content: [{ type: "text", text }] } }, makeCtx());
335
+ }
336
+ }
337
+
338
+ function fireTurnEnd(branch: any[] = []): Promise<unknown> {
339
+ const h = handlers["turn_end"];
340
+ if (!h) throw new Error("No turn_end handler registered");
341
+ const ctx = makeCtx(branch);
342
+ return Promise.all(h.map((fn) => fn({}, ctx)));
343
+ }
344
+
345
+ beforeEach(() => {
346
+ handlers = {};
347
+ execCalls = [];
348
+ notifyCalls = [];
349
+ directCalls = [];
350
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "correction-detector-test-"));
351
+ dbManager = new DatabaseManager(tmpDir);
352
+ });
353
+
354
+ afterEach(() => {
355
+ dbManager.close();
356
+ fs.rmSync(tmpDir, { recursive: true, force: true });
357
+ });
358
+
359
+ it("triggers pi.exec when correction detected", async () => {
360
+ const pi = createMockPi();
361
+ setupCorrectionDetector(pi, mockStore, null, config);
362
+
363
+ const branch = [
364
+ { type: "message", message: { role: "user", content: [{ type: "text", text: "don't do that" }] } },
365
+ { type: "message", message: { role: "assistant", content: [{ type: "text", text: "ok" }] } },
366
+ ];
367
+
368
+ fireMessageEnd("user", "don't do that");
369
+ await fireTurnEnd(branch);
370
+
371
+ assert.ok(execCalls.length >= 1, "pi.exec should be called on correction");
372
+ const options = execCalls[0][2] as { cwd?: string };
373
+ assert.equal(options.cwd, "/tmp/active-project");
374
+ const args = logicalChildArgs(execCalls[0]);
375
+ assert.deepStrictEqual(args.slice(0, 4), [
376
+ "-p", "--no-session", "--model", "local-llama/local-9b",
377
+ ]);
378
+ });
379
+
380
+ it("passes child LLM override args and defaults thinking to off when only a model override is set", async () => {
381
+ const pi = createMockPi();
382
+ setupCorrectionDetector(pi, mockStore, null, {
383
+ ...config,
384
+ llmModelOverride: "openrouter/deepseek/deepseek-v4-flash",
385
+ });
386
+
387
+ const branch = [
388
+ { type: "message", message: { role: "user", content: [{ type: "text", text: "don't do that" }] } },
389
+ { type: "message", message: { role: "assistant", content: [{ type: "text", text: "ok" }] } },
390
+ ];
391
+
392
+ fireMessageEnd("user", "don't do that");
393
+ await fireTurnEnd(branch);
394
+
395
+ const cmdArgs = logicalChildArgs(execCalls[0]);
396
+ assert.deepStrictEqual(
397
+ cmdArgs.slice(0, 6),
398
+ ["-p", "--no-session", "--model", "openrouter/deepseek/deepseek-v4-flash", "--thinking", "off"],
399
+ );
400
+ });
401
+
402
+ it("does NOT trigger on normal messages", async () => {
403
+ const pi = createMockPi();
404
+ setupCorrectionDetector(pi, mockStore, null, config);
405
+
406
+ fireMessageEnd("user", "looks good");
407
+ await fireTurnEnd([]);
408
+
409
+ assert.strictEqual(execCalls.length, 0, "pi.exec should NOT be called for normal messages");
410
+ });
411
+
412
+ it("rate limits: does not trigger on consecutive corrections within 3 turns", async () => {
413
+ const pi = createMockPi();
414
+ setupCorrectionDetector(pi, mockStore, null, config);
415
+
416
+ // First correction
417
+ fireMessageEnd("user", "don't do that");
418
+ await fireTurnEnd([]);
419
+
420
+ const firstCallCount = execCalls.length;
421
+ assert.ok(firstCallCount >= 1, "first correction should trigger");
422
+
423
+ // Second correction within 3 turns — should be rate-limited
424
+ fireMessageEnd("user", "not like that");
425
+ await fireTurnEnd([]);
426
+
427
+ assert.strictEqual(execCalls.length, firstCallCount, "second correction should be rate-limited");
428
+ });
429
+
430
+ it("syncs direct correction saves into SQLite", async () => {
431
+ const pi = createMockPi();
432
+ const correctionStore = new MemoryStore({ ...config, memoryDir: tmpDir } as any);
433
+ await correctionStore.loadFromDisk();
434
+ registerMemoryTool(pi, correctionStore, null, dbManager);
435
+
436
+ setupCorrectionDetector(pi, correctionStore, null, config, dbManager);
437
+
438
+ const branch = [
439
+ { type: "message", message: { role: "user", content: [{ type: "text", text: "no, use pnpm instead" }] } },
440
+ { type: "message", message: { role: "assistant", content: [{ type: "text", text: "ok" }] } },
441
+ ];
442
+
443
+ fireMessageEnd("user", "no, use pnpm instead");
444
+ await fireTurnEnd(branch);
445
+
446
+ const failures = getMemories(dbManager, { target: 'failure' });
447
+ assert.strictEqual(failures.length, 1);
448
+ assert.match(failures[0].content, /use pnpm instead/);
449
+ assert.strictEqual(failures[0].category, 'correction');
450
+ assert.strictEqual(failures[0].project, null);
451
+ });
452
+
453
+ it("saves the latest user message as the correction failure", async () => {
454
+ const pi = createMockPi();
455
+ const correctionStore = new MemoryStore({ ...config, memoryDir: tmpDir } as any);
456
+ await correctionStore.loadFromDisk();
457
+ setupCorrectionDetector(pi, correctionStore, null, config);
458
+
459
+ const branch = [
460
+ { type: "message", message: { role: "user", content: [{ type: "text", text: "First, use Maven for the build." }] } },
461
+ { type: "message", message: { role: "assistant", content: [{ type: "text", text: "I will use Maven." }] } },
462
+ { type: "message", message: { role: "user", content: [{ type: "text", text: "Continue with the implementation." }] } },
463
+ { type: "message", message: { role: "assistant", content: [{ type: "text", text: "Implemented." }] } },
464
+ { type: "message", message: { role: "user", content: [{ type: "text", text: "No, that is incorrect. Use javac only, not Maven." }] } },
465
+ { type: "message", message: { role: "assistant", content: [{ type: "text", text: "Understood." }] } },
466
+ ];
467
+
468
+ fireMessageEnd("user", "No, that is incorrect. Use javac only, not Maven.");
469
+ await fireTurnEnd(branch);
470
+
471
+ const failures = correctionStore.getFailureEntries();
472
+ assert.strictEqual(failures.length, 1);
473
+ assert.match(failures[0], /use javac only, not Maven/i);
474
+ assert.doesNotMatch(failures[0], /First, use Maven/i);
475
+ });
476
+
477
+ it("syncs project correction saves into SQLite with project scope", async () => {
478
+ const pi = createMockPi();
479
+ const correctionStore = new MemoryStore({ ...config, memoryDir: tmpDir } as any);
480
+ await correctionStore.loadFromDisk();
481
+ const projectStore = {
482
+ getMemoryEntries: () => [],
483
+ } as any;
484
+ registerMemoryTool(pi, correctionStore, projectStore, dbManager, 'project-a');
485
+
486
+ setupCorrectionDetector(pi, correctionStore, projectStore, config, dbManager, 'project-a');
487
+
488
+ const branch = [
489
+ { type: "message", message: { role: "user", content: [{ type: "text", text: "no, use pnpm in this repo" }] } },
490
+ { type: "message", message: { role: "assistant", content: [{ type: "text", text: "ok" }] } },
491
+ ];
492
+
493
+ fireMessageEnd("user", "no, use pnpm in this repo");
494
+ await fireTurnEnd(branch);
495
+
496
+ const projectFailures = getMemories(dbManager, { target: 'failure', project: 'project-a' });
497
+ assert.strictEqual(projectFailures.length, 1);
498
+ assert.match(projectFailures[0].content, /use pnpm in this repo/);
499
+ assert.doesNotMatch(projectFailures[0].content, /Project: project-a/);
500
+ assert.strictEqual(projectFailures[0].category, 'correction');
501
+ assert.strictEqual(getMemories(dbManager, { target: 'failure', project: null }).length, 0);
502
+ });
503
+
504
+ it("does not break correction handling when SQLite sync fails", async () => {
505
+ const pi = createMockPi();
506
+ const correctionStore = new MemoryStore({ ...config, memoryDir: tmpDir } as any);
507
+ await correctionStore.loadFromDisk();
508
+
509
+ const failingDbManager = {
510
+ getDb: () => {
511
+ throw new Error('sqlite unavailable');
512
+ },
513
+ } as unknown as DatabaseManager;
514
+
515
+ registerMemoryTool(pi, correctionStore, null, failingDbManager);
516
+ setupCorrectionDetector(pi, correctionStore, null, config, failingDbManager);
517
+
518
+ const branch = [
519
+ { type: "message", message: { role: "user", content: [{ type: "text", text: "no, use yarn instead" }] } },
520
+ { type: "message", message: { role: "assistant", content: [{ type: "text", text: "ok" }] } },
521
+ ];
522
+
523
+ fireMessageEnd("user", "no, use yarn instead");
524
+ await fireTurnEnd(branch);
525
+
526
+ assert.ok(execCalls.length >= 1, 'correction review should still run');
527
+ assert.strictEqual(correctionStore.getFailureEntries().length, 1, 'Markdown correction save should still happen');
528
+ });
529
+
530
+ describe("direct memory completion transport", () => {
531
+ it("skips subprocess and notifies when direct succeeds with applied memories", async () => {
532
+ const pi = createMockPi();
533
+ const { store } = storeWithFailureTracking();
534
+ setupCorrectionDetector(
535
+ pi,
536
+ store as unknown as MemoryStore,
537
+ null,
538
+ directTransportConfig,
539
+ null,
540
+ null,
541
+ makeDirectDeps({ ok: true, appliedCount: 1 }),
542
+ );
543
+
544
+ fireMessageEnd("user", "don't do that");
545
+ await fireTurnEnd(correctionBranch());
546
+
547
+ assert.strictEqual(directCalls.length, 1);
548
+ assert.strictEqual(execCalls.length, 0, "subprocess must not run on successful direct correction");
549
+ assert.deepStrictEqual(
550
+ notifyCalls.filter((n) => n.msg === "🔧 Correction detected — memory updated"),
551
+ [{ msg: "🔧 Correction detected — memory updated", level: "info" }],
552
+ );
553
+ });
554
+
555
+ it("includes project and failure target routing in direct correction prompts", async () => {
556
+ const pi = createMockPi();
557
+ const { store } = storeWithFailureTracking();
558
+ const projectStore = { getMemoryEntries: () => ["existing project fact"] } as unknown as Parameters<typeof setupCorrectionDetector>[2];
559
+ setupCorrectionDetector(
560
+ pi,
561
+ store as unknown as MemoryStore,
562
+ projectStore,
563
+ directTransportConfig,
564
+ null,
565
+ "project-a",
566
+ makeDirectDeps({ ok: true, appliedCount: 1 }),
567
+ );
568
+
569
+ fireMessageEnd("user", "don't do that");
570
+ await fireTurnEnd(correctionBranch());
571
+
572
+ const options = directCalls[0][3] as { systemPrompt: string; userPrompt: string };
573
+ assert.match(options.systemPrompt, /project-specific facts.*target "project"/i);
574
+ assert.match(options.systemPrompt, /failures, corrections.*target "failure"/i);
575
+ assert.match(options.userPrompt, /--- Current Project Memory ---/);
576
+ });
577
+
578
+ it("skips subprocess and omits memory-updated notify when direct ok with zero applied", async () => {
579
+ const pi = createMockPi();
580
+ const { store } = storeWithFailureTracking();
581
+ setupCorrectionDetector(
582
+ pi,
583
+ store as unknown as MemoryStore,
584
+ null,
585
+ directTransportConfig,
586
+ null,
587
+ null,
588
+ makeDirectDeps({ ok: true, appliedCount: 0 }),
589
+ );
590
+
591
+ fireMessageEnd("user", "don't do that");
592
+ await fireTurnEnd(correctionBranch());
593
+
594
+ assert.strictEqual(directCalls.length, 1);
595
+ assert.strictEqual(execCalls.length, 0, "ok:true with appliedCount 0 still completes via direct transport");
596
+ assert.strictEqual(
597
+ notifyCalls.some((n) => n.msg === "🔧 Correction detected — memory updated"),
598
+ false,
599
+ );
600
+ });
601
+
602
+ it("falls back to subprocess when direct returns ok false", async () => {
603
+ const pi = createMockPi();
604
+ const { store } = storeWithFailureTracking();
605
+ setupCorrectionDetector(
606
+ pi,
607
+ store as unknown as MemoryStore,
608
+ null,
609
+ directTransportConfig,
610
+ null,
611
+ null,
612
+ makeDirectDeps({ ok: false, appliedCount: 0 }),
613
+ );
614
+
615
+ fireMessageEnd("user", "don't do that");
616
+ await fireTurnEnd(correctionBranch());
617
+
618
+ assert.strictEqual(directCalls.length, 1);
619
+ assert.ok(execCalls.length >= 1, "failed direct result must fall back to subprocess");
620
+ });
621
+
622
+ it("falls back to subprocess when direct throws without propagating", async () => {
623
+ const pi = createMockPi();
624
+ const { store } = storeWithFailureTracking();
625
+ setupCorrectionDetector(
626
+ pi,
627
+ store as unknown as MemoryStore,
628
+ null,
629
+ directTransportConfig,
630
+ null,
631
+ null,
632
+ makeDirectDeps("throw"),
633
+ );
634
+
635
+ fireMessageEnd("user", "don't do that");
636
+ await fireTurnEnd(correctionBranch());
637
+
638
+ assert.strictEqual(directCalls.length, 1);
639
+ assert.ok(execCalls.length >= 1, "thrown direct error must fall back to subprocess");
640
+ });
641
+
642
+ it("uses subprocess only when reviewTransport is subprocess", async () => {
643
+ const pi = createMockPi();
644
+ const { store } = storeWithFailureTracking();
645
+ const subprocessConfig: MemoryConfig = { ...config, reviewTransport: "subprocess" };
646
+ setupCorrectionDetector(
647
+ pi,
648
+ store as unknown as MemoryStore,
649
+ null,
650
+ subprocessConfig,
651
+ null,
652
+ null,
653
+ makeDirectDeps({ ok: true, appliedCount: 1 }),
654
+ );
655
+
656
+ fireMessageEnd("user", "don't do that");
657
+ await fireTurnEnd(correctionBranch());
658
+
659
+ assert.strictEqual(directCalls.length, 0, "direct transport must be skipped for subprocess config");
660
+ assert.ok(execCalls.length >= 1, "subprocess must run when direct transport is disabled");
661
+ });
662
+ });
663
+
664
+ it("does not register handlers when correctionDetection is false", () => {
665
+ const pi = createMockPi();
666
+ const disabledConfig = { ...config, correctionDetection: false };
667
+ setupCorrectionDetector(pi, mockStore, null, disabledConfig);
668
+
669
+ assert.strictEqual(Object.keys(handlers).length, 0, "no handlers should be registered when disabled");
670
+ });
671
+ });