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

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 (143) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/bundled-plugins/agent-loop-policy/agent-forge.json +1 -1
  3. package/bundled-plugins/agent-loop-policy/plugin.json +1 -1
  4. package/bundled-plugins/coding-tools/agent-forge.json +1 -1
  5. package/bundled-plugins/coding-tools/plugin.json +1 -1
  6. package/bundled-plugins/compaction-policy/agent-forge.json +1 -1
  7. package/bundled-plugins/compaction-policy/plugin.json +1 -1
  8. package/bundled-plugins/overflow-policy/agent-forge.json +1 -1
  9. package/bundled-plugins/overflow-policy/plugin.json +1 -1
  10. package/bundled-plugins/provider-failover/agent-forge.json +1 -1
  11. package/bundled-plugins/provider-failover/plugin.json +1 -1
  12. package/bundled-plugins/retry-policy/agent-forge.json +1 -1
  13. package/bundled-plugins/retry-policy/plugin.json +1 -1
  14. package/dist/bundle/.build-manifest.json +68 -58
  15. package/dist/bundle/chunks/{chunk-D3ARGZFR.js → chunk-44I47ACN.js} +3 -3
  16. package/dist/bundle/chunks/{chunk-Z72JWUZ4.js → chunk-6F5JWGKE.js} +1 -1
  17. package/dist/bundle/chunks/{chunk-LZOEQITZ.js → chunk-HTC5K5SM.js} +56 -45
  18. package/dist/bundle/chunks/{chunk-AQLNTW2B.js → chunk-LSP24WNH.js} +8 -7
  19. package/dist/bundle/chunks/image-resize-worker.js +3 -3
  20. package/dist/bundle/chunks/{virtual-modules-WF6WRHP7.js → virtual-modules-MRXD3RWG.js} +1 -1
  21. package/dist/bundle/cli.js +1 -1
  22. package/dist/bundle/client.js +1 -1
  23. package/dist/bundle/index.js +1 -1
  24. package/dist/bundle/rpc-entry.js +1 -1
  25. package/dist/cli/plugin-command.d.ts.map +1 -1
  26. package/dist/cli/plugin-command.js +8 -2
  27. package/dist/cli/plugin-command.js.map +1 -1
  28. package/dist/core/agent-session-internal.d.ts +2 -0
  29. package/dist/core/agent-session-internal.d.ts.map +1 -1
  30. package/dist/core/agent-session-internal.js.map +1 -1
  31. package/dist/core/agent-session-services.d.ts +2 -0
  32. package/dist/core/agent-session-services.d.ts.map +1 -1
  33. package/dist/core/agent-session-services.js +1 -0
  34. package/dist/core/agent-session-services.js.map +1 -1
  35. package/dist/core/agent-session-store.d.ts.map +1 -1
  36. package/dist/core/agent-session-store.js +6 -1
  37. package/dist/core/agent-session-store.js.map +1 -1
  38. package/dist/core/agent-session-tools.d.ts.map +1 -1
  39. package/dist/core/agent-session-tools.js +13 -0
  40. package/dist/core/agent-session-tools.js.map +1 -1
  41. package/dist/core/agent-session.d.ts +24 -0
  42. package/dist/core/agent-session.d.ts.map +1 -1
  43. package/dist/core/agent-session.js +58 -4
  44. package/dist/core/agent-session.js.map +1 -1
  45. package/dist/core/i18n/locales/zh-cn/cli.d.ts.map +1 -1
  46. package/dist/core/i18n/locales/zh-cn/cli.js +2 -0
  47. package/dist/core/i18n/locales/zh-cn/cli.js.map +1 -1
  48. package/dist/core/i18n/locales/zh-cn/index.d.ts.map +1 -1
  49. package/dist/core/i18n/locales/zh-cn/index.js +2 -0
  50. package/dist/core/i18n/locales/zh-cn/index.js.map +1 -1
  51. package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts.map +1 -1
  52. package/dist/core/i18n/locales/zh-cn/interactive-mode.js +5 -0
  53. package/dist/core/i18n/locales/zh-cn/interactive-mode.js.map +1 -1
  54. package/dist/core/i18n/locales/zh-cn/session-cleanup.d.ts +7 -0
  55. package/dist/core/i18n/locales/zh-cn/session-cleanup.d.ts.map +1 -0
  56. package/dist/core/i18n/locales/zh-cn/session-cleanup.js +15 -0
  57. package/dist/core/i18n/locales/zh-cn/session-cleanup.js.map +1 -0
  58. package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts.map +1 -1
  59. package/dist/core/i18n/locales/zh-cn/slash-commands.js +1 -0
  60. package/dist/core/i18n/locales/zh-cn/slash-commands.js.map +1 -1
  61. package/dist/core/sdk.d.ts.map +1 -1
  62. package/dist/core/sdk.js +24 -1
  63. package/dist/core/sdk.js.map +1 -1
  64. package/dist/core/session-cleanup.d.ts +49 -0
  65. package/dist/core/session-cleanup.d.ts.map +1 -0
  66. package/dist/core/session-cleanup.js +159 -0
  67. package/dist/core/session-cleanup.js.map +1 -0
  68. package/dist/core/session-index.d.ts +75 -0
  69. package/dist/core/session-index.d.ts.map +1 -0
  70. package/dist/core/session-index.js +455 -0
  71. package/dist/core/session-index.js.map +1 -0
  72. package/dist/core/session-manager.d.ts +9 -0
  73. package/dist/core/session-manager.d.ts.map +1 -1
  74. package/dist/core/session-manager.js +202 -47
  75. package/dist/core/session-manager.js.map +1 -1
  76. package/dist/core/slash-commands.d.ts.map +1 -1
  77. package/dist/core/slash-commands.js +5 -0
  78. package/dist/core/slash-commands.js.map +1 -1
  79. package/dist/core/system-prompt.d.ts.map +1 -1
  80. package/dist/core/system-prompt.js +12 -1
  81. package/dist/core/system-prompt.js.map +1 -1
  82. package/dist/core/tools/capability-mount.d.ts +40 -0
  83. package/dist/core/tools/capability-mount.d.ts.map +1 -0
  84. package/dist/core/tools/capability-mount.js +112 -0
  85. package/dist/core/tools/capability-mount.js.map +1 -0
  86. package/dist/main.d.ts.map +1 -1
  87. package/dist/main.js +1 -0
  88. package/dist/main.js.map +1 -1
  89. package/dist/modes/interactive/components/assistant-message.d.ts +3 -0
  90. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  91. package/dist/modes/interactive/components/assistant-message.js +27 -5
  92. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  93. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  94. package/dist/modes/interactive/components/session-selector-search.js +5 -1
  95. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  96. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  97. package/dist/modes/interactive/components/session-selector.js +9 -0
  98. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  99. package/dist/modes/interactive/components/tool-execution.d.ts +17 -0
  100. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  101. package/dist/modes/interactive/components/tool-execution.js +43 -0
  102. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  103. package/dist/modes/interactive/components/tool-run-group.d.ts +44 -0
  104. package/dist/modes/interactive/components/tool-run-group.d.ts.map +1 -0
  105. package/dist/modes/interactive/components/tool-run-group.js +121 -0
  106. package/dist/modes/interactive/components/tool-run-group.js.map +1 -0
  107. package/dist/modes/interactive/interactive-commands.d.ts +2 -0
  108. package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
  109. package/dist/modes/interactive/interactive-commands.js +7 -0
  110. package/dist/modes/interactive/interactive-commands.js.map +1 -1
  111. package/dist/modes/interactive/interactive-mode.d.ts +18 -0
  112. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  113. package/dist/modes/interactive/interactive-mode.js +85 -3
  114. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  115. package/dist/plugins/ecosystem/cli.d.ts.map +1 -1
  116. package/dist/plugins/ecosystem/cli.js +6 -3
  117. package/dist/plugins/ecosystem/cli.js.map +1 -1
  118. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts +7 -1
  119. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts.map +1 -1
  120. package/dist/plugins/ecosystem/node-plugin-bootstrap.js +50 -3
  121. package/dist/plugins/ecosystem/node-plugin-bootstrap.js.map +1 -1
  122. package/dist/plugins/ecosystem/plugin-bootstrap.d.ts +28 -16
  123. package/dist/plugins/ecosystem/plugin-bootstrap.d.ts.map +1 -1
  124. package/dist/plugins/ecosystem/plugin-bootstrap.js +35 -33
  125. package/dist/plugins/ecosystem/plugin-bootstrap.js.map +1 -1
  126. package/dist/profile/plugin-profiles.d.ts +1 -1
  127. package/dist/profile/plugin-profiles.d.ts.map +1 -1
  128. package/dist/profile/plugin-profiles.js +18 -0
  129. package/dist/profile/plugin-profiles.js.map +1 -1
  130. package/dist/profiles/builtin-suites.d.ts +14 -4
  131. package/dist/profiles/builtin-suites.d.ts.map +1 -1
  132. package/dist/profiles/builtin-suites.js +20 -5
  133. package/dist/profiles/builtin-suites.js.map +1 -1
  134. package/docs/settings.md +354 -354
  135. package/docs/usage.md +292 -292
  136. package/examples/extensions/with-deps/package-lock.json +2 -2
  137. package/examples/extensions/with-deps/package.json +1 -1
  138. package/examples/extensions/with-deps/plugin.json +1 -1
  139. package/package.json +1 -1
  140. package/examples/extensions/mcp-stdio/index.d.ts +0 -64
  141. package/examples/extensions/mcp-stdio/index.d.ts.map +0 -1
  142. package/examples/extensions/mcp-stdio/index.js +0 -292
  143. package/examples/extensions/mcp-stdio/index.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"slash-commands.d.ts","sourceRoot":"","sources":["../../src/core/slash-commands.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;AAElE,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,UAAU,EAAE,UAAU,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,sBAAsB,EAAE,aAAa,CAAC,mBAAmB,CAiErE,CAAC","sourcesContent":["import { APP_NAME } from \"../config.ts\";\nimport { t } from \"./i18n/index.ts\";\nimport type { SourceInfo } from \"./source-info.ts\";\n\nexport type SlashCommandSource = \"extension\" | \"prompt\" | \"skill\";\n\nexport interface SlashCommandInfo {\n\tname: string;\n\tdescription?: string;\n\tsource: SlashCommandSource;\n\tsourceInfo: SourceInfo;\n}\n\nexport interface BuiltinSlashCommand {\n\tname: string;\n\tdescription: string;\n\targumentHint?: string;\n}\n\nexport const BUILTIN_SLASH_COMMANDS: ReadonlyArray<BuiltinSlashCommand> = [\n\t{ name: \"settings\", description: t(\"Open settings menu\") },\n\t{\n\t\tname: \"model\",\n\t\tdescription: t(\"Select model (opens selector UI)\"),\n\t\targumentHint: t(\"<provider/model>\"),\n\t},\n\t{ name: \"tree\", description: t(\"Navigate session tree (switch branches)\") },\n\t{ name: \"thinking\", description: t(\"Set thinking level\"), argumentHint: t(\"<level>\") },\n\t{\n\t\tname: \"suite\",\n\t\tdescription: t(\"Set the active suite (takes effect in new sessions)\"),\n\t\targumentHint: t(\"[id]\"),\n\t},\n\t{ name: \"scoped-models\", description: t(\"Enable/disable models in the /model cycling scope\") },\n\t{ name: \"export\", description: t(\"Export session (HTML default, or specify path: .html/.jsonl)\") },\n\t{ name: \"import\", description: t(\"Import and resume a session from a JSONL file\") },\n\t{ name: \"copy\", description: t(\"Copy last agent message to clipboard\") },\n\t{ name: \"name\", description: t(\"Set session display name\") },\n\t{ name: \"session\", description: t(\"Show session info and stats\") },\n\t{\n\t\tname: \"metrics\",\n\t\tdescription: t(\"Show product metrics (turns, tools, memory recall)\"),\n\t\targumentHint: t(\"[turns]\"),\n\t},\n\t{ name: \"changelog\", description: t(\"Show changelog entries\") },\n\t{ name: \"help\", description: t(\"Show available commands\") },\n\t{ name: \"hotkeys\", description: t(\"Show all keyboard shortcuts\") },\n\t{\n\t\tname: \"fork\",\n\t\tdescription: t(\"Return to any earlier prompt and continue from there (the original path stays as a branch)\"),\n\t},\n\t{ name: \"clone\", description: t(\"Duplicate the current session at the current position\") },\n\t{\n\t\tname: \"login\",\n\t\tdescription: t(\"Configure provider authentication\"),\n\t\targumentHint: t(\"<provider>\"),\n\t},\n\t{ name: \"logout\", description: t(\"Remove provider authentication\") },\n\t{ name: \"new\", description: t(\"Start a new session\") },\n\t{\n\t\tname: \"stop-agents\",\n\t\tdescription: t(\"Terminate all background subagents (Esc never touches them)\"),\n\t},\n\t{ name: \"compact\", description: t(\"Manually compact the session context\") },\n\t{ name: \"resume\", description: t(\"Resume a different session\") },\n\t{\n\t\tname: \"queue\",\n\t\tdescription: t(\"Queue a message for after the current run\"),\n\t\targumentHint: t(\"<text>\"),\n\t},\n\t{ name: \"dequeue\", description: t(\"Restore queued messages back to the editor\") },\n\t{ name: \"queue-list\", description: t(\"Open the queued messages manager\") },\n\t{ name: \"editor\", description: t(\"Edit the current input in an external editor\") },\n\t{ name: \"agents\", description: t(\"Browse this session's subagent sessions (read-only)\") },\n\t{\n\t\tname: \"reload\",\n\t\tdescription: t(\"Reload keybindings, extensions, skills, prompts, themes, and context files\"),\n\t},\n\t{\n\t\tname: \"promote\",\n\t\tdescription: t(\"Promote a memory preference to user-default (visible in every suite)\"),\n\t\targumentHint: t(\"<memoryId>\"),\n\t},\n\t{ name: \"quit\", description: t(\"Quit {app}\", { app: APP_NAME }) },\n];\n"]}
