@ai-agent-forge/agent-forge 0.88.1 → 0.88.3

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 (518) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +1 -1
  3. package/bundled-plugins/agent-loop-policy/agent-forge.json +1 -1
  4. package/bundled-plugins/agent-loop-policy/plugin.json +1 -1
  5. package/bundled-plugins/coding-tools/agent-forge.json +1 -1
  6. package/bundled-plugins/coding-tools/plugin.json +1 -1
  7. package/bundled-plugins/compaction-policy/agent-forge.json +1 -1
  8. package/bundled-plugins/compaction-policy/plugin.json +1 -1
  9. package/bundled-plugins/overflow-policy/agent-forge.json +1 -1
  10. package/bundled-plugins/overflow-policy/plugin.json +1 -1
  11. package/bundled-plugins/provider-failover/agent-forge.json +1 -1
  12. package/bundled-plugins/provider-failover/plugin.json +1 -1
  13. package/bundled-plugins/retry-policy/agent-forge.json +1 -1
  14. package/bundled-plugins/retry-policy/plugin.json +1 -1
  15. package/dist/artifacts/paged-read.d.ts +6 -1
  16. package/dist/artifacts/paged-read.d.ts.map +1 -1
  17. package/dist/artifacts/paged-read.js.map +1 -1
  18. package/dist/bundle/.build-manifest.json +283 -263
  19. package/dist/bundle/chunks/{anthropic-messages-PLAKXR73.js → anthropic-messages-3FJHRAJL.js} +2 -2
  20. package/dist/bundle/chunks/anthropic.js +1 -1
  21. package/dist/bundle/chunks/{azure-openai-responses-OUWQ2AZD.js → azure-openai-responses-GCL47IDS.js} +1 -1
  22. package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
  23. package/dist/bundle/chunks/{chunk-Z72JWUZ4.js → chunk-32YDZI4J.js} +1 -1
  24. package/dist/bundle/chunks/{chunk-AQLNTW2B.js → chunk-755VNWIF.js} +17 -16
  25. package/dist/bundle/chunks/{chunk-LZOEQITZ.js → chunk-B42Y2VME.js} +120 -104
  26. package/dist/bundle/chunks/{chunk-DRQDKNXA.js → chunk-BVVSHK6W.js} +1 -1
  27. package/dist/bundle/chunks/{chunk-6R7UI4IY.js → chunk-QDLOMKF6.js} +1 -1
  28. package/dist/bundle/chunks/{chunk-D3ARGZFR.js → chunk-V3ACW7VD.js} +3 -3
  29. package/dist/bundle/chunks/{google-generative-ai-DLII6DAT.js → google-generative-ai-6BMXWA44.js} +1 -1
  30. package/dist/bundle/chunks/{google-vertex-G7BZL7GM.js → google-vertex-6H7NLRTK.js} +1 -1
  31. package/dist/bundle/chunks/image-resize-worker.js +3 -3
  32. package/dist/bundle/chunks/{mistral-conversations-JXUK24ID.js → mistral-conversations-IXUHSFSJ.js} +1 -1
  33. package/dist/bundle/chunks/{openai-codex-responses-5GSGFIPG.js → openai-codex-responses-YHUAEVCM.js} +1 -1
  34. package/dist/bundle/chunks/openai-codex.js +1 -1
  35. package/dist/bundle/chunks/{openai-completions-EI2I6DTG.js → openai-completions-ULQCFC72.js} +1 -1
  36. package/dist/bundle/chunks/openai-responses-NLLAJDPS.js +2 -0
  37. package/dist/bundle/chunks/{openrouter-images-G4GQRUSG.js → openrouter-images-GZZQZXMS.js} +1 -1
  38. package/dist/bundle/chunks/openrouter.js +1 -1
  39. package/dist/bundle/chunks/{pi-messages-PWU2VJMR.js → pi-messages-EJTI2EJ3.js} +1 -1
  40. package/dist/bundle/chunks/virtual-modules-TQWEGNNZ.js +5 -0
  41. package/dist/bundle/cli.js +1 -1
  42. package/dist/bundle/client.js +1 -1
  43. package/dist/bundle/index.js +1 -1
  44. package/dist/bundle/rpc-entry.js +1 -1
  45. package/dist/cli/args.d.ts +0 -1
  46. package/dist/cli/args.d.ts.map +1 -1
  47. package/dist/cli/args.js +1 -4
  48. package/dist/cli/args.js.map +1 -1
  49. package/dist/cli/config-selector.d.ts.map +1 -1
  50. package/dist/cli/config-selector.js +1 -1
  51. package/dist/cli/config-selector.js.map +1 -1
  52. package/dist/cli/experimental/cli.d.ts +3 -3
  53. package/dist/cli/experimental/cli.d.ts.map +1 -1
  54. package/dist/cli/experimental/cli.js +2 -2
  55. package/dist/cli/experimental/cli.js.map +1 -1
  56. package/dist/cli/experimental/commands/agent-forge.d.ts +15 -0
  57. package/dist/cli/experimental/commands/agent-forge.d.ts.map +1 -0
  58. package/dist/cli/experimental/commands/{pi.js → agent-forge.js} +4 -4
  59. package/dist/cli/experimental/commands/agent-forge.js.map +1 -0
  60. package/dist/cli/plugin-command.d.ts.map +1 -1
  61. package/dist/cli/plugin-command.js +8 -2
  62. package/dist/cli/plugin-command.js.map +1 -1
  63. package/dist/cli/startup-ui.d.ts.map +1 -1
  64. package/dist/cli/startup-ui.js +1 -1
  65. package/dist/cli/startup-ui.js.map +1 -1
  66. package/dist/config.d.ts +4 -4
  67. package/dist/config.d.ts.map +1 -1
  68. package/dist/config.js +7 -7
  69. package/dist/config.js.map +1 -1
  70. package/dist/core/agent-forge-manifest.d.ts +7 -0
  71. package/dist/core/agent-forge-manifest.d.ts.map +1 -0
  72. package/dist/core/{pi-manifest.js → agent-forge-manifest.js} +4 -4
  73. package/dist/core/agent-forge-manifest.js.map +1 -0
  74. package/dist/core/agent-session-compaction.d.ts +1 -1
  75. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  76. package/dist/core/agent-session-compaction.js +3 -3
  77. package/dist/core/agent-session-compaction.js.map +1 -1
  78. package/dist/core/agent-session-internal.d.ts +2 -0
  79. package/dist/core/agent-session-internal.d.ts.map +1 -1
  80. package/dist/core/agent-session-internal.js.map +1 -1
  81. package/dist/core/agent-session-lifecycle.d.ts.map +1 -1
  82. package/dist/core/agent-session-lifecycle.js +12 -1
  83. package/dist/core/agent-session-lifecycle.js.map +1 -1
  84. package/dist/core/agent-session-projection.d.ts.map +1 -1
  85. package/dist/core/agent-session-projection.js +3 -3
  86. package/dist/core/agent-session-projection.js.map +1 -1
  87. package/dist/core/agent-session-services.d.ts +3 -1
  88. package/dist/core/agent-session-services.d.ts.map +1 -1
  89. package/dist/core/agent-session-services.js +2 -1
  90. package/dist/core/agent-session-services.js.map +1 -1
  91. package/dist/core/agent-session-store.d.ts.map +1 -1
  92. package/dist/core/agent-session-store.js +6 -1
  93. package/dist/core/agent-session-store.js.map +1 -1
  94. package/dist/core/agent-session-tools.d.ts.map +1 -1
  95. package/dist/core/agent-session-tools.js +13 -0
  96. package/dist/core/agent-session-tools.js.map +1 -1
  97. package/dist/core/agent-session.d.ts +24 -0
  98. package/dist/core/agent-session.d.ts.map +1 -1
  99. package/dist/core/agent-session.js +58 -4
  100. package/dist/core/agent-session.js.map +1 -1
  101. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  102. package/dist/core/compaction/branch-summarization.js +1 -1
  103. package/dist/core/compaction/branch-summarization.js.map +1 -1
  104. package/dist/core/experimental.d.ts.map +1 -1
  105. package/dist/core/experimental.js +1 -3
  106. package/dist/core/experimental.js.map +1 -1
  107. package/dist/core/extensions/capability-runtime-store.d.ts +20 -1
  108. package/dist/core/extensions/capability-runtime-store.d.ts.map +1 -1
  109. package/dist/core/extensions/capability-runtime-store.js +67 -0
  110. package/dist/core/extensions/capability-runtime-store.js.map +1 -1
  111. package/dist/core/extensions/capability-runtime-types.d.ts +14 -0
  112. package/dist/core/extensions/capability-runtime-types.d.ts.map +1 -1
  113. package/dist/core/extensions/capability-runtime-types.js +7 -1
  114. package/dist/core/extensions/capability-runtime-types.js.map +1 -1
  115. package/dist/core/extensions/capability-runtime.d.ts.map +1 -1
  116. package/dist/core/extensions/capability-runtime.js +144 -42
  117. package/dist/core/extensions/capability-runtime.js.map +1 -1
  118. package/dist/core/extensions/virtual-modules.d.ts.map +1 -1
  119. package/dist/core/extensions/virtual-modules.js +6 -1
  120. package/dist/core/extensions/virtual-modules.js.map +1 -1
  121. package/dist/core/facade/coding-agent-facade.d.ts +1 -1
  122. package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
  123. package/dist/core/facade/coding-agent-facade.js +1 -1
  124. package/dist/core/facade/coding-agent-facade.js.map +1 -1
  125. package/dist/core/i18n/locales/zh-cn/cli.d.ts.map +1 -1
  126. package/dist/core/i18n/locales/zh-cn/cli.js +2 -0
  127. package/dist/core/i18n/locales/zh-cn/cli.js.map +1 -1
  128. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts +1 -1
  129. package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts.map +1 -1
  130. package/dist/core/i18n/locales/zh-cn/core-contract-final.js +3 -3
  131. package/dist/core/i18n/locales/zh-cn/core-contract-final.js.map +1 -1
  132. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts.map +1 -1
  133. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js +1 -1
  134. package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js.map +1 -1
  135. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts.map +1 -1
  136. package/dist/core/i18n/locales/zh-cn/core-errors.js +1 -1
  137. package/dist/core/i18n/locales/zh-cn/core-errors.js.map +1 -1
  138. package/dist/core/i18n/locales/zh-cn/index.d.ts.map +1 -1
  139. package/dist/core/i18n/locales/zh-cn/index.js +2 -0
  140. package/dist/core/i18n/locales/zh-cn/index.js.map +1 -1
  141. package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts.map +1 -1
  142. package/dist/core/i18n/locales/zh-cn/interactive-mode.js +5 -0
  143. package/dist/core/i18n/locales/zh-cn/interactive-mode.js.map +1 -1
  144. package/dist/core/i18n/locales/zh-cn/session-cleanup.d.ts +7 -0
  145. package/dist/core/i18n/locales/zh-cn/session-cleanup.d.ts.map +1 -0
  146. package/dist/core/i18n/locales/zh-cn/session-cleanup.js +15 -0
  147. package/dist/core/i18n/locales/zh-cn/session-cleanup.js.map +1 -0
  148. package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts.map +1 -1
  149. package/dist/core/i18n/locales/zh-cn/slash-commands.js +1 -0
  150. package/dist/core/i18n/locales/zh-cn/slash-commands.js.map +1 -1
  151. package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts.map +1 -1
  152. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js +2 -0
  153. package/dist/core/i18n/locales/zh-cn/tui-components-misc.js.map +1 -1
  154. package/dist/core/model-resolver.d.ts +2 -0
  155. package/dist/core/model-resolver.d.ts.map +1 -1
  156. package/dist/core/model-resolver.js +4 -1
  157. package/dist/core/model-resolver.js.map +1 -1
  158. package/dist/core/package-resource-collection.d.ts.map +1 -1
  159. package/dist/core/package-resource-collection.js +5 -5
  160. package/dist/core/package-resource-collection.js.map +1 -1
  161. package/dist/core/provider-composer.d.ts.map +1 -1
  162. package/dist/core/provider-composer.js +3 -3
  163. package/dist/core/provider-composer.js.map +1 -1
  164. package/dist/core/resource-loader.d.ts.map +1 -1
  165. package/dist/core/resource-loader.js +1 -1
  166. package/dist/core/resource-loader.js.map +1 -1
  167. package/dist/core/sdk.d.ts +1 -1
  168. package/dist/core/sdk.d.ts.map +1 -1
  169. package/dist/core/sdk.js +30 -8
  170. package/dist/core/sdk.js.map +1 -1
  171. package/dist/core/session-cleanup.d.ts +49 -0
  172. package/dist/core/session-cleanup.d.ts.map +1 -0
  173. package/dist/core/session-cleanup.js +159 -0
  174. package/dist/core/session-cleanup.js.map +1 -0
  175. package/dist/core/session-index.d.ts +75 -0
  176. package/dist/core/session-index.d.ts.map +1 -0
  177. package/dist/core/session-index.js +455 -0
  178. package/dist/core/session-index.js.map +1 -0
  179. package/dist/core/session-manager.d.ts +9 -0
  180. package/dist/core/session-manager.d.ts.map +1 -1
  181. package/dist/core/session-manager.js +206 -51
  182. package/dist/core/session-manager.js.map +1 -1
  183. package/dist/core/settings-manager.d.ts.map +1 -1
  184. package/dist/core/settings-manager.js +5 -10
  185. package/dist/core/settings-manager.js.map +1 -1
  186. package/dist/core/slash-commands.d.ts.map +1 -1
  187. package/dist/core/slash-commands.js +5 -0
  188. package/dist/core/slash-commands.js.map +1 -1
  189. package/dist/core/system-prompt.d.ts.map +1 -1
  190. package/dist/core/system-prompt.js +12 -1
  191. package/dist/core/system-prompt.js.map +1 -1
  192. package/dist/core/timings.d.ts.map +1 -1
  193. package/dist/core/timings.js +1 -3
  194. package/dist/core/timings.js.map +1 -1
  195. package/dist/core/tools/capability-mount.d.ts +40 -0
  196. package/dist/core/tools/capability-mount.d.ts.map +1 -0
  197. package/dist/core/tools/capability-mount.js +112 -0
  198. package/dist/core/tools/capability-mount.js.map +1 -0
  199. package/dist/core/tools/render-utils.d.ts +1 -1
  200. package/dist/core/tools/render-utils.d.ts.map +1 -1
  201. package/dist/core/tools/render-utils.js.map +1 -1
  202. package/dist/core/tools/tool-definition.d.ts +1 -1
  203. package/dist/core/tools/tool-definition.d.ts.map +1 -1
  204. package/dist/core/tools/tool-definition.js.map +1 -1
  205. package/dist/core/trace-retention.d.ts +16 -1
  206. package/dist/core/trace-retention.d.ts.map +1 -1
  207. package/dist/core/trace-retention.js +43 -20
  208. package/dist/core/trace-retention.js.map +1 -1
  209. package/dist/export-html/ansi-to-html.d.ts.map +1 -0
  210. package/dist/export-html/ansi-to-html.js.map +1 -0
  211. package/dist/{core/export-html → export-html}/index.d.ts +1 -1
  212. package/dist/export-html/index.d.ts.map +1 -0
  213. package/dist/{core/export-html → export-html}/index.js +5 -5
  214. package/dist/export-html/index.js.map +1 -0
  215. package/dist/{core/export-html → export-html}/tool-renderer.d.ts +2 -2
  216. package/dist/export-html/tool-renderer.d.ts.map +1 -0
  217. package/dist/export-html/tool-renderer.js.map +1 -0
  218. package/dist/{modes/interactive → host}/model-catalog-refresh.d.ts +1 -1
  219. package/dist/host/model-catalog-refresh.d.ts.map +1 -0
  220. package/dist/{modes/interactive → host}/model-catalog-refresh.js +1 -1
  221. package/dist/host/model-catalog-refresh.js.map +1 -0
  222. package/dist/index.d.ts +5 -5
  223. package/dist/index.d.ts.map +1 -1
  224. package/dist/index.js +12 -12
  225. package/dist/index.js.map +1 -1
  226. package/dist/main.d.ts.map +1 -1
  227. package/dist/main.js +26 -14
  228. package/dist/main.js.map +1 -1
  229. package/dist/modes/interactive/components/agents-view.d.ts.map +1 -1
  230. package/dist/modes/interactive/components/agents-view.js +1 -1
  231. package/dist/modes/interactive/components/agents-view.js.map +1 -1
  232. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  233. package/dist/modes/interactive/components/armin.js +1 -1
  234. package/dist/modes/interactive/components/armin.js.map +1 -1
  235. package/dist/modes/interactive/components/assistant-message.d.ts +6 -0
  236. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  237. package/dist/modes/interactive/components/assistant-message.js +108 -27
  238. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  239. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  240. package/dist/modes/interactive/components/bash-execution.js +1 -1
  241. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  242. package/dist/modes/interactive/components/bordered-loader.d.ts +1 -1
  243. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  244. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  245. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  246. package/dist/modes/interactive/components/branch-summary-message.js +1 -1
  247. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  248. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  249. package/dist/modes/interactive/components/compaction-summary-message.js +1 -1
  250. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  251. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  252. package/dist/modes/interactive/components/config-selector.js +1 -1
  253. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  254. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  255. package/dist/modes/interactive/components/custom-entry.js +1 -1
  256. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  257. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  258. package/dist/modes/interactive/components/custom-message.js +1 -1
  259. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  260. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  261. package/dist/modes/interactive/components/daxnuts.js +1 -1
  262. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  263. package/dist/modes/interactive/components/dialog-editor.d.ts.map +1 -1
  264. package/dist/modes/interactive/components/dialog-editor.js +1 -1
  265. package/dist/modes/interactive/components/dialog-editor.js.map +1 -1
  266. package/dist/modes/interactive/components/dialog-input.d.ts.map +1 -1
  267. package/dist/modes/interactive/components/dialog-input.js +1 -1
  268. package/dist/modes/interactive/components/dialog-input.js.map +1 -1
  269. package/dist/modes/interactive/components/dialog-selector.d.ts.map +1 -1
  270. package/dist/modes/interactive/components/dialog-selector.js +1 -1
  271. package/dist/modes/interactive/components/dialog-selector.js.map +1 -1
  272. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  273. package/dist/modes/interactive/components/diff.js +1 -1
  274. package/dist/modes/interactive/components/diff.js.map +1 -1
  275. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  276. package/dist/modes/interactive/components/dynamic-border.js +1 -1
  277. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  278. package/dist/modes/interactive/components/first-time-setup.d.ts +1 -1
  279. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  280. package/dist/modes/interactive/components/first-time-setup.js +1 -1
  281. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  282. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  283. package/dist/modes/interactive/components/footer.js +1 -1
  284. package/dist/modes/interactive/components/footer.js.map +1 -1
  285. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  286. package/dist/modes/interactive/components/keybinding-hints.js +1 -1
  287. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  288. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  289. package/dist/modes/interactive/components/login-dialog.js +1 -1
  290. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  291. package/dist/modes/interactive/components/mermaid.d.ts +1 -1
  292. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
  293. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  294. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  295. package/dist/modes/interactive/components/model-selector.js +2 -2
  296. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  297. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  298. package/dist/modes/interactive/components/oauth-selector.js +1 -1
  299. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  300. package/dist/modes/interactive/components/plugin-manager-entry.d.ts.map +1 -1
  301. package/dist/modes/interactive/components/plugin-manager-entry.js +1 -1
  302. package/dist/modes/interactive/components/plugin-manager-entry.js.map +1 -1
  303. package/dist/modes/interactive/components/plugin-selection-entry.d.ts.map +1 -1
  304. package/dist/modes/interactive/components/plugin-selection-entry.js +1 -1
  305. package/dist/modes/interactive/components/plugin-selection-entry.js.map +1 -1
  306. package/dist/modes/interactive/components/queue-manager-selector.d.ts.map +1 -1
  307. package/dist/modes/interactive/components/queue-manager-selector.js +1 -1
  308. package/dist/modes/interactive/components/queue-manager-selector.js.map +1 -1
  309. package/dist/modes/interactive/components/render-types.d.ts +1 -1
  310. package/dist/modes/interactive/components/render-types.d.ts.map +1 -1
  311. package/dist/modes/interactive/components/render-types.js.map +1 -1
  312. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  313. package/dist/modes/interactive/components/scoped-models-selector.js +1 -1
  314. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  315. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  316. package/dist/modes/interactive/components/session-selector-search.js +5 -1
  317. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  318. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  319. package/dist/modes/interactive/components/session-selector.js +11 -2
  320. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  321. package/dist/modes/interactive/components/settings-selector.d.ts +1 -1
  322. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  323. package/dist/modes/interactive/components/settings-selector.js +1 -1
  324. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  325. package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -1
  326. package/dist/modes/interactive/components/settings-submenu.js +1 -1
  327. package/dist/modes/interactive/components/settings-submenu.js.map +1 -1
  328. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  329. package/dist/modes/interactive/components/show-images-selector.js +1 -1
  330. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  331. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  332. package/dist/modes/interactive/components/skill-invocation-message.js +1 -1
  333. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  334. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  335. package/dist/modes/interactive/components/status-indicator.js +1 -1
  336. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  337. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  338. package/dist/modes/interactive/components/theme-selector.js +1 -1
  339. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  340. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  341. package/dist/modes/interactive/components/thinking-selector.js +1 -1
  342. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  343. package/dist/modes/interactive/components/tool-execution.d.ts +19 -0
  344. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  345. package/dist/modes/interactive/components/tool-execution.js +139 -4
  346. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  347. package/dist/modes/interactive/components/tool-run-group.d.ts +44 -0
  348. package/dist/modes/interactive/components/tool-run-group.d.ts.map +1 -0
  349. package/dist/modes/interactive/components/tool-run-group.js +121 -0
  350. package/dist/modes/interactive/components/tool-run-group.js.map +1 -0
  351. package/dist/modes/interactive/components/tree-list.d.ts.map +1 -1
  352. package/dist/modes/interactive/components/tree-list.js +1 -1
  353. package/dist/modes/interactive/components/tree-list.js.map +1 -1
  354. package/dist/modes/interactive/components/tree-render.d.ts.map +1 -1
  355. package/dist/modes/interactive/components/tree-render.js +1 -1
  356. package/dist/modes/interactive/components/tree-render.js.map +1 -1
  357. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  358. package/dist/modes/interactive/components/tree-selector.js +1 -1
  359. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  360. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  361. package/dist/modes/interactive/components/user-message-selector.js +1 -1
  362. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  363. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  364. package/dist/modes/interactive/components/user-message.js +1 -1
  365. package/dist/modes/interactive/components/user-message.js.map +1 -1
  366. package/dist/modes/interactive/components/workflow-view.d.ts.map +1 -1
  367. package/dist/modes/interactive/components/workflow-view.js +1 -1
  368. package/dist/modes/interactive/components/workflow-view.js.map +1 -1
  369. package/dist/modes/interactive/interactive-auth.d.ts +1 -1
  370. package/dist/modes/interactive/interactive-auth.d.ts.map +1 -1
  371. package/dist/modes/interactive/interactive-auth.js +1 -1
  372. package/dist/modes/interactive/interactive-auth.js.map +1 -1
  373. package/dist/modes/interactive/interactive-commands.d.ts +125 -6
  374. package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
  375. package/dist/modes/interactive/interactive-commands.js +698 -4
  376. package/dist/modes/interactive/interactive-commands.js.map +1 -1
  377. package/dist/modes/interactive/interactive-events.d.ts +174 -0
  378. package/dist/modes/interactive/interactive-events.d.ts.map +1 -0
  379. package/dist/modes/interactive/interactive-events.js +704 -0
  380. package/dist/modes/interactive/interactive-events.js.map +1 -0
  381. package/dist/modes/interactive/interactive-format.d.ts.map +1 -1
  382. package/dist/modes/interactive/interactive-format.js +1 -1
  383. package/dist/modes/interactive/interactive-format.js.map +1 -1
  384. package/dist/modes/interactive/interactive-lifecycle.d.ts +94 -0
  385. package/dist/modes/interactive/interactive-lifecycle.d.ts.map +1 -0
  386. package/dist/modes/interactive/interactive-lifecycle.js +177 -0
  387. package/dist/modes/interactive/interactive-lifecycle.js.map +1 -0
  388. package/dist/modes/interactive/interactive-mode.d.ts +254 -129
  389. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  390. package/dist/modes/interactive/interactive-mode.js +275 -2101
  391. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  392. package/dist/modes/interactive/interactive-queues.d.ts +96 -0
  393. package/dist/modes/interactive/interactive-queues.d.ts.map +1 -0
  394. package/dist/modes/interactive/interactive-queues.js +183 -0
  395. package/dist/modes/interactive/interactive-queues.js.map +1 -0
  396. package/dist/modes/interactive/interactive-selectors.d.ts +95 -5
  397. package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
  398. package/dist/modes/interactive/interactive-selectors.js +517 -6
  399. package/dist/modes/interactive/interactive-selectors.js.map +1 -1
  400. package/dist/modes/interactive/startup-services.d.ts +31 -0
  401. package/dist/modes/interactive/startup-services.d.ts.map +1 -0
  402. package/dist/modes/interactive/startup-services.js +123 -0
  403. package/dist/modes/interactive/startup-services.js.map +1 -0
  404. package/dist/modes/memory-preheat.d.ts +11 -0
  405. package/dist/modes/memory-preheat.d.ts.map +1 -0
  406. package/dist/modes/memory-preheat.js +20 -0
  407. package/dist/modes/memory-preheat.js.map +1 -0
  408. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  409. package/dist/modes/rpc/rpc-mode.js +3 -1
  410. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  411. package/dist/plugins/ecosystem/cli.d.ts.map +1 -1
  412. package/dist/plugins/ecosystem/cli.js +6 -3
  413. package/dist/plugins/ecosystem/cli.js.map +1 -1
  414. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts +7 -1
  415. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts.map +1 -1
  416. package/dist/plugins/ecosystem/node-plugin-bootstrap.js +50 -3
  417. package/dist/plugins/ecosystem/node-plugin-bootstrap.js.map +1 -1
  418. package/dist/plugins/ecosystem/plugin-bootstrap.d.ts +28 -16
  419. package/dist/plugins/ecosystem/plugin-bootstrap.d.ts.map +1 -1
  420. package/dist/plugins/ecosystem/plugin-bootstrap.js +35 -33
  421. package/dist/plugins/ecosystem/plugin-bootstrap.js.map +1 -1
  422. package/dist/profile/plugin-profiles.d.ts +1 -1
  423. package/dist/profile/plugin-profiles.d.ts.map +1 -1
  424. package/dist/profile/plugin-profiles.js +18 -0
  425. package/dist/profile/plugin-profiles.js.map +1 -1
  426. package/dist/remote/server-assembly.d.ts.map +1 -1
  427. package/dist/remote/server-assembly.js +7 -2
  428. package/dist/remote/server-assembly.js.map +1 -1
  429. package/dist/{profiles → suites}/builtin-suites.d.ts +14 -4
  430. package/dist/suites/builtin-suites.d.ts.map +1 -0
  431. package/dist/{profiles → suites}/builtin-suites.js +20 -5
  432. package/dist/suites/builtin-suites.js.map +1 -0
  433. package/dist/suites/resolved-agent-profile.d.ts.map +1 -0
  434. package/dist/suites/resolved-agent-profile.js.map +1 -0
  435. package/dist/suites/suite-lifecycle.d.ts.map +1 -0
  436. package/dist/suites/suite-lifecycle.js.map +1 -0
  437. package/dist/suites/suite-loader.d.ts.map +1 -0
  438. package/dist/suites/suite-loader.js.map +1 -0
  439. package/dist/{modes/interactive/theme → theme}/dark.json +1 -1
  440. package/dist/{modes/interactive/theme → theme}/light.json +1 -1
  441. package/dist/{modes/interactive/theme → theme}/theme-controller.d.ts +1 -1
  442. package/dist/theme/theme-controller.d.ts.map +1 -0
  443. package/dist/{modes/interactive/theme → theme}/theme-controller.js +1 -1
  444. package/dist/theme/theme-controller.js.map +1 -0
  445. package/dist/{modes/interactive/theme → theme}/theme.d.ts +1 -1
  446. package/dist/theme/theme.d.ts.map +1 -0
  447. package/dist/{modes/interactive/theme → theme}/theme.js +5 -5
  448. package/dist/theme/theme.js.map +1 -0
  449. package/docs/compaction.md +7 -7
  450. package/docs/environment-variables.md +10 -4
  451. package/docs/keybindings.md +3 -3
  452. package/docs/models.md +17 -17
  453. package/docs/packages.md +1 -1
  454. package/docs/prompt-templates.md +1 -1
  455. package/docs/rpc.md +2 -2
  456. package/docs/sdk.md +5 -5
  457. package/docs/session-format.md +3 -3
  458. package/docs/settings.md +368 -354
  459. package/docs/shell-aliases.md +1 -1
  460. package/docs/skills.md +1 -1
  461. package/docs/terminal-setup.md +17 -17
  462. package/docs/themes.md +5 -5
  463. package/docs/tmux.md +4 -4
  464. package/docs/tui.md +1 -1
  465. package/docs/windows.md +1 -1
  466. package/examples/extensions/bash-spawn-hook/index.ts +1 -1
  467. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  468. package/examples/extensions/with-deps/package-lock.json +2 -2
  469. package/examples/extensions/with-deps/package.json +1 -6
  470. package/examples/extensions/with-deps/plugin.json +1 -1
  471. package/package.json +2 -2
  472. package/dist/bundle/chunks/openai-responses-AUJQ3NWT.js +0 -2
  473. package/dist/bundle/chunks/virtual-modules-WF6WRHP7.js +0 -5
  474. package/dist/cli/experimental/commands/pi.d.ts +0 -15
  475. package/dist/cli/experimental/commands/pi.d.ts.map +0 -1
  476. package/dist/cli/experimental/commands/pi.js.map +0 -1
  477. package/dist/core/export-html/ansi-to-html.d.ts.map +0 -1
  478. package/dist/core/export-html/ansi-to-html.js.map +0 -1
  479. package/dist/core/export-html/index.d.ts.map +0 -1
  480. package/dist/core/export-html/index.js.map +0 -1
  481. package/dist/core/export-html/tool-renderer.d.ts.map +0 -1
  482. package/dist/core/export-html/tool-renderer.js.map +0 -1
  483. package/dist/core/pi-manifest.d.ts +0 -7
  484. package/dist/core/pi-manifest.d.ts.map +0 -1
  485. package/dist/core/pi-manifest.js.map +0 -1
  486. package/dist/modes/interactive/model-catalog-refresh.d.ts.map +0 -1
  487. package/dist/modes/interactive/model-catalog-refresh.js.map +0 -1
  488. package/dist/modes/interactive/theme/theme-controller.d.ts.map +0 -1
  489. package/dist/modes/interactive/theme/theme-controller.js.map +0 -1
  490. package/dist/modes/interactive/theme/theme.d.ts.map +0 -1
  491. package/dist/modes/interactive/theme/theme.js.map +0 -1
  492. package/dist/profiles/builtin-suites.d.ts.map +0 -1
  493. package/dist/profiles/builtin-suites.js.map +0 -1
  494. package/dist/profiles/resolved-agent-profile.d.ts.map +0 -1
  495. package/dist/profiles/resolved-agent-profile.js.map +0 -1
  496. package/dist/profiles/suite-lifecycle.d.ts.map +0 -1
  497. package/dist/profiles/suite-lifecycle.js.map +0 -1
  498. package/dist/profiles/suite-loader.d.ts.map +0 -1
  499. package/dist/profiles/suite-loader.js.map +0 -1
  500. package/dist/utils/deprecation.d.ts +0 -4
  501. package/dist/utils/deprecation.d.ts.map +0 -1
  502. package/dist/utils/deprecation.js +0 -13
  503. package/dist/utils/deprecation.js.map +0 -1
  504. /package/dist/{core/export-html → export-html}/ansi-to-html.d.ts +0 -0
  505. /package/dist/{core/export-html → export-html}/ansi-to-html.js +0 -0
  506. /package/dist/{core/export-html → export-html}/template.css +0 -0
  507. /package/dist/{core/export-html → export-html}/template.html +0 -0
  508. /package/dist/{core/export-html → export-html}/template.js +0 -0
  509. /package/dist/{core/export-html → export-html}/tool-renderer.js +0 -0
  510. /package/dist/{core/export-html → export-html}/vendor/highlight.min.js +0 -0
  511. /package/dist/{core/export-html → export-html}/vendor/marked.min.js +0 -0
  512. /package/dist/{profiles → suites}/resolved-agent-profile.d.ts +0 -0
  513. /package/dist/{profiles → suites}/resolved-agent-profile.js +0 -0
  514. /package/dist/{profiles → suites}/suite-lifecycle.d.ts +0 -0
  515. /package/dist/{profiles → suites}/suite-lifecycle.js +0 -0
  516. /package/dist/{profiles → suites}/suite-loader.d.ts +0 -0
  517. /package/dist/{profiles → suites}/suite-loader.js +0 -0
  518. /package/dist/{modes/interactive/theme → theme}/theme-schema.json +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"agent-session-store.d.ts","sourceRoot":"","sources":["../../src/core/agent-session-store.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,qGAA6C;IAC7C,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,qFAAmC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,2EAAqC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,0FAA0C;IAC1C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,yEAA6C;IAC7C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAMD,+FAAuD;AACvD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAIvD;AAED,gIAAoE;AACpE,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUlF;AAoBD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B,GAAG,kBAAkB,GAAG,SAAS,CAyCjC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,SAAS,qBAAqB,EAAE,CAwCnC","sourcesContent":["/**\n * 子代理会话存取(D-060 S2):子会话与 root 会话一样落 JSONL 文件,但放在\n * `<agentDir>/sessions/_agents/` —— 与用户的会话列表分开(子会话不进用户会话选择器),\n * 同时仍可按 `sessionId` 精确回读、可按父会话 id 反查。\n *\n * 三条纪律:\n * - **文件是持久层**:内存索引(调度器的 `maxRetainedRecords`)淘汰不影响这里的可读性;\n * - **有界**:回读按字节上限截断并给 `truncated` 标记,绝不把整份 transcript 无声塞给调用方;\n * - **寻址安全**:`sessionId` 先过形状校验(UUID/`st:` 形态、无路径分隔符),再做路径拼接,\n * 杜绝 `../` 逃逸;跨父作用域由调用方(宿主)用返回的 `parentAgentSession` 判定。\n */\nimport { readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { agentSessionsDir } from \"./agent-session-paths.ts\";\n\nexport interface AgentSessionReadV1 {\n\treadonly sessionId: string;\n\t/** 血缘:父 agent 会话 id(子会话必有;缺失说明文件非本次设计产物)。 */\n\treadonly parentAgentSession?: string;\n\t/** 血缘:创建该会话的角色 id(审计用途,不是权限判据)。 */\n\treadonly agentRole?: string;\n\treadonly cwd?: string;\n\treadonly createdAt?: string;\n\t/** 文件字节数(整份 transcript,而不是返回的片段)。 */\n\treadonly bytes: number;\n\t/** 解析出的 entry 条数(不含头行);截断时是**已返回**的条数。 */\n\treadonly entryCount: number;\n\t/** 达到 `maxBytes` 上限、只返回了前段 entry 时为 true。 */\n\treadonly truncated: boolean;\n\treadonly entries: readonly unknown[];\n}\n\nexport interface AgentSessionSummaryV1 {\n\treadonly sessionId: string;\n\treadonly parentAgentSession?: string;\n\treadonly agentRole?: string;\n\treadonly createdAt?: string;\n\treadonly modifiedAt: number;\n\treadonly bytes: number;\n}\n\nconst DEFAULT_MAX_BYTES = 262_144;\nconst DEFAULT_LIST_LIMIT = 200;\nconst HEADER_SCAN_BYTES = 8192;\n\n/** 会话 id 形状:UUID(root/子会话)或池化 wire 任务 id(`st:` 前缀)。 */\nexport function isAgentSessionId(value: string): boolean {\n\tif (value.length === 0 || value.length > 128) return false;\n\tif (value.startsWith(\"st:\")) return /^st:[0-9]+:[a-z0-9-]+$/i.test(value);\n\treturn /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);\n}\n\n/** 目录内定位某会话文件:命名形如 `<时间戳>_<sessionId>.jsonl`。导出给宿主的 resume 打开路径。 */\nexport function findSessionFile(dir: string, sessionId: string): string | undefined {\n\tlet names: string[];\n\ttry {\n\t\tnames = readdirSync(dir);\n\t} catch {\n\t\treturn undefined;\n\t}\n\tconst suffix = `_${sessionId}.jsonl`;\n\tconst match = names.find((name) => name === `${sessionId}.jsonl` || name.endsWith(suffix));\n\treturn match === undefined ? undefined : join(dir, match);\n}\n\nfunction parseHeader(line: string): Record<string, unknown> | undefined {\n\ttry {\n\t\tconst parsed = JSON.parse(line) as unknown;\n\t\tif (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) return undefined;\n\t\tconst record = parsed as Record<string, unknown>;\n\t\treturn record.type === \"session\" ? record : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction readHeader(filePath: string): { header?: Record<string, unknown>; bytes: number } {\n\tconst bytes = statSync(filePath).size;\n\tconst buffer = readFileSync(filePath, { encoding: \"utf-8\", flag: \"r\" });\n\tconst firstLine = buffer.slice(0, HEADER_SCAN_BYTES).split(\"\\n\", 1)[0] ?? \"\";\n\treturn { header: parseHeader(firstLine), bytes };\n}\n\n/**\n * 按 `sessionId` 有界回读一份子会话 transcript。不存在/形状非法/无头行都返回 undefined\n * (与\"无权\"同型,不区分原因)。\n */\nexport function readAgentSession(options: {\n\treadonly agentDir: string;\n\treadonly sessionId: string;\n\treadonly maxBytes?: number;\n}): AgentSessionReadV1 | undefined {\n\tif (!isAgentSessionId(options.sessionId)) return undefined;\n\tconst dir = agentSessionsDir(options.agentDir);\n\tconst filePath = findSessionFile(dir, options.sessionId);\n\tif (filePath === undefined) return undefined;\n\tlet text: string;\n\tlet bytes: number;\n\ttry {\n\t\tbytes = statSync(filePath).size;\n\t\ttext = readFileSync(filePath, { encoding: \"utf-8\", flag: \"r\" });\n\t} catch {\n\t\treturn undefined;\n\t}\n\tconst maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\tconst truncated = text.length > maxBytes;\n\tconst bounded = truncated ? text.slice(0, maxBytes) : text;\n\tconst lines = bounded.split(\"\\n\").filter((line) => line.trim() !== \"\");\n\tconst header = lines.length > 0 ? parseHeader(lines[0] as string) : undefined;\n\tconst entries: unknown[] = [];\n\tfor (const line of lines.slice(header === undefined ? 0 : 1)) {\n\t\ttry {\n\t\t\tentries.push(JSON.parse(line) as unknown);\n\t\t} catch {\n\t\t\t// 截断可能切在行中间:忽略无法解析的尾行(truncated 已如实置位)。\n\t\t}\n\t}\n\tconst parentAgentSession = typeof header?.parentAgentSession === \"string\" ? header.parentAgentSession : undefined;\n\tconst agentRole = typeof header?.agentRole === \"string\" ? header.agentRole : undefined;\n\tconst cwd = typeof header?.cwd === \"string\" ? header.cwd : undefined;\n\tconst createdAt = typeof header?.timestamp === \"string\" ? header.timestamp : undefined;\n\treturn {\n\t\tsessionId: options.sessionId,\n\t\t...(parentAgentSession === undefined ? {} : { parentAgentSession }),\n\t\t...(agentRole === undefined ? {} : { agentRole }),\n\t\t...(cwd === undefined ? {} : { cwd }),\n\t\t...(createdAt === undefined ? {} : { createdAt }),\n\t\tbytes,\n\t\tentryCount: entries.length,\n\t\ttruncated,\n\t\tentries: Object.freeze(entries),\n\t};\n}\n\n/**\n * 列子会话摘要(只读头行,不解析正文):`parentAgentSession` 提供时只返回该父会话的子会话——\n * \"按父反查\"是审计入口;`limit` 默认 200,超过按修改时间倒序截断。\n */\nexport function listAgentSessions(options: {\n\treadonly agentDir: string;\n\treadonly parentAgentSession?: string;\n\treadonly limit?: number;\n}): readonly AgentSessionSummaryV1[] {\n\tlet names: string[];\n\tlet dir: string;\n\ttry {\n\t\tdir = agentSessionsDir(options.agentDir);\n\t\tnames = readdirSync(dir).filter((name) => name.endsWith(\".jsonl\"));\n\t} catch {\n\t\treturn Object.freeze([]);\n\t}\n\tconst summaries: AgentSessionSummaryV1[] = [];\n\tfor (const name of names) {\n\t\tconst stem = name.slice(0, -\".jsonl\".length);\n\t\tconst separator = stem.lastIndexOf(\"_\");\n\t\tconst sessionId = separator === -1 ? stem : stem.slice(separator + 1);\n\t\tif (!isAgentSessionId(sessionId)) continue;\n\t\tconst filePath = join(dir, name);\n\t\tlet scanned: { header?: Record<string, unknown>; bytes: number };\n\t\tlet modifiedAt: number;\n\t\ttry {\n\t\t\tscanned = readHeader(filePath);\n\t\t\tmodifiedAt = statSync(filePath).mtimeMs;\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tconst parentAgentSession =\n\t\t\ttypeof scanned.header?.parentAgentSession === \"string\" ? scanned.header.parentAgentSession : undefined;\n\t\tif (options.parentAgentSession !== undefined && parentAgentSession !== options.parentAgentSession) continue;\n\t\tconst agentRole = typeof scanned.header?.agentRole === \"string\" ? scanned.header.agentRole : undefined;\n\t\tconst createdAt = typeof scanned.header?.timestamp === \"string\" ? scanned.header.timestamp : undefined;\n\t\tsummaries.push({\n\t\t\tsessionId,\n\t\t\t...(parentAgentSession === undefined ? {} : { parentAgentSession }),\n\t\t\t...(agentRole === undefined ? {} : { agentRole }),\n\t\t\t...(createdAt === undefined ? {} : { createdAt }),\n\t\t\tmodifiedAt,\n\t\t\tbytes: scanned.bytes,\n\t\t});\n\t}\n\tsummaries.sort((left, right) => right.modifiedAt - left.modifiedAt);\n\treturn Object.freeze(summaries.slice(0, options.limit ?? DEFAULT_LIST_LIMIT));\n}\n"]}
