@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
@@ -10,6 +10,7 @@ import { DefaultPackageManager } from "./package-manager.js";
10
10
  import { loadPromptTemplates } from "./prompt-templates.js";
11
11
  import { SettingsManager } from "./settings-manager.js";
12
12
  import { loadSkills } from "./skills.js";
13
+ import { createSourceInfo } from "./source-info.js";
13
14
  function resolvePromptInput(input, description) {
14
15
  if (!input) {
15
16
  return undefined;
@@ -110,8 +111,10 @@ export class DefaultResourceLoader {
110
111
  this.themeDiagnostics = [];
111
112
  this.agentsFiles = [];
112
113
  this.appendSystemPrompt = [];
113
- this.pathMetadata = new Map();
114
114
  this.lastSkillPaths = [];
115
+ this.extensionSkillSourceInfos = new Map();
116
+ this.extensionPromptSourceInfos = new Map();
117
+ this.extensionThemeSourceInfos = new Map();
115
118
  this.lastPromptPaths = [];
116
119
  this.lastThemePaths = [];
117
120
  }
@@ -136,24 +139,30 @@ export class DefaultResourceLoader {
136
139
  getAppendSystemPrompt() {
137
140
  return this.appendSystemPrompt;
138
141
  }
139
- getPathMetadata() {
140
- return this.pathMetadata;
141
- }
142
142
  extendResources(paths) {
143
143
  const skillPaths = this.normalizeExtensionPaths(paths.skillPaths ?? []);
144
144
  const promptPaths = this.normalizeExtensionPaths(paths.promptPaths ?? []);
145
145
  const themePaths = this.normalizeExtensionPaths(paths.themePaths ?? []);
146
+ for (const entry of skillPaths) {
147
+ this.extensionSkillSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));
148
+ }
149
+ for (const entry of promptPaths) {
150
+ this.extensionPromptSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));
151
+ }
152
+ for (const entry of themePaths) {
153
+ this.extensionThemeSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));
154
+ }
146
155
  if (skillPaths.length > 0) {
147
156
  this.lastSkillPaths = this.mergePaths(this.lastSkillPaths, skillPaths.map((entry) => entry.path));
148
- this.updateSkillsFromPaths(this.lastSkillPaths, skillPaths);
157
+ this.updateSkillsFromPaths(this.lastSkillPaths);
149
158
  }
150
159
  if (promptPaths.length > 0) {
151
160
  this.lastPromptPaths = this.mergePaths(this.lastPromptPaths, promptPaths.map((entry) => entry.path));
152
- this.updatePromptsFromPaths(this.lastPromptPaths, promptPaths);
161
+ this.updatePromptsFromPaths(this.lastPromptPaths);
153
162
  }
154
163
  if (themePaths.length > 0) {
155
164
  this.lastThemePaths = this.mergePaths(this.lastThemePaths, themePaths.map((entry) => entry.path));
156
- this.updateThemesFromPaths(this.lastThemePaths, themePaths);
165
+ this.updateThemesFromPaths(this.lastThemePaths);
157
166
  }
158
167
  }
