@hyperspaceng/neural-coding-agent 0.61.6 → 0.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +136 -108
  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 +151 -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 +162 -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 +126 -679
  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 +14 -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;
@@ -106,8 +107,10 @@ export class DefaultResourceLoader {
106
107
  agentsFiles;
107
108
  systemPrompt;
108
109
  appendSystemPrompt;
109
- pathMetadata;
110
110
  lastSkillPaths;
111
+ extensionSkillSourceInfos;
112
+ extensionPromptSourceInfos;
113
+ extensionThemeSourceInfos;
111
114
  lastPromptPaths;
112
115
  lastThemePaths;
113
116
  constructor(options) {
@@ -147,8 +150,10 @@ export class DefaultResourceLoader {
147
150
  this.themeDiagnostics = [];
148
151
  this.agentsFiles = [];
149
152
  this.appendSystemPrompt = [];
150
- this.pathMetadata = new Map();
151
153
  this.lastSkillPaths = [];
154
+ this.extensionSkillSourceInfos = new Map();
155
+ this.extensionPromptSourceInfos = new Map();
156
+ this.extensionThemeSourceInfos = new Map();
152
157
  this.lastPromptPaths = [];
153
158
  this.lastThemePaths = [];
154
159
  }
@@ -173,24 +178,30 @@ export class DefaultResourceLoader {
173
178
  getAppendSystemPrompt() {
174
179
  return this.appendSystemPrompt;
175
180
  }
176
- getPathMetadata() {
177
- return this.pathMetadata;
178
- }
179
181
  extendResources(paths) {
180
182
  const skillPaths = this.normalizeExtensionPaths(paths.skillPaths ?? []);
181
183
  const promptPaths = this.normalizeExtensionPaths(paths.promptPaths ?? []);
182
184
  const themePaths = this.normalizeExtensionPaths(paths.themePaths ?? []);
185
+ for (const entry of skillPaths) {
186
+ this.extensionSkillSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));
187
+ }
188
+ for (const entry of promptPaths) {
189
+ this.extensionPromptSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));
190
+ }
191
+ for (const entry of themePaths) {
192
+ this.extensionThemeSourceInfos.set(entry.path, createSourceInfo(entry.path, entry.metadata));
193
+ }
183
194
  if (skillPaths.length > 0) {
184
195
  this.lastSkillPaths = this.mergePaths(this.lastSkillPaths, skillPaths.map((entry) => entry.path));
185
- this.updateSkillsFromPaths(this.lastSkillPaths, skillPaths);
196
+ this.updateSkillsFromPaths(this.lastSkillPaths);
186
197
  }
187
198
  if (promptPaths.length > 0) {
188
199
  this.lastPromptPaths = this.mergePaths(this.lastPromptPaths, promptPaths.map((entry) => entry.path));
189
- this.updatePromptsFromPaths(this.lastPromptPaths, promptPaths);
200
+ this.updatePromptsFromPaths(this.lastPromptPaths);
190
201
  }
191
202
  if (themePaths.length > 0) {
192
203
  this.lastThemePaths = this.mergePaths(this.lastThemePaths, themePaths.map((entry) => entry.path));
193
- this.updateThemesFromPaths(this.lastThemePaths, themePaths);
204
+ this.updateThemesFromPaths(this.lastThemePaths);
194
205
  }
195
206
  }
