@draht/coding-agent 2026.3.14 → 2026.3.25-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (345) hide show
  1. package/README.md +45 -30
  2. package/dist/bun/cli.d.ts +3 -0
  3. package/dist/bun/cli.d.ts.map +1 -0
  4. package/dist/bun/cli.js +7 -0
  5. package/dist/bun/cli.js.map +1 -0
  6. package/dist/bun/register-bedrock.d.ts +2 -0
  7. package/dist/bun/register-bedrock.d.ts.map +1 -0
  8. package/dist/bun/register-bedrock.js +4 -0
  9. package/dist/bun/register-bedrock.js.map +1 -0
  10. package/dist/cli/args.d.ts +1 -0
  11. package/dist/cli/args.d.ts.map +1 -1
  12. package/dist/cli/args.js +11 -6
  13. package/dist/cli/args.js.map +1 -1
  14. package/dist/cli/file-processor.d.ts.map +1 -1
  15. package/dist/cli/file-processor.js +4 -0
  16. package/dist/cli/file-processor.js.map +1 -1
  17. package/dist/cli/initial-message.d.ts +18 -0
  18. package/dist/cli/initial-message.d.ts.map +1 -0
  19. package/dist/cli/initial-message.js +22 -0
  20. package/dist/cli/initial-message.js.map +1 -0
  21. package/dist/cli/session-picker.d.ts.map +1 -1
  22. package/dist/cli/session-picker.js +2 -1
  23. package/dist/cli/session-picker.js.map +1 -1
  24. package/dist/cli.d.ts.map +1 -1
  25. package/dist/cli.js +1 -3
  26. package/dist/cli.js.map +1 -1
  27. package/dist/core/agent-session.d.ts +38 -5
  28. package/dist/core/agent-session.d.ts.map +1 -1
  29. package/dist/core/agent-session.js +201 -73
  30. package/dist/core/agent-session.js.map +1 -1
  31. package/dist/core/bash-executor.d.ts +6 -7
  32. package/dist/core/bash-executor.d.ts.map +1 -1
  33. package/dist/core/bash-executor.js +8 -107
  34. package/dist/core/bash-executor.js.map +1 -1
  35. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  36. package/dist/core/compaction/branch-summarization.js +1 -0
  37. package/dist/core/compaction/branch-summarization.js.map +1 -1
  38. package/dist/core/compaction/compaction.d.ts.map +1 -1
  39. package/dist/core/compaction/compaction.js +2 -0
  40. package/dist/core/compaction/compaction.js.map +1 -1
  41. package/dist/core/exec.d.ts.map +1 -1
  42. package/dist/core/exec.js +7 -3
  43. package/dist/core/exec.js.map +1 -1
  44. package/dist/core/export-html/index.d.ts +2 -2
  45. package/dist/core/export-html/index.d.ts.map +1 -1
  46. package/dist/core/export-html/index.js +7 -6
  47. package/dist/core/export-html/index.js.map +1 -1
  48. package/dist/core/export-html/template.css +43 -13
  49. package/dist/core/export-html/template.html +1 -0
  50. package/dist/core/export-html/template.js +107 -0
  51. package/dist/core/export-html/tool-renderer.d.ts +2 -2
  52. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  53. package/dist/core/export-html/tool-renderer.js +41 -16
  54. package/dist/core/export-html/tool-renderer.js.map +1 -1
  55. package/dist/core/extensions/index.d.ts +4 -3
  56. package/dist/core/extensions/index.d.ts.map +1 -1
  57. package/dist/core/extensions/index.js +1 -1
  58. package/dist/core/extensions/index.js.map +1 -1
  59. package/dist/core/extensions/loader.d.ts.map +1 -1
  60. package/dist/core/extensions/loader.js +16 -6
  61. package/dist/core/extensions/loader.js.map +1 -1
  62. package/dist/core/extensions/runner.d.ts +9 -9
  63. package/dist/core/extensions/runner.d.ts.map +1 -1
  64. package/dist/core/extensions/runner.js +89 -71
  65. package/dist/core/extensions/runner.js.map +1 -1
  66. package/dist/core/extensions/types.d.ts +49 -13
  67. package/dist/core/extensions/types.d.ts.map +1 -1
  68. package/dist/core/extensions/types.js.map +1 -1
  69. package/dist/core/extensions/wrapper.d.ts +4 -11
  70. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  71. package/dist/core/extensions/wrapper.js +6 -86
  72. package/dist/core/extensions/wrapper.js.map +1 -1
  73. package/dist/core/footer-data-provider.d.ts +13 -1
  74. package/dist/core/footer-data-provider.d.ts.map +1 -1
  75. package/dist/core/footer-data-provider.js +155 -37
  76. package/dist/core/footer-data-provider.js.map +1 -1
  77. package/dist/core/index.d.ts +2 -1
  78. package/dist/core/index.d.ts.map +1 -1
  79. package/dist/core/index.js +2 -1
  80. package/dist/core/index.js.map +1 -1
  81. package/dist/core/keybindings.d.ts +270 -50
  82. package/dist/core/keybindings.d.ts.map +1 -1
  83. package/dist/core/keybindings.js +222 -134
  84. package/dist/core/keybindings.js.map +1 -1
  85. package/dist/core/model-registry.d.ts +1 -0
  86. package/dist/core/model-registry.d.ts.map +1 -1
  87. package/dist/core/model-registry.js +49 -23
  88. package/dist/core/model-registry.js.map +1 -1
  89. package/dist/core/model-resolver.d.ts +6 -0
  90. package/dist/core/model-resolver.d.ts.map +1 -1
  91. package/dist/core/model-resolver.js +41 -17
  92. package/dist/core/model-resolver.js.map +1 -1
  93. package/dist/core/output-guard.d.ts +6 -0
  94. package/dist/core/output-guard.d.ts.map +1 -0
  95. package/dist/core/output-guard.js +59 -0
  96. package/dist/core/output-guard.js.map +1 -0
  97. package/dist/core/package-manager.d.ts +22 -1
  98. package/dist/core/package-manager.d.ts.map +1 -1
  99. package/dist/core/package-manager.js +373 -53
  100. package/dist/core/package-manager.js.map +1 -1
  101. package/dist/core/prompt-templates.d.ts +2 -1
  102. package/dist/core/prompt-templates.d.ts.map +1 -1
  103. package/dist/core/prompt-templates.js +39 -39
  104. package/dist/core/prompt-templates.js.map +1 -1
  105. package/dist/core/resolve-config-value.d.ts.map +1 -1
  106. package/dist/core/resolve-config-value.js +43 -8
  107. package/dist/core/resolve-config-value.js.map +1 -1
  108. package/dist/core/resource-loader.d.ts +6 -7
  109. package/dist/core/resource-loader.d.ts.map +1 -1
  110. package/dist/core/resource-loader.js +141 -118
  111. package/dist/core/resource-loader.js.map +1 -1
  112. package/dist/core/sdk.d.ts +3 -3
  113. package/dist/core/sdk.d.ts.map +1 -1
  114. package/dist/core/sdk.js +4 -4
  115. package/dist/core/sdk.js.map +1 -1
  116. package/dist/core/session-manager.d.ts +6 -0
  117. package/dist/core/session-manager.d.ts.map +1 -1
  118. package/dist/core/session-manager.js +9 -10
  119. package/dist/core/session-manager.js.map +1 -1
  120. package/dist/core/settings-manager.d.ts +3 -0
  121. package/dist/core/settings-manager.d.ts.map +1 -1
  122. package/dist/core/settings-manager.js +8 -0
  123. package/dist/core/settings-manager.js.map +1 -1
  124. package/dist/core/skills.d.ts +5 -3
  125. package/dist/core/skills.d.ts.map +1 -1
  126. package/dist/core/skills.js +54 -9
  127. package/dist/core/skills.js.map +1 -1
  128. package/dist/core/slash-commands.d.ts +2 -3
  129. package/dist/core/slash-commands.d.ts.map +1 -1
  130. package/dist/core/slash-commands.js +3 -2
  131. package/dist/core/slash-commands.js.map +1 -1
  132. package/dist/core/source-info.d.ts +18 -0
  133. package/dist/core/source-info.d.ts.map +1 -0
  134. package/dist/core/source-info.js +19 -0
  135. package/dist/core/source-info.js.map +1 -0
  136. package/dist/core/system-prompt.d.ts.map +1 -1
  137. package/dist/core/system-prompt.js +17 -60
  138. package/dist/core/system-prompt.js.map +1 -1
  139. package/dist/core/tools/bash.d.ts +24 -6
  140. package/dist/core/tools/bash.d.ts.map +1 -1
  141. package/dist/core/tools/bash.js +210 -110
  142. package/dist/core/tools/bash.js.map +1 -1
  143. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  144. package/dist/core/tools/edit-diff.js +1 -0
  145. package/dist/core/tools/edit-diff.js.map +1 -1
  146. package/dist/core/tools/edit.d.ts +14 -2
  147. package/dist/core/tools/edit.d.ts.map +1 -1
  148. package/dist/core/tools/edit.js +95 -23
  149. package/dist/core/tools/edit.js.map +1 -1
  150. package/dist/core/tools/file-mutation-queue.d.ts +6 -0
  151. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -0
  152. package/dist/core/tools/file-mutation-queue.js +37 -0
  153. package/dist/core/tools/file-mutation-queue.js.map +1 -0
  154. package/dist/core/tools/find.d.ts +11 -4
  155. package/dist/core/tools/find.d.ts.map +1 -1
  156. package/dist/core/tools/find.js +82 -30
  157. package/dist/core/tools/find.js.map +1 -1
  158. package/dist/core/tools/grep.d.ts +15 -4
  159. package/dist/core/tools/grep.d.ts.map +1 -1
  160. package/dist/core/tools/grep.js +83 -29
  161. package/dist/core/tools/grep.js.map +1 -1
  162. package/dist/core/tools/index.d.ts +58 -19
  163. package/dist/core/tools/index.d.ts.map +1 -1
  164. package/dist/core/tools/index.js +51 -26
  165. package/dist/core/tools/index.js.map +1 -1
  166. package/dist/core/tools/ls.d.ts +9 -3
  167. package/dist/core/tools/ls.d.ts.map +1 -1
  168. package/dist/core/tools/ls.js +67 -13
  169. package/dist/core/tools/ls.js.map +1 -1
  170. package/dist/core/tools/read.d.ts +10 -3
  171. package/dist/core/tools/read.d.ts.map +1 -1
  172. package/dist/core/tools/read.js +110 -51
  173. package/dist/core/tools/read.js.map +1 -1
  174. package/dist/core/tools/render-utils.d.ts +21 -0
  175. package/dist/core/tools/render-utils.d.ts.map +1 -0
  176. package/dist/core/tools/render-utils.js +49 -0
  177. package/dist/core/tools/render-utils.js.map +1 -0
  178. package/dist/core/tools/tool-definition-wrapper.d.ts +14 -0
  179. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -0
  180. package/dist/core/tools/tool-definition-wrapper.js +30 -0
  181. package/dist/core/tools/tool-definition-wrapper.js.map +1 -0
  182. package/dist/core/tools/write.d.ts +9 -3
  183. package/dist/core/tools/write.d.ts.map +1 -1
  184. package/dist/core/tools/write.js +168 -30
  185. package/dist/core/tools/write.js.map +1 -1
  186. package/dist/index.d.ts +5 -4
  187. package/dist/index.d.ts.map +1 -1
  188. package/dist/index.js +4 -3
  189. package/dist/index.js.map +1 -1
  190. package/dist/main.d.ts.map +1 -1
  191. package/dist/main.js +105 -226
  192. package/dist/main.js.map +1 -1
  193. package/dist/modes/interactive/components/bash-execution.d.ts +0 -1
  194. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  195. package/dist/modes/interactive/components/bash-execution.js +22 -9
  196. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  197. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  198. package/dist/modes/interactive/components/bordered-loader.js +1 -1
  199. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  200. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  201. package/dist/modes/interactive/components/branch-summary-message.js +2 -2
  202. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  203. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  204. package/dist/modes/interactive/components/compaction-summary-message.js +2 -2
  205. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  206. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  207. package/dist/modes/interactive/components/config-selector.js +8 -8
  208. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  209. package/dist/modes/interactive/components/custom-editor.d.ts +3 -3
  210. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  211. package/dist/modes/interactive/components/custom-editor.js +6 -6
  212. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  213. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  214. package/dist/modes/interactive/components/extension-editor.js +9 -9
  215. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  216. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  217. package/dist/modes/interactive/components/extension-input.js +5 -5
  218. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  219. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  220. package/dist/modes/interactive/components/extension-selector.js +8 -8
  221. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  222. package/dist/modes/interactive/components/index.d.ts +1 -1
  223. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  224. package/dist/modes/interactive/components/index.js +1 -1
  225. package/dist/modes/interactive/components/index.js.map +1 -1
  226. package/dist/modes/interactive/components/keybinding-hints.d.ts +3 -36
  227. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  228. package/dist/modes/interactive/components/keybinding-hints.js +5 -44
  229. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  230. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  231. package/dist/modes/interactive/components/login-dialog.js +6 -6
  232. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  233. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  234. package/dist/modes/interactive/components/model-selector.js +13 -9
  235. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  236. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  237. package/dist/modes/interactive/components/oauth-selector.js +6 -6
  238. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  239. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  240. package/dist/modes/interactive/components/scoped-models-selector.js +4 -4
  241. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  242. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  243. package/dist/modes/interactive/components/session-selector.js +32 -35
  244. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  245. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  246. package/dist/modes/interactive/components/settings-selector.js +5 -1
  247. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  248. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  249. package/dist/modes/interactive/components/show-images-selector.js +5 -1
  250. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  251. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  252. package/dist/modes/interactive/components/skill-invocation-message.js +2 -2
  253. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  254. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  255. package/dist/modes/interactive/components/theme-selector.js +5 -1
  256. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  257. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  258. package/dist/modes/interactive/components/thinking-selector.js +5 -1
  259. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  260. package/dist/modes/interactive/components/tool-execution.d.ts +16 -34
  261. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  262. package/dist/modes/interactive/components/tool-execution.js +128 -636
  263. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  264. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  265. package/dist/modes/interactive/components/tree-selector.js +27 -16
  266. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  267. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  268. package/dist/modes/interactive/components/user-message-selector.js +6 -6
  269. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  270. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  271. package/dist/modes/interactive/components/user-message.js +2 -1
  272. package/dist/modes/interactive/components/user-message.js.map +1 -1
  273. package/dist/modes/interactive/interactive-mode.d.ts +7 -11
  274. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  275. package/dist/modes/interactive/interactive-mode.js +353 -214
  276. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  277. package/dist/modes/interactive/theme/theme.d.ts +3 -0
  278. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  279. package/dist/modes/interactive/theme/theme.js +63 -37
  280. package/dist/modes/interactive/theme/theme.js.map +1 -1
  281. package/dist/modes/print-mode.d.ts.map +1 -1
  282. package/dist/modes/print-mode.js +5 -11
  283. package/dist/modes/print-mode.js.map +1 -1
  284. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  285. package/dist/modes/rpc/rpc-mode.js +27 -17
  286. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  287. package/dist/modes/rpc/rpc-types.d.ts +3 -4
  288. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  289. package/dist/modes/rpc/rpc-types.js.map +1 -1
  290. package/dist/utils/child-process.d.ts +11 -0
  291. package/dist/utils/child-process.d.ts.map +1 -0
  292. package/dist/utils/child-process.js +78 -0
  293. package/dist/utils/child-process.js.map +1 -0
  294. package/dist/utils/clipboard-image.d.ts.map +1 -1
  295. package/dist/utils/clipboard-image.js +94 -11
  296. package/dist/utils/clipboard-image.js.map +1 -1
  297. package/dist/utils/clipboard-native.d.ts +1 -0
  298. package/dist/utils/clipboard-native.d.ts.map +1 -1
  299. package/dist/utils/clipboard-native.js.map +1 -1
  300. package/dist/utils/clipboard.d.ts +1 -1
  301. package/dist/utils/clipboard.d.ts.map +1 -1
  302. package/dist/utils/clipboard.js +27 -16
  303. package/dist/utils/clipboard.js.map +1 -1
  304. package/dist/utils/exif-orientation.d.ts +5 -0
  305. package/dist/utils/exif-orientation.d.ts.map +1 -0
  306. package/dist/utils/exif-orientation.js +158 -0
  307. package/dist/utils/exif-orientation.js.map +1 -0
  308. package/dist/utils/image-convert.d.ts.map +1 -1
  309. package/dist/utils/image-convert.js +5 -1
  310. package/dist/utils/image-convert.js.map +1 -1
  311. package/dist/utils/image-resize.d.ts +5 -5
  312. package/dist/utils/image-resize.d.ts.map +1 -1
  313. package/dist/utils/image-resize.js +51 -95
  314. package/dist/utils/image-resize.js.map +1 -1
  315. package/dist/utils/tools-manager.d.ts.map +1 -1
  316. package/dist/utils/tools-manager.js +5 -4
  317. package/dist/utils/tools-manager.js.map +1 -1
  318. package/docs/custom-provider.md +6 -2
  319. package/docs/extensions.md +108 -21
  320. package/docs/keybindings.md +103 -112
  321. package/docs/models.md +39 -1
  322. package/docs/packages.md +9 -0
  323. package/docs/providers.md +7 -0
  324. package/docs/rpc.md +15 -6
  325. package/docs/sdk.md +2 -2
  326. package/docs/settings.md +9 -0
  327. package/docs/terminal-setup.md +11 -0
  328. package/docs/tui.md +2 -2
  329. package/examples/extensions/README.md +2 -2
  330. package/examples/extensions/antigravity-image-gen.ts +5 -3
  331. package/examples/extensions/built-in-tool-renderer.ts +8 -8
  332. package/examples/extensions/commands.ts +3 -3
  333. package/examples/extensions/minimal-mode.ts +14 -14
  334. package/examples/extensions/question.ts +2 -2
  335. package/examples/extensions/questionnaire.ts +2 -2
  336. package/examples/extensions/subagent/index.ts +30 -8
  337. package/examples/extensions/titlebar-spinner.ts +2 -2
  338. package/examples/extensions/todo.ts +2 -2
  339. package/examples/extensions/tool-override.ts +9 -7
  340. package/examples/extensions/truncated-tool.ts +8 -5
  341. package/examples/sdk/04-skills.ts +8 -2
  342. package/examples/sdk/08-prompt-templates.ts +8 -2
  343. package/examples/sdk/12-full-control.ts +0 -1
  344. package/examples/sdk/README.md +1 -1
  345. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"resource-loader.d.ts","sourceRoot":"","sources":["../../src/core/resource-loader.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve, sep } from \"node:path\";\nimport chalk from \"chalk\";\nimport { getAgentDir, getProjectConfigDir } from \"../config.js\";\nimport { loadThemeFromPath, type Theme } from \"../modes/interactive/theme/theme.js\";\nimport type { ResourceDiagnostic } from \"./diagnostics.js\";\n\nexport type { ResourceCollision, ResourceDiagnostic } from \"./diagnostics.js\";\n\nimport subagentExtension from \"./builtins/subagent.js\";\nimport { createEventBus, type EventBus } from \"./event-bus.js\";\nimport { createExtensionRuntime, loadExtensionFromFactory, loadExtensions } from \"./extensions/loader.js\";\nimport type { Extension, ExtensionFactory, ExtensionRuntime, LoadExtensionsResult } from \"./extensions/types.js\";\n\n/** Built-in extension factories that are always loaded. */\nconst builtinExtensionFactories: ExtensionFactory[] = [subagentExtension];\n\nimport { DefaultPackageManager, type PathMetadata } from \"./package-manager.js\";\nimport type { PromptTemplate } from \"./prompt-templates.js\";\nimport { loadPromptTemplates } from \"./prompt-templates.js\";\nimport { SettingsManager } from \"./settings-manager.js\";\nimport type { Skill } from \"./skills.js\";\nimport { loadSkills } from \"./skills.js\";\n\nexport interface ResourceExtensionPaths {\n\tskillPaths?: Array<{ path: string; metadata: PathMetadata }>;\n\tpromptPaths?: Array<{ path: string; metadata: PathMetadata }>;\n\tthemePaths?: Array<{ path: string; metadata: PathMetadata }>;\n}\n\nexport interface ResourceLoader {\n\tgetExtensions(): LoadExtensionsResult;\n\tgetSkills(): { skills: Skill[]; diagnostics: ResourceDiagnostic[] };\n\tgetPrompts(): { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] };\n\tgetThemes(): { themes: Theme[]; diagnostics: ResourceDiagnostic[] };\n\tgetAgentsFiles(): { agentsFiles: Array<{ path: string; content: string }> };\n\tgetSystemPrompt(): string | undefined;\n\tgetAppendSystemPrompt(): string[];\n\tgetPathMetadata(): Map<string, PathMetadata>;\n\textendResources(paths: ResourceExtensionPaths): void;\n\treload(): Promise<void>;\n}\n\nfunction resolvePromptInput(input: string | undefined, description: string): string | undefined {\n\tif (!input) {\n\t\treturn undefined;\n\t}\n\n\tif (existsSync(input)) {\n\t\ttry {\n\t\t\treturn readFileSync(input, \"utf-8\");\n\t\t} catch (error) {\n\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${description} file ${input}: ${error}`));\n\t\t\treturn input;\n\t\t}\n\t}\n\n\treturn input;\n}\n\nfunction loadContextFileFromDir(dir: string): { path: string; content: string } | null {\n\tconst candidates = [\"AGENTS.md\", \"CLAUDE.md\"];\n\tfor (const filename of candidates) {\n\t\tconst filePath = join(dir, filename);\n\t\tif (existsSync(filePath)) {\n\t\t\ttry {\n\t\t\t\treturn {\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\tcontent: readFileSync(filePath, \"utf-8\"),\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${filePath}: ${error}`));\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction loadProjectContextFiles(\n\toptions: { cwd?: string; agentDir?: string } = {},\n): Array<{ path: string; content: string }> {\n\tconst resolvedCwd = options.cwd ?? process.cwd();\n\tconst resolvedAgentDir = options.agentDir ?? getAgentDir();\n\n\tconst contextFiles: Array<{ path: string; content: string }> = [];\n\tconst seenPaths = new Set<string>();\n\n\tconst globalContext = loadContextFileFromDir(resolvedAgentDir);\n\tif (globalContext) {\n\t\tcontextFiles.push(globalContext);\n\t\tseenPaths.add(globalContext.path);\n\t}\n\n\tconst ancestorContextFiles: Array<{ path: string; content: string }> = [];\n\n\tlet currentDir = resolvedCwd;\n\tconst root = resolve(\"/\");\n\n\twhile (true) {\n\t\tconst contextFile = loadContextFileFromDir(currentDir);\n\t\tif (contextFile && !seenPaths.has(contextFile.path)) {\n\t\t\tancestorContextFiles.unshift(contextFile);\n\t\t\tseenPaths.add(contextFile.path);\n\t\t}\n\n\t\tif (currentDir === root) break;\n\n\t\tconst parentDir = resolve(currentDir, \"..\");\n\t\tif (parentDir === currentDir) break;\n\t\tcurrentDir = parentDir;\n\t}\n\n\tcontextFiles.push(...ancestorContextFiles);\n\n\treturn contextFiles;\n}\n\nexport interface DefaultResourceLoaderOptions {\n\tcwd?: string;\n\tagentDir?: string;\n\tsettingsManager?: SettingsManager;\n\teventBus?: EventBus;\n\tadditionalExtensionPaths?: string[];\n\tadditionalSkillPaths?: string[];\n\tadditionalPromptTemplatePaths?: string[];\n\tadditionalThemePaths?: string[];\n\textensionFactories?: ExtensionFactory[];\n\t/** Skip built-in extension factories (subagent etc). For testing only. */\n\tnoBuiltinExtensions?: boolean;\n\tnoExtensions?: boolean;\n\tnoSkills?: boolean;\n\tnoPromptTemplates?: boolean;\n\tnoThemes?: boolean;\n\tsystemPrompt?: string;\n\tappendSystemPrompt?: string;\n\textensionsOverride?: (base: LoadExtensionsResult) => LoadExtensionsResult;\n\tskillsOverride?: (base: { skills: Skill[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tskills: Skill[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tpromptsOverride?: (base: { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tprompts: PromptTemplate[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tthemesOverride?: (base: { themes: Theme[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tthemes: Theme[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tagentsFilesOverride?: (base: { agentsFiles: Array<{ path: string; content: string }> }) => {\n\t\tagentsFiles: Array<{ path: string; content: string }>;\n\t};\n\tsystemPromptOverride?: (base: string | undefined) => string | undefined;\n\tappendSystemPromptOverride?: (base: string[]) => string[];\n}\n\nexport class DefaultResourceLoader implements ResourceLoader {\n\tprivate cwd: string;\n\tprivate agentDir: string;\n\tprivate settingsManager: SettingsManager;\n\tprivate eventBus: EventBus;\n\tprivate packageManager: DefaultPackageManager;\n\tprivate additionalExtensionPaths: string[];\n\tprivate additionalSkillPaths: string[];\n\tprivate additionalPromptTemplatePaths: string[];\n\tprivate additionalThemePaths: string[];\n\tprivate extensionFactories: ExtensionFactory[];\n\tprivate noExtensions: boolean;\n\tprivate noSkills: boolean;\n\tprivate noPromptTemplates: boolean;\n\tprivate noThemes: boolean;\n\tprivate systemPromptSource?: string;\n\tprivate appendSystemPromptSource?: string;\n\tprivate extensionsOverride?: (base: LoadExtensionsResult) => LoadExtensionsResult;\n\tprivate skillsOverride?: (base: { skills: Skill[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tskills: Skill[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tprivate promptsOverride?: (base: { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tprompts: PromptTemplate[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tprivate themesOverride?: (base: { themes: Theme[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tthemes: Theme[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tprivate agentsFilesOverride?: (base: { agentsFiles: Array<{ path: string; content: string }> }) => {\n\t\tagentsFiles: Array<{ path: string; content: string }>;\n\t};\n\tprivate systemPromptOverride?: (base: string | undefined) => string | undefined;\n\tprivate appendSystemPromptOverride?: (base: string[]) => string[];\n\n\tprivate extensionsResult: LoadExtensionsResult;\n\tprivate skills: Skill[];\n\tprivate skillDiagnostics: ResourceDiagnostic[];\n\tprivate prompts: PromptTemplate[];\n\tprivate promptDiagnostics: ResourceDiagnostic[];\n\tprivate themes: Theme[];\n\tprivate themeDiagnostics: ResourceDiagnostic[];\n\tprivate agentsFiles: Array<{ path: string; content: string }>;\n\tprivate systemPrompt?: string;\n\tprivate appendSystemPrompt: string[];\n\tprivate pathMetadata: Map<string, PathMetadata>;\n\tprivate lastSkillPaths: string[];\n\tprivate lastPromptPaths: string[];\n\tprivate lastThemePaths: string[];\n\n\tconstructor(options: DefaultResourceLoaderOptions) {\n\t\tthis.cwd = options.cwd ?? process.cwd();\n\t\tthis.agentDir = options.agentDir ?? getAgentDir();\n\t\tthis.settingsManager = options.settingsManager ?? SettingsManager.create(this.cwd, this.agentDir);\n\t\tthis.eventBus = options.eventBus ?? createEventBus();\n\t\tthis.packageManager = new DefaultPackageManager({\n\t\t\tcwd: this.cwd,\n\t\t\tagentDir: this.agentDir,\n\t\t\tsettingsManager: this.settingsManager,\n\t\t});\n\t\tthis.additionalExtensionPaths = options.additionalExtensionPaths ?? [];\n\t\tthis.additionalSkillPaths = options.additionalSkillPaths ?? [];\n\t\tthis.additionalPromptTemplatePaths = options.additionalPromptTemplatePaths ?? [];\n\t\tthis.additionalThemePaths = options.additionalThemePaths ?? [];\n\t\tconst builtins = options.noBuiltinExtensions ? [] : builtinExtensionFactories;\n\t\tthis.extensionFactories = [...builtins, ...(options.extensionFactories ?? [])];\n\t\tthis.noExtensions = options.noExtensions ?? false;\n\t\tthis.noSkills = options.noSkills ?? false;\n\t\tthis.noPromptTemplates = options.noPromptTemplates ?? false;\n\t\tthis.noThemes = options.noThemes ?? false;\n\t\tthis.systemPromptSource = options.systemPrompt;\n\t\tthis.appendSystemPromptSource = options.appendSystemPrompt;\n\t\tthis.extensionsOverride = options.extensionsOverride;\n\t\tthis.skillsOverride = options.skillsOverride;\n\t\tthis.promptsOverride = options.promptsOverride;\n\t\tthis.themesOverride = options.themesOverride;\n\t\tthis.agentsFilesOverride = options.agentsFilesOverride;\n\t\tthis.systemPromptOverride = options.systemPromptOverride;\n\t\tthis.appendSystemPromptOverride = options.appendSystemPromptOverride;\n\n\t\tthis.extensionsResult = { extensions: [], errors: [], runtime: createExtensionRuntime() };\n\t\tthis.skills = [];\n\t\tthis.skillDiagnostics = [];\n\t\tthis.prompts = [];\n\t\tthis.promptDiagnostics = [];\n\t\tthis.themes = [];\n\t\tthis.themeDiagnostics = [];\n\t\tthis.agentsFiles = [];\n\t\tthis.appendSystemPrompt = [];\n\t\tthis.pathMetadata = new Map();\n\t\tthis.lastSkillPaths = [];\n\t\tthis.lastPromptPaths = [];\n\t\tthis.lastThemePaths = [];\n\t}\n\n\tgetExtensions(): LoadExtensionsResult {\n\t\treturn this.extensionsResult;\n\t}\n\n\tgetSkills(): { skills: Skill[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn { skills: this.skills, diagnostics: this.skillDiagnostics };\n\t}\n\n\tgetPrompts(): { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn { prompts: this.prompts, diagnostics: this.promptDiagnostics };\n\t}\n\n\tgetThemes(): { themes: Theme[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn { themes: this.themes, diagnostics: this.themeDiagnostics };\n\t}\n\n\tgetAgentsFiles(): { agentsFiles: Array<{ path: string; content: string }> } {\n\t\treturn { agentsFiles: this.agentsFiles };\n\t}\n\n\tgetSystemPrompt(): string | undefined {\n\t\treturn this.systemPrompt;\n\t}\n\n\tgetAppendSystemPrompt(): string[] {\n\t\treturn this.appendSystemPrompt;\n\t}\n\n\tgetPathMetadata(): Map<string, PathMetadata> {\n\t\treturn this.pathMetadata;\n\t}\n\n\textendResources(paths: ResourceExtensionPaths): void {\n\t\tconst skillPaths = this.normalizeExtensionPaths(paths.skillPaths ?? []);\n\t\tconst promptPaths = this.normalizeExtensionPaths(paths.promptPaths ?? []);\n\t\tconst themePaths = this.normalizeExtensionPaths(paths.themePaths ?? []);\n\n\t\tif (skillPaths.length > 0) {\n\t\t\tthis.lastSkillPaths = this.mergePaths(\n\t\t\t\tthis.lastSkillPaths,\n\t\t\t\tskillPaths.map((entry) => entry.path),\n\t\t\t);\n\t\t\tthis.updateSkillsFromPaths(this.lastSkillPaths, skillPaths);\n\t\t}\n\n\t\tif (promptPaths.length > 0) {\n\t\t\tthis.lastPromptPaths = this.mergePaths(\n\t\t\t\tthis.lastPromptPaths,\n\t\t\t\tpromptPaths.map((entry) => entry.path),\n\t\t\t);\n\t\t\tthis.updatePromptsFromPaths(this.lastPromptPaths, promptPaths);\n\t\t}\n\n\t\tif (themePaths.length > 0) {\n\t\t\tthis.lastThemePaths = this.mergePaths(\n\t\t\t\tthis.lastThemePaths,\n\t\t\t\tthemePaths.map((entry) => entry.path),\n\t\t\t);\n\t\t\tthis.updateThemesFromPaths(this.lastThemePaths, themePaths);\n\t\t}\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tconst resolvedPaths = await this.packageManager.resolve();\n\t\tconst cliExtensionPaths = await this.packageManager.resolveExtensionSources(this.additionalExtensionPaths, {\n\t\t\ttemporary: true,\n\t\t});\n\n\t\t// Helper to extract enabled paths and store metadata\n\t\tconst getEnabledResources = (\n\t\t\tresources: Array<{ path: string; enabled: boolean; metadata: PathMetadata }>,\n\t\t): Array<{ path: string; enabled: boolean; metadata: PathMetadata }> => {\n\t\t\tfor (const r of resources) {\n\t\t\t\tif (!this.pathMetadata.has(r.path)) {\n\t\t\t\t\tthis.pathMetadata.set(r.path, r.metadata);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn resources.filter((r) => r.enabled);\n\t\t};\n\n\t\tconst getEnabledPaths = (\n\t\t\tresources: Array<{ path: string; enabled: boolean; metadata: PathMetadata }>,\n\t\t): string[] => getEnabledResources(resources).map((r) => r.path);\n\n\t\t// Store metadata and get enabled paths\n\t\tthis.pathMetadata = new Map();\n\t\tconst enabledExtensions = getEnabledPaths(resolvedPaths.extensions);\n\t\tconst enabledSkillResources = getEnabledResources(resolvedPaths.skills);\n\t\tconst enabledPrompts = getEnabledPaths(resolvedPaths.prompts);\n\t\tconst enabledThemes = getEnabledPaths(resolvedPaths.themes);\n\n\t\tconst mapSkillPath = (resource: { path: string; metadata: PathMetadata }): string => {\n\t\t\tif (resource.metadata.source !== \"auto\" && resource.metadata.origin !== \"package\") {\n\t\t\t\treturn resource.path;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst stats = statSync(resource.path);\n\t\t\t\tif (!stats.isDirectory()) {\n\t\t\t\t\treturn resource.path;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\treturn resource.path;\n\t\t\t}\n\t\t\tconst skillFile = join(resource.path, \"SKILL.md\");\n\t\t\tif (existsSync(skillFile)) {\n\t\t\t\tif (!this.pathMetadata.has(skillFile)) {\n\t\t\t\t\tthis.pathMetadata.set(skillFile, resource.metadata);\n\t\t\t\t}\n\t\t\t\treturn skillFile;\n\t\t\t}\n\t\t\treturn resource.path;\n\t\t};\n\n\t\tconst enabledSkills = enabledSkillResources.map(mapSkillPath);\n\n\t\t// Add CLI paths metadata\n\t\tfor (const r of cliExtensionPaths.extensions) {\n\t\t\tif (!this.pathMetadata.has(r.path)) {\n\t\t\t\tthis.pathMetadata.set(r.path, { source: \"cli\", scope: \"temporary\", origin: \"top-level\" });\n\t\t\t}\n\t\t}\n\t\tfor (const r of cliExtensionPaths.skills) {\n\t\t\tif (!this.pathMetadata.has(r.path)) {\n\t\t\t\tthis.pathMetadata.set(r.path, { source: \"cli\", scope: \"temporary\", origin: \"top-level\" });\n\t\t\t}\n\t\t}\n\n\t\tconst cliEnabledExtensions = getEnabledPaths(cliExtensionPaths.extensions);\n\t\tconst cliEnabledSkills = getEnabledPaths(cliExtensionPaths.skills);\n\t\tconst cliEnabledPrompts = getEnabledPaths(cliExtensionPaths.prompts);\n\t\tconst cliEnabledThemes = getEnabledPaths(cliExtensionPaths.themes);\n\n\t\tconst extensionPaths = this.noExtensions\n\t\t\t? cliEnabledExtensions\n\t\t\t: this.mergePaths(cliEnabledExtensions, enabledExtensions);\n\n\t\tconst extensionsResult = await loadExtensions(extensionPaths, this.cwd, this.eventBus);\n\t\tconst inlineExtensions = await this.loadExtensionFactories(extensionsResult.runtime);\n\t\textensionsResult.extensions.push(...inlineExtensions.extensions);\n\t\textensionsResult.errors.push(...inlineExtensions.errors);\n\n\t\t// Detect extension conflicts (tools, commands, flags with same names from different extensions)\n\t\t// Keep all extensions loaded. Conflicts are reported as diagnostics, and precedence is handled by load order.\n\t\tconst conflicts = this.detectExtensionConflicts(extensionsResult.extensions);\n\t\tfor (const conflict of conflicts) {\n\t\t\textensionsResult.errors.push({ path: conflict.path, error: conflict.message });\n\t\t}\n\n\t\tthis.extensionsResult = this.extensionsOverride ? this.extensionsOverride(extensionsResult) : extensionsResult;\n\n\t\tconst skillPaths = this.noSkills\n\t\t\t? this.mergePaths(cliEnabledSkills, this.additionalSkillPaths)\n\t\t\t: this.mergePaths([...enabledSkills, ...cliEnabledSkills], this.additionalSkillPaths);\n\n\t\tthis.lastSkillPaths = skillPaths;\n\t\tthis.updateSkillsFromPaths(skillPaths);\n\n\t\tconst promptPaths = this.noPromptTemplates\n\t\t\t? this.mergePaths(cliEnabledPrompts, this.additionalPromptTemplatePaths)\n\t\t\t: this.mergePaths([...enabledPrompts, ...cliEnabledPrompts], this.additionalPromptTemplatePaths);\n\n\t\tthis.lastPromptPaths = promptPaths;\n\t\tthis.updatePromptsFromPaths(promptPaths);\n\n\t\tconst themePaths = this.noThemes\n\t\t\t? this.mergePaths(cliEnabledThemes, this.additionalThemePaths)\n\t\t\t: this.mergePaths([...enabledThemes, ...cliEnabledThemes], this.additionalThemePaths);\n\n\t\tthis.lastThemePaths = themePaths;\n\t\tthis.updateThemesFromPaths(themePaths);\n\n\t\tfor (const extension of this.extensionsResult.extensions) {\n\t\t\tthis.addDefaultMetadataForPath(extension.path);\n\t\t}\n\n\t\tconst agentsFiles = { agentsFiles: loadProjectContextFiles({ cwd: this.cwd, agentDir: this.agentDir }) };\n\t\tconst resolvedAgentsFiles = this.agentsFilesOverride ? this.agentsFilesOverride(agentsFiles) : agentsFiles;\n\t\tthis.agentsFiles = resolvedAgentsFiles.agentsFiles;\n\n\t\tconst baseSystemPrompt = resolvePromptInput(\n\t\t\tthis.systemPromptSource ?? this.discoverSystemPromptFile(),\n\t\t\t\"system prompt\",\n\t\t);\n\t\tthis.systemPrompt = this.systemPromptOverride ? this.systemPromptOverride(baseSystemPrompt) : baseSystemPrompt;\n\n\t\tconst appendSource = this.appendSystemPromptSource ?? this.discoverAppendSystemPromptFile();\n\t\tconst resolvedAppend = resolvePromptInput(appendSource, \"append system prompt\");\n\t\tconst baseAppend = resolvedAppend ? [resolvedAppend] : [];\n\t\tthis.appendSystemPrompt = this.appendSystemPromptOverride\n\t\t\t? this.appendSystemPromptOverride(baseAppend)\n\t\t\t: baseAppend;\n\t}\n\n\tprivate normalizeExtensionPaths(\n\t\tentries: Array<{ path: string; metadata: PathMetadata }>,\n\t): Array<{ path: string; metadata: PathMetadata }> {\n\t\treturn entries.map((entry) => ({\n\t\t\tpath: this.resolveResourcePath(entry.path),\n\t\t\tmetadata: entry.metadata,\n\t\t}));\n\t}\n\n\tprivate updateSkillsFromPaths(\n\t\tskillPaths: string[],\n\t\textensionPaths: Array<{ path: string; metadata: PathMetadata }> = [],\n\t): void {\n\t\tlet skillsResult: { skills: Skill[]; diagnostics: ResourceDiagnostic[] };\n\t\tif (this.noSkills && skillPaths.length === 0) {\n\t\t\tskillsResult = { skills: [], diagnostics: [] };\n\t\t} else {\n\t\t\tskillsResult = loadSkills({\n\t\t\t\tcwd: this.cwd,\n\t\t\t\tagentDir: this.agentDir,\n\t\t\t\tskillPaths,\n\t\t\t\tincludeDefaults: false,\n\t\t\t});\n\t\t}\n\t\tconst resolvedSkills = this.skillsOverride ? this.skillsOverride(skillsResult) : skillsResult;\n\t\tthis.skills = resolvedSkills.skills;\n\t\tthis.skillDiagnostics = resolvedSkills.diagnostics;\n\t\tthis.applyExtensionMetadata(\n\t\t\textensionPaths,\n\t\t\tthis.skills.map((skill) => skill.filePath),\n\t\t);\n\t\tfor (const skill of this.skills) {\n\t\t\tthis.addDefaultMetadataForPath(skill.filePath);\n\t\t}\n\t}\n\n\tprivate updatePromptsFromPaths(\n\t\tpromptPaths: string[],\n\t\textensionPaths: Array<{ path: string; metadata: PathMetadata }> = [],\n\t): void {\n\t\tlet promptsResult: { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] };\n\t\tif (this.noPromptTemplates && promptPaths.length === 0) {\n\t\t\tpromptsResult = { prompts: [], diagnostics: [] };\n\t\t} else {\n\t\t\tconst allPrompts = loadPromptTemplates({\n\t\t\t\tcwd: this.cwd,\n\t\t\t\tagentDir: this.agentDir,\n\t\t\t\tpromptPaths,\n\t\t\t\tincludeDefaults: false,\n\t\t\t});\n\t\t\tpromptsResult = this.dedupePrompts(allPrompts);\n\t\t}\n\t\tconst resolvedPrompts = this.promptsOverride ? this.promptsOverride(promptsResult) : promptsResult;\n\t\tthis.prompts = resolvedPrompts.prompts;\n\t\tthis.promptDiagnostics = resolvedPrompts.diagnostics;\n\t\tthis.applyExtensionMetadata(\n\t\t\textensionPaths,\n\t\t\tthis.prompts.map((prompt) => prompt.filePath),\n\t\t);\n\t\tfor (const prompt of this.prompts) {\n\t\t\tthis.addDefaultMetadataForPath(prompt.filePath);\n\t\t}\n\t}\n\n\tprivate updateThemesFromPaths(\n\t\tthemePaths: string[],\n\t\textensionPaths: Array<{ path: string; metadata: PathMetadata }> = [],\n\t): void {\n\t\tlet themesResult: { themes: Theme[]; diagnostics: ResourceDiagnostic[] };\n\t\tif (this.noThemes && themePaths.length === 0) {\n\t\t\tthemesResult = { themes: [], diagnostics: [] };\n\t\t} else {\n\t\t\tconst loaded = this.loadThemes(themePaths, false);\n\t\t\tconst deduped = this.dedupeThemes(loaded.themes);\n\t\t\tthemesResult = { themes: deduped.themes, diagnostics: [...loaded.diagnostics, ...deduped.diagnostics] };\n\t\t}\n\t\tconst resolvedThemes = this.themesOverride ? this.themesOverride(themesResult) : themesResult;\n\t\tthis.themes = resolvedThemes.themes;\n\t\tthis.themeDiagnostics = resolvedThemes.diagnostics;\n\t\tconst themePathsWithSource = this.themes.flatMap((theme) => (theme.sourcePath ? [theme.sourcePath] : []));\n\t\tthis.applyExtensionMetadata(extensionPaths, themePathsWithSource);\n\t\tfor (const theme of this.themes) {\n\t\t\tif (theme.sourcePath) {\n\t\t\t\tthis.addDefaultMetadataForPath(theme.sourcePath);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate applyExtensionMetadata(\n\t\textensionPaths: Array<{ path: string; metadata: PathMetadata }>,\n\t\tresourcePaths: string[],\n\t): void {\n\t\tif (extensionPaths.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst normalized = extensionPaths.map((entry) => ({\n\t\t\tpath: resolve(entry.path),\n\t\t\tmetadata: entry.metadata,\n\t\t}));\n\n\t\tfor (const entry of normalized) {\n\t\t\tif (!this.pathMetadata.has(entry.path)) {\n\t\t\t\tthis.pathMetadata.set(entry.path, entry.metadata);\n\t\t\t}\n\t\t}\n\n\t\tfor (const resourcePath of resourcePaths) {\n\t\t\tconst normalizedResourcePath = resolve(resourcePath);\n\t\t\tif (this.pathMetadata.has(normalizedResourcePath) || this.pathMetadata.has(resourcePath)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst match = normalized.find(\n\t\t\t\t(entry) =>\n\t\t\t\t\tnormalizedResourcePath === entry.path || normalizedResourcePath.startsWith(`${entry.path}${sep}`),\n\t\t\t);\n\t\t\tif (match) {\n\t\t\t\tthis.pathMetadata.set(normalizedResourcePath, match.metadata);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate mergePaths(primary: string[], additional: string[]): string[] {\n\t\tconst merged: string[] = [];\n\t\tconst seen = new Set<string>();\n\n\t\tfor (const p of [...primary, ...additional]) {\n\t\t\tconst resolved = this.resolveResourcePath(p);\n\t\t\tif (seen.has(resolved)) continue;\n\t\t\tseen.add(resolved);\n\t\t\tmerged.push(resolved);\n\t\t}\n\n\t\treturn merged;\n\t}\n\n\tprivate resolveResourcePath(p: string): string {\n\t\tconst trimmed = p.trim();\n\t\tlet expanded = trimmed;\n\t\tif (trimmed === \"~\") {\n\t\t\texpanded = homedir();\n\t\t} else if (trimmed.startsWith(\"~/\")) {\n\t\t\texpanded = join(homedir(), trimmed.slice(2));\n\t\t} else if (trimmed.startsWith(\"~\")) {\n\t\t\texpanded = join(homedir(), trimmed.slice(1));\n\t\t}\n\t\treturn resolve(this.cwd, expanded);\n\t}\n\n\tprivate loadThemes(\n\t\tpaths: string[],\n\t\tincludeDefaults: boolean = true,\n\t): {\n\t\tthemes: Theme[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t} {\n\t\tconst themes: Theme[] = [];\n\t\tconst diagnostics: ResourceDiagnostic[] = [];\n\t\tif (includeDefaults) {\n\t\t\tconst defaultDirs = [join(this.agentDir, \"themes\"), join(getProjectConfigDir(this.cwd), \"themes\")];\n\n\t\t\tfor (const dir of defaultDirs) {\n\t\t\t\tthis.loadThemesFromDir(dir, themes, diagnostics);\n\t\t\t}\n\t\t}\n\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = resolve(this.cwd, p);\n\t\t\tif (!existsSync(resolved)) {\n\t\t\t\tdiagnostics.push({ type: \"warning\", message: \"theme path does not exist\", path: resolved });\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst stats = statSync(resolved);\n\t\t\t\tif (stats.isDirectory()) {\n\t\t\t\t\tthis.loadThemesFromDir(resolved, themes, diagnostics);\n\t\t\t\t} else if (stats.isFile() && resolved.endsWith(\".json\")) {\n\t\t\t\t\tthis.loadThemeFromFile(resolved, themes, diagnostics);\n\t\t\t\t} else {\n\t\t\t\t\tdiagnostics.push({ type: \"warning\", message: \"theme path is not a json file\", path: resolved });\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : \"failed to read theme path\";\n\t\t\t\tdiagnostics.push({ type: \"warning\", message, path: resolved });\n\t\t\t}\n\t\t}\n\n\t\treturn { themes, diagnostics };\n\t}\n\n\tprivate loadThemesFromDir(dir: string, themes: Theme[], diagnostics: ResourceDiagnostic[]): void {\n\t\tif (!existsSync(dir)) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\t\t\tfor (const entry of entries) {\n\t\t\t\tlet isFile = entry.isFile();\n\t\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tisFile = statSync(join(dir, entry.name)).isFile();\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!isFile) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (!entry.name.endsWith(\".json\")) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthis.loadThemeFromFile(join(dir, entry.name), themes, diagnostics);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"failed to read theme directory\";\n\t\t\tdiagnostics.push({ type: \"warning\", message, path: dir });\n\t\t}\n\t}\n\n\tprivate loadThemeFromFile(filePath: string, themes: Theme[], diagnostics: ResourceDiagnostic[]): void {\n\t\ttry {\n\t\t\tthemes.push(loadThemeFromPath(filePath));\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"failed to load theme\";\n\t\t\tdiagnostics.push({ type: \"warning\", message, path: filePath });\n\t\t}\n\t}\n\n\tprivate async loadExtensionFactories(runtime: ExtensionRuntime): Promise<{\n\t\textensions: Extension[];\n\t\terrors: Array<{ path: string; error: string }>;\n\t}> {\n\t\tconst extensions: Extension[] = [];\n\t\tconst errors: Array<{ path: string; error: string }> = [];\n\n\t\tfor (const [index, factory] of this.extensionFactories.entries()) {\n\t\t\tconst extensionPath = `<inline:${index + 1}>`;\n\t\t\ttry {\n\t\t\t\tconst extension = await loadExtensionFromFactory(factory, this.cwd, this.eventBus, runtime, extensionPath);\n\t\t\t\textensions.push(extension);\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : \"failed to load extension\";\n\t\t\t\terrors.push({ path: extensionPath, error: message });\n\t\t\t}\n\t\t}\n\n\t\treturn { extensions, errors };\n\t}\n\n\tprivate dedupePrompts(prompts: PromptTemplate[]): { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] } {\n\t\tconst seen = new Map<string, PromptTemplate>();\n\t\tconst diagnostics: ResourceDiagnostic[] = [];\n\n\t\tfor (const prompt of prompts) {\n\t\t\tconst existing = seen.get(prompt.name);\n\t\t\tif (existing) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\ttype: \"collision\",\n\t\t\t\t\tmessage: `name \"/${prompt.name}\" collision`,\n\t\t\t\t\tpath: prompt.filePath,\n\t\t\t\t\tcollision: {\n\t\t\t\t\t\tresourceType: \"prompt\",\n\t\t\t\t\t\tname: prompt.name,\n\t\t\t\t\t\twinnerPath: existing.filePath,\n\t\t\t\t\t\tloserPath: prompt.filePath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tseen.set(prompt.name, prompt);\n\t\t\t}\n\t\t}\n\n\t\treturn { prompts: Array.from(seen.values()), diagnostics };\n\t}\n\n\tprivate dedupeThemes(themes: Theme[]): { themes: Theme[]; diagnostics: ResourceDiagnostic[] } {\n\t\tconst seen = new Map<string, Theme>();\n\t\tconst diagnostics: ResourceDiagnostic[] = [];\n\n\t\tfor (const t of themes) {\n\t\t\tconst name = t.name ?? \"unnamed\";\n\t\t\tconst existing = seen.get(name);\n\t\t\tif (existing) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\ttype: \"collision\",\n\t\t\t\t\tmessage: `name \"${name}\" collision`,\n\t\t\t\t\tpath: t.sourcePath,\n\t\t\t\t\tcollision: {\n\t\t\t\t\t\tresourceType: \"theme\",\n\t\t\t\t\t\tname,\n\t\t\t\t\t\twinnerPath: existing.sourcePath ?? \"<builtin>\",\n\t\t\t\t\t\tloserPath: t.sourcePath ?? \"<builtin>\",\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tseen.set(name, t);\n\t\t\t}\n\t\t}\n\n\t\treturn { themes: Array.from(seen.values()), diagnostics };\n\t}\n\n\tprivate discoverSystemPromptFile(): string | undefined {\n\t\tconst projectPath = join(getProjectConfigDir(this.cwd), \"SYSTEM.md\");\n\t\tif (existsSync(projectPath)) {\n\t\t\treturn projectPath;\n\t\t}\n\n\t\tconst globalPath = join(this.agentDir, \"SYSTEM.md\");\n\t\tif (existsSync(globalPath)) {\n\t\t\treturn globalPath;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate discoverAppendSystemPromptFile(): string | undefined {\n\t\tconst projectPath = join(getProjectConfigDir(this.cwd), \"APPEND_SYSTEM.md\");\n\t\tif (existsSync(projectPath)) {\n\t\t\treturn projectPath;\n\t\t}\n\n\t\tconst globalPath = join(this.agentDir, \"APPEND_SYSTEM.md\");\n\t\tif (existsSync(globalPath)) {\n\t\t\treturn globalPath;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate addDefaultMetadataForPath(filePath: string): void {\n\t\tif (!filePath || filePath.startsWith(\"<\")) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst normalizedPath = resolve(filePath);\n\t\tif (this.pathMetadata.has(normalizedPath) || this.pathMetadata.has(filePath)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst agentRoots = [\n\t\t\tjoin(this.agentDir, \"skills\"),\n\t\t\tjoin(this.agentDir, \"prompts\"),\n\t\t\tjoin(this.agentDir, \"themes\"),\n\t\t\tjoin(this.agentDir, \"extensions\"),\n\t\t];\n\t\tconst projectConfigDir = getProjectConfigDir(this.cwd);\n\t\tconst projectRoots = [\n\t\t\tjoin(projectConfigDir, \"skills\"),\n\t\t\tjoin(projectConfigDir, \"prompts\"),\n\t\t\tjoin(projectConfigDir, \"themes\"),\n\t\t\tjoin(projectConfigDir, \"extensions\"),\n\t\t];\n\n\t\tfor (const root of agentRoots) {\n\t\t\tif (this.isUnderPath(normalizedPath, root)) {\n\t\t\t\tthis.pathMetadata.set(normalizedPath, { source: \"local\", scope: \"user\", origin: \"top-level\" });\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tfor (const root of projectRoots) {\n\t\t\tif (this.isUnderPath(normalizedPath, root)) {\n\t\t\t\tthis.pathMetadata.set(normalizedPath, { source: \"local\", scope: \"project\", origin: \"top-level\" });\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate isUnderPath(target: string, root: string): boolean {\n\t\tconst normalizedRoot = resolve(root);\n\t\tif (target === normalizedRoot) {\n\t\t\treturn true;\n\t\t}\n\t\tconst prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;\n\t\treturn target.startsWith(prefix);\n\t}\n\n\tprivate detectExtensionConflicts(extensions: Extension[]): Array<{ path: string; message: string }> {\n\t\tconst conflicts: Array<{ path: string; message: string }> = [];\n\n\t\t// Track which extension registered each tool, command, and flag\n\t\tconst toolOwners = new Map<string, string>();\n\t\tconst commandOwners = new Map<string, string>();\n\t\tconst flagOwners = new Map<string, string>();\n\n\t\tfor (const ext of extensions) {\n\t\t\t// Check tools\n\t\t\tfor (const toolName of ext.tools.keys()) {\n\t\t\t\tconst existingOwner = toolOwners.get(toolName);\n\t\t\t\tif (existingOwner && existingOwner !== ext.path) {\n\t\t\t\t\tconflicts.push({\n\t\t\t\t\t\tpath: ext.path,\n\t\t\t\t\t\tmessage: `Tool \"${toolName}\" conflicts with ${existingOwner}`,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\ttoolOwners.set(toolName, ext.path);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check commands\n\t\t\tfor (const commandName of ext.commands.keys()) {\n\t\t\t\tconst existingOwner = commandOwners.get(commandName);\n\t\t\t\tif (existingOwner && existingOwner !== ext.path) {\n\t\t\t\t\tconflicts.push({\n\t\t\t\t\t\tpath: ext.path,\n\t\t\t\t\t\tmessage: `Command \"/${commandName}\" conflicts with ${existingOwner}`,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tcommandOwners.set(commandName, ext.path);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check flags\n\t\t\tfor (const flagName of ext.flags.keys()) {\n\t\t\t\tconst existingOwner = flagOwners.get(flagName);\n\t\t\t\tif (existingOwner && existingOwner !== ext.path) {\n\t\t\t\t\tconflicts.push({\n\t\t\t\t\t\tpath: ext.path,\n\t\t\t\t\t\tmessage: `Flag \"--${flagName}\" conflicts with ${existingOwner}`,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tflagOwners.set(flagName, ext.path);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn conflicts;\n\t}\n}\n"]}
