@fleetagent/pi-coding-agent 0.0.10 → 0.0.12

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 (116) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/cli/args.d.ts +3 -2
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +20 -8
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/core/agent-session.d.ts +10 -2
  7. package/dist/core/agent-session.d.ts.map +1 -1
  8. package/dist/core/agent-session.js +75 -14
  9. package/dist/core/agent-session.js.map +1 -1
  10. package/dist/core/bash-executor.d.ts +2 -0
  11. package/dist/core/bash-executor.d.ts.map +1 -1
  12. package/dist/core/bash-executor.js +1 -0
  13. package/dist/core/bash-executor.js.map +1 -1
  14. package/dist/core/extensions/index.d.ts +1 -1
  15. package/dist/core/extensions/index.d.ts.map +1 -1
  16. package/dist/core/extensions/index.js.map +1 -1
  17. package/dist/core/extensions/loader.d.ts.map +1 -1
  18. package/dist/core/extensions/loader.js +86 -0
  19. package/dist/core/extensions/loader.js.map +1 -1
  20. package/dist/core/extensions/runner.d.ts +3 -0
  21. package/dist/core/extensions/runner.d.ts.map +1 -1
  22. package/dist/core/extensions/runner.js +27 -0
  23. package/dist/core/extensions/runner.js.map +1 -1
  24. package/dist/core/extensions/types.d.ts +55 -2
  25. package/dist/core/extensions/types.d.ts.map +1 -1
  26. package/dist/core/extensions/types.js.map +1 -1
  27. package/dist/core/pi-agent.d.ts.map +1 -1
  28. package/dist/core/pi-agent.js +1 -0
  29. package/dist/core/pi-agent.js.map +1 -1
  30. package/dist/core/prompt-templates.d.ts +5 -0
  31. package/dist/core/prompt-templates.d.ts.map +1 -1
  32. package/dist/core/prompt-templates.js +115 -0
  33. package/dist/core/prompt-templates.js.map +1 -1
  34. package/dist/core/resource-loader.d.ts +15 -0
  35. package/dist/core/resource-loader.d.ts.map +1 -1
  36. package/dist/core/resource-loader.js +355 -40
  37. package/dist/core/resource-loader.js.map +1 -1
  38. package/dist/core/rules.d.ts +6 -0
  39. package/dist/core/rules.d.ts.map +1 -1
  40. package/dist/core/rules.js +231 -10
  41. package/dist/core/rules.js.map +1 -1
  42. package/dist/core/skills.d.ts +6 -0
  43. package/dist/core/skills.d.ts.map +1 -1
  44. package/dist/core/skills.js +231 -10
  45. package/dist/core/skills.js.map +1 -1
  46. package/dist/core/slash-commands.d.ts.map +1 -1
  47. package/dist/core/slash-commands.js +1 -1
  48. package/dist/core/slash-commands.js.map +1 -1
  49. package/dist/core/source-info.d.ts +2 -0
  50. package/dist/core/source-info.d.ts.map +1 -1
  51. package/dist/core/source-info.js +6 -0
  52. package/dist/core/source-info.js.map +1 -1
  53. package/dist/core/tools/bash.d.ts.map +1 -1
  54. package/dist/core/tools/bash.js +11 -8
  55. package/dist/core/tools/bash.js.map +1 -1
  56. package/dist/core/tools/edit.d.ts.map +1 -1
  57. package/dist/core/tools/edit.js +5 -5
  58. package/dist/core/tools/edit.js.map +1 -1
  59. package/dist/core/tools/find.d.ts.map +1 -1
  60. package/dist/core/tools/find.js +2 -2
  61. package/dist/core/tools/find.js.map +1 -1
  62. package/dist/core/tools/grep.d.ts.map +1 -1
  63. package/dist/core/tools/grep.js +2 -2
  64. package/dist/core/tools/grep.js.map +1 -1
  65. package/dist/core/tools/index.d.ts +1 -1
  66. package/dist/core/tools/index.d.ts.map +1 -1
  67. package/dist/core/tools/index.js +1 -1
  68. package/dist/core/tools/index.js.map +1 -1
  69. package/dist/core/tools/ls.d.ts.map +1 -1
  70. package/dist/core/tools/ls.js +2 -2
  71. package/dist/core/tools/ls.js.map +1 -1
  72. package/dist/core/tools/operations.d.ts +49 -4
  73. package/dist/core/tools/operations.d.ts.map +1 -1
  74. package/dist/core/tools/operations.js +340 -4
  75. package/dist/core/tools/operations.js.map +1 -1
  76. package/dist/core/tools/read.d.ts +2 -0
  77. package/dist/core/tools/read.d.ts.map +1 -1
  78. package/dist/core/tools/read.js +14 -6
  79. package/dist/core/tools/read.js.map +1 -1
  80. package/dist/core/tools/render-utils.d.ts +9 -0
  81. package/dist/core/tools/render-utils.d.ts.map +1 -1
  82. package/dist/core/tools/render-utils.js +16 -0
  83. package/dist/core/tools/render-utils.js.map +1 -1
  84. package/dist/core/tools/write.d.ts.map +1 -1
  85. package/dist/core/tools/write.js +3 -2
  86. package/dist/core/tools/write.js.map +1 -1
  87. package/dist/index.d.ts +2 -2
  88. package/dist/index.d.ts.map +1 -1
  89. package/dist/index.js +1 -1
  90. package/dist/index.js.map +1 -1
  91. package/dist/main.d.ts.map +1 -1
  92. package/dist/main.js +36 -19
  93. package/dist/main.js.map +1 -1
  94. package/dist/modes/interactive/interactive-mode.d.ts +3 -1
  95. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  96. package/dist/modes/interactive/interactive-mode.js +61 -28
  97. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  98. package/dist/modes/rpc/rpc-client.d.ts +11 -4
  99. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  100. package/dist/modes/rpc/rpc-client.js +6 -6
  101. package/dist/modes/rpc/rpc-client.js.map +1 -1
  102. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  103. package/dist/modes/rpc/rpc-mode.js +11 -7
  104. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  105. package/dist/modes/rpc/rpc-types.d.ts +10 -4
  106. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  107. package/dist/modes/rpc/rpc-types.js.map +1 -1
  108. package/docs/extensions.md +83 -4
  109. package/docs/rpc.md +31 -0
  110. package/docs/usage.md +5 -0
  111. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  112. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  113. package/examples/extensions/sandbox/package.json +1 -1
  114. package/examples/extensions/with-deps/package.json +1 -1
  115. package/npm-shrinkwrap.json +12 -12
  116. package/package.json +4 -4