1
+ {"version":3,"file":"agent-session-store.d.ts","sourceRoot":"","sources":["../../src/core/agent-session-store.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,qGAA6C;IAC7C,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,qFAAmC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,2EAAqC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,0FAA0C;IAC1C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,yEAA6C;IAC7C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAMD,+FAAuD;AACvD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAQvD;AAED,gIAAoE;AACpE,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUlF;AAoBD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B,GAAG,kBAAkB,GAAG,SAAS,CAyCjC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,SAAS,qBAAqB,EAAE,CAwCnC","sourcesContent":["/**\n * 子代理会话存取(D-060 S2):子会话与 root 会话一样落 JSONL 文件,但放在\n * `<agentDir>/sessions/_agents/` —— 与用户的会话列表分开(子会话不进用户会话选择器),\n * 同时仍可按 `sessionId` 精确回读、可按父会话 id 反查。\n *\n * 三条纪律:\n * - **文件是持久层**:内存索引(调度器的 `maxRetainedRecords`)淘汰不影响这里的可读性;\n * - **有界**:回读按字节上限截断并给 `truncated` 标记,绝不把整份 transcript 无声塞给调用方;\n * - **寻址安全**:`sessionId` 先过形状校验(UUID/`st:` 形态、无路径分隔符),再做路径拼接,\n * 杜绝 `../` 逃逸;跨父作用域由调用方(宿主)用返回的 `parentAgentSession` 判定。\n */\nimport { readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { agentSessionsDir } from \"./agent-session-paths.ts\";\n\nexport interface AgentSessionReadV1 {\n\treadonly sessionId: string;\n\t/** 血缘:父 agent 会话 id(子会话必有;缺失说明文件非本次设计产物)。 */\n\treadonly parentAgentSession?: string;\n\t/** 血缘:创建该会话的角色 id(审计用途,不是权限判据)。 */\n\treadonly agentRole?: string;\n\treadonly cwd?: string;\n\treadonly createdAt?: string;\n\t/** 文件字节数(整份 transcript,而不是返回的片段)。 */\n\treadonly bytes: number;\n\t/** 解析出的 entry 条数(不含头行);截断时是**已返回**的条数。 */\n\treadonly entryCount: number;\n\t/** 达到 `maxBytes` 上限、只返回了前段 entry 时为 true。 */\n\treadonly truncated: boolean;\n\treadonly entries: readonly unknown[];\n}\n\nexport interface AgentSessionSummaryV1 {\n\treadonly sessionId: string;\n\treadonly parentAgentSession?: string;\n\treadonly agentRole?: string;\n\treadonly createdAt?: string;\n\treadonly modifiedAt: number;\n\treadonly bytes: number;\n}\n\nconst DEFAULT_MAX_BYTES = 262_144;\nconst DEFAULT_LIST_LIMIT = 200;\nconst HEADER_SCAN_BYTES = 8192;\n\n/** 会话 id 形状:UUID(root/子会话)或池化 wire 任务 id(`st:` 前缀)。 */\nexport function isAgentSessionId(value: string): boolean {\n\tif (value.length === 0 || value.length > 128) return false;\n\tif (value.startsWith(\"st:\")) return /^st:[0-9]+:[a-z0-9-]+$/i.test(value);\n\tif (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value)) return true;\n\t// 产品面允许自定义 session id(--session-id <id>;2026-10-05 dogfood 实证:\n\t// 非 UUID 会话 id 的子代理委派被此处拒掉)。寻址安全只需要单段、无路径\n\t// 逃逸语义(\".\" / \"..\" / 分隔符),不必是 UUID 形态。\n\treturn /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(value) && value !== \".\" && value !== \"..\";\n}\n\n/** 目录内定位某会话文件:命名形如 `<时间戳>_<sessionId>.jsonl`。导出给宿主的 resume 打开路径。 */\nexport function findSessionFile(dir: string, sessionId: string): string | undefined {\n\tlet names: string[];\n\ttry {\n\t\tnames = readdirSync(dir);\n\t} catch {\n\t\treturn undefined;\n\t}\n\tconst suffix = `_${sessionId}.jsonl`;\n\tconst match = names.find((name) => name === `${sessionId}.jsonl` || name.endsWith(suffix));\n\treturn match === undefined ? undefined : join(dir, match);\n}\n\nfunction parseHeader(line: string): Record<string, unknown> | undefined {\n\ttry {\n\t\tconst parsed = JSON.parse(line) as unknown;\n\t\tif (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) return undefined;\n\t\tconst record = parsed as Record<string, unknown>;\n\t\treturn record.type === \"session\" ? record : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction readHeader(filePath: string): { header?: Record<string, unknown>; bytes: number } {\n\tconst bytes = statSync(filePath).size;\n\tconst buffer = readFileSync(filePath, { encoding: \"utf-8\", flag: \"r\" });\n\tconst firstLine = buffer.slice(0, HEADER_SCAN_BYTES).split(\"\\n\", 1)[0] ?? \"\";\n\treturn { header: parseHeader(firstLine), bytes };\n}\n\n/**\n * 按 `sessionId` 有界回读一份子会话 transcript。不存在/形状非法/无头行都返回 undefined\n * (与\"无权\"同型,不区分原因)。\n */\nexport function readAgentSession(options: {\n\treadonly agentDir: string;\n\treadonly sessionId: string;\n\treadonly maxBytes?: number;\n}): AgentSessionReadV1 | undefined {\n\tif (!isAgentSessionId(options.sessionId)) return undefined;\n\tconst dir = agentSessionsDir(options.agentDir);\n\tconst filePath = findSessionFile(dir, options.sessionId);\n\tif (filePath === undefined) return undefined;\n\tlet text: string;\n\tlet bytes: number;\n\ttry {\n\t\tbytes = statSync(filePath).size;\n\t\ttext = readFileSync(filePath, { encoding: \"utf-8\", flag: \"r\" });\n\t} catch {\n\t\treturn undefined;\n\t}\n\tconst maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\tconst truncated = text.length > maxBytes;\n\tconst bounded = truncated ? text.slice(0, maxBytes) : text;\n\tconst lines = bounded.split(\"\\n\").filter((line) => line.trim() !== \"\");\n\tconst header = lines.length > 0 ? parseHeader(lines[0] as string) : undefined;\n\tconst entries: unknown[] = [];\n\tfor (const line of lines.slice(header === undefined ? 0 : 1)) {\n\t\ttry {\n\t\t\tentries.push(JSON.parse(line) as unknown);\n\t\t} catch {\n\t\t\t// 截断可能切在行中间:忽略无法解析的尾行(truncated 已如实置位)。\n\t\t}\n\t}\n\tconst parentAgentSession = typeof header?.parentAgentSession === \"string\" ? header.parentAgentSession : undefined;\n\tconst agentRole = typeof header?.agentRole === \"string\" ? header.agentRole : undefined;\n\tconst cwd = typeof header?.cwd === \"string\" ? header.cwd : undefined;\n\tconst createdAt = typeof header?.timestamp === \"string\" ? header.timestamp : undefined;\n\treturn {\n\t\tsessionId: options.sessionId,\n\t\t...(parentAgentSession === undefined ? {} : { parentAgentSession }),\n\t\t...(agentRole === undefined ? {} : { agentRole }),\n\t\t...(cwd === undefined ? {} : { cwd }),\n\t\t...(createdAt === undefined ? {} : { createdAt }),\n\t\tbytes,\n\t\tentryCount: entries.length,\n\t\ttruncated,\n\t\tentries: Object.freeze(entries),\n\t};\n}\n\n/**\n * 列子会话摘要(只读头行,不解析正文):`parentAgentSession` 提供时只返回该父会话的子会话——\n * \"按父反查\"是审计入口;`limit` 默认 200,超过按修改时间倒序截断。\n */\nexport function listAgentSessions(options: {\n\treadonly agentDir: string;\n\treadonly parentAgentSession?: string;\n\treadonly limit?: number;\n}): readonly AgentSessionSummaryV1[] {\n\tlet names: string[];\n\tlet dir: string;\n\ttry {\n\t\tdir = agentSessionsDir(options.agentDir);\n\t\tnames = readdirSync(dir).filter((name) => name.endsWith(\".jsonl\"));\n\t} catch {\n\t\treturn Object.freeze([]);\n\t}\n\tconst summaries: AgentSessionSummaryV1[] = [];\n\tfor (const name of names) {\n\t\tconst stem = name.slice(0, -\".jsonl\".length);\n\t\tconst separator = stem.lastIndexOf(\"_\");\n\t\tconst sessionId = separator === -1 ? stem : stem.slice(separator + 1);\n\t\tif (!isAgentSessionId(sessionId)) continue;\n\t\tconst filePath = join(dir, name);\n\t\tlet scanned: { header?: Record<string, unknown>; bytes: number };\n\t\tlet modifiedAt: number;\n\t\ttry {\n\t\t\tscanned = readHeader(filePath);\n\t\t\tmodifiedAt = statSync(filePath).mtimeMs;\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tconst parentAgentSession =\n\t\t\ttypeof scanned.header?.parentAgentSession === \"string\" ? scanned.header.parentAgentSession : undefined;\n\t\tif (options.parentAgentSession !== undefined && parentAgentSession !== options.parentAgentSession) continue;\n\t\tconst agentRole = typeof scanned.header?.agentRole === \"string\" ? scanned.header.agentRole : undefined;\n\t\tconst createdAt = typeof scanned.header?.timestamp === \"string\" ? scanned.header.timestamp : undefined;\n\t\tsummaries.push({\n\t\t\tsessionId,\n\t\t\t...(parentAgentSession === undefined ? {} : { parentAgentSession }),\n\t\t\t...(agentRole === undefined ? {} : { agentRole }),\n\t\t\t...(createdAt === undefined ? {} : { createdAt }),\n\t\t\tmodifiedAt,\n\t\t\tbytes: scanned.bytes,\n\t\t});\n\t}\n\tsummaries.sort((left, right) => right.modifiedAt - left.modifiedAt);\n\treturn Object.freeze(summaries.slice(0, options.limit ?? DEFAULT_LIST_LIMIT));\n}\n"]}
@@ -21,7 +21,12 @@ export function isAgentSessionId(value) {
21
21
  return false;
22
22
  if (value.startsWith("st:"))
23
23
  return /^st:[0-9]+:[a-z0-9-]+$/i.test(value);
24
- return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
24
+ if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value))
25
+ return true;
26
+ // 产品面允许自定义 session id(--session-id <id>;2026-10-05 dogfood 实证:
27
+ // 非 UUID 会话 id 的子代理委派被此处拒掉)。寻址安全只需要单段、无路径
28
+ // 逃逸语义("." / ".." / 分隔符),不必是 UUID 形态。
29
+ return /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(value) && value !== "." && value !== "..";
25
30
  }
