agents-inc 0.172.0 → 0.174.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 (81) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/dist/{chunk-6LUTY35Q.js → chunk-3PJZ4QNJ.js} +7 -7
  3. package/dist/{chunk-255DGUCH.js → chunk-6PGXTLA4.js} +12 -6
  4. package/dist/{chunk-255DGUCH.js.map → chunk-6PGXTLA4.js.map} +1 -1
  5. package/dist/{chunk-KCLBLK3F.js → chunk-7BHDKEGK.js} +3 -3
  6. package/dist/{chunk-7OG635DK.js → chunk-AIBVAYHS.js} +6 -2
  7. package/dist/{chunk-7OG635DK.js.map → chunk-AIBVAYHS.js.map} +1 -1
  8. package/dist/{chunk-5MGRHS2G.js → chunk-APWMMZOK.js} +42 -25
  9. package/dist/chunk-APWMMZOK.js.map +1 -0
  10. package/dist/{chunk-VILFCMRN.js → chunk-E45IT3HC.js} +368 -123
  11. package/dist/chunk-E45IT3HC.js.map +1 -0
  12. package/dist/{chunk-MOL2J5HS.js → chunk-ECPFYHDX.js} +2 -2
  13. package/dist/{chunk-LUKDDHSI.js → chunk-EFXVYQGT.js} +4 -4
  14. package/dist/{chunk-G7NUK3BF.js → chunk-FQF6VHO3.js} +29 -19
  15. package/dist/chunk-FQF6VHO3.js.map +1 -0
  16. package/dist/chunk-H5E6IO2L.js +116 -0
  17. package/dist/chunk-H5E6IO2L.js.map +1 -0
  18. package/dist/{chunk-3R3LHA4Q.js → chunk-I3WF6L43.js} +2 -2
  19. package/dist/{chunk-7ZOWSCAO.js → chunk-IAQFZFWD.js} +4 -4
  20. package/dist/{chunk-NISWBQNS.js → chunk-IXVGBUWI.js} +5 -5
  21. package/dist/{chunk-MBIOZ5LW.js → chunk-ORO2T4K2.js} +19 -5
  22. package/dist/chunk-ORO2T4K2.js.map +1 -0
  23. package/dist/{chunk-A3ZAXL5T.js → chunk-QCX66KBM.js} +3 -3
  24. package/dist/{chunk-6CRA46YO.js → chunk-R7GKQBZJ.js} +44 -21
  25. package/dist/chunk-R7GKQBZJ.js.map +1 -0
  26. package/dist/{chunk-Y23MP2OC.js → chunk-REHVGFJE.js} +5 -5
  27. package/dist/{chunk-5PPB6HT6.js → chunk-TVEDNGVP.js} +2 -2
  28. package/dist/{chunk-MHAQWMNJ.js → chunk-WUSEZFER.js} +1 -5
  29. package/dist/{chunk-MHAQWMNJ.js.map → chunk-WUSEZFER.js.map} +1 -1
  30. package/dist/commands/build/marketplace.js +4 -4
  31. package/dist/commands/build/plugins.js +6 -6
  32. package/dist/commands/compile.js +12 -12
  33. package/dist/commands/doctor.js +33 -15
  34. package/dist/commands/doctor.js.map +1 -1
  35. package/dist/commands/edit.js +56 -59
  36. package/dist/commands/edit.js.map +1 -1
  37. package/dist/commands/eject.js +25 -30
  38. package/dist/commands/eject.js.map +1 -1
  39. package/dist/commands/init.js +17 -18
  40. package/dist/commands/list.js +41 -16
  41. package/dist/commands/list.js.map +1 -1
  42. package/dist/commands/new/marketplace.js +4 -4
  43. package/dist/commands/search.js +9 -9
  44. package/dist/commands/share.js +9 -9
  45. package/dist/commands/uninstall.js +61 -56
  46. package/dist/commands/uninstall.js.map +1 -1
  47. package/dist/commands/update.js +6 -6
  48. package/dist/components/common/select-list.js +2 -2
  49. package/dist/components/common/skill-agent-summary.js +3 -3
  50. package/dist/components/common/summary-panel.js +4 -7
  51. package/dist/hooks/init.js +57 -33
  52. package/dist/hooks/init.js.map +1 -1
  53. package/dist/load-agent-defs-5U5KAURA.js +14 -0
  54. package/dist/{recompile-project-agents-5A44NJRD.js → recompile-project-agents-KYK44C24.js} +8 -8
  55. package/dist/{source-loader-LQNRI5UZ.js → source-loader-G5I4RNUP.js} +4 -4
  56. package/package.json +1 -1
  57. package/dist/chunk-33JICQD5.js +0 -196
  58. package/dist/chunk-33JICQD5.js.map +0 -1
  59. package/dist/chunk-5MGRHS2G.js.map +0 -1
  60. package/dist/chunk-6CRA46YO.js.map +0 -1
  61. package/dist/chunk-G7NUK3BF.js.map +0 -1
  62. package/dist/chunk-MBIOZ5LW.js.map +0 -1
  63. package/dist/chunk-N33AKFLR.js +0 -24
  64. package/dist/chunk-N33AKFLR.js.map +0 -1
  65. package/dist/chunk-VILFCMRN.js.map +0 -1
  66. package/dist/components/common/scroll-affordance.js +0 -9
  67. package/dist/load-agent-defs-54VIKN4T.js +0 -14
  68. package/dist/source-loader-LQNRI5UZ.js.map +0 -1
  69. /package/dist/{chunk-6LUTY35Q.js.map → chunk-3PJZ4QNJ.js.map} +0 -0
  70. /package/dist/{chunk-KCLBLK3F.js.map → chunk-7BHDKEGK.js.map} +0 -0
  71. /package/dist/{chunk-MOL2J5HS.js.map → chunk-ECPFYHDX.js.map} +0 -0
  72. /package/dist/{chunk-LUKDDHSI.js.map → chunk-EFXVYQGT.js.map} +0 -0
  73. /package/dist/{chunk-3R3LHA4Q.js.map → chunk-I3WF6L43.js.map} +0 -0
  74. /package/dist/{chunk-7ZOWSCAO.js.map → chunk-IAQFZFWD.js.map} +0 -0
  75. /package/dist/{chunk-NISWBQNS.js.map → chunk-IXVGBUWI.js.map} +0 -0
  76. /package/dist/{chunk-A3ZAXL5T.js.map → chunk-QCX66KBM.js.map} +0 -0
  77. /package/dist/{chunk-Y23MP2OC.js.map → chunk-REHVGFJE.js.map} +0 -0
  78. /package/dist/{chunk-5PPB6HT6.js.map → chunk-TVEDNGVP.js.map} +0 -0
  79. /package/dist/{components/common/scroll-affordance.js.map → load-agent-defs-5U5KAURA.js.map} +0 -0
  80. /package/dist/{recompile-project-agents-5A44NJRD.js.map → recompile-project-agents-KYK44C24.js.map} +0 -0
  81. /package/dist/{load-agent-defs-54VIKN4T.js.map → source-loader-G5I4RNUP.js.map} +0 -0
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  BUILT_IN_MATRIX,
4
4
  getSkillById,
