@caupulican/pi-adaptative 0.81.40 → 0.81.41

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 (406) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -1
  3. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +1 -0
  4. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -1
  5. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +1 -0
  6. package/dist/cli/args.d.ts +2 -0
  7. package/dist/cli/args.d.ts.map +1 -1
  8. package/dist/cli/args.js +22 -1
  9. package/dist/cli/args.js.map +1 -1
  10. package/dist/core/agent-paths.d.ts +6 -0
  11. package/dist/core/agent-paths.d.ts.map +1 -1
  12. package/dist/core/agent-paths.js +12 -0
  13. package/dist/core/agent-paths.js.map +1 -1
  14. package/dist/core/agent-session-contracts.d.ts +293 -0
  15. package/dist/core/agent-session-contracts.d.ts.map +1 -0
  16. package/dist/core/agent-session-contracts.js +26 -0
  17. package/dist/core/agent-session-contracts.js.map +1 -0
  18. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  19. package/dist/core/agent-session-runtime.js +3 -0
  20. package/dist/core/agent-session-runtime.js.map +1 -1
  21. package/dist/core/agent-session.d.ts +26 -405
  22. package/dist/core/agent-session.d.ts.map +1 -1
  23. package/dist/core/agent-session.js +86 -307
  24. package/dist/core/agent-session.js.map +1 -1
  25. package/dist/core/auth-storage.d.ts.map +1 -1
  26. package/dist/core/auth-storage.js +3 -1
  27. package/dist/core/auth-storage.js.map +1 -1
  28. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
  29. package/dist/core/autonomy/lane-tool-surface.js +2 -1
  30. package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
  31. package/dist/core/background-lane-controller.d.ts +3 -1
  32. package/dist/core/background-lane-controller.d.ts.map +1 -1
  33. package/dist/core/background-lane-controller.js +1 -0
  34. package/dist/core/background-lane-controller.js.map +1 -1
  35. package/dist/core/bedrock-sso-login.d.ts +16 -0
  36. package/dist/core/bedrock-sso-login.d.ts.map +1 -0
  37. package/dist/core/bedrock-sso-login.js +98 -0
  38. package/dist/core/bedrock-sso-login.js.map +1 -0
  39. package/dist/core/compaction-controller.d.ts.map +1 -1
  40. package/dist/core/compaction-controller.js +1 -1
  41. package/dist/core/compaction-controller.js.map +1 -1
  42. package/dist/core/compaction-support.d.ts +3 -8
  43. package/dist/core/compaction-support.d.ts.map +1 -1
  44. package/dist/core/compaction-support.js +3 -3
  45. package/dist/core/compaction-support.js.map +1 -1
  46. package/dist/core/context-pipeline.d.ts +1 -1
  47. package/dist/core/context-pipeline.d.ts.map +1 -1
  48. package/dist/core/context-pipeline.js +7 -33
  49. package/dist/core/context-pipeline.js.map +1 -1
  50. package/dist/core/cost/cost-summary.d.ts.map +1 -1
  51. package/dist/core/cost/cost-summary.js +5 -3
  52. package/dist/core/cost/cost-summary.js.map +1 -1
  53. package/dist/core/cost/daily-usage.d.ts.map +1 -1
  54. package/dist/core/cost/daily-usage.js +4 -5
  55. package/dist/core/cost/daily-usage.js.map +1 -1
  56. package/dist/core/default-tool-surface.d.ts.map +1 -1
  57. package/dist/core/default-tool-surface.js +1 -0
  58. package/dist/core/default-tool-surface.js.map +1 -1
  59. package/dist/core/extension-import-authority.d.ts +6 -0
  60. package/dist/core/extension-import-authority.d.ts.map +1 -0
  61. package/dist/core/extension-import-authority.js +10 -0
  62. package/dist/core/extension-import-authority.js.map +1 -0
  63. package/dist/core/extensions/loader.d.ts.map +1 -1
  64. package/dist/core/extensions/loader.js +2 -3
  65. package/dist/core/extensions/loader.js.map +1 -1
  66. package/dist/core/extensions/runner.d.ts +3 -0
  67. package/dist/core/extensions/runner.d.ts.map +1 -1
  68. package/dist/core/extensions/runner.js +14 -5
  69. package/dist/core/extensions/runner.js.map +1 -1
  70. package/dist/core/extensions/stale-context.d.ts +2 -0
  71. package/dist/core/extensions/stale-context.d.ts.map +1 -0
  72. package/dist/core/extensions/stale-context.js +2 -0
  73. package/dist/core/extensions/stale-context.js.map +1 -0
  74. package/dist/core/extensions/types.d.ts +8 -0
  75. package/dist/core/extensions/types.d.ts.map +1 -1
  76. package/dist/core/extensions/types.js.map +1 -1
  77. package/dist/core/foreground-recovery-controller.d.ts +1 -0
  78. package/dist/core/foreground-recovery-controller.d.ts.map +1 -1
  79. package/dist/core/foreground-recovery-controller.js +13 -13
  80. package/dist/core/foreground-recovery-controller.js.map +1 -1
  81. package/dist/core/goal-loop-controller.d.ts +14 -9
  82. package/dist/core/goal-loop-controller.d.ts.map +1 -1
  83. package/dist/core/goal-loop-controller.js +47 -75
  84. package/dist/core/goal-loop-controller.js.map +1 -1
  85. package/dist/core/goals/compact-goal-context.d.ts +11 -0
  86. package/dist/core/goals/compact-goal-context.d.ts.map +1 -0
  87. package/dist/core/goals/compact-goal-context.js +59 -0
  88. package/dist/core/goals/compact-goal-context.js.map +1 -0
  89. package/dist/core/goals/goal-acceptance.d.ts.map +1 -1
  90. package/dist/core/goals/goal-acceptance.js +2 -0
  91. package/dist/core/goals/goal-acceptance.js.map +1 -1
  92. package/dist/core/goals/goal-auto-continue-controller.d.ts +2 -1
  93. package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -1
  94. package/dist/core/goals/goal-auto-continue-controller.js +5 -8
  95. package/dist/core/goals/goal-auto-continue-controller.js.map +1 -1
  96. package/dist/core/goals/goal-continuation-controller.d.ts +2 -2
  97. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
  98. package/dist/core/goals/goal-continuation-controller.js +42 -11
  99. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  100. package/dist/core/goals/goal-continuation-defaults.d.ts +4 -29
  101. package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
  102. package/dist/core/goals/goal-continuation-defaults.js +4 -32
  103. package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
  104. package/dist/core/goals/goal-continuation-prompt.d.ts +8 -18
  105. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  106. package/dist/core/goals/goal-continuation-prompt.js +9 -179
  107. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  108. package/dist/core/goals/goal-lifecycle.d.ts +35 -12
  109. package/dist/core/goals/goal-lifecycle.d.ts.map +1 -1
  110. package/dist/core/goals/goal-lifecycle.js +98 -13
  111. package/dist/core/goals/goal-lifecycle.js.map +1 -1
  112. package/dist/core/goals/goal-record.d.ts +17 -0
  113. package/dist/core/goals/goal-record.d.ts.map +1 -0
  114. package/dist/core/goals/goal-record.js +31 -0
  115. package/dist/core/goals/goal-record.js.map +1 -0
  116. package/dist/core/goals/goal-session-controller.d.ts +42 -0
  117. package/dist/core/goals/goal-session-controller.d.ts.map +1 -0
  118. package/dist/core/goals/goal-session-controller.js +128 -0
  119. package/dist/core/goals/goal-session-controller.js.map +1 -0
  120. package/dist/core/goals/goal-state.d.ts +45 -25
  121. package/dist/core/goals/goal-state.d.ts.map +1 -1
  122. package/dist/core/goals/goal-state.js +85 -15
  123. package/dist/core/goals/goal-state.js.map +1 -1
  124. package/dist/core/goals/goal-tool-core.d.ts +1 -4
  125. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  126. package/dist/core/goals/goal-tool-core.js +49 -34
  127. package/dist/core/goals/goal-tool-core.js.map +1 -1
  128. package/dist/core/goals/session-goal-state.d.ts +18 -8
  129. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  130. package/dist/core/goals/session-goal-state.js +134 -11
  131. package/dist/core/goals/session-goal-state.js.map +1 -1
  132. package/dist/core/human-input-controller.d.ts +47 -0
  133. package/dist/core/human-input-controller.d.ts.map +1 -0
  134. package/dist/core/human-input-controller.js +181 -0
  135. package/dist/core/human-input-controller.js.map +1 -0
  136. package/dist/core/local-runtime-controller.d.ts +1 -1
  137. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  138. package/dist/core/local-runtime-controller.js.map +1 -1
  139. package/dist/core/model-capability.d.ts +0 -19
  140. package/dist/core/model-capability.d.ts.map +1 -1
  141. package/dist/core/model-capability.js +0 -19
  142. package/dist/core/model-capability.js.map +1 -1
  143. package/dist/core/model-registry.d.ts +6 -1
  144. package/dist/core/model-registry.d.ts.map +1 -1
  145. package/dist/core/model-registry.js +13 -5
  146. package/dist/core/model-registry.js.map +1 -1
  147. package/dist/core/model-resolver.d.ts +16 -1
  148. package/dist/core/model-resolver.d.ts.map +1 -1
  149. package/dist/core/model-resolver.js +32 -16
  150. package/dist/core/model-resolver.js.map +1 -1
  151. package/dist/core/model-router-controller.d.ts +1 -1
  152. package/dist/core/model-router-controller.d.ts.map +1 -1
  153. package/dist/core/model-router-controller.js.map +1 -1
  154. package/dist/core/model-selection-controller.d.ts +1 -1
  155. package/dist/core/model-selection-controller.d.ts.map +1 -1
  156. package/dist/core/model-selection-controller.js.map +1 -1
  157. package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -1
  158. package/dist/core/orchestration/delegation-ledger.js +3 -0
  159. package/dist/core/orchestration/delegation-ledger.js.map +1 -1
  160. package/dist/core/orchestration/work-state-projection.d.ts.map +1 -1
  161. package/dist/core/orchestration/work-state-projection.js +1 -1
  162. package/dist/core/orchestration/work-state-projection.js.map +1 -1
  163. package/dist/core/package-manager.d.ts.map +1 -1
  164. package/dist/core/package-manager.js +20 -3
  165. package/dist/core/package-manager.js.map +1 -1
  166. package/dist/core/profile-filter-controller.d.ts +8 -1
  167. package/dist/core/profile-filter-controller.d.ts.map +1 -1
  168. package/dist/core/profile-filter-controller.js +23 -5
  169. package/dist/core/profile-filter-controller.js.map +1 -1
  170. package/dist/core/prompt-templates.d.ts +1 -0
  171. package/dist/core/prompt-templates.d.ts.map +1 -1
  172. package/dist/core/prompt-templates.js +18 -29
  173. package/dist/core/prompt-templates.js.map +1 -1
  174. package/dist/core/reflection-controller.d.ts +1 -1
  175. package/dist/core/reflection-controller.d.ts.map +1 -1
  176. package/dist/core/reflection-controller.js +3 -1
  177. package/dist/core/reflection-controller.js.map +1 -1
  178. package/dist/core/request-auth.d.ts +7 -0
  179. package/dist/core/request-auth.d.ts.map +1 -0
  180. package/dist/core/request-auth.js +8 -0
  181. package/dist/core/request-auth.js.map +1 -0
  182. package/dist/core/resource-loader.d.ts.map +1 -1
  183. package/dist/core/resource-loader.js +16 -6
  184. package/dist/core/resource-loader.js.map +1 -1
  185. package/dist/core/risk-classifier.d.ts.map +1 -1
  186. package/dist/core/risk-classifier.js +8 -0
  187. package/dist/core/risk-classifier.js.map +1 -1
  188. package/dist/core/runtime-builder.d.ts +15 -3
  189. package/dist/core/runtime-builder.d.ts.map +1 -1
  190. package/dist/core/runtime-builder.js +132 -79
  191. package/dist/core/runtime-builder.js.map +1 -1
  192. package/dist/core/sdk.d.ts.map +1 -1
  193. package/dist/core/sdk.js +7 -1
  194. package/dist/core/sdk.js.map +1 -1
  195. package/dist/core/secrets/credential-exposure-guard.d.ts +9 -0
  196. package/dist/core/secrets/credential-exposure-guard.d.ts.map +1 -0
  197. package/dist/core/secrets/credential-exposure-guard.js +241 -0
  198. package/dist/core/secrets/credential-exposure-guard.js.map +1 -0
  199. package/dist/core/secrets/secret-dotenv.d.ts +27 -0
  200. package/dist/core/secrets/secret-dotenv.d.ts.map +1 -0
  201. package/dist/core/secrets/secret-dotenv.js +183 -0
  202. package/dist/core/secrets/secret-dotenv.js.map +1 -0
  203. package/dist/core/secrets/secret-vault-format.d.ts +112 -0
  204. package/dist/core/secrets/secret-vault-format.d.ts.map +1 -0
  205. package/dist/core/secrets/secret-vault-format.js +397 -0
  206. package/dist/core/secrets/secret-vault-format.js.map +1 -0
  207. package/dist/core/secrets/secret-vault.d.ts +72 -0
  208. package/dist/core/secrets/secret-vault.d.ts.map +1 -0
  209. package/dist/core/secrets/secret-vault.js +671 -0
  210. package/dist/core/secrets/secret-vault.js.map +1 -0
  211. package/dist/core/session-analytics.d.ts +4 -23
  212. package/dist/core/session-analytics.d.ts.map +1 -1
  213. package/dist/core/session-analytics.js +39 -69
  214. package/dist/core/session-analytics.js.map +1 -1
  215. package/dist/core/session-role.d.ts +5 -0
  216. package/dist/core/session-role.d.ts.map +1 -1
  217. package/dist/core/session-role.js +14 -1
  218. package/dist/core/session-role.js.map +1 -1
  219. package/dist/core/session-tree-navigator.d.ts +4 -6
  220. package/dist/core/session-tree-navigator.d.ts.map +1 -1
  221. package/dist/core/session-tree-navigator.js +4 -1
  222. package/dist/core/session-tree-navigator.js.map +1 -1
  223. package/dist/core/settings-manager.d.ts +1 -1
  224. package/dist/core/settings-manager.d.ts.map +1 -1
  225. package/dist/core/settings-manager.js +1 -1
  226. package/dist/core/settings-manager.js.map +1 -1
  227. package/dist/core/slash-commands.d.ts.map +1 -1
  228. package/dist/core/slash-commands.js +2 -2
  229. package/dist/core/slash-commands.js.map +1 -1
  230. package/dist/core/tool-capability-policy.d.ts.map +1 -1
  231. package/dist/core/tool-capability-policy.js +1 -0
  232. package/dist/core/tool-capability-policy.js.map +1 -1
  233. package/dist/core/tool-gate-controller.d.ts.map +1 -1
  234. package/dist/core/tool-gate-controller.js +8 -2
  235. package/dist/core/tool-gate-controller.js.map +1 -1
  236. package/dist/core/tool-protocol-controller.d.ts +2 -4
  237. package/dist/core/tool-protocol-controller.d.ts.map +1 -1
  238. package/dist/core/tool-protocol-controller.js.map +1 -1
  239. package/dist/core/tool-recovery-stats.d.ts +21 -1
  240. package/dist/core/tool-recovery-stats.d.ts.map +1 -1
  241. package/dist/core/tool-recovery-stats.js.map +1 -1
  242. package/dist/core/tools/bash.d.ts +5 -0
  243. package/dist/core/tools/bash.d.ts.map +1 -1
  244. package/dist/core/tools/bash.js +59 -5
  245. package/dist/core/tools/bash.js.map +1 -1
  246. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  247. package/dist/core/tools/delegate-status.js +6 -7
  248. package/dist/core/tools/delegate-status.js.map +1 -1
  249. package/dist/core/tools/delegate.d.ts.map +1 -1
  250. package/dist/core/tools/delegate.js +6 -8
  251. package/dist/core/tools/delegate.js.map +1 -1
  252. package/dist/core/tools/git-filter.d.ts +1 -8
  253. package/dist/core/tools/git-filter.d.ts.map +1 -1
  254. package/dist/core/tools/git-filter.js +2 -63
  255. package/dist/core/tools/git-filter.js.map +1 -1
  256. package/dist/core/tools/goal.d.ts +5 -3
  257. package/dist/core/tools/goal.d.ts.map +1 -1
  258. package/dist/core/tools/goal.js +97 -19
  259. package/dist/core/tools/goal.js.map +1 -1
  260. package/dist/core/tools/index.d.ts +1 -0
  261. package/dist/core/tools/index.d.ts.map +1 -1
  262. package/dist/core/tools/index.js +1 -0
  263. package/dist/core/tools/index.js.map +1 -1
  264. package/dist/core/tools/orchestration-panel.d.ts +1 -4
  265. package/dist/core/tools/orchestration-panel.d.ts.map +1 -1
  266. package/dist/core/tools/orchestration-panel.js +0 -44
  267. package/dist/core/tools/orchestration-panel.js.map +1 -1
  268. package/dist/core/tools/output-accumulator.d.ts +11 -0
  269. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  270. package/dist/core/tools/output-accumulator.js +36 -3
  271. package/dist/core/tools/output-accumulator.js.map +1 -1
  272. package/dist/core/tools/python.d.ts +2 -0
  273. package/dist/core/tools/python.d.ts.map +1 -1
  274. package/dist/core/tools/python.js +3 -1
  275. package/dist/core/tools/python.js.map +1 -1
  276. package/dist/core/tools/read.d.ts.map +1 -1
  277. package/dist/core/tools/read.js +1 -1
  278. package/dist/core/tools/read.js.map +1 -1
  279. package/dist/core/tools/search-command-guard.d.ts +14 -0
  280. package/dist/core/tools/search-command-guard.d.ts.map +1 -0
  281. package/dist/core/tools/search-command-guard.js +333 -0
  282. package/dist/core/tools/search-command-guard.js.map +1 -0
  283. package/dist/core/tools/secret-store.d.ts +38 -0
  284. package/dist/core/tools/secret-store.d.ts.map +1 -0
  285. package/dist/core/tools/secret-store.js +412 -0
  286. package/dist/core/tools/secret-store.js.map +1 -0
  287. package/dist/core/tools/shell-command-parser.d.ts +16 -0
  288. package/dist/core/tools/shell-command-parser.d.ts.map +1 -0
  289. package/dist/core/tools/shell-command-parser.js +113 -0
  290. package/dist/core/tools/shell-command-parser.js.map +1 -0
  291. package/dist/core/tools/task-steps.d.ts.map +1 -1
  292. package/dist/core/tools/task-steps.js +4 -7
  293. package/dist/core/tools/task-steps.js.map +1 -1
  294. package/dist/core/util/atomic-file.d.ts +6 -2
  295. package/dist/core/util/atomic-file.d.ts.map +1 -1
  296. package/dist/core/util/atomic-file.js +4 -4
  297. package/dist/core/util/atomic-file.js.map +1 -1
  298. package/dist/index.d.ts +3 -2
  299. package/dist/index.d.ts.map +1 -1
  300. package/dist/index.js +2 -1
  301. package/dist/index.js.map +1 -1
  302. package/dist/main.d.ts.map +1 -1
  303. package/dist/main.js +25 -11
  304. package/dist/main.js.map +1 -1
  305. package/dist/modes/interactive/auth-dialogs-controller.d.ts +4 -0
  306. package/dist/modes/interactive/auth-dialogs-controller.d.ts.map +1 -1
  307. package/dist/modes/interactive/auth-dialogs-controller.js +60 -1
  308. package/dist/modes/interactive/auth-dialogs-controller.js.map +1 -1
  309. package/dist/modes/interactive/components/activity-lane.d.ts +55 -0
  310. package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -0
  311. package/dist/modes/interactive/components/activity-lane.js +304 -0
  312. package/dist/modes/interactive/components/activity-lane.js.map +1 -0
  313. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  314. package/dist/modes/interactive/components/assistant-message.js +19 -10
  315. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  316. package/dist/modes/interactive/components/expandable-text.d.ts +12 -0
  317. package/dist/modes/interactive/components/expandable-text.d.ts.map +1 -0
  318. package/dist/modes/interactive/components/expandable-text.js +17 -0
  319. package/dist/modes/interactive/components/expandable-text.js.map +1 -0
  320. package/dist/modes/interactive/components/extension-editor.d.ts +15 -1
  321. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  322. package/dist/modes/interactive/components/extension-editor.js +30 -21
  323. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  324. package/dist/modes/interactive/components/extension-input.d.ts +1 -0
  325. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  326. package/dist/modes/interactive/components/extension-input.js +6 -1
  327. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  328. package/dist/modes/interactive/components/scoped-models-selector.d.ts +2 -2
  329. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  330. package/dist/modes/interactive/components/scoped-models-selector.js +23 -14
  331. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  332. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  333. package/dist/modes/interactive/components/settings-selector.js +4 -4
  334. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  335. package/dist/modes/interactive/components/tool-execution.d.ts +19 -11
  336. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  337. package/dist/modes/interactive/components/tool-execution.js +53 -20
  338. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  339. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  340. package/dist/modes/interactive/components/tool-group.js +3 -0
  341. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  342. package/dist/modes/interactive/components/usage-action-selector.d.ts +16 -0
  343. package/dist/modes/interactive/components/usage-action-selector.d.ts.map +1 -0
  344. package/dist/modes/interactive/components/usage-action-selector.js +46 -0
  345. package/dist/modes/interactive/components/usage-action-selector.js.map +1 -0
  346. package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
  347. package/dist/modes/interactive/extension-ui-host.js +1 -0
  348. package/dist/modes/interactive/extension-ui-host.js.map +1 -1
  349. package/dist/modes/interactive/external-editor.d.ts +15 -0
  350. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  351. package/dist/modes/interactive/external-editor.js +27 -19
  352. package/dist/modes/interactive/external-editor.js.map +1 -1
  353. package/dist/modes/interactive/history-reload-math.d.ts +6 -2
  354. package/dist/modes/interactive/history-reload-math.d.ts.map +1 -1
  355. package/dist/modes/interactive/history-reload-math.js +10 -5
  356. package/dist/modes/interactive/history-reload-math.js.map +1 -1
  357. package/dist/modes/interactive/interactive-event-controller.d.ts +74 -0
  358. package/dist/modes/interactive/interactive-event-controller.d.ts.map +1 -0
  359. package/dist/modes/interactive/interactive-event-controller.js +328 -0
  360. package/dist/modes/interactive/interactive-event-controller.js.map +1 -0
  361. package/dist/modes/interactive/interactive-mode.d.ts +20 -25
  362. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  363. package/dist/modes/interactive/interactive-mode.js +196 -608
  364. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  365. package/dist/modes/interactive/loaded-resources-view.d.ts +20 -0
  366. package/dist/modes/interactive/loaded-resources-view.d.ts.map +1 -0
  367. package/dist/modes/interactive/loaded-resources-view.js +147 -0
  368. package/dist/modes/interactive/loaded-resources-view.js.map +1 -0
  369. package/dist/modes/interactive/resource-display.d.ts.map +1 -1
  370. package/dist/modes/interactive/resource-display.js +8 -2
  371. package/dist/modes/interactive/resource-display.js.map +1 -1
  372. package/dist/modes/interactive/resource-shell-commands.d.ts +1 -5
  373. package/dist/modes/interactive/resource-shell-commands.d.ts.map +1 -1
  374. package/dist/modes/interactive/resource-shell-commands.js +0 -5
  375. package/dist/modes/interactive/resource-shell-commands.js.map +1 -1
  376. package/dist/modes/interactive/session-flow-commands.d.ts +10 -6
  377. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  378. package/dist/modes/interactive/session-flow-commands.js +123 -70
  379. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  380. package/dist/modes/interactive/usage-commands.d.ts +34 -0
  381. package/dist/modes/interactive/usage-commands.d.ts.map +1 -0
  382. package/dist/modes/interactive/usage-commands.js +225 -0
  383. package/dist/modes/interactive/usage-commands.js.map +1 -0
  384. package/dist/utils/shell.d.ts.map +1 -1
  385. package/dist/utils/shell.js +5 -3
  386. package/dist/utils/shell.js.map +1 -1
  387. package/dist/utils/version-check.d.ts.map +1 -1
  388. package/dist/utils/version-check.js +3 -1
  389. package/dist/utils/version-check.js.map +1 -1
  390. package/docs/UI_POLISH_ORCHESTRATION.md +25 -31
  391. package/docs/UI_QUALITY_ORCHESTRATION.md +22 -24
  392. package/docs/providers.md +9 -1
  393. package/docs/ui-reference/README.md +6 -6
  394. package/docs/ui-reference/orchestration-after.txt +14 -7
  395. package/docs/ui-reference/orchestration-before.txt +12 -6
  396. package/docs/ui-reference/orchestration-reference.txt +15 -5
  397. package/docs/usage.md +9 -1
  398. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  399. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  400. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  401. package/examples/extensions/sandbox/package-lock.json +2 -2
  402. package/examples/extensions/sandbox/package.json +1 -1
  403. package/examples/extensions/with-deps/package-lock.json +2 -2
  404. package/examples/extensions/with-deps/package.json +1 -1
  405. package/npm-shrinkwrap.json +13 -13
  406. package/package.json +4 -4