1
+ {"version":3,"file":"resource-loader.d.ts","sourceRoot":"","sources":["../../src/core/resource-loader.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve, sep } from \"node:path\";\nimport chalk from \"chalk\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.js\";\nimport { loadThemeFromPath, type Theme } from \"../modes/interactive/theme/theme.js\";\nimport type { ResourceDiagnostic } from \"./diagnostics.js\";\n\nexport type { ResourceCollision, ResourceDiagnostic } from \"./diagnostics.js\";\n\nimport { createEventBus, type EventBus } from \"./event-bus.js\";\nimport { createExtensionRuntime, loadExtensionFromFactory, loadExtensions } from \"./extensions/loader.js\";\nimport type { Extension, ExtensionFactory, ExtensionRuntime, LoadExtensionsResult } from \"./extensions/types.js\";\nimport { DefaultPackageManager, type PathMetadata } from \"./package-manager.js\";\nimport type { PromptTemplate } from \"./prompt-templates.js\";\nimport { loadPromptTemplates } from \"./prompt-templates.js\";\nimport { SettingsManager } from \"./settings-manager.js\";\nimport type { Skill } from \"./skills.js\";\nimport { loadSkills } from \"./skills.js\";\nimport { createSourceInfo, type SourceInfo } from \"./source-info.js\";\n\nexport interface ResourceExtensionPaths {\n\tskillPaths?: Array<{ path: string; metadata: PathMetadata }>;\n\tpromptPaths?: Array<{ path: string; metadata: PathMetadata }>;\n\tthemePaths?: Array<{ path: string; metadata: PathMetadata }>;\n}\n\nexport interface ResourceLoader {\n\tgetExtensions(): LoadExtensionsResult;\n\tgetSkills(): { skills: Skill[]; diagnostics: ResourceDiagnostic[] };\n\tgetPrompts(): { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] };\n\tgetThemes(): { themes: Theme[]; diagnostics: ResourceDiagnostic[] };\n\tgetAgentsFiles(): { agentsFiles: Array<{ path: string; content: string }> };\n\tgetSystemPrompt(): string | undefined;\n\tgetAppendSystemPrompt(): string[];\n\textendResources(paths: ResourceExtensionPaths): void;\n\treload(): Promise<void>;\n}\n\nfunction resolvePromptInput(input: string | undefined, description: string): string | undefined {\n\tif (!input) {\n\t\treturn undefined;\n\t}\n\n\tif (existsSync(input)) {\n\t\ttry {\n\t\t\treturn readFileSync(input, \"utf-8\");\n\t\t} catch (error) {\n\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${description} file ${input}: ${error}`));\n\t\t\treturn input;\n\t\t}\n\t}\n\n\treturn input;\n}\n\nfunction loadContextFileFromDir(dir: string): { path: string; content: string } | null {\n\tconst candidates = [\"AGENTS.md\", \"CLAUDE.md\"];\n\tfor (const filename of candidates) {\n\t\tconst filePath = join(dir, filename);\n\t\tif (existsSync(filePath)) {\n\t\t\ttry {\n\t\t\t\treturn {\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\tcontent: readFileSync(filePath, \"utf-8\"),\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${filePath}: ${error}`));\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction loadProjectContextFiles(\n\toptions: { cwd?: string; agentDir?: string } = {},\n): Array<{ path: string; content: string }> {\n\tconst resolvedCwd = options.cwd ?? process.cwd();\n\tconst resolvedAgentDir = options.agentDir ?? getAgentDir();\n\n\tconst contextFiles: Array<{ path: string; content: string }> = [];\n\tconst seenPaths = new Set<string>();\n\n\tconst globalContext = loadContextFileFromDir(resolvedAgentDir);\n\tif (globalContext) {\n\t\tcontextFiles.push(globalContext);\n\t\tseenPaths.add(globalContext.path);\n\t}\n\n\tconst ancestorContextFiles: Array<{ path: string; content: string }> = [];\n\n\tlet currentDir = resolvedCwd;\n\tconst root = resolve(\"/\");\n\n\twhile (true) {\n\t\tconst contextFile = loadContextFileFromDir(currentDir);\n\t\tif (contextFile && !seenPaths.has(contextFile.path)) {\n\t\t\tancestorContextFiles.unshift(contextFile);\n\t\t\tseenPaths.add(contextFile.path);\n\t\t}\n\n\t\tif (currentDir === root) break;\n\n\t\tconst parentDir = resolve(currentDir, \"..\");\n\t\tif (parentDir === currentDir) break;\n\t\tcurrentDir = parentDir;\n\t}\n\n\tcontextFiles.push(...ancestorContextFiles);\n\n\treturn contextFiles;\n}\n\nexport interface DefaultResourceLoaderOptions {\n\tcwd?: string;\n\tagentDir?: string;\n\tsettingsManager?: SettingsManager;\n\teventBus?: EventBus;\n\tadditionalExtensionPaths?: string[];\n\tadditionalSkillPaths?: string[];\n\tadditionalPromptTemplatePaths?: string[];\n\tadditionalThemePaths?: string[];\n\textensionFactories?: ExtensionFactory[];\n\tnoExtensions?: boolean;\n\tnoSkills?: boolean;\n\tnoPromptTemplates?: boolean;\n\tnoThemes?: boolean;\n\tsystemPrompt?: string;\n\tappendSystemPrompt?: string;\n\textensionsOverride?: (base: LoadExtensionsResult) => LoadExtensionsResult;\n\tskillsOverride?: (base: { skills: Skill[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tskills: Skill[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tpromptsOverride?: (base: { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tprompts: PromptTemplate[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tthemesOverride?: (base: { themes: Theme[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tthemes: Theme[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tagentsFilesOverride?: (base: { agentsFiles: Array<{ path: string; content: string }> }) => {\n\t\tagentsFiles: Array<{ path: string; content: string }>;\n\t};\n\tsystemPromptOverride?: (base: string | undefined) => string | undefined;\n\tappendSystemPromptOverride?: (base: string[]) => string[];\n}\n\nexport class DefaultResourceLoader implements ResourceLoader {\n\tprivate cwd: string;\n\tprivate agentDir: string;\n\tprivate settingsManager: SettingsManager;\n\tprivate eventBus: EventBus;\n\tprivate packageManager: DefaultPackageManager;\n\tprivate additionalExtensionPaths: string[];\n\tprivate additionalSkillPaths: string[];\n\tprivate additionalPromptTemplatePaths: string[];\n\tprivate additionalThemePaths: string[];\n\tprivate extensionFactories: ExtensionFactory[];\n\tprivate noExtensions: boolean;\n\tprivate noSkills: boolean;\n\tprivate noPromptTemplates: boolean;\n\tprivate noThemes: boolean;\n\tprivate systemPromptSource?: string;\n\tprivate appendSystemPromptSource?: string;\n\tprivate extensionsOverride?: (base: LoadExtensionsResult) => LoadExtensionsResult;\n\tprivate skillsOverride?: (base: { skills: Skill[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tskills: Skill[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tprivate promptsOverride?: (base: { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tprompts: PromptTemplate[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tprivate themesOverride?: (base: { themes: Theme[]; diagnostics: ResourceDiagnostic[] }) => {\n\t\tthemes: Theme[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t};\n\tprivate agentsFilesOverride?: (base: { agentsFiles: Array<{ path: string; content: string }> }) => {\n\t\tagentsFiles: Array<{ path: string; content: string }>;\n\t};\n\tprivate systemPromptOverride?: (base: string | undefined) => string | undefined;\n\tprivate appendSystemPromptOverride?: (base: string[]) => string[];\n\n\tprivate extensionsResult: LoadExtensionsResult;\n\tprivate skills: Skill[];\n\tprivate skillDiagnostics: ResourceDiagnostic[];\n\tprivate prompts: PromptTemplate[];\n\tprivate promptDiagnostics: ResourceDiagnostic[];\n\tprivate themes: Theme[];\n\tprivate themeDiagnostics: ResourceDiagnostic[];\n\tprivate agentsFiles: Array<{ path: string; content: string }>;\n\tprivate systemPrompt?: string;\n\tprivate appendSystemPrompt: string[];\n\tprivate lastSkillPaths: string[];\n\tprivate extensionSkillSourceInfos: Map<string, SourceInfo>;\n\tprivate extensionPromptSourceInfos: Map<string, SourceInfo>;\n\tprivate extensionThemeSourceInfos: Map<string, SourceInfo>;\n\tprivate lastPromptPaths: string[];\n\tprivate lastThemePaths: string[];\n\n\tconstructor(options: DefaultResourceLoaderOptions) {\n\t\tthis.cwd = options.cwd ?? process.cwd();\n\t\tthis.agentDir = options.agentDir ?? getAgentDir();\n\t\tthis.settingsManager = options.settingsManager ?? SettingsManager.create(this.cwd, this.agentDir);\n\t\tthis.eventBus = options.eventBus ?? createEventBus();\n\t\tthis.packageManager = new DefaultPackageManager({\n\t\t\tcwd: this.cwd,\n\t\t\tagentDir: this.agentDir,\n\t\t\tsettingsManager: this.settingsManager,\n\t\t});\n\t\tthis.additionalExtensionPaths = options.additionalExtensionPaths ?? [];\n\t\tthis.additionalSkillPaths = options.additionalSkillPaths ?? [];\n\t\tthis.additionalPromptTemplatePaths = options.additionalPromptTemplatePaths ?? [];\n\t\tthis.additionalThemePaths = options.additionalThemePaths ?? [];\n\t\tthis.extensionFactories = options.extensionFactories ?? [];\n\t\tthis.noExtensions = options.noExtensions ?? false;\n\t\tthis.noSkills = options.noSkills ?? false;\n\t\tthis.noPromptTemplates = options.noPromptTemplates ?? false;\n\t\tthis.noThemes = options.noThemes ?? false;\n\t\tthis.systemPromptSource = options.systemPrompt;\n\t\tthis.appendSystemPromptSource = options.appendSystemPrompt;\n\t\tthis.extensionsOverride = options.extensionsOverride;\n\t\tthis.skillsOverride = options.skillsOverride;\n\t\tthis.promptsOverride = options.promptsOverride;\n\t\tthis.themesOverride = options.themesOverride;\n\t\tthis.agentsFilesOverride = options.agentsFilesOverride;\n\t\tthis.systemPromptOverride = options.systemPromptOverride;\n\t\tthis.appendSystemPromptOverride = options.appendSystemPromptOverride;\n\n\t\tthis.extensionsResult = { extensions: [], errors: [], runtime: createExtensionRuntime() };\n\t\tthis.skills = [];\n\t\tthis.skillDiagnostics = [];\n\t\tthis.prompts = [];\n\t\tthis.promptDiagnostics = [];\n\t\tthis.themes = [];\n\t\tthis.themeDiagnostics = [];\n\t\tthis.agentsFiles = [];\n\t\tthis.appendSystemPrompt = [];\n\t\tthis.lastSkillPaths = [];\n\t\tthis.extensionSkillSourceInfos = new Map();\n\t\tthis.extensionPromptSourceInfos = new Map();\n\t\tthis.extensionThemeSourceInfos = new Map();\n\t\tthis.lastPromptPaths = [];\n\t\tthis.lastThemePaths = [];\n\t}\n\n\tgetExtensions(): LoadExtensionsResult {\n\t\treturn this.extensionsResult;\n\t}\n\n\tgetSkills(): { skills: Skill[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn { skills: this.skills, diagnostics: this.skillDiagnostics };\n\t}\n\n\tgetPrompts(): { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn { prompts: this.prompts, diagnostics: this.promptDiagnostics };\n\t}\n\n\tgetThemes(): { themes: Theme[]; diagnostics: ResourceDiagnostic[] } {\n\t\treturn { themes: this.themes, diagnostics: this.themeDiagnostics };\n\t}\n\n\tgetAgentsFiles(): { agentsFiles: Array<{ path: string; content: string }> } {\n\t\treturn { agentsFiles: this.agentsFiles };\n\t}\n\n\tgetSystemPrompt(): string | undefined {\n\t\treturn this.systemPrompt;\n\t}\n\n\tgetAppendSystemPrompt(): string[] {\n\t\treturn this.appendSystemPrompt;\n\t}\n\n\textendResources(paths: ResourceExtensionPaths): void {\n\t\tconst skillPaths = this.normalizeExtensionPaths(paths.skillPaths ?? []);\n\t\tconst promptPaths = this.normalizeExtensionPaths(paths.promptPaths ?? []);\n\t\tconst themePaths = this.normalizeExtensionPaths(paths.themePaths ?? []);\n\n\t\tfor (const entry of skillPaths) {\n\t\t\tthis.extensionSkillSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));\n\t\t}\n\t\tfor (const entry of promptPaths) {\n\t\t\tthis.extensionPromptSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));\n\t\t}\n\t\tfor (const entry of themePaths) {\n\t\t\tthis.extensionThemeSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));\n\t\t}\n\n\t\tif (skillPaths.length > 0) {\n\t\t\tthis.lastSkillPaths = this.mergePaths(\n\t\t\t\tthis.lastSkillPaths,\n\t\t\t\tskillPaths.map((entry) => entry.path),\n\t\t\t);\n\t\t\tthis.updateSkillsFromPaths(this.lastSkillPaths);\n\t\t}\n\n\t\tif (promptPaths.length > 0) {\n\t\t\tthis.lastPromptPaths = this.mergePaths(\n\t\t\t\tthis.lastPromptPaths,\n\t\t\t\tpromptPaths.map((entry) => entry.path),\n\t\t\t);\n\t\t\tthis.updatePromptsFromPaths(this.lastPromptPaths);\n\t\t}\n\n\t\tif (themePaths.length > 0) {\n\t\t\tthis.lastThemePaths = this.mergePaths(\n\t\t\t\tthis.lastThemePaths,\n\t\t\t\tthemePaths.map((entry) => entry.path),\n\t\t\t);\n\t\t\tthis.updateThemesFromPaths(this.lastThemePaths);\n\t\t}\n\t}\n\n\tasync reload(): Promise<void> {\n\t\tconst resolvedPaths = await this.packageManager.resolve();\n\t\tconst cliExtensionPaths = await this.packageManager.resolveExtensionSources(this.additionalExtensionPaths, {\n\t\t\ttemporary: true,\n\t\t});\n\t\tconst metadataByPath = new Map<string, PathMetadata>();\n\n\t\tthis.extensionSkillSourceInfos = new Map();\n\t\tthis.extensionPromptSourceInfos = new Map();\n\t\tthis.extensionThemeSourceInfos = new Map();\n\n\t\t// Helper to extract enabled paths and store metadata\n\t\tconst getEnabledResources = (\n\t\t\tresources: Array<{ path: string; enabled: boolean; metadata: PathMetadata }>,\n\t\t): Array<{ path: string; enabled: boolean; metadata: PathMetadata }> => {\n\t\t\tfor (const r of resources) {\n\t\t\t\tif (!metadataByPath.has(r.path)) {\n\t\t\t\t\tmetadataByPath.set(r.path, r.metadata);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn resources.filter((r) => r.enabled);\n\t\t};\n\n\t\tconst getEnabledPaths = (\n\t\t\tresources: Array<{ path: string; enabled: boolean; metadata: PathMetadata }>,\n\t\t): string[] => getEnabledResources(resources).map((r) => r.path);\n\t\tconst enabledExtensions = getEnabledPaths(resolvedPaths.extensions);\n\t\tconst enabledSkillResources = getEnabledResources(resolvedPaths.skills);\n\t\tconst enabledPrompts = getEnabledPaths(resolvedPaths.prompts);\n\t\tconst enabledThemes = getEnabledPaths(resolvedPaths.themes);\n\n\t\tconst mapSkillPath = (resource: { path: string; metadata: PathMetadata }): string => {\n\t\t\tif (resource.metadata.source !== \"auto\" && resource.metadata.origin !== \"package\") {\n\t\t\t\treturn resource.path;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst stats = statSync(resource.path);\n\t\t\t\tif (!stats.isDirectory()) {\n\t\t\t\t\treturn resource.path;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\treturn resource.path;\n\t\t\t}\n\t\t\tconst skillFile = join(resource.path, \"SKILL.md\");\n\t\t\tif (existsSync(skillFile)) {\n\t\t\t\tif (!metadataByPath.has(skillFile)) {\n\t\t\t\t\tmetadataByPath.set(skillFile, resource.metadata);\n\t\t\t\t}\n\t\t\t\treturn skillFile;\n\t\t\t}\n\t\t\treturn resource.path;\n\t\t};\n\n\t\tconst enabledSkills = enabledSkillResources.map(mapSkillPath);\n\n\t\t// Add CLI paths metadata\n\t\tfor (const r of cliExtensionPaths.extensions) {\n\t\t\tif (!metadataByPath.has(r.path)) {\n\t\t\t\tmetadataByPath.set(r.path, { source: \"cli\", scope: \"temporary\", origin: \"top-level\" });\n\t\t\t}\n\t\t}\n\t\tfor (const r of cliExtensionPaths.skills) {\n\t\t\tif (!metadataByPath.has(r.path)) {\n\t\t\t\tmetadataByPath.set(r.path, { source: \"cli\", scope: \"temporary\", origin: \"top-level\" });\n\t\t\t}\n\t\t}\n\n\t\tconst cliEnabledExtensions = getEnabledPaths(cliExtensionPaths.extensions);\n\t\tconst cliEnabledSkills = getEnabledPaths(cliExtensionPaths.skills);\n\t\tconst cliEnabledPrompts = getEnabledPaths(cliExtensionPaths.prompts);\n\t\tconst cliEnabledThemes = getEnabledPaths(cliExtensionPaths.themes);\n\n\t\tconst extensionPaths = this.noExtensions\n\t\t\t? cliEnabledExtensions\n\t\t\t: this.mergePaths(cliEnabledExtensions, enabledExtensions);\n\n\t\tconst extensionsResult = await loadExtensions(extensionPaths, this.cwd, this.eventBus);\n\t\tconst inlineExtensions = await this.loadExtensionFactories(extensionsResult.runtime);\n\t\textensionsResult.extensions.push(...inlineExtensions.extensions);\n\t\textensionsResult.errors.push(...inlineExtensions.errors);\n\n\t\t// Detect extension conflicts (tools, commands, flags with same names from different extensions)\n\t\t// Keep all extensions loaded. Conflicts are reported as diagnostics, and precedence is handled by load order.\n\t\tconst conflicts = this.detectExtensionConflicts(extensionsResult.extensions);\n\t\tfor (const conflict of conflicts) {\n\t\t\textensionsResult.errors.push({ path: conflict.path, error: conflict.message });\n\t\t}\n\n\t\tthis.extensionsResult = this.extensionsOverride ? this.extensionsOverride(extensionsResult) : extensionsResult;\n\t\tthis.applyExtensionSourceInfo(this.extensionsResult.extensions, metadataByPath);\n\n\t\tconst skillPaths = this.noSkills\n\t\t\t? this.mergePaths(cliEnabledSkills, this.additionalSkillPaths)\n\t\t\t: this.mergePaths([...enabledSkills, ...cliEnabledSkills], this.additionalSkillPaths);\n\n\t\tthis.lastSkillPaths = skillPaths;\n\t\tthis.updateSkillsFromPaths(skillPaths, metadataByPath);\n\n\t\tconst promptPaths = this.noPromptTemplates\n\t\t\t? this.mergePaths(cliEnabledPrompts, this.additionalPromptTemplatePaths)\n\t\t\t: this.mergePaths([...enabledPrompts, ...cliEnabledPrompts], this.additionalPromptTemplatePaths);\n\n\t\tthis.lastPromptPaths = promptPaths;\n\t\tthis.updatePromptsFromPaths(promptPaths, metadataByPath);\n\n\t\tconst themePaths = this.noThemes\n\t\t\t? this.mergePaths(cliEnabledThemes, this.additionalThemePaths)\n\t\t\t: this.mergePaths([...enabledThemes, ...cliEnabledThemes], this.additionalThemePaths);\n\n\t\tthis.lastThemePaths = themePaths;\n\t\tthis.updateThemesFromPaths(themePaths, metadataByPath);\n\n\t\tconst agentsFiles = { agentsFiles: loadProjectContextFiles({ cwd: this.cwd, agentDir: this.agentDir }) };\n\t\tconst resolvedAgentsFiles = this.agentsFilesOverride ? this.agentsFilesOverride(agentsFiles) : agentsFiles;\n\t\tthis.agentsFiles = resolvedAgentsFiles.agentsFiles;\n\n\t\tconst baseSystemPrompt = resolvePromptInput(\n\t\t\tthis.systemPromptSource ?? this.discoverSystemPromptFile(),\n\t\t\t\"system prompt\",\n\t\t);\n\t\tthis.systemPrompt = this.systemPromptOverride ? this.systemPromptOverride(baseSystemPrompt) : baseSystemPrompt;\n\n\t\tconst appendSource = this.appendSystemPromptSource ?? this.discoverAppendSystemPromptFile();\n\t\tconst resolvedAppend = resolvePromptInput(appendSource, \"append system prompt\");\n\t\tconst baseAppend = resolvedAppend ? [resolvedAppend] : [];\n\t\tthis.appendSystemPrompt = this.appendSystemPromptOverride\n\t\t\t? this.appendSystemPromptOverride(baseAppend)\n\t\t\t: baseAppend;\n\t}\n\n\tprivate normalizeExtensionPaths(\n\t\tentries: Array<{ path: string; metadata: PathMetadata }>,\n\t): Array<{ path: string; metadata: PathMetadata }> {\n\t\treturn entries.map((entry) => ({\n\t\t\tpath: this.resolveResourcePath(entry.path),\n\t\t\tmetadata: entry.metadata,\n\t\t}));\n\t}\n\n\tprivate updateSkillsFromPaths(skillPaths: string[], metadataByPath?: Map<string, PathMetadata>): void {\n\t\tlet skillsResult: { skills: Skill[]; diagnostics: ResourceDiagnostic[] };\n\t\tif (this.noSkills && skillPaths.length === 0) {\n\t\t\tskillsResult = { skills: [], diagnostics: [] };\n\t\t} else {\n\t\t\tskillsResult = loadSkills({\n\t\t\t\tcwd: this.cwd,\n\t\t\t\tagentDir: this.agentDir,\n\t\t\t\tskillPaths,\n\t\t\t\tincludeDefaults: false,\n\t\t\t});\n\t\t}\n\t\tconst resolvedSkills = this.skillsOverride ? this.skillsOverride(skillsResult) : skillsResult;\n\t\tthis.skills = resolvedSkills.skills.map((skill) => ({\n\t\t\t...skill,\n\t\t\tsourceInfo:\n\t\t\t\tthis.findSourceInfoForPath(skill.filePath, this.extensionSkillSourceInfos, metadataByPath) ??\n\t\t\t\tskill.sourceInfo ??\n\t\t\t\tthis.getDefaultSourceInfoForPath(skill.filePath),\n\t\t}));\n\t\tthis.skillDiagnostics = resolvedSkills.diagnostics;\n\t}\n\n\tprivate updatePromptsFromPaths(promptPaths: string[], metadataByPath?: Map<string, PathMetadata>): void {\n\t\tlet promptsResult: { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] };\n\t\tif (this.noPromptTemplates && promptPaths.length === 0) {\n\t\t\tpromptsResult = { prompts: [], diagnostics: [] };\n\t\t} else {\n\t\t\tconst allPrompts = loadPromptTemplates({\n\t\t\t\tcwd: this.cwd,\n\t\t\t\tagentDir: this.agentDir,\n\t\t\t\tpromptPaths,\n\t\t\t\tincludeDefaults: false,\n\t\t\t});\n\t\t\tpromptsResult = this.dedupePrompts(allPrompts);\n\t\t}\n\t\tconst resolvedPrompts = this.promptsOverride ? this.promptsOverride(promptsResult) : promptsResult;\n\t\tthis.prompts = resolvedPrompts.prompts.map((prompt) => ({\n\t\t\t...prompt,\n\t\t\tsourceInfo:\n\t\t\t\tthis.findSourceInfoForPath(prompt.filePath, this.extensionPromptSourceInfos, metadataByPath) ??\n\t\t\t\tprompt.sourceInfo ??\n\t\t\t\tthis.getDefaultSourceInfoForPath(prompt.filePath),\n\t\t}));\n\t\tthis.promptDiagnostics = resolvedPrompts.diagnostics;\n\t}\n\n\tprivate updateThemesFromPaths(themePaths: string[], metadataByPath?: Map<string, PathMetadata>): void {\n\t\tlet themesResult: { themes: Theme[]; diagnostics: ResourceDiagnostic[] };\n\t\tif (this.noThemes && themePaths.length === 0) {\n\t\t\tthemesResult = { themes: [], diagnostics: [] };\n\t\t} else {\n\t\t\tconst loaded = this.loadThemes(themePaths, false);\n\t\t\tconst deduped = this.dedupeThemes(loaded.themes);\n\t\t\tthemesResult = { themes: deduped.themes, diagnostics: [...loaded.diagnostics, ...deduped.diagnostics] };\n\t\t}\n\t\tconst resolvedThemes = this.themesOverride ? this.themesOverride(themesResult) : themesResult;\n\t\tthis.themes = resolvedThemes.themes.map((theme) => {\n\t\t\tconst sourcePath = theme.sourcePath;\n\t\t\ttheme.sourceInfo = sourcePath\n\t\t\t\t? (this.findSourceInfoForPath(sourcePath, this.extensionThemeSourceInfos, metadataByPath) ??\n\t\t\t\t\ttheme.sourceInfo ??\n\t\t\t\t\tthis.getDefaultSourceInfoForPath(sourcePath))\n\t\t\t\t: theme.sourceInfo;\n\t\t\treturn theme;\n\t\t});\n\t\tthis.themeDiagnostics = resolvedThemes.diagnostics;\n\t}\n\n\tprivate applyExtensionSourceInfo(extensions: Extension[], metadataByPath: Map<string, PathMetadata>): void {\n\t\tfor (const extension of extensions) {\n\t\t\textension.sourceInfo =\n\t\t\t\tthis.findSourceInfoForPath(extension.path, undefined, metadataByPath) ??\n\t\t\t\tthis.getDefaultSourceInfoForPath(extension.path);\n\t\t\tfor (const command of extension.commands.values()) {\n\t\t\t\tcommand.sourceInfo = extension.sourceInfo;\n\t\t\t}\n\t\t\tfor (const tool of extension.tools.values()) {\n\t\t\t\ttool.sourceInfo = extension.sourceInfo;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate findSourceInfoForPath(\n\t\tresourcePath: string,\n\t\textraSourceInfos?: Map<string, SourceInfo>,\n\t\tmetadataByPath?: Map<string, PathMetadata>,\n\t): SourceInfo | undefined {\n\t\tif (!resourcePath) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (resourcePath.startsWith(\"<\")) {\n\t\t\treturn this.getDefaultSourceInfoForPath(resourcePath);\n\t\t}\n\n\t\tconst normalizedResourcePath = resolve(resourcePath);\n\t\tif (extraSourceInfos) {\n\t\t\tfor (const [sourcePath, sourceInfo] of extraSourceInfos.entries()) {\n\t\t\t\tconst normalizedSourcePath = resolve(sourcePath);\n\t\t\t\tif (\n\t\t\t\t\tnormalizedResourcePath === normalizedSourcePath ||\n\t\t\t\t\tnormalizedResourcePath.startsWith(`${normalizedSourcePath}${sep}`)\n\t\t\t\t) {\n\t\t\t\t\treturn { ...sourceInfo, path: resourcePath };\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (metadataByPath) {\n\t\t\tconst exact = metadataByPath.get(normalizedResourcePath) ?? metadataByPath.get(resourcePath);\n\t\t\tif (exact) {\n\t\t\t\treturn createSourceInfo(resourcePath, exact);\n\t\t\t}\n\n\t\t\tfor (const [sourcePath, metadata] of metadataByPath.entries()) {\n\t\t\t\tconst normalizedSourcePath = resolve(sourcePath);\n\t\t\t\tif (\n\t\t\t\t\tnormalizedResourcePath === normalizedSourcePath ||\n\t\t\t\t\tnormalizedResourcePath.startsWith(`${normalizedSourcePath}${sep}`)\n\t\t\t\t) {\n\t\t\t\t\treturn createSourceInfo(resourcePath, metadata);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate getDefaultSourceInfoForPath(filePath: string): SourceInfo {\n\t\tif (filePath.startsWith(\"<\") && filePath.endsWith(\">\")) {\n\t\t\treturn {\n\t\t\t\tpath: filePath,\n\t\t\t\tsource: filePath.slice(1, -1).split(\":\")[0] || \"temporary\",\n\t\t\t\tscope: \"temporary\",\n\t\t\t\torigin: \"top-level\",\n\t\t\t};\n\t\t}\n\n\t\tconst normalizedPath = resolve(filePath);\n\t\tconst agentRoots = [\n\t\t\tjoin(this.agentDir, \"skills\"),\n\t\t\tjoin(this.agentDir, \"prompts\"),\n\t\t\tjoin(this.agentDir, \"themes\"),\n\t\t\tjoin(this.agentDir, \"extensions\"),\n\t\t];\n\t\tconst projectRoots = [\n\t\t\tjoin(this.cwd, CONFIG_DIR_NAME, \"skills\"),\n\t\t\tjoin(this.cwd, CONFIG_DIR_NAME, \"prompts\"),\n\t\t\tjoin(this.cwd, CONFIG_DIR_NAME, \"themes\"),\n\t\t\tjoin(this.cwd, CONFIG_DIR_NAME, \"extensions\"),\n\t\t];\n\n\t\tfor (const root of agentRoots) {\n\t\t\tif (this.isUnderPath(normalizedPath, root)) {\n\t\t\t\treturn { path: filePath, source: \"local\", scope: \"user\", origin: \"top-level\", baseDir: root };\n\t\t\t}\n\t\t}\n\n\t\tfor (const root of projectRoots) {\n\t\t\tif (this.isUnderPath(normalizedPath, root)) {\n\t\t\t\treturn { path: filePath, source: \"local\", scope: \"project\", origin: \"top-level\", baseDir: root };\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tpath: filePath,\n\t\t\tsource: \"local\",\n\t\t\tscope: \"temporary\",\n\t\t\torigin: \"top-level\",\n\t\t\tbaseDir: statSync(normalizedPath).isDirectory() ? normalizedPath : resolve(normalizedPath, \"..\"),\n\t\t};\n\t}\n\n\tprivate mergePaths(primary: string[], additional: string[]): string[] {\n\t\tconst merged: string[] = [];\n\t\tconst seen = new Set<string>();\n\n\t\tfor (const p of [...primary, ...additional]) {\n\t\t\tconst resolved = this.resolveResourcePath(p);\n\t\t\tif (seen.has(resolved)) continue;\n\t\t\tseen.add(resolved);\n\t\t\tmerged.push(resolved);\n\t\t}\n\n\t\treturn merged;\n\t}\n\n\tprivate resolveResourcePath(p: string): string {\n\t\tconst trimmed = p.trim();\n\t\tlet expanded = trimmed;\n\t\tif (trimmed === \"~\") {\n\t\t\texpanded = homedir();\n\t\t} else if (trimmed.startsWith(\"~/\")) {\n\t\t\texpanded = join(homedir(), trimmed.slice(2));\n\t\t} else if (trimmed.startsWith(\"~\")) {\n\t\t\texpanded = join(homedir(), trimmed.slice(1));\n\t\t}\n\t\treturn resolve(this.cwd, expanded);\n\t}\n\n\tprivate loadThemes(\n\t\tpaths: string[],\n\t\tincludeDefaults: boolean = true,\n\t): {\n\t\tthemes: Theme[];\n\t\tdiagnostics: ResourceDiagnostic[];\n\t} {\n\t\tconst themes: Theme[] = [];\n\t\tconst diagnostics: ResourceDiagnostic[] = [];\n\t\tif (includeDefaults) {\n\t\t\tconst defaultDirs = [join(this.agentDir, \"themes\"), join(this.cwd, CONFIG_DIR_NAME, \"themes\")];\n\n\t\t\tfor (const dir of defaultDirs) {\n\t\t\t\tthis.loadThemesFromDir(dir, themes, diagnostics);\n\t\t\t}\n\t\t}\n\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = resolve(this.cwd, p);\n\t\t\tif (!existsSync(resolved)) {\n\t\t\t\tdiagnostics.push({ type: \"warning\", message: \"theme path does not exist\", path: resolved });\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst stats = statSync(resolved);\n\t\t\t\tif (stats.isDirectory()) {\n\t\t\t\t\tthis.loadThemesFromDir(resolved, themes, diagnostics);\n\t\t\t\t} else if (stats.isFile() && resolved.endsWith(\".json\")) {\n\t\t\t\t\tthis.loadThemeFromFile(resolved, themes, diagnostics);\n\t\t\t\t} else {\n\t\t\t\t\tdiagnostics.push({ type: \"warning\", message: \"theme path is not a json file\", path: resolved });\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : \"failed to read theme path\";\n\t\t\t\tdiagnostics.push({ type: \"warning\", message, path: resolved });\n\t\t\t}\n\t\t}\n\n\t\treturn { themes, diagnostics };\n\t}\n\n\tprivate loadThemesFromDir(dir: string, themes: Theme[], diagnostics: ResourceDiagnostic[]): void {\n\t\tif (!existsSync(dir)) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\t\t\tfor (const entry of entries) {\n\t\t\t\tlet isFile = entry.isFile();\n\t\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tisFile = statSync(join(dir, entry.name)).isFile();\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!isFile) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (!entry.name.endsWith(\".json\")) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthis.loadThemeFromFile(join(dir, entry.name), themes, diagnostics);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"failed to read theme directory\";\n\t\t\tdiagnostics.push({ type: \"warning\", message, path: dir });\n\t\t}\n\t}\n\n\tprivate loadThemeFromFile(filePath: string, themes: Theme[], diagnostics: ResourceDiagnostic[]): void {\n\t\ttry {\n\t\t\tthemes.push(loadThemeFromPath(filePath));\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"failed to load theme\";\n\t\t\tdiagnostics.push({ type: \"warning\", message, path: filePath });\n\t\t}\n\t}\n\n\tprivate async loadExtensionFactories(runtime: ExtensionRuntime): Promise<{\n\t\textensions: Extension[];\n\t\terrors: Array<{ path: string; error: string }>;\n\t}> {\n\t\tconst extensions: Extension[] = [];\n\t\tconst errors: Array<{ path: string; error: string }> = [];\n\n\t\tfor (const [index, factory] of this.extensionFactories.entries()) {\n\t\t\tconst extensionPath = `<inline:${index + 1}>`;\n\t\t\ttry {\n\t\t\t\tconst extension = await loadExtensionFromFactory(factory, this.cwd, this.eventBus, runtime, extensionPath);\n\t\t\t\textensions.push(extension);\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : \"failed to load extension\";\n\t\t\t\terrors.push({ path: extensionPath, error: message });\n\t\t\t}\n\t\t}\n\n\t\treturn { extensions, errors };\n\t}\n\n\tprivate dedupePrompts(prompts: PromptTemplate[]): { prompts: PromptTemplate[]; diagnostics: ResourceDiagnostic[] } {\n\t\tconst seen = new Map<string, PromptTemplate>();\n\t\tconst diagnostics: ResourceDiagnostic[] = [];\n\n\t\tfor (const prompt of prompts) {\n\t\t\tconst existing = seen.get(prompt.name);\n\t\t\tif (existing) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\ttype: \"collision\",\n\t\t\t\t\tmessage: `name \"/${prompt.name}\" collision`,\n\t\t\t\t\tpath: prompt.filePath,\n\t\t\t\t\tcollision: {\n\t\t\t\t\t\tresourceType: \"prompt\",\n\t\t\t\t\t\tname: prompt.name,\n\t\t\t\t\t\twinnerPath: existing.filePath,\n\t\t\t\t\t\tloserPath: prompt.filePath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tseen.set(prompt.name, prompt);\n\t\t\t}\n\t\t}\n\n\t\treturn { prompts: Array.from(seen.values()), diagnostics };\n\t}\n\n\tprivate dedupeThemes(themes: Theme[]): { themes: Theme[]; diagnostics: ResourceDiagnostic[] } {\n\t\tconst seen = new Map<string, Theme>();\n\t\tconst diagnostics: ResourceDiagnostic[] = [];\n\n\t\tfor (const t of themes) {\n\t\t\tconst name = t.name ?? \"unnamed\";\n\t\t\tconst existing = seen.get(name);\n\t\t\tif (existing) {\n\t\t\t\tdiagnostics.push({\n\t\t\t\t\ttype: \"collision\",\n\t\t\t\t\tmessage: `name \"${name}\" collision`,\n\t\t\t\t\tpath: t.sourcePath,\n\t\t\t\t\tcollision: {\n\t\t\t\t\t\tresourceType: \"theme\",\n\t\t\t\t\t\tname,\n\t\t\t\t\t\twinnerPath: existing.sourcePath ?? \"<builtin>\",\n\t\t\t\t\t\tloserPath: t.sourcePath ?? \"<builtin>\",\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tseen.set(name, t);\n\t\t\t}\n\t\t}\n\n\t\treturn { themes: Array.from(seen.values()), diagnostics };\n\t}\n\n\tprivate discoverSystemPromptFile(): string | undefined {\n\t\tconst projectPath = join(this.cwd, CONFIG_DIR_NAME, \"SYSTEM.md\");\n\t\tif (existsSync(projectPath)) {\n\t\t\treturn projectPath;\n\t\t}\n\n\t\tconst globalPath = join(this.agentDir, \"SYSTEM.md\");\n\t\tif (existsSync(globalPath)) {\n\t\t\treturn globalPath;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate discoverAppendSystemPromptFile(): string | undefined {\n\t\tconst projectPath = join(this.cwd, CONFIG_DIR_NAME, \"APPEND_SYSTEM.md\");\n\t\tif (existsSync(projectPath)) {\n\t\t\treturn projectPath;\n\t\t}\n\n\t\tconst globalPath = join(this.agentDir, \"APPEND_SYSTEM.md\");\n\t\tif (existsSync(globalPath)) {\n\t\t\treturn globalPath;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate isUnderPath(target: string, root: string): boolean {\n\t\tconst normalizedRoot = resolve(root);\n\t\tif (target === normalizedRoot) {\n\t\t\treturn true;\n\t\t}\n\t\tconst prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;\n\t\treturn target.startsWith(prefix);\n\t}\n\n\tprivate detectExtensionConflicts(extensions: Extension[]): Array<{ path: string; message: string }> {\n\t\tconst conflicts: Array<{ path: string; message: string }> = [];\n\n\t\t// Track which extension registered each tool and flag\n\t\tconst toolOwners = new Map<string, string>();\n\t\tconst flagOwners = new Map<string, string>();\n\n\t\tfor (const ext of extensions) {\n\t\t\t// Check tools\n\t\t\tfor (const toolName of ext.tools.keys()) {\n\t\t\t\tconst existingOwner = toolOwners.get(toolName);\n\t\t\t\tif (existingOwner && existingOwner !== ext.path) {\n\t\t\t\t\tconflicts.push({\n\t\t\t\t\t\tpath: ext.path,\n\t\t\t\t\t\tmessage: `Tool \"${toolName}\" conflicts with ${existingOwner}`,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\ttoolOwners.set(toolName, ext.path);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check flags\n\t\t\tfor (const flagName of ext.flags.keys()) {\n\t\t\t\tconst existingOwner = flagOwners.get(flagName);\n\t\t\t\tif (existingOwner && existingOwner !== ext.path) {\n\t\t\t\t\tconflicts.push({\n\t\t\t\t\t\tpath: ext.path,\n\t\t\t\t\t\tmessage: `Flag \"--${flagName}\" conflicts with ${existingOwner}`,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tflagOwners.set(flagName, ext.path);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn conflicts;\n\t}\n}\n"]}
@@ -2,17 +2,15 @@ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
3
  import { join, resolve, sep } from "node:path";