5
- getSkillDisplayName,
5
+ getSkillEntryDisplayName,
6
6
  inertLine,
7
7
  initializeMatrix,
8
8
  matrix,
@@ -13,7 +13,7 @@ import {
13
13
  typedFromEntries,
14
14
  typedKeys,
15
15
  typedValues
16
- } from "./chunk-7OG635DK.js";
16
+ } from "./chunk-AIBVAYHS.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-MHAQWMNJ.js";
85
+ } from "./chunk-WUSEZFER.js";
86
86
  import {
87
87
  defaultCategories,
88
88
  defaultRules,
@@ -490,8 +490,9 @@ function sourceRootOf(root) {
490
490
  return { dir: path.join(root, SOURCE_ROOT_DIR), relName: SOURCE_ROOT_DIR };
491
491
  }
492
492
  var RETIRED_SOURCE_FOLDER = ".claude-src";
493
- function retiredSourceFolderIn(roots) {
494
- return [...new Set(roots)].filter(holdsTheRetiredSourceFolder);
493
+ function rootsHoldingTheRetiredSourceFolder(cwd) {
494
+ const roots = isHomeDirectory(cwd) ? [os2.homedir()] : [os2.homedir(), cwd];
495
+ return roots.filter(holdsTheRetiredSourceFolder);
495
496
  }
496
497
  function holdsTheRetiredSourceFolder(root) {
497
498
  return directoryExists(path.join(root, RETIRED_SOURCE_FOLDER));
@@ -504,6 +505,9 @@ var providerChosenForThisRun;
504
505
  function chooseProviderForThisRun(provider) {
505
506
  providerChosenForThisRun = provider;
506
507
  }
508
+ function forgetTheProviderChosenForThisRun() {
509
+ providerChosenForThisRun = void 0;
510
+ }
507
511
  function providerInUse(root) {
508
512
  if (providerChosenForThisRun !== void 0) return providerChosenForThisRun;
509
513
  if (root === void 0) return PROVIDER_OF_A_NEW_INSTALLATION;
@@ -744,8 +748,8 @@ async function fileExists(filePath) {
744
748
  }
745
749
  async function directoryExists2(dirPath) {
746
750
  try {
747
- const stat = await fs3.stat(dirPath);
748
- return stat.isDirectory();
751
+ const stat2 = await fs3.stat(dirPath);
752
+ return stat2.isDirectory();
749
753
  } catch {
750
754
  return false;
751
755
  }
@@ -953,6 +957,8 @@ var INFO_MESSAGES = {
953
957
  CONFIG_TYPES_REFRESHED: `Refreshed ${STANDARD_FILES.CONFIG_TYPES_TS}`,
954
958
  EJECTED_SKILLS_USER_OWNED: `Ejected skills are yours to own \u2014 '${CLI_INVOKE_COMMAND} update' does not change them.`,
955
959
  NO_PLUGIN_MARKETPLACES: "No plugin marketplaces are configured \u2014 nothing to refresh.",
960
+ /** Under doctor's marketplace row, when its download replaced a saved copy whose files differed. */
961
+ SAVED_COPY_REPLACED: "The saved copy differed from the marketplace and has been replaced",
956
962
  /** Printed under the destination already named, so it names files only. */
957
963
  AGENT_PARTIALS_CUSTOMIZABLE: `Each sub-agent directory there holds ${AGENT_PARTIAL_FILES.join(", ")} \u2014 edit those to customize that sub-agent.`
958
964
  };
@@ -1010,6 +1016,9 @@ function marketplaceRefreshFailed(marketplace, reason) {
1010
1016
  function sourceUnreachableUsingCache(source) {
1011
1017
  return `Could not reach ${source} \u2014 using the cached copy, which may be out of date.`;
1012
1018
  }
1019
+ function sourceRefusedUsingCache(source, status) {
1020
+ return `${source} refused the request (${status}) \u2014 using the cached copy, which may be out of date.`;
1021
+ }
1013
1022
  function marketplacesRefreshFailed(marketplaces) {
1014
1023
  return `${plural(marketplaces.length, "marketplace")} could not be updated: ${marketplaces.join(", ")}`;
1015
1024
  }
@@ -1213,8 +1222,9 @@ function keptAsInstalledGlobally(skillIds, agentNames, idAppliedAtHome, provider
1213
1222
  ]
1214
1223
  ].join("\n");
1215
1224
  }
1216
- function skillsMoved(verb, skillIds) {
1217
- return skillIds.length === 0 ? [] : [`${verb} ${listed(skillIds.map(getSkillDisplayName))}`];
1225
+ function skillsMoved(verb, skillIds, namedBy) {
1226
+ const names = skillIds.map((id) => getSkillEntryDisplayName(namedBy[id] ?? { id }));
1227
+ return names.length === 0 ? [] : [`${verb} ${listed(names)}`];
1218
1228
  }
1219
1229
  function settingMoved({ setting, from, to }) {
1220
1230
  return `${setting} ${from ?? "default"} \u2192 ${to ?? "default"}`;
@@ -1224,10 +1234,17 @@ function listed(names) {
1224
1234
  return `${names.slice(0, -1).join(", ")} and ${names.at(-1)}`;
1225
1235
  }
1226
1236
  var SKILLS_REASSIGNED = "skills reassigned";
1227
- function subAgentChanged({ name, scope, gains, loses, settings }) {
1237
+ function subAgentChanged({
1238
+ name,
1239
+ scope,
1240
+ gains,
1241
+ loses,
1242
+ settings,
1243
+ namedBy = {}
1244
+ }) {
1228
1245
  const details = [
1229
- ...skillsMoved("gains", gains),
1230
- ...skillsMoved("loses", loses),
1246
+ ...skillsMoved("gains", gains, namedBy),
1247
+ ...skillsMoved("loses", loses, namedBy),
1231
1248
  ...settings.map(settingMoved)
1232
1249
  ];
1233
1250
  const where = scope === "global" ? " (global)" : "";
@@ -1316,8 +1333,9 @@ function sentenceCase(text) {
1316
1333
  function layoutIsCurrent(label, to) {
1317
1334
  return `${label} is on ${to}/`;
1318
1335
  }
1319
- function retiredSourceFolderUnsupported(root) {
1320
- return `${path3.join(root, RETIRED_SOURCE_FOLDER)}/ is no longer supported (agents-inc now serves Claude and Codex). Move it to ${path3.join(root, sourceDirName("claude"))}/.`;
1336
+ function retiredSourceFolderIgnored(root, provider) {
1337
+ const named = isHomeDirectory(root) ? "~" : root;
1338
+ return `${path3.join(named, RETIRED_SOURCE_FOLDER)}/ is ignored; agents-inc reads ${path3.join(named, sourceDirName(provider))}/. Delete the old folder once you have kept anything you need from it.`;
1321
1339
  }
1322
1340
 
1323
1341
  // src/cli/types/generated/source-types.ts
@@ -2139,6 +2157,7 @@ var projectConfigFields = z2.object({
2139
2157
  id: z2.string(),
2140
2158
  scope: z2.enum(["project", "global"]),
2141
2159
  origin: z2.string(),
2160
+ displayName: z2.string().exactOptional(),
2142
2161
  excluded: z2.boolean().exactOptional()
2143
2162
  })
2144
2163
  ).exactOptional(),
@@ -2549,14 +2568,12 @@ async function loadConfig(configPath, schema) {
2549
2568
  if (declaresNoDefaultExport(namespace)) {
2550
2569
  throw new ConfigDefaultExportError(configPath);
2551
2570
  }
2552
- if (schema) {
2553
- const result = schema.safeParse(raw);
2554
- if (!result.success) {
2555
- throw new ConfigSchemaError(configPath, formatZodIssues(result.error.issues));
2556
- }
2557
- return result.data;
2571
+ if (!schema) return raw;
2572
+ const result = schema.safeParse(raw);
2573
+ if (!result.success) {
2574
+ throw new ConfigSchemaError(configPath, formatZodIssues(result.error.issues));
2558
2575
  }
2559
- return raw;
2576
+ return result.data;
2560
2577
  }
2561
2578
  async function importConfigModule(configPath) {
2562
2579
  try {
@@ -3177,7 +3194,16 @@ function brokenUnionLayout(members, bodyIndent) {
3177
3194
  }
3178
3195
  function renderUnionBody(members, layout, bodyIndent) {
3179
3196
  const padding = spaces(bodyIndent);
3180
- return layout === "indented" ? `${padding}${flatUnion(members)}` : members.map((member) => `${padding}| ${member}`).join("\n");
3197
+ switch (layout) {
3198
+ case "indented":
3199
+ return `${padding}${flatUnion(members)}`;
3200
+ case "stacked":
3201
+ return members.map((member) => `${padding}| ${member}`).join("\n");
3202
+ default: {
3203
+ const _exhaustive = layout;
3204
+ return _exhaustive;
3205
+ }
3206
+ }
3181
3207
  }
3182
3208
  function flatUnion(members) {
3183
3209
  return members.join(" | ");
@@ -3225,9 +3251,18 @@ function renderArray(entries, position) {
3225
3251
  return ["[", ...lines, `${spaces(position.indent)}]`].join("\n");
3226
3252
  }
3227
3253
  function renderEntryLine(entry, indent) {
3228
- if (entry.kind === "comment") return `${spaces(indent)}// ${entry.text}`;
3229
- if (entry.kind === "source") return `${spaces(indent)}${entry.source},`;
3230
- return renderValueLine(entry.value, { indent, prefix: "", suffix: "," });
3254
+ switch (entry.kind) {
3255
+ case "comment":
3256
+ return `${spaces(indent)}// ${entry.text}`;
3257
+ case "source":
3258
+ return `${spaces(indent)}${entry.source},`;
3259
+ case "value":
3260
+ return renderValueLine(entry.value, { indent, prefix: "", suffix: "," });
3261
+ default: {
3262
+ const _exhaustive = entry;
3263
+ return _exhaustive;
3264
+ }
3265
+ }
3231
3266
  }
3232
3267
  function renderRecord(record, position) {
3233
3268
  const properties = Object.entries(record);
@@ -3247,11 +3282,27 @@ function propertyPosition(key, indent) {
3247
3282
  function flatArray(entries) {
3248
3283
  const items = [];
3249
3284
  for (const entry of entries) {
3250
- if (entry.kind === "comment") return void 0;
3251
- items.push(entry.kind === "source" ? entry.source : flatValue(entry.value));
3285
+ const item = flatEntry(entry);
3286
+ if (item === void 0) return void 0;
3287
+ items.push(item);
3252
3288
  }
3253
3289
  return flatList(items);
3254
3290
  }
3291
+ function flatEntry(entry) {
3292
+ switch (entry.kind) {
3293
+ // A `//` line cannot fold onto one line.
3294
+ case "comment":
3295
+ return void 0;
3296
+ case "source":
3297
+ return entry.source;
3298
+ case "value":
3299
+ return flatValue(entry.value);
3300
+ default: {
3301
+ const _exhaustive = entry;
3302
+ return _exhaustive;
3303
+ }
3304
+ }
3305
+ }
3255
3306
  function flatValue(value) {
3256
3307
  if (Array.isArray(value)) return flatList(value.map(flatValue));
3257
3308
  if (isKeyedRecord(value)) return flatRecord(value);
@@ -3297,12 +3348,16 @@ var GLOBAL_IDENTITY_FIELDS = [
3297
3348
  ...HAND_WRITTEN_FIELDS,
3298
3349
  "description"
3299
3350
  ];
3300
- var EXTRACTED_FIELDS = /* @__PURE__ */ new Set([
3351
+ var EXTRACTED_FIELDS = [
3301
3352
  "skills",
3302
3353
  "agents",
3303
3354
  "stack",
3304
3355
  "selectedDomains"
3305
- ]);
3356
+ ];
3357
+ var extractedFields = new Set(EXTRACTED_FIELDS);
3358
+ function isExtractedField(key) {
3359
+ return extractedFields.has(key);
3360
+ }
3306
3361
  var CANONICAL_FIELD_ORDER = [
3307
3362
  "name",
3308
3363
  "description",
@@ -3319,6 +3374,7 @@ var CANONICAL_SKILL_ENTRY_ORDER = [
3319
3374
  "id",
3320
3375
  "scope",
3321
3376
  "origin",
3377
+ "displayName",
3322
3378
  "excluded"
3323
3379
  ];
3324
3380
  var CANONICAL_AGENT_ENTRY_ORDER = [
@@ -3503,11 +3559,21 @@ function generateStandaloneConfig(cleaned) {
3503
3559
  });
3504
3560
  }
3505
3561
  function standaloneExportField(key, value, emitted) {
3506
- if (!EXTRACTED_FIELDS.has(key)) return [renderScalarField(key, value)];
3507
- if (key === "skills") return [` skills${emitted.hasSkills ? "" : ": []"},`];
3508
- if (key === "agents") return [` agents${emitted.hasAgents ? "" : ": []"},`];
3509
- if (key === "stack") return emitted.hasStack ? [` stack,`] : [];
3510
- return [` selectedDomains${emitted.hasSelectedDomains ? "" : ": []"},`];
3562
+ if (!isExtractedField(key)) return [renderScalarField(key, value)];
3563
+ switch (key) {
3564
+ case "skills":
3565
+ return [` skills${emitted.hasSkills ? "" : ": []"},`];
3566
+ case "agents":
3567
+ return [` agents${emitted.hasAgents ? "" : ": []"},`];
3568
+ case "stack":
3569
+ return emitted.hasStack ? [` stack,`] : [];
3570
+ case "selectedDomains":
3571
+ return [` selectedDomains${emitted.hasSelectedDomains ? "" : ": []"},`];
3572
+ default: {
3573
+ const _exhaustive = key;
3574
+ return _exhaustive;
3575
+ }
3576
+ }
3511
3577
  }
3512
3578
  function assembleConfigSource({
3513
3579
  imports,
@@ -3538,7 +3604,7 @@ function buildTypeImports(flags) {
3538
3604
  ].filter((t) => Boolean(t));
3539
3605
  }
3540
3606
  function isCopiedScalarField(key) {
3541
- return !EXTRACTED_FIELDS.has(key) && key !== "name";
3607
+ return !isExtractedField(key) && key !== "name";
3542
3608
  }
3543
3609
  function resolveProjectName(cleaned) {
3544
3610
  return cleaned.name && cleaned.name !== GLOBAL_CONFIG_NAME ? cleaned.name : DEFAULT_PLUGIN_NAME;
@@ -4140,7 +4206,8 @@ function toSeedSkillConfig({
4140
4206
  return {
4141
4207
  id,
4142
4208
  scope: seedSkill.scope,
4143
- origin: seedSkill.install === "eject" ? EJECT_SOURCE : sourceForSkill(catalogSkill)
4209
+ origin: seedSkill.install === "eject" ? EJECT_SOURCE : sourceForSkill(catalogSkill),
4210
+ displayName: catalogSkill.displayName
4144
4211
  };
4145
4212
  }
4146
4213
  function sourceForSkill(skill) {
@@ -4310,12 +4377,12 @@ async function loadStackById(stackId, configDir, source) {
4310
4377
  );
4311
4378
  return null;
4312
4379
  }
4313
- const defaultStack = defaultStacks.find((s) => s.id === stackId) ?? null;
4314
- if (defaultStack) {
4315
- verbose(`Found default stack: ${defaultStack.name} (${stackId})`);
4316
- } else {
4380
+ const defaultStack = defaultStacks.find((s) => s.id === stackId);
4381
+ if (!defaultStack) {
4317
4382
  verbose(`Stack '${stackId}' not found in the default marketplace or the built-ins`);
4383
+ return null;
4318
4384
  }
4385
+ verbose(`Found default stack: ${defaultStack.name} (${stackId})`);
4319
4386
  return defaultStack;
4320
4387
  }
4321
4388
  function stackNotOfferedMessage(stackId, source) {
@@ -4446,10 +4513,8 @@ async function loadProjectConfig(projectDir) {
4446
4513
  const provider = providerInUse(projectDir);
4447
4514
  const projectResult = await loadProjectConfigFromDir(projectDir, provider);
4448
4515
  if (projectResult) return projectResult;
4449
- if (!isHomeDirectory(projectDir)) {
4450
- return loadProjectConfigFromDir(os5.homedir(), provider);
4451
- }
4452
- return null;
4516
+ if (isHomeDirectory(projectDir)) return null;
4517
+ return loadProjectConfigFromDir(os5.homedir(), provider);
4453
4518
  }
4454
4519
  function validateProjectConfig(config) {
4455
4520
  const result = projectConfigLoaderSchema.safeParse(config);
@@ -5236,10 +5301,13 @@ async function loadPluginSkills(pluginDir) {
5236
5301
  // src/cli/lib/loading/source-fetcher.ts
5237
5302
  import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
5238
5303
  import { createHash as createHash2 } from "crypto";
5239
- import { rename } from "fs/promises";
5304
+ import { readFileSync } from "fs";
5305
+ import { rename, stat } from "fs/promises";
5240
5306
  import { downloadTemplate } from "giget";
5241
5307
  import os8 from "os";
5242
5308
  import path17 from "path";
5309
+ import { isDeepEqual } from "remeda";
5310
+ import { z as z4 } from "zod";
5243
5311
 
5244
5312
  // src/cli/lib/marketplace-generator.ts
5245
5313
  import path16 from "path";
@@ -5368,17 +5436,43 @@ var MarketplaceUnreachableError = class extends Error {
5368
5436
  reason;
5369
5437
  };
5370
5438
  var TarballWithheldError = class extends Error {
5439
+ status;
5371
5440
  constructor({ status, statusText }) {
5372
5441
  super(`the marketplace answered ${status} ${statusText}`.trimEnd());
5373
5442
  this.name = "TarballWithheldError";
5443
+ this.status = status;
5374
5444
  }
5375
5445
  };
5376
5446
  var marketplaceMustAnswer = new AsyncLocalStorage3();
5377
5447
  function askingEachMarketplaceItself(body) {
5378
- return marketplaceMustAnswer.run(true, body);
5448
+ const differingCopiesReplaced = /* @__PURE__ */ new Set();
5449
+ return marketplaceMustAnswer.run(differingCopiesReplaced, () => body(differingCopiesReplaced));
5379
5450
  }
5380
5451
  function mustAnswer() {
5381
- return marketplaceMustAnswer.getStore() === true;
5452
+ return marketplaceMustAnswer.getStore() !== void 0;
5453
+ }
5454
+ var refusalStopsTheLoad = new AsyncLocalStorage3();
5455
+ function stoppingOnARefusal(body) {
5456
+ return refusalStopsTheLoad.run(true, body);
5457
+ }
5458
+ function stopsOnARefusal() {
5459
+ return refusalStopsTheLoad.getStore() !== void 0;
5460
+ }
5461
+ var METHOD_NOT_ALLOWED = 405;
5462
+ function postureOn(status) {
5463
+ if (mustAnswer()) return "stop";
5464
+ if (status === METHOD_NOT_ALLOWED || isServerError(status)) return "keep";
5465
+ if (!isClientError(status)) return void 0;
5466
+ return stopsOnARefusal() ? "stop" : "pass over";
5467
+ }
5468
+ var FIRST_CLIENT_ERROR = 400;
5469
+ var FIRST_SERVER_ERROR = 500;
5470
+ var PAST_THE_SERVER_ERRORS = 600;
5471
+ function isClientError(status) {
5472
+ return status >= FIRST_CLIENT_ERROR && status < FIRST_SERVER_ERROR;
5473
+ }
5474
+ function isServerError(status) {
5475
+ return status >= FIRST_SERVER_ERROR && status < PAST_THE_SERVER_ERRORS;
5382
5476
  }
5383
5477
  function sanitizeSourceForCache(source) {
5384
5478
  const hash = createHash2("sha256").update(source).digest("hex").slice(0, CACHE_HASH_LENGTH);
@@ -5430,8 +5524,10 @@ function getGigetCacheDir(source) {
5430
5524
  return void 0;
5431
5525
  }
5432
5526
  const templateName = uriMatch.groups.repo.replace("/", "-").replace(/[^\da-z-]/gi, "-");
5433
- const gigetCacheRoot = process.env.XDG_CACHE_HOME ? path17.resolve(process.env.XDG_CACHE_HOME, "giget") : path17.resolve(os8.homedir(), ".cache", "giget");
5434
- return path17.join(gigetCacheRoot, providerName, templateName);
5527
+ return path17.join(gigetCacheRoot(), providerName, templateName);
5528
+ }
5529
+ function gigetCacheRoot() {
5530
+ return process.env.XDG_CACHE_HOME ? path17.resolve(process.env.XDG_CACHE_HOME, "giget") : path17.resolve(os8.homedir(), ".cache", "giget");
5435
5531
  }
5436
5532
  async function clearGigetCache(source) {
5437
5533
  const gigetDir = getGigetCacheDir(source);
@@ -5448,7 +5544,7 @@ async function fetchFromRemoteSource(source, subdir) {
5448
5544
  verbose(`Cache directory: ${cacheDir}`);
5449
5545
  if (await directoryExists2(cacheDir)) {
5450
5546
  const verdict = await revalidateCachedCopy(cacheDir, source);
5451
- if (verdict === "current" || verdict === "unreachable") {
5547
+ if (keepsTheCopy(verdict)) {
5452
5548
  verbose(`Using cached marketplace: ${cacheDir}`);
5453
5549
  return {
5454
5550
  path: cacheDir,
@@ -5460,7 +5556,8 @@ async function fetchFromRemoteSource(source, subdir) {
5460
5556
  announceRefetch(verdict);
5461
5557
  if (!mustAnswer()) await discardCachedCopy(cacheDir, source);
5462
5558
  }
5463
- return mustAnswer() ? downloadAnsweredFor(cacheDir, source, fullSource) : downloadFreshCopy(cacheDir, source, fullSource);
5559
+ const differingCopiesReplaced = marketplaceMustAnswer.getStore();
5560
+ return differingCopiesReplaced ? downloadAnsweredFor(cacheDir, source, fullSource, differingCopiesReplaced) : downloadFreshCopy(cacheDir, source, fullSource);
5464
5561
  }
5465
5562
  async function discardCachedCopy(cacheDir, source) {
5466
5563
  await clearGigetCache(source);
@@ -5469,14 +5566,15 @@ async function discardCachedCopy(cacheDir, source) {
5469
5566
  async function downloadFreshCopy(cacheDir, source, fullSource) {
5470
5567
  await ensureDir(path17.dirname(cacheDir));
5471
5568
  try {
5472
- const result = await downloadTemplate(fullSource, {
5569
+ const { result, savedTarball } = await gigetDownload(source, fullSource, {
5473
5570
  dir: cacheDir,
5474
5571
  force: true,
5475
5572
  // Always force when downloading to avoid "already exists" error
5476
5573
  offline: false
5477
5574
  });
5478
5575
  verbose(`Downloaded to: ${result.dir}`);
5479
- await recordFetchedCopy(cacheDir, result);
5576
+ if (savedTarball) await askBeforeKeepingTheSavedTarball(cacheDir, result, source);
5577
+ await recordFetchedCopy(cacheDir, result, savedTarball);
5480
5578
  markCopyCurrentForThisRun(cacheDir);
5481
5579
  return {
5482
5580
  path: result.dir,
@@ -5488,19 +5586,50 @@ async function downloadFreshCopy(cacheDir, source, fullSource) {
5488
5586
  throw createDetailedFetchError(error, source);
5489
5587
  }
5490
5588
  }
5589
+ async function askBeforeKeepingTheSavedTarball(cacheDir, result, source) {
5590
+ const tar = tarballOf(result);
5591
+ if (tar === void 0) return;
5592
+ const answer = await answerAbout(tar);
5593
+ if (answer === "answered") return;
5594
+ if (answer === "unreachable") {
5595
+ warn(sourceUnreachableUsingCache(source));
5596
+ return;
5597
+ }
5598
+ if (stopsTheLoad(answer)) {
5599
+ await remove(cacheDir);
5600
+ throw answer;
5601
+ }
5602
+ announceTheCopyKept(answer, source);
5603
+ }
5604
+ async function answerAbout(tar) {
5605
+ try {
5606
+ await fetchEtag(tar);
5607
+ return "answered";
5608
+ } catch (error) {
5609
+ if (error instanceof TarballWithheldError) return error;
5610
+ verbose(`Could not ask ${tar} about the tarball giget saved: ${getErrorMessage(error)}`);
5611
+ return "unreachable";
5612
+ }
5613
+ }
5491
5614
  var STAGED_DOWNLOAD_SUFFIX = ".download";
5492
- async function downloadAnsweredFor(cacheDir, source, fullSource) {
5615
+ var ONLY_A_SAVED_COPY_CAME_BACK = "the download failed and only a saved copy came back";
5616
+ var SET_ASIDE_SUFFIX = ".set-aside";
5617
+ async function downloadAnsweredFor(cacheDir, source, fullSource, differingCopiesReplaced) {
5493
5618
  const staged = `${cacheDir}${STAGED_DOWNLOAD_SUFFIX}`;
5619
+ const downloadStaged = () => gigetDownload(source, fullSource, {
5620
+ dir: staged,
5621
+ force: true,
5622
+ forceClean: true,
5623
+ offline: false
5624
+ });
5494
5625
  await ensureDir(path17.dirname(cacheDir));
5495
5626
  try {
5496
- const result = await downloadTemplate(fullSource, {
5497
- dir: staged,
5498
- force: true,
5499
- forceClean: true,
5500
- offline: false
5501
- });
5627
+ const { result, savedTarball } = await downloadStaged();
5502
5628
  const record = await askAfterTheDownload(result, source);
5629
+ if (savedTarball) await downloadPast(savedTarball, record, downloadStaged, source);
5630
+ const differed = await savedCopyDiffers(cacheDir, staged);
5503
5631
  await replaceCopy(cacheDir, staged, record);
5632
+ if (differed) differingCopiesReplaced.add(source);
5504
5633
  markCopyCurrentForThisRun(cacheDir);
5505
5634
  return { path: cacheDir, fromCache: false, unreachable: false, source: fullSource };
5506
5635
  } catch (error) {
@@ -5510,11 +5639,99 @@ async function downloadAnsweredFor(cacheDir, source, fullSource) {
5510
5639
  await remove(staged);
5511
5640
  }
5512
5641
  }
5642
+ async function downloadPast(savedTarball, record, download, source) {
5643
+ if (!savedUnder(savedTarball, record)) {
5644
+ throw new MarketplaceUnreachableError(source, ONLY_A_SAVED_COPY_CAME_BACK);
5645
+ }
5646
+ await withTarballSetAside(savedTarball.path, download);
5647
+ }
5648
+ async function withTarballSetAside(tarball, download) {
5649
+ const record = gigetRecordOf(tarball);
5650
+ await rename(record, setAsideOf(record));
5651
+ await rename(tarball, setAsideOf(tarball));
5652
+ try {
5653
+ await download();
5654
+ } catch (error) {
5655
+ await rename(setAsideOf(tarball), tarball);
5656
+ await rename(setAsideOf(record), record);
5657
+ throw error;
5658
+ }
5659
+ await Promise.all([remove(setAsideOf(tarball)), remove(setAsideOf(record))]);
5660
+ }
5661
+ function setAsideOf(file) {
5662
+ return `${file}${SET_ASIDE_SUFFIX}`;
5663
+ }
5664
+ async function savedCopyDiffers(cacheDir, downloaded) {
5665
+ if (!await directoryExists2(cacheDir)) return false;
5666
+ try {
5667
+ return !await holdSameFiles(cacheDir, downloaded);
5668
+ } catch (error) {
5669
+ verbose(`Could not read the saved copy at ${cacheDir}: ${getErrorMessage(error)}`);
5670
+ return true;
5671
+ }
5672
+ }
5673
+ async function holdSameFiles(left, right) {
5674
+ const [leftFiles, rightFiles] = await Promise.all([everyFileIn(left), everyFileIn(right)]);
5675
+ return isDeepEqual(leftFiles, rightFiles) && leftFiles.every((file) => sameBytesAt(file, left, right));
5676
+ }
5677
+ var EVERY_FILE = "**/*";
5678
+ function everyFileIn(dir) {
5679
+ return glob(EVERY_FILE, dir, { dot: true });
5680
+ }
5681
+ function sameBytesAt(file, left, right) {
5682
+ return readFileSync(path17.join(left, file)).equals(readFileSync(path17.join(right, file)));
5683
+ }
5513
5684
  async function replaceCopy(cacheDir, staged, record) {
5514
5685
  await remove(cacheDir);
5515
5686
  await rename(staged, cacheDir);
5516
5687
  await writeFile(fetchRecordPath(cacheDir), JSON.stringify(record));
5517
5688
  }
5689
+ var GIGET_TARBALLS = "**/*.tar.gz";
5690
+ var gigetTarballRecordSchema = z4.object({ etag: z4.string().min(1).optional() });
5691
+ async function gigetDownload(source, fullSource, options) {
5692
+ 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) } };
5700
+ }
5701
+ function gigetProviderDir(source) {
5702
+ const provider = SOURCE_PROTO_RE.exec(source)?.[1];
5703
+ if (provider === void 0) throw new Error(`No provider named in '${source}'`);
5704
+ return path17.join(gigetCacheRoot(), provider);
5705
+ }
5706
+ async function tarballTimes(providerDir) {
5707
+ 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)])));
5710
+ }
5711
+ async function modifiedAt(file) {
5712
+ return await fileExists(file) ? (await stat(file)).mtimeMs : void 0;
5713
+ }
5714
+ function gigetTarballOf(result) {
5715
+ const name = result.name;
5716
+ const version = result.version;
5717
+ if (typeof name !== "string") throw new Error("the download named no template");
5718
+ const stem = typeof version === "string" && version !== "" ? version : name;
5719
+ return path17.join(name, `${stem}.tar.gz`);
5720
+ }
5721
+ function gigetRecordOf(tarball) {
5722
+ return `${tarball}.json`;
5723
+ }
5724
+ async function etagSavedWith(tarballPath) {
5725
+ const raw = await readFileOptional(gigetRecordOf(tarballPath));
5726
+ const parsed = gigetTarballRecordSchema.safeParse(parseJsonOrUndefined(raw));
5727
+ return parsed.success ? parsed.data.etag : void 0;
5728
+ }
5729
+ function savedUnder(savedTarball, record) {
5730
+ return savedTarball.etag !== void 0 && savedTarball.etag === record.etag;
5731
+ }
5732
+ function keepsTheCopy(verdict) {
5733
+ return verdict === "current" || verdict === "unreachable" || verdict === "refused";
5734
+ }
5518
5735
  var REVALIDATION_TIMEOUT_MS = 5e3;
5519
5736
  var FETCH_RECORD_SUFFIX = ".etag.json";
5520
5737
  var askedThisRun = /* @__PURE__ */ new Map();
@@ -5546,21 +5763,31 @@ async function classifyCachedCopy(cacheDir, source) {
5546
5763
  return "current";
5547
5764
  }
5548
5765
  try {
5549
- const live = await fetchEtag(record.tar);
5550
- if (live !== void 0 && record.etag !== void 0) {
5551
- return live === record.etag ? "current" : "superseded";
5552
- }
5553
- if (mustAnswer()) return "unconfirmed";
5554
- verbose(`${record.tar} answered without an ETag \u2014 keeping the cached copy`);
5555
- return "current";
5766
+ return judgeAnswer(record, await fetchEtag(record.tar));
5556
5767
  } catch (error) {
5557
- if (error instanceof TarballWithheldError) throw createDetailedFetchError(error, source);
5768
+ if (error instanceof TarballWithheldError) return stopOrKeepTheCopy(error, source);
5558
5769
  verbose(`Could not revalidate ${record.tar}: ${getErrorMessage(error)}`);
5559
5770
  if (mustAnswer()) throw new MarketplaceUnreachableError(source, getErrorMessage(error));
5560
5771
  warn(sourceUnreachableUsingCache(source));
5561
5772
  return "unreachable";
5562
5773
  }
5563
5774
  }
5775
+ function stopOrKeepTheCopy(refusal2, source) {
5776
+ if (stopsTheLoad(refusal2)) throw createDetailedFetchError(refusal2, source);
5777
+ announceTheCopyKept(refusal2, source);
5778
+ return "refused";
5779
+ }
5780
+ function judgeAnswer(record, live) {
5781
+ if (movedOn(record, live)) return "superseded";
5782
+ if (mustAnswer()) return "answered";
5783
+ if (live === void 0) {
5784
+ verbose(`${record.tar} answered without an ETag \u2014 keeping the cached copy`);
5785
+ }
5786
+ return "current";
5787
+ }
5788
+ function movedOn(record, live) {
5789
+ return live !== void 0 && record.etag !== void 0 && live !== record.etag;
5790
+ }
5564
5791
  async function fetchEtag(tar) {
5565
5792
  const auth = process.env.GIGET_AUTH;
5566
5793
  const response = await fetch(tar, {
@@ -5569,9 +5796,22 @@ async function fetchEtag(tar) {
5569
5796
  signal: AbortSignal.timeout(REVALIDATION_TIMEOUT_MS)
5570
5797
  });
5571
5798
  await response.body?.cancel();
5572
- if (mustAnswer() && !response.ok) throw new TarballWithheldError(response);
5799
+ if (withheld(response)) throw new TarballWithheldError(response);
5573
5800
  return response.headers.get("etag") ?? void 0;
5574
5801
  }
5802
+ function withheld({ ok, status }) {
5803
+ return !ok && postureOn(status) !== void 0;
5804
+ }
5805
+ function stopsTheLoad(refusal2) {
5806
+ return postureOn(refusal2.status) === "stop";
5807
+ }
5808
+ function announceTheCopyKept(refusal2, source) {
5809
+ if (postureOn(refusal2.status) === "keep") {
5810
+ warn(sourceRefusedUsingCache(source, refusal2.status));
5811
+ return;
5812
+ }
5813
+ verbose(`Keeping the saved copy of ${source} over its refusal: ${refusal2.message}`);
5814
+ }
5575
5815
  function fetchRecordPath(cacheDir) {
5576
5816
  return `${cacheDir}${FETCH_RECORD_SUFFIX}`;
5577
5817
  }
@@ -5585,13 +5825,13 @@ async function readFetchRecord(cacheDir) {
5585
5825
  }
5586
5826
  return parsed.data;
5587
5827
  }
5588
- async function recordFetchedCopy(cacheDir, result) {
5828
+ async function recordFetchedCopy(cacheDir, result, savedTarball) {
5589
5829
  const tar = tarballOf(result);
5590
5830
  if (tar === void 0) {
5591
5831
  verbose("No tarball URL came back from the download \u2014 the copy cannot be revalidated");
5592
5832
  return;
5593
5833
  }
5594
- const etag = await etagIfAnswered(tar);
5834
+ const etag = savedTarball ? savedTarball.etag : await etagIfAnswered(tar);
5595
5835
  await writeFile(fetchRecordPath(cacheDir), JSON.stringify(fetchRecord(tar, etag)));
5596
5836
  }
5597
5837
  async function etagIfAnswered(tar) {
@@ -6140,7 +6380,7 @@ async function installationIfPresent(candidate) {
6140
6380
  // src/cli/lib/hosts/claude-host.ts
6141
6381
  import os12 from "os";
6142
6382
  import path21 from "path";
6143
- import { z as z5 } from "zod";
6383
+ import { z as z6 } from "zod";
6144
6384
 
6145
6385
  // src/cli/utils/exec.ts
6146
6386
  import { spawn } from "child_process";
@@ -6243,24 +6483,24 @@ async function execCommand(command, args, options) {
6243
6483
 
6244
6484
  // src/cli/lib/plugins/plugin-settings.ts
6245
6485
  import path20 from "path";
6246
- import { z as z4 } from "zod";
6247
- var pluginSettingsSchema = z4.object({
6486
+ import { z as z5 } from "zod";
6487
+ var pluginSettingsSchema = z5.object({
6248
6488
  // Absent when no plugin is enabled.
6249
- enabledPlugins: z4.record(z4.string(), z4.unknown()).exactOptional()
6489
+ enabledPlugins: z5.record(z5.string(), z5.unknown()).exactOptional()
6250
6490
  }).passthrough();
6251
6491
  var installationFields = {
6252
- installPath: z4.string(),
6253
- version: z4.string(),
6254
- installedAt: z4.string()
6492
+ installPath: z5.string(),
6493
+ version: z5.string(),
6494
+ installedAt: z5.string()
6255
6495
  };
6256
- var pluginInstallationSchema = z4.discriminatedUnion("scope", [
6257
- z4.object({ scope: z4.literal("project"), projectPath: z4.string(), ...installationFields }),
6258
- z4.object({ scope: z4.literal("user"), ...installationFields }),
6259
- z4.object({ scope: z4.literal("local"), ...installationFields })
6496
+ var pluginInstallationSchema = z5.discriminatedUnion("scope", [
6497
+ z5.object({ scope: z5.literal("project"), projectPath: z5.string(), ...installationFields }),
6498
+ z5.object({ scope: z5.literal("user"), ...installationFields }),
6499
+ z5.object({ scope: z5.literal("local"), ...installationFields })
6260
6500
  ]);
6261
- var installedPluginsSchema = z4.object({
6262
- version: z4.number(),
6263
- plugins: z4.record(z4.string(), z4.array(pluginInstallationSchema))
6501
+ var installedPluginsSchema = z5.object({
6502
+ version: z5.number(),
6503
+ plugins: z5.record(z5.string(), z5.array(pluginInstallationSchema))
6264
6504
  }).passthrough();
6265
6505
  function getInstalledPluginsRegistryPath(pluginsDir2) {
6266
6506
  return path20.join(pluginsDir2, INSTALLED_PLUGINS_FILE);
@@ -6364,12 +6604,12 @@ async function isClaudeCLIAvailable(options) {
6364
6604
  return false;
6365
6605
  }
6366
6606
  }
6367
- var marketplaceInfoListSchema = z5.array(
6368
- z5.object({
6369
- name: z5.string(),
6370
- source: z5.string(),
6371
- repo: z5.string().exactOptional(),
6372
- path: z5.string().exactOptional()
6607
+ var marketplaceInfoListSchema = z6.array(
6608
+ z6.object({
6609
+ name: z6.string(),
6610
+ source: z6.string(),
6611
+ repo: z6.string().exactOptional(),
6612
+ path: z6.string().exactOptional()
6373
6613
  })
6374
6614
  );
6375
6615
  async function claudePluginMarketplaceList(options) {
@@ -6480,7 +6720,7 @@ function claudeHost() {
6480
6720
  // src/cli/lib/hosts/codex-host.ts
6481
6721
  import os13 from "os";
6482
6722
  import path22 from "path";
6483
- import { z as z6 } from "zod";
6723
+ import { z as z7 } from "zod";
6484
6724
  var CODEX = "codex";
6485
6725
  var PLUGIN_CACHE_SUBDIR = "cache";
6486
6726
  var STANDING_WARNING = /could not create PATH aliases/;
@@ -6543,22 +6783,22 @@ async function readJsonFromCodex(schema, args, options, attempt, askedFrom) {
6543
6783
  }
6544
6784
  return validated.data;
6545
6785
  }
6546
- var marketplaceRegistrySchema = z6.object({
6547
- marketplaces: z6.array(
6548
- z6.object({
6549
- name: z6.string(),
6550
- marketplaceSource: z6.object({ sourceType: z6.string(), source: z6.string() })
6786
+ var marketplaceRegistrySchema = z7.object({
6787
+ marketplaces: z7.array(
6788
+ z7.object({
6789
+ name: z7.string(),
6790
+ marketplaceSource: z7.object({ sourceType: z7.string(), source: z7.string() })
6551
6791
  })
6552
6792
  )
6553
6793
  });
6554
- var pluginListingSchema = z6.object({
6555
- installed: z6.array(
6556
- z6.object({
6557
- pluginId: z6.string(),
6558
- name: z6.string(),
6559
- marketplaceName: z6.string(),
6560
- version: z6.string(),
6561
- enabled: z6.boolean()
6794
+ var pluginListingSchema = z7.object({
6795
+ installed: z7.array(
6796
+ z7.object({
6797
+ pluginId: z7.string(),
6798
+ name: z7.string(),
6799
+ marketplaceName: z7.string(),
6800
+ version: z7.string(),
6801
+ enabled: z7.boolean()
6562
6802
  })
6563
6803
  )
6564
6804
  });
@@ -7004,12 +7244,14 @@ async function countDirEntries(dir, pred) {
7004
7244
  return 0;
7005
7245
  }
7006
7246
  }
7007
- function formatInstallationDisplay(info) {
7247
+ function formatInstallationDisplay(info, skillLines = []) {
7248
+ const namedSkillLines = skillLines.map((line2) => `
7249
+ ${line2}`).join("");
7008
7250
  const agentDirLines = info.agentDirs.map((dir) => `
7009
7251
  Agents: ${dir}`).join("");
7010
7252
  return `Installation: ${info.name}
7011
7253
  Mode: ${INSTALL_MODE_LABELS[info.mode]}
7012
- Skills: ${info.skillCount}
7254
+ Skills: ${info.skillCount}${namedSkillLines}
7013
7255
  Agents: ${info.agentCount}
7014
7256
  Config: ${info.configPath}${agentDirLines}`;
7015
7257
  }
@@ -7529,16 +7771,15 @@ Compiled ${plural(results.length, "skill plugin")}:`);
7529
7771
 
7530
7772
  // src/cli/lib/skills/local-skill-loader.ts
7531
7773
  import path25 from "path";
7532
- function copiedInSkillsAt(root) {
7774
+ function copiedInSkillsAt(root, provider) {
7533
7775
  const scope = isHomeDirectory(root) ? "global" : "project";
7534
- const provider = providerInUse(root);
7535
7776
  return {
7536
7777
  dir: skillsDir(provider, scope, root),
7537
7778
  pathPrefix: skillsPathPrefix(provider, scope, root)
7538
7779
  };
7539
7780
  }
7540
- async function discoverLocalSkills(root) {
7541
- const { dir: localSkillsPath, pathPrefix } = copiedInSkillsAt(root);
7781
+ async function discoverLocalSkills(root, provider = providerInUse(root)) {
7782
+ const { dir: localSkillsPath, pathPrefix } = copiedInSkillsAt(root, provider);
7542
7783
  if (!await directoryExists2(localSkillsPath)) {
7543
7784
  verbose(`Local skills directory not found: ${localSkillsPath}`);
7544
7785
  return null;
@@ -7739,9 +7980,10 @@ async function extractSkill(skillsDir2, metadataFile) {
7739
7980
  const frontmatter = parseFrontmatterOrWarn(skillDir, skillMdPath, await readFile(skillMdPath));
7740
7981
  if (!frontmatter) return null;
7741
7982
  if (!metadata.displayName) {
7742
- throw new Error(
7743
- `Skill at ${metadataFile} is missing required '${METADATA_KEYS.DISPLAY_NAME}' field in metadata.yaml`
7983
+ warn(
7984
+ `Skipping '${metadataFile}': invalid ${STANDARD_FILES.METADATA_YAML} \u2014 missing required field: ${METADATA_KEYS.DISPLAY_NAME}`
7744
7985
  );
7986
+ return null;
7745
7987
  }
7746
7988
  const skillId = frontmatter.name;
7747
7989
  const extracted = {
@@ -9678,7 +9920,7 @@ async function loadCatalogue(options) {
9678
9920
  ...catalogue,
9679
9921
  marketplaceSkillIds: new Set(typedKeys(catalogue.matrix.skills))
9680
9922
  };
9681
- result.matrix = await mergeLocalSkills(result.matrix, resolvedProjectDir);
9923
+ result.matrix = await mergeLocalSkills(result.matrix, resolvedProjectDir, provider);
9682
9924
  await seatGlobalInstallationSkills(result.matrix, source, purpose);
9683
9925
  if (!options.skipExtraSources) {
9684
9926
  await loadSkillsFromAllSources(
@@ -9840,12 +10082,12 @@ function goesOnWithoutManifest(source, purpose) {
9840
10082
  function configuredLabel(sourceConfig) {
9841
10083
  return sourceConfig.marketplace === void 0 ? {} : { marketplace: sourceConfig.marketplace };
9842
10084
  }
9843
- async function mergeLocalSkills(matrix2, projectDir) {
9844
- const withGlobal = isHomeDirectory(projectDir) ? matrix2 : await mergeDiscoveredLocalSkills(matrix2, os14.homedir(), "global");
9845
- return mergeDiscoveredLocalSkills(withGlobal, projectDir, "project");
10085
+ async function mergeLocalSkills(matrix2, projectDir, provider) {
10086
+ const withGlobal = isHomeDirectory(projectDir) ? matrix2 : await mergeDiscoveredLocalSkills(matrix2, os14.homedir(), "global", provider);
10087
+ return mergeDiscoveredLocalSkills(withGlobal, projectDir, "project", provider);
9846
10088
  }
9847
- async function mergeDiscoveredLocalSkills(matrix2, dir, label) {
9848
- const discovered = await discoverLocalSkills(dir);
10089
+ async function mergeDiscoveredLocalSkills(matrix2, dir, label, provider) {
10090
+ const discovered = await discoverLocalSkills(dir, provider);
9849
10091
  if (!discovered || discovered.skills.length === 0) return matrix2;
9850
10092
  verbose(
9851
10093
  `Found ${discovered.skills.length} ${label} local skill(s) in ${discovered.localSkillsPath}`
@@ -10110,9 +10352,11 @@ export {
10110
10352
  pluginRefFor,
10111
10353
  renderAgent,
10112
10354
  renderAgentBody,
10355
+ isHomeDirectory,
10113
10356
  sourceRootOf,
10114
- retiredSourceFolderIn,
10357
+ rootsHoldingTheRetiredSourceFolder,
10115
10358
  chooseProviderForThisRun,
10359
+ forgetTheProviderChosenForThisRun,
10116
10360
  providerInUse,
10117
10361
  sourceFolderInUse,
10118
10362
  relativeConfigPath,
@@ -10198,7 +10442,7 @@ export {
10198
10442
  scopeNoun,
10199
10443
  scopeLabel,
10200
10444
  layoutIsCurrent,
10201
- retiredSourceFolderUnsupported,
10445
+ retiredSourceFolderIgnored,
10202
10446
  GlobalPairWriteViolation,
10203
10447
  withGateToken,
10204
10448
  assertGateToken,
@@ -10240,7 +10484,6 @@ export {
10240
10484
  resolveInstallPaths,
10241
10485
  providerToNameAt,
10242
10486
  initProviderToNameAt,
10243
- isHomeDirectory,
10244
10487
  SOURCE_ENV_VAR,
10245
10488
  readSourceRepoConfig,
10246
10489
  loadSourceRepoConfig,
@@ -10280,6 +10523,7 @@ export {
10280
10523
  flatUnion,
10281
10524
  renderTypeImportLine,
10282
10525
  spaces,
10526
+ EXTRACTED_FIELDS,
10283
10527
  generateConfigSource,
10284
10528
  refuseUnwritableStack,
10285
10529
  generateBlankGlobalConfigSource,
@@ -10352,6 +10596,7 @@ export {
10352
10596
  getMarketplaceStats,
10353
10597
  MarketplaceUnreachableError,
10354
10598
  askingEachMarketplaceItself,
10599
+ stoppingOnARefusal,
10355
10600
  MarketplaceNameRefusedError,
10356
10601
  fetchMarketplace,
10357
10602
  isLocalOnlySkill,
@@ -10375,4 +10620,4 @@ export {
10375
10620
  executeMigration,
10376
10621
  keepsGlobalInstall
10377
10622
  };
10378
- //# sourceMappingURL=chunk-VILFCMRN.js.map
10623
+ //# sourceMappingURL=chunk-E45IT3HC.js.map