@codex-infinity/pi-infinity 0.61.2 → 0.62.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +2 -2
  3. package/dist/cli/file-processor.d.ts.map +1 -1
  4. package/dist/cli/file-processor.js +4 -0
  5. package/dist/cli/file-processor.js.map +1 -1
  6. package/dist/core/agent-session.d.ts +10 -3
  7. package/dist/core/agent-session.d.ts.map +1 -1
  8. package/dist/core/agent-session.js +60 -46
  9. package/dist/core/agent-session.js.map +1 -1
  10. package/dist/core/export-html/index.d.ts +2 -2
  11. package/dist/core/export-html/index.d.ts.map +1 -1
  12. package/dist/core/export-html/index.js +2 -2
  13. package/dist/core/export-html/index.js.map +1 -1
  14. package/dist/core/export-html/tool-renderer.d.ts +2 -2
  15. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  16. package/dist/core/export-html/tool-renderer.js +41 -16
  17. package/dist/core/export-html/tool-renderer.js.map +1 -1
  18. package/dist/core/extensions/index.d.ts +3 -2
  19. package/dist/core/extensions/index.d.ts.map +1 -1
  20. package/dist/core/extensions/index.js.map +1 -1
  21. package/dist/core/extensions/loader.d.ts.map +1 -1
  22. package/dist/core/extensions/loader.js +12 -2
  23. package/dist/core/extensions/loader.js.map +1 -1
  24. package/dist/core/extensions/runner.d.ts +4 -7
  25. package/dist/core/extensions/runner.d.ts.map +1 -1
  26. package/dist/core/extensions/runner.js +27 -38
  27. package/dist/core/extensions/runner.js.map +1 -1
  28. package/dist/core/extensions/types.d.ts +44 -9
  29. package/dist/core/extensions/types.d.ts.map +1 -1
  30. package/dist/core/extensions/types.js.map +1 -1
  31. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  32. package/dist/core/extensions/wrapper.js +2 -8
  33. package/dist/core/extensions/wrapper.js.map +1 -1
  34. package/dist/core/index.d.ts +1 -0
  35. package/dist/core/index.d.ts.map +1 -1
  36. package/dist/core/index.js +1 -0
  37. package/dist/core/index.js.map +1 -1
  38. package/dist/core/output-guard.d.ts +6 -0
  39. package/dist/core/output-guard.d.ts.map +1 -0
  40. package/dist/core/output-guard.js +59 -0
  41. package/dist/core/output-guard.js.map +1 -0
  42. package/dist/core/package-manager.d.ts +1 -0
  43. package/dist/core/package-manager.d.ts.map +1 -1
  44. package/dist/core/package-manager.js +27 -8
  45. package/dist/core/package-manager.js.map +1 -1
  46. package/dist/core/prompt-templates.d.ts +2 -1
  47. package/dist/core/prompt-templates.d.ts.map +1 -1
  48. package/dist/core/prompt-templates.js +30 -32
  49. package/dist/core/prompt-templates.js.map +1 -1
  50. package/dist/core/resource-loader.d.ts +6 -5
  51. package/dist/core/resource-loader.d.ts.map +1 -1
  52. package/dist/core/resource-loader.js +133 -107
  53. package/dist/core/resource-loader.js.map +1 -1
  54. package/dist/core/sdk.d.ts +1 -1
  55. package/dist/core/sdk.d.ts.map +1 -1
  56. package/dist/core/sdk.js.map +1 -1
  57. package/dist/core/skills.d.ts +2 -1
  58. package/dist/core/skills.d.ts.map +1 -1
  59. package/dist/core/skills.js +25 -1
  60. package/dist/core/skills.js.map +1 -1
  61. package/dist/core/slash-commands.d.ts +2 -3
  62. package/dist/core/slash-commands.d.ts.map +1 -1
  63. package/dist/core/slash-commands.js.map +1 -1
  64. package/dist/core/source-info.d.ts +18 -0
  65. package/dist/core/source-info.d.ts.map +1 -0
  66. package/dist/core/source-info.js +19 -0
  67. package/dist/core/source-info.js.map +1 -0
  68. package/dist/core/system-prompt.d.ts.map +1 -1
  69. package/dist/core/system-prompt.js +3 -38
  70. package/dist/core/system-prompt.js.map +1 -1
  71. package/dist/core/tools/bash.d.ts +19 -9
  72. package/dist/core/tools/bash.d.ts.map +1 -1
  73. package/dist/core/tools/bash.js +154 -59
  74. package/dist/core/tools/bash.js.map +1 -1
  75. package/dist/core/tools/edit.d.ts +14 -2
  76. package/dist/core/tools/edit.d.ts.map +1 -1
  77. package/dist/core/tools/edit.js +92 -21
  78. package/dist/core/tools/edit.js.map +1 -1
  79. package/dist/core/tools/find.d.ts +11 -4
  80. package/dist/core/tools/find.d.ts.map +1 -1
  81. package/dist/core/tools/find.js +76 -27
  82. package/dist/core/tools/find.js.map +1 -1
  83. package/dist/core/tools/grep.d.ts +15 -4
  84. package/dist/core/tools/grep.d.ts.map +1 -1
  85. package/dist/core/tools/grep.js +83 -29
  86. package/dist/core/tools/grep.js.map +1 -1
  87. package/dist/core/tools/index.d.ts +57 -19
  88. package/dist/core/tools/index.d.ts.map +1 -1
  89. package/dist/core/tools/index.js +50 -26
  90. package/dist/core/tools/index.js.map +1 -1
  91. package/dist/core/tools/ls.d.ts +9 -3
  92. package/dist/core/tools/ls.d.ts.map +1 -1
  93. package/dist/core/tools/ls.js +67 -13
  94. package/dist/core/tools/ls.js.map +1 -1
  95. package/dist/core/tools/read.d.ts +10 -3
  96. package/dist/core/tools/read.d.ts.map +1 -1
  97. package/dist/core/tools/read.js +110 -51
  98. package/dist/core/tools/read.js.map +1 -1
  99. package/dist/core/tools/render-utils.d.ts +21 -0
  100. package/dist/core/tools/render-utils.d.ts.map +1 -0
  101. package/dist/core/tools/render-utils.js +49 -0
  102. package/dist/core/tools/render-utils.js.map +1 -0
  103. package/dist/core/tools/tool-definition-wrapper.d.ts +14 -0
  104. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -0
  105. package/dist/core/tools/tool-definition-wrapper.js +30 -0
  106. package/dist/core/tools/tool-definition-wrapper.js.map +1 -0
  107. package/dist/core/tools/write.d.ts +9 -3
  108. package/dist/core/tools/write.d.ts.map +1 -1
  109. package/dist/core/tools/write.js +161 -27
  110. package/dist/core/tools/write.js.map +1 -1
  111. package/dist/index.d.ts +3 -2
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +2 -1
  114. package/dist/index.js.map +1 -1
  115. package/dist/main.d.ts.map +1 -1
  116. package/dist/main.js +29 -9
  117. package/dist/main.js.map +1 -1
  118. package/dist/modes/interactive/components/tool-execution.d.ts +15 -40
  119. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  120. package/dist/modes/interactive/components/tool-execution.js +120 -670
  121. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  122. package/dist/modes/interactive/interactive-mode.d.ts +4 -11
  123. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  124. package/dist/modes/interactive/interactive-mode.js +144 -92
  125. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  126. package/dist/modes/interactive/theme/theme.d.ts +3 -0
  127. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  128. package/dist/modes/interactive/theme/theme.js +1 -0
  129. package/dist/modes/interactive/theme/theme.js.map +1 -1
  130. package/dist/modes/print-mode.d.ts.map +1 -1
  131. package/dist/modes/print-mode.js +5 -11
  132. package/dist/modes/print-mode.js.map +1 -1
  133. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  134. package/dist/modes/rpc/rpc-mode.js +27 -20
  135. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  136. package/dist/modes/rpc/rpc-types.d.ts +3 -4
  137. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  138. package/dist/modes/rpc/rpc-types.js.map +1 -1
  139. package/dist/utils/image-resize.d.ts +5 -5
  140. package/dist/utils/image-resize.d.ts.map +1 -1
  141. package/dist/utils/image-resize.js +45 -94
  142. package/dist/utils/image-resize.js.map +1 -1
  143. package/docs/extensions.md +72 -32
  144. package/docs/tui.md +2 -2
  145. package/examples/extensions/built-in-tool-renderer.ts +8 -8
  146. package/examples/extensions/commands.ts +3 -3
  147. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  148. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  149. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  150. package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
  151. package/examples/extensions/minimal-mode.ts +14 -14
  152. package/examples/extensions/question.ts +2 -2
  153. package/examples/extensions/questionnaire.ts +2 -2
  154. package/examples/extensions/subagent/index.ts +2 -2
  155. package/examples/extensions/todo.ts +2 -2
  156. package/examples/extensions/truncated-tool.ts +2 -2
  157. package/examples/extensions/with-deps/package-lock.json +2 -2
  158. package/examples/extensions/with-deps/package.json +1 -1
  159. package/examples/sdk/04-skills.ts +8 -2
  160. package/examples/sdk/08-prompt-templates.ts +2 -1
  161. package/examples/sdk/12-full-control.ts +0 -1
  162. package/package.json +4 -4
