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.
- package/CHANGELOG.md +48 -0
- package/dist/{chunk-IAQFZFWD.js → chunk-37QFHJUW.js} +142 -13
- package/dist/chunk-37QFHJUW.js.map +1 -0
- package/dist/{chunk-H5E6IO2L.js → chunk-6HJVH27C.js} +9 -11
- package/dist/chunk-6HJVH27C.js.map +1 -0
- package/dist/{chunk-7BHDKEGK.js → chunk-DQB3E2SX.js} +3 -3
- package/dist/{chunk-APWMMZOK.js → chunk-EGC7PNDI.js} +31 -24
- package/dist/chunk-EGC7PNDI.js.map +1 -0
- package/dist/{chunk-6PGXTLA4.js → chunk-EHEBN4NB.js} +2 -2
- package/dist/{chunk-EFXVYQGT.js → chunk-GNMRXXRY.js} +39 -40
- package/dist/chunk-GNMRXXRY.js.map +1 -0
- package/dist/{chunk-FQF6VHO3.js → chunk-ICHWAFAC.js} +3 -3
- package/dist/{chunk-FQF6VHO3.js.map → chunk-ICHWAFAC.js.map} +1 -1
- package/dist/{chunk-3PJZ4QNJ.js → chunk-MFCZARV2.js} +9 -9
- package/dist/chunk-MFCZARV2.js.map +1 -0
- package/dist/{chunk-TVEDNGVP.js → chunk-P5XEK7HC.js} +2 -2
- package/dist/{chunk-REHVGFJE.js → chunk-Q4NWATGH.js} +31 -27
- package/dist/chunk-Q4NWATGH.js.map +1 -0
- package/dist/{chunk-IXVGBUWI.js → chunk-SI2LLEIR.js} +5 -5
- package/dist/{chunk-R7GKQBZJ.js → chunk-SNXEYAFP.js} +44 -30
- package/dist/chunk-SNXEYAFP.js.map +1 -0
- package/dist/{chunk-QCX66KBM.js → chunk-SRII2GMF.js} +3 -3
- package/dist/{chunk-AIBVAYHS.js → chunk-TG3SPPZY.js} +2 -2
- package/dist/{chunk-WUSEZFER.js → chunk-U46LYYRA.js} +3 -2
- package/dist/{chunk-WUSEZFER.js.map → chunk-U46LYYRA.js.map} +1 -1
- package/dist/{chunk-I3WF6L43.js → chunk-XYBHH3M5.js} +2 -2
- package/dist/{chunk-ECPFYHDX.js → chunk-YLFKFVQP.js} +11 -11
- package/dist/chunk-YLFKFVQP.js.map +1 -0
- package/dist/{chunk-E45IT3HC.js → chunk-YM3VEDAP.js} +585 -307
- package/dist/chunk-YM3VEDAP.js.map +1 -0
- package/dist/commands/build/marketplace.js +4 -4
- package/dist/commands/build/plugins.js +6 -6
- package/dist/commands/compile.js +16 -16
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/doctor.js +73 -78
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +45 -38
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +27 -18
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/init.js +16 -17
- package/dist/commands/list.js +7 -8
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/marketplace.js +4 -4
- package/dist/commands/search.js +9 -9
- package/dist/commands/share.js +13 -13
- package/dist/commands/share.js.map +1 -1
- package/dist/commands/uninstall.js +16 -15
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +17 -18
- package/dist/commands/update.js.map +1 -1
- package/dist/components/common/select-list.js +2 -2
- package/dist/components/common/skill-agent-summary.js +3 -3
- package/dist/components/common/summary-panel.js +4 -4
- package/dist/hooks/init.js +23 -25
- package/dist/hooks/init.js.map +1 -1
- package/dist/load-agent-defs-BJ4KBKBA.js +14 -0
- package/dist/{recompile-project-agents-KYK44C24.js → recompile-project-agents-2QTFMYDC.js} +8 -8
- package/dist/{source-loader-G5I4RNUP.js → source-loader-I6SWWDUF.js} +4 -4
- package/package.json +1 -1
- package/dist/chunk-3PJZ4QNJ.js.map +0 -1
- package/dist/chunk-APWMMZOK.js.map +0 -1
- package/dist/chunk-E45IT3HC.js.map +0 -1
- package/dist/chunk-ECPFYHDX.js.map +0 -1
- package/dist/chunk-EFXVYQGT.js.map +0 -1
- package/dist/chunk-H5E6IO2L.js.map +0 -1
- package/dist/chunk-IAQFZFWD.js.map +0 -1
- package/dist/chunk-ORO2T4K2.js +0 -96
- package/dist/chunk-ORO2T4K2.js.map +0 -1
- package/dist/chunk-R7GKQBZJ.js.map +0 -1
- package/dist/chunk-REHVGFJE.js.map +0 -1
- package/dist/load-agent-defs-5U5KAURA.js +0 -14
- /package/dist/{chunk-7BHDKEGK.js.map → chunk-DQB3E2SX.js.map} +0 -0
- /package/dist/{chunk-6PGXTLA4.js.map → chunk-EHEBN4NB.js.map} +0 -0
- /package/dist/{chunk-TVEDNGVP.js.map → chunk-P5XEK7HC.js.map} +0 -0
- /package/dist/{chunk-IXVGBUWI.js.map → chunk-SI2LLEIR.js.map} +0 -0
- /package/dist/{chunk-QCX66KBM.js.map → chunk-SRII2GMF.js.map} +0 -0
- /package/dist/{chunk-AIBVAYHS.js.map → chunk-TG3SPPZY.js.map} +0 -0
- /package/dist/{chunk-I3WF6L43.js.map → chunk-XYBHH3M5.js.map} +0 -0
- /package/dist/{load-agent-defs-5U5KAURA.js.map → load-agent-defs-BJ4KBKBA.js.map} +0 -0
- /package/dist/{recompile-project-agents-KYK44C24.js.map → recompile-project-agents-2QTFMYDC.js.map} +0 -0
- /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-
|
|
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-
|
|
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
|
|
95
|
-
import
|
|
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
|
-
|
|
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(
|
|
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(
|
|
975
|
-
return `${plural(
|
|
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
|
-
|
|
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
|
-
|
|
1173
|
-
...installedWithout
|
|
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
|
|
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) =>
|
|
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: "${
|
|
2020
|
+
return `Unrecognized key: "${inertLine(issue.keys.join('", "'))}"`;
|
|
1978
2021
|
}
|
|
1979
|
-
|
|
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,
|
|
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: [...
|
|
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] =
|
|
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] =
|
|
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 =
|
|
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
|
|
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
|
|
3706
|
+
const partition6 = partitionInlinedConfigEntries(cleaned, cleanedGlobal);
|
|
3660
3707
|
const emitted = {
|
|
3661
|
-
hasSkills:
|
|
3662
|
-
hasAgents:
|
|
3663
|
-
hasStack: hasStackEntries(
|
|
3664
|
-
hasSelectedDomains:
|
|
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(
|
|
3722
|
+
scopeSectionEntries(partition6.globalSkills, partition6.projectSkills)
|
|
3676
3723
|
) : [],
|
|
3677
3724
|
...emitted.hasAgents ? entryDeclaration(
|
|
3678
3725
|
"agents",
|
|
3679
3726
|
"AgentScopeConfig[]",
|
|
3680
|
-
scopeSectionEntries(
|
|
3727
|
+
scopeSectionEntries(partition6.globalAgents, partition6.projectAgents)
|
|
3681
3728
|
) : [],
|
|
3682
|
-
...emitted.hasStack ? declaration("stack", STACK_TYPE,
|
|
3683
|
-
...emitted.hasSelectedDomains ? declaration("selectedDomains", "Domain[]",
|
|
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] =
|
|
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] =
|
|
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] =
|
|
4080
|
+
const [globalSkills, projectSkills] = partition3(
|
|
4034
4081
|
config.skills,
|
|
4035
4082
|
(s) => isActiveAt(s, "global")
|
|
4036
4083
|
);
|
|
4037
|
-
const [globalAgents, projectAgents] =
|
|
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(
|
|
4134
|
-
const 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(
|
|
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
|
|
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] =
|
|
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
|
|
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
|
|
4497
|
-
|
|
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(
|
|
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(
|
|
4569
|
+
async function configLoadFailure2({
|
|
4570
|
+
dir,
|
|
4571
|
+
provider
|
|
4572
|
+
}) {
|
|
4504
4573
|
try {
|
|
4505
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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:
|
|
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(
|
|
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,
|
|
5208
|
-
const projectAgentsDir =
|
|
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 =
|
|
5241
|
-
const skillDir =
|
|
5242
|
-
const relativePath =
|
|
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:
|
|
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 =
|
|
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(
|
|
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
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
|
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 ?
|
|
5496
|
-
const absolutePath =
|
|
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
|
|
5605
|
+
return path16.join(gigetCacheRoot(), providerName, templateName);
|
|
5528
5606
|
}
|
|
5529
5607
|
function gigetCacheRoot() {
|
|
5530
|
-
return process.env.XDG_CACHE_HOME ?
|
|
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
|
-
|
|
5536
|
-
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
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
|
|
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
|
-
|
|
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) =>
|
|
5709
|
-
return new Map(await Promise.all(paths.map(async (at) => [at, await
|
|
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
|
|
5712
|
-
return
|
|
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
|
|
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 :
|
|
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
|
-
|
|
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(
|
|
6365
|
-
|
|
6366
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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:
|
|
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
|
|
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(
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
7580
|
+
const pluginDir = path22.dirname(path22.dirname(manifestPath));
|
|
7344
7581
|
if (isNonEmptyString(manifest.skills)) {
|
|
7345
|
-
const skillsPath =
|
|
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 =
|
|
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 =
|
|
7421
|
-
return prefixResult(await validate(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 =
|
|
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 =
|
|
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(
|
|
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(
|
|
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
|
|
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 !== ".." &&
|
|
7839
|
+
return name !== "" && name !== "." && name !== ".." && path23.basename(name) === name;
|
|
7603
7840
|
}
|
|
7604
|
-
async function assertClearable(pluginDir, skillPath,
|
|
7605
|
-
const skill = `Skill '${
|
|
7606
|
-
const file = `File: ${
|
|
7607
|
-
if (!isSingleFolderName(
|
|
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 '${
|
|
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 ${
|
|
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 =
|
|
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(
|
|
7643
|
-
return `# ${
|
|
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": ["${
|
|
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(
|
|
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 =
|
|
7909
|
+
const sourcePath = path23.join(skillPath, fileName);
|
|
7673
7910
|
if (await fileExists(sourcePath)) {
|
|
7674
7911
|
const content = await readFile(sourcePath);
|
|
7675
|
-
await writeFile(
|
|
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 =
|
|
7917
|
+
const sourceDir2 = path23.join(skillPath, dirName);
|
|
7681
7918
|
if (await fileExists(sourceDir2)) {
|
|
7682
|
-
await copy(sourceDir2,
|
|
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 =
|
|
7689
|
-
const skillMdPath =
|
|
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
|
|
7708
|
-
const pluginDir =
|
|
7709
|
-
await assertClearable(pluginDir, skillPath,
|
|
7710
|
-
verbose(`Compiling skill plugin: ${
|
|
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
|
-
|
|
7962
|
+
path23.join(pluginDir, STANDARD_DIRS.SKILLS, skillName2),
|
|
7726
7963
|
skillMdContent
|
|
7727
7964
|
);
|
|
7728
|
-
const readme = generateReadme(
|
|
7729
|
-
await writeFile(
|
|
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 ${
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
7800
|
-
const metadataPath =
|
|
7801
|
-
const skillMdPath =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
7888
|
-
const skillPath =
|
|
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 =
|
|
7907
|
-
const toSkillsDir =
|
|
7908
|
-
const fromPath =
|
|
7909
|
-
const toPath =
|
|
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
|
|
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
|
|
8201
|
+
const folders = [];
|
|
7965
8202
|
for (const metadataFile of metadataFiles) {
|
|
7966
|
-
|
|
7967
|
-
if (skill) skills.push(skill);
|
|
8203
|
+
folders.push(await readSkillFolder(skillsDir2, metadataFile));
|
|
7968
8204
|
}
|
|
7969
|
-
return
|
|
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
|
|
7972
|
-
const skillDir =
|
|
7973
|
-
const skillMdPath =
|
|
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
|
-
|
|
7976
|
-
return
|
|
8216
|
+
warn(`Skipping '${metadataFile}': No ${STANDARD_FILES.SKILL_MD} found`);
|
|
8217
|
+
return { kind: "unnamed" };
|
|
7977
8218
|
}
|
|
7978
|
-
const metadata = await readMatrixMetadataOrWarn(metadataFile,
|
|
7979
|
-
if (!metadata) return
|
|
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
|
|
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
|
|
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 '${
|
|
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
|
-
|
|
9924
|
-
|
|
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(
|
|
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({
|
|
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",
|
|
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
|
|
10367
|
+
const { matrix: matrix2, unloadedSkillIds } = await loadAndMergeFromBasePath(skillsPath, source);
|
|
10101
10368
|
const labels = await resolveMarketplaceLabels(skillsPath, sourceConfig, purpose);
|
|
10102
10369
|
return {
|
|
10103
|
-
matrix:
|
|
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
|
|
10383
|
+
const { matrix: matrix2, unloadedSkillIds } = await loadAndMergeFromBasePath(fetchResult.path, source);
|
|
10116
10384
|
const labels = await resolveMarketplaceLabels(source, sourceConfig, purpose);
|
|
10117
10385
|
return {
|
|
10118
|
-
matrix:
|
|
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 =
|
|
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(
|
|
10152
|
-
|
|
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 =
|
|
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 =
|
|
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] =
|
|
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
|
|
10261
|
-
return id in
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
10901
|
+
//# sourceMappingURL=chunk-YM3VEDAP.js.map
|