@@ -7,12 +7,12 @@ import { canonicalizePath, isLocalPath, resolvePath } from "../utils/paths.js";
7
7
  import { createEventBus } from "./event-bus.js";
8
8
  import { createExtensionRuntime, loadExtensionFromFactory, loadExtensions } from "./extensions/loader.js";
9
9
  import { DefaultPackageManager } from "./package-manager.js";
10
- import { loadPromptTemplates } from "./prompt-templates.js";
11
- import { loadRules } from "./rules.js";
10
+ import { loadPromptTemplates, loadPromptTemplatesWithOperations } from "./prompt-templates.js";
11
+ import { loadRules, loadRulesWithOperations } from "./rules.js";
12
12
  import { SettingsManager } from "./settings-manager.js";
13
- import { loadSkills } from "./skills.js";
13
+ import { loadSkills, loadSkillsWithOperations } from "./skills.js";
14
14
  import { createSourceInfo } from "./source-info.js";
15
- function resolvePromptInput(input, description) {
15
+ async function resolvePromptInput(input, description, operations) {
16
16
  if (!input) {
17
17
  return undefined;
18
18
  }
@@ -25,6 +25,13 @@ function resolvePromptInput(input, description) {
25
25
  return input;
26
26
  }
27
27
  }
28
+ if (operations) {
29
+ try {
30
+ await operations.access(input, "read");
31
+ return (await operations.readFile(input)).toString("utf-8");
32
+ }
33
+ catch { }
34
+ }
28
35
  return input;
29
36
  }