26
31
  /** 目录内定位某会话文件:命名形如 `<时间戳>_<sessionId>.jsonl`。导出给宿主的 resume 打开路径。 */
27
32
  export function findSessionFile(dir, sessionId) {
@@ -1 +1 @@
1
- {"version":3,"file":"agent-session-store.js","sourceRoot":"","sources":["../../src/core/agent-session-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 子代理会话存取(D-060 S2):子会话与 root 会话一样落 JSONL 文件,但放在\n * `<agentDir>/sessions/_agents/` —— 与用户的会话列表分开(子会话不进用户会话选择器),\n * 同时仍可按 `sessionId` 精确回读、可按父会话 id 反查。\n *\n * 三条纪律:\n * - **文件是持久层**:内存索引(调度器的 `maxRetainedRecords`)淘汰不影响这里的可读性;\n * - **有界**:回读按字节上限截断并给 `truncated` 标记,绝不把整份 transcript 无声塞给调用方;\n * - **寻址安全**:`sessionId` 先过形状校验(UUID/`st:` 形态、无路径分隔符),再做路径拼接,\n * 杜绝 `../` 逃逸;跨父作用域由调用方(宿主)用返回的 `parentAgentSession` 判定。\n */\nimport { readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { agentSessionsDir } from \"./agent-session-paths.ts\";\n\nexport interface AgentSessionReadV1 {\n\treadonly sessionId: string;\n\t/** 血缘:父 agent 会话 id(子会话必有;缺失说明文件非本次设计产物)。 */\n\treadonly parentAgentSession?: string;\n\t/** 血缘:创建该会话的角色 id(审计用途,不是权限判据)。 */\n\treadonly agentRole?: string;\n\treadonly cwd?: string;\n\treadonly createdAt?: string;\n\t/** 文件字节数(整份 transcript,而不是返回的片段)。 */\n\treadonly bytes: number;\n\t/** 解析出的 entry 条数(不含头行);截断时是**已返回**的条数。 */\n\treadonly entryCount: number;\n\t/** 达到 `maxBytes` 上限、只返回了前段 entry 时为 true。 */\n\treadonly truncated: boolean;\n\treadonly entries: readonly unknown[];\n}\n\nexport interface AgentSessionSummaryV1 {\n\treadonly sessionId: string;\n\treadonly parentAgentSession?: string;\n\treadonly agentRole?: string;\n\treadonly createdAt?: string;\n\treadonly modifiedAt: number;\n\treadonly bytes: number;\n}\n\nconst DEFAULT_MAX_BYTES = 262_144;\nconst DEFAULT_LIST_LIMIT = 200;\nconst HEADER_SCAN_BYTES = 8192;\n\n/** 会话 id 形状:UUID(root/子会话)或池化 wire 任务 id(`st:` 前缀)。 */\nexport function isAgentSessionId(value: string): boolean {\n\tif (value.length === 0 || value.length > 128) return false;\n\tif (value.startsWith(\"st:\")) return /^st:[0-9]+:[a-z0-9-]+$/i.test(value);\n\treturn /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);\n}\n\n/** 目录内定位某会话文件:命名形如 `<时间戳>_<sessionId>.jsonl`。导出给宿主的 resume 打开路径。 */\nexport function findSessionFile(dir: string, sessionId: string): string | undefined {\n\tlet names: string[];\n\ttry {\n\t\tnames = readdirSync(dir);\n\t} catch {\n\t\treturn undefined;\n\t}\n\tconst suffix = `_${sessionId}.jsonl`;\n\tconst match = names.find((name) => name === `${sessionId}.jsonl` || name.endsWith(suffix));\n\treturn match === undefined ? undefined : join(dir, match);\n}\n\nfunction parseHeader(line: string): Record<string, unknown> | undefined {\n\ttry {\n\t\tconst parsed = JSON.parse(line) as unknown;\n\t\tif (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) return undefined;\n\t\tconst record = parsed as Record<string, unknown>;\n\t\treturn record.type === \"session\" ? record : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction readHeader(filePath: string): { header?: Record<string, unknown>; bytes: number } {\n\tconst bytes = statSync(filePath).size;\n\tconst buffer = readFileSync(filePath, { encoding: \"utf-8\", flag: \"r\" });\n\tconst firstLine = buffer.slice(0, HEADER_SCAN_BYTES).split(\"\\n\", 1)[0] ?? \"\";\n\treturn { header: parseHeader(firstLine), bytes };\n}\n\n/**\n * 按 `sessionId` 有界回读一份子会话 transcript。不存在/形状非法/无头行都返回 undefined\n * (与\"无权\"同型,不区分原因)。\n */\nexport function readAgentSession(options: {\n\treadonly agentDir: string;\n\treadonly sessionId: string;\n\treadonly maxBytes?: number;\n}): AgentSessionReadV1 | undefined {\n\tif (!isAgentSessionId(options.sessionId)) return undefined;\n\tconst dir = agentSessionsDir(options.agentDir);\n\tconst filePath = findSessionFile(dir, options.sessionId);\n\tif (filePath === undefined) return undefined;\n\tlet text: string;\n\tlet bytes: number;\n\ttry {\n\t\tbytes = statSync(filePath).size;\n\t\ttext = readFileSync(filePath, { encoding: \"utf-8\", flag: \"r\" });\n\t} catch {\n\t\treturn undefined;\n\t}\n\tconst maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\tconst truncated = text.length > maxBytes;\n\tconst bounded = truncated ? text.slice(0, maxBytes) : text;\n\tconst lines = bounded.split(\"\\n\").filter((line) => line.trim() !== \"\");\n\tconst header = lines.length > 0 ? parseHeader(lines[0] as string) : undefined;\n\tconst entries: unknown[] = [];\n\tfor (const line of lines.slice(header === undefined ? 0 : 1)) {\n\t\ttry {\n\t\t\tentries.push(JSON.parse(line) as unknown);\n\t\t} catch {\n\t\t\t// 截断可能切在行中间:忽略无法解析的尾行(truncated 已如实置位)。\n\t\t}\n\t}\n\tconst parentAgentSession = typeof header?.parentAgentSession === \"string\" ? header.parentAgentSession : undefined;\n\tconst agentRole = typeof header?.agentRole === \"string\" ? header.agentRole : undefined;\n\tconst cwd = typeof header?.cwd === \"string\" ? header.cwd : undefined;\n\tconst createdAt = typeof header?.timestamp === \"string\" ? header.timestamp : undefined;\n\treturn {\n\t\tsessionId: options.sessionId,\n\t\t...(parentAgentSession === undefined ? {} : { parentAgentSession }),\n\t\t...(agentRole === undefined ? {} : { agentRole }),\n\t\t...(cwd === undefined ? {} : { cwd }),\n\t\t...(createdAt === undefined ? {} : { createdAt }),\n\t\tbytes,\n\t\tentryCount: entries.length,\n\t\ttruncated,\n\t\tentries: Object.freeze(entries),\n\t};\n}\n\n/**\n * 列子会话摘要(只读头行,不解析正文):`parentAgentSession` 提供时只返回该父会话的子会话——\n * \"按父反查\"是审计入口;`limit` 默认 200,超过按修改时间倒序截断。\n */\nexport function listAgentSessions(options: {\n\treadonly agentDir: string;\n\treadonly parentAgentSession?: string;\n\treadonly limit?: number;\n}): readonly AgentSessionSummaryV1[] {\n\tlet names: string[];\n\tlet dir: string;\n\ttry {\n\t\tdir = agentSessionsDir(options.agentDir);\n\t\tnames = readdirSync(dir).filter((name) => name.endsWith(\".jsonl\"));\n\t} catch {\n\t\treturn Object.freeze([]);\n\t}\n\tconst summaries: AgentSessionSummaryV1[] = [];\n\tfor (const name of names) {\n\t\tconst stem = name.slice(0, -\".jsonl\".length);\n\t\tconst separator = stem.lastIndexOf(\"_\");\n\t\tconst sessionId = separator === -1 ? stem : stem.slice(separator + 1);\n\t\tif (!isAgentSessionId(sessionId)) continue;\n\t\tconst filePath = join(dir, name);\n\t\tlet scanned: { header?: Record<string, unknown>; bytes: number };\n\t\tlet modifiedAt: number;\n\t\ttry {\n\t\t\tscanned = readHeader(filePath);\n\t\t\tmodifiedAt = statSync(filePath).mtimeMs;\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tconst parentAgentSession =\n\t\t\ttypeof scanned.header?.parentAgentSession === \"string\" ? scanned.header.parentAgentSession : undefined;\n\t\tif (options.parentAgentSession !== undefined && parentAgentSession !== options.parentAgentSession) continue;\n\t\tconst agentRole = typeof scanned.header?.agentRole === \"string\" ? scanned.header.agentRole : undefined;\n\t\tconst createdAt = typeof scanned.header?.timestamp === \"string\" ? scanned.header.timestamp : undefined;\n\t\tsummaries.push({\n\t\t\tsessionId,\n\t\t\t...(parentAgentSession === undefined ? {} : { parentAgentSession }),\n\t\t\t...(agentRole === undefined ? {} : { agentRole }),\n\t\t\t...(createdAt === undefined ? {} : { createdAt }),\n\t\t\tmodifiedAt,\n\t\t\tbytes: scanned.bytes,\n\t\t});\n\t}\n\tsummaries.sort((left, right) => right.modifiedAt - left.modifiedAt);\n\treturn Object.freeze(summaries.slice(0, options.limit ?? DEFAULT_LIST_LIMIT));\n}\n"]}
1
+ {"version":3,"file":"agent-session-store.js","sourceRoot":"","sources":["../../src/core/agent-session-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 子代理会话存取(D-060 S2):子会话与 root 会话一样落 JSONL 文件,但放在\n * `<agentDir>/sessions/_agents/` —— 与用户的会话列表分开(子会话不进用户会话选择器),\n * 同时仍可按 `sessionId` 精确回读、可按父会话 id 反查。\n *\n * 三条纪律:\n * - **文件是持久层**:内存索引(调度器的 `maxRetainedRecords`)淘汰不影响这里的可读性;\n * - **有界**:回读按字节上限截断并给 `truncated` 标记,绝不把整份 transcript 无声塞给调用方;\n * - **寻址安全**:`sessionId` 先过形状校验(UUID/`st:` 形态、无路径分隔符),再做路径拼接,\n * 杜绝 `../` 逃逸;跨父作用域由调用方(宿主)用返回的 `parentAgentSession` 判定。\n */\nimport { readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { agentSessionsDir } from \"./agent-session-paths.ts\";\n\nexport interface AgentSessionReadV1 {\n\treadonly sessionId: string;\n\t/** 血缘:父 agent 会话 id(子会话必有;缺失说明文件非本次设计产物)。 */\n\treadonly parentAgentSession?: string;\n\t/** 血缘:创建该会话的角色 id(审计用途,不是权限判据)。 */\n\treadonly agentRole?: string;\n\treadonly cwd?: string;\n\treadonly createdAt?: string;\n\t/** 文件字节数(整份 transcript,而不是返回的片段)。 */\n\treadonly bytes: number;\n\t/** 解析出的 entry 条数(不含头行);截断时是**已返回**的条数。 */\n\treadonly entryCount: number;\n\t/** 达到 `maxBytes` 上限、只返回了前段 entry 时为 true。 */\n\treadonly truncated: boolean;\n\treadonly entries: readonly unknown[];\n}\n\nexport interface AgentSessionSummaryV1 {\n\treadonly sessionId: string;\n\treadonly parentAgentSession?: string;\n\treadonly agentRole?: string;\n\treadonly createdAt?: string;\n\treadonly modifiedAt: number;\n\treadonly bytes: number;\n}\n\nconst DEFAULT_MAX_BYTES = 262_144;\nconst DEFAULT_LIST_LIMIT = 200;\nconst HEADER_SCAN_BYTES = 8192;\n\n/** 会话 id 形状:UUID(root/子会话)或池化 wire 任务 id(`st:` 前缀)。 */\nexport function isAgentSessionId(value: string): boolean {\n\tif (value.length === 0 || value.length > 128) return false;\n\tif (value.startsWith(\"st:\")) return /^st:[0-9]+:[a-z0-9-]+$/i.test(value);\n\tif (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value)) return true;\n\t// 产品面允许自定义 session id(--session-id <id>;2026-10-05 dogfood 实证:\n\t// 非 UUID 会话 id 的子代理委派被此处拒掉)。寻址安全只需要单段、无路径\n\t// 逃逸语义(\".\" / \"..\" / 分隔符),不必是 UUID 形态。\n\treturn /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(value) && value !== \".\" && value !== \"..\";\n}\n\n/** 目录内定位某会话文件:命名形如 `<时间戳>_<sessionId>.jsonl`。导出给宿主的 resume 打开路径。 */\nexport function findSessionFile(dir: string, sessionId: string): string | undefined {\n\tlet names: string[];\n\ttry {\n\t\tnames = readdirSync(dir);\n\t} catch {\n\t\treturn undefined;\n\t}\n\tconst suffix = `_${sessionId}.jsonl`;\n\tconst match = names.find((name) => name === `${sessionId}.jsonl` || name.endsWith(suffix));\n\treturn match === undefined ? undefined : join(dir, match);\n}\n\nfunction parseHeader(line: string): Record<string, unknown> | undefined {\n\ttry {\n\t\tconst parsed = JSON.parse(line) as unknown;\n\t\tif (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) return undefined;\n\t\tconst record = parsed as Record<string, unknown>;\n\t\treturn record.type === \"session\" ? record : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction readHeader(filePath: string): { header?: Record<string, unknown>; bytes: number } {\n\tconst bytes = statSync(filePath).size;\n\tconst buffer = readFileSync(filePath, { encoding: \"utf-8\", flag: \"r\" });\n\tconst firstLine = buffer.slice(0, HEADER_SCAN_BYTES).split(\"\\n\", 1)[0] ?? \"\";\n\treturn { header: parseHeader(firstLine), bytes };\n}\n\n/**\n * 按 `sessionId` 有界回读一份子会话 transcript。不存在/形状非法/无头行都返回 undefined\n * (与\"无权\"同型,不区分原因)。\n */\nexport function readAgentSession(options: {\n\treadonly agentDir: string;\n\treadonly sessionId: string;\n\treadonly maxBytes?: number;\n}): AgentSessionReadV1 | undefined {\n\tif (!isAgentSessionId(options.sessionId)) return undefined;\n\tconst dir = agentSessionsDir(options.agentDir);\n\tconst filePath = findSessionFile(dir, options.sessionId);\n\tif (filePath === undefined) return undefined;\n\tlet text: string;\n\tlet bytes: number;\n\ttry {\n\t\tbytes = statSync(filePath).size;\n\t\ttext = readFileSync(filePath, { encoding: \"utf-8\", flag: \"r\" });\n\t} catch {\n\t\treturn undefined;\n\t}\n\tconst maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\tconst truncated = text.length > maxBytes;\n\tconst bounded = truncated ? text.slice(0, maxBytes) : text;\n\tconst lines = bounded.split(\"\\n\").filter((line) => line.trim() !== \"\");\n\tconst header = lines.length > 0 ? parseHeader(lines[0] as string) : undefined;\n\tconst entries: unknown[] = [];\n\tfor (const line of lines.slice(header === undefined ? 0 : 1)) {\n\t\ttry {\n\t\t\tentries.push(JSON.parse(line) as unknown);\n\t\t} catch {\n\t\t\t// 截断可能切在行中间:忽略无法解析的尾行(truncated 已如实置位)。\n\t\t}\n\t}\n\tconst parentAgentSession = typeof header?.parentAgentSession === \"string\" ? header.parentAgentSession : undefined;\n\tconst agentRole = typeof header?.agentRole === \"string\" ? header.agentRole : undefined;\n\tconst cwd = typeof header?.cwd === \"string\" ? header.cwd : undefined;\n\tconst createdAt = typeof header?.timestamp === \"string\" ? header.timestamp : undefined;\n\treturn {\n\t\tsessionId: options.sessionId,\n\t\t...(parentAgentSession === undefined ? {} : { parentAgentSession }),\n\t\t...(agentRole === undefined ? {} : { agentRole }),\n\t\t...(cwd === undefined ? {} : { cwd }),\n\t\t...(createdAt === undefined ? {} : { createdAt }),\n\t\tbytes,\n\t\tentryCount: entries.length,\n\t\ttruncated,\n\t\tentries: Object.freeze(entries),\n\t};\n}\n\n/**\n * 列子会话摘要(只读头行,不解析正文):`parentAgentSession` 提供时只返回该父会话的子会话——\n * \"按父反查\"是审计入口;`limit` 默认 200,超过按修改时间倒序截断。\n */\nexport function listAgentSessions(options: {\n\treadonly agentDir: string;\n\treadonly parentAgentSession?: string;\n\treadonly limit?: number;\n}): readonly AgentSessionSummaryV1[] {\n\tlet names: string[];\n\tlet dir: string;\n\ttry {\n\t\tdir = agentSessionsDir(options.agentDir);\n\t\tnames = readdirSync(dir).filter((name) => name.endsWith(\".jsonl\"));\n\t} catch {\n\t\treturn Object.freeze([]);\n\t}\n\tconst summaries: AgentSessionSummaryV1[] = [];\n\tfor (const name of names) {\n\t\tconst stem = name.slice(0, -\".jsonl\".length);\n\t\tconst separator = stem.lastIndexOf(\"_\");\n\t\tconst sessionId = separator === -1 ? stem : stem.slice(separator + 1);\n\t\tif (!isAgentSessionId(sessionId)) continue;\n\t\tconst filePath = join(dir, name);\n\t\tlet scanned: { header?: Record<string, unknown>; bytes: number };\n\t\tlet modifiedAt: number;\n\t\ttry {\n\t\t\tscanned = readHeader(filePath);\n\t\t\tmodifiedAt = statSync(filePath).mtimeMs;\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tconst parentAgentSession =\n\t\t\ttypeof scanned.header?.parentAgentSession === \"string\" ? scanned.header.parentAgentSession : undefined;\n\t\tif (options.parentAgentSession !== undefined && parentAgentSession !== options.parentAgentSession) continue;\n\t\tconst agentRole = typeof scanned.header?.agentRole === \"string\" ? scanned.header.agentRole : undefined;\n\t\tconst createdAt = typeof scanned.header?.timestamp === \"string\" ? scanned.header.timestamp : undefined;\n\t\tsummaries.push({\n\t\t\tsessionId,\n\t\t\t...(parentAgentSession === undefined ? {} : { parentAgentSession }),\n\t\t\t...(agentRole === undefined ? {} : { agentRole }),\n\t\t\t...(createdAt === undefined ? {} : { createdAt }),\n\t\t\tmodifiedAt,\n\t\t\tbytes: scanned.bytes,\n\t\t});\n\t}\n\tsummaries.sort((left, right) => right.modifiedAt - left.modifiedAt);\n\treturn Object.freeze(summaries.slice(0, options.limit ?? DEFAULT_LIST_LIMIT));\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"agent-session-tools.d.ts","sourceRoot":"","sources":["../../src/core/agent-session-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,qBAAqB,EAAuB,MAAM,6BAA6B,CAAC;AAQ9F,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGzC,OAAO,KAAK,EAAE,cAAc,EAAsB,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAG/F,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAOnF;AAED,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,EAAE,CAapF;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,qBAAqB,GAAG,QAAQ,EAAE,CAQtE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,qBAAqB,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAE1G;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAe9F;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,CAmC/F;AAED,wBAAgB,mBAAmB,CAClC,OAAO,EAAE,qBAAqB,EAC9B,OAAO,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,wBAAwB,CAAC,EAAE,OAAO,CAAA;CAAE,GAC1E,IAAI,CA8HN;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAMxE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,KAAK,EAAE,CAmD3E;AAED,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAkBrF;AAED,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAc1F","sourcesContent":["/**\n * Tool registry, capability skills, and system-prompt assembly for\n * AgentSession.\n *\n * Extracted from `agent-session.ts`. Every function here operates on the\n * internal session facade ({@link AgentSessionInternals}); `AgentSession`\n * keeps same-name delegates so call sites, dynamic dispatch, and test spies\n * keep working unchanged.\n */\n\nimport type { AgentTool } from \"@agent-forge/agent-core\";\nimport type { AgentSessionInternals, ToolDefinitionEntry } from \"./agent-session-internal.ts\";\nimport {\n\tinstallSessionBootstrapSkills,\n\trefreshSessionBootstrapSkills,\n\tSKILL_CONTRIBUTION_POINT_ID,\n\tSKILL_CONTRIBUTION_POINT_VERSION,\n} from \"./extensions/index.ts\";\nimport { t } from \"./i18n/index.ts\";\nimport type { Skill } from \"./skills.ts\";\nimport { createSyntheticSourceInfo } from \"./source-info.ts\";\nimport { buildSystemPrompt } from \"./system-prompt.ts\";\nimport type { ToolDefinition, ToolExecuteContext, ToolInfo } from \"./tools/tool-definition.ts\";\nimport { wrapToolDefinition } from \"./tools/tool-definition-wrapper.ts\";\n\nexport function normalizePromptSnippet(text: string | undefined): string | undefined {\n\tif (!text) return undefined;\n\tconst oneLine = text\n\t\t.replace(/[\\r\\n]+/g, \" \")\n\t\t.replace(/\\s+/g, \" \")\n\t\t.trim();\n\treturn oneLine.length > 0 ? oneLine : undefined;\n}\n\nexport function normalizePromptGuidelines(guidelines: string[] | undefined): string[] {\n\tif (!guidelines || guidelines.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst unique = new Set<string>();\n\tfor (const guideline of guidelines) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0) {\n\t\t\tunique.add(normalized);\n\t\t}\n\t}\n\treturn Array.from(unique);\n}\n\n/**\n * Get all configured tools with name, description, parameter schema, prompt guidelines, and source metadata.\n */\nexport function getAllTools(session: AgentSessionInternals): ToolInfo[] {\n\treturn Array.from(session._toolDefinitions.values()).map(({ definition, sourceInfo }) => ({\n\t\tname: definition.name,\n\t\tdescription: definition.description,\n\t\tparameters: definition.parameters,\n\t\tpromptGuidelines: definition.promptGuidelines,\n\t\tsourceInfo,\n\t}));\n}\n\nexport function getToolDefinition(session: AgentSessionInternals, name: string): ToolDefinition | undefined {\n\treturn session._toolDefinitions.get(name)?.definition;\n}\n\n/**\n * Set active tools by name.\n * Only tools in the registry can be enabled. Unknown tool names are ignored.\n * Also rebuilds the system prompt to reflect the new tool set.\n * Changes take effect on the next agent turn.\n */\nexport function setActiveToolsByName(session: AgentSessionInternals, toolNames: string[]): void {\n\tconst tools: AgentTool[] = [];\n\tconst validToolNames: string[] = [];\n\tfor (const name of toolNames) {\n\t\tconst tool = session._toolRegistry.get(name);\n\t\tif (tool) {\n\t\t\ttools.push(tool);\n\t\t\tvalidToolNames.push(name);\n\t\t}\n\t}\n\tsession.agent.state.tools = tools;\n\n\t// Rebuild base system prompt with new tool set\n\tsession._baseSystemPrompt = session._rebuildSystemPrompt(validToolNames);\n\tsession.agent.state.systemPrompt = session._systemPromptOverride ?? session._baseSystemPrompt;\n}\n\nexport function rebuildSystemPrompt(session: AgentSessionInternals, toolNames: string[]): string {\n\tconst validToolNames = toolNames.filter((name) => session._toolRegistry.has(name));\n\tconst toolSnippets: Record<string, string> = {};\n\tconst promptGuidelines: string[] = [];\n\tfor (const name of validToolNames) {\n\t\tconst snippet = session._toolPromptSnippets.get(name);\n\t\tif (snippet) {\n\t\t\ttoolSnippets[name] = snippet;\n\t\t}\n\n\t\tconst toolGuidelines = session._toolPromptGuidelines.get(name);\n\t\tif (toolGuidelines) {\n\t\t\tpromptGuidelines.push(...toolGuidelines);\n\t\t}\n\t}\n\n\tconst loaderSystemPrompt = session._resourceLoader.getSystemPrompt();\n\tconst loaderAppendSystemPrompt = session._resourceLoader.getAppendSystemPrompt();\n\tconst appendSystemPrompt = loaderAppendSystemPrompt.length > 0 ? loaderAppendSystemPrompt.join(\"\\n\\n\") : undefined;\n\tconst loadedSkills = session._getAvailableSkills();\n\tconst loadedContextFiles = session._resourceLoader.getAgentsFiles().agentsFiles;\n\n\tsession._baseSystemPromptOptions = {\n\t\tcwd: session._cwd,\n\t\tskills: loadedSkills,\n\t\tcontextFiles: loadedContextFiles,\n\t\tcustomPrompt: loaderSystemPrompt,\n\t\torientationPrompt: session._orientationPrompt,\n\t\tpreferenceCard: session._preferenceCard,\n\t\tappendSystemPrompt,\n\t\tselectedTools: validToolNames,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t};\n\treturn buildSystemPrompt(session._baseSystemPromptOptions);\n}\n\nexport function refreshToolRegistry(\n\tsession: AgentSessionInternals,\n\toptions?: { activeToolNames?: string[]; includeAllExtensionTools?: boolean },\n): void {\n\tconst previousRegistryNames = new Set(session._toolRegistry.keys());\n\tconst previousActiveToolNames = session.getActiveToolNames();\n\tconst allowedToolNames = session._allowedToolNames;\n\tconst excludedToolNames = session._excludedToolNames;\n\tconst isAllowedTool = (name: string): boolean =>\n\t\t(!allowedToolNames || allowedToolNames.has(name)) && !excludedToolNames?.has(name);\n\n\tconst allCustomTools = session._customTools\n\t\t.map((definition) => ({\n\t\t\tdefinition,\n\t\t\tsourceInfo: createSyntheticSourceInfo(`<sdk:${definition.name}>`, { source: \"sdk\" }),\n\t\t}))\n\t\t.filter((tool) => isAllowedTool(tool.definition.name));\n\tconst definitionRegistry = new Map<string, ToolDefinitionEntry>(\n\t\tArray.from(session._baseToolDefinitions.entries())\n\t\t\t.filter(([name]) => isAllowedTool(name))\n\t\t\t.map(([name, definition]) => [\n\t\t\t\tname,\n\t\t\t\t{\n\t\t\t\t\tdefinition,\n\t\t\t\t\t// syncCapabilityTools populates _baseToolSources in lockstep with\n\t\t\t\t\t// _baseToolDefinitions, so this fallback is a desync guard only;\n\t\t\t\t\t// the default coding tools surface rides the coding-tools package\n\t\t\t\t\t// id since D-082 批 1.\n\t\t\t\t\tsourceInfo:\n\t\t\t\t\t\tsession._baseToolSources.get(name) ??\n\t\t\t\t\t\tcreateSyntheticSourceInfo(`<bootstrap:${name}>`, { source: \"agent-forge.plugin.coding-tools\" }),\n\t\t\t\t},\n\t\t\t]),\n\t);\n\tfor (const tool of allCustomTools) {\n\t\tdefinitionRegistry.set(tool.definition.name, {\n\t\t\tdefinition: tool.definition,\n\t\t\tsourceInfo: tool.sourceInfo,\n\t\t});\n\t}\n\tsession._toolDefinitions = definitionRegistry;\n\tsession._toolPromptSnippets = new Map(\n\t\tArray.from(definitionRegistry.values())\n\t\t\t.map(({ definition }) => {\n\t\t\t\tconst snippet = normalizePromptSnippet(definition.promptSnippet);\n\t\t\t\treturn snippet ? ([definition.name, snippet] as const) : undefined;\n\t\t\t})\n\t\t\t.filter((entry): entry is readonly [string, string] => entry !== undefined),\n\t);\n\tsession._toolPromptGuidelines = new Map(\n\t\tArray.from(definitionRegistry.values())\n\t\t\t.map(({ definition }) => {\n\t\t\t\tconst guidelines = normalizePromptGuidelines(definition.promptGuidelines);\n\t\t\t\treturn guidelines.length > 0 ? ([definition.name, guidelines] as const) : undefined;\n\t\t\t})\n\t\t\t.filter((entry): entry is readonly [string, string[]] => entry !== undefined),\n\t);\n\t// Session-resolved execute context and dynamic-tool tracking replace the\n\t// former runner-mediated wrapper: tools receive the same session facts and\n\t// a tool that activates more tools during execute still surfaces them via\n\t// addedToolNames.\n\tconst executeContext = (): ToolExecuteContext => ({\n\t\tcwd: session.sessionManager.getCwd(),\n\t\tmodel: session.model,\n\t\tsessionManager: session.sessionManager,\n\t\tthinkingLevel: session.thinkingLevel,\n\t});\n\tconst wrapWithDynamicToolTracking = ({ definition }: { definition: ToolDefinition }): AgentTool => {\n\t\tconst tool = wrapToolDefinition(definition, executeContext);\n\t\tconst execute = tool.execute;\n\t\treturn {\n\t\t\t...tool,\n\t\t\texecute: async (toolCallId, params, signal, onUpdate) => {\n\t\t\t\tconst activeBefore = session.getActiveToolNames();\n\t\t\t\tconst result = await execute(toolCallId, params, signal, onUpdate);\n\t\t\t\tconst activeAfter = session.getActiveToolNames();\n\t\t\t\tif (!activeBefore.every((name) => activeAfter.includes(name))) return result;\n\n\t\t\t\tconst beforeNames = new Set(activeBefore);\n\t\t\t\tconst addedToolNames = activeAfter.filter((name) => !beforeNames.has(name));\n\t\t\t\tif (addedToolNames.length === 0) return result;\n\t\t\t\treturn {\n\t\t\t\t\t...result,\n\t\t\t\t\taddedToolNames: [...new Set([...(result.addedToolNames ?? []), ...addedToolNames])],\n\t\t\t\t};\n\t\t\t},\n\t\t};\n\t};\n\tconst wrappedExtensionTools = allCustomTools.map(wrapWithDynamicToolTracking);\n\tconst wrappedBuiltInTools = Array.from(session._baseToolDefinitions.values())\n\t\t.filter((definition) => isAllowedTool(definition.name))\n\t\t.map((definition) => wrapWithDynamicToolTracking({ definition }));\n\n\tconst toolRegistry = new Map(wrappedBuiltInTools.map((tool) => [tool.name, tool]));\n\tfor (const tool of wrappedExtensionTools as AgentTool[]) {\n\t\ttoolRegistry.set(tool.name, tool);\n\t}\n\tsession._toolRegistry = toolRegistry;\n\n\tconst nextActiveToolNames = (\n\t\toptions?.activeToolNames ? [...options.activeToolNames] : [...previousActiveToolNames]\n\t).filter((name) => isAllowedTool(name));\n\n\tif (allowedToolNames) {\n\t\tfor (const toolName of session._toolRegistry.keys()) {\n\t\t\tif (allowedToolNames.has(toolName)) {\n\t\t\t\tnextActiveToolNames.push(toolName);\n\t\t\t}\n\t\t}\n\t} else if (options?.includeAllExtensionTools) {\n\t\tfor (const tool of wrappedExtensionTools) {\n\t\t\tnextActiveToolNames.push(tool.name);\n\t\t}\n\t} else if (!options?.activeToolNames) {\n\t\tfor (const toolName of session._toolRegistry.keys()) {\n\t\t\tif (previousRegistryNames.has(toolName)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Deferred tools (e.g. MCP servers configured with deferredTools)\n\t\t\t// register but stay out of the default active set until tool_search\n\t\t\t// or an explicit activation names them.\n\t\t\tif (session._deferredToolPluginIds.has(session._baseToolSources.get(toolName)?.source ?? \"\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tnextActiveToolNames.push(toolName);\n\t\t}\n\t}\n\n\tsession.setActiveToolsByName([...new Set(nextActiveToolNames)]);\n}\n\nexport function syncCapabilityTools(session: AgentSessionInternals): void {\n\tconst tools = session._capabilityRuntime?.listTools() ?? [];\n\tsession._baseToolDefinitions = new Map(tools.map(({ name, definition }) => [name, definition as ToolDefinition]));\n\tsession._baseToolSources = new Map(\n\t\ttools.map(({ name, source }) => [name, createSyntheticSourceInfo(`<plugin:${source}:${name}>`, { source })]),\n\t);\n}\n\nexport function getCapabilitySkills(session: AgentSessionInternals): Skill[] {\n\tconst runtime = session._capabilityRuntime;\n\tif (!runtime) return [];\n\t// The skill contribution point is owned by the bootstrap-skills plugin. In\n\t// hosts that never install it (assistant suite, print mode) — or while that\n\t// owner is inactive — `listContributions` throws \"Contribution point is not\n\t// defined\". That state means \"no contributed skills\", not a failure: every\n\t// tool-registry change rebuilds the system prompt, so propagating the error\n\t// turned each rebuild into an error-level plugin.log record. Any other\n\t// failure still propagates.\n\tlet contributed: ReturnType<typeof runtime.listContributions>;\n\ttry {\n\t\tcontributed = runtime.listContributions(SKILL_CONTRIBUTION_POINT_ID, SKILL_CONTRIBUTION_POINT_VERSION);\n\t} catch (error) {\n\t\tif (!(error instanceof Error) || !error.message.startsWith(\"Contribution point is not defined\")) throw error;\n\t\treturn [];\n\t}\n\tconst contributedSkills = contributed\n\t\t.filter(\n\t\t\t(entry): entry is typeof entry & { value: Skill } =>\n\t\t\t\tentry.value !== null && typeof entry.value === \"object\" && \"name\" in entry.value,\n\t\t)\n\t\t.map((entry) => ({\n\t\t\t...entry.value,\n\t\t\tdisableModelInvocation: entry.value.disableModelInvocation === true,\n\t\t\tsourceInfo: createSyntheticSourceInfo(`<contribution:${entry.owner}:${entry.id}>`, {\n\t\t\t\tsource: entry.owner,\n\t\t\t\tbaseDir: entry.value.baseDir,\n\t\t\t}),\n\t\t}));\n\tconst contributedNames = new Set(contributedSkills.map((skill) => skill.name));\n\tconst legacyFilter = session._capabilitySkillsFilter;\n\tconst legacy = runtime\n\t\t.listSkills()\n\t\t.filter(({ definition }) => !contributedNames.has(definition.name))\n\t\t.map(({ definition, source }) => ({\n\t\t\t...definition,\n\t\t\tdisableModelInvocation: definition.disableModelInvocation === true,\n\t\t\tsourceInfo: createSyntheticSourceInfo(`<plugin:${source}:${definition.name}>`, {\n\t\t\t\tsource,\n\t\t\t\tbaseDir: definition.baseDir,\n\t\t\t}),\n\t\t}))\n\t\t// Suite association filtering (方案系统 M3): the assembler owns the\n\t\t// policy; the session only applies the injected function. The\n\t\t// bootstrap-skills contribution face is already loader-filtered and\n\t\t// must not be filtered twice.\n\t\t.filter((skill) => (legacyFilter ? legacyFilter([skill]).length > 0 : true));\n\treturn [...contributedSkills, ...legacy].sort(\n\t\t(left, right) => left.name.localeCompare(right.name) || left.sourceInfo.path.localeCompare(right.sourceInfo.path),\n\t);\n}\n\nexport function validateCapabilitySkillConflicts(session: AgentSessionInternals): void {\n\tconst resourceNames = new Set<string>();\n\tconst resourceFilePaths = new Set<string>();\n\tfor (const skill of session._resourceLoader.getSkills().skills) {\n\t\tif (resourceNames.has(skill.name))\n\t\t\tthrow new Error(t(\"Skill is duplicated in resources: {name}\", { name: skill.name }));\n\t\tresourceNames.add(skill.name);\n\t\tresourceFilePaths.add(skill.filePath);\n\t}\n\tfor (const skill of session._getCapabilitySkills()) {\n\t\t// bootstrap-skills mirrors the same on-disk SKILL.md into the capability\n\t\t// layer: same name AND same file is one skill seen through two channels,\n\t\t// not a conflict. Same name from a different file (e.g. an MCP server\n\t\t// contributing a skill that collides with a disk skill) is a real one.\n\t\tif (typeof skill.filePath === \"string\" && resourceFilePaths.has(skill.filePath)) continue;\n\t\tif (resourceNames.has(skill.name))\n\t\t\tthrow new Error(t(\"Skill conflicts with a resource skill: {name}\", { name: skill.name }));\n\t}\n}\n\nexport async function refreshBootstrapSkills(session: AgentSessionInternals): Promise<void> {\n\tconst runtime = session._capabilityRuntime;\n\tif (!runtime) return;\n\tsession._validateCapabilitySkillConflicts();\n\tif (session._bootstrapSkillsHandle) {\n\t\tawait refreshSessionBootstrapSkills(runtime, session._resourceLoader.getSkills().skills);\n\t} else {\n\t\tsession._bootstrapSkillsHandle = installSessionBootstrapSkills(\n\t\t\truntime,\n\t\t\tsession._resourceLoader.getSkills().skills,\n\t\t);\n\t}\n\tsession._baseSystemPrompt = session._rebuildSystemPrompt(session.getActiveToolNames());\n\tsession.agent.state.systemPrompt = session._baseSystemPrompt;\n}\n"]}
1
+ {"version":3,"file":"agent-session-tools.d.ts","sourceRoot":"","sources":["../../src/core/agent-session-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,qBAAqB,EAAuB,MAAM,6BAA6B,CAAC;AAQ9F,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGzC,OAAO,KAAK,EAAE,cAAc,EAAsB,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAG/F,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAOnF;AAED,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,EAAE,CAapF;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,qBAAqB,GAAG,QAAQ,EAAE,CAQtE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,qBAAqB,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAE1G;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAe9F;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,CAoD/F;AAED,wBAAgB,mBAAmB,CAClC,OAAO,EAAE,qBAAqB,EAC9B,OAAO,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,wBAAwB,CAAC,EAAE,OAAO,CAAA;CAAE,GAC1E,IAAI,CA8HN;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAMxE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,KAAK,EAAE,CAmD3E;AAED,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAkBrF;AAED,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAc1F","sourcesContent":["/**\n * Tool registry, capability skills, and system-prompt assembly for\n * AgentSession.\n *\n * Extracted from `agent-session.ts`. Every function here operates on the\n * internal session facade ({@link AgentSessionInternals}); `AgentSession`\n * keeps same-name delegates so call sites, dynamic dispatch, and test spies\n * keep working unchanged.\n */\n\nimport type { AgentTool } from \"@agent-forge/agent-core\";\nimport type { AgentSessionInternals, ToolDefinitionEntry } from \"./agent-session-internal.ts\";\nimport {\n\tinstallSessionBootstrapSkills,\n\trefreshSessionBootstrapSkills,\n\tSKILL_CONTRIBUTION_POINT_ID,\n\tSKILL_CONTRIBUTION_POINT_VERSION,\n} from \"./extensions/index.ts\";\nimport { t } from \"./i18n/index.ts\";\nimport type { Skill } from \"./skills.ts\";\nimport { createSyntheticSourceInfo } from \"./source-info.ts\";\nimport { buildSystemPrompt } from \"./system-prompt.ts\";\nimport type { ToolDefinition, ToolExecuteContext, ToolInfo } from \"./tools/tool-definition.ts\";\nimport { wrapToolDefinition } from \"./tools/tool-definition-wrapper.ts\";\n\nexport function normalizePromptSnippet(text: string | undefined): string | undefined {\n\tif (!text) return undefined;\n\tconst oneLine = text\n\t\t.replace(/[\\r\\n]+/g, \" \")\n\t\t.replace(/\\s+/g, \" \")\n\t\t.trim();\n\treturn oneLine.length > 0 ? oneLine : undefined;\n}\n\nexport function normalizePromptGuidelines(guidelines: string[] | undefined): string[] {\n\tif (!guidelines || guidelines.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst unique = new Set<string>();\n\tfor (const guideline of guidelines) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0) {\n\t\t\tunique.add(normalized);\n\t\t}\n\t}\n\treturn Array.from(unique);\n}\n\n/**\n * Get all configured tools with name, description, parameter schema, prompt guidelines, and source metadata.\n */\nexport function getAllTools(session: AgentSessionInternals): ToolInfo[] {\n\treturn Array.from(session._toolDefinitions.values()).map(({ definition, sourceInfo }) => ({\n\t\tname: definition.name,\n\t\tdescription: definition.description,\n\t\tparameters: definition.parameters,\n\t\tpromptGuidelines: definition.promptGuidelines,\n\t\tsourceInfo,\n\t}));\n}\n\nexport function getToolDefinition(session: AgentSessionInternals, name: string): ToolDefinition | undefined {\n\treturn session._toolDefinitions.get(name)?.definition;\n}\n\n/**\n * Set active tools by name.\n * Only tools in the registry can be enabled. Unknown tool names are ignored.\n * Also rebuilds the system prompt to reflect the new tool set.\n * Changes take effect on the next agent turn.\n */\nexport function setActiveToolsByName(session: AgentSessionInternals, toolNames: string[]): void {\n\tconst tools: AgentTool[] = [];\n\tconst validToolNames: string[] = [];\n\tfor (const name of toolNames) {\n\t\tconst tool = session._toolRegistry.get(name);\n\t\tif (tool) {\n\t\t\ttools.push(tool);\n\t\t\tvalidToolNames.push(name);\n\t\t}\n\t}\n\tsession.agent.state.tools = tools;\n\n\t// Rebuild base system prompt with new tool set\n\tsession._baseSystemPrompt = session._rebuildSystemPrompt(validToolNames);\n\tsession.agent.state.systemPrompt = session._systemPromptOverride ?? session._baseSystemPrompt;\n}\n\nexport function rebuildSystemPrompt(session: AgentSessionInternals, toolNames: string[]): string {\n\tconst validToolNames = toolNames.filter((name) => session._toolRegistry.has(name));\n\tconst toolSnippets: Record<string, string> = {};\n\tconst promptGuidelines: string[] = [];\n\tfor (const name of validToolNames) {\n\t\tconst snippet = session._toolPromptSnippets.get(name);\n\t\tif (snippet) {\n\t\t\ttoolSnippets[name] = snippet;\n\t\t}\n\n\t\tconst toolGuidelines = session._toolPromptGuidelines.get(name);\n\t\tif (toolGuidelines) {\n\t\t\tpromptGuidelines.push(...toolGuidelines);\n\t\t}\n\t}\n\n\tconst loaderSystemPrompt = session._resourceLoader.getSystemPrompt();\n\tconst loaderAppendSystemPrompt = session._resourceLoader.getAppendSystemPrompt();\n\tconst appendSystemPrompt = loaderAppendSystemPrompt.length > 0 ? loaderAppendSystemPrompt.join(\"\\n\\n\") : undefined;\n\tconst loadedSkills = session._getAvailableSkills();\n\tconst loadedContextFiles = session._resourceLoader.getAgentsFiles().agentsFiles;\n\t// Mountable capability cards (插件按需挂载与能力手册设计 §4): only cards whose\n\t// tools are still (partially) deferred; fully mounted ones drop off.\n\tconst activeToolNameSet = new Set(validToolNames);\n\tconst sourceByToolName = new Map(\n\t\tArray.from(session._toolDefinitions.entries()).map(([name, entry]) => [name, entry.sourceInfo.source] as const),\n\t);\n\tconst capabilityCards = session._deferredCapabilityCards\n\t\t.map((card) => ({\n\t\t\tpluginId: card.pluginId,\n\t\t\tdescription: card.description,\n\t\t\tdeferred: [...sourceByToolName.entries()].some(\n\t\t\t\t([name, source]) => source === card.pluginId && !activeToolNameSet.has(name),\n\t\t\t),\n\t\t}))\n\t\t.filter((card) => card.deferred)\n\t\t.map(({ pluginId, description }) => ({ pluginId, description }));\n\n\tsession._baseSystemPromptOptions = {\n\t\tcwd: session._cwd,\n\t\tskills: loadedSkills,\n\t\tcontextFiles: loadedContextFiles,\n\t\tcustomPrompt: loaderSystemPrompt,\n\t\torientationPrompt: session._orientationPrompt,\n\t\tpreferenceCard: session._preferenceCard,\n\t\tappendSystemPrompt,\n\t\tselectedTools: validToolNames,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t\tcapabilityCards,\n\t};\n\treturn buildSystemPrompt(session._baseSystemPromptOptions);\n}\n\nexport function refreshToolRegistry(\n\tsession: AgentSessionInternals,\n\toptions?: { activeToolNames?: string[]; includeAllExtensionTools?: boolean },\n): void {\n\tconst previousRegistryNames = new Set(session._toolRegistry.keys());\n\tconst previousActiveToolNames = session.getActiveToolNames();\n\tconst allowedToolNames = session._allowedToolNames;\n\tconst excludedToolNames = session._excludedToolNames;\n\tconst isAllowedTool = (name: string): boolean =>\n\t\t(!allowedToolNames || allowedToolNames.has(name)) && !excludedToolNames?.has(name);\n\n\tconst allCustomTools = session._customTools\n\t\t.map((definition) => ({\n\t\t\tdefinition,\n\t\t\tsourceInfo: createSyntheticSourceInfo(`<sdk:${definition.name}>`, { source: \"sdk\" }),\n\t\t}))\n\t\t.filter((tool) => isAllowedTool(tool.definition.name));\n\tconst definitionRegistry = new Map<string, ToolDefinitionEntry>(\n\t\tArray.from(session._baseToolDefinitions.entries())\n\t\t\t.filter(([name]) => isAllowedTool(name))\n\t\t\t.map(([name, definition]) => [\n\t\t\t\tname,\n\t\t\t\t{\n\t\t\t\t\tdefinition,\n\t\t\t\t\t// syncCapabilityTools populates _baseToolSources in lockstep with\n\t\t\t\t\t// _baseToolDefinitions, so this fallback is a desync guard only;\n\t\t\t\t\t// the default coding tools surface rides the coding-tools package\n\t\t\t\t\t// id since D-082 批 1.\n\t\t\t\t\tsourceInfo:\n\t\t\t\t\t\tsession._baseToolSources.get(name) ??\n\t\t\t\t\t\tcreateSyntheticSourceInfo(`<bootstrap:${name}>`, { source: \"agent-forge.plugin.coding-tools\" }),\n\t\t\t\t},\n\t\t\t]),\n\t);\n\tfor (const tool of allCustomTools) {\n\t\tdefinitionRegistry.set(tool.definition.name, {\n\t\t\tdefinition: tool.definition,\n\t\t\tsourceInfo: tool.sourceInfo,\n\t\t});\n\t}\n\tsession._toolDefinitions = definitionRegistry;\n\tsession._toolPromptSnippets = new Map(\n\t\tArray.from(definitionRegistry.values())\n\t\t\t.map(({ definition }) => {\n\t\t\t\tconst snippet = normalizePromptSnippet(definition.promptSnippet);\n\t\t\t\treturn snippet ? ([definition.name, snippet] as const) : undefined;\n\t\t\t})\n\t\t\t.filter((entry): entry is readonly [string, string] => entry !== undefined),\n\t);\n\tsession._toolPromptGuidelines = new Map(\n\t\tArray.from(definitionRegistry.values())\n\t\t\t.map(({ definition }) => {\n\t\t\t\tconst guidelines = normalizePromptGuidelines(definition.promptGuidelines);\n\t\t\t\treturn guidelines.length > 0 ? ([definition.name, guidelines] as const) : undefined;\n\t\t\t})\n\t\t\t.filter((entry): entry is readonly [string, string[]] => entry !== undefined),\n\t);\n\t// Session-resolved execute context and dynamic-tool tracking replace the\n\t// former runner-mediated wrapper: tools receive the same session facts and\n\t// a tool that activates more tools during execute still surfaces them via\n\t// addedToolNames.\n\tconst executeContext = (): ToolExecuteContext => ({\n\t\tcwd: session.sessionManager.getCwd(),\n\t\tmodel: session.model,\n\t\tsessionManager: session.sessionManager,\n\t\tthinkingLevel: session.thinkingLevel,\n\t});\n\tconst wrapWithDynamicToolTracking = ({ definition }: { definition: ToolDefinition }): AgentTool => {\n\t\tconst tool = wrapToolDefinition(definition, executeContext);\n\t\tconst execute = tool.execute;\n\t\treturn {\n\t\t\t...tool,\n\t\t\texecute: async (toolCallId, params, signal, onUpdate) => {\n\t\t\t\tconst activeBefore = session.getActiveToolNames();\n\t\t\t\tconst result = await execute(toolCallId, params, signal, onUpdate);\n\t\t\t\tconst activeAfter = session.getActiveToolNames();\n\t\t\t\tif (!activeBefore.every((name) => activeAfter.includes(name))) return result;\n\n\t\t\t\tconst beforeNames = new Set(activeBefore);\n\t\t\t\tconst addedToolNames = activeAfter.filter((name) => !beforeNames.has(name));\n\t\t\t\tif (addedToolNames.length === 0) return result;\n\t\t\t\treturn {\n\t\t\t\t\t...result,\n\t\t\t\t\taddedToolNames: [...new Set([...(result.addedToolNames ?? []), ...addedToolNames])],\n\t\t\t\t};\n\t\t\t},\n\t\t};\n\t};\n\tconst wrappedExtensionTools = allCustomTools.map(wrapWithDynamicToolTracking);\n\tconst wrappedBuiltInTools = Array.from(session._baseToolDefinitions.values())\n\t\t.filter((definition) => isAllowedTool(definition.name))\n\t\t.map((definition) => wrapWithDynamicToolTracking({ definition }));\n\n\tconst toolRegistry = new Map(wrappedBuiltInTools.map((tool) => [tool.name, tool]));\n\tfor (const tool of wrappedExtensionTools as AgentTool[]) {\n\t\ttoolRegistry.set(tool.name, tool);\n\t}\n\tsession._toolRegistry = toolRegistry;\n\n\tconst nextActiveToolNames = (\n\t\toptions?.activeToolNames ? [...options.activeToolNames] : [...previousActiveToolNames]\n\t).filter((name) => isAllowedTool(name));\n\n\tif (allowedToolNames) {\n\t\tfor (const toolName of session._toolRegistry.keys()) {\n\t\t\tif (allowedToolNames.has(toolName)) {\n\t\t\t\tnextActiveToolNames.push(toolName);\n\t\t\t}\n\t\t}\n\t} else if (options?.includeAllExtensionTools) {\n\t\tfor (const tool of wrappedExtensionTools) {\n\t\t\tnextActiveToolNames.push(tool.name);\n\t\t}\n\t} else if (!options?.activeToolNames) {\n\t\tfor (const toolName of session._toolRegistry.keys()) {\n\t\t\tif (previousRegistryNames.has(toolName)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Deferred tools (e.g. MCP servers configured with deferredTools)\n\t\t\t// register but stay out of the default active set until tool_search\n\t\t\t// or an explicit activation names them.\n\t\t\tif (session._deferredToolPluginIds.has(session._baseToolSources.get(toolName)?.source ?? \"\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tnextActiveToolNames.push(toolName);\n\t\t}\n\t}\n\n\tsession.setActiveToolsByName([...new Set(nextActiveToolNames)]);\n}\n\nexport function syncCapabilityTools(session: AgentSessionInternals): void {\n\tconst tools = session._capabilityRuntime?.listTools() ?? [];\n\tsession._baseToolDefinitions = new Map(tools.map(({ name, definition }) => [name, definition as ToolDefinition]));\n\tsession._baseToolSources = new Map(\n\t\ttools.map(({ name, source }) => [name, createSyntheticSourceInfo(`<plugin:${source}:${name}>`, { source })]),\n\t);\n}\n\nexport function getCapabilitySkills(session: AgentSessionInternals): Skill[] {\n\tconst runtime = session._capabilityRuntime;\n\tif (!runtime) return [];\n\t// The skill contribution point is owned by the bootstrap-skills plugin. In\n\t// hosts that never install it (assistant suite, print mode) — or while that\n\t// owner is inactive — `listContributions` throws \"Contribution point is not\n\t// defined\". That state means \"no contributed skills\", not a failure: every\n\t// tool-registry change rebuilds the system prompt, so propagating the error\n\t// turned each rebuild into an error-level plugin.log record. Any other\n\t// failure still propagates.\n\tlet contributed: ReturnType<typeof runtime.listContributions>;\n\ttry {\n\t\tcontributed = runtime.listContributions(SKILL_CONTRIBUTION_POINT_ID, SKILL_CONTRIBUTION_POINT_VERSION);\n\t} catch (error) {\n\t\tif (!(error instanceof Error) || !error.message.startsWith(\"Contribution point is not defined\")) throw error;\n\t\treturn [];\n\t}\n\tconst contributedSkills = contributed\n\t\t.filter(\n\t\t\t(entry): entry is typeof entry & { value: Skill } =>\n\t\t\t\tentry.value !== null && typeof entry.value === \"object\" && \"name\" in entry.value,\n\t\t)\n\t\t.map((entry) => ({\n\t\t\t...entry.value,\n\t\t\tdisableModelInvocation: entry.value.disableModelInvocation === true,\n\t\t\tsourceInfo: createSyntheticSourceInfo(`<contribution:${entry.owner}:${entry.id}>`, {\n\t\t\t\tsource: entry.owner,\n\t\t\t\tbaseDir: entry.value.baseDir,\n\t\t\t}),\n\t\t}));\n\tconst contributedNames = new Set(contributedSkills.map((skill) => skill.name));\n\tconst legacyFilter = session._capabilitySkillsFilter;\n\tconst legacy = runtime\n\t\t.listSkills()\n\t\t.filter(({ definition }) => !contributedNames.has(definition.name))\n\t\t.map(({ definition, source }) => ({\n\t\t\t...definition,\n\t\t\tdisableModelInvocation: definition.disableModelInvocation === true,\n\t\t\tsourceInfo: createSyntheticSourceInfo(`<plugin:${source}:${definition.name}>`, {\n\t\t\t\tsource,\n\t\t\t\tbaseDir: definition.baseDir,\n\t\t\t}),\n\t\t}))\n\t\t// Suite association filtering (方案系统 M3): the assembler owns the\n\t\t// policy; the session only applies the injected function. The\n\t\t// bootstrap-skills contribution face is already loader-filtered and\n\t\t// must not be filtered twice.\n\t\t.filter((skill) => (legacyFilter ? legacyFilter([skill]).length > 0 : true));\n\treturn [...contributedSkills, ...legacy].sort(\n\t\t(left, right) => left.name.localeCompare(right.name) || left.sourceInfo.path.localeCompare(right.sourceInfo.path),\n\t);\n}\n\nexport function validateCapabilitySkillConflicts(session: AgentSessionInternals): void {\n\tconst resourceNames = new Set<string>();\n\tconst resourceFilePaths = new Set<string>();\n\tfor (const skill of session._resourceLoader.getSkills().skills) {\n\t\tif (resourceNames.has(skill.name))\n\t\t\tthrow new Error(t(\"Skill is duplicated in resources: {name}\", { name: skill.name }));\n\t\tresourceNames.add(skill.name);\n\t\tresourceFilePaths.add(skill.filePath);\n\t}\n\tfor (const skill of session._getCapabilitySkills()) {\n\t\t// bootstrap-skills mirrors the same on-disk SKILL.md into the capability\n\t\t// layer: same name AND same file is one skill seen through two channels,\n\t\t// not a conflict. Same name from a different file (e.g. an MCP server\n\t\t// contributing a skill that collides with a disk skill) is a real one.\n\t\tif (typeof skill.filePath === \"string\" && resourceFilePaths.has(skill.filePath)) continue;\n\t\tif (resourceNames.has(skill.name))\n\t\t\tthrow new Error(t(\"Skill conflicts with a resource skill: {name}\", { name: skill.name }));\n\t}\n}\n\nexport async function refreshBootstrapSkills(session: AgentSessionInternals): Promise<void> {\n\tconst runtime = session._capabilityRuntime;\n\tif (!runtime) return;\n\tsession._validateCapabilitySkillConflicts();\n\tif (session._bootstrapSkillsHandle) {\n\t\tawait refreshSessionBootstrapSkills(runtime, session._resourceLoader.getSkills().skills);\n\t} else {\n\t\tsession._bootstrapSkillsHandle = installSessionBootstrapSkills(\n\t\t\truntime,\n\t\t\tsession._resourceLoader.getSkills().skills,\n\t\t);\n\t}\n\tsession._baseSystemPrompt = session._rebuildSystemPrompt(session.getActiveToolNames());\n\tsession.agent.state.systemPrompt = session._baseSystemPrompt;\n}\n"]}
@@ -89,6 +89,18 @@ export function rebuildSystemPrompt(session, toolNames) {
89
89
  const appendSystemPrompt = loaderAppendSystemPrompt.length > 0 ? loaderAppendSystemPrompt.join("\n\n") : undefined;
90
90
  const loadedSkills = session._getAvailableSkills();
91
91
  const loadedContextFiles = session._resourceLoader.getAgentsFiles().agentsFiles;
92
+ // Mountable capability cards (插件按需挂载与能力手册设计 §4): only cards whose
93
+ // tools are still (partially) deferred; fully mounted ones drop off.
94
+ const activeToolNameSet = new Set(validToolNames);
95
+ const sourceByToolName = new Map(Array.from(session._toolDefinitions.entries()).map(([name, entry]) => [name, entry.sourceInfo.source]));
96
+ const capabilityCards = session._deferredCapabilityCards
97
+ .map((card) => ({
98
+ pluginId: card.pluginId,
99
+ description: card.description,
100
+ deferred: [...sourceByToolName.entries()].some(([name, source]) => source === card.pluginId && !activeToolNameSet.has(name)),
101
+ }))
102
+ .filter((card) => card.deferred)
103
+ .map(({ pluginId, description }) => ({ pluginId, description }));
92
104
  session._baseSystemPromptOptions = {
93
105
  cwd: session._cwd,
94
106
  skills: loadedSkills,
@@ -100,6 +112,7 @@ export function rebuildSystemPrompt(session, toolNames) {
100
112
  selectedTools: validToolNames,
101
113
  toolSnippets,
102
114
  promptGuidelines,
115
+ capabilityCards,
103
116
  };
104
117
  return buildSystemPrompt(session._baseSystemPromptOptions);
105
118
  }
@@ -1 +1 @@
1
- {"version":3,"file":"agent-session-tools.js","sourceRoot":"","sources":["../../src/core/agent-session-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tool registry, capability skills, and system-prompt assembly for\n * AgentSession.\n *\n * Extracted from `agent-session.ts`. Every function here operates on the\n * internal session facade ({@link AgentSessionInternals}); `AgentSession`\n * keeps same-name delegates so call sites, dynamic dispatch, and test spies\n * keep working unchanged.\n */\n\nimport type { AgentTool } from \"@agent-forge/agent-core\";\nimport type { AgentSessionInternals, ToolDefinitionEntry } from \"./agent-session-internal.ts\";\nimport {\n\tinstallSessionBootstrapSkills,\n\trefreshSessionBootstrapSkills,\n\tSKILL_CONTRIBUTION_POINT_ID,\n\tSKILL_CONTRIBUTION_POINT_VERSION,\n} from \"./extensions/index.ts\";\nimport { t } from \"./i18n/index.ts\";\nimport type { Skill } from \"./skills.ts\";\nimport { createSyntheticSourceInfo } from \"./source-info.ts\";\nimport { buildSystemPrompt } from \"./system-prompt.ts\";\nimport type { ToolDefinition, ToolExecuteContext, ToolInfo } from \"./tools/tool-definition.ts\";\nimport { wrapToolDefinition } from \"./tools/tool-definition-wrapper.ts\";\n\nexport function normalizePromptSnippet(text: string | undefined): string | undefined {\n\tif (!text) return undefined;\n\tconst oneLine = text\n\t\t.replace(/[\\r\\n]+/g, \" \")\n\t\t.replace(/\\s+/g, \" \")\n\t\t.trim();\n\treturn oneLine.length > 0 ? oneLine : undefined;\n}\n\nexport function normalizePromptGuidelines(guidelines: string[] | undefined): string[] {\n\tif (!guidelines || guidelines.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst unique = new Set<string>();\n\tfor (const guideline of guidelines) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0) {\n\t\t\tunique.add(normalized);\n\t\t}\n\t}\n\treturn Array.from(unique);\n}\n\n/**\n * Get all configured tools with name, description, parameter schema, prompt guidelines, and source metadata.\n */\nexport function getAllTools(session: AgentSessionInternals): ToolInfo[] {\n\treturn Array.from(session._toolDefinitions.values()).map(({ definition, sourceInfo }) => ({\n\t\tname: definition.name,\n\t\tdescription: definition.description,\n\t\tparameters: definition.parameters,\n\t\tpromptGuidelines: definition.promptGuidelines,\n\t\tsourceInfo,\n\t}));\n}\n\nexport function getToolDefinition(session: AgentSessionInternals, name: string): ToolDefinition | undefined {\n\treturn session._toolDefinitions.get(name)?.definition;\n}\n\n/**\n * Set active tools by name.\n * Only tools in the registry can be enabled. Unknown tool names are ignored.\n * Also rebuilds the system prompt to reflect the new tool set.\n * Changes take effect on the next agent turn.\n */\nexport function setActiveToolsByName(session: AgentSessionInternals, toolNames: string[]): void {\n\tconst tools: AgentTool[] = [];\n\tconst validToolNames: string[] = [];\n\tfor (const name of toolNames) {\n\t\tconst tool = session._toolRegistry.get(name);\n\t\tif (tool) {\n\t\t\ttools.push(tool);\n\t\t\tvalidToolNames.push(name);\n\t\t}\n\t}\n\tsession.agent.state.tools = tools;\n\n\t// Rebuild base system prompt with new tool set\n\tsession._baseSystemPrompt = session._rebuildSystemPrompt(validToolNames);\n\tsession.agent.state.systemPrompt = session._systemPromptOverride ?? session._baseSystemPrompt;\n}\n\nexport function rebuildSystemPrompt(session: AgentSessionInternals, toolNames: string[]): string {\n\tconst validToolNames = toolNames.filter((name) => session._toolRegistry.has(name));\n\tconst toolSnippets: Record<string, string> = {};\n\tconst promptGuidelines: string[] = [];\n\tfor (const name of validToolNames) {\n\t\tconst snippet = session._toolPromptSnippets.get(name);\n\t\tif (snippet) {\n\t\t\ttoolSnippets[name] = snippet;\n\t\t}\n\n\t\tconst toolGuidelines = session._toolPromptGuidelines.get(name);\n\t\tif (toolGuidelines) {\n\t\t\tpromptGuidelines.push(...toolGuidelines);\n\t\t}\n\t}\n\n\tconst loaderSystemPrompt = session._resourceLoader.getSystemPrompt();\n\tconst loaderAppendSystemPrompt = session._resourceLoader.getAppendSystemPrompt();\n\tconst appendSystemPrompt = loaderAppendSystemPrompt.length > 0 ? loaderAppendSystemPrompt.join(\"\\n\\n\") : undefined;\n\tconst loadedSkills = session._getAvailableSkills();\n\tconst loadedContextFiles = session._resourceLoader.getAgentsFiles().agentsFiles;\n\n\tsession._baseSystemPromptOptions = {\n\t\tcwd: session._cwd,\n\t\tskills: loadedSkills,\n\t\tcontextFiles: loadedContextFiles,\n\t\tcustomPrompt: loaderSystemPrompt,\n\t\torientationPrompt: session._orientationPrompt,\n\t\tpreferenceCard: session._preferenceCard,\n\t\tappendSystemPrompt,\n\t\tselectedTools: validToolNames,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t};\n\treturn buildSystemPrompt(session._baseSystemPromptOptions);\n}\n\nexport function refreshToolRegistry(\n\tsession: AgentSessionInternals,\n\toptions?: { activeToolNames?: string[]; includeAllExtensionTools?: boolean },\n): void {\n\tconst previousRegistryNames = new Set(session._toolRegistry.keys());\n\tconst previousActiveToolNames = session.getActiveToolNames();\n\tconst allowedToolNames = session._allowedToolNames;\n\tconst excludedToolNames = session._excludedToolNames;\n\tconst isAllowedTool = (name: string): boolean =>\n\t\t(!allowedToolNames || allowedToolNames.has(name)) && !excludedToolNames?.has(name);\n\n\tconst allCustomTools = session._customTools\n\t\t.map((definition) => ({\n\t\t\tdefinition,\n\t\t\tsourceInfo: createSyntheticSourceInfo(`<sdk:${definition.name}>`, { source: \"sdk\" }),\n\t\t}))\n\t\t.filter((tool) => isAllowedTool(tool.definition.name));\n\tconst definitionRegistry = new Map<string, ToolDefinitionEntry>(\n\t\tArray.from(session._baseToolDefinitions.entries())\n\t\t\t.filter(([name]) => isAllowedTool(name))\n\t\t\t.map(([name, definition]) => [\n\t\t\t\tname,\n\t\t\t\t{\n\t\t\t\t\tdefinition,\n\t\t\t\t\t// syncCapabilityTools populates _baseToolSources in lockstep with\n\t\t\t\t\t// _baseToolDefinitions, so this fallback is a desync guard only;\n\t\t\t\t\t// the default coding tools surface rides the coding-tools package\n\t\t\t\t\t// id since D-082 批 1.\n\t\t\t\t\tsourceInfo:\n\t\t\t\t\t\tsession._baseToolSources.get(name) ??\n\t\t\t\t\t\tcreateSyntheticSourceInfo(`<bootstrap:${name}>`, { source: \"agent-forge.plugin.coding-tools\" }),\n\t\t\t\t},\n\t\t\t]),\n\t);\n\tfor (const tool of allCustomTools) {\n\t\tdefinitionRegistry.set(tool.definition.name, {\n\t\t\tdefinition: tool.definition,\n\t\t\tsourceInfo: tool.sourceInfo,\n\t\t});\n\t}\n\tsession._toolDefinitions = definitionRegistry;\n\tsession._toolPromptSnippets = new Map(\n\t\tArray.from(definitionRegistry.values())\n\t\t\t.map(({ definition }) => {\n\t\t\t\tconst snippet = normalizePromptSnippet(definition.promptSnippet);\n\t\t\t\treturn snippet ? ([definition.name, snippet] as const) : undefined;\n\t\t\t})\n\t\t\t.filter((entry): entry is readonly [string, string] => entry !== undefined),\n\t);\n\tsession._toolPromptGuidelines = new Map(\n\t\tArray.from(definitionRegistry.values())\n\t\t\t.map(({ definition }) => {\n\t\t\t\tconst guidelines = normalizePromptGuidelines(definition.promptGuidelines);\n\t\t\t\treturn guidelines.length > 0 ? ([definition.name, guidelines] as const) : undefined;\n\t\t\t})\n\t\t\t.filter((entry): entry is readonly [string, string[]] => entry !== undefined),\n\t);\n\t// Session-resolved execute context and dynamic-tool tracking replace the\n\t// former runner-mediated wrapper: tools receive the same session facts and\n\t// a tool that activates more tools during execute still surfaces them via\n\t// addedToolNames.\n\tconst executeContext = (): ToolExecuteContext => ({\n\t\tcwd: session.sessionManager.getCwd(),\n\t\tmodel: session.model,\n\t\tsessionManager: session.sessionManager,\n\t\tthinkingLevel: session.thinkingLevel,\n\t});\n\tconst wrapWithDynamicToolTracking = ({ definition }: { definition: ToolDefinition }): AgentTool => {\n\t\tconst tool = wrapToolDefinition(definition, executeContext);\n\t\tconst execute = tool.execute;\n\t\treturn {\n\t\t\t...tool,\n\t\t\texecute: async (toolCallId, params, signal, onUpdate) => {\n\t\t\t\tconst activeBefore = session.getActiveToolNames();\n\t\t\t\tconst result = await execute(toolCallId, params, signal, onUpdate);\n\t\t\t\tconst activeAfter = session.getActiveToolNames();\n\t\t\t\tif (!activeBefore.every((name) => activeAfter.includes(name))) return result;\n\n\t\t\t\tconst beforeNames = new Set(activeBefore);\n\t\t\t\tconst addedToolNames = activeAfter.filter((name) => !beforeNames.has(name));\n\t\t\t\tif (addedToolNames.length === 0) return result;\n\t\t\t\treturn {\n\t\t\t\t\t...result,\n\t\t\t\t\taddedToolNames: [...new Set([...(result.addedToolNames ?? []), ...addedToolNames])],\n\t\t\t\t};\n\t\t\t},\n\t\t};\n\t};\n\tconst wrappedExtensionTools = allCustomTools.map(wrapWithDynamicToolTracking);\n\tconst wrappedBuiltInTools = Array.from(session._baseToolDefinitions.values())\n\t\t.filter((definition) => isAllowedTool(definition.name))\n\t\t.map((definition) => wrapWithDynamicToolTracking({ definition }));\n\n\tconst toolRegistry = new Map(wrappedBuiltInTools.map((tool) => [tool.name, tool]));\n\tfor (const tool of wrappedExtensionTools as AgentTool[]) {\n\t\ttoolRegistry.set(tool.name, tool);\n\t}\n\tsession._toolRegistry = toolRegistry;\n\n\tconst nextActiveToolNames = (\n\t\toptions?.activeToolNames ? [...options.activeToolNames] : [...previousActiveToolNames]\n\t).filter((name) => isAllowedTool(name));\n\n\tif (allowedToolNames) {\n\t\tfor (const toolName of session._toolRegistry.keys()) {\n\t\t\tif (allowedToolNames.has(toolName)) {\n\t\t\t\tnextActiveToolNames.push(toolName);\n\t\t\t}\n\t\t}\n\t} else if (options?.includeAllExtensionTools) {\n\t\tfor (const tool of wrappedExtensionTools) {\n\t\t\tnextActiveToolNames.push(tool.name);\n\t\t}\n\t} else if (!options?.activeToolNames) {\n\t\tfor (const toolName of session._toolRegistry.keys()) {\n\t\t\tif (previousRegistryNames.has(toolName)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Deferred tools (e.g. MCP servers configured with deferredTools)\n\t\t\t// register but stay out of the default active set until tool_search\n\t\t\t// or an explicit activation names them.\n\t\t\tif (session._deferredToolPluginIds.has(session._baseToolSources.get(toolName)?.source ?? \"\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tnextActiveToolNames.push(toolName);\n\t\t}\n\t}\n\n\tsession.setActiveToolsByName([...new Set(nextActiveToolNames)]);\n}\n\nexport function syncCapabilityTools(session: AgentSessionInternals): void {\n\tconst tools = session._capabilityRuntime?.listTools() ?? [];\n\tsession._baseToolDefinitions = new Map(tools.map(({ name, definition }) => [name, definition as ToolDefinition]));\n\tsession._baseToolSources = new Map(\n\t\ttools.map(({ name, source }) => [name, createSyntheticSourceInfo(`<plugin:${source}:${name}>`, { source })]),\n\t);\n}\n\nexport function getCapabilitySkills(session: AgentSessionInternals): Skill[] {\n\tconst runtime = session._capabilityRuntime;\n\tif (!runtime) return [];\n\t// The skill contribution point is owned by the bootstrap-skills plugin. In\n\t// hosts that never install it (assistant suite, print mode) — or while that\n\t// owner is inactive — `listContributions` throws \"Contribution point is not\n\t// defined\". That state means \"no contributed skills\", not a failure: every\n\t// tool-registry change rebuilds the system prompt, so propagating the error\n\t// turned each rebuild into an error-level plugin.log record. Any other\n\t// failure still propagates.\n\tlet contributed: ReturnType<typeof runtime.listContributions>;\n\ttry {\n\t\tcontributed = runtime.listContributions(SKILL_CONTRIBUTION_POINT_ID, SKILL_CONTRIBUTION_POINT_VERSION);\n\t} catch (error) {\n\t\tif (!(error instanceof Error) || !error.message.startsWith(\"Contribution point is not defined\")) throw error;\n\t\treturn [];\n\t}\n\tconst contributedSkills = contributed\n\t\t.filter(\n\t\t\t(entry): entry is typeof entry & { value: Skill } =>\n\t\t\t\tentry.value !== null && typeof entry.value === \"object\" && \"name\" in entry.value,\n\t\t)\n\t\t.map((entry) => ({\n\t\t\t...entry.value,\n\t\t\tdisableModelInvocation: entry.value.disableModelInvocation === true,\n\t\t\tsourceInfo: createSyntheticSourceInfo(`<contribution:${entry.owner}:${entry.id}>`, {\n\t\t\t\tsource: entry.owner,\n\t\t\t\tbaseDir: entry.value.baseDir,\n\t\t\t}),\n\t\t}));\n\tconst contributedNames = new Set(contributedSkills.map((skill) => skill.name));\n\tconst legacyFilter = session._capabilitySkillsFilter;\n\tconst legacy = runtime\n\t\t.listSkills()\n\t\t.filter(({ definition }) => !contributedNames.has(definition.name))\n\t\t.map(({ definition, source }) => ({\n\t\t\t...definition,\n\t\t\tdisableModelInvocation: definition.disableModelInvocation === true,\n\t\t\tsourceInfo: createSyntheticSourceInfo(`<plugin:${source}:${definition.name}>`, {\n\t\t\t\tsource,\n\t\t\t\tbaseDir: definition.baseDir,\n\t\t\t}),\n\t\t}))\n\t\t// Suite association filtering (方案系统 M3): the assembler owns the\n\t\t// policy; the session only applies the injected function. The\n\t\t// bootstrap-skills contribution face is already loader-filtered and\n\t\t// must not be filtered twice.\n\t\t.filter((skill) => (legacyFilter ? legacyFilter([skill]).length > 0 : true));\n\treturn [...contributedSkills, ...legacy].sort(\n\t\t(left, right) => left.name.localeCompare(right.name) || left.sourceInfo.path.localeCompare(right.sourceInfo.path),\n\t);\n}\n\nexport function validateCapabilitySkillConflicts(session: AgentSessionInternals): void {\n\tconst resourceNames = new Set<string>();\n\tconst resourceFilePaths = new Set<string>();\n\tfor (const skill of session._resourceLoader.getSkills().skills) {\n\t\tif (resourceNames.has(skill.name))\n\t\t\tthrow new Error(t(\"Skill is duplicated in resources: {name}\", { name: skill.name }));\n\t\tresourceNames.add(skill.name);\n\t\tresourceFilePaths.add(skill.filePath);\n\t}\n\tfor (const skill of session._getCapabilitySkills()) {\n\t\t// bootstrap-skills mirrors the same on-disk SKILL.md into the capability\n\t\t// layer: same name AND same file is one skill seen through two channels,\n\t\t// not a conflict. Same name from a different file (e.g. an MCP server\n\t\t// contributing a skill that collides with a disk skill) is a real one.\n\t\tif (typeof skill.filePath === \"string\" && resourceFilePaths.has(skill.filePath)) continue;\n\t\tif (resourceNames.has(skill.name))\n\t\t\tthrow new Error(t(\"Skill conflicts with a resource skill: {name}\", { name: skill.name }));\n\t}\n}\n\nexport async function refreshBootstrapSkills(session: AgentSessionInternals): Promise<void> {\n\tconst runtime = session._capabilityRuntime;\n\tif (!runtime) return;\n\tsession._validateCapabilitySkillConflicts();\n\tif (session._bootstrapSkillsHandle) {\n\t\tawait refreshSessionBootstrapSkills(runtime, session._resourceLoader.getSkills().skills);\n\t} else {\n\t\tsession._bootstrapSkillsHandle = installSessionBootstrapSkills(\n\t\t\truntime,\n\t\t\tsession._resourceLoader.getSkills().skills,\n\t\t);\n\t}\n\tsession._baseSystemPrompt = session._rebuildSystemPrompt(session.getActiveToolNames());\n\tsession.agent.state.systemPrompt = session._baseSystemPrompt;\n}\n"]}
1
+ {"version":3,"file":"agent-session-tools.js","sourceRoot":"","sources":["../../src/core/agent-session-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tool registry, capability skills, and system-prompt assembly for\n * AgentSession.\n *\n * Extracted from `agent-session.ts`. Every function here operates on the\n * internal session facade ({@link AgentSessionInternals}); `AgentSession`\n * keeps same-name delegates so call sites, dynamic dispatch, and test spies\n * keep working unchanged.\n */\n\nimport type { AgentTool } from \"@agent-forge/agent-core\";\nimport type { AgentSessionInternals, ToolDefinitionEntry } from \"./agent-session-internal.ts\";\nimport {\n\tinstallSessionBootstrapSkills,\n\trefreshSessionBootstrapSkills,\n\tSKILL_CONTRIBUTION_POINT_ID,\n\tSKILL_CONTRIBUTION_POINT_VERSION,\n} from \"./extensions/index.ts\";\nimport { t } from \"./i18n/index.ts\";\nimport type { Skill } from \"./skills.ts\";\nimport { createSyntheticSourceInfo } from \"./source-info.ts\";\nimport { buildSystemPrompt } from \"./system-prompt.ts\";\nimport type { ToolDefinition, ToolExecuteContext, ToolInfo } from \"./tools/tool-definition.ts\";\nimport { wrapToolDefinition } from \"./tools/tool-definition-wrapper.ts\";\n\nexport function normalizePromptSnippet(text: string | undefined): string | undefined {\n\tif (!text) return undefined;\n\tconst oneLine = text\n\t\t.replace(/[\\r\\n]+/g, \" \")\n\t\t.replace(/\\s+/g, \" \")\n\t\t.trim();\n\treturn oneLine.length > 0 ? oneLine : undefined;\n}\n\nexport function normalizePromptGuidelines(guidelines: string[] | undefined): string[] {\n\tif (!guidelines || guidelines.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst unique = new Set<string>();\n\tfor (const guideline of guidelines) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0) {\n\t\t\tunique.add(normalized);\n\t\t}\n\t}\n\treturn Array.from(unique);\n}\n\n/**\n * Get all configured tools with name, description, parameter schema, prompt guidelines, and source metadata.\n */\nexport function getAllTools(session: AgentSessionInternals): ToolInfo[] {\n\treturn Array.from(session._toolDefinitions.values()).map(({ definition, sourceInfo }) => ({\n\t\tname: definition.name,\n\t\tdescription: definition.description,\n\t\tparameters: definition.parameters,\n\t\tpromptGuidelines: definition.promptGuidelines,\n\t\tsourceInfo,\n\t}));\n}\n\nexport function getToolDefinition(session: AgentSessionInternals, name: string): ToolDefinition | undefined {\n\treturn session._toolDefinitions.get(name)?.definition;\n}\n\n/**\n * Set active tools by name.\n * Only tools in the registry can be enabled. Unknown tool names are ignored.\n * Also rebuilds the system prompt to reflect the new tool set.\n * Changes take effect on the next agent turn.\n */\nexport function setActiveToolsByName(session: AgentSessionInternals, toolNames: string[]): void {\n\tconst tools: AgentTool[] = [];\n\tconst validToolNames: string[] = [];\n\tfor (const name of toolNames) {\n\t\tconst tool = session._toolRegistry.get(name);\n\t\tif (tool) {\n\t\t\ttools.push(tool);\n\t\t\tvalidToolNames.push(name);\n\t\t}\n\t}\n\tsession.agent.state.tools = tools;\n\n\t// Rebuild base system prompt with new tool set\n\tsession._baseSystemPrompt = session._rebuildSystemPrompt(validToolNames);\n\tsession.agent.state.systemPrompt = session._systemPromptOverride ?? session._baseSystemPrompt;\n}\n\nexport function rebuildSystemPrompt(session: AgentSessionInternals, toolNames: string[]): string {\n\tconst validToolNames = toolNames.filter((name) => session._toolRegistry.has(name));\n\tconst toolSnippets: Record<string, string> = {};\n\tconst promptGuidelines: string[] = [];\n\tfor (const name of validToolNames) {\n\t\tconst snippet = session._toolPromptSnippets.get(name);\n\t\tif (snippet) {\n\t\t\ttoolSnippets[name] = snippet;\n\t\t}\n\n\t\tconst toolGuidelines = session._toolPromptGuidelines.get(name);\n\t\tif (toolGuidelines) {\n\t\t\tpromptGuidelines.push(...toolGuidelines);\n\t\t}\n\t}\n\n\tconst loaderSystemPrompt = session._resourceLoader.getSystemPrompt();\n\tconst loaderAppendSystemPrompt = session._resourceLoader.getAppendSystemPrompt();\n\tconst appendSystemPrompt = loaderAppendSystemPrompt.length > 0 ? loaderAppendSystemPrompt.join(\"\\n\\n\") : undefined;\n\tconst loadedSkills = session._getAvailableSkills();\n\tconst loadedContextFiles = session._resourceLoader.getAgentsFiles().agentsFiles;\n\t// Mountable capability cards (插件按需挂载与能力手册设计 §4): only cards whose\n\t// tools are still (partially) deferred; fully mounted ones drop off.\n\tconst activeToolNameSet = new Set(validToolNames);\n\tconst sourceByToolName = new Map(\n\t\tArray.from(session._toolDefinitions.entries()).map(([name, entry]) => [name, entry.sourceInfo.source] as const),\n\t);\n\tconst capabilityCards = session._deferredCapabilityCards\n\t\t.map((card) => ({\n\t\t\tpluginId: card.pluginId,\n\t\t\tdescription: card.description,\n\t\t\tdeferred: [...sourceByToolName.entries()].some(\n\t\t\t\t([name, source]) => source === card.pluginId && !activeToolNameSet.has(name),\n\t\t\t),\n\t\t}))\n\t\t.filter((card) => card.deferred)\n\t\t.map(({ pluginId, description }) => ({ pluginId, description }));\n\n\tsession._baseSystemPromptOptions = {\n\t\tcwd: session._cwd,\n\t\tskills: loadedSkills,\n\t\tcontextFiles: loadedContextFiles,\n\t\tcustomPrompt: loaderSystemPrompt,\n\t\torientationPrompt: session._orientationPrompt,\n\t\tpreferenceCard: session._preferenceCard,\n\t\tappendSystemPrompt,\n\t\tselectedTools: validToolNames,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t\tcapabilityCards,\n\t};\n\treturn buildSystemPrompt(session._baseSystemPromptOptions);\n}\n\nexport function refreshToolRegistry(\n\tsession: AgentSessionInternals,\n\toptions?: { activeToolNames?: string[]; includeAllExtensionTools?: boolean },\n): void {\n\tconst previousRegistryNames = new Set(session._toolRegistry.keys());\n\tconst previousActiveToolNames = session.getActiveToolNames();\n\tconst allowedToolNames = session._allowedToolNames;\n\tconst excludedToolNames = session._excludedToolNames;\n\tconst isAllowedTool = (name: string): boolean =>\n\t\t(!allowedToolNames || allowedToolNames.has(name)) && !excludedToolNames?.has(name);\n\n\tconst allCustomTools = session._customTools\n\t\t.map((definition) => ({\n\t\t\tdefinition,\n\t\t\tsourceInfo: createSyntheticSourceInfo(`<sdk:${definition.name}>`, { source: \"sdk\" }),\n\t\t}))\n\t\t.filter((tool) => isAllowedTool(tool.definition.name));\n\tconst definitionRegistry = new Map<string, ToolDefinitionEntry>(\n\t\tArray.from(session._baseToolDefinitions.entries())\n\t\t\t.filter(([name]) => isAllowedTool(name))\n\t\t\t.map(([name, definition]) => [\n\t\t\t\tname,\n\t\t\t\t{\n\t\t\t\t\tdefinition,\n\t\t\t\t\t// syncCapabilityTools populates _baseToolSources in lockstep with\n\t\t\t\t\t// _baseToolDefinitions, so this fallback is a desync guard only;\n\t\t\t\t\t// the default coding tools surface rides the coding-tools package\n\t\t\t\t\t// id since D-082 批 1.\n\t\t\t\t\tsourceInfo:\n\t\t\t\t\t\tsession._baseToolSources.get(name) ??\n\t\t\t\t\t\tcreateSyntheticSourceInfo(`<bootstrap:${name}>`, { source: \"agent-forge.plugin.coding-tools\" }),\n\t\t\t\t},\n\t\t\t]),\n\t);\n\tfor (const tool of allCustomTools) {\n\t\tdefinitionRegistry.set(tool.definition.name, {\n\t\t\tdefinition: tool.definition,\n\t\t\tsourceInfo: tool.sourceInfo,\n\t\t});\n\t}\n\tsession._toolDefinitions = definitionRegistry;\n\tsession._toolPromptSnippets = new Map(\n\t\tArray.from(definitionRegistry.values())\n\t\t\t.map(({ definition }) => {\n\t\t\t\tconst snippet = normalizePromptSnippet(definition.promptSnippet);\n\t\t\t\treturn snippet ? ([definition.name, snippet] as const) : undefined;\n\t\t\t})\n\t\t\t.filter((entry): entry is readonly [string, string] => entry !== undefined),\n\t);\n\tsession._toolPromptGuidelines = new Map(\n\t\tArray.from(definitionRegistry.values())\n\t\t\t.map(({ definition }) => {\n\t\t\t\tconst guidelines = normalizePromptGuidelines(definition.promptGuidelines);\n\t\t\t\treturn guidelines.length > 0 ? ([definition.name, guidelines] as const) : undefined;\n\t\t\t})\n\t\t\t.filter((entry): entry is readonly [string, string[]] => entry !== undefined),\n\t);\n\t// Session-resolved execute context and dynamic-tool tracking replace the\n\t// former runner-mediated wrapper: tools receive the same session facts and\n\t// a tool that activates more tools during execute still surfaces them via\n\t// addedToolNames.\n\tconst executeContext = (): ToolExecuteContext => ({\n\t\tcwd: session.sessionManager.getCwd(),\n\t\tmodel: session.model,\n\t\tsessionManager: session.sessionManager,\n\t\tthinkingLevel: session.thinkingLevel,\n\t});\n\tconst wrapWithDynamicToolTracking = ({ definition }: { definition: ToolDefinition }): AgentTool => {\n\t\tconst tool = wrapToolDefinition(definition, executeContext);\n\t\tconst execute = tool.execute;\n\t\treturn {\n\t\t\t...tool,\n\t\t\texecute: async (toolCallId, params, signal, onUpdate) => {\n\t\t\t\tconst activeBefore = session.getActiveToolNames();\n\t\t\t\tconst result = await execute(toolCallId, params, signal, onUpdate);\n\t\t\t\tconst activeAfter = session.getActiveToolNames();\n\t\t\t\tif (!activeBefore.every((name) => activeAfter.includes(name))) return result;\n\n\t\t\t\tconst beforeNames = new Set(activeBefore);\n\t\t\t\tconst addedToolNames = activeAfter.filter((name) => !beforeNames.has(name));\n\t\t\t\tif (addedToolNames.length === 0) return result;\n\t\t\t\treturn {\n\t\t\t\t\t...result,\n\t\t\t\t\taddedToolNames: [...new Set([...(result.addedToolNames ?? []), ...addedToolNames])],\n\t\t\t\t};\n\t\t\t},\n\t\t};\n\t};\n\tconst wrappedExtensionTools = allCustomTools.map(wrapWithDynamicToolTracking);\n\tconst wrappedBuiltInTools = Array.from(session._baseToolDefinitions.values())\n\t\t.filter((definition) => isAllowedTool(definition.name))\n\t\t.map((definition) => wrapWithDynamicToolTracking({ definition }));\n\n\tconst toolRegistry = new Map(wrappedBuiltInTools.map((tool) => [tool.name, tool]));\n\tfor (const tool of wrappedExtensionTools as AgentTool[]) {\n\t\ttoolRegistry.set(tool.name, tool);\n\t}\n\tsession._toolRegistry = toolRegistry;\n\n\tconst nextActiveToolNames = (\n\t\toptions?.activeToolNames ? [...options.activeToolNames] : [...previousActiveToolNames]\n\t).filter((name) => isAllowedTool(name));\n\n\tif (allowedToolNames) {\n\t\tfor (const toolName of session._toolRegistry.keys()) {\n\t\t\tif (allowedToolNames.has(toolName)) {\n\t\t\t\tnextActiveToolNames.push(toolName);\n\t\t\t}\n\t\t}\n\t} else if (options?.includeAllExtensionTools) {\n\t\tfor (const tool of wrappedExtensionTools) {\n\t\t\tnextActiveToolNames.push(tool.name);\n\t\t}\n\t} else if (!options?.activeToolNames) {\n\t\tfor (const toolName of session._toolRegistry.keys()) {\n\t\t\tif (previousRegistryNames.has(toolName)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Deferred tools (e.g. MCP servers configured with deferredTools)\n\t\t\t// register but stay out of the default active set until tool_search\n\t\t\t// or an explicit activation names them.\n\t\t\tif (session._deferredToolPluginIds.has(session._baseToolSources.get(toolName)?.source ?? \"\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tnextActiveToolNames.push(toolName);\n\t\t}\n\t}\n\n\tsession.setActiveToolsByName([...new Set(nextActiveToolNames)]);\n}\n\nexport function syncCapabilityTools(session: AgentSessionInternals): void {\n\tconst tools = session._capabilityRuntime?.listTools() ?? [];\n\tsession._baseToolDefinitions = new Map(tools.map(({ name, definition }) => [name, definition as ToolDefinition]));\n\tsession._baseToolSources = new Map(\n\t\ttools.map(({ name, source }) => [name, createSyntheticSourceInfo(`<plugin:${source}:${name}>`, { source })]),\n\t);\n}\n\nexport function getCapabilitySkills(session: AgentSessionInternals): Skill[] {\n\tconst runtime = session._capabilityRuntime;\n\tif (!runtime) return [];\n\t// The skill contribution point is owned by the bootstrap-skills plugin. In\n\t// hosts that never install it (assistant suite, print mode) — or while that\n\t// owner is inactive — `listContributions` throws \"Contribution point is not\n\t// defined\". That state means \"no contributed skills\", not a failure: every\n\t// tool-registry change rebuilds the system prompt, so propagating the error\n\t// turned each rebuild into an error-level plugin.log record. Any other\n\t// failure still propagates.\n\tlet contributed: ReturnType<typeof runtime.listContributions>;\n\ttry {\n\t\tcontributed = runtime.listContributions(SKILL_CONTRIBUTION_POINT_ID, SKILL_CONTRIBUTION_POINT_VERSION);\n\t} catch (error) {\n\t\tif (!(error instanceof Error) || !error.message.startsWith(\"Contribution point is not defined\")) throw error;\n\t\treturn [];\n\t}\n\tconst contributedSkills = contributed\n\t\t.filter(\n\t\t\t(entry): entry is typeof entry & { value: Skill } =>\n\t\t\t\tentry.value !== null && typeof entry.value === \"object\" && \"name\" in entry.value,\n\t\t)\n\t\t.map((entry) => ({\n\t\t\t...entry.value,\n\t\t\tdisableModelInvocation: entry.value.disableModelInvocation === true,\n\t\t\tsourceInfo: createSyntheticSourceInfo(`<contribution:${entry.owner}:${entry.id}>`, {\n\t\t\t\tsource: entry.owner,\n\t\t\t\tbaseDir: entry.value.baseDir,\n\t\t\t}),\n\t\t}));\n\tconst contributedNames = new Set(contributedSkills.map((skill) => skill.name));\n\tconst legacyFilter = session._capabilitySkillsFilter;\n\tconst legacy = runtime\n\t\t.listSkills()\n\t\t.filter(({ definition }) => !contributedNames.has(definition.name))\n\t\t.map(({ definition, source }) => ({\n\t\t\t...definition,\n\t\t\tdisableModelInvocation: definition.disableModelInvocation === true,\n\t\t\tsourceInfo: createSyntheticSourceInfo(`<plugin:${source}:${definition.name}>`, {\n\t\t\t\tsource,\n\t\t\t\tbaseDir: definition.baseDir,\n\t\t\t}),\n\t\t}))\n\t\t// Suite association filtering (方案系统 M3): the assembler owns the\n\t\t// policy; the session only applies the injected function. The\n\t\t// bootstrap-skills contribution face is already loader-filtered and\n\t\t// must not be filtered twice.\n\t\t.filter((skill) => (legacyFilter ? legacyFilter([skill]).length > 0 : true));\n\treturn [...contributedSkills, ...legacy].sort(\n\t\t(left, right) => left.name.localeCompare(right.name) || left.sourceInfo.path.localeCompare(right.sourceInfo.path),\n\t);\n}\n\nexport function validateCapabilitySkillConflicts(session: AgentSessionInternals): void {\n\tconst resourceNames = new Set<string>();\n\tconst resourceFilePaths = new Set<string>();\n\tfor (const skill of session._resourceLoader.getSkills().skills) {\n\t\tif (resourceNames.has(skill.name))\n\t\t\tthrow new Error(t(\"Skill is duplicated in resources: {name}\", { name: skill.name }));\n\t\tresourceNames.add(skill.name);\n\t\tresourceFilePaths.add(skill.filePath);\n\t}\n\tfor (const skill of session._getCapabilitySkills()) {\n\t\t// bootstrap-skills mirrors the same on-disk SKILL.md into the capability\n\t\t// layer: same name AND same file is one skill seen through two channels,\n\t\t// not a conflict. Same name from a different file (e.g. an MCP server\n\t\t// contributing a skill that collides with a disk skill) is a real one.\n\t\tif (typeof skill.filePath === \"string\" && resourceFilePaths.has(skill.filePath)) continue;\n\t\tif (resourceNames.has(skill.name))\n\t\t\tthrow new Error(t(\"Skill conflicts with a resource skill: {name}\", { name: skill.name }));\n\t}\n}\n\nexport async function refreshBootstrapSkills(session: AgentSessionInternals): Promise<void> {\n\tconst runtime = session._capabilityRuntime;\n\tif (!runtime) return;\n\tsession._validateCapabilitySkillConflicts();\n\tif (session._bootstrapSkillsHandle) {\n\t\tawait refreshSessionBootstrapSkills(runtime, session._resourceLoader.getSkills().skills);\n\t} else {\n\t\tsession._bootstrapSkillsHandle = installSessionBootstrapSkills(\n\t\t\truntime,\n\t\t\tsession._resourceLoader.getSkills().skills,\n\t\t);\n\t}\n\tsession._baseSystemPrompt = session._rebuildSystemPrompt(session.getActiveToolNames());\n\tsession.agent.state.systemPrompt = session._baseSystemPrompt;\n}\n"]}
@@ -39,6 +39,7 @@ import type { SessionStartMetadata } from "./session-start.ts";
39
39
  import type { SettingsManager } from "./settings-manager.ts";
40
40
  import type { Skill } from "./skills.ts";
41
41
  import type { BashOperations } from "./tools/bash-operations.ts";
42
+ import { type DeferredCapabilityCardV1 } from "./tools/capability-mount.ts";
42
43
  import type { ToolDefinition, ToolInfo } from "./tools/tool-definition.ts";
43
44
  /** Parsed skill block from a user message */
44
45
  export interface ParsedSkillBlock {
@@ -187,6 +188,16 @@ export interface AgentSessionConfig {
187
188
  * setActiveTools) overrides the deferral.
188
189
  */
189
190
  deferredToolPluginIds?: readonly string[];
191
+ /**
192
+ * On-demand capability cards (插件按需挂载与能力手册设计 §4/§5): manifests
193
+ * declaring `activation: "on-demand"` surface here. Registers the
194
+ * capability_mount / capability_unmount pair; the system prompt carries a
195
+ * one-line card per still-deferred capability, and mounting returns the
196
+ * plugin's AI manual. Cards may also arrive after construction through
197
+ * {@link registerDeferredCapabilityCards} (the sdk assembly resolves them
198
+ * once the plugin pool settles).
199
+ */
200
+ deferredCapabilityCards?: readonly DeferredCapabilityCardV1[];
190
201
  /**
191
202
  * Bootstrap plugin ids to SKIP at session construction (宪法 §1: bootstrap
192
203
  * 插件可禁用)。Id values are the exported BOOTSTRAP_*_PLUGIN_ID constants
@@ -466,6 +477,8 @@ export declare class AgentSession {
466
477
  private _resourceLoader;
467
478
  private _customTools;
468
479
  private _deferredToolPluginIds;
480
+ private _deferredCapabilityCards;
481
+ private _capabilityMountToolsRegistered;
469
482
  /** Abort reason supplied to the in-flight abort(); consumed by the interruption marker. */
470
483
  private _pendingAbortReason;
471
484
  /** Set when the in-flight prompt run produced an aborted terminal assistant turn. */
@@ -1048,6 +1061,17 @@ export declare class AgentSession {
1048
1061
  private buildExtensionResourcePaths;
1049
1062
  private getExtensionSourceLabel;
1050
1063
  private _refreshToolRegistry;
1064
+ /** Registry tool names whose owning capability plugin is `pluginId`. */
1065
+ private _toolNamesForPlugin;
1066
+ private _readManual;
1067
+ private _createCapabilityMountTools;
1068
+ /**
1069
+ * Register on-demand capability cards after construction (插件按需挂载与能力手册设计 §4).
1070
+ * The sdk assembly calls this once the plugin pool settles, before loading;
1071
+ * first call also injects the capability_mount / capability_unmount pair.
1072
+ * Idempotent: later calls replace the card set.
1073
+ */
1074
+ registerDeferredCapabilityCards(cards: readonly DeferredCapabilityCardV1[]): void;
1051
1075
  private _syncCapabilityTools;
1052
1076
  private _getCapabilitySkills;
1053
1077
  private _getAvailableSkills;