agents-inc 0.174.0 → 0.175.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 (82) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/dist/{chunk-IAQFZFWD.js → chunk-37QFHJUW.js} +142 -13
  3. package/dist/chunk-37QFHJUW.js.map +1 -0
  4. package/dist/{chunk-H5E6IO2L.js → chunk-6HJVH27C.js} +9 -11
  5. package/dist/chunk-6HJVH27C.js.map +1 -0
  6. package/dist/{chunk-7BHDKEGK.js → chunk-DQB3E2SX.js} +3 -3
  7. package/dist/{chunk-APWMMZOK.js → chunk-EGC7PNDI.js} +31 -24
  8. package/dist/chunk-EGC7PNDI.js.map +1 -0
  9. package/dist/{chunk-6PGXTLA4.js → chunk-EHEBN4NB.js} +2 -2
  10. package/dist/{chunk-EFXVYQGT.js → chunk-GNMRXXRY.js} +39 -40
  11. package/dist/chunk-GNMRXXRY.js.map +1 -0
  12. package/dist/{chunk-FQF6VHO3.js → chunk-ICHWAFAC.js} +3 -3
  13. package/dist/{chunk-FQF6VHO3.js.map → chunk-ICHWAFAC.js.map} +1 -1
  14. package/dist/{chunk-3PJZ4QNJ.js → chunk-MFCZARV2.js} +9 -9
  15. package/dist/chunk-MFCZARV2.js.map +1 -0
  16. package/dist/{chunk-TVEDNGVP.js → chunk-P5XEK7HC.js} +2 -2
  17. package/dist/{chunk-REHVGFJE.js → chunk-Q4NWATGH.js} +31 -27
  18. package/dist/chunk-Q4NWATGH.js.map +1 -0
  19. package/dist/{chunk-IXVGBUWI.js → chunk-SI2LLEIR.js} +5 -5
  20. package/dist/{chunk-R7GKQBZJ.js → chunk-SNXEYAFP.js} +44 -30
  21. package/dist/chunk-SNXEYAFP.js.map +1 -0
  22. package/dist/{chunk-QCX66KBM.js → chunk-SRII2GMF.js} +3 -3
  23. package/dist/{chunk-AIBVAYHS.js → chunk-TG3SPPZY.js} +2 -2
  24. package/dist/{chunk-WUSEZFER.js → chunk-U46LYYRA.js} +3 -2
  25. package/dist/{chunk-WUSEZFER.js.map → chunk-U46LYYRA.js.map} +1 -1
  26. package/dist/{chunk-I3WF6L43.js → chunk-XYBHH3M5.js} +2 -2
  27. package/dist/{chunk-ECPFYHDX.js → chunk-YLFKFVQP.js} +11 -11
  28. package/dist/chunk-YLFKFVQP.js.map +1 -0
  29. package/dist/{chunk-E45IT3HC.js → chunk-YM3VEDAP.js} +585 -307
  30. package/dist/chunk-YM3VEDAP.js.map +1 -0
  31. package/dist/commands/build/marketplace.js +4 -4
  32. package/dist/commands/build/plugins.js +6 -6
  33. package/dist/commands/compile.js +16 -16
  34. package/dist/commands/compile.js.map +1 -1
  35. package/dist/commands/doctor.js +73 -78
  36. package/dist/commands/doctor.js.map +1 -1
  37. package/dist/commands/edit.js +45 -38
  38. package/dist/commands/edit.js.map +1 -1
  39. package/dist/commands/eject.js +27 -18
  40. package/dist/commands/eject.js.map +1 -1
  41. package/dist/commands/init.js +16 -17
  42. package/dist/commands/list.js +7 -8
  43. package/dist/commands/list.js.map +1 -1
  44. package/dist/commands/new/marketplace.js +4 -4
  45. package/dist/commands/search.js +9 -9
  46. package/dist/commands/share.js +13 -13
  47. package/dist/commands/share.js.map +1 -1
  48. package/dist/commands/uninstall.js +16 -15
  49. package/dist/commands/uninstall.js.map +1 -1
  50. package/dist/commands/update.js +17 -18
  51. package/dist/commands/update.js.map +1 -1
  52. package/dist/components/common/select-list.js +2 -2
  53. package/dist/components/common/skill-agent-summary.js +3 -3
  54. package/dist/components/common/summary-panel.js +4 -4
  55. package/dist/hooks/init.js +23 -25
  56. package/dist/hooks/init.js.map +1 -1
  57. package/dist/load-agent-defs-BJ4KBKBA.js +14 -0
  58. package/dist/{recompile-project-agents-KYK44C24.js → recompile-project-agents-2QTFMYDC.js} +8 -8
  59. package/dist/{source-loader-G5I4RNUP.js → source-loader-I6SWWDUF.js} +4 -4
  60. package/package.json +1 -1
  61. package/dist/chunk-3PJZ4QNJ.js.map +0 -1
  62. package/dist/chunk-APWMMZOK.js.map +0 -1
  63. package/dist/chunk-E45IT3HC.js.map +0 -1
  64. package/dist/chunk-ECPFYHDX.js.map +0 -1
  65. package/dist/chunk-EFXVYQGT.js.map +0 -1
  66. package/dist/chunk-H5E6IO2L.js.map +0 -1
  67. package/dist/chunk-IAQFZFWD.js.map +0 -1
  68. package/dist/chunk-ORO2T4K2.js +0 -96
  69. package/dist/chunk-ORO2T4K2.js.map +0 -1
  70. package/dist/chunk-R7GKQBZJ.js.map +0 -1
  71. package/dist/chunk-REHVGFJE.js.map +0 -1
  72. package/dist/load-agent-defs-5U5KAURA.js +0 -14
  73. /package/dist/{chunk-7BHDKEGK.js.map → chunk-DQB3E2SX.js.map} +0 -0
  74. /package/dist/{chunk-6PGXTLA4.js.map → chunk-EHEBN4NB.js.map} +0 -0
  75. /package/dist/{chunk-TVEDNGVP.js.map → chunk-P5XEK7HC.js.map} +0 -0
  76. /package/dist/{chunk-IXVGBUWI.js.map → chunk-SI2LLEIR.js.map} +0 -0
  77. /package/dist/{chunk-QCX66KBM.js.map → chunk-SRII2GMF.js.map} +0 -0
  78. /package/dist/{chunk-AIBVAYHS.js.map → chunk-TG3SPPZY.js.map} +0 -0
  79. /package/dist/{chunk-I3WF6L43.js.map → chunk-XYBHH3M5.js.map} +0 -0
  80. /package/dist/{load-agent-defs-5U5KAURA.js.map → load-agent-defs-BJ4KBKBA.js.map} +0 -0
  81. /package/dist/{recompile-project-agents-KYK44C24.js.map → recompile-project-agents-2QTFMYDC.js.map} +0 -0
  82. /package/dist/{source-loader-G5I4RNUP.js.map → source-loader-I6SWWDUF.js.map} +0 -0
