@phi-code-admin/phi-code 0.74.2 → 0.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (656) hide show
  1. package/CHANGELOG.md +1186 -4
  2. package/README.md +478 -379
  3. package/dist/bun/cli.d.ts +3 -0
  4. package/dist/bun/cli.d.ts.map +1 -0
  5. package/dist/bun/cli.js +9 -0
  6. package/dist/bun/cli.js.map +1 -0
  7. package/dist/bun/register-bedrock.d.ts +2 -0
  8. package/dist/bun/register-bedrock.d.ts.map +1 -0
  9. package/dist/bun/register-bedrock.js +4 -0
  10. package/dist/bun/register-bedrock.js.map +1 -0
  11. package/dist/bun/restore-sandbox-env.d.ts +13 -0
  12. package/dist/bun/restore-sandbox-env.d.ts.map +1 -0
  13. package/dist/bun/restore-sandbox-env.js +32 -0
  14. package/dist/bun/restore-sandbox-env.js.map +1 -0
  15. package/dist/cli/args.d.ts +12 -7
  16. package/dist/cli/args.d.ts.map +1 -1
  17. package/dist/cli/args.js +87 -45
  18. package/dist/cli/args.js.map +1 -1
  19. package/dist/cli/config-selector.d.ts.map +1 -1
  20. package/dist/cli/config-selector.js.map +1 -1
  21. package/dist/cli/file-processor.d.ts.map +1 -1
  22. package/dist/cli/file-processor.js +4 -0
  23. package/dist/cli/file-processor.js.map +1 -1
  24. package/dist/cli/initial-message.d.ts +18 -0
  25. package/dist/cli/initial-message.d.ts.map +1 -0
  26. package/dist/cli/initial-message.js +22 -0
  27. package/dist/cli/initial-message.js.map +1 -0
  28. package/dist/cli/list-models.d.ts.map +1 -1
  29. package/dist/cli/list-models.js +7 -1
  30. package/dist/cli/list-models.js.map +1 -1
  31. package/dist/cli/session-picker.d.ts.map +1 -1
  32. package/dist/cli/session-picker.js +2 -1
  33. package/dist/cli/session-picker.js.map +1 -1
  34. package/dist/cli.d.ts.map +1 -1
  35. package/dist/cli.js +9 -5
  36. package/dist/cli.js.map +1 -1
  37. package/dist/config.d.ts +24 -0
  38. package/dist/config.d.ts.map +1 -1
  39. package/dist/config.js +226 -30
  40. package/dist/config.js.map +1 -1
  41. package/dist/core/agent-session-runtime.d.ts +117 -0
  42. package/dist/core/agent-session-runtime.d.ts.map +1 -0
  43. package/dist/core/agent-session-runtime.js +300 -0
  44. package/dist/core/agent-session-runtime.js.map +1 -0
  45. package/dist/core/agent-session-services.d.ts +86 -0
  46. package/dist/core/agent-session-services.d.ts.map +1 -0
  47. package/dist/core/agent-session-services.js +117 -0
  48. package/dist/core/agent-session-services.js.map +1 -0
  49. package/dist/core/agent-session.d.ts +63 -82
  50. package/dist/core/agent-session.d.ts.map +1 -1
  51. package/dist/core/agent-session.js +674 -628
  52. package/dist/core/agent-session.js.map +1 -1
  53. package/dist/core/api-key-store.d.ts +87 -0
  54. package/dist/core/api-key-store.d.ts.map +1 -0
  55. package/dist/core/api-key-store.js +168 -0
  56. package/dist/core/api-key-store.js.map +1 -0
  57. package/dist/core/auth-guidance.d.ts +5 -0
  58. package/dist/core/auth-guidance.d.ts.map +1 -0
  59. package/dist/core/auth-guidance.js +21 -0
  60. package/dist/core/auth-guidance.js.map +1 -0
  61. package/dist/core/auth-storage.d.ts +12 -5
  62. package/dist/core/auth-storage.d.ts.map +1 -1
  63. package/dist/core/auth-storage.js +34 -8
  64. package/dist/core/auth-storage.js.map +1 -1
  65. package/dist/core/bash-executor.d.ts +0 -15
  66. package/dist/core/bash-executor.d.ts.map +1 -1
  67. package/dist/core/bash-executor.js +28 -129
  68. package/dist/core/bash-executor.js.map +1 -1
  69. package/dist/core/compaction/branch-summarization.d.ts +2 -0
  70. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  71. package/dist/core/compaction/branch-summarization.js +3 -2
  72. package/dist/core/compaction/branch-summarization.js.map +1 -1
  73. package/dist/core/compaction/compaction.d.ts +4 -4
  74. package/dist/core/compaction/compaction.d.ts.map +1 -1
  75. package/dist/core/compaction/compaction.js +32 -27
  76. package/dist/core/compaction/compaction.js.map +1 -1
  77. package/dist/core/compaction/index.d.ts.map +1 -1
  78. package/dist/core/compaction/utils.d.ts.map +1 -1
  79. package/dist/core/compaction/utils.js.map +1 -1
  80. package/dist/core/config-watcher.d.ts +47 -0
  81. package/dist/core/config-watcher.d.ts.map +1 -0
  82. package/dist/core/config-watcher.js +135 -0
  83. package/dist/core/config-watcher.js.map +1 -0
  84. package/dist/core/default-models.json +80 -0
  85. package/dist/core/defaults.d.ts.map +1 -1
  86. package/dist/core/diagnostics.d.ts.map +1 -1
  87. package/dist/core/event-bus.d.ts.map +1 -1
  88. package/dist/core/event-bus.js.map +1 -1
  89. package/dist/core/exec.d.ts.map +1 -1
  90. package/dist/core/exec.js +7 -3
  91. package/dist/core/exec.js.map +1 -1
  92. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  93. package/dist/core/export-html/ansi-to-html.js +1 -1
  94. package/dist/core/export-html/ansi-to-html.js.map +1 -1
  95. package/dist/core/export-html/index.d.ts +7 -4
  96. package/dist/core/export-html/index.d.ts.map +1 -1
  97. package/dist/core/export-html/index.js +15 -13
  98. package/dist/core/export-html/index.js.map +1 -1
  99. package/dist/core/export-html/template.css +112 -17
  100. package/dist/core/export-html/template.html +1 -0
  101. package/dist/core/export-html/template.js +312 -64
  102. package/dist/core/export-html/tool-renderer.d.ts +9 -10
  103. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  104. package/dist/core/export-html/tool-renderer.js +61 -16
  105. package/dist/core/export-html/tool-renderer.js.map +1 -1
  106. package/dist/core/extensions/index.d.ts +5 -4
  107. package/dist/core/extensions/index.d.ts.map +1 -1
  108. package/dist/core/extensions/index.js +2 -2
  109. package/dist/core/extensions/index.js.map +1 -1
  110. package/dist/core/extensions/loader.d.ts +0 -1
  111. package/dist/core/extensions/loader.d.ts.map +1 -1
  112. package/dist/core/extensions/loader.js +98 -18
  113. package/dist/core/extensions/loader.js.map +1 -1
  114. package/dist/core/extensions/runner.d.ts +27 -14
  115. package/dist/core/extensions/runner.d.ts.map +1 -1
  116. package/dist/core/extensions/runner.js +299 -115
  117. package/dist/core/extensions/runner.js.map +1 -1
  118. package/dist/core/extensions/types.d.ts +200 -44
  119. package/dist/core/extensions/types.d.ts.map +1 -1
  120. package/dist/core/extensions/types.js +10 -0
  121. package/dist/core/extensions/types.js.map +1 -1
  122. package/dist/core/extensions/wrapper.d.ts +4 -11
  123. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  124. package/dist/core/extensions/wrapper.js +7 -87
  125. package/dist/core/extensions/wrapper.js.map +1 -1
  126. package/dist/core/footer-data-provider.d.ts +22 -2
  127. package/dist/core/footer-data-provider.d.ts.map +1 -1
  128. package/dist/core/footer-data-provider.js +225 -49
  129. package/dist/core/footer-data-provider.js.map +1 -1
  130. package/dist/core/index.d.ts +5 -2
  131. package/dist/core/index.d.ts.map +1 -1
  132. package/dist/core/index.js +5 -2
  133. package/dist/core/index.js.map +1 -1
  134. package/dist/core/keybindings.d.ts +348 -50
  135. package/dist/core/keybindings.d.ts.map +1 -1
  136. package/dist/core/keybindings.js +276 -132
  137. package/dist/core/keybindings.js.map +1 -1
  138. package/dist/core/messages.d.ts.map +1 -1
  139. package/dist/core/messages.js.map +1 -1
  140. package/dist/core/model-registry.d.ts +41 -5
  141. package/dist/core/model-registry.d.ts.map +1 -1
  142. package/dist/core/model-registry.js +316 -136
  143. package/dist/core/model-registry.js.map +1 -1
  144. package/dist/core/model-resolver.d.ts +6 -0
  145. package/dist/core/model-resolver.d.ts.map +1 -1
  146. package/dist/core/model-resolver.js +70 -37
  147. package/dist/core/model-resolver.js.map +1 -1
  148. package/dist/core/output-guard.d.ts +6 -0
  149. package/dist/core/output-guard.d.ts.map +1 -0
  150. package/dist/core/output-guard.js +59 -0
  151. package/dist/core/output-guard.js.map +1 -0
  152. package/dist/core/package-manager.d.ts +49 -7
  153. package/dist/core/package-manager.d.ts.map +1 -1
  154. package/dist/core/package-manager.js +655 -122
  155. package/dist/core/package-manager.js.map +1 -1
  156. package/dist/core/prompt-templates.d.ts +12 -10
  157. package/dist/core/prompt-templates.d.ts.map +1 -1
  158. package/dist/core/prompt-templates.js +37 -38
  159. package/dist/core/prompt-templates.js.map +1 -1
  160. package/dist/core/provider-display-names.d.ts +2 -0
  161. package/dist/core/provider-display-names.d.ts.map +1 -0
  162. package/dist/core/provider-display-names.js +33 -0
  163. package/dist/core/provider-display-names.js.map +1 -0
  164. package/dist/core/resolve-config-value.d.ts +6 -0
  165. package/dist/core/resolve-config-value.d.ts.map +1 -1
  166. package/dist/core/resolve-config-value.js +75 -8
  167. package/dist/core/resolve-config-value.js.map +1 -1
  168. package/dist/core/resource-loader.d.ts +18 -8
  169. package/dist/core/resource-loader.d.ts.map +1 -1
  170. package/dist/core/resource-loader.js +217 -123
  171. package/dist/core/resource-loader.js.map +1 -1
  172. package/dist/core/sdk.d.ts +25 -8
  173. package/dist/core/sdk.d.ts.map +1 -1
  174. package/dist/core/sdk.js +84 -37
  175. package/dist/core/sdk.js.map +1 -1
  176. package/dist/core/session-cwd.d.ts +19 -0
  177. package/dist/core/session-cwd.d.ts.map +1 -0
  178. package/dist/core/session-cwd.js +38 -0
  179. package/dist/core/session-cwd.js.map +1 -0
  180. package/dist/core/session-manager.d.ts +11 -1
  181. package/dist/core/session-manager.d.ts.map +1 -1
  182. package/dist/core/session-manager.js +42 -27
  183. package/dist/core/session-manager.js.map +1 -1
  184. package/dist/core/settings-manager.d.ts +34 -5
  185. package/dist/core/settings-manager.d.ts.map +1 -1
  186. package/dist/core/settings-manager.js +113 -13
  187. package/dist/core/settings-manager.js.map +1 -1
  188. package/dist/core/skills.d.ts +13 -11
  189. package/dist/core/skills.d.ts.map +1 -1
  190. package/dist/core/skills.js +59 -19
  191. package/dist/core/skills.js.map +1 -1
  192. package/dist/core/slash-commands.d.ts +2 -3
  193. package/dist/core/slash-commands.d.ts.map +1 -1
  194. package/dist/core/slash-commands.js +9 -6
  195. package/dist/core/slash-commands.js.map +1 -1
  196. package/dist/core/source-info.d.ts +18 -0
  197. package/dist/core/source-info.d.ts.map +1 -0
  198. package/dist/core/source-info.js +19 -0
  199. package/dist/core/source-info.js.map +1 -0
  200. package/dist/core/system-prompt.d.ts +3 -3
  201. package/dist/core/system-prompt.d.ts.map +1 -1
  202. package/dist/core/system-prompt.js +16 -55
  203. package/dist/core/system-prompt.js.map +1 -1
  204. package/dist/core/telemetry.d.ts +3 -0
  205. package/dist/core/telemetry.d.ts.map +1 -0
  206. package/dist/core/telemetry.js +9 -0
  207. package/dist/core/telemetry.js.map +1 -0
  208. package/dist/core/timings.d.ts +1 -0
  209. package/dist/core/timings.d.ts.map +1 -1
  210. package/dist/core/timings.js +6 -0
  211. package/dist/core/timings.js.map +1 -1
  212. package/dist/core/tools/bash.d.ts +27 -14
  213. package/dist/core/tools/bash.d.ts.map +1 -1
  214. package/dist/core/tools/bash.js +301 -208
  215. package/dist/core/tools/bash.js.map +1 -1
  216. package/dist/core/tools/edit-diff.d.ts +23 -1
  217. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  218. package/dist/core/tools/edit-diff.js +154 -59
  219. package/dist/core/tools/edit-diff.js.map +1 -1
  220. package/dist/core/tools/edit.d.ts +22 -12
  221. package/dist/core/tools/edit.d.ts.map +1 -1
  222. package/dist/core/tools/edit.js +243 -65
  223. package/dist/core/tools/edit.js.map +1 -1
  224. package/dist/core/tools/file-mutation-queue.d.ts +6 -0
  225. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -0
  226. package/dist/core/tools/file-mutation-queue.js +37 -0
  227. package/dist/core/tools/file-mutation-queue.js.map +1 -0
  228. package/dist/core/tools/find.d.ts +10 -14
  229. package/dist/core/tools/find.d.ts.map +1 -1
  230. package/dist/core/tools/find.js +202 -110
  231. package/dist/core/tools/find.js.map +1 -1
  232. package/dist/core/tools/grep.d.ts +14 -22
  233. package/dist/core/tools/grep.d.ts.map +1 -1
  234. package/dist/core/tools/grep.js +100 -35
  235. package/dist/core/tools/grep.js.map +1 -1
  236. package/dist/core/tools/index.d.ts +27 -60
  237. package/dist/core/tools/index.d.ts.map +1 -1
  238. package/dist/core/tools/index.js +96 -45
  239. package/dist/core/tools/index.js.map +1 -1
  240. package/dist/core/tools/ls.d.ts +8 -11
  241. package/dist/core/tools/ls.d.ts.map +1 -1
  242. package/dist/core/tools/ls.js +66 -15
  243. package/dist/core/tools/ls.js.map +1 -1
  244. package/dist/core/tools/output-accumulator.d.ts +50 -0
  245. package/dist/core/tools/output-accumulator.d.ts.map +1 -0
  246. package/dist/core/tools/output-accumulator.js +178 -0
  247. package/dist/core/tools/output-accumulator.js.map +1 -0
  248. package/dist/core/tools/path-utils.d.ts.map +1 -1
  249. package/dist/core/tools/path-utils.js +1 -1
  250. package/dist/core/tools/path-utils.js.map +1 -1
  251. package/dist/core/tools/read.d.ts +9 -13
  252. package/dist/core/tools/read.d.ts.map +1 -1
  253. package/dist/core/tools/read.js +175 -52
  254. package/dist/core/tools/read.js.map +1 -1
  255. package/dist/core/tools/render-utils.d.ts +21 -0
  256. package/dist/core/tools/render-utils.d.ts.map +1 -0
  257. package/dist/core/tools/render-utils.js +49 -0
  258. package/dist/core/tools/render-utils.js.map +1 -0
  259. package/dist/core/tools/tool-definition-wrapper.d.ts +14 -0
  260. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -0
  261. package/dist/core/tools/tool-definition-wrapper.js +34 -0
  262. package/dist/core/tools/tool-definition-wrapper.js.map +1 -0
  263. package/dist/core/tools/truncate.d.ts.map +1 -1
  264. package/dist/core/tools/truncate.js.map +1 -1
  265. package/dist/core/tools/write.d.ts +8 -11
  266. package/dist/core/tools/write.d.ts.map +1 -1
  267. package/dist/core/tools/write.js +167 -32
  268. package/dist/core/tools/write.js.map +1 -1
  269. package/dist/index.d.ts +12 -9
  270. package/dist/index.d.ts.map +1 -1
  271. package/dist/index.js +12 -10
  272. package/dist/index.js.map +1 -1
  273. package/dist/main.d.ts +5 -1
  274. package/dist/main.d.ts.map +1 -1
  275. package/dist/main.js +326 -404
  276. package/dist/main.js.map +1 -1
  277. package/dist/migrations.d.ts +2 -2
  278. package/dist/migrations.d.ts.map +1 -1
  279. package/dist/migrations.js +24 -4
  280. package/dist/migrations.js.map +1 -1
  281. package/dist/modes/index.d.ts.map +1 -1
  282. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  283. package/dist/modes/interactive/components/armin.js +10 -6
  284. package/dist/modes/interactive/components/armin.js.map +1 -1
  285. package/dist/modes/interactive/components/assistant-message.d.ts +5 -1
  286. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  287. package/dist/modes/interactive/components/assistant-message.js +32 -3
  288. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  289. package/dist/modes/interactive/components/bash-execution.d.ts +0 -1
  290. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  291. package/dist/modes/interactive/components/bash-execution.js +31 -12
  292. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  293. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  294. package/dist/modes/interactive/components/bordered-loader.js +7 -1
  295. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  296. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  297. package/dist/modes/interactive/components/branch-summary-message.js +5 -3
  298. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  299. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  300. package/dist/modes/interactive/components/compaction-summary-message.js +5 -3
  301. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  302. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  303. package/dist/modes/interactive/components/config-selector.js +49 -16
  304. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  305. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  306. package/dist/modes/interactive/components/countdown-timer.js +5 -0
  307. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  308. package/dist/modes/interactive/components/custom-editor.d.ts +3 -3
  309. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  310. package/dist/modes/interactive/components/custom-editor.js +14 -7
  311. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  312. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  313. package/dist/modes/interactive/components/custom-message.js +6 -1
  314. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  315. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  316. package/dist/modes/interactive/components/daxnuts.js +8 -6
  317. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  318. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  319. package/dist/modes/interactive/components/diff.js.map +1 -1
  320. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  321. package/dist/modes/interactive/components/dynamic-border.js +1 -0
  322. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  323. package/dist/modes/interactive/components/earendil-announcement.d.ts +5 -0
  324. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -0
  325. package/dist/modes/interactive/components/earendil-announcement.js +40 -0
  326. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -0
  327. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  328. package/dist/modes/interactive/components/extension-editor.js +16 -10
  329. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  330. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  331. package/dist/modes/interactive/components/extension-input.js +13 -7
  332. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  333. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  334. package/dist/modes/interactive/components/extension-selector.js +18 -11
  335. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  336. package/dist/modes/interactive/components/footer.d.ts +1 -0
  337. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  338. package/dist/modes/interactive/components/footer.js +7 -2
  339. package/dist/modes/interactive/components/footer.js.map +1 -1
  340. package/dist/modes/interactive/components/index.d.ts +1 -1
  341. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  342. package/dist/modes/interactive/components/index.js +1 -1
  343. package/dist/modes/interactive/components/index.js.map +1 -1
  344. package/dist/modes/interactive/components/keybinding-hints.d.ts +8 -36
  345. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  346. package/dist/modes/interactive/components/keybinding-hints.js +23 -48
  347. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  348. package/dist/modes/interactive/components/login-dialog.d.ts +5 -1
  349. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  350. package/dist/modes/interactive/components/login-dialog.js +35 -14
  351. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  352. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  353. package/dist/modes/interactive/components/model-selector.js +41 -22
  354. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  355. package/dist/modes/interactive/components/oauth-selector.d.ts +18 -6
  356. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  357. package/dist/modes/interactive/components/oauth-selector.js +104 -31
  358. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  359. package/dist/modes/interactive/components/scoped-models-selector.d.ts +5 -12
  360. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  361. package/dist/modes/interactive/components/scoped-models-selector.js +61 -42
  362. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  363. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  364. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  365. package/dist/modes/interactive/components/session-selector.d.ts +2 -1
  366. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  367. package/dist/modes/interactive/components/session-selector.js +109 -73
  368. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  369. package/dist/modes/interactive/components/settings-selector.d.ts +9 -0
  370. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  371. package/dist/modes/interactive/components/settings-selector.js +84 -4
  372. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  373. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  374. package/dist/modes/interactive/components/show-images-selector.js +6 -1
  375. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  376. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  377. package/dist/modes/interactive/components/skill-invocation-message.js +5 -3
  378. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  379. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  380. package/dist/modes/interactive/components/theme-selector.js +7 -1
  381. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  382. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  383. package/dist/modes/interactive/components/thinking-selector.js +6 -1
  384. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  385. package/dist/modes/interactive/components/tool-execution.d.ts +20 -34
  386. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  387. package/dist/modes/interactive/components/tool-execution.js +158 -636
  388. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  389. package/dist/modes/interactive/components/tree-selector.d.ts +21 -2
  390. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  391. package/dist/modes/interactive/components/tree-selector.js +224 -52
  392. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  393. package/dist/modes/interactive/components/user-message-selector.d.ts +2 -2
  394. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  395. package/dist/modes/interactive/components/user-message-selector.js +20 -16
  396. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  397. package/dist/modes/interactive/components/user-message.d.ts +1 -0
  398. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  399. package/dist/modes/interactive/components/user-message.js +8 -6
  400. package/dist/modes/interactive/components/user-message.js.map +1 -1
  401. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  402. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  403. package/dist/modes/interactive/interactive-mode.d.ts +67 -39
  404. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  405. package/dist/modes/interactive/interactive-mode.js +1556 -680
  406. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  407. package/dist/modes/interactive/theme/dark.json +1 -1
  408. package/dist/modes/interactive/theme/light.json +1 -1
  409. package/dist/modes/interactive/theme/theme.d.ts +3 -0
  410. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  411. package/dist/modes/interactive/theme/theme.js +101 -72
  412. package/dist/modes/interactive/theme/theme.js.map +1 -1
  413. package/dist/modes/print-mode.d.ts +2 -2
  414. package/dist/modes/print-mode.d.ts.map +1 -1
  415. package/dist/modes/print-mode.js +107 -77
  416. package/dist/modes/print-mode.js.map +1 -1
  417. package/dist/modes/rpc/jsonl.d.ts +17 -0
  418. package/dist/modes/rpc/jsonl.d.ts.map +1 -0
  419. package/dist/modes/rpc/jsonl.js +49 -0
  420. package/dist/modes/rpc/jsonl.js.map +1 -0
  421. package/dist/modes/rpc/rpc-client.d.ts +8 -1
  422. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  423. package/dist/modes/rpc/rpc-client.js +22 -16
  424. package/dist/modes/rpc/rpc-client.js.map +1 -1
  425. package/dist/modes/rpc/rpc-mode.d.ts +2 -2
  426. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  427. package/dist/modes/rpc/rpc-mode.js +184 -94
  428. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  429. package/dist/modes/rpc/rpc-types.d.ts +14 -4
  430. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  431. package/dist/modes/rpc/rpc-types.js.map +1 -1
  432. package/dist/package-manager-cli.d.ts +4 -0
  433. package/dist/package-manager-cli.d.ts.map +1 -0
  434. package/dist/package-manager-cli.js +460 -0
  435. package/dist/package-manager-cli.js.map +1 -0
  436. package/dist/utils/changelog.d.ts.map +1 -1
  437. package/dist/utils/changelog.js.map +1 -1
  438. package/dist/utils/child-process.d.ts +12 -0
  439. package/dist/utils/child-process.d.ts.map +1 -0
  440. package/dist/utils/child-process.js +86 -0
  441. package/dist/utils/child-process.js.map +1 -0
  442. package/dist/utils/clipboard-image.d.ts.map +1 -1
  443. package/dist/utils/clipboard-image.js +94 -11
  444. package/dist/utils/clipboard-image.js.map +1 -1
  445. package/dist/utils/clipboard-native.d.ts +1 -0
  446. package/dist/utils/clipboard-native.d.ts.map +1 -1
  447. package/dist/utils/clipboard-native.js.map +1 -1
  448. package/dist/utils/clipboard.d.ts +1 -1
  449. package/dist/utils/clipboard.d.ts.map +1 -1
  450. package/dist/utils/clipboard.js +96 -46
  451. package/dist/utils/clipboard.js.map +1 -1
  452. package/dist/utils/exif-orientation.d.ts +5 -0
  453. package/dist/utils/exif-orientation.d.ts.map +1 -0
  454. package/dist/utils/exif-orientation.js +158 -0
  455. package/dist/utils/exif-orientation.js.map +1 -0
  456. package/dist/utils/frontmatter.d.ts.map +1 -1
  457. package/dist/utils/frontmatter.js.map +1 -1
  458. package/dist/utils/fs-watch.d.ts +5 -0
  459. package/dist/utils/fs-watch.d.ts.map +1 -0
  460. package/dist/utils/fs-watch.js +25 -0
  461. package/dist/utils/fs-watch.js.map +1 -0
  462. package/dist/utils/git.d.ts.map +1 -1
  463. package/dist/utils/git.js.map +1 -1
  464. package/dist/utils/image-convert.d.ts.map +1 -1
  465. package/dist/utils/image-convert.js +5 -1
  466. package/dist/utils/image-convert.js.map +1 -1
  467. package/dist/utils/image-resize.d.ts +5 -5
  468. package/dist/utils/image-resize.d.ts.map +1 -1
  469. package/dist/utils/image-resize.js +51 -95
  470. package/dist/utils/image-resize.js.map +1 -1
  471. package/dist/utils/mime.d.ts.map +1 -1
  472. package/dist/utils/mime.js.map +1 -1
  473. package/dist/utils/paths.d.ts +16 -0
  474. package/dist/utils/paths.d.ts.map +1 -0
  475. package/dist/utils/paths.js +50 -0
  476. package/dist/utils/paths.js.map +1 -0
  477. package/dist/utils/photon.d.ts.map +1 -1
  478. package/dist/utils/photon.js.map +1 -1
  479. package/dist/utils/pi-user-agent.d.ts +2 -0
  480. package/dist/utils/pi-user-agent.d.ts.map +1 -0
  481. package/dist/utils/pi-user-agent.js +5 -0
  482. package/dist/utils/pi-user-agent.js.map +1 -0
  483. package/dist/utils/shell.d.ts +10 -6
  484. package/dist/utils/shell.d.ts.map +1 -1
  485. package/dist/utils/shell.js +29 -25
  486. package/dist/utils/shell.js.map +1 -1
  487. package/dist/utils/sleep.d.ts.map +1 -1
  488. package/dist/utils/sleep.js.map +1 -1
  489. package/dist/utils/tools-manager.d.ts.map +1 -1
  490. package/dist/utils/tools-manager.js +11 -6
  491. package/dist/utils/tools-manager.js.map +1 -1
  492. package/dist/utils/version-check.d.ts +14 -0
  493. package/dist/utils/version-check.d.ts.map +1 -0
  494. package/dist/utils/version-check.js +77 -0
  495. package/dist/utils/version-check.js.map +1 -0
  496. package/docs/compaction.md +394 -0
  497. package/docs/custom-provider.md +646 -0
  498. package/docs/development.md +71 -0
  499. package/docs/docs.json +148 -0
  500. package/docs/extensions.md +2596 -0
  501. package/docs/images/doom-extension.png +0 -0
  502. package/docs/images/exy.png +0 -0
  503. package/docs/images/interactive-mode.png +0 -0
  504. package/docs/images/tree-view.png +0 -0
  505. package/docs/index.md +70 -0
  506. package/docs/json.md +82 -0
  507. package/docs/keybindings.md +197 -0
  508. package/docs/models.md +474 -0
  509. package/docs/packages.md +223 -0
  510. package/docs/prompt-templates.md +88 -0
  511. package/docs/providers.md +243 -0
  512. package/docs/quickstart.md +142 -0
  513. package/docs/rpc.md +1407 -0
  514. package/docs/sdk.md +1149 -0
  515. package/docs/session-format.md +412 -0
  516. package/docs/sessions.md +137 -0
  517. package/docs/settings.md +279 -0
  518. package/docs/shell-aliases.md +13 -0
  519. package/docs/skills.md +232 -0
  520. package/docs/terminal-setup.md +106 -0
  521. package/docs/termux.md +127 -0
  522. package/docs/themes.md +295 -0
  523. package/docs/tmux.md +61 -0
  524. package/docs/tui.md +918 -0
  525. package/docs/usage.md +277 -0
  526. package/docs/windows.md +17 -0
  527. package/examples/README.md +25 -0
  528. package/examples/extensions/README.md +208 -0
  529. package/examples/extensions/auto-commit-on-exit.ts +49 -0
  530. package/examples/extensions/bash-spawn-hook.ts +30 -0
  531. package/examples/extensions/bookmark.ts +50 -0
  532. package/examples/extensions/border-status-editor.ts +150 -0
  533. package/examples/extensions/built-in-tool-renderer.ts +249 -0
  534. package/examples/extensions/claude-rules.ts +86 -0
  535. package/examples/extensions/commands.ts +72 -0
  536. package/examples/extensions/confirm-destructive.ts +59 -0
  537. package/examples/extensions/custom-compaction.ts +127 -0
  538. package/examples/extensions/custom-footer.ts +64 -0
  539. package/examples/extensions/custom-header.ts +73 -0
  540. package/examples/extensions/custom-provider-anthropic/index.ts +604 -0
  541. package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
  542. package/examples/extensions/custom-provider-anthropic/package.json +19 -0
  543. package/examples/extensions/custom-provider-gitlab-duo/index.ts +349 -0
  544. package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
  545. package/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -0
  546. package/examples/extensions/dirty-repo-guard.ts +56 -0
  547. package/examples/extensions/doom-overlay/README.md +46 -0
  548. package/examples/extensions/doom-overlay/doom/build/doom.js +21 -0
  549. package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  550. package/examples/extensions/doom-overlay/doom/build.sh +152 -0
  551. package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
  552. package/examples/extensions/doom-overlay/doom-component.ts +132 -0
  553. package/examples/extensions/doom-overlay/doom-engine.ts +173 -0
  554. package/examples/extensions/doom-overlay/doom-keys.ts +104 -0
  555. package/examples/extensions/doom-overlay/index.ts +74 -0
  556. package/examples/extensions/doom-overlay/wad-finder.ts +51 -0
  557. package/examples/extensions/dynamic-resources/SKILL.md +8 -0
  558. package/examples/extensions/dynamic-resources/dynamic.json +79 -0
  559. package/examples/extensions/dynamic-resources/dynamic.md +5 -0
  560. package/examples/extensions/dynamic-resources/index.ts +15 -0
  561. package/examples/extensions/dynamic-tools.ts +74 -0
  562. package/examples/extensions/event-bus.ts +43 -0
  563. package/examples/extensions/file-trigger.ts +41 -0
  564. package/examples/extensions/git-checkpoint.ts +53 -0
  565. package/examples/extensions/github-issue-autocomplete.ts +185 -0
  566. package/examples/extensions/handoff.ts +191 -0
  567. package/examples/extensions/hello.ts +26 -0
  568. package/examples/extensions/hidden-thinking-label.ts +53 -0
  569. package/examples/extensions/inline-bash.ts +94 -0
  570. package/examples/extensions/input-transform.ts +43 -0
  571. package/examples/extensions/interactive-shell.ts +196 -0
  572. package/examples/extensions/mac-system-theme.ts +47 -0
  573. package/examples/extensions/message-renderer.ts +59 -0
  574. package/examples/extensions/minimal-mode.ts +426 -0
  575. package/examples/extensions/modal-editor.ts +85 -0
  576. package/examples/extensions/model-status.ts +31 -0
  577. package/examples/extensions/notify.ts +55 -0
  578. package/examples/extensions/overlay-qa-tests.ts +1348 -0
  579. package/examples/extensions/overlay-test.ts +150 -0
  580. package/examples/extensions/permission-gate.ts +34 -0
  581. package/examples/extensions/pirate.ts +47 -0
  582. package/examples/extensions/plan-mode/README.md +65 -0
  583. package/examples/extensions/plan-mode/index.ts +340 -0
  584. package/examples/extensions/plan-mode/utils.ts +168 -0
  585. package/examples/extensions/preset.ts +430 -0
  586. package/examples/extensions/prompt-customizer.ts +97 -0
  587. package/examples/extensions/protected-paths.ts +30 -0
  588. package/examples/extensions/provider-payload.ts +18 -0
  589. package/examples/extensions/qna.ts +122 -0
  590. package/examples/extensions/question.ts +264 -0
  591. package/examples/extensions/questionnaire.ts +427 -0
  592. package/examples/extensions/rainbow-editor.ts +88 -0
  593. package/examples/extensions/reload-runtime.ts +37 -0
  594. package/examples/extensions/rpc-demo.ts +118 -0
  595. package/examples/extensions/sandbox/index.ts +321 -0
  596. package/examples/extensions/sandbox/package-lock.json +92 -0
  597. package/examples/extensions/sandbox/package.json +19 -0
  598. package/examples/extensions/send-user-message.ts +97 -0
  599. package/examples/extensions/session-name.ts +27 -0
  600. package/examples/extensions/shutdown-command.ts +63 -0
  601. package/examples/extensions/snake.ts +343 -0
  602. package/examples/extensions/space-invaders.ts +560 -0
  603. package/examples/extensions/ssh.ts +220 -0
  604. package/examples/extensions/status-line.ts +32 -0
  605. package/examples/extensions/structured-output.ts +65 -0
  606. package/examples/extensions/subagent/README.md +172 -0
  607. package/examples/extensions/subagent/agents/planner.md +37 -0
  608. package/examples/extensions/subagent/agents/reviewer.md +35 -0
  609. package/examples/extensions/subagent/agents/scout.md +50 -0
  610. package/examples/extensions/subagent/agents/worker.md +24 -0
  611. package/examples/extensions/subagent/agents.ts +126 -0
  612. package/examples/extensions/subagent/index.ts +987 -0
  613. package/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
  614. package/examples/extensions/subagent/prompts/implement.md +10 -0
  615. package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
  616. package/examples/extensions/summarize.ts +206 -0
  617. package/examples/extensions/system-prompt-header.ts +17 -0
  618. package/examples/extensions/tic-tac-toe.ts +1008 -0
  619. package/examples/extensions/timed-confirm.ts +70 -0
  620. package/examples/extensions/titlebar-spinner.ts +58 -0
  621. package/examples/extensions/todo.ts +297 -0
  622. package/examples/extensions/tool-override.ts +144 -0
  623. package/examples/extensions/tools.ts +141 -0
  624. package/examples/extensions/trigger-compact.ts +50 -0
  625. package/examples/extensions/truncated-tool.ts +195 -0
  626. package/examples/extensions/widget-placement.ts +9 -0
  627. package/examples/extensions/with-deps/index.ts +32 -0
  628. package/examples/extensions/with-deps/package-lock.json +31 -0
  629. package/examples/extensions/with-deps/package.json +22 -0
  630. package/examples/extensions/working-indicator.ts +123 -0
  631. package/examples/extensions/working-message-test.ts +25 -0
  632. package/examples/rpc-extension-ui.ts +632 -0
  633. package/examples/sdk/01-minimal.ts +22 -0
  634. package/examples/sdk/02-custom-model.ts +49 -0
  635. package/examples/sdk/03-custom-prompt.ts +62 -0
  636. package/examples/sdk/04-skills.ts +55 -0
  637. package/examples/sdk/05-tools.ts +44 -0
  638. package/examples/sdk/06-extensions.ts +90 -0
  639. package/examples/sdk/07-context-files.ts +42 -0
  640. package/examples/sdk/08-prompt-templates.ts +51 -0
  641. package/examples/sdk/09-api-keys-and-oauth.ts +48 -0
  642. package/examples/sdk/10-settings.ts +53 -0
  643. package/examples/sdk/11-sessions.ts +48 -0
  644. package/examples/sdk/12-full-control.ts +73 -0
  645. package/examples/sdk/13-session-runtime.ts +67 -0
  646. package/examples/sdk/README.md +147 -0
  647. package/extensions/phi/init.ts +15 -1
  648. package/extensions/phi/keys.ts +186 -0
  649. package/extensions/phi/providers/alibaba.ts +126 -0
  650. package/extensions/phi/providers/opencode-go.ts +204 -0
  651. package/extensions/phi/setup.ts +692 -0
  652. package/extensions/phi/smart-router.ts +8 -0
  653. package/extensions/phi/web-search.ts +432 -186
  654. package/package.json +111 -106
  655. package/scripts/copy-assets.sh +0 -0
  656. package/scripts/migrate-sessions.sh +0 -0