1
+ {"version":3,"file":"slash-commands.d.ts","sourceRoot":"","sources":["../../src/core/slash-commands.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;AAElE,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,UAAU,EAAE,UAAU,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,sBAAsB,EAAE,aAAa,CAAC,mBAAmB,CAsErE,CAAC","sourcesContent":["import { APP_NAME } from \"../config.ts\";\nimport { t } from \"./i18n/index.ts\";\nimport type { SourceInfo } from \"./source-info.ts\";\n\nexport type SlashCommandSource = \"extension\" | \"prompt\" | \"skill\";\n\nexport interface SlashCommandInfo {\n\tname: string;\n\tdescription?: string;\n\tsource: SlashCommandSource;\n\tsourceInfo: SourceInfo;\n}\n\nexport interface BuiltinSlashCommand {\n\tname: string;\n\tdescription: string;\n\targumentHint?: string;\n}\n\nexport const BUILTIN_SLASH_COMMANDS: ReadonlyArray<BuiltinSlashCommand> = [\n\t{ name: \"settings\", description: t(\"Open settings menu\") },\n\t{\n\t\tname: \"model\",\n\t\tdescription: t(\"Select model (opens selector UI)\"),\n\t\targumentHint: t(\"<provider/model>\"),\n\t},\n\t{ name: \"tree\", description: t(\"Navigate session tree (switch branches)\") },\n\t{ name: \"thinking\", description: t(\"Set thinking level\"), argumentHint: t(\"<level>\") },\n\t{\n\t\tname: \"suite\",\n\t\tdescription: t(\"Set the active suite (takes effect in new sessions)\"),\n\t\targumentHint: t(\"[id]\"),\n\t},\n\t{ name: \"scoped-models\", description: t(\"Enable/disable models in the /model cycling scope\") },\n\t{ name: \"export\", description: t(\"Export session (HTML default, or specify path: .html/.jsonl)\") },\n\t{ name: \"import\", description: t(\"Import and resume a session from a JSONL file\") },\n\t{ name: \"copy\", description: t(\"Copy last agent message to clipboard\") },\n\t{ name: \"name\", description: t(\"Set session display name\") },\n\t{ name: \"session\", description: t(\"Show session info and stats\") },\n\t{\n\t\tname: \"metrics\",\n\t\tdescription: t(\"Show product metrics (turns, tools, memory recall)\"),\n\t\targumentHint: t(\"[turns]\"),\n\t},\n\t{ name: \"changelog\", description: t(\"Show changelog entries\") },\n\t{ name: \"help\", description: t(\"Show available commands\") },\n\t{ name: \"hotkeys\", description: t(\"Show all keyboard shortcuts\") },\n\t{\n\t\tname: \"fork\",\n\t\tdescription: t(\"Return to any earlier prompt and continue from there (the original path stays as a branch)\"),\n\t},\n\t{ name: \"clone\", description: t(\"Duplicate the current session at the current position\") },\n\t{\n\t\tname: \"login\",\n\t\tdescription: t(\"Configure provider authentication\"),\n\t\targumentHint: t(\"<provider>\"),\n\t},\n\t{ name: \"logout\", description: t(\"Remove provider authentication\") },\n\t{ name: \"new\", description: t(\"Start a new session\") },\n\t{\n\t\tname: \"stop-agents\",\n\t\tdescription: t(\"Terminate all background subagents (Esc never touches them)\"),\n\t},\n\t{ name: \"compact\", description: t(\"Manually compact the session context\") },\n\t{ name: \"resume\", description: t(\"Resume a different session\") },\n\t{\n\t\tname: \"clean-sessions\",\n\t\tdescription: t(\"Delete session files untouched for N days to free disk space\"),\n\t\targumentHint: t(\"[days]\"),\n\t},\n\t{\n\t\tname: \"queue\",\n\t\tdescription: t(\"Queue a message for after the current run\"),\n\t\targumentHint: t(\"<text>\"),\n\t},\n\t{ name: \"dequeue\", description: t(\"Restore queued messages back to the editor\") },\n\t{ name: \"queue-list\", description: t(\"Open the queued messages manager\") },\n\t{ name: \"editor\", description: t(\"Edit the current input in an external editor\") },\n\t{ name: \"agents\", description: t(\"Browse this session's subagent sessions (read-only)\") },\n\t{\n\t\tname: \"reload\",\n\t\tdescription: t(\"Reload keybindings, extensions, skills, prompts, themes, and context files\"),\n\t},\n\t{\n\t\tname: \"promote\",\n\t\tdescription: t(\"Promote a memory preference to user-default (visible in every suite)\"),\n\t\targumentHint: t(\"<memoryId>\"),\n\t},\n\t{ name: \"quit\", description: t(\"Quit {app}\", { app: APP_NAME }) },\n];\n"]}
@@ -46,6 +46,11 @@ export const BUILTIN_SLASH_COMMANDS = [
46
46
  },
47
47
  { name: "compact", description: t("Manually compact the session context") },
48
48
  { name: "resume", description: t("Resume a different session") },
49
+ {
50
+ name: "clean-sessions",
51
+ description: t("Delete session files untouched for N days to free disk space"),
52
+ argumentHint: t("[days]"),
53
+ },
49
54
  {
50
55
  name: "queue",
51
56
  description: t("Queue a message for after the current run"),
@@ -1 +1 @@
1
- {"version":3,"file":"slash-commands.js","sourceRoot":"","sources":["../../src/core/slash-commands.ts"],"names":[],"mappings":"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","sourcesContent":["import { APP_NAME } from \"../config.ts\";\nimport { t } from \"./i18n/index.ts\";\nimport type { SourceInfo } from \"./source-info.ts\";\n\nexport type SlashCommandSource = \"extension\" | \"prompt\" | \"skill\";\n\nexport interface SlashCommandInfo {\n\tname: string;\n\tdescription?: string;\n\tsource: SlashCommandSource;\n\tsourceInfo: SourceInfo;\n}\n\nexport interface BuiltinSlashCommand {\n\tname: string;\n\tdescription: string;\n\targumentHint?: string;\n}\n\nexport const BUILTIN_SLASH_COMMANDS: ReadonlyArray<BuiltinSlashCommand> = [\n\t{ name: \"settings\", description: t(\"Open settings menu\") },\n\t{\n\t\tname: \"model\",\n\t\tdescription: t(\"Select model (opens selector UI)\"),\n\t\targumentHint: t(\"<provider/model>\"),\n\t},\n\t{ name: \"tree\", description: t(\"Navigate session tree (switch branches)\") },\n\t{ name: \"thinking\", description: t(\"Set thinking level\"), argumentHint: t(\"<level>\") },\n\t{\n\t\tname: \"suite\",\n\t\tdescription: t(\"Set the active suite (takes effect in new sessions)\"),\n\t\targumentHint: t(\"[id]\"),\n\t},\n\t{ name: \"scoped-models\", description: t(\"Enable/disable models in the /model cycling scope\") },\n\t{ name: \"export\", description: t(\"Export session (HTML default, or specify path: .html/.jsonl)\") },\n\t{ name: \"import\", description: t(\"Import and resume a session from a JSONL file\") },\n\t{ name: \"copy\", description: t(\"Copy last agent message to clipboard\") },\n\t{ name: \"name\", description: t(\"Set session display name\") },\n\t{ name: \"session\", description: t(\"Show session info and stats\") },\n\t{\n\t\tname: \"metrics\",\n\t\tdescription: t(\"Show product metrics (turns, tools, memory recall)\"),\n\t\targumentHint: t(\"[turns]\"),\n\t},\n\t{ name: \"changelog\", description: t(\"Show changelog entries\") },\n\t{ name: \"help\", description: t(\"Show available commands\") },\n\t{ name: \"hotkeys\", description: t(\"Show all keyboard shortcuts\") },\n\t{\n\t\tname: \"fork\",\n\t\tdescription: t(\"Return to any earlier prompt and continue from there (the original path stays as a branch)\"),\n\t},\n\t{ name: \"clone\", description: t(\"Duplicate the current session at the current position\") },\n\t{\n\t\tname: \"login\",\n\t\tdescription: t(\"Configure provider authentication\"),\n\t\targumentHint: t(\"<provider>\"),\n\t},\n\t{ name: \"logout\", description: t(\"Remove provider authentication\") },\n\t{ name: \"new\", description: t(\"Start a new session\") },\n\t{\n\t\tname: \"stop-agents\",\n\t\tdescription: t(\"Terminate all background subagents (Esc never touches them)\"),\n\t},\n\t{ name: \"compact\", description: t(\"Manually compact the session context\") },\n\t{ name: \"resume\", description: t(\"Resume a different session\") },\n\t{\n\t\tname: \"queue\",\n\t\tdescription: t(\"Queue a message for after the current run\"),\n\t\targumentHint: t(\"<text>\"),\n\t},\n\t{ name: \"dequeue\", description: t(\"Restore queued messages back to the editor\") },\n\t{ name: \"queue-list\", description: t(\"Open the queued messages manager\") },\n\t{ name: \"editor\", description: t(\"Edit the current input in an external editor\") },\n\t{ name: \"agents\", description: t(\"Browse this session's subagent sessions (read-only)\") },\n\t{\n\t\tname: \"reload\",\n\t\tdescription: t(\"Reload keybindings, extensions, skills, prompts, themes, and context files\"),\n\t},\n\t{\n\t\tname: \"promote\",\n\t\tdescription: t(\"Promote a memory preference to user-default (visible in every suite)\"),\n\t\targumentHint: t(\"<memoryId>\"),\n\t},\n\t{ name: \"quit\", description: t(\"Quit {app}\", { app: APP_NAME }) },\n];\n"]}
1
+ {"version":3,"file":"slash-commands.js","sourceRoot":"","sources":["../../src/core/slash-commands.ts"],"names":[],"mappings":"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","sourcesContent":["import { APP_NAME } from \"../config.ts\";\nimport { t } from \"./i18n/index.ts\";\nimport type { SourceInfo } from \"./source-info.ts\";\n\nexport type SlashCommandSource = \"extension\" | \"prompt\" | \"skill\";\n\nexport interface SlashCommandInfo {\n\tname: string;\n\tdescription?: string;\n\tsource: SlashCommandSource;\n\tsourceInfo: SourceInfo;\n}\n\nexport interface BuiltinSlashCommand {\n\tname: string;\n\tdescription: string;\n\targumentHint?: string;\n}\n\nexport const BUILTIN_SLASH_COMMANDS: ReadonlyArray<BuiltinSlashCommand> = [\n\t{ name: \"settings\", description: t(\"Open settings menu\") },\n\t{\n\t\tname: \"model\",\n\t\tdescription: t(\"Select model (opens selector UI)\"),\n\t\targumentHint: t(\"<provider/model>\"),\n\t},\n\t{ name: \"tree\", description: t(\"Navigate session tree (switch branches)\") },\n\t{ name: \"thinking\", description: t(\"Set thinking level\"), argumentHint: t(\"<level>\") },\n\t{\n\t\tname: \"suite\",\n\t\tdescription: t(\"Set the active suite (takes effect in new sessions)\"),\n\t\targumentHint: t(\"[id]\"),\n\t},\n\t{ name: \"scoped-models\", description: t(\"Enable/disable models in the /model cycling scope\") },\n\t{ name: \"export\", description: t(\"Export session (HTML default, or specify path: .html/.jsonl)\") },\n\t{ name: \"import\", description: t(\"Import and resume a session from a JSONL file\") },\n\t{ name: \"copy\", description: t(\"Copy last agent message to clipboard\") },\n\t{ name: \"name\", description: t(\"Set session display name\") },\n\t{ name: \"session\", description: t(\"Show session info and stats\") },\n\t{\n\t\tname: \"metrics\",\n\t\tdescription: t(\"Show product metrics (turns, tools, memory recall)\"),\n\t\targumentHint: t(\"[turns]\"),\n\t},\n\t{ name: \"changelog\", description: t(\"Show changelog entries\") },\n\t{ name: \"help\", description: t(\"Show available commands\") },\n\t{ name: \"hotkeys\", description: t(\"Show all keyboard shortcuts\") },\n\t{\n\t\tname: \"fork\",\n\t\tdescription: t(\"Return to any earlier prompt and continue from there (the original path stays as a branch)\"),\n\t},\n\t{ name: \"clone\", description: t(\"Duplicate the current session at the current position\") },\n\t{\n\t\tname: \"login\",\n\t\tdescription: t(\"Configure provider authentication\"),\n\t\targumentHint: t(\"<provider>\"),\n\t},\n\t{ name: \"logout\", description: t(\"Remove provider authentication\") },\n\t{ name: \"new\", description: t(\"Start a new session\") },\n\t{\n\t\tname: \"stop-agents\",\n\t\tdescription: t(\"Terminate all background subagents (Esc never touches them)\"),\n\t},\n\t{ name: \"compact\", description: t(\"Manually compact the session context\") },\n\t{ name: \"resume\", description: t(\"Resume a different session\") },\n\t{\n\t\tname: \"clean-sessions\",\n\t\tdescription: t(\"Delete session files untouched for N days to free disk space\"),\n\t\targumentHint: t(\"[days]\"),\n\t},\n\t{\n\t\tname: \"queue\",\n\t\tdescription: t(\"Queue a message for after the current run\"),\n\t\targumentHint: t(\"<text>\"),\n\t},\n\t{ name: \"dequeue\", description: t(\"Restore queued messages back to the editor\") },\n\t{ name: \"queue-list\", description: t(\"Open the queued messages manager\") },\n\t{ name: \"editor\", description: t(\"Edit the current input in an external editor\") },\n\t{ name: \"agents\", description: t(\"Browse this session's subagent sessions (read-only)\") },\n\t{\n\t\tname: \"reload\",\n\t\tdescription: t(\"Reload keybindings, extensions, skills, prompts, themes, and context files\"),\n\t},\n\t{\n\t\tname: \"promote\",\n\t\tdescription: t(\"Promote a memory preference to user-default (visible in every suite)\"),\n\t\targumentHint: t(\"<memoryId>\"),\n\t},\n\t{ name: \"quit\", description: t(\"Quit {app}\", { app: APP_NAME }) },\n];\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAexE,YAAY,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEhG,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CA0L3E","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport type { BuildSystemPromptOptions } from \"@agent-forge/plugin-sdk\";\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.ts\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.ts\";\n\n// Capability tool guides (memory / task management) moved to their owning\n// plugins in D-071 (the memory capability itself moved to the\n// @agent-forge/plugin-memory package in D-075 S4-4): the plugin's\n// MEMORY_TOOLS_GUIDE rides memory_recall's promptGuidelines and the goal\n// plugin's TASK_TOOLS_GUIDE rides goal_set's (宪法 §3 — prompt text lives with\n// the plugin that owns the tools). The kernel composes whatever the active\n// tools declare.\n\n// BuildSystemPromptOptions authority moved to @agent-forge/plugin-sdk\n// (D-075 S2); re-exported here so existing consumers keep resolving. The SDK\n// type projects skills structurally; hosts always pass their full Skill objects.\nexport type { BuildSystemPromptOptions, BuildSystemPromptSkill } from \"@agent-forge/plugin-sdk\";\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n\tconst {\n\t\tcustomPrompt,\n\t\torientationPrompt,\n\t\tpreferenceCard,\n\t\tselectedTools,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst promptCwd = cwd.replace(/\\\\/g, \"/\");\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\tconst orientationSection = orientationPrompt ? `\\n\\n${orientationPrompt}` : \"\";\n\tconst preferenceCardSection = preferenceCard ? `\\n\\n${preferenceCard}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\t// SDK options type projects skills structurally; narrow to the host Skill\n\t// for the formatter (D-075 S2 move).\n\tconst skills = (providedSkills as Skill[] | undefined) ?? [];\n\tconst tools = selectedTools || [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst skillFileReadTool = ([\"read\", \"bash\"] as const).find((tool) => tools.includes(tool));\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\t// The orientation is a session-nature declaration (设计 §6.2): it rides\n\t\t// the customPrompt branch too, ahead of the appended extras. The\n\t\t// preference card follows it (H2: same M2 injection pattern).\n\t\tif (orientationSection) {\n\t\t\tprompt += orientationSection;\n\t\t}\n\t\tif (preferenceCardSection) {\n\t\t\tprompt += preferenceCardSection;\n\t\t}\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t\t}\n\t\t\tprompt += \"</project_context>\\n\";\n\t\t}\n\n\t\t// Append skills when a tool capable of reading their files is available.\n\t\tif (skillFileReadTool && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills, skillFileReadTool);\n\t\t}\n\n\t\tprompt += `\\nCurrent working directory: ${promptCwd}\\n`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\t// Build tools list based on selected tools.\n\t// A tool appears in Available tools only when the caller provides a one-line snippet.\n\tconst visibleTools = tools.filter((name) => !!toolSnippets?.[name]);\n\tconst toolsList =\n\t\tvisibleTools.length > 0 ? visibleTools.map((name) => `- ${name}: ${toolSnippets![name]}`).join(\"\\n\") : \"(none)\";\n\n\t// Read-only tool surface (提示词设计宪法 §6 2026-10-02): when no known\n\t// mutating tool is active (--tools narrowing, readonly embeds), the intro\n\t// must not promise file editing and a work rule reframes execution requests\n\t// as change-plan requests. New mutating capability tools must be added here.\n\tconst MUTATING_TOOL_NAMES = new Set([\n\t\t\"write\",\n\t\t\"edit\",\n\t\t\"bash\",\n\t\t\"powershell\",\n\t\t\"process_exec\",\n\t\t\"workspace_write\",\n\t\t\"test_run\",\n\t\t\"formatter_linter_check\",\n\t\t\"desktop_execute\",\n\t\t\"image_edit\",\n\t]);\n\tconst readOnlySession = !tools.some((name) => MUTATING_TOOL_NAMES.has(name));\n\tconst introScope = readOnlySession\n\t\t? \"you complete the user's task in the current working directory by reading code and running non-mutating commands. This session has no tools that modify files or run state-changing commands, so you cannot make changes here\"\n\t\t: \"you complete the user's task in the current working directory by reading code, running commands, and editing or creating files\";\n\tconst readOnlyWorkRule = readOnlySession\n\t\t? \"\\n- Treat execution requests as requests for a change plan: this session cannot make changes, so when the task needs them, delivering the exact plan — which files, what edits, how to verify — completes the task; do not attempt workarounds for the missing tools.\"\n\t\t: \"\";\n\n\t// Build guidelines based on which tools are actually available\n\tconst guidelinesList: string[] = [];\n\tconst guidelinesSet = new Set<string>();\n\tconst addGuideline = (guideline: string): void => {\n\t\tif (guidelinesSet.has(guideline)) {\n\t\t\treturn;\n\t\t}\n\t\tguidelinesSet.add(guideline);\n\t\tguidelinesList.push(guideline);\n\t};\n\n\tconst hasBash = tools.includes(\"bash\");\n\tconst hasPowerShell = tools.includes(\"powershell\");\n\tconst hasGrep = tools.includes(\"grep\");\n\tconst hasFind = tools.includes(\"find\");\n\tconst hasLs = tools.includes(\"ls\");\n\n\t// File exploration guidelines\n\tif ((hasBash || hasPowerShell) && !hasGrep && !hasFind && !hasLs) {\n\t\tif (hasBash && hasPowerShell) {\n\t\t\taddGuideline(\"Use bash or PowerShell for file operations like listing, searching, and finding files\");\n\t\t} else if (hasPowerShell) {\n\t\t\taddGuideline(\"Use PowerShell for file operations like listing, searching, and finding files\");\n\t\t} else {\n\t\t\taddGuideline(\"Use bash for file operations like ls, rg, find\");\n\t\t}\n\t}\n\n\tfor (const guideline of promptGuidelines ?? []) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0) {\n\t\t\taddGuideline(normalized);\n\t\t}\n\t}\n\n\t// Always include this\n\taddGuideline(\"Show file paths clearly when working with files\");\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\tlet prompt = `You are Agent Forge, a coding agent: ${introScope}. Agent Forge is a minimal, extensible runtime: capabilities beyond the built-in tools come from installed plugins, skills, MCP servers, and CLI bridges — choose and compose them yourself when they serve the goal. The runtime defines only the readonly and full-control host modes; approval and safety policy belongs to the user's installed extensions, not to you.\n\nWork rules:\n- Work toward the stated outcome: start multi-step requests with a tool call, keep working through tools until the task is complete, and end with a summary of results — never with a plan or a promise of future work.\n- Make the smallest change that fully satisfies the task; add nothing unsolicited — no extra features, refactors, warnings, or disclaimers.\n- Report outcomes faithfully: failures with their output, skipped steps as skipped, finished and verified work as finished.\n- Lead replies with the outcome and keep only the evidence needed to assess it; drop filler.${readOnlyWorkRule}\n- The user's instructions and project context files take precedence over these defaults.${orientationSection}${preferenceCardSection}\n\nAvailable tools:\n${toolsList}\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.\n\nGuidelines:\n${guidelines}\n\nAgent Forge documentation (read only when the user asks about Agent Forge itself, its SDK, extensions, themes, skills, or TUI):\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- Examples: ${examplesPath} (extensions, custom tools, SDK)\n- When reading Agent Forge docs or examples, resolve docs/... under Additional docs and examples/... under Examples, not the current working directory\n- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), packages (docs/packages.md), environment variables (docs/environment-variables.md)\n- When working on Agent Forge topics, read the docs and examples, and follow .md cross-references before implementing\n- Always read the relevant .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t}\n\t\tprompt += \"</project_context>\\n\";\n\t}\n\n\t// Append skills when a tool capable of reading their files is available.\n\tif (skillFileReadTool && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills, skillFileReadTool);\n\t}\n\n\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\treturn prompt;\n}\n"]}
1
+ {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAexE,YAAY,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEhG,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CAuM3E","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport type { BuildSystemPromptOptions } from \"@agent-forge/plugin-sdk\";\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.ts\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.ts\";\n\n// Capability tool guides (memory / task management) moved to their owning\n// plugins in D-071 (the memory capability itself moved to the\n// @agent-forge/plugin-memory package in D-075 S4-4): the plugin's\n// MEMORY_TOOLS_GUIDE rides memory_recall's promptGuidelines and the goal\n// plugin's TASK_TOOLS_GUIDE rides goal_set's (宪法 §3 — prompt text lives with\n// the plugin that owns the tools). The kernel composes whatever the active\n// tools declare.\n\n// BuildSystemPromptOptions authority moved to @agent-forge/plugin-sdk\n// (D-075 S2); re-exported here so existing consumers keep resolving. The SDK\n// type projects skills structurally; hosts always pass their full Skill objects.\nexport type { BuildSystemPromptOptions, BuildSystemPromptSkill } from \"@agent-forge/plugin-sdk\";\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n\tconst {\n\t\tcustomPrompt,\n\t\torientationPrompt,\n\t\tpreferenceCard,\n\t\tselectedTools,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t\tcapabilityCards,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst promptCwd = cwd.replace(/\\\\/g, \"/\");\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\tconst orientationSection = orientationPrompt ? `\\n\\n${orientationPrompt}` : \"\";\n\tconst preferenceCardSection = preferenceCard ? `\\n\\n${preferenceCard}` : \"\";\n\t// Mountable capability cards (插件按需挂载与能力手册设计 §4): one line per\n\t// deferred on-demand plugin. capability_mount loads the full tool set and\n\t// returns the plugin's manual; mounted capabilities drop off this section\n\t// on the next prompt rebuild.\n\tconst capabilityCardsSection =\n\t\tcapabilityCards === undefined || capabilityCards.length === 0\n\t\t\t? \"\"\n\t\t\t: `\\n\\nMountable capabilities (deferred plugins; call capability_mount with the plugin id to load the full tool set and its usage manual):\\n${capabilityCards\n\t\t\t\t\t.map((card) => `- ${card.pluginId}${card.description ? `: ${card.description}` : \"\"}`)\n\t\t\t\t\t.join(\"\\n\")}`;\n\n\tconst contextFiles = providedContextFiles ?? [];\n\t// SDK options type projects skills structurally; narrow to the host Skill\n\t// for the formatter (D-075 S2 move).\n\tconst skills = (providedSkills as Skill[] | undefined) ?? [];\n\tconst tools = selectedTools || [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst skillFileReadTool = ([\"read\", \"bash\"] as const).find((tool) => tools.includes(tool));\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\t// The orientation is a session-nature declaration (设计 §6.2): it rides\n\t\t// the customPrompt branch too, ahead of the appended extras. The\n\t\t// preference card follows it (H2: same M2 injection pattern).\n\t\tif (orientationSection) {\n\t\t\tprompt += orientationSection;\n\t\t}\n\t\tif (preferenceCardSection) {\n\t\t\tprompt += preferenceCardSection;\n\t\t}\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\t\tprompt += capabilityCardsSection;\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t\t}\n\t\t\tprompt += \"</project_context>\\n\";\n\t\t}\n\n\t\t// Append skills when a tool capable of reading their files is available.\n\t\tif (skillFileReadTool && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills, skillFileReadTool);\n\t\t}\n\n\t\tprompt += `\\nCurrent working directory: ${promptCwd}\\n`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\t// Build tools list based on selected tools.\n\t// A tool appears in Available tools only when the caller provides a one-line snippet.\n\tconst visibleTools = tools.filter((name) => !!toolSnippets?.[name]);\n\tconst toolsList =\n\t\tvisibleTools.length > 0 ? visibleTools.map((name) => `- ${name}: ${toolSnippets![name]}`).join(\"\\n\") : \"(none)\";\n\n\t// Read-only tool surface (提示词设计宪法 §6 2026-10-02): when no known\n\t// mutating tool is active (--tools narrowing, readonly embeds), the intro\n\t// must not promise file editing and a work rule reframes execution requests\n\t// as change-plan requests. New mutating capability tools must be added here.\n\tconst MUTATING_TOOL_NAMES = new Set([\n\t\t\"write\",\n\t\t\"edit\",\n\t\t\"bash\",\n\t\t\"powershell\",\n\t\t\"process_exec\",\n\t\t\"workspace_write\",\n\t\t\"test_run\",\n\t\t\"formatter_linter_check\",\n\t\t\"desktop_execute\",\n\t\t\"image_edit\",\n\t]);\n\tconst readOnlySession = !tools.some((name) => MUTATING_TOOL_NAMES.has(name));\n\tconst introScope = readOnlySession\n\t\t? \"you complete the user's task in the current working directory by reading code and running non-mutating commands. This session has no tools that modify files or run state-changing commands, so you cannot make changes here\"\n\t\t: \"you complete the user's task in the current working directory by reading code, running commands, and editing or creating files\";\n\tconst readOnlyWorkRule = readOnlySession\n\t\t? \"\\n- Treat execution requests as requests for a change plan: this session cannot make changes, so when the task needs them, delivering the exact plan — which files, what edits, how to verify — completes the task; do not attempt workarounds for the missing tools.\"\n\t\t: \"\";\n\n\t// Build guidelines based on which tools are actually available\n\tconst guidelinesList: string[] = [];\n\tconst guidelinesSet = new Set<string>();\n\tconst addGuideline = (guideline: string): void => {\n\t\tif (guidelinesSet.has(guideline)) {\n\t\t\treturn;\n\t\t}\n\t\tguidelinesSet.add(guideline);\n\t\tguidelinesList.push(guideline);\n\t};\n\n\tconst hasBash = tools.includes(\"bash\");\n\tconst hasPowerShell = tools.includes(\"powershell\");\n\tconst hasGrep = tools.includes(\"grep\");\n\tconst hasFind = tools.includes(\"find\");\n\tconst hasLs = tools.includes(\"ls\");\n\n\t// File exploration guidelines\n\tif ((hasBash || hasPowerShell) && !hasGrep && !hasFind && !hasLs) {\n\t\tif (hasBash && hasPowerShell) {\n\t\t\taddGuideline(\"Use bash or PowerShell for file operations like listing, searching, and finding files\");\n\t\t} else if (hasPowerShell) {\n\t\t\taddGuideline(\"Use PowerShell for file operations like listing, searching, and finding files\");\n\t\t} else {\n\t\t\taddGuideline(\"Use bash for file operations like ls, rg, find\");\n\t\t}\n\t}\n\n\tfor (const guideline of promptGuidelines ?? []) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0) {\n\t\t\taddGuideline(normalized);\n\t\t}\n\t}\n\n\t// Always include this\n\taddGuideline(\"Show file paths clearly when working with files\");\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\tlet prompt = `You are Agent Forge, a coding agent: ${introScope}. Agent Forge is a minimal, extensible runtime: capabilities beyond the built-in tools come from installed plugins, skills, MCP servers, and CLI bridges — choose and compose them yourself when they serve the goal. The runtime defines only the readonly and full-control host modes; approval and safety policy belongs to the user's installed extensions, not to you.\n\nWork rules:\n- Work toward the stated outcome: start multi-step requests with a tool call, keep working through tools until the task is complete, and end with a summary of results — never with a plan or a promise of future work.\n- Make the smallest change that fully satisfies the task; add nothing unsolicited — no extra features, refactors, warnings, or disclaimers.\n- Report outcomes faithfully: failures with their output, skipped steps as skipped, finished and verified work as finished.\n- Lead replies with the outcome and keep only the evidence needed to assess it; drop filler.${readOnlyWorkRule}\n- The user's instructions and project context files take precedence over these defaults.${orientationSection}${preferenceCardSection}\n\nAvailable tools:\n${toolsList}\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.\n\nGuidelines:\n${guidelines}\n\nAgent Forge documentation (read only when the user asks about Agent Forge itself, its SDK, extensions, themes, skills, or TUI):\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- Examples: ${examplesPath} (extensions, custom tools, SDK)\n- When reading Agent Forge docs or examples, resolve docs/... under Additional docs and examples/... under Examples, not the current working directory\n- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), packages (docs/packages.md), environment variables (docs/environment-variables.md)\n- When working on Agent Forge topics, read the docs and examples, and follow .md cross-references before implementing\n- Always read the relevant .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\tprompt += capabilityCardsSection;\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t}\n\t\tprompt += \"</project_context>\\n\";\n\t}\n\n\t// Append skills when a tool capable of reading their files is available.\n\tif (skillFileReadTool && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills, skillFileReadTool);\n\t}\n\n\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\treturn prompt;\n}\n"]}
@@ -5,11 +5,20 @@ import { getDocsPath, getExamplesPath, getReadmePath } from "../config.js";
5
5
  import { formatSkillsForPrompt } from "./skills.js";
6
6
  /** Build the system prompt with tools, guidelines, and context */
7
7
  export function buildSystemPrompt(options) {
8
- const { customPrompt, orientationPrompt, preferenceCard, selectedTools, toolSnippets, promptGuidelines, appendSystemPrompt, cwd, contextFiles: providedContextFiles, skills: providedSkills, } = options;
8
+ const { customPrompt, orientationPrompt, preferenceCard, selectedTools, toolSnippets, promptGuidelines, capabilityCards, appendSystemPrompt, cwd, contextFiles: providedContextFiles, skills: providedSkills, } = options;
9
9
  const promptCwd = cwd.replace(/\\/g, "/");
10
10
  const appendSection = appendSystemPrompt ? `\n\n${appendSystemPrompt}` : "";
11
11
  const orientationSection = orientationPrompt ? `\n\n${orientationPrompt}` : "";
12
12
  const preferenceCardSection = preferenceCard ? `\n\n${preferenceCard}` : "";
13
+ // Mountable capability cards (插件按需挂载与能力手册设计 §4): one line per
14
+ // deferred on-demand plugin. capability_mount loads the full tool set and
15
+ // returns the plugin's manual; mounted capabilities drop off this section
16
+ // on the next prompt rebuild.
17
+ const capabilityCardsSection = capabilityCards === undefined || capabilityCards.length === 0
18
+ ? ""
19
+ : `\n\nMountable capabilities (deferred plugins; call capability_mount with the plugin id to load the full tool set and its usage manual):\n${capabilityCards
20
+ .map((card) => `- ${card.pluginId}${card.description ? `: ${card.description}` : ""}`)
21
+ .join("\n")}`;
13
22
  const contextFiles = providedContextFiles ?? [];
14
23
  // SDK options type projects skills structurally; narrow to the host Skill
15
24
  // for the formatter (D-075 S2 move).
@@ -30,6 +39,7 @@ export function buildSystemPrompt(options) {
30
39
  if (appendSection) {
31
40
  prompt += appendSection;
32
41
  }
42
+ prompt += capabilityCardsSection;
33
43
  // Append project context files
34
44
  if (contextFiles.length > 0) {
35
45
  prompt += "\n\n<project_context>\n\n";
@@ -141,6 +151,7 @@ Agent Forge documentation (read only when the user asks about Agent Forge itself
141
151
  if (appendSection) {
142
152
  prompt += appendSection;
143
153
  }
154
+ prompt += capabilityCardsSection;
144
155
  // Append project context files
145
156
  if (contextFiles.length > 0) {
146
157
  prompt += "\n\n<project_context>\n\n";
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport type { BuildSystemPromptOptions } from \"@agent-forge/plugin-sdk\";\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.ts\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.ts\";\n\n// Capability tool guides (memory / task management) moved to their owning\n// plugins in D-071 (the memory capability itself moved to the\n// @agent-forge/plugin-memory package in D-075 S4-4): the plugin's\n// MEMORY_TOOLS_GUIDE rides memory_recall's promptGuidelines and the goal\n// plugin's TASK_TOOLS_GUIDE rides goal_set's (宪法 §3 — prompt text lives with\n// the plugin that owns the tools). The kernel composes whatever the active\n// tools declare.\n\n// BuildSystemPromptOptions authority moved to @agent-forge/plugin-sdk\n// (D-075 S2); re-exported here so existing consumers keep resolving. The SDK\n// type projects skills structurally; hosts always pass their full Skill objects.\nexport type { BuildSystemPromptOptions, BuildSystemPromptSkill } from \"@agent-forge/plugin-sdk\";\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n\tconst {\n\t\tcustomPrompt,\n\t\torientationPrompt,\n\t\tpreferenceCard,\n\t\tselectedTools,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst promptCwd = cwd.replace(/\\\\/g, \"/\");\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\tconst orientationSection = orientationPrompt ? `\\n\\n${orientationPrompt}` : \"\";\n\tconst preferenceCardSection = preferenceCard ? `\\n\\n${preferenceCard}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\t// SDK options type projects skills structurally; narrow to the host Skill\n\t// for the formatter (D-075 S2 move).\n\tconst skills = (providedSkills as Skill[] | undefined) ?? [];\n\tconst tools = selectedTools || [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst skillFileReadTool = ([\"read\", \"bash\"] as const).find((tool) => tools.includes(tool));\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\t// The orientation is a session-nature declaration (设计 §6.2): it rides\n\t\t// the customPrompt branch too, ahead of the appended extras. The\n\t\t// preference card follows it (H2: same M2 injection pattern).\n\t\tif (orientationSection) {\n\t\t\tprompt += orientationSection;\n\t\t}\n\t\tif (preferenceCardSection) {\n\t\t\tprompt += preferenceCardSection;\n\t\t}\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t\t}\n\t\t\tprompt += \"</project_context>\\n\";\n\t\t}\n\n\t\t// Append skills when a tool capable of reading their files is available.\n\t\tif (skillFileReadTool && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills, skillFileReadTool);\n\t\t}\n\n\t\tprompt += `\\nCurrent working directory: ${promptCwd}\\n`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\t// Build tools list based on selected tools.\n\t// A tool appears in Available tools only when the caller provides a one-line snippet.\n\tconst visibleTools = tools.filter((name) => !!toolSnippets?.[name]);\n\tconst toolsList =\n\t\tvisibleTools.length > 0 ? visibleTools.map((name) => `- ${name}: ${toolSnippets![name]}`).join(\"\\n\") : \"(none)\";\n\n\t// Read-only tool surface (提示词设计宪法 §6 2026-10-02): when no known\n\t// mutating tool is active (--tools narrowing, readonly embeds), the intro\n\t// must not promise file editing and a work rule reframes execution requests\n\t// as change-plan requests. New mutating capability tools must be added here.\n\tconst MUTATING_TOOL_NAMES = new Set([\n\t\t\"write\",\n\t\t\"edit\",\n\t\t\"bash\",\n\t\t\"powershell\",\n\t\t\"process_exec\",\n\t\t\"workspace_write\",\n\t\t\"test_run\",\n\t\t\"formatter_linter_check\",\n\t\t\"desktop_execute\",\n\t\t\"image_edit\",\n\t]);\n\tconst readOnlySession = !tools.some((name) => MUTATING_TOOL_NAMES.has(name));\n\tconst introScope = readOnlySession\n\t\t? \"you complete the user's task in the current working directory by reading code and running non-mutating commands. This session has no tools that modify files or run state-changing commands, so you cannot make changes here\"\n\t\t: \"you complete the user's task in the current working directory by reading code, running commands, and editing or creating files\";\n\tconst readOnlyWorkRule = readOnlySession\n\t\t? \"\\n- Treat execution requests as requests for a change plan: this session cannot make changes, so when the task needs them, delivering the exact plan — which files, what edits, how to verify — completes the task; do not attempt workarounds for the missing tools.\"\n\t\t: \"\";\n\n\t// Build guidelines based on which tools are actually available\n\tconst guidelinesList: string[] = [];\n\tconst guidelinesSet = new Set<string>();\n\tconst addGuideline = (guideline: string): void => {\n\t\tif (guidelinesSet.has(guideline)) {\n\t\t\treturn;\n\t\t}\n\t\tguidelinesSet.add(guideline);\n\t\tguidelinesList.push(guideline);\n\t};\n\n\tconst hasBash = tools.includes(\"bash\");\n\tconst hasPowerShell = tools.includes(\"powershell\");\n\tconst hasGrep = tools.includes(\"grep\");\n\tconst hasFind = tools.includes(\"find\");\n\tconst hasLs = tools.includes(\"ls\");\n\n\t// File exploration guidelines\n\tif ((hasBash || hasPowerShell) && !hasGrep && !hasFind && !hasLs) {\n\t\tif (hasBash && hasPowerShell) {\n\t\t\taddGuideline(\"Use bash or PowerShell for file operations like listing, searching, and finding files\");\n\t\t} else if (hasPowerShell) {\n\t\t\taddGuideline(\"Use PowerShell for file operations like listing, searching, and finding files\");\n\t\t} else {\n\t\t\taddGuideline(\"Use bash for file operations like ls, rg, find\");\n\t\t}\n\t}\n\n\tfor (const guideline of promptGuidelines ?? []) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0) {\n\t\t\taddGuideline(normalized);\n\t\t}\n\t}\n\n\t// Always include this\n\taddGuideline(\"Show file paths clearly when working with files\");\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\tlet prompt = `You are Agent Forge, a coding agent: ${introScope}. Agent Forge is a minimal, extensible runtime: capabilities beyond the built-in tools come from installed plugins, skills, MCP servers, and CLI bridges — choose and compose them yourself when they serve the goal. The runtime defines only the readonly and full-control host modes; approval and safety policy belongs to the user's installed extensions, not to you.\n\nWork rules:\n- Work toward the stated outcome: start multi-step requests with a tool call, keep working through tools until the task is complete, and end with a summary of results — never with a plan or a promise of future work.\n- Make the smallest change that fully satisfies the task; add nothing unsolicited — no extra features, refactors, warnings, or disclaimers.\n- Report outcomes faithfully: failures with their output, skipped steps as skipped, finished and verified work as finished.\n- Lead replies with the outcome and keep only the evidence needed to assess it; drop filler.${readOnlyWorkRule}\n- The user's instructions and project context files take precedence over these defaults.${orientationSection}${preferenceCardSection}\n\nAvailable tools:\n${toolsList}\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.\n\nGuidelines:\n${guidelines}\n\nAgent Forge documentation (read only when the user asks about Agent Forge itself, its SDK, extensions, themes, skills, or TUI):\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- Examples: ${examplesPath} (extensions, custom tools, SDK)\n- When reading Agent Forge docs or examples, resolve docs/... under Additional docs and examples/... under Examples, not the current working directory\n- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), packages (docs/packages.md), environment variables (docs/environment-variables.md)\n- When working on Agent Forge topics, read the docs and examples, and follow .md cross-references before implementing\n- Always read the relevant .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t}\n\t\tprompt += \"</project_context>\\n\";\n\t}\n\n\t// Append skills when a tool capable of reading their files is available.\n\tif (skillFileReadTool && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills, skillFileReadTool);\n\t}\n\n\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\treturn prompt;\n}\n"]}
1
+ {"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport type { BuildSystemPromptOptions } from \"@agent-forge/plugin-sdk\";\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.ts\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.ts\";\n\n// Capability tool guides (memory / task management) moved to their owning\n// plugins in D-071 (the memory capability itself moved to the\n// @agent-forge/plugin-memory package in D-075 S4-4): the plugin's\n// MEMORY_TOOLS_GUIDE rides memory_recall's promptGuidelines and the goal\n// plugin's TASK_TOOLS_GUIDE rides goal_set's (宪法 §3 — prompt text lives with\n// the plugin that owns the tools). The kernel composes whatever the active\n// tools declare.\n\n// BuildSystemPromptOptions authority moved to @agent-forge/plugin-sdk\n// (D-075 S2); re-exported here so existing consumers keep resolving. The SDK\n// type projects skills structurally; hosts always pass their full Skill objects.\nexport type { BuildSystemPromptOptions, BuildSystemPromptSkill } from \"@agent-forge/plugin-sdk\";\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions): string {\n\tconst {\n\t\tcustomPrompt,\n\t\torientationPrompt,\n\t\tpreferenceCard,\n\t\tselectedTools,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t\tcapabilityCards,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst promptCwd = cwd.replace(/\\\\/g, \"/\");\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\tconst orientationSection = orientationPrompt ? `\\n\\n${orientationPrompt}` : \"\";\n\tconst preferenceCardSection = preferenceCard ? `\\n\\n${preferenceCard}` : \"\";\n\t// Mountable capability cards (插件按需挂载与能力手册设计 §4): one line per\n\t// deferred on-demand plugin. capability_mount loads the full tool set and\n\t// returns the plugin's manual; mounted capabilities drop off this section\n\t// on the next prompt rebuild.\n\tconst capabilityCardsSection =\n\t\tcapabilityCards === undefined || capabilityCards.length === 0\n\t\t\t? \"\"\n\t\t\t: `\\n\\nMountable capabilities (deferred plugins; call capability_mount with the plugin id to load the full tool set and its usage manual):\\n${capabilityCards\n\t\t\t\t\t.map((card) => `- ${card.pluginId}${card.description ? `: ${card.description}` : \"\"}`)\n\t\t\t\t\t.join(\"\\n\")}`;\n\n\tconst contextFiles = providedContextFiles ?? [];\n\t// SDK options type projects skills structurally; narrow to the host Skill\n\t// for the formatter (D-075 S2 move).\n\tconst skills = (providedSkills as Skill[] | undefined) ?? [];\n\tconst tools = selectedTools || [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst skillFileReadTool = ([\"read\", \"bash\"] as const).find((tool) => tools.includes(tool));\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\t// The orientation is a session-nature declaration (设计 §6.2): it rides\n\t\t// the customPrompt branch too, ahead of the appended extras. The\n\t\t// preference card follows it (H2: same M2 injection pattern).\n\t\tif (orientationSection) {\n\t\t\tprompt += orientationSection;\n\t\t}\n\t\tif (preferenceCardSection) {\n\t\t\tprompt += preferenceCardSection;\n\t\t}\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\t\tprompt += capabilityCardsSection;\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t\t}\n\t\t\tprompt += \"</project_context>\\n\";\n\t\t}\n\n\t\t// Append skills when a tool capable of reading their files is available.\n\t\tif (skillFileReadTool && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills, skillFileReadTool);\n\t\t}\n\n\t\tprompt += `\\nCurrent working directory: ${promptCwd}\\n`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\t// Build tools list based on selected tools.\n\t// A tool appears in Available tools only when the caller provides a one-line snippet.\n\tconst visibleTools = tools.filter((name) => !!toolSnippets?.[name]);\n\tconst toolsList =\n\t\tvisibleTools.length > 0 ? visibleTools.map((name) => `- ${name}: ${toolSnippets![name]}`).join(\"\\n\") : \"(none)\";\n\n\t// Read-only tool surface (提示词设计宪法 §6 2026-10-02): when no known\n\t// mutating tool is active (--tools narrowing, readonly embeds), the intro\n\t// must not promise file editing and a work rule reframes execution requests\n\t// as change-plan requests. New mutating capability tools must be added here.\n\tconst MUTATING_TOOL_NAMES = new Set([\n\t\t\"write\",\n\t\t\"edit\",\n\t\t\"bash\",\n\t\t\"powershell\",\n\t\t\"process_exec\",\n\t\t\"workspace_write\",\n\t\t\"test_run\",\n\t\t\"formatter_linter_check\",\n\t\t\"desktop_execute\",\n\t\t\"image_edit\",\n\t]);\n\tconst readOnlySession = !tools.some((name) => MUTATING_TOOL_NAMES.has(name));\n\tconst introScope = readOnlySession\n\t\t? \"you complete the user's task in the current working directory by reading code and running non-mutating commands. This session has no tools that modify files or run state-changing commands, so you cannot make changes here\"\n\t\t: \"you complete the user's task in the current working directory by reading code, running commands, and editing or creating files\";\n\tconst readOnlyWorkRule = readOnlySession\n\t\t? \"\\n- Treat execution requests as requests for a change plan: this session cannot make changes, so when the task needs them, delivering the exact plan — which files, what edits, how to verify — completes the task; do not attempt workarounds for the missing tools.\"\n\t\t: \"\";\n\n\t// Build guidelines based on which tools are actually available\n\tconst guidelinesList: string[] = [];\n\tconst guidelinesSet = new Set<string>();\n\tconst addGuideline = (guideline: string): void => {\n\t\tif (guidelinesSet.has(guideline)) {\n\t\t\treturn;\n\t\t}\n\t\tguidelinesSet.add(guideline);\n\t\tguidelinesList.push(guideline);\n\t};\n\n\tconst hasBash = tools.includes(\"bash\");\n\tconst hasPowerShell = tools.includes(\"powershell\");\n\tconst hasGrep = tools.includes(\"grep\");\n\tconst hasFind = tools.includes(\"find\");\n\tconst hasLs = tools.includes(\"ls\");\n\n\t// File exploration guidelines\n\tif ((hasBash || hasPowerShell) && !hasGrep && !hasFind && !hasLs) {\n\t\tif (hasBash && hasPowerShell) {\n\t\t\taddGuideline(\"Use bash or PowerShell for file operations like listing, searching, and finding files\");\n\t\t} else if (hasPowerShell) {\n\t\t\taddGuideline(\"Use PowerShell for file operations like listing, searching, and finding files\");\n\t\t} else {\n\t\t\taddGuideline(\"Use bash for file operations like ls, rg, find\");\n\t\t}\n\t}\n\n\tfor (const guideline of promptGuidelines ?? []) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0) {\n\t\t\taddGuideline(normalized);\n\t\t}\n\t}\n\n\t// Always include this\n\taddGuideline(\"Show file paths clearly when working with files\");\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\tlet prompt = `You are Agent Forge, a coding agent: ${introScope}. Agent Forge is a minimal, extensible runtime: capabilities beyond the built-in tools come from installed plugins, skills, MCP servers, and CLI bridges — choose and compose them yourself when they serve the goal. The runtime defines only the readonly and full-control host modes; approval and safety policy belongs to the user's installed extensions, not to you.\n\nWork rules:\n- Work toward the stated outcome: start multi-step requests with a tool call, keep working through tools until the task is complete, and end with a summary of results — never with a plan or a promise of future work.\n- Make the smallest change that fully satisfies the task; add nothing unsolicited — no extra features, refactors, warnings, or disclaimers.\n- Report outcomes faithfully: failures with their output, skipped steps as skipped, finished and verified work as finished.\n- Lead replies with the outcome and keep only the evidence needed to assess it; drop filler.${readOnlyWorkRule}\n- The user's instructions and project context files take precedence over these defaults.${orientationSection}${preferenceCardSection}\n\nAvailable tools:\n${toolsList}\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.\n\nGuidelines:\n${guidelines}\n\nAgent Forge documentation (read only when the user asks about Agent Forge itself, its SDK, extensions, themes, skills, or TUI):\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- Examples: ${examplesPath} (extensions, custom tools, SDK)\n- When reading Agent Forge docs or examples, resolve docs/... under Additional docs and examples/... under Examples, not the current working directory\n- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), packages (docs/packages.md), environment variables (docs/environment-variables.md)\n- When working on Agent Forge topics, read the docs and examples, and follow .md cross-references before implementing\n- Always read the relevant .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\tprompt += capabilityCardsSection;\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n<project_context>\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `<project_instructions path=\"${filePath}\">\\n${content}\\n</project_instructions>\\n\\n`;\n\t\t}\n\t\tprompt += \"</project_context>\\n\";\n\t}\n\n\t// Append skills when a tool capable of reading their files is available.\n\tif (skillFileReadTool && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills, skillFileReadTool);\n\t}\n\n\tprompt += `\\nCurrent working directory: ${promptCwd}`;\n\n\treturn prompt;\n}\n"]}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * capability_mount / capability_unmount: plugin-granular on-demand tool
3
+ * loading (插件按需挂载与能力手册设计 §5.2).
4
+ *
5
+ * Manifests declaring `activation: "on-demand"` register their tools into the
6
+ * registry but keep them out of the active set; the model sees a one-line
7
+ * capability card in the system prompt instead. `capability_mount` pulls the
8
+ * plugin's full tool set into the active surface (next request) and returns
9
+ * the plugin's AI manual; `capability_unmount` removes it from the active
10
+ * surface without touching any runtime state — session teardown remains the
11
+ * primary cleanup path. Kernel mechanism only: no plugin-specific branches.
12
+ */
13
+ import { Type } from "typebox";
14
+ import type { ToolDefinition } from "./tool-definition.ts";
15
+ export interface DeferredCapabilityCardV1 {
16
+ readonly pluginId: string;
17
+ /** One-line capability summary from the manifest `description` field. */
18
+ readonly description?: string;
19
+ /** Absolute path to the plugin's AI manual (manifest `manual`, resolved). */
20
+ readonly manualPath?: string;
21
+ }
22
+ export interface CapabilityMountDeps {
23
+ getCards(): readonly DeferredCapabilityCardV1[];
24
+ /** Registry tool names whose source is this plugin id. */
25
+ toolNamesForPlugin(pluginId: string): string[];
26
+ getActiveToolNames(): readonly string[];
27
+ setActiveToolsByName(toolNames: string[]): void;
28
+ readManual(path: string): Promise<string>;
29
+ }
30
+ export declare const CAPABILITY_MOUNT_TOOL_NAME = "capability_mount";
31
+ export declare const CAPABILITY_UNMOUNT_TOOL_NAME = "capability_unmount";
32
+ declare const mountParameters: Type.TObject<{
33
+ plugin: Type.TString;
34
+ }>;
35
+ declare const unmountParameters: Type.TObject<{
36
+ plugin: Type.TString;
37
+ }>;
38
+ export declare function createCapabilityMountTools(deps: CapabilityMountDeps): readonly [ToolDefinition<typeof mountParameters>, ToolDefinition<typeof unmountParameters>];
39
+ export {};
40
+ //# sourceMappingURL=capability-mount.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-mount.d.ts","sourceRoot":"","sources":["../../../src/core/tools/capability-mount.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,6EAA6E;IAC7E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IACnC,QAAQ,IAAI,SAAS,wBAAwB,EAAE,CAAC;IAChD,0DAA0D;IAC1D,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC/C,kBAAkB,IAAI,SAAS,MAAM,EAAE,CAAC;IACxC,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAChD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC1C;AAID,eAAO,MAAM,0BAA0B,qBAAqB,CAAC;AAC7D,eAAO,MAAM,4BAA4B,uBAAuB,CAAC;AAEjE,QAAA,MAAM,eAAe;;EAInB,CAAC;AAEH,QAAA,MAAM,iBAAiB;;EAErB,CAAC;AAEH,wBAAgB,0BAA0B,CACzC,IAAI,EAAE,mBAAmB,GACvB,SAAS,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,EAAE,cAAc,CAAC,OAAO,iBAAiB,CAAC,CAAC,CA+F7F","sourcesContent":["/**\n * capability_mount / capability_unmount: plugin-granular on-demand tool\n * loading (插件按需挂载与能力手册设计 §5.2).\n *\n * Manifests declaring `activation: \"on-demand\"` register their tools into the\n * registry but keep them out of the active set; the model sees a one-line\n * capability card in the system prompt instead. `capability_mount` pulls the\n * plugin's full tool set into the active surface (next request) and returns\n * the plugin's AI manual; `capability_unmount` removes it from the active\n * surface without touching any runtime state — session teardown remains the\n * primary cleanup path. Kernel mechanism only: no plugin-specific branches.\n */\n\nimport { type Static, Type } from \"typebox\";\nimport type { ToolDefinition } from \"./tool-definition.ts\";\n\nexport interface DeferredCapabilityCardV1 {\n\treadonly pluginId: string;\n\t/** One-line capability summary from the manifest `description` field. */\n\treadonly description?: string;\n\t/** Absolute path to the plugin's AI manual (manifest `manual`, resolved). */\n\treadonly manualPath?: string;\n}\n\nexport interface CapabilityMountDeps {\n\tgetCards(): readonly DeferredCapabilityCardV1[];\n\t/** Registry tool names whose source is this plugin id. */\n\ttoolNamesForPlugin(pluginId: string): string[];\n\tgetActiveToolNames(): readonly string[];\n\tsetActiveToolsByName(toolNames: string[]): void;\n\treadManual(path: string): Promise<string>;\n}\n\nconst MANUAL_MAX_CHARS = 16_000;\n\nexport const CAPABILITY_MOUNT_TOOL_NAME = \"capability_mount\";\nexport const CAPABILITY_UNMOUNT_TOOL_NAME = \"capability_unmount\";\n\nconst mountParameters = Type.Object({\n\tplugin: Type.String({\n\t\tdescription: \"Plugin id from the mountable-capabilities card, e.g. agent-forge.plugin.browser-playwright\",\n\t}),\n});\n\nconst unmountParameters = Type.Object({\n\tplugin: Type.String({ description: \"Plugin id to unmount, e.g. agent-forge.plugin.browser-playwright\" }),\n});\n\nexport function createCapabilityMountTools(\n\tdeps: CapabilityMountDeps,\n): readonly [ToolDefinition<typeof mountParameters>, ToolDefinition<typeof unmountParameters>] {\n\tconst mountTool: ToolDefinition<typeof mountParameters> = {\n\t\tname: CAPABILITY_MOUNT_TOOL_NAME,\n\t\tlabel: \"Capability mount\",\n\t\tdescription:\n\t\t\t\"Load a deferred plugin capability on demand: activates all of its tools for subsequent turns and returns \" +\n\t\t\t\"the plugin's usage manual. Mountable capabilities are listed in the system prompt's mountable-capabilities section.\",\n\t\tpromptSnippet:\n\t\t\t\"Activate a deferred plugin capability (browser tools, desktop control, image generation, ...) when its one-line card in the mountable-capabilities section matches the task\",\n\t\tparameters: mountParameters,\n\t\texecute: async (_toolCallId, params: Static<typeof mountParameters>) => {\n\t\t\tconst pluginId = params.plugin.trim();\n\t\t\tconst card = deps.getCards().find((entry) => entry.pluginId === pluginId);\n\t\t\tif (card === undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Unknown capability \"${pluginId}\". Mountable capabilities are listed in the system prompt's mountable-capabilities section.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { activated: false },\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst toolNames = deps.toolNamesForPlugin(pluginId);\n\t\t\tif (toolNames.length === 0) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Capability \"${pluginId}\" has no registered tools to activate.` }],\n\t\t\t\t\tdetails: { activated: false },\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst active = new Set(deps.getActiveToolNames());\n\t\t\tconst missing = toolNames.filter((name) => !active.has(name));\n\t\t\tif (missing.length > 0) {\n\t\t\t\tdeps.setActiveToolsByName([...deps.getActiveToolNames(), ...toolNames]);\n\t\t\t}\n\t\t\tconst manual =\n\t\t\t\tcard.manualPath === undefined ? undefined : await deps.readManual(card.manualPath).catch(() => undefined);\n\t\t\tconst activationLine =\n\t\t\t\tmissing.length === 0\n\t\t\t\t\t? `Capability \"${pluginId}\" is already active (${toolNames.length} tool(s)).`\n\t\t\t\t\t: `Activated ${missing.length} tool(s) for \"${pluginId}\": ${toolNames.join(\", \")}. They are available from the next turn.`;\n\t\t\tconst manualBlock =\n\t\t\t\tmanual === undefined\n\t\t\t\t\t? \"\"\n\t\t\t\t\t: `\\n\\n---\\n\\n${manual.slice(0, MANUAL_MAX_CHARS)}${manual.length > MANUAL_MAX_CHARS ? \"\\n\\n(manual truncated)\" : \"\"}`;\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: `${activationLine}${manualBlock}` }],\n\t\t\t\tdetails: { activated: missing.length > 0 },\n\t\t\t};\n\t\t},\n\t};\n\n\tconst unmountTool: ToolDefinition<typeof unmountParameters> = {\n\t\tname: CAPABILITY_UNMOUNT_TOOL_NAME,\n\t\tlabel: \"Capability unmount\",\n\t\tdescription:\n\t\t\t\"Remove a mounted plugin capability's tools from the active surface when the task that needed them is done. \" +\n\t\t\t\"Runtime state (e.g. an open browser session) is not torn down; it follows the plugin's own idle timeout. \" +\n\t\t\t\"Session teardown clears all mounts anyway, so unmounting is an optional long-session optimization.\",\n\t\tpromptSnippet:\n\t\t\t\"Deactivate a mounted plugin capability after finishing the task that needed it (optional; sessions clear mounts on teardown)\",\n\t\tparameters: unmountParameters,\n\t\texecute: async (_toolCallId, params: Static<typeof unmountParameters>) => {\n\t\t\tconst pluginId = params.plugin.trim();\n\t\t\tconst card = deps.getCards().find((entry) => entry.pluginId === pluginId);\n\t\t\tif (card === undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Unknown capability \"${pluginId}\".` }],\n\t\t\t\t\tdetails: { unmounted: false },\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst toolNames = deps.toolNamesForPlugin(pluginId);\n\t\t\tconst active = new Set(deps.getActiveToolNames());\n\t\t\tconst mountedNames = toolNames.filter((name) => active.has(name));\n\t\t\tif (mountedNames.length === 0) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Capability \"${pluginId}\" is not mounted.` }],\n\t\t\t\t\tdetails: { unmounted: false },\n\t\t\t\t};\n\t\t\t}\n\t\t\tdeps.setActiveToolsByName(deps.getActiveToolNames().filter((name) => !mountedNames.includes(name)));\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `Unmounted \"${pluginId}\": removed ${mountedNames.length} tool(s) from the active surface. Runtime state was not touched.`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails: { unmounted: true },\n\t\t\t};\n\t\t},\n\t};\n\n\treturn [mountTool, unmountTool] as const;\n}\n"]}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * capability_mount / capability_unmount: plugin-granular on-demand tool
3
+ * loading (插件按需挂载与能力手册设计 §5.2).
4
+ *
5
+ * Manifests declaring `activation: "on-demand"` register their tools into the
6
+ * registry but keep them out of the active set; the model sees a one-line
7
+ * capability card in the system prompt instead. `capability_mount` pulls the
8
+ * plugin's full tool set into the active surface (next request) and returns
9
+ * the plugin's AI manual; `capability_unmount` removes it from the active
10
+ * surface without touching any runtime state — session teardown remains the
11
+ * primary cleanup path. Kernel mechanism only: no plugin-specific branches.
12
+ */
13
+ import { Type } from "typebox";
14
+ const MANUAL_MAX_CHARS = 16_000;
15
+ export const CAPABILITY_MOUNT_TOOL_NAME = "capability_mount";
16
+ export const CAPABILITY_UNMOUNT_TOOL_NAME = "capability_unmount";
17
+ const mountParameters = Type.Object({
18
+ plugin: Type.String({
19
+ description: "Plugin id from the mountable-capabilities card, e.g. agent-forge.plugin.browser-playwright",
20
+ }),
21
+ });
22
+ const unmountParameters = Type.Object({
23
+ plugin: Type.String({ description: "Plugin id to unmount, e.g. agent-forge.plugin.browser-playwright" }),
24
+ });
25
+ export function createCapabilityMountTools(deps) {
26
+ const mountTool = {
27
+ name: CAPABILITY_MOUNT_TOOL_NAME,
28
+ label: "Capability mount",
29
+ description: "Load a deferred plugin capability on demand: activates all of its tools for subsequent turns and returns " +
30
+ "the plugin's usage manual. Mountable capabilities are listed in the system prompt's mountable-capabilities section.",
31
+ promptSnippet: "Activate a deferred plugin capability (browser tools, desktop control, image generation, ...) when its one-line card in the mountable-capabilities section matches the task",
32
+ parameters: mountParameters,
33
+ execute: async (_toolCallId, params) => {
34
+ const pluginId = params.plugin.trim();
35
+ const card = deps.getCards().find((entry) => entry.pluginId === pluginId);
36
+ if (card === undefined) {
37
+ return {
38
+ content: [
39
+ {
40
+ type: "text",
41
+ text: `Unknown capability "${pluginId}". Mountable capabilities are listed in the system prompt's mountable-capabilities section.`,
42
+ },
43
+ ],
44
+ details: { activated: false },
45
+ };
46
+ }
47
+ const toolNames = deps.toolNamesForPlugin(pluginId);
48
+ if (toolNames.length === 0) {
49
+ return {
50
+ content: [{ type: "text", text: `Capability "${pluginId}" has no registered tools to activate.` }],
51
+ details: { activated: false },
52
+ };
53
+ }
54
+ const active = new Set(deps.getActiveToolNames());
55
+ const missing = toolNames.filter((name) => !active.has(name));
56
+ if (missing.length > 0) {
57
+ deps.setActiveToolsByName([...deps.getActiveToolNames(), ...toolNames]);
58
+ }
59
+ const manual = card.manualPath === undefined ? undefined : await deps.readManual(card.manualPath).catch(() => undefined);
60
+ const activationLine = missing.length === 0
61
+ ? `Capability "${pluginId}" is already active (${toolNames.length} tool(s)).`
62
+ : `Activated ${missing.length} tool(s) for "${pluginId}": ${toolNames.join(", ")}. They are available from the next turn.`;
63
+ const manualBlock = manual === undefined
64
+ ? ""
65
+ : `\n\n---\n\n${manual.slice(0, MANUAL_MAX_CHARS)}${manual.length > MANUAL_MAX_CHARS ? "\n\n(manual truncated)" : ""}`;
66
+ return {
67
+ content: [{ type: "text", text: `${activationLine}${manualBlock}` }],
68
+ details: { activated: missing.length > 0 },
69
+ };
70
+ },
71
+ };
72
+ const unmountTool = {
73
+ name: CAPABILITY_UNMOUNT_TOOL_NAME,
74
+ label: "Capability unmount",
75
+ description: "Remove a mounted plugin capability's tools from the active surface when the task that needed them is done. " +
76
+ "Runtime state (e.g. an open browser session) is not torn down; it follows the plugin's own idle timeout. " +
77
+ "Session teardown clears all mounts anyway, so unmounting is an optional long-session optimization.",
78
+ promptSnippet: "Deactivate a mounted plugin capability after finishing the task that needed it (optional; sessions clear mounts on teardown)",
79
+ parameters: unmountParameters,
80
+ execute: async (_toolCallId, params) => {
81
+ const pluginId = params.plugin.trim();
82
+ const card = deps.getCards().find((entry) => entry.pluginId === pluginId);
83
+ if (card === undefined) {
84
+ return {
85
+ content: [{ type: "text", text: `Unknown capability "${pluginId}".` }],
86
+ details: { unmounted: false },
87
+ };
88
+ }
89
+ const toolNames = deps.toolNamesForPlugin(pluginId);
90
+ const active = new Set(deps.getActiveToolNames());
91
+ const mountedNames = toolNames.filter((name) => active.has(name));
92
+ if (mountedNames.length === 0) {
93
+ return {
94
+ content: [{ type: "text", text: `Capability "${pluginId}" is not mounted.` }],
95
+ details: { unmounted: false },
96
+ };
97
+ }
98
+ deps.setActiveToolsByName(deps.getActiveToolNames().filter((name) => !mountedNames.includes(name)));
99
+ return {
100
+ content: [
101
+ {
102
+ type: "text",
103
+ text: `Unmounted "${pluginId}": removed ${mountedNames.length} tool(s) from the active surface. Runtime state was not touched.`,
104
+ },
105
+ ],
106
+ details: { unmounted: true },
107
+ };
108
+ },
109
+ };
110
+ return [mountTool, unmountTool];
111
+ }
112
+ //# sourceMappingURL=capability-mount.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-mount.js","sourceRoot":"","sources":["../../../src/core/tools/capability-mount.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * capability_mount / capability_unmount: plugin-granular on-demand tool\n * loading (插件按需挂载与能力手册设计 §5.2).\n *\n * Manifests declaring `activation: \"on-demand\"` register their tools into the\n * registry but keep them out of the active set; the model sees a one-line\n * capability card in the system prompt instead. `capability_mount` pulls the\n * plugin's full tool set into the active surface (next request) and returns\n * the plugin's AI manual; `capability_unmount` removes it from the active\n * surface without touching any runtime state — session teardown remains the\n * primary cleanup path. Kernel mechanism only: no plugin-specific branches.\n */\n\nimport { type Static, Type } from \"typebox\";\nimport type { ToolDefinition } from \"./tool-definition.ts\";\n\nexport interface DeferredCapabilityCardV1 {\n\treadonly pluginId: string;\n\t/** One-line capability summary from the manifest `description` field. */\n\treadonly description?: string;\n\t/** Absolute path to the plugin's AI manual (manifest `manual`, resolved). */\n\treadonly manualPath?: string;\n}\n\nexport interface CapabilityMountDeps {\n\tgetCards(): readonly DeferredCapabilityCardV1[];\n\t/** Registry tool names whose source is this plugin id. */\n\ttoolNamesForPlugin(pluginId: string): string[];\n\tgetActiveToolNames(): readonly string[];\n\tsetActiveToolsByName(toolNames: string[]): void;\n\treadManual(path: string): Promise<string>;\n}\n\nconst MANUAL_MAX_CHARS = 16_000;\n\nexport const CAPABILITY_MOUNT_TOOL_NAME = \"capability_mount\";\nexport const CAPABILITY_UNMOUNT_TOOL_NAME = \"capability_unmount\";\n\nconst mountParameters = Type.Object({\n\tplugin: Type.String({\n\t\tdescription: \"Plugin id from the mountable-capabilities card, e.g. agent-forge.plugin.browser-playwright\",\n\t}),\n});\n\nconst unmountParameters = Type.Object({\n\tplugin: Type.String({ description: \"Plugin id to unmount, e.g. agent-forge.plugin.browser-playwright\" }),\n});\n\nexport function createCapabilityMountTools(\n\tdeps: CapabilityMountDeps,\n): readonly [ToolDefinition<typeof mountParameters>, ToolDefinition<typeof unmountParameters>] {\n\tconst mountTool: ToolDefinition<typeof mountParameters> = {\n\t\tname: CAPABILITY_MOUNT_TOOL_NAME,\n\t\tlabel: \"Capability mount\",\n\t\tdescription:\n\t\t\t\"Load a deferred plugin capability on demand: activates all of its tools for subsequent turns and returns \" +\n\t\t\t\"the plugin's usage manual. Mountable capabilities are listed in the system prompt's mountable-capabilities section.\",\n\t\tpromptSnippet:\n\t\t\t\"Activate a deferred plugin capability (browser tools, desktop control, image generation, ...) when its one-line card in the mountable-capabilities section matches the task\",\n\t\tparameters: mountParameters,\n\t\texecute: async (_toolCallId, params: Static<typeof mountParameters>) => {\n\t\t\tconst pluginId = params.plugin.trim();\n\t\t\tconst card = deps.getCards().find((entry) => entry.pluginId === pluginId);\n\t\t\tif (card === undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `Unknown capability \"${pluginId}\". Mountable capabilities are listed in the system prompt's mountable-capabilities section.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { activated: false },\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst toolNames = deps.toolNamesForPlugin(pluginId);\n\t\t\tif (toolNames.length === 0) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Capability \"${pluginId}\" has no registered tools to activate.` }],\n\t\t\t\t\tdetails: { activated: false },\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst active = new Set(deps.getActiveToolNames());\n\t\t\tconst missing = toolNames.filter((name) => !active.has(name));\n\t\t\tif (missing.length > 0) {\n\t\t\t\tdeps.setActiveToolsByName([...deps.getActiveToolNames(), ...toolNames]);\n\t\t\t}\n\t\t\tconst manual =\n\t\t\t\tcard.manualPath === undefined ? undefined : await deps.readManual(card.manualPath).catch(() => undefined);\n\t\t\tconst activationLine =\n\t\t\t\tmissing.length === 0\n\t\t\t\t\t? `Capability \"${pluginId}\" is already active (${toolNames.length} tool(s)).`\n\t\t\t\t\t: `Activated ${missing.length} tool(s) for \"${pluginId}\": ${toolNames.join(\", \")}. They are available from the next turn.`;\n\t\t\tconst manualBlock =\n\t\t\t\tmanual === undefined\n\t\t\t\t\t? \"\"\n\t\t\t\t\t: `\\n\\n---\\n\\n${manual.slice(0, MANUAL_MAX_CHARS)}${manual.length > MANUAL_MAX_CHARS ? \"\\n\\n(manual truncated)\" : \"\"}`;\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: `${activationLine}${manualBlock}` }],\n\t\t\t\tdetails: { activated: missing.length > 0 },\n\t\t\t};\n\t\t},\n\t};\n\n\tconst unmountTool: ToolDefinition<typeof unmountParameters> = {\n\t\tname: CAPABILITY_UNMOUNT_TOOL_NAME,\n\t\tlabel: \"Capability unmount\",\n\t\tdescription:\n\t\t\t\"Remove a mounted plugin capability's tools from the active surface when the task that needed them is done. \" +\n\t\t\t\"Runtime state (e.g. an open browser session) is not torn down; it follows the plugin's own idle timeout. \" +\n\t\t\t\"Session teardown clears all mounts anyway, so unmounting is an optional long-session optimization.\",\n\t\tpromptSnippet:\n\t\t\t\"Deactivate a mounted plugin capability after finishing the task that needed it (optional; sessions clear mounts on teardown)\",\n\t\tparameters: unmountParameters,\n\t\texecute: async (_toolCallId, params: Static<typeof unmountParameters>) => {\n\t\t\tconst pluginId = params.plugin.trim();\n\t\t\tconst card = deps.getCards().find((entry) => entry.pluginId === pluginId);\n\t\t\tif (card === undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Unknown capability \"${pluginId}\".` }],\n\t\t\t\t\tdetails: { unmounted: false },\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst toolNames = deps.toolNamesForPlugin(pluginId);\n\t\t\tconst active = new Set(deps.getActiveToolNames());\n\t\t\tconst mountedNames = toolNames.filter((name) => active.has(name));\n\t\t\tif (mountedNames.length === 0) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Capability \"${pluginId}\" is not mounted.` }],\n\t\t\t\t\tdetails: { unmounted: false },\n\t\t\t\t};\n\t\t\t}\n\t\t\tdeps.setActiveToolsByName(deps.getActiveToolNames().filter((name) => !mountedNames.includes(name)));\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `Unmounted \"${pluginId}\": removed ${mountedNames.length} tool(s) from the active surface. Runtime state was not touched.`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails: { unmounted: true },\n\t\t\t};\n\t\t},\n\t};\n\n\treturn [mountTool, unmountTool] as const;\n}\n"]}