4
4
  import chalk from "chalk";
5
- import { getAgentDir, getProjectConfigDir } from "../config.js";
5
+ import { CONFIG_DIR_NAME, getAgentDir } from "../config.js";
6
6
  import { loadThemeFromPath } from "../modes/interactive/theme/theme.js";
7
- import subagentExtension from "./builtins/subagent.js";
8
7
  import { createEventBus } from "./event-bus.js";
9
8
  import { createExtensionRuntime, loadExtensionFromFactory, loadExtensions } from "./extensions/loader.js";
10
- /** Built-in extension factories that are always loaded. */
11
- const builtinExtensionFactories = [subagentExtension];
12
9
  import { DefaultPackageManager } from "./package-manager.js";
13
10
  import { loadPromptTemplates } from "./prompt-templates.js";
14
11
  import { SettingsManager } from "./settings-manager.js";
15
12
  import { loadSkills } from "./skills.js";
13
+ import { createSourceInfo } from "./source-info.js";
16
14
  function resolvePromptInput(input, description) {
17
15
  if (!input) {
18
16
  return undefined;
@@ -109,8 +107,10 @@ export class DefaultResourceLoader {
109
107
  agentsFiles;
110
108
  systemPrompt;
111
109
  appendSystemPrompt;
112
- pathMetadata;
113
110
  lastSkillPaths;
111
+ extensionSkillSourceInfos;
112
+ extensionPromptSourceInfos;
113
+ extensionThemeSourceInfos;
114
114
  lastPromptPaths;
115
115
  lastThemePaths;
116
116
  constructor(options) {
@@ -127,8 +127,7 @@ export class DefaultResourceLoader {
127
127
  this.additionalSkillPaths = options.additionalSkillPaths ?? [];
128
128
  this.additionalPromptTemplatePaths = options.additionalPromptTemplatePaths ?? [];
129
129
  this.additionalThemePaths = options.additionalThemePaths ?? [];
130
- const builtins = options.noBuiltinExtensions ? [] : builtinExtensionFactories;
131
- this.extensionFactories = [...builtins, ...(options.extensionFactories ?? [])];
130
+ this.extensionFactories = options.extensionFactories ?? [];
132
131
  this.noExtensions = options.noExtensions ?? false;
133
132
  this.noSkills = options.noSkills ?? false;
134
133
  this.noPromptTemplates = options.noPromptTemplates ?? false;
@@ -151,8 +150,10 @@ export class DefaultResourceLoader {
151
150
  this.themeDiagnostics = [];
152
151
  this.agentsFiles = [];
153
152
  this.appendSystemPrompt = [];
154
- this.pathMetadata = new Map();
155
153
  this.lastSkillPaths = [];
154
+ this.extensionSkillSourceInfos = new Map();
155
+ this.extensionPromptSourceInfos = new Map();
156
+ this.extensionThemeSourceInfos = new Map();
156
157
  this.lastPromptPaths = [];
157
158
  this.lastThemePaths = [];
158
159
  }
@@ -177,24 +178,30 @@ export class DefaultResourceLoader {
177
178
  getAppendSystemPrompt() {
178
179
  return this.appendSystemPrompt;
179
180
  }
180
- getPathMetadata() {
181
- return this.pathMetadata;
182
- }
183
181
  extendResources(paths) {
184
182
  const skillPaths = this.normalizeExtensionPaths(paths.skillPaths ?? []);
185
183
  const promptPaths = this.normalizeExtensionPaths(paths.promptPaths ?? []);
186
184
  const themePaths = this.normalizeExtensionPaths(paths.themePaths ?? []);
185
+ for (const entry of skillPaths) {
186
+ this.extensionSkillSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));
187
+ }
188
+ for (const entry of promptPaths) {
189
+ this.extensionPromptSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));
190
+ }
191
+ for (const entry of themePaths) {
192
+ this.extensionThemeSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));
193
+ }
187
194
  if (skillPaths.length > 0) {
188
195
  this.lastSkillPaths = this.mergePaths(this.lastSkillPaths, skillPaths.map((entry) => entry.path));
189
- this.updateSkillsFromPaths(this.lastSkillPaths, skillPaths);
196
+ this.updateSkillsFromPaths(this.lastSkillPaths);
190
197
  }
191
198
  if (promptPaths.length > 0) {
192
199
  this.lastPromptPaths = this.mergePaths(this.lastPromptPaths, promptPaths.map((entry) => entry.path));
193
- this.updatePromptsFromPaths(this.lastPromptPaths, promptPaths);
200
+ this.updatePromptsFromPaths(this.lastPromptPaths);
194
201
  }
195
202
  if (themePaths.length > 0) {
196
203
  this.lastThemePaths = this.mergePaths(this.lastThemePaths, themePaths.map((entry) => entry.path));
197
- this.updateThemesFromPaths(this.lastThemePaths, themePaths);
204
+ this.updateThemesFromPaths(this.lastThemePaths);
198
205
  }
199
206
  }