@@ -2,18 +2,61 @@ import { spawn, spawnSync } from "node:child_process";
2
2
  import { createHash } from "node:crypto";
3
3
  import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
4
4
  import { homedir, tmpdir } from "node:os";
5
+ function getEnv() {
6
+ if (process.platform !== "linux" || Object.keys(process.env).length > 0) {
7
+ return process.env;
8
+ }
9
+ try {
10
+ const data = readFileSync("/proc/self/environ", "utf-8");
11
+ const env = {};
12
+ for (const entry of data.split("\0")) {
13
+ const idx = entry.indexOf("=");
14
+ if (idx > 0) {
15
+ env[entry.slice(0, idx)] = entry.slice(idx + 1);
16
+ }
17
+ }
18
+ return env;
19
+ }
20
+ catch {
21
+ return process.env;
22
+ }
23
+ }
5
24
  import { basename, dirname, join, relative, resolve, sep } from "node:path";
25
+ import { globSync } from "glob";
6
26
  import ignore from "ignore";
7
27
  import { minimatch } from "minimatch";
8
28
  import { CONFIG_DIR_NAME } from "../config.js";
29
+ import { shouldUseWindowsShell } from "../utils/child-process.js";
9
30
  import { parseGitUrl } from "../utils/git.js";
31
+ import { canonicalizePath, isLocalPath } from "../utils/paths.js";
32
+ import { isStdoutTakenOver } from "./output-guard.js";
10
33
  const NETWORK_TIMEOUT_MS = 10000;