30
37
  function loadContextFileFromDir(dir) {
@@ -74,6 +81,45 @@ export function loadProjectContextFiles(options) {
74
81
  contextFiles.push(...ancestorContextFiles);
75
82
  return contextFiles;
76
83
  }
84
+ async function loadContextFileFromDirWithOperations(operations, dir) {
85
+ const candidates = ["AGENTS.md", "AGENTS.MD", "CLAUDE.md", "CLAUDE.MD"];
86
+ for (const filename of candidates) {
87
+ const filePath = join(dir, filename);
88
+ try {
89
+ await operations.access(filePath, "read");
90
+ return { path: filePath, content: (await operations.readFile(filePath)).toString("utf-8") };
91
+ }
92
+ catch { }
93
+ }
94
+ return null;
95
+ }
96
+ async function loadProjectContextFilesWithOperations(options) {
97
+ const contextFiles = [];
98
+ const seenPaths = new Set();
99
+ const globalContext = loadContextFileFromDir(resolvePath(options.agentDir));
100
+ if (globalContext) {
101
+ contextFiles.push(globalContext);
102
+ seenPaths.add(globalContext.path);
103
+ }
104
+ const ancestorContextFiles = [];
105
+ let currentDir = resolvePath(options.cwd);
106
+ const root = resolve("/");
107
+ while (true) {
108
+ const contextFile = await loadContextFileFromDirWithOperations(options.operations, currentDir);
109
+ if (contextFile && !seenPaths.has(contextFile.path)) {
110
+ ancestorContextFiles.unshift(contextFile);
111
+ seenPaths.add(contextFile.path);
112
+ }
113
+ if (currentDir === root)
114
+ break;
115
+ const parentDir = resolve(currentDir, "..");
116
+ if (parentDir === currentDir)
117
+ break;
118
+ currentDir = parentDir;
119
+ }
120
+ contextFiles.push(...ancestorContextFiles);
121
+ return contextFiles;
122
+ }
77
123
  export class DefaultResourceLoader {
78
124
  cwd;
79
125
  agentDir;
@@ -94,6 +140,7 @@ export class DefaultResourceLoader {
94
140
  noContextFiles;
95
141
  systemPromptSource;
96
142
  appendSystemPromptSource;
143
+ toolOperations;
97
144
  extensionsOverride;
98
145
  skillsOverride;
99
146
  rulesOverride;
@@ -146,6 +193,7 @@ export class DefaultResourceLoader {
146
193
  this.noContextFiles = options.noContextFiles ?? false;
147
194
  this.systemPromptSource = options.systemPrompt;
148
195
  this.appendSystemPromptSource = options.appendSystemPrompt;
196
+ this.toolOperations = options.toolOperations;
149
197
  this.extensionsOverride = options.extensionsOverride;
150
198
  this.skillsOverride = options.skillsOverride;
151
199
  this.rulesOverride = options.rulesOverride;
@@ -198,6 +246,50 @@ export class DefaultResourceLoader {
198
246
  getAppendSystemPrompt() {
199
247
  return this.appendSystemPrompt;
200
248
  }
249
+ getInstructionOperations() {
250
+ const backend = this.toolOperations?.getBackendInfo?.();
251
+ return (backend?.type === "ssh" || backend?.type === "remote") && backend.configured
252
+ ? this.toolOperations
253
+ : undefined;
254
+ }
255
+ getRemoteProjectInstructionResourcePaths(cwd, source) {
256
+ const projectBaseDir = join(cwd, CONFIG_DIR_NAME);
257
+ const projectMetadata = {
258
+ source,
259
+ scope: "project",
260
+ origin: "top-level",
261
+ baseDir: projectBaseDir,
262
+ };
263
+ const skills = [
264
+ { path: join(projectBaseDir, "skills"), metadata: projectMetadata },
265
+ ];
266
+ const rules = [
267
+ { path: join(projectBaseDir, "rules"), metadata: projectMetadata },
268
+ ];
269
+ const prompts = [
270
+ { path: join(projectBaseDir, "prompts"), metadata: projectMetadata },
271
+ ];
272
+ let currentDir = resolve(cwd);
273
+ const root = resolve("/");
274
+ while (true) {
275
+ const agentsBaseDir = join(currentDir, ".agents");
276
+ const agentsMetadata = {
277
+ source,
278
+ scope: "project",
279
+ origin: "top-level",
280
+ baseDir: agentsBaseDir,
281
+ };
282
+ skills.push({ path: join(agentsBaseDir, "skills"), metadata: agentsMetadata });
283
+ rules.push({ path: join(agentsBaseDir, "rules"), metadata: agentsMetadata });
284
+ if (currentDir === root)
285
+ break;
286
+ const parentDir = resolve(currentDir, "..");
287
+ if (parentDir === currentDir)
288
+ break;
289
+ currentDir = parentDir;
290
+ }
291
+ return { skills, rules, prompts };
292
+ }
201
293
  extendResources(paths) {
202
294
  const skillPaths = this.normalizeExtensionPaths(paths.skillPaths ?? []);
203
295
  const rulePaths = this.normalizeExtensionPaths(paths.rulePaths ?? []);
@@ -253,10 +345,16 @@ export class DefaultResourceLoader {
253
345
  return resources.filter((r) => r.enabled);
254
346
  };
255
347
  const getEnabledPaths = (resources) => getEnabledResources(resources).map((r) => r.path);
348
+ const instructionOperations = this.getInstructionOperations();
349
+ const loadProjectInstructionsRemotely = instructionOperations !== undefined;
350
+ const isLocalProjectInstructionResource = (resource) => loadProjectInstructionsRemotely &&
351
+ resource.metadata.scope === "project" &&
352
+ resource.metadata.origin === "top-level";
256
353
  const enabledExtensions = getEnabledPaths(resolvedPaths.extensions);
257
- const enabledSkillResources = getEnabledResources(resolvedPaths.skills);
258
- const enabledRuleResources = getEnabledResources(resolvedPaths.rules);
259
- const enabledPrompts = getEnabledPaths(resolvedPaths.prompts);
354
+ const enabledSkillResources = getEnabledResources(resolvedPaths.skills).filter((resource) => !isLocalProjectInstructionResource(resource));
355
+ const enabledRuleResources = getEnabledResources(resolvedPaths.rules).filter((resource) => !isLocalProjectInstructionResource(resource));
356
+ const enabledPromptResources = getEnabledResources(resolvedPaths.prompts).filter((resource) => !isLocalProjectInstructionResource(resource));
357
+ const enabledPrompts = enabledPromptResources.map((resource) => resource.path);
260
358
  const enabledThemes = getEnabledPaths(resolvedPaths.themes);
261
359
  const mapSkillPath = (resource) => {
262
360
  if (resource.metadata.source !== "auto" && resource.metadata.origin !== "package") {
@@ -280,7 +378,41 @@ export class DefaultResourceLoader {
280
378
  }
281
379
  return resource.path;
282
380
  };
283
- const enabledSkills = enabledSkillResources.map(mapSkillPath);
381
+ const instructionBackendType = instructionOperations?.getBackendInfo?.()?.type;
382
+ const discoveredRemoteInstructionResourcePaths = instructionOperations
383
+ ? this.getRemoteProjectInstructionResourcePaths(instructionOperations.cwd, instructionBackendType === "remote" ? "remote" : "ssh")
384
+ : { skills: [], rules: [], prompts: [] };
385
+ const filterExistingRemoteInstructionPaths = async (entries) => {
386
+ if (!instructionOperations)
387
+ return [];
388
+ const existing = [];
389
+ for (const entry of entries) {
390
+ try {
391
+ await instructionOperations.access(entry.path, "exists");
392
+ existing.push(entry);
393
+ }
394
+ catch { }
395
+ }
396
+ return existing;
397
+ };
398
+ const remoteInstructionResourcePaths = instructionOperations
399
+ ? {
400
+ skills: await filterExistingRemoteInstructionPaths(discoveredRemoteInstructionResourcePaths.skills),
401
+ rules: await filterExistingRemoteInstructionPaths(discoveredRemoteInstructionResourcePaths.rules),
402
+ prompts: await filterExistingRemoteInstructionPaths(discoveredRemoteInstructionResourcePaths.prompts),
403
+ }
404
+ : discoveredRemoteInstructionResourcePaths;
405
+ for (const entry of [
406
+ ...remoteInstructionResourcePaths.skills,
407
+ ...remoteInstructionResourcePaths.rules,
408
+ ...remoteInstructionResourcePaths.prompts,
409
+ ]) {
410
+ metadataByPath.set(entry.path, entry.metadata);
411
+ }
412
+ const enabledSkills = [
413
+ ...enabledSkillResources.map(mapSkillPath),
414
+ ...remoteInstructionResourcePaths.skills.map((entry) => entry.path),
415
+ ];
284
416
  const mapRulePath = (resource) => {
285
417
  if (resource.metadata.source !== "auto" && resource.metadata.origin !== "package") {
286
418
  return resource.path;
@@ -303,7 +435,10 @@ export class DefaultResourceLoader {
303
435
  }
304
436
  return resource.path;
305
437
  };
306
- const enabledRules = enabledRuleResources.map(mapRulePath);
438
+ const enabledRules = [
439
+ ...enabledRuleResources.map(mapRulePath),
440
+ ...remoteInstructionResourcePaths.rules.map((entry) => entry.path),
441
+ ];
307
442
  // Add CLI paths metadata
308
443
  for (const r of cliExtensionPaths.extensions) {
309
444
  if (!metadataByPath.has(r.path)) {
@@ -352,7 +487,7 @@ export class DefaultResourceLoader {
352
487
  ? this.mergePaths(cliEnabledSkills, this.additionalSkillPaths)
353
488
  : this.mergePaths([...cliEnabledSkills, ...enabledSkills], this.additionalSkillPaths);
354
489
  this.lastSkillPaths = skillPaths;
355
- this.updateSkillsFromPaths(skillPaths, metadataByPath);
490
+ await this.updateSkillsFromPathsForReload(skillPaths, metadataByPath);
356
491
  for (const p of this.additionalSkillPaths) {
357
492
  if (isLocalPath(p)) {
358
493
  const resolved = this.resolveResourcePath(p);
@@ -365,7 +500,7 @@ export class DefaultResourceLoader {
365
500
  ? this.mergePaths(cliEnabledRules, this.additionalRulePaths)
366
501
  : this.mergePaths([...cliEnabledRules, ...enabledRules], this.additionalRulePaths);
367
502
  this.lastRulePaths = rulePaths;
368
- this.updateRulesFromPaths(rulePaths, metadataByPath);
503
+ await this.updateRulesFromPathsForReload(rulePaths, metadataByPath);
369
504
  for (const p of this.additionalRulePaths) {
370
505
  if (isLocalPath(p)) {
371
506
  const resolved = this.resolveResourcePath(p);
@@ -374,11 +509,12 @@ export class DefaultResourceLoader {
374
509
  }
375
510
  }
376
511
  }
512
+ const remotePromptPaths = remoteInstructionResourcePaths.prompts.map((entry) => entry.path);
377
513
  const promptPaths = this.noPromptTemplates
378
514
  ? this.mergePaths(cliEnabledPrompts, this.additionalPromptTemplatePaths)
379
- : this.mergePaths([...cliEnabledPrompts, ...enabledPrompts], this.additionalPromptTemplatePaths);
515
+ : this.mergePaths([...cliEnabledPrompts, ...enabledPrompts, ...remotePromptPaths], this.additionalPromptTemplatePaths);
380
516
  this.lastPromptPaths = promptPaths;
381
- this.updatePromptsFromPaths(promptPaths, metadataByPath);
517
+ await this.updatePromptsFromPathsForReload(promptPaths, metadataByPath);
382
518
  for (const p of this.additionalPromptTemplatePaths) {
383
519
  if (isLocalPath(p)) {
384
520
  const resolved = this.resolveResourcePath(p);
@@ -403,17 +539,23 @@ export class DefaultResourceLoader {
403
539
  }
404
540
  }
405
541
  const agentsFiles = {
406
- agentsFiles: this.noContextFiles ? [] : loadProjectContextFiles({ cwd: this.cwd, agentDir: this.agentDir }),
542
+ agentsFiles: this.noContextFiles
543
+ ? []
544
+ : instructionOperations
545
+ ? await loadProjectContextFilesWithOperations({
546
+ cwd: instructionOperations.cwd,
547
+ agentDir: this.agentDir,
548
+ operations: instructionOperations,
549
+ })
550
+ : loadProjectContextFiles({ cwd: this.cwd, agentDir: this.agentDir }),
407
551
  };
408
552
  const resolvedAgentsFiles = this.agentsFilesOverride ? this.agentsFilesOverride(agentsFiles) : agentsFiles;
409
553
  this.agentsFiles = resolvedAgentsFiles.agentsFiles;
410
- const baseSystemPrompt = resolvePromptInput(this.systemPromptSource ?? this.discoverSystemPromptFile(), "system prompt");
554
+ const baseSystemPrompt = await resolvePromptInput(this.systemPromptSource ?? this.discoverSystemPromptFile(), "system prompt", this.getInstructionOperations());
411
555
  this.systemPrompt = this.systemPromptOverride ? this.systemPromptOverride(baseSystemPrompt) : baseSystemPrompt;
412
556
  const appendSources = this.appendSystemPromptSource ??
413
557
  (this.discoverAppendSystemPromptFile() ? [this.discoverAppendSystemPromptFile()] : []);
414
- const baseAppend = appendSources
415
- .map((s) => resolvePromptInput(s, "append system prompt"))
416
- .filter((s) => s !== undefined);
558
+ const baseAppend = (await Promise.all(appendSources.map((s) => resolvePromptInput(s, "append system prompt", this.getInstructionOperations())))).filter((s) => s !== undefined);
417
559
  this.appendSystemPrompt = this.appendSystemPromptOverride
418
560
  ? this.appendSystemPromptOverride(baseAppend)
419
561
  : baseAppend;
@@ -429,6 +571,31 @@ export class DefaultResourceLoader {
429
571
  };
430
572
  });
431
573
  }
574
+ getExtensionRegisteredSkills() {
575
+ return this.extensionsResult.extensions.flatMap((extension) => Array.from(extension.skills.values()));
576
+ }
577
+ getExtensionRegisteredRules() {
578
+ return this.extensionsResult.extensions.flatMap((extension) => Array.from(extension.rules.values()));
579
+ }
580
+ getExtensionRegisteredPrompts() {
581
+ return this.extensionsResult.extensions.flatMap((extension) => Array.from(extension.prompts.values()));
582
+ }
583
+ applyLoadedSkills(skillsResult, metadataByPath) {
584
+ const extensionSkills = this.getExtensionRegisteredSkills();
585
+ const seenSkillNames = new Set(extensionSkills.map((skill) => skill.name));
586
+ const baseSkillsResult = {
587
+ skills: [...extensionSkills, ...skillsResult.skills.filter((skill) => !seenSkillNames.has(skill.name))],
588
+ diagnostics: skillsResult.diagnostics,
589
+ };
590
+ const resolvedSkills = this.skillsOverride ? this.skillsOverride(baseSkillsResult) : baseSkillsResult;
591
+ this.skills = resolvedSkills.skills.map((skill) => ({
592
+ ...skill,
593
+ sourceInfo: this.findSourceInfoForPath(skill.filePath, this.extensionSkillSourceInfos, metadataByPath) ??
594
+ skill.sourceInfo ??
595
+ this.getDefaultSourceInfoForPath(skill.filePath),
596
+ }));
597
+ this.skillDiagnostics = resolvedSkills.diagnostics;
598
+ }
432
599
  updateSkillsFromPaths(skillPaths, metadataByPath) {
433
600
  let skillsResult;
434
601
  if (this.noSkills && skillPaths.length === 0) {
@@ -442,14 +609,76 @@ export class DefaultResourceLoader {
442
609
  includeDefaults: false,
443
610
  });
444
611
  }
445
- const resolvedSkills = this.skillsOverride ? this.skillsOverride(skillsResult) : skillsResult;
446
- this.skills = resolvedSkills.skills.map((skill) => ({
447
- ...skill,
448
- sourceInfo: this.findSourceInfoForPath(skill.filePath, this.extensionSkillSourceInfos, metadataByPath) ??
449
- skill.sourceInfo ??
450
- this.getDefaultSourceInfoForPath(skill.filePath),
612
+ this.applyLoadedSkills(skillsResult, metadataByPath);
613
+ }
614
+ shouldLoadPathWithInstructionOperations(path, metadataByPath) {
615
+ const operations = this.getInstructionOperations();
616
+ if (!operations)
617
+ return false;
618
+ const sourceInfo = this.findSourceInfoForPath(path, undefined, metadataByPath);
619
+ if (sourceInfo?.source === "ssh" || sourceInfo?.source === "remote")
620
+ return true;
621
+ const cwd = operations.cwd.endsWith(sep) ? operations.cwd : `${operations.cwd}${sep}`;
622
+ return path === operations.cwd || path.startsWith(cwd);
623
+ }
624
+ async updateSkillsFromPathsForReload(skillPaths, metadataByPath) {
625
+ let skillsResult;
626
+ const operations = this.getInstructionOperations();
627
+ if (this.noSkills && skillPaths.length === 0) {
628
+ skillsResult = { skills: [], diagnostics: [] };
629
+ }
630
+ else if (operations) {
631
+ const remotePaths = skillPaths.filter((path) => this.shouldLoadPathWithInstructionOperations(path, metadataByPath));
632
+ const localPaths = skillPaths.filter((path) => !this.shouldLoadPathWithInstructionOperations(path, metadataByPath));
633
+ const remoteResult = await loadSkillsWithOperations({
634
+ cwd: operations.cwd,
635
+ agentDir: this.agentDir,
636
+ skillPaths: remotePaths,
637
+ includeDefaults: false,
638
+ operations,
639
+ });
640
+ const localResult = loadSkills({
641
+ cwd: this.cwd,
642
+ agentDir: this.agentDir,
643
+ skillPaths: localPaths,
644
+ includeDefaults: false,
645
+ });
646
+ const skillsByName = new Map();
647
+ for (const skill of [...remoteResult.skills, ...localResult.skills]) {
648
+ if (!skillsByName.has(skill.name)) {
649
+ skillsByName.set(skill.name, skill);
650
+ }
651
+ }
652
+ skillsResult = {
653
+ skills: Array.from(skillsByName.values()),
654
+ diagnostics: [...remoteResult.diagnostics, ...localResult.diagnostics],
655
+ };
656
+ }
657
+ else {
658
+ skillsResult = loadSkills({
659
+ cwd: this.cwd,
660
+ agentDir: this.agentDir,
661
+ skillPaths,
662
+ includeDefaults: false,
663
+ });
664
+ }
665
+ this.applyLoadedSkills(skillsResult, metadataByPath);
666
+ }
667
+ applyLoadedRules(rulesResult, metadataByPath) {
668
+ const extensionRules = this.getExtensionRegisteredRules();
669
+ const seenRuleNames = new Set(extensionRules.map((rule) => rule.name));
670
+ const baseRulesResult = {
671
+ rules: [...extensionRules, ...rulesResult.rules.filter((rule) => !seenRuleNames.has(rule.name))],
672
+ diagnostics: rulesResult.diagnostics,
673
+ };
674
+ const resolvedRules = this.rulesOverride ? this.rulesOverride(baseRulesResult) : baseRulesResult;
675
+ this.rules = resolvedRules.rules.map((rule) => ({
676
+ ...rule,
677
+ sourceInfo: this.findSourceInfoForPath(rule.filePath, this.extensionRuleSourceInfos, metadataByPath) ??
678
+ rule.sourceInfo ??
679
+ this.getDefaultSourceInfoForPath(rule.filePath),
451
680
  }));
452
- this.skillDiagnostics = resolvedSkills.diagnostics;
681
+ this.ruleDiagnostics = resolvedRules.diagnostics;
453
682
  }
454
683
  updateRulesFromPaths(rulePaths, metadataByPath) {
455
684
  let rulesResult;
@@ -464,14 +693,63 @@ export class DefaultResourceLoader {
464
693
  includeDefaults: false,
465
694
  });
466
695
  }
467
- const resolvedRules = this.rulesOverride ? this.rulesOverride(rulesResult) : rulesResult;
468
- this.rules = resolvedRules.rules.map((rule) => ({
469
- ...rule,
470
- sourceInfo: this.findSourceInfoForPath(rule.filePath, this.extensionRuleSourceInfos, metadataByPath) ??
471
- rule.sourceInfo ??
472
- this.getDefaultSourceInfoForPath(rule.filePath),
696
+ this.applyLoadedRules(rulesResult, metadataByPath);
697
+ }
698
+ async updateRulesFromPathsForReload(rulePaths, metadataByPath) {
699
+ let rulesResult;
700
+ const operations = this.getInstructionOperations();
701
+ if (this.noRules && rulePaths.length === 0) {
702
+ rulesResult = { rules: [], diagnostics: [] };
703
+ }
704
+ else if (operations) {
705
+ const remotePaths = rulePaths.filter((path) => this.shouldLoadPathWithInstructionOperations(path, metadataByPath));
706
+ const localPaths = rulePaths.filter((path) => !this.shouldLoadPathWithInstructionOperations(path, metadataByPath));
707
+ const remoteResult = await loadRulesWithOperations({
708
+ cwd: operations.cwd,
709
+ agentDir: this.agentDir,
710
+ rulePaths: remotePaths,
711
+ includeDefaults: false,
712
+ operations,
713
+ });
714
+ const localResult = loadRules({
715
+ cwd: this.cwd,
716
+ agentDir: this.agentDir,
717
+ rulePaths: localPaths,
718
+ includeDefaults: false,
719
+ });
720
+ const rulesByName = new Map();
721
+ for (const rule of [...remoteResult.rules, ...localResult.rules]) {
722
+ if (!rulesByName.has(rule.name)) {
723
+ rulesByName.set(rule.name, rule);
724
+ }
725
+ }
726
+ rulesResult = {
727
+ rules: Array.from(rulesByName.values()),
728
+ diagnostics: [...remoteResult.diagnostics, ...localResult.diagnostics],
729
+ };
730
+ }
731
+ else {
732
+ rulesResult = loadRules({
733
+ cwd: this.cwd,
734
+ agentDir: this.agentDir,
735
+ rulePaths,
736
+ includeDefaults: false,
737
+ });
738
+ }
739
+ this.applyLoadedRules(rulesResult, metadataByPath);
740
+ }
741
+ applyLoadedPrompts(promptsResult, metadataByPath) {
742
+ const extensionPrompts = this.getExtensionRegisteredPrompts();
743
+ const basePromptsResult = this.dedupePrompts([...extensionPrompts, ...promptsResult.prompts]);
744
+ basePromptsResult.diagnostics.unshift(...promptsResult.diagnostics);
745
+ const resolvedPrompts = this.promptsOverride ? this.promptsOverride(basePromptsResult) : basePromptsResult;
746
+ this.prompts = resolvedPrompts.prompts.map((prompt) => ({
747
+ ...prompt,
748
+ sourceInfo: this.findSourceInfoForPath(prompt.filePath, this.extensionPromptSourceInfos, metadataByPath) ??
749
+ prompt.sourceInfo ??
750
+ this.getDefaultSourceInfoForPath(prompt.filePath),
473
751
  }));
474
- this.ruleDiagnostics = resolvedRules.diagnostics;
752
+ this.promptDiagnostics = resolvedPrompts.diagnostics;
475
753
  }
476
754
  updatePromptsFromPaths(promptPaths, metadataByPath) {
477
755
  let promptsResult;
@@ -487,14 +765,42 @@ export class DefaultResourceLoader {
487
765
  });
488
766
  promptsResult = this.dedupePrompts(allPrompts);
489
767
  }
490
- const resolvedPrompts = this.promptsOverride ? this.promptsOverride(promptsResult) : promptsResult;
491
- this.prompts = resolvedPrompts.prompts.map((prompt) => ({
492
- ...prompt,
493
- sourceInfo: this.findSourceInfoForPath(prompt.filePath, this.extensionPromptSourceInfos, metadataByPath) ??
494
- prompt.sourceInfo ??
495
- this.getDefaultSourceInfoForPath(prompt.filePath),
496
- }));
497
- this.promptDiagnostics = resolvedPrompts.diagnostics;
768
+ this.applyLoadedPrompts(promptsResult, metadataByPath);
769
+ }
770
+ async updatePromptsFromPathsForReload(promptPaths, metadataByPath) {
771
+ let promptsResult;
772
+ const operations = this.getInstructionOperations();
773
+ if (this.noPromptTemplates && promptPaths.length === 0) {
774
+ promptsResult = { prompts: [], diagnostics: [] };
775
+ }
776
+ else if (operations) {
777
+ const remotePaths = promptPaths.filter((path) => this.shouldLoadPathWithInstructionOperations(path, metadataByPath));
778
+ const localPaths = promptPaths.filter((path) => !this.shouldLoadPathWithInstructionOperations(path, metadataByPath));
779
+ const remotePrompts = await loadPromptTemplatesWithOperations({
780
+ cwd: operations.cwd,
781
+ agentDir: this.agentDir,
782
+ promptPaths: remotePaths,
783
+ includeDefaults: false,
784
+ operations,
785
+ });
786
+ const localPrompts = loadPromptTemplates({
787
+ cwd: this.cwd,
788
+ agentDir: this.agentDir,
789
+ promptPaths: localPaths,
790
+ includeDefaults: false,
791
+ });
792
+ promptsResult = this.dedupePrompts([...remotePrompts, ...localPrompts]);
793
+ }
794
+ else {
795
+ const allPrompts = loadPromptTemplates({
796
+ cwd: this.cwd,
797
+ agentDir: this.agentDir,
798
+ promptPaths,
799
+ includeDefaults: false,
800
+ });
801
+ promptsResult = this.dedupePrompts(allPrompts);
802
+ }
803
+ this.applyLoadedPrompts(promptsResult, metadataByPath);
498
804
  }
499
805
  updateThemesFromPaths(themePaths, metadataByPath) {
500
806
  let themesResult;
@@ -529,6 +835,15 @@ export class DefaultResourceLoader {
529
835
  for (const tool of extension.tools.values()) {
530
836
  tool.sourceInfo = extension.sourceInfo;
531
837
  }
838
+ for (const skill of extension.skills.values()) {
839
+ skill.sourceInfo = extension.sourceInfo;
840
+ }
841
+ for (const rule of extension.rules.values()) {
842
+ rule.sourceInfo = extension.sourceInfo;
843
+ }
844
+ for (const prompt of extension.prompts.values()) {
845
+ prompt.sourceInfo = extension.sourceInfo;
846
+ }
532
847
  }
533
848
  }
534
849
  findSourceInfoForPath(resourcePath, extraSourceInfos, metadataByPath) {