@@ -20,6 +20,7 @@ import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
20
20
  import { getChangelogPath, getNewEntries, parseChangelog } from "../../utils/changelog.js";
21
21
  import { copyToClipboard } from "../../utils/clipboard.js";
22
22
  import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
23
+ import { parseGitUrl } from "../../utils/git.js";
23
24
  import { ensureTool } from "../../utils/tools-manager.js";
24
25
  import { ArminComponent } from "./components/armin.js";
25
26
  import { AssistantMessageComponent } from "./components/assistant-message.js";
@@ -148,6 +149,48 @@ export class InteractiveMode {
148
149
  setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
149
150
  initTheme(this.settingsManager.getTheme(), true);
150
151
  }
152
+ getAutocompleteSourceTag(sourceInfo) {
153
+ if (!sourceInfo) {
154
+ return undefined;
155
+ }
156
+ const scopePrefix = sourceInfo.scope === "user" ? "u" : sourceInfo.scope === "project" ? "p" : "t";
157
+ const source = sourceInfo.source.trim();
158
+ if (source === "auto" || source === "local" || source === "cli") {
159
+ return scopePrefix;
160
+ }
161
+ if (source.startsWith("npm:")) {
162
+ return `${scopePrefix}:${source}`;
163
+ }
164
+ const gitSource = parseGitUrl(source);
165
+ if (gitSource) {
166
+ const ref = gitSource.ref ? `@${gitSource.ref}` : "";
167
+ return `${scopePrefix}:git:${gitSource.host}/${gitSource.path}${ref}`;
168
+ }
169
+ return scopePrefix;
170
+ }
171
+ prefixAutocompleteDescription(description, sourceInfo) {
172
+ const sourceTag = this.getAutocompleteSourceTag(sourceInfo);
173
+ if (!sourceTag) {
174
+ return description;
175
+ }
176
+ return description ? `[${sourceTag}] ${description}` : `[${sourceTag}]`;
177
+ }
178
+ getBuiltInCommandConflictDiagnostics(extensionRunner) {
179
+ if (!extensionRunner) {
180
+ return [];
181
+ }
182
+ const builtinNames = new Set(BUILTIN_SLASH_COMMANDS.map((command) => command.name));
183
+ return extensionRunner
184
+ .getRegisteredCommands()
185
+ .filter((command) => builtinNames.has(command.name))
186
+ .map((command) => ({
187
+ type: "warning",
188
+ message: command.invocationName === command.name
189
+ ? `Extension command '/${command.name}' conflicts with built-in interactive command. Skipping in autocomplete.`
190
+ : `Extension command '/${command.name}' conflicts with built-in interactive command. Available as '/${command.invocationName}'.`,
191
+ path: command.sourceInfo.path,
192
+ }));
193
+ }
151
194
  setupAutocomplete(fdPath) {
152
195
  // Define commands for autocomplete
153
196
  const slashCommands = BUILTIN_SLASH_COMMANDS.map((command) => ({
@@ -183,13 +226,13 @@ export class InteractiveMode {
183
226
  // Convert prompt templates to SlashCommand format for autocomplete
184
227
  const templateCommands = this.session.promptTemplates.map((cmd) => ({
185
228
  name: cmd.name,
186
- description: cmd.description,
229
+ description: this.prefixAutocompleteDescription(cmd.description, cmd.sourceInfo),
187
230
  }));
188
231
  // Convert extension commands to SlashCommand format
189
232
  const builtinCommandNames = new Set(slashCommands.map((c) => c.name));
190
- const extensionCommands = (this.session.extensionRunner?.getRegisteredCommands(builtinCommandNames) ?? []).map((cmd) => ({
191
- name: cmd.name,
192
- description: cmd.description ?? "(extension command)",
233
+ const extensionCommands = (this.session.extensionRunner?.getRegisteredCommands().filter((cmd) => !builtinCommandNames.has(cmd.name)) ?? []).map((cmd) => ({
234
+ name: cmd.invocationName,
235
+ description: this.prefixAutocompleteDescription(cmd.description, cmd.sourceInfo),
193
236
  getArgumentCompletions: cmd.getArgumentCompletions,
194
237
  }));
195
238
  // Build skill commands from session.skills (if enabled)
@@ -199,7 +242,10 @@ export class InteractiveMode {
199
242
  for (const skill of this.session.resourceLoader.getSkills().skills) {
200
243
  const commandName = `skill:${skill.name}`;
201
244
  this.skillCommands.set(commandName, skill.filePath);
202
- skillCommandList.push({ name: commandName, description: skill.description });
245
+ skillCommandList.push({
246
+ name: commandName,
247
+ description: this.prefixAutocompleteDescription(skill.description, skill.sourceInfo),
248
+ });
203
249
  }
204
250
  }
205
251
  // Setup autocomplete
@@ -527,21 +573,21 @@ export class InteractiveMode {
527
573
  /**
528
574
  * Get a short path relative to the package root for display.
529
575
  */
530
- getShortPath(fullPath, source) {
531
- // For npm packages, show path relative to node_modules/pkg/
576
+ getShortPath(fullPath, sourceInfo) {
577
+ const source = sourceInfo?.source ?? "";
532
578
  const npmMatch = fullPath.match(/node_modules\/(@?[^/]+(?:\/[^/]+)?)\/(.*)/);
533
579
  if (npmMatch && source.startsWith("npm:")) {
534
580
  return npmMatch[2];
535
581
  }
536
- // For git packages, show path relative to repo root
537
582
  const gitMatch = fullPath.match(/git\/[^/]+\/[^/]+\/(.*)/);
538
583
  if (gitMatch && source.startsWith("git:")) {
539
584
  return gitMatch[1];
540
585
  }
541
- // For local/auto, just use formatDisplayPath
542
586
  return this.formatDisplayPath(fullPath);
543
587
  }
544
- getDisplaySourceInfo(source, scope) {
588
+ getDisplaySourceInfo(sourceInfo) {
589
+ const source = sourceInfo?.source ?? "local";
590
+ const scope = sourceInfo?.scope ?? "project";
545
591
  if (source === "local") {
546
592
  if (scope === "user") {
547
593
  return { label: "user", color: "muted" };
@@ -560,7 +606,9 @@ export class InteractiveMode {
560
606
  const scopeLabel = scope === "user" ? "user" : scope === "project" ? "project" : scope === "temporary" ? "temp" : undefined;
561
607
  return { label: source, scopeLabel, color: "accent" };
562
608
  }
563
- getScopeGroup(source, scope) {
609
+ getScopeGroup(sourceInfo) {
610
+ const source = sourceInfo?.source ?? "local";
611
+ const scope = sourceInfo?.scope ?? "project";
564
612
  if (source === "cli" || scope === "temporary")
565
613
  return "path";
566
614
  if (scope === "user")
@@ -569,28 +617,27 @@ export class InteractiveMode {
569
617
  return "project";
570
618
  return "path";
571
619
  }
572
- isPackageSource(source) {
620
+ isPackageSource(sourceInfo) {
621
+ const source = sourceInfo?.source ?? "";
573
622
  return source.startsWith("npm:") || source.startsWith("git:");
574
623
  }
575
- buildScopeGroups(paths, metadata) {
624
+ buildScopeGroups(items) {
576
625
  const groups = {
577
626
  user: { scope: "user", paths: [], packages: new Map() },
578
627
  project: { scope: "project", paths: [], packages: new Map() },
579
628
  path: { scope: "path", paths: [], packages: new Map() },
580
629
  };
581
- for (const p of paths) {
582
- const meta = this.findMetadata(p, metadata);
583
- const source = meta?.source ?? "local";
584
- const scope = meta?.scope ?? "project";
585
- const groupKey = this.getScopeGroup(source, scope);
630
+ for (const item of items) {
631
+ const groupKey = this.getScopeGroup(item.sourceInfo);
586
632
  const group = groups[groupKey];
587
- if (this.isPackageSource(source)) {
633
+ const source = item.sourceInfo?.source ?? "local";
634
+ if (this.isPackageSource(item.sourceInfo)) {
588
635
  const list = group.packages.get(source) ?? [];
589
- list.push(p);
636
+ list.push(item);
590
637
  group.packages.set(source, list);
591
638
  }
592
639
  else {
593
- group.paths.push(p);
640
+ group.paths.push(item);
594
641
  }
595
642
  }
596
643
  return [groups.project, groups.user, groups.path].filter((group) => group.paths.length > 0 || group.packages.size > 0);
@@ -599,57 +646,44 @@ export class InteractiveMode {
599
646
  const lines = [];
600
647
  for (const group of groups) {
601
648
  lines.push(` ${theme.fg("accent", group.scope)}`);
602
- const sortedPaths = [...group.paths].sort((a, b) => a.localeCompare(b));
603
- for (const p of sortedPaths) {
604
- lines.push(theme.fg("dim", ` ${options.formatPath(p)}`));
649
+ const sortedPaths = [...group.paths].sort((a, b) => a.path.localeCompare(b.path));
650
+ for (const item of sortedPaths) {
651
+ lines.push(theme.fg("dim", ` ${options.formatPath(item)}`));
605
652
  }
606
653
  const sortedPackages = Array.from(group.packages.entries()).sort(([a], [b]) => a.localeCompare(b));
607
- for (const [source, paths] of sortedPackages) {
654
+ for (const [source, items] of sortedPackages) {
608
655
  lines.push(` ${theme.fg("mdLink", source)}`);
609
- const sortedPackagePaths = [...paths].sort((a, b) => a.localeCompare(b));
610
- for (const p of sortedPackagePaths) {
611
- lines.push(theme.fg("dim", ` ${options.formatPackagePath(p, source)}`));
656
+ const sortedPackagePaths = [...items].sort((a, b) => a.path.localeCompare(b.path));
657
+ for (const item of sortedPackagePaths) {
658
+ lines.push(theme.fg("dim", ` ${options.formatPackagePath(item, source)}`));
612
659
  }
613
660
  }
614
661
  }
615
662
  return lines.join("\n");
616
663
  }
617
- /**
618
- * Find metadata for a path, checking parent directories if exact match fails.
619
- * Package manager stores metadata for directories, but we display file paths.
620
- */
621
- findMetadata(p, metadata) {
622
- // Try exact match first
623
- const exact = metadata.get(p);
664
+ findSourceInfoForPath(p, sourceInfos) {
665
+ const exact = sourceInfos.get(p);
624
666
  if (exact)
625
667
  return exact;
626
- // Try parent directories (package manager stores directory paths)
627
668
  let current = p;
628
669
  while (current.includes("/")) {
629
670
  current = current.substring(0, current.lastIndexOf("/"));
630
- const parent = metadata.get(current);
671
+ const parent = sourceInfos.get(current);
631
672
  if (parent)
632
673
  return parent;
633
674
  }
634
675
  return undefined;
635
676
  }
636
- /**
637
- * Format a path with its source/scope info from metadata.
638
- */
639
- formatPathWithSource(p, metadata) {
640
- const meta = this.findMetadata(p, metadata);
641
- if (meta) {
642
- const shortPath = this.getShortPath(p, meta.source);
643
- const { label, scopeLabel } = this.getDisplaySourceInfo(meta.source, meta.scope);
677
+ formatPathWithSource(p, sourceInfo) {
678
+ if (sourceInfo) {
679
+ const shortPath = this.getShortPath(p, sourceInfo);
680
+ const { label, scopeLabel } = this.getDisplaySourceInfo(sourceInfo);
644
681
  const labelText = scopeLabel ? `${label} (${scopeLabel})` : label;
645
682
  return `${labelText} ${shortPath}`;
646
683
  }
647
684
  return this.formatDisplayPath(p);
648
685
  }
649
- /**
650
- * Format resource diagnostics with nice collision display using metadata.
651
- */
652
- formatDiagnostics(diagnostics, metadata) {
686
+ formatDiagnostics(diagnostics, sourceInfos) {
653
687
  const lines = [];
654
688
  // Group collision diagnostics by name
655
689
  const collisions = new Map();
@@ -670,21 +704,17 @@ export class InteractiveMode {
670
704
  if (!first)
671
705
  continue;
672
706
  lines.push(theme.fg("warning", ` "${name}" collision:`));
673
- // Show winner
674
- lines.push(theme.fg("dim", ` ${theme.fg("success", "✓")} ${this.formatPathWithSource(first.winnerPath, metadata)}`));
675
- // Show all losers
707
+ lines.push(theme.fg("dim", ` ${theme.fg("success", "✓")} ${this.formatPathWithSource(first.winnerPath, this.findSourceInfoForPath(first.winnerPath, sourceInfos))}`));
676
708
  for (const d of collisionList) {
677
709
  if (d.collision) {
678
- lines.push(theme.fg("dim", ` ${theme.fg("warning", "✗")} ${this.formatPathWithSource(d.collision.loserPath, metadata)} (skipped)`));
710
+ lines.push(theme.fg("dim", ` ${theme.fg("warning", "✗")} ${this.formatPathWithSource(d.collision.loserPath, this.findSourceInfoForPath(d.collision.loserPath, sourceInfos))} (skipped)`));
679
711
  }
680
712
  }
681
713
  }
682
- // Format other diagnostics (skill name collisions, parse errors, etc.)
683
714
  for (const d of otherDiagnostics) {
684
715
  if (d.path) {
685
- // Use metadata-aware formatting for paths
686
- const sourceInfo = this.formatPathWithSource(d.path, metadata);
687
- lines.push(theme.fg(d.type === "error" ? "error" : "warning", ` ${sourceInfo}`));
716
+ const formattedPath = this.formatPathWithSource(d.path, this.findSourceInfoForPath(d.path, sourceInfos));
717
+ lines.push(theme.fg(d.type === "error" ? "error" : "warning", ` ${formattedPath}`));
688
718
  lines.push(theme.fg(d.type === "error" ? "error" : "warning", ` ${d.message}`));
689
719
  }
690
720
  else {
@@ -699,11 +729,36 @@ export class InteractiveMode {
699
729
  if (!showListing && !showDiagnostics) {
700
730
  return;
701
731
  }
702
- const metadata = this.session.resourceLoader.getPathMetadata();
703
732
  const sectionHeader = (name, color = "mdHeading") => theme.fg(color, `[${name}]`);
704
733
  const skillsResult = this.session.resourceLoader.getSkills();
705
734
  const promptsResult = this.session.resourceLoader.getPrompts();
706
735
  const themesResult = this.session.resourceLoader.getThemes();
736
+ const extensions = options?.extensions ??
737
+ this.session.resourceLoader.getExtensions().extensions.map((extension) => ({
738
+ path: extension.path,
739
+ sourceInfo: extension.sourceInfo,
740
+ }));
741
+ const sourceInfos = new Map();
742
+ for (const extension of extensions) {
743
+ if (extension.sourceInfo) {
744
+ sourceInfos.set(extension.path, extension.sourceInfo);
745
+ }
746
+ }
747
+ for (const skill of skillsResult.skills) {
748
+ if (skill.sourceInfo) {
749
+ sourceInfos.set(skill.filePath, skill.sourceInfo);
750
+ }
751
+ }
752
+ for (const prompt of promptsResult.prompts) {
753
+ if (prompt.sourceInfo) {
754
+ sourceInfos.set(prompt.filePath, prompt.sourceInfo);
755
+ }
756
+ }
757
+ for (const loadedTheme of themesResult.themes) {
758
+ if (loadedTheme.sourcePath && loadedTheme.sourceInfo) {
759
+ sourceInfos.set(loadedTheme.sourcePath, loadedTheme.sourceInfo);
760
+ }
761
+ }
707
762
  if (showListing) {
708
763
  const contextFiles = this.session.resourceLoader.getAgentsFiles().agentsFiles;
709
764
  if (contextFiles.length > 0) {
@@ -716,39 +771,36 @@ export class InteractiveMode {
716
771
  }
717
772
  const skills = skillsResult.skills;
718
773
  if (skills.length > 0) {
719
- const skillPaths = skills.map((s) => s.filePath);
720
- const groups = this.buildScopeGroups(skillPaths, metadata);
774
+ const groups = this.buildScopeGroups(skills.map((skill) => ({ path: skill.filePath, sourceInfo: skill.sourceInfo })));
721
775
  const skillList = this.formatScopeGroups(groups, {
722
- formatPath: (p) => this.formatDisplayPath(p),
723
- formatPackagePath: (p, source) => this.getShortPath(p, source),
776
+ formatPath: (item) => this.formatDisplayPath(item.path),
777
+ formatPackagePath: (item) => this.getShortPath(item.path, item.sourceInfo),
724
778
  });
725
779
  this.chatContainer.addChild(new Text(`${sectionHeader("Skills")}\n${skillList}`, 0, 0));
726
780
  this.chatContainer.addChild(new Spacer(1));
727
781
  }
728
782
  const templates = this.session.promptTemplates;
729
783
  if (templates.length > 0) {
730
- const templatePaths = templates.map((t) => t.filePath);
731
- const groups = this.buildScopeGroups(templatePaths, metadata);
784
+ const groups = this.buildScopeGroups(templates.map((template) => ({ path: template.filePath, sourceInfo: template.sourceInfo })));
732
785
  const templateByPath = new Map(templates.map((t) => [t.filePath, t]));
733
786
  const templateList = this.formatScopeGroups(groups, {
734
- formatPath: (p) => {
735
- const template = templateByPath.get(p);
736
- return template ? `/${template.name}` : this.formatDisplayPath(p);
787
+ formatPath: (item) => {
788
+ const template = templateByPath.get(item.path);
789
+ return template ? `/${template.name}` : this.formatDisplayPath(item.path);
737
790
  },
738
- formatPackagePath: (p) => {
739
- const template = templateByPath.get(p);
740
- return template ? `/${template.name}` : this.formatDisplayPath(p);
791
+ formatPackagePath: (item) => {
792
+ const template = templateByPath.get(item.path);
793
+ return template ? `/${template.name}` : this.formatDisplayPath(item.path);
741
794
  },
742
795
  });
743
796
  this.chatContainer.addChild(new Text(`${sectionHeader("Prompts")}\n${templateList}`, 0, 0));
744
797
  this.chatContainer.addChild(new Spacer(1));
745
798
  }
746
- const extensionPaths = options?.extensionPaths ?? [];
747
- if (extensionPaths.length > 0) {
748
- const groups = this.buildScopeGroups(extensionPaths, metadata);
799
+ if (extensions.length > 0) {
800
+ const groups = this.buildScopeGroups(extensions);
749
801
  const extList = this.formatScopeGroups(groups, {
750
- formatPath: (p) => this.formatDisplayPath(p),
751
- formatPackagePath: (p, source) => this.getShortPath(p, source),
802
+ formatPath: (item) => this.formatDisplayPath(item.path),
803
+ formatPackagePath: (item) => this.getShortPath(item.path, item.sourceInfo),
752
804
  });
753
805
  this.chatContainer.addChild(new Text(`${sectionHeader("Extensions", "mdHeading")}\n${extList}`, 0, 0));
754
806
  this.chatContainer.addChild(new Spacer(1));
@@ -757,11 +809,13 @@ export class InteractiveMode {
757
809
  const loadedThemes = themesResult.themes;
758
810
  const customThemes = loadedThemes.filter((t) => t.sourcePath);
759
811
  if (customThemes.length > 0) {
760
- const themePaths = customThemes.map((t) => t.sourcePath);
761
- const groups = this.buildScopeGroups(themePaths, metadata);
812
+ const groups = this.buildScopeGroups(customThemes.map((loadedTheme) => ({
813
+ path: loadedTheme.sourcePath,
814
+ sourceInfo: loadedTheme.sourceInfo,
815
+ })));
762
816
  const themeList = this.formatScopeGroups(groups, {
763
- formatPath: (p) => this.formatDisplayPath(p),
764
- formatPackagePath: (p, source) => this.getShortPath(p, source),
817
+ formatPath: (item) => this.formatDisplayPath(item.path),
818
+ formatPackagePath: (item) => this.getShortPath(item.path, item.sourceInfo),
765
819
  });
766
820
  this.chatContainer.addChild(new Text(`${sectionHeader("Themes")}\n${themeList}`, 0, 0));
767
821
  this.chatContainer.addChild(new Spacer(1));
@@ -770,13 +824,13 @@ export class InteractiveMode {
770
824
  if (showDiagnostics) {
771
825
  const skillDiagnostics = skillsResult.diagnostics;
772
826
  if (skillDiagnostics.length > 0) {
773
- const warningLines = this.formatDiagnostics(skillDiagnostics, metadata);
827
+ const warningLines = this.formatDiagnostics(skillDiagnostics, sourceInfos);
774
828
  this.chatContainer.addChild(new Text(`${theme.fg("warning", "[Skill conflicts]")}\n${warningLines}`, 0, 0));
775
829
  this.chatContainer.addChild(new Spacer(1));
776
830
  }
777
831
  const promptDiagnostics = promptsResult.diagnostics;
778
832
  if (promptDiagnostics.length > 0) {
779
- const warningLines = this.formatDiagnostics(promptDiagnostics, metadata);
833
+ const warningLines = this.formatDiagnostics(promptDiagnostics, sourceInfos);
780
834
  this.chatContainer.addChild(new Text(`${theme.fg("warning", "[Prompt conflicts]")}\n${warningLines}`, 0, 0));
781
835
  this.chatContainer.addChild(new Spacer(1));
782
836
  }
@@ -789,16 +843,17 @@ export class InteractiveMode {
789
843
  }
790
844
  const commandDiagnostics = this.session.extensionRunner?.getCommandDiagnostics() ?? [];
791
845
  extensionDiagnostics.push(...commandDiagnostics);
846
+ extensionDiagnostics.push(...this.getBuiltInCommandConflictDiagnostics(this.session.extensionRunner));
792
847
  const shortcutDiagnostics = this.session.extensionRunner?.getShortcutDiagnostics() ?? [];
793
848
  extensionDiagnostics.push(...shortcutDiagnostics);
794
849
  if (extensionDiagnostics.length > 0) {
795
- const warningLines = this.formatDiagnostics(extensionDiagnostics, metadata);
850
+ const warningLines = this.formatDiagnostics(extensionDiagnostics, sourceInfos);
796
851
  this.chatContainer.addChild(new Text(`${theme.fg("warning", "[Extension issues]")}\n${warningLines}`, 0, 0));
797
852
  this.chatContainer.addChild(new Spacer(1));
798
853
  }
799
854
  const themeDiagnostics = themesResult.diagnostics;
800
855
  if (themeDiagnostics.length > 0) {
801
- const warningLines = this.formatDiagnostics(themeDiagnostics, metadata);
856
+ const warningLines = this.formatDiagnostics(themeDiagnostics, sourceInfos);
802
857
  this.chatContainer.addChild(new Text(`${theme.fg("warning", "[Theme conflicts]")}\n${warningLines}`, 0, 0));
803
858
  this.chatContainer.addChild(new Spacer(1));
804
859
  }
@@ -887,19 +942,17 @@ export class InteractiveMode {
887
942
  this.setupAutocomplete(this.fdPath);
888
943
  const extensionRunner = this.session.extensionRunner;
889
944
  if (!extensionRunner) {
890
- this.showLoadedResources({ extensionPaths: [], force: false });
945
+ this.showLoadedResources({ extensions: [], force: false });
891
946
  return;
892
947
  }
893
948
  this.setupExtensionShortcuts(extensionRunner);
894
- this.showLoadedResources({ extensionPaths: extensionRunner.getExtensionPaths(), force: false });
949
+ this.showLoadedResources({ force: false });
895
950
  }
896
951
  /**
897
952
  * Get a registered tool definition by name (for custom rendering).
898
953
  */
899
954
  getRegisteredToolDefinition(toolName) {
900
- const tools = this.session.extensionRunner?.getAllRegisteredTools() ?? [];
901
- const registeredTool = tools.find((t) => t.definition.name === toolName);
902
- return registeredTool?.definition;
955
+ return this.session.getToolDefinition(toolName);
903
956
  }
904
957
  /**
905
958
  * Set up keyboard shortcuts registered by extensions.
@@ -1789,7 +1842,7 @@ export class InteractiveMode {
1789
1842
  for (const content of this.streamingMessage.content) {
1790
1843
  if (content.type === "toolCall") {
1791
1844
  if (!this.pendingTools.has(content.id)) {
1792
- const component = new ToolExecutionComponent(content.name, content.arguments, {
1845
+ const component = new ToolExecutionComponent(content.name, content.id, content.arguments, {
1793
1846
  showImages: this.settingsManager.getShowImages(),
1794
1847
  }, this.getRegisteredToolDefinition(content.name), this.ui);
1795
1848
  component.setExpanded(this.toolOutputExpanded);
@@ -1849,7 +1902,7 @@ export class InteractiveMode {
1849
1902
  case "tool_execution_start": {
1850
1903
  let component = this.pendingTools.get(event.toolCallId);
1851
1904
  if (!component) {
1852
- component = new ToolExecutionComponent(event.toolName, event.args, {
1905
+ component = new ToolExecutionComponent(event.toolName, event.toolCallId, event.args, {
1853
1906
  showImages: this.settingsManager.getShowImages(),
1854
1907
  }, this.getRegisteredToolDefinition(event.toolName), this.ui);
1855
1908
  component.setExpanded(this.toolOutputExpanded);
@@ -2105,7 +2158,7 @@ export class InteractiveMode {
2105
2158
  // Render tool call components
2106
2159
  for (const content of message.content) {
2107
2160
  if (content.type === "toolCall") {
2108
- const component = new ToolExecutionComponent(content.name, content.arguments, { showImages: this.settingsManager.getShowImages() }, this.getRegisteredToolDefinition(content.name), this.ui);
2161
+ const component = new ToolExecutionComponent(content.name, content.id, content.arguments, { showImages: this.settingsManager.getShowImages() }, this.getRegisteredToolDefinition(content.name), this.ui);
2109
2162
  component.setExpanded(this.toolOutputExpanded);
2110
2163
  this.chatContainer.addChild(component);
2111
2164
  if (message.stopReason === "aborted" || message.stopReason === "error") {
@@ -3261,7 +3314,6 @@ export class InteractiveMode {
3261
3314
  this.rebuildChatFromMessages();
3262
3315
  dismissLoader(this.editor);
3263
3316
  this.showLoadedResources({
3264
- extensionPaths: runner?.getExtensionPaths() ?? [],
3265
3317
  force: false,
3266
3318
  showDiagnosticsWhenQuiet: true,
3267
3319
  });