34
+ const UPDATE_CHECK_CONCURRENCY = 4;
35
+ const GIT_UPDATE_CONCURRENCY = 4;
11
36
  function isOfflineModeEnabled() {
12
37
  const value = process.env.PI_OFFLINE;
13
38
  if (!value)
14
39
  return false;
15
40
  return value === "1" || value.toLowerCase() === "true" || value.toLowerCase() === "yes";
16
41
  }
42
+ /**
43
+ * Compute a numeric precedence rank for a resource based on its metadata.
44
+ * Lower rank = higher precedence. Used to sort resolved resources so that
45
+ * name-collision resolution ("first wins") produces the correct outcome.
46
+ *
47
+ * Precedence (highest to lowest):
48
+ * 0 project + settings entry (source: "local", scope: "project")
49
+ * 1 project + auto-discovered (source: "auto", scope: "project")
50
+ * 2 user + settings entry (source: "local", scope: "user")
51
+ * 3 user + auto-discovered (source: "auto", scope: "user")
52
+ * 4 package resource (origin: "package")
53
+ */
54
+ function resourcePrecedenceRank(m) {
55
+ if (m.origin === "package")
56
+ return 4;
57
+ const scopeBase = m.scope === "project" ? 0 : 2;
58
+ return scopeBase + (m.source === "local" ? 0 : 1);
59
+ }
17
60
  const RESOURCE_TYPES = ["extensions", "skills", "prompts", "themes"];