@@ -13,7 +13,7 @@ import {
13
13
  typedFromEntries,
14
14
  typedKeys,
15
15
  typedValues
16
- } from "./chunk-AIBVAYHS.js";
16
+ } from "./chunk-TG3SPPZY.js";
17
17
  import {
18
18
  AGENT_NAMES,
19
19
  AUTHOR_HANDLE_PATTERN,
@@ -82,7 +82,7 @@ import {
82
82
  seedAgentScope,
83
83
  sourceDirName,
84
84
  validateSelection
85
- } from "./chunk-WUSEZFER.js";
85
+ } from "./chunk-U46LYYRA.js";
86
86
  import {
87
87
  defaultCategories,
88
88
  defaultRules,
@@ -91,8 +91,8 @@ import {
91
91
 
92
92
  // src/cli/lib/loading/source-loader.ts
93
93
  import os14 from "os";
94
- import { partition as partition4, unique as unique6 } from "remeda";
95
- import path29 from "path";
94
+ import { partition as partition5, unique as unique6 } from "remeda";
95
+ import path28 from "path";
96
96
 
97
97
  // src/cli/lib/installation/is-home-directory.ts
98
98
  import fs from "fs";
@@ -105,33 +105,6 @@ function isHomeDirectory(dir) {
105
105
  }
106
106
  }
107
107
 
108
- // src/cli/lib/metadata-keys.ts
109
- var METADATA_KEYS = {
110
- DISPLAY_NAME: "displayName",
111
- CLI_DESCRIPTION: "cliDescription",
112
- CATEGORY: "category",
113
- FORKED_FROM: "forkedFrom",
114
- CONTENT_HASH: "contentHash",
115
- USAGE_GUIDANCE: "usageGuidance",
116
- CUSTOM: "custom"
117
- };
118
- var LOCAL_DEFAULTS = {
119
- AUTHOR: "@dummy-author"
120
- };
121
- var SKILL_CONTENT_FILES = [STANDARD_FILES.SKILL_MD, STANDARD_FILES.REFERENCE_MD];
122
- var SKILL_CONTENT_DIRS = [STANDARD_DIRS.EXAMPLES, STANDARD_DIRS.SCRIPTS];
123
-
124
- // src/cli/utils/errors.ts
125
- function getErrorMessage(error) {
126
- return stripTerminalControls(error instanceof Error ? error.message : String(error));
127
- }
128
-
129
- // src/cli/utils/fs.ts
130
- import fs3 from "fs-extra";
131
- import fg from "fast-glob";
132
- import os3 from "os";
133
- import path2 from "path";
134
-
135
108
  // src/cli/lib/installation/install-layout.ts
136
109
  import fs2 from "fs";
137
110
  import os2 from "os";
@@ -508,11 +481,37 @@ function chooseProviderForThisRun(provider) {
508
481
  function forgetTheProviderChosenForThisRun() {
509
482
  providerChosenForThisRun = void 0;
510
483
  }
484
+ var declaresNothingAsRead = /* @__PURE__ */ new Map();
485
+ function recordWhetherItDeclaresNothing(configPath, declaresNothing) {
486
+ const stamp = stampOf(configPath);
487
+ if (stamp !== null) declaresNothingAsRead.set(configPath, { stamp, declaresNothing });
488
+ }
489
+ function declaresNothingAsLastRead(configPath) {
490
+ const read = declaresNothingAsRead.get(configPath);
491
+ if (read === void 0 || read.stamp !== stampOf(configPath)) return void 0;
492
+ return read.declaresNothing;
493
+ }
494
+ function stampOf(file) {
495
+ try {
496
+ const stats = fs2.statSync(file, { throwIfNoEntry: false });
497
+ return stats === void 0 ? null : `${stats.mtimeMs}:${stats.size}`;
498
+ } catch {
499
+ return null;
500
+ }
501
+ }
511
502
  function providerInUse(root) {
512
503
  if (providerChosenForThisRun !== void 0) return providerChosenForThisRun;
513
504
  if (root === void 0) return PROVIDER_OF_A_NEW_INSTALLATION;
514
505
  return providerOnDisk(root);
515
506
  }
507
+ function inheritedGlobalProvider(projectDir, own = providerInUse(projectDir)) {
508
+ const home = os2.homedir();
509
+ const inheritsItsOwn = holdsAnInstallation(projectDir, own) && holdsAnInstallation(home, own);
510
+ return inheritsItsOwn ? own : providerInUse(home);
511
+ }
512
+ function providerAtScope(projectDir, scope) {
513
+ return scope === "global" ? inheritedGlobalProvider(projectDir) : providerInUse(projectDir);
514
+ }
516
515
  function providerOnDisk(root) {
517
516
  const live = PROVIDERS.find((provider) => holdsAnInstallation(root, provider));
518
517
  if (live !== void 0) return live;
@@ -520,7 +519,8 @@ function providerOnDisk(root) {
520
519
  return started ?? PROVIDER_OF_A_NEW_INSTALLATION;
521
520
  }
522
521
  function holdsAnInstallation(root, provider) {
523
- return holdsAConfig(sourceDir(root, provider));
522
+ const dir = sourceDir(root, provider);
523
+ return holdsAConfig(dir) && declaresNothingAsLastRead(configIn(dir)) !== true;
524
524
  }
525
525
  function holdsASourceFolder(root, provider) {
526
526
  return holdsAnything(sourceDir(root, provider));
@@ -676,7 +676,10 @@ function advisesOnPermissions(provider) {
676
676
  }
677
677
  }
678
678
  function holdsAConfig(dir) {
679
- return fs2.existsSync(path.join(dir, STANDARD_FILES.CONFIG_TS));
679
+ return fs2.existsSync(configIn(dir));
680
+ }
681
+ function configIn(dir) {
682
+ return path.join(dir, STANDARD_FILES.CONFIG_TS);
680
683
  }
681
684
  function holdsAnything(dir) {
682
685
  return directoryExists(dir) && isNotEmpty(dir);
@@ -696,6 +699,29 @@ function directoryExists(dir) {
696
699
  }
697
700
  }
698
701
 
702
+ // src/cli/lib/metadata-keys.ts
703
+ var METADATA_KEYS = {
704
+ DISPLAY_NAME: "displayName",
705
+ CATEGORY: "category",
706
+ CUSTOM: "custom"
707
+ };
708
+ var LOCAL_DEFAULTS = {
709
+ AUTHOR: "@dummy-author"
710
+ };
711
+ var SKILL_CONTENT_FILES = [STANDARD_FILES.SKILL_MD, STANDARD_FILES.REFERENCE_MD];
712
+ var SKILL_CONTENT_DIRS = [STANDARD_DIRS.EXAMPLES, STANDARD_DIRS.SCRIPTS];
713
+
714
+ // src/cli/utils/errors.ts
715
+ function getErrorMessage(error) {
716
+ return stripTerminalControls(error instanceof Error ? error.message : String(error));
717
+ }
718
+
719
+ // src/cli/utils/fs.ts
720
+ import fs3 from "fs-extra";
721
+ import fg from "fast-glob";
722
+ import os3 from "os";
723
+ import path2 from "path";
724
+
699
725
  // src/cli/lib/config-gate/gate-token.ts
700
726
  import { AsyncLocalStorage } from "async_hooks";
701
727
  var gateToken = new AsyncLocalStorage();
@@ -876,6 +902,7 @@ function warnOnce(msg) {
876
902
 
877
903
  // src/cli/utils/messages.ts
878
904
  import path3 from "path";
905
+ import { partition } from "remeda";
879
906
 
880
907
  // src/cli/lib/validate-kebab-name.ts
881
908
  import { unique } from "remeda";
@@ -957,6 +984,8 @@ var INFO_MESSAGES = {
957
984
  CONFIG_TYPES_REFRESHED: `Refreshed ${STANDARD_FILES.CONFIG_TYPES_TS}`,
958
985
  EJECTED_SKILLS_USER_OWNED: `Ejected skills are yours to own \u2014 '${CLI_INVOKE_COMMAND} update' does not change them.`,
959
986
  NO_PLUGIN_MARKETPLACES: "No plugin marketplaces are configured \u2014 nothing to refresh.",
987
+ /** The owner's words (2026-10-24), on stderr before the command's own output. */
988
+ GLOBAL_INSTALLATION_STANDS_IN: "This project's config declares nothing, so this works on your global installation.",
960
989
  /** Under doctor's marketplace row, when its download replaced a saved copy whose files differed. */
961
990
  SAVED_COPY_REPLACED: "The saved copy differed from the marketplace and has been replaced",
962
991
  /** Printed under the destination already named, so it names files only. */
@@ -971,8 +1000,8 @@ function pluginsInstalled(count) {
971
1000
  function localSkillsCopied(count) {
972
1001
  return `Copied ${count} local skill(s)`;
973
1002
  }
974
- function recompileSummary(rewritten, unchanged, subject) {
975
- return `${plural(rewritten, subject)} rewritten, ${unchanged} unchanged`;
1003
+ function recompileSummary(rewritten2, unchanged, subject) {
1004
+ return `${plural(rewritten2, subject)} rewritten, ${unchanged} unchanged`;
976
1005
  }
977
1006
  function agentsNotCompiled(agentNames) {
978
1007
  return `${agentNames.length} sub-agent(s) did not compile: ${agentNames.join(", ")}`;
@@ -1167,14 +1196,27 @@ function changeTheGlobalInstallFromHome(named) {
1167
1196
  function unknownKeys(keys) {
1168
1197
  return keys.map(inertLine).join(", ");
1169
1198
  }
1170
- function skippedUnknownSkills(skillIds, installedWithout) {
1199
+ var SKIP_CAUSE = {
1200
+ UNLOADED: "could not load",
1201
+ UNKNOWN: "does not know"
1202
+ };
1203
+ function skippedSkills(skillIds, installedWithout, unloadedSkillIds) {
1204
+ const [unloaded, unknown] = partition(skillIds, (id) => unloadedSkillIds.has(id));
1171
1205
  return [
1172
- `Skipped ${skillIds.length} skill(s) this catalog does not know: ${unknownKeys(skillIds)}`,
1173
- ...installedWithout.map(
1174
- ({ skillId, agentNames }) => ` sub-agent(s) installed without ${unknownKeys([skillId])}, carrying nothing else this catalog knows: ${agentNames.join(", ")}`
1175
- )
1206
+ ...skippedFor(SKIP_CAUSE.UNLOADED, unloaded, installedWithout),
1207
+ ...skippedFor(SKIP_CAUSE.UNKNOWN, unknown, installedWithout)
1176
1208
  ].join("\n");
1177
1209
  }
1210
+ function skippedFor(cause, skillIds, installedWithout) {
1211
+ if (skillIds.length === 0) return [];
1212
+ return [
1213
+ `Skipped ${skillIds.length} skill(s) this catalog ${cause}: ${unknownKeys(skillIds)}`,
1214
+ ...installedWithout.filter(({ skillId }) => skillIds.includes(skillId)).map(subAgentsInstalledWithout)
1215
+ ];
1216
+ }
1217
+ function subAgentsInstalledWithout({ skillId, agentNames }) {
1218
+ return ` sub-agent(s) installed without ${unknownKeys([skillId])}, carrying nothing else this catalog knows: ${agentNames.join(", ")}`;
1219
+ }
1178
1220
  function skippedUnknownAgents(agentNames) {
1179
1221
  return `Skipped ${agentNames.length} unknown sub-agent(s): ${unknownKeys(agentNames)}`;
1180
1222
  }
@@ -1212,10 +1254,13 @@ function addMarketplaceInTheEditor(ref, isFolder) {
1212
1254
  var SHARED_CONFIG_ARRIVALS = {
1213
1255
  INSTALL_CONFIRM: "Install this configuration?"
1214
1256
  };
1215
- function keptAsInstalledGlobally(skillIds, agentNames, idAppliedAtHome, provider) {
1257
+ function skillName(id, namedBy) {
1258
+ return getSkillEntryDisplayName(namedBy[id] ?? { id });
1259
+ }
1260
+ function keptAsInstalledGlobally(skillIds, agentNames, idAppliedAtHome, provider, namedBy) {
1216
1261
  return [
1217
1262
  "Kept as installed in the global install \u2014 this configuration states them differently or leaves them out, and a project run only adds to the global install:",
1218
- ...skillIds.map((id) => ` skill ${id}`),
1263
+ ...skillIds.map((id) => ` skill ${skillName(id, namedBy)}`),
1219
1264
  ...agentNames.map((name) => ` sub-agent ${name}`),
1220
1265
  ...idAppliedAtHome === void 0 ? [] : [
1221
1266
  `Change them with '${CLI_INVOKE_COMMAND} edit --from ${idAppliedAtHome}${providerArgument(provider)}' from your home directory.`
@@ -1223,7 +1268,7 @@ function keptAsInstalledGlobally(skillIds, agentNames, idAppliedAtHome, provider
1223
1268
  ].join("\n");
1224
1269
  }
1225
1270
  function skillsMoved(verb, skillIds, namedBy) {
1226
- const names = skillIds.map((id) => getSkillEntryDisplayName(namedBy[id] ?? { id }));
1271
+ const names = skillIds.map((id) => skillName(id, namedBy));
1227
1272
  return names.length === 0 ? [] : [`${verb} ${listed(names)}`];
1228
1273
  }
1229
1274
  function settingMoved({ setting, from, to }) {
@@ -1250,29 +1295,28 @@ function subAgentChanged({
1250
1295
  const where = scope === "global" ? " (global)" : "";
1251
1296
  return `~ ${name}${where}: ${details.length > 0 ? details.join(", ") : SKILLS_REASSIGNED}`;
1252
1297
  }
1253
- function addedToGlobalSubAgents(joined) {
1298
+ function addedToGlobalSubAgents(joined, namedBy) {
1299
+ const gains = (skillIds) => skillIds.map((id) => skillName(id, namedBy)).join(", ");
1254
1300
  return [
1255
1301
  "Added to sub-agents in the global install \u2014 each keeps everything it already has, since a project run only adds to the global install:",
1256
- ...joined.map(
1257
- ({ agentName, skillIds }) => ` sub-agent ${agentName}: + ${skillIds.join(", ")}`
1258
- )
1302
+ ...joined.map(({ agentName, skillIds }) => ` sub-agent ${agentName}: + ${gains(skillIds)}`)
1259
1303
  ].join("\n");
1260
1304
  }
1261
- function authoredHereKept(skillIds) {
1305
+ function authoredHereKept(skillIds, namedBy) {
1262
1306
  return [
1263
1307
  "Kept \u2014 written here rather than installed, so a shared configuration never carried them:",
1264
- ...skillIds.map((id) => ` skill ${id}`)
1308
+ ...skillIds.map((id) => ` skill ${skillName(id, namedBy)}`)
1265
1309
  ].join("\n");
1266
1310
  }
1267
- function unplaceableKept(skillIds) {
1311
+ function unplaceableKept(skillIds, namedBy) {
1268
1312
  return [
1269
1313
  "Kept \u2014 named by this configuration, and this catalogue cannot place them:",
1270
- ...skillIds.map((id) => ` skill ${id}`),
1314
+ ...skillIds.map((id) => ` skill ${skillName(id, namedBy)}`),
1271
1315
  `Run '${CLI_INVOKE_COMMAND} update' to refresh this installation's marketplace, then apply the configuration again.`
1272
1316
  ].join("\n");
1273
1317
  }
1274
- function keptUnassigned(skillId, agentName, category) {
1275
- return `${skillId}: kept, no longer assigned to ${agentName}'s ${category}`;
1318
+ function keptUnassigned({ skillId, agentName, category }, namedBy) {
1319
+ return `${skillName(skillId, namedBy)}: kept, no longer assigned to ${agentName}'s ${category}`;
1276
1320
  }
1277
1321
  function doctorReportsTheSame(count) {
1278
1322
  return `'${CLI_INVOKE_COMMAND} doctor' reports the same ${count === 1 ? "file" : "files"}, alongside whatever else is wrong here.`;
@@ -1967,16 +2011,16 @@ import { z as z3 } from "zod";
1967
2011
 
1968
2012
  // src/cli/lib/schemas.ts
1969
2013
  import { z as z2 } from "zod";
1970
- import { partition } from "remeda";
2014
+ import { partition as partition2 } from "remeda";
1971
2015
 
1972
2016
  // src/cli/lib/schema-validator.ts
1973
2017
  import "zod";
1974
2018
  function formatZodIssue(issue) {
1975
- const path30 = stripTerminalControls(issue.path.join("."));
1976
2019
  if (issue.code === "unrecognized_keys") {
1977
- return `Unrecognized key: "${stripTerminalControls(issue.keys.join('", "'))}"`;
2020
+ return `Unrecognized key: "${inertLine(issue.keys.join('", "'))}"`;
1978
2021
  }
1979
- return path30 ? `${path30}: ${stripTerminalControls(issue.message)}` : stripTerminalControls(issue.message);
2022
+ const path29 = inertLine(issue.path.join("."));
2023
+ return path29 ? `${path29}: ${inertLine(issue.message)}` : inertLine(issue.message);
1980
2024
  }
1981
2025
  function formatZodErrors(error) {
1982
2026
  return error.issues.map(formatZodIssue);
@@ -2118,12 +2162,12 @@ var RENAMED_SKILL_ENTRY_FIELDS = { source: "origin" };
2118
2162
  function renamedFieldMessage(oldKey, newKey) {
2119
2163
  return `"${oldKey}" was renamed to "${newKey}". Rename the key in this config \u2014 the CLI does not read "${oldKey}" any more and will not fall back to it.`;
2120
2164
  }
2121
- function reportRenamedKeys(record, renames, path30, ctx) {
2165
+ function reportRenamedKeys(record, renames, path29, ctx) {
2122
2166
  for (const [oldKey, newKey] of Object.entries(renames)) {
2123
2167
  if (!(oldKey in record)) continue;
2124
2168
  ctx.addIssue({
2125
2169
  code: "custom",
2126
- path: [...path30, oldKey],
2170
+ path: [...path29, oldKey],
2127
2171
  message: renamedFieldMessage(oldKey, newKey)
2128
2172
  });
2129
2173
  }
@@ -2454,7 +2498,7 @@ function metadataSchemaFor(raw) {
2454
2498
  return isCarriedMetadata(raw) ? carriedMetadataValidationSchema : customMetadataValidationSchema;
2455
2499
  }
2456
2500
  function describeMetadataSchemaFailure(issues, rawMetadata) {
2457
- const [absent, malformed] = partition(issues, (issue) => isAbsentField(issue, rawMetadata));
2501
+ const [absent, malformed] = partition2(issues, (issue) => isAbsentField(issue, rawMetadata));
2458
2502
  return [
2459
2503
  ...absent.length > 0 ? [nameMissingFields(absent)] : [],
2460
2504
  ...malformed.map(formatZodIssue)
@@ -2481,7 +2525,7 @@ function formatOverLengthWarning(issue, cliDescription) {
2481
2525
  return `cliDescription is ${cliDescription.length} characters \u2014 exceeds the recommended maximum of ${CLI_DESCRIPTION_MAX_LENGTH}`;
2482
2526
  }
2483
2527
  function splitMetadataValidationIssues(error, rawMetadata) {
2484
- const [overLength, hardFailures] = partition(error.issues, isOverLengthCliDescription);
2528
+ const [overLength, hardFailures] = partition2(error.issues, isOverLengthCliDescription);
2485
2529
  const cliDescription = readCliDescription(rawMetadata);
2486
2530
  const warnings = overLength.map((issue) => formatOverLengthWarning(issue, cliDescription));
2487
2531
  return { errors: hardFailures.map(formatZodIssue), warnings };
@@ -2598,7 +2642,7 @@ function getInstalledConfigPath(dir) {
2598
2642
  }
2599
2643
  function resolveInstallPaths(projectDir, scope = "project") {
2600
2644
  const baseDir = installBaseDir(projectDir, scope);
2601
- const provider = providerInUse(baseDir);
2645
+ const provider = providerAtScope(projectDir, scope);
2602
2646
  return {
2603
2647
  skillsDir: skillsDir(provider, scope, projectDir),
2604
2648
  agentsDir: agentsDir(provider, scope, projectDir),
@@ -2688,13 +2732,16 @@ async function loadSourceRepoConfig(basePath) {
2688
2732
  async function loadProjectSourceConfig(projectDir) {
2689
2733
  return loadSourceConfig(projectDir, isHomeDirectory(projectDir) ? "global" : "project");
2690
2734
  }
2691
- async function loadGlobalSourceConfig() {
2692
- return loadSourceConfig(os4.homedir(), "global");
2735
+ async function loadGlobalSourceConfig(provider) {
2736
+ return loadSourceConfig(os4.homedir(), "global", provider);
2693
2737
  }
2694
2738
  async function loadEffectiveSourceConfig(projectDir, provider) {
2695
2739
  const ownDir = ownProjectDir(projectDir);
2696
2740
  const own = ownDir === null ? null : await readStoredRung(ownDir, "project", provider);
2697
- return own ?? await readStoredRung(os4.homedir(), "global", provider);
2741
+ return own ?? await readStoredRung(os4.homedir(), "global", provider ?? inheritedBy(projectDir));
2742
+ }
2743
+ function inheritedBy(projectDir) {
2744
+ return inheritedGlobalProvider(projectDir ?? os4.homedir());
2698
2745
  }
2699
2746
  async function readStoredRung(dir, origin, provider) {
2700
2747
  const config = await loadSourceConfig(dir, origin, provider);
@@ -2793,7 +2840,7 @@ ${getErrorMessage(error)}`
2793
2840
  async function resolveBranding(projectDir) {
2794
2841
  const [own, global] = await Promise.all([
2795
2842
  loadOwnProjectSourceConfig(projectDir),
2796
- loadGlobalSourceConfig()
2843
+ loadGlobalSourceConfig(inheritedBy(projectDir))
2797
2844
  ]);
2798
2845
  return {
2799
2846
  name: own?.branding?.name ?? global?.branding?.name ?? DEFAULT_BRANDING.NAME
@@ -3139,7 +3186,7 @@ seatDiagnostics({
3139
3186
  });
3140
3187
 
3141
3188
  // ../compile/src/seed-to-config.ts
3142
- import { groupBy, indexBy, isDefined, mapValues, omit as omit2, partition as partition2 } from "remeda";
3189
+ import { groupBy, indexBy, isDefined, mapValues, omit as omit2, partition as partition3 } from "remeda";
3143
3190
 
3144
3191
  // ../compile/src/config-source.ts
3145
3192
  import { omit } from "remeda";
@@ -3656,12 +3703,12 @@ function mergeInlinedScalarFields(cleaned, cleanedGlobal) {
3656
3703
  ).filter(([key]) => isCopiedScalarField(key));
3657
3704
  }
3658
3705
  function generateProjectConfigWithInlinedGlobal(cleaned, cleanedGlobal) {
3659
- const partition5 = partitionInlinedConfigEntries(cleaned, cleanedGlobal);
3706
+ const partition6 = partitionInlinedConfigEntries(cleaned, cleanedGlobal);
3660
3707
  const emitted = {
3661
- hasSkills: partition5.globalSkills.length > 0 || partition5.projectSkills.length > 0,
3662
- hasAgents: partition5.globalAgents.length > 0 || partition5.projectAgents.length > 0,
3663
- hasStack: hasStackEntries(partition5.filteredStack),
3664
- hasSelectedDomains: partition5.selectedDomains.length > 0
3708
+ hasSkills: partition6.globalSkills.length > 0 || partition6.projectSkills.length > 0,
3709
+ hasAgents: partition6.globalAgents.length > 0 || partition6.projectAgents.length > 0,
3710
+ hasStack: hasStackEntries(partition6.filteredStack),
3711
+ hasSelectedDomains: partition6.selectedDomains.length > 0
3665
3712
  };
3666
3713
  const scalarFields = mergeInlinedScalarFields(cleaned, cleanedGlobal);
3667
3714
  return assembleConfigSource({
@@ -3672,15 +3719,15 @@ function generateProjectConfigWithInlinedGlobal(cleaned, cleanedGlobal) {
3672
3719
  ...emitted.hasSkills ? entryDeclaration(
3673
3720
  "skills",
3674
3721
  "SkillConfig[]",
3675
- scopeSectionEntries(partition5.globalSkills, partition5.projectSkills)
3722
+ scopeSectionEntries(partition6.globalSkills, partition6.projectSkills)
3676
3723
  ) : [],
3677
3724
  ...emitted.hasAgents ? entryDeclaration(
3678
3725
  "agents",
3679
3726
  "AgentScopeConfig[]",
3680
- scopeSectionEntries(partition5.globalAgents, partition5.projectAgents)
3727
+ scopeSectionEntries(partition6.globalAgents, partition6.projectAgents)
3681
3728
  ) : [],
3682
- ...emitted.hasStack ? declaration("stack", STACK_TYPE, partition5.filteredStack) : [],
3683
- ...emitted.hasSelectedDomains ? declaration("selectedDomains", "Domain[]", partition5.selectedDomains) : []
3729
+ ...emitted.hasStack ? declaration("stack", STACK_TYPE, partition6.filteredStack) : [],
3730
+ ...emitted.hasSelectedDomains ? declaration("selectedDomains", "Domain[]", partition6.selectedDomains) : []
3684
3731
  ],
3685
3732
  exportFields: [
3686
3733
  renderScalarField("name", resolveProjectName(cleaned)),
@@ -3835,7 +3882,7 @@ function assertScopeConfigsGiven(skillConfigs, agentConfigs) {
3835
3882
  }
3836
3883
  }
3837
3884
  function resolveValidSkills(selectedSkillIds, skillConfigs, catalog) {
3838
- const [found, absent] = partition2(
3885
+ const [found, absent] = partition3(
3839
3886
  selectedSkillIds.map((skillId) => ({
3840
3887
  skillId,
3841
3888
  skill: catalog.skills[skillId]
@@ -3885,7 +3932,7 @@ function skillIdsByCategory(skills) {
3885
3932
  );
3886
3933
  }
3887
3934
  function buildSkillScopeMap(skillConfigs) {
3888
- const [excludedConfigs, activeConfigs] = partition2(
3935
+ const [excludedConfigs, activeConfigs] = partition3(
3889
3936
  skillConfigs,
3890
3937
  (s) => Boolean(s.excluded)
3891
3938
  );
@@ -4030,11 +4077,11 @@ function mapCategoriesDroppingEmpty(agentStack, transform) {
4030
4077
  );
4031
4078
  }
4032
4079
  function splitConfigByScope(config) {
4033
- const [globalSkills, projectSkills] = partition2(
4080
+ const [globalSkills, projectSkills] = partition3(
4034
4081
  config.skills,
4035
4082
  (s) => isActiveAt(s, "global")
4036
4083
  );
4037
- const [globalAgents, projectAgents] = partition2(
4084
+ const [globalAgents, projectAgents] = partition3(
4038
4085
  config.agents,
4039
4086
  (a) => isActiveAt(a, "global")
4040
4087
  );
@@ -4094,9 +4141,9 @@ function splitAgentStack(agentStack, globalSkillIds) {
4094
4141
  }
4095
4142
  function seedToInstallSelection(payload, catalog) {
4096
4143
  const agentMap = readAgentMap(payload.agents);
4144
+ refuseUnwritableAssignments(payload.skills, agentMap);
4097
4145
  const { installable, skipped } = resolveSeedSkills(payload.skills, catalog);
4098
4146
  const rows = installable.flatMap((skill) => assignmentRows(skill, agentMap));
4099
- refuseUnwritableAssignments(rows);
4100
4147
  const placed = rows.filter((row) => row.kind === "placed");
4101
4148
  const carried = new Set(agentsCarriedIn(placed, agentMap));
4102
4149
  const selectedAgents = withAgentsSkippedSkillsName(carried, skipped, agentMap);
@@ -4130,12 +4177,23 @@ function seedToInstallSelection(payload, catalog) {
4130
4177
  )
4131
4178
  };
4132
4179
  }
4133
- function refuseUnwritableAssignments(rows) {
4134
- const unwritable = rows.filter((row) => row.kind === "unwritable");
4180
+ function refuseUnwritableAssignments(seedSkills, agentMap) {
4181
+ const unwritable = unwritableAssignmentsOf(seedSkills, agentMap);
4135
4182
  if (unwritable.length > 0) {
4136
4183
  throw new Error(unwritableAssignmentsError(unwritable));
4137
4184
  }
4138
4185
  }
4186
+ function unwritableAssignmentsOf(seedSkills, agentMap) {
4187
+ return Object.entries(seedSkills).flatMap(
4188
+ ([skillId, seedSkill]) => agentsNamedBy(seedSkill, agentMap).filter((agent) => !isWritablePair(seedSkill, agent, agentMap)).map((agent) => ({ skillId, agent }))
4189
+ );
4190
+ }
4191
+ function isWritablePair(seedSkill, agent, agentMap) {
4192
+ return isScopePairCompatible(
4193
+ seedSkill.scope,
4194
+ seedAgentScope(agentMap.known.get(agent))
4195
+ );
4196
+ }
4139
4197
  function agentsCarriedIn(placed, agentMap) {
4140
4198
  return [...placed.map((row) => row.agent), ...agentsSwitchedOn(agentMap)];
4141
4199
  }
@@ -4143,7 +4201,7 @@ function withAgentsSkippedSkillsName(carried, skipped, agentMap) {
4143
4201
  return [
4144
4202
  .../* @__PURE__ */ new Set([
4145
4203
  ...carried,
4146
- ...skipped.flatMap((skill) => agentsNamedBy(skill, agentMap))
4204
+ ...skipped.flatMap((skill) => agentsNamedBy(skill.seedSkill, agentMap))
4147
4205
  ])
4148
4206
  ];
4149
4207
  }
@@ -4151,11 +4209,11 @@ function skippedAgentNamesOf(agentMap, rows) {
4151
4209
  const unknownAssignees = rows.filter((row) => row.kind === "unknownAgent").map((row) => row.agentName);
4152
4210
  return [.../* @__PURE__ */ new Set([...agentMap.unknown, ...unknownAssignees])];
4153
4211
  }
4154
- function agentsNamedBy({ seedSkill }, agentMap) {
4212
+ function agentsNamedBy(seedSkill, agentMap) {
4155
4213
  return Object.keys(seedSkill.assignments).filter(isAgentName2).filter((name) => !agentMap.switchedOff.has(name));
4156
4214
  }
4157
4215
  function agentsOnlyItCarried(skill, agentMap, carried) {
4158
- const agentNames = agentsNamedBy(skill, agentMap).filter(
4216
+ const agentNames = agentsNamedBy(skill.seedSkill, agentMap).filter(
4159
4217
  (name) => !carried.has(name)
4160
4218
  );
4161
4219
  return agentNames.length === 0 ? [] : [{ skillId: skill.skillId, agentNames }];
@@ -4219,10 +4277,6 @@ function assignmentRows(skill, agentMap) {
4219
4277
  function assignmentRow(skill, agentName, load, agentMap) {
4220
4278
  if (agentMap.switchedOff.has(agentName)) return void 0;
4221
4279
  if (!isAgentName2(agentName)) return { kind: "unknownAgent", agentName };
4222
- const agentScope = seedAgentScope(agentMap.known.get(agentName));
4223
- if (!isScopePairCompatible(skill.seedSkill.scope, agentScope)) {
4224
- return { kind: "unwritable", skillId: skill.id, agent: agentName };
4225
- }
4226
4280
  return {
4227
4281
  kind: "placed",
4228
4282
  agent: agentName,
@@ -4281,7 +4335,7 @@ import path8 from "path";
4281
4335
 
4282
4336
  // src/cli/lib/stacks/stacks-loader.ts
4283
4337
  import path7 from "path";
4284
- import { flatMap, groupBy as groupBy2, mapValues as mapValues2, partition as partition3, pipe, unique as unique2, uniqueBy } from "remeda";
4338
+ import { flatMap, groupBy as groupBy2, mapValues as mapValues2, partition as partition4, pipe, unique as unique2, uniqueBy } from "remeda";
4285
4339
  var stacksCache = /* @__PURE__ */ new Map();
4286
4340
  function normalizeAgentConfig(agentConfig) {
4287
4341
  return mapValues2(agentConfig, (value) => {
@@ -4312,7 +4366,7 @@ function placeAssignments(agentConfig) {
4312
4366
  );
4313
4367
  }
4314
4368
  function rekeyToLiveCategories(agentConfig) {
4315
- const [settled, moved] = partition3(
4369
+ const [settled, moved] = partition4(
4316
4370
  placeAssignments(agentConfig),
4317
4371
  (placed) => placed.liveCategory === placed.storedCategory
4318
4372
  );
@@ -4437,6 +4491,14 @@ var ConfigLoadError = class extends Error {
4437
4491
  /** Named in the remedy's `init --from` half, which a bare run would answer with another one. */
4438
4492
  initProviderToName;
4439
4493
  };
4494
+ function declaresNoContent(config) {
4495
+ return config.skills.length === 0 && config.agents.length === 0;
4496
+ }
4497
+ async function configDeclaresNothing(projectDir, provider) {
4498
+ const configPath = getProjectConfigPath(projectDir, provider);
4499
+ const parsed = await parseConfigFile(configPath, refusalAt(configPath, projectDir, provider));
4500
+ return declaresNoContent({ skills: parsed.skills ?? [], agents: parsed.agents ?? [] });
4501
+ }
4440
4502
  async function loadProjectConfigFromDir(projectDir, provider) {
4441
4503
  return loadProjectConfigAt(getProjectConfigPath(projectDir, provider), projectDir, provider);
4442
4504
  }
@@ -4447,8 +4509,7 @@ async function loadProjectConfigAt(configPath, projectDir, provider) {
4447
4509
  verbose(`${scopeLabel2} config not found at ${configPath}`);
4448
4510
  return null;
4449
4511
  }
4450
- const refuse = (reason) => new ConfigLoadError(configPath, reason, projectDir, provider);
4451
- const parsed = await parseConfigFile(configPath, refuse);
4512
+ const parsed = await parseConfigFile(configPath, refusalAt(configPath, projectDir, provider));
4452
4513
  const config = asProjectConfig(parsed, projectDir);
4453
4514
  warnOfDefaultedFields(parsed, configPath);
4454
4515
  verbose(`Loaded ${scope} config from ${configPath}`);
@@ -4458,6 +4519,9 @@ async function loadProjectConfigAt(configPath, projectDir, provider) {
4458
4519
  provider
4459
4520
  };
4460
4521
  }
4522
+ function refusalAt(configPath, projectDir, provider) {
4523
+ return (reason) => new ConfigLoadError(configPath, reason, projectDir, provider);
4524
+ }
4461
4525
  async function parseConfigFile(configPath, refuse) {
4462
4526
  let raw;
4463
4527
  try {
@@ -4493,29 +4557,39 @@ function warnOfDefaultedFields(parsed, configPath) {
4493
4557
  async function loadInstalledConfig(dir) {
4494
4558
  return loadProjectConfigFromDir(dir, providerInUse(dir));
4495
4559
  }
4496
- function configDirsInPlay(projectDir) {
4497
- return isHomeDirectory(projectDir) ? [projectDir] : [projectDir, os5.homedir()];
4560
+ function configsInPlay(projectDir) {
4561
+ const own = { dir: projectDir, provider: providerInUse(projectDir) };
4562
+ if (isHomeDirectory(projectDir)) return [own];
4563
+ return [own, { dir: os5.homedir(), provider: inheritedGlobalProvider(projectDir) }];
4498
4564
  }
4499
4565
  async function findConfigLoadFailures(projectDir) {
4500
- const outcomes = await Promise.all(configDirsInPlay(projectDir).map(configLoadFailure2));
4566
+ const outcomes = await Promise.all(configsInPlay(projectDir).map(configLoadFailure2));
4501
4567
  return outcomes.filter((failure) => failure !== void 0);
4502
4568
  }
4503
- async function configLoadFailure2(dir) {
4569
+ async function configLoadFailure2({
4570
+ dir,
4571
+ provider
4572
+ }) {
4504
4573
  try {
4505
- await loadInstalledConfig(dir);
4574
+ await loadProjectConfigFromDir(dir, provider);
4506
4575
  return void 0;
4507
4576
  } catch (error) {
4508
4577
  if (error instanceof ConfigLoadError) return error;
4509
4578
  throw error;
4510
4579
  }
4511
4580
  }
4512
- async function loadProjectConfig(projectDir) {
4513
- const provider = providerInUse(projectDir);
4581
+ async function loadProjectConfig(projectDir, provider = providerInUse(projectDir)) {
4514
4582
  const projectResult = await loadProjectConfigFromDir(projectDir, provider);
4515
4583
  if (projectResult) return projectResult;
4516
4584
  if (isHomeDirectory(projectDir)) return null;
4517
4585
  return loadProjectConfigFromDir(os5.homedir(), provider);
4518
4586
  }
4587
+ async function loadConfigInPlay(projectDir) {
4588
+ const own = await loadInstalledConfig(projectDir);
4589
+ if (isHomeDirectory(projectDir)) return own;
4590
+ if (own !== null && !declaresNoContent(own.config)) return own;
4591
+ return loadInstalledConfig(os5.homedir());
4592
+ }
4519
4593
  function validateProjectConfig(config) {
4520
4594
  const result = projectConfigLoaderSchema.safeParse(config);
4521
4595
  if (!result.success) {
@@ -4870,6 +4944,21 @@ async function copySkillsToLocalFlattened(selectedSkillIds, localSkillsDir, sour
4870
4944
  (skillId) => copySelectedSkill(skillId, localSkillsDir, sourceResult, sourceSelections?.[skillId])
4871
4945
  );
4872
4946
  }
4947
+ async function copyMarketplaceSkillsToLocalFlattened(marketplaceSkillIds, localSkillsDir, sourceResult) {
4948
+ return copyEachSkill(
4949
+ marketplaceSkillIds,
4950
+ (skillId) => copySkillToLocalFlattened(
4951
+ marketplaceSkillOf(skillId, sourceResult),
4952
+ localSkillsDir,
4953
+ sourceResult
4954
+ )
4955
+ );
4956
+ }
4957
+ function marketplaceSkillOf(skillId, sourceResult) {
4958
+ const skill = sourceResult.marketplaceSkills[skillId];
4959
+ if (!skill) throw new Error(`Not one of the marketplace's skills: ${skillId}`);
4960
+ return skill;
4961
+ }
4873
4962
  async function copySelectedSkill(skillId, localSkillsDir, sourceResult, selectedSource) {
4874
4963
  const skill = getSkillById(skillId);
4875
4964
  const localPath = picksRemoteSource(selectedSource) ? void 0 : localPathOf(skill);
@@ -4896,7 +4985,7 @@ async function copyLocalSkillTo(skill, localPath, destPath) {
4896
4985
  }
4897
4986
 
4898
4987
  // src/cli/lib/skills/skill-plugin-compiler.ts
4899
- import path24 from "path";
4988
+ import path23 from "path";
4900
4989
  import { parse as parseYaml4 } from "yaml";
4901
4990
 
4902
4991
  // src/cli/lib/plugins/plugin-manifest.ts
@@ -5003,7 +5092,6 @@ import { readdir } from "fs/promises";
5003
5092
 
5004
5093
  // src/cli/lib/installation/installation.ts
5005
5094
  import os7 from "os";
5006
- import path14 from "path";
5007
5095
  var INSTALL_MODE_LABELS = {
5008
5096
  plugin: "Plugin",
5009
5097
  mixed: "Mixed",
@@ -5013,9 +5101,6 @@ var INSTALL_MODE_DESCRIPTIONS = {
5013
5101
  plugin: `${INSTALL_MODE_LABELS.plugin} (native install)`,
5014
5102
  eject: `${INSTALL_MODE_LABELS.eject} (local copy)`
5015
5103
  };
5016
- function declaresNoContent(config) {
5017
- return config.skills.length === 0 && config.agents.length === 0;
5018
- }
5019
5104
  function deriveInstallMode(skills) {
5020
5105
  if (skills.length === 0) return "eject";
5021
5106
  const hasEject = skills.some((s) => s.origin === EJECT_SOURCE);
@@ -5023,8 +5108,7 @@ function deriveInstallMode(skills) {
5023
5108
  if (hasEject && hasPlugin) return "mixed";
5024
5109
  return hasEject ? "eject" : "plugin";
5025
5110
  }
5026
- async function detectInstallationInDir(dir, scope) {
5027
- const provider = providerInUse(dir);
5111
+ async function detectInstallationInDir(dir, scope, provider = providerInUse(dir)) {
5028
5112
  const configPath = getProjectConfigPath(dir, provider);
5029
5113
  if (!await fileExists(configPath)) {
5030
5114
  return null;
@@ -5036,17 +5120,10 @@ async function detectInstallationInDir(dir, scope) {
5036
5120
  if (declaresNoContent(loaded.config)) {
5037
5121
  return null;
5038
5122
  }
5039
- const mode = deriveInstallMode(loaded.config.skills);
5040
5123
  return {
5041
- mode,
5124
+ mode: deriveInstallMode(loaded.config.skills),
5042
5125
  configPath,
5043
5126
  agentsDir: agentsDir(provider, scope, dir),
5044
- // Mixed mode uses the local skills dir, as eject does.
5045
- skillsDir: path14.join(
5046
- dir,
5047
- CLAUDE_DIR,
5048
- mode === "plugin" ? PLUGINS_SUBDIR : STANDARD_DIRS.SKILLS
5049
- ),
5050
5127
  projectDir: dir
5051
5128
  };
5052
5129
  }
@@ -5061,23 +5138,23 @@ async function holdsItsOwnInstallation(dir) {
5061
5138
  throw error;
5062
5139
  }
5063
5140
  }
5064
- async function detectGlobalInstallation() {
5065
- return detectInstallationInDir(os7.homedir(), "global");
5141
+ async function detectGlobalInstallation(projectDir) {
5142
+ return detectInstallationInDir(os7.homedir(), "global", inheritedGlobalProvider(projectDir));
5066
5143
  }
5067
5144
  async function detectInstallation(projectDir = process.cwd()) {
5068
5145
  const projectInstallation = await detectProjectInstallation(projectDir);
5069
5146
  if (projectInstallation) return projectInstallation;
5070
- return detectGlobalInstallation();
5147
+ return detectGlobalInstallation(projectDir);
5071
5148
  }
5072
5149
 
5073
5150
  // src/cli/lib/installation/local-installer.ts
5074
5151
  import os10 from "os";
5075
- import path18 from "path";
5152
+ import path17 from "path";
5076
5153
  import { unique as unique4 } from "remeda";
5077
5154
 
5078
5155
  // src/cli/lib/loading/loader.ts
5079
5156
  import { parse as parseYaml3 } from "yaml";
5080
- import path15 from "path";
5157
+ import path14 from "path";
5081
5158
 
5082
5159
  // src/cli/utils/frontmatter.ts
5083
5160
  import { parse as parseYaml2 } from "yaml";
@@ -5150,7 +5227,7 @@ async function loadAgentsFromDir(agentsDir2, sourceRoot, options) {
5150
5227
  return agents;
5151
5228
  }
5152
5229
  async function readAgentDefinition(agentsDir2, file, sourceRoot, options) {
5153
- const fullPath = path15.join(agentsDir2, file);
5230
+ const fullPath = path14.join(agentsDir2, file);
5154
5231
  try {
5155
5232
  const content = await readFile(fullPath);
5156
5233
  const parsed = agentYamlConfigSchema.safeParse(parseYaml3(content));
@@ -5183,7 +5260,7 @@ function toAgentDefinition(config, file, sourceRoot, options) {
5183
5260
  ...config.hooks !== void 0 && { hooks: config.hooks },
5184
5261
  ...config.experimental !== void 0 && { experimental: config.experimental },
5185
5262
  ...config.outputFormat !== void 0 && { outputFormat: config.outputFormat },
5186
- path: path15.dirname(file),
5263
+ path: path14.dirname(file),
5187
5264
  sourceRoot,
5188
5265
  ...options.agentBaseDir ? { agentBaseDir: options.agentBaseDir } : {},
5189
5266
  ...config.domain ? { domain: config.domain } : {},
@@ -5191,7 +5268,7 @@ function toAgentDefinition(config, file, sourceRoot, options) {
5191
5268
  };
5192
5269
  }
5193
5270
  async function loadAllAgents(projectRoot) {
5194
- return loadAgentsFromDir(path15.join(projectRoot, DIRS.agents), projectRoot, {
5271
+ return loadAgentsFromDir(path14.join(projectRoot, DIRS.agents), projectRoot, {
5195
5272
  includeCustomFlag: true,
5196
5273
  verboseLabel: "agent"
5197
5274
  });
@@ -5203,9 +5280,9 @@ async function loadMergedAgents(sourcePath) {
5203
5280
  ]);
5204
5281
  return { ...cliAgents, ...sourceAgents };
5205
5282
  }
5206
- async function loadProjectAgents(projectRoot) {
5207
- const sourceFolder = sourceFolderInUse(projectRoot, providerInUse(projectRoot));
5208
- const projectAgentsDir = path15.join(sourceFolder.dir, STANDARD_DIRS.AGENTS);
5283
+ async function loadProjectAgents(projectRoot, provider = providerInUse(projectRoot)) {
5284
+ const sourceFolder = sourceFolderInUse(projectRoot, provider);
5285
+ const projectAgentsDir = path14.join(sourceFolder.dir, STANDARD_DIRS.AGENTS);
5209
5286
  if (!await directoryExists2(projectAgentsDir)) {
5210
5287
  verbose(`No project agents directory at ${projectAgentsDir}`);
5211
5288
  return {};
@@ -5237,19 +5314,19 @@ async function loadSkillsFromDir(skillsDir2, options = {}) {
5237
5314
  return { skills, unusableMetadata };
5238
5315
  }
5239
5316
  function locateSkill(skillsDir2, skillFile, pathPrefix) {
5240
- const skillMdPath = path15.join(skillsDir2, skillFile);
5241
- const skillDir = path15.dirname(skillMdPath);
5242
- const relativePath = path15.relative(skillsDir2, skillDir);
5317
+ const skillMdPath = path14.join(skillsDir2, skillFile);
5318
+ const skillDir = path14.dirname(skillMdPath);
5319
+ const relativePath = path14.relative(skillsDir2, skillDir);
5243
5320
  return {
5244
5321
  skillFile,
5245
5322
  skillMdPath,
5246
5323
  skillDir,
5247
- skillDirName: path15.basename(skillDir),
5324
+ skillDirName: path14.basename(skillDir),
5248
5325
  displayPath: pathPrefix ? `${pathPrefix}/${relativePath}/` : `${relativePath}/`
5249
5326
  };
5250
5327
  }
5251
5328
  async function judgeSkillMetadata(skill) {
5252
- const metadataPath = path15.join(skill.skillDir, STANDARD_FILES.METADATA_YAML);
5329
+ const metadataPath = path14.join(skill.skillDir, STANDARD_FILES.METADATA_YAML);
5253
5330
  if (!await fileExists(metadataPath)) {
5254
5331
  warn(
5255
5332
  `Skill '${skill.skillDirName}' in '${skill.displayPath}' is missing ${STANDARD_FILES.METADATA_YAML} \u2014 skipped. Add ${STANDARD_FILES.METADATA_YAML} to register it with the CLI.`
@@ -5291,7 +5368,7 @@ async function readSkillDefinition(skill) {
5291
5368
  }
5292
5369
  }
5293
5370
  async function loadPluginSkills(pluginDir) {
5294
- const { skills } = await loadSkillsFromDir(path15.join(pluginDir, "skills"), {
5371
+ const { skills } = await loadSkillsFromDir(path14.join(pluginDir, "skills"), {
5295
5372
  pathPrefix: "skills",
5296
5373
  requireMetadata: false
5297
5374
  });
@@ -5300,17 +5377,18 @@ async function loadPluginSkills(pluginDir) {
5300
5377
 
5301
5378
  // src/cli/lib/loading/source-fetcher.ts
5302
5379
  import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
5303
- import { createHash as createHash2 } from "crypto";
5380
+ import { createHash as createHash2, randomUUID } from "crypto";
5304
5381
  import { readFileSync } from "fs";
5305
- import { rename, stat } from "fs/promises";
5382
+ import { open, rename, stat } from "fs/promises";
5383
+ import { setTimeout as sleep } from "timers/promises";
5306
5384
  import { downloadTemplate } from "giget";
5307
5385
  import os8 from "os";
5308
- import path17 from "path";
5386
+ import path16 from "path";
5309
5387
  import { isDeepEqual } from "remeda";
5310
5388
  import { z as z4 } from "zod";
5311
5389
 
5312
5390
  // src/cli/lib/marketplace-generator.ts
5313
- import path16 from "path";
5391
+ import path15 from "path";
5314
5392
  import { countBy, sortBy } from "remeda";
5315
5393
  var PLUGIN_MANIFEST_PATH = `${PLUGIN_MANIFEST_DIR}/${PLUGIN_MANIFEST_FILE}`;
5316
5394
  var MARKETPLACE_SCHEMA_URL = "https://anthropic.com/claude-code/marketplace.schema.json";
@@ -5342,7 +5420,7 @@ async function generateMarketplace(pluginsDir2, options) {
5342
5420
  const rootWithoutDotSlash = options.pluginRoot.replace(/^\.\//, "");
5343
5421
  for (const manifestFile of manifestFiles) {
5344
5422
  const pluginDirName = pluginDirNameOf(manifestFile);
5345
- const pluginDir = path16.join(pluginsDir2, pluginDirName);
5423
+ const pluginDir = path15.join(pluginsDir2, pluginDirName);
5346
5424
  const manifest = await readPluginManifest(pluginDir);
5347
5425
  if (!manifest) {
5348
5426
  warn(`Could not read plugin manifest: '${manifestFile}'`);
@@ -5407,7 +5485,7 @@ function namespaceViolationError(foreignIds, marketplaceName) {
5407
5485
  ].join("\n");
5408
5486
  }
5409
5487
  async function writeMarketplace(outputPath, marketplace) {
5410
- await ensureDir(path16.dirname(outputPath));
5488
+ await ensureDir(path15.dirname(outputPath));
5411
5489
  const content = `${JSON.stringify(marketplace, null, 2)}
5412
5490
  `;
5413
5491
  await writeFile(outputPath, content);
@@ -5481,7 +5559,7 @@ function sanitizeSourceForCache(source) {
5481
5559
  }
5482
5560
  function getCacheDir(source) {
5483
5561
  const sanitized = sanitizeSourceForCache(source) || "unknown";
5484
- return path17.join(cacheRoot(), "sources", sanitized);
5562
+ return path16.join(cacheRoot(), "sources", sanitized);
5485
5563
  }
5486
5564
  async function fetchFromSource(source, options = {}) {
5487
5565
  const { subdir } = options;
@@ -5492,8 +5570,8 @@ async function fetchFromSource(source, options = {}) {
5492
5570
  return fetchFromRemoteSource(source, subdir);
5493
5571
  }
5494
5572
  async function fetchFromLocalSource(source, subdir) {
5495
- const fullPath = subdir ? path17.join(source, subdir) : source;
5496
- const absolutePath = path17.isAbsolute(fullPath) ? fullPath : path17.resolve(process.cwd(), fullPath);
5573
+ const fullPath = subdir ? path16.join(source, subdir) : source;
5574
+ const absolutePath = path16.isAbsolute(fullPath) ? fullPath : path16.resolve(process.cwd(), fullPath);
5497
5575
  if (!await directoryExists2(absolutePath)) {
5498
5576
  throw new Error(
5499
5577
  `Local marketplace not found: '${absolutePath}'
@@ -5524,18 +5602,16 @@ function getGigetCacheDir(source) {
5524
5602
  return void 0;
5525
5603
  }
5526
5604
  const templateName = uriMatch.groups.repo.replace("/", "-").replace(/[^\da-z-]/gi, "-");
5527
- return path17.join(gigetCacheRoot(), providerName, templateName);
5605
+ return path16.join(gigetCacheRoot(), providerName, templateName);
5528
5606
  }
5529
5607
  function gigetCacheRoot() {
5530
- return process.env.XDG_CACHE_HOME ? path17.resolve(process.env.XDG_CACHE_HOME, "giget") : path17.resolve(os8.homedir(), ".cache", "giget");
5608
+ return process.env.XDG_CACHE_HOME ? path16.resolve(process.env.XDG_CACHE_HOME, "giget") : path16.resolve(os8.homedir(), ".cache", "giget");
5531
5609
  }
5532
5610
  async function clearGigetCache(source) {
5533
5611
  const gigetDir = getGigetCacheDir(source);
5534
- if (!gigetDir) return;
5535
- if (await directoryExists2(gigetDir)) {
5536
- verbose(`Clearing giget cache: ${gigetDir}`);
5537
- await remove(gigetDir);
5538
- }
5612
+ if (!gigetDir || !await directoryExists2(gigetDir)) return;
5613
+ verbose(`Clearing giget cache: ${gigetDir}`);
5614
+ await holdingGigetFolder(path16.dirname(gigetDir), () => remove(gigetDir));
5539
5615
  }
5540
5616
  async function fetchFromRemoteSource(source, subdir) {
5541
5617
  const cacheDir = getCacheDir(source);
@@ -5564,7 +5640,7 @@ async function discardCachedCopy(cacheDir, source) {
5564
5640
  await remove(cacheDir);
5565
5641
  }
5566
5642
  async function downloadFreshCopy(cacheDir, source, fullSource) {
5567
- await ensureDir(path17.dirname(cacheDir));
5643
+ await ensureDir(path16.dirname(cacheDir));
5568
5644
  try {
5569
5645
  const { result, savedTarball } = await gigetDownload(source, fullSource, {
5570
5646
  dir: cacheDir,
@@ -5622,7 +5698,7 @@ async function downloadAnsweredFor(cacheDir, source, fullSource, differingCopies
5622
5698
  forceClean: true,
5623
5699
  offline: false
5624
5700
  });
5625
- await ensureDir(path17.dirname(cacheDir));
5701
+ await ensureDir(path16.dirname(cacheDir));
5626
5702
  try {
5627
5703
  const { result, savedTarball } = await downloadStaged();
5628
5704
  const record = await askAfterTheDownload(result, source);
@@ -5643,7 +5719,10 @@ async function downloadPast(savedTarball, record, download, source) {
5643
5719
  if (!savedUnder(savedTarball, record)) {
5644
5720
  throw new MarketplaceUnreachableError(source, ONLY_A_SAVED_COPY_CAME_BACK);
5645
5721
  }
5646
- await withTarballSetAside(savedTarball.path, download);
5722
+ await holdingGigetFolder(
5723
+ gigetProviderDir(source),
5724
+ () => withTarballSetAside(savedTarball.path, download)
5725
+ );
5647
5726
  }
5648
5727
  async function withTarballSetAside(tarball, download) {
5649
5728
  const record = gigetRecordOf(tarball);
@@ -5679,7 +5758,7 @@ function everyFileIn(dir) {
5679
5758
  return glob(EVERY_FILE, dir, { dot: true });
5680
5759
  }
5681
5760
  function sameBytesAt(file, left, right) {
5682
- return readFileSync(path17.join(left, file)).equals(readFileSync(path17.join(right, file)));
5761
+ return readFileSync(path16.join(left, file)).equals(readFileSync(path16.join(right, file)));
5683
5762
  }
5684
5763
  async function replaceCopy(cacheDir, staged, record) {
5685
5764
  await remove(cacheDir);
@@ -5690,33 +5769,156 @@ var GIGET_TARBALLS = "**/*.tar.gz";
5690
5769
  var gigetTarballRecordSchema = z4.object({ etag: z4.string().min(1).optional() });
5691
5770
  async function gigetDownload(source, fullSource, options) {
5692
5771
  const providerDir = gigetProviderDir(source);
5693
- const timesBefore = await tarballTimes(providerDir);
5694
- const result = await downloadTemplate(fullSource, options);
5695
- const tarball = path17.join(providerDir, gigetTarballOf(result));
5696
- const writtenByThisDownload = timesBefore.get(tarball) !== await modifiedAt(tarball);
5697
- if (writtenByThisDownload) return { result };
5698
- verbose(`giget extracted the tarball it saved earlier, not a download: ${tarball}`);
5699
- return { result, savedTarball: { path: tarball, etag: await etagSavedWith(tarball) } };
5772
+ return holdingGigetFolder(
5773
+ providerDir,
5774
+ () => downloadOverMarkedRecords(providerDir, fullSource, options)
5775
+ );
5776
+ }
5777
+ async function downloadOverMarkedRecords(providerDir, fullSource, options) {
5778
+ const marks = await markSavedRecords(providerDir);
5779
+ try {
5780
+ const result = await downloadTemplate(fullSource, options);
5781
+ const tarball = path16.join(providerDir, gigetTarballOf(result));
5782
+ if (await writtenByThisDownload(marks.get(tarball))) return { result };
5783
+ verbose(`giget extracted the tarball it saved earlier, not a download: ${tarball}`);
5784
+ return { result, savedTarball: { path: tarball, etag: await etagSavedWith(tarball) } };
5785
+ } finally {
5786
+ await Promise.all([...marks.values()].map(unmark));
5787
+ }
5700
5788
  }
5701
5789
  function gigetProviderDir(source) {
5702
5790
  const provider = SOURCE_PROTO_RE.exec(source)?.[1];
5703
5791
  if (provider === void 0) throw new Error(`No provider named in '${source}'`);
5704
- return path17.join(gigetCacheRoot(), provider);
5792
+ return path16.join(gigetCacheRoot(), provider);
5793
+ }
5794
+ var GIGET_FOLDER_LOCK = "agents-inc.lock";
5795
+ var EXCLUSIVE_CREATE = "wx";
5796
+ var LOCK_RETRY_MS = 100;
5797
+ var LOCK_ABANDONED_MS = 10 * 60 * 1e3;
5798
+ var gigetFolderHeld = new AsyncLocalStorage3();
5799
+ var holdersInThisProcess = /* @__PURE__ */ new Set();
5800
+ async function holdingGigetFolder(folder, body) {
5801
+ if (gigetFolderHeld.getStore() === folder) return body();
5802
+ const lock = lockFor(folder);
5803
+ try {
5804
+ await lockGigetFolder(folder, lock);
5805
+ return await gigetFolderHeld.run(folder, body);
5806
+ } finally {
5807
+ await letGo(lock);
5808
+ }
5809
+ }
5810
+ function lockFor(folder) {
5811
+ const holder = `${process.pid} ${randomUUID()}`;
5812
+ holdersInThisProcess.add(holder);
5813
+ return { path: path16.join(folder, GIGET_FOLDER_LOCK), holder };
5814
+ }
5815
+ async function letGo({ path: lockPath, holder }) {
5816
+ try {
5817
+ await removeLockHeldBy(lockPath, holder);
5818
+ } finally {
5819
+ holdersInThisProcess.delete(holder);
5820
+ }
5821
+ }
5822
+ async function lockGigetFolder(folder, lock) {
5823
+ await ensureDir(folder);
5824
+ while (!await created(lock)) {
5825
+ const holder = await readFileOptional(lock.path);
5826
+ if (await abandoned(lock.path, holder)) {
5827
+ verbose(`Taking over the lock on ${folder}: its run ended, or held it past any download`);
5828
+ await removeLockHeldBy(lock.path, holder);
5829
+ } else {
5830
+ await sleep(LOCK_RETRY_MS);
5831
+ }
5832
+ }
5833
+ }
5834
+ async function created({ path: lockPath, holder }) {
5835
+ try {
5836
+ await (await open(lockPath, EXCLUSIVE_CREATE)).close();
5837
+ } catch (error) {
5838
+ if (failedWith(error, "EEXIST")) return false;
5839
+ throw error;
5840
+ }
5841
+ await writeFile(lockPath, holder);
5842
+ return true;
5843
+ }
5844
+ async function abandoned(lockPath, holder) {
5845
+ return holderEnded(holder) || await outlastedAnyDownload(lockPath);
5705
5846
  }
5706
- async function tarballTimes(providerDir) {
5847
+ function holderEnded(holder) {
5848
+ const pid = Number.parseInt(holder, 10);
5849
+ if (pid === process.pid) return !holdersInThisProcess.has(holder);
5850
+ return pid > 0 && !processRunning(pid);
5851
+ }
5852
+ async function outlastedAnyDownload(lockPath) {
5853
+ const age = await ageOf(lockPath);
5854
+ return age !== void 0 && age > LOCK_ABANDONED_MS;
5855
+ }
5856
+ function processRunning(pid) {
5857
+ try {
5858
+ process.kill(pid, 0);
5859
+ return true;
5860
+ } catch (error) {
5861
+ return !failedWith(error, "ESRCH");
5862
+ }
5863
+ }
5864
+ async function ageOf(file) {
5865
+ try {
5866
+ return Date.now() - (await stat(file)).mtimeMs;
5867
+ } catch (error) {
5868
+ if (failedWith(error, "ENOENT")) return void 0;
5869
+ throw error;
5870
+ }
5871
+ }
5872
+ async function removeLockHeldBy(lockPath, holder) {
5873
+ if (await readFileOptional(lockPath) === holder) await remove(lockPath);
5874
+ }
5875
+ function failedWith(error, code) {
5876
+ return isRecord(error) && error.code === code;
5877
+ }
5878
+ var RECORD_MARK = "\n";
5879
+ var NO_RECORD = "{}";
5880
+ var UNMARKED_SUFFIX = ".unmarked";
5881
+ async function markSavedRecords(providerDir) {
5707
5882
  const tarballs = await glob(GIGET_TARBALLS, providerDir);
5708
- const paths = tarballs.map((tarball) => path17.join(providerDir, tarball));
5709
- return new Map(await Promise.all(paths.map(async (at) => [at, await modifiedAt(at)])));
5883
+ const paths = tarballs.map((tarball) => path16.join(providerDir, tarball));
5884
+ return new Map(await Promise.all(paths.map(async (at) => [at, await markRecordOf(at)])));
5885
+ }
5886
+ async function markRecordOf(tarball) {
5887
+ const record = gigetRecordOf(tarball);
5888
+ await putBackLeftUnmarked(record);
5889
+ const held = await fileExists(record);
5890
+ const marked = `${RECORD_MARK}${await readFileOptional(record, NO_RECORD)}`;
5891
+ if (held) await rename(record, unmarkedOf(record));
5892
+ await writeFile(record, marked);
5893
+ return { record, marked, held };
5894
+ }
5895
+ async function putBackLeftUnmarked(record) {
5896
+ if (await fileExists(unmarkedOf(record))) await rename(unmarkedOf(record), record);
5897
+ }
5898
+ function unmarkedOf(record) {
5899
+ return `${record}${UNMARKED_SUFFIX}`;
5710
5900
  }
5711
- async function modifiedAt(file) {
5712
- return await fileExists(file) ? (await stat(file)).mtimeMs : void 0;
5901
+ async function writtenByThisDownload(mark) {
5902
+ return mark === void 0 || await rewritten(mark);
5903
+ }
5904
+ async function rewritten({ record, marked }) {
5905
+ return await readFileOptional(record, marked) !== marked;
5906
+ }
5907
+ async function unmark(mark) {
5908
+ const { record, held } = mark;
5909
+ if (await rewritten(mark)) {
5910
+ if (held) await remove(unmarkedOf(record));
5911
+ return;
5912
+ }
5913
+ if (held) await rename(unmarkedOf(record), record);
5914
+ else await remove(record);
5713
5915
  }
5714
5916
  function gigetTarballOf(result) {
5715
5917
  const name = result.name;
5716
5918
  const version = result.version;
5717
5919
  if (typeof name !== "string") throw new Error("the download named no template");
5718
5920
  const stem = typeof version === "string" && version !== "" ? version : name;
5719
- return path17.join(name, `${stem}.tar.gz`);
5921
+ return path16.join(name, `${stem}.tar.gz`);
5720
5922
  }
5721
5923
  function gigetRecordOf(tarball) {
5722
5924
  return `${tarball}.json`;
@@ -6102,7 +6304,7 @@ function markInstalledAsPlugin(skill, primarySourceName, primarySourceType) {
6102
6304
  }
6103
6305
  async function collectPluginSkillIds(projectDir) {
6104
6306
  const projectSkillIds = await pluginSkillIdsIn(projectDir);
6105
- const globalSkillIds = isHomeDirectory(projectDir) ? [] : await pluginSkillIdsIn(os9.homedir());
6307
+ const globalSkillIds = isHomeDirectory(projectDir) ? [] : await pluginSkillIdsIn(os9.homedir(), inheritedGlobalProvider(projectDir));
6106
6308
  if (globalSkillIds.length > 0) {
6107
6309
  verbose(`Found ${globalSkillIds.length} global plugin skill(s)`);
6108
6310
  return unique3([...projectSkillIds, ...globalSkillIds]);
@@ -6112,8 +6314,8 @@ async function collectPluginSkillIds(projectDir) {
6112
6314
  }
6113
6315
  return projectSkillIds;
6114
6316
  }
6115
- async function pluginSkillIdsIn(dir) {
6116
- return typedKeys(await discoverAllPluginSkills(dir));
6317
+ async function pluginSkillIdsIn(dir, provider) {
6318
+ return typedKeys(await discoverAllPluginSkills(dir, provider));
6117
6319
  }
6118
6320
  function setActiveSources(matrix2) {
6119
6321
  for (const [, skill] of typedEntries(matrix2.skills)) {
@@ -6206,14 +6408,18 @@ function resolveDescription(loadedStack, shared) {
6206
6408
  return shared ?? loadedStack?.description;
6207
6409
  }
6208
6410
  function configNameFor(projectDir) {
6209
- return isHomeDirectory(projectDir) ? DEFAULT_PLUGIN_NAME : path18.basename(projectDir);
6411
+ return isHomeDirectory(projectDir) ? DEFAULT_PLUGIN_NAME : path17.basename(projectDir);
6210
6412
  }
6211
6413
  async function loadCuratedStack(projectDir, projectStack) {
6212
- const globalStack = isHomeDirectory(projectDir) ? void 0 : await loadGlobalStack();
6414
+ const globalStack = isHomeDirectory(projectDir) ? void 0 : await loadGlobalStack(projectDir);
6213
6415
  return { ...globalStack, ...projectStack };
6214
6416
  }
6215
- async function loadGlobalStack() {
6216
- return (await loadInstalledConfig(os10.homedir()))?.config.stack;
6417
+ async function loadGlobalStack(projectDir) {
6418
+ const inherited = await loadProjectConfigFromDir(
6419
+ os10.homedir(),
6420
+ inheritedGlobalProvider(projectDir)
6421
+ );
6422
+ return inherited?.config.stack;
6217
6423
  }
6218
6424
  async function buildInstallConfig(selection, sourceResult, projectDir) {
6219
6425
  const skillIds = unique4(selection.skills.map((s) => s.id));
@@ -6360,31 +6566,61 @@ async function describeScope(kind, root, provider) {
6360
6566
 
6361
6567
  // src/cli/lib/installation/detect-installations.ts
6362
6568
  async function detectInstallations(cwd) {
6569
+ const configs = await configsRead(cwd);
6570
+ return configs.filter((config) => !config.declaresNothingInAProject).map(asInstallation);
6571
+ }
6572
+ async function configsDeclaringNothing(cwd) {
6573
+ const configs = await configsRead(cwd);
6574
+ return configs.filter((config) => config.declaresNothingInAProject).map(asInstallation);
6575
+ }
6576
+ async function holdsAConfigDeclaringNothing(cwd) {
6577
+ return (await configsDeclaringNothing(cwd)).length > 0;
6578
+ }
6579
+ async function configsRead(cwd) {
6363
6580
  const everywhereOneCouldBe = scopeRootsInPlay(cwd).flatMap(everyProviderUnder);
6364
- const found = await Promise.all(everywhereOneCouldBe.map(installationIfPresent));
6365
- return found.filter(
6366
- (installation) => installation !== null
6367
- );
6581
+ const found = await Promise.all(everywhereOneCouldBe.map(configIfPresent));
6582
+ const onDisk = found.filter((config) => config !== null);
6583
+ return Promise.all(onDisk.map(withWhetherItDeclaresNothing));
6368
6584
  }
6369
6585
  function everyProviderUnder({ kind, root }) {
6370
6586
  return PROVIDERS.map((provider) => ({
6371
6587
  provider,
6372
6588
  scope: kind,
6589
+ root,
6373
6590
  configPath: getProjectConfigPath(root, provider)
6374
6591
  }));
6375
6592
  }
6376
- async function installationIfPresent(candidate) {
6593
+ async function configIfPresent(candidate) {
6377
6594
  return await fileExists(candidate.configPath) ? candidate : null;
6378
6595
  }
6596
+ async function withWhetherItDeclaresNothing(config) {
6597
+ return { ...config, declaresNothingInAProject: await declaresNothingInAProject(config) };
6598
+ }
6599
+ async function declaresNothingInAProject(config) {
6600
+ if (config.scope === "global") return false;
6601
+ const asRead = declaresNothingAsLastRead(config.configPath);
6602
+ if (asRead !== void 0) return asRead;
6603
+ try {
6604
+ const declaresNothing = await configDeclaresNothing(config.root, config.provider);
6605
+ recordWhetherItDeclaresNothing(config.configPath, declaresNothing);
6606
+ return declaresNothing;
6607
+ } catch (error) {
6608
+ if (error instanceof ConfigLoadError) return false;
6609
+ throw error;
6610
+ }
6611
+ }
6612
+ function asInstallation({ provider, scope, configPath }) {
6613
+ return { provider, scope, configPath };
6614
+ }
6379
6615
 
6380
6616
  // src/cli/lib/hosts/claude-host.ts
6381
6617
  import os12 from "os";
6382
- import path21 from "path";
6618
+ import path20 from "path";
6383
6619
  import { z as z6 } from "zod";
6384
6620
 
6385
6621
  // src/cli/utils/exec.ts
6386
6622
  import { spawn } from "child_process";
6387
- import path19 from "path";
6623
+ import path18 from "path";
6388
6624
  var MAX_PLUGIN_PATH_LENGTH = 1024;
6389
6625
  var MAX_PLUGIN_NAME_LENGTH = 256;
6390
6626
  var MAX_MARKETPLACE_SOURCE_LENGTH = 1024;
@@ -6392,7 +6628,7 @@ var SAFE_NAME_PATTERN2 = /^[a-zA-Z0-9._@/-]+$/;
6392
6628
  var SAFE_PLUGIN_PATH_PATTERN = /^[a-zA-Z0-9._@/:~-]+$/;
6393
6629
  var OPENS_A_RELATIVE_PATH = /^\.\.?[/\\]/;
6394
6630
  function namesADirectoryOnThisMachine(source) {
6395
- return path19.isAbsolute(source) || OPENS_A_RELATIVE_PATH.test(source);
6631
+ return path18.isAbsolute(source) || OPENS_A_RELATIVE_PATH.test(source);
6396
6632
  }
6397
6633
  var CONTROL_CHAR_PATTERN = /[\x00-\x08\x0E-\x1F\x7F]/u;
6398
6634
  function validatePluginPath(pluginPath) {
@@ -6482,7 +6718,7 @@ async function execCommand(command, args, options) {
6482
6718
  }
6483
6719
 
6484
6720
  // src/cli/lib/plugins/plugin-settings.ts
6485
- import path20 from "path";
6721
+ import path19 from "path";
6486
6722
  import { z as z5 } from "zod";
6487
6723
  var pluginSettingsSchema = z5.object({
6488
6724
  // Absent when no plugin is enabled.
@@ -6503,7 +6739,7 @@ var installedPluginsSchema = z5.object({
6503
6739
  plugins: z5.record(z5.string(), z5.array(pluginInstallationSchema))
6504
6740
  }).passthrough();
6505
6741
  function getInstalledPluginsRegistryPath(pluginsDir2) {
6506
- return path20.join(pluginsDir2, INSTALLED_PLUGINS_FILE);
6742
+ return path19.join(pluginsDir2, INSTALLED_PLUGINS_FILE);
6507
6743
  }
6508
6744
  async function readRegisteredInstallations(pluginsDir2) {
6509
6745
  const registryPath = getInstalledPluginsRegistryPath(pluginsDir2);
@@ -6536,7 +6772,7 @@ async function listPluginInstallsForProject(pluginsDir2, projectDir) {
6536
6772
  });
6537
6773
  }
6538
6774
  async function getEnabledPluginKeys(projectDir) {
6539
- const settingsPath = path20.join(projectDir, CLAUDE_DIR, STANDARD_FILES.SETTINGS_JSON);
6775
+ const settingsPath = path19.join(projectDir, CLAUDE_DIR, STANDARD_FILES.SETTINGS_JSON);
6540
6776
  if (!await fileExists(settingsPath)) {
6541
6777
  verbose(`No settings.json found at '${settingsPath}'`);
6542
6778
  return [];
@@ -6684,7 +6920,7 @@ function namesNothingThere(message) {
6684
6920
  return NOT_INSTALLED_MESSAGES.some((phrase) => message.includes(phrase));
6685
6921
  }
6686
6922
  function claudePluginsRoot(projectDir, options) {
6687
- if (options?.configDir !== void 0) return path21.join(options.configDir, PLUGINS_SUBDIR);
6923
+ if (options?.configDir !== void 0) return path20.join(options.configDir, PLUGINS_SUBDIR);
6688
6924
  return pluginsDir(CLAUDE, "global", projectDir);
6689
6925
  }
6690
6926
  async function claudeListPlugins(projectDir, options) {
@@ -6719,7 +6955,7 @@ function claudeHost() {
6719
6955
 
6720
6956
  // src/cli/lib/hosts/codex-host.ts
6721
6957
  import os13 from "os";
6722
- import path22 from "path";
6958
+ import path21 from "path";
6723
6959
  import { z as z7 } from "zod";
6724
6960
  var CODEX = "codex";
6725
6961
  var PLUGIN_CACHE_SUBDIR = "cache";
@@ -6803,7 +7039,7 @@ var pluginListingSchema = z7.object({
6803
7039
  )
6804
7040
  });
6805
7041
  function codexPluginsRoot(projectDir, options) {
6806
- if (options?.configDir !== void 0) return path22.join(options.configDir, PLUGINS_SUBDIR);
7042
+ if (options?.configDir !== void 0) return path21.join(options.configDir, PLUGINS_SUBDIR);
6807
7043
  return pluginsDir(CODEX, "global", projectDir);
6808
7044
  }
6809
7045
  async function isCodexCLIAvailable(options) {
@@ -6933,7 +7169,7 @@ async function codexListPlugins(projectDir, options) {
6933
7169
  async function codexPluginsOrUnreadable(projectDir, options) {
6934
7170
  const pluginsRoot = codexPluginsRoot(projectDir, options);
6935
7171
  if (pluginsRoot === null) return { kind: "listed", plugins: [] };
6936
- const cacheRoot2 = path22.join(pluginsRoot, PLUGIN_CACHE_SUBDIR);
7172
+ const cacheRoot2 = path21.join(pluginsRoot, PLUGIN_CACHE_SUBDIR);
6937
7173
  let installed;
6938
7174
  try {
6939
7175
  installed = await codexPluginListing(options, projectDir);
@@ -6945,7 +7181,7 @@ async function codexPluginsOrUnreadable(projectDir, options) {
6945
7181
  kind: "listed",
6946
7182
  plugins: installed.map((plugin) => ({
6947
7183
  pluginKey: plugin.pluginId,
6948
- installPath: path22.join(cacheRoot2, plugin.marketplaceName, plugin.name, plugin.version),
7184
+ installPath: path21.join(cacheRoot2, plugin.marketplaceName, plugin.name, plugin.version),
6949
7185
  enabled: plugin.enabled
6950
7186
  }))
6951
7187
  };
@@ -7225,10 +7461,11 @@ function sumCounts(scopeCounts) {
7225
7461
  async function countCompiledAgentsPerScope(installation, scopes) {
7226
7462
  return Promise.all(
7227
7463
  scopes.map(async (scope) => {
7228
- const dir = resolveInstallPaths(installation.projectDir, scope).agentsDir;
7464
+ const provider = providerAtScope(installation.projectDir, scope);
7465
+ const dir = agentsDir(provider, scope, installation.projectDir);
7229
7466
  return {
7230
7467
  dir,
7231
- count: await countDirEntries(dir, isCompiledAgentFileIn(agentCodec("claude").extension))
7468
+ count: await countDirEntries(dir, isCompiledAgentFileIn(agentCodec(provider).extension))
7232
7469
  };
7233
7470
  })
7234
7471
  );
@@ -7257,7 +7494,7 @@ function formatInstallationDisplay(info, skillLines = []) {
7257
7494
  }
7258
7495
 
7259
7496
  // src/cli/lib/plugins/plugin-validator.ts
7260
- import path23 from "path";
7497
+ import path22 from "path";
7261
7498
 
7262
7499
  // src/cli/lib/validation-result.ts
7263
7500
  function validResult() {
@@ -7289,15 +7526,15 @@ async function validatePluginStructure(pluginPath) {
7289
7526
  if (!await directoryExists2(pluginPath)) {
7290
7527
  return invalidResult(`Plugin directory does not exist: ${pluginPath}`);
7291
7528
  }
7292
- const pluginDir = path23.join(pluginPath, PLUGIN_MANIFEST_DIR);
7529
+ const pluginDir = path22.join(pluginPath, PLUGIN_MANIFEST_DIR);
7293
7530
  if (!await directoryExists2(pluginDir)) {
7294
7531
  errors.push(`Missing ${PLUGIN_MANIFEST_DIR}/ directory`);
7295
7532
  }
7296
- const manifestPath = path23.join(pluginDir, STANDARD_FILES.PLUGIN_JSON);
7533
+ const manifestPath = path22.join(pluginDir, STANDARD_FILES.PLUGIN_JSON);
7297
7534
  if (!await fileExists(manifestPath)) {
7298
7535
  errors.push(`Missing ${PLUGIN_MANIFEST_DIR}/${STANDARD_FILES.PLUGIN_JSON}`);
7299
7536
  }
7300
- const readmePath = path23.join(pluginPath, STANDARD_FILES.README_MD);
7537
+ const readmePath = path22.join(pluginPath, STANDARD_FILES.README_MD);
7301
7538
  if (!await fileExists(readmePath)) {
7302
7539
  warnings.push("Missing README.md (recommended for documentation)");
7303
7540
  }
@@ -7340,15 +7577,15 @@ async function validatePluginManifest(manifestPath) {
7340
7577
  if (!manifest.description) {
7341
7578
  warnings.push("Missing description field (recommended for discoverability)");
7342
7579
  }
7343
- const pluginDir = path23.dirname(path23.dirname(manifestPath));
7580
+ const pluginDir = path22.dirname(path22.dirname(manifestPath));
7344
7581
  if (isNonEmptyString(manifest.skills)) {
7345
- const skillsPath = path23.join(pluginDir, manifest.skills);
7582
+ const skillsPath = path22.join(pluginDir, manifest.skills);
7346
7583
  if (!await directoryExists2(skillsPath)) {
7347
7584
  errors.push(`Skills path does not exist: ${manifest.skills}`);
7348
7585
  }
7349
7586
  }
7350
7587
  if (isNonEmptyString(manifest.agents)) {
7351
- const agentsPath = path23.join(pluginDir, manifest.agents);
7588
+ const agentsPath = path22.join(pluginDir, manifest.agents);
7352
7589
  if (!await directoryExists2(agentsPath)) {
7353
7590
  errors.push(`Agents path does not exist: ${manifest.agents}`);
7354
7591
  }
@@ -7417,14 +7654,14 @@ function prefixResult(result, prefix) {
7417
7654
  async function validateEachFile(pluginPath, scannedDir, files, validate) {
7418
7655
  const results = await Promise.all(
7419
7656
  files.map(async (file) => {
7420
- const filePath = path23.join(scannedDir, file);
7421
- return prefixResult(await validate(filePath), path23.relative(pluginPath, filePath));
7657
+ const filePath = path22.join(scannedDir, file);
7658
+ return prefixResult(await validate(filePath), path22.relative(pluginPath, filePath));
7422
7659
  })
7423
7660
  );
7424
7661
  return mergeValidationResults(results);
7425
7662
  }
7426
7663
  async function validatePluginSkillFiles(pluginPath, skillsRelPath) {
7427
- const skillsDir2 = path23.join(pluginPath, skillsRelPath);
7664
+ const skillsDir2 = path22.join(pluginPath, skillsRelPath);
7428
7665
  if (!await directoryExists2(skillsDir2)) return validResult();
7429
7666
  const files = await glob(`**/${STANDARD_FILES.SKILL_MD}`, skillsDir2);
7430
7667
  if (files.length === 0) {
@@ -7437,7 +7674,7 @@ async function validatePluginSkillFiles(pluginPath, skillsRelPath) {
7437
7674
  return validateEachFile(pluginPath, skillsDir2, files, validateSkillFrontmatter);
7438
7675
  }
7439
7676
  async function validatePluginAgentFiles(pluginPath, agentsRelPath) {
7440
- const agentsDir2 = path23.join(pluginPath, agentsRelPath);
7677
+ const agentsDir2 = path22.join(pluginPath, agentsRelPath);
7441
7678
  if (!await directoryExists2(agentsDir2)) return validResult();
7442
7679
  const files = await glob(agentCodec("claude").listGlob, agentsDir2);
7443
7680
  if (files.length === 0) {
@@ -7508,7 +7745,7 @@ async function listPluginDirNames(pluginsDir2) {
7508
7745
  const dirChecks = await Promise.all(
7509
7746
  allDirs.map(async (dirName) => ({
7510
7747
  dirName,
7511
- isPlugin: await directoryExists2(path23.join(pluginsDir2, dirName, PLUGIN_MANIFEST_DIR))
7748
+ isPlugin: await directoryExists2(path22.join(pluginsDir2, dirName, PLUGIN_MANIFEST_DIR))
7512
7749
  }))
7513
7750
  );
7514
7751
  return dirChecks.filter((c) => c.isPlugin).map((c) => c.dirName);
@@ -7516,7 +7753,7 @@ async function listPluginDirNames(pluginsDir2) {
7516
7753
  async function validateEachPlugin(pluginsDir2, pluginDirs) {
7517
7754
  const results = [];
7518
7755
  for (const pluginName of pluginDirs) {
7519
- const result = await validatePlugin(path23.join(pluginsDir2, pluginName));
7756
+ const result = await validatePlugin(path22.join(pluginsDir2, pluginName));
7520
7757
  results.push({ name: pluginName, result });
7521
7758
  }
7522
7759
  return results;
@@ -7537,10 +7774,10 @@ function summarizePluginValidations(results) {
7537
7774
  }
7538
7775
 
7539
7776
  // src/cli/lib/plugins/plugin-discovery.ts
7540
- async function getVerifiedPluginInstallPaths(projectDir) {
7777
+ async function getVerifiedPluginInstallPaths(projectDir, provider = providerInUse(projectDir)) {
7541
7778
  let enabled;
7542
7779
  try {
7543
- const installed = await hostAt(projectDir).listPlugins(projectDir);
7780
+ const installed = await hostFor(provider).listPlugins(projectDir);
7544
7781
  enabled = installed.filter((plugin) => plugin.enabled).map(({ pluginKey, installPath }) => ({ pluginKey, installPath }));
7545
7782
  } catch (error) {
7546
7783
  verbose(`Failed to list installed plugins: ${getErrorMessage(error)}`);
@@ -7559,8 +7796,8 @@ async function hasManifestOnDisk({ pluginKey, installPath }) {
7559
7796
  }
7560
7797
  return manifestExists;
7561
7798
  }
7562
- async function discoverAllPluginSkills(projectDir) {
7563
- const pluginPaths = await getVerifiedPluginInstallPaths(projectDir);
7799
+ async function discoverAllPluginSkills(projectDir, provider = providerInUse(projectDir)) {
7800
+ const pluginPaths = await getVerifiedPluginInstallPaths(projectDir, provider);
7564
7801
  if (pluginPaths.length === 0) {
7565
7802
  verbose(`No enabled plugins found for '${projectDir}'`);
7566
7803
  return {};
@@ -7599,14 +7836,14 @@ function sanitizeSkillName(name) {
7599
7836
  return name.replace(/\+/g, "-");
7600
7837
  }
7601
7838
  function isSingleFolderName(name) {
7602
- return name !== "" && name !== "." && name !== ".." && path24.basename(name) === name;
7839
+ return name !== "" && name !== "." && name !== ".." && path23.basename(name) === name;
7603
7840
  }
7604
- async function assertClearable(pluginDir, skillPath, skillName) {
7605
- const skill = `Skill '${path24.basename(skillPath)}'`;
7606
- const file = `File: ${path24.join(skillPath, STANDARD_FILES.SKILL_MD)}`;
7607
- if (!isSingleFolderName(skillName)) {
7841
+ async function assertClearable(pluginDir, skillPath, skillName2) {
7842
+ const skill = `Skill '${path23.basename(skillPath)}'`;
7843
+ const file = `File: ${path23.join(skillPath, STANDARD_FILES.SKILL_MD)}`;
7844
+ if (!isSingleFolderName(skillName2)) {
7608
7845
  throw new Error(
7609
- `${skill} is named '${skillName}', which is not a single folder name, so its plugin cannot be built inside the output directory. ${file}`
7846
+ `${skill} is named '${skillName2}', which is not a single folder name, so its plugin cannot be built inside the output directory. ${file}`
7610
7847
  );
7611
7848
  }
7612
7849
  if (isPathWithin(skillPath, pluginDir)) {
@@ -7616,12 +7853,12 @@ async function assertClearable(pluginDir, skillPath, skillName) {
7616
7853
  }
7617
7854
  if (await holdsContentNoBuildMade(pluginDir)) {
7618
7855
  throw new Error(
7619
- `${skill} would be built into ${pluginDir}, which holds no ${path24.join(PLUGIN_MANIFEST_DIR, PLUGIN_MANIFEST_FILE)} and is not empty, so no earlier build made it and a rebuild would delete what it holds. Move its contents out, or build into another output directory. ${file}`
7856
+ `${skill} would be built into ${pluginDir}, which holds no ${path23.join(PLUGIN_MANIFEST_DIR, PLUGIN_MANIFEST_FILE)} and is not empty, so no earlier build made it and a rebuild would delete what it holds. Move its contents out, or build into another output directory. ${file}`
7620
7857
  );
7621
7858
  }
7622
7859
  }
7623
7860
  async function readPluginSkillMetadata(skillPath) {
7624
- const metadataPath = path24.join(skillPath, STANDARD_FILES.METADATA_YAML);
7861
+ const metadataPath = path23.join(skillPath, STANDARD_FILES.METADATA_YAML);
7625
7862
  if (!await fileExists(metadataPath)) {
7626
7863
  return null;
7627
7864
  }
@@ -7639,8 +7876,8 @@ async function readPluginSkillMetadata(skillPath) {
7639
7876
  return null;
7640
7877
  }
7641
7878
  }
7642
- function generateReadme(skillName, frontmatter) {
7643
- return `# ${skillName}
7879
+ function generateReadme(skillName2, frontmatter) {
7880
+ return `# ${skillName2}
7644
7881
 
7645
7882
  ${frontmatter.description}
7646
7883
 
@@ -7650,7 +7887,7 @@ Add this plugin to your Claude Code configuration:
7650
7887
 
7651
7888
  \`\`\`json
7652
7889
  {
7653
- "plugins": ["${skillName}"]
7890
+ "plugins": ["${skillName2}"]
7654
7891
  }
7655
7892
  \`\`\`
7656
7893
 
@@ -7665,28 +7902,28 @@ This skill is automatically available when installed.
7665
7902
  }
7666
7903
  async function writeSkillFiles(skillPath, pluginSkillDir, skillMdContent) {
7667
7904
  await ensureDir(pluginSkillDir);
7668
- await writeFile(path24.join(pluginSkillDir, STANDARD_FILES.SKILL_MD), skillMdContent);
7905
+ await writeFile(path23.join(pluginSkillDir, STANDARD_FILES.SKILL_MD), skillMdContent);
7669
7906
  verbose(` Copied ${STANDARD_FILES.SKILL_MD}`);
7670
7907
  for (const fileName of SKILL_CONTENT_FILES) {
7671
7908
  if (fileName === STANDARD_FILES.SKILL_MD) continue;
7672
- const sourcePath = path24.join(skillPath, fileName);
7909
+ const sourcePath = path23.join(skillPath, fileName);
7673
7910
  if (await fileExists(sourcePath)) {
7674
7911
  const content = await readFile(sourcePath);
7675
- await writeFile(path24.join(pluginSkillDir, fileName), content);
7912
+ await writeFile(path23.join(pluginSkillDir, fileName), content);
7676
7913
  verbose(` Copied ${fileName}`);
7677
7914
  }
7678
7915
  }
7679
7916
  for (const dirName of SKILL_CONTENT_DIRS) {
7680
- const sourceDir2 = path24.join(skillPath, dirName);
7917
+ const sourceDir2 = path23.join(skillPath, dirName);
7681
7918
  if (await fileExists(sourceDir2)) {
7682
- await copy(sourceDir2, path24.join(pluginSkillDir, dirName));
7919
+ await copy(sourceDir2, path23.join(pluginSkillDir, dirName));
7683
7920
  verbose(` Copied ${dirName}/`);
7684
7921
  }
7685
7922
  }
7686
7923
  }
7687
7924
  async function readSkillMdToBuild(skillPath) {
7688
- const dirBasename = path24.basename(skillPath);
7689
- const skillMdPath = path24.join(skillPath, STANDARD_FILES.SKILL_MD);
7925
+ const dirBasename = path23.basename(skillPath);
7926
+ const skillMdPath = path23.join(skillPath, STANDARD_FILES.SKILL_MD);
7690
7927
  if (!await fileExists(skillMdPath)) {
7691
7928
  throw new Error(
7692
7929
  `Skill '${dirBasename}' is missing required ${STANDARD_FILES.SKILL_MD} file. Expected at: ${skillMdPath}`
@@ -7704,13 +7941,13 @@ async function readSkillMdToBuild(skillPath) {
7704
7941
  async function compileSkillPlugin(options) {
7705
7942
  const { skillPath, outputDir, skillName: overrideName } = options;
7706
7943
  const { skillMdContent, frontmatter } = await readSkillMdToBuild(skillPath);
7707
- const skillName = overrideName ?? sanitizeSkillName(frontmatter.name);
7708
- const pluginDir = path24.join(outputDir, skillName);
7709
- await assertClearable(pluginDir, skillPath, skillName);
7710
- verbose(`Compiling skill plugin: ${skillName} from ${skillPath}`);
7944
+ const skillName2 = overrideName ?? sanitizeSkillName(frontmatter.name);
7945
+ const pluginDir = path23.join(outputDir, skillName2);
7946
+ await assertClearable(pluginDir, skillPath, skillName2);
7947
+ verbose(`Compiling skill plugin: ${skillName2} from ${skillPath}`);
7711
7948
  const metadata = await readPluginSkillMetadata(skillPath);
7712
7949
  const manifestAt = (version) => generateSkillPluginManifest({
7713
- skillName,
7950
+ skillName: skillName2,
7714
7951
  description: frontmatter.description,
7715
7952
  ...metadata?.author !== void 0 && { author: metadata.author },
7716
7953
  ...metadata?.category !== void 0 && { category: metadata.category },
@@ -7722,21 +7959,21 @@ async function compileSkillPlugin(options) {
7722
7959
  await writeContentHash(pluginDir, await computeSkillFolderHash(skillPath), getPluginManifestPath);
7723
7960
  await writeSkillFiles(
7724
7961
  skillPath,
7725
- path24.join(pluginDir, STANDARD_DIRS.SKILLS, skillName),
7962
+ path23.join(pluginDir, STANDARD_DIRS.SKILLS, skillName2),
7726
7963
  skillMdContent
7727
7964
  );
7728
- const readme = generateReadme(skillName, frontmatter);
7729
- await writeFile(path24.join(pluginDir, STANDARD_FILES.README_MD), readme);
7965
+ const readme = generateReadme(skillName2, frontmatter);
7966
+ await writeFile(path23.join(pluginDir, STANDARD_FILES.README_MD), readme);
7730
7967
  verbose(" Generated README.md");
7731
7968
  const manifest = manifestAt(
7732
7969
  versionAfterRebuild(earlierBuild, await computeShippedHash(pluginDir))
7733
7970
  );
7734
7971
  await writePluginManifest(pluginDir, manifest);
7735
- verbose(` Wrote plugin.json for ${skillName} (v${manifest.version})`);
7972
+ verbose(` Wrote plugin.json for ${skillName2} (v${manifest.version})`);
7736
7973
  return {
7737
7974
  pluginPath: pluginDir,
7738
7975
  manifest,
7739
- skillName
7976
+ skillName: skillName2
7740
7977
  };
7741
7978
  }
7742
7979
  async function compileAllSkillPlugins(skillsDir2, outputDir) {
@@ -7744,7 +7981,7 @@ async function compileAllSkillPlugins(skillsDir2, outputDir) {
7744
7981
  const failed = [];
7745
7982
  const skillMdFiles = await glob(`**/${STANDARD_FILES.SKILL_MD}`, skillsDir2);
7746
7983
  for (const skillMdFile of skillMdFiles) {
7747
- const skillPath = path24.join(skillsDir2, path24.dirname(skillMdFile));
7984
+ const skillPath = path23.join(skillsDir2, path23.dirname(skillMdFile));
7748
7985
  try {
7749
7986
  const result = await compileSkillPlugin({
7750
7987
  skillPath,
@@ -7754,7 +7991,7 @@ async function compileAllSkillPlugins(skillsDir2, outputDir) {
7754
7991
  log(` [OK] ${result.skillName}`);
7755
7992
  } catch (error) {
7756
7993
  const errorMessage = getErrorMessage(error);
7757
- const dirBasename = path24.basename(skillPath);
7994
+ const dirBasename = path23.basename(skillPath);
7758
7995
  failed.push(dirBasename);
7759
7996
  warn(`Failed to compile skill from '${dirBasename}': ${errorMessage}`);
7760
7997
  }
@@ -7770,7 +8007,7 @@ Compiled ${plural(results.length, "skill plugin")}:`);
7770
8007
  }
7771
8008
 
7772
8009
  // src/cli/lib/skills/local-skill-loader.ts
7773
- import path25 from "path";
8010
+ import path24 from "path";
7774
8011
  function copiedInSkillsAt(root, provider) {
7775
8012
  const scope = isHomeDirectory(root) ? "global" : "project";
7776
8013
  return {
@@ -7796,9 +8033,9 @@ async function discoverLocalSkills(root, provider = providerInUse(root)) {
7796
8033
  };
7797
8034
  }
7798
8035
  async function extractLocalSkill(localSkillsPath, pathPrefix, skillDirName) {
7799
- const skillDir = path25.join(localSkillsPath, skillDirName);
7800
- const metadataPath = path25.join(skillDir, STANDARD_FILES.METADATA_YAML);
7801
- const skillMdPath = path25.join(skillDir, STANDARD_FILES.SKILL_MD);
8036
+ const skillDir = path24.join(localSkillsPath, skillDirName);
8037
+ const metadataPath = path24.join(skillDir, STANDARD_FILES.METADATA_YAML);
8038
+ const skillMdPath = path24.join(skillDir, STANDARD_FILES.SKILL_MD);
7802
8039
  if (!await fileExists(metadataPath)) {
7803
8040
  verbose(`Skipping local skill '${skillDirName}': No metadata.yaml found`);
7804
8041
  return null;
@@ -7828,7 +8065,7 @@ async function extractLocalSkill(localSkillsPath, pathPrefix, skillDirName) {
7828
8065
  return null;
7829
8066
  }
7830
8067
  const relativePath = `${pathPrefix}/${skillDirName}/`;
7831
- const absolutePath = path25.join(localSkillsPath, skillDirName) + path25.sep;
8068
+ const absolutePath = path24.join(localSkillsPath, skillDirName) + path24.sep;
7832
8069
  const skillId = frontmatter.name;
7833
8070
  const extracted = {
7834
8071
  id: skillId,
@@ -7851,7 +8088,7 @@ async function extractLocalSkill(localSkillsPath, pathPrefix, skillDirName) {
7851
8088
  }
7852
8089
 
7853
8090
  // src/cli/lib/skills/unresolved-skill-entries.ts
7854
- import path26 from "path";
8091
+ import path25 from "path";
7855
8092
  async function findUnusableSavedSkillMetadata(savedSkills, projectDir) {
7856
8093
  const verdicts = await Promise.all(
7857
8094
  savedSkills.map((saved) => unusableMetadataOf(saved, projectDir))
@@ -7870,11 +8107,11 @@ function claimsLocalCopy(saved) {
7870
8107
  }
7871
8108
  function installedMetadataPath(saved, projectDir) {
7872
8109
  const { skillsDir: skillsDir2 } = resolveInstallPaths(projectDir, saved.scope);
7873
- return path26.join(skillsDir2, saved.id, STANDARD_FILES.METADATA_YAML);
8110
+ return path25.join(skillsDir2, saved.id, STANDARD_FILES.METADATA_YAML);
7874
8111
  }
7875
8112
 
7876
8113
  // src/cli/lib/skills/local-skill-mover.ts
7877
- import path27 from "path";
8114
+ import path26 from "path";
7878
8115
  var THE_DIRECTORY_ITSELF = ".";
7879
8116
  function validateSkillId(skillId) {
7880
8117
  return !(skillId.length === 0 || skillId === THE_DIRECTORY_ITSELF || skillId.includes("\0") || skillId.includes("..") || skillId.includes("/") || skillId.includes("\\"));
@@ -7884,8 +8121,8 @@ async function deleteLocalSkill(projectDir, skillId, scope = "project") {
7884
8121
  warn(`Invalid skill ID for deletion: '${skillId}'`);
7885
8122
  return;
7886
8123
  }
7887
- const skillsDir2 = path27.resolve(resolveInstallPaths(projectDir, scope).skillsDir);
7888
- const skillPath = path27.resolve(skillsDir2, skillId);
8124
+ const skillsDir2 = path26.resolve(resolveInstallPaths(projectDir, scope).skillsDir);
8125
+ const skillPath = path26.resolve(skillsDir2, skillId);
7889
8126
  if (!isPathWithin(skillPath, skillsDir2)) {
7890
8127
  warn(`Skill ID '${skillId}' resolves outside the skills directory.`);
7891
8128
  return;
@@ -7903,10 +8140,10 @@ async function migrateLocalSkillScope(skillId, fromScope, projectDir) {
7903
8140
  return;
7904
8141
  }
7905
8142
  const toScope = fromScope === "global" ? "project" : "global";
7906
- const fromSkillsDir = path27.resolve(resolveInstallPaths(projectDir, fromScope).skillsDir);
7907
- const toSkillsDir = path27.resolve(resolveInstallPaths(projectDir, toScope).skillsDir);
7908
- const fromPath = path27.resolve(fromSkillsDir, skillId);
7909
- const toPath = path27.resolve(toSkillsDir, skillId);
8143
+ const fromSkillsDir = path26.resolve(resolveInstallPaths(projectDir, fromScope).skillsDir);
8144
+ const toSkillsDir = path26.resolve(resolveInstallPaths(projectDir, toScope).skillsDir);
8145
+ const fromPath = path26.resolve(fromSkillsDir, skillId);
8146
+ const toPath = path26.resolve(toSkillsDir, skillId);
7910
8147
  if (!isPathWithin(fromPath, fromSkillsDir)) {
7911
8148
  warn(`Skill ID '${skillId}' resolves outside the source skills directory.`);
7912
8149
  return;
@@ -7933,7 +8170,7 @@ async function migrateLocalSkillScope(skillId, fromScope, projectDir) {
7933
8170
 
7934
8171
  // src/cli/lib/matrix/matrix-loader.ts
7935
8172
  import { parse as parseYaml5 } from "yaml";
7936
- import path28 from "path";
8173
+ import path27 from "path";
7937
8174
  async function loadSkillCategories(configPath) {
7938
8175
  const data = await loadConfig(configPath, skillCategoriesFileSchema);
7939
8176
  if (!data) {
@@ -7961,29 +8198,33 @@ async function loadSkillRules(configPath) {
7961
8198
  }
7962
8199
  async function extractAllSkills(skillsDir2) {
7963
8200
  const metadataFiles = await glob(`**/${STANDARD_FILES.METADATA_YAML}`, skillsDir2);
7964
- const skills = [];
8201
+ const folders = [];
7965
8202
  for (const metadataFile of metadataFiles) {
7966
- const skill = await extractSkill(skillsDir2, metadataFile);
7967
- if (skill) skills.push(skill);
8203
+ folders.push(await readSkillFolder(skillsDir2, metadataFile));
7968
8204
  }
7969
- return skills;
8205
+ return {
8206
+ skills: folders.flatMap((folder) => folder.kind === "loaded" ? [folder.skill] : []),
8207
+ unloadedSkillIds: folders.flatMap(
8208
+ (folder) => folder.kind === "unloaded" ? [folder.skillId] : []
8209
+ )
8210
+ };
7970
8211
  }
7971
- async function extractSkill(skillsDir2, metadataFile) {
7972
- const skillDir = path28.dirname(metadataFile);
7973
- const skillMdPath = path28.join(skillsDir2, skillDir, STANDARD_FILES.SKILL_MD);
8212
+ async function readSkillFolder(skillsDir2, metadataFile) {
8213
+ const skillDir = path27.dirname(metadataFile);
8214
+ const skillMdPath = path27.join(skillsDir2, skillDir, STANDARD_FILES.SKILL_MD);
7974
8215
  if (!await fileExists(skillMdPath)) {
7975
- verbose(`Skipping ${metadataFile}: No ${STANDARD_FILES.SKILL_MD} found`);
7976
- return null;
8216
+ warn(`Skipping '${metadataFile}': No ${STANDARD_FILES.SKILL_MD} found`);
8217
+ return { kind: "unnamed" };
7977
8218
  }
7978
- const metadata = await readMatrixMetadataOrWarn(metadataFile, path28.join(skillsDir2, metadataFile));
7979
- if (!metadata) return null;
8219
+ const metadata = await readMatrixMetadataOrWarn(metadataFile, path27.join(skillsDir2, metadataFile));
8220
+ if (!metadata) return unloadedSkillNamedBy(skillMdPath);
7980
8221
  const frontmatter = parseFrontmatterOrWarn(skillDir, skillMdPath, await readFile(skillMdPath));
7981
- if (!frontmatter) return null;
8222
+ if (!frontmatter) return { kind: "unnamed" };
7982
8223
  if (!metadata.displayName) {
7983
8224
  warn(
7984
8225
  `Skipping '${metadataFile}': invalid ${STANDARD_FILES.METADATA_YAML} \u2014 missing required field: ${METADATA_KEYS.DISPLAY_NAME}`
7985
8226
  );
7986
- return null;
8227
+ return { kind: "unloaded", skillId: frontmatter.name };
7987
8228
  }
7988
8229
  const skillId = frontmatter.name;
7989
8230
  const extracted = {
@@ -8001,7 +8242,16 @@ async function extractSkill(skillsDir2, metadataFile) {
8001
8242
  ...metadata.custom === true ? { custom: true } : {}
8002
8243
  };
8003
8244
  verbose(`Extracted skill: ${skillId}`);
8004
- return extracted;
8245
+ return { kind: "loaded", skill: extracted };
8246
+ }
8247
+ async function unloadedSkillNamedBy(skillMdPath) {
8248
+ try {
8249
+ const frontmatter = parseFrontmatter(await readFile(skillMdPath), skillMdPath);
8250
+ return frontmatter ? { kind: "unloaded", skillId: frontmatter.name } : { kind: "unnamed" };
8251
+ } catch (error) {
8252
+ verbose(`No skill named by '${skillMdPath}' \u2014 ${getErrorMessage(error)}`);
8253
+ return { kind: "unnamed" };
8254
+ }
8005
8255
  }
8006
8256
  async function readMatrixMetadataOrWarn(metadataFile, metadataPath) {
8007
8257
  const metadataContent = await readFile(metadataPath);
@@ -8029,7 +8279,7 @@ function parseFrontmatterOrWarn(skillDir, skillMdPath, skillMdContent) {
8029
8279
  const unreadable = unreadableFrontmatter(skillMdContent);
8030
8280
  if (unreadable !== void 0) {
8031
8281
  warn(
8032
- `Skipping '${path28.join(skillDir, STANDARD_FILES.SKILL_MD)}': unparseable ${STANDARD_FILES.SKILL_MD} frontmatter at ${skillMdPath} \u2014 ${unreadable}`
8282
+ `Skipping '${path27.join(skillDir, STANDARD_FILES.SKILL_MD)}': unparseable ${STANDARD_FILES.SKILL_MD} frontmatter at ${skillMdPath} \u2014 ${unreadable}`
8033
8283
  );
8034
8284
  }
8035
8285
  return null;
@@ -9918,10 +10168,17 @@ async function loadCatalogue(options) {
9918
10168
  const resolvedProjectDir = projectDir || process.cwd();
9919
10169
  const result = {
9920
10170
  ...catalogue,
9921
- marketplaceSkillIds: new Set(typedKeys(catalogue.matrix.skills))
10171
+ marketplaceSkillIds: new Set(typedKeys(catalogue.matrix.skills)),
10172
+ marketplaceSkills: { ...catalogue.matrix.skills }
9922
10173
  };
9923
- result.matrix = await mergeLocalSkills(result.matrix, resolvedProjectDir, provider);
9924
- await seatGlobalInstallationSkills(result.matrix, source, purpose);
10174
+ const globalProvider = provider ?? inheritedGlobalProvider(resolvedProjectDir);
10175
+ result.matrix = await mergeLocalSkills(
10176
+ result.matrix,
10177
+ resolvedProjectDir,
10178
+ provider,
10179
+ globalProvider
10180
+ );
10181
+ await seatGlobalInstallationSkills(result.matrix, source, purpose, globalProvider);
9925
10182
  if (!options.skipExtraSources) {
9926
10183
  await loadSkillsFromAllSources(
9927
10184
  result.matrix,
@@ -9935,16 +10192,20 @@ async function loadCatalogue(options) {
9935
10192
  initializeMatrix(result.matrix);
9936
10193
  return result;
9937
10194
  }
9938
- async function seatGlobalInstallationSkills(matrix2, loadedSource, purpose) {
9939
- const uncarried = await globalPluginSkillsUncarried(matrix2);
10195
+ async function seatGlobalInstallationSkills(matrix2, loadedSource, purpose, globalProvider) {
10196
+ const uncarried = await globalPluginSkillsUncarried(matrix2, globalProvider);
9940
10197
  if (uncarried.length === 0) return;
9941
- const globalCatalogue = await loadGlobalInstallationCatalogue(loadedSource, purpose);
10198
+ const globalCatalogue = await loadGlobalInstallationCatalogue(
10199
+ loadedSource,
10200
+ purpose,
10201
+ globalProvider
10202
+ );
9942
10203
  if (globalCatalogue === null) return;
9943
10204
  for (const id of uncarried) seatFromCatalogue(matrix2, globalCatalogue, id);
9944
10205
  }
9945
- async function globalPluginSkillsUncarried(matrix2) {
10206
+ async function globalPluginSkillsUncarried(matrix2, globalProvider) {
9946
10207
  try {
9947
- const globalConfig = await loadGlobalSourceConfig();
10208
+ const globalConfig = await loadGlobalSourceConfig(globalProvider);
9948
10209
  return (globalConfig?.skills ?? []).filter(isActivePlugin).filter((skill) => matrix2.skills[skill.id] === void 0).map((skill) => skill.id);
9949
10210
  } catch (error) {
9950
10211
  verbose(`Global installation's skills not seated \u2014 ${getErrorMessage(error)}`);
@@ -9954,9 +10215,13 @@ async function globalPluginSkillsUncarried(matrix2) {
9954
10215
  function isActivePlugin(skill) {
9955
10216
  return !skill.excluded && skill.origin !== EJECT_SOURCE;
9956
10217
  }
9957
- async function loadGlobalInstallationCatalogue(loadedSource, purpose) {
10218
+ async function loadGlobalInstallationCatalogue(loadedSource, purpose, globalProvider) {
9958
10219
  try {
9959
- const globalSourceConfig = await resolveSource({ caller: "stored", projectDir: os14.homedir() });
10220
+ const globalSourceConfig = await resolveSource({
10221
+ caller: "stored",
10222
+ projectDir: os14.homedir(),
10223
+ provider: globalProvider
10224
+ });
9960
10225
  if (globalSourceConfig.source === loadedSource) return null;
9961
10226
  return await resolveBaseResult(globalSourceConfig, {
9962
10227
  purpose,
@@ -10012,6 +10277,8 @@ async function resolveBaseResult(sourceConfig, { purpose, devMode, matrixOnly })
10012
10277
  const fetched = matrixOnly ? NOTHING_FETCHED : await fetchFromSource(source);
10013
10278
  return {
10014
10279
  matrix: copyOfBuiltInMatrix(),
10280
+ // Checked when it was generated, so nothing in it failed to load.
10281
+ unloadedSkillIds: /* @__PURE__ */ new Set(),
10015
10282
  sourceConfig,
10016
10283
  sourcePath: fetched.path,
10017
10284
  isLocal: false,
@@ -10082,8 +10349,8 @@ function goesOnWithoutManifest(source, purpose) {
10082
10349
  function configuredLabel(sourceConfig) {
10083
10350
  return sourceConfig.marketplace === void 0 ? {} : { marketplace: sourceConfig.marketplace };
10084
10351
  }
10085
- async function mergeLocalSkills(matrix2, projectDir, provider) {
10086
- const withGlobal = isHomeDirectory(projectDir) ? matrix2 : await mergeDiscoveredLocalSkills(matrix2, os14.homedir(), "global", provider);
10352
+ async function mergeLocalSkills(matrix2, projectDir, provider, globalProvider) {
10353
+ const withGlobal = isHomeDirectory(projectDir) ? matrix2 : await mergeDiscoveredLocalSkills(matrix2, os14.homedir(), "global", globalProvider);
10087
10354
  return mergeDiscoveredLocalSkills(withGlobal, projectDir, "project", provider);
10088
10355
  }
10089
10356
  async function mergeDiscoveredLocalSkills(matrix2, dir, label, provider) {
@@ -10097,10 +10364,11 @@ async function mergeDiscoveredLocalSkills(matrix2, dir, label, provider) {
10097
10364
  async function loadFromLocal(source, sourceConfig, purpose) {
10098
10365
  const skillsPath = isLocalSource(source) ? (await fetchFromSource(source)).path : PROJECT_ROOT;
10099
10366
  verbose(`Loading skills from local path: ${skillsPath}`);
10100
- const mergedMatrix = await loadAndMergeFromBasePath(skillsPath, source);
10367
+ const { matrix: matrix2, unloadedSkillIds } = await loadAndMergeFromBasePath(skillsPath, source);
10101
10368
  const labels = await resolveMarketplaceLabels(skillsPath, sourceConfig, purpose);
10102
10369
  return {
10103
- matrix: mergedMatrix,
10370
+ matrix: matrix2,
10371
+ unloadedSkillIds,
10104
10372
  sourceConfig,
10105
10373
  sourcePath: skillsPath,
10106
10374
  isLocal: true,
@@ -10112,10 +10380,11 @@ async function loadFromRemote(source, sourceConfig, purpose) {
10112
10380
  verbose(`Fetching skills from remote source: ${source}`);
10113
10381
  const fetchResult = await fetchFromSource(source);
10114
10382
  verbose(`Fetched to: ${fetchResult.path}`);
10115
- const mergedMatrix = await loadAndMergeFromBasePath(fetchResult.path, source);
10383
+ const { matrix: matrix2, unloadedSkillIds } = await loadAndMergeFromBasePath(fetchResult.path, source);
10116
10384
  const labels = await resolveMarketplaceLabels(source, sourceConfig, purpose);
10117
10385
  return {
10118
- matrix: mergedMatrix,
10386
+ matrix: matrix2,
10387
+ unloadedSkillIds,
10119
10388
  sourceConfig,
10120
10389
  sourcePath: fetchResult.path,
10121
10390
  isLocal: false,
@@ -10124,7 +10393,7 @@ async function loadFromRemote(source, sourceConfig, purpose) {
10124
10393
  };
10125
10394
  }
10126
10395
  async function loadMarketplaceMatrix(marketplaceDir) {
10127
- const matrix2 = await loadAndMergeFromBasePath(marketplaceDir, marketplaceDir);
10396
+ const { matrix: matrix2 } = await loadAndMergeFromBasePath(marketplaceDir, marketplaceDir);
10128
10397
  return { ...matrix2, categories: categoriesTheseSkillsAreIn(matrix2) };
10129
10398
  }
10130
10399
  function categoriesTheseSkillsAreIn(matrix2) {
@@ -10140,16 +10409,17 @@ async function loadAndMergeFromBasePath(basePath, source) {
10140
10409
  const skillsDirRelPath = sourceProjectConfig?.skillsDir ?? SKILLS_DIR_PATH;
10141
10410
  const stacksRelFile = sourceProjectConfig?.stacksFile;
10142
10411
  const { categories, sourceRules } = await loadSourceTaxonomy(basePath);
10143
- const skillsDir2 = path29.join(basePath, skillsDirRelPath);
10412
+ const skillsDir2 = path28.join(basePath, skillsDirRelPath);
10144
10413
  verbose(`Skills from source: ${skillsDir2}`);
10145
- const skills = await extractAllSkills(skillsDir2);
10414
+ const { skills, unloadedSkillIds } = await extractAllSkills(skillsDir2);
10146
10415
  await refuseCatalogueCollisions(basePath, source, skills);
10147
10416
  const relationships = relationshipsForSource(skills, sourceRules);
10148
10417
  const mergedMatrix = mergeMatrixWithSkills(categories, relationships, skills);
10149
- initializeMatrix(mergedMatrix);
10150
10418
  const stacks = await resolveOfferedStacks(basePath, stacksRelFile, source);
10151
- mergedMatrix.suggestedStacks = stacks.map((stack) => convertStackToResolvedStack(stack));
10152
- return mergedMatrix;
10419
+ mergedMatrix.suggestedStacks = stacks.map(
10420
+ (stack) => convertStackToResolvedStack(stack, mergedMatrix)
10421
+ );
10422
+ return { matrix: mergedMatrix, unloadedSkillIds: new Set(unloadedSkillIds) };
10153
10423
  }
10154
10424
  async function loadSourceTaxonomy(basePath) {
10155
10425
  const sourceCategories = await loadSourceCategories(basePath);
@@ -10163,7 +10433,7 @@ async function loadSourceTaxonomy(basePath) {
10163
10433
  return { categories, sourceRules };
10164
10434
  }
10165
10435
  async function loadSourceCategories(basePath) {
10166
- const categoriesPath = path29.join(basePath, SKILL_CATEGORIES_PATH);
10436
+ const categoriesPath = path28.join(basePath, SKILL_CATEGORIES_PATH);
10167
10437
  if (!await fileExists(categoriesPath)) return void 0;
10168
10438
  const categories = await loadSkillCategories(categoriesPath);
10169
10439
  verbose(
@@ -10172,7 +10442,7 @@ async function loadSourceCategories(basePath) {
10172
10442
  return categories;
10173
10443
  }
10174
10444
  async function loadSourceRules(basePath) {
10175
- const rulesPath = path29.join(basePath, SKILL_RULES_PATH);
10445
+ const rulesPath = path28.join(basePath, SKILL_RULES_PATH);
10176
10446
  if (!await fileExists(rulesPath)) return void 0;
10177
10447
  const rules = await loadSkillRules(rulesPath);
10178
10448
  verbose(`Loaded source rules: ${rulesPath}`);
@@ -10226,11 +10496,12 @@ function withdrawnSkillsWarning(stack, withdrawn) {
10226
10496
  const named = withdrawn.map((id) => `'${id}'`).join(", ");
10227
10497
  return `Stack '${stack.id}' names ${withdrawn.length} skill(s) this marketplace's catalogue does not carry: ${named}. Left out of the stack \u2014 selecting it would install nothing.`;
10228
10498
  }
10229
- function convertStackToResolvedStack(stack) {
10499
+ function convertStackToResolvedStack(stack, catalogue) {
10230
10500
  const { declared, undeclared } = declaredAgentsIn(stack);
10231
10501
  if (undeclared.length > 0) warn(undeclaredAgentsWarning(stack, undeclared));
10502
+ const isCarried = carriedBy(catalogue);
10232
10503
  const agentConfigs = agentConfigsFor(stack, declared);
10233
- const [allSkillIds, withdrawn] = partition4(namedSkillIds(agentConfigs), isInCurrentCatalogue);
10504
+ const [allSkillIds, withdrawn] = partition5(namedSkillIds(agentConfigs), isCarried);
10234
10505
  if (withdrawn.length > 0) warn(withdrawnSkillsWarning(stack, withdrawn));
10235
10506
  verbose(
10236
10507
  `Stack '${stack.id}' has ${allSkillIds.length} skills from ${agentConfigs.length} agents`
@@ -10239,7 +10510,7 @@ function convertStackToResolvedStack(stack) {
10239
10510
  id: stack.id,
10240
10511
  name: stack.name,
10241
10512
  description: stack.description,
10242
- skills: skillsByAgent(agentConfigs),
10513
+ skills: skillsByAgent(agentConfigs, isCarried),
10243
10514
  allSkillIds,
10244
10515
  philosophy: stack.philosophy || ""
10245
10516
  };
@@ -10257,21 +10528,21 @@ function namedSkillIds(agentConfigs) {
10257
10528
  )
10258
10529
  );
10259
10530
  }
10260
- function isInCurrentCatalogue(id) {
10261
- return id in matrix.skills;
10531
+ function carriedBy(catalogue) {
10532
+ return (id) => id in catalogue.skills;
10262
10533
  }
10263
- function skillsByAgent(agentConfigs) {
10534
+ function skillsByAgent(agentConfigs, isCarried) {
10264
10535
  return typedFromEntries(
10265
10536
  agentConfigs.map(
10266
- ({ agentId, agentConfig }) => [agentId, resolveStackAgentSkills(agentConfig)]
10537
+ ({ agentId, agentConfig }) => [agentId, resolveStackAgentSkills(agentConfig, isCarried)]
10267
10538
  )
10268
10539
  );
10269
10540
  }
10270
- function resolveStackAgentSkills(agentConfig) {
10541
+ function resolveStackAgentSkills(agentConfig, isCarried) {
10271
10542
  const carriedByCategory = typedEntries(agentConfig).map(
10272
10543
  ([category, assignments]) => (
10273
10544
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Object.entries drops the `| undefined` a Partial<Record> admits
10274
- [category, (assignments ?? []).map((a) => a.id).filter(isInCurrentCatalogue)]
10545
+ [category, (assignments ?? []).map((a) => a.id).filter(isCarried)]
10275
10546
  )
10276
10547
  );
10277
10548
  return typedFromEntries(carriedByCategory.filter(([, ids]) => ids.length > 0));
@@ -10280,7 +10551,7 @@ function declaresCategory(matrix2, category) {
10280
10551
  return category !== LOCAL_PSEUDO_CATEGORY && matrix2.categories[category] !== void 0;
10281
10552
  }
10282
10553
  function undeclaredCategoryRefusal(metadata, category) {
10283
- const metadataPath = path29.join(metadata.path, STANDARD_FILES.METADATA_YAML);
10554
+ const metadataPath = path28.join(metadata.path, STANDARD_FILES.METADATA_YAML);
10284
10555
  return `Skipping local skill '${metadata.id}': ${METADATA_KEYS.CATEGORY} '${category}' is not one this installation declares, so the skill belongs in no grid tab and can be given to no sub-agent. Set ${METADATA_KEYS.CATEGORY} in ${metadataPath} to a category that already exists \u2014 a skill is placed in the taxonomy, it does not extend it.`;
10285
10556
  }
10286
10557
  function mergeLocalSkillsIntoMatrix(matrix2, localResult) {
@@ -10358,6 +10629,8 @@ export {
10358
10629
  chooseProviderForThisRun,
10359
10630
  forgetTheProviderChosenForThisRun,
10360
10631
  providerInUse,
10632
+ inheritedGlobalProvider,
10633
+ providerAtScope,
10361
10634
  sourceFolderInUse,
10362
10635
  relativeConfigPath,
10363
10636
  sourceFolderName,
@@ -10414,7 +10687,7 @@ export {
10414
10687
  sharedSkillsLeftBehind,
10415
10688
  sharedConfigExistingInstall,
10416
10689
  sharedConfigProjectScopeAtHome,
10417
- skippedUnknownSkills,
10690
+ skippedSkills,
10418
10691
  skippedUnknownAgents,
10419
10692
  carriedSkillsWritten,
10420
10693
  SHARED_CONFIG_APPLY,
@@ -10499,16 +10772,17 @@ export {
10499
10772
  resolveAgentConfigToSkills,
10500
10773
  getStackSkillIds,
10501
10774
  ConfigLoadError,
10775
+ declaresNoContent,
10502
10776
  loadProjectConfigFromDir,
10503
10777
  loadProjectConfigAt,
10504
10778
  loadInstalledConfig,
10505
- configDirsInPlay,
10779
+ configsInPlay,
10506
10780
  findConfigLoadFailures,
10507
10781
  loadProjectConfig,
10782
+ loadConfigInPlay,
10508
10783
  validateProjectConfig,
10509
10784
  INSTALL_MODE_LABELS,
10510
10785
  INSTALL_MODE_DESCRIPTIONS,
10511
- declaresNoContent,
10512
10786
  deriveInstallMode,
10513
10787
  detectProjectInstallation,
10514
10788
  holdsItsOwnInstallation,
@@ -10550,6 +10824,7 @@ export {
10550
10824
  readLocalSkillMetadata,
10551
10825
  validateSkillPath,
10552
10826
  copySkillsToLocalFlattened,
10827
+ copyMarketplaceSkillsToLocalFlattened,
10553
10828
  getUserPluginsDir,
10554
10829
  getProjectPluginsDir,
10555
10830
  getPluginAgentsDir,
@@ -10579,6 +10854,7 @@ export {
10579
10854
  refuseUnofferedPlacements,
10580
10855
  hostFor,
10581
10856
  hostAt,
10857
+ getVerifiedPluginInstallPaths,
10582
10858
  discoverAllPluginSkills,
10583
10859
  listPluginNames,
10584
10860
  compileSkillPlugin,
@@ -10613,6 +10889,8 @@ export {
10613
10889
  sourceScopesInPlay,
10614
10890
  scopeRootsInPlay,
10615
10891
  detectInstallations,
10892
+ configsDeclaringNothing,
10893
+ holdsAConfigDeclaringNothing,
10616
10894
  ejectCopyFailureError,
10617
10895
  copyingBesideGlobalPlugins,
10618
10896
  installingBesideGlobalCopies,
@@ -10620,4 +10898,4 @@ export {
10620
10898
  executeMigration,
10621
10899
  keepsGlobalInstall
10622
10900
  };
10623
- //# sourceMappingURL=chunk-E45IT3HC.js.map
10901
+ //# sourceMappingURL=chunk-YM3VEDAP.js.map