@mariozechner/pi-coding-agent 0.34.2 → 0.36.0

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 (260) hide show
  1. package/CHANGELOG.md +210 -0
  2. package/README.md +246 -107
  3. package/dist/cli/args.d.ts +3 -4
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +13 -18
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/config.d.ts +2 -2
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +3 -3
  10. package/dist/config.js.map +1 -1
  11. package/dist/core/agent-session.d.ts +39 -50
  12. package/dist/core/agent-session.d.ts.map +1 -1
  13. package/dist/core/agent-session.js +166 -197
  14. package/dist/core/agent-session.js.map +1 -1
  15. package/dist/core/auth-storage.d.ts.map +1 -1
  16. package/dist/core/auth-storage.js +4 -1
  17. package/dist/core/auth-storage.js.map +1 -1
  18. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  19. package/dist/core/compaction/branch-summarization.js +3 -3
  20. package/dist/core/compaction/branch-summarization.js.map +1 -1
  21. package/dist/core/compaction/compaction.d.ts +1 -1
  22. package/dist/core/compaction/compaction.d.ts.map +1 -1
  23. package/dist/core/compaction/compaction.js +6 -5
  24. package/dist/core/compaction/compaction.js.map +1 -1
  25. package/dist/core/event-bus.d.ts +9 -0
  26. package/dist/core/event-bus.d.ts.map +1 -0
  27. package/dist/core/event-bus.js +25 -0
  28. package/dist/core/event-bus.js.map +1 -0
  29. package/dist/core/exec.d.ts +1 -1
  30. package/dist/core/exec.d.ts.map +1 -1
  31. package/dist/core/exec.js +1 -1
  32. package/dist/core/exec.js.map +1 -1
  33. package/dist/core/extensions/index.d.ts +10 -0
  34. package/dist/core/extensions/index.d.ts.map +1 -0
  35. package/dist/core/extensions/index.js +9 -0
  36. package/dist/core/extensions/index.js.map +1 -0
  37. package/dist/core/extensions/loader.d.ts +21 -0
  38. package/dist/core/extensions/loader.d.ts.map +1 -0
  39. package/dist/core/extensions/loader.js +400 -0
  40. package/dist/core/extensions/loader.js.map +1 -0
  41. package/dist/core/extensions/runner.d.ts +88 -0
  42. package/dist/core/extensions/runner.d.ts.map +1 -0
  43. package/dist/core/{hooks → extensions}/runner.js +52 -141
  44. package/dist/core/extensions/runner.js.map +1 -0
  45. package/dist/core/extensions/types.d.ts +461 -0
  46. package/dist/core/extensions/types.d.ts.map +1 -0
  47. package/dist/core/{hooks → extensions}/types.js +7 -4
  48. package/dist/core/extensions/types.js.map +1 -0
  49. package/dist/core/extensions/wrapper.d.ts +25 -0
  50. package/dist/core/extensions/wrapper.d.ts.map +1 -0
  51. package/dist/core/{hooks/tool-wrapper.js → extensions/wrapper.js} +39 -24
  52. package/dist/core/extensions/wrapper.js.map +1 -0
  53. package/dist/core/index.d.ts +2 -2
  54. package/dist/core/index.d.ts.map +1 -1
  55. package/dist/core/index.js +3 -2
  56. package/dist/core/index.js.map +1 -1
  57. package/dist/core/messages.d.ts +7 -7
  58. package/dist/core/messages.d.ts.map +1 -1
  59. package/dist/core/messages.js +4 -4
  60. package/dist/core/messages.js.map +1 -1
  61. package/dist/core/model-registry.d.ts.map +1 -1
  62. package/dist/core/model-registry.js +2 -0
  63. package/dist/core/model-registry.js.map +1 -1
  64. package/dist/core/model-resolver.d.ts.map +1 -1
  65. package/dist/core/model-resolver.js +1 -0
  66. package/dist/core/model-resolver.js.map +1 -1
  67. package/dist/core/prompt-templates.d.ts +40 -0
  68. package/dist/core/prompt-templates.d.ts.map +1 -0
  69. package/dist/core/{slash-commands.js → prompt-templates.js} +31 -31
  70. package/dist/core/prompt-templates.js.map +1 -0
  71. package/dist/core/sdk.d.ts +29 -52
  72. package/dist/core/sdk.d.ts.map +1 -1
  73. package/dist/core/sdk.js +111 -211
  74. package/dist/core/sdk.js.map +1 -1
  75. package/dist/core/session-manager.d.ts +17 -17
  76. package/dist/core/session-manager.d.ts.map +1 -1
  77. package/dist/core/session-manager.js +25 -10
  78. package/dist/core/session-manager.js.map +1 -1
  79. package/dist/core/settings-manager.d.ts +3 -6
  80. package/dist/core/settings-manager.d.ts.map +1 -1
  81. package/dist/core/settings-manager.js +4 -11
  82. package/dist/core/settings-manager.js.map +1 -1
  83. package/dist/core/system-prompt.d.ts.map +1 -1
  84. package/dist/core/system-prompt.js +4 -2
  85. package/dist/core/system-prompt.js.map +1 -1
  86. package/dist/index.d.ts +4 -5
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +5 -6
  89. package/dist/index.js.map +1 -1
  90. package/dist/main.d.ts.map +1 -1
  91. package/dist/main.js +36 -33
  92. package/dist/main.js.map +1 -1
  93. package/dist/migrations.d.ts +7 -2
  94. package/dist/migrations.d.ts.map +1 -1
  95. package/dist/migrations.js +93 -4
  96. package/dist/migrations.js.map +1 -1
  97. package/dist/modes/interactive/components/bordered-loader.d.ts +1 -1
  98. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  99. package/dist/modes/interactive/components/bordered-loader.js +1 -1
  100. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  101. package/dist/modes/interactive/components/branch-summary-message.d.ts +1 -1
  102. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  103. package/dist/modes/interactive/components/branch-summary-message.js +1 -1
  104. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  105. package/dist/modes/interactive/components/compaction-summary-message.d.ts +1 -1
  106. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  107. package/dist/modes/interactive/components/compaction-summary-message.js +1 -1
  108. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  109. package/dist/modes/interactive/components/custom-editor.d.ts +2 -2
  110. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  111. package/dist/modes/interactive/components/custom-editor.js +4 -4
  112. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  113. package/dist/modes/interactive/components/custom-message.d.ts +18 -0
  114. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -0
  115. package/dist/modes/interactive/components/{hook-message.js → custom-message.js} +3 -3
  116. package/dist/modes/interactive/components/custom-message.js.map +1 -0
  117. package/dist/modes/interactive/components/dynamic-border.d.ts +2 -2
  118. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  119. package/dist/modes/interactive/components/dynamic-border.js +2 -2
  120. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  121. package/dist/modes/interactive/components/{hook-editor.d.ts → extension-editor.d.ts} +3 -3
  122. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -0
  123. package/dist/modes/interactive/components/{hook-editor.js → extension-editor.js} +4 -4
  124. package/dist/modes/interactive/components/extension-editor.js.map +1 -0
  125. package/dist/modes/interactive/components/{hook-input.d.ts → extension-input.d.ts} +3 -3
  126. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -0
  127. package/dist/modes/interactive/components/{hook-input.js → extension-input.js} +3 -3
  128. package/dist/modes/interactive/components/extension-input.js.map +1 -0
  129. package/dist/modes/interactive/components/{hook-selector.d.ts → extension-selector.d.ts} +3 -3
  130. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -0
  131. package/dist/modes/interactive/components/{hook-selector.js → extension-selector.js} +3 -3
  132. package/dist/modes/interactive/components/extension-selector.js.map +1 -0
  133. package/dist/modes/interactive/components/footer.d.ts +3 -3
  134. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  135. package/dist/modes/interactive/components/footer.js +8 -8
  136. package/dist/modes/interactive/components/footer.js.map +1 -1
  137. package/dist/modes/interactive/components/tool-execution.d.ts +3 -3
  138. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  139. package/dist/modes/interactive/components/tool-execution.js +9 -9
  140. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  141. package/dist/modes/interactive/interactive-mode.d.ts +37 -44
  142. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  143. package/dist/modes/interactive/interactive-mode.js +143 -189
  144. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  145. package/dist/modes/print-mode.d.ts.map +1 -1
  146. package/dist/modes/print-mode.js +10 -33
  147. package/dist/modes/print-mode.js.map +1 -1
  148. package/dist/modes/rpc/rpc-client.d.ts +3 -3
  149. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  150. package/dist/modes/rpc/rpc-client.js +3 -3
  151. package/dist/modes/rpc/rpc-client.js.map +1 -1
  152. package/dist/modes/rpc/rpc-mode.d.ts +2 -2
  153. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  154. package/dist/modes/rpc/rpc-mode.js +33 -57
  155. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  156. package/dist/modes/rpc/rpc-types.d.ts +16 -16
  157. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  158. package/dist/modes/rpc/rpc-types.js.map +1 -1
  159. package/docs/extensions.md +1053 -0
  160. package/docs/rpc.md +4 -4
  161. package/docs/sdk.md +62 -93
  162. package/docs/session.md +22 -19
  163. package/docs/skills.md +1 -1
  164. package/docs/tui.md +1 -1
  165. package/examples/README.md +9 -15
  166. package/examples/extensions/README.md +141 -0
  167. package/examples/{hooks → extensions}/auto-commit-on-exit.ts +3 -3
  168. package/examples/extensions/chalk-logger.ts +26 -0
  169. package/examples/{hooks → extensions}/confirm-destructive.ts +3 -3
  170. package/examples/{hooks → extensions}/custom-compaction.ts +6 -6
  171. package/examples/{hooks → extensions}/dirty-repo-guard.ts +8 -4
  172. package/examples/{hooks → extensions}/file-trigger.ts +3 -3
  173. package/examples/{hooks → extensions}/git-checkpoint.ts +3 -3
  174. package/examples/{hooks → extensions}/handoff.ts +3 -3
  175. package/examples/extensions/hello.ts +25 -0
  176. package/examples/{hooks → extensions}/permission-gate.ts +3 -3
  177. package/examples/{hooks → extensions}/pirate.ts +5 -5
  178. package/examples/{hooks → extensions}/plan-mode.ts +6 -6
  179. package/examples/{hooks → extensions}/protected-paths.ts +3 -3
  180. package/examples/{hooks → extensions}/qna.ts +3 -3
  181. package/examples/{custom-tools/question/index.ts → extensions/question.ts} +13 -17
  182. package/examples/{hooks → extensions}/snake.ts +3 -3
  183. package/examples/{hooks → extensions}/status-line.ts +3 -3
  184. package/examples/{custom-tools → extensions}/subagent/README.md +15 -15
  185. package/examples/{custom-tools → extensions}/subagent/index.ts +22 -43
  186. package/examples/{custom-tools/todo/index.ts → extensions/todo.ts} +122 -39
  187. package/examples/{hooks → extensions}/tools.ts +5 -5
  188. package/examples/extensions/with-deps/index.ts +36 -0
  189. package/examples/extensions/with-deps/package-lock.json +31 -0
  190. package/examples/extensions/with-deps/package.json +16 -0
  191. package/examples/sdk/01-minimal.ts +1 -1
  192. package/examples/sdk/05-tools.ts +7 -41
  193. package/examples/sdk/06-extensions.ts +81 -0
  194. package/examples/sdk/08-prompt-templates.ts +42 -0
  195. package/examples/sdk/12-full-control.ts +10 -29
  196. package/examples/sdk/README.md +5 -5
  197. package/package.json +4 -4
  198. package/dist/core/custom-tools/index.d.ts +0 -7
  199. package/dist/core/custom-tools/index.d.ts.map +0 -1
  200. package/dist/core/custom-tools/index.js +0 -6
  201. package/dist/core/custom-tools/index.js.map +0 -1
  202. package/dist/core/custom-tools/loader.d.ts +0 -30
  203. package/dist/core/custom-tools/loader.d.ts.map +0 -1
  204. package/dist/core/custom-tools/loader.js +0 -276
  205. package/dist/core/custom-tools/loader.js.map +0 -1
  206. package/dist/core/custom-tools/types.d.ts +0 -144
  207. package/dist/core/custom-tools/types.d.ts.map +0 -1
  208. package/dist/core/custom-tools/types.js +0 -8
  209. package/dist/core/custom-tools/types.js.map +0 -1
  210. package/dist/core/custom-tools/wrapper.d.ts +0 -15
  211. package/dist/core/custom-tools/wrapper.d.ts.map +0 -1
  212. package/dist/core/custom-tools/wrapper.js +0 -23
  213. package/dist/core/custom-tools/wrapper.js.map +0 -1
  214. package/dist/core/hooks/index.d.ts +0 -6
  215. package/dist/core/hooks/index.d.ts.map +0 -1
  216. package/dist/core/hooks/index.js +0 -6
  217. package/dist/core/hooks/index.js.map +0 -1
  218. package/dist/core/hooks/loader.d.ts +0 -146
  219. package/dist/core/hooks/loader.d.ts.map +0 -1
  220. package/dist/core/hooks/loader.js +0 -275
  221. package/dist/core/hooks/loader.js.map +0 -1
  222. package/dist/core/hooks/runner.d.ts +0 -173
  223. package/dist/core/hooks/runner.d.ts.map +0 -1
  224. package/dist/core/hooks/runner.js.map +0 -1
  225. package/dist/core/hooks/tool-wrapper.d.ts +0 -17
  226. package/dist/core/hooks/tool-wrapper.d.ts.map +0 -1
  227. package/dist/core/hooks/tool-wrapper.js.map +0 -1
  228. package/dist/core/hooks/types.d.ts +0 -767
  229. package/dist/core/hooks/types.d.ts.map +0 -1
  230. package/dist/core/hooks/types.js.map +0 -1
  231. package/dist/core/slash-commands.d.ts +0 -40
  232. package/dist/core/slash-commands.d.ts.map +0 -1
  233. package/dist/core/slash-commands.js.map +0 -1
  234. package/dist/modes/interactive/components/hook-editor.d.ts.map +0 -1
  235. package/dist/modes/interactive/components/hook-editor.js.map +0 -1
  236. package/dist/modes/interactive/components/hook-input.d.ts.map +0 -1
  237. package/dist/modes/interactive/components/hook-input.js.map +0 -1
  238. package/dist/modes/interactive/components/hook-message.d.ts +0 -18
  239. package/dist/modes/interactive/components/hook-message.d.ts.map +0 -1
  240. package/dist/modes/interactive/components/hook-message.js.map +0 -1
  241. package/dist/modes/interactive/components/hook-selector.d.ts.map +0 -1
  242. package/dist/modes/interactive/components/hook-selector.js.map +0 -1
  243. package/docs/custom-tools.md +0 -514
  244. package/docs/extension-loading.md +0 -1004
  245. package/docs/hooks.md +0 -979
  246. package/docs/session-tree-plan.md +0 -441
  247. package/examples/custom-tools/README.md +0 -114
  248. package/examples/custom-tools/hello/index.ts +0 -21
  249. package/examples/hooks/README.md +0 -60
  250. package/examples/hooks/todo/index.ts +0 -134
  251. package/examples/sdk/06-hooks.ts +0 -61
  252. package/examples/sdk/08-slash-commands.ts +0 -42
  253. /package/examples/{custom-tools → extensions}/subagent/agents/planner.md +0 -0
  254. /package/examples/{custom-tools → extensions}/subagent/agents/reviewer.md +0 -0
  255. /package/examples/{custom-tools → extensions}/subagent/agents/scout.md +0 -0
  256. /package/examples/{custom-tools → extensions}/subagent/agents/worker.md +0 -0
  257. /package/examples/{custom-tools → extensions}/subagent/agents.ts +0 -0
  258. /package/examples/{custom-tools/subagent/commands → extensions/subagent/prompts}/implement-and-review.md +0 -0
  259. /package/examples/{custom-tools/subagent/commands → extensions/subagent/prompts}/implement.md +0 -0
  260. /package/examples/{custom-tools/subagent/commands → extensions/subagent/prompts}/scout-and-plan.md +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SDK for programmatic usage of AgentSession.\n *\n * Provides a factory function and discovery helpers that allow full control\n * over agent configuration, or sensible defaults that match CLI behavior.\n *\n * @example\n * ```typescript\n * // Minimal - everything auto-discovered\n * const session = await createAgentSession();\n *\n * // With custom hooks\n * const session = await createAgentSession({\n * hooks: [\n * ...await discoverHooks(),\n * { factory: myHookFactory },\n * ],\n * });\n *\n * // Full control\n * const session = await createAgentSession({\n * model: myModel,\n * getApiKey: async () => process.env.MY_KEY,\n * tools: [readTool, bashTool],\n * hooks: [],\n * skills: [],\n * sessionFile: false,\n * });\n * ```\n */\n\nimport { Agent, type AgentTool, type ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport type { Model } from \"@mariozechner/pi-ai\";\nimport type { KeyId } from \"@mariozechner/pi-tui\";\nimport { join } from \"path\";\nimport { getAgentDir } from \"../config.js\";\nimport { AgentSession } from \"./agent-session.js\";\nimport { AuthStorage } from \"./auth-storage.js\";\nimport {\n\ttype CustomToolsLoadResult,\n\tdiscoverAndLoadCustomTools,\n\ttype LoadedCustomTool,\n\twrapCustomTools,\n} from \"./custom-tools/index.js\";\nimport type { CustomTool } from \"./custom-tools/types.js\";\nimport { discoverAndLoadHooks, HookRunner, type LoadedHook, wrapToolsWithHooks } from \"./hooks/index.js\";\nimport type { HookFactory } from \"./hooks/types.js\";\nimport { convertToLlm } from \"./messages.js\";\nimport { ModelRegistry } from \"./model-registry.js\";\nimport { SessionManager } from \"./session-manager.js\";\nimport { type Settings, SettingsManager, type SkillsSettings } from \"./settings-manager.js\";\nimport { loadSkills as loadSkillsInternal, type Skill } from \"./skills.js\";\nimport { type FileSlashCommand, loadSlashCommands as loadSlashCommandsInternal } from \"./slash-commands.js\";\nimport {\n\tbuildSystemPrompt as buildSystemPromptInternal,\n\tloadProjectContextFiles as loadContextFilesInternal,\n} from \"./system-prompt.js\";\nimport { time } from \"./timings.js\";\nimport {\n\tallTools,\n\tbashTool,\n\tcodingTools,\n\tcreateAllTools,\n\tcreateBashTool,\n\tcreateCodingTools,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\teditTool,\n\tfindTool,\n\tgrepTool,\n\tlsTool,\n\treadOnlyTools,\n\treadTool,\n\ttype Tool,\n\ttype ToolName,\n\twriteTool,\n} from \"./tools/index.js\";\n\n// Types\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.pi/agent */\n\tagentDir?: string;\n\n\t/** Auth storage for credentials. Default: discoverAuthStorage(agentDir) */\n\tauthStorage?: AuthStorage;\n\t/** Model registry. Default: discoverModels(authStorage, agentDir) */\n\tmodelRegistry?: ModelRegistry;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'off' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;\n\n\t/** System prompt. String replaces default, function receives default and returns final. */\n\tsystemPrompt?: string | ((defaultPrompt: string) => string);\n\n\t/** Built-in tools to use. Default: codingTools [read, bash, edit, write] */\n\ttools?: Tool[];\n\t/** Custom tools (replaces discovery). */\n\tcustomTools?: Array<{ path?: string; tool: CustomTool }>;\n\t/** Additional custom tool paths to load (merged with discovery). */\n\tadditionalCustomToolPaths?: string[];\n\n\t/** Hooks (replaces discovery). */\n\thooks?: Array<{ path?: string; factory: HookFactory }>;\n\t/** Additional hook paths to load (merged with discovery). */\n\tadditionalHookPaths?: string[];\n\t/** Pre-loaded hooks (skips loading, used when hooks were loaded early for CLI flags). */\n\tpreloadedHooks?: LoadedHook[];\n\n\t/** Skills. Default: discovered from multiple locations */\n\tskills?: Skill[];\n\t/** Context files (AGENTS.md content). Default: discovered walking up from cwd */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Slash commands. Default: discovered from cwd/.pi/commands/ + agentDir/commands/ */\n\tslashCommands?: FileSlashCommand[];\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n}\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Custom tools result (for UI context setup in interactive mode) */\n\tcustomToolsResult: CustomToolsLoadResult;\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport type { CustomTool } from \"./custom-tools/types.js\";\nexport type { HookAPI, HookCommandContext, HookContext, HookFactory } from \"./hooks/types.js\";\nexport type { Settings, SkillsSettings } from \"./settings-manager.js\";\nexport type { Skill } from \"./skills.js\";\nexport type { FileSlashCommand } from \"./slash-commands.js\";\nexport type { Tool } from \"./tools/index.js\";\n\nexport {\n\t// Pre-built tools (use process.cwd())\n\treadTool,\n\tbashTool,\n\teditTool,\n\twriteTool,\n\tgrepTool,\n\tfindTool,\n\tlsTool,\n\tcodingTools,\n\treadOnlyTools,\n\tallTools as allBuiltInTools,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateBashTool,\n\tcreateEditTool,\n\tcreateWriteTool,\n\tcreateGrepTool,\n\tcreateFindTool,\n\tcreateLsTool,\n};\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\n// Discovery Functions\n\n/**\n * Create an AuthStorage instance for the given agent directory.\n */\nexport function discoverAuthStorage(agentDir: string = getDefaultAgentDir()): AuthStorage {\n\treturn new AuthStorage(join(agentDir, \"auth.json\"));\n}\n\n/**\n * Create a ModelRegistry for the given agent directory.\n */\nexport function discoverModels(authStorage: AuthStorage, agentDir: string = getDefaultAgentDir()): ModelRegistry {\n\treturn new ModelRegistry(authStorage, join(agentDir, \"models.json\"));\n}\n\n/**\n * Discover hooks from cwd and agentDir.\n */\nexport async function discoverHooks(\n\tcwd?: string,\n\tagentDir?: string,\n): Promise<Array<{ path: string; factory: HookFactory }>> {\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst { hooks, errors } = await discoverAndLoadHooks([], resolvedCwd, resolvedAgentDir);\n\n\t// Log errors but don't fail\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(`Failed to load hook \"${path}\": ${error}`);\n\t}\n\n\treturn hooks.map((h) => ({\n\t\tpath: h.path,\n\t\tfactory: createFactoryFromLoadedHook(h),\n\t}));\n}\n\n/**\n * Discover custom tools from cwd and agentDir.\n */\nexport async function discoverCustomTools(\n\tcwd?: string,\n\tagentDir?: string,\n): Promise<Array<{ path: string; tool: CustomTool }>> {\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst { tools, errors } = await discoverAndLoadCustomTools([], resolvedCwd, Object.keys(allTools), resolvedAgentDir);\n\n\t// Log errors but don't fail\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(`Failed to load custom tool \"${path}\": ${error}`);\n\t}\n\n\treturn tools.map((t) => ({\n\t\tpath: t.path,\n\t\ttool: t.tool,\n\t}));\n}\n\n/**\n * Discover skills from cwd and agentDir.\n */\nexport function discoverSkills(cwd?: string, agentDir?: string, settings?: SkillsSettings): Skill[] {\n\tconst { skills } = loadSkillsInternal({\n\t\t...settings,\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n\treturn skills;\n}\n\n/**\n * Discover context files (AGENTS.md) walking up from cwd.\n */\nexport function discoverContextFiles(cwd?: string, agentDir?: string): Array<{ path: string; content: string }> {\n\treturn loadContextFilesInternal({\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n}\n\n/**\n * Discover slash commands from cwd and agentDir.\n */\nexport function discoverSlashCommands(cwd?: string, agentDir?: string): FileSlashCommand[] {\n\treturn loadSlashCommandsInternal({\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n}\n\n// API Key Helpers\n\n// System Prompt\n\nexport interface BuildSystemPromptOptions {\n\ttools?: Tool[];\n\tskills?: Skill[];\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\tcwd?: string;\n\tappendPrompt?: string;\n}\n\n/**\n * Build the default system prompt.\n */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\treturn buildSystemPromptInternal({\n\t\tcwd: options.cwd,\n\t\tskills: options.skills,\n\t\tcontextFiles: options.contextFiles,\n\t\tappendSystemPrompt: options.appendPrompt,\n\t});\n}\n\n// Settings\n\n/**\n * Load settings from agentDir/settings.json merged with cwd/.pi/settings.json.\n */\nexport function loadSettings(cwd?: string, agentDir?: string): Settings {\n\tconst manager = SettingsManager.create(cwd ?? process.cwd(), agentDir ?? getDefaultAgentDir());\n\treturn {\n\t\tdefaultProvider: manager.getDefaultProvider(),\n\t\tdefaultModel: manager.getDefaultModel(),\n\t\tdefaultThinkingLevel: manager.getDefaultThinkingLevel(),\n\t\tsteeringMode: manager.getSteeringMode(),\n\t\tfollowUpMode: manager.getFollowUpMode(),\n\t\ttheme: manager.getTheme(),\n\t\tcompaction: manager.getCompactionSettings(),\n\t\tretry: manager.getRetrySettings(),\n\t\thideThinkingBlock: manager.getHideThinkingBlock(),\n\t\tshellPath: manager.getShellPath(),\n\t\tcollapseChangelog: manager.getCollapseChangelog(),\n\t\thooks: manager.getHookPaths(),\n\t\tcustomTools: manager.getCustomToolPaths(),\n\t\tskills: manager.getSkillsSettings(),\n\t\tterminal: { showImages: manager.getShowImages() },\n\t};\n}\n\n// Internal Helpers\n\n/**\n * Create a HookFactory from a LoadedHook.\n * This allows mixing discovered hooks with inline hooks.\n */\nfunction createFactoryFromLoadedHook(loaded: LoadedHook): HookFactory {\n\treturn (api) => {\n\t\tfor (const [eventType, handlers] of loaded.handlers) {\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tapi.on(eventType as any, handler as any);\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * Convert hook definitions to LoadedHooks for the HookRunner.\n */\nfunction createLoadedHooksFromDefinitions(definitions: Array<{ path?: string; factory: HookFactory }>): LoadedHook[] {\n\treturn definitions.map((def) => {\n\t\tconst hookPath = def.path ?? \"<inline>\";\n\t\tconst handlers = new Map<string, Array<(...args: unknown[]) => Promise<unknown>>>();\n\t\tconst messageRenderers = new Map<string, any>();\n\t\tconst commands = new Map<string, any>();\n\t\tconst flags = new Map<string, any>();\n\t\tconst flagValues = new Map<string, boolean | string>();\n\t\tconst shortcuts = new Map<KeyId, any>();\n\t\tlet sendMessageHandler: (\n\t\t\tmessage: any,\n\t\t\toptions?: { triggerTurn?: boolean; deliverAs?: \"steer\" | \"followUp\" },\n\t\t) => void = () => {};\n\t\tlet appendEntryHandler: (customType: string, data?: any) => void = () => {};\n\t\tlet getActiveToolsHandler: () => string[] = () => [];\n\t\tlet getAllToolsHandler: () => string[] = () => [];\n\t\tlet setActiveToolsHandler: (toolNames: string[]) => void = () => {};\n\t\tlet newSessionHandler: (options?: any) => Promise<{ cancelled: boolean }> = async () => ({ cancelled: false });\n\t\tlet branchHandler: (entryId: string) => Promise<{ cancelled: boolean }> = async () => ({ cancelled: false });\n\t\tlet navigateTreeHandler: (targetId: string, options?: any) => Promise<{ cancelled: boolean }> = async () => ({\n\t\t\tcancelled: false,\n\t\t});\n\n\t\tconst api = {\n\t\t\ton: (event: string, handler: (...args: unknown[]) => Promise<unknown>) => {\n\t\t\t\tconst list = handlers.get(event) ?? [];\n\t\t\t\tlist.push(handler);\n\t\t\t\thandlers.set(event, list);\n\t\t\t},\n\t\t\tsendMessage: (message: any, options?: { triggerTurn?: boolean; deliverAs?: \"steer\" | \"followUp\" }) => {\n\t\t\t\tsendMessageHandler(message, options);\n\t\t\t},\n\t\t\tappendEntry: (customType: string, data?: any) => {\n\t\t\t\tappendEntryHandler(customType, data);\n\t\t\t},\n\t\t\tregisterMessageRenderer: (customType: string, renderer: any) => {\n\t\t\t\tmessageRenderers.set(customType, renderer);\n\t\t\t},\n\t\t\tregisterCommand: (name: string, options: any) => {\n\t\t\t\tcommands.set(name, { name, ...options });\n\t\t\t},\n\t\t\tregisterFlag: (name: string, options: any) => {\n\t\t\t\tflags.set(name, { name, hookPath, ...options });\n\t\t\t\tif (options.default !== undefined) {\n\t\t\t\t\tflagValues.set(name, options.default);\n\t\t\t\t}\n\t\t\t},\n\t\t\tgetFlag: (name: string) => flagValues.get(name),\n\t\t\tregisterShortcut: (shortcut: KeyId, options: any) => {\n\t\t\t\tshortcuts.set(shortcut, { shortcut, hookPath, ...options });\n\t\t\t},\n\t\t\tnewSession: (options?: any) => newSessionHandler(options),\n\t\t\tbranch: (entryId: string) => branchHandler(entryId),\n\t\t\tnavigateTree: (targetId: string, options?: any) => navigateTreeHandler(targetId, options),\n\t\t\tgetActiveTools: () => getActiveToolsHandler(),\n\t\t\tgetAllTools: () => getAllToolsHandler(),\n\t\t\tsetActiveTools: (toolNames: string[]) => setActiveToolsHandler(toolNames),\n\t\t};\n\n\t\tdef.factory(api as any);\n\n\t\treturn {\n\t\t\tpath: hookPath,\n\t\t\tresolvedPath: hookPath,\n\t\t\thandlers,\n\t\t\tmessageRenderers,\n\t\t\tcommands,\n\t\t\tflags,\n\t\t\tflagValues,\n\t\t\tshortcuts,\n\t\t\tsetSendMessageHandler: (\n\t\t\t\thandler: (message: any, options?: { triggerTurn?: boolean; deliverAs?: \"steer\" | \"followUp\" }) => void,\n\t\t\t) => {\n\t\t\t\tsendMessageHandler = handler;\n\t\t\t},\n\t\t\tsetAppendEntryHandler: (handler: (customType: string, data?: any) => void) => {\n\t\t\t\tappendEntryHandler = handler;\n\t\t\t},\n\t\t\tsetNewSessionHandler: (handler: (options?: any) => Promise<{ cancelled: boolean }>) => {\n\t\t\t\tnewSessionHandler = handler;\n\t\t\t},\n\t\t\tsetBranchHandler: (handler: (entryId: string) => Promise<{ cancelled: boolean }>) => {\n\t\t\t\tbranchHandler = handler;\n\t\t\t},\n\t\t\tsetNavigateTreeHandler: (handler: (targetId: string, options?: any) => Promise<{ cancelled: boolean }>) => {\n\t\t\t\tnavigateTreeHandler = handler;\n\t\t\t},\n\t\t\tsetGetActiveToolsHandler: (handler: () => string[]) => {\n\t\t\t\tgetActiveToolsHandler = handler;\n\t\t\t},\n\t\t\tsetGetAllToolsHandler: (handler: () => string[]) => {\n\t\t\t\tgetAllToolsHandler = handler;\n\t\t\t},\n\t\t\tsetSetActiveToolsHandler: (handler: (toolNames: string[]) => void) => {\n\t\t\t\tsetActiveToolsHandler = handler;\n\t\t\t},\n\t\t\tsetFlagValue: (name: string, value: boolean | string) => {\n\t\t\t\tflagValues.set(name, value);\n\t\t\t},\n\t\t};\n\t});\n}\n\n// Factory\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * import { getModel } from '@mariozechner/pi-ai';\n * const { session } = await createAgentSession({\n * model: getModel('anthropic', 'claude-opus-4-5'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const { session } = await createAgentSession({\n * model: myModel,\n * getApiKey: async () => process.env.MY_KEY,\n * systemPrompt: 'You are helpful.',\n * tools: [readTool, bashTool],\n * hooks: [],\n * skills: [],\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = options.cwd ?? process.cwd();\n\tconst agentDir = options.agentDir ?? getDefaultAgentDir();\n\n\t// Use provided or create AuthStorage and ModelRegistry\n\tconst authStorage = options.authStorage ?? discoverAuthStorage(agentDir);\n\tconst modelRegistry = options.modelRegistry ?? discoverModels(authStorage, agentDir);\n\ttime(\"discoverModels\");\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\ttime(\"settingsManager\");\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd);\n\ttime(\"sessionManager\");\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.buildSessionContext();\n\ttime(\"loadSession\");\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = modelRegistry.find(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && (await modelRegistry.getApiKey(restoredModel))) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// If still no model, try settings default\n\tif (!model) {\n\t\tconst defaultProvider = settingsManager.getDefaultProvider();\n\t\tconst defaultModelId = settingsManager.getDefaultModel();\n\t\tif (defaultProvider && defaultModelId) {\n\t\t\tconst settingsModel = modelRegistry.find(defaultProvider, defaultModelId);\n\t\t\tif (settingsModel && (await modelRegistry.getApiKey(settingsModel))) {\n\t\t\t\tmodel = settingsModel;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fall back to first available model with a valid API key\n\tif (!model) {\n\t\tfor (const m of modelRegistry.getAll()) {\n\t\t\tif (await modelRegistry.getApiKey(m)) {\n\t\t\t\tmodel = m;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\ttime(\"findAvailableModel\");\n\t\tif (model) {\n\t\t\tif (modelFallbackMessage) {\n\t\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t\t}\n\t\t} else {\n\t\t\t// No models available - set message so user knows to /login or configure keys\n\t\t\tmodelFallbackMessage = \"No models available. Use /login or set an API key environment variable.\";\n\t\t}\n\t}\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = existingSession.thinkingLevel as ThinkingLevel;\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? \"off\";\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model || !model.reasoning) {\n\t\tthinkingLevel = \"off\";\n\t}\n\n\tconst skills = options.skills ?? discoverSkills(cwd, agentDir, settingsManager.getSkillsSettings());\n\ttime(\"discoverSkills\");\n\n\tconst contextFiles = options.contextFiles ?? discoverContextFiles(cwd, agentDir);\n\ttime(\"discoverContextFiles\");\n\n\tconst autoResizeImages = settingsManager.getImageAutoResize();\n\t// Create ALL built-in tools for the registry (hooks can enable any of them)\n\tconst allBuiltInToolsMap = createAllTools(cwd, { read: { autoResizeImages } });\n\t// Determine initially active built-in tools (default: read, bash, edit, write)\n\tconst defaultActiveToolNames: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst initialActiveToolNames: ToolName[] = options.tools\n\t\t? options.tools.map((t) => t.name).filter((n): n is ToolName => n in allBuiltInToolsMap)\n\t\t: defaultActiveToolNames;\n\tconst initialActiveBuiltInTools = initialActiveToolNames.map((name) => allBuiltInToolsMap[name]);\n\ttime(\"createAllTools\");\n\n\tlet customToolsResult: CustomToolsLoadResult;\n\tif (options.customTools !== undefined) {\n\t\t// Use provided custom tools\n\t\tconst loadedTools: LoadedCustomTool[] = options.customTools.map((ct) => ({\n\t\t\tpath: ct.path ?? \"<inline>\",\n\t\t\tresolvedPath: ct.path ?? \"<inline>\",\n\t\t\ttool: ct.tool,\n\t\t}));\n\t\tcustomToolsResult = {\n\t\t\ttools: loadedTools,\n\t\t\terrors: [],\n\t\t\tsetUIContext: () => {},\n\t\t};\n\t} else {\n\t\t// Discover custom tools, merging with additional paths\n\t\tconst configuredPaths = [...settingsManager.getCustomToolPaths(), ...(options.additionalCustomToolPaths ?? [])];\n\t\tcustomToolsResult = await discoverAndLoadCustomTools(configuredPaths, cwd, Object.keys(allTools), agentDir);\n\t\ttime(\"discoverAndLoadCustomTools\");\n\t\tfor (const { path, error } of customToolsResult.errors) {\n\t\t\tconsole.error(`Failed to load custom tool \"${path}\": ${error}`);\n\t\t}\n\t}\n\n\tlet hookRunner: HookRunner | undefined;\n\tif (options.preloadedHooks !== undefined && options.preloadedHooks.length > 0) {\n\t\t// Use pre-loaded hooks (from early CLI flag discovery)\n\t\thookRunner = new HookRunner(options.preloadedHooks, cwd, sessionManager, modelRegistry);\n\t} else if (options.hooks !== undefined) {\n\t\tif (options.hooks.length > 0) {\n\t\t\tconst loadedHooks = createLoadedHooksFromDefinitions(options.hooks);\n\t\t\thookRunner = new HookRunner(loadedHooks, cwd, sessionManager, modelRegistry);\n\t\t}\n\t} else {\n\t\t// Discover hooks, merging with additional paths\n\t\tconst configuredPaths = [...settingsManager.getHookPaths(), ...(options.additionalHookPaths ?? [])];\n\t\tconst { hooks, errors } = await discoverAndLoadHooks(configuredPaths, cwd, agentDir);\n\t\ttime(\"discoverAndLoadHooks\");\n\t\tfor (const { path, error } of errors) {\n\t\t\tconsole.error(`Failed to load hook \"${path}\": ${error}`);\n\t\t}\n\t\tif (hooks.length > 0) {\n\t\t\thookRunner = new HookRunner(hooks, cwd, sessionManager, modelRegistry);\n\t\t}\n\t}\n\n\t// Wrap custom tools with context getter (agent/session assigned below, accessed at execute time)\n\tlet agent: Agent;\n\tlet session: AgentSession;\n\tconst wrappedCustomTools = wrapCustomTools(customToolsResult.tools, () => ({\n\t\tsessionManager,\n\t\tmodelRegistry,\n\t\tmodel: agent.state.model,\n\t\tisIdle: () => !session.isStreaming,\n\t\thasPendingMessages: () => session.pendingMessageCount > 0,\n\t\tabort: () => {\n\t\t\tsession.abort();\n\t\t},\n\t}));\n\n\t// Create tool registry mapping name -> tool (for hook getTools/setTools)\n\t// Registry contains ALL built-in tools so hooks can enable any of them\n\tconst toolRegistry = new Map<string, AgentTool>();\n\tfor (const [name, tool] of Object.entries(allBuiltInToolsMap)) {\n\t\ttoolRegistry.set(name, tool as AgentTool);\n\t}\n\tfor (const tool of wrappedCustomTools as AgentTool[]) {\n\t\ttoolRegistry.set(tool.name, tool);\n\t}\n\n\t// Initially active tools = active built-in + custom\n\tlet activeToolsArray: Tool[] = [...initialActiveBuiltInTools, ...wrappedCustomTools];\n\ttime(\"combineTools\");\n\n\t// Wrap tools with hooks if available\n\tlet wrappedToolRegistry: Map<string, AgentTool> | undefined;\n\tif (hookRunner) {\n\t\tactiveToolsArray = wrapToolsWithHooks(activeToolsArray as AgentTool[], hookRunner);\n\t\t// Wrap ALL registry tools (not just active) so hooks can enable any\n\t\tconst allRegistryTools = Array.from(toolRegistry.values());\n\t\tconst wrappedAllTools = wrapToolsWithHooks(allRegistryTools, hookRunner);\n\t\twrappedToolRegistry = new Map<string, AgentTool>();\n\t\tfor (const tool of wrappedAllTools) {\n\t\t\twrappedToolRegistry.set(tool.name, tool);\n\t\t}\n\t}\n\n\t// Function to rebuild system prompt when tools change\n\t// Captures static options (cwd, agentDir, skills, contextFiles, customPrompt)\n\tconst rebuildSystemPrompt = (toolNames: string[]): string => {\n\t\t// Filter to valid tool names\n\t\tconst validToolNames = toolNames.filter((n): n is ToolName => n in allBuiltInToolsMap);\n\t\tconst defaultPrompt = buildSystemPromptInternal({\n\t\t\tcwd,\n\t\t\tagentDir,\n\t\t\tskills,\n\t\t\tcontextFiles,\n\t\t\tselectedTools: validToolNames,\n\t\t});\n\n\t\tif (options.systemPrompt === undefined) {\n\t\t\treturn defaultPrompt;\n\t\t} else if (typeof options.systemPrompt === \"string\") {\n\t\t\treturn buildSystemPromptInternal({\n\t\t\t\tcwd,\n\t\t\t\tagentDir,\n\t\t\t\tskills,\n\t\t\t\tcontextFiles,\n\t\t\t\tselectedTools: validToolNames,\n\t\t\t\tcustomPrompt: options.systemPrompt,\n\t\t\t});\n\t\t} else {\n\t\t\treturn options.systemPrompt(defaultPrompt);\n\t\t}\n\t};\n\n\tconst systemPrompt = rebuildSystemPrompt(initialActiveToolNames);\n\ttime(\"buildSystemPrompt\");\n\n\tconst slashCommands = options.slashCommands ?? discoverSlashCommands(cwd, agentDir);\n\ttime(\"discoverSlashCommands\");\n\n\tagent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt,\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: activeToolsArray,\n\t\t},\n\t\tconvertToLlm,\n\t\ttransformContext: hookRunner\n\t\t\t? async (messages) => {\n\t\t\t\t\treturn hookRunner.emitContext(messages);\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tsteeringMode: settingsManager.getSteeringMode(),\n\t\tfollowUpMode: settingsManager.getFollowUpMode(),\n\t\tgetApiKey: async () => {\n\t\t\tconst currentModel = agent.state.model;\n\t\t\tif (!currentModel) {\n\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t}\n\t\t\tconst key = await modelRegistry.getApiKey(currentModel);\n\t\t\tif (!key) {\n\t\t\t\tthrow new Error(`No API key found for provider \"${currentModel.provider}\"`);\n\t\t\t}\n\t\t\treturn key;\n\t\t},\n\t});\n\ttime(\"createAgent\");\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.replaceMessages(existingSession.messages);\n\t} else {\n\t\t// Save initial model and thinking level for new sessions so they can be restored on resume\n\t\tif (model) {\n\t\t\tsessionManager.appendModelChange(model.provider, model.id);\n\t\t}\n\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t}\n\n\tsession = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tscopedModels: options.scopedModels,\n\t\tfileCommands: slashCommands,\n\t\thookRunner,\n\t\tcustomTools: customToolsResult.tools,\n\t\tskillsSettings: settingsManager.getSkillsSettings(),\n\t\tmodelRegistry,\n\t\ttoolRegistry: wrappedToolRegistry ?? toolRegistry,\n\t\trebuildSystemPrompt,\n\t});\n\ttime(\"createAgentSession\");\n\n\treturn {\n\t\tsession,\n\t\tcustomToolsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
1
+ {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SDK for programmatic usage of AgentSession.\n *\n * Provides a factory function and discovery helpers that allow full control\n * over agent configuration, or sensible defaults that match CLI behavior.\n *\n * @example\n * ```typescript\n * // Minimal - everything auto-discovered\n * const session = await createAgentSession();\n *\n * // Full control\n * const session = await createAgentSession({\n * model: myModel,\n * getApiKey: async () => process.env.MY_KEY,\n * tools: [readTool, bashTool],\n * skills: [],\n * sessionFile: false,\n * });\n * ```\n */\n\nimport { Agent, type AgentTool, type ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport type { Model } from \"@mariozechner/pi-ai\";\nimport { join } from \"path\";\nimport { getAgentDir } from \"../config.js\";\nimport { AgentSession } from \"./agent-session.js\";\nimport { AuthStorage } from \"./auth-storage.js\";\nimport { createEventBus, type EventBus } from \"./event-bus.js\";\nimport {\n\tdiscoverAndLoadExtensions,\n\ttype ExtensionFactory,\n\tExtensionRunner,\n\ttype LoadExtensionsResult,\n\ttype LoadedExtension,\n\tloadExtensionFromFactory,\n\ttype ToolDefinition,\n\twrapRegisteredTools,\n\twrapToolsWithExtensions,\n} from \"./extensions/index.js\";\nimport { convertToLlm } from \"./messages.js\";\nimport { ModelRegistry } from \"./model-registry.js\";\nimport { loadPromptTemplates as loadPromptTemplatesInternal, type PromptTemplate } from \"./prompt-templates.js\";\nimport { SessionManager } from \"./session-manager.js\";\nimport { type Settings, SettingsManager, type SkillsSettings } from \"./settings-manager.js\";\nimport { loadSkills as loadSkillsInternal, type Skill } from \"./skills.js\";\nimport {\n\tbuildSystemPrompt as buildSystemPromptInternal,\n\tloadProjectContextFiles as loadContextFilesInternal,\n} from \"./system-prompt.js\";\nimport { time } from \"./timings.js\";\nimport {\n\tallTools,\n\tbashTool,\n\tcodingTools,\n\tcreateAllTools,\n\tcreateBashTool,\n\tcreateCodingTools,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\teditTool,\n\tfindTool,\n\tgrepTool,\n\tlsTool,\n\treadOnlyTools,\n\treadTool,\n\ttype Tool,\n\ttype ToolName,\n\twriteTool,\n} from \"./tools/index.js\";\n\n// Types\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.pi/agent */\n\tagentDir?: string;\n\n\t/** Auth storage for credentials. Default: discoverAuthStorage(agentDir) */\n\tauthStorage?: AuthStorage;\n\t/** Model registry. Default: discoverModels(authStorage, agentDir) */\n\tmodelRegistry?: ModelRegistry;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'off' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;\n\n\t/** System prompt. String replaces default, function receives default and returns final. */\n\tsystemPrompt?: string | ((defaultPrompt: string) => string);\n\n\t/** Built-in tools to use. Default: codingTools [read, bash, edit, write] */\n\ttools?: Tool[];\n\t/** Custom tools to register (in addition to built-in tools). */\n\tcustomTools?: ToolDefinition[];\n\t/** Inline extensions (merged with discovery). */\n\textensions?: ExtensionFactory[];\n\t/** Additional extension paths to load (merged with discovery). */\n\tadditionalExtensionPaths?: string[];\n\t/**\n\t * Pre-loaded extensions (skips file discovery).\n\t * @internal Used by CLI when extensions are loaded early to parse custom flags.\n\t */\n\tpreloadedExtensions?: LoadedExtension[];\n\n\t/** Shared event bus for tool/extension communication. Default: creates new bus. */\n\teventBus?: EventBus;\n\n\t/** Skills. Default: discovered from multiple locations */\n\tskills?: Skill[];\n\t/** Context files (AGENTS.md content). Default: discovered walking up from cwd */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Prompt templates. Default: discovered from cwd/.pi/prompts/ + agentDir/prompts/ */\n\tpromptTemplates?: PromptTemplate[];\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n}\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Extensions result (for UI context setup in interactive mode) */\n\textensionsResult: LoadExtensionsResult;\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport type {\n\tExtensionAPI,\n\tExtensionCommandContext,\n\tExtensionContext,\n\tExtensionFactory,\n\tToolDefinition,\n} from \"./extensions/index.js\";\nexport type { PromptTemplate } from \"./prompt-templates.js\";\nexport type { Settings, SkillsSettings } from \"./settings-manager.js\";\nexport type { Skill } from \"./skills.js\";\nexport type { Tool } from \"./tools/index.js\";\n\nexport {\n\t// Pre-built tools (use process.cwd())\n\treadTool,\n\tbashTool,\n\teditTool,\n\twriteTool,\n\tgrepTool,\n\tfindTool,\n\tlsTool,\n\tcodingTools,\n\treadOnlyTools,\n\tallTools as allBuiltInTools,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateBashTool,\n\tcreateEditTool,\n\tcreateWriteTool,\n\tcreateGrepTool,\n\tcreateFindTool,\n\tcreateLsTool,\n};\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\n// Discovery Functions\n\n/**\n * Create an AuthStorage instance for the given agent directory.\n */\nexport function discoverAuthStorage(agentDir: string = getDefaultAgentDir()): AuthStorage {\n\treturn new AuthStorage(join(agentDir, \"auth.json\"));\n}\n\n/**\n * Create a ModelRegistry for the given agent directory.\n */\nexport function discoverModels(authStorage: AuthStorage, agentDir: string = getDefaultAgentDir()): ModelRegistry {\n\treturn new ModelRegistry(authStorage, join(agentDir, \"models.json\"));\n}\n\n/**\n * Discover extensions from cwd and agentDir.\n * @param eventBus - Shared event bus for extension communication. Pass to createAgentSession too.\n * @param cwd - Current working directory\n * @param agentDir - Agent configuration directory\n */\nexport async function discoverExtensions(\n\teventBus: EventBus,\n\tcwd?: string,\n\tagentDir?: string,\n): Promise<LoadExtensionsResult> {\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst result = await discoverAndLoadExtensions([], resolvedCwd, resolvedAgentDir, eventBus);\n\n\t// Log errors but don't fail\n\tfor (const { path, error } of result.errors) {\n\t\tconsole.error(`Failed to load extension \"${path}\": ${error}`);\n\t}\n\n\treturn result;\n}\n\n/**\n * Discover skills from cwd and agentDir.\n */\nexport function discoverSkills(cwd?: string, agentDir?: string, settings?: SkillsSettings): Skill[] {\n\tconst { skills } = loadSkillsInternal({\n\t\t...settings,\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n\treturn skills;\n}\n\n/**\n * Discover context files (AGENTS.md) walking up from cwd.\n */\nexport function discoverContextFiles(cwd?: string, agentDir?: string): Array<{ path: string; content: string }> {\n\treturn loadContextFilesInternal({\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n}\n\n/**\n * Discover prompt templates from cwd and agentDir.\n */\nexport function discoverPromptTemplates(cwd?: string, agentDir?: string): PromptTemplate[] {\n\treturn loadPromptTemplatesInternal({\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n}\n\n// API Key Helpers\n\n// System Prompt\n\nexport interface BuildSystemPromptOptions {\n\ttools?: Tool[];\n\tskills?: Skill[];\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\tcwd?: string;\n\tappendPrompt?: string;\n}\n\n/**\n * Build the default system prompt.\n */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\treturn buildSystemPromptInternal({\n\t\tcwd: options.cwd,\n\t\tskills: options.skills,\n\t\tcontextFiles: options.contextFiles,\n\t\tappendSystemPrompt: options.appendPrompt,\n\t});\n}\n\n// Settings\n\n/**\n * Load settings from agentDir/settings.json merged with cwd/.pi/settings.json.\n */\nexport function loadSettings(cwd?: string, agentDir?: string): Settings {\n\tconst manager = SettingsManager.create(cwd ?? process.cwd(), agentDir ?? getDefaultAgentDir());\n\treturn {\n\t\tdefaultProvider: manager.getDefaultProvider(),\n\t\tdefaultModel: manager.getDefaultModel(),\n\t\tdefaultThinkingLevel: manager.getDefaultThinkingLevel(),\n\t\tsteeringMode: manager.getSteeringMode(),\n\t\tfollowUpMode: manager.getFollowUpMode(),\n\t\ttheme: manager.getTheme(),\n\t\tcompaction: manager.getCompactionSettings(),\n\t\tretry: manager.getRetrySettings(),\n\t\thideThinkingBlock: manager.getHideThinkingBlock(),\n\t\tshellPath: manager.getShellPath(),\n\t\tcollapseChangelog: manager.getCollapseChangelog(),\n\t\textensions: manager.getExtensionPaths(),\n\t\tskills: manager.getSkillsSettings(),\n\t\tterminal: { showImages: manager.getShowImages() },\n\t};\n}\n\n// Factory\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * import { getModel } from '@mariozechner/pi-ai';\n * const { session } = await createAgentSession({\n * model: getModel('anthropic', 'claude-opus-4-5'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const { session } = await createAgentSession({\n * model: myModel,\n * getApiKey: async () => process.env.MY_KEY,\n * systemPrompt: 'You are helpful.',\n * tools: [readTool, bashTool],\n * skills: [],\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = options.cwd ?? process.cwd();\n\tconst agentDir = options.agentDir ?? getDefaultAgentDir();\n\tconst eventBus = options.eventBus ?? createEventBus();\n\n\t// Use provided or create AuthStorage and ModelRegistry\n\tconst authStorage = options.authStorage ?? discoverAuthStorage(agentDir);\n\tconst modelRegistry = options.modelRegistry ?? discoverModels(authStorage, agentDir);\n\ttime(\"discoverModels\");\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\ttime(\"settingsManager\");\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd);\n\ttime(\"sessionManager\");\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.buildSessionContext();\n\ttime(\"loadSession\");\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = modelRegistry.find(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && (await modelRegistry.getApiKey(restoredModel))) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// If still no model, try settings default\n\tif (!model) {\n\t\tconst defaultProvider = settingsManager.getDefaultProvider();\n\t\tconst defaultModelId = settingsManager.getDefaultModel();\n\t\tif (defaultProvider && defaultModelId) {\n\t\t\tconst settingsModel = modelRegistry.find(defaultProvider, defaultModelId);\n\t\t\tif (settingsModel && (await modelRegistry.getApiKey(settingsModel))) {\n\t\t\t\tmodel = settingsModel;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fall back to first available model with a valid API key\n\tif (!model) {\n\t\tfor (const m of modelRegistry.getAll()) {\n\t\t\tif (await modelRegistry.getApiKey(m)) {\n\t\t\t\tmodel = m;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\ttime(\"findAvailableModel\");\n\t\tif (model) {\n\t\t\tif (modelFallbackMessage) {\n\t\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t\t}\n\t\t} else {\n\t\t\t// No models available - set message so user knows to /login or configure keys\n\t\t\tmodelFallbackMessage = \"No models available. Use /login or set an API key environment variable.\";\n\t\t}\n\t}\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = existingSession.thinkingLevel as ThinkingLevel;\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? \"off\";\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model || !model.reasoning) {\n\t\tthinkingLevel = \"off\";\n\t}\n\n\tconst skills = options.skills ?? discoverSkills(cwd, agentDir, settingsManager.getSkillsSettings());\n\ttime(\"discoverSkills\");\n\n\tconst contextFiles = options.contextFiles ?? discoverContextFiles(cwd, agentDir);\n\ttime(\"discoverContextFiles\");\n\n\tconst autoResizeImages = settingsManager.getImageAutoResize();\n\t// Create ALL built-in tools for the registry (extensions can enable any of them)\n\tconst allBuiltInToolsMap = createAllTools(cwd, { read: { autoResizeImages } });\n\t// Determine initially active built-in tools (default: read, bash, edit, write)\n\tconst defaultActiveToolNames: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst initialActiveToolNames: ToolName[] = options.tools\n\t\t? options.tools.map((t) => t.name).filter((n): n is ToolName => n in allBuiltInToolsMap)\n\t\t: defaultActiveToolNames;\n\tconst initialActiveBuiltInTools = initialActiveToolNames.map((name) => allBuiltInToolsMap[name]);\n\ttime(\"createAllTools\");\n\n\t// Load extensions (discovers from standard locations + configured paths)\n\tlet extensionsResult: LoadExtensionsResult;\n\tif (options.preloadedExtensions !== undefined && options.preloadedExtensions.length > 0) {\n\t\t// Use pre-loaded extensions (from early CLI flag discovery)\n\t\textensionsResult = {\n\t\t\textensions: options.preloadedExtensions,\n\t\t\terrors: [],\n\t\t\tsetUIContext: () => {},\n\t\t};\n\t} else {\n\t\t// Discover extensions, merging with additional paths\n\t\tconst configuredPaths = [...settingsManager.getExtensionPaths(), ...(options.additionalExtensionPaths ?? [])];\n\t\textensionsResult = await discoverAndLoadExtensions(configuredPaths, cwd, agentDir, eventBus);\n\t\ttime(\"discoverAndLoadExtensions\");\n\t\tfor (const { path, error } of extensionsResult.errors) {\n\t\t\tconsole.error(`Failed to load extension \"${path}\": ${error}`);\n\t\t}\n\t}\n\n\t// Load inline extensions from factories\n\tif (options.extensions && options.extensions.length > 0) {\n\t\t// Create shared UI context holder that will be set later\n\t\tconst uiHolder: { ui: any; hasUI: boolean } = {\n\t\t\tui: {\n\t\t\t\tselect: async () => undefined,\n\t\t\t\tconfirm: async () => false,\n\t\t\t\tinput: async () => undefined,\n\t\t\t\tnotify: () => {},\n\t\t\t\tsetStatus: () => {},\n\t\t\t\tsetWidget: () => {},\n\t\t\t\tsetTitle: () => {},\n\t\t\t\tcustom: async () => undefined as never,\n\t\t\t\tsetEditorText: () => {},\n\t\t\t\tgetEditorText: () => \"\",\n\t\t\t\teditor: async () => undefined,\n\t\t\t\tget theme() {\n\t\t\t\t\treturn {} as any;\n\t\t\t\t},\n\t\t\t},\n\t\t\thasUI: false,\n\t\t};\n\t\tfor (let i = 0; i < options.extensions.length; i++) {\n\t\t\tconst factory = options.extensions[i];\n\t\t\tconst loaded = loadExtensionFromFactory(factory, cwd, eventBus, uiHolder, `<inline-${i}>`);\n\t\t\textensionsResult.extensions.push(loaded);\n\t\t}\n\t\t// Extend setUIContext to update inline extensions too\n\t\tconst originalSetUIContext = extensionsResult.setUIContext;\n\t\textensionsResult.setUIContext = (uiContext, hasUI) => {\n\t\t\toriginalSetUIContext(uiContext, hasUI);\n\t\t\tuiHolder.ui = uiContext;\n\t\t\tuiHolder.hasUI = hasUI;\n\t\t};\n\t}\n\n\t// Create extension runner if we have extensions\n\tlet extensionRunner: ExtensionRunner | undefined;\n\tif (extensionsResult.extensions.length > 0) {\n\t\textensionRunner = new ExtensionRunner(extensionsResult.extensions, cwd, sessionManager, modelRegistry);\n\t}\n\n\t// Wrap extension-registered tools and SDK-provided custom tools with context getter\n\t// (agent/session assigned below, accessed at execute time)\n\tlet agent: Agent;\n\tlet session: AgentSession;\n\tconst registeredTools = extensionRunner?.getAllRegisteredTools() ?? [];\n\t// Combine extension-registered tools with SDK-provided custom tools\n\tconst allCustomTools = [\n\t\t...registeredTools,\n\t\t...(options.customTools?.map((def) => ({ definition: def, extensionPath: \"<sdk>\" })) ?? []),\n\t];\n\tconst wrappedExtensionTools = wrapRegisteredTools(allCustomTools, () => ({\n\t\tui: extensionRunner?.getUIContext() ?? {\n\t\t\tselect: async () => undefined,\n\t\t\tconfirm: async () => false,\n\t\t\tinput: async () => undefined,\n\t\t\tnotify: () => {},\n\t\t\tsetStatus: () => {},\n\t\t\tsetWidget: () => {},\n\t\t\tsetTitle: () => {},\n\t\t\tcustom: async () => undefined as never,\n\t\t\tsetEditorText: () => {},\n\t\t\tgetEditorText: () => \"\",\n\t\t\teditor: async () => undefined,\n\t\t\tget theme() {\n\t\t\t\treturn {} as any;\n\t\t\t},\n\t\t},\n\t\thasUI: extensionRunner?.getHasUI() ?? false,\n\t\tcwd,\n\t\tsessionManager,\n\t\tmodelRegistry,\n\t\tmodel: agent.state.model,\n\t\tisIdle: () => !session.isStreaming,\n\t\thasPendingMessages: () => session.pendingMessageCount > 0,\n\t\tabort: () => {\n\t\t\tsession.abort();\n\t\t},\n\t}));\n\n\t// Create tool registry mapping name -> tool (for extension getTools/setTools)\n\t// Registry contains ALL built-in tools so extensions can enable any of them\n\tconst toolRegistry = new Map<string, AgentTool>();\n\tfor (const [name, tool] of Object.entries(allBuiltInToolsMap)) {\n\t\ttoolRegistry.set(name, tool as AgentTool);\n\t}\n\tfor (const tool of wrappedExtensionTools as AgentTool[]) {\n\t\ttoolRegistry.set(tool.name, tool);\n\t}\n\n\t// Initially active tools = active built-in + extension tools\n\tlet activeToolsArray: Tool[] = [...initialActiveBuiltInTools, ...wrappedExtensionTools];\n\ttime(\"combineTools\");\n\n\t// Wrap tools with extensions if available\n\tlet wrappedToolRegistry: Map<string, AgentTool> | undefined;\n\tif (extensionRunner) {\n\t\tactiveToolsArray = wrapToolsWithExtensions(activeToolsArray as AgentTool[], extensionRunner);\n\t\t// Wrap ALL registry tools (not just active) so extensions can enable any\n\t\tconst allRegistryTools = Array.from(toolRegistry.values());\n\t\tconst wrappedAllTools = wrapToolsWithExtensions(allRegistryTools, extensionRunner);\n\t\twrappedToolRegistry = new Map<string, AgentTool>();\n\t\tfor (const tool of wrappedAllTools) {\n\t\t\twrappedToolRegistry.set(tool.name, tool);\n\t\t}\n\t}\n\n\t// Function to rebuild system prompt when tools change\n\t// Captures static options (cwd, agentDir, skills, contextFiles, customPrompt)\n\tconst rebuildSystemPrompt = (toolNames: string[]): string => {\n\t\t// Filter to valid tool names\n\t\tconst validToolNames = toolNames.filter((n): n is ToolName => n in allBuiltInToolsMap);\n\t\tconst defaultPrompt = buildSystemPromptInternal({\n\t\t\tcwd,\n\t\t\tagentDir,\n\t\t\tskills,\n\t\t\tcontextFiles,\n\t\t\tselectedTools: validToolNames,\n\t\t});\n\n\t\tif (options.systemPrompt === undefined) {\n\t\t\treturn defaultPrompt;\n\t\t} else if (typeof options.systemPrompt === \"string\") {\n\t\t\treturn buildSystemPromptInternal({\n\t\t\t\tcwd,\n\t\t\t\tagentDir,\n\t\t\t\tskills,\n\t\t\t\tcontextFiles,\n\t\t\t\tselectedTools: validToolNames,\n\t\t\t\tcustomPrompt: options.systemPrompt,\n\t\t\t});\n\t\t} else {\n\t\t\treturn options.systemPrompt(defaultPrompt);\n\t\t}\n\t};\n\n\tconst systemPrompt = rebuildSystemPrompt(initialActiveToolNames);\n\ttime(\"buildSystemPrompt\");\n\n\tconst promptTemplates = options.promptTemplates ?? discoverPromptTemplates(cwd, agentDir);\n\ttime(\"discoverPromptTemplates\");\n\n\tagent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt,\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: activeToolsArray,\n\t\t},\n\t\tconvertToLlm,\n\t\ttransformContext: extensionRunner\n\t\t\t? async (messages) => {\n\t\t\t\t\treturn extensionRunner.emitContext(messages);\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tsteeringMode: settingsManager.getSteeringMode(),\n\t\tfollowUpMode: settingsManager.getFollowUpMode(),\n\t\tgetApiKey: async () => {\n\t\t\tconst currentModel = agent.state.model;\n\t\t\tif (!currentModel) {\n\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t}\n\t\t\tconst key = await modelRegistry.getApiKey(currentModel);\n\t\t\tif (!key) {\n\t\t\t\tthrow new Error(`No API key found for provider \"${currentModel.provider}\"`);\n\t\t\t}\n\t\t\treturn key;\n\t\t},\n\t});\n\ttime(\"createAgent\");\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.replaceMessages(existingSession.messages);\n\t} else {\n\t\t// Save initial model and thinking level for new sessions so they can be restored on resume\n\t\tif (model) {\n\t\t\tsessionManager.appendModelChange(model.provider, model.id);\n\t\t}\n\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t}\n\n\tsession = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tscopedModels: options.scopedModels,\n\t\tpromptTemplates: promptTemplates,\n\t\textensionRunner,\n\t\tskillsSettings: settingsManager.getSkillsSettings(),\n\t\tmodelRegistry,\n\t\ttoolRegistry: wrappedToolRegistry ?? toolRegistry,\n\t\trebuildSystemPrompt,\n\t});\n\ttime(\"createAgentSession\");\n\n\treturn {\n\t\tsession,\n\t\textensionsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
package/dist/core/sdk.js CHANGED
@@ -9,20 +9,11 @@
9
9
  * // Minimal - everything auto-discovered
10
10
  * const session = await createAgentSession();
11
11
  *
12
- * // With custom hooks
13
- * const session = await createAgentSession({
14
- * hooks: [
15
- * ...await discoverHooks(),
16
- * { factory: myHookFactory },
17
- * ],
18
- * });
19
- *
20
12
  * // Full control
21
13
  * const session = await createAgentSession({
22
14
  * model: myModel,
23
15
  * getApiKey: async () => process.env.MY_KEY,
24
16
  * tools: [readTool, bashTool],
25
- * hooks: [],
26
17
  * skills: [],
27
18
  * sessionFile: false,
28
19
  * });
@@ -33,14 +24,14 @@ import { join } from "path";
33
24
  import { getAgentDir } from "../config.js";
34
25
  import { AgentSession } from "./agent-session.js";
35
26
  import { AuthStorage } from "./auth-storage.js";
36
- import { discoverAndLoadCustomTools, wrapCustomTools, } from "./custom-tools/index.js";
37
- import { discoverAndLoadHooks, HookRunner, wrapToolsWithHooks } from "./hooks/index.js";
27
+ import { createEventBus } from "./event-bus.js";
28
+ import { discoverAndLoadExtensions, ExtensionRunner, loadExtensionFromFactory, wrapRegisteredTools, wrapToolsWithExtensions, } from "./extensions/index.js";
38
29
  import { convertToLlm } from "./messages.js";
39
30
  import { ModelRegistry } from "./model-registry.js";
31
+ import { loadPromptTemplates as loadPromptTemplatesInternal } from "./prompt-templates.js";
40
32
  import { SessionManager } from "./session-manager.js";
41
33
  import { SettingsManager } from "./settings-manager.js";
42
34
  import { loadSkills as loadSkillsInternal } from "./skills.js";
43
- import { loadSlashCommands as loadSlashCommandsInternal } from "./slash-commands.js";
44
35
  import { buildSystemPrompt as buildSystemPromptInternal, loadProjectContextFiles as loadContextFilesInternal, } from "./system-prompt.js";
45
36
  import { time } from "./timings.js";
46
37
  import { allTools, bashTool, codingTools, createAllTools, createBashTool, createCodingTools, createEditTool, createFindTool, createGrepTool, createLsTool, createReadOnlyTools, createReadTool, createWriteTool, editTool, findTool, grepTool, lsTool, readOnlyTools, readTool, writeTool, } from "./tools/index.js";
@@ -67,36 +58,20 @@ export function discoverModels(authStorage, agentDir = getDefaultAgentDir()) {
67
58
  return new ModelRegistry(authStorage, join(agentDir, "models.json"));
68
59
  }
69
60
  /**
70
- * Discover hooks from cwd and agentDir.
61
+ * Discover extensions from cwd and agentDir.
62
+ * @param eventBus - Shared event bus for extension communication. Pass to createAgentSession too.
63
+ * @param cwd - Current working directory
64
+ * @param agentDir - Agent configuration directory
71
65
  */
72
- export async function discoverHooks(cwd, agentDir) {
66
+ export async function discoverExtensions(eventBus, cwd, agentDir) {
73
67
  const resolvedCwd = cwd ?? process.cwd();
74
68
  const resolvedAgentDir = agentDir ?? getDefaultAgentDir();
75
- const { hooks, errors } = await discoverAndLoadHooks([], resolvedCwd, resolvedAgentDir);
69
+ const result = await discoverAndLoadExtensions([], resolvedCwd, resolvedAgentDir, eventBus);
76
70
  // Log errors but don't fail
77
- for (const { path, error } of errors) {
78
- console.error(`Failed to load hook "${path}": ${error}`);
71
+ for (const { path, error } of result.errors) {
72
+ console.error(`Failed to load extension "${path}": ${error}`);
79
73
  }
80
- return hooks.map((h) => ({
81
- path: h.path,
82
- factory: createFactoryFromLoadedHook(h),
83
- }));
84
- }
85
- /**
86
- * Discover custom tools from cwd and agentDir.
87
- */
88
- export async function discoverCustomTools(cwd, agentDir) {
89
- const resolvedCwd = cwd ?? process.cwd();
90
- const resolvedAgentDir = agentDir ?? getDefaultAgentDir();
91
- const { tools, errors } = await discoverAndLoadCustomTools([], resolvedCwd, Object.keys(allTools), resolvedAgentDir);
92
- // Log errors but don't fail
93
- for (const { path, error } of errors) {
94
- console.error(`Failed to load custom tool "${path}": ${error}`);
95
- }
96
- return tools.map((t) => ({
97
- path: t.path,
98
- tool: t.tool,
99
- }));
74
+ return result;
100
75
  }
101
76
  /**
102
77
  * Discover skills from cwd and agentDir.
@@ -119,10 +94,10 @@ export function discoverContextFiles(cwd, agentDir) {
119
94
  });
120
95
  }
121
96
  /**
122
- * Discover slash commands from cwd and agentDir.
97
+ * Discover prompt templates from cwd and agentDir.
123
98
  */
124
- export function discoverSlashCommands(cwd, agentDir) {
125
- return loadSlashCommandsInternal({
99
+ export function discoverPromptTemplates(cwd, agentDir) {
100
+ return loadPromptTemplatesInternal({
126
101
  cwd: cwd ?? process.cwd(),
127
102
  agentDir: agentDir ?? getDefaultAgentDir(),
128
103
  });
@@ -156,123 +131,11 @@ export function loadSettings(cwd, agentDir) {
156
131
  hideThinkingBlock: manager.getHideThinkingBlock(),
157
132
  shellPath: manager.getShellPath(),
158
133
  collapseChangelog: manager.getCollapseChangelog(),
159
- hooks: manager.getHookPaths(),
160
- customTools: manager.getCustomToolPaths(),
134
+ extensions: manager.getExtensionPaths(),
161
135
  skills: manager.getSkillsSettings(),
162
136
  terminal: { showImages: manager.getShowImages() },
163
137
  };
164
138
  }
165
- // Internal Helpers
166
- /**
167
- * Create a HookFactory from a LoadedHook.
168
- * This allows mixing discovered hooks with inline hooks.
169
- */
170
- function createFactoryFromLoadedHook(loaded) {
171
- return (api) => {
172
- for (const [eventType, handlers] of loaded.handlers) {
173
- for (const handler of handlers) {
174
- api.on(eventType, handler);
175
- }
176
- }
177
- };
178
- }
179
- /**
180
- * Convert hook definitions to LoadedHooks for the HookRunner.
181
- */
182
- function createLoadedHooksFromDefinitions(definitions) {
183
- return definitions.map((def) => {
184
- const hookPath = def.path ?? "<inline>";
185
- const handlers = new Map();
186
- const messageRenderers = new Map();
187
- const commands = new Map();
188
- const flags = new Map();
189
- const flagValues = new Map();
190
- const shortcuts = new Map();
191
- let sendMessageHandler = () => { };
192
- let appendEntryHandler = () => { };
193
- let getActiveToolsHandler = () => [];
194
- let getAllToolsHandler = () => [];
195
- let setActiveToolsHandler = () => { };
196
- let newSessionHandler = async () => ({ cancelled: false });
197
- let branchHandler = async () => ({ cancelled: false });
198
- let navigateTreeHandler = async () => ({
199
- cancelled: false,
200
- });
201
- const api = {
202
- on: (event, handler) => {
203
- const list = handlers.get(event) ?? [];
204
- list.push(handler);
205
- handlers.set(event, list);
206
- },
207
- sendMessage: (message, options) => {
208
- sendMessageHandler(message, options);
209
- },
210
- appendEntry: (customType, data) => {
211
- appendEntryHandler(customType, data);
212
- },
213
- registerMessageRenderer: (customType, renderer) => {
214
- messageRenderers.set(customType, renderer);
215
- },
216
- registerCommand: (name, options) => {
217
- commands.set(name, { name, ...options });
218
- },
219
- registerFlag: (name, options) => {
220
- flags.set(name, { name, hookPath, ...options });
221
- if (options.default !== undefined) {
222
- flagValues.set(name, options.default);
223
- }
224
- },
225
- getFlag: (name) => flagValues.get(name),
226
- registerShortcut: (shortcut, options) => {
227
- shortcuts.set(shortcut, { shortcut, hookPath, ...options });
228
- },
229
- newSession: (options) => newSessionHandler(options),
230
- branch: (entryId) => branchHandler(entryId),
231
- navigateTree: (targetId, options) => navigateTreeHandler(targetId, options),
232
- getActiveTools: () => getActiveToolsHandler(),
233
- getAllTools: () => getAllToolsHandler(),
234
- setActiveTools: (toolNames) => setActiveToolsHandler(toolNames),
235
- };
236
- def.factory(api);
237
- return {
238
- path: hookPath,
239
- resolvedPath: hookPath,
240
- handlers,
241
- messageRenderers,
242
- commands,
243
- flags,
244
- flagValues,
245
- shortcuts,
246
- setSendMessageHandler: (handler) => {
247
- sendMessageHandler = handler;
248
- },
249
- setAppendEntryHandler: (handler) => {
250
- appendEntryHandler = handler;
251
- },
252
- setNewSessionHandler: (handler) => {
253
- newSessionHandler = handler;
254
- },
255
- setBranchHandler: (handler) => {
256
- branchHandler = handler;
257
- },
258
- setNavigateTreeHandler: (handler) => {
259
- navigateTreeHandler = handler;
260
- },
261
- setGetActiveToolsHandler: (handler) => {
262
- getActiveToolsHandler = handler;
263
- },
264
- setGetAllToolsHandler: (handler) => {
265
- getAllToolsHandler = handler;
266
- },
267
- setSetActiveToolsHandler: (handler) => {
268
- setActiveToolsHandler = handler;
269
- },
270
- setFlagValue: (name, value) => {
271
- flagValues.set(name, value);
272
- },
273
- };
274
- });
275
- }
276
139
  // Factory
277
140
  /**
278
141
  * Create an AgentSession with the specified options.
@@ -300,7 +163,6 @@ function createLoadedHooksFromDefinitions(definitions) {
300
163
  * getApiKey: async () => process.env.MY_KEY,
301
164
  * systemPrompt: 'You are helpful.',
302
165
  * tools: [readTool, bashTool],
303
- * hooks: [],
304
166
  * skills: [],
305
167
  * sessionManager: SessionManager.inMemory(),
306
168
  * });
@@ -309,6 +171,7 @@ function createLoadedHooksFromDefinitions(definitions) {
309
171
  export async function createAgentSession(options = {}) {
310
172
  const cwd = options.cwd ?? process.cwd();
311
173
  const agentDir = options.agentDir ?? getDefaultAgentDir();
174
+ const eventBus = options.eventBus ?? createEventBus();
312
175
  // Use provided or create AuthStorage and ModelRegistry
313
176
  const authStorage = options.authStorage ?? discoverAuthStorage(agentDir);
314
177
  const modelRegistry = options.modelRegistry ?? discoverModels(authStorage, agentDir);
@@ -381,7 +244,7 @@ export async function createAgentSession(options = {}) {
381
244
  const contextFiles = options.contextFiles ?? discoverContextFiles(cwd, agentDir);
382
245
  time("discoverContextFiles");
383
246
  const autoResizeImages = settingsManager.getImageAutoResize();
384
- // Create ALL built-in tools for the registry (hooks can enable any of them)
247
+ // Create ALL built-in tools for the registry (extensions can enable any of them)
385
248
  const allBuiltInToolsMap = createAllTools(cwd, { read: { autoResizeImages } });
386
249
  // Determine initially active built-in tools (default: read, bash, edit, write)
387
250
  const defaultActiveToolNames = ["read", "bash", "edit", "write"];
@@ -390,56 +253,94 @@ export async function createAgentSession(options = {}) {
390
253
  : defaultActiveToolNames;
391
254
  const initialActiveBuiltInTools = initialActiveToolNames.map((name) => allBuiltInToolsMap[name]);
392
255
  time("createAllTools");
393
- let customToolsResult;
394
- if (options.customTools !== undefined) {
395
- // Use provided custom tools
396
- const loadedTools = options.customTools.map((ct) => ({
397
- path: ct.path ?? "<inline>",
398
- resolvedPath: ct.path ?? "<inline>",
399
- tool: ct.tool,
400
- }));
401
- customToolsResult = {
402
- tools: loadedTools,
256
+ // Load extensions (discovers from standard locations + configured paths)
257
+ let extensionsResult;
258
+ if (options.preloadedExtensions !== undefined && options.preloadedExtensions.length > 0) {
259
+ // Use pre-loaded extensions (from early CLI flag discovery)
260
+ extensionsResult = {
261
+ extensions: options.preloadedExtensions,
403
262
  errors: [],
404
263
  setUIContext: () => { },
405
264
  };
406
265
  }
407
266
  else {
408
- // Discover custom tools, merging with additional paths
409
- const configuredPaths = [...settingsManager.getCustomToolPaths(), ...(options.additionalCustomToolPaths ?? [])];
410
- customToolsResult = await discoverAndLoadCustomTools(configuredPaths, cwd, Object.keys(allTools), agentDir);
411
- time("discoverAndLoadCustomTools");
412
- for (const { path, error } of customToolsResult.errors) {
413
- console.error(`Failed to load custom tool "${path}": ${error}`);
267
+ // Discover extensions, merging with additional paths
268
+ const configuredPaths = [...settingsManager.getExtensionPaths(), ...(options.additionalExtensionPaths ?? [])];
269
+ extensionsResult = await discoverAndLoadExtensions(configuredPaths, cwd, agentDir, eventBus);
270
+ time("discoverAndLoadExtensions");
271
+ for (const { path, error } of extensionsResult.errors) {
272
+ console.error(`Failed to load extension "${path}": ${error}`);
414
273
  }
415
274
  }
416
- let hookRunner;
417
- if (options.preloadedHooks !== undefined && options.preloadedHooks.length > 0) {
418
- // Use pre-loaded hooks (from early CLI flag discovery)
419
- hookRunner = new HookRunner(options.preloadedHooks, cwd, sessionManager, modelRegistry);
420
- }
421
- else if (options.hooks !== undefined) {
422
- if (options.hooks.length > 0) {
423
- const loadedHooks = createLoadedHooksFromDefinitions(options.hooks);
424
- hookRunner = new HookRunner(loadedHooks, cwd, sessionManager, modelRegistry);
275
+ // Load inline extensions from factories
276
+ if (options.extensions && options.extensions.length > 0) {
277
+ // Create shared UI context holder that will be set later
278
+ const uiHolder = {
279
+ ui: {
280
+ select: async () => undefined,
281
+ confirm: async () => false,
282
+ input: async () => undefined,
283
+ notify: () => { },
284
+ setStatus: () => { },
285
+ setWidget: () => { },
286
+ setTitle: () => { },
287
+ custom: async () => undefined,
288
+ setEditorText: () => { },
289
+ getEditorText: () => "",
290
+ editor: async () => undefined,
291
+ get theme() {
292
+ return {};
293
+ },
294
+ },
295
+ hasUI: false,
296
+ };
297
+ for (let i = 0; i < options.extensions.length; i++) {
298
+ const factory = options.extensions[i];
299
+ const loaded = loadExtensionFromFactory(factory, cwd, eventBus, uiHolder, `<inline-${i}>`);
300
+ extensionsResult.extensions.push(loaded);
425
301
  }
302
+ // Extend setUIContext to update inline extensions too
303
+ const originalSetUIContext = extensionsResult.setUIContext;
304
+ extensionsResult.setUIContext = (uiContext, hasUI) => {
305
+ originalSetUIContext(uiContext, hasUI);
306
+ uiHolder.ui = uiContext;
307
+ uiHolder.hasUI = hasUI;
308
+ };
426
309
  }
427
- else {
428
- // Discover hooks, merging with additional paths
429
- const configuredPaths = [...settingsManager.getHookPaths(), ...(options.additionalHookPaths ?? [])];
430
- const { hooks, errors } = await discoverAndLoadHooks(configuredPaths, cwd, agentDir);
431
- time("discoverAndLoadHooks");
432
- for (const { path, error } of errors) {
433
- console.error(`Failed to load hook "${path}": ${error}`);
434
- }
435
- if (hooks.length > 0) {
436
- hookRunner = new HookRunner(hooks, cwd, sessionManager, modelRegistry);
437
- }
310
+ // Create extension runner if we have extensions
311
+ let extensionRunner;
312
+ if (extensionsResult.extensions.length > 0) {
313
+ extensionRunner = new ExtensionRunner(extensionsResult.extensions, cwd, sessionManager, modelRegistry);
438
314
  }
439
- // Wrap custom tools with context getter (agent/session assigned below, accessed at execute time)
315
+ // Wrap extension-registered tools and SDK-provided custom tools with context getter
316
+ // (agent/session assigned below, accessed at execute time)
440
317
  let agent;
441
318
  let session;
442
- const wrappedCustomTools = wrapCustomTools(customToolsResult.tools, () => ({
319
+ const registeredTools = extensionRunner?.getAllRegisteredTools() ?? [];
320
+ // Combine extension-registered tools with SDK-provided custom tools
321
+ const allCustomTools = [
322
+ ...registeredTools,
323
+ ...(options.customTools?.map((def) => ({ definition: def, extensionPath: "<sdk>" })) ?? []),
324
+ ];
325
+ const wrappedExtensionTools = wrapRegisteredTools(allCustomTools, () => ({
326
+ ui: extensionRunner?.getUIContext() ?? {
327
+ select: async () => undefined,
328
+ confirm: async () => false,
329
+ input: async () => undefined,
330
+ notify: () => { },
331
+ setStatus: () => { },
332
+ setWidget: () => { },
333
+ setTitle: () => { },
334
+ custom: async () => undefined,
335
+ setEditorText: () => { },
336
+ getEditorText: () => "",
337
+ editor: async () => undefined,
338
+ get theme() {
339
+ return {};
340
+ },
341
+ },
342
+ hasUI: extensionRunner?.getHasUI() ?? false,
343
+ cwd,
443
344
  sessionManager,
444
345
  modelRegistry,
445
346
  model: agent.state.model,
@@ -449,25 +350,25 @@ export async function createAgentSession(options = {}) {
449
350
  session.abort();
450
351
  },
451
352
  }));
452
- // Create tool registry mapping name -> tool (for hook getTools/setTools)
453
- // Registry contains ALL built-in tools so hooks can enable any of them
353
+ // Create tool registry mapping name -> tool (for extension getTools/setTools)
354
+ // Registry contains ALL built-in tools so extensions can enable any of them
454
355
  const toolRegistry = new Map();
455
356
  for (const [name, tool] of Object.entries(allBuiltInToolsMap)) {
456
357
  toolRegistry.set(name, tool);
457
358
  }
458
- for (const tool of wrappedCustomTools) {
359
+ for (const tool of wrappedExtensionTools) {
459
360
  toolRegistry.set(tool.name, tool);
460
361
  }
461
- // Initially active tools = active built-in + custom
462
- let activeToolsArray = [...initialActiveBuiltInTools, ...wrappedCustomTools];
362
+ // Initially active tools = active built-in + extension tools
363
+ let activeToolsArray = [...initialActiveBuiltInTools, ...wrappedExtensionTools];
463
364
  time("combineTools");
464
- // Wrap tools with hooks if available
365
+ // Wrap tools with extensions if available
465
366
  let wrappedToolRegistry;
466
- if (hookRunner) {
467
- activeToolsArray = wrapToolsWithHooks(activeToolsArray, hookRunner);
468
- // Wrap ALL registry tools (not just active) so hooks can enable any
367
+ if (extensionRunner) {
368
+ activeToolsArray = wrapToolsWithExtensions(activeToolsArray, extensionRunner);
369
+ // Wrap ALL registry tools (not just active) so extensions can enable any
469
370
  const allRegistryTools = Array.from(toolRegistry.values());
470
- const wrappedAllTools = wrapToolsWithHooks(allRegistryTools, hookRunner);
371
+ const wrappedAllTools = wrapToolsWithExtensions(allRegistryTools, extensionRunner);
471
372
  wrappedToolRegistry = new Map();
472
373
  for (const tool of wrappedAllTools) {
473
374
  wrappedToolRegistry.set(tool.name, tool);
@@ -504,8 +405,8 @@ export async function createAgentSession(options = {}) {
504
405
  };
505
406
  const systemPrompt = rebuildSystemPrompt(initialActiveToolNames);
506
407
  time("buildSystemPrompt");
507
- const slashCommands = options.slashCommands ?? discoverSlashCommands(cwd, agentDir);
508
- time("discoverSlashCommands");
408
+ const promptTemplates = options.promptTemplates ?? discoverPromptTemplates(cwd, agentDir);
409
+ time("discoverPromptTemplates");
509
410
  agent = new Agent({
510
411
  initialState: {
511
412
  systemPrompt,
@@ -514,9 +415,9 @@ export async function createAgentSession(options = {}) {
514
415
  tools: activeToolsArray,
515
416
  },
516
417
  convertToLlm,
517
- transformContext: hookRunner
418
+ transformContext: extensionRunner
518
419
  ? async (messages) => {
519
- return hookRunner.emitContext(messages);
420
+ return extensionRunner.emitContext(messages);
520
421
  }
521
422
  : undefined,
522
423
  steeringMode: settingsManager.getSteeringMode(),
@@ -550,9 +451,8 @@ export async function createAgentSession(options = {}) {
550
451
  sessionManager,
551
452
  settingsManager,
552
453
  scopedModels: options.scopedModels,
553
- fileCommands: slashCommands,
554
- hookRunner,
555
- customTools: customToolsResult.tools,
454
+ promptTemplates: promptTemplates,
455
+ extensionRunner,
556
456
  skillsSettings: settingsManager.getSkillsSettings(),
557
457
  modelRegistry,
558
458
  toolRegistry: wrappedToolRegistry ?? toolRegistry,
@@ -561,7 +461,7 @@ export async function createAgentSession(options = {}) {
561
461
  time("createAgentSession");
562
462
  return {
563
463
  session,
564
- customToolsResult,
464
+ extensionsResult,
565
465
  modelFallbackMessage,
566
466
  };
567
467
  }