@eminent337/aery 0.1.63 → 0.1.65

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 (626) hide show
  1. package/docs/custom-provider.md +1 -1
  2. package/docs/extensions.md +18 -18
  3. package/docs/index.md +5 -5
  4. package/docs/json.md +1 -1
  5. package/docs/keybindings.md +2 -2
  6. package/docs/models.md +2 -2
  7. package/docs/packages.md +13 -13
  8. package/docs/providers.md +5 -5
  9. package/docs/quickstart.md +19 -19
  10. package/docs/rpc.md +3 -3
  11. package/docs/sdk.md +1 -1
  12. package/docs/session-format.md +3 -3
  13. package/docs/sessions.md +10 -10
  14. package/docs/settings.md +4 -4
  15. package/docs/skills.md +2 -2
  16. package/docs/terminal-setup.md +6 -6
  17. package/docs/termux.md +3 -3
  18. package/docs/themes.md +3 -3
  19. package/docs/tmux.md +1 -1
  20. package/docs/tui.md +2 -2
  21. package/docs/usage.md +33 -33
  22. package/examples/extensions/README.md +3 -3
  23. package/examples/extensions/antigravity-image-gen.ts +6 -6
  24. package/examples/extensions/auto-commit-on-exit.ts +1 -1
  25. package/examples/extensions/bash-spawn-hook.ts +1 -1
  26. package/examples/extensions/built-in-tool-renderer.ts +1 -1
  27. package/examples/extensions/claude-rules.ts +1 -1
  28. package/examples/extensions/commands.ts +1 -1
  29. package/examples/extensions/custom-compaction.ts +1 -1
  30. package/examples/extensions/custom-header.ts +2 -2
  31. package/examples/extensions/custom-provider-anthropic/index.ts +2 -2
  32. package/examples/extensions/custom-provider-gitlab-duo/index.ts +2 -2
  33. package/examples/extensions/custom-provider-qwen-cli/index.ts +1 -1
  34. package/examples/extensions/doom-overlay/README.md +2 -2
  35. package/examples/extensions/doom-overlay/doom/build.sh +2 -2
  36. package/examples/extensions/doom-overlay/index.ts +1 -1
  37. package/examples/extensions/hidden-thinking-label.ts +1 -1
  38. package/examples/extensions/inline-bash.ts +2 -2
  39. package/examples/extensions/input-transform.ts +3 -3
  40. package/examples/extensions/interactive-shell.ts +1 -1
  41. package/examples/extensions/mac-system-theme.ts +2 -2
  42. package/examples/extensions/minimal-mode.ts +1 -1
  43. package/examples/extensions/modal-editor.ts +1 -1
  44. package/examples/extensions/model-status.ts +1 -1
  45. package/examples/extensions/overlay-qa-tests.ts +1 -1
  46. package/examples/extensions/overlay-test.ts +1 -1
  47. package/examples/extensions/pirate.ts +1 -1
  48. package/examples/extensions/preset.ts +12 -6
  49. package/examples/extensions/prompt-customizer.ts +1 -1
  50. package/examples/extensions/provider-payload.ts +1 -1
  51. package/examples/extensions/rainbow-editor.ts +1 -1
  52. package/examples/extensions/rpc-demo.ts +1 -1
  53. package/examples/extensions/sandbox/index.ts +8 -8
  54. package/examples/extensions/shutdown-command.ts +5 -5
  55. package/examples/extensions/ssh.ts +2 -2
  56. package/examples/extensions/subagent/README.md +13 -13
  57. package/examples/extensions/subagent/agents.ts +1 -1
  58. package/examples/extensions/subagent/index.ts +5 -5
  59. package/examples/extensions/titlebar-spinner.ts +1 -1
  60. package/examples/extensions/tool-override.ts +2 -2
  61. package/examples/extensions/tools.ts +1 -1
  62. package/examples/extensions/truncated-tool.ts +1 -1
  63. package/examples/extensions/working-indicator.ts +4 -4
  64. package/examples/extensions/working-message-test.ts +1 -1
  65. package/examples/sdk/01-minimal.ts +1 -1
  66. package/examples/sdk/03-custom-prompt.ts +1 -1
  67. package/examples/sdk/04-skills.ts +1 -1
  68. package/examples/sdk/06-extensions.ts +2 -2
  69. package/examples/sdk/08-prompt-templates.ts +1 -1
  70. package/examples/sdk/09-api-keys-and-oauth.ts +2 -2
  71. package/examples/sdk/README.md +1 -1
  72. package/package.json +3 -3
  73. package/dist/bun/cli.d.ts +0 -3
  74. package/dist/bun/cli.d.ts.map +0 -1
  75. package/dist/bun/cli.js +0 -8
  76. package/dist/bun/cli.js.map +0 -1
  77. package/dist/bun/register-bedrock.d.ts +0 -2
  78. package/dist/bun/register-bedrock.d.ts.map +0 -1
  79. package/dist/bun/register-bedrock.js +0 -4
  80. package/dist/bun/register-bedrock.js.map +0 -1
  81. package/dist/bun/restore-sandbox-env.d.ts +0 -13
  82. package/dist/bun/restore-sandbox-env.d.ts.map +0 -1
  83. package/dist/bun/restore-sandbox-env.js +0 -32
  84. package/dist/bun/restore-sandbox-env.js.map +0 -1
  85. package/dist/cli/args.d.ts +0 -53
  86. package/dist/cli/args.d.ts.map +0 -1
  87. package/dist/cli/args.js +0 -329
  88. package/dist/cli/args.js.map +0 -1
  89. package/dist/cli/config-selector.d.ts +0 -14
  90. package/dist/cli/config-selector.d.ts.map +0 -1
  91. package/dist/cli/config-selector.js +0 -31
  92. package/dist/cli/config-selector.js.map +0 -1
  93. package/dist/cli/file-processor.d.ts +0 -15
  94. package/dist/cli/file-processor.d.ts.map +0 -1
  95. package/dist/cli/file-processor.js +0 -83
  96. package/dist/cli/file-processor.js.map +0 -1
  97. package/dist/cli/initial-message.d.ts +0 -18
  98. package/dist/cli/initial-message.d.ts.map +0 -1
  99. package/dist/cli/initial-message.js +0 -22
  100. package/dist/cli/initial-message.js.map +0 -1
  101. package/dist/cli/list-models.d.ts +0 -9
  102. package/dist/cli/list-models.d.ts.map +0 -1
  103. package/dist/cli/list-models.js +0 -98
  104. package/dist/cli/list-models.js.map +0 -1
  105. package/dist/cli/session-picker.d.ts +0 -9
  106. package/dist/cli/session-picker.d.ts.map +0 -1
  107. package/dist/cli/session-picker.js +0 -35
  108. package/dist/cli/session-picker.js.map +0 -1
  109. package/dist/cli.d.ts +0 -3
  110. package/dist/cli.d.ts.map +0 -1
  111. package/dist/cli.js +0 -19
  112. package/dist/cli.js.map +0 -1
  113. package/dist/config.d.ts +0 -86
  114. package/dist/config.d.ts.map +0 -1
  115. package/dist/config.js +0 -332
  116. package/dist/config.js.map +0 -1
  117. package/dist/core/agent-session-runtime.d.ts +0 -117
  118. package/dist/core/agent-session-runtime.d.ts.map +0 -1
  119. package/dist/core/agent-session-runtime.js +0 -300
  120. package/dist/core/agent-session-runtime.js.map +0 -1
  121. package/dist/core/agent-session-services.d.ts +0 -86
  122. package/dist/core/agent-session-services.d.ts.map +0 -1
  123. package/dist/core/agent-session-services.js +0 -117
  124. package/dist/core/agent-session-services.js.map +0 -1
  125. package/dist/core/agent-session.d.ts +0 -595
  126. package/dist/core/agent-session.d.ts.map +0 -1
  127. package/dist/core/agent-session.js +0 -2520
  128. package/dist/core/agent-session.js.map +0 -1
  129. package/dist/core/auth-guidance.d.ts +0 -5
  130. package/dist/core/auth-guidance.d.ts.map +0 -1
  131. package/dist/core/auth-guidance.js +0 -21
  132. package/dist/core/auth-guidance.js.map +0 -1
  133. package/dist/core/auth-storage.d.ts +0 -141
  134. package/dist/core/auth-storage.d.ts.map +0 -1
  135. package/dist/core/auth-storage.js +0 -441
  136. package/dist/core/auth-storage.js.map +0 -1
  137. package/dist/core/bash-executor.d.ts +0 -32
  138. package/dist/core/bash-executor.d.ts.map +0 -1
  139. package/dist/core/bash-executor.js +0 -111
  140. package/dist/core/bash-executor.js.map +0 -1
  141. package/dist/core/compaction/branch-summarization.d.ts +0 -88
  142. package/dist/core/compaction/branch-summarization.d.ts.map +0 -1
  143. package/dist/core/compaction/branch-summarization.js +0 -243
  144. package/dist/core/compaction/branch-summarization.js.map +0 -1
  145. package/dist/core/compaction/compaction.d.ts +0 -121
  146. package/dist/core/compaction/compaction.d.ts.map +0 -1
  147. package/dist/core/compaction/compaction.js +0 -615
  148. package/dist/core/compaction/compaction.js.map +0 -1
  149. package/dist/core/compaction/index.d.ts +0 -7
  150. package/dist/core/compaction/index.d.ts.map +0 -1
  151. package/dist/core/compaction/index.js +0 -7
  152. package/dist/core/compaction/index.js.map +0 -1
  153. package/dist/core/compaction/utils.d.ts +0 -38
  154. package/dist/core/compaction/utils.d.ts.map +0 -1
  155. package/dist/core/compaction/utils.js +0 -153
  156. package/dist/core/compaction/utils.js.map +0 -1
  157. package/dist/core/defaults.d.ts +0 -3
  158. package/dist/core/defaults.d.ts.map +0 -1
  159. package/dist/core/defaults.js +0 -2
  160. package/dist/core/defaults.js.map +0 -1
  161. package/dist/core/diagnostics.d.ts +0 -15
  162. package/dist/core/diagnostics.d.ts.map +0 -1
  163. package/dist/core/diagnostics.js +0 -2
  164. package/dist/core/diagnostics.js.map +0 -1
  165. package/dist/core/event-bus.d.ts +0 -9
  166. package/dist/core/event-bus.d.ts.map +0 -1
  167. package/dist/core/event-bus.js +0 -25
  168. package/dist/core/event-bus.js.map +0 -1
  169. package/dist/core/exec.d.ts +0 -29
  170. package/dist/core/exec.d.ts.map +0 -1
  171. package/dist/core/exec.js +0 -75
  172. package/dist/core/exec.js.map +0 -1
  173. package/dist/core/export-html/ansi-to-html.d.ts +0 -22
  174. package/dist/core/export-html/ansi-to-html.d.ts.map +0 -1
  175. package/dist/core/export-html/ansi-to-html.js +0 -249
  176. package/dist/core/export-html/ansi-to-html.js.map +0 -1
  177. package/dist/core/export-html/index.d.ts +0 -37
  178. package/dist/core/export-html/index.d.ts.map +0 -1
  179. package/dist/core/export-html/index.js +0 -224
  180. package/dist/core/export-html/index.js.map +0 -1
  181. package/dist/core/export-html/template.css +0 -1022
  182. package/dist/core/export-html/template.html +0 -55
  183. package/dist/core/export-html/template.js +0 -1770
  184. package/dist/core/export-html/tool-renderer.d.ts +0 -34
  185. package/dist/core/export-html/tool-renderer.d.ts.map +0 -1
  186. package/dist/core/export-html/tool-renderer.js +0 -108
  187. package/dist/core/export-html/tool-renderer.js.map +0 -1
  188. package/dist/core/export-html/vendor/highlight.min.js +0 -1213
  189. package/dist/core/export-html/vendor/marked.min.js +0 -6
  190. package/dist/core/extensions/index.d.ts +0 -12
  191. package/dist/core/extensions/index.d.ts.map +0 -1
  192. package/dist/core/extensions/index.js +0 -9
  193. package/dist/core/extensions/index.js.map +0 -1
  194. package/dist/core/extensions/loader.d.ts +0 -25
  195. package/dist/core/extensions/loader.d.ts.map +0 -1
  196. package/dist/core/extensions/loader.js +0 -476
  197. package/dist/core/extensions/loader.js.map +0 -1
  198. package/dist/core/extensions/runner.d.ts +0 -158
  199. package/dist/core/extensions/runner.d.ts.map +0 -1
  200. package/dist/core/extensions/runner.js +0 -784
  201. package/dist/core/extensions/runner.js.map +0 -1
  202. package/dist/core/extensions/types.d.ts +0 -1153
  203. package/dist/core/extensions/types.d.ts.map +0 -1
  204. package/dist/core/extensions/types.js +0 -45
  205. package/dist/core/extensions/types.js.map +0 -1
  206. package/dist/core/extensions/wrapper.d.ts +0 -20
  207. package/dist/core/extensions/wrapper.d.ts.map +0 -1
  208. package/dist/core/extensions/wrapper.js +0 -22
  209. package/dist/core/extensions/wrapper.js.map +0 -1
  210. package/dist/core/footer-data-provider.d.ts +0 -52
  211. package/dist/core/footer-data-provider.d.ts.map +0 -1
  212. package/dist/core/footer-data-provider.js +0 -310
  213. package/dist/core/footer-data-provider.js.map +0 -1
  214. package/dist/core/index.d.ts +0 -12
  215. package/dist/core/index.d.ts.map +0 -1
  216. package/dist/core/index.js +0 -12
  217. package/dist/core/index.js.map +0 -1
  218. package/dist/core/keybindings.d.ts +0 -353
  219. package/dist/core/keybindings.d.ts.map +0 -1
  220. package/dist/core/keybindings.js +0 -295
  221. package/dist/core/keybindings.js.map +0 -1
  222. package/dist/core/messages.d.ts +0 -77
  223. package/dist/core/messages.d.ts.map +0 -1
  224. package/dist/core/messages.js +0 -123
  225. package/dist/core/messages.js.map +0 -1
  226. package/dist/core/model-registry.d.ts +0 -144
  227. package/dist/core/model-registry.d.ts.map +0 -1
  228. package/dist/core/model-registry.js +0 -699
  229. package/dist/core/model-registry.js.map +0 -1
  230. package/dist/core/model-resolver.d.ts +0 -110
  231. package/dist/core/model-resolver.d.ts.map +0 -1
  232. package/dist/core/model-resolver.js +0 -489
  233. package/dist/core/model-resolver.js.map +0 -1
  234. package/dist/core/output-guard.d.ts +0 -6
  235. package/dist/core/output-guard.d.ts.map +0 -1
  236. package/dist/core/output-guard.js +0 -59
  237. package/dist/core/output-guard.js.map +0 -1
  238. package/dist/core/package-manager.d.ts +0 -199
  239. package/dist/core/package-manager.d.ts.map +0 -1
  240. package/dist/core/package-manager.js +0 -1974
  241. package/dist/core/package-manager.js.map +0 -1
  242. package/dist/core/prompt-templates.d.ts +0 -52
  243. package/dist/core/prompt-templates.d.ts.map +0 -1
  244. package/dist/core/prompt-templates.js +0 -250
  245. package/dist/core/prompt-templates.js.map +0 -1
  246. package/dist/core/resolve-config-value.d.ts +0 -23
  247. package/dist/core/resolve-config-value.d.ts.map +0 -1
  248. package/dist/core/resolve-config-value.js +0 -126
  249. package/dist/core/resolve-config-value.js.map +0 -1
  250. package/dist/core/resource-loader.d.ts +0 -194
  251. package/dist/core/resource-loader.d.ts.map +0 -1
  252. package/dist/core/resource-loader.js +0 -727
  253. package/dist/core/resource-loader.js.map +0 -1
  254. package/dist/core/sdk.d.ts +0 -107
  255. package/dist/core/sdk.d.ts.map +0 -1
  256. package/dist/core/sdk.js +0 -274
  257. package/dist/core/sdk.js.map +0 -1
  258. package/dist/core/session-cwd.d.ts +0 -19
  259. package/dist/core/session-cwd.d.ts.map +0 -1
  260. package/dist/core/session-cwd.js +0 -38
  261. package/dist/core/session-cwd.js.map +0 -1
  262. package/dist/core/session-manager.d.ts +0 -333
  263. package/dist/core/session-manager.d.ts.map +0 -1
  264. package/dist/core/session-manager.js +0 -1109
  265. package/dist/core/session-manager.js.map +0 -1
  266. package/dist/core/settings-manager.d.ts +0 -261
  267. package/dist/core/settings-manager.d.ts.map +0 -1
  268. package/dist/core/settings-manager.js +0 -782
  269. package/dist/core/settings-manager.js.map +0 -1
  270. package/dist/core/skills.d.ts +0 -60
  271. package/dist/core/skills.d.ts.map +0 -1
  272. package/dist/core/skills.js +0 -404
  273. package/dist/core/skills.js.map +0 -1
  274. package/dist/core/slash-commands.d.ts +0 -14
  275. package/dist/core/slash-commands.d.ts.map +0 -1
  276. package/dist/core/slash-commands.js +0 -25
  277. package/dist/core/slash-commands.js.map +0 -1
  278. package/dist/core/source-info.d.ts +0 -18
  279. package/dist/core/source-info.d.ts.map +0 -1
  280. package/dist/core/source-info.js +0 -19
  281. package/dist/core/source-info.js.map +0 -1
  282. package/dist/core/system-prompt.d.ts +0 -28
  283. package/dist/core/system-prompt.d.ts.map +0 -1
  284. package/dist/core/system-prompt.js +0 -120
  285. package/dist/core/system-prompt.js.map +0 -1
  286. package/dist/core/telemetry.d.ts +0 -3
  287. package/dist/core/telemetry.d.ts.map +0 -1
  288. package/dist/core/telemetry.js +0 -9
  289. package/dist/core/telemetry.js.map +0 -1
  290. package/dist/core/timings.d.ts +0 -8
  291. package/dist/core/timings.d.ts.map +0 -1
  292. package/dist/core/timings.js +0 -31
  293. package/dist/core/timings.js.map +0 -1
  294. package/dist/core/tools/bash.d.ts +0 -68
  295. package/dist/core/tools/bash.d.ts.map +0 -1
  296. package/dist/core/tools/bash.js +0 -355
  297. package/dist/core/tools/bash.js.map +0 -1
  298. package/dist/core/tools/edit-diff.d.ts +0 -85
  299. package/dist/core/tools/edit-diff.d.ts.map +0 -1
  300. package/dist/core/tools/edit-diff.js +0 -338
  301. package/dist/core/tools/edit-diff.js.map +0 -1
  302. package/dist/core/tools/edit.d.ts +0 -49
  303. package/dist/core/tools/edit.d.ts.map +0 -1
  304. package/dist/core/tools/edit.js +0 -324
  305. package/dist/core/tools/edit.js.map +0 -1
  306. package/dist/core/tools/file-mutation-queue.d.ts +0 -6
  307. package/dist/core/tools/file-mutation-queue.d.ts.map +0 -1
  308. package/dist/core/tools/file-mutation-queue.js +0 -37
  309. package/dist/core/tools/file-mutation-queue.js.map +0 -1
  310. package/dist/core/tools/find.d.ts +0 -35
  311. package/dist/core/tools/find.d.ts.map +0 -1
  312. package/dist/core/tools/find.js +0 -298
  313. package/dist/core/tools/find.js.map +0 -1
  314. package/dist/core/tools/grep.d.ts +0 -37
  315. package/dist/core/tools/grep.d.ts.map +0 -1
  316. package/dist/core/tools/grep.js +0 -304
  317. package/dist/core/tools/grep.js.map +0 -1
  318. package/dist/core/tools/index.d.ts +0 -40
  319. package/dist/core/tools/index.d.ts.map +0 -1
  320. package/dist/core/tools/index.js +0 -112
  321. package/dist/core/tools/index.js.map +0 -1
  322. package/dist/core/tools/ls.d.ts +0 -37
  323. package/dist/core/tools/ls.d.ts.map +0 -1
  324. package/dist/core/tools/ls.js +0 -169
  325. package/dist/core/tools/ls.js.map +0 -1
  326. package/dist/core/tools/path-utils.d.ts +0 -8
  327. package/dist/core/tools/path-utils.d.ts.map +0 -1
  328. package/dist/core/tools/path-utils.js +0 -81
  329. package/dist/core/tools/path-utils.js.map +0 -1
  330. package/dist/core/tools/read.d.ts +0 -35
  331. package/dist/core/tools/read.d.ts.map +0 -1
  332. package/dist/core/tools/read.js +0 -232
  333. package/dist/core/tools/read.js.map +0 -1
  334. package/dist/core/tools/render-utils.d.ts +0 -21
  335. package/dist/core/tools/render-utils.d.ts.map +0 -1
  336. package/dist/core/tools/render-utils.js +0 -49
  337. package/dist/core/tools/render-utils.js.map +0 -1
  338. package/dist/core/tools/tool-definition-wrapper.d.ts +0 -14
  339. package/dist/core/tools/tool-definition-wrapper.d.ts.map +0 -1
  340. package/dist/core/tools/tool-definition-wrapper.js +0 -34
  341. package/dist/core/tools/tool-definition-wrapper.js.map +0 -1
  342. package/dist/core/tools/truncate.d.ts +0 -70
  343. package/dist/core/tools/truncate.d.ts.map +0 -1
  344. package/dist/core/tools/truncate.js +0 -205
  345. package/dist/core/tools/truncate.js.map +0 -1
  346. package/dist/core/tools/write.d.ts +0 -26
  347. package/dist/core/tools/write.d.ts.map +0 -1
  348. package/dist/core/tools/write.js +0 -213
  349. package/dist/core/tools/write.js.map +0 -1
  350. package/dist/index.d.ts +0 -28
  351. package/dist/index.d.ts.map +0 -1
  352. package/dist/index.js +0 -41
  353. package/dist/index.js.map +0 -1
  354. package/dist/main.d.ts +0 -12
  355. package/dist/main.d.ts.map +0 -1
  356. package/dist/main.js +0 -589
  357. package/dist/main.js.map +0 -1
  358. package/dist/migrations.d.ts +0 -33
  359. package/dist/migrations.d.ts.map +0 -1
  360. package/dist/migrations.js +0 -281
  361. package/dist/migrations.js.map +0 -1
  362. package/dist/modes/index.d.ts +0 -9
  363. package/dist/modes/index.d.ts.map +0 -1
  364. package/dist/modes/index.js +0 -8
  365. package/dist/modes/index.js.map +0 -1
  366. package/dist/modes/interactive/assets/clankolas.png +0 -0
  367. package/dist/modes/interactive/components/armin.d.ts +0 -34
  368. package/dist/modes/interactive/components/armin.d.ts.map +0 -1
  369. package/dist/modes/interactive/components/armin.js +0 -333
  370. package/dist/modes/interactive/components/armin.js.map +0 -1
  371. package/dist/modes/interactive/components/assistant-message.d.ts +0 -20
  372. package/dist/modes/interactive/components/assistant-message.d.ts.map +0 -1
  373. package/dist/modes/interactive/components/assistant-message.js +0 -121
  374. package/dist/modes/interactive/components/assistant-message.js.map +0 -1
  375. package/dist/modes/interactive/components/bash-execution.d.ts +0 -34
  376. package/dist/modes/interactive/components/bash-execution.d.ts.map +0 -1
  377. package/dist/modes/interactive/components/bash-execution.js +0 -175
  378. package/dist/modes/interactive/components/bash-execution.js.map +0 -1
  379. package/dist/modes/interactive/components/bordered-loader.d.ts +0 -16
  380. package/dist/modes/interactive/components/bordered-loader.d.ts.map +0 -1
  381. package/dist/modes/interactive/components/bordered-loader.js +0 -54
  382. package/dist/modes/interactive/components/bordered-loader.js.map +0 -1
  383. package/dist/modes/interactive/components/branch-summary-message.d.ts +0 -16
  384. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +0 -1
  385. package/dist/modes/interactive/components/branch-summary-message.js +0 -44
  386. package/dist/modes/interactive/components/branch-summary-message.js.map +0 -1
  387. package/dist/modes/interactive/components/compaction-summary-message.d.ts +0 -16
  388. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +0 -1
  389. package/dist/modes/interactive/components/compaction-summary-message.js +0 -45
  390. package/dist/modes/interactive/components/compaction-summary-message.js.map +0 -1
  391. package/dist/modes/interactive/components/config-selector.d.ts +0 -71
  392. package/dist/modes/interactive/components/config-selector.d.ts.map +0 -1
  393. package/dist/modes/interactive/components/config-selector.js +0 -481
  394. package/dist/modes/interactive/components/config-selector.js.map +0 -1
  395. package/dist/modes/interactive/components/countdown-timer.d.ts +0 -14
  396. package/dist/modes/interactive/components/countdown-timer.d.ts.map +0 -1
  397. package/dist/modes/interactive/components/countdown-timer.js +0 -33
  398. package/dist/modes/interactive/components/countdown-timer.js.map +0 -1
  399. package/dist/modes/interactive/components/custom-editor.d.ts +0 -21
  400. package/dist/modes/interactive/components/custom-editor.d.ts.map +0 -1
  401. package/dist/modes/interactive/components/custom-editor.js +0 -70
  402. package/dist/modes/interactive/components/custom-editor.js.map +0 -1
  403. package/dist/modes/interactive/components/custom-message.d.ts +0 -20
  404. package/dist/modes/interactive/components/custom-message.d.ts.map +0 -1
  405. package/dist/modes/interactive/components/custom-message.js +0 -79
  406. package/dist/modes/interactive/components/custom-message.js.map +0 -1
  407. package/dist/modes/interactive/components/daxnuts.d.ts +0 -23
  408. package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
  409. package/dist/modes/interactive/components/daxnuts.js +0 -140
  410. package/dist/modes/interactive/components/daxnuts.js.map +0 -1
  411. package/dist/modes/interactive/components/diff.d.ts +0 -12
  412. package/dist/modes/interactive/components/diff.d.ts.map +0 -1
  413. package/dist/modes/interactive/components/diff.js +0 -133
  414. package/dist/modes/interactive/components/diff.js.map +0 -1
  415. package/dist/modes/interactive/components/dynamic-border.d.ts +0 -15
  416. package/dist/modes/interactive/components/dynamic-border.d.ts.map +0 -1
  417. package/dist/modes/interactive/components/dynamic-border.js +0 -21
  418. package/dist/modes/interactive/components/dynamic-border.js.map +0 -1
  419. package/dist/modes/interactive/components/earendil-announcement.d.ts +0 -5
  420. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +0 -1
  421. package/dist/modes/interactive/components/earendil-announcement.js +0 -40
  422. package/dist/modes/interactive/components/earendil-announcement.js.map +0 -1
  423. package/dist/modes/interactive/components/extension-editor.d.ts +0 -20
  424. package/dist/modes/interactive/components/extension-editor.d.ts.map +0 -1
  425. package/dist/modes/interactive/components/extension-editor.js +0 -111
  426. package/dist/modes/interactive/components/extension-editor.js.map +0 -1
  427. package/dist/modes/interactive/components/extension-input.d.ts +0 -23
  428. package/dist/modes/interactive/components/extension-input.d.ts.map +0 -1
  429. package/dist/modes/interactive/components/extension-input.js +0 -61
  430. package/dist/modes/interactive/components/extension-input.js.map +0 -1
  431. package/dist/modes/interactive/components/extension-selector.d.ts +0 -24
  432. package/dist/modes/interactive/components/extension-selector.d.ts.map +0 -1
  433. package/dist/modes/interactive/components/extension-selector.js +0 -78
  434. package/dist/modes/interactive/components/extension-selector.js.map +0 -1
  435. package/dist/modes/interactive/components/footer.d.ts +0 -27
  436. package/dist/modes/interactive/components/footer.d.ts.map +0 -1
  437. package/dist/modes/interactive/components/footer.js +0 -201
  438. package/dist/modes/interactive/components/footer.js.map +0 -1
  439. package/dist/modes/interactive/components/index.d.ts +0 -32
  440. package/dist/modes/interactive/components/index.d.ts.map +0 -1
  441. package/dist/modes/interactive/components/index.js +0 -33
  442. package/dist/modes/interactive/components/index.js.map +0 -1
  443. package/dist/modes/interactive/components/keybinding-hints.d.ts +0 -8
  444. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +0 -1
  445. package/dist/modes/interactive/components/keybinding-hints.js +0 -22
  446. package/dist/modes/interactive/components/keybinding-hints.js.map +0 -1
  447. package/dist/modes/interactive/components/login-dialog.d.ts +0 -46
  448. package/dist/modes/interactive/components/login-dialog.d.ts.map +0 -1
  449. package/dist/modes/interactive/components/login-dialog.js +0 -158
  450. package/dist/modes/interactive/components/login-dialog.js.map +0 -1
  451. package/dist/modes/interactive/components/model-selector.d.ts +0 -47
  452. package/dist/modes/interactive/components/model-selector.d.ts.map +0 -1
  453. package/dist/modes/interactive/components/model-selector.js +0 -278
  454. package/dist/modes/interactive/components/model-selector.js.map +0 -1
  455. package/dist/modes/interactive/components/oauth-selector.d.ts +0 -29
  456. package/dist/modes/interactive/components/oauth-selector.d.ts.map +0 -1
  457. package/dist/modes/interactive/components/oauth-selector.js +0 -141
  458. package/dist/modes/interactive/components/oauth-selector.js.map +0 -1
  459. package/dist/modes/interactive/components/scoped-models-selector.d.ts +0 -42
  460. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +0 -1
  461. package/dist/modes/interactive/components/scoped-models-selector.js +0 -290
  462. package/dist/modes/interactive/components/scoped-models-selector.js.map +0 -1
  463. package/dist/modes/interactive/components/session-selector-search.d.ts +0 -23
  464. package/dist/modes/interactive/components/session-selector-search.d.ts.map +0 -1
  465. package/dist/modes/interactive/components/session-selector-search.js +0 -155
  466. package/dist/modes/interactive/components/session-selector-search.js.map +0 -1
  467. package/dist/modes/interactive/components/session-selector.d.ts +0 -96
  468. package/dist/modes/interactive/components/session-selector.d.ts.map +0 -1
  469. package/dist/modes/interactive/components/session-selector.js +0 -861
  470. package/dist/modes/interactive/components/session-selector.js.map +0 -1
  471. package/dist/modes/interactive/components/settings-selector.d.ts +0 -67
  472. package/dist/modes/interactive/components/settings-selector.d.ts.map +0 -1
  473. package/dist/modes/interactive/components/settings-selector.js +0 -373
  474. package/dist/modes/interactive/components/settings-selector.js.map +0 -1
  475. package/dist/modes/interactive/components/show-images-selector.d.ts +0 -10
  476. package/dist/modes/interactive/components/show-images-selector.d.ts.map +0 -1
  477. package/dist/modes/interactive/components/show-images-selector.js +0 -39
  478. package/dist/modes/interactive/components/show-images-selector.js.map +0 -1
  479. package/dist/modes/interactive/components/skill-invocation-message.d.ts +0 -17
  480. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +0 -1
  481. package/dist/modes/interactive/components/skill-invocation-message.js +0 -47
  482. package/dist/modes/interactive/components/skill-invocation-message.js.map +0 -1
  483. package/dist/modes/interactive/components/theme-selector.d.ts +0 -11
  484. package/dist/modes/interactive/components/theme-selector.d.ts.map +0 -1
  485. package/dist/modes/interactive/components/theme-selector.js +0 -50
  486. package/dist/modes/interactive/components/theme-selector.js.map +0 -1
  487. package/dist/modes/interactive/components/thinking-selector.d.ts +0 -11
  488. package/dist/modes/interactive/components/thinking-selector.d.ts.map +0 -1
  489. package/dist/modes/interactive/components/thinking-selector.js +0 -51
  490. package/dist/modes/interactive/components/thinking-selector.js.map +0 -1
  491. package/dist/modes/interactive/components/tool-execution.d.ts +0 -63
  492. package/dist/modes/interactive/components/tool-execution.d.ts.map +0 -1
  493. package/dist/modes/interactive/components/tool-execution.js +0 -295
  494. package/dist/modes/interactive/components/tool-execution.js.map +0 -1
  495. package/dist/modes/interactive/components/tree-selector.d.ts +0 -89
  496. package/dist/modes/interactive/components/tree-selector.d.ts.map +0 -1
  497. package/dist/modes/interactive/components/tree-selector.js +0 -1092
  498. package/dist/modes/interactive/components/tree-selector.js.map +0 -1
  499. package/dist/modes/interactive/components/user-message-selector.d.ts +0 -30
  500. package/dist/modes/interactive/components/user-message-selector.d.ts.map +0 -1
  501. package/dist/modes/interactive/components/user-message-selector.js +0 -114
  502. package/dist/modes/interactive/components/user-message-selector.js.map +0 -1
  503. package/dist/modes/interactive/components/user-message.d.ts +0 -10
  504. package/dist/modes/interactive/components/user-message.d.ts.map +0 -1
  505. package/dist/modes/interactive/components/user-message.js +0 -29
  506. package/dist/modes/interactive/components/user-message.js.map +0 -1
  507. package/dist/modes/interactive/components/visual-truncate.d.ts +0 -24
  508. package/dist/modes/interactive/components/visual-truncate.d.ts.map +0 -1
  509. package/dist/modes/interactive/components/visual-truncate.js +0 -33
  510. package/dist/modes/interactive/components/visual-truncate.js.map +0 -1
  511. package/dist/modes/interactive/interactive-mode.d.ts +0 -359
  512. package/dist/modes/interactive/interactive-mode.d.ts.map +0 -1
  513. package/dist/modes/interactive/interactive-mode.js +0 -4573
  514. package/dist/modes/interactive/interactive-mode.js.map +0 -1
  515. package/dist/modes/interactive/theme/aery.json +0 -84
  516. package/dist/modes/interactive/theme/catppuccin-mocha.json +0 -81
  517. package/dist/modes/interactive/theme/dark.json +0 -85
  518. package/dist/modes/interactive/theme/dracula.json +0 -81
  519. package/dist/modes/interactive/theme/light.json +0 -84
  520. package/dist/modes/interactive/theme/nord.json +0 -81
  521. package/dist/modes/interactive/theme/theme-schema.json +0 -335
  522. package/dist/modes/interactive/theme/theme.d.ts +0 -81
  523. package/dist/modes/interactive/theme/theme.d.ts.map +0 -1
  524. package/dist/modes/interactive/theme/theme.js +0 -975
  525. package/dist/modes/interactive/theme/theme.js.map +0 -1
  526. package/dist/modes/interactive/theme/tokyo-night.json +0 -81
  527. package/dist/modes/print-mode.d.ts +0 -28
  528. package/dist/modes/print-mode.d.ts.map +0 -1
  529. package/dist/modes/print-mode.js +0 -131
  530. package/dist/modes/print-mode.js.map +0 -1
  531. package/dist/modes/rpc/jsonl.d.ts +0 -17
  532. package/dist/modes/rpc/jsonl.d.ts.map +0 -1
  533. package/dist/modes/rpc/jsonl.js +0 -49
  534. package/dist/modes/rpc/jsonl.js.map +0 -1
  535. package/dist/modes/rpc/rpc-client.d.ts +0 -224
  536. package/dist/modes/rpc/rpc-client.d.ts.map +0 -1
  537. package/dist/modes/rpc/rpc-client.js +0 -410
  538. package/dist/modes/rpc/rpc-client.js.map +0 -1
  539. package/dist/modes/rpc/rpc-mode.d.ts +0 -20
  540. package/dist/modes/rpc/rpc-mode.d.ts.map +0 -1
  541. package/dist/modes/rpc/rpc-mode.js +0 -597
  542. package/dist/modes/rpc/rpc-mode.js.map +0 -1
  543. package/dist/modes/rpc/rpc-types.d.ts +0 -419
  544. package/dist/modes/rpc/rpc-types.d.ts.map +0 -1
  545. package/dist/modes/rpc/rpc-types.js +0 -8
  546. package/dist/modes/rpc/rpc-types.js.map +0 -1
  547. package/dist/package-manager-cli.d.ts +0 -4
  548. package/dist/package-manager-cli.d.ts.map +0 -1
  549. package/dist/package-manager-cli.js +0 -468
  550. package/dist/package-manager-cli.js.map +0 -1
  551. package/dist/utils/aery-user-agent.d.ts +0 -2
  552. package/dist/utils/aery-user-agent.d.ts.map +0 -1
  553. package/dist/utils/aery-user-agent.js +0 -5
  554. package/dist/utils/aery-user-agent.js.map +0 -1
  555. package/dist/utils/changelog.d.ts +0 -21
  556. package/dist/utils/changelog.d.ts.map +0 -1
  557. package/dist/utils/changelog.js +0 -87
  558. package/dist/utils/changelog.js.map +0 -1
  559. package/dist/utils/child-process.d.ts +0 -11
  560. package/dist/utils/child-process.d.ts.map +0 -1
  561. package/dist/utils/child-process.js +0 -78
  562. package/dist/utils/child-process.js.map +0 -1
  563. package/dist/utils/clipboard-image.d.ts +0 -11
  564. package/dist/utils/clipboard-image.d.ts.map +0 -1
  565. package/dist/utils/clipboard-image.js +0 -245
  566. package/dist/utils/clipboard-image.js.map +0 -1
  567. package/dist/utils/clipboard-native.d.ts +0 -8
  568. package/dist/utils/clipboard-native.d.ts.map +0 -1
  569. package/dist/utils/clipboard-native.js +0 -14
  570. package/dist/utils/clipboard-native.js.map +0 -1
  571. package/dist/utils/clipboard.d.ts +0 -2
  572. package/dist/utils/clipboard.d.ts.map +0 -1
  573. package/dist/utils/clipboard.js +0 -110
  574. package/dist/utils/clipboard.js.map +0 -1
  575. package/dist/utils/exif-orientation.d.ts +0 -5
  576. package/dist/utils/exif-orientation.d.ts.map +0 -1
  577. package/dist/utils/exif-orientation.js +0 -158
  578. package/dist/utils/exif-orientation.js.map +0 -1
  579. package/dist/utils/frontmatter.d.ts +0 -8
  580. package/dist/utils/frontmatter.d.ts.map +0 -1
  581. package/dist/utils/frontmatter.js +0 -26
  582. package/dist/utils/frontmatter.js.map +0 -1
  583. package/dist/utils/fs-watch.d.ts +0 -5
  584. package/dist/utils/fs-watch.d.ts.map +0 -1
  585. package/dist/utils/fs-watch.js +0 -25
  586. package/dist/utils/fs-watch.js.map +0 -1
  587. package/dist/utils/git.d.ts +0 -26
  588. package/dist/utils/git.d.ts.map +0 -1
  589. package/dist/utils/git.js +0 -163
  590. package/dist/utils/git.js.map +0 -1
  591. package/dist/utils/image-convert.d.ts +0 -9
  592. package/dist/utils/image-convert.d.ts.map +0 -1
  593. package/dist/utils/image-convert.js +0 -39
  594. package/dist/utils/image-convert.js.map +0 -1
  595. package/dist/utils/image-resize.d.ts +0 -36
  596. package/dist/utils/image-resize.d.ts.map +0 -1
  597. package/dist/utils/image-resize.js +0 -137
  598. package/dist/utils/image-resize.js.map +0 -1
  599. package/dist/utils/mime.d.ts +0 -2
  600. package/dist/utils/mime.d.ts.map +0 -1
  601. package/dist/utils/mime.js +0 -26
  602. package/dist/utils/mime.js.map +0 -1
  603. package/dist/utils/paths.d.ts +0 -14
  604. package/dist/utils/paths.d.ts.map +0 -1
  605. package/dist/utils/paths.js +0 -34
  606. package/dist/utils/paths.js.map +0 -1
  607. package/dist/utils/photon.d.ts +0 -21
  608. package/dist/utils/photon.d.ts.map +0 -1
  609. package/dist/utils/photon.js +0 -121
  610. package/dist/utils/photon.js.map +0 -1
  611. package/dist/utils/shell.d.ts +0 -30
  612. package/dist/utils/shell.d.ts.map +0 -1
  613. package/dist/utils/shell.js +0 -190
  614. package/dist/utils/shell.js.map +0 -1
  615. package/dist/utils/sleep.d.ts +0 -5
  616. package/dist/utils/sleep.d.ts.map +0 -1
  617. package/dist/utils/sleep.js +0 -17
  618. package/dist/utils/sleep.js.map +0 -1
  619. package/dist/utils/tools-manager.d.ts +0 -3
  620. package/dist/utils/tools-manager.d.ts.map +0 -1
  621. package/dist/utils/tools-manager.js +0 -256
  622. package/dist/utils/tools-manager.js.map +0 -1
  623. package/dist/utils/version-check.d.ts +0 -7
  624. package/dist/utils/version-check.d.ts.map +0 -1
  625. package/dist/utils/version-check.js +0 -70
  626. package/dist/utils/version-check.js.map +0 -1