159
168
  async reload() {
@@ -161,18 +170,20 @@ export class DefaultResourceLoader {
161
170
  const cliExtensionPaths = await this.packageManager.resolveExtensionSources(this.additionalExtensionPaths, {
162
171
  temporary: true,
163
172
  });
173
+ const metadataByPath = new Map();
174
+ this.extensionSkillSourceInfos = new Map();
175
+ this.extensionPromptSourceInfos = new Map();
176
+ this.extensionThemeSourceInfos = new Map();
164
177
  // Helper to extract enabled paths and store metadata
165
178
  const getEnabledResources = (resources) => {
166
179
  for (const r of resources) {
167
- if (!this.pathMetadata.has(r.path)) {
168
- this.pathMetadata.set(r.path, r.metadata);
180
+ if (!metadataByPath.has(r.path)) {
181
+ metadataByPath.set(r.path, r.metadata);
169
182
  }
170
183
  }
171
184
  return resources.filter((r) => r.enabled);
172
185
  };
173
186
  const getEnabledPaths = (resources) => getEnabledResources(resources).map((r) => r.path);
174
- // Store metadata and get enabled paths
175
- this.pathMetadata = new Map();
176
187
  const enabledExtensions = getEnabledPaths(resolvedPaths.extensions);
177
188
  const enabledSkillResources = getEnabledResources(resolvedPaths.skills);
178
189
  const enabledPrompts = getEnabledPaths(resolvedPaths.prompts);
@@ -192,8 +203,8 @@ export class DefaultResourceLoader {
192
203
  }
193
204
  const skillFile = join(resource.path, "SKILL.md");
194
205
  if (existsSync(skillFile)) {
195
- if (!this.pathMetadata.has(skillFile)) {
196
- this.pathMetadata.set(skillFile, resource.metadata);
206
+ if (!metadataByPath.has(skillFile)) {
207
+ metadataByPath.set(skillFile, resource.metadata);
197
208
  }
198
209
  return skillFile;
199
210
  }
@@ -202,13 +213,13 @@ export class DefaultResourceLoader {
202
213
  const enabledSkills = enabledSkillResources.map(mapSkillPath);
203
214
  // Add CLI paths metadata
204
215
  for (const r of cliExtensionPaths.extensions) {
205
- if (!this.pathMetadata.has(r.path)) {
206
- this.pathMetadata.set(r.path, { source: "cli", scope: "temporary", origin: "top-level" });
216
+ if (!metadataByPath.has(r.path)) {
217
+ metadataByPath.set(r.path, { source: "cli", scope: "temporary", origin: "top-level" });
207
218
  }
208
219
  }
209
220
  for (const r of cliExtensionPaths.skills) {
210
- if (!this.pathMetadata.has(r.path)) {
211
- this.pathMetadata.set(r.path, { source: "cli", scope: "temporary", origin: "top-level" });
221
+ if (!metadataByPath.has(r.path)) {
222
+ metadataByPath.set(r.path, { source: "cli", scope: "temporary", origin: "top-level" });
212
223
  }
213
224
  }
214
225
  const cliEnabledExtensions = getEnabledPaths(cliExtensionPaths.extensions);
@@ -229,24 +240,22 @@ export class DefaultResourceLoader {
229
240
  extensionsResult.errors.push({ path: conflict.path, error: conflict.message });
230
241
  }
231
242
  this.extensionsResult = this.extensionsOverride ? this.extensionsOverride(extensionsResult) : extensionsResult;
243
+ this.applyExtensionSourceInfo(this.extensionsResult.extensions, metadataByPath);
232
244
  const skillPaths = this.noSkills
233
245
  ? this.mergePaths(cliEnabledSkills, this.additionalSkillPaths)
234
246
  : this.mergePaths([...enabledSkills, ...cliEnabledSkills], this.additionalSkillPaths);
235
247
  this.lastSkillPaths = skillPaths;
236
- this.updateSkillsFromPaths(skillPaths);
248
+ this.updateSkillsFromPaths(skillPaths, metadataByPath);
237
249
  const promptPaths = this.noPromptTemplates
238
250
  ? this.mergePaths(cliEnabledPrompts, this.additionalPromptTemplatePaths)
239
251
  : this.mergePaths([...enabledPrompts, ...cliEnabledPrompts], this.additionalPromptTemplatePaths);
240
252
  this.lastPromptPaths = promptPaths;
241
- this.updatePromptsFromPaths(promptPaths);
253
+ this.updatePromptsFromPaths(promptPaths, metadataByPath);
242
254
  const themePaths = this.noThemes
243
255
  ? this.mergePaths(cliEnabledThemes, this.additionalThemePaths)
244
256
  : this.mergePaths([...enabledThemes, ...cliEnabledThemes], this.additionalThemePaths);
245
257
  this.lastThemePaths = themePaths;
246
- this.updateThemesFromPaths(themePaths);
247
- for (const extension of this.extensionsResult.extensions) {
248
- this.addDefaultMetadataForPath(extension.path);
249
- }
258
+ this.updateThemesFromPaths(themePaths, metadataByPath);
250
259
  const agentsFiles = { agentsFiles: loadProjectContextFiles({ cwd: this.cwd, agentDir: this.agentDir }) };
251
260
  const resolvedAgentsFiles = this.agentsFilesOverride ? this.agentsFilesOverride(agentsFiles) : agentsFiles;
252
261
  this.agentsFiles = resolvedAgentsFiles.agentsFiles;
@@ -265,7 +274,7 @@ export class DefaultResourceLoader {
265
274
  metadata: entry.metadata,
266
275
  }));
267
276
  }
268
- updateSkillsFromPaths(skillPaths, extensionPaths = []) {
277
+ updateSkillsFromPaths(skillPaths, metadataByPath) {
269
278
  let skillsResult;
270
279
  if (this.noSkills && skillPaths.length === 0) {
271
280
  skillsResult = { skills: [], diagnostics: [] };
@@ -279,14 +288,15 @@ export class DefaultResourceLoader {
279
288
  });
280
289
  }
281
290
  const resolvedSkills = this.skillsOverride ? this.skillsOverride(skillsResult) : skillsResult;
282
- this.skills = resolvedSkills.skills;
291
+ this.skills = resolvedSkills.skills.map((skill) => ({
292
+ ...skill,
293
+ sourceInfo: this.findSourceInfoForPath(skill.filePath, this.extensionSkillSourceInfos, metadataByPath) ??
294
+ skill.sourceInfo ??
295
+ this.getDefaultSourceInfoForPath(skill.filePath),
296
+ }));
283
297
  this.skillDiagnostics = resolvedSkills.diagnostics;
284
- this.applyExtensionMetadata(extensionPaths, this.skills.map((skill) => skill.filePath));
285
- for (const skill of this.skills) {
286
- this.addDefaultMetadataForPath(skill.filePath);
287
- }
288
298
  }
289
- updatePromptsFromPaths(promptPaths, extensionPaths = []) {
299
+ updatePromptsFromPaths(promptPaths, metadataByPath) {
290
300
  let promptsResult;
291
301
  if (this.noPromptTemplates && promptPaths.length === 0) {
292
302
  promptsResult = { prompts: [], diagnostics: [] };
@@ -301,14 +311,15 @@ export class DefaultResourceLoader {
301
311
  promptsResult = this.dedupePrompts(allPrompts);
302
312
  }
303
313
  const resolvedPrompts = this.promptsOverride ? this.promptsOverride(promptsResult) : promptsResult;
304
- this.prompts = resolvedPrompts.prompts;
314
+ this.prompts = resolvedPrompts.prompts.map((prompt) => ({
315
+ ...prompt,
316
+ sourceInfo: this.findSourceInfoForPath(prompt.filePath, this.extensionPromptSourceInfos, metadataByPath) ??
317
+ prompt.sourceInfo ??
318
+ this.getDefaultSourceInfoForPath(prompt.filePath),
319
+ }));
305
320
  this.promptDiagnostics = resolvedPrompts.diagnostics;
306
- this.applyExtensionMetadata(extensionPaths, this.prompts.map((prompt) => prompt.filePath));
307
- for (const prompt of this.prompts) {
308
- this.addDefaultMetadataForPath(prompt.filePath);
309
- }
310
321
  }
311
- updateThemesFromPaths(themePaths, extensionPaths = []) {
322
+ updateThemesFromPaths(themePaths, metadataByPath) {
312
323
  let themesResult;
313
324
  if (this.noThemes && themePaths.length === 0) {
314
325
  themesResult = { themes: [], diagnostics: [] };
@@ -319,39 +330,101 @@ export class DefaultResourceLoader {
319
330
  themesResult = { themes: deduped.themes, diagnostics: [...loaded.diagnostics, ...deduped.diagnostics] };
320
331
  }
321
332
  const resolvedThemes = this.themesOverride ? this.themesOverride(themesResult) : themesResult;
322
- this.themes = resolvedThemes.themes;
333
+ this.themes = resolvedThemes.themes.map((theme) => {
334
+ const sourcePath = theme.sourcePath;
335
+ theme.sourceInfo = sourcePath
336
+ ? (this.findSourceInfoForPath(sourcePath, this.extensionThemeSourceInfos, metadataByPath) ??
337
+ theme.sourceInfo ??
338
+ this.getDefaultSourceInfoForPath(sourcePath))
339
+ : theme.sourceInfo;
340
+ return theme;
341
+ });
323
342
  this.themeDiagnostics = resolvedThemes.diagnostics;
324
- const themePathsWithSource = this.themes.flatMap((theme) => (theme.sourcePath ? [theme.sourcePath] : []));
325
- this.applyExtensionMetadata(extensionPaths, themePathsWithSource);
326
- for (const theme of this.themes) {
327
- if (theme.sourcePath) {
328
- this.addDefaultMetadataForPath(theme.sourcePath);
343
+ }
344
+ applyExtensionSourceInfo(extensions, metadataByPath) {
345
+ for (const extension of extensions) {
346
+ extension.sourceInfo =
347
+ this.findSourceInfoForPath(extension.path, undefined, metadataByPath) ??
348
+ this.getDefaultSourceInfoForPath(extension.path);
349
+ for (const command of extension.commands.values()) {
350
+ command.sourceInfo = extension.sourceInfo;
351
+ }
352
+ for (const tool of extension.tools.values()) {
353
+ tool.sourceInfo = extension.sourceInfo;
329
354
  }
330
355
  }
331
356
  }
332
- applyExtensionMetadata(extensionPaths, resourcePaths) {
333
- if (extensionPaths.length === 0) {
334
- return;
357
+ findSourceInfoForPath(resourcePath, extraSourceInfos, metadataByPath) {
358
+ if (!resourcePath) {
359
+ return undefined;
335
360
  }
336
- const normalized = extensionPaths.map((entry) => ({
337
- path: resolve(entry.path),
338
- metadata: entry.metadata,
339
- }));
340
- for (const entry of normalized) {
341
- if (!this.pathMetadata.has(entry.path)) {
342
- this.pathMetadata.set(entry.path, entry.metadata);
361
+ if (resourcePath.startsWith("<")) {
362
+ return this.getDefaultSourceInfoForPath(resourcePath);
363
+ }
364
+ const normalizedResourcePath = resolve(resourcePath);
365
+ if (extraSourceInfos) {
366
+ for (const [sourcePath, sourceInfo] of extraSourceInfos.entries()) {
367
+ const normalizedSourcePath = resolve(sourcePath);
368
+ if (normalizedResourcePath === normalizedSourcePath ||
369
+ normalizedResourcePath.startsWith(`${normalizedSourcePath}${sep}`)) {
370
+ return { ...sourceInfo, path: resourcePath };
371
+ }
343
372
  }
344
373
  }
345
- for (const resourcePath of resourcePaths) {
346
- const normalizedResourcePath = resolve(resourcePath);
347
- if (this.pathMetadata.has(normalizedResourcePath) || this.pathMetadata.has(resourcePath)) {
348
- continue;
374
+ if (metadataByPath) {
375
+ const exact = metadataByPath.get(normalizedResourcePath) ?? metadataByPath.get(resourcePath);
376
+ if (exact) {
377
+ return createSourceInfo(resourcePath, exact);
378
+ }
379
+ for (const [sourcePath, metadata] of metadataByPath.entries()) {
380
+ const normalizedSourcePath = resolve(sourcePath);
381
+ if (normalizedResourcePath === normalizedSourcePath ||
382
+ normalizedResourcePath.startsWith(`${normalizedSourcePath}${sep}`)) {
383
+ return createSourceInfo(resourcePath, metadata);
384
+ }
385
+ }
386
+ }
387
+ return undefined;
388
+ }
389
+ getDefaultSourceInfoForPath(filePath) {
390
+ if (filePath.startsWith("<") && filePath.endsWith(">")) {
391
+ return {
392
+ path: filePath,
393
+ source: filePath.slice(1, -1).split(":")[0] || "temporary",
394
+ scope: "temporary",
395
+ origin: "top-level",
396
+ };
397
+ }
398
+ const normalizedPath = resolve(filePath);
399
+ const agentRoots = [
400
+ join(this.agentDir, "skills"),
401
+ join(this.agentDir, "prompts"),
402
+ join(this.agentDir, "themes"),
403
+ join(this.agentDir, "extensions"),
404
+ ];
405
+ const projectRoots = [
406
+ join(this.cwd, CONFIG_DIR_NAME, "skills"),
407
+ join(this.cwd, CONFIG_DIR_NAME, "prompts"),
408
+ join(this.cwd, CONFIG_DIR_NAME, "themes"),
409
+ join(this.cwd, CONFIG_DIR_NAME, "extensions"),
410
+ ];
411
+ for (const root of agentRoots) {
412
+ if (this.isUnderPath(normalizedPath, root)) {
413
+ return { path: filePath, source: "local", scope: "user", origin: "top-level", baseDir: root };
349
414
  }
350
- const match = normalized.find((entry) => normalizedResourcePath === entry.path || normalizedResourcePath.startsWith(`${entry.path}${sep}`));
351
- if (match) {
352
- this.pathMetadata.set(normalizedResourcePath, match.metadata);
415
+ }
416
+ for (const root of projectRoots) {
417
+ if (this.isUnderPath(normalizedPath, root)) {
418
+ return { path: filePath, source: "local", scope: "project", origin: "top-level", baseDir: root };
353
419
  }
354
420
  }
421
+ return {
422
+ path: filePath,
423
+ source: "local",
424
+ scope: "temporary",
425
+ origin: "top-level",
426
+ baseDir: statSync(normalizedPath).isDirectory() ? normalizedPath : resolve(normalizedPath, ".."),
427
+ };
355
428
  }
356
429
  mergePaths(primary, additional) {
357
430
  const merged = [];
@@ -539,39 +612,6 @@ export class DefaultResourceLoader {
539
612
  }
540
613
  return undefined;
541
614
  }
542
- addDefaultMetadataForPath(filePath) {
543
- if (!filePath || filePath.startsWith("<")) {
544
- return;
545
- }
546
- const normalizedPath = resolve(filePath);
547
- if (this.pathMetadata.has(normalizedPath) || this.pathMetadata.has(filePath)) {
548
- return;
549
- }
550
- const agentRoots = [
551
- join(this.agentDir, "skills"),
552
- join(this.agentDir, "prompts"),
553
- join(this.agentDir, "themes"),
554
- join(this.agentDir, "extensions"),
555
- ];
556
- const projectRoots = [
557
- join(this.cwd, CONFIG_DIR_NAME, "skills"),
558
- join(this.cwd, CONFIG_DIR_NAME, "prompts"),
559
- join(this.cwd, CONFIG_DIR_NAME, "themes"),
560
- join(this.cwd, CONFIG_DIR_NAME, "extensions"),
561
- ];
562
- for (const root of agentRoots) {
563
- if (this.isUnderPath(normalizedPath, root)) {
564
- this.pathMetadata.set(normalizedPath, { source: "local", scope: "user", origin: "top-level" });
565
- return;
566
- }
567
- }
568
- for (const root of projectRoots) {
569
- if (this.isUnderPath(normalizedPath, root)) {
570
- this.pathMetadata.set(normalizedPath, { source: "local", scope: "project", origin: "top-level" });
571
- return;
572
- }
573
- }
574
- }
575
615
  isUnderPath(target, root) {
576
616
  const normalizedRoot = resolve(root);
577
617
  if (target === normalizedRoot) {
@@ -582,9 +622,8 @@ export class DefaultResourceLoader {
582
622
  }
583
623
  detectExtensionConflicts(extensions) {
584
624
  const conflicts = [];
585
- // Track which extension registered each tool, command, and flag
625
+ // Track which extension registered each tool and flag
586
626
  const toolOwners = new Map();
587
- const commandOwners = new Map();
588
627
  const flagOwners = new Map();
589
628
  for (const ext of extensions) {
590
629
  // Check tools
@@ -600,19 +639,6 @@ export class DefaultResourceLoader {
600
639
  toolOwners.set(toolName, ext.path);
601
640
  }
602
641
  }
603
- // Check commands
604
- for (const commandName of ext.commands.keys()) {
605
- const existingOwner = commandOwners.get(commandName);
606
- if (existingOwner && existingOwner !== ext.path) {
607
- conflicts.push({
608
- path: ext.path,
609
- message: `Command "/${commandName}" conflicts with ${existingOwner}`,
610
- });
611
- }
612
- else {
613
- commandOwners.set(commandName, ext.path);
614
- }
615
- }
616
642
  // Check flags
617
643
  for (const flagName of ext.flags.keys()) {
618
644
  const existingOwner = flagOwners.get(flagName);