@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
@@ -2,11 +2,21 @@ import { createHash } from "node:crypto";
2
2
  import * as fs from "node:fs";
3
3
  import * as os from "node:os";
4
4
  import * as path from "node:path";
5
+ import { findConfiguredProjectRoot } from "../../agents/agents.ts";
5
6
  import { getAgentDir, getProjectConfigDir } from "../../shared/utils.ts";
7
+ import { isMcpServerDefinition, loadAgentPluginMcpServers, loadPackageMcpServers, type McpServerDefinition } from "./mcp-config-sources.ts";
8
+ import {
9
+ normalizeMcpDirectToolSelectors,
10
+ parseMcpDirectToolSelectors,
11
+ planMcpDirectToolGrant,
12
+ } from "./mcp-direct-tool-grant.ts";
13
+ import type { McpToolPrefix, ResolvedMcpDirectToolSelection } from "./mcp-direct-tool-grant.ts";
14
+
15
+ export { formatUnresolvedMcpDirectToolSelectors } from "./mcp-direct-tool-grant.ts";
16
+ export type { ResolvedMcpDirectToolSelection } from "./mcp-direct-tool-grant.ts";
6
17
 
7
18
  const CACHE_VERSION = 1;
8
19
  const CACHE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
9
- const BUILTIN_TOOL_NAMES = new Set(["read", "bash", "edit", "write", "grep", "find", "ls", "mcp"]);
10
20
  const GENERIC_GLOBAL_CONFIG_PATH = path.join(os.homedir(), ".config", "mcp", "mcp.json");
