@kolisachint/hoocode-agent 0.4.105 → 0.4.107

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 (289) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cli/args.d.ts.map +1 -1
  3. package/dist/cli/args.js +4 -4
  4. package/dist/cli/args.js.map +1 -1
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +0 -1
  7. package/dist/cli.js.map +1 -1
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +2 -2
  10. package/dist/config.js.map +1 -1
  11. package/dist/core/agent-session.d.ts +1 -3
  12. package/dist/core/agent-session.d.ts.map +1 -1
  13. package/dist/core/agent-session.js +2 -2
  14. package/dist/core/agent-session.js.map +1 -1
  15. package/dist/core/bash-executor.d.ts.map +1 -1
  16. package/dist/core/bash-executor.js +1 -1
  17. package/dist/core/bash-executor.js.map +1 -1
  18. package/dist/core/extension-mcp-servers.d.ts +1 -1
  19. package/dist/core/extension-mcp-servers.d.ts.map +1 -1
  20. package/dist/core/extension-mcp-servers.js +1 -1
  21. package/dist/core/extension-mcp-servers.js.map +1 -1
  22. package/dist/core/extensions/plugins/index.d.ts.map +1 -1
  23. package/dist/core/extensions/plugins/index.js +1 -1
  24. package/dist/core/extensions/plugins/index.js.map +1 -1
  25. package/dist/core/extensions/types.d.ts +1 -3
  26. package/dist/core/extensions/types.d.ts.map +1 -1
  27. package/dist/core/extensions/types.js.map +1 -1
  28. package/dist/core/index.d.ts +1 -1
  29. package/dist/core/index.d.ts.map +1 -1
  30. package/dist/core/index.js.map +1 -1
  31. package/dist/core/mode-prompts.d.ts +1 -1
  32. package/dist/core/mode-prompts.d.ts.map +1 -1
  33. package/dist/core/mode-prompts.js +1 -1
  34. package/dist/core/mode-prompts.js.map +1 -1
  35. package/dist/core/package-manager.d.ts.map +1 -1
  36. package/dist/core/package-manager.js +1 -1
  37. package/dist/core/package-manager.js.map +1 -1
  38. package/dist/core/sdk.d.ts.map +1 -1
  39. package/dist/core/sdk.js +1 -2
  40. package/dist/core/sdk.js.map +1 -1
  41. package/dist/core/session-manager.d.ts +2 -97
  42. package/dist/core/session-manager.d.ts.map +1 -1
  43. package/dist/core/session-manager.js +4 -65
  44. package/dist/core/session-manager.js.map +1 -1
  45. package/dist/core/settings-manager.d.ts.map +1 -1
  46. package/dist/core/settings-manager.js +2 -3
  47. package/dist/core/settings-manager.js.map +1 -1
  48. package/dist/core/telemetry.d.ts.map +1 -1
  49. package/dist/core/telemetry.js +1 -1
  50. package/dist/core/telemetry.js.map +1 -1
  51. package/dist/core/timings.d.ts +1 -1
  52. package/dist/core/timings.d.ts.map +1 -1
  53. package/dist/core/timings.js +2 -2
  54. package/dist/core/timings.js.map +1 -1
  55. package/dist/core/tools/{browser-continue.d.ts → browser/browser-continue.d.ts} +1 -1
  56. package/dist/core/tools/browser/browser-continue.d.ts.map +1 -0
  57. package/dist/core/tools/{browser-continue.js → browser/browser-continue.js} +2 -2
  58. package/dist/core/tools/browser/browser-continue.js.map +1 -0
  59. package/dist/core/tools/{browser-run.d.ts → browser/browser-run.d.ts} +2 -2
  60. package/dist/core/tools/browser/browser-run.d.ts.map +1 -0
  61. package/dist/core/tools/{browser-run.js → browser/browser-run.js} +2 -2
  62. package/dist/core/tools/browser/browser-run.js.map +1 -0
  63. package/dist/core/tools/browser/browsertools-shared.d.ts.map +1 -0
  64. package/dist/core/tools/{browsertools-shared.js → browser/browsertools-shared.js} +1 -1
  65. package/dist/core/tools/browser/browsertools-shared.js.map +1 -0
  66. package/dist/core/tools/browser/index.d.ts +8 -0
  67. package/dist/core/tools/browser/index.d.ts.map +1 -0
  68. package/dist/core/tools/browser/index.js +8 -0
  69. package/dist/core/tools/browser/index.js.map +1 -0
  70. package/dist/core/tools/{docedit.d.ts → doc/docedit.d.ts} +2 -2
  71. package/dist/core/tools/doc/docedit.d.ts.map +1 -0
  72. package/dist/core/tools/{docedit.js → doc/docedit.js} +7 -7
  73. package/dist/core/tools/doc/docedit.js.map +1 -0
  74. package/dist/core/tools/{docgrep.d.ts → doc/docgrep.d.ts} +2 -2
  75. package/dist/core/tools/doc/docgrep.d.ts.map +1 -0
  76. package/dist/core/tools/{docgrep.js → doc/docgrep.js} +6 -6
  77. package/dist/core/tools/doc/docgrep.js.map +1 -0
  78. package/dist/core/tools/{docpeek.d.ts → doc/docpeek.d.ts} +2 -2
  79. package/dist/core/tools/{docpeek.js.map → doc/docpeek.d.ts.map} +1 -1
  80. package/dist/core/tools/{docpeek.js → doc/docpeek.js} +6 -6
  81. package/dist/core/tools/doc/docpeek.js.map +1 -0
  82. package/dist/core/tools/{docread.d.ts → doc/docread.d.ts} +2 -2
  83. package/dist/core/tools/doc/docread.d.ts.map +1 -0
  84. package/dist/core/tools/{docread.js → doc/docread.js} +6 -6
  85. package/dist/core/tools/doc/docread.js.map +1 -0
  86. package/dist/core/tools/{docscan.d.ts → doc/docscan.d.ts} +2 -2
  87. package/dist/core/tools/doc/docscan.d.ts.map +1 -0
  88. package/dist/core/tools/{docscan.js → doc/docscan.js} +6 -6
  89. package/dist/core/tools/doc/docscan.js.map +1 -0
  90. package/dist/core/tools/{docwrite.d.ts → doc/docwrite.d.ts} +1 -1
  91. package/dist/core/tools/doc/docwrite.d.ts.map +1 -0
  92. package/dist/core/tools/{docwrite.js → doc/docwrite.js} +6 -6
  93. package/dist/core/tools/doc/docwrite.js.map +1 -0
  94. package/dist/core/tools/doc/index.d.ts +11 -0
  95. package/dist/core/tools/doc/index.d.ts.map +1 -0
  96. package/dist/core/tools/doc/index.js +11 -0
  97. package/dist/core/tools/doc/index.js.map +1 -0
  98. package/dist/core/tools/grep.d.ts.map +1 -1
  99. package/dist/core/tools/grep.js +1 -1
  100. package/dist/core/tools/grep.js.map +1 -1
  101. package/dist/core/tools/index.d.ts +42 -28
  102. package/dist/core/tools/index.d.ts.map +1 -1
  103. package/dist/core/tools/index.js +61 -199
  104. package/dist/core/tools/index.js.map +1 -1
  105. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  106. package/dist/core/tools/output-accumulator.js +1 -1
  107. package/dist/core/tools/output-accumulator.js.map +1 -1
  108. package/dist/core/tools/read.d.ts.map +1 -1
  109. package/dist/core/tools/read.js +1 -1
  110. package/dist/core/tools/read.js.map +1 -1
  111. package/dist/extensions/core/ask-options.d.ts +10 -0
  112. package/dist/extensions/core/ask-options.d.ts.map +1 -0
  113. package/dist/extensions/core/ask-options.js +83 -0
  114. package/dist/extensions/core/ask-options.js.map +1 -0
  115. package/dist/extensions/core/config.d.ts +80 -0
  116. package/dist/extensions/core/config.d.ts.map +1 -0
  117. package/dist/extensions/core/config.js +110 -0
  118. package/dist/extensions/core/config.js.map +1 -0
  119. package/dist/extensions/core/cost.d.ts +11 -0
  120. package/dist/extensions/core/cost.d.ts.map +1 -0
  121. package/dist/extensions/core/cost.js +64 -0
  122. package/dist/extensions/core/cost.js.map +1 -0
  123. package/dist/extensions/core/hoo-core.d.ts +16 -179
  124. package/dist/extensions/core/hoo-core.d.ts.map +1 -1
  125. package/dist/extensions/core/hoo-core.js +27 -1663
  126. package/dist/extensions/core/hoo-core.js.map +1 -1
  127. package/dist/extensions/core/loop.d.ts +15 -0
  128. package/dist/extensions/core/loop.d.ts.map +1 -0
  129. package/dist/extensions/core/loop.js +235 -0
  130. package/dist/extensions/core/loop.js.map +1 -0
  131. package/dist/extensions/core/marketplace.d.ts +17 -0
  132. package/dist/extensions/core/marketplace.d.ts.map +1 -0
  133. package/dist/extensions/core/marketplace.js +167 -0
  134. package/dist/extensions/core/marketplace.js.map +1 -0
  135. package/dist/extensions/core/mcp-loader.d.ts +26 -0
  136. package/dist/extensions/core/mcp-loader.d.ts.map +1 -0
  137. package/dist/extensions/core/mcp-loader.js +391 -0
  138. package/dist/extensions/core/mcp-loader.js.map +1 -0
  139. package/dist/extensions/core/modes.d.ts +56 -0
  140. package/dist/extensions/core/modes.d.ts.map +1 -0
  141. package/dist/extensions/core/modes.js +268 -0
  142. package/dist/extensions/core/modes.js.map +1 -0
  143. package/dist/extensions/core/permission-gate.d.ts +10 -0
  144. package/dist/extensions/core/permission-gate.d.ts.map +1 -0
  145. package/dist/extensions/core/permission-gate.js +167 -0
  146. package/dist/extensions/core/permission-gate.js.map +1 -0
  147. package/dist/extensions/core/scaffold.d.ts +9 -0
  148. package/dist/extensions/core/scaffold.d.ts.map +1 -0
  149. package/dist/extensions/core/scaffold.js +146 -0
  150. package/dist/extensions/core/scaffold.js.map +1 -0
  151. package/dist/extensions/core/thinking-escalation.d.ts +18 -0
  152. package/dist/extensions/core/thinking-escalation.d.ts.map +1 -0
  153. package/dist/extensions/core/thinking-escalation.js +70 -0
  154. package/dist/extensions/core/thinking-escalation.js.map +1 -0
  155. package/dist/index.d.ts +2 -3
  156. package/dist/index.d.ts.map +1 -1
  157. package/dist/index.js +3 -4
  158. package/dist/index.js.map +1 -1
  159. package/dist/main.d.ts.map +1 -1
  160. package/dist/main.js +2 -2
  161. package/dist/main.js.map +1 -1
  162. package/dist/modes/interactive/command-executor.d.ts +0 -5
  163. package/dist/modes/interactive/command-executor.d.ts.map +1 -1
  164. package/dist/modes/interactive/command-executor.js +0 -7
  165. package/dist/modes/interactive/command-executor.js.map +1 -1
  166. package/dist/modes/interactive/components/branch-summary-message.d.ts +1 -1
  167. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  168. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  169. package/dist/modes/interactive/components/compaction-summary-message.d.ts +1 -1
  170. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  171. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  172. package/dist/modes/interactive/components/custom-message.d.ts +1 -1
  173. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  174. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  175. package/dist/modes/interactive/components/index.d.ts +0 -2
  176. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  177. package/dist/modes/interactive/components/index.js +0 -2
  178. package/dist/modes/interactive/components/index.js.map +1 -1
  179. package/dist/modes/interactive/extension-chrome.d.ts +56 -0
  180. package/dist/modes/interactive/extension-chrome.d.ts.map +1 -0
  181. package/dist/modes/interactive/extension-chrome.js +172 -0
  182. package/dist/modes/interactive/extension-chrome.js.map +1 -0
  183. package/dist/modes/interactive/extension-dialogs.d.ts +82 -0
  184. package/dist/modes/interactive/extension-dialogs.d.ts.map +1 -0
  185. package/dist/modes/interactive/extension-dialogs.js +259 -0
  186. package/dist/modes/interactive/extension-dialogs.js.map +1 -0
  187. package/dist/modes/interactive/interactive-mode.d.ts +11 -161
  188. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  189. package/dist/modes/interactive/interactive-mode.js +263 -1571
  190. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  191. package/dist/modes/interactive/resource-display.d.ts +59 -0
  192. package/dist/modes/interactive/resource-display.d.ts.map +1 -0
  193. package/dist/modes/interactive/resource-display.js +499 -0
  194. package/dist/modes/interactive/resource-display.js.map +1 -0
  195. package/dist/modes/interactive/startup-checks.d.ts +17 -0
  196. package/dist/modes/interactive/startup-checks.d.ts.map +1 -0
  197. package/dist/modes/interactive/startup-checks.js +102 -0
  198. package/dist/modes/interactive/startup-checks.js.map +1 -0
  199. package/dist/modes/interactive/team-focus.d.ts +56 -0
  200. package/dist/modes/interactive/team-focus.d.ts.map +1 -0
  201. package/dist/modes/interactive/team-focus.js +167 -0
  202. package/dist/modes/interactive/team-focus.js.map +1 -0
  203. package/dist/modes/interactive/voice/voice-controller.d.ts +66 -0
  204. package/dist/modes/interactive/voice/voice-controller.d.ts.map +1 -0
  205. package/dist/modes/interactive/voice/voice-controller.js +312 -0
  206. package/dist/modes/interactive/voice/voice-controller.js.map +1 -0
  207. package/dist/modes/interactive/voice/voice-panel.d.ts.map +1 -0
  208. package/dist/modes/interactive/voice/voice-panel.js.map +1 -0
  209. package/dist/modes/interactive/{voice-transcribe.d.ts → voice/voice-transcribe.d.ts} +16 -1
  210. package/dist/modes/interactive/voice/voice-transcribe.d.ts.map +1 -0
  211. package/dist/modes/interactive/{voice-transcribe.js → voice/voice-transcribe.js} +31 -4
  212. package/dist/modes/interactive/voice/voice-transcribe.js.map +1 -0
  213. package/dist/modes/rpc/rpc-client.d.ts +1 -2
  214. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  215. package/dist/modes/rpc/rpc-client.js.map +1 -1
  216. package/dist/modes/rpc/rpc-types.d.ts +1 -2
  217. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  218. package/dist/modes/rpc/rpc-types.js.map +1 -1
  219. package/dist/resources-cli.d.ts.map +1 -1
  220. package/dist/resources-cli.js +1 -1
  221. package/dist/resources-cli.js.map +1 -1
  222. package/dist/utils/tools-manager.d.ts.map +1 -1
  223. package/dist/utils/tools-manager.js +1 -1
  224. package/dist/utils/tools-manager.js.map +1 -1
  225. package/dist/utils/version-check.d.ts.map +1 -1
  226. package/dist/utils/version-check.js +2 -2
  227. package/dist/utils/version-check.js.map +1 -1
  228. package/docs/project-local-resources.md +1 -1
  229. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  230. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  231. package/examples/extensions/sandbox/package.json +1 -1
  232. package/examples/extensions/with-deps/package.json +1 -1
  233. package/package.json +4 -4
  234. package/dist/core/compaction/branch-summarization.d.ts +0 -88
  235. package/dist/core/compaction/branch-summarization.d.ts.map +0 -1
  236. package/dist/core/compaction/branch-summarization.js +0 -243
  237. package/dist/core/compaction/branch-summarization.js.map +0 -1
  238. package/dist/core/compaction/compaction.d.ts +0 -123
  239. package/dist/core/compaction/compaction.d.ts.map +0 -1
  240. package/dist/core/compaction/compaction.js +0 -635
  241. package/dist/core/compaction/compaction.js.map +0 -1
  242. package/dist/core/compaction/index.d.ts +0 -7
  243. package/dist/core/compaction/index.d.ts.map +0 -1
  244. package/dist/core/compaction/index.js +0 -7
  245. package/dist/core/compaction/index.js.map +0 -1
  246. package/dist/core/compaction/utils.d.ts +0 -38
  247. package/dist/core/compaction/utils.d.ts.map +0 -1
  248. package/dist/core/compaction/utils.js +0 -156
  249. package/dist/core/compaction/utils.js.map +0 -1
  250. package/dist/core/messages.d.ts +0 -124
  251. package/dist/core/messages.d.ts.map +0 -1
  252. package/dist/core/messages.js +0 -221
  253. package/dist/core/messages.js.map +0 -1
  254. package/dist/core/tools/browser-continue.d.ts.map +0 -1
  255. package/dist/core/tools/browser-continue.js.map +0 -1
  256. package/dist/core/tools/browser-run.d.ts.map +0 -1
  257. package/dist/core/tools/browser-run.js.map +0 -1
  258. package/dist/core/tools/browsertools-shared.d.ts.map +0 -1
  259. package/dist/core/tools/browsertools-shared.js.map +0 -1
  260. package/dist/core/tools/docedit.d.ts.map +0 -1
  261. package/dist/core/tools/docedit.js.map +0 -1
  262. package/dist/core/tools/docgrep.d.ts.map +0 -1
  263. package/dist/core/tools/docgrep.js.map +0 -1
  264. package/dist/core/tools/docpeek.d.ts.map +0 -1
  265. package/dist/core/tools/docread.d.ts.map +0 -1
  266. package/dist/core/tools/docread.js.map +0 -1
  267. package/dist/core/tools/docscan.d.ts.map +0 -1
  268. package/dist/core/tools/docscan.js.map +0 -1
  269. package/dist/core/tools/docwrite.d.ts.map +0 -1
  270. package/dist/core/tools/docwrite.js.map +0 -1
  271. package/dist/core/tools/output-compression.d.ts +0 -53
  272. package/dist/core/tools/output-compression.d.ts.map +0 -1
  273. package/dist/core/tools/output-compression.js +0 -392
  274. package/dist/core/tools/output-compression.js.map +0 -1
  275. package/dist/modes/interactive/components/armin.d.ts +0 -34
  276. package/dist/modes/interactive/components/armin.d.ts.map +0 -1
  277. package/dist/modes/interactive/components/armin.js +0 -333
  278. package/dist/modes/interactive/components/armin.js.map +0 -1
  279. package/dist/modes/interactive/components/daxnuts.d.ts +0 -23
  280. package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
  281. package/dist/modes/interactive/components/daxnuts.js +0 -140
  282. package/dist/modes/interactive/components/daxnuts.js.map +0 -1
  283. package/dist/modes/interactive/components/voice-panel.d.ts.map +0 -1
  284. package/dist/modes/interactive/components/voice-panel.js.map +0 -1
  285. package/dist/modes/interactive/voice-transcribe.d.ts.map +0 -1
  286. package/dist/modes/interactive/voice-transcribe.js.map +0 -1
  287. /package/dist/core/tools/{browsertools-shared.d.ts → browser/browsertools-shared.d.ts} +0 -0
  288. /package/dist/modes/interactive/{components → voice}/voice-panel.d.ts +0 -0
  289. /package/dist/modes/interactive/{components → voice}/voice-panel.js +0 -0
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Startup/reload resource listing: path and source-label formatting, scope
3
+ * grouping, diagnostics rendering, and the [Resources]/[Skills]/… sections
4
+ * shown in the chat. Extracted from interactive-mode.ts; everything here is
5
+ * either pure formatting or rendering into a container passed via deps.
6
+ */
7
+ import { type Container, Text } from "@kolisachint/hoocode-tui";
8
+ import type { ExtensionRunner } from "../../core/extensions/index.js";
9
+ import type { PromptTemplate } from "../../core/prompt-templates.js";
10
+ import type { ResourceDiagnostic, ResourceLoader } from "../../core/resource-loader.js";
11
+ import type { SourceInfo } from "../../core/source-info.js";
12
+ export interface Expandable {
13
+ setExpanded(expanded: boolean): void;
14
+ }
15
+ export declare function isExpandable(obj: unknown): obj is Expandable;
16
+ export declare class ExpandableText extends Text implements Expandable {
17
+ private collapsed;
18
+ private expanded;
19
+ constructor(collapsed: () => string, expanded: () => string, initiallyExpanded: boolean, paddingX: number, paddingY: number);
20
+ setExpanded(expanded: boolean): void;
21
+ }
22
+ export declare function formatDisplayPath(p: string): string;
23
+ export declare function formatExtensionDisplayPath(extensionPath: string): string;
24
+ export declare function formatContextPath(p: string, cwd: string): string;
25
+ /**
26
+ * Get a short path relative to the package root for display.
27
+ */
28
+ export declare function getShortPath(fullPath: string, sourceInfo?: SourceInfo): string;
29
+ export declare function getCompactPathLabel(resourcePath: string, sourceInfo?: SourceInfo): string;
30
+ export declare function getCompactExtensionLabels(extensions: Array<{
31
+ path: string;
32
+ sourceInfo?: SourceInfo;
33
+ displayName?: string;
34
+ }>): string[];
35
+ export declare function formatDiagnostics(diagnostics: readonly ResourceDiagnostic[], sourceInfos: Map<string, SourceInfo>): string;
36
+ /** The slice of the interactive mode the resource listing renders into. */
37
+ export interface ResourceDisplayDeps {
38
+ chatContainer: Container;
39
+ getCwd(): string;
40
+ getResourceLoader(): ResourceLoader;
41
+ getPromptTemplates(): ReadonlyArray<PromptTemplate>;
42
+ getExtensionRunner(): ExtensionRunner;
43
+ getActiveMode(): string;
44
+ getSubagentEnabled(): boolean;
45
+ quietStartup(): boolean;
46
+ verbose: boolean;
47
+ /** Startup expansion state for the collapsible sections. */
48
+ isExpanded(): boolean;
49
+ getBuiltInCommandConflictDiagnostics(extensionRunner: ExtensionRunner): ResourceDiagnostic[];
50
+ }
51
+ export declare function showLoadedResources(deps: ResourceDisplayDeps, options?: {
52
+ extensions?: Array<{
53
+ path: string;
54
+ sourceInfo?: SourceInfo;
55
+ }>;
56
+ force?: boolean;
57
+ showDiagnosticsWhenQuiet?: boolean;
58
+ }): void;
59
+ //# sourceMappingURL=resource-display.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-display.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/resource-display.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,KAAK,SAAS,EAAU,IAAI,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACxF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAS5D,MAAM,WAAW,UAAU;IAC1B,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;CACrC;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,UAAU,CAE5D;AAED,qBAAa,cAAe,SAAQ,IAAK,YAAW,UAAU;IAE5D,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,QAAQ;IAFjB,YACS,SAAS,EAAE,MAAM,MAAM,EACvB,QAAQ,EAAE,MAAM,MAAM,EAC9B,iBAAiB,EAAE,OAAO,EAC1B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAGhB;IAED,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAEnC;CACD;AAMD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAUnD;AAED,wBAAgB,0BAA0B,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAIxE;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAShE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,MAAM,CA2B9E;AAED,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,MAAM,CAQzF;AAuED,wBAAgB,yBAAyB,CACxC,UAAU,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAChF,MAAM,EAAE,CAgCV;AA6ID,wBAAgB,iBAAiB,CAChC,WAAW,EAAE,SAAS,kBAAkB,EAAE,EAC1C,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,GAClC,MAAM,CAmDR;AAMD,2EAA2E;AAC3E,MAAM,WAAW,mBAAmB;IACnC,aAAa,EAAE,SAAS,CAAC;IACzB,MAAM,IAAI,MAAM,CAAC;IACjB,iBAAiB,IAAI,cAAc,CAAC;IACpC,kBAAkB,IAAI,aAAa,CAAC,cAAc,CAAC,CAAC;IACpD,kBAAkB,IAAI,eAAe,CAAC;IACtC,aAAa,IAAI,MAAM,CAAC;IACxB,kBAAkB,IAAI,OAAO,CAAC;IAC9B,YAAY,IAAI,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,4DAA4D;IAC5D,UAAU,IAAI,OAAO,CAAC;IACtB,oCAAoC,CAAC,eAAe,EAAE,eAAe,GAAG,kBAAkB,EAAE,CAAC;CAC7F;AAED,wBAAgB,mBAAmB,CAClC,IAAI,EAAE,mBAAmB,EACzB,OAAO,CAAC,EAAE;IACT,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,GACC,IAAI,CAuPN","sourcesContent":["/**\n * Startup/reload resource listing: path and source-label formatting, scope\n * grouping, diagnostics rendering, and the [Resources]/[Skills]/… sections\n * shown in the chat. Extracted from interactive-mode.ts; everything here is\n * either pure formatting or rendering into a container passed via deps.\n */\n\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { type Container, Spacer, Text } from \"@kolisachint/hoocode-tui\";\nimport type { ExtensionRunner } from \"../../core/extensions/index.js\";\nimport type { PromptTemplate } from \"../../core/prompt-templates.js\";\nimport type { ResourceDiagnostic, ResourceLoader } from \"../../core/resource-loader.js\";\nimport type { SourceInfo } from \"../../core/source-info.js\";\nimport { parseGitUrl } from \"../../utils/git.js\";\nimport { getCwdRelativePath } from \"../../utils/paths.js\";\nimport { type ThemeColor, theme } from \"./theme/theme.js\";\n\n// ============================================================================\n// Expandable sections\n// ============================================================================\n\nexport interface Expandable {\n\tsetExpanded(expanded: boolean): void;\n}\n\nexport function isExpandable(obj: unknown): obj is Expandable {\n\treturn typeof obj === \"object\" && obj !== null && \"setExpanded\" in obj;\n}\n\nexport class ExpandableText extends Text implements Expandable {\n\tconstructor(\n\t\tprivate collapsed: () => string,\n\t\tprivate expanded: () => string,\n\t\tinitiallyExpanded: boolean,\n\t\tpaddingX: number,\n\t\tpaddingY: number,\n\t) {\n\t\tsuper(initiallyExpanded ? expanded() : collapsed(), paddingX, paddingY);\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.setText(expanded ? this.expanded() : this.collapsed());\n\t}\n}\n\n// ============================================================================\n// Path and source-label formatting\n// ============================================================================\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(extensionPath: string): string {\n\tlet result = formatDisplayPath(extensionPath);\n\tresult = result.replace(/\\/index\\.ts$/, \"\").replace(/\\/index\\.js$/, \"\");\n\treturn result;\n}\n\nexport function formatContextPath(p: string, cwd: string): string {\n\tconst resolvedCwd = path.resolve(cwd);\n\tconst absolutePath = path.isAbsolute(p) ? path.resolve(p) : path.resolve(resolvedCwd, p);\n\tconst relativePath = getCwdRelativePath(absolutePath, resolvedCwd);\n\tif (relativePath !== undefined) {\n\t\treturn relativePath;\n\t}\n\n\treturn formatDisplayPath(absolutePath);\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\nfunction 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\nfunction 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\nfunction 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\nfunction 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(\n\textensions: Array<{ path: string; sourceInfo?: SourceInfo; displayName?: string }>,\n): 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 (extension.displayName) {\n\t\t\treturn extension.displayName;\n\t\t}\n\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\nfunction 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\nfunction 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\nfunction isPackageSource(sourceInfo?: SourceInfo): boolean {\n\tconst source = sourceInfo?.source ?? \"\";\n\treturn source.startsWith(\"npm:\") || source.startsWith(\"git:\");\n}\n\n// ============================================================================\n// Scope grouping and diagnostics\n// ============================================================================\n\ninterface ScopedItem {\n\tpath: string;\n\tsourceInfo?: SourceInfo;\n\tdisplayName?: string;\n}\n\ninterface ScopeGroup {\n\tscope: \"user\" | \"project\" | \"path\";\n\tpaths: ScopedItem[];\n\tpackages: Map<string, ScopedItem[]>;\n}\n\nfunction buildScopeGroups(items: ScopedItem[]): ScopeGroup[] {\n\tconst groups: Record<\"user\" | \"project\" | \"path\", ScopeGroup> = {\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\nfunction formatScopeGroups(\n\tgroups: ScopeGroup[],\n\toptions: {\n\t\tformatPath: (item: ScopedItem) => string;\n\t\tformatPackagePath: (item: ScopedItem, 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\nfunction 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\nfunction 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\n// ============================================================================\n// Loaded-resources listing\n// ============================================================================\n\n/** The slice of the interactive mode the resource listing renders into. */\nexport interface ResourceDisplayDeps {\n\tchatContainer: Container;\n\tgetCwd(): string;\n\tgetResourceLoader(): ResourceLoader;\n\tgetPromptTemplates(): ReadonlyArray<PromptTemplate>;\n\tgetExtensionRunner(): ExtensionRunner;\n\tgetActiveMode(): string;\n\tgetSubagentEnabled(): boolean;\n\tquietStartup(): boolean;\n\tverbose: boolean;\n\t/** Startup expansion state for the collapsible sections. */\n\tisExpanded(): boolean;\n\tgetBuiltInCommandConflictDiagnostics(extensionRunner: ExtensionRunner): ResourceDiagnostic[];\n}\n\nexport function showLoadedResources(\n\tdeps: ResourceDisplayDeps,\n\toptions?: {\n\t\textensions?: Array<{ path: string; sourceInfo?: SourceInfo }>;\n\t\tforce?: boolean;\n\t\tshowDiagnosticsWhenQuiet?: boolean;\n\t},\n): void {\n\tconst showListing = options?.force || deps.verbose || !deps.quietStartup();\n\tconst showDiagnostics = showListing || options?.showDiagnosticsWhenQuiet === true;\n\tif (!showListing && !showDiagnostics) {\n\t\treturn;\n\t}\n\n\tconst resourceLoader = deps.getResourceLoader();\n\tconst chatContainer = deps.chatContainer;\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) {\n\t\t\tlabels.sort((a, b) => a.localeCompare(b));\n\t\t}\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\tconst section = new ExpandableText(\n\t\t\t() => `${sectionHeader(name, color)}\\n${collapsedBody}`,\n\t\t\t() => `${sectionHeader(name, color)}\\n${expandedBody}`,\n\t\t\tdeps.isExpanded(),\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t\tchatContainer.addChild(section);\n\t\tchatContainer.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\n\t\t\t.getExtensions()\n\t\t\t.extensions.filter((extension) => !extension.internal)\n\t\t\t.map((extension) => ({\n\t\t\t\tpath: extension.path,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\tdisplayName: extension.displayName,\n\t\t\t}));\n\tconst sourceInfos = new Map<string, SourceInfo>();\n\tfor (const extension of extensions) {\n\t\tif (extension.sourceInfo) {\n\t\t\tsourceInfos.set(extension.path, extension.sourceInfo);\n\t\t}\n\t}\n\tfor (const skill of skillsResult.skills) {\n\t\tif (skill.sourceInfo) {\n\t\t\tsourceInfos.set(skill.filePath, skill.sourceInfo);\n\t\t}\n\t}\n\tfor (const prompt of promptsResult.prompts) {\n\t\tif (prompt.sourceInfo) {\n\t\t\tsourceInfos.set(prompt.filePath, prompt.sourceInfo);\n\t\t}\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\tchatContainer.addChild(new Spacer(1));\n\n\t\tconst { agentsFiles: contextFiles, warnings: contextWarnings } = resourceLoader.getAgentsFiles();\n\t\tconst skills = skillsResult.skills;\n\t\tconst templates = deps.getPromptTemplates();\n\t\tconst loadedThemes = themesResult.themes;\n\t\tconst customThemes = loadedThemes.filter((t) => t.sourcePath);\n\n\t\tconst totalItems =\n\t\t\tcontextFiles.length + skills.length + templates.length + extensions.length + customThemes.length;\n\n\t\t// Meta items: active mode and subagent system prompt (always shown)\n\t\tconst metaItems: string[] = [];\n\t\tconst rawMode = deps.getActiveMode().replace(\" + subagent\", \"\");\n\t\tmetaItems.push(`mode/${rawMode}`);\n\t\tif (deps.getSubagentEnabled()) {\n\t\t\tmetaItems.push(\"subagent_system_prompt\");\n\t\t}\n\n\t\tif (totalItems > 0 && totalItems <= 5) {\n\t\t\tconst allCompactItems: string[] = [...metaItems];\n\t\t\tif (contextFiles.length > 0) {\n\t\t\t\tallCompactItems.push(\n\t\t\t\t\t...contextFiles.map((contextFile) => formatContextPath(contextFile.path, deps.getCwd())),\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (skills.length > 0) {\n\t\t\t\tallCompactItems.push(...skills.map((skill) => skill.name));\n\t\t\t}\n\t\t\tif (templates.length > 0) {\n\t\t\t\tallCompactItems.push(...templates.map((template) => `/${template.name}`));\n\t\t\t}\n\t\t\tif (extensions.length > 0) {\n\t\t\t\tallCompactItems.push(...getCompactExtensionLabels(extensions));\n\t\t\t}\n\t\t\tif (customThemes.length > 0) {\n\t\t\t\tallCompactItems.push(\n\t\t\t\t\t...customThemes.map(\n\t\t\t\t\t\t(loadedTheme) =>\n\t\t\t\t\t\t\tloadedTheme.name ?? getCompactPathLabel(loadedTheme.sourcePath!, loadedTheme.sourceInfo),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\tchatContainer.addChild(\n\t\t\t\tnew Text(`${theme.fg(\"mdHeading\", \"[Resources]\")} ${theme.fg(\"dim\", allCompactItems.join(\", \"))}`, 0, 0),\n\t\t\t);\n\t\t} else if (totalItems === 0) {\n\t\t\tchatContainer.addChild(\n\t\t\t\tnew Text(`${theme.fg(\"mdHeading\", \"[Resources]\")} ${theme.fg(\"dim\", metaItems.join(\", \"))}`, 0, 0),\n\t\t\t);\n\t\t} else {\n\t\t\taddLoadedSection(\"Resources\", formatCompactList(metaItems), formatCompactList(metaItems));\n\t\t\tif (contextFiles.length > 0) {\n\t\t\t\tchatContainer.addChild(new Spacer(1));\n\t\t\t\tconst contextList = contextFiles.map((f) => theme.fg(\"dim\", ` ${formatDisplayPath(f.path)}`)).join(\"\\n\");\n\t\t\t\tconst contextCompactList = formatCompactList(\n\t\t\t\t\tcontextFiles.map((contextFile) => formatContextPath(contextFile.path, deps.getCwd())),\n\t\t\t\t\t{ sort: false },\n\t\t\t\t);\n\t\t\t\taddLoadedSection(\"Context\", contextCompactList, contextList);\n\t\t\t}\n\n\t\t\tif (skills.length > 0) {\n\t\t\t\tconst groups = buildScopeGroups(\n\t\t\t\t\tskills.map((skill) => ({ path: skill.filePath, sourceInfo: skill.sourceInfo })),\n\t\t\t\t);\n\t\t\t\tconst skillList = formatScopeGroups(groups, {\n\t\t\t\t\tformatPath: (item) => formatDisplayPath(item.path),\n\t\t\t\t\tformatPackagePath: (item) => getShortPath(item.path, item.sourceInfo),\n\t\t\t\t});\n\t\t\t\tconst skillCompactList = formatCompactList(skills.map((skill) => skill.name));\n\t\t\t\taddLoadedSection(\"Skills\", skillCompactList, skillList);\n\t\t\t}\n\n\t\t\tif (templates.length > 0) {\n\t\t\t\tconst groups = buildScopeGroups(\n\t\t\t\t\ttemplates.map((template) => ({ path: template.filePath, sourceInfo: template.sourceInfo })),\n\t\t\t\t);\n\t\t\t\tconst templateByPath = new Map(templates.map((t) => [t.filePath, t]));\n\t\t\t\tconst templateList = formatScopeGroups(groups, {\n\t\t\t\t\tformatPath: (item) => {\n\t\t\t\t\t\tconst template = templateByPath.get(item.path);\n\t\t\t\t\t\treturn template ? `/${template.name}` : formatDisplayPath(item.path);\n\t\t\t\t\t},\n\t\t\t\t\tformatPackagePath: (item) => {\n\t\t\t\t\t\tconst template = templateByPath.get(item.path);\n\t\t\t\t\t\treturn template ? `/${template.name}` : formatDisplayPath(item.path);\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tconst promptCompactList = formatCompactList(templates.map((template) => `/${template.name}`));\n\t\t\t\taddLoadedSection(\"Prompts\", promptCompactList, templateList);\n\t\t\t}\n\n\t\t\tif (extensions.length > 0) {\n\t\t\t\tconst groups = buildScopeGroups(extensions);\n\t\t\t\tconst extList = formatScopeGroups(groups, {\n\t\t\t\t\tformatPath: (item) => item.displayName ?? formatExtensionDisplayPath(item.path),\n\t\t\t\t\tformatPackagePath: (item) =>\n\t\t\t\t\t\titem.displayName ?? formatExtensionDisplayPath(getShortPath(item.path, item.sourceInfo)),\n\t\t\t\t});\n\t\t\t\tconst extensionCompactList = formatCompactList(getCompactExtensionLabels(extensions));\n\t\t\t\taddLoadedSection(\"Extensions\", extensionCompactList, extList, \"mdHeading\");\n\t\t\t}\n\n\t\t\tif (customThemes.length > 0) {\n\t\t\t\tconst groups = buildScopeGroups(\n\t\t\t\t\tcustomThemes.map((loadedTheme) => ({\n\t\t\t\t\t\tpath: loadedTheme.sourcePath!,\n\t\t\t\t\t\tsourceInfo: loadedTheme.sourceInfo,\n\t\t\t\t\t})),\n\t\t\t\t);\n\t\t\t\tconst themeList = formatScopeGroups(groups, {\n\t\t\t\t\tformatPath: (item) => formatDisplayPath(item.path),\n\t\t\t\t\tformatPackagePath: (item) => getShortPath(item.path, item.sourceInfo),\n\t\t\t\t});\n\t\t\t\tconst themeCompactList = formatCompactList(\n\t\t\t\t\tcustomThemes.map(\n\t\t\t\t\t\t(loadedTheme) =>\n\t\t\t\t\t\t\tloadedTheme.name ?? getCompactPathLabel(loadedTheme.sourcePath!, loadedTheme.sourceInfo),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\taddLoadedSection(\"Themes\", themeCompactList, themeList);\n\t\t\t}\n\t\t}\n\n\t\tif (contextWarnings.length > 0) {\n\t\t\tfor (const warning of contextWarnings) {\n\t\t\t\tchatContainer.addChild(new Text(theme.fg(\"warning\", warning), 0, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\tif (showDiagnostics) {\n\t\tconst skillDiagnostics = skillsResult.diagnostics;\n\t\tif (skillDiagnostics.length > 0) {\n\t\t\tconst warningLines = formatDiagnostics(skillDiagnostics, sourceInfos);\n\t\t\tchatContainer.addChild(new Text(`${theme.fg(\"warning\", \"[Skill conflicts]\")}\\n${warningLines}`, 0, 0));\n\t\t\tchatContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\tconst promptDiagnostics = promptsResult.diagnostics;\n\t\tif (promptDiagnostics.length > 0) {\n\t\t\tconst warningLines = formatDiagnostics(promptDiagnostics, sourceInfos);\n\t\t\tchatContainer.addChild(new Text(`${theme.fg(\"warning\", \"[Prompt conflicts]\")}\\n${warningLines}`, 0, 0));\n\t\t\tchatContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\tconst extensionDiagnostics: ResourceDiagnostic[] = [];\n\t\tconst extensionErrors = resourceLoader.getExtensions().errors;\n\t\tif (extensionErrors.length > 0) {\n\t\t\tfor (const error of extensionErrors) {\n\t\t\t\textensionDiagnostics.push({ type: \"error\", message: error.error, path: error.path });\n\t\t\t}\n\t\t}\n\n\t\tconst extensionRunner = deps.getExtensionRunner();\n\t\tconst commandDiagnostics = extensionRunner.getCommandDiagnostics();\n\t\textensionDiagnostics.push(...commandDiagnostics);\n\t\textensionDiagnostics.push(...deps.getBuiltInCommandConflictDiagnostics(extensionRunner));\n\n\t\tconst shortcutDiagnostics = extensionRunner.getShortcutDiagnostics();\n\t\textensionDiagnostics.push(...shortcutDiagnostics);\n\n\t\tif (extensionDiagnostics.length > 0) {\n\t\t\tconst warningLines = formatDiagnostics(extensionDiagnostics, sourceInfos);\n\t\t\tchatContainer.addChild(new Text(`${theme.fg(\"warning\", \"[Extension issues]\")}\\n${warningLines}`, 0, 0));\n\t\t\tchatContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\tconst themeDiagnostics = themesResult.diagnostics;\n\t\tif (themeDiagnostics.length > 0) {\n\t\t\tconst warningLines = formatDiagnostics(themeDiagnostics, sourceInfos);\n\t\t\tchatContainer.addChild(new Text(`${theme.fg(\"warning\", \"[Theme conflicts]\")}\\n${warningLines}`, 0, 0));\n\t\t\tchatContainer.addChild(new Spacer(1));\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,499 @@
1
+ /**
2
+ * Startup/reload resource listing: path and source-label formatting, scope
3
+ * grouping, diagnostics rendering, and the [Resources]/[Skills]/… sections
4
+ * shown in the chat. Extracted from interactive-mode.ts; everything here is
5
+ * either pure formatting or rendering into a container passed via deps.
6
+ */
7
+ import * as os from "node:os";
8
+ import * as path from "node:path";
9
+ import { Spacer, Text } from "@kolisachint/hoocode-tui";
10
+ import { parseGitUrl } from "../../utils/git.js";
11
+ import { getCwdRelativePath } from "../../utils/paths.js";
12
+ import { theme } from "./theme/theme.js";
13
+ export function isExpandable(obj) {
14
+ return typeof obj === "object" && obj !== null && "setExpanded" in obj;
15
+ }
16
+ export class ExpandableText extends Text {
17
+ collapsed;
18
+ expanded;
19
+ constructor(collapsed, expanded, initiallyExpanded, paddingX, paddingY) {
20
+ super(initiallyExpanded ? expanded() : collapsed(), paddingX, paddingY);
21
+ this.collapsed = collapsed;
22
+ this.expanded = expanded;
23
+ }
24
+ setExpanded(expanded) {
25
+ this.setText(expanded ? this.expanded() : this.collapsed());
26
+ }
27
+ }
28
+ // ============================================================================
29
+ // Path and source-label formatting
30
+ // ============================================================================
31
+ export function formatDisplayPath(p) {
32
+ const home = os.homedir();
33
+ let result = p;
34
+ // Replace home directory with ~
35
+ if (result.startsWith(home)) {
36
+ result = `~${result.slice(home.length)}`;
37
+ }
38
+ return result;
39
+ }
40
+ export function formatExtensionDisplayPath(extensionPath) {
41
+ let result = formatDisplayPath(extensionPath);
42
+ result = result.replace(/\/index\.ts$/, "").replace(/\/index\.js$/, "");
43
+ return result;
44
+ }
45
+ export function formatContextPath(p, cwd) {
46
+ const resolvedCwd = path.resolve(cwd);
47
+ const absolutePath = path.isAbsolute(p) ? path.resolve(p) : path.resolve(resolvedCwd, p);
48
+ const relativePath = getCwdRelativePath(absolutePath, resolvedCwd);
49
+ if (relativePath !== undefined) {
50
+ return relativePath;
51
+ }
52
+ return formatDisplayPath(absolutePath);
53
+ }
54
+ /**
55
+ * Get a short path relative to the package root for display.
56
+ */
57
+ export function getShortPath(fullPath, sourceInfo) {
58
+ const baseDir = sourceInfo?.baseDir;
59
+ if (baseDir && isPackageSource(sourceInfo)) {
60
+ const relativePath = path.relative(path.resolve(baseDir), path.resolve(fullPath));
61
+ if (relativePath &&
62
+ relativePath !== "." &&
63
+ !relativePath.startsWith("..") &&
64
+ !relativePath.startsWith(`..${path.sep}`) &&
65
+ !path.isAbsolute(relativePath)) {
66
+ return relativePath.replace(/\\/g, "/");
67
+ }
68
+ }
69
+ const source = sourceInfo?.source ?? "";
70
+ const npmMatch = fullPath.match(/node_modules\/(@?[^/]+(?:\/[^/]+)?)\/(.*)/);
71
+ if (npmMatch && source.startsWith("npm:")) {
72
+ return npmMatch[2];
73
+ }
74
+ const gitMatch = fullPath.match(/git\/[^/]+\/[^/]+\/(.*)/);
75
+ if (gitMatch && source.startsWith("git:")) {
76
+ return gitMatch[1];
77
+ }
78
+ return formatDisplayPath(fullPath);
79
+ }
80
+ export function getCompactPathLabel(resourcePath, sourceInfo) {
81
+ const shortPath = getShortPath(resourcePath, sourceInfo);
82
+ const normalizedPath = shortPath.replace(/\\/g, "/");
83
+ const segments = normalizedPath.split("/").filter((segment) => segment.length > 0 && segment !== "~");
84
+ if (segments.length > 0) {
85
+ return segments[segments.length - 1];
86
+ }
87
+ return shortPath;
88
+ }
89
+ function getCompactPackageSourceLabel(sourceInfo) {
90
+ const source = sourceInfo?.source ?? "";
91
+ if (source.startsWith("npm:")) {
92
+ return source.slice("npm:".length) || source;
93
+ }
94
+ const gitSource = parseGitUrl(source);
95
+ if (gitSource) {
96
+ return gitSource.path || source;
97
+ }
98
+ return source;
99
+ }
100
+ function getCompactExtensionLabel(resourcePath, sourceInfo) {
101
+ if (!isPackageSource(sourceInfo)) {
102
+ return getCompactPathLabel(resourcePath, sourceInfo);
103
+ }
104
+ const sourceLabel = getCompactPackageSourceLabel(sourceInfo);
105
+ if (!sourceLabel) {
106
+ return getCompactPathLabel(resourcePath, sourceInfo);
107
+ }
108
+ const shortPath = getShortPath(resourcePath, sourceInfo).replace(/\\/g, "/");
109
+ const packagePath = shortPath.startsWith("extensions/") ? shortPath.slice("extensions/".length) : shortPath;
110
+ const parsedPath = path.posix.parse(packagePath);
111
+ if (parsedPath.name === "index") {
112
+ return !parsedPath.dir || parsedPath.dir === "." ? sourceLabel : `${sourceLabel}:${parsedPath.dir}`;
113
+ }
114
+ return `${sourceLabel}:${packagePath}`;
115
+ }
116
+ function getCompactDisplayPathSegments(resourcePath) {
117
+ return formatDisplayPath(resourcePath)
118
+ .replace(/\\/g, "/")
119
+ .split("/")
120
+ .filter((segment) => segment.length > 0 && segment !== "~");
121
+ }
122
+ function getCompactNonPackageExtensionLabel(resourcePath, index, allPaths) {
123
+ const segments = allPaths[index]?.segments;
124
+ if (!segments || segments.length === 0) {
125
+ return getCompactPathLabel(resourcePath);
126
+ }
127
+ for (let segmentCount = 1; segmentCount <= segments.length; segmentCount += 1) {
128
+ const candidate = segments.slice(-segmentCount).join("/");
129
+ const isUnique = allPaths.every((item, itemIndex) => {
130
+ if (itemIndex === index) {
131
+ return true;
132
+ }
133
+ return item.segments.slice(-segmentCount).join("/") !== candidate;
134
+ });
135
+ if (isUnique) {
136
+ return candidate;
137
+ }
138
+ }
139
+ return segments.join("/");
140
+ }
141
+ export function getCompactExtensionLabels(extensions) {
142
+ const nonPackageExtensions = extensions
143
+ .map((extension) => {
144
+ const segments = getCompactDisplayPathSegments(extension.path);
145
+ const lastSegment = segments[segments.length - 1];
146
+ if (segments.length > 1 && (lastSegment === "index.ts" || lastSegment === "index.js")) {
147
+ segments.pop();
148
+ }
149
+ return {
150
+ path: extension.path,
151
+ sourceInfo: extension.sourceInfo,
152
+ segments,
153
+ };
154
+ })
155
+ .filter((extension) => !isPackageSource(extension.sourceInfo));
156
+ return extensions.map((extension) => {
157
+ if (extension.displayName) {
158
+ return extension.displayName;
159
+ }
160
+ if (isPackageSource(extension.sourceInfo)) {
161
+ return getCompactExtensionLabel(extension.path, extension.sourceInfo);
162
+ }
163
+ const nonPackageIndex = nonPackageExtensions.findIndex((item) => item.path === extension.path);
164
+ if (nonPackageIndex === -1) {
165
+ return getCompactPathLabel(extension.path, extension.sourceInfo);
166
+ }
167
+ return getCompactNonPackageExtensionLabel(extension.path, nonPackageIndex, nonPackageExtensions);
168
+ });
169
+ }
170
+ function getDisplaySourceInfo(sourceInfo) {
171
+ const source = sourceInfo?.source ?? "local";
172
+ const scope = sourceInfo?.scope ?? "project";
173
+ if (source === "local") {
174
+ if (scope === "user") {
175
+ return { label: "user", color: "muted" };
176
+ }
177
+ if (scope === "project") {
178
+ return { label: "project", color: "muted" };
179
+ }
180
+ if (scope === "temporary") {
181
+ return { label: "path", scopeLabel: "temp", color: "muted" };
182
+ }
183
+ return { label: "path", color: "muted" };
184
+ }
185
+ if (source === "cli") {
186
+ return { label: "path", scopeLabel: scope === "temporary" ? "temp" : undefined, color: "muted" };
187
+ }
188
+ const scopeLabel = scope === "user" ? "user" : scope === "project" ? "project" : scope === "temporary" ? "temp" : undefined;
189
+ return { label: source, scopeLabel, color: "accent" };
190
+ }
191
+ function getScopeGroup(sourceInfo) {
192
+ const source = sourceInfo?.source ?? "local";
193
+ const scope = sourceInfo?.scope ?? "project";
194
+ if (source === "cli" || scope === "temporary")
195
+ return "path";
196
+ if (scope === "user")
197
+ return "user";
198
+ if (scope === "project")
199
+ return "project";
200
+ return "path";
201
+ }
202
+ function isPackageSource(sourceInfo) {
203
+ const source = sourceInfo?.source ?? "";
204
+ return source.startsWith("npm:") || source.startsWith("git:");
205
+ }
206
+ function buildScopeGroups(items) {
207
+ const groups = {
208
+ user: { scope: "user", paths: [], packages: new Map() },
209
+ project: { scope: "project", paths: [], packages: new Map() },
210
+ path: { scope: "path", paths: [], packages: new Map() },
211
+ };
212
+ for (const item of items) {
213
+ const groupKey = getScopeGroup(item.sourceInfo);
214
+ const group = groups[groupKey];
215
+ const source = item.sourceInfo?.source ?? "local";
216
+ if (isPackageSource(item.sourceInfo)) {
217
+ const list = group.packages.get(source) ?? [];
218
+ list.push(item);
219
+ group.packages.set(source, list);
220
+ }
221
+ else {
222
+ group.paths.push(item);
223
+ }
224
+ }
225
+ return [groups.project, groups.user, groups.path].filter((group) => group.paths.length > 0 || group.packages.size > 0);
226
+ }
227
+ function formatScopeGroups(groups, options) {
228
+ const lines = [];
229
+ for (const group of groups) {
230
+ lines.push(` ${theme.fg("accent", group.scope)}`);
231
+ const sortedPaths = [...group.paths].sort((a, b) => a.path.localeCompare(b.path));
232
+ for (const item of sortedPaths) {
233
+ lines.push(theme.fg("dim", ` ${options.formatPath(item)}`));
234
+ }
235
+ const sortedPackages = Array.from(group.packages.entries()).sort(([a], [b]) => a.localeCompare(b));
236
+ for (const [source, items] of sortedPackages) {
237
+ lines.push(` ${theme.fg("mdLink", source)}`);
238
+ const sortedPackagePaths = [...items].sort((a, b) => a.path.localeCompare(b.path));
239
+ for (const item of sortedPackagePaths) {
240
+ lines.push(theme.fg("dim", ` ${options.formatPackagePath(item, source)}`));
241
+ }
242
+ }
243
+ }
244
+ return lines.join("\n");
245
+ }
246
+ function findSourceInfoForPath(p, sourceInfos) {
247
+ const exact = sourceInfos.get(p);
248
+ if (exact)
249
+ return exact;
250
+ let current = p;
251
+ while (current.includes("/")) {
252
+ current = current.substring(0, current.lastIndexOf("/"));
253
+ const parent = sourceInfos.get(current);
254
+ if (parent)
255
+ return parent;
256
+ }
257
+ return undefined;
258
+ }
259
+ function formatPathWithSource(p, sourceInfo) {
260
+ if (sourceInfo) {
261
+ const shortPath = getShortPath(p, sourceInfo);
262
+ const { label, scopeLabel } = getDisplaySourceInfo(sourceInfo);
263
+ const labelText = scopeLabel ? `${label} (${scopeLabel})` : label;
264
+ return `${labelText} ${shortPath}`;
265
+ }
266
+ return formatDisplayPath(p);
267
+ }
268
+ export function formatDiagnostics(diagnostics, sourceInfos) {
269
+ const lines = [];
270
+ // Group collision diagnostics by name
271
+ const collisions = new Map();
272
+ const otherDiagnostics = [];
273
+ for (const d of diagnostics) {
274
+ if (d.type === "collision" && d.collision) {
275
+ const list = collisions.get(d.collision.name) ?? [];
276
+ list.push(d);
277
+ collisions.set(d.collision.name, list);
278
+ }
279
+ else {
280
+ otherDiagnostics.push(d);
281
+ }
282
+ }
283
+ // Format collision diagnostics grouped by name
284
+ for (const [name, collisionList] of collisions) {
285
+ const first = collisionList[0]?.collision;
286
+ if (!first)
287
+ continue;
288
+ lines.push(theme.fg("warning", ` "${name}" collision:`));
289
+ lines.push(theme.fg("dim", ` ${theme.fg("success", "✓")} ${formatPathWithSource(first.winnerPath, findSourceInfoForPath(first.winnerPath, sourceInfos))}`));
290
+ for (const d of collisionList) {
291
+ if (d.collision) {
292
+ lines.push(theme.fg("dim", ` ${theme.fg("warning", "✗")} ${formatPathWithSource(d.collision.loserPath, findSourceInfoForPath(d.collision.loserPath, sourceInfos))} (skipped)`));
293
+ }
294
+ }
295
+ }
296
+ for (const d of otherDiagnostics) {
297
+ if (d.path) {
298
+ const formattedPath = formatPathWithSource(d.path, findSourceInfoForPath(d.path, sourceInfos));
299
+ lines.push(theme.fg(d.type === "error" ? "error" : "warning", ` ${formattedPath}`));
300
+ lines.push(theme.fg(d.type === "error" ? "error" : "warning", ` ${d.message}`));
301
+ }
302
+ else {
303
+ lines.push(theme.fg(d.type === "error" ? "error" : "warning", ` ${d.message}`));
304
+ }
305
+ }
306
+ return lines.join("\n");
307
+ }
308
+ export function showLoadedResources(deps, options) {
309
+ const showListing = options?.force || deps.verbose || !deps.quietStartup();
310
+ const showDiagnostics = showListing || options?.showDiagnosticsWhenQuiet === true;
311
+ if (!showListing && !showDiagnostics) {
312
+ return;
313
+ }
314
+ const resourceLoader = deps.getResourceLoader();
315
+ const chatContainer = deps.chatContainer;
316
+ const sectionHeader = (name, color = "mdHeading") => theme.fg(color, `[${name}]`);
317
+ const formatCompactList = (items, listOptions) => {
318
+ const labels = items.map((item) => item.trim()).filter((item) => item.length > 0);
319
+ if (listOptions?.sort !== false) {
320
+ labels.sort((a, b) => a.localeCompare(b));
321
+ }
322
+ return theme.fg("dim", ` ${labels.join(", ")}`);
323
+ };
324
+ const addLoadedSection = (name, collapsedBody, expandedBody = collapsedBody, color = "mdHeading") => {
325
+ const section = new ExpandableText(() => `${sectionHeader(name, color)}\n${collapsedBody}`, () => `${sectionHeader(name, color)}\n${expandedBody}`, deps.isExpanded(), 0, 0);
326
+ chatContainer.addChild(section);
327
+ chatContainer.addChild(new Spacer(1));
328
+ };
329
+ const skillsResult = resourceLoader.getSkills();
330
+ const promptsResult = resourceLoader.getPrompts();
331
+ const themesResult = resourceLoader.getThemes();
332
+ const extensions = options?.extensions ??
333
+ resourceLoader
334
+ .getExtensions()
335
+ .extensions.filter((extension) => !extension.internal)
336
+ .map((extension) => ({
337
+ path: extension.path,
338
+ sourceInfo: extension.sourceInfo,
339
+ displayName: extension.displayName,
340
+ }));
341
+ const sourceInfos = new Map();
342
+ for (const extension of extensions) {
343
+ if (extension.sourceInfo) {
344
+ sourceInfos.set(extension.path, extension.sourceInfo);
345
+ }
346
+ }
347
+ for (const skill of skillsResult.skills) {
348
+ if (skill.sourceInfo) {
349
+ sourceInfos.set(skill.filePath, skill.sourceInfo);
350
+ }
351
+ }
352
+ for (const prompt of promptsResult.prompts) {
353
+ if (prompt.sourceInfo) {
354
+ sourceInfos.set(prompt.filePath, prompt.sourceInfo);
355
+ }
356
+ }
357
+ for (const loadedTheme of themesResult.themes) {
358
+ if (loadedTheme.sourcePath && loadedTheme.sourceInfo) {
359
+ sourceInfos.set(loadedTheme.sourcePath, loadedTheme.sourceInfo);
360
+ }
361
+ }
362
+ if (showListing) {
363
+ chatContainer.addChild(new Spacer(1));
364
+ const { agentsFiles: contextFiles, warnings: contextWarnings } = resourceLoader.getAgentsFiles();
365
+ const skills = skillsResult.skills;
366
+ const templates = deps.getPromptTemplates();
367
+ const loadedThemes = themesResult.themes;
368
+ const customThemes = loadedThemes.filter((t) => t.sourcePath);
369
+ const totalItems = contextFiles.length + skills.length + templates.length + extensions.length + customThemes.length;
370
+ // Meta items: active mode and subagent system prompt (always shown)
371
+ const metaItems = [];
372
+ const rawMode = deps.getActiveMode().replace(" + subagent", "");
373
+ metaItems.push(`mode/${rawMode}`);
374
+ if (deps.getSubagentEnabled()) {
375
+ metaItems.push("subagent_system_prompt");
376
+ }
377
+ if (totalItems > 0 && totalItems <= 5) {
378
+ const allCompactItems = [...metaItems];
379
+ if (contextFiles.length > 0) {
380
+ allCompactItems.push(...contextFiles.map((contextFile) => formatContextPath(contextFile.path, deps.getCwd())));
381
+ }
382
+ if (skills.length > 0) {
383
+ allCompactItems.push(...skills.map((skill) => skill.name));
384
+ }
385
+ if (templates.length > 0) {
386
+ allCompactItems.push(...templates.map((template) => `/${template.name}`));
387
+ }
388
+ if (extensions.length > 0) {
389
+ allCompactItems.push(...getCompactExtensionLabels(extensions));
390
+ }
391
+ if (customThemes.length > 0) {
392
+ allCompactItems.push(...customThemes.map((loadedTheme) => loadedTheme.name ?? getCompactPathLabel(loadedTheme.sourcePath, loadedTheme.sourceInfo)));
393
+ }
394
+ chatContainer.addChild(new Text(`${theme.fg("mdHeading", "[Resources]")} ${theme.fg("dim", allCompactItems.join(", "))}`, 0, 0));
395
+ }
396
+ else if (totalItems === 0) {
397
+ chatContainer.addChild(new Text(`${theme.fg("mdHeading", "[Resources]")} ${theme.fg("dim", metaItems.join(", "))}`, 0, 0));
398
+ }
399
+ else {
400
+ addLoadedSection("Resources", formatCompactList(metaItems), formatCompactList(metaItems));
401
+ if (contextFiles.length > 0) {
402
+ chatContainer.addChild(new Spacer(1));
403
+ const contextList = contextFiles.map((f) => theme.fg("dim", ` ${formatDisplayPath(f.path)}`)).join("\n");
404
+ const contextCompactList = formatCompactList(contextFiles.map((contextFile) => formatContextPath(contextFile.path, deps.getCwd())), { sort: false });
405
+ addLoadedSection("Context", contextCompactList, contextList);
406
+ }
407
+ if (skills.length > 0) {
408
+ const groups = buildScopeGroups(skills.map((skill) => ({ path: skill.filePath, sourceInfo: skill.sourceInfo })));
409
+ const skillList = formatScopeGroups(groups, {
410
+ formatPath: (item) => formatDisplayPath(item.path),
411
+ formatPackagePath: (item) => getShortPath(item.path, item.sourceInfo),
412
+ });
413
+ const skillCompactList = formatCompactList(skills.map((skill) => skill.name));
414
+ addLoadedSection("Skills", skillCompactList, skillList);
415
+ }
416
+ if (templates.length > 0) {
417
+ const groups = buildScopeGroups(templates.map((template) => ({ path: template.filePath, sourceInfo: template.sourceInfo })));
418
+ const templateByPath = new Map(templates.map((t) => [t.filePath, t]));
419
+ const templateList = formatScopeGroups(groups, {
420
+ formatPath: (item) => {
421
+ const template = templateByPath.get(item.path);
422
+ return template ? `/${template.name}` : formatDisplayPath(item.path);
423
+ },
424
+ formatPackagePath: (item) => {
425
+ const template = templateByPath.get(item.path);
426
+ return template ? `/${template.name}` : formatDisplayPath(item.path);
427
+ },
428
+ });
429
+ const promptCompactList = formatCompactList(templates.map((template) => `/${template.name}`));
430
+ addLoadedSection("Prompts", promptCompactList, templateList);
431
+ }
432
+ if (extensions.length > 0) {
433
+ const groups = buildScopeGroups(extensions);
434
+ const extList = formatScopeGroups(groups, {
435
+ formatPath: (item) => item.displayName ?? formatExtensionDisplayPath(item.path),
436
+ formatPackagePath: (item) => item.displayName ?? formatExtensionDisplayPath(getShortPath(item.path, item.sourceInfo)),
437
+ });
438
+ const extensionCompactList = formatCompactList(getCompactExtensionLabels(extensions));
439
+ addLoadedSection("Extensions", extensionCompactList, extList, "mdHeading");
440
+ }
441
+ if (customThemes.length > 0) {
442
+ const groups = buildScopeGroups(customThemes.map((loadedTheme) => ({
443
+ path: loadedTheme.sourcePath,
444
+ sourceInfo: loadedTheme.sourceInfo,
445
+ })));
446
+ const themeList = formatScopeGroups(groups, {
447
+ formatPath: (item) => formatDisplayPath(item.path),
448
+ formatPackagePath: (item) => getShortPath(item.path, item.sourceInfo),
449
+ });
450
+ const themeCompactList = formatCompactList(customThemes.map((loadedTheme) => loadedTheme.name ?? getCompactPathLabel(loadedTheme.sourcePath, loadedTheme.sourceInfo)));
451
+ addLoadedSection("Themes", themeCompactList, themeList);
452
+ }
453
+ }
454
+ if (contextWarnings.length > 0) {
455
+ for (const warning of contextWarnings) {
456
+ chatContainer.addChild(new Text(theme.fg("warning", warning), 0, 0));
457
+ }
458
+ }
459
+ }
460
+ if (showDiagnostics) {
461
+ const skillDiagnostics = skillsResult.diagnostics;
462
+ if (skillDiagnostics.length > 0) {
463
+ const warningLines = formatDiagnostics(skillDiagnostics, sourceInfos);
464
+ chatContainer.addChild(new Text(`${theme.fg("warning", "[Skill conflicts]")}\n${warningLines}`, 0, 0));
465
+ chatContainer.addChild(new Spacer(1));
466
+ }
467
+ const promptDiagnostics = promptsResult.diagnostics;
468
+ if (promptDiagnostics.length > 0) {
469
+ const warningLines = formatDiagnostics(promptDiagnostics, sourceInfos);
470
+ chatContainer.addChild(new Text(`${theme.fg("warning", "[Prompt conflicts]")}\n${warningLines}`, 0, 0));
471
+ chatContainer.addChild(new Spacer(1));
472
+ }
473
+ const extensionDiagnostics = [];
474
+ const extensionErrors = resourceLoader.getExtensions().errors;
475
+ if (extensionErrors.length > 0) {
476
+ for (const error of extensionErrors) {
477
+ extensionDiagnostics.push({ type: "error", message: error.error, path: error.path });
478
+ }
479
+ }
480
+ const extensionRunner = deps.getExtensionRunner();
481
+ const commandDiagnostics = extensionRunner.getCommandDiagnostics();
482
+ extensionDiagnostics.push(...commandDiagnostics);
483
+ extensionDiagnostics.push(...deps.getBuiltInCommandConflictDiagnostics(extensionRunner));
484
+ const shortcutDiagnostics = extensionRunner.getShortcutDiagnostics();
485
+ extensionDiagnostics.push(...shortcutDiagnostics);
486
+ if (extensionDiagnostics.length > 0) {
487
+ const warningLines = formatDiagnostics(extensionDiagnostics, sourceInfos);
488
+ chatContainer.addChild(new Text(`${theme.fg("warning", "[Extension issues]")}\n${warningLines}`, 0, 0));
489
+ chatContainer.addChild(new Spacer(1));
490
+ }
491
+ const themeDiagnostics = themesResult.diagnostics;
492
+ if (themeDiagnostics.length > 0) {
493
+ const warningLines = formatDiagnostics(themeDiagnostics, sourceInfos);
494
+ chatContainer.addChild(new Text(`${theme.fg("warning", "[Theme conflicts]")}\n${warningLines}`, 0, 0));
495
+ chatContainer.addChild(new Spacer(1));
496
+ }
497
+ }
498
+ }
499
+ //# sourceMappingURL=resource-display.js.map