@@ -1,199 +0,0 @@
1
- import type { SettingsManager } from "./settings-manager.js";
2
- export interface PathMetadata {
3
- source: string;
4
- scope: SourceScope;
5
- origin: "package" | "top-level";
6
- baseDir?: string;
7
- }
8
- export interface ResolvedResource {
9
- path: string;
10
- enabled: boolean;
11
- metadata: PathMetadata;
12
- }
13
- export interface ResolvedPaths {
14
- extensions: ResolvedResource[];
15
- skills: ResolvedResource[];
16
- prompts: ResolvedResource[];
17
- themes: ResolvedResource[];
18
- }
19
- export type MissingSourceAction = "install" | "skip" | "error";
20
- export interface ProgressEvent {
21
- type: "start" | "progress" | "complete" | "error";
22
- action: "install" | "remove" | "update" | "clone" | "pull";
23
- source: string;
24
- message?: string;
25
- }
26
- export type ProgressCallback = (event: ProgressEvent) => void;
27
- export interface PackageUpdate {
28
- source: string;
29
- displayName: string;
30
- type: "npm" | "git";
31
- scope: Exclude<SourceScope, "temporary">;
32
- }
33
- export interface ConfiguredPackage {
34
- source: string;
35
- scope: "user" | "project";
36
- filtered: boolean;
37
- installedPath?: string;
38
- }
39
- export interface PackageManager {
40
- resolve(onMissing?: (source: string) => Promise<MissingSourceAction>): Promise<ResolvedPaths>;
41
- install(source: string, options?: {
42
- local?: boolean;
43
- }): Promise<void>;
44
- installAndPersist(source: string, options?: {
45
- local?: boolean;
46
- }): Promise<void>;
47
- remove(source: string, options?: {
48
- local?: boolean;
49
- }): Promise<void>;
50
- removeAndPersist(source: string, options?: {
51
- local?: boolean;
52
- }): Promise<boolean>;
53
- update(source?: string): Promise<void>;
54
- listConfiguredPackages(): ConfiguredPackage[];
55
- resolveExtensionSources(sources: string[], options?: {
56
- local?: boolean;
57
- temporary?: boolean;
58
- }): Promise<ResolvedPaths>;
59
- addSourceToSettings(source: string, options?: {
60
- local?: boolean;
61
- }): boolean;
62
- removeSourceFromSettings(source: string, options?: {
63
- local?: boolean;
64
- }): boolean;
65
- setProgressCallback(callback: ProgressCallback | undefined): void;
66
- getInstalledPath(source: string, scope: "user" | "project"): string | undefined;
67
- }
68
- interface PackageManagerOptions {
69
- cwd: string;
70
- agentDir: string;
71
- settingsManager: SettingsManager;
72
- }
73
- type SourceScope = "user" | "project" | "temporary";
74
- export declare class DefaultPackageManager implements PackageManager {
75
- private cwd;
76
- private agentDir;
77
- private settingsManager;
78
- private globalNpmRoot;
79
- private globalNpmRootCommandKey;
80
- private progressCallback;
81
- constructor(options: PackageManagerOptions);
82
- setProgressCallback(callback: ProgressCallback | undefined): void;
83
- addSourceToSettings(source: string, options?: {
84
- local?: boolean;
85
- }): boolean;
86
- removeSourceFromSettings(source: string, options?: {
87
- local?: boolean;
88
- }): boolean;
89
- getInstalledPath(source: string, scope: "user" | "project"): string | undefined;
90
- private emitProgress;
91
- private withProgress;
92
- resolve(onMissing?: (source: string) => Promise<MissingSourceAction>): Promise<ResolvedPaths>;
93
- resolveExtensionSources(sources: string[], options?: {
94
- local?: boolean;
95
- temporary?: boolean;
96
- }): Promise<ResolvedPaths>;
97
- listConfiguredPackages(): ConfiguredPackage[];
98
- install(source: string, options?: {
99
- local?: boolean;
100
- }): Promise<void>;
101
- installAndPersist(source: string, options?: {
102
- local?: boolean;
103
- }): Promise<void>;
104
- remove(source: string, options?: {
105
- local?: boolean;
106
- }): Promise<void>;
107
- removeAndPersist(source: string, options?: {
108
- local?: boolean;
109
- }): Promise<boolean>;
110
- update(source?: string): Promise<void>;
111
- private updateConfiguredSources;
112
- private shouldUpdateNpmSource;
113
- private updateNpmBatch;
114
- private installNpmBatch;
115
- checkForAvailableUpdates(): Promise<PackageUpdate[]>;
116
- private resolvePackageSources;
117
- private resolveLocalExtensionSource;
118
- private installParsedSource;
119
- private getPackageSourceString;
120
- private getSourceMatchKeyForInput;
121
- private getSourceMatchKeyForSettings;
122
- private buildNoMatchingPackageMessage;
123
- private findSuggestedConfiguredSource;
124
- private packageSourcesMatch;
125
- private normalizePackageSourceForSettings;
126
- private parseSource;
127
- private installedNpmMatchesPinnedVersion;
128
- private npmHasAvailableUpdate;
129
- private getInstalledNpmVersion;
130
- private getLatestNpmVersion;
131
- private gitHasAvailableUpdate;
132
- private getRemoteGitHead;
133
- private getLocalGitUpdateTarget;
134
- private getGitUpstreamRef;
135
- private runGitRemoteCommand;
136
- private runWithConcurrency;
137
- /**
138
- * Get a unique identity for a package, ignoring version/ref.
139
- * Used to detect when the same package is in both global and project settings.
140
- * For git packages, uses normalized host/path to ensure SSH and HTTPS URLs
141
- * for the same repository are treated as identical.
142
- */
143
- private getPackageIdentity;
144
- /**
145
- * Dedupe packages: if same package identity appears in both global and project,
146
- * keep only the project one (project wins).
147
- */
148
- private dedupePackages;
149
- private parseNpmSpec;
150
- private getNpmCommand;
151
- private runNpmCommand;
152
- private getGitDependencyInstallArgs;
153
- private runNpmCommandSync;
154
- private installNpm;
155
- private uninstallNpm;
156
- private installGit;
157
- private updateGit;
158
- private refreshTemporaryGitSource;
159
- private removeGit;
160
- private pruneEmptyGitParents;
161
- private ensureNpmProject;
162
- private ensureGitIgnore;
163
- private getNpmInstallRoot;
164
- private getGlobalNpmRoot;
165
- private getNpmInstallPath;
166
- private getGitInstallPath;
167
- private getGitInstallRoot;
168
- private getTemporaryDir;
169
- private getBaseDirForScope;
170
- private resolvePath;
171
- private resolvePathFromBase;
172
- private collectPackageResources;
173
- private collectDefaultResources;
174
- private applyPackageFilter;
175
- /**
176
- * Collect all files from a package for a resource type, applying manifest patterns.
177
- * Returns { allFiles, enabledByManifest } where enabledByManifest is the set of files
178
- * that pass the manifest's own patterns.
179
- */
180
- private collectManifestFiles;
181
- private readPiManifest;
182
- private addManifestEntries;
183
- private collectFilesFromManifestEntries;
184
- private resolveLocalEntries;
185
- private addAutoDiscoveredResources;
186
- private collectFilesFromPaths;
187
- private getTargetMap;
188
- private addResource;
189
- private createAccumulator;
190
- private toResolvedPaths;
191
- private shouldUseWindowsShell;
192
- private spawnCommand;
193
- private spawnCaptureCommand;
194
- private runCommandCapture;
195
- private runCommand;
196
- private runCommandSync;
197
- }
198
- export {};
199
- //# sourceMappingURL=package-manager.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"package-manager.d.ts","sourceRoot":"","sources":["../../src/core/package-manager.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAiB,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAY5E,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,EAAE,SAAS,GAAG,WAAW,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,YAAY,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC7B,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAED,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;AAE/D,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,OAAO,CAAC;IAClD,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;IAC3D,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAE9D,MAAM,WAAW,aAAa;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,KAAK,GAAG,KAAK,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,iBAAiB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC9B,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC9F,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrE,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClF,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,sBAAsB,IAAI,iBAAiB,EAAE,CAAC;IAC9C,uBAAuB,CACtB,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAChD,OAAO,CAAC,aAAa,CAAC,CAAC;IAC1B,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC;IAC5E,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC;IACjF,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,SAAS,GAAG,IAAI,CAAC;IAClE,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;CAChF;AAED,UAAU,qBAAqB;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,eAAe,CAAC;CACjC;AAED,KAAK,WAAW,GAAG,MAAM,GAAG,SAAS,GAAG,WAAW,CAAC;AAioBpD,qBAAa,qBAAsB,YAAW,cAAc;IAC3D,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,uBAAuB,CAAqB;IACpD,OAAO,CAAC,gBAAgB,CAA+B;IAEvD,YAAY,OAAO,EAAE,qBAAqB,EAIzC;IAED,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,SAAS,GAAG,IAAI,CAEhE;IAED,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAiB1E;IAED,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAgB/E;IAED,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAgB9E;IAED,OAAO,CAAC,YAAY;YAIN,YAAY;IAiBpB,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAoDlG;IAEK,uBAAuB,CAC5B,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAChD,OAAO,CAAC,aAAa,CAAC,CAMxB;IAED,sBAAsB,IAAI,iBAAiB,EAAE,CA0B5C;IAEK,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB1E;IAEK,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpF;IAEK,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBzE;IAEK,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAGtF;IAEK,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8B3C;YAEa,uBAAuB;YA0DvB,qBAAqB;YAgBrB,cAAc;YAcd,eAAe;IAUvB,wBAAwB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CA+DzD;YAEa,qBAAqB;IA4DnC,OAAO,CAAC,2BAA2B;YA+BrB,mBAAmB;IAWjC,OAAO,CAAC,sBAAsB;IAI9B,OAAO,CAAC,yBAAyB;IAWjC,OAAO,CAAC,4BAA4B;IAYpC,OAAO,CAAC,6BAA6B;IAQrC,OAAO,CAAC,6BAA6B;IAyBrC,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,iCAAiC;IAWzC,OAAO,CAAC,WAAW;YAyBL,gCAAgC;YAchC,qBAAqB;IAkBnC,OAAO,CAAC,sBAAsB;YAYhB,mBAAmB;YAYnB,qBAAqB;YAiBrB,gBAAgB;YAkBhB,uBAAuB;YA+DvB,iBAAiB;IAiB/B,OAAO,CAAC,mBAAmB;YAUb,kBAAkB;IAwBhC;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAgB1B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAuBtB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,aAAa;YAYP,aAAa;IAK3B,OAAO,CAAC,2BAA2B;IAQnC,OAAO,CAAC,iBAAiB;YAKX,UAAU;YAUV,YAAY;YAYZ,UAAU;YAqBV,SAAS;YAmCT,yBAAyB;YAazB,SAAS;IAOvB,OAAO,CAAC,oBAAoB;IAsB5B,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,gBAAgB;IAiBxB,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,uBAAuB;IAiD/B,OAAO,CAAC,uBAAuB;IAsB/B,OAAO,CAAC,kBAAkB;IA0B1B;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAsB5B,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,kBAAkB;IAoB1B,OAAO,CAAC,+BAA+B;IAiBvC,OAAO,CAAC,mBAAmB;IAuB3B,OAAO,CAAC,0BAA0B;IAiIlC,OAAO,CAAC,qBAAqB;IAmB7B,OAAO,CAAC,YAAY;IAkBpB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,eAAe;IA4BvB,OAAO,CAAC,qBAAqB;IAiB7B,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,mBAAmB;IAc3B,OAAO,CAAC,iBAAiB;IA4CzB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,cAAc;CActB","sourcesContent":["import { type ChildProcess, type ChildProcessByStdio, spawn, spawnSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from \"node:fs\";\nimport { homedir, tmpdir } from \"node:os\";\n\nfunction getEnv(): NodeJS.ProcessEnv {\n\tif (process.platform !== \"linux\" || Object.keys(process.env).length > 0) {\n\t\treturn process.env;\n\t}\n\ttry {\n\t\tconst data = readFileSync(\"/proc/self/environ\", \"utf-8\");\n\t\tconst env: NodeJS.ProcessEnv = {};\n\t\tfor (const entry of data.split(\"\\0\")) {\n\t\t\tconst idx = entry.indexOf(\"=\");\n\t\t\tif (idx > 0) {\n\t\t\t\tenv[entry.slice(0, idx)] = entry.slice(idx + 1);\n\t\t\t}\n\t\t}\n\t\treturn env;\n\t} catch {\n\t\treturn process.env;\n\t}\n}\n\nimport { basename, dirname, join, relative, resolve, sep } from \"node:path\";\nimport type { Readable } from \"node:stream\";\nimport { globSync } from \"glob\";\nimport ignore from \"ignore\";\nimport { minimatch } from \"minimatch\";\nimport { CONFIG_DIR_NAME } from \"../config.js\";\nimport { type GitSource, parseGitUrl } from \"../utils/git.js\";\nimport { canonicalizePath, isLocalPath } from \"../utils/paths.js\";\nimport { isStdoutTakenOver } from \"./output-guard.js\";\nimport type { PackageSource, SettingsManager } from \"./settings-manager.js\";\n\nconst NETWORK_TIMEOUT_MS = 10000;\nconst UPDATE_CHECK_CONCURRENCY = 4;\nconst GIT_UPDATE_CONCURRENCY = 4;\n\nfunction isOfflineModeEnabled(): boolean {\n\tconst value = process.env.PI_OFFLINE;\n\tif (!value) return false;\n\treturn value === \"1\" || value.toLowerCase() === \"true\" || value.toLowerCase() === \"yes\";\n}\n\nexport interface PathMetadata {\n\tsource: string;\n\tscope: SourceScope;\n\torigin: \"package\" | \"top-level\";\n\tbaseDir?: string;\n}\n\nexport interface ResolvedResource {\n\tpath: string;\n\tenabled: boolean;\n\tmetadata: PathMetadata;\n}\n\nexport interface ResolvedPaths {\n\textensions: ResolvedResource[];\n\tskills: ResolvedResource[];\n\tprompts: ResolvedResource[];\n\tthemes: ResolvedResource[];\n}\n\nexport type MissingSourceAction = \"install\" | \"skip\" | \"error\";\n\nexport interface ProgressEvent {\n\ttype: \"start\" | \"progress\" | \"complete\" | \"error\";\n\taction: \"install\" | \"remove\" | \"update\" | \"clone\" | \"pull\";\n\tsource: string;\n\tmessage?: string;\n}\n\nexport type ProgressCallback = (event: ProgressEvent) => void;\n\nexport interface PackageUpdate {\n\tsource: string;\n\tdisplayName: string;\n\ttype: \"npm\" | \"git\";\n\tscope: Exclude<SourceScope, \"temporary\">;\n}\n\nexport interface ConfiguredPackage {\n\tsource: string;\n\tscope: \"user\" | \"project\";\n\tfiltered: boolean;\n\tinstalledPath?: string;\n}\n\nexport interface PackageManager {\n\tresolve(onMissing?: (source: string) => Promise<MissingSourceAction>): Promise<ResolvedPaths>;\n\tinstall(source: string, options?: { local?: boolean }): Promise<void>;\n\tinstallAndPersist(source: string, options?: { local?: boolean }): Promise<void>;\n\tremove(source: string, options?: { local?: boolean }): Promise<void>;\n\tremoveAndPersist(source: string, options?: { local?: boolean }): Promise<boolean>;\n\tupdate(source?: string): Promise<void>;\n\tlistConfiguredPackages(): ConfiguredPackage[];\n\tresolveExtensionSources(\n\t\tsources: string[],\n\t\toptions?: { local?: boolean; temporary?: boolean },\n\t): Promise<ResolvedPaths>;\n\taddSourceToSettings(source: string, options?: { local?: boolean }): boolean;\n\tremoveSourceFromSettings(source: string, options?: { local?: boolean }): boolean;\n\tsetProgressCallback(callback: ProgressCallback | undefined): void;\n\tgetInstalledPath(source: string, scope: \"user\" | \"project\"): string | undefined;\n}\n\ninterface PackageManagerOptions {\n\tcwd: string;\n\tagentDir: string;\n\tsettingsManager: SettingsManager;\n}\n\ntype SourceScope = \"user\" | \"project\" | \"temporary\";\n\ntype NpmSource = {\n\ttype: \"npm\";\n\tspec: string;\n\tname: string;\n\tpinned: boolean;\n};\n\ntype LocalSource = {\n\ttype: \"local\";\n\tpath: string;\n};\n\ntype ParsedSource = NpmSource | GitSource | LocalSource;\n\ntype InstalledSourceScope = Exclude<SourceScope, \"temporary\">;\n\ninterface ConfiguredUpdateSource {\n\tsource: string;\n\tscope: InstalledSourceScope;\n}\n\ninterface NpmUpdateTarget extends ConfiguredUpdateSource {\n\tparsed: NpmSource;\n}\n\ninterface GitUpdateTarget extends ConfiguredUpdateSource {\n\tparsed: GitSource;\n}\n\ninterface PiManifest {\n\textensions?: string[];\n\tskills?: string[];\n\tprompts?: string[];\n\tthemes?: string[];\n}\n\ninterface ResourceAccumulator {\n\textensions: Map<string, { metadata: PathMetadata; enabled: boolean }>;\n\tskills: Map<string, { metadata: PathMetadata; enabled: boolean }>;\n\tprompts: Map<string, { metadata: PathMetadata; enabled: boolean }>;\n\tthemes: Map<string, { metadata: PathMetadata; enabled: boolean }>;\n}\n\n/**\n * Compute a numeric precedence rank for a resource based on its metadata.\n * Lower rank = higher precedence. Used to sort resolved resources so that\n * name-collision resolution (\"first wins\") produces the correct outcome.\n *\n * Precedence (highest to lowest):\n * 0 project + settings entry (source: \"local\", scope: \"project\")\n * 1 project + auto-discovered (source: \"auto\", scope: \"project\")\n * 2 user + settings entry (source: \"local\", scope: \"user\")\n * 3 user + auto-discovered (source: \"auto\", scope: \"user\")\n * 4 package resource (origin: \"package\")\n */\nfunction resourcePrecedenceRank(m: PathMetadata): number {\n\tif (m.origin === \"package\") return 4;\n\tconst scopeBase = m.scope === \"project\" ? 0 : 2;\n\treturn scopeBase + (m.source === \"local\" ? 0 : 1);\n}\n\ninterface PackageFilter {\n\textensions?: string[];\n\tskills?: string[];\n\tprompts?: string[];\n\tthemes?: string[];\n}\n\ntype ResourceType = \"extensions\" | \"skills\" | \"prompts\" | \"themes\";\n\nconst RESOURCE_TYPES: ResourceType[] = [\"extensions\", \"skills\", \"prompts\", \"themes\"];\n\nconst FILE_PATTERNS: Record<ResourceType, RegExp> = {\n\textensions: /\\.(ts|js)$/,\n\tskills: /\\.md$/,\n\tprompts: /\\.md$/,\n\tthemes: /\\.json$/,\n};\n\nconst IGNORE_FILE_NAMES = [\".gitignore\", \".ignore\", \".fdignore\"];\n\ntype IgnoreMatcher = ReturnType<typeof ignore>;\n\nfunction toPosixPath(p: string): string {\n\treturn p.split(sep).join(\"/\");\n}\n\nfunction getHomeDir(): string {\n\treturn process.env.HOME || homedir();\n}\n\nfunction prefixIgnorePattern(line: string, prefix: string): string | null {\n\tconst trimmed = line.trim();\n\tif (!trimmed) return null;\n\tif (trimmed.startsWith(\"#\") && !trimmed.startsWith(\"\\\\#\")) return null;\n\n\tlet pattern = line;\n\tlet negated = false;\n\n\tif (pattern.startsWith(\"!\")) {\n\t\tnegated = true;\n\t\tpattern = pattern.slice(1);\n\t} else if (pattern.startsWith(\"\\\\!\")) {\n\t\tpattern = pattern.slice(1);\n\t}\n\n\tif (pattern.startsWith(\"/\")) {\n\t\tpattern = pattern.slice(1);\n\t}\n\n\tconst prefixed = prefix ? `${prefix}${pattern}` : pattern;\n\treturn negated ? `!${prefixed}` : prefixed;\n}\n\nfunction addIgnoreRules(ig: IgnoreMatcher, dir: string, rootDir: string): void {\n\tconst relativeDir = relative(rootDir, dir);\n\tconst prefix = relativeDir ? `${toPosixPath(relativeDir)}/` : \"\";\n\n\tfor (const filename of IGNORE_FILE_NAMES) {\n\t\tconst ignorePath = join(dir, filename);\n\t\tif (!existsSync(ignorePath)) continue;\n\t\ttry {\n\t\t\tconst content = readFileSync(ignorePath, \"utf-8\");\n\t\t\tconst patterns = content\n\t\t\t\t.split(/\\r?\\n/)\n\t\t\t\t.map((line) => prefixIgnorePattern(line, prefix))\n\t\t\t\t.filter((line): line is string => Boolean(line));\n\t\t\tif (patterns.length > 0) {\n\t\t\t\tig.add(patterns);\n\t\t\t}\n\t\t} catch {}\n\t}\n}\n\nfunction isPattern(s: string): boolean {\n\treturn s.startsWith(\"!\") || s.startsWith(\"+\") || s.startsWith(\"-\") || s.includes(\"*\") || s.includes(\"?\");\n}\n\nfunction isOverridePattern(s: string): boolean {\n\treturn s.startsWith(\"!\") || s.startsWith(\"+\") || s.startsWith(\"-\");\n}\n\nfunction hasGlobPattern(s: string): boolean {\n\treturn s.includes(\"*\") || s.includes(\"?\");\n}\n\nfunction splitPatterns(entries: string[]): { plain: string[]; patterns: string[] } {\n\tconst plain: string[] = [];\n\tconst patterns: string[] = [];\n\tfor (const entry of entries) {\n\t\tif (isPattern(entry)) {\n\t\t\tpatterns.push(entry);\n\t\t} else {\n\t\t\tplain.push(entry);\n\t\t}\n\t}\n\treturn { plain, patterns };\n}\n\nfunction collectFiles(\n\tdir: string,\n\tfilePattern: RegExp,\n\tskipNodeModules = true,\n\tignoreMatcher?: IgnoreMatcher,\n\trootDir?: string,\n): string[] {\n\tconst files: string[] = [];\n\tif (!existsSync(dir)) return files;\n\n\tconst root = rootDir ?? dir;\n\tconst ig = ignoreMatcher ?? ignore();\n\taddIgnoreRules(ig, dir, root);\n\n\ttry {\n\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.name.startsWith(\".\")) continue;\n\t\t\tif (skipNodeModules && entry.name === \"node_modules\") continue;\n\n\t\t\tconst fullPath = join(dir, entry.name);\n\t\t\tlet isDir = entry.isDirectory();\n\t\t\tlet isFile = entry.isFile();\n\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(fullPath);\n\t\t\t\t\tisDir = stats.isDirectory();\n\t\t\t\t\tisFile = stats.isFile();\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst relPath = toPosixPath(relative(root, fullPath));\n\t\t\tconst ignorePath = isDir ? `${relPath}/` : relPath;\n\t\t\tif (ig.ignores(ignorePath)) continue;\n\n\t\t\tif (isDir) {\n\t\t\t\tfiles.push(...collectFiles(fullPath, filePattern, skipNodeModules, ig, root));\n\t\t\t} else if (isFile && filePattern.test(entry.name)) {\n\t\t\t\tfiles.push(fullPath);\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ignore errors\n\t}\n\n\treturn files;\n}\n\ntype SkillDiscoveryMode = \"aery\" | \"agents\";\n\nfunction collectSkillEntries(\n\tdir: string,\n\tmode: SkillDiscoveryMode,\n\tignoreMatcher?: IgnoreMatcher,\n\trootDir?: string,\n): string[] {\n\tconst entries: string[] = [];\n\tif (!existsSync(dir)) return entries;\n\n\tconst root = rootDir ?? dir;\n\tconst ig = ignoreMatcher ?? ignore();\n\taddIgnoreRules(ig, dir, root);\n\n\ttry {\n\t\tconst dirEntries = readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of dirEntries) {\n\t\t\tif (entry.name !== \"SKILL.md\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst fullPath = join(dir, entry.name);\n\t\t\tlet isFile = entry.isFile();\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tisFile = statSync(fullPath).isFile();\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst relPath = toPosixPath(relative(root, fullPath));\n\t\t\tif (isFile && !ig.ignores(relPath)) {\n\t\t\t\tentries.push(fullPath);\n\t\t\t\treturn entries;\n\t\t\t}\n\t\t}\n\n\t\tfor (const entry of dirEntries) {\n\t\t\tif (entry.name.startsWith(\".\")) continue;\n\t\t\tif (entry.name === \"node_modules\") continue;\n\n\t\t\tconst fullPath = join(dir, entry.name);\n\t\t\tlet isDir = entry.isDirectory();\n\t\t\tlet isFile = entry.isFile();\n\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(fullPath);\n\t\t\t\t\tisDir = stats.isDirectory();\n\t\t\t\t\tisFile = stats.isFile();\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst relPath = toPosixPath(relative(root, fullPath));\n\t\t\tif (mode === \"aery\" && dir === root && isFile && entry.name.endsWith(\".md\") && !ig.ignores(relPath)) {\n\t\t\t\tentries.push(fullPath);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!isDir) continue;\n\t\t\tif (ig.ignores(`${relPath}/`)) continue;\n\n\t\t\tentries.push(...collectSkillEntries(fullPath, mode, ig, root));\n\t\t}\n\t} catch {\n\t\t// Ignore errors\n\t}\n\n\treturn entries;\n}\n\nfunction collectAutoSkillEntries(dir: string, mode: SkillDiscoveryMode): string[] {\n\treturn collectSkillEntries(dir, mode);\n}\n\nfunction findGitRepoRoot(startDir: string): string | null {\n\tlet dir = resolve(startDir);\n\twhile (true) {\n\t\tif (existsSync(join(dir, \".git\"))) {\n\t\t\treturn dir;\n\t\t}\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) {\n\t\t\treturn null;\n\t\t}\n\t\tdir = parent;\n\t}\n}\n\nfunction collectAncestorAgentsSkillDirs(startDir: string): string[] {\n\tconst skillDirs: string[] = [];\n\tconst resolvedStartDir = resolve(startDir);\n\tconst gitRepoRoot = findGitRepoRoot(resolvedStartDir);\n\n\tlet dir = resolvedStartDir;\n\twhile (true) {\n\t\tskillDirs.push(join(dir, \".agents\", \"skills\"));\n\t\tif (gitRepoRoot && dir === gitRepoRoot) {\n\t\t\tbreak;\n\t\t}\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) {\n\t\t\tbreak;\n\t\t}\n\t\tdir = parent;\n\t}\n\n\treturn skillDirs;\n}\n\nfunction collectAutoPromptEntries(dir: string): string[] {\n\tconst entries: string[] = [];\n\tif (!existsSync(dir)) return entries;\n\n\tconst ig = ignore();\n\taddIgnoreRules(ig, dir, dir);\n\n\ttry {\n\t\tconst dirEntries = readdirSync(dir, { withFileTypes: true });\n\t\tfor (const entry of dirEntries) {\n\t\t\tif (entry.name.startsWith(\".\")) continue;\n\t\t\tif (entry.name === \"node_modules\") continue;\n\n\t\t\tconst fullPath = join(dir, entry.name);\n\t\t\tlet isFile = entry.isFile();\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tisFile = statSync(fullPath).isFile();\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst relPath = toPosixPath(relative(dir, fullPath));\n\t\t\tif (ig.ignores(relPath)) continue;\n\n\t\t\tif (isFile && entry.name.endsWith(\".md\")) {\n\t\t\t\tentries.push(fullPath);\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ignore errors\n\t}\n\n\treturn entries;\n}\n\nfunction collectAutoThemeEntries(dir: string): string[] {\n\tconst entries: string[] = [];\n\tif (!existsSync(dir)) return entries;\n\n\tconst ig = ignore();\n\taddIgnoreRules(ig, dir, dir);\n\n\ttry {\n\t\tconst dirEntries = readdirSync(dir, { withFileTypes: true });\n\t\tfor (const entry of dirEntries) {\n\t\t\tif (entry.name.startsWith(\".\")) continue;\n\t\t\tif (entry.name === \"node_modules\") continue;\n\n\t\t\tconst fullPath = join(dir, entry.name);\n\t\t\tlet isFile = entry.isFile();\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tisFile = statSync(fullPath).isFile();\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst relPath = toPosixPath(relative(dir, fullPath));\n\t\t\tif (ig.ignores(relPath)) continue;\n\n\t\t\tif (isFile && entry.name.endsWith(\".json\")) {\n\t\t\t\tentries.push(fullPath);\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ignore errors\n\t}\n\n\treturn entries;\n}\n\nfunction readPiManifestFile(packageJsonPath: string): PiManifest | null {\n\ttry {\n\t\tconst content = readFileSync(packageJsonPath, \"utf-8\");\n\t\tconst pkg = JSON.parse(content) as { pi?: PiManifest; aery?: PiManifest };\n\t\treturn pkg.aery ?? pkg.pi ?? null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction resolveExtensionEntries(dir: string): string[] | null {\n\tconst packageJsonPath = join(dir, \"package.json\");\n\tif (existsSync(packageJsonPath)) {\n\t\tconst manifest = readPiManifestFile(packageJsonPath);\n\t\tif (manifest?.extensions?.length) {\n\t\t\tconst entries: string[] = [];\n\t\t\tfor (const extPath of manifest.extensions) {\n\t\t\t\tconst resolvedExtPath = resolve(dir, extPath);\n\t\t\t\tif (existsSync(resolvedExtPath)) {\n\t\t\t\t\tentries.push(resolvedExtPath);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (entries.length > 0) {\n\t\t\t\treturn entries;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst indexTs = join(dir, \"index.ts\");\n\tconst indexJs = join(dir, \"index.js\");\n\tif (existsSync(indexTs)) {\n\t\treturn [indexTs];\n\t}\n\tif (existsSync(indexJs)) {\n\t\treturn [indexJs];\n\t}\n\n\treturn null;\n}\n\nfunction collectAutoExtensionEntries(dir: string): string[] {\n\tconst entries: string[] = [];\n\tif (!existsSync(dir)) return entries;\n\n\t// First check if this directory itself has explicit extension entries (package.json or index)\n\tconst rootEntries = resolveExtensionEntries(dir);\n\tif (rootEntries) {\n\t\treturn rootEntries;\n\t}\n\n\t// Otherwise, discover extensions from directory contents\n\tconst ig = ignore();\n\taddIgnoreRules(ig, dir, dir);\n\n\ttry {\n\t\tconst dirEntries = readdirSync(dir, { withFileTypes: true });\n\t\tfor (const entry of dirEntries) {\n\t\t\tif (entry.name.startsWith(\".\")) continue;\n\t\t\tif (entry.name === \"node_modules\") continue;\n\n\t\t\tconst fullPath = join(dir, entry.name);\n\t\t\tlet isDir = entry.isDirectory();\n\t\t\tlet isFile = entry.isFile();\n\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(fullPath);\n\t\t\t\t\tisDir = stats.isDirectory();\n\t\t\t\t\tisFile = stats.isFile();\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst relPath = toPosixPath(relative(dir, fullPath));\n\t\t\tconst ignorePath = isDir ? `${relPath}/` : relPath;\n\t\t\tif (ig.ignores(ignorePath)) continue;\n\n\t\t\tif (isFile && (entry.name.endsWith(\".ts\") || entry.name.endsWith(\".js\"))) {\n\t\t\t\tentries.push(fullPath);\n\t\t\t} else if (isDir) {\n\t\t\t\tconst resolvedEntries = resolveExtensionEntries(fullPath);\n\t\t\t\tif (resolvedEntries) {\n\t\t\t\t\tentries.push(...resolvedEntries);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ignore errors\n\t}\n\n\treturn entries;\n}\n\n/**\n * Collect resource files from a directory based on resource type.\n * Extensions use smart discovery (index.ts in subdirs), others use recursive collection.\n */\nfunction collectResourceFiles(dir: string, resourceType: ResourceType): string[] {\n\tif (resourceType === \"skills\") {\n\t\treturn collectSkillEntries(dir, \"aery\");\n\t}\n\tif (resourceType === \"extensions\") {\n\t\treturn collectAutoExtensionEntries(dir);\n\t}\n\treturn collectFiles(dir, FILE_PATTERNS[resourceType]);\n}\n\nfunction matchesAnyPattern(filePath: string, patterns: string[], baseDir: string): boolean {\n\tconst rel = toPosixPath(relative(baseDir, filePath));\n\tconst name = basename(filePath);\n\tconst filePathPosix = toPosixPath(filePath);\n\tconst isSkillFile = name === \"SKILL.md\";\n\tconst parentDir = isSkillFile ? dirname(filePath) : undefined;\n\tconst parentRel = isSkillFile ? toPosixPath(relative(baseDir, parentDir!)) : undefined;\n\tconst parentName = isSkillFile ? basename(parentDir!) : undefined;\n\tconst parentDirPosix = isSkillFile ? toPosixPath(parentDir!) : undefined;\n\n\treturn patterns.some((pattern) => {\n\t\tconst normalizedPattern = toPosixPath(pattern);\n\t\tif (\n\t\t\tminimatch(rel, normalizedPattern) ||\n\t\t\tminimatch(name, normalizedPattern) ||\n\t\t\tminimatch(filePathPosix, normalizedPattern)\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!isSkillFile) return false;\n\t\treturn (\n\t\t\tminimatch(parentRel!, normalizedPattern) ||\n\t\t\tminimatch(parentName!, normalizedPattern) ||\n\t\t\tminimatch(parentDirPosix!, normalizedPattern)\n\t\t);\n\t});\n}\n\nfunction normalizeExactPattern(pattern: string): string {\n\tconst normalized = pattern.startsWith(\"./\") || pattern.startsWith(\".\\\\\") ? pattern.slice(2) : pattern;\n\treturn toPosixPath(normalized);\n}\n\nfunction matchesAnyExactPattern(filePath: string, patterns: string[], baseDir: string): boolean {\n\tif (patterns.length === 0) return false;\n\tconst rel = toPosixPath(relative(baseDir, filePath));\n\tconst name = basename(filePath);\n\tconst filePathPosix = toPosixPath(filePath);\n\tconst isSkillFile = name === \"SKILL.md\";\n\tconst parentDir = isSkillFile ? dirname(filePath) : undefined;\n\tconst parentRel = isSkillFile ? toPosixPath(relative(baseDir, parentDir!)) : undefined;\n\tconst parentDirPosix = isSkillFile ? toPosixPath(parentDir!) : undefined;\n\n\treturn patterns.some((pattern) => {\n\t\tconst normalized = normalizeExactPattern(pattern);\n\t\tif (normalized === rel || normalized === filePathPosix) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!isSkillFile) return false;\n\t\treturn normalized === parentRel || normalized === parentDirPosix;\n\t});\n}\n\nfunction getOverridePatterns(entries: string[]): string[] {\n\treturn entries.filter((pattern) => pattern.startsWith(\"!\") || pattern.startsWith(\"+\") || pattern.startsWith(\"-\"));\n}\n\nfunction isEnabledByOverrides(filePath: string, patterns: string[], baseDir: string): boolean {\n\tconst overrides = getOverridePatterns(patterns);\n\tconst excludes = overrides.filter((pattern) => pattern.startsWith(\"!\")).map((pattern) => pattern.slice(1));\n\tconst forceIncludes = overrides.filter((pattern) => pattern.startsWith(\"+\")).map((pattern) => pattern.slice(1));\n\tconst forceExcludes = overrides.filter((pattern) => pattern.startsWith(\"-\")).map((pattern) => pattern.slice(1));\n\n\tlet enabled = true;\n\tif (excludes.length > 0 && matchesAnyPattern(filePath, excludes, baseDir)) {\n\t\tenabled = false;\n\t}\n\tif (forceIncludes.length > 0 && matchesAnyExactPattern(filePath, forceIncludes, baseDir)) {\n\t\tenabled = true;\n\t}\n\tif (forceExcludes.length > 0 && matchesAnyExactPattern(filePath, forceExcludes, baseDir)) {\n\t\tenabled = false;\n\t}\n\treturn enabled;\n}\n\n/**\n * Apply patterns to paths and return a Set of enabled paths.\n * Pattern types:\n * - Plain patterns: include matching paths\n * - `!pattern`: exclude matching paths\n * - `+path`: force-include exact path (overrides exclusions)\n * - `-path`: force-exclude exact path (overrides force-includes)\n */\nfunction applyPatterns(allPaths: string[], patterns: string[], baseDir: string): Set<string> {\n\tconst includes: string[] = [];\n\tconst excludes: string[] = [];\n\tconst forceIncludes: string[] = [];\n\tconst forceExcludes: string[] = [];\n\n\tfor (const p of patterns) {\n\t\tif (p.startsWith(\"+\")) {\n\t\t\tforceIncludes.push(p.slice(1));\n\t\t} else if (p.startsWith(\"-\")) {\n\t\t\tforceExcludes.push(p.slice(1));\n\t\t} else if (p.startsWith(\"!\")) {\n\t\t\texcludes.push(p.slice(1));\n\t\t} else {\n\t\t\tincludes.push(p);\n\t\t}\n\t}\n\n\t// Step 1: Apply includes (or all if no includes)\n\tlet result: string[];\n\tif (includes.length === 0) {\n\t\tresult = [...allPaths];\n\t} else {\n\t\tresult = allPaths.filter((filePath) => matchesAnyPattern(filePath, includes, baseDir));\n\t}\n\n\t// Step 2: Apply excludes\n\tif (excludes.length > 0) {\n\t\tresult = result.filter((filePath) => !matchesAnyPattern(filePath, excludes, baseDir));\n\t}\n\n\t// Step 3: Force-include (add back from allPaths, overriding exclusions)\n\tif (forceIncludes.length > 0) {\n\t\tfor (const filePath of allPaths) {\n\t\t\tif (!result.includes(filePath) && matchesAnyExactPattern(filePath, forceIncludes, baseDir)) {\n\t\t\t\tresult.push(filePath);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Step 4: Force-exclude (remove even if included or force-included)\n\tif (forceExcludes.length > 0) {\n\t\tresult = result.filter((filePath) => !matchesAnyExactPattern(filePath, forceExcludes, baseDir));\n\t}\n\n\treturn new Set(result);\n}\n\nexport class DefaultPackageManager implements PackageManager {\n\tprivate cwd: string;\n\tprivate agentDir: string;\n\tprivate settingsManager: SettingsManager;\n\tprivate globalNpmRoot: string | undefined;\n\tprivate globalNpmRootCommandKey: string | undefined;\n\tprivate progressCallback: ProgressCallback | undefined;\n\n\tconstructor(options: PackageManagerOptions) {\n\t\tthis.cwd = options.cwd;\n\t\tthis.agentDir = options.agentDir;\n\t\tthis.settingsManager = options.settingsManager;\n\t}\n\n\tsetProgressCallback(callback: ProgressCallback | undefined): void {\n\t\tthis.progressCallback = callback;\n\t}\n\n\taddSourceToSettings(source: string, options?: { local?: boolean }): boolean {\n\t\tconst scope: SourceScope = options?.local ? \"project\" : \"user\";\n\t\tconst currentSettings =\n\t\t\tscope === \"project\" ? this.settingsManager.getProjectSettings() : this.settingsManager.getGlobalSettings();\n\t\tconst currentPackages = currentSettings.packages ?? [];\n\t\tconst normalizedSource = this.normalizePackageSourceForSettings(source, scope);\n\t\tconst exists = currentPackages.some((existing) => this.packageSourcesMatch(existing, source, scope));\n\t\tif (exists) {\n\t\t\treturn false;\n\t\t}\n\t\tconst nextPackages = [...currentPackages, normalizedSource];\n\t\tif (scope === \"project\") {\n\t\t\tthis.settingsManager.setProjectPackages(nextPackages);\n\t\t} else {\n\t\t\tthis.settingsManager.setPackages(nextPackages);\n\t\t}\n\t\treturn true;\n\t}\n\n\tremoveSourceFromSettings(source: string, options?: { local?: boolean }): boolean {\n\t\tconst scope: SourceScope = options?.local ? \"project\" : \"user\";\n\t\tconst currentSettings =\n\t\t\tscope === \"project\" ? this.settingsManager.getProjectSettings() : this.settingsManager.getGlobalSettings();\n\t\tconst currentPackages = currentSettings.packages ?? [];\n\t\tconst nextPackages = currentPackages.filter((existing) => !this.packageSourcesMatch(existing, source, scope));\n\t\tconst changed = nextPackages.length !== currentPackages.length;\n\t\tif (!changed) {\n\t\t\treturn false;\n\t\t}\n\t\tif (scope === \"project\") {\n\t\t\tthis.settingsManager.setProjectPackages(nextPackages);\n\t\t} else {\n\t\t\tthis.settingsManager.setPackages(nextPackages);\n\t\t}\n\t\treturn true;\n\t}\n\n\tgetInstalledPath(source: string, scope: \"user\" | \"project\"): string | undefined {\n\t\tconst parsed = this.parseSource(source);\n\t\tif (parsed.type === \"npm\") {\n\t\t\tconst path = this.getNpmInstallPath(parsed, scope);\n\t\t\treturn existsSync(path) ? path : undefined;\n\t\t}\n\t\tif (parsed.type === \"git\") {\n\t\t\tconst path = this.getGitInstallPath(parsed, scope);\n\t\t\treturn existsSync(path) ? path : undefined;\n\t\t}\n\t\tif (parsed.type === \"local\") {\n\t\t\tconst baseDir = this.getBaseDirForScope(scope);\n\t\t\tconst path = this.resolvePathFromBase(parsed.path, baseDir);\n\t\t\treturn existsSync(path) ? path : undefined;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate emitProgress(event: ProgressEvent): void {\n\t\tthis.progressCallback?.(event);\n\t}\n\n\tprivate async withProgress(\n\t\taction: ProgressEvent[\"action\"],\n\t\tsource: string,\n\t\tmessage: string,\n\t\toperation: () => Promise<void>,\n\t): Promise<void> {\n\t\tthis.emitProgress({ type: \"start\", action, source, message });\n\t\ttry {\n\t\t\tawait operation();\n\t\t\tthis.emitProgress({ type: \"complete\", action, source });\n\t\t} catch (error) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tthis.emitProgress({ type: \"error\", action, source, message: errorMessage });\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync resolve(onMissing?: (source: string) => Promise<MissingSourceAction>): Promise<ResolvedPaths> {\n\t\tconst accumulator = this.createAccumulator();\n\t\tconst globalSettings = this.settingsManager.getGlobalSettings();\n\t\tconst projectSettings = this.settingsManager.getProjectSettings();\n\n\t\t// Collect all packages with scope (project first so cwd resources win collisions)\n\t\tconst allPackages: Array<{ pkg: PackageSource; scope: SourceScope }> = [];\n\t\tfor (const pkg of projectSettings.packages ?? []) {\n\t\t\tallPackages.push({ pkg, scope: \"project\" });\n\t\t}\n\t\tfor (const pkg of globalSettings.packages ?? []) {\n\t\t\tallPackages.push({ pkg, scope: \"user\" });\n\t\t}\n\n\t\t// Dedupe: project scope wins over global for same package identity\n\t\tconst packageSources = this.dedupePackages(allPackages);\n\t\tawait this.resolvePackageSources(packageSources, accumulator, onMissing);\n\n\t\tconst globalBaseDir = this.agentDir;\n\t\tconst projectBaseDir = join(this.cwd, CONFIG_DIR_NAME);\n\n\t\tfor (const resourceType of RESOURCE_TYPES) {\n\t\t\tconst target = this.getTargetMap(accumulator, resourceType);\n\t\t\tconst globalEntries = (globalSettings[resourceType] ?? []) as string[];\n\t\t\tconst projectEntries = (projectSettings[resourceType] ?? []) as string[];\n\t\t\tthis.resolveLocalEntries(\n\t\t\t\tprojectEntries,\n\t\t\t\tresourceType,\n\t\t\t\ttarget,\n\t\t\t\t{\n\t\t\t\t\tsource: \"local\",\n\t\t\t\t\tscope: \"project\",\n\t\t\t\t\torigin: \"top-level\",\n\t\t\t\t},\n\t\t\t\tprojectBaseDir,\n\t\t\t);\n\t\t\tthis.resolveLocalEntries(\n\t\t\t\tglobalEntries,\n\t\t\t\tresourceType,\n\t\t\t\ttarget,\n\t\t\t\t{\n\t\t\t\t\tsource: \"local\",\n\t\t\t\t\tscope: \"user\",\n\t\t\t\t\torigin: \"top-level\",\n\t\t\t\t},\n\t\t\t\tglobalBaseDir,\n\t\t\t);\n\t\t}\n\n\t\tthis.addAutoDiscoveredResources(accumulator, globalSettings, projectSettings, globalBaseDir, projectBaseDir);\n\n\t\treturn this.toResolvedPaths(accumulator);\n\t}\n\n\tasync resolveExtensionSources(\n\t\tsources: string[],\n\t\toptions?: { local?: boolean; temporary?: boolean },\n\t): Promise<ResolvedPaths> {\n\t\tconst accumulator = this.createAccumulator();\n\t\tconst scope: SourceScope = options?.temporary ? \"temporary\" : options?.local ? \"project\" : \"user\";\n\t\tconst packageSources = sources.map((source) => ({ pkg: source as PackageSource, scope }));\n\t\tawait this.resolvePackageSources(packageSources, accumulator);\n\t\treturn this.toResolvedPaths(accumulator);\n\t}\n\n\tlistConfiguredPackages(): ConfiguredPackage[] {\n\t\tconst globalSettings = this.settingsManager.getGlobalSettings();\n\t\tconst projectSettings = this.settingsManager.getProjectSettings();\n\t\tconst configuredPackages: ConfiguredPackage[] = [];\n\n\t\tfor (const pkg of globalSettings.packages ?? []) {\n\t\t\tconst source = typeof pkg === \"string\" ? pkg : pkg.source;\n\t\t\tconfiguredPackages.push({\n\t\t\t\tsource,\n\t\t\t\tscope: \"user\",\n\t\t\t\tfiltered: typeof pkg === \"object\",\n\t\t\t\tinstalledPath: this.getInstalledPath(source, \"user\"),\n\t\t\t});\n\t\t}\n\n\t\tfor (const pkg of projectSettings.packages ?? []) {\n\t\t\tconst source = typeof pkg === \"string\" ? pkg : pkg.source;\n\t\t\tconfiguredPackages.push({\n\t\t\t\tsource,\n\t\t\t\tscope: \"project\",\n\t\t\t\tfiltered: typeof pkg === \"object\",\n\t\t\t\tinstalledPath: this.getInstalledPath(source, \"project\"),\n\t\t\t});\n\t\t}\n\n\t\treturn configuredPackages;\n\t}\n\n\tasync install(source: string, options?: { local?: boolean }): Promise<void> {\n\t\tconst parsed = this.parseSource(source);\n\t\tconst scope: SourceScope = options?.local ? \"project\" : \"user\";\n\t\tawait this.withProgress(\"install\", source, `Installing ${source}...`, async () => {\n\t\t\tif (parsed.type === \"npm\") {\n\t\t\t\tawait this.installNpm(parsed, scope, false);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (parsed.type === \"git\") {\n\t\t\t\tawait this.installGit(parsed, scope);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (parsed.type === \"local\") {\n\t\t\t\tconst resolved = this.resolvePath(parsed.path);\n\t\t\t\tif (!existsSync(resolved)) {\n\t\t\t\t\tthrow new Error(`Path does not exist: ${resolved}`);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new Error(`Unsupported install source: ${source}`);\n\t\t});\n\t}\n\n\tasync installAndPersist(source: string, options?: { local?: boolean }): Promise<void> {\n\t\tawait this.install(source, options);\n\t\tthis.addSourceToSettings(source, options);\n\t}\n\n\tasync remove(source: string, options?: { local?: boolean }): Promise<void> {\n\t\tconst parsed = this.parseSource(source);\n\t\tconst scope: SourceScope = options?.local ? \"project\" : \"user\";\n\t\tawait this.withProgress(\"remove\", source, `Removing ${source}...`, async () => {\n\t\t\tif (parsed.type === \"npm\") {\n\t\t\t\tawait this.uninstallNpm(parsed, scope);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (parsed.type === \"git\") {\n\t\t\t\tawait this.removeGit(parsed, scope);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (parsed.type === \"local\") {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new Error(`Unsupported remove source: ${source}`);\n\t\t});\n\t}\n\n\tasync removeAndPersist(source: string, options?: { local?: boolean }): Promise<boolean> {\n\t\tawait this.remove(source, options);\n\t\treturn this.removeSourceFromSettings(source, options);\n\t}\n\n\tasync update(source?: string): Promise<void> {\n\t\tconst globalSettings = this.settingsManager.getGlobalSettings();\n\t\tconst projectSettings = this.settingsManager.getProjectSettings();\n\t\tconst identity = source ? this.getPackageIdentity(source) : undefined;\n\t\tlet matched = false;\n\t\tconst updateSources: ConfiguredUpdateSource[] = [];\n\n\t\tfor (const pkg of globalSettings.packages ?? []) {\n\t\t\tconst sourceStr = typeof pkg === \"string\" ? pkg : pkg.source;\n\t\t\tif (identity && this.getPackageIdentity(sourceStr, \"user\") !== identity) continue;\n\t\t\tmatched = true;\n\t\t\tupdateSources.push({ source: sourceStr, scope: \"user\" });\n\t\t}\n\t\tfor (const pkg of projectSettings.packages ?? []) {\n\t\t\tconst sourceStr = typeof pkg === \"string\" ? pkg : pkg.source;\n\t\t\tif (identity && this.getPackageIdentity(sourceStr, \"project\") !== identity) continue;\n\t\t\tmatched = true;\n\t\t\tupdateSources.push({ source: sourceStr, scope: \"project\" });\n\t\t}\n\n\t\tif (source && !matched) {\n\t\t\tthrow new Error(\n\t\t\t\tthis.buildNoMatchingPackageMessage(source, [\n\t\t\t\t\t...(globalSettings.packages ?? []),\n\t\t\t\t\t...(projectSettings.packages ?? []),\n\t\t\t\t]),\n\t\t\t);\n\t\t}\n\n\t\tawait this.updateConfiguredSources(updateSources);\n\t}\n\n\tprivate async updateConfiguredSources(sources: ConfiguredUpdateSource[]): Promise<void> {\n\t\tif (isOfflineModeEnabled() || sources.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst npmCandidates: NpmUpdateTarget[] = [];\n\t\tconst gitCandidates: GitUpdateTarget[] = [];\n\n\t\tfor (const entry of sources) {\n\t\t\tconst parsed = this.parseSource(entry.source);\n\t\t\tif (parsed.type === \"local\" || parsed.pinned) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (parsed.type === \"npm\") {\n\t\t\t\tnpmCandidates.push({ ...entry, parsed });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tgitCandidates.push({ ...entry, parsed });\n\t\t}\n\n\t\tconst npmCheckTasks = npmCandidates.map((entry) => async () => ({\n\t\t\tentry,\n\t\t\tshouldUpdate: await this.shouldUpdateNpmSource(entry.parsed, entry.scope),\n\t\t}));\n\t\tconst npmCheckResults = await this.runWithConcurrency(npmCheckTasks, UPDATE_CHECK_CONCURRENCY);\n\t\tconst userNpmUpdates: NpmUpdateTarget[] = [];\n\t\tconst projectNpmUpdates: NpmUpdateTarget[] = [];\n\t\tfor (const result of npmCheckResults) {\n\t\t\tif (!result.shouldUpdate) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (result.entry.scope === \"user\") {\n\t\t\t\tuserNpmUpdates.push(result.entry);\n\t\t\t} else {\n\t\t\t\tprojectNpmUpdates.push(result.entry);\n\t\t\t}\n\t\t}\n\n\t\tconst tasks: Promise<void>[] = [];\n\t\tif (userNpmUpdates.length > 0) {\n\t\t\ttasks.push(this.updateNpmBatch(userNpmUpdates, \"user\"));\n\t\t}\n\t\tif (projectNpmUpdates.length > 0) {\n\t\t\ttasks.push(this.updateNpmBatch(projectNpmUpdates, \"project\"));\n\t\t}\n\t\tif (gitCandidates.length > 0) {\n\t\t\tconst gitTasks = gitCandidates.map(\n\t\t\t\t(entry) => async () =>\n\t\t\t\t\tthis.withProgress(\"update\", entry.source, `Updating ${entry.source}...`, async () => {\n\t\t\t\t\t\tawait this.updateGit(entry.parsed, entry.scope);\n\t\t\t\t\t}),\n\t\t\t);\n\t\t\ttasks.push(this.runWithConcurrency(gitTasks, GIT_UPDATE_CONCURRENCY).then(() => {}));\n\t\t}\n\n\t\tawait Promise.all(tasks);\n\t}\n\n\tprivate async shouldUpdateNpmSource(source: NpmSource, scope: InstalledSourceScope): Promise<boolean> {\n\t\tconst installedPath = this.getNpmInstallPath(source, scope);\n\t\tconst installedVersion = existsSync(installedPath) ? this.getInstalledNpmVersion(installedPath) : undefined;\n\t\tif (!installedVersion) {\n\t\t\treturn true;\n\t\t}\n\n\t\ttry {\n\t\t\tconst latestVersion = await this.getLatestNpmVersion(source.name);\n\t\t\treturn latestVersion !== installedVersion;\n\t\t} catch {\n\t\t\t// Preserve existing update behavior when version lookup fails.\n\t\t\treturn true;\n\t\t}\n\t}\n\n\tprivate async updateNpmBatch(sources: NpmUpdateTarget[], scope: InstalledSourceScope): Promise<void> {\n\t\tif (sources.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst sourceLabel = sources.length === 1 ? sources[0].source : `${scope} npm packages`;\n\t\tconst message = sources.length === 1 ? `Updating ${sources[0].source}...` : `Updating ${scope} npm packages...`;\n\t\tconst specs = sources.map((entry) => `${entry.parsed.name}@latest`);\n\n\t\tawait this.withProgress(\"update\", sourceLabel, message, async () => {\n\t\t\tawait this.installNpmBatch(specs, scope);\n\t\t});\n\t}\n\n\tprivate async installNpmBatch(specs: string[], scope: InstalledSourceScope): Promise<void> {\n\t\tif (scope === \"user\") {\n\t\t\tawait this.runNpmCommand([\"install\", \"-g\", ...specs]);\n\t\t\treturn;\n\t\t}\n\t\tconst installRoot = this.getNpmInstallRoot(scope, false);\n\t\tthis.ensureNpmProject(installRoot);\n\t\tawait this.runNpmCommand([\"install\", ...specs, \"--prefix\", installRoot]);\n\t}\n\n\tasync checkForAvailableUpdates(): Promise<PackageUpdate[]> {\n\t\tif (isOfflineModeEnabled()) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst globalSettings = this.settingsManager.getGlobalSettings();\n\t\tconst projectSettings = this.settingsManager.getProjectSettings();\n\t\tconst allPackages: Array<{ pkg: PackageSource; scope: SourceScope }> = [];\n\t\tfor (const pkg of projectSettings.packages ?? []) {\n\t\t\tallPackages.push({ pkg, scope: \"project\" });\n\t\t}\n\t\tfor (const pkg of globalSettings.packages ?? []) {\n\t\t\tallPackages.push({ pkg, scope: \"user\" });\n\t\t}\n\n\t\tconst packageSources = this.dedupePackages(allPackages);\n\t\tconst checks = packageSources\n\t\t\t.filter(\n\t\t\t\t(entry): entry is { pkg: PackageSource; scope: Exclude<SourceScope, \"temporary\"> } =>\n\t\t\t\t\tentry.scope !== \"temporary\",\n\t\t\t)\n\t\t\t.map((entry) => async (): Promise<PackageUpdate | undefined> => {\n\t\t\t\tconst source = typeof entry.pkg === \"string\" ? entry.pkg : entry.pkg.source;\n\t\t\t\tconst parsed = this.parseSource(source);\n\t\t\t\tif (parsed.type === \"local\" || parsed.pinned) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\tif (parsed.type === \"npm\") {\n\t\t\t\t\tconst installedPath = this.getNpmInstallPath(parsed, entry.scope);\n\t\t\t\t\tif (!existsSync(installedPath)) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\tconst hasUpdate = await this.npmHasAvailableUpdate(parsed, installedPath);\n\t\t\t\t\tif (!hasUpdate) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsource,\n\t\t\t\t\t\tdisplayName: parsed.name,\n\t\t\t\t\t\ttype: \"npm\",\n\t\t\t\t\t\tscope: entry.scope,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst installedPath = this.getGitInstallPath(parsed, entry.scope);\n\t\t\t\tif (!existsSync(installedPath)) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tconst hasUpdate = await this.gitHasAvailableUpdate(installedPath);\n\t\t\t\tif (!hasUpdate) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tsource,\n\t\t\t\t\tdisplayName: `${parsed.host}/${parsed.path}`,\n\t\t\t\t\ttype: \"git\",\n\t\t\t\t\tscope: entry.scope,\n\t\t\t\t};\n\t\t\t});\n\n\t\tconst results = await this.runWithConcurrency(checks, UPDATE_CHECK_CONCURRENCY);\n\t\treturn results.filter((result): result is PackageUpdate => result !== undefined);\n\t}\n\n\tprivate async resolvePackageSources(\n\t\tsources: Array<{ pkg: PackageSource; scope: SourceScope }>,\n\t\taccumulator: ResourceAccumulator,\n\t\tonMissing?: (source: string) => Promise<MissingSourceAction>,\n\t): Promise<void> {\n\t\tfor (const { pkg, scope } of sources) {\n\t\t\tconst sourceStr = typeof pkg === \"string\" ? pkg : pkg.source;\n\t\t\tconst filter = typeof pkg === \"object\" ? pkg : undefined;\n\t\t\tconst parsed = this.parseSource(sourceStr);\n\t\t\tconst metadata: PathMetadata = { source: sourceStr, scope, origin: \"package\" };\n\n\t\t\tif (parsed.type === \"local\") {\n\t\t\t\tconst baseDir = this.getBaseDirForScope(scope);\n\t\t\t\tthis.resolveLocalExtensionSource(parsed, accumulator, filter, metadata, baseDir);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst installMissing = async (): Promise<boolean> => {\n\t\t\t\tif (isOfflineModeEnabled()) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif (!onMissing) {\n\t\t\t\t\tawait this.installParsedSource(parsed, scope);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tconst action = await onMissing(sourceStr);\n\t\t\t\tif (action === \"skip\") return false;\n\t\t\t\tif (action === \"error\") throw new Error(`Missing source: ${sourceStr}`);\n\t\t\t\tawait this.installParsedSource(parsed, scope);\n\t\t\t\treturn true;\n\t\t\t};\n\n\t\t\tif (parsed.type === \"npm\") {\n\t\t\t\tconst installedPath = this.getNpmInstallPath(parsed, scope);\n\t\t\t\tconst needsInstall =\n\t\t\t\t\t!existsSync(installedPath) ||\n\t\t\t\t\t(parsed.pinned && !(await this.installedNpmMatchesPinnedVersion(parsed, installedPath)));\n\t\t\t\tif (needsInstall) {\n\t\t\t\t\tconst installed = await installMissing();\n\t\t\t\t\tif (!installed) continue;\n\t\t\t\t}\n\t\t\t\tmetadata.baseDir = installedPath;\n\t\t\t\tthis.collectPackageResources(installedPath, accumulator, filter, metadata);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (parsed.type === \"git\") {\n\t\t\t\tconst installedPath = this.getGitInstallPath(parsed, scope);\n\t\t\t\tif (!existsSync(installedPath)) {\n\t\t\t\t\tconst installed = await installMissing();\n\t\t\t\t\tif (!installed) continue;\n\t\t\t\t} else if (scope === \"temporary\" && !parsed.pinned && !isOfflineModeEnabled()) {\n\t\t\t\t\tawait this.refreshTemporaryGitSource(parsed, sourceStr);\n\t\t\t\t}\n\t\t\t\tmetadata.baseDir = installedPath;\n\t\t\t\tthis.collectPackageResources(installedPath, accumulator, filter, metadata);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate resolveLocalExtensionSource(\n\t\tsource: LocalSource,\n\t\taccumulator: ResourceAccumulator,\n\t\tfilter: PackageFilter | undefined,\n\t\tmetadata: PathMetadata,\n\t\tbaseDir: string,\n\t): void {\n\t\tconst resolved = this.resolvePathFromBase(source.path, baseDir);\n\t\tif (!existsSync(resolved)) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst stats = statSync(resolved);\n\t\t\tif (stats.isFile()) {\n\t\t\t\tmetadata.baseDir = dirname(resolved);\n\t\t\t\tthis.addResource(accumulator.extensions, resolved, metadata, true);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\tmetadata.baseDir = resolved;\n\t\t\t\tconst resources = this.collectPackageResources(resolved, accumulator, filter, metadata);\n\t\t\t\tif (!resources) {\n\t\t\t\t\tthis.addResource(accumulator.extensions, resolved, metadata, true);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tprivate async installParsedSource(parsed: ParsedSource, scope: SourceScope): Promise<void> {\n\t\tif (parsed.type === \"npm\") {\n\t\t\tawait this.installNpm(parsed, scope, scope === \"temporary\");\n\t\t\treturn;\n\t\t}\n\t\tif (parsed.type === \"git\") {\n\t\t\tawait this.installGit(parsed, scope);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tprivate getPackageSourceString(pkg: PackageSource): string {\n\t\treturn typeof pkg === \"string\" ? pkg : pkg.source;\n\t}\n\n\tprivate getSourceMatchKeyForInput(source: string): string {\n\t\tconst parsed = this.parseSource(source);\n\t\tif (parsed.type === \"npm\") {\n\t\t\treturn `npm:${parsed.name}`;\n\t\t}\n\t\tif (parsed.type === \"git\") {\n\t\t\treturn `git:${parsed.host}/${parsed.path}`;\n\t\t}\n\t\treturn `local:${this.resolvePath(parsed.path)}`;\n\t}\n\n\tprivate getSourceMatchKeyForSettings(source: string, scope: SourceScope): string {\n\t\tconst parsed = this.parseSource(source);\n\t\tif (parsed.type === \"npm\") {\n\t\t\treturn `npm:${parsed.name}`;\n\t\t}\n\t\tif (parsed.type === \"git\") {\n\t\t\treturn `git:${parsed.host}/${parsed.path}`;\n\t\t}\n\t\tconst baseDir = this.getBaseDirForScope(scope);\n\t\treturn `local:${this.resolvePathFromBase(parsed.path, baseDir)}`;\n\t}\n\n\tprivate buildNoMatchingPackageMessage(source: string, configuredPackages: PackageSource[]): string {\n\t\tconst suggestion = this.findSuggestedConfiguredSource(source, configuredPackages);\n\t\tif (!suggestion) {\n\t\t\treturn `No matching package found for ${source}`;\n\t\t}\n\t\treturn `No matching package found for ${source}. Did you mean ${suggestion}?`;\n\t}\n\n\tprivate findSuggestedConfiguredSource(source: string, configuredPackages: PackageSource[]): string | undefined {\n\t\tconst trimmedSource = source.trim();\n\t\tconst suggestions = new Set<string>();\n\n\t\tfor (const pkg of configuredPackages) {\n\t\t\tconst sourceStr = this.getPackageSourceString(pkg);\n\t\t\tconst parsed = this.parseSource(sourceStr);\n\t\t\tif (parsed.type === \"npm\") {\n\t\t\t\tif (trimmedSource === parsed.name || trimmedSource === parsed.spec) {\n\t\t\t\t\tsuggestions.add(sourceStr);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (parsed.type === \"git\") {\n\t\t\t\tconst shorthand = `${parsed.host}/${parsed.path}`;\n\t\t\t\tconst shorthandWithRef = parsed.ref ? `${shorthand}@${parsed.ref}` : undefined;\n\t\t\t\tif (trimmedSource === shorthand || (shorthandWithRef && trimmedSource === shorthandWithRef)) {\n\t\t\t\t\tsuggestions.add(sourceStr);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn suggestions.values().next().value;\n\t}\n\n\tprivate packageSourcesMatch(existing: PackageSource, inputSource: string, scope: SourceScope): boolean {\n\t\tconst left = this.getSourceMatchKeyForSettings(this.getPackageSourceString(existing), scope);\n\t\tconst right = this.getSourceMatchKeyForInput(inputSource);\n\t\treturn left === right;\n\t}\n\n\tprivate normalizePackageSourceForSettings(source: string, scope: SourceScope): string {\n\t\tconst parsed = this.parseSource(source);\n\t\tif (parsed.type !== \"local\") {\n\t\t\treturn source;\n\t\t}\n\t\tconst baseDir = this.getBaseDirForScope(scope);\n\t\tconst resolved = this.resolvePath(parsed.path);\n\t\tconst rel = relative(baseDir, resolved);\n\t\treturn rel || \".\";\n\t}\n\n\tprivate parseSource(source: string): ParsedSource {\n\t\tif (source.startsWith(\"npm:\")) {\n\t\t\tconst spec = source.slice(\"npm:\".length).trim();\n\t\t\tconst { name, version } = this.parseNpmSpec(spec);\n\t\t\treturn {\n\t\t\t\ttype: \"npm\",\n\t\t\t\tspec,\n\t\t\t\tname,\n\t\t\t\tpinned: Boolean(version),\n\t\t\t};\n\t\t}\n\n\t\tif (isLocalPath(source)) {\n\t\t\treturn { type: \"local\", path: source };\n\t\t}\n\n\t\t// Try parsing as git URL\n\t\tconst gitParsed = parseGitUrl(source);\n\t\tif (gitParsed) {\n\t\t\treturn gitParsed;\n\t\t}\n\n\t\treturn { type: \"local\", path: source };\n\t}\n\n\tprivate async installedNpmMatchesPinnedVersion(source: NpmSource, installedPath: string): Promise<boolean> {\n\t\tconst installedVersion = this.getInstalledNpmVersion(installedPath);\n\t\tif (!installedVersion) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst { version: pinnedVersion } = this.parseNpmSpec(source.spec);\n\t\tif (!pinnedVersion) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn installedVersion === pinnedVersion;\n\t}\n\n\tprivate async npmHasAvailableUpdate(source: NpmSource, installedPath: string): Promise<boolean> {\n\t\tif (isOfflineModeEnabled()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst installedVersion = this.getInstalledNpmVersion(installedPath);\n\t\tif (!installedVersion) {\n\t\t\treturn false;\n\t\t}\n\n\t\ttry {\n\t\t\tconst latestVersion = await this.getLatestNpmVersion(source.name);\n\t\t\treturn latestVersion !== installedVersion;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate getInstalledNpmVersion(installedPath: string): string | undefined {\n\t\tconst packageJsonPath = join(installedPath, \"package.json\");\n\t\tif (!existsSync(packageJsonPath)) return undefined;\n\t\ttry {\n\t\t\tconst content = readFileSync(packageJsonPath, \"utf-8\");\n\t\t\tconst pkg = JSON.parse(content) as { version?: string };\n\t\t\treturn pkg.version;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate async getLatestNpmVersion(packageName: string): Promise<string> {\n\t\tconst npmCommand = this.getNpmCommand();\n\t\tconst stdout = await this.runCommandCapture(\n\t\t\tnpmCommand.command,\n\t\t\t[...npmCommand.args, \"view\", packageName, \"version\", \"--json\"],\n\t\t\t{ cwd: this.cwd, timeoutMs: NETWORK_TIMEOUT_MS },\n\t\t);\n\t\tconst raw = stdout.trim();\n\t\tif (!raw) throw new Error(\"Empty response from npm view\");\n\t\treturn JSON.parse(raw);\n\t}\n\n\tprivate async gitHasAvailableUpdate(installedPath: string): Promise<boolean> {\n\t\tif (isOfflineModeEnabled()) {\n\t\t\treturn false;\n\t\t}\n\n\t\ttry {\n\t\t\tconst localHead = await this.runCommandCapture(\"git\", [\"rev-parse\", \"HEAD\"], {\n\t\t\t\tcwd: installedPath,\n\t\t\t\ttimeoutMs: NETWORK_TIMEOUT_MS,\n\t\t\t});\n\t\t\tconst remoteHead = await this.getRemoteGitHead(installedPath);\n\t\t\treturn localHead.trim() !== remoteHead.trim();\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate async getRemoteGitHead(installedPath: string): Promise<string> {\n\t\tconst upstreamRef = await this.getGitUpstreamRef(installedPath);\n\t\tif (upstreamRef) {\n\t\t\tconst remoteHead = await this.runGitRemoteCommand(installedPath, [\"ls-remote\", \"origin\", upstreamRef]);\n\t\t\tconst match = remoteHead.match(/^([0-9a-f]{40})\\s+/m);\n\t\t\tif (match?.[1]) {\n\t\t\t\treturn match[1];\n\t\t\t}\n\t\t}\n\n\t\tconst remoteHead = await this.runGitRemoteCommand(installedPath, [\"ls-remote\", \"origin\", \"HEAD\"]);\n\t\tconst match = remoteHead.match(/^([0-9a-f]{40})\\s+HEAD$/m);\n\t\tif (!match?.[1]) {\n\t\t\tthrow new Error(\"Failed to determine remote HEAD\");\n\t\t}\n\t\treturn match[1];\n\t}\n\n\tprivate async getLocalGitUpdateTarget(\n\t\tinstalledPath: string,\n\t): Promise<{ ref: string; head: string; fetchArgs: string[] }> {\n\t\ttry {\n\t\t\tconst upstream = await this.runCommandCapture(\"git\", [\"rev-parse\", \"--abbrev-ref\", \"@{upstream}\"], {\n\t\t\t\tcwd: installedPath,\n\t\t\t\ttimeoutMs: NETWORK_TIMEOUT_MS,\n\t\t\t});\n\t\t\tconst trimmedUpstream = upstream.trim();\n\t\t\tif (!trimmedUpstream.startsWith(\"origin/\")) {\n\t\t\t\tthrow new Error(`Unsupported upstream remote: ${trimmedUpstream}`);\n\t\t\t}\n\t\t\tconst branch = trimmedUpstream.slice(\"origin/\".length);\n\t\t\tif (!branch) {\n\t\t\t\tthrow new Error(\"Missing upstream branch name\");\n\t\t\t}\n\t\t\tconst head = await this.runCommandCapture(\"git\", [\"rev-parse\", \"@{upstream}\"], {\n\t\t\t\tcwd: installedPath,\n\t\t\t\ttimeoutMs: NETWORK_TIMEOUT_MS,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tref: \"@{upstream}\",\n\t\t\t\thead,\n\t\t\t\tfetchArgs: [\n\t\t\t\t\t\"fetch\",\n\t\t\t\t\t\"--prune\",\n\t\t\t\t\t\"--no-tags\",\n\t\t\t\t\t\"origin\",\n\t\t\t\t\t`+refs/heads/${branch}:refs/remotes/origin/${branch}`,\n\t\t\t\t],\n\t\t\t};\n\t\t} catch {\n\t\t\tawait this.runCommand(\"git\", [\"remote\", \"set-head\", \"origin\", \"-a\"], { cwd: installedPath }).catch(() => {});\n\t\t\tconst head = await this.runCommandCapture(\"git\", [\"rev-parse\", \"origin/HEAD\"], {\n\t\t\t\tcwd: installedPath,\n\t\t\t\ttimeoutMs: NETWORK_TIMEOUT_MS,\n\t\t\t});\n\t\t\tconst originHeadRef = await this.runCommandCapture(\"git\", [\"symbolic-ref\", \"refs/remotes/origin/HEAD\"], {\n\t\t\t\tcwd: installedPath,\n\t\t\t\ttimeoutMs: NETWORK_TIMEOUT_MS,\n\t\t\t}).catch(() => \"\");\n\t\t\tconst branch = originHeadRef.trim().replace(/^refs\\/remotes\\/origin\\//, \"\");\n\t\t\tif (branch) {\n\t\t\t\treturn {\n\t\t\t\t\tref: \"origin/HEAD\",\n\t\t\t\t\thead,\n\t\t\t\t\tfetchArgs: [\n\t\t\t\t\t\t\"fetch\",\n\t\t\t\t\t\t\"--prune\",\n\t\t\t\t\t\t\"--no-tags\",\n\t\t\t\t\t\t\"origin\",\n\t\t\t\t\t\t`+refs/heads/${branch}:refs/remotes/origin/${branch}`,\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tref: \"origin/HEAD\",\n\t\t\t\thead,\n\t\t\t\tfetchArgs: [\"fetch\", \"--prune\", \"--no-tags\", \"origin\", \"+HEAD:refs/remotes/origin/HEAD\"],\n\t\t\t};\n\t\t}\n\t}\n\n\tprivate async getGitUpstreamRef(installedPath: string): Promise<string | undefined> {\n\t\ttry {\n\t\t\tconst upstream = await this.runCommandCapture(\"git\", [\"rev-parse\", \"--abbrev-ref\", \"@{upstream}\"], {\n\t\t\t\tcwd: installedPath,\n\t\t\t\ttimeoutMs: NETWORK_TIMEOUT_MS,\n\t\t\t});\n\t\t\tconst trimmed = upstream.trim();\n\t\t\tif (!trimmed.startsWith(\"origin/\")) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tconst branch = trimmed.slice(\"origin/\".length);\n\t\t\treturn branch ? `refs/heads/${branch}` : undefined;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate runGitRemoteCommand(installedPath: string, args: string[]): Promise<string> {\n\t\treturn this.runCommandCapture(\"git\", args, {\n\t\t\tcwd: installedPath,\n\t\t\ttimeoutMs: NETWORK_TIMEOUT_MS,\n\t\t\tenv: {\n\t\t\t\tGIT_TERMINAL_PROMPT: \"0\",\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate async runWithConcurrency<T>(tasks: Array<() => Promise<T>>, limit: number): Promise<T[]> {\n\t\tif (tasks.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst results: T[] = new Array(tasks.length);\n\t\tlet nextIndex = 0;\n\t\tconst workerCount = Math.max(1, Math.min(limit, tasks.length));\n\n\t\tconst worker = async () => {\n\t\t\twhile (true) {\n\t\t\t\tconst index = nextIndex;\n\t\t\t\tnextIndex += 1;\n\t\t\t\tif (index >= tasks.length) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tresults[index] = await tasks[index]();\n\t\t\t}\n\t\t};\n\n\t\tawait Promise.all(Array.from({ length: workerCount }, () => worker()));\n\t\treturn results;\n\t}\n\n\t/**\n\t * Get a unique identity for a package, ignoring version/ref.\n\t * Used to detect when the same package is in both global and project settings.\n\t * For git packages, uses normalized host/path to ensure SSH and HTTPS URLs\n\t * for the same repository are treated as identical.\n\t */\n\tprivate getPackageIdentity(source: string, scope?: SourceScope): string {\n\t\tconst parsed = this.parseSource(source);\n\t\tif (parsed.type === \"npm\") {\n\t\t\treturn `npm:${parsed.name}`;\n\t\t}\n\t\tif (parsed.type === \"git\") {\n\t\t\t// Use host/path for identity to normalize SSH and HTTPS\n\t\t\treturn `git:${parsed.host}/${parsed.path}`;\n\t\t}\n\t\tif (scope) {\n\t\t\tconst baseDir = this.getBaseDirForScope(scope);\n\t\t\treturn `local:${this.resolvePathFromBase(parsed.path, baseDir)}`;\n\t\t}\n\t\treturn `local:${this.resolvePath(parsed.path)}`;\n\t}\n\n\t/**\n\t * Dedupe packages: if same package identity appears in both global and project,\n\t * keep only the project one (project wins).\n\t */\n\tprivate dedupePackages(\n\t\tpackages: Array<{ pkg: PackageSource; scope: SourceScope }>,\n\t): Array<{ pkg: PackageSource; scope: SourceScope }> {\n\t\tconst seen = new Map<string, { pkg: PackageSource; scope: SourceScope }>();\n\n\t\tfor (const entry of packages) {\n\t\t\tconst sourceStr = typeof entry.pkg === \"string\" ? entry.pkg : entry.pkg.source;\n\t\t\tconst identity = this.getPackageIdentity(sourceStr, entry.scope);\n\n\t\t\tconst existing = seen.get(identity);\n\t\t\tif (!existing) {\n\t\t\t\tseen.set(identity, entry);\n\t\t\t} else if (entry.scope === \"project\" && existing.scope === \"user\") {\n\t\t\t\t// Project wins over user\n\t\t\t\tseen.set(identity, entry);\n\t\t\t}\n\t\t\t// If existing is project and new is global, keep existing (project)\n\t\t\t// If both are same scope, keep first one\n\t\t}\n\n\t\treturn Array.from(seen.values());\n\t}\n\n\tprivate parseNpmSpec(spec: string): { name: string; version?: string } {\n\t\tconst match = spec.match(/^(@?[^@]+(?:\\/[^@]+)?)(?:@(.+))?$/);\n\t\tif (!match) {\n\t\t\treturn { name: spec };\n\t\t}\n\t\tconst name = match[1] ?? spec;\n\t\tconst version = match[2];\n\t\treturn { name, version };\n\t}\n\n\tprivate getNpmCommand(): { command: string; args: string[] } {\n\t\tconst configuredCommand = this.settingsManager.getNpmCommand();\n\t\tif (!configuredCommand || configuredCommand.length === 0) {\n\t\t\treturn { command: \"npm\", args: [] };\n\t\t}\n\t\tconst [command, ...args] = configuredCommand;\n\t\tif (!command) {\n\t\t\tthrow new Error(\"Invalid npmCommand: first array entry must be a non-empty command\");\n\t\t}\n\t\treturn { command, args };\n\t}\n\n\tprivate async runNpmCommand(args: string[], options?: { cwd?: string }): Promise<void> {\n\t\tconst npmCommand = this.getNpmCommand();\n\t\tawait this.runCommand(npmCommand.command, [...npmCommand.args, ...args], options);\n\t}\n\n\tprivate getGitDependencyInstallArgs(): string[] {\n\t\tconst configuredCommand = this.settingsManager.getNpmCommand();\n\t\tif (configuredCommand && configuredCommand.length > 0) {\n\t\t\treturn [\"install\"];\n\t\t}\n\t\treturn [\"install\", \"--omit=dev\"];\n\t}\n\n\tprivate runNpmCommandSync(args: string[]): string {\n\t\tconst npmCommand = this.getNpmCommand();\n\t\treturn this.runCommandSync(npmCommand.command, [...npmCommand.args, ...args]);\n\t}\n\n\tprivate async installNpm(source: NpmSource, scope: SourceScope, temporary: boolean): Promise<void> {\n\t\tif (scope === \"user\" && !temporary) {\n\t\t\tawait this.runNpmCommand([\"install\", \"-g\", source.spec]);\n\t\t\treturn;\n\t\t}\n\t\tconst installRoot = this.getNpmInstallRoot(scope, temporary);\n\t\tthis.ensureNpmProject(installRoot);\n\t\tawait this.runNpmCommand([\"install\", source.spec, \"--prefix\", installRoot]);\n\t}\n\n\tprivate async uninstallNpm(source: NpmSource, scope: SourceScope): Promise<void> {\n\t\tif (scope === \"user\") {\n\t\t\tawait this.runNpmCommand([\"uninstall\", \"-g\", source.name]);\n\t\t\treturn;\n\t\t}\n\t\tconst installRoot = this.getNpmInstallRoot(scope, false);\n\t\tif (!existsSync(installRoot)) {\n\t\t\treturn;\n\t\t}\n\t\tawait this.runNpmCommand([\"uninstall\", source.name, \"--prefix\", installRoot]);\n\t}\n\n\tprivate async installGit(source: GitSource, scope: SourceScope): Promise<void> {\n\t\tconst targetDir = this.getGitInstallPath(source, scope);\n\t\tif (existsSync(targetDir)) {\n\t\t\treturn;\n\t\t}\n\t\tconst gitRoot = this.getGitInstallRoot(scope);\n\t\tif (gitRoot) {\n\t\t\tthis.ensureGitIgnore(gitRoot);\n\t\t}\n\t\tmkdirSync(dirname(targetDir), { recursive: true });\n\n\t\tawait this.runCommand(\"git\", [\"clone\", source.repo, targetDir]);\n\t\tif (source.ref) {\n\t\t\tawait this.runCommand(\"git\", [\"checkout\", source.ref], { cwd: targetDir });\n\t\t}\n\t\tconst packageJsonPath = join(targetDir, \"package.json\");\n\t\tif (existsSync(packageJsonPath)) {\n\t\t\tawait this.runNpmCommand(this.getGitDependencyInstallArgs(), { cwd: targetDir });\n\t\t}\n\t}\n\n\tprivate async updateGit(source: GitSource, scope: SourceScope): Promise<void> {\n\t\tconst targetDir = this.getGitInstallPath(source, scope);\n\t\tif (!existsSync(targetDir)) {\n\t\t\tawait this.installGit(source, scope);\n\t\t\treturn;\n\t\t}\n\n\t\tconst target = await this.getLocalGitUpdateTarget(targetDir);\n\n\t\t// Fetch only the ref we will reset to, avoiding unrelated branch/tag noise.\n\t\tawait this.runCommand(\"git\", target.fetchArgs, { cwd: targetDir });\n\n\t\tconst localHead = await this.runCommandCapture(\"git\", [\"rev-parse\", \"HEAD\"], {\n\t\t\tcwd: targetDir,\n\t\t\ttimeoutMs: NETWORK_TIMEOUT_MS,\n\t\t});\n\t\tconst refreshedTargetHead = await this.runCommandCapture(\"git\", [\"rev-parse\", target.ref], {\n\t\t\tcwd: targetDir,\n\t\t\ttimeoutMs: NETWORK_TIMEOUT_MS,\n\t\t});\n\t\tif (localHead.trim() === refreshedTargetHead.trim()) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.runCommand(\"git\", [\"reset\", \"--hard\", target.ref], { cwd: targetDir });\n\n\t\t// Clean untracked files (extensions should be pristine)\n\t\tawait this.runCommand(\"git\", [\"clean\", \"-fdx\"], { cwd: targetDir });\n\n\t\tconst packageJsonPath = join(targetDir, \"package.json\");\n\t\tif (existsSync(packageJsonPath)) {\n\t\t\tawait this.runNpmCommand(this.getGitDependencyInstallArgs(), { cwd: targetDir });\n\t\t}\n\t}\n\n\tprivate async refreshTemporaryGitSource(source: GitSource, sourceStr: string): Promise<void> {\n\t\tif (isOfflineModeEnabled()) {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tawait this.withProgress(\"pull\", sourceStr, `Refreshing ${sourceStr}...`, async () => {\n\t\t\t\tawait this.updateGit(source, \"temporary\");\n\t\t\t});\n\t\t} catch {\n\t\t\t// Keep cached temporary checkout if refresh fails.\n\t\t}\n\t}\n\n\tprivate async removeGit(source: GitSource, scope: SourceScope): Promise<void> {\n\t\tconst targetDir = this.getGitInstallPath(source, scope);\n\t\tif (!existsSync(targetDir)) return;\n\t\trmSync(targetDir, { recursive: true, force: true });\n\t\tthis.pruneEmptyGitParents(targetDir, this.getGitInstallRoot(scope));\n\t}\n\n\tprivate pruneEmptyGitParents(targetDir: string, installRoot: string | undefined): void {\n\t\tif (!installRoot) return;\n\t\tconst resolvedRoot = resolve(installRoot);\n\t\tlet current = dirname(targetDir);\n\t\twhile (current.startsWith(resolvedRoot) && current !== resolvedRoot) {\n\t\t\tif (!existsSync(current)) {\n\t\t\t\tcurrent = dirname(current);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst entries = readdirSync(current);\n\t\t\tif (entries.length > 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\trmSync(current, { recursive: true, force: true });\n\t\t\t} catch {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcurrent = dirname(current);\n\t\t}\n\t}\n\n\tprivate ensureNpmProject(installRoot: string): void {\n\t\tif (!existsSync(installRoot)) {\n\t\t\tmkdirSync(installRoot, { recursive: true });\n\t\t}\n\t\tthis.ensureGitIgnore(installRoot);\n\t\tconst packageJsonPath = join(installRoot, \"package.json\");\n\t\tif (!existsSync(packageJsonPath)) {\n\t\t\tconst pkgJson = { name: \"aery-extensions\", private: true };\n\t\t\twriteFileSync(packageJsonPath, JSON.stringify(pkgJson, null, 2), \"utf-8\");\n\t\t}\n\t}\n\n\tprivate ensureGitIgnore(dir: string): void {\n\t\tif (!existsSync(dir)) {\n\t\t\tmkdirSync(dir, { recursive: true });\n\t\t}\n\t\tconst ignorePath = join(dir, \".gitignore\");\n\t\tif (!existsSync(ignorePath)) {\n\t\t\twriteFileSync(ignorePath, \"*\\n!.gitignore\\n\", \"utf-8\");\n\t\t}\n\t}\n\n\tprivate getNpmInstallRoot(scope: SourceScope, temporary: boolean): string {\n\t\tif (temporary) {\n\t\t\treturn this.getTemporaryDir(\"npm\");\n\t\t}\n\t\tif (scope === \"project\") {\n\t\t\treturn join(this.cwd, CONFIG_DIR_NAME, \"npm\");\n\t\t}\n\t\treturn join(this.getGlobalNpmRoot(), \"..\");\n\t}\n\n\tprivate getGlobalNpmRoot(): string {\n\t\tconst npmCommand = this.getNpmCommand();\n\t\tconst commandKey = [npmCommand.command, ...npmCommand.args].join(\"\\0\");\n\t\tif (this.globalNpmRoot && this.globalNpmRootCommandKey === commandKey) {\n\t\t\treturn this.globalNpmRoot;\n\t\t}\n\t\tconst isBunPackageManager = npmCommand.command === \"bun\";\n\t\tif (isBunPackageManager) {\n\t\t\tconst binDir = this.runNpmCommandSync([\"pm\", \"bin\", \"-g\"]).trim();\n\t\t\tthis.globalNpmRoot = join(dirname(binDir), \"install\", \"global\", \"node_modules\");\n\t\t} else {\n\t\t\tthis.globalNpmRoot = this.runNpmCommandSync([\"root\", \"-g\"]).trim();\n\t\t}\n\t\tthis.globalNpmRootCommandKey = commandKey;\n\t\treturn this.globalNpmRoot;\n\t}\n\n\tprivate getNpmInstallPath(source: NpmSource, scope: SourceScope): string {\n\t\tif (scope === \"temporary\") {\n\t\t\treturn join(this.getTemporaryDir(\"npm\"), \"node_modules\", source.name);\n\t\t}\n\t\tif (scope === \"project\") {\n\t\t\treturn join(this.cwd, CONFIG_DIR_NAME, \"npm\", \"node_modules\", source.name);\n\t\t}\n\t\treturn join(this.getGlobalNpmRoot(), source.name);\n\t}\n\n\tprivate getGitInstallPath(source: GitSource, scope: SourceScope): string {\n\t\tif (scope === \"temporary\") {\n\t\t\treturn this.getTemporaryDir(`git-${source.host}`, source.path);\n\t\t}\n\t\tif (scope === \"project\") {\n\t\t\treturn join(this.cwd, CONFIG_DIR_NAME, \"git\", source.host, source.path);\n\t\t}\n\t\treturn join(this.agentDir, \"git\", source.host, source.path);\n\t}\n\n\tprivate getGitInstallRoot(scope: SourceScope): string | undefined {\n\t\tif (scope === \"temporary\") {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (scope === \"project\") {\n\t\t\treturn join(this.cwd, CONFIG_DIR_NAME, \"git\");\n\t\t}\n\t\treturn join(this.agentDir, \"git\");\n\t}\n\n\tprivate getTemporaryDir(prefix: string, suffix?: string): string {\n\t\tconst hash = createHash(\"sha256\")\n\t\t\t.update(`${prefix}-${suffix ?? \"\"}`)\n\t\t\t.digest(\"hex\")\n\t\t\t.slice(0, 8);\n\t\treturn join(tmpdir(), \"aery-extensions\", prefix, hash, suffix ?? \"\");\n\t}\n\n\tprivate getBaseDirForScope(scope: SourceScope): string {\n\t\tif (scope === \"project\") {\n\t\t\treturn join(this.cwd, CONFIG_DIR_NAME);\n\t\t}\n\t\tif (scope === \"user\") {\n\t\t\treturn this.agentDir;\n\t\t}\n\t\treturn this.cwd;\n\t}\n\n\tprivate resolvePath(input: string): string {\n\t\tconst trimmed = input.trim();\n\t\tif (trimmed === \"~\") return getHomeDir();\n\t\tif (trimmed.startsWith(\"~/\")) return join(getHomeDir(), trimmed.slice(2));\n\t\tif (trimmed.startsWith(\"~\")) return join(getHomeDir(), trimmed.slice(1));\n\t\treturn resolve(this.cwd, trimmed);\n\t}\n\n\tprivate resolvePathFromBase(input: string, baseDir: string): string {\n\t\tconst trimmed = input.trim();\n\t\tif (trimmed === \"~\") return getHomeDir();\n\t\tif (trimmed.startsWith(\"~/\")) return join(getHomeDir(), trimmed.slice(2));\n\t\tif (trimmed.startsWith(\"~\")) return join(getHomeDir(), trimmed.slice(1));\n\t\treturn resolve(baseDir, trimmed);\n\t}\n\n\tprivate collectPackageResources(\n\t\tpackageRoot: string,\n\t\taccumulator: ResourceAccumulator,\n\t\tfilter: PackageFilter | undefined,\n\t\tmetadata: PathMetadata,\n\t): boolean {\n\t\tif (filter) {\n\t\t\tfor (const resourceType of RESOURCE_TYPES) {\n\t\t\t\tconst patterns = filter[resourceType as keyof PackageFilter];\n\t\t\t\tconst target = this.getTargetMap(accumulator, resourceType);\n\t\t\t\tif (patterns !== undefined) {\n\t\t\t\t\tthis.applyPackageFilter(packageRoot, patterns, resourceType, target, metadata);\n\t\t\t\t} else {\n\t\t\t\t\tthis.collectDefaultResources(packageRoot, resourceType, target, metadata);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tconst manifest = this.readPiManifest(packageRoot);\n\t\tif (manifest) {\n\t\t\tfor (const resourceType of RESOURCE_TYPES) {\n\t\t\t\tconst entries = manifest[resourceType as keyof PiManifest];\n\t\t\t\tthis.addManifestEntries(\n\t\t\t\t\tentries,\n\t\t\t\t\tpackageRoot,\n\t\t\t\t\tresourceType,\n\t\t\t\t\tthis.getTargetMap(accumulator, resourceType),\n\t\t\t\t\tmetadata,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tlet hasAnyDir = false;\n\t\tfor (const resourceType of RESOURCE_TYPES) {\n\t\t\tconst dir = join(packageRoot, resourceType);\n\t\t\tif (existsSync(dir)) {\n\t\t\t\t// Collect all files from the directory (all enabled by default)\n\t\t\t\tconst files = collectResourceFiles(dir, resourceType);\n\t\t\t\tfor (const f of files) {\n\t\t\t\t\tthis.addResource(this.getTargetMap(accumulator, resourceType), f, metadata, true);\n\t\t\t\t}\n\t\t\t\thasAnyDir = true;\n\t\t\t}\n\t\t}\n\t\treturn hasAnyDir;\n\t}\n\n\tprivate collectDefaultResources(\n\t\tpackageRoot: string,\n\t\tresourceType: ResourceType,\n\t\ttarget: Map<string, { metadata: PathMetadata; enabled: boolean }>,\n\t\tmetadata: PathMetadata,\n\t): void {\n\t\tconst manifest = this.readPiManifest(packageRoot);\n\t\tconst entries = manifest?.[resourceType as keyof PiManifest];\n\t\tif (entries) {\n\t\t\tthis.addManifestEntries(entries, packageRoot, resourceType, target, metadata);\n\t\t\treturn;\n\t\t}\n\t\tconst dir = join(packageRoot, resourceType);\n\t\tif (existsSync(dir)) {\n\t\t\t// Collect all files from the directory (all enabled by default)\n\t\t\tconst files = collectResourceFiles(dir, resourceType);\n\t\t\tfor (const f of files) {\n\t\t\t\tthis.addResource(target, f, metadata, true);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate applyPackageFilter(\n\t\tpackageRoot: string,\n\t\tuserPatterns: string[],\n\t\tresourceType: ResourceType,\n\t\ttarget: Map<string, { metadata: PathMetadata; enabled: boolean }>,\n\t\tmetadata: PathMetadata,\n\t): void {\n\t\tconst { allFiles } = this.collectManifestFiles(packageRoot, resourceType);\n\n\t\tif (userPatterns.length === 0) {\n\t\t\t// Empty array explicitly disables all resources of this type\n\t\t\tfor (const f of allFiles) {\n\t\t\t\tthis.addResource(target, f, metadata, false);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Apply user patterns\n\t\tconst enabledByUser = applyPatterns(allFiles, userPatterns, packageRoot);\n\n\t\tfor (const f of allFiles) {\n\t\t\tconst enabled = enabledByUser.has(f);\n\t\t\tthis.addResource(target, f, metadata, enabled);\n\t\t}\n\t}\n\n\t/**\n\t * Collect all files from a package for a resource type, applying manifest patterns.\n\t * Returns { allFiles, enabledByManifest } where enabledByManifest is the set of files\n\t * that pass the manifest's own patterns.\n\t */\n\tprivate collectManifestFiles(\n\t\tpackageRoot: string,\n\t\tresourceType: ResourceType,\n\t): { allFiles: string[]; enabledByManifest: Set<string> } {\n\t\tconst manifest = this.readPiManifest(packageRoot);\n\t\tconst entries = manifest?.[resourceType as keyof PiManifest];\n\t\tif (entries && entries.length > 0) {\n\t\t\tconst allFiles = this.collectFilesFromManifestEntries(entries, packageRoot, resourceType);\n\t\t\tconst manifestPatterns = entries.filter(isOverridePattern);\n\t\t\tconst enabledByManifest =\n\t\t\t\tmanifestPatterns.length > 0 ? applyPatterns(allFiles, manifestPatterns, packageRoot) : new Set(allFiles);\n\t\t\treturn { allFiles: Array.from(enabledByManifest), enabledByManifest };\n\t\t}\n\n\t\tconst conventionDir = join(packageRoot, resourceType);\n\t\tif (!existsSync(conventionDir)) {\n\t\t\treturn { allFiles: [], enabledByManifest: new Set() };\n\t\t}\n\t\tconst allFiles = collectResourceFiles(conventionDir, resourceType);\n\t\treturn { allFiles, enabledByManifest: new Set(allFiles) };\n\t}\n\n\tprivate readPiManifest(packageRoot: string): PiManifest | null {\n\t\tconst packageJsonPath = join(packageRoot, \"package.json\");\n\t\tif (!existsSync(packageJsonPath)) {\n\t\t\treturn null;\n\t\t}\n\n\t\ttry {\n\t\t\tconst content = readFileSync(packageJsonPath, \"utf-8\");\n\t\t\tconst pkg = JSON.parse(content) as { pi?: PiManifest; aery?: PiManifest };\n\t\t\treturn pkg.aery ?? pkg.pi ?? null;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate addManifestEntries(\n\t\tentries: string[] | undefined,\n\t\troot: string,\n\t\tresourceType: ResourceType,\n\t\ttarget: Map<string, { metadata: PathMetadata; enabled: boolean }>,\n\t\tmetadata: PathMetadata,\n\t): void {\n\t\tif (!entries) return;\n\n\t\tconst allFiles = this.collectFilesFromManifestEntries(entries, root, resourceType);\n\t\tconst patterns = entries.filter(isOverridePattern);\n\t\tconst enabledPaths = applyPatterns(allFiles, patterns, root);\n\n\t\tfor (const f of allFiles) {\n\t\t\tif (enabledPaths.has(f)) {\n\t\t\t\tthis.addResource(target, f, metadata, true);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate collectFilesFromManifestEntries(entries: string[], root: string, resourceType: ResourceType): string[] {\n\t\tconst sourceEntries = entries.filter((entry) => !isOverridePattern(entry));\n\t\tconst resolved = sourceEntries.flatMap((entry) => {\n\t\t\tif (!hasGlobPattern(entry)) {\n\t\t\t\treturn [resolve(root, entry)];\n\t\t\t}\n\n\t\t\treturn globSync(entry, {\n\t\t\t\tcwd: root,\n\t\t\t\tabsolute: true,\n\t\t\t\tdot: false,\n\t\t\t\tnodir: false,\n\t\t\t}).map((match) => resolve(match));\n\t\t});\n\t\treturn this.collectFilesFromPaths(resolved, resourceType);\n\t}\n\n\tprivate resolveLocalEntries(\n\t\tentries: string[],\n\t\tresourceType: ResourceType,\n\t\ttarget: Map<string, { metadata: PathMetadata; enabled: boolean }>,\n\t\tmetadata: PathMetadata,\n\t\tbaseDir: string,\n\t): void {\n\t\tif (entries.length === 0) return;\n\n\t\t// Collect all files from plain entries (non-pattern entries)\n\t\tconst { plain, patterns } = splitPatterns(entries);\n\t\tconst resolvedPlain = plain.map((p) => this.resolvePathFromBase(p, baseDir));\n\t\tconst allFiles = this.collectFilesFromPaths(resolvedPlain, resourceType);\n\n\t\t// Determine which files are enabled based on patterns\n\t\tconst enabledPaths = applyPatterns(allFiles, patterns, baseDir);\n\n\t\t// Add all files with their enabled state\n\t\tfor (const f of allFiles) {\n\t\t\tthis.addResource(target, f, metadata, enabledPaths.has(f));\n\t\t}\n\t}\n\n\tprivate addAutoDiscoveredResources(\n\t\taccumulator: ResourceAccumulator,\n\t\tglobalSettings: ReturnType<SettingsManager[\"getGlobalSettings\"]>,\n\t\tprojectSettings: ReturnType<SettingsManager[\"getProjectSettings\"]>,\n\t\tglobalBaseDir: string,\n\t\tprojectBaseDir: string,\n\t): void {\n\t\tconst userMetadata: PathMetadata = {\n\t\t\tsource: \"auto\",\n\t\t\tscope: \"user\",\n\t\t\torigin: \"top-level\",\n\t\t\tbaseDir: globalBaseDir,\n\t\t};\n\t\tconst projectMetadata: PathMetadata = {\n\t\t\tsource: \"auto\",\n\t\t\tscope: \"project\",\n\t\t\torigin: \"top-level\",\n\t\t\tbaseDir: projectBaseDir,\n\t\t};\n\n\t\tconst userOverrides = {\n\t\t\textensions: (globalSettings.extensions ?? []) as string[],\n\t\t\tskills: (globalSettings.skills ?? []) as string[],\n\t\t\tprompts: (globalSettings.prompts ?? []) as string[],\n\t\t\tthemes: (globalSettings.themes ?? []) as string[],\n\t\t};\n\t\tconst projectOverrides = {\n\t\t\textensions: (projectSettings.extensions ?? []) as string[],\n\t\t\tskills: (projectSettings.skills ?? []) as string[],\n\t\t\tprompts: (projectSettings.prompts ?? []) as string[],\n\t\t\tthemes: (projectSettings.themes ?? []) as string[],\n\t\t};\n\n\t\tconst userDirs = {\n\t\t\textensions: join(globalBaseDir, \"extensions\"),\n\t\t\tskills: join(globalBaseDir, \"skills\"),\n\t\t\tprompts: join(globalBaseDir, \"prompts\"),\n\t\t\tthemes: join(globalBaseDir, \"themes\"),\n\t\t};\n\t\tconst projectDirs = {\n\t\t\textensions: join(projectBaseDir, \"extensions\"),\n\t\t\tskills: join(projectBaseDir, \"skills\"),\n\t\t\tprompts: join(projectBaseDir, \"prompts\"),\n\t\t\tthemes: join(projectBaseDir, \"themes\"),\n\t\t};\n\t\tconst userAgentsSkillsDir = join(getHomeDir(), \".agents\", \"skills\");\n\t\tconst projectAgentsSkillDirs = collectAncestorAgentsSkillDirs(this.cwd).filter(\n\t\t\t(dir) => resolve(dir) !== resolve(userAgentsSkillsDir),\n\t\t);\n\n\t\tconst addResources = (\n\t\t\tresourceType: ResourceType,\n\t\t\tpaths: string[],\n\t\t\tmetadata: PathMetadata,\n\t\t\toverrides: string[],\n\t\t\tbaseDir: string,\n\t\t) => {\n\t\t\tconst target = this.getTargetMap(accumulator, resourceType);\n\t\t\tfor (const path of paths) {\n\t\t\t\tconst enabled = isEnabledByOverrides(path, overrides, baseDir);\n\t\t\t\tthis.addResource(target, path, metadata, enabled);\n\t\t\t}\n\t\t};\n\n\t\taddResources(\n\t\t\t\"extensions\",\n\t\t\tcollectAutoExtensionEntries(projectDirs.extensions),\n\t\t\tprojectMetadata,\n\t\t\tprojectOverrides.extensions,\n\t\t\tprojectBaseDir,\n\t\t);\n\t\taddResources(\n\t\t\t\"skills\",\n\t\t\t[\n\t\t\t\t...collectAutoSkillEntries(projectDirs.skills, \"aery\"),\n\t\t\t\t...projectAgentsSkillDirs.flatMap((dir) => collectAutoSkillEntries(dir, \"agents\")),\n\t\t\t],\n\t\t\tprojectMetadata,\n\t\t\tprojectOverrides.skills,\n\t\t\tprojectBaseDir,\n\t\t);\n\t\taddResources(\n\t\t\t\"prompts\",\n\t\t\tcollectAutoPromptEntries(projectDirs.prompts),\n\t\t\tprojectMetadata,\n\t\t\tprojectOverrides.prompts,\n\t\t\tprojectBaseDir,\n\t\t);\n\t\taddResources(\n\t\t\t\"themes\",\n\t\t\tcollectAutoThemeEntries(projectDirs.themes),\n\t\t\tprojectMetadata,\n\t\t\tprojectOverrides.themes,\n\t\t\tprojectBaseDir,\n\t\t);\n\n\t\taddResources(\n\t\t\t\"extensions\",\n\t\t\tcollectAutoExtensionEntries(userDirs.extensions),\n\t\t\tuserMetadata,\n\t\t\tuserOverrides.extensions,\n\t\t\tglobalBaseDir,\n\t\t);\n\t\taddResources(\n\t\t\t\"skills\",\n\t\t\t[\n\t\t\t\t...collectAutoSkillEntries(userDirs.skills, \"aery\"),\n\t\t\t\t...collectAutoSkillEntries(userAgentsSkillsDir, \"agents\"),\n\t\t\t],\n\t\t\tuserMetadata,\n\t\t\tuserOverrides.skills,\n\t\t\tglobalBaseDir,\n\t\t);\n\t\taddResources(\n\t\t\t\"prompts\",\n\t\t\tcollectAutoPromptEntries(userDirs.prompts),\n\t\t\tuserMetadata,\n\t\t\tuserOverrides.prompts,\n\t\t\tglobalBaseDir,\n\t\t);\n\t\taddResources(\n\t\t\t\"themes\",\n\t\t\tcollectAutoThemeEntries(userDirs.themes),\n\t\t\tuserMetadata,\n\t\t\tuserOverrides.themes,\n\t\t\tglobalBaseDir,\n\t\t);\n\t}\n\n\tprivate collectFilesFromPaths(paths: string[], resourceType: ResourceType): string[] {\n\t\tconst files: string[] = [];\n\t\tfor (const p of paths) {\n\t\t\tif (!existsSync(p)) continue;\n\n\t\t\ttry {\n\t\t\t\tconst stats = statSync(p);\n\t\t\t\tif (stats.isFile()) {\n\t\t\t\t\tfiles.push(p);\n\t\t\t\t} else if (stats.isDirectory()) {\n\t\t\t\t\tfiles.push(...collectResourceFiles(p, resourceType));\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Ignore errors\n\t\t\t}\n\t\t}\n\t\treturn files;\n\t}\n\n\tprivate getTargetMap(\n\t\taccumulator: ResourceAccumulator,\n\t\tresourceType: ResourceType,\n\t): Map<string, { metadata: PathMetadata; enabled: boolean }> {\n\t\tswitch (resourceType) {\n\t\t\tcase \"extensions\":\n\t\t\t\treturn accumulator.extensions;\n\t\t\tcase \"skills\":\n\t\t\t\treturn accumulator.skills;\n\t\t\tcase \"prompts\":\n\t\t\t\treturn accumulator.prompts;\n\t\t\tcase \"themes\":\n\t\t\t\treturn accumulator.themes;\n\t\t\tdefault:\n\t\t\t\tthrow new Error(`Unknown resource type: ${resourceType}`);\n\t\t}\n\t}\n\n\tprivate addResource(\n\t\tmap: Map<string, { metadata: PathMetadata; enabled: boolean }>,\n\t\tpath: string,\n\t\tmetadata: PathMetadata,\n\t\tenabled: boolean,\n\t): void {\n\t\tif (!path) return;\n\t\tif (!map.has(path)) {\n\t\t\tmap.set(path, { metadata, enabled });\n\t\t}\n\t}\n\n\tprivate createAccumulator(): ResourceAccumulator {\n\t\treturn {\n\t\t\textensions: new Map(),\n\t\t\tskills: new Map(),\n\t\t\tprompts: new Map(),\n\t\t\tthemes: new Map(),\n\t\t};\n\t}\n\n\tprivate toResolvedPaths(accumulator: ResourceAccumulator): ResolvedPaths {\n\t\tconst mapToResolved = (\n\t\t\tentries: Map<string, { metadata: PathMetadata; enabled: boolean }>,\n\t\t): ResolvedResource[] => {\n\t\t\tconst resolved = Array.from(entries.entries()).map(([path, { metadata, enabled }]) => ({\n\t\t\t\tpath,\n\t\t\t\tenabled,\n\t\t\t\tmetadata,\n\t\t\t}));\n\t\t\tresolved.sort((a, b) => resourcePrecedenceRank(a.metadata) - resourcePrecedenceRank(b.metadata));\n\n\t\t\tconst seen = new Set<string>();\n\t\t\treturn resolved.filter((entry) => {\n\t\t\t\tconst canonicalPath = canonicalizePath(entry.path);\n\t\t\t\tif (seen.has(canonicalPath)) return false;\n\t\t\t\tseen.add(canonicalPath);\n\t\t\t\treturn true;\n\t\t\t});\n\t\t};\n\n\t\treturn {\n\t\t\textensions: mapToResolved(accumulator.extensions),\n\t\t\tskills: mapToResolved(accumulator.skills),\n\t\t\tprompts: mapToResolved(accumulator.prompts),\n\t\t\tthemes: mapToResolved(accumulator.themes),\n\t\t};\n\t}\n\n\tprivate shouldUseWindowsShell(command: string): boolean {\n\t\tif (process.platform !== \"win32\") {\n\t\t\treturn false;\n\t\t}\n\t\tconst commandName = basename(command).toLowerCase();\n\t\treturn (\n\t\t\tcommandName === \"npm\" ||\n\t\t\tcommandName === \"npx\" ||\n\t\t\tcommandName === \"pnpm\" ||\n\t\t\tcommandName === \"yarn\" ||\n\t\t\tcommandName === \"yarnpkg\" ||\n\t\t\tcommandName === \"corepack\" ||\n\t\t\tcommandName.endsWith(\".cmd\") ||\n\t\t\tcommandName.endsWith(\".bat\")\n\t\t);\n\t}\n\n\tprivate spawnCommand(command: string, args: string[], options?: { cwd?: string }): ChildProcess {\n\t\treturn spawn(command, args, {\n\t\t\tcwd: options?.cwd,\n\t\t\tstdio: isStdoutTakenOver() ? [\"ignore\", 2, 2] : \"inherit\",\n\t\t\tshell: this.shouldUseWindowsShell(command),\n\t\t\tenv: getEnv(),\n\t\t});\n\t}\n\n\tprivate spawnCaptureCommand(\n\t\tcommand: string,\n\t\targs: string[],\n\t\toptions?: { cwd?: string; env?: Record<string, string> },\n\t): ChildProcessByStdio<null, Readable, Readable> {\n\t\tconst baseEnv = getEnv();\n\t\treturn spawn(command, args, {\n\t\t\tcwd: options?.cwd,\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\tshell: this.shouldUseWindowsShell(command),\n\t\t\tenv: options?.env ? { ...baseEnv, ...options.env } : baseEnv,\n\t\t});\n\t}\n\n\tprivate runCommandCapture(\n\t\tcommand: string,\n\t\targs: string[],\n\t\toptions?: { cwd?: string; timeoutMs?: number; env?: Record<string, string> },\n\t): Promise<string> {\n\t\treturn new Promise((resolvePromise, reject) => {\n\t\t\tconst child = this.spawnCaptureCommand(command, args, options);\n\t\t\tlet stdout = \"\";\n\t\t\tlet stderr = \"\";\n\t\t\tlet timedOut = false;\n\t\t\tconst timeout =\n\t\t\t\ttypeof options?.timeoutMs === \"number\"\n\t\t\t\t\t? setTimeout(() => {\n\t\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\t\tchild.kill();\n\t\t\t\t\t\t}, options.timeoutMs)\n\t\t\t\t\t: undefined;\n\n\t\t\tchild.stdout?.on(\"data\", (data) => {\n\t\t\t\tstdout += data.toString();\n\t\t\t});\n\t\t\tchild.stderr?.on(\"data\", (data) => {\n\t\t\t\tstderr += data.toString();\n\t\t\t});\n\t\t\tchild.once(\"error\", (error) => {\n\t\t\t\tif (timeout) clearTimeout(timeout);\n\t\t\t\treject(error);\n\t\t\t});\n\t\t\tchild.once(\"close\", (code, signal) => {\n\t\t\t\tif (timeout) clearTimeout(timeout);\n\t\t\t\tif (timedOut) {\n\t\t\t\t\treject(new Error(`${command} ${args.join(\" \")} timed out after ${options?.timeoutMs}ms`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (code === 0) {\n\t\t\t\t\tresolvePromise(stdout.trim());\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst exitStatus = code === null ? `signal ${signal ?? \"unknown\"}` : `code ${code}`;\n\t\t\t\treject(new Error(`${command} ${args.join(\" \")} failed with ${exitStatus}: ${stderr || stdout}`));\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate runCommand(command: string, args: string[], options?: { cwd?: string }): Promise<void> {\n\t\treturn new Promise((resolvePromise, reject) => {\n\t\t\tconst child = this.spawnCommand(command, args, options);\n\t\t\tchild.on(\"error\", reject);\n\t\t\tchild.on(\"exit\", (code) => {\n\t\t\t\tif (code === 0) {\n\t\t\t\t\tresolvePromise();\n\t\t\t\t} else {\n\t\t\t\t\treject(new Error(`${command} ${args.join(\" \")} failed with code ${code}`));\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate runCommandSync(command: string, args: string[]): string {\n\t\tconst result = spawnSync(command, args, {\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\tencoding: \"utf-8\",\n\t\t\tshell: this.shouldUseWindowsShell(command),\n\t\t\tenv: getEnv(),\n\t\t});\n\t\tif (result.error || result.status !== 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to run ${command} ${args.join(\" \")}: ${result.error?.message || result.stderr || result.stdout}`,\n\t\t\t);\n\t\t}\n\t\treturn (result.stdout || result.stderr || \"\").trim();\n\t}\n}\n"]}