@@ -0,0 +1,20 @@
1
+ import { type Container } from "@caupulican/pi-tui";
2
+ import type { AgentSession } from "../../core/agent-session.ts";
3
+ import type { SourceInfo } from "../../core/source-info.ts";
4
+ export interface LoadedResourcesViewHost {
5
+ session: AgentSession;
6
+ chatContainer: Container;
7
+ verbose: boolean;
8
+ expanded: boolean;
9
+ }
10
+ export interface LoadedResourcesViewOptions {
11
+ extensions?: Array<{
12
+ path: string;
13
+ sourceInfo?: SourceInfo;
14
+ }>;
15
+ force?: boolean;
16
+ showDiagnosticsWhenQuiet?: boolean;
17
+ }
18
+ /** Render startup resources and diagnostics without making InteractiveMode own their formatting rules. */
19
+ export declare function renderLoadedResources(host: LoadedResourcesViewHost, options?: LoadedResourcesViewOptions): void;
20
+ //# sourceMappingURL=loaded-resources-view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loaded-resources-view.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/loaded-resources-view.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAgB,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAM5D,MAAM,WAAW,uBAAuB;IACvC,OAAO,EAAE,YAAY,CAAC;IACtB,aAAa,EAAE,SAAS,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,0BAA0B;IAC1C,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,UAAU,CAAA;KAAE,CAAC,CAAC;IAC9D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACnC;AAuBD,0GAA0G;AAC1G,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,uBAAuB,EAAE,OAAO,GAAE,0BAA+B,GAAG,IAAI,CAgKnH","sourcesContent":["import * as path from \"node:path\";\nimport { type Container, Spacer, Text } from \"@caupulican/pi-tui\";\nimport type { AgentSession } from \"../../core/agent-session.ts\";\nimport type { ResourceDiagnostic } from \"../../core/resource-loader.ts\";\nimport { BUILTIN_SLASH_COMMANDS } from \"../../core/slash-commands.ts\";\nimport type { SourceInfo } from \"../../core/source-info.ts\";\nimport { getCwdRelativePath } from \"../../utils/paths.ts\";\nimport { ExpandableText } from \"./components/expandable-text.ts\";\nimport * as resourceDisplay from \"./resource-display.ts\";\nimport { type ThemeColor, theme } from \"./theme/theme.ts\";\n\nexport interface LoadedResourcesViewHost {\n\tsession: AgentSession;\n\tchatContainer: Container;\n\tverbose: boolean;\n\texpanded: boolean;\n}\n\nexport interface LoadedResourcesViewOptions {\n\textensions?: Array<{ path: string; sourceInfo?: SourceInfo }>;\n\tforce?: boolean;\n\tshowDiagnosticsWhenQuiet?: boolean;\n}\n\nfunction getBuiltInCommandConflictDiagnostics(host: LoadedResourcesViewHost): ResourceDiagnostic[] {\n\tconst builtinNames = new Set(BUILTIN_SLASH_COMMANDS.map((command) => command.name));\n\treturn host.session.extensionRunner\n\t\t.getRegisteredCommands()\n\t\t.filter((command) => builtinNames.has(command.name))\n\t\t.map((command) => ({\n\t\t\ttype: \"warning\" as const,\n\t\t\tmessage:\n\t\t\t\tcommand.invocationName === command.name\n\t\t\t\t\t? `Extension command '/${command.name}' conflicts with built-in interactive command. Skipping in autocomplete.`\n\t\t\t\t\t: `Extension command '/${command.name}' conflicts with built-in interactive command. Available as '/${command.invocationName}'.`,\n\t\t\tpath: command.sourceInfo.path,\n\t\t}));\n}\n\nfunction formatContextPath(host: LoadedResourcesViewHost, value: string): string {\n\tconst cwd = path.resolve(host.session.sessionManager.getCwd());\n\tconst absolutePath = path.isAbsolute(value) ? path.resolve(value) : path.resolve(cwd, value);\n\treturn getCwdRelativePath(absolutePath, cwd) ?? resourceDisplay.formatDisplayPath(absolutePath);\n}\n\n/** Render startup resources and diagnostics without making InteractiveMode own their formatting rules. */\nexport function renderLoadedResources(host: LoadedResourcesViewHost, options: LoadedResourcesViewOptions = {}): void {\n\tconst settingsManager = host.session.settingsManager;\n\tconst resourceLoader = host.session.resourceLoader;\n\tconst showListing = options.force || host.verbose || !settingsManager.getQuietStartup();\n\tconst showDiagnostics = showListing || options.showDiagnosticsWhenQuiet === true;\n\tif (!showListing && !showDiagnostics) return;\n\n\tconst sectionHeader = (name: string, color: ThemeColor = \"mdHeading\") => theme.fg(color, `[${name}]`);\n\tconst formatCompactList = (items: string[], listOptions?: { sort?: boolean }): string => {\n\t\tconst labels = items.map((item) => item.trim()).filter((item) => item.length > 0);\n\t\tif (listOptions?.sort !== false) labels.sort((a, b) => a.localeCompare(b));\n\t\treturn theme.fg(\"dim\", ` ${labels.join(\", \")}`);\n\t};\n\tconst addLoadedSection = (\n\t\tname: string,\n\t\tcollapsedBody: string,\n\t\texpandedBody = collapsedBody,\n\t\tcolor: ThemeColor = \"mdHeading\",\n\t): void => {\n\t\thost.chatContainer.addChild(\n\t\t\tnew ExpandableText(\n\t\t\t\t() => `${sectionHeader(name, color)}\\n${collapsedBody}`,\n\t\t\t\t() => `${sectionHeader(name, color)}\\n${expandedBody}`,\n\t\t\t\thost.expanded,\n\t\t\t),\n\t\t);\n\t\thost.chatContainer.addChild(new Spacer(1));\n\t};\n\n\tconst skillsResult = resourceLoader.getSkills();\n\tconst promptsResult = resourceLoader.getPrompts();\n\tconst themesResult = resourceLoader.getThemes();\n\tconst extensions =\n\t\toptions.extensions ??\n\t\tresourceLoader.getExtensions().extensions.map((extension) => ({\n\t\t\tpath: extension.path,\n\t\t\tsourceInfo: extension.sourceInfo,\n\t\t}));\n\tconst sourceInfos = new Map<string, SourceInfo>();\n\tfor (const extension of extensions) {\n\t\tif (extension.sourceInfo) sourceInfos.set(extension.path, extension.sourceInfo);\n\t}\n\tfor (const skill of skillsResult.skills) {\n\t\tif (skill.sourceInfo) sourceInfos.set(skill.filePath, skill.sourceInfo);\n\t}\n\tfor (const prompt of promptsResult.prompts) {\n\t\tif (prompt.sourceInfo) sourceInfos.set(prompt.filePath, prompt.sourceInfo);\n\t}\n\tfor (const loadedTheme of themesResult.themes) {\n\t\tif (loadedTheme.sourcePath && loadedTheme.sourceInfo) {\n\t\t\tsourceInfos.set(loadedTheme.sourcePath, loadedTheme.sourceInfo);\n\t\t}\n\t}\n\n\tif (showListing) {\n\t\tconst contextFiles = resourceLoader.getAgentsFiles().agentsFiles;\n\t\tif (contextFiles.length > 0) {\n\t\t\thost.chatContainer.addChild(new Spacer(1));\n\t\t\tconst contextList = contextFiles\n\t\t\t\t.map((file) => theme.fg(\"dim\", ` ${resourceDisplay.formatDisplayPath(file.path)}`))\n\t\t\t\t.join(\"\\n\");\n\t\t\taddLoadedSection(\n\t\t\t\t\"Context\",\n\t\t\t\tformatCompactList(\n\t\t\t\t\tcontextFiles.map((file) => formatContextPath(host, file.path)),\n\t\t\t\t\t{ sort: false },\n\t\t\t\t),\n\t\t\t\tcontextList,\n\t\t\t);\n\t\t}\n\n\t\tconst skills = resourceLoader.getActiveSkills();\n\t\tif (skills.length > 0) {\n\t\t\tconst groups = resourceDisplay.buildScopeGroups(\n\t\t\t\tskills.map((skill) => ({ path: skill.filePath, sourceInfo: skill.sourceInfo })),\n\t\t\t);\n\t\t\tconst skillList = resourceDisplay.formatScopeGroups(groups, {\n\t\t\t\tformatPath: (item) => resourceDisplay.formatDisplayPath(item.path),\n\t\t\t\tformatPackagePath: (item) => resourceDisplay.getShortPath(item.path, item.sourceInfo),\n\t\t\t});\n\t\t\taddLoadedSection(\"Skills\", formatCompactList(skills.map((skill) => skill.name)), skillList);\n\t\t}\n\n\t\tconst templates = host.session.promptTemplates;\n\t\tif (templates.length > 0) {\n\t\t\tconst groups = resourceDisplay.buildScopeGroups(\n\t\t\t\ttemplates.map((template) => ({ path: template.filePath, sourceInfo: template.sourceInfo })),\n\t\t\t);\n\t\t\tconst templateByPath = new Map(templates.map((template) => [template.filePath, template]));\n\t\t\tconst templateList = resourceDisplay.formatScopeGroups(groups, {\n\t\t\t\tformatPath: (item) => {\n\t\t\t\t\tconst template = templateByPath.get(item.path);\n\t\t\t\t\treturn template ? `/${template.name}` : resourceDisplay.formatDisplayPath(item.path);\n\t\t\t\t},\n\t\t\t\tformatPackagePath: (item) => {\n\t\t\t\t\tconst template = templateByPath.get(item.path);\n\t\t\t\t\treturn template ? `/${template.name}` : resourceDisplay.formatDisplayPath(item.path);\n\t\t\t\t},\n\t\t\t});\n\t\t\taddLoadedSection(\"Prompts\", formatCompactList(templates.map((template) => `/${template.name}`)), templateList);\n\t\t}\n\n\t\tif (extensions.length > 0) {\n\t\t\tconst groups = resourceDisplay.buildScopeGroups(extensions);\n\t\t\tconst extensionList = resourceDisplay.formatScopeGroups(groups, {\n\t\t\t\tformatPath: (item) => resourceDisplay.formatExtensionDisplayPath(item.path),\n\t\t\t\tformatPackagePath: (item) =>\n\t\t\t\t\tresourceDisplay.formatExtensionDisplayPath(resourceDisplay.getShortPath(item.path, item.sourceInfo)),\n\t\t\t});\n\t\t\taddLoadedSection(\n\t\t\t\t\"Extensions\",\n\t\t\t\tformatCompactList(resourceDisplay.getCompactExtensionLabels(extensions)),\n\t\t\t\textensionList,\n\t\t\t);\n\t\t}\n\n\t\tconst customThemes = themesResult.themes.filter((loadedTheme) => loadedTheme.sourcePath);\n\t\tif (customThemes.length > 0) {\n\t\t\tconst groups = resourceDisplay.buildScopeGroups(\n\t\t\t\tcustomThemes.map((loadedTheme) => ({\n\t\t\t\t\tpath: loadedTheme.sourcePath!,\n\t\t\t\t\tsourceInfo: loadedTheme.sourceInfo,\n\t\t\t\t})),\n\t\t\t);\n\t\t\tconst themeList = resourceDisplay.formatScopeGroups(groups, {\n\t\t\t\tformatPath: (item) => resourceDisplay.formatDisplayPath(item.path),\n\t\t\t\tformatPackagePath: (item) => resourceDisplay.getShortPath(item.path, item.sourceInfo),\n\t\t\t});\n\t\t\taddLoadedSection(\n\t\t\t\t\"Themes\",\n\t\t\t\tformatCompactList(\n\t\t\t\t\tcustomThemes.map(\n\t\t\t\t\t\t(loadedTheme) =>\n\t\t\t\t\t\t\tloadedTheme.name ??\n\t\t\t\t\t\t\tresourceDisplay.getCompactPathLabel(loadedTheme.sourcePath!, loadedTheme.sourceInfo),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tthemeList,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (!showDiagnostics) return;\n\tconst addDiagnostics = (name: string, diagnostics: readonly ResourceDiagnostic[]): void => {\n\t\tif (diagnostics.length === 0) return;\n\t\tconst warningLines = resourceDisplay.formatDiagnostics(diagnostics, sourceInfos);\n\t\thost.chatContainer.addChild(new Text(`${theme.fg(\"warning\", `[${name}]`)}\\n${warningLines}`, 0, 0));\n\t\thost.chatContainer.addChild(new Spacer(1));\n\t};\n\taddDiagnostics(\"Skill conflicts\", skillsResult.diagnostics);\n\taddDiagnostics(\"Prompt conflicts\", promptsResult.diagnostics);\n\n\tconst extensionDiagnostics: ResourceDiagnostic[] = resourceLoader\n\t\t.getExtensions()\n\t\t.errors.map((error) => ({ type: \"error\", message: error.error, path: error.path }));\n\textensionDiagnostics.push(...host.session.extensionRunner.getCommandDiagnostics());\n\textensionDiagnostics.push(...getBuiltInCommandConflictDiagnostics(host));\n\textensionDiagnostics.push(...host.session.extensionRunner.getShortcutDiagnostics());\n\taddDiagnostics(\"Extension issues\", extensionDiagnostics);\n\taddDiagnostics(\"Theme conflicts\", themesResult.diagnostics);\n}\n"]}
@@ -0,0 +1,147 @@
1
+ import * as path from "node:path";
2
+ import { Spacer, Text } from "@caupulican/pi-tui";
3
+ import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
4
+ import { getCwdRelativePath } from "../../utils/paths.js";
5
+ import { ExpandableText } from "./components/expandable-text.js";
6
+ import * as resourceDisplay from "./resource-display.js";
7
+ import { theme } from "./theme/theme.js";
8
+ function getBuiltInCommandConflictDiagnostics(host) {
9
+ const builtinNames = new Set(BUILTIN_SLASH_COMMANDS.map((command) => command.name));
10
+ return host.session.extensionRunner
11
+ .getRegisteredCommands()
12
+ .filter((command) => builtinNames.has(command.name))
13
+ .map((command) => ({
14
+ type: "warning",
15
+ message: command.invocationName === command.name
16
+ ? `Extension command '/${command.name}' conflicts with built-in interactive command. Skipping in autocomplete.`
17
+ : `Extension command '/${command.name}' conflicts with built-in interactive command. Available as '/${command.invocationName}'.`,
18
+ path: command.sourceInfo.path,
19
+ }));
20
+ }
21
+ function formatContextPath(host, value) {
22
+ const cwd = path.resolve(host.session.sessionManager.getCwd());
23
+ const absolutePath = path.isAbsolute(value) ? path.resolve(value) : path.resolve(cwd, value);
24
+ return getCwdRelativePath(absolutePath, cwd) ?? resourceDisplay.formatDisplayPath(absolutePath);
25
+ }
26
+ /** Render startup resources and diagnostics without making InteractiveMode own their formatting rules. */
27
+ export function renderLoadedResources(host, options = {}) {
28
+ const settingsManager = host.session.settingsManager;
29
+ const resourceLoader = host.session.resourceLoader;
30
+ const showListing = options.force || host.verbose || !settingsManager.getQuietStartup();
31
+ const showDiagnostics = showListing || options.showDiagnosticsWhenQuiet === true;
32
+ if (!showListing && !showDiagnostics)
33
+ return;
34
+ const sectionHeader = (name, color = "mdHeading") => theme.fg(color, `[${name}]`);
35
+ const formatCompactList = (items, listOptions) => {
36
+ const labels = items.map((item) => item.trim()).filter((item) => item.length > 0);
37
+ if (listOptions?.sort !== false)
38
+ labels.sort((a, b) => a.localeCompare(b));
39
+ return theme.fg("dim", ` ${labels.join(", ")}`);
40
+ };
41
+ const addLoadedSection = (name, collapsedBody, expandedBody = collapsedBody, color = "mdHeading") => {
42
+ host.chatContainer.addChild(new ExpandableText(() => `${sectionHeader(name, color)}\n${collapsedBody}`, () => `${sectionHeader(name, color)}\n${expandedBody}`, host.expanded));
43
+ host.chatContainer.addChild(new Spacer(1));
44
+ };
45
+ const skillsResult = resourceLoader.getSkills();
46
+ const promptsResult = resourceLoader.getPrompts();
47
+ const themesResult = resourceLoader.getThemes();
48
+ const extensions = options.extensions ??
49
+ resourceLoader.getExtensions().extensions.map((extension) => ({
50
+ path: extension.path,
51
+ sourceInfo: extension.sourceInfo,
52
+ }));
53
+ const sourceInfos = new Map();
54
+ for (const extension of extensions) {
55
+ if (extension.sourceInfo)
56
+ sourceInfos.set(extension.path, extension.sourceInfo);
57
+ }
58
+ for (const skill of skillsResult.skills) {
59
+ if (skill.sourceInfo)
60
+ sourceInfos.set(skill.filePath, skill.sourceInfo);
61
+ }
62
+ for (const prompt of promptsResult.prompts) {
63
+ if (prompt.sourceInfo)
64
+ sourceInfos.set(prompt.filePath, prompt.sourceInfo);
65
+ }
66
+ for (const loadedTheme of themesResult.themes) {
67
+ if (loadedTheme.sourcePath && loadedTheme.sourceInfo) {
68
+ sourceInfos.set(loadedTheme.sourcePath, loadedTheme.sourceInfo);
69
+ }
70
+ }
71
+ if (showListing) {
72
+ const contextFiles = resourceLoader.getAgentsFiles().agentsFiles;
73
+ if (contextFiles.length > 0) {
74
+ host.chatContainer.addChild(new Spacer(1));
75
+ const contextList = contextFiles
76
+ .map((file) => theme.fg("dim", ` ${resourceDisplay.formatDisplayPath(file.path)}`))
77
+ .join("\n");
78
+ addLoadedSection("Context", formatCompactList(contextFiles.map((file) => formatContextPath(host, file.path)), { sort: false }), contextList);
79
+ }
80
+ const skills = resourceLoader.getActiveSkills();
81
+ if (skills.length > 0) {
82
+ const groups = resourceDisplay.buildScopeGroups(skills.map((skill) => ({ path: skill.filePath, sourceInfo: skill.sourceInfo })));
83
+ const skillList = resourceDisplay.formatScopeGroups(groups, {
84
+ formatPath: (item) => resourceDisplay.formatDisplayPath(item.path),
85
+ formatPackagePath: (item) => resourceDisplay.getShortPath(item.path, item.sourceInfo),
86
+ });
87
+ addLoadedSection("Skills", formatCompactList(skills.map((skill) => skill.name)), skillList);
88
+ }
89
+ const templates = host.session.promptTemplates;
90
+ if (templates.length > 0) {
91
+ const groups = resourceDisplay.buildScopeGroups(templates.map((template) => ({ path: template.filePath, sourceInfo: template.sourceInfo })));
92
+ const templateByPath = new Map(templates.map((template) => [template.filePath, template]));
93
+ const templateList = resourceDisplay.formatScopeGroups(groups, {
94
+ formatPath: (item) => {
95
+ const template = templateByPath.get(item.path);
96
+ return template ? `/${template.name}` : resourceDisplay.formatDisplayPath(item.path);
97
+ },
98
+ formatPackagePath: (item) => {
99
+ const template = templateByPath.get(item.path);
100
+ return template ? `/${template.name}` : resourceDisplay.formatDisplayPath(item.path);
101
+ },
102
+ });
103
+ addLoadedSection("Prompts", formatCompactList(templates.map((template) => `/${template.name}`)), templateList);
104
+ }
105
+ if (extensions.length > 0) {
106
+ const groups = resourceDisplay.buildScopeGroups(extensions);
107
+ const extensionList = resourceDisplay.formatScopeGroups(groups, {
108
+ formatPath: (item) => resourceDisplay.formatExtensionDisplayPath(item.path),
109
+ formatPackagePath: (item) => resourceDisplay.formatExtensionDisplayPath(resourceDisplay.getShortPath(item.path, item.sourceInfo)),
110
+ });
111
+ addLoadedSection("Extensions", formatCompactList(resourceDisplay.getCompactExtensionLabels(extensions)), extensionList);
112
+ }
113
+ const customThemes = themesResult.themes.filter((loadedTheme) => loadedTheme.sourcePath);
114
+ if (customThemes.length > 0) {
115
+ const groups = resourceDisplay.buildScopeGroups(customThemes.map((loadedTheme) => ({
116
+ path: loadedTheme.sourcePath,
117
+ sourceInfo: loadedTheme.sourceInfo,
118
+ })));
119
+ const themeList = resourceDisplay.formatScopeGroups(groups, {
120
+ formatPath: (item) => resourceDisplay.formatDisplayPath(item.path),
121
+ formatPackagePath: (item) => resourceDisplay.getShortPath(item.path, item.sourceInfo),
122
+ });
123
+ addLoadedSection("Themes", formatCompactList(customThemes.map((loadedTheme) => loadedTheme.name ??
124
+ resourceDisplay.getCompactPathLabel(loadedTheme.sourcePath, loadedTheme.sourceInfo))), themeList);
125
+ }
126
+ }
127
+ if (!showDiagnostics)
128
+ return;
129
+ const addDiagnostics = (name, diagnostics) => {
130
+ if (diagnostics.length === 0)
131
+ return;
132
+ const warningLines = resourceDisplay.formatDiagnostics(diagnostics, sourceInfos);
133
+ host.chatContainer.addChild(new Text(`${theme.fg("warning", `[${name}]`)}\n${warningLines}`, 0, 0));
134
+ host.chatContainer.addChild(new Spacer(1));
135
+ };
136
+ addDiagnostics("Skill conflicts", skillsResult.diagnostics);
137
+ addDiagnostics("Prompt conflicts", promptsResult.diagnostics);
138
+ const extensionDiagnostics = resourceLoader
139
+ .getExtensions()
140
+ .errors.map((error) => ({ type: "error", message: error.error, path: error.path }));
141
+ extensionDiagnostics.push(...host.session.extensionRunner.getCommandDiagnostics());
142
+ extensionDiagnostics.push(...getBuiltInCommandConflictDiagnostics(host));
143
+ extensionDiagnostics.push(...host.session.extensionRunner.getShortcutDiagnostics());
144
+ addDiagnostics("Extension issues", extensionDiagnostics);
145
+ addDiagnostics("Theme conflicts", themesResult.diagnostics);
146
+ }
147
+ //# sourceMappingURL=loaded-resources-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loaded-resources-view.js","sourceRoot":"","sources":["../../../src/modes/interactive/loaded-resources-view.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from \"node:path\";\nimport { type Container, Spacer, Text } from \"@caupulican/pi-tui\";\nimport type { AgentSession } from \"../../core/agent-session.ts\";\nimport type { ResourceDiagnostic } from \"../../core/resource-loader.ts\";\nimport { BUILTIN_SLASH_COMMANDS } from \"../../core/slash-commands.ts\";\nimport type { SourceInfo } from \"../../core/source-info.ts\";\nimport { getCwdRelativePath } from \"../../utils/paths.ts\";\nimport { ExpandableText } from \"./components/expandable-text.ts\";\nimport * as resourceDisplay from \"./resource-display.ts\";\nimport { type ThemeColor, theme } from \"./theme/theme.ts\";\n\nexport interface LoadedResourcesViewHost {\n\tsession: AgentSession;\n\tchatContainer: Container;\n\tverbose: boolean;\n\texpanded: boolean;\n}\n\nexport interface LoadedResourcesViewOptions {\n\textensions?: Array<{ path: string; sourceInfo?: SourceInfo }>;\n\tforce?: boolean;\n\tshowDiagnosticsWhenQuiet?: boolean;\n}\n\nfunction getBuiltInCommandConflictDiagnostics(host: LoadedResourcesViewHost): ResourceDiagnostic[] {\n\tconst builtinNames = new Set(BUILTIN_SLASH_COMMANDS.map((command) => command.name));\n\treturn host.session.extensionRunner\n\t\t.getRegisteredCommands()\n\t\t.filter((command) => builtinNames.has(command.name))\n\t\t.map((command) => ({\n\t\t\ttype: \"warning\" as const,\n\t\t\tmessage:\n\t\t\t\tcommand.invocationName === command.name\n\t\t\t\t\t? `Extension command '/${command.name}' conflicts with built-in interactive command. Skipping in autocomplete.`\n\t\t\t\t\t: `Extension command '/${command.name}' conflicts with built-in interactive command. Available as '/${command.invocationName}'.`,\n\t\t\tpath: command.sourceInfo.path,\n\t\t}));\n}\n\nfunction formatContextPath(host: LoadedResourcesViewHost, value: string): string {\n\tconst cwd = path.resolve(host.session.sessionManager.getCwd());\n\tconst absolutePath = path.isAbsolute(value) ? path.resolve(value) : path.resolve(cwd, value);\n\treturn getCwdRelativePath(absolutePath, cwd) ?? resourceDisplay.formatDisplayPath(absolutePath);\n}\n\n/** Render startup resources and diagnostics without making InteractiveMode own their formatting rules. */\nexport function renderLoadedResources(host: LoadedResourcesViewHost, options: LoadedResourcesViewOptions = {}): void {\n\tconst settingsManager = host.session.settingsManager;\n\tconst resourceLoader = host.session.resourceLoader;\n\tconst showListing = options.force || host.verbose || !settingsManager.getQuietStartup();\n\tconst showDiagnostics = showListing || options.showDiagnosticsWhenQuiet === true;\n\tif (!showListing && !showDiagnostics) return;\n\n\tconst sectionHeader = (name: string, color: ThemeColor = \"mdHeading\") => theme.fg(color, `[${name}]`);\n\tconst formatCompactList = (items: string[], listOptions?: { sort?: boolean }): string => {\n\t\tconst labels = items.map((item) => item.trim()).filter((item) => item.length > 0);\n\t\tif (listOptions?.sort !== false) labels.sort((a, b) => a.localeCompare(b));\n\t\treturn theme.fg(\"dim\", ` ${labels.join(\", \")}`);\n\t};\n\tconst addLoadedSection = (\n\t\tname: string,\n\t\tcollapsedBody: string,\n\t\texpandedBody = collapsedBody,\n\t\tcolor: ThemeColor = \"mdHeading\",\n\t): void => {\n\t\thost.chatContainer.addChild(\n\t\t\tnew ExpandableText(\n\t\t\t\t() => `${sectionHeader(name, color)}\\n${collapsedBody}`,\n\t\t\t\t() => `${sectionHeader(name, color)}\\n${expandedBody}`,\n\t\t\t\thost.expanded,\n\t\t\t),\n\t\t);\n\t\thost.chatContainer.addChild(new Spacer(1));\n\t};\n\n\tconst skillsResult = resourceLoader.getSkills();\n\tconst promptsResult = resourceLoader.getPrompts();\n\tconst themesResult = resourceLoader.getThemes();\n\tconst extensions =\n\t\toptions.extensions ??\n\t\tresourceLoader.getExtensions().extensions.map((extension) => ({\n\t\t\tpath: extension.path,\n\t\t\tsourceInfo: extension.sourceInfo,\n\t\t}));\n\tconst sourceInfos = new Map<string, SourceInfo>();\n\tfor (const extension of extensions) {\n\t\tif (extension.sourceInfo) sourceInfos.set(extension.path, extension.sourceInfo);\n\t}\n\tfor (const skill of skillsResult.skills) {\n\t\tif (skill.sourceInfo) sourceInfos.set(skill.filePath, skill.sourceInfo);\n\t}\n\tfor (const prompt of promptsResult.prompts) {\n\t\tif (prompt.sourceInfo) sourceInfos.set(prompt.filePath, prompt.sourceInfo);\n\t}\n\tfor (const loadedTheme of themesResult.themes) {\n\t\tif (loadedTheme.sourcePath && loadedTheme.sourceInfo) {\n\t\t\tsourceInfos.set(loadedTheme.sourcePath, loadedTheme.sourceInfo);\n\t\t}\n\t}\n\n\tif (showListing) {\n\t\tconst contextFiles = resourceLoader.getAgentsFiles().agentsFiles;\n\t\tif (contextFiles.length > 0) {\n\t\t\thost.chatContainer.addChild(new Spacer(1));\n\t\t\tconst contextList = contextFiles\n\t\t\t\t.map((file) => theme.fg(\"dim\", ` ${resourceDisplay.formatDisplayPath(file.path)}`))\n\t\t\t\t.join(\"\\n\");\n\t\t\taddLoadedSection(\n\t\t\t\t\"Context\",\n\t\t\t\tformatCompactList(\n\t\t\t\t\tcontextFiles.map((file) => formatContextPath(host, file.path)),\n\t\t\t\t\t{ sort: false },\n\t\t\t\t),\n\t\t\t\tcontextList,\n\t\t\t);\n\t\t}\n\n\t\tconst skills = resourceLoader.getActiveSkills();\n\t\tif (skills.length > 0) {\n\t\t\tconst groups = resourceDisplay.buildScopeGroups(\n\t\t\t\tskills.map((skill) => ({ path: skill.filePath, sourceInfo: skill.sourceInfo })),\n\t\t\t);\n\t\t\tconst skillList = resourceDisplay.formatScopeGroups(groups, {\n\t\t\t\tformatPath: (item) => resourceDisplay.formatDisplayPath(item.path),\n\t\t\t\tformatPackagePath: (item) => resourceDisplay.getShortPath(item.path, item.sourceInfo),\n\t\t\t});\n\t\t\taddLoadedSection(\"Skills\", formatCompactList(skills.map((skill) => skill.name)), skillList);\n\t\t}\n\n\t\tconst templates = host.session.promptTemplates;\n\t\tif (templates.length > 0) {\n\t\t\tconst groups = resourceDisplay.buildScopeGroups(\n\t\t\t\ttemplates.map((template) => ({ path: template.filePath, sourceInfo: template.sourceInfo })),\n\t\t\t);\n\t\t\tconst templateByPath = new Map(templates.map((template) => [template.filePath, template]));\n\t\t\tconst templateList = resourceDisplay.formatScopeGroups(groups, {\n\t\t\t\tformatPath: (item) => {\n\t\t\t\t\tconst template = templateByPath.get(item.path);\n\t\t\t\t\treturn template ? `/${template.name}` : resourceDisplay.formatDisplayPath(item.path);\n\t\t\t\t},\n\t\t\t\tformatPackagePath: (item) => {\n\t\t\t\t\tconst template = templateByPath.get(item.path);\n\t\t\t\t\treturn template ? `/${template.name}` : resourceDisplay.formatDisplayPath(item.path);\n\t\t\t\t},\n\t\t\t});\n\t\t\taddLoadedSection(\"Prompts\", formatCompactList(templates.map((template) => `/${template.name}`)), templateList);\n\t\t}\n\n\t\tif (extensions.length > 0) {\n\t\t\tconst groups = resourceDisplay.buildScopeGroups(extensions);\n\t\t\tconst extensionList = resourceDisplay.formatScopeGroups(groups, {\n\t\t\t\tformatPath: (item) => resourceDisplay.formatExtensionDisplayPath(item.path),\n\t\t\t\tformatPackagePath: (item) =>\n\t\t\t\t\tresourceDisplay.formatExtensionDisplayPath(resourceDisplay.getShortPath(item.path, item.sourceInfo)),\n\t\t\t});\n\t\t\taddLoadedSection(\n\t\t\t\t\"Extensions\",\n\t\t\t\tformatCompactList(resourceDisplay.getCompactExtensionLabels(extensions)),\n\t\t\t\textensionList,\n\t\t\t);\n\t\t}\n\n\t\tconst customThemes = themesResult.themes.filter((loadedTheme) => loadedTheme.sourcePath);\n\t\tif (customThemes.length > 0) {\n\t\t\tconst groups = resourceDisplay.buildScopeGroups(\n\t\t\t\tcustomThemes.map((loadedTheme) => ({\n\t\t\t\t\tpath: loadedTheme.sourcePath!,\n\t\t\t\t\tsourceInfo: loadedTheme.sourceInfo,\n\t\t\t\t})),\n\t\t\t);\n\t\t\tconst themeList = resourceDisplay.formatScopeGroups(groups, {\n\t\t\t\tformatPath: (item) => resourceDisplay.formatDisplayPath(item.path),\n\t\t\t\tformatPackagePath: (item) => resourceDisplay.getShortPath(item.path, item.sourceInfo),\n\t\t\t});\n\t\t\taddLoadedSection(\n\t\t\t\t\"Themes\",\n\t\t\t\tformatCompactList(\n\t\t\t\t\tcustomThemes.map(\n\t\t\t\t\t\t(loadedTheme) =>\n\t\t\t\t\t\t\tloadedTheme.name ??\n\t\t\t\t\t\t\tresourceDisplay.getCompactPathLabel(loadedTheme.sourcePath!, loadedTheme.sourceInfo),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tthemeList,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (!showDiagnostics) return;\n\tconst addDiagnostics = (name: string, diagnostics: readonly ResourceDiagnostic[]): void => {\n\t\tif (diagnostics.length === 0) return;\n\t\tconst warningLines = resourceDisplay.formatDiagnostics(diagnostics, sourceInfos);\n\t\thost.chatContainer.addChild(new Text(`${theme.fg(\"warning\", `[${name}]`)}\\n${warningLines}`, 0, 0));\n\t\thost.chatContainer.addChild(new Spacer(1));\n\t};\n\taddDiagnostics(\"Skill conflicts\", skillsResult.diagnostics);\n\taddDiagnostics(\"Prompt conflicts\", promptsResult.diagnostics);\n\n\tconst extensionDiagnostics: ResourceDiagnostic[] = resourceLoader\n\t\t.getExtensions()\n\t\t.errors.map((error) => ({ type: \"error\", message: error.error, path: error.path }));\n\textensionDiagnostics.push(...host.session.extensionRunner.getCommandDiagnostics());\n\textensionDiagnostics.push(...getBuiltInCommandConflictDiagnostics(host));\n\textensionDiagnostics.push(...host.session.extensionRunner.getShortcutDiagnostics());\n\taddDiagnostics(\"Extension issues\", extensionDiagnostics);\n\taddDiagnostics(\"Theme conflicts\", themesResult.diagnostics);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"resource-display.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/resource-display.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure formatters for the startup \"loaded resources\" listing and diagnostics.\n *\n * Every function here reads only its arguments (paths, source metadata, diagnostics)\n * and returns strings/data; none touch UI components, session state, or `this`.\n * `showLoadedResources` and other stateful display code in interactive-mode delegate\n * to these so the presentation math is unit-testable in isolation.\n */\n\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { ResourceDiagnostic } from \"../../core/resource-loader.ts\";\nimport type { SourceInfo } from \"../../core/source-info.ts\";\nimport { parseGitUrl } from \"../../utils/git.ts\";\nimport { theme } from \"./theme/theme.ts\";\n\nexport function formatDisplayPath(p: string): string {\n\tconst home = os.homedir();\n\tlet result = p;\n\n\t// Replace home directory with ~\n\tif (result.startsWith(home)) {\n\t\tresult = `~${result.slice(home.length)}`;\n\t}\n\n\treturn result;\n}\n\nexport function formatExtensionDisplayPath(p: string): string {\n\tlet result = formatDisplayPath(p);\n\tresult = result.replace(/\\/index\\.ts$/, \"\").replace(/\\/index\\.js$/, \"\");\n\treturn result;\n}\n\nexport function isPackageSource(sourceInfo?: SourceInfo): boolean {\n\tconst source = sourceInfo?.source ?? \"\";\n\treturn source.startsWith(\"npm:\") || source.startsWith(\"git:\");\n}\n\n/**\n * Get a short path relative to the package root for display.\n */\nexport function getShortPath(fullPath: string, sourceInfo?: SourceInfo): string {\n\tconst baseDir = sourceInfo?.baseDir;\n\tif (baseDir && isPackageSource(sourceInfo)) {\n\t\tconst relativePath = path.relative(path.resolve(baseDir), path.resolve(fullPath));\n\t\tif (\n\t\t\trelativePath &&\n\t\t\trelativePath !== \".\" &&\n\t\t\t!relativePath.startsWith(\"..\") &&\n\t\t\t!relativePath.startsWith(`..${path.sep}`) &&\n\t\t\t!path.isAbsolute(relativePath)\n\t\t) {\n\t\t\treturn relativePath.replace(/\\\\/g, \"/\");\n\t\t}\n\t}\n\n\tconst source = sourceInfo?.source ?? \"\";\n\tconst npmMatch = fullPath.match(/node_modules\\/(@?[^/]+(?:\\/[^/]+)?)\\/(.*)/);\n\tif (npmMatch && source.startsWith(\"npm:\")) {\n\t\treturn npmMatch[2];\n\t}\n\n\tconst gitMatch = fullPath.match(/git\\/[^/]+\\/[^/]+\\/(.*)/);\n\tif (gitMatch && source.startsWith(\"git:\")) {\n\t\treturn gitMatch[1];\n\t}\n\n\treturn formatDisplayPath(fullPath);\n}\n\nexport function getCompactPathLabel(resourcePath: string, sourceInfo?: SourceInfo): string {\n\tconst shortPath = getShortPath(resourcePath, sourceInfo);\n\tconst normalizedPath = shortPath.replace(/\\\\/g, \"/\");\n\tconst segments = normalizedPath.split(\"/\").filter((segment) => segment.length > 0 && segment !== \"~\");\n\tif (segments.length > 0) {\n\t\treturn segments[segments.length - 1]!;\n\t}\n\treturn shortPath;\n}\n\nexport function getCompactPackageSourceLabel(sourceInfo?: SourceInfo): string {\n\tconst source = sourceInfo?.source ?? \"\";\n\tif (source.startsWith(\"npm:\")) {\n\t\treturn source.slice(\"npm:\".length) || source;\n\t}\n\n\tconst gitSource = parseGitUrl(source);\n\tif (gitSource) {\n\t\treturn gitSource.path || source;\n\t}\n\n\treturn source;\n}\n\nexport function getCompactExtensionLabel(resourcePath: string, sourceInfo?: SourceInfo): string {\n\tif (!isPackageSource(sourceInfo)) {\n\t\treturn getCompactPathLabel(resourcePath, sourceInfo);\n\t}\n\n\tconst sourceLabel = getCompactPackageSourceLabel(sourceInfo);\n\tif (!sourceLabel) {\n\t\treturn getCompactPathLabel(resourcePath, sourceInfo);\n\t}\n\n\tconst shortPath = getShortPath(resourcePath, sourceInfo).replace(/\\\\/g, \"/\");\n\tconst packagePath = shortPath.startsWith(\"extensions/\") ? shortPath.slice(\"extensions/\".length) : shortPath;\n\tconst parsedPath = path.posix.parse(packagePath);\n\n\tif (parsedPath.name === \"index\") {\n\t\treturn !parsedPath.dir || parsedPath.dir === \".\" ? sourceLabel : `${sourceLabel}:${parsedPath.dir}`;\n\t}\n\n\treturn `${sourceLabel}:${packagePath}`;\n}\n\nexport function getCompactDisplayPathSegments(resourcePath: string): string[] {\n\treturn formatDisplayPath(resourcePath)\n\t\t.replace(/\\\\/g, \"/\")\n\t\t.split(\"/\")\n\t\t.filter((segment) => segment.length > 0 && segment !== \"~\");\n}\n\nexport function getCompactNonPackageExtensionLabel(\n\tresourcePath: string,\n\tindex: number,\n\tallPaths: Array<{ path: string; segments: string[] }>,\n): string {\n\tconst segments = allPaths[index]?.segments;\n\tif (!segments || segments.length === 0) {\n\t\treturn getCompactPathLabel(resourcePath);\n\t}\n\n\tfor (let segmentCount = 1; segmentCount <= segments.length; segmentCount += 1) {\n\t\tconst candidate = segments.slice(-segmentCount).join(\"/\");\n\t\tconst isUnique = allPaths.every((item, itemIndex) => {\n\t\t\tif (itemIndex === index) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn item.segments.slice(-segmentCount).join(\"/\") !== candidate;\n\t\t});\n\n\t\tif (isUnique) {\n\t\t\treturn candidate;\n\t\t}\n\t}\n\n\treturn segments.join(\"/\");\n}\n\nexport function getCompactExtensionLabels(extensions: Array<{ path: string; sourceInfo?: SourceInfo }>): string[] {\n\tconst nonPackageExtensions = extensions\n\t\t.map((extension) => {\n\t\t\tconst segments = getCompactDisplayPathSegments(extension.path);\n\t\t\tconst lastSegment = segments[segments.length - 1];\n\t\t\tif (segments.length > 1 && (lastSegment === \"index.ts\" || lastSegment === \"index.js\")) {\n\t\t\t\tsegments.pop();\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tpath: extension.path,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\tsegments,\n\t\t\t};\n\t\t})\n\t\t.filter((extension) => !isPackageSource(extension.sourceInfo));\n\n\treturn extensions.map((extension) => {\n\t\tif (isPackageSource(extension.sourceInfo)) {\n\t\t\treturn getCompactExtensionLabel(extension.path, extension.sourceInfo);\n\t\t}\n\n\t\tconst nonPackageIndex = nonPackageExtensions.findIndex((item) => item.path === extension.path);\n\t\tif (nonPackageIndex === -1) {\n\t\t\treturn getCompactPathLabel(extension.path, extension.sourceInfo);\n\t\t}\n\n\t\treturn getCompactNonPackageExtensionLabel(extension.path, nonPackageIndex, nonPackageExtensions);\n\t});\n}\n\nexport function getDisplaySourceInfo(sourceInfo?: SourceInfo): {\n\tlabel: string;\n\tscopeLabel?: string;\n\tcolor: \"accent\" | \"muted\";\n} {\n\tconst source = sourceInfo?.source ?? \"local\";\n\tconst scope = sourceInfo?.scope ?? \"project\";\n\tif (source === \"local\") {\n\t\tif (scope === \"user\") {\n\t\t\treturn { label: \"user\", color: \"muted\" };\n\t\t}\n\t\tif (scope === \"project\") {\n\t\t\treturn { label: \"project\", color: \"muted\" };\n\t\t}\n\t\tif (scope === \"temporary\") {\n\t\t\treturn { label: \"path\", scopeLabel: \"temp\", color: \"muted\" };\n\t\t}\n\t\treturn { label: \"path\", color: \"muted\" };\n\t}\n\n\tif (source === \"cli\") {\n\t\treturn { label: \"path\", scopeLabel: scope === \"temporary\" ? \"temp\" : undefined, color: \"muted\" };\n\t}\n\n\tconst scopeLabel =\n\t\tscope === \"user\" ? \"user\" : scope === \"project\" ? \"project\" : scope === \"temporary\" ? \"temp\" : undefined;\n\treturn { label: source, scopeLabel, color: \"accent\" };\n}\n\nexport function getScopeGroup(sourceInfo?: SourceInfo): \"user\" | \"project\" | \"path\" {\n\tconst source = sourceInfo?.source ?? \"local\";\n\tconst scope = sourceInfo?.scope ?? \"project\";\n\tif (source === \"cli\" || scope === \"temporary\") return \"path\";\n\tif (scope === \"user\") return \"user\";\n\tif (scope === \"project\") return \"project\";\n\treturn \"path\";\n}\n\nexport function buildScopeGroups(items: Array<{ path: string; sourceInfo?: SourceInfo }>): Array<{\n\tscope: \"user\" | \"project\" | \"path\";\n\tpaths: Array<{ path: string; sourceInfo?: SourceInfo }>;\n\tpackages: Map<string, Array<{ path: string; sourceInfo?: SourceInfo }>>;\n}> {\n\tconst groups: Record<\n\t\t\"user\" | \"project\" | \"path\",\n\t\t{\n\t\t\tscope: \"user\" | \"project\" | \"path\";\n\t\t\tpaths: Array<{ path: string; sourceInfo?: SourceInfo }>;\n\t\t\tpackages: Map<string, Array<{ path: string; sourceInfo?: SourceInfo }>>;\n\t\t}\n\t> = {\n\t\tuser: { scope: \"user\", paths: [], packages: new Map() },\n\t\tproject: { scope: \"project\", paths: [], packages: new Map() },\n\t\tpath: { scope: \"path\", paths: [], packages: new Map() },\n\t};\n\n\tfor (const item of items) {\n\t\tconst groupKey = getScopeGroup(item.sourceInfo);\n\t\tconst group = groups[groupKey];\n\t\tconst source = item.sourceInfo?.source ?? \"local\";\n\n\t\tif (isPackageSource(item.sourceInfo)) {\n\t\t\tconst list = group.packages.get(source) ?? [];\n\t\t\tlist.push(item);\n\t\t\tgroup.packages.set(source, list);\n\t\t} else {\n\t\t\tgroup.paths.push(item);\n\t\t}\n\t}\n\n\treturn [groups.project, groups.user, groups.path].filter(\n\t\t(group) => group.paths.length > 0 || group.packages.size > 0,\n\t);\n}\n\nexport function formatScopeGroups(\n\tgroups: Array<{\n\t\tscope: \"user\" | \"project\" | \"path\";\n\t\tpaths: Array<{ path: string; sourceInfo?: SourceInfo }>;\n\t\tpackages: Map<string, Array<{ path: string; sourceInfo?: SourceInfo }>>;\n\t}>,\n\toptions: {\n\t\tformatPath: (item: { path: string; sourceInfo?: SourceInfo }) => string;\n\t\tformatPackagePath: (item: { path: string; sourceInfo?: SourceInfo }, source: string) => string;\n\t},\n): string {\n\tconst lines: string[] = [];\n\n\tfor (const group of groups) {\n\t\tlines.push(` ${theme.fg(\"accent\", group.scope)}`);\n\n\t\tconst sortedPaths = [...group.paths].sort((a, b) => a.path.localeCompare(b.path));\n\t\tfor (const item of sortedPaths) {\n\t\t\tlines.push(theme.fg(\"dim\", ` ${options.formatPath(item)}`));\n\t\t}\n\n\t\tconst sortedPackages = Array.from(group.packages.entries()).sort(([a], [b]) => a.localeCompare(b));\n\t\tfor (const [source, items] of sortedPackages) {\n\t\t\tlines.push(` ${theme.fg(\"mdLink\", source)}`);\n\t\t\tconst sortedPackagePaths = [...items].sort((a, b) => a.path.localeCompare(b.path));\n\t\t\tfor (const item of sortedPackagePaths) {\n\t\t\t\tlines.push(theme.fg(\"dim\", ` ${options.formatPackagePath(item, source)}`));\n\t\t\t}\n\t\t}\n\t}\n\n\treturn lines.join(\"\\n\");\n}\n\nexport function findSourceInfoForPath(p: string, sourceInfos: Map<string, SourceInfo>): SourceInfo | undefined {\n\tconst exact = sourceInfos.get(p);\n\tif (exact) return exact;\n\n\tlet current = p;\n\twhile (current.includes(\"/\")) {\n\t\tcurrent = current.substring(0, current.lastIndexOf(\"/\"));\n\t\tconst parent = sourceInfos.get(current);\n\t\tif (parent) return parent;\n\t}\n\n\treturn undefined;\n}\n\nexport function formatPathWithSource(p: string, sourceInfo?: SourceInfo): string {\n\tif (sourceInfo) {\n\t\tconst shortPath = getShortPath(p, sourceInfo);\n\t\tconst { label, scopeLabel } = getDisplaySourceInfo(sourceInfo);\n\t\tconst labelText = scopeLabel ? `${label} (${scopeLabel})` : label;\n\t\treturn `${labelText} ${shortPath}`;\n\t}\n\treturn formatDisplayPath(p);\n}\n\nexport function formatDiagnostics(\n\tdiagnostics: readonly ResourceDiagnostic[],\n\tsourceInfos: Map<string, SourceInfo>,\n): string {\n\tconst lines: string[] = [];\n\n\t// Group collision diagnostics by name\n\tconst collisions = new Map<string, ResourceDiagnostic[]>();\n\tconst otherDiagnostics: ResourceDiagnostic[] = [];\n\n\tfor (const d of diagnostics) {\n\t\tif (d.type === \"collision\" && d.collision) {\n\t\t\tconst list = collisions.get(d.collision.name) ?? [];\n\t\t\tlist.push(d);\n\t\t\tcollisions.set(d.collision.name, list);\n\t\t} else {\n\t\t\totherDiagnostics.push(d);\n\t\t}\n\t}\n\n\t// Format collision diagnostics grouped by name\n\tfor (const [name, collisionList] of collisions) {\n\t\tconst first = collisionList[0]?.collision;\n\t\tif (!first) continue;\n\t\tlines.push(theme.fg(\"warning\", ` \"${name}\" collision:`));\n\t\tlines.push(\n\t\t\ttheme.fg(\n\t\t\t\t\"dim\",\n\t\t\t\t` ${theme.fg(\"success\", \"✓\")} ${formatPathWithSource(first.winnerPath, findSourceInfoForPath(first.winnerPath, sourceInfos))}`,\n\t\t\t),\n\t\t);\n\t\tfor (const d of collisionList) {\n\t\t\tif (d.collision) {\n\t\t\t\tlines.push(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"dim\",\n\t\t\t\t\t\t` ${theme.fg(\"warning\", \"✗\")} ${formatPathWithSource(d.collision.loserPath, findSourceInfoForPath(d.collision.loserPath, sourceInfos))} (skipped)`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const d of otherDiagnostics) {\n\t\tif (d.path) {\n\t\t\tconst formattedPath = formatPathWithSource(d.path, findSourceInfoForPath(d.path, sourceInfos));\n\t\t\tlines.push(theme.fg(d.type === \"error\" ? \"error\" : \"warning\", ` ${formattedPath}`));\n\t\t\tlines.push(theme.fg(d.type === \"error\" ? \"error\" : \"warning\", ` ${d.message}`));\n\t\t} else {\n\t\t\tlines.push(theme.fg(d.type === \"error\" ? \"error\" : \"warning\", ` ${d.message}`));\n\t\t}\n\t}\n\n\treturn lines.join(\"\\n\");\n}\n"]}
1
+ {"version":3,"file":"resource-display.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/resource-display.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure formatters for the startup \"loaded resources\" listing and diagnostics.\n *\n * Every function here reads only its arguments (paths, source metadata, diagnostics)\n * and returns strings/data; none touch UI components, session state, or `this`.\n * `showLoadedResources` and other stateful display code in interactive-mode delegate\n * to these so the presentation math is unit-testable in isolation.\n */\n\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { ResourceDiagnostic } from \"../../core/resource-loader.ts\";\nimport type { SourceInfo } from \"../../core/source-info.ts\";\nimport { parseGitUrl } from \"../../utils/git.ts\";\nimport { theme } from \"./theme/theme.ts\";\n\nexport function formatDisplayPath(p: string): string {\n\tconst home = os.homedir();\n\tlet result = p;\n\n\t// Replace home directory with ~\n\tif (result.startsWith(home)) {\n\t\tresult = `~${result.slice(home.length)}`;\n\t}\n\n\treturn result;\n}\n\nexport function formatExtensionDisplayPath(p: string): string {\n\tlet result = formatDisplayPath(p);\n\tresult = result.replace(/\\/index\\.ts$/, \"\").replace(/\\/index\\.js$/, \"\");\n\treturn result;\n}\n\nexport function isPackageSource(sourceInfo?: SourceInfo): boolean {\n\tconst source = sourceInfo?.source ?? \"\";\n\treturn source.startsWith(\"npm:\") || source.startsWith(\"git:\");\n}\n\n/**\n * Get a short path relative to the package root for display.\n */\nexport function getShortPath(fullPath: string, sourceInfo?: SourceInfo): string {\n\tconst normalizedFullPath = fullPath.replace(/\\\\/g, \"/\");\n\tconst baseDir = sourceInfo?.baseDir;\n\tif (baseDir && isPackageSource(sourceInfo)) {\n\t\tconst normalizedBaseDir = baseDir.replace(/\\\\/g, \"/\");\n\t\tconst npmRootMatch = normalizedBaseDir.match(/^(.*\\/node_modules)\\/(@?[^/]+(?:\\/[^/]+)?)$/);\n\t\tif (npmRootMatch?.[1] && normalizedFullPath.startsWith(`${npmRootMatch[1]}/`)) {\n\t\t\treturn path.posix.relative(normalizedBaseDir, normalizedFullPath);\n\t\t}\n\n\t\tconst relativePath = path.relative(path.resolve(baseDir), path.resolve(fullPath));\n\t\tif (\n\t\t\trelativePath &&\n\t\t\trelativePath !== \".\" &&\n\t\t\t!relativePath.startsWith(\"..\") &&\n\t\t\t!relativePath.startsWith(`..${path.sep}`) &&\n\t\t\t!path.isAbsolute(relativePath)\n\t\t) {\n\t\t\treturn relativePath.replace(/\\\\/g, \"/\");\n\t\t}\n\t}\n\n\tconst source = sourceInfo?.source ?? \"\";\n\tconst npmMatch = normalizedFullPath.match(/node_modules\\/(@?[^/]+(?:\\/[^/]+)?)\\/(.*)/);\n\tif (npmMatch && source.startsWith(\"npm:\")) {\n\t\treturn npmMatch[2];\n\t}\n\n\tconst gitMatch = normalizedFullPath.match(/git\\/[^/]+\\/[^/]+\\/(.*)/);\n\tif (gitMatch && source.startsWith(\"git:\")) {\n\t\treturn gitMatch[1];\n\t}\n\n\treturn formatDisplayPath(fullPath);\n}\n\nexport function getCompactPathLabel(resourcePath: string, sourceInfo?: SourceInfo): string {\n\tconst shortPath = getShortPath(resourcePath, sourceInfo);\n\tconst normalizedPath = shortPath.replace(/\\\\/g, \"/\");\n\tconst segments = normalizedPath.split(\"/\").filter((segment) => segment.length > 0 && segment !== \"~\");\n\tif (segments.length > 0) {\n\t\treturn segments[segments.length - 1]!;\n\t}\n\treturn shortPath;\n}\n\nexport function getCompactPackageSourceLabel(sourceInfo?: SourceInfo): string {\n\tconst source = sourceInfo?.source ?? \"\";\n\tif (source.startsWith(\"npm:\")) {\n\t\treturn source.slice(\"npm:\".length) || source;\n\t}\n\n\tconst gitSource = parseGitUrl(source);\n\tif (gitSource) {\n\t\treturn gitSource.path || source;\n\t}\n\n\treturn source;\n}\n\nexport function getCompactExtensionLabel(resourcePath: string, sourceInfo?: SourceInfo): string {\n\tif (!isPackageSource(sourceInfo)) {\n\t\treturn getCompactPathLabel(resourcePath, sourceInfo);\n\t}\n\n\tconst sourceLabel = getCompactPackageSourceLabel(sourceInfo);\n\tif (!sourceLabel) {\n\t\treturn getCompactPathLabel(resourcePath, sourceInfo);\n\t}\n\n\tconst shortPath = getShortPath(resourcePath, sourceInfo).replace(/\\\\/g, \"/\");\n\tconst packagePath = shortPath.startsWith(\"extensions/\") ? shortPath.slice(\"extensions/\".length) : shortPath;\n\tconst parsedPath = path.posix.parse(packagePath);\n\n\tif (parsedPath.name === \"index\") {\n\t\treturn !parsedPath.dir || parsedPath.dir === \".\" ? sourceLabel : `${sourceLabel}:${parsedPath.dir}`;\n\t}\n\n\treturn `${sourceLabel}:${packagePath}`;\n}\n\nexport function getCompactDisplayPathSegments(resourcePath: string): string[] {\n\treturn formatDisplayPath(resourcePath)\n\t\t.replace(/\\\\/g, \"/\")\n\t\t.split(\"/\")\n\t\t.filter((segment) => segment.length > 0 && segment !== \"~\");\n}\n\nexport function getCompactNonPackageExtensionLabel(\n\tresourcePath: string,\n\tindex: number,\n\tallPaths: Array<{ path: string; segments: string[] }>,\n): string {\n\tconst segments = allPaths[index]?.segments;\n\tif (!segments || segments.length === 0) {\n\t\treturn getCompactPathLabel(resourcePath);\n\t}\n\n\tfor (let segmentCount = 1; segmentCount <= segments.length; segmentCount += 1) {\n\t\tconst candidate = segments.slice(-segmentCount).join(\"/\");\n\t\tconst isUnique = allPaths.every((item, itemIndex) => {\n\t\t\tif (itemIndex === index) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn item.segments.slice(-segmentCount).join(\"/\") !== candidate;\n\t\t});\n\n\t\tif (isUnique) {\n\t\t\treturn candidate;\n\t\t}\n\t}\n\n\treturn segments.join(\"/\");\n}\n\nexport function getCompactExtensionLabels(extensions: Array<{ path: string; sourceInfo?: SourceInfo }>): string[] {\n\tconst nonPackageExtensions = extensions\n\t\t.map((extension) => {\n\t\t\tconst segments = getCompactDisplayPathSegments(extension.path);\n\t\t\tconst lastSegment = segments[segments.length - 1];\n\t\t\tif (segments.length > 1 && (lastSegment === \"index.ts\" || lastSegment === \"index.js\")) {\n\t\t\t\tsegments.pop();\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tpath: extension.path,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\tsegments,\n\t\t\t};\n\t\t})\n\t\t.filter((extension) => !isPackageSource(extension.sourceInfo));\n\n\treturn extensions.map((extension) => {\n\t\tif (isPackageSource(extension.sourceInfo)) {\n\t\t\treturn getCompactExtensionLabel(extension.path, extension.sourceInfo);\n\t\t}\n\n\t\tconst nonPackageIndex = nonPackageExtensions.findIndex((item) => item.path === extension.path);\n\t\tif (nonPackageIndex === -1) {\n\t\t\treturn getCompactPathLabel(extension.path, extension.sourceInfo);\n\t\t}\n\n\t\treturn getCompactNonPackageExtensionLabel(extension.path, nonPackageIndex, nonPackageExtensions);\n\t});\n}\n\nexport function getDisplaySourceInfo(sourceInfo?: SourceInfo): {\n\tlabel: string;\n\tscopeLabel?: string;\n\tcolor: \"accent\" | \"muted\";\n} {\n\tconst source = sourceInfo?.source ?? \"local\";\n\tconst scope = sourceInfo?.scope ?? \"project\";\n\tif (source === \"local\") {\n\t\tif (scope === \"user\") {\n\t\t\treturn { label: \"user\", color: \"muted\" };\n\t\t}\n\t\tif (scope === \"project\") {\n\t\t\treturn { label: \"project\", color: \"muted\" };\n\t\t}\n\t\tif (scope === \"temporary\") {\n\t\t\treturn { label: \"path\", scopeLabel: \"temp\", color: \"muted\" };\n\t\t}\n\t\treturn { label: \"path\", color: \"muted\" };\n\t}\n\n\tif (source === \"cli\") {\n\t\treturn { label: \"path\", scopeLabel: scope === \"temporary\" ? \"temp\" : undefined, color: \"muted\" };\n\t}\n\n\tconst scopeLabel =\n\t\tscope === \"user\" ? \"user\" : scope === \"project\" ? \"project\" : scope === \"temporary\" ? \"temp\" : undefined;\n\treturn { label: source, scopeLabel, color: \"accent\" };\n}\n\nexport function getScopeGroup(sourceInfo?: SourceInfo): \"user\" | \"project\" | \"path\" {\n\tconst source = sourceInfo?.source ?? \"local\";\n\tconst scope = sourceInfo?.scope ?? \"project\";\n\tif (source === \"cli\" || scope === \"temporary\") return \"path\";\n\tif (scope === \"user\") return \"user\";\n\tif (scope === \"project\") return \"project\";\n\treturn \"path\";\n}\n\nexport function buildScopeGroups(items: Array<{ path: string; sourceInfo?: SourceInfo }>): Array<{\n\tscope: \"user\" | \"project\" | \"path\";\n\tpaths: Array<{ path: string; sourceInfo?: SourceInfo }>;\n\tpackages: Map<string, Array<{ path: string; sourceInfo?: SourceInfo }>>;\n}> {\n\tconst groups: Record<\n\t\t\"user\" | \"project\" | \"path\",\n\t\t{\n\t\t\tscope: \"user\" | \"project\" | \"path\";\n\t\t\tpaths: Array<{ path: string; sourceInfo?: SourceInfo }>;\n\t\t\tpackages: Map<string, Array<{ path: string; sourceInfo?: SourceInfo }>>;\n\t\t}\n\t> = {\n\t\tuser: { scope: \"user\", paths: [], packages: new Map() },\n\t\tproject: { scope: \"project\", paths: [], packages: new Map() },\n\t\tpath: { scope: \"path\", paths: [], packages: new Map() },\n\t};\n\n\tfor (const item of items) {\n\t\tconst groupKey = getScopeGroup(item.sourceInfo);\n\t\tconst group = groups[groupKey];\n\t\tconst source = item.sourceInfo?.source ?? \"local\";\n\n\t\tif (isPackageSource(item.sourceInfo)) {\n\t\t\tconst list = group.packages.get(source) ?? [];\n\t\t\tlist.push(item);\n\t\t\tgroup.packages.set(source, list);\n\t\t} else {\n\t\t\tgroup.paths.push(item);\n\t\t}\n\t}\n\n\treturn [groups.project, groups.user, groups.path].filter(\n\t\t(group) => group.paths.length > 0 || group.packages.size > 0,\n\t);\n}\n\nexport function formatScopeGroups(\n\tgroups: Array<{\n\t\tscope: \"user\" | \"project\" | \"path\";\n\t\tpaths: Array<{ path: string; sourceInfo?: SourceInfo }>;\n\t\tpackages: Map<string, Array<{ path: string; sourceInfo?: SourceInfo }>>;\n\t}>,\n\toptions: {\n\t\tformatPath: (item: { path: string; sourceInfo?: SourceInfo }) => string;\n\t\tformatPackagePath: (item: { path: string; sourceInfo?: SourceInfo }, source: string) => string;\n\t},\n): string {\n\tconst lines: string[] = [];\n\n\tfor (const group of groups) {\n\t\tlines.push(` ${theme.fg(\"accent\", group.scope)}`);\n\n\t\tconst sortedPaths = [...group.paths].sort((a, b) => a.path.localeCompare(b.path));\n\t\tfor (const item of sortedPaths) {\n\t\t\tlines.push(theme.fg(\"dim\", ` ${options.formatPath(item)}`));\n\t\t}\n\n\t\tconst sortedPackages = Array.from(group.packages.entries()).sort(([a], [b]) => a.localeCompare(b));\n\t\tfor (const [source, items] of sortedPackages) {\n\t\t\tlines.push(` ${theme.fg(\"mdLink\", source)}`);\n\t\t\tconst sortedPackagePaths = [...items].sort((a, b) => a.path.localeCompare(b.path));\n\t\t\tfor (const item of sortedPackagePaths) {\n\t\t\t\tlines.push(theme.fg(\"dim\", ` ${options.formatPackagePath(item, source)}`));\n\t\t\t}\n\t\t}\n\t}\n\n\treturn lines.join(\"\\n\");\n}\n\nexport function findSourceInfoForPath(p: string, sourceInfos: Map<string, SourceInfo>): SourceInfo | undefined {\n\tconst exact = sourceInfos.get(p);\n\tif (exact) return exact;\n\n\tlet current = p;\n\twhile (current.includes(\"/\")) {\n\t\tcurrent = current.substring(0, current.lastIndexOf(\"/\"));\n\t\tconst parent = sourceInfos.get(current);\n\t\tif (parent) return parent;\n\t}\n\n\treturn undefined;\n}\n\nexport function formatPathWithSource(p: string, sourceInfo?: SourceInfo): string {\n\tif (sourceInfo) {\n\t\tconst shortPath = getShortPath(p, sourceInfo);\n\t\tconst { label, scopeLabel } = getDisplaySourceInfo(sourceInfo);\n\t\tconst labelText = scopeLabel ? `${label} (${scopeLabel})` : label;\n\t\treturn `${labelText} ${shortPath}`;\n\t}\n\treturn formatDisplayPath(p);\n}\n\nexport function formatDiagnostics(\n\tdiagnostics: readonly ResourceDiagnostic[],\n\tsourceInfos: Map<string, SourceInfo>,\n): string {\n\tconst lines: string[] = [];\n\n\t// Group collision diagnostics by name\n\tconst collisions = new Map<string, ResourceDiagnostic[]>();\n\tconst otherDiagnostics: ResourceDiagnostic[] = [];\n\n\tfor (const d of diagnostics) {\n\t\tif (d.type === \"collision\" && d.collision) {\n\t\t\tconst list = collisions.get(d.collision.name) ?? [];\n\t\t\tlist.push(d);\n\t\t\tcollisions.set(d.collision.name, list);\n\t\t} else {\n\t\t\totherDiagnostics.push(d);\n\t\t}\n\t}\n\n\t// Format collision diagnostics grouped by name\n\tfor (const [name, collisionList] of collisions) {\n\t\tconst first = collisionList[0]?.collision;\n\t\tif (!first) continue;\n\t\tlines.push(theme.fg(\"warning\", ` \"${name}\" collision:`));\n\t\tlines.push(\n\t\t\ttheme.fg(\n\t\t\t\t\"dim\",\n\t\t\t\t` ${theme.fg(\"success\", \"✓\")} ${formatPathWithSource(first.winnerPath, findSourceInfoForPath(first.winnerPath, sourceInfos))}`,\n\t\t\t),\n\t\t);\n\t\tfor (const d of collisionList) {\n\t\t\tif (d.collision) {\n\t\t\t\tlines.push(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"dim\",\n\t\t\t\t\t\t` ${theme.fg(\"warning\", \"✗\")} ${formatPathWithSource(d.collision.loserPath, findSourceInfoForPath(d.collision.loserPath, sourceInfos))} (skipped)`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const d of otherDiagnostics) {\n\t\tif (d.path) {\n\t\t\tconst formattedPath = formatPathWithSource(d.path, findSourceInfoForPath(d.path, sourceInfos));\n\t\t\tlines.push(theme.fg(d.type === \"error\" ? \"error\" : \"warning\", ` ${formattedPath}`));\n\t\t\tlines.push(theme.fg(d.type === \"error\" ? \"error\" : \"warning\", ` ${d.message}`));\n\t\t} else {\n\t\t\tlines.push(theme.fg(d.type === \"error\" ? \"error\" : \"warning\", ` ${d.message}`));\n\t\t}\n\t}\n\n\treturn lines.join(\"\\n\");\n}\n"]}
@@ -32,8 +32,14 @@ export function isPackageSource(sourceInfo) {
32
32
  * Get a short path relative to the package root for display.
33
33
  */
34
34
  export function getShortPath(fullPath, sourceInfo) {
35
+ const normalizedFullPath = fullPath.replace(/\\/g, "/");
35
36
  const baseDir = sourceInfo?.baseDir;
36
37
  if (baseDir && isPackageSource(sourceInfo)) {
38
+ const normalizedBaseDir = baseDir.replace(/\\/g, "/");
39
+ const npmRootMatch = normalizedBaseDir.match(/^(.*\/node_modules)\/(@?[^/]+(?:\/[^/]+)?)$/);
40
+ if (npmRootMatch?.[1] && normalizedFullPath.startsWith(`${npmRootMatch[1]}/`)) {
41
+ return path.posix.relative(normalizedBaseDir, normalizedFullPath);
42
+ }
37
43
  const relativePath = path.relative(path.resolve(baseDir), path.resolve(fullPath));
38
44
  if (relativePath &&
39
45
  relativePath !== "." &&
@@ -44,11 +50,11 @@ export function getShortPath(fullPath, sourceInfo) {
44
50
  }
45
51
  }
46
52
  const source = sourceInfo?.source ?? "";
47
- const npmMatch = fullPath.match(/node_modules\/(@?[^/]+(?:\/[^/]+)?)\/(.*)/);
53
+ const npmMatch = normalizedFullPath.match(/node_modules\/(@?[^/]+(?:\/[^/]+)?)\/(.*)/);
48
54
  if (npmMatch && source.startsWith("npm:")) {
49
55
  return npmMatch[2];
50
56
  }
51
- const gitMatch = fullPath.match(/git\/[^/]+\/[^/]+\/(.*)/);
57
+ const gitMatch = normalizedFullPath.match(/git\/[^/]+\/[^/]+\/(.*)/);
52
58
  if (gitMatch && source.startsWith("git:")) {
53
59
  return gitMatch[1];
54
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"resource-display.js","sourceRoot":"","sources":["../../../src/modes/interactive/resource-display.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure formatters for the startup \"loaded resources\" listing and diagnostics.\n *\n * Every function here reads only its arguments (paths, source metadata, diagnostics)\n * and returns strings/data; none touch UI components, session state, or `this`.\n * `showLoadedResources` and other stateful display code in interactive-mode delegate\n * to these so the presentation math is unit-testable in isolation.\n */\n\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { ResourceDiagnostic } from \"../../core/resource-loader.ts\";\nimport type { SourceInfo } from \"../../core/source-info.ts\";\nimport { parseGitUrl } from \"../../utils/git.ts\";\nimport { theme } from \"./theme/theme.ts\";\n\nexport function formatDisplayPath(p: string): string {\n\tconst home = os.homedir();\n\tlet result = p;\n\n\t// Replace home directory with ~\n\tif (result.startsWith(home)) {\n\t\tresult = `~${result.slice(home.length)}`;\n\t}\n\n\treturn result;\n}\n\nexport function formatExtensionDisplayPath(p: string): string {\n\tlet result = formatDisplayPath(p);\n\tresult = result.replace(/\\/index\\.ts$/, \"\").replace(/\\/index\\.js$/, \"\");\n\treturn result;\n}\n\nexport function isPackageSource(sourceInfo?: SourceInfo): boolean {\n\tconst source = sourceInfo?.source ?? \"\";\n\treturn source.startsWith(\"npm:\") || source.startsWith(\"git:\");\n}\n\n/**\n * Get a short path relative to the package root for display.\n */\nexport function getShortPath(fullPath: string, sourceInfo?: SourceInfo): string {\n\tconst baseDir = sourceInfo?.baseDir;\n\tif (baseDir && isPackageSource(sourceInfo)) {\n\t\tconst relativePath = path.relative(path.resolve(baseDir), path.resolve(fullPath));\n\t\tif (\n\t\t\trelativePath &&\n\t\t\trelativePath !== \".\" &&\n\t\t\t!relativePath.startsWith(\"..\") &&\n\t\t\t!relativePath.startsWith(`..${path.sep}`) &&\n\t\t\t!path.isAbsolute(relativePath)\n\t\t) {\n\t\t\treturn relativePath.replace(/\\\\/g, \"/\");\n\t\t}\n\t}\n\n\tconst source = sourceInfo?.source ?? \"\";\n\tconst npmMatch = fullPath.match(/node_modules\\/(@?[^/]+(?:\\/[^/]+)?)\\/(.*)/);\n\tif (npmMatch && source.startsWith(\"npm:\")) {\n\t\treturn npmMatch[2];\n\t}\n\n\tconst gitMatch = fullPath.match(/git\\/[^/]+\\/[^/]+\\/(.*)/);\n\tif (gitMatch && source.startsWith(\"git:\")) {\n\t\treturn gitMatch[1];\n\t}\n\n\treturn formatDisplayPath(fullPath);\n}\n\nexport function getCompactPathLabel(resourcePath: string, sourceInfo?: SourceInfo): string {\n\tconst shortPath = getShortPath(resourcePath, sourceInfo);\n\tconst normalizedPath = shortPath.replace(/\\\\/g, \"/\");\n\tconst segments = normalizedPath.split(\"/\").filter((segment) => segment.length > 0 && segment !== \"~\");\n\tif (segments.length > 0) {\n\t\treturn segments[segments.length - 1]!;\n\t}\n\treturn shortPath;\n}\n\nexport function getCompactPackageSourceLabel(sourceInfo?: SourceInfo): string {\n\tconst source = sourceInfo?.source ?? \"\";\n\tif (source.startsWith(\"npm:\")) {\n\t\treturn source.slice(\"npm:\".length) || source;\n\t}\n\n\tconst gitSource = parseGitUrl(source);\n\tif (gitSource) {\n\t\treturn gitSource.path || source;\n\t}\n\n\treturn source;\n}\n\nexport function getCompactExtensionLabel(resourcePath: string, sourceInfo?: SourceInfo): string {\n\tif (!isPackageSource(sourceInfo)) {\n\t\treturn getCompactPathLabel(resourcePath, sourceInfo);\n\t}\n\n\tconst sourceLabel = getCompactPackageSourceLabel(sourceInfo);\n\tif (!sourceLabel) {\n\t\treturn getCompactPathLabel(resourcePath, sourceInfo);\n\t}\n\n\tconst shortPath = getShortPath(resourcePath, sourceInfo).replace(/\\\\/g, \"/\");\n\tconst packagePath = shortPath.startsWith(\"extensions/\") ? shortPath.slice(\"extensions/\".length) : shortPath;\n\tconst parsedPath = path.posix.parse(packagePath);\n\n\tif (parsedPath.name === \"index\") {\n\t\treturn !parsedPath.dir || parsedPath.dir === \".\" ? sourceLabel : `${sourceLabel}:${parsedPath.dir}`;\n\t}\n\n\treturn `${sourceLabel}:${packagePath}`;\n}\n\nexport function getCompactDisplayPathSegments(resourcePath: string): string[] {\n\treturn formatDisplayPath(resourcePath)\n\t\t.replace(/\\\\/g, \"/\")\n\t\t.split(\"/\")\n\t\t.filter((segment) => segment.length > 0 && segment !== \"~\");\n}\n\nexport function getCompactNonPackageExtensionLabel(\n\tresourcePath: string,\n\tindex: number,\n\tallPaths: Array<{ path: string; segments: string[] }>,\n): string {\n\tconst segments = allPaths[index]?.segments;\n\tif (!segments || segments.length === 0) {\n\t\treturn getCompactPathLabel(resourcePath);\n\t}\n\n\tfor (let segmentCount = 1; segmentCount <= segments.length; segmentCount += 1) {\n\t\tconst candidate = segments.slice(-segmentCount).join(\"/\");\n\t\tconst isUnique = allPaths.every((item, itemIndex) => {\n\t\t\tif (itemIndex === index) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn item.segments.slice(-segmentCount).join(\"/\") !== candidate;\n\t\t});\n\n\t\tif (isUnique) {\n\t\t\treturn candidate;\n\t\t}\n\t}\n\n\treturn segments.join(\"/\");\n}\n\nexport function getCompactExtensionLabels(extensions: Array<{ path: string; sourceInfo?: SourceInfo }>): string[] {\n\tconst nonPackageExtensions = extensions\n\t\t.map((extension) => {\n\t\t\tconst segments = getCompactDisplayPathSegments(extension.path);\n\t\t\tconst lastSegment = segments[segments.length - 1];\n\t\t\tif (segments.length > 1 && (lastSegment === \"index.ts\" || lastSegment === \"index.js\")) {\n\t\t\t\tsegments.pop();\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tpath: extension.path,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\tsegments,\n\t\t\t};\n\t\t})\n\t\t.filter((extension) => !isPackageSource(extension.sourceInfo));\n\n\treturn extensions.map((extension) => {\n\t\tif (isPackageSource(extension.sourceInfo)) {\n\t\t\treturn getCompactExtensionLabel(extension.path, extension.sourceInfo);\n\t\t}\n\n\t\tconst nonPackageIndex = nonPackageExtensions.findIndex((item) => item.path === extension.path);\n\t\tif (nonPackageIndex === -1) {\n\t\t\treturn getCompactPathLabel(extension.path, extension.sourceInfo);\n\t\t}\n\n\t\treturn getCompactNonPackageExtensionLabel(extension.path, nonPackageIndex, nonPackageExtensions);\n\t});\n}\n\nexport function getDisplaySourceInfo(sourceInfo?: SourceInfo): {\n\tlabel: string;\n\tscopeLabel?: string;\n\tcolor: \"accent\" | \"muted\";\n} {\n\tconst source = sourceInfo?.source ?? \"local\";\n\tconst scope = sourceInfo?.scope ?? \"project\";\n\tif (source === \"local\") {\n\t\tif (scope === \"user\") {\n\t\t\treturn { label: \"user\", color: \"muted\" };\n\t\t}\n\t\tif (scope === \"project\") {\n\t\t\treturn { label: \"project\", color: \"muted\" };\n\t\t}\n\t\tif (scope === \"temporary\") {\n\t\t\treturn { label: \"path\", scopeLabel: \"temp\", color: \"muted\" };\n\t\t}\n\t\treturn { label: \"path\", color: \"muted\" };\n\t}\n\n\tif (source === \"cli\") {\n\t\treturn { label: \"path\", scopeLabel: scope === \"temporary\" ? \"temp\" : undefined, color: \"muted\" };\n\t}\n\n\tconst scopeLabel =\n\t\tscope === \"user\" ? \"user\" : scope === \"project\" ? \"project\" : scope === \"temporary\" ? \"temp\" : undefined;\n\treturn { label: source, scopeLabel, color: \"accent\" };\n}\n\nexport function getScopeGroup(sourceInfo?: SourceInfo): \"user\" | \"project\" | \"path\" {\n\tconst source = sourceInfo?.source ?? \"local\";\n\tconst scope = sourceInfo?.scope ?? \"project\";\n\tif (source === \"cli\" || scope === \"temporary\") return \"path\";\n\tif (scope === \"user\") return \"user\";\n\tif (scope === \"project\") return \"project\";\n\treturn \"path\";\n}\n\nexport function buildScopeGroups(items: Array<{ path: string; sourceInfo?: SourceInfo }>): Array<{\n\tscope: \"user\" | \"project\" | \"path\";\n\tpaths: Array<{ path: string; sourceInfo?: SourceInfo }>;\n\tpackages: Map<string, Array<{ path: string; sourceInfo?: SourceInfo }>>;\n}> {\n\tconst groups: Record<\n\t\t\"user\" | \"project\" | \"path\",\n\t\t{\n\t\t\tscope: \"user\" | \"project\" | \"path\";\n\t\t\tpaths: Array<{ path: string; sourceInfo?: SourceInfo }>;\n\t\t\tpackages: Map<string, Array<{ path: string; sourceInfo?: SourceInfo }>>;\n\t\t}\n\t> = {\n\t\tuser: { scope: \"user\", paths: [], packages: new Map() },\n\t\tproject: { scope: \"project\", paths: [], packages: new Map() },\n\t\tpath: { scope: \"path\", paths: [], packages: new Map() },\n\t};\n\n\tfor (const item of items) {\n\t\tconst groupKey = getScopeGroup(item.sourceInfo);\n\t\tconst group = groups[groupKey];\n\t\tconst source = item.sourceInfo?.source ?? \"local\";\n\n\t\tif (isPackageSource(item.sourceInfo)) {\n\t\t\tconst list = group.packages.get(source) ?? [];\n\t\t\tlist.push(item);\n\t\t\tgroup.packages.set(source, list);\n\t\t} else {\n\t\t\tgroup.paths.push(item);\n\t\t}\n\t}\n\n\treturn [groups.project, groups.user, groups.path].filter(\n\t\t(group) => group.paths.length > 0 || group.packages.size > 0,\n\t);\n}\n\nexport function formatScopeGroups(\n\tgroups: Array<{\n\t\tscope: \"user\" | \"project\" | \"path\";\n\t\tpaths: Array<{ path: string; sourceInfo?: SourceInfo }>;\n\t\tpackages: Map<string, Array<{ path: string; sourceInfo?: SourceInfo }>>;\n\t}>,\n\toptions: {\n\t\tformatPath: (item: { path: string; sourceInfo?: SourceInfo }) => string;\n\t\tformatPackagePath: (item: { path: string; sourceInfo?: SourceInfo }, source: string) => string;\n\t},\n): string {\n\tconst lines: string[] = [];\n\n\tfor (const group of groups) {\n\t\tlines.push(` ${theme.fg(\"accent\", group.scope)}`);\n\n\t\tconst sortedPaths = [...group.paths].sort((a, b) => a.path.localeCompare(b.path));\n\t\tfor (const item of sortedPaths) {\n\t\t\tlines.push(theme.fg(\"dim\", ` ${options.formatPath(item)}`));\n\t\t}\n\n\t\tconst sortedPackages = Array.from(group.packages.entries()).sort(([a], [b]) => a.localeCompare(b));\n\t\tfor (const [source, items] of sortedPackages) {\n\t\t\tlines.push(` ${theme.fg(\"mdLink\", source)}`);\n\t\t\tconst sortedPackagePaths = [...items].sort((a, b) => a.path.localeCompare(b.path));\n\t\t\tfor (const item of sortedPackagePaths) {\n\t\t\t\tlines.push(theme.fg(\"dim\", ` ${options.formatPackagePath(item, source)}`));\n\t\t\t}\n\t\t}\n\t}\n\n\treturn lines.join(\"\\n\");\n}\n\nexport function findSourceInfoForPath(p: string, sourceInfos: Map<string, SourceInfo>): SourceInfo | undefined {\n\tconst exact = sourceInfos.get(p);\n\tif (exact) return exact;\n\n\tlet current = p;\n\twhile (current.includes(\"/\")) {\n\t\tcurrent = current.substring(0, current.lastIndexOf(\"/\"));\n\t\tconst parent = sourceInfos.get(current);\n\t\tif (parent) return parent;\n\t}\n\n\treturn undefined;\n}\n\nexport function formatPathWithSource(p: string, sourceInfo?: SourceInfo): string {\n\tif (sourceInfo) {\n\t\tconst shortPath = getShortPath(p, sourceInfo);\n\t\tconst { label, scopeLabel } = getDisplaySourceInfo(sourceInfo);\n\t\tconst labelText = scopeLabel ? `${label} (${scopeLabel})` : label;\n\t\treturn `${labelText} ${shortPath}`;\n\t}\n\treturn formatDisplayPath(p);\n}\n\nexport function formatDiagnostics(\n\tdiagnostics: readonly ResourceDiagnostic[],\n\tsourceInfos: Map<string, SourceInfo>,\n): string {\n\tconst lines: string[] = [];\n\n\t// Group collision diagnostics by name\n\tconst collisions = new Map<string, ResourceDiagnostic[]>();\n\tconst otherDiagnostics: ResourceDiagnostic[] = [];\n\n\tfor (const d of diagnostics) {\n\t\tif (d.type === \"collision\" && d.collision) {\n\t\t\tconst list = collisions.get(d.collision.name) ?? [];\n\t\t\tlist.push(d);\n\t\t\tcollisions.set(d.collision.name, list);\n\t\t} else {\n\t\t\totherDiagnostics.push(d);\n\t\t}\n\t}\n\n\t// Format collision diagnostics grouped by name\n\tfor (const [name, collisionList] of collisions) {\n\t\tconst first = collisionList[0]?.collision;\n\t\tif (!first) continue;\n\t\tlines.push(theme.fg(\"warning\", ` \"${name}\" collision:`));\n\t\tlines.push(\n\t\t\ttheme.fg(\n\t\t\t\t\"dim\",\n\t\t\t\t` ${theme.fg(\"success\", \"✓\")} ${formatPathWithSource(first.winnerPath, findSourceInfoForPath(first.winnerPath, sourceInfos))}`,\n\t\t\t),\n\t\t);\n\t\tfor (const d of collisionList) {\n\t\t\tif (d.collision) {\n\t\t\t\tlines.push(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"dim\",\n\t\t\t\t\t\t` ${theme.fg(\"warning\", \"✗\")} ${formatPathWithSource(d.collision.loserPath, findSourceInfoForPath(d.collision.loserPath, sourceInfos))} (skipped)`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const d of otherDiagnostics) {\n\t\tif (d.path) {\n\t\t\tconst formattedPath = formatPathWithSource(d.path, findSourceInfoForPath(d.path, sourceInfos));\n\t\t\tlines.push(theme.fg(d.type === \"error\" ? \"error\" : \"warning\", ` ${formattedPath}`));\n\t\t\tlines.push(theme.fg(d.type === \"error\" ? \"error\" : \"warning\", ` ${d.message}`));\n\t\t} else {\n\t\t\tlines.push(theme.fg(d.type === \"error\" ? \"error\" : \"warning\", ` ${d.message}`));\n\t\t}\n\t}\n\n\treturn lines.join(\"\\n\");\n}\n"]}
1
+ {"version":3,"file":"resource-display.js","sourceRoot":"","sources":["../../../src/modes/interactive/resource-display.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure formatters for the startup \"loaded resources\" listing and diagnostics.\n *\n * Every function here reads only its arguments (paths, source metadata, diagnostics)\n * and returns strings/data; none touch UI components, session state, or `this`.\n * `showLoadedResources` and other stateful display code in interactive-mode delegate\n * to these so the presentation math is unit-testable in isolation.\n */\n\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { ResourceDiagnostic } from \"../../core/resource-loader.ts\";\nimport type { SourceInfo } from \"../../core/source-info.ts\";\nimport { parseGitUrl } from \"../../utils/git.ts\";\nimport { theme } from \"./theme/theme.ts\";\n\nexport function formatDisplayPath(p: string): string {\n\tconst home = os.homedir();\n\tlet result = p;\n\n\t// Replace home directory with ~\n\tif (result.startsWith(home)) {\n\t\tresult = `~${result.slice(home.length)}`;\n\t}\n\n\treturn result;\n}\n\nexport function formatExtensionDisplayPath(p: string): string {\n\tlet result = formatDisplayPath(p);\n\tresult = result.replace(/\\/index\\.ts$/, \"\").replace(/\\/index\\.js$/, \"\");\n\treturn result;\n}\n\nexport function isPackageSource(sourceInfo?: SourceInfo): boolean {\n\tconst source = sourceInfo?.source ?? \"\";\n\treturn source.startsWith(\"npm:\") || source.startsWith(\"git:\");\n}\n\n/**\n * Get a short path relative to the package root for display.\n */\nexport function getShortPath(fullPath: string, sourceInfo?: SourceInfo): string {\n\tconst normalizedFullPath = fullPath.replace(/\\\\/g, \"/\");\n\tconst baseDir = sourceInfo?.baseDir;\n\tif (baseDir && isPackageSource(sourceInfo)) {\n\t\tconst normalizedBaseDir = baseDir.replace(/\\\\/g, \"/\");\n\t\tconst npmRootMatch = normalizedBaseDir.match(/^(.*\\/node_modules)\\/(@?[^/]+(?:\\/[^/]+)?)$/);\n\t\tif (npmRootMatch?.[1] && normalizedFullPath.startsWith(`${npmRootMatch[1]}/`)) {\n\t\t\treturn path.posix.relative(normalizedBaseDir, normalizedFullPath);\n\t\t}\n\n\t\tconst relativePath = path.relative(path.resolve(baseDir), path.resolve(fullPath));\n\t\tif (\n\t\t\trelativePath &&\n\t\t\trelativePath !== \".\" &&\n\t\t\t!relativePath.startsWith(\"..\") &&\n\t\t\t!relativePath.startsWith(`..${path.sep}`) &&\n\t\t\t!path.isAbsolute(relativePath)\n\t\t) {\n\t\t\treturn relativePath.replace(/\\\\/g, \"/\");\n\t\t}\n\t}\n\n\tconst source = sourceInfo?.source ?? \"\";\n\tconst npmMatch = normalizedFullPath.match(/node_modules\\/(@?[^/]+(?:\\/[^/]+)?)\\/(.*)/);\n\tif (npmMatch && source.startsWith(\"npm:\")) {\n\t\treturn npmMatch[2];\n\t}\n\n\tconst gitMatch = normalizedFullPath.match(/git\\/[^/]+\\/[^/]+\\/(.*)/);\n\tif (gitMatch && source.startsWith(\"git:\")) {\n\t\treturn gitMatch[1];\n\t}\n\n\treturn formatDisplayPath(fullPath);\n}\n\nexport function getCompactPathLabel(resourcePath: string, sourceInfo?: SourceInfo): string {\n\tconst shortPath = getShortPath(resourcePath, sourceInfo);\n\tconst normalizedPath = shortPath.replace(/\\\\/g, \"/\");\n\tconst segments = normalizedPath.split(\"/\").filter((segment) => segment.length > 0 && segment !== \"~\");\n\tif (segments.length > 0) {\n\t\treturn segments[segments.length - 1]!;\n\t}\n\treturn shortPath;\n}\n\nexport function getCompactPackageSourceLabel(sourceInfo?: SourceInfo): string {\n\tconst source = sourceInfo?.source ?? \"\";\n\tif (source.startsWith(\"npm:\")) {\n\t\treturn source.slice(\"npm:\".length) || source;\n\t}\n\n\tconst gitSource = parseGitUrl(source);\n\tif (gitSource) {\n\t\treturn gitSource.path || source;\n\t}\n\n\treturn source;\n}\n\nexport function getCompactExtensionLabel(resourcePath: string, sourceInfo?: SourceInfo): string {\n\tif (!isPackageSource(sourceInfo)) {\n\t\treturn getCompactPathLabel(resourcePath, sourceInfo);\n\t}\n\n\tconst sourceLabel = getCompactPackageSourceLabel(sourceInfo);\n\tif (!sourceLabel) {\n\t\treturn getCompactPathLabel(resourcePath, sourceInfo);\n\t}\n\n\tconst shortPath = getShortPath(resourcePath, sourceInfo).replace(/\\\\/g, \"/\");\n\tconst packagePath = shortPath.startsWith(\"extensions/\") ? shortPath.slice(\"extensions/\".length) : shortPath;\n\tconst parsedPath = path.posix.parse(packagePath);\n\n\tif (parsedPath.name === \"index\") {\n\t\treturn !parsedPath.dir || parsedPath.dir === \".\" ? sourceLabel : `${sourceLabel}:${parsedPath.dir}`;\n\t}\n\n\treturn `${sourceLabel}:${packagePath}`;\n}\n\nexport function getCompactDisplayPathSegments(resourcePath: string): string[] {\n\treturn formatDisplayPath(resourcePath)\n\t\t.replace(/\\\\/g, \"/\")\n\t\t.split(\"/\")\n\t\t.filter((segment) => segment.length > 0 && segment !== \"~\");\n}\n\nexport function getCompactNonPackageExtensionLabel(\n\tresourcePath: string,\n\tindex: number,\n\tallPaths: Array<{ path: string; segments: string[] }>,\n): string {\n\tconst segments = allPaths[index]?.segments;\n\tif (!segments || segments.length === 0) {\n\t\treturn getCompactPathLabel(resourcePath);\n\t}\n\n\tfor (let segmentCount = 1; segmentCount <= segments.length; segmentCount += 1) {\n\t\tconst candidate = segments.slice(-segmentCount).join(\"/\");\n\t\tconst isUnique = allPaths.every((item, itemIndex) => {\n\t\t\tif (itemIndex === index) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn item.segments.slice(-segmentCount).join(\"/\") !== candidate;\n\t\t});\n\n\t\tif (isUnique) {\n\t\t\treturn candidate;\n\t\t}\n\t}\n\n\treturn segments.join(\"/\");\n}\n\nexport function getCompactExtensionLabels(extensions: Array<{ path: string; sourceInfo?: SourceInfo }>): string[] {\n\tconst nonPackageExtensions = extensions\n\t\t.map((extension) => {\n\t\t\tconst segments = getCompactDisplayPathSegments(extension.path);\n\t\t\tconst lastSegment = segments[segments.length - 1];\n\t\t\tif (segments.length > 1 && (lastSegment === \"index.ts\" || lastSegment === \"index.js\")) {\n\t\t\t\tsegments.pop();\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tpath: extension.path,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\tsegments,\n\t\t\t};\n\t\t})\n\t\t.filter((extension) => !isPackageSource(extension.sourceInfo));\n\n\treturn extensions.map((extension) => {\n\t\tif (isPackageSource(extension.sourceInfo)) {\n\t\t\treturn getCompactExtensionLabel(extension.path, extension.sourceInfo);\n\t\t}\n\n\t\tconst nonPackageIndex = nonPackageExtensions.findIndex((item) => item.path === extension.path);\n\t\tif (nonPackageIndex === -1) {\n\t\t\treturn getCompactPathLabel(extension.path, extension.sourceInfo);\n\t\t}\n\n\t\treturn getCompactNonPackageExtensionLabel(extension.path, nonPackageIndex, nonPackageExtensions);\n\t});\n}\n\nexport function getDisplaySourceInfo(sourceInfo?: SourceInfo): {\n\tlabel: string;\n\tscopeLabel?: string;\n\tcolor: \"accent\" | \"muted\";\n} {\n\tconst source = sourceInfo?.source ?? \"local\";\n\tconst scope = sourceInfo?.scope ?? \"project\";\n\tif (source === \"local\") {\n\t\tif (scope === \"user\") {\n\t\t\treturn { label: \"user\", color: \"muted\" };\n\t\t}\n\t\tif (scope === \"project\") {\n\t\t\treturn { label: \"project\", color: \"muted\" };\n\t\t}\n\t\tif (scope === \"temporary\") {\n\t\t\treturn { label: \"path\", scopeLabel: \"temp\", color: \"muted\" };\n\t\t}\n\t\treturn { label: \"path\", color: \"muted\" };\n\t}\n\n\tif (source === \"cli\") {\n\t\treturn { label: \"path\", scopeLabel: scope === \"temporary\" ? \"temp\" : undefined, color: \"muted\" };\n\t}\n\n\tconst scopeLabel =\n\t\tscope === \"user\" ? \"user\" : scope === \"project\" ? \"project\" : scope === \"temporary\" ? \"temp\" : undefined;\n\treturn { label: source, scopeLabel, color: \"accent\" };\n}\n\nexport function getScopeGroup(sourceInfo?: SourceInfo): \"user\" | \"project\" | \"path\" {\n\tconst source = sourceInfo?.source ?? \"local\";\n\tconst scope = sourceInfo?.scope ?? \"project\";\n\tif (source === \"cli\" || scope === \"temporary\") return \"path\";\n\tif (scope === \"user\") return \"user\";\n\tif (scope === \"project\") return \"project\";\n\treturn \"path\";\n}\n\nexport function buildScopeGroups(items: Array<{ path: string; sourceInfo?: SourceInfo }>): Array<{\n\tscope: \"user\" | \"project\" | \"path\";\n\tpaths: Array<{ path: string; sourceInfo?: SourceInfo }>;\n\tpackages: Map<string, Array<{ path: string; sourceInfo?: SourceInfo }>>;\n}> {\n\tconst groups: Record<\n\t\t\"user\" | \"project\" | \"path\",\n\t\t{\n\t\t\tscope: \"user\" | \"project\" | \"path\";\n\t\t\tpaths: Array<{ path: string; sourceInfo?: SourceInfo }>;\n\t\t\tpackages: Map<string, Array<{ path: string; sourceInfo?: SourceInfo }>>;\n\t\t}\n\t> = {\n\t\tuser: { scope: \"user\", paths: [], packages: new Map() },\n\t\tproject: { scope: \"project\", paths: [], packages: new Map() },\n\t\tpath: { scope: \"path\", paths: [], packages: new Map() },\n\t};\n\n\tfor (const item of items) {\n\t\tconst groupKey = getScopeGroup(item.sourceInfo);\n\t\tconst group = groups[groupKey];\n\t\tconst source = item.sourceInfo?.source ?? \"local\";\n\n\t\tif (isPackageSource(item.sourceInfo)) {\n\t\t\tconst list = group.packages.get(source) ?? [];\n\t\t\tlist.push(item);\n\t\t\tgroup.packages.set(source, list);\n\t\t} else {\n\t\t\tgroup.paths.push(item);\n\t\t}\n\t}\n\n\treturn [groups.project, groups.user, groups.path].filter(\n\t\t(group) => group.paths.length > 0 || group.packages.size > 0,\n\t);\n}\n\nexport function formatScopeGroups(\n\tgroups: Array<{\n\t\tscope: \"user\" | \"project\" | \"path\";\n\t\tpaths: Array<{ path: string; sourceInfo?: SourceInfo }>;\n\t\tpackages: Map<string, Array<{ path: string; sourceInfo?: SourceInfo }>>;\n\t}>,\n\toptions: {\n\t\tformatPath: (item: { path: string; sourceInfo?: SourceInfo }) => string;\n\t\tformatPackagePath: (item: { path: string; sourceInfo?: SourceInfo }, source: string) => string;\n\t},\n): string {\n\tconst lines: string[] = [];\n\n\tfor (const group of groups) {\n\t\tlines.push(` ${theme.fg(\"accent\", group.scope)}`);\n\n\t\tconst sortedPaths = [...group.paths].sort((a, b) => a.path.localeCompare(b.path));\n\t\tfor (const item of sortedPaths) {\n\t\t\tlines.push(theme.fg(\"dim\", ` ${options.formatPath(item)}`));\n\t\t}\n\n\t\tconst sortedPackages = Array.from(group.packages.entries()).sort(([a], [b]) => a.localeCompare(b));\n\t\tfor (const [source, items] of sortedPackages) {\n\t\t\tlines.push(` ${theme.fg(\"mdLink\", source)}`);\n\t\t\tconst sortedPackagePaths = [...items].sort((a, b) => a.path.localeCompare(b.path));\n\t\t\tfor (const item of sortedPackagePaths) {\n\t\t\t\tlines.push(theme.fg(\"dim\", ` ${options.formatPackagePath(item, source)}`));\n\t\t\t}\n\t\t}\n\t}\n\n\treturn lines.join(\"\\n\");\n}\n\nexport function findSourceInfoForPath(p: string, sourceInfos: Map<string, SourceInfo>): SourceInfo | undefined {\n\tconst exact = sourceInfos.get(p);\n\tif (exact) return exact;\n\n\tlet current = p;\n\twhile (current.includes(\"/\")) {\n\t\tcurrent = current.substring(0, current.lastIndexOf(\"/\"));\n\t\tconst parent = sourceInfos.get(current);\n\t\tif (parent) return parent;\n\t}\n\n\treturn undefined;\n}\n\nexport function formatPathWithSource(p: string, sourceInfo?: SourceInfo): string {\n\tif (sourceInfo) {\n\t\tconst shortPath = getShortPath(p, sourceInfo);\n\t\tconst { label, scopeLabel } = getDisplaySourceInfo(sourceInfo);\n\t\tconst labelText = scopeLabel ? `${label} (${scopeLabel})` : label;\n\t\treturn `${labelText} ${shortPath}`;\n\t}\n\treturn formatDisplayPath(p);\n}\n\nexport function formatDiagnostics(\n\tdiagnostics: readonly ResourceDiagnostic[],\n\tsourceInfos: Map<string, SourceInfo>,\n): string {\n\tconst lines: string[] = [];\n\n\t// Group collision diagnostics by name\n\tconst collisions = new Map<string, ResourceDiagnostic[]>();\n\tconst otherDiagnostics: ResourceDiagnostic[] = [];\n\n\tfor (const d of diagnostics) {\n\t\tif (d.type === \"collision\" && d.collision) {\n\t\t\tconst list = collisions.get(d.collision.name) ?? [];\n\t\t\tlist.push(d);\n\t\t\tcollisions.set(d.collision.name, list);\n\t\t} else {\n\t\t\totherDiagnostics.push(d);\n\t\t}\n\t}\n\n\t// Format collision diagnostics grouped by name\n\tfor (const [name, collisionList] of collisions) {\n\t\tconst first = collisionList[0]?.collision;\n\t\tif (!first) continue;\n\t\tlines.push(theme.fg(\"warning\", ` \"${name}\" collision:`));\n\t\tlines.push(\n\t\t\ttheme.fg(\n\t\t\t\t\"dim\",\n\t\t\t\t` ${theme.fg(\"success\", \"✓\")} ${formatPathWithSource(first.winnerPath, findSourceInfoForPath(first.winnerPath, sourceInfos))}`,\n\t\t\t),\n\t\t);\n\t\tfor (const d of collisionList) {\n\t\t\tif (d.collision) {\n\t\t\t\tlines.push(\n\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\"dim\",\n\t\t\t\t\t\t` ${theme.fg(\"warning\", \"✗\")} ${formatPathWithSource(d.collision.loserPath, findSourceInfoForPath(d.collision.loserPath, sourceInfos))} (skipped)`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const d of otherDiagnostics) {\n\t\tif (d.path) {\n\t\t\tconst formattedPath = formatPathWithSource(d.path, findSourceInfoForPath(d.path, sourceInfos));\n\t\t\tlines.push(theme.fg(d.type === \"error\" ? \"error\" : \"warning\", ` ${formattedPath}`));\n\t\t\tlines.push(theme.fg(d.type === \"error\" ? \"error\" : \"warning\", ` ${d.message}`));\n\t\t} else {\n\t\t\tlines.push(theme.fg(d.type === \"error\" ? \"error\" : \"warning\", ` ${d.message}`));\n\t\t}\n\t}\n\n\treturn lines.join(\"\\n\");\n}\n"]}
@@ -10,7 +10,7 @@
10
10
  * install-resources test), so interactive-mode keeps thin delegating wrappers.
11
11
  */
12
12
  import type { SessionManager } from "@caupulican/pi-agent-core/node";
13
- import type { Component, Container, Loader, TUI } from "@caupulican/pi-tui";
13
+ import type { Component, Container, TUI } from "@caupulican/pi-tui";
14
14
  import type { AgentSession } from "../../core/agent-session.ts";
15
15
  import type { SettingsManager } from "../../core/settings-manager.ts";
16
16
  import { BashExecutionComponent } from "./components/bash-execution.ts";
@@ -46,10 +46,6 @@ export interface BashCommandHost {
46
46
  export interface CompactCommandHost {
47
47
  readonly sessionManager: Pick<SessionManager, "getEntries">;
48
48
  showWarning(message: string): void;
49
- loadingAnimation: Loader | undefined;
50
- readonly statusContainer: {
51
- clear: () => void;
52
- };
53
49
  readonly session: Pick<AgentSession, "compact">;
54
50
  }
55
51
  export declare function handleInstallResourcesCommand(host: InstallResourcesHost, argsString: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"resource-shell-commands.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/resource-shell-commands.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Resource-install and shell/compaction command bodies extracted from\n * interactive-mode.\n *\n * `/install-resources` copies a trusted external resource tree into the agent\n * dir; `/curate` proposes/applies skill-curation actions; `!`/`!!` bash runs a\n * shell command (rendering a BashExecutionComponent, deferred while streaming);\n * `/compact` triggers manual compaction. Each takes a narrow host seam;\n * `copyResourcesRecursively` stays host-side (referenced directly by the\n * install-resources test), so interactive-mode keeps thin delegating wrappers.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { SessionManager, TruncationResult } from \"@caupulican/pi-agent-core/node\";\nimport type { Component, Container, Loader, TUI } from \"@caupulican/pi-tui\";\nimport { getAgentDir } from \"../../config.ts\";\nimport type { AgentSession } from \"../../core/agent-session.ts\";\nimport type { SettingsManager } from \"../../core/settings-manager.ts\";\nimport { BashExecutionComponent } from \"./components/bash-execution.ts\";\nimport { SelectSubmenu } from \"./components/settings-selector.ts\";\n\nexport interface InstallResourcesHost {\n\treadonly settingsManager: Pick<\n\t\tSettingsManager,\n\t\t\"canonicalizePath\" | \"getTrustedResourceRoots\" | \"addTrustedResourceRoot\"\n\t>;\n\tshowError(message: string): void;\n\tshowStatus(message: string): void;\n\tshowSelector(\n\t\tcreate: (done: () => void) => {\n\t\t\tcomponent: Component;\n\t\t\tfocus: Component;\n\t\t\tonSuperseded?: () => void;\n\t\t},\n\t): void;\n\thandleReloadCommand(): Promise<void>;\n\tcopyResourcesRecursively(\n\t\tsrc: string,\n\t\tdest: string,\n\t\tforce: boolean,\n\t\tstats: { installed: string[]; skipped: string[] },\n\t): void;\n}\n\nexport interface CurateCommandHost {\n\treadonly session: Pick<AgentSession, \"archivePromotedSkill\" | \"restorePromotedSkill\" | \"proposeSkillCuration\">;\n\tshowStatus(message: string): void;\n}\n\nexport interface BashCommandHost {\n\treadonly session: Pick<AgentSession, \"extensionRunner\" | \"isStreaming\" | \"recordBashResult\" | \"executeBash\">;\n\treadonly sessionManager: Pick<SessionManager, \"getCwd\">;\n\treadonly ui: TUI;\n\treadonly chatContainer: Container;\n\treadonly pendingMessagesContainer: Container;\n\treadonly pendingBashComponents: BashExecutionComponent[];\n\tbashComponent: BashExecutionComponent | undefined;\n\tshowError(message: string): void;\n}\n\nexport interface CompactCommandHost {\n\treadonly sessionManager: Pick<SessionManager, \"getEntries\">;\n\tshowWarning(message: string): void;\n\tloadingAnimation: Loader | undefined;\n\treadonly statusContainer: { clear: () => void };\n\treadonly session: Pick<AgentSession, \"compact\">;\n}\n\nexport async function handleInstallResourcesCommand(host: InstallResourcesHost, argsString: string): Promise<void> {\n\ttry {\n\t\tconst tokens = argsString.split(/\\s+/).filter(Boolean);\n\t\tlet force = false;\n\t\tlet dir = \"\";\n\t\tfor (const t of tokens) {\n\t\t\tif (t === \"--force\") {\n\t\t\t\tforce = true;\n\t\t\t} else {\n\t\t\t\tdir = t;\n\t\t\t}\n\t\t}\n\n\t\tif (!dir) {\n\t\t\thost.showError(\"Usage: /install-resources <dir> [--force]\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst canonical = host.settingsManager.canonicalizePath(dir);\n\t\tif (!canonical || !fs.existsSync(canonical)) {\n\t\t\thost.showError(`Source directory does not exist: ${dir}`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst trustedRoots = host.settingsManager.getTrustedResourceRoots();\n\t\tconst trusted = trustedRoots.includes(canonical);\n\n\t\tif (!trusted) {\n\t\t\tconst trust = await new Promise<boolean>((resolve) => {\n\t\t\t\thost.showSelector((done) => {\n\t\t\t\t\tconst submenu = new SelectSubmenu(\n\t\t\t\t\t\t\"Trust external source for installation?\",\n\t\t\t\t\t\t`The directory \"${canonical}\" contains extensions/resources to install. Extensions can execute arbitrary code on your machine. Do you trust it?`,\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue: \"yes\",\n\t\t\t\t\t\t\t\tlabel: \"Yes\",\n\t\t\t\t\t\t\t\tdescription: \"Trust this directory and proceed with installation.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{ value: \"no\", label: \"No\", description: \"Do not trust this directory. Abort.\" },\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"no\",\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tdone();\n\t\t\t\t\t\t\tresolve(value === \"yes\");\n\t\t\t\t\t\t},\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\tdone();\n\t\t\t\t\t\t\tresolve(false);\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcomponent: submenu,\n\t\t\t\t\t\tfocus: submenu.getSelectList(),\n\t\t\t\t\t\tonSuperseded: () => resolve(false),\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tif (!trust) {\n\t\t\t\thost.showStatus(\"Installation aborted. Source directory was not trusted.\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\thost.settingsManager.addTrustedResourceRoot(canonical, \"global\");\n\t\t}\n\n\t\tconst subdirs = [\"skills\", \"extensions\", \"prompts\", \"themes\", \"profiles\", \"agents\"];\n\t\tconst stats = { installed: [] as string[], skipped: [] as string[] };\n\t\tconst userAgentDir = getAgentDir();\n\n\t\tfor (const sub of subdirs) {\n\t\t\tconst srcSub = path.join(canonical, sub);\n\t\t\tconst destSub = path.join(userAgentDir, sub);\n\t\t\tif (fs.existsSync(srcSub)) {\n\t\t\t\thost.copyResourcesRecursively(srcSub, destSub, force, stats);\n\t\t\t}\n\t\t}\n\n\t\tconst installedCount = stats.installed.length;\n\t\tconst skippedCount = stats.skipped.length;\n\t\thost.showStatus(`Installation complete: ${installedCount} resources installed, ${skippedCount} skipped.`);\n\n\t\tawait host.handleReloadCommand();\n\t} catch (error) {\n\t\thost.showError(error instanceof Error ? error.message : String(error));\n\t}\n}\n\n/**\n * `/curate` — skill curator (#32). With no args, lists reflection-promoted skills proposed for\n * archival (stale/unused) and pairs proposed for consolidation (overlapping). PROPOSE-ONLY: the user\n * applies actions explicitly via `/curate archive <name>` / `/curate restore <name>`. Never touches\n * hand-authored skills; archival is restorable.\n */\nexport function handleCurateCommand(host: CurateCommandHost, args: string): void {\n\tconst [sub, name] = args.split(/\\s+/, 2);\n\tif (sub === \"archive\" && name) {\n\t\thost.showStatus(\n\t\t\thost.session.archivePromotedSkill(name)\n\t\t\t\t? `Archived promoted skill '${name}'`\n\t\t\t\t: `Could not archive '${name}' (not a promoted skill?)`,\n\t\t);\n\t\treturn;\n\t}\n\tif (sub === \"restore\" && name) {\n\t\thost.showStatus(\n\t\t\thost.session.restorePromotedSkill(name) ? `Restored skill '${name}'` : `Could not restore '${name}'`,\n\t\t);\n\t\treturn;\n\t}\n\tconst proposals = host.session.proposeSkillCuration();\n\tif (proposals.archive.length === 0 && proposals.consolidate.length === 0) {\n\t\thost.showStatus(\"Curator: no stale or overlapping promoted skills. Nothing to propose.\");\n\t\treturn;\n\t}\n\tconst lines: string[] = [\"Skill curator proposals (nothing applied automatically):\"];\n\tfor (const a of proposals.archive) {\n\t\tlines.push(` • archive '${a.name}' — ${a.reason} → /curate archive ${a.name}`);\n\t}\n\tfor (const c of proposals.consolidate) {\n\t\tlines.push(` • consider merging '${c.names[0]}' + '${c.names[1]}' (overlap ${(c.overlap * 100) | 0}%)`);\n\t}\n\thost.showStatus(lines.join(\"\\n\"));\n}\n\nexport async function handleBashCommand(\n\thost: BashCommandHost,\n\tcommand: string,\n\texcludeFromContext = false,\n): Promise<void> {\n\tconst extensionRunner = host.session.extensionRunner;\n\n\t// Emit user_bash event to let extensions intercept\n\tconst eventResult = await extensionRunner.emitUserBash({\n\t\ttype: \"user_bash\",\n\t\tcommand,\n\t\texcludeFromContext,\n\t\tcwd: host.sessionManager.getCwd(),\n\t});\n\n\t// If extension returned a full result, use it directly\n\tif (eventResult?.result) {\n\t\tconst result = eventResult.result;\n\n\t\t// Create UI component for display\n\t\thost.bashComponent = new BashExecutionComponent(command, host.ui, excludeFromContext);\n\t\tif (host.session.isStreaming) {\n\t\t\thost.pendingMessagesContainer.addChild(host.bashComponent);\n\t\t\thost.pendingBashComponents.push(host.bashComponent);\n\t\t} else {\n\t\t\thost.chatContainer.addChild(host.bashComponent);\n\t\t}\n\n\t\t// Show output and complete\n\t\tif (result.output) {\n\t\t\thost.bashComponent.appendOutput(result.output);\n\t\t}\n\t\thost.bashComponent.setComplete(\n\t\t\tresult.exitCode,\n\t\t\tresult.cancelled,\n\t\t\tresult.truncated ? ({ truncated: true, content: result.output } as TruncationResult) : undefined,\n\t\t\tresult.fullOutputPath,\n\t\t);\n\n\t\t// Record the result in session\n\t\thost.session.recordBashResult(command, result, { excludeFromContext });\n\t\thost.bashComponent = undefined;\n\t\thost.ui.requestRender();\n\t\treturn;\n\t}\n\n\t// Normal execution path (possibly with custom operations)\n\tconst isDeferred = host.session.isStreaming;\n\thost.bashComponent = new BashExecutionComponent(command, host.ui, excludeFromContext);\n\n\tif (isDeferred) {\n\t\t// Show in pending area when agent is streaming\n\t\thost.pendingMessagesContainer.addChild(host.bashComponent);\n\t\thost.pendingBashComponents.push(host.bashComponent);\n\t} else {\n\t\t// Show in chat immediately when agent is idle\n\t\thost.chatContainer.addChild(host.bashComponent);\n\t}\n\thost.ui.requestRender();\n\n\ttry {\n\t\tconst result = await host.session.executeBash(\n\t\t\tcommand,\n\t\t\t(chunk) => {\n\t\t\t\tif (host.bashComponent) {\n\t\t\t\t\thost.bashComponent.appendOutput(chunk);\n\t\t\t\t\thost.ui.requestRender();\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ excludeFromContext, operations: eventResult?.operations },\n\t\t);\n\n\t\tif (host.bashComponent) {\n\t\t\thost.bashComponent.setComplete(\n\t\t\t\tresult.exitCode,\n\t\t\t\tresult.cancelled,\n\t\t\t\tresult.truncated ? ({ truncated: true, content: result.output } as TruncationResult) : undefined,\n\t\t\t\tresult.fullOutputPath,\n\t\t\t);\n\t\t}\n\t} catch (error) {\n\t\tif (host.bashComponent) {\n\t\t\thost.bashComponent.setComplete(undefined, false);\n\t\t}\n\t\thost.showError(`Bash command failed: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n\t}\n\n\thost.bashComponent = undefined;\n\thost.ui.requestRender();\n}\n\nexport async function handleCompactCommand(host: CompactCommandHost, customInstructions?: string): Promise<void> {\n\tconst entries = host.sessionManager.getEntries();\n\tconst messageCount = entries.filter((e) => e.type === \"message\").length;\n\n\tif (messageCount < 2) {\n\t\thost.showWarning(\"Nothing to compact (no messages yet)\");\n\t\treturn;\n\t}\n\n\tif (host.loadingAnimation) {\n\t\thost.loadingAnimation.stop();\n\t\thost.loadingAnimation = undefined;\n\t}\n\thost.statusContainer.clear();\n\n\ttry {\n\t\tawait host.session.compact(customInstructions);\n\t} catch {\n\t\t// Ignore, will be emitted as an event\n\t}\n}\n"]}
1
+ {"version":3,"file":"resource-shell-commands.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/resource-shell-commands.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Resource-install and shell/compaction command bodies extracted from\n * interactive-mode.\n *\n * `/install-resources` copies a trusted external resource tree into the agent\n * dir; `/curate` proposes/applies skill-curation actions; `!`/`!!` bash runs a\n * shell command (rendering a BashExecutionComponent, deferred while streaming);\n * `/compact` triggers manual compaction. Each takes a narrow host seam;\n * `copyResourcesRecursively` stays host-side (referenced directly by the\n * install-resources test), so interactive-mode keeps thin delegating wrappers.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { SessionManager, TruncationResult } from \"@caupulican/pi-agent-core/node\";\nimport type { Component, Container, TUI } from \"@caupulican/pi-tui\";\nimport { getAgentDir } from \"../../config.ts\";\nimport type { AgentSession } from \"../../core/agent-session.ts\";\nimport type { SettingsManager } from \"../../core/settings-manager.ts\";\nimport { BashExecutionComponent } from \"./components/bash-execution.ts\";\nimport { SelectSubmenu } from \"./components/settings-selector.ts\";\n\nexport interface InstallResourcesHost {\n\treadonly settingsManager: Pick<\n\t\tSettingsManager,\n\t\t\"canonicalizePath\" | \"getTrustedResourceRoots\" | \"addTrustedResourceRoot\"\n\t>;\n\tshowError(message: string): void;\n\tshowStatus(message: string): void;\n\tshowSelector(\n\t\tcreate: (done: () => void) => {\n\t\t\tcomponent: Component;\n\t\t\tfocus: Component;\n\t\t\tonSuperseded?: () => void;\n\t\t},\n\t): void;\n\thandleReloadCommand(): Promise<void>;\n\tcopyResourcesRecursively(\n\t\tsrc: string,\n\t\tdest: string,\n\t\tforce: boolean,\n\t\tstats: { installed: string[]; skipped: string[] },\n\t): void;\n}\n\nexport interface CurateCommandHost {\n\treadonly session: Pick<AgentSession, \"archivePromotedSkill\" | \"restorePromotedSkill\" | \"proposeSkillCuration\">;\n\tshowStatus(message: string): void;\n}\n\nexport interface BashCommandHost {\n\treadonly session: Pick<AgentSession, \"extensionRunner\" | \"isStreaming\" | \"recordBashResult\" | \"executeBash\">;\n\treadonly sessionManager: Pick<SessionManager, \"getCwd\">;\n\treadonly ui: TUI;\n\treadonly chatContainer: Container;\n\treadonly pendingMessagesContainer: Container;\n\treadonly pendingBashComponents: BashExecutionComponent[];\n\tbashComponent: BashExecutionComponent | undefined;\n\tshowError(message: string): void;\n}\n\nexport interface CompactCommandHost {\n\treadonly sessionManager: Pick<SessionManager, \"getEntries\">;\n\tshowWarning(message: string): void;\n\treadonly session: Pick<AgentSession, \"compact\">;\n}\n\nexport async function handleInstallResourcesCommand(host: InstallResourcesHost, argsString: string): Promise<void> {\n\ttry {\n\t\tconst tokens = argsString.split(/\\s+/).filter(Boolean);\n\t\tlet force = false;\n\t\tlet dir = \"\";\n\t\tfor (const t of tokens) {\n\t\t\tif (t === \"--force\") {\n\t\t\t\tforce = true;\n\t\t\t} else {\n\t\t\t\tdir = t;\n\t\t\t}\n\t\t}\n\n\t\tif (!dir) {\n\t\t\thost.showError(\"Usage: /install-resources <dir> [--force]\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst canonical = host.settingsManager.canonicalizePath(dir);\n\t\tif (!canonical || !fs.existsSync(canonical)) {\n\t\t\thost.showError(`Source directory does not exist: ${dir}`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst trustedRoots = host.settingsManager.getTrustedResourceRoots();\n\t\tconst trusted = trustedRoots.includes(canonical);\n\n\t\tif (!trusted) {\n\t\t\tconst trust = await new Promise<boolean>((resolve) => {\n\t\t\t\thost.showSelector((done) => {\n\t\t\t\t\tconst submenu = new SelectSubmenu(\n\t\t\t\t\t\t\"Trust external source for installation?\",\n\t\t\t\t\t\t`The directory \"${canonical}\" contains extensions/resources to install. Extensions can execute arbitrary code on your machine. Do you trust it?`,\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue: \"yes\",\n\t\t\t\t\t\t\t\tlabel: \"Yes\",\n\t\t\t\t\t\t\t\tdescription: \"Trust this directory and proceed with installation.\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{ value: \"no\", label: \"No\", description: \"Do not trust this directory. Abort.\" },\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"no\",\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tdone();\n\t\t\t\t\t\t\tresolve(value === \"yes\");\n\t\t\t\t\t\t},\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\tdone();\n\t\t\t\t\t\t\tresolve(false);\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcomponent: submenu,\n\t\t\t\t\t\tfocus: submenu.getSelectList(),\n\t\t\t\t\t\tonSuperseded: () => resolve(false),\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tif (!trust) {\n\t\t\t\thost.showStatus(\"Installation aborted. Source directory was not trusted.\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\thost.settingsManager.addTrustedResourceRoot(canonical, \"global\");\n\t\t}\n\n\t\tconst subdirs = [\"skills\", \"extensions\", \"prompts\", \"themes\", \"profiles\", \"agents\"];\n\t\tconst stats = { installed: [] as string[], skipped: [] as string[] };\n\t\tconst userAgentDir = getAgentDir();\n\n\t\tfor (const sub of subdirs) {\n\t\t\tconst srcSub = path.join(canonical, sub);\n\t\t\tconst destSub = path.join(userAgentDir, sub);\n\t\t\tif (fs.existsSync(srcSub)) {\n\t\t\t\thost.copyResourcesRecursively(srcSub, destSub, force, stats);\n\t\t\t}\n\t\t}\n\n\t\tconst installedCount = stats.installed.length;\n\t\tconst skippedCount = stats.skipped.length;\n\t\thost.showStatus(`Installation complete: ${installedCount} resources installed, ${skippedCount} skipped.`);\n\n\t\tawait host.handleReloadCommand();\n\t} catch (error) {\n\t\thost.showError(error instanceof Error ? error.message : String(error));\n\t}\n}\n\n/**\n * `/curate` — skill curator (#32). With no args, lists reflection-promoted skills proposed for\n * archival (stale/unused) and pairs proposed for consolidation (overlapping). PROPOSE-ONLY: the user\n * applies actions explicitly via `/curate archive <name>` / `/curate restore <name>`. Never touches\n * hand-authored skills; archival is restorable.\n */\nexport function handleCurateCommand(host: CurateCommandHost, args: string): void {\n\tconst [sub, name] = args.split(/\\s+/, 2);\n\tif (sub === \"archive\" && name) {\n\t\thost.showStatus(\n\t\t\thost.session.archivePromotedSkill(name)\n\t\t\t\t? `Archived promoted skill '${name}'`\n\t\t\t\t: `Could not archive '${name}' (not a promoted skill?)`,\n\t\t);\n\t\treturn;\n\t}\n\tif (sub === \"restore\" && name) {\n\t\thost.showStatus(\n\t\t\thost.session.restorePromotedSkill(name) ? `Restored skill '${name}'` : `Could not restore '${name}'`,\n\t\t);\n\t\treturn;\n\t}\n\tconst proposals = host.session.proposeSkillCuration();\n\tif (proposals.archive.length === 0 && proposals.consolidate.length === 0) {\n\t\thost.showStatus(\"Curator: no stale or overlapping promoted skills. Nothing to propose.\");\n\t\treturn;\n\t}\n\tconst lines: string[] = [\"Skill curator proposals (nothing applied automatically):\"];\n\tfor (const a of proposals.archive) {\n\t\tlines.push(` • archive '${a.name}' — ${a.reason} → /curate archive ${a.name}`);\n\t}\n\tfor (const c of proposals.consolidate) {\n\t\tlines.push(` • consider merging '${c.names[0]}' + '${c.names[1]}' (overlap ${(c.overlap * 100) | 0}%)`);\n\t}\n\thost.showStatus(lines.join(\"\\n\"));\n}\n\nexport async function handleBashCommand(\n\thost: BashCommandHost,\n\tcommand: string,\n\texcludeFromContext = false,\n): Promise<void> {\n\tconst extensionRunner = host.session.extensionRunner;\n\n\t// Emit user_bash event to let extensions intercept\n\tconst eventResult = await extensionRunner.emitUserBash({\n\t\ttype: \"user_bash\",\n\t\tcommand,\n\t\texcludeFromContext,\n\t\tcwd: host.sessionManager.getCwd(),\n\t});\n\n\t// If extension returned a full result, use it directly\n\tif (eventResult?.result) {\n\t\tconst result = eventResult.result;\n\n\t\t// Create UI component for display\n\t\thost.bashComponent = new BashExecutionComponent(command, host.ui, excludeFromContext);\n\t\tif (host.session.isStreaming) {\n\t\t\thost.pendingMessagesContainer.addChild(host.bashComponent);\n\t\t\thost.pendingBashComponents.push(host.bashComponent);\n\t\t} else {\n\t\t\thost.chatContainer.addChild(host.bashComponent);\n\t\t}\n\n\t\t// Show output and complete\n\t\tif (result.output) {\n\t\t\thost.bashComponent.appendOutput(result.output);\n\t\t}\n\t\thost.bashComponent.setComplete(\n\t\t\tresult.exitCode,\n\t\t\tresult.cancelled,\n\t\t\tresult.truncated ? ({ truncated: true, content: result.output } as TruncationResult) : undefined,\n\t\t\tresult.fullOutputPath,\n\t\t);\n\n\t\t// Record the result in session\n\t\thost.session.recordBashResult(command, result, { excludeFromContext });\n\t\thost.bashComponent = undefined;\n\t\thost.ui.requestRender();\n\t\treturn;\n\t}\n\n\t// Normal execution path (possibly with custom operations)\n\tconst isDeferred = host.session.isStreaming;\n\thost.bashComponent = new BashExecutionComponent(command, host.ui, excludeFromContext);\n\n\tif (isDeferred) {\n\t\t// Show in pending area when agent is streaming\n\t\thost.pendingMessagesContainer.addChild(host.bashComponent);\n\t\thost.pendingBashComponents.push(host.bashComponent);\n\t} else {\n\t\t// Show in chat immediately when agent is idle\n\t\thost.chatContainer.addChild(host.bashComponent);\n\t}\n\thost.ui.requestRender();\n\n\ttry {\n\t\tconst result = await host.session.executeBash(\n\t\t\tcommand,\n\t\t\t(chunk) => {\n\t\t\t\tif (host.bashComponent) {\n\t\t\t\t\thost.bashComponent.appendOutput(chunk);\n\t\t\t\t\thost.ui.requestRender();\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ excludeFromContext, operations: eventResult?.operations },\n\t\t);\n\n\t\tif (host.bashComponent) {\n\t\t\thost.bashComponent.setComplete(\n\t\t\t\tresult.exitCode,\n\t\t\t\tresult.cancelled,\n\t\t\t\tresult.truncated ? ({ truncated: true, content: result.output } as TruncationResult) : undefined,\n\t\t\t\tresult.fullOutputPath,\n\t\t\t);\n\t\t}\n\t} catch (error) {\n\t\tif (host.bashComponent) {\n\t\t\thost.bashComponent.setComplete(undefined, false);\n\t\t}\n\t\thost.showError(`Bash command failed: ${error instanceof Error ? error.message : \"Unknown error\"}`);\n\t}\n\n\thost.bashComponent = undefined;\n\thost.ui.requestRender();\n}\n\nexport async function handleCompactCommand(host: CompactCommandHost, customInstructions?: string): Promise<void> {\n\tconst entries = host.sessionManager.getEntries();\n\tconst messageCount = entries.filter((e) => e.type === \"message\").length;\n\n\tif (messageCount < 2) {\n\t\thost.showWarning(\"Nothing to compact (no messages yet)\");\n\t\treturn;\n\t}\n\n\ttry {\n\t\tawait host.session.compact(customInstructions);\n\t} catch {\n\t\t// Ignore, will be emitted as an event\n\t}\n}\n"]}
@@ -191,11 +191,6 @@ export async function handleCompactCommand(host, customInstructions) {
191
191
  host.showWarning("Nothing to compact (no messages yet)");
192
192
  return;
193
193
  }
194
- if (host.loadingAnimation) {
195
- host.loadingAnimation.stop();
196
- host.loadingAnimation = undefined;
197
- }
198
- host.statusContainer.clear();
199
194
  try {
200
195
  await host.session.compact(customInstructions);
201
196
  }