18
61
  const FILE_PATTERNS = {
19
62
  extensions: /\.(ts|js)$/,
@@ -25,6 +68,9 @@ const IGNORE_FILE_NAMES = [".gitignore", ".ignore", ".fdignore"];
25
68
  function toPosixPath(p) {
26
69
  return p.split(sep).join("/");
27
70
  }
71
+ function getHomeDir() {
72
+ return process.env.HOME || homedir();
73
+ }
28
74
  function prefixIgnorePattern(line, prefix) {
29
75
  const trimmed = line.trim();
30
76
  if (!trimmed)
@@ -69,6 +115,12 @@ function addIgnoreRules(ig, dir, rootDir) {
69
115
  function isPattern(s) {
70
116
  return s.startsWith("!") || s.startsWith("+") || s.startsWith("-") || s.includes("*") || s.includes("?");
71
117
  }
118
+ function isOverridePattern(s) {
119
+ return s.startsWith("!") || s.startsWith("+") || s.startsWith("-");
120
+ }
121
+ function hasGlobPattern(s) {
122
+ return s.includes("*") || s.includes("?");
123
+ }
72
124
  function splitPatterns(entries) {
73
125
  const plain = [];
74
126
  const patterns = [];
@@ -126,7 +178,7 @@ function collectFiles(dir, filePattern, skipNodeModules = true, ignoreMatcher, r
126
178
  }
127
179
  return files;
128
180
  }
129
- function collectSkillEntries(dir, includeRootFiles = true, ignoreMatcher, rootDir) {
181
+ function collectSkillEntries(dir, mode, ignoreMatcher, rootDir) {
130
182
  const entries = [];
131
183
  if (!existsSync(dir))
132
184
  return entries;
@@ -135,6 +187,26 @@ function collectSkillEntries(dir, includeRootFiles = true, ignoreMatcher, rootDi
135
187
  addIgnoreRules(ig, dir, root);
136
188
  try {
137
189
  const dirEntries = readdirSync(dir, { withFileTypes: true });
190
+ for (const entry of dirEntries) {
191
+ if (entry.name !== "SKILL.md") {
192
+ continue;
193
+ }
194
+ const fullPath = join(dir, entry.name);
195
+ let isFile = entry.isFile();
196
+ if (entry.isSymbolicLink()) {
197
+ try {
198
+ isFile = statSync(fullPath).isFile();
199
+ }
200
+ catch {
201
+ continue;
202
+ }
203
+ }
204
+ const relPath = toPosixPath(relative(root, fullPath));
205
+ if (isFile && !ig.ignores(relPath)) {
206
+ entries.push(fullPath);
207
+ return entries;
208
+ }
209
+ }
138
210
  for (const entry of dirEntries) {
139
211
  if (entry.name.startsWith("."))
140
212
  continue;
@@ -154,19 +226,15 @@ function collectSkillEntries(dir, includeRootFiles = true, ignoreMatcher, rootDi
154
226
  }
155
227
  }
156
228
  const relPath = toPosixPath(relative(root, fullPath));
157
- const ignorePath = isDir ? `${relPath}/` : relPath;
158
- if (ig.ignores(ignorePath))
229
+ if (mode === "pi" && dir === root && isFile && entry.name.endsWith(".md") && !ig.ignores(relPath)) {
230
+ entries.push(fullPath);
159
231
  continue;
160
- if (isDir) {
161
- entries.push(...collectSkillEntries(fullPath, false, ig, root));
162
- }
163
- else if (isFile) {
164
- const isRootMd = includeRootFiles && entry.name.endsWith(".md");
165
- const isSkillMd = !includeRootFiles && entry.name === "SKILL.md";
166
- if (isRootMd || isSkillMd) {
167
- entries.push(fullPath);
168
- }
169
232
  }
233
+ if (!isDir)
234
+ continue;
235
+ if (ig.ignores(`${relPath}/`))
236
+ continue;
237
+ entries.push(...collectSkillEntries(fullPath, mode, ig, root));
170
238
  }
171
239
  }
172
240
  catch {
@@ -174,8 +242,8 @@ function collectSkillEntries(dir, includeRootFiles = true, ignoreMatcher, rootDi
174
242
  }
175
243
  return entries;
176
244
  }
177
- function collectAutoSkillEntries(dir, includeRootFiles = true) {
178
- return collectSkillEntries(dir, includeRootFiles);
245
+ function collectAutoSkillEntries(dir, mode) {
246
+ return collectSkillEntries(dir, mode);
179
247
  }
180
248
  function findGitRepoRoot(startDir) {
181
249
  let dir = resolve(startDir);
@@ -375,7 +443,7 @@ function collectAutoExtensionEntries(dir) {
375
443
  */
376
444
  function collectResourceFiles(dir, resourceType) {
377
445
  if (resourceType === "skills") {
378
- return collectSkillEntries(dir);
446
+ return collectSkillEntries(dir, "pi");
379
447
  }
380
448
  if (resourceType === "extensions") {
381
449
  return collectAutoExtensionEntries(dir);
@@ -383,43 +451,50 @@ function collectResourceFiles(dir, resourceType) {
383
451
  return collectFiles(dir, FILE_PATTERNS[resourceType]);
384
452
  }
385
453
  function matchesAnyPattern(filePath, patterns, baseDir) {
386
- const rel = relative(baseDir, filePath);
454
+ const rel = toPosixPath(relative(baseDir, filePath));
387
455
  const name = basename(filePath);
456
+ const filePathPosix = toPosixPath(filePath);
388
457
  const isSkillFile = name === "SKILL.md";
389
458
  const parentDir = isSkillFile ? dirname(filePath) : undefined;
390
- const parentRel = isSkillFile ? relative(baseDir, parentDir) : undefined;
459
+ const parentRel = isSkillFile ? toPosixPath(relative(baseDir, parentDir)) : undefined;
391
460
  const parentName = isSkillFile ? basename(parentDir) : undefined;
461
+ const parentDirPosix = isSkillFile ? toPosixPath(parentDir) : undefined;
392
462
  return patterns.some((pattern) => {
393
- if (minimatch(rel, pattern) || minimatch(name, pattern) || minimatch(filePath, pattern)) {
463
+ const normalizedPattern = toPosixPath(pattern);
464
+ if (minimatch(rel, normalizedPattern) ||
465
+ minimatch(name, normalizedPattern) ||
466
+ minimatch(filePathPosix, normalizedPattern)) {
394
467
  return true;
395
468
  }
396
469
  if (!isSkillFile)
397
470
  return false;
398
- return minimatch(parentRel, pattern) || minimatch(parentName, pattern) || minimatch(parentDir, pattern);
471
+ return (minimatch(parentRel, normalizedPattern) ||
472
+ minimatch(parentName, normalizedPattern) ||
473
+ minimatch(parentDirPosix, normalizedPattern));
399
474
  });
400
475
  }
401
476
  function normalizeExactPattern(pattern) {
402
- if (pattern.startsWith("./") || pattern.startsWith(".\\")) {
403
- return pattern.slice(2);
404
- }
405
- return pattern;
477
+ const normalized = pattern.startsWith("./") || pattern.startsWith(".\\") ? pattern.slice(2) : pattern;
478
+ return toPosixPath(normalized);
406
479
  }
407
480
  function matchesAnyExactPattern(filePath, patterns, baseDir) {
408
481
  if (patterns.length === 0)
409
482
  return false;
410
- const rel = relative(baseDir, filePath);
483
+ const rel = toPosixPath(relative(baseDir, filePath));
411
484
  const name = basename(filePath);
485
+ const filePathPosix = toPosixPath(filePath);
412
486
  const isSkillFile = name === "SKILL.md";
413
487
  const parentDir = isSkillFile ? dirname(filePath) : undefined;
414
- const parentRel = isSkillFile ? relative(baseDir, parentDir) : undefined;
488
+ const parentRel = isSkillFile ? toPosixPath(relative(baseDir, parentDir)) : undefined;
489
+ const parentDirPosix = isSkillFile ? toPosixPath(parentDir) : undefined;
415
490
  return patterns.some((pattern) => {
416
491
  const normalized = normalizeExactPattern(pattern);
417
- if (normalized === rel || normalized === filePath) {
492
+ if (normalized === rel || normalized === filePathPosix) {
418
493
  return true;
419
494
  }
420
495
  if (!isSkillFile)
421
496
  return false;
422
- return normalized === parentRel || normalized === parentDir;
497
+ return normalized === parentRel || normalized === parentDirPosix;
423
498
  });
424
499
  }
425
500
  function getOverridePatterns(entries) {
@@ -496,6 +571,12 @@ function applyPatterns(allPaths, patterns, baseDir) {
496
571
  return new Set(result);
497
572
  }
498
573
  export class DefaultPackageManager {
574
+ cwd;
575
+ agentDir;
576
+ settingsManager;
577
+ globalNpmRoot;
578
+ globalNpmRootCommandKey;
579
+ progressCallback;
499
580
  constructor(options) {
500
581
  this.cwd = options.cwd;
501
582
  this.agentDir = options.agentDir;
@@ -613,6 +694,30 @@ export class DefaultPackageManager {
613
694
  await this.resolvePackageSources(packageSources, accumulator);
614
695
  return this.toResolvedPaths(accumulator);
615
696
  }
697
+ listConfiguredPackages() {
698
+ const globalSettings = this.settingsManager.getGlobalSettings();
699
+ const projectSettings = this.settingsManager.getProjectSettings();
700
+ const configuredPackages = [];
701
+ for (const pkg of globalSettings.packages ?? []) {
702
+ const source = typeof pkg === "string" ? pkg : pkg.source;
703
+ configuredPackages.push({
704
+ source,
705
+ scope: "user",
706
+ filtered: typeof pkg === "object",
707
+ installedPath: this.getInstalledPath(source, "user"),
708
+ });
709
+ }
710
+ for (const pkg of projectSettings.packages ?? []) {
711
+ const source = typeof pkg === "string" ? pkg : pkg.source;
712
+ configuredPackages.push({
713
+ source,
714
+ scope: "project",
715
+ filtered: typeof pkg === "object",
716
+ installedPath: this.getInstalledPath(source, "project"),
717
+ });
718
+ }
719
+ return configuredPackages;
720
+ }
616
721
  async install(source, options) {
617
722
  const parsed = this.parseSource(source);
618
723
  const scope = options?.local ? "project" : "user";
@@ -635,6 +740,10 @@ export class DefaultPackageManager {
635
740
  throw new Error(`Unsupported install source: ${source}`);
636
741
  });
637
742
  }
743
+ async installAndPersist(source, options) {
744
+ await this.install(source, options);
745
+ this.addSourceToSettings(source, options);
746
+ }
638
747
  async remove(source, options) {
639
748
  const parsed = this.parseSource(source);
640
749
  const scope = options?.local ? "project" : "user";
@@ -653,44 +762,178 @@ export class DefaultPackageManager {
653
762
  throw new Error(`Unsupported remove source: ${source}`);
654
763
  });
655
764
  }
765
+ async removeAndPersist(source, options) {
766
+ await this.remove(source, options);
767
+ return this.removeSourceFromSettings(source, options);
768
+ }
656
769
  async update(source) {
657
770
  const globalSettings = this.settingsManager.getGlobalSettings();
658
771
  const projectSettings = this.settingsManager.getProjectSettings();
659
772
  const identity = source ? this.getPackageIdentity(source) : undefined;
773
+ let matched = false;
774
+ const updateSources = [];
660
775
  for (const pkg of globalSettings.packages ?? []) {
661
776
  const sourceStr = typeof pkg === "string" ? pkg : pkg.source;
662
777
  if (identity && this.getPackageIdentity(sourceStr, "user") !== identity)
663
778
  continue;
664
- await this.updateSourceForScope(sourceStr, "user");
779
+ matched = true;
780
+ updateSources.push({ source: sourceStr, scope: "user" });
665
781
  }
666
782
  for (const pkg of projectSettings.packages ?? []) {
667
783
  const sourceStr = typeof pkg === "string" ? pkg : pkg.source;
668
784
  if (identity && this.getPackageIdentity(sourceStr, "project") !== identity)
669
785
  continue;
670
- await this.updateSourceForScope(sourceStr, "project");
786
+ matched = true;
787
+ updateSources.push({ source: sourceStr, scope: "project" });
788
+ }
789
+ if (source && !matched) {
790
+ throw new Error(this.buildNoMatchingPackageMessage(source, [
791
+ ...(globalSettings.packages ?? []),
792
+ ...(projectSettings.packages ?? []),
793
+ ]));
671
794
  }
795
+ await this.updateConfiguredSources(updateSources);
672
796
  }
673
- async updateSourceForScope(source, scope) {
674
- if (isOfflineModeEnabled()) {
797
+ async updateConfiguredSources(sources) {
798
+ if (isOfflineModeEnabled() || sources.length === 0) {
675
799
  return;
676
800
  }
677
- const parsed = this.parseSource(source);
678
- if (parsed.type === "npm") {
679
- if (parsed.pinned)
680
- return;
681
- await this.withProgress("update", source, `Updating ${source}...`, async () => {
682
- await this.installNpm(parsed, scope, false);
683
- });
801
+ const npmCandidates = [];
802
+ const gitCandidates = [];
803
+ for (const entry of sources) {
804
+ const parsed = this.parseSource(entry.source);
805
+ if (parsed.type === "local" || parsed.pinned) {
806
+ continue;
807
+ }
808
+ if (parsed.type === "npm") {
809
+ npmCandidates.push({ ...entry, parsed });
810
+ continue;
811
+ }
812
+ gitCandidates.push({ ...entry, parsed });
813
+ }
814
+ const npmCheckTasks = npmCandidates.map((entry) => async () => ({
815
+ entry,
816
+ shouldUpdate: await this.shouldUpdateNpmSource(entry.parsed, entry.scope),
817
+ }));
818
+ const npmCheckResults = await this.runWithConcurrency(npmCheckTasks, UPDATE_CHECK_CONCURRENCY);
819
+ const userNpmUpdates = [];
820
+ const projectNpmUpdates = [];
821
+ for (const result of npmCheckResults) {
822
+ if (!result.shouldUpdate) {
823
+ continue;
824
+ }
825
+ if (result.entry.scope === "user") {
826
+ userNpmUpdates.push(result.entry);
827
+ }
828
+ else {
829
+ projectNpmUpdates.push(result.entry);
830
+ }
831
+ }
832
+ const tasks = [];
833
+ if (userNpmUpdates.length > 0) {
834
+ tasks.push(this.updateNpmBatch(userNpmUpdates, "user"));
835
+ }
836
+ if (projectNpmUpdates.length > 0) {
837
+ tasks.push(this.updateNpmBatch(projectNpmUpdates, "project"));
838
+ }
839
+ if (gitCandidates.length > 0) {
840
+ const gitTasks = gitCandidates.map((entry) => async () => this.withProgress("update", entry.source, `Updating ${entry.source}...`, async () => {
841
+ await this.updateGit(entry.parsed, entry.scope);
842
+ }));
843
+ tasks.push(this.runWithConcurrency(gitTasks, GIT_UPDATE_CONCURRENCY).then(() => { }));
844
+ }
845
+ await Promise.all(tasks);
846
+ }
847
+ async shouldUpdateNpmSource(source, scope) {
848
+ const installedPath = this.getNpmInstallPath(source, scope);
849
+ const installedVersion = existsSync(installedPath) ? this.getInstalledNpmVersion(installedPath) : undefined;
850
+ if (!installedVersion) {
851
+ return true;
852
+ }
853
+ try {
854
+ const latestVersion = await this.getLatestNpmVersion(source.name);
855
+ return latestVersion !== installedVersion;
856
+ }
857
+ catch {
858
+ // Preserve existing update behavior when version lookup fails.
859
+ return true;
860
+ }
861
+ }
862
+ async updateNpmBatch(sources, scope) {
863
+ if (sources.length === 0) {
684
864
  return;
685
865
  }
686
- if (parsed.type === "git") {
687
- if (parsed.pinned)
688
- return;
689
- await this.withProgress("update", source, `Updating ${source}...`, async () => {
690
- await this.updateGit(parsed, scope);
691
- });
866
+ const sourceLabel = sources.length === 1 ? sources[0].source : `${scope} npm packages`;
867
+ const message = sources.length === 1 ? `Updating ${sources[0].source}...` : `Updating ${scope} npm packages...`;
868
+ const specs = sources.map((entry) => `${entry.parsed.name}@latest`);
869
+ await this.withProgress("update", sourceLabel, message, async () => {
870
+ await this.installNpmBatch(specs, scope);
871
+ });
872
+ }
873
+ async installNpmBatch(specs, scope) {
874
+ if (scope === "user") {
875
+ await this.runNpmCommand(["install", "-g", ...specs]);
692
876
  return;
693
877
  }
878
+ const installRoot = this.getNpmInstallRoot(scope, false);
879
+ this.ensureNpmProject(installRoot);
880
+ await this.runNpmCommand(["install", ...specs, "--prefix", installRoot]);
881
+ }
882
+ async checkForAvailableUpdates() {
883
+ if (isOfflineModeEnabled()) {
884
+ return [];
885
+ }
886
+ const globalSettings = this.settingsManager.getGlobalSettings();
887
+ const projectSettings = this.settingsManager.getProjectSettings();
888
+ const allPackages = [];
889
+ for (const pkg of projectSettings.packages ?? []) {
890
+ allPackages.push({ pkg, scope: "project" });
891
+ }
892
+ for (const pkg of globalSettings.packages ?? []) {
893
+ allPackages.push({ pkg, scope: "user" });
894
+ }
895
+ const packageSources = this.dedupePackages(allPackages);
896
+ const checks = packageSources
897
+ .filter((entry) => entry.scope !== "temporary")
898
+ .map((entry) => async () => {
899
+ const source = typeof entry.pkg === "string" ? entry.pkg : entry.pkg.source;
900
+ const parsed = this.parseSource(source);
901
+ if (parsed.type === "local" || parsed.pinned) {
902
+ return undefined;
903
+ }
904
+ if (parsed.type === "npm") {
905
+ const installedPath = this.getNpmInstallPath(parsed, entry.scope);
906
+ if (!existsSync(installedPath)) {
907
+ return undefined;
908
+ }
909
+ const hasUpdate = await this.npmHasAvailableUpdate(parsed, installedPath);
910
+ if (!hasUpdate) {
911
+ return undefined;
912
+ }
913
+ return {
914
+ source,
915
+ displayName: parsed.name,
916
+ type: "npm",
917
+ scope: entry.scope,
918
+ };
919
+ }
920
+ const installedPath = this.getGitInstallPath(parsed, entry.scope);
921
+ if (!existsSync(installedPath)) {
922
+ return undefined;
923
+ }
924
+ const hasUpdate = await this.gitHasAvailableUpdate(installedPath);
925
+ if (!hasUpdate) {
926
+ return undefined;
927
+ }
928
+ return {
929
+ source,
930
+ displayName: `${parsed.host}/${parsed.path}`,
931
+ type: "git",
932
+ scope: entry.scope,
933
+ };
934
+ });
935
+ const results = await this.runWithConcurrency(checks, UPDATE_CHECK_CONCURRENCY);
936
+ return results.filter((result) => result !== undefined);
694
937
  }
695
938
  async resolvePackageSources(sources, accumulator, onMissing) {
696
939
  for (const { pkg, scope } of sources) {
@@ -721,7 +964,8 @@ export class DefaultPackageManager {
721
964
  };
722
965
  if (parsed.type === "npm") {
723
966
  const installedPath = this.getNpmInstallPath(parsed, scope);
724
- const needsInstall = !existsSync(installedPath) || (await this.npmNeedsUpdate(parsed, installedPath));
967
+ const needsInstall = !existsSync(installedPath) ||
968
+ (parsed.pinned && !(await this.installedNpmMatchesPinnedVersion(parsed, installedPath)));
725
969
  if (needsInstall) {
726
970
  const installed = await installMissing();
727
971
  if (!installed)
@@ -804,6 +1048,35 @@ export class DefaultPackageManager {
804
1048
  const baseDir = this.getBaseDirForScope(scope);
805
1049
  return `local:${this.resolvePathFromBase(parsed.path, baseDir)}`;
806
1050
  }
1051
+ buildNoMatchingPackageMessage(source, configuredPackages) {
1052
+ const suggestion = this.findSuggestedConfiguredSource(source, configuredPackages);
1053
+ if (!suggestion) {
1054
+ return `No matching package found for ${source}`;
1055
+ }
1056
+ return `No matching package found for ${source}. Did you mean ${suggestion}?`;
1057
+ }
1058
+ findSuggestedConfiguredSource(source, configuredPackages) {
1059
+ const trimmedSource = source.trim();
1060
+ const suggestions = new Set();
1061
+ for (const pkg of configuredPackages) {
1062
+ const sourceStr = this.getPackageSourceString(pkg);
1063
+ const parsed = this.parseSource(sourceStr);
1064
+ if (parsed.type === "npm") {
1065
+ if (trimmedSource === parsed.name || trimmedSource === parsed.spec) {
1066
+ suggestions.add(sourceStr);
1067
+ }
1068
+ continue;
1069
+ }
1070
+ if (parsed.type === "git") {
1071
+ const shorthand = `${parsed.host}/${parsed.path}`;
1072
+ const shorthandWithRef = parsed.ref ? `${shorthand}@${parsed.ref}` : undefined;
1073
+ if (trimmedSource === shorthand || (shorthandWithRef && trimmedSource === shorthandWithRef)) {
1074
+ suggestions.add(sourceStr);
1075
+ }
1076
+ }
1077
+ }
1078
+ return suggestions.values().next().value;
1079
+ }
807
1080
  packageSourcesMatch(existing, inputSource, scope) {
808
1081
  const left = this.getSourceMatchKeyForSettings(this.getPackageSourceString(existing), scope);
809
1082
  const right = this.getSourceMatchKeyForInput(inputSource);
@@ -830,14 +1103,7 @@ export class DefaultPackageManager {
830
1103
  pinned: Boolean(version),
831
1104
  };
832
1105
  }
833
- const trimmed = source.trim();
834
- const isWindowsAbsolutePath = /^[A-Za-z]:[\\/]|^\\\\/.test(trimmed);
835
- const isLocalPathLike = trimmed.startsWith(".") ||
836
- trimmed.startsWith("/") ||
837
- trimmed === "~" ||
838
- trimmed.startsWith("~/") ||
839
- isWindowsAbsolutePath;
840
- if (isLocalPathLike) {
1106
+ if (isLocalPath(source)) {
841
1107
  return { type: "local", path: source };
842
1108
  }
843
1109
  // Try parsing as git URL
@@ -847,30 +1113,30 @@ export class DefaultPackageManager {
847
1113
  }
848
1114
  return { type: "local", path: source };
849
1115
  }
850
- /**
851
- * Check if an npm package needs to be updated.
852
- * - For unpinned packages: check if registry has a newer version
853
- * - For pinned packages: check if installed version matches the pinned version
854
- */
855
- async npmNeedsUpdate(source, installedPath) {
1116
+ async installedNpmMatchesPinnedVersion(source, installedPath) {
1117
+ const installedVersion = this.getInstalledNpmVersion(installedPath);
1118
+ if (!installedVersion) {
1119
+ return false;
1120
+ }
1121
+ const { version: pinnedVersion } = this.parseNpmSpec(source.spec);
1122
+ if (!pinnedVersion) {
1123
+ return true;
1124
+ }
1125
+ return installedVersion === pinnedVersion;
1126
+ }
1127
+ async npmHasAvailableUpdate(source, installedPath) {
856
1128
  if (isOfflineModeEnabled()) {
857
1129
  return false;
858
1130
  }
859
1131
  const installedVersion = this.getInstalledNpmVersion(installedPath);
860
- if (!installedVersion)
861
- return true;
862
- const { version: pinnedVersion } = this.parseNpmSpec(source.spec);
863
- if (pinnedVersion) {
864
- // Pinned: check if installed matches pinned (exact match for now)
865
- return installedVersion !== pinnedVersion;
1132
+ if (!installedVersion) {
1133
+ return false;
866
1134
  }
867
- // Unpinned: check registry for latest version
868
1135
  try {
869
1136
  const latestVersion = await this.getLatestNpmVersion(source.name);
870
1137
  return latestVersion !== installedVersion;
871
1138
  }
872
1139
  catch {
873
- // If we can't check registry, assume it's fine
874
1140
  return false;
875
1141
  }
876
1142
  }
@@ -888,13 +1154,151 @@ export class DefaultPackageManager {
888
1154
  }
889
1155
  }
890
1156
  async getLatestNpmVersion(packageName) {
891
- const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`, {
892
- signal: AbortSignal.timeout(NETWORK_TIMEOUT_MS),
1157
+ const npmCommand = this.getNpmCommand();
1158
+ const stdout = await this.runCommandCapture(npmCommand.command, [...npmCommand.args, "view", packageName, "version", "--json"], { cwd: this.cwd, timeoutMs: NETWORK_TIMEOUT_MS });
1159
+ const raw = stdout.trim();
1160
+ if (!raw)
1161
+ throw new Error("Empty response from npm view");
1162
+ return JSON.parse(raw);
1163
+ }
1164
+ async gitHasAvailableUpdate(installedPath) {
1165
+ if (isOfflineModeEnabled()) {
1166
+ return false;
1167
+ }
1168
+ try {
1169
+ const localHead = await this.runCommandCapture("git", ["rev-parse", "HEAD"], {
1170
+ cwd: installedPath,
1171
+ timeoutMs: NETWORK_TIMEOUT_MS,
1172
+ });
1173
+ const remoteHead = await this.getRemoteGitHead(installedPath);
1174
+ return localHead.trim() !== remoteHead.trim();
1175
+ }
1176
+ catch {
1177
+ return false;
1178
+ }
1179
+ }
1180
+ async getRemoteGitHead(installedPath) {
1181
+ const upstreamRef = await this.getGitUpstreamRef(installedPath);
1182
+ if (upstreamRef) {
1183
+ const remoteHead = await this.runGitRemoteCommand(installedPath, ["ls-remote", "origin", upstreamRef]);
1184
+ const match = remoteHead.match(/^([0-9a-f]{40})\s+/m);
1185
+ if (match?.[1]) {
1186
+ return match[1];
1187
+ }
1188
+ }
1189
+ const remoteHead = await this.runGitRemoteCommand(installedPath, ["ls-remote", "origin", "HEAD"]);
1190
+ const match = remoteHead.match(/^([0-9a-f]{40})\s+HEAD$/m);
1191
+ if (!match?.[1]) {
1192
+ throw new Error("Failed to determine remote HEAD");
1193
+ }
1194
+ return match[1];
1195
+ }
1196
+ async getLocalGitUpdateTarget(installedPath) {
1197
+ try {
1198
+ const upstream = await this.runCommandCapture("git", ["rev-parse", "--abbrev-ref", "@{upstream}"], {
1199
+ cwd: installedPath,
1200
+ timeoutMs: NETWORK_TIMEOUT_MS,
1201
+ });
1202
+ const trimmedUpstream = upstream.trim();
1203
+ if (!trimmedUpstream.startsWith("origin/")) {
1204
+ throw new Error(`Unsupported upstream remote: ${trimmedUpstream}`);
1205
+ }
1206
+ const branch = trimmedUpstream.slice("origin/".length);
1207
+ if (!branch) {
1208
+ throw new Error("Missing upstream branch name");
1209
+ }
1210
+ const head = await this.runCommandCapture("git", ["rev-parse", "@{upstream}"], {
1211
+ cwd: installedPath,
1212
+ timeoutMs: NETWORK_TIMEOUT_MS,
1213
+ });
1214
+ return {
1215
+ ref: "@{upstream}",
1216
+ head,
1217
+ fetchArgs: [
1218
+ "fetch",
1219
+ "--prune",
1220
+ "--no-tags",
1221
+ "origin",
1222
+ `+refs/heads/${branch}:refs/remotes/origin/${branch}`,
1223
+ ],
1224
+ };
1225
+ }
1226
+ catch {
1227
+ await this.runCommand("git", ["remote", "set-head", "origin", "-a"], { cwd: installedPath }).catch(() => { });
1228
+ const head = await this.runCommandCapture("git", ["rev-parse", "origin/HEAD"], {
1229
+ cwd: installedPath,
1230
+ timeoutMs: NETWORK_TIMEOUT_MS,
1231
+ });
1232
+ const originHeadRef = await this.runCommandCapture("git", ["symbolic-ref", "refs/remotes/origin/HEAD"], {
1233
+ cwd: installedPath,
1234
+ timeoutMs: NETWORK_TIMEOUT_MS,
1235
+ }).catch(() => "");
1236
+ const branch = originHeadRef.trim().replace(/^refs\/remotes\/origin\//, "");
1237
+ if (branch) {
1238
+ return {
1239
+ ref: "origin/HEAD",
1240
+ head,
1241
+ fetchArgs: [
1242
+ "fetch",
1243
+ "--prune",
1244
+ "--no-tags",
1245
+ "origin",
1246
+ `+refs/heads/${branch}:refs/remotes/origin/${branch}`,
1247
+ ],
1248
+ };
1249
+ }
1250
+ return {
1251
+ ref: "origin/HEAD",
1252
+ head,
1253
+ fetchArgs: ["fetch", "--prune", "--no-tags", "origin", "+HEAD:refs/remotes/origin/HEAD"],
1254
+ };
1255
+ }
1256
+ }
1257
+ async getGitUpstreamRef(installedPath) {
1258
+ try {
1259
+ const upstream = await this.runCommandCapture("git", ["rev-parse", "--abbrev-ref", "@{upstream}"], {
1260
+ cwd: installedPath,
1261
+ timeoutMs: NETWORK_TIMEOUT_MS,
1262
+ });
1263
+ const trimmed = upstream.trim();
1264
+ if (!trimmed.startsWith("origin/")) {
1265
+ return undefined;
1266
+ }
1267
+ const branch = trimmed.slice("origin/".length);
1268
+ return branch ? `refs/heads/${branch}` : undefined;
1269
+ }
1270
+ catch {
1271
+ return undefined;
1272
+ }
1273
+ }
1274
+ runGitRemoteCommand(installedPath, args) {
1275
+ return this.runCommandCapture("git", args, {
1276
+ cwd: installedPath,
1277
+ timeoutMs: NETWORK_TIMEOUT_MS,
1278
+ env: {
1279
+ GIT_TERMINAL_PROMPT: "0",
1280
+ },
893
1281
  });
894
- if (!response.ok)
895
- throw new Error(`Failed to fetch npm registry: ${response.status}`);
896
- const data = (await response.json());
897
- return data.version;
1282
+ }
1283
+ async runWithConcurrency(tasks, limit) {
1284
+ if (tasks.length === 0) {
1285
+ return [];
1286
+ }
1287
+ const results = new Array(tasks.length);
1288
+ let nextIndex = 0;
1289
+ const workerCount = Math.max(1, Math.min(limit, tasks.length));
1290
+ const worker = async () => {
1291
+ while (true) {
1292
+ const index = nextIndex;
1293
+ nextIndex += 1;
1294
+ if (index >= tasks.length) {
1295
+ return;
1296
+ }
1297
+ results[index] = await tasks[index]();
1298
+ }
1299
+ };
1300
+ await Promise.all(Array.from({ length: workerCount }, () => worker()));
1301
+ return results;
898
1302
  }
899
1303
  /**
900
1304
  * Get a unique identity for a package, ignoring version/ref.
@@ -948,25 +1352,51 @@ export class DefaultPackageManager {
948
1352
  const version = match[2];
949
1353
  return { name, version };
950
1354
  }
1355
+ getNpmCommand() {
1356
+ const configuredCommand = this.settingsManager.getNpmCommand();
1357
+ if (!configuredCommand || configuredCommand.length === 0) {
1358
+ return { command: "npm", args: [] };
1359
+ }
1360
+ const [command, ...args] = configuredCommand;
1361
+ if (!command) {
1362
+ throw new Error("Invalid npmCommand: first array entry must be a non-empty command");
1363
+ }
1364
+ return { command, args };
1365
+ }
1366
+ async runNpmCommand(args, options) {
1367
+ const npmCommand = this.getNpmCommand();
1368
+ await this.runCommand(npmCommand.command, [...npmCommand.args, ...args], options);
1369
+ }
1370
+ getGitDependencyInstallArgs() {
1371
+ const configuredCommand = this.settingsManager.getNpmCommand();
1372
+ if (configuredCommand && configuredCommand.length > 0) {
1373
+ return ["install"];
1374
+ }
1375
+ return ["install", "--omit=dev"];
1376
+ }
1377
+ runNpmCommandSync(args) {
1378
+ const npmCommand = this.getNpmCommand();
1379
+ return this.runCommandSync(npmCommand.command, [...npmCommand.args, ...args]);
1380
+ }
951
1381
  async installNpm(source, scope, temporary) {
952
1382
  if (scope === "user" && !temporary) {
953
- await this.runCommand("npm", ["install", "-g", source.spec]);
1383
+ await this.runNpmCommand(["install", "-g", source.spec]);
954
1384
  return;
955
1385
  }
956
1386
  const installRoot = this.getNpmInstallRoot(scope, temporary);
957
1387
  this.ensureNpmProject(installRoot);
958
- await this.runCommand("npm", ["install", source.spec, "--prefix", installRoot]);
1388
+ await this.runNpmCommand(["install", source.spec, "--prefix", installRoot]);
959
1389
  }
960
1390
  async uninstallNpm(source, scope) {
961
1391
  if (scope === "user") {
962
- await this.runCommand("npm", ["uninstall", "-g", source.name]);
1392
+ await this.runNpmCommand(["uninstall", "-g", source.name]);
963
1393
  return;
964
1394
  }
965
1395
  const installRoot = this.getNpmInstallRoot(scope, false);
966
1396
  if (!existsSync(installRoot)) {
967
1397
  return;
968
1398
  }
969
- await this.runCommand("npm", ["uninstall", source.name, "--prefix", installRoot]);
1399
+ await this.runNpmCommand(["uninstall", source.name, "--prefix", installRoot]);
970
1400
  }
971
1401
  async installGit(source, scope) {
972
1402
  const targetDir = this.getGitInstallPath(source, scope);
@@ -984,7 +1414,7 @@ export class DefaultPackageManager {
984
1414
  }
985
1415
  const packageJsonPath = join(targetDir, "package.json");
986
1416
  if (existsSync(packageJsonPath)) {
987
- await this.runCommand("npm", ["install"], { cwd: targetDir });
1417
+ await this.runNpmCommand(this.getGitDependencyInstallArgs(), { cwd: targetDir });
988
1418
  }
989
1419
  }
990
1420
  async updateGit(source, scope) {
@@ -993,21 +1423,26 @@ export class DefaultPackageManager {
993
1423
  await this.installGit(source, scope);
994
1424
  return;
995
1425
  }
996
- // Fetch latest from remote (handles force-push by getting new history)
997
- await this.runCommand("git", ["fetch", "--prune", "origin"], { cwd: targetDir });
998
- // Reset to tracking branch. Fall back to origin/HEAD when no upstream is configured.
999
- try {
1000
- await this.runCommand("git", ["reset", "--hard", "@{upstream}"], { cwd: targetDir });
1001
- }
1002
- catch {
1003
- await this.runCommand("git", ["remote", "set-head", "origin", "-a"], { cwd: targetDir }).catch(() => { });
1004
- await this.runCommand("git", ["reset", "--hard", "origin/HEAD"], { cwd: targetDir });
1426
+ const target = await this.getLocalGitUpdateTarget(targetDir);
1427
+ // Fetch only the ref we will reset to, avoiding unrelated branch/tag noise.
1428
+ await this.runCommand("git", target.fetchArgs, { cwd: targetDir });
1429
+ const localHead = await this.runCommandCapture("git", ["rev-parse", "HEAD"], {
1430
+ cwd: targetDir,
1431
+ timeoutMs: NETWORK_TIMEOUT_MS,
1432
+ });
1433
+ const refreshedTargetHead = await this.runCommandCapture("git", ["rev-parse", target.ref], {
1434
+ cwd: targetDir,
1435
+ timeoutMs: NETWORK_TIMEOUT_MS,
1436
+ });
1437
+ if (localHead.trim() === refreshedTargetHead.trim()) {
1438
+ return;
1005
1439
  }
1440
+ await this.runCommand("git", ["reset", "--hard", target.ref], { cwd: targetDir });
1006
1441
  // Clean untracked files (extensions should be pristine)
1007
1442
  await this.runCommand("git", ["clean", "-fdx"], { cwd: targetDir });
1008
1443
  const packageJsonPath = join(targetDir, "package.json");
1009
1444
  if (existsSync(packageJsonPath)) {
1010
- await this.runCommand("npm", ["install"], { cwd: targetDir });
1445
+ await this.runNpmCommand(this.getGitDependencyInstallArgs(), { cwd: targetDir });
1011
1446
  }
1012
1447
  }
1013
1448
  async refreshTemporaryGitSource(source, sourceStr) {
@@ -1083,11 +1518,20 @@ export class DefaultPackageManager {
1083
1518
  return join(this.getGlobalNpmRoot(), "..");
1084
1519
  }
1085
1520
  getGlobalNpmRoot() {
1086
- if (this.globalNpmRoot) {
1521
+ const npmCommand = this.getNpmCommand();
1522
+ const commandKey = [npmCommand.command, ...npmCommand.args].join("\0");
1523
+ if (this.globalNpmRoot && this.globalNpmRootCommandKey === commandKey) {
1087
1524
  return this.globalNpmRoot;
1088
1525
  }
1089
- const result = this.runCommandSync("npm", ["root", "-g"]);
1090
- this.globalNpmRoot = result.trim();
1526
+ const isBunPackageManager = npmCommand.command === "bun";
1527
+ if (isBunPackageManager) {
1528
+ const binDir = this.runNpmCommandSync(["pm", "bin", "-g"]).trim();
1529
+ this.globalNpmRoot = join(dirname(binDir), "install", "global", "node_modules");
1530
+ }
1531
+ else {
1532
+ this.globalNpmRoot = this.runNpmCommandSync(["root", "-g"]).trim();
1533
+ }
1534
+ this.globalNpmRootCommandKey = commandKey;
1091
1535
  return this.globalNpmRoot;
1092
1536
  }
1093
1537
  getNpmInstallPath(source, scope) {
@@ -1136,21 +1580,21 @@ export class DefaultPackageManager {
1136
1580
  resolvePath(input) {
1137
1581
  const trimmed = input.trim();
1138
1582
  if (trimmed === "~")
1139
- return homedir();
1583
+ return getHomeDir();
1140
1584
  if (trimmed.startsWith("~/"))
1141
- return join(homedir(), trimmed.slice(2));
1585
+ return join(getHomeDir(), trimmed.slice(2));
1142
1586
  if (trimmed.startsWith("~"))
1143
- return join(homedir(), trimmed.slice(1));
1587
+ return join(getHomeDir(), trimmed.slice(1));
1144
1588
  return resolve(this.cwd, trimmed);
1145
1589
  }
1146
1590
  resolvePathFromBase(input, baseDir) {
1147
1591
  const trimmed = input.trim();
1148
1592
  if (trimmed === "~")
1149
- return homedir();
1593
+ return getHomeDir();
1150
1594
  if (trimmed.startsWith("~/"))
1151
- return join(homedir(), trimmed.slice(2));
1595
+ return join(getHomeDir(), trimmed.slice(2));
1152
1596
  if (trimmed.startsWith("~"))
1153
- return join(homedir(), trimmed.slice(1));
1597
+ return join(getHomeDir(), trimmed.slice(1));
1154
1598
  return resolve(baseDir, trimmed);
1155
1599
  }
1156
1600
  collectPackageResources(packageRoot, accumulator, filter, metadata) {
@@ -1231,7 +1675,7 @@ export class DefaultPackageManager {
1231
1675
  const entries = manifest?.[resourceType];
1232
1676
  if (entries && entries.length > 0) {
1233
1677
  const allFiles = this.collectFilesFromManifestEntries(entries, packageRoot, resourceType);
1234
- const manifestPatterns = entries.filter(isPattern);
1678
+ const manifestPatterns = entries.filter(isOverridePattern);
1235
1679
  const enabledByManifest = manifestPatterns.length > 0 ? applyPatterns(allFiles, manifestPatterns, packageRoot) : new Set(allFiles);
1236
1680
  return { allFiles: Array.from(enabledByManifest), enabledByManifest };
1237
1681
  }
@@ -1260,7 +1704,7 @@ export class DefaultPackageManager {
1260
1704
  if (!entries)
1261
1705
  return;
1262
1706
  const allFiles = this.collectFilesFromManifestEntries(entries, root, resourceType);
1263
- const patterns = entries.filter(isPattern);
1707
+ const patterns = entries.filter(isOverridePattern);
1264
1708
  const enabledPaths = applyPatterns(allFiles, patterns, root);
1265
1709
  for (const f of allFiles) {
1266
1710
  if (enabledPaths.has(f)) {
@@ -1269,8 +1713,18 @@ export class DefaultPackageManager {
1269
1713
  }
1270
1714
  }
1271
1715
  collectFilesFromManifestEntries(entries, root, resourceType) {
1272
- const plain = entries.filter((entry) => !isPattern(entry));
1273
- const resolved = plain.map((entry) => resolve(root, entry));
1716
+ const sourceEntries = entries.filter((entry) => !isOverridePattern(entry));
1717
+ const resolved = sourceEntries.flatMap((entry) => {
1718
+ if (!hasGlobPattern(entry)) {
1719
+ return [resolve(root, entry)];
1720
+ }
1721
+ return globSync(entry, {
1722
+ cwd: root,
1723
+ absolute: true,
1724
+ dot: false,
1725
+ nodir: false,
1726
+ }).map((match) => resolve(match));
1727
+ });
1274
1728
  return this.collectFilesFromPaths(resolved, resourceType);
1275
1729
  }
1276
1730
  resolveLocalEntries(entries, resourceType, target, metadata, baseDir) {
@@ -1324,8 +1778,8 @@ export class DefaultPackageManager {
1324
1778
  prompts: join(projectBaseDir, "prompts"),
1325
1779
  themes: join(projectBaseDir, "themes"),
1326
1780
  };
1327
- const userAgentsSkillsDir = join(homedir(), ".agents", "skills");
1328
- const projectAgentsSkillDirs = collectAncestorAgentsSkillDirs(this.cwd);
1781
+ const userAgentsSkillsDir = join(getHomeDir(), ".agents", "skills");
1782
+ const projectAgentsSkillDirs = collectAncestorAgentsSkillDirs(this.cwd).filter((dir) => resolve(dir) !== resolve(userAgentsSkillsDir));
1329
1783
  const addResources = (resourceType, paths, metadata, overrides, baseDir) => {
1330
1784
  const target = this.getTargetMap(accumulator, resourceType);
1331
1785
  for (const path of paths) {
@@ -1333,15 +1787,32 @@ export class DefaultPackageManager {
1333
1787
  this.addResource(target, path, metadata, enabled);
1334
1788
  }
1335
1789
  };
1790
+ // Project extensions from .pi/
1336
1791
  addResources("extensions", collectAutoExtensionEntries(projectDirs.extensions), projectMetadata, projectOverrides.extensions, projectBaseDir);
1337
- addResources("skills", [
1338
- ...collectAutoSkillEntries(projectDirs.skills),
1339
- ...projectAgentsSkillDirs.flatMap((dir) => collectAutoSkillEntries(dir)),
1340
- ], projectMetadata, projectOverrides.skills, projectBaseDir);
1792
+ // Project skills from .pi/
1793
+ addResources("skills", collectAutoSkillEntries(projectDirs.skills, "pi"), projectMetadata, projectOverrides.skills, projectBaseDir);
1794
+ // Project skills from .agents/ (each with its own baseDir)
1795
+ for (const agentsSkillsDir of projectAgentsSkillDirs) {
1796
+ const agentsBaseDir = dirname(agentsSkillsDir); // the .agents directory
1797
+ const agentsMetadata = {
1798
+ ...projectMetadata,
1799
+ baseDir: agentsBaseDir,
1800
+ };
1801
+ addResources("skills", collectAutoSkillEntries(agentsSkillsDir, "agents"), agentsMetadata, projectOverrides.skills, agentsBaseDir);
1802
+ }
1341
1803
  addResources("prompts", collectAutoPromptEntries(projectDirs.prompts), projectMetadata, projectOverrides.prompts, projectBaseDir);
1342
1804
  addResources("themes", collectAutoThemeEntries(projectDirs.themes), projectMetadata, projectOverrides.themes, projectBaseDir);
1805
+ // User extensions from ~/.pi/agent/
1343
1806
  addResources("extensions", collectAutoExtensionEntries(userDirs.extensions), userMetadata, userOverrides.extensions, globalBaseDir);
1344
- addResources("skills", [...collectAutoSkillEntries(userDirs.skills), ...collectAutoSkillEntries(userAgentsSkillsDir)], userMetadata, userOverrides.skills, globalBaseDir);
1807
+ // User skills from ~/.pi/agent/
1808
+ addResources("skills", collectAutoSkillEntries(userDirs.skills, "pi"), userMetadata, userOverrides.skills, globalBaseDir);
1809
+ // User skills from ~/.agents/ (with its own baseDir)
1810
+ const userAgentsBaseDir = dirname(userAgentsSkillsDir);
1811
+ const userAgentsMetadata = {
1812
+ ...userMetadata,
1813
+ baseDir: userAgentsBaseDir,
1814
+ };
1815
+ addResources("skills", collectAutoSkillEntries(userAgentsSkillsDir, "agents"), userAgentsMetadata, userOverrides.skills, userAgentsBaseDir);
1345
1816
  addResources("prompts", collectAutoPromptEntries(userDirs.prompts), userMetadata, userOverrides.prompts, globalBaseDir);
1346
1817
  addResources("themes", collectAutoThemeEntries(userDirs.themes), userMetadata, userOverrides.themes, globalBaseDir);
1347
1818
  }
@@ -1395,27 +1866,88 @@ export class DefaultPackageManager {
1395
1866
  };
1396
1867
  }
1397
1868
  toResolvedPaths(accumulator) {
1398
- const toResolved = (entries) => {
1399
- return Array.from(entries.entries()).map(([path, { metadata, enabled }]) => ({
1869
+ const mapToResolved = (entries) => {
1870
+ const resolved = Array.from(entries.entries()).map(([path, { metadata, enabled }]) => ({
1400
1871
  path,
1401
1872
  enabled,
1402
1873
  metadata,
1403
1874
  }));
1875
+ resolved.sort((a, b) => resourcePrecedenceRank(a.metadata) - resourcePrecedenceRank(b.metadata));
1876
+ const seen = new Set();
1877
+ return resolved.filter((entry) => {
1878
+ const canonicalPath = canonicalizePath(entry.path);
1879
+ if (seen.has(canonicalPath))
1880
+ return false;
1881
+ seen.add(canonicalPath);
1882
+ return true;
1883
+ });
1404
1884
  };
1405
1885
  return {
1406
- extensions: toResolved(accumulator.extensions),
1407
- skills: toResolved(accumulator.skills),
1408
- prompts: toResolved(accumulator.prompts),
1409
- themes: toResolved(accumulator.themes),
1886
+ extensions: mapToResolved(accumulator.extensions),
1887
+ skills: mapToResolved(accumulator.skills),
1888
+ prompts: mapToResolved(accumulator.prompts),
1889
+ themes: mapToResolved(accumulator.themes),
1410
1890
  };
1411
1891
  }
1412
- runCommand(command, args, options) {
1892
+ spawnCommand(command, args, options) {
1893
+ return spawn(command, args, {
1894
+ cwd: options?.cwd,
1895
+ stdio: isStdoutTakenOver() ? ["ignore", 2, 2] : "inherit",
1896
+ shell: shouldUseWindowsShell(command),
1897
+ env: getEnv(),
1898
+ });
1899
+ }
1900
+ spawnCaptureCommand(command, args, options) {
1901
+ const baseEnv = getEnv();
1902
+ return spawn(command, args, {
1903
+ cwd: options?.cwd,
1904
+ stdio: ["ignore", "pipe", "pipe"],
1905
+ shell: shouldUseWindowsShell(command),
1906
+ env: options?.env ? { ...baseEnv, ...options.env } : baseEnv,
1907
+ });
1908
+ }
1909
+ runCommandCapture(command, args, options) {
1413
1910
  return new Promise((resolvePromise, reject) => {
1414
- const child = spawn(command, args, {
1415
- cwd: options?.cwd,
1416
- stdio: "inherit",
1417
- shell: process.platform === "win32",
1911
+ const child = this.spawnCaptureCommand(command, args, options);
1912
+ let stdout = "";
1913
+ let stderr = "";
1914
+ let timedOut = false;
1915
+ const timeout = typeof options?.timeoutMs === "number"
1916
+ ? setTimeout(() => {
1917
+ timedOut = true;
1918
+ child.kill();
1919
+ }, options.timeoutMs)
1920
+ : undefined;
1921
+ child.stdout?.on("data", (data) => {
1922
+ stdout += data.toString();
1923
+ });
1924
+ child.stderr?.on("data", (data) => {
1925
+ stderr += data.toString();
1418
1926
  });
1927
+ child.once("error", (error) => {
1928
+ if (timeout)
1929
+ clearTimeout(timeout);
1930
+ reject(error);
1931
+ });
1932
+ child.once("close", (code, signal) => {
1933
+ if (timeout)
1934
+ clearTimeout(timeout);
1935
+ if (timedOut) {
1936
+ reject(new Error(`${command} ${args.join(" ")} timed out after ${options?.timeoutMs}ms`));
1937
+ return;
1938
+ }
1939
+ if (code === 0) {
1940
+ resolvePromise(stdout.trim());
1941
+ return;
1942
+ }
1943
+ const exitStatus = code === null ? `signal ${signal ?? "unknown"}` : `code ${code}`;
1944
+ reject(new Error(`${command} ${args.join(" ")} failed with ${exitStatus}: ${stderr || stdout}`));
1945
+ });
1946
+ });
1947
+ }
1948
+ runCommand(command, args, options) {
1949
+ return new Promise((resolvePromise, reject) => {
1950
+ const child = this.spawnCommand(command, args, options);
1419
1951
  child.on("error", reject);
1420
1952
  child.on("exit", (code) => {
1421
1953
  if (code === 0) {
@@ -1431,10 +1963,11 @@ export class DefaultPackageManager {
1431
1963
  const result = spawnSync(command, args, {
1432
1964
  stdio: ["ignore", "pipe", "pipe"],
1433
1965
  encoding: "utf-8",
1434
- shell: process.platform === "win32",
1966
+ shell: shouldUseWindowsShell(command),
1967
+ env: getEnv(),
1435
1968
  });
1436
- if (result.status !== 0) {
1437
- throw new Error(`Failed to run ${command} ${args.join(" ")}: ${result.stderr || result.stdout}`);
1969
+ if (result.error || result.status !== 0) {
1970
+ throw new Error(`Failed to run ${command} ${args.join(" ")}: ${result.error?.message || result.stderr || result.stdout}`);
1438
1971
  }
1439
1972
  return (result.stdout || result.stderr || "").trim();
1440
1973
  }