196
207
  async reload() {
@@ -198,18 +209,20 @@ export class DefaultResourceLoader {
198
209
  const cliExtensionPaths = await this.packageManager.resolveExtensionSources(this.additionalExtensionPaths, {
199
210
  temporary: true,
200
211
  });
212
+ const metadataByPath = new Map();
213
+ this.extensionSkillSourceInfos = new Map();
214
+ this.extensionPromptSourceInfos = new Map();
215
+ this.extensionThemeSourceInfos = new Map();
201
216
  // Helper to extract enabled paths and store metadata
202
217
  const getEnabledResources = (resources) => {
203
218
  for (const r of resources) {
204
- if (!this.pathMetadata.has(r.path)) {
205
- this.pathMetadata.set(r.path, r.metadata);
219
+ if (!metadataByPath.has(r.path)) {
220
+ metadataByPath.set(r.path, r.metadata);
206
221
  }
207
222
  }
208
223
  return resources.filter((r) => r.enabled);
209
224
  };
210
225
  const getEnabledPaths = (resources) => getEnabledResources(resources).map((r) => r.path);
211
- // Store metadata and get enabled paths
212
- this.pathMetadata = new Map();
213
226
  const enabledExtensions = getEnabledPaths(resolvedPaths.extensions);
214
227
  const enabledSkillResources = getEnabledResources(resolvedPaths.skills);
215
228
  const enabledPrompts = getEnabledPaths(resolvedPaths.prompts);
@@ -229,8 +242,8 @@ export class DefaultResourceLoader {
229
242
  }
230
243
  const skillFile = join(resource.path, "SKILL.md");
231
244
  if (existsSync(skillFile)) {
232
- if (!this.pathMetadata.has(skillFile)) {
233
- this.pathMetadata.set(skillFile, resource.metadata);
245
+ if (!metadataByPath.has(skillFile)) {
246
+ metadataByPath.set(skillFile, resource.metadata);
234
247
  }
235
248
  return skillFile;
236
249
  }
@@ -239,13 +252,13 @@ export class DefaultResourceLoader {
239
252
  const enabledSkills = enabledSkillResources.map(mapSkillPath);
240
253
  // Add CLI paths metadata
241
254
  for (const r of cliExtensionPaths.extensions) {
242
- if (!this.pathMetadata.has(r.path)) {
243
- this.pathMetadata.set(r.path, { source: "cli", scope: "temporary", origin: "top-level" });
255
+ if (!metadataByPath.has(r.path)) {
256
+ metadataByPath.set(r.path, { source: "cli", scope: "temporary", origin: "top-level" });
244
257
  }
245
258
  }
246
259
  for (const r of cliExtensionPaths.skills) {
247
- if (!this.pathMetadata.has(r.path)) {
248
- this.pathMetadata.set(r.path, { source: "cli", scope: "temporary", origin: "top-level" });
260
+ if (!metadataByPath.has(r.path)) {
261
+ metadataByPath.set(r.path, { source: "cli", scope: "temporary", origin: "top-level" });
249
262
  }
250
263
  }
251
264
  const cliEnabledExtensions = getEnabledPaths(cliExtensionPaths.extensions);
@@ -266,24 +279,22 @@ export class DefaultResourceLoader {
266
279
  extensionsResult.errors.push({ path: conflict.path, error: conflict.message });
267
280
  }
268
281
  this.extensionsResult = this.extensionsOverride ? this.extensionsOverride(extensionsResult) : extensionsResult;
282
+ this.applyExtensionSourceInfo(this.extensionsResult.extensions, metadataByPath);
269
283
  const skillPaths = this.noSkills
270
284
  ? this.mergePaths(cliEnabledSkills, this.additionalSkillPaths)
271
285
  : this.mergePaths([...enabledSkills, ...cliEnabledSkills], this.additionalSkillPaths);
272
286
  this.lastSkillPaths = skillPaths;
273
- this.updateSkillsFromPaths(skillPaths);
287
+ this.updateSkillsFromPaths(skillPaths, metadataByPath);
274
288
  const promptPaths = this.noPromptTemplates
275
289
  ? this.mergePaths(cliEnabledPrompts, this.additionalPromptTemplatePaths)
276
290
  : this.mergePaths([...enabledPrompts, ...cliEnabledPrompts], this.additionalPromptTemplatePaths);
277
291
  this.lastPromptPaths = promptPaths;
278
- this.updatePromptsFromPaths(promptPaths);
292
+ this.updatePromptsFromPaths(promptPaths, metadataByPath);
279
293
  const themePaths = this.noThemes
280
294
  ? this.mergePaths(cliEnabledThemes, this.additionalThemePaths)
281
295
  : this.mergePaths([...enabledThemes, ...cliEnabledThemes], this.additionalThemePaths);
282
296
  this.lastThemePaths = themePaths;
283
- this.updateThemesFromPaths(themePaths);
284
- for (const extension of this.extensionsResult.extensions) {
285
- this.addDefaultMetadataForPath(extension.path);
286
- }
297
+ this.updateThemesFromPaths(themePaths, metadataByPath);
287
298
  const agentsFiles = { agentsFiles: loadProjectContextFiles({ cwd: this.cwd, agentDir: this.agentDir }) };
288
299
  const resolvedAgentsFiles = this.agentsFilesOverride ? this.agentsFilesOverride(agentsFiles) : agentsFiles;
289
300
  this.agentsFiles = resolvedAgentsFiles.agentsFiles;
@@ -302,7 +313,7 @@ export class DefaultResourceLoader {
302
313
  metadata: entry.metadata,
303
314
  }));
304
315
  }
305
- updateSkillsFromPaths(skillPaths, extensionPaths = []) {
316
+ updateSkillsFromPaths(skillPaths, metadataByPath) {
306
317
  let skillsResult;
307
318
  if (this.noSkills && skillPaths.length === 0) {
308
319
  skillsResult = { skills: [], diagnostics: [] };
@@ -316,14 +327,15 @@ export class DefaultResourceLoader {
316
327
  });
317
328
  }
318
329
  const resolvedSkills = this.skillsOverride ? this.skillsOverride(skillsResult) : skillsResult;
319
- this.skills = resolvedSkills.skills;
330
+ this.skills = resolvedSkills.skills.map((skill) => ({
331
+ ...skill,
332
+ sourceInfo: this.findSourceInfoForPath(skill.filePath, this.extensionSkillSourceInfos, metadataByPath) ??
333
+ skill.sourceInfo ??
334
+ this.getDefaultSourceInfoForPath(skill.filePath),
335
+ }));
320
336
  this.skillDiagnostics = resolvedSkills.diagnostics;
321
- this.applyExtensionMetadata(extensionPaths, this.skills.map((skill) => skill.filePath));
322
- for (const skill of this.skills) {
323
- this.addDefaultMetadataForPath(skill.filePath);
324
- }
325
337
  }
326
- updatePromptsFromPaths(promptPaths, extensionPaths = []) {
338
+ updatePromptsFromPaths(promptPaths, metadataByPath) {
327
339
  let promptsResult;
328
340
  if (this.noPromptTemplates && promptPaths.length === 0) {
329
341
  promptsResult = { prompts: [], diagnostics: [] };
@@ -338,14 +350,15 @@ export class DefaultResourceLoader {
338
350
  promptsResult = this.dedupePrompts(allPrompts);
339
351
  }
340
352
  const resolvedPrompts = this.promptsOverride ? this.promptsOverride(promptsResult) : promptsResult;
341
- this.prompts = resolvedPrompts.prompts;
353
+ this.prompts = resolvedPrompts.prompts.map((prompt) => ({
354
+ ...prompt,
355
+ sourceInfo: this.findSourceInfoForPath(prompt.filePath, this.extensionPromptSourceInfos, metadataByPath) ??
356
+ prompt.sourceInfo ??
357
+ this.getDefaultSourceInfoForPath(prompt.filePath),
358
+ }));
342
359
  this.promptDiagnostics = resolvedPrompts.diagnostics;
343
- this.applyExtensionMetadata(extensionPaths, this.prompts.map((prompt) => prompt.filePath));
344
- for (const prompt of this.prompts) {
345
- this.addDefaultMetadataForPath(prompt.filePath);
346
- }
347
360
  }
348
- updateThemesFromPaths(themePaths, extensionPaths = []) {
361
+ updateThemesFromPaths(themePaths, metadataByPath) {
349
362
  let themesResult;
350
363
  if (this.noThemes && themePaths.length === 0) {
351
364
  themesResult = { themes: [], diagnostics: [] };
@@ -356,39 +369,101 @@ export class DefaultResourceLoader {
356
369
  themesResult = { themes: deduped.themes, diagnostics: [...loaded.diagnostics, ...deduped.diagnostics] };
357
370
  }
358
371
  const resolvedThemes = this.themesOverride ? this.themesOverride(themesResult) : themesResult;
359
- this.themes = resolvedThemes.themes;
372
+ this.themes = resolvedThemes.themes.map((theme) => {
373
+ const sourcePath = theme.sourcePath;
374
+ theme.sourceInfo = sourcePath
375
+ ? (this.findSourceInfoForPath(sourcePath, this.extensionThemeSourceInfos, metadataByPath) ??
376
+ theme.sourceInfo ??
377
+ this.getDefaultSourceInfoForPath(sourcePath))
378
+ : theme.sourceInfo;
379
+ return theme;
380
+ });
360
381
  this.themeDiagnostics = resolvedThemes.diagnostics;
361
- const themePathsWithSource = this.themes.flatMap((theme) => (theme.sourcePath ? [theme.sourcePath] : []));
362
- this.applyExtensionMetadata(extensionPaths, themePathsWithSource);
363
- for (const theme of this.themes) {
364
- if (theme.sourcePath) {
365
- this.addDefaultMetadataForPath(theme.sourcePath);
382
+ }
383
+ applyExtensionSourceInfo(extensions, metadataByPath) {
384
+ for (const extension of extensions) {
385
+ extension.sourceInfo =
386
+ this.findSourceInfoForPath(extension.path, undefined, metadataByPath) ??
387
+ this.getDefaultSourceInfoForPath(extension.path);
388
+ for (const command of extension.commands.values()) {
389
+ command.sourceInfo = extension.sourceInfo;
390
+ }
391
+ for (const tool of extension.tools.values()) {
392
+ tool.sourceInfo = extension.sourceInfo;
366
393
  }
367
394
  }
368
395
  }
369
- applyExtensionMetadata(extensionPaths, resourcePaths) {
370
- if (extensionPaths.length === 0) {
371
- return;
396
+ findSourceInfoForPath(resourcePath, extraSourceInfos, metadataByPath) {
397
+ if (!resourcePath) {
398
+ return undefined;
372
399
  }
373
- const normalized = extensionPaths.map((entry) => ({
374
- path: resolve(entry.path),
375
- metadata: entry.metadata,
376
- }));
377
- for (const entry of normalized) {
378
- if (!this.pathMetadata.has(entry.path)) {
379
- this.pathMetadata.set(entry.path, entry.metadata);
400
+ if (resourcePath.startsWith("<")) {
401
+ return this.getDefaultSourceInfoForPath(resourcePath);
402
+ }
403
+ const normalizedResourcePath = resolve(resourcePath);
404
+ if (extraSourceInfos) {
405
+ for (const [sourcePath, sourceInfo] of extraSourceInfos.entries()) {
406
+ const normalizedSourcePath = resolve(sourcePath);
407
+ if (normalizedResourcePath === normalizedSourcePath ||
408
+ normalizedResourcePath.startsWith(`${normalizedSourcePath}${sep}`)) {
409
+ return { ...sourceInfo, path: resourcePath };
410
+ }
380
411
  }
381
412
  }
382
- for (const resourcePath of resourcePaths) {
383
- const normalizedResourcePath = resolve(resourcePath);
384
- if (this.pathMetadata.has(normalizedResourcePath) || this.pathMetadata.has(resourcePath)) {
385
- continue;
413
+ if (metadataByPath) {
414
+ const exact = metadataByPath.get(normalizedResourcePath) ?? metadataByPath.get(resourcePath);
415
+ if (exact) {
416
+ return createSourceInfo(resourcePath, exact);
417
+ }
418
+ for (const [sourcePath, metadata] of metadataByPath.entries()) {
419
+ const normalizedSourcePath = resolve(sourcePath);
420
+ if (normalizedResourcePath === normalizedSourcePath ||
421
+ normalizedResourcePath.startsWith(`${normalizedSourcePath}${sep}`)) {
422
+ return createSourceInfo(resourcePath, metadata);
423
+ }
424
+ }
425
+ }
426
+ return undefined;
427
+ }
428
+ getDefaultSourceInfoForPath(filePath) {
429
+ if (filePath.startsWith("<") && filePath.endsWith(">")) {
430
+ return {
431
+ path: filePath,
432
+ source: filePath.slice(1, -1).split(":")[0] || "temporary",
433
+ scope: "temporary",
434
+ origin: "top-level",
435
+ };
436
+ }
437
+ const normalizedPath = resolve(filePath);
438
+ const agentRoots = [
439
+ join(this.agentDir, "skills"),
440
+ join(this.agentDir, "prompts"),
441
+ join(this.agentDir, "themes"),
442
+ join(this.agentDir, "extensions"),
443
+ ];
444
+ const projectRoots = [
445
+ join(this.cwd, CONFIG_DIR_NAME, "skills"),
446
+ join(this.cwd, CONFIG_DIR_NAME, "prompts"),
447
+ join(this.cwd, CONFIG_DIR_NAME, "themes"),
448
+ join(this.cwd, CONFIG_DIR_NAME, "extensions"),
449
+ ];
450
+ for (const root of agentRoots) {
451
+ if (this.isUnderPath(normalizedPath, root)) {
452
+ return { path: filePath, source: "local", scope: "user", origin: "top-level", baseDir: root };
386
453
  }
387
- const match = normalized.find((entry) => normalizedResourcePath === entry.path || normalizedResourcePath.startsWith(`${entry.path}${sep}`));
388
- if (match) {
389
- this.pathMetadata.set(normalizedResourcePath, match.metadata);
454
+ }
455
+ for (const root of projectRoots) {
456
+ if (this.isUnderPath(normalizedPath, root)) {
457
+ return { path: filePath, source: "local", scope: "project", origin: "top-level", baseDir: root };
390
458
  }
391
459
  }
460
+ return {
461
+ path: filePath,
462
+ source: "local",
463
+ scope: "temporary",
464
+ origin: "top-level",
465
+ baseDir: statSync(normalizedPath).isDirectory() ? normalizedPath : resolve(normalizedPath, ".."),
466
+ };
392
467
  }
393
468
  mergePaths(primary, additional) {
394
469
  const merged = [];
@@ -576,39 +651,6 @@ export class DefaultResourceLoader {
576
651
  }
577
652
  return undefined;
578
653
  }
579
- addDefaultMetadataForPath(filePath) {
580
- if (!filePath || filePath.startsWith("<")) {
581
- return;
582
- }
583
- const normalizedPath = resolve(filePath);
584
- if (this.pathMetadata.has(normalizedPath) || this.pathMetadata.has(filePath)) {
585
- return;
586
- }
587
- const agentRoots = [
588
- join(this.agentDir, "skills"),
589
- join(this.agentDir, "prompts"),
590
- join(this.agentDir, "themes"),
591
- join(this.agentDir, "extensions"),
592
- ];
593
- const projectRoots = [
594
- join(this.cwd, CONFIG_DIR_NAME, "skills"),
595
- join(this.cwd, CONFIG_DIR_NAME, "prompts"),
596
- join(this.cwd, CONFIG_DIR_NAME, "themes"),
597
- join(this.cwd, CONFIG_DIR_NAME, "extensions"),
598
- ];
599
- for (const root of agentRoots) {
600
- if (this.isUnderPath(normalizedPath, root)) {
601
- this.pathMetadata.set(normalizedPath, { source: "local", scope: "user", origin: "top-level" });
602
- return;
603
- }
604
- }
605
- for (const root of projectRoots) {
606
- if (this.isUnderPath(normalizedPath, root)) {
607
- this.pathMetadata.set(normalizedPath, { source: "local", scope: "project", origin: "top-level" });
608
- return;
609
- }
610
- }
611
- }
612
654
  isUnderPath(target, root) {
613
655
  const normalizedRoot = resolve(root);
614
656
  if (target === normalizedRoot) {
@@ -619,9 +661,8 @@ export class DefaultResourceLoader {
619
661
  }
620
662
  detectExtensionConflicts(extensions) {
621
663
  const conflicts = [];
622
- // Track which extension registered each tool, command, and flag
664
+ // Track which extension registered each tool and flag
623
665
  const toolOwners = new Map();
624
- const commandOwners = new Map();
625
666
  const flagOwners = new Map();
626
667
  for (const ext of extensions) {
627
668
  // Check tools
@@ -637,19 +678,6 @@ export class DefaultResourceLoader {
637
678
  toolOwners.set(toolName, ext.path);
638
679
  }
639
680
  }
640
- // Check commands
641
- for (const commandName of ext.commands.keys()) {
642
- const existingOwner = commandOwners.get(commandName);
643
- if (existingOwner && existingOwner !== ext.path) {
644
- conflicts.push({
645
- path: ext.path,
646
- message: `Command "/${commandName}" conflicts with ${existingOwner}`,
647
- });
648
- }
649
- else {
650
- commandOwners.set(commandName, ext.path);
651
- }
652
- }
653
681
  // Check flags
654
682
  for (const flagName of ext.flags.keys()) {
655
683
  const existingOwner = flagOwners.get(flagName);