11
21
  const IMPORT_PATHS = {
12
22
  cursor: [path.join(os.homedir(), ".cursor", "mcp.json")],
@@ -21,39 +31,41 @@ const IMPORT_PATHS = {
21
31
  vscode: [".vscode/mcp.json"],
22
32
  } as const;
23
33
 
24
- type ToolPrefix = "server" | "none" | "short";
25
34
  type ImportKind = keyof typeof IMPORT_PATHS;
26
35
 
27
- interface ServerEntry {
28
- command?: string;
29
- args?: string[];
30
- socket?: string;
31
- env?: Record<string, string>;
32
- cwd?: string;
33
- url?: string;
34
- headers?: Record<string, string>;
35
- requestHeadersCommand?: {
36
- command: string;
37
- args?: string[];
38
- env?: Record<string, string>;
39
- timeoutMs?: number;
40
- };
41
- auth?: "oauth" | "bearer" | false;
42
- bearerToken?: string;
43
- bearerTokenEnv?: string;
44
- exposeResources?: boolean;
45
- includeTools?: string[];
46
- excludeTools?: string[];
47
- protocolVersion?: string;
48
- directTools?: boolean | string[];
49
- }
36
+ type ServerEntry = McpServerDefinition;
50
37
 
51
- interface McpConfig {
38
+ export interface McpConfig {
52
39
  mcpServers: Record<string, ServerEntry>;
53
40
  imports?: ImportKind[];
54
41
  settings?: {
55
- toolPrefix?: ToolPrefix;
42
+ toolPrefix?: McpToolPrefix;
56
43
  directTools?: boolean;
44
+ agentPluginPaths?: unknown;
45
+ };
46
+ }
47
+
48
+ export const MCP_RUNTIME_SNAPSHOT_EVENT = "pi-mcp-adapter:runtime-snapshot:v1" as const;
49
+ export const MCP_RUNTIME_SNAPSHOT_VERSION = 1 as const;
50
+
51
+ export interface McpRuntimeServerSnapshot {
52
+ readonly name: string;
53
+ readonly definition: ServerEntry;
54
+ readonly runtime: true;
55
+ readonly persisted: false;
56
+ }
57
+
58
+ interface McpRuntimeSnapshotRequest {
59
+ version: typeof MCP_RUNTIME_SNAPSHOT_VERSION;
60
+ name: string;
61
+ result?:
62
+ | { ok: true; snapshot: McpRuntimeServerSnapshot }
63
+ | { ok: false; error: Error };
64
+ }
65
+
66
+ export interface McpRuntimeSnapshotHost {
67
+ events: {
68
+ emit(event: string, request: McpRuntimeSnapshotRequest): void;
57
69
  };
58
70
  }
59
71
 
@@ -78,19 +90,59 @@ interface MetadataCache {
78
90
  servers: Record<string, ServerCacheEntry>;
79
91
  }
80
92
 
81
- export interface ResolvedMcpDirectToolSelection { name: string; selector: string }
82
-
83
- export function resolveMcpDirectToolSelections(mcpDirectTools: string[] | undefined, cwd = process.cwd()): ResolvedMcpDirectToolSelection[] {
84
- if (!mcpDirectTools?.length) return [];
85
-
86
- try {
87
- const config = loadMcpConfig(cwd);
88
- const cache = loadMetadataCache();
89
- if (!cache) return [];
90
- return resolveDirectToolSelections(config, cache, getToolPrefix(config.settings?.toolPrefix), mcpDirectTools);
91
- } catch {
92
- return [];
93
+ export interface McpDirectToolResolution {
94
+ selections: ResolvedMcpDirectToolSelection[];
95
+ unresolvedSelectors: string[];
96
+ /** Normal loaded config plus the selected runtime server definitions. */
97
+ mcpConfig?: McpConfig;
98
+ runtimeServerNames?: string[];
99
+ }
100
+
101
+ export function resolveMcpDirectToolResolution(
102
+ mcpDirectTools: string[] | undefined,
103
+ cwd = process.cwd(),
104
+ runtimeSnapshotHost?: McpRuntimeSnapshotHost,
105
+ configOverride?: McpConfig,
106
+ ): McpDirectToolResolution {
107
+ const selectors = normalizeMcpDirectToolSelectors(mcpDirectTools);
108
+ if (selectors.length === 0) return { selections: [], unresolvedSelectors: [] };
109
+
110
+ const config = configOverride ?? loadMcpConfig(cwd);
111
+ const { servers: selectedServers, tools: selectedTools } = parseMcpDirectToolSelectors(selectors);
112
+ const runtimeSelectionServers = new Set([...selectedServers, ...selectedTools.keys()]);
113
+ const runtimeServers = resolveRuntimeMcpServers(config, runtimeSelectionServers, runtimeSnapshotHost);
114
+ const resolvedConfig = Object.keys(runtimeServers).length > 0
115
+ ? mergeConfigs(config, { mcpServers: runtimeServers })
116
+ : config;
117
+ validateSelectedServerDefinitions(resolvedConfig, selectors);
118
+ const cache = loadMetadataCache();
119
+ if (!cache) return { selections: [], unresolvedSelectors: selectors };
120
+ const validMetadata: Record<string, ServerCacheEntry> = {};
121
+ for (const [serverName, definition] of Object.entries(resolvedConfig.mcpServers)) {
122
+ const serverCache = cache.servers[serverName];
123
+ if (isServerCacheValid(serverCache, definition)) validMetadata[serverName] = serverCache;
93
124
  }
125
+ const grant = planMcpDirectToolGrant({
126
+ selectors,
127
+ servers: resolvedConfig.mcpServers,
128
+ metadata: validMetadata,
129
+ toolPrefix: resolvedConfig.settings?.toolPrefix,
130
+ });
131
+ return {
132
+ selections: grant.selections,
133
+ unresolvedSelectors: grant.unresolvedSelectors,
134
+ ...(Object.keys(runtimeServers).length > 0
135
+ ? { mcpConfig: resolvedConfig, runtimeServerNames: Object.keys(runtimeServers) }
136
+ : {}),
137
+ };
138
+ }
139
+
140
+ export function resolveMcpDirectToolSelections(
141
+ mcpDirectTools: string[] | undefined,
142
+ cwd = process.cwd(),
143
+ runtimeSnapshotHost?: McpRuntimeSnapshotHost,
144
+ ): ResolvedMcpDirectToolSelection[] {
145
+ return resolveMcpDirectToolResolution(mcpDirectTools, cwd, runtimeSnapshotHost).selections;
94
146
  }
95
147
 
96
148
  function loadMetadataCache(): MetadataCache | null {
@@ -102,28 +154,116 @@ function loadMetadataCache(): MetadataCache | null {
102
154
  return null;
103
155
  }
104
156
 
105
- if (!parsed || typeof parsed !== "object") return null;
106
- const raw = parsed as Record<string, unknown>;
107
- if (raw.version !== CACHE_VERSION || !raw.servers || typeof raw.servers !== "object" || Array.isArray(raw.servers)) {
108
- return null;
157
+ if (!isRecord(parsed) || parsed.version !== CACHE_VERSION || !isRecord(parsed.servers)) return null;
158
+ const servers: Record<string, ServerCacheEntry> = {};
159
+ for (const [name, value] of Object.entries(parsed.servers)) {
160
+ const entry = parseServerCacheEntry(value);
161
+ if (entry) servers[name] = entry;
162
+ }
163
+ return { version: CACHE_VERSION, servers };
164
+ }
165
+
166
+ function parseServerCacheEntry(value: unknown): ServerCacheEntry | undefined {
167
+ if (!isRecord(value)) return undefined;
168
+ if (value.configHash !== undefined && typeof value.configHash !== "string") return undefined;
169
+ if (value.cachedAt !== undefined && (typeof value.cachedAt !== "number" || !Number.isFinite(value.cachedAt))) return undefined;
170
+ if (value.tools !== undefined && !Array.isArray(value.tools)) return undefined;
171
+ if (value.resources !== undefined && !Array.isArray(value.resources)) return undefined;
172
+ const tools = value.tools?.map(parseCachedTool);
173
+ const resources = value.resources?.map(parseCachedResource);
174
+ if (tools && !tools.every((entry): entry is CachedTool => entry !== undefined)) return undefined;
175
+ if (resources && !resources.every((entry): entry is CachedResource => entry !== undefined)) return undefined;
176
+ return {
177
+ ...(value.configHash !== undefined ? { configHash: value.configHash } : {}),
178
+ ...(value.cachedAt !== undefined ? { cachedAt: value.cachedAt } : {}),
179
+ ...(tools ? { tools } : {}),
180
+ ...(resources ? { resources } : {}),
181
+ };
182
+ }
183
+
184
+ function parseCachedTool(value: unknown): CachedTool | undefined {
185
+ if (!isRecord(value) || (value.name !== undefined && typeof value.name !== "string")) return undefined;
186
+ return value.name === undefined ? {} : { name: value.name };
187
+ }
188
+
189
+ function parseCachedResource(value: unknown): CachedResource | undefined {
190
+ if (!isRecord(value)) return undefined;
191
+ if (value.uri !== undefined && typeof value.uri !== "string") return undefined;
192
+ if (value.name !== undefined && typeof value.name !== "string") return undefined;
193
+ return {
194
+ ...(value.uri !== undefined ? { uri: value.uri } : {}),
195
+ ...(value.name !== undefined ? { name: value.name } : {}),
196
+ };
197
+ }
198
+
199
+ function resolveRuntimeMcpServers(
200
+ config: McpConfig,
201
+ selectedServers: ReadonlySet<string>,
202
+ runtimeSnapshotHost: McpRuntimeSnapshotHost | undefined,
203
+ ): Record<string, ServerEntry> {
204
+ if (!runtimeSnapshotHost) return {};
205
+ const runtimeServers: Record<string, ServerEntry> = {};
206
+ for (const serverName of selectedServers) {
207
+ if (Object.hasOwn(config.mcpServers, serverName)) continue;
208
+ try {
209
+ const snapshot = getRuntimeMcpServerSnapshot(runtimeSnapshotHost, serverName);
210
+ runtimeServers[serverName] = snapshot.definition;
211
+ } catch {
212
+ // Missing, disposed, or shadowed runtime servers remain unresolved below.
213
+ }
214
+ }
215
+ return runtimeServers;
216
+ }
217
+
218
+ function getRuntimeMcpServerSnapshot(
219
+ host: McpRuntimeSnapshotHost,
220
+ name: string,
221
+ ): McpRuntimeServerSnapshot {
222
+ const request: McpRuntimeSnapshotRequest = {
223
+ version: MCP_RUNTIME_SNAPSHOT_VERSION,
224
+ name,
225
+ };
226
+ host.events.emit(MCP_RUNTIME_SNAPSHOT_EVENT, request);
227
+ if (!request.result) throw new Error("pi-mcp-adapter is not installed for this Pi instance");
228
+ if (!request.result.ok) throw request.result.error;
229
+ const snapshot = request.result.snapshot;
230
+ if (
231
+ !snapshot ||
232
+ snapshot.name !== name ||
233
+ snapshot.runtime !== true ||
234
+ snapshot.persisted !== false ||
235
+ !isMcpServerDefinition(snapshot.definition)
236
+ ) {
237
+ throw new Error(`Invalid MCP runtime snapshot for server "${name}"`);
109
238
  }
110
- return raw as unknown as MetadataCache;
239
+ return snapshot;
111
240
  }
112
241
 
113
242
  function loadMcpConfig(cwd: string): McpConfig {
243
+ const resolvedCwd = path.resolve(cwd);
244
+ const projectRoot = findConfiguredProjectRoot(resolvedCwd) ?? resolvedCwd;
114
245
  let config: McpConfig = { mcpServers: {} };
115
- for (const sourcePath of getConfigPaths(cwd)) {
246
+ for (const sourcePath of getConfigPaths(projectRoot)) {
116
247
  const loaded = readConfig(sourcePath);
117
248
  if (!loaded) continue;
118
- config = mergeConfigs(config, expandImports(loaded, cwd));
249
+ config = mergeConfigs(config, expandImports(loaded, projectRoot));
119
250
  }
120
- return config;
251
+
252
+ const packageServers = loadPackageMcpServers(projectRoot);
253
+ const pluginServers = loadAgentPluginMcpServers(config.settings?.agentPluginPaths, projectRoot);
254
+ const packageOnlyServers = Object.fromEntries(
255
+ Object.entries(packageServers).filter(([name]) => !Object.hasOwn(pluginServers, name)),
256
+ );
257
+ return mergeConfigs(
258
+ { mcpServers: packageOnlyServers },
259
+ mergeConfigs({ mcpServers: pluginServers }, config),
260
+ );
121
261
  }
122
262
 
123
- function getConfigPaths(cwd: string): string[] {
263
+ function getConfigPaths(projectRoot: string): string[] {
124
264
  const piGlobalPath = path.join(getAgentDir(), "mcp.json");
125
- const projectPath = path.resolve(cwd, ".mcp.json");
126
- const projectPiPath = path.resolve(getProjectConfigDir(cwd), "mcp.json");
265
+ const projectPath = path.resolve(projectRoot, ".mcp.json");
266
+ const projectPiPath = path.resolve(getProjectConfigDir(projectRoot), "mcp.json");
127
267
  const sources: string[] = [];
128
268
  if (GENERIC_GLOBAL_CONFIG_PATH !== piGlobalPath) sources.push(GENERIC_GLOBAL_CONFIG_PATH);
129
269
  sources.push(piGlobalPath);
@@ -143,18 +283,33 @@ function readConfig(configPath: string): McpConfig | null {
143
283
  }
144
284
 
145
285
  function validateConfig(raw: unknown): McpConfig {
146
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) return { mcpServers: {} };
147
- const obj = raw as Record<string, unknown>;
286
+ if (!isRecord(raw)) return { mcpServers: {} };
287
+ const obj = raw;
148
288
  const servers = obj.mcpServers ?? obj["mcp-servers"] ?? {};
149
289
  return {
150
- mcpServers: servers && typeof servers === "object" && !Array.isArray(servers) ? servers as Record<string, ServerEntry> : {},
290
+ mcpServers: parseServerEntries(servers),
151
291
  imports: Array.isArray(obj.imports) ? obj.imports.filter((value): value is ImportKind => isImportKind(value)) : undefined,
152
- settings: obj.settings && typeof obj.settings === "object" && !Array.isArray(obj.settings)
153
- ? obj.settings as McpConfig["settings"]
154
- : undefined,
292
+ settings: parseSettings(obj.settings),
155
293
  };
156
294
  }
157
295
 
296
+ function parseServerEntries(value: unknown): Record<string, ServerEntry> {
297
+ if (!isRecord(value)) return {};
298
+ return Object.fromEntries(Object.entries(value).filter((entry): entry is [string, ServerEntry] => isMcpServerDefinition(entry[1])));
299
+ }
300
+
301
+ function parseSettings(value: unknown): McpConfig["settings"] | undefined {
302
+ if (!isRecord(value)) return undefined;
303
+ const toolPrefix = value.toolPrefix === "server" || value.toolPrefix === "short" || value.toolPrefix === "none" ? value.toolPrefix : undefined;
304
+ const directTools = typeof value.directTools === "boolean" ? value.directTools : undefined;
305
+ const settings: NonNullable<McpConfig["settings"]> = {
306
+ ...(toolPrefix ? { toolPrefix } : {}),
307
+ ...(directTools !== undefined ? { directTools } : {}),
308
+ ...(value.agentPluginPaths !== undefined ? { agentPluginPaths: value.agentPluginPaths } : {}),
309
+ };
310
+ return Object.keys(settings).length ? settings : undefined;
311
+ }
312
+
158
313
  function mergeConfigs(base: McpConfig, next: McpConfig): McpConfig {
159
314
  const imports = [...(base.imports ?? []), ...(next.imports ?? [])];
160
315
  return {
@@ -198,76 +353,24 @@ function resolveImportPath(importKind: ImportKind, cwd: string): string | null {
198
353
  }
199
354
 
200
355
  function extractServers(config: unknown, kind: ImportKind): Record<string, ServerEntry> {
201
- if (!config || typeof config !== "object" || Array.isArray(config)) return {};
202
- const obj = config as Record<string, unknown>;
356
+ if (!isRecord(config)) return {};
357
+ const obj = config;
203
358
  const servers = kind === "cursor" || kind === "windsurf" || kind === "vscode"
204
359
  ? obj.mcpServers ?? obj["mcp-servers"]
205
360
  : obj.mcpServers;
206
- return servers && typeof servers === "object" && !Array.isArray(servers) ? servers as Record<string, ServerEntry> : {};
207
- }
208
-
209
- function resolveDirectToolSelections(config: McpConfig, cache: MetadataCache, prefix: ToolPrefix, envOverride: string[]): ResolvedMcpDirectToolSelection[] {
210
- const names: ResolvedMcpDirectToolSelection[] = [];
211
- const seenNames = new Set<string>();
212
- const { servers: selectedServers, tools: selectedTools } = parseSelections(envOverride);
213
-
214
- for (const [serverName, definition] of Object.entries(config.mcpServers)) {
215
- const serverCache = cache.servers[serverName];
216
- if (!isServerCacheValid(serverCache, definition)) continue;
217
-
218
- const toolFilter = selectedServers.has(serverName)
219
- ? true
220
- : selectedTools.get(serverName);
221
- if (!toolFilter) continue;
222
-
223
- for (const tool of Array.isArray(serverCache.tools) ? serverCache.tools : []) {
224
- if (typeof tool?.name !== "string" || !tool.name) continue;
225
- if (toolFilter !== true && !toolFilter.has(tool.name)) continue;
226
- if (isToolExcluded(tool.name, serverName, prefix, definition.excludeTools)) continue;
227
- const prefixedName = formatToolName(tool.name, serverName, prefix);
228
- if (BUILTIN_TOOL_NAMES.has(prefixedName) || seenNames.has(prefixedName)) continue;
229
- seenNames.add(prefixedName);
230
- names.push({ name: prefixedName, selector: `${serverName}/${tool.name}` });
231
- }
232
-
233
- if (definition.exposeResources === false) continue;
234
- for (const resource of Array.isArray(serverCache.resources) ? serverCache.resources : []) {
235
- if (typeof resource?.name !== "string" || !resource.name || typeof resource.uri !== "string" || !resource.uri) continue;
236
- const baseName = `get_${resourceNameToToolName(resource.name)}`;
237
- if (toolFilter !== true && !toolFilter.has(baseName)) continue;
238
- if (isToolExcluded(baseName, serverName, prefix, definition.excludeTools)) continue;
239
- const prefixedName = formatToolName(baseName, serverName, prefix);
240
- if (BUILTIN_TOOL_NAMES.has(prefixedName) || seenNames.has(prefixedName)) continue;
241
- seenNames.add(prefixedName);
242
- names.push({ name: prefixedName, selector: `${serverName}/${baseName}` });
243
- }
244
- }
245
-
246
- return names;
361
+ return parseServerEntries(servers);
247
362
  }
248
363
 
249
364
  export function resolveMcpDirectToolNames(mcpDirectTools: string[] | undefined, cwd = process.cwd()): string[] {
250
365
  return resolveMcpDirectToolSelections(mcpDirectTools, cwd).map((selection) => selection.name);
251
366
  }
252
367
 
253
- function parseSelections(selections: string[]): { servers: Set<string>; tools: Map<string, Set<string>> } {
254
- const servers = new Set<string>();
255
- const tools = new Map<string, Set<string>>();
256
- for (let item of selections) {
257
- item = item.replace(/\/+$/, "");
258
- if (item.includes("/")) {
259
- const [server, tool] = item.split("/", 2);
260
- if (server && tool) {
261
- if (!tools.has(server)) tools.set(server, new Set());
262
- tools.get(server)!.add(tool);
263
- } else if (server) {
264
- servers.add(server);
265
- }
266
- } else if (item) {
267
- servers.add(item);
268
- }
368
+ function validateSelectedServerDefinitions(config: McpConfig, selectors: string[]): void {
369
+ const { servers, tools } = parseMcpDirectToolSelectors(selectors);
370
+ for (const serverName of new Set([...servers, ...tools.keys()])) {
371
+ const definition = config.mcpServers[serverName];
372
+ if (definition) computeMcpServerHash(definition);
269
373
  }
270
- return { servers, tools };
271
374
  }
272
375
 
273
376
  function isServerCacheValid(entry: ServerCacheEntry | undefined, definition: ServerEntry): entry is ServerCacheEntry {
@@ -304,52 +407,12 @@ export function computeMcpServerHash(definition: ServerEntry): string {
304
407
  return createHash("sha256").update(stableStringify(identity)).digest("hex");
305
408
  }
306
409
 
307
- function getToolPrefix(value: unknown): ToolPrefix {
308
- return value === "none" || value === "short" || value === "server" ? value : "server";
309
- }
310
-
311
410
  function isImportKind(value: unknown): value is ImportKind {
312
411
  return typeof value === "string" && Object.hasOwn(IMPORT_PATHS, value);
313
412
  }
314
413
 
315
- function getServerPrefix(serverName: string, mode: ToolPrefix): string {
316
- if (mode === "none") return "";
317
- if (mode === "short") {
318
- const short = serverName.replace(/-?mcp$/i, "").replace(/-/g, "_");
319
- return short || "mcp";
320
- }
321
- return serverName.replace(/-/g, "_");
322
- }
323
-
324
- function formatToolName(toolName: string, serverName: string, prefix: ToolPrefix): string {
325
- const serverPrefix = getServerPrefix(serverName, prefix);
326
- return serverPrefix ? `${serverPrefix}_${toolName}` : toolName;
327
- }
328
-
329
- function isToolExcluded(toolName: string, serverName: string, prefix: ToolPrefix, excludeTools: unknown): boolean {
330
- if (!Array.isArray(excludeTools) || excludeTools.length === 0) return false;
331
- const candidates = new Set([
332
- normalizeToolName(toolName),
333
- normalizeToolName(formatToolName(toolName, serverName, prefix)),
334
- normalizeToolName(formatToolName(toolName, serverName, "server")),
335
- normalizeToolName(formatToolName(toolName, serverName, "short")),
336
- ]);
337
- return excludeTools.some((excluded) => typeof excluded === "string" && candidates.has(normalizeToolName(excluded)));
338
- }
339
-
340
- function normalizeToolName(value: string): string {
341
- return value.replace(/-/g, "_");
342
- }
343
-
344
- function resourceNameToToolName(name: string): string {
345
- let result = name
346
- .replace(/[^a-zA-Z0-9]/g, "_")
347
- .replace(/_+/g, "_")
348
- .replace(/^_+/, "")
349
- .replace(/_+$/, "")
350
- .toLowerCase();
351
- if (!result || /^\d/.test(result)) result = `resource${result ? `_${result}` : ""}`;
352
- return result;
414
+ function isRecord(value: unknown): value is Record<string, unknown> {
415
+ return value !== null && typeof value === "object" && !Array.isArray(value);
353
416
  }
354
417
 
355
418
  function interpolateEnvRecord(values: Record<string, string> | undefined): Record<string, string> | undefined {
@@ -0,0 +1,197 @@
1
+ const BUILTIN_TOOL_NAMES = new Set(["read", "bash", "edit", "write", "grep", "find", "ls", "mcp"]);
2
+
3
+ export type McpToolPrefix = "server" | "none" | "short";
4
+
5
+ export interface McpGrantServerFacts {
6
+ readonly exposeResources?: boolean;
7
+ readonly includeTools?: readonly unknown[];
8
+ readonly excludeTools?: readonly unknown[];
9
+ }
10
+
11
+ export interface McpGrantToolMetadata {
12
+ readonly name?: string;
13
+ }
14
+
15
+ export interface McpGrantResourceMetadata {
16
+ readonly name?: string;
17
+ readonly uri?: string;
18
+ }
19
+
20
+ export interface McpGrantServerMetadata {
21
+ readonly tools?: readonly McpGrantToolMetadata[];
22
+ readonly resources?: readonly McpGrantResourceMetadata[];
23
+ }
24
+
25
+ export interface McpDirectToolGrantInput {
26
+ readonly selectors?: readonly string[];
27
+ readonly servers: Readonly<Record<string, McpGrantServerFacts>>;
28
+ /** Cache entries already validated by the source-loading adapter. */
29
+ readonly metadata: Readonly<Record<string, McpGrantServerMetadata>>;
30
+ readonly toolPrefix?: unknown;
31
+ }
32
+
33
+ export interface ResolvedMcpDirectToolSelection {
34
+ name: string;
35
+ selector: string;
36
+ }
37
+
38
+ export interface McpDirectToolGrant {
39
+ selections: ResolvedMcpDirectToolSelection[];
40
+ unresolvedSelectors: string[];
41
+ }
42
+
43
+ export function normalizeMcpDirectToolSelectors(selectors: readonly string[] | undefined): string[] {
44
+ return [...new Set((selectors ?? []).map((selector) => selector.replace(/\/+$/, "")).filter(Boolean))];
45
+ }
46
+
47
+ export function parseMcpDirectToolSelectors(selectors: readonly string[]): {
48
+ servers: Set<string>;
49
+ tools: Map<string, Set<string>>;
50
+ } {
51
+ const servers = new Set<string>();
52
+ const tools = new Map<string, Set<string>>();
53
+ for (const item of selectors) {
54
+ if (item.includes("/")) {
55
+ const [server, tool] = item.split("/", 2);
56
+ if (server && tool) {
57
+ if (!tools.has(server)) tools.set(server, new Set());
58
+ tools.get(server)!.add(tool);
59
+ } else if (server) {
60
+ servers.add(server);
61
+ }
62
+ } else if (item) {
63
+ servers.add(item);
64
+ }
65
+ }
66
+ return { servers, tools };
67
+ }
68
+
69
+ export function planMcpDirectToolGrant(input: McpDirectToolGrantInput): McpDirectToolGrant {
70
+ const selectors = normalizeMcpDirectToolSelectors(input.selectors);
71
+ if (selectors.length === 0) return { selections: [], unresolvedSelectors: [] };
72
+
73
+ const { servers: selectedServers, tools: selectedTools } = parseMcpDirectToolSelectors(selectors);
74
+ const selections: ResolvedMcpDirectToolSelection[] = [];
75
+ const seenNames = new Set<string>();
76
+ const prefix = normalizeMcpToolPrefix(input.toolPrefix);
77
+
78
+ for (const [serverName, server] of Object.entries(input.servers)) {
79
+ const metadata = input.metadata[serverName];
80
+ if (!metadata) continue;
81
+
82
+ const toolFilter: true | ReadonlySet<string> | undefined = selectedServers.has(serverName)
83
+ ? true
84
+ : selectedTools.get(serverName);
85
+ if (!toolFilter) continue;
86
+
87
+ for (const tool of Array.isArray(metadata.tools) ? metadata.tools : []) {
88
+ if (typeof tool?.name !== "string" || !tool.name) continue;
89
+ if (toolFilter !== true && !toolFilter.has(tool.name)) continue;
90
+ if (!isToolAllowed(tool.name, serverName, prefix, server.includeTools, server.excludeTools)) continue;
91
+ const name = formatToolName(tool.name, serverName, prefix);
92
+ if (BUILTIN_TOOL_NAMES.has(name) || seenNames.has(name)) continue;
93
+ seenNames.add(name);
94
+ selections.push({ name, selector: `${serverName}/${tool.name}` });
95
+ }
96
+
97
+ if (server.exposeResources === false) continue;
98
+ for (const resource of Array.isArray(metadata.resources) ? metadata.resources : []) {
99
+ if (typeof resource?.name !== "string" || !resource.name || typeof resource.uri !== "string" || !resource.uri) continue;
100
+ const baseName = `get_${resourceNameToToolName(resource.name)}`;
101
+ if (toolFilter !== true && !toolFilter.has(baseName)) continue;
102
+ if (!isToolAllowed(baseName, serverName, prefix, server.includeTools, server.excludeTools)) continue;
103
+ const name = formatToolName(baseName, serverName, prefix);
104
+ if (BUILTIN_TOOL_NAMES.has(name) || seenNames.has(name)) continue;
105
+ seenNames.add(name);
106
+ selections.push({ name, selector: `${serverName}/${baseName}` });
107
+ }
108
+ }
109
+
110
+ const unresolvedSelectors = selectors.filter((selector) =>
111
+ selector.includes("/")
112
+ ? !selections.some((selection) => selection.selector === selector)
113
+ : !selections.some((selection) => selection.selector.startsWith(`${selector}/`)),
114
+ );
115
+ return { selections, unresolvedSelectors };
116
+ }
117
+
118
+ export function normalizeMcpToolPrefix(value: unknown): McpToolPrefix {
119
+ return value === "none" || value === "short" || value === "server" ? value : "server";
120
+ }
121
+
122
+ export function formatUnresolvedMcpDirectToolSelectors(selectors: readonly string[]): string {
123
+ return `Unresolved MCP direct-tool selectors: ${selectors.join(", ")}. Direct MCP tools require a matching configured server and fresh metadata cache; runtime-registered servers require a host/pi-mcp-adapter handoff before child launch.`;
124
+ }
125
+
126
+ function getServerPrefix(serverName: string, mode: McpToolPrefix): string {
127
+ if (mode === "none") return "";
128
+ if (mode === "short") {
129
+ const short = serverName.replace(/-?mcp$/i, "").replace(/-/g, "_");
130
+ return short || "mcp";
131
+ }
132
+ return serverName.replace(/-/g, "_");
133
+ }
134
+
135
+ function formatToolName(toolName: string, serverName: string, prefix: McpToolPrefix): string {
136
+ const serverPrefix = getServerPrefix(serverName, prefix);
137
+ return serverPrefix ? `${serverPrefix}_${toolName}` : toolName;
138
+ }
139
+
140
+ function isToolAllowed(
141
+ toolName: string,
142
+ serverName: string,
143
+ prefix: McpToolPrefix,
144
+ includeTools: readonly unknown[] | undefined,
145
+ excludeTools: readonly unknown[] | undefined,
146
+ ): boolean {
147
+ const candidates = toolNameCandidates(toolName, serverName, prefix);
148
+ return (!Array.isArray(includeTools) || includeTools.length === 0 || matchesToolPatterns(candidates, includeTools))
149
+ && !matchesToolPatterns(candidates, excludeTools);
150
+ }
151
+
152
+ function toolNameCandidates(toolName: string, serverName: string, prefix: McpToolPrefix): Set<string> {
153
+ return new Set([
154
+ toolName,
155
+ `mcp_${toolName}`,
156
+ formatToolName(toolName, serverName, prefix),
157
+ formatToolName(toolName, serverName, "server"),
158
+ formatToolName(toolName, serverName, "short"),
159
+ formatToolName(toolName, serverName, "none"),
160
+ ]);
161
+ }
162
+
163
+ function matchesToolPatterns(candidates: ReadonlySet<string>, patterns: readonly unknown[] | undefined): boolean {
164
+ if (!Array.isArray(patterns) || patterns.length === 0) return false;
165
+ for (const pattern of patterns) {
166
+ if (typeof pattern !== "string") continue;
167
+ const normalizedPattern = normalizeToolName(pattern);
168
+ const matcher = normalizedPattern.includes("*") || normalizedPattern.includes("?")
169
+ ? globToRegExp(normalizedPattern)
170
+ : undefined;
171
+ for (const candidate of candidates) {
172
+ const normalizedCandidate = normalizeToolName(candidate);
173
+ if (matcher ? matcher.test(normalizedCandidate) : normalizedCandidate === normalizedPattern) return true;
174
+ }
175
+ }
176
+ return false;
177
+ }
178
+
179
+ function globToRegExp(pattern: string): RegExp {
180
+ const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
181
+ return new RegExp(`^${escaped}$`);
182
+ }
183
+
184
+ function normalizeToolName(value: string): string {
185
+ return value.replace(/-/g, "_");
186
+ }
187
+
188
+ function resourceNameToToolName(name: string): string {
189
+ let result = name
190
+ .replace(/[^a-zA-Z0-9]/g, "_")
191
+ .replace(/_+/g, "_")
192
+ .replace(/^_+/, "")
193
+ .replace(/_+$/, "")
194
+ .toLowerCase();
195
+ if (!result || /^\d/.test(result)) result = `resource${result ? `_${result}` : ""}`;
196
+ return result;
197
+ }