200
207
  async reload() {
@@ -202,18 +209,20 @@ export class DefaultResourceLoader {
202
209
  const cliExtensionPaths = await this.packageManager.resolveExtensionSources(this.additionalExtensionPaths, {
203
210
  temporary: true,
204
211
  });
212
+ const metadataByPath = new Map();
213
+ this.extensionSkillSourceInfos = new Map();
214
+ this.extensionPromptSourceInfos = new Map();
215
+ this.extensionThemeSourceInfos = new Map();
205
216
  // Helper to extract enabled paths and store metadata
206
217
  const getEnabledResources = (resources) => {
207
218
  for (const r of resources) {
208
- if (!this.pathMetadata.has(r.path)) {
209
- this.pathMetadata.set(r.path, r.metadata);
219
+ if (!metadataByPath.has(r.path)) {
220
+ metadataByPath.set(r.path, r.metadata);
210
221
  }
211
222
  }
212
223
  return resources.filter((r) => r.enabled);
213
224
  };
214
225
  const getEnabledPaths = (resources) => getEnabledResources(resources).map((r) => r.path);
215
- // Store metadata and get enabled paths
216
- this.pathMetadata = new Map();
217
226
  const enabledExtensions = getEnabledPaths(resolvedPaths.extensions);
218
227
  const enabledSkillResources = getEnabledResources(resolvedPaths.skills);
219
228
  const enabledPrompts = getEnabledPaths(resolvedPaths.prompts);
@@ -233,8 +242,8 @@ export class DefaultResourceLoader {
233
242
  }
234
243
  const skillFile = join(resource.path, "SKILL.md");
235
244
  if (existsSync(skillFile)) {
236
- if (!this.pathMetadata.has(skillFile)) {
237
- this.pathMetadata.set(skillFile, resource.metadata);
245
+ if (!metadataByPath.has(skillFile)) {
246
+ metadataByPath.set(skillFile, resource.metadata);
238
247
  }
239
248
  return skillFile;
240
249
  }
@@ -243,13 +252,13 @@ export class DefaultResourceLoader {
243
252
  const enabledSkills = enabledSkillResources.map(mapSkillPath);
244
253
  // Add CLI paths metadata
245
254
  for (const r of cliExtensionPaths.extensions) {
246
- if (!this.pathMetadata.has(r.path)) {
247
- this.pathMetadata.set(r.path, { source: "cli", scope: "temporary", origin: "top-level" });
255
+ if (!metadataByPath.has(r.path)) {
256
+ metadataByPath.set(r.path, { source: "cli", scope: "temporary", origin: "top-level" });
248
257
  }
249
258
  }
250
259
  for (const r of cliExtensionPaths.skills) {
251
- if (!this.pathMetadata.has(r.path)) {
252
- this.pathMetadata.set(r.path, { source: "cli", scope: "temporary", origin: "top-level" });
260
+ if (!metadataByPath.has(r.path)) {
261
+ metadataByPath.set(r.path, { source: "cli", scope: "temporary", origin: "top-level" });
253
262
  }
254
263
  }
255
264
  const cliEnabledExtensions = getEnabledPaths(cliExtensionPaths.extensions);
@@ -270,24 +279,22 @@ export class DefaultResourceLoader {
270
279
  extensionsResult.errors.push({ path: conflict.path, error: conflict.message });
271
280
  }
272
281
  this.extensionsResult = this.extensionsOverride ? this.extensionsOverride(extensionsResult) : extensionsResult;
282
+ this.applyExtensionSourceInfo(this.extensionsResult.extensions, metadataByPath);
273
283
  const skillPaths = this.noSkills
274
284
  ? this.mergePaths(cliEnabledSkills, this.additionalSkillPaths)
275
285
  : this.mergePaths([...enabledSkills, ...cliEnabledSkills], this.additionalSkillPaths);
276
286
  this.lastSkillPaths = skillPaths;
277
- this.updateSkillsFromPaths(skillPaths);
287
+ this.updateSkillsFromPaths(skillPaths, metadataByPath);
278
288
  const promptPaths = this.noPromptTemplates
279
289
  ? this.mergePaths(cliEnabledPrompts, this.additionalPromptTemplatePaths)
280
290
  : this.mergePaths([...enabledPrompts, ...cliEnabledPrompts], this.additionalPromptTemplatePaths);
281
291
  this.lastPromptPaths = promptPaths;
282
- this.updatePromptsFromPaths(promptPaths);
292
+ this.updatePromptsFromPaths(promptPaths, metadataByPath);
283
293
  const themePaths = this.noThemes
284
294
  ? this.mergePaths(cliEnabledThemes, this.additionalThemePaths)
285
295
  : this.mergePaths([...enabledThemes, ...cliEnabledThemes], this.additionalThemePaths);
286
296
  this.lastThemePaths = themePaths;
287
- this.updateThemesFromPaths(themePaths);
288
- for (const extension of this.extensionsResult.extensions) {
289
- this.addDefaultMetadataForPath(extension.path);
290
- }
297
+ this.updateThemesFromPaths(themePaths, metadataByPath);
291
298
  const agentsFiles = { agentsFiles: loadProjectContextFiles({ cwd: this.cwd, agentDir: this.agentDir }) };
292
299
  const resolvedAgentsFiles = this.agentsFilesOverride ? this.agentsFilesOverride(agentsFiles) : agentsFiles;
293
300
  this.agentsFiles = resolvedAgentsFiles.agentsFiles;
@@ -306,7 +313,7 @@ export class DefaultResourceLoader {
306
313
  metadata: entry.metadata,
307
314
  }));
308
315
  }
309
- updateSkillsFromPaths(skillPaths, extensionPaths = []) {
316
+ updateSkillsFromPaths(skillPaths, metadataByPath) {
310
317
  let skillsResult;
311
318
  if (this.noSkills && skillPaths.length === 0) {
312
319
  skillsResult = { skills: [], diagnostics: [] };
@@ -320,14 +327,15 @@ export class DefaultResourceLoader {
320
327
  });
321
328
  }
322
329
  const resolvedSkills = this.skillsOverride ? this.skillsOverride(skillsResult) : skillsResult;
323
- this.skills = resolvedSkills.skills;
330
+ this.skills = resolvedSkills.skills.map((skill) => ({
331
+ ...skill,
332
+ sourceInfo: this.findSourceInfoForPath(skill.filePath, this.extensionSkillSourceInfos, metadataByPath) ??
333
+ skill.sourceInfo ??
334
+ this.getDefaultSourceInfoForPath(skill.filePath),
335
+ }));
324
336
  this.skillDiagnostics = resolvedSkills.diagnostics;
325
- this.applyExtensionMetadata(extensionPaths, this.skills.map((skill) => skill.filePath));
326
- for (const skill of this.skills) {
327
- this.addDefaultMetadataForPath(skill.filePath);
328
- }
329
337
  }
330
- updatePromptsFromPaths(promptPaths, extensionPaths = []) {
338
+ updatePromptsFromPaths(promptPaths, metadataByPath) {
331
339
  let promptsResult;
332
340
  if (this.noPromptTemplates && promptPaths.length === 0) {
333
341
  promptsResult = { prompts: [], diagnostics: [] };
@@ -342,14 +350,15 @@ export class DefaultResourceLoader {
342
350
  promptsResult = this.dedupePrompts(allPrompts);
343
351
  }
344
352
  const resolvedPrompts = this.promptsOverride ? this.promptsOverride(promptsResult) : promptsResult;
345
- this.prompts = resolvedPrompts.prompts;
353
+ this.prompts = resolvedPrompts.prompts.map((prompt) => ({
354
+ ...prompt,
355
+ sourceInfo: this.findSourceInfoForPath(prompt.filePath, this.extensionPromptSourceInfos, metadataByPath) ??
356
+ prompt.sourceInfo ??
357
+ this.getDefaultSourceInfoForPath(prompt.filePath),
358
+ }));
346
359
  this.promptDiagnostics = resolvedPrompts.diagnostics;
347
- this.applyExtensionMetadata(extensionPaths, this.prompts.map((prompt) => prompt.filePath));
348
- for (const prompt of this.prompts) {
349
- this.addDefaultMetadataForPath(prompt.filePath);
350
- }
351
360
  }
352
- updateThemesFromPaths(themePaths, extensionPaths = []) {
361
+ updateThemesFromPaths(themePaths, metadataByPath) {
353
362
  let themesResult;
354
363
  if (this.noThemes && themePaths.length === 0) {
355
364
  themesResult = { themes: [], diagnostics: [] };
@@ -360,39 +369,101 @@ export class DefaultResourceLoader {
360
369
  themesResult = { themes: deduped.themes, diagnostics: [...loaded.diagnostics, ...deduped.diagnostics] };
361
370
  }
362
371
  const resolvedThemes = this.themesOverride ? this.themesOverride(themesResult) : themesResult;
363
- this.themes = resolvedThemes.themes;
372
+ this.themes = resolvedThemes.themes.map((theme) => {
373
+ const sourcePath = theme.sourcePath;
374
+ theme.sourceInfo = sourcePath
375
+ ? (this.findSourceInfoForPath(sourcePath, this.extensionThemeSourceInfos, metadataByPath) ??
376
+ theme.sourceInfo ??
377
+ this.getDefaultSourceInfoForPath(sourcePath))
378
+ : theme.sourceInfo;
379
+ return theme;
380
+ });
364
381
  this.themeDiagnostics = resolvedThemes.diagnostics;
365
- const themePathsWithSource = this.themes.flatMap((theme) => (theme.sourcePath ? [theme.sourcePath] : []));
366
- this.applyExtensionMetadata(extensionPaths, themePathsWithSource);
367
- for (const theme of this.themes) {
368
- if (theme.sourcePath) {
369
- this.addDefaultMetadataForPath(theme.sourcePath);
382
+ }
383
+ applyExtensionSourceInfo(extensions, metadataByPath) {
384
+ for (const extension of extensions) {
385
+ extension.sourceInfo =
386
+ this.findSourceInfoForPath(extension.path, undefined, metadataByPath) ??
387
+ this.getDefaultSourceInfoForPath(extension.path);
388
+ for (const command of extension.commands.values()) {
389
+ command.sourceInfo = extension.sourceInfo;
390
+ }
391
+ for (const tool of extension.tools.values()) {
392
+ tool.sourceInfo = extension.sourceInfo;
370
393
  }
371
394
  }
372
395
  }
373
- applyExtensionMetadata(extensionPaths, resourcePaths) {
374
- if (extensionPaths.length === 0) {
375
- return;
396
+ findSourceInfoForPath(resourcePath, extraSourceInfos, metadataByPath) {
397
+ if (!resourcePath) {
398
+ return undefined;
376
399
  }
377
- const normalized = extensionPaths.map((entry) => ({
378
- path: resolve(entry.path),
379
- metadata: entry.metadata,
380
- }));
381
- for (const entry of normalized) {
382
- if (!this.pathMetadata.has(entry.path)) {
383
- this.pathMetadata.set(entry.path, entry.metadata);
400
+ if (resourcePath.startsWith("<")) {
401
+ return this.getDefaultSourceInfoForPath(resourcePath);
402
+ }
403
+ const normalizedResourcePath = resolve(resourcePath);
404
+ if (extraSourceInfos) {
405
+ for (const [sourcePath, sourceInfo] of extraSourceInfos.entries()) {
406
+ const normalizedSourcePath = resolve(sourcePath);
407
+ if (normalizedResourcePath === normalizedSourcePath ||
408
+ normalizedResourcePath.startsWith(`${normalizedSourcePath}${sep}`)) {
409
+ return { ...sourceInfo, path: resourcePath };
410
+ }
384
411
  }
385
412
  }
386
- for (const resourcePath of resourcePaths) {
387
- const normalizedResourcePath = resolve(resourcePath);
388
- if (this.pathMetadata.has(normalizedResourcePath) || this.pathMetadata.has(resourcePath)) {
389
- continue;
413
+ if (metadataByPath) {
414
+ const exact = metadataByPath.get(normalizedResourcePath) ?? metadataByPath.get(resourcePath);
415
+ if (exact) {
416
+ return createSourceInfo(resourcePath, exact);
417
+ }
418
+ for (const [sourcePath, metadata] of metadataByPath.entries()) {
419
+ const normalizedSourcePath = resolve(sourcePath);
420
+ if (normalizedResourcePath === normalizedSourcePath ||
421
+ normalizedResourcePath.startsWith(`${normalizedSourcePath}${sep}`)) {
422
+ return createSourceInfo(resourcePath, metadata);
423
+ }
424
+ }
425
+ }
426
+ return undefined;
427
+ }
428
+ getDefaultSourceInfoForPath(filePath) {
429
+ if (filePath.startsWith("<") && filePath.endsWith(">")) {
430
+ return {
431
+ path: filePath,
432
+ source: filePath.slice(1, -1).split(":")[0] || "temporary",
433
+ scope: "temporary",
434
+ origin: "top-level",
435
+ };
436
+ }
437
+ const normalizedPath = resolve(filePath);
438
+ const agentRoots = [
439
+ join(this.agentDir, "skills"),
440
+ join(this.agentDir, "prompts"),
441
+ join(this.agentDir, "themes"),
442
+ join(this.agentDir, "extensions"),
443
+ ];
444
+ const projectRoots = [
445
+ join(this.cwd, CONFIG_DIR_NAME, "skills"),
446
+ join(this.cwd, CONFIG_DIR_NAME, "prompts"),
447
+ join(this.cwd, CONFIG_DIR_NAME, "themes"),
448
+ join(this.cwd, CONFIG_DIR_NAME, "extensions"),
449
+ ];
450
+ for (const root of agentRoots) {
451
+ if (this.isUnderPath(normalizedPath, root)) {
452
+ return { path: filePath, source: "local", scope: "user", origin: "top-level", baseDir: root };
390
453
  }
391
- const match = normalized.find((entry) => normalizedResourcePath === entry.path || normalizedResourcePath.startsWith(`${entry.path}${sep}`));
392
- if (match) {
393
- this.pathMetadata.set(normalizedResourcePath, match.metadata);
454
+ }
455
+ for (const root of projectRoots) {
456
+ if (this.isUnderPath(normalizedPath, root)) {
457
+ return { path: filePath, source: "local", scope: "project", origin: "top-level", baseDir: root };
394
458
  }
395
459
  }
460
+ return {
461
+ path: filePath,
462
+ source: "local",
463
+ scope: "temporary",
464
+ origin: "top-level",
465
+ baseDir: statSync(normalizedPath).isDirectory() ? normalizedPath : resolve(normalizedPath, ".."),
466
+ };
396
467
  }
397
468
  mergePaths(primary, additional) {
398
469
  const merged = [];
@@ -424,7 +495,7 @@ export class DefaultResourceLoader {
424
495
  const themes = [];
425
496
  const diagnostics = [];
426
497
  if (includeDefaults) {
427
- const defaultDirs = [join(this.agentDir, "themes"), join(getProjectConfigDir(this.cwd), "themes")];
498
+ const defaultDirs = [join(this.agentDir, "themes"), join(this.cwd, CONFIG_DIR_NAME, "themes")];
428
499
  for (const dir of defaultDirs) {
429
500
  this.loadThemesFromDir(dir, themes, diagnostics);
430
501
  }
@@ -559,7 +630,7 @@ export class DefaultResourceLoader {
559
630
  return { themes: Array.from(seen.values()), diagnostics };
560
631
  }
561
632
  discoverSystemPromptFile() {
562
- const projectPath = join(getProjectConfigDir(this.cwd), "SYSTEM.md");
633
+ const projectPath = join(this.cwd, CONFIG_DIR_NAME, "SYSTEM.md");
563
634
  if (existsSync(projectPath)) {
564
635
  return projectPath;
565
636
  }
@@ -570,7 +641,7 @@ export class DefaultResourceLoader {
570
641
  return undefined;
571
642
  }
572
643
  discoverAppendSystemPromptFile() {
573
- const projectPath = join(getProjectConfigDir(this.cwd), "APPEND_SYSTEM.md");
644
+ const projectPath = join(this.cwd, CONFIG_DIR_NAME, "APPEND_SYSTEM.md");
574
645
  if (existsSync(projectPath)) {
575
646
  return projectPath;
576
647
  }
@@ -580,40 +651,6 @@ export class DefaultResourceLoader {
580
651
  }
581
652
  return undefined;
582
653
  }
583
- addDefaultMetadataForPath(filePath) {
584
- if (!filePath || filePath.startsWith("<")) {
585
- return;
586
- }
587
- const normalizedPath = resolve(filePath);
588
- if (this.pathMetadata.has(normalizedPath) || this.pathMetadata.has(filePath)) {
589
- return;
590
- }
591
- const agentRoots = [
592
- join(this.agentDir, "skills"),
593
- join(this.agentDir, "prompts"),
594
- join(this.agentDir, "themes"),
595
- join(this.agentDir, "extensions"),
596
- ];
597
- const projectConfigDir = getProjectConfigDir(this.cwd);
598
- const projectRoots = [
599
- join(projectConfigDir, "skills"),
600
- join(projectConfigDir, "prompts"),
601
- join(projectConfigDir, "themes"),
602
- join(projectConfigDir, "extensions"),
603
- ];
604
- for (const root of agentRoots) {
605
- if (this.isUnderPath(normalizedPath, root)) {
606
- this.pathMetadata.set(normalizedPath, { source: "local", scope: "user", origin: "top-level" });
607
- return;
608
- }
609
- }
610
- for (const root of projectRoots) {
611
- if (this.isUnderPath(normalizedPath, root)) {
612
- this.pathMetadata.set(normalizedPath, { source: "local", scope: "project", origin: "top-level" });
613
- return;
614
- }
615
- }
616
- }
617
654
  isUnderPath(target, root) {
618
655
  const normalizedRoot = resolve(root);
619
656
  if (target === normalizedRoot) {
@@ -624,9 +661,8 @@ export class DefaultResourceLoader {
624
661
  }
625
662
  detectExtensionConflicts(extensions) {
626
663
  const conflicts = [];
627
- // Track which extension registered each tool, command, and flag
664
+ // Track which extension registered each tool and flag
628
665
  const toolOwners = new Map();
629
- const commandOwners = new Map();
630
666
  const flagOwners = new Map();
631
667
  for (const ext of extensions) {
632
668
  // Check tools
@@ -642,19 +678,6 @@ export class DefaultResourceLoader {
642
678
  toolOwners.set(toolName, ext.path);
643
679
  }
644
680
  }
645
- // Check commands
646
- for (const commandName of ext.commands.keys()) {
647
- const existingOwner = commandOwners.get(commandName);
648
- if (existingOwner && existingOwner !== ext.path) {
649
- conflicts.push({
650
- path: ext.path,
651
- message: `Command "/${commandName}" conflicts with ${existingOwner}`,
652
- });
653
- }
654
- else {
655
- commandOwners.set(commandName, ext.path);
656
- }
657
- }
658
681
  // Check flags
659
682
  for (const flagName of ext.flags.keys()) {
660
683
  const existingOwner = flagOwners.get(flagName);