agents-inc 0.175.0 → 0.176.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 +67 -0
- package/dist/{chunk-EGC7PNDI.js → chunk-3F5LT433.js} +138 -41
- package/dist/chunk-3F5LT433.js.map +1 -0
- package/dist/chunk-5CFHP6Z5.js +109 -0
- package/dist/chunk-5CFHP6Z5.js.map +1 -0
- package/dist/{chunk-MFCZARV2.js → chunk-B7AVWSK2.js} +18 -8
- package/dist/chunk-B7AVWSK2.js.map +1 -0
- package/dist/{chunk-6HJVH27C.js → chunk-C2BSCEDN.js} +2 -2
- package/dist/{chunk-SNXEYAFP.js → chunk-CKBWEWHZ.js} +60 -30
- package/dist/chunk-CKBWEWHZ.js.map +1 -0
- package/dist/{chunk-SI2LLEIR.js → chunk-EC3JXT23.js} +4 -4
- package/dist/{chunk-YM3VEDAP.js → chunk-ENET4IF6.js} +440 -192
- package/dist/chunk-ENET4IF6.js.map +1 -0
- package/dist/{chunk-ICHWAFAC.js → chunk-FACDJH6O.js} +11 -104
- package/dist/chunk-FACDJH6O.js.map +1 -0
- package/dist/{chunk-P5XEK7HC.js → chunk-H6WUOW5F.js} +2 -2
- package/dist/{chunk-DQB3E2SX.js → chunk-JNRACLNS.js} +3 -3
- package/dist/{chunk-37QFHJUW.js → chunk-JTMSFBCA.js} +106 -28
- package/dist/chunk-JTMSFBCA.js.map +1 -0
- package/dist/{chunk-GNMRXXRY.js → chunk-MQZNDK5F.js} +3 -3
- package/dist/chunk-MQZNDK5F.js.map +1 -0
- package/dist/{chunk-SRII2GMF.js → chunk-SN64WNWE.js} +2 -2
- package/dist/{chunk-EHEBN4NB.js → chunk-U672FZVC.js} +2 -2
- package/dist/{chunk-TG3SPPZY.js → chunk-UE4Z3YMB.js} +1 -1
- package/dist/chunk-UE4Z3YMB.js.map +1 -0
- package/dist/{chunk-Q4NWATGH.js → chunk-XMQIWPIR.js} +58 -10
- package/dist/chunk-XMQIWPIR.js.map +1 -0
- package/dist/{chunk-YLFKFVQP.js → chunk-ZBI6GFJD.js} +2 -2
- package/dist/commands/build/marketplace.js +4 -3
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +6 -5
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/compile.js +15 -11
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/doctor.js +38 -14
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +46 -25
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +12 -8
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/init.js +15 -14
- package/dist/commands/list.js +8 -6
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/marketplace.js +4 -3
- package/dist/commands/new/marketplace.js.map +1 -1
- package/dist/commands/search.js +13 -8
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/share.js +14 -16
- package/dist/commands/share.js.map +1 -1
- package/dist/commands/uninstall.js +18 -14
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +97 -17
- package/dist/commands/update.js.map +1 -1
- package/dist/components/common/skill-agent-summary.js +3 -2
- package/dist/components/common/summary-panel.js +4 -3
- package/dist/hooks/init.js +15 -14
- package/dist/hooks/init.js.map +1 -1
- package/dist/load-agent-defs-5BSECHE6.js +14 -0
- package/dist/{recompile-project-agents-2QTFMYDC.js → recompile-project-agents-U3UGHPWG.js} +7 -7
- package/dist/{source-loader-I6SWWDUF.js → source-loader-E2Y5MMN5.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-37QFHJUW.js.map +0 -1
- package/dist/chunk-EGC7PNDI.js.map +0 -1
- package/dist/chunk-GNMRXXRY.js.map +0 -1
- package/dist/chunk-ICHWAFAC.js.map +0 -1
- package/dist/chunk-MFCZARV2.js.map +0 -1
- package/dist/chunk-Q4NWATGH.js.map +0 -1
- package/dist/chunk-SNXEYAFP.js.map +0 -1
- package/dist/chunk-TG3SPPZY.js.map +0 -1
- package/dist/chunk-YM3VEDAP.js.map +0 -1
- package/dist/load-agent-defs-BJ4KBKBA.js +0 -14
- /package/dist/{chunk-6HJVH27C.js.map → chunk-C2BSCEDN.js.map} +0 -0
- /package/dist/{chunk-SI2LLEIR.js.map → chunk-EC3JXT23.js.map} +0 -0
- /package/dist/{chunk-P5XEK7HC.js.map → chunk-H6WUOW5F.js.map} +0 -0
- /package/dist/{chunk-DQB3E2SX.js.map → chunk-JNRACLNS.js.map} +0 -0
- /package/dist/{chunk-SRII2GMF.js.map → chunk-SN64WNWE.js.map} +0 -0
- /package/dist/{chunk-EHEBN4NB.js.map → chunk-U672FZVC.js.map} +0 -0
- /package/dist/{chunk-YLFKFVQP.js.map → chunk-ZBI6GFJD.js.map} +0 -0
- /package/dist/{load-agent-defs-BJ4KBKBA.js.map → load-agent-defs-5BSECHE6.js.map} +0 -0
- /package/dist/{recompile-project-agents-2QTFMYDC.js.map → recompile-project-agents-U3UGHPWG.js.map} +0 -0
- /package/dist/{source-loader-I6SWWDUF.js.map → source-loader-E2Y5MMN5.js.map} +0 -0
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
typedFromEntries,
|
|
14
14
|
typedKeys,
|
|
15
15
|
typedValues
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-UE4Z3YMB.js";
|
|
17
17
|
import {
|
|
18
18
|
AGENT_NAMES,
|
|
19
19
|
AUTHOR_HANDLE_PATTERN,
|
|
@@ -91,7 +91,7 @@ import {
|
|
|
91
91
|
|
|
92
92
|
// src/cli/lib/loading/source-loader.ts
|
|
93
93
|
import os14 from "os";
|
|
94
|
-
import { partition as
|
|
94
|
+
import { partition as partition6, unique as unique6 } from "remeda";
|
|
95
95
|
import path28 from "path";
|
|
96
96
|
|
|
97
97
|
// src/cli/lib/installation/is-home-directory.ts
|
|
@@ -481,6 +481,9 @@ function chooseProviderForThisRun(provider) {
|
|
|
481
481
|
function forgetTheProviderChosenForThisRun() {
|
|
482
482
|
providerChosenForThisRun = void 0;
|
|
483
483
|
}
|
|
484
|
+
function declaresNoContent(config) {
|
|
485
|
+
return config.skills.length === 0 && config.agents.length === 0;
|
|
486
|
+
}
|
|
484
487
|
var declaresNothingAsRead = /* @__PURE__ */ new Map();
|
|
485
488
|
function recordWhetherItDeclaresNothing(configPath, declaresNothing) {
|
|
486
489
|
const stamp = stampOf(configPath);
|
|
@@ -505,9 +508,7 @@ function providerInUse(root) {
|
|
|
505
508
|
return providerOnDisk(root);
|
|
506
509
|
}
|
|
507
510
|
function inheritedGlobalProvider(projectDir, own = providerInUse(projectDir)) {
|
|
508
|
-
|
|
509
|
-
const inheritsItsOwn = holdsAnInstallation(projectDir, own) && holdsAnInstallation(home, own);
|
|
510
|
-
return inheritsItsOwn ? own : providerInUse(home);
|
|
511
|
+
return holdsAnInstallation(projectDir, own) ? own : providerInUse(os2.homedir());
|
|
511
512
|
}
|
|
512
513
|
function providerAtScope(projectDir, scope) {
|
|
513
514
|
return scope === "global" ? inheritedGlobalProvider(projectDir) : providerInUse(projectDir);
|
|
@@ -984,8 +985,16 @@ var INFO_MESSAGES = {
|
|
|
984
985
|
CONFIG_TYPES_REFRESHED: `Refreshed ${STANDARD_FILES.CONFIG_TYPES_TS}`,
|
|
985
986
|
EJECTED_SKILLS_USER_OWNED: `Ejected skills are yours to own \u2014 '${CLI_INVOKE_COMMAND} update' does not change them.`,
|
|
986
987
|
NO_PLUGIN_MARKETPLACES: "No plugin marketplaces are configured \u2014 nothing to refresh.",
|
|
987
|
-
/**
|
|
988
|
+
/**
|
|
989
|
+
* The owner's words (2026-10-24), on stderr before the command's own output. The lines after it
|
|
990
|
+
* are each true of a run this one is not (owner, 2026-10-26: "A line worded for each").
|
|
991
|
+
*/
|
|
988
992
|
GLOBAL_INSTALLATION_STANDS_IN: "This project's config declares nothing, so this works on your global installation.",
|
|
993
|
+
NO_GLOBAL_INSTALLATION_STANDS_IN: "This project's config declares nothing, and there is no global installation for this to work on.",
|
|
994
|
+
DECLARES_NOTHING_TO_UNINSTALL: "This project's config declares nothing, so there is nothing to uninstall in this project.",
|
|
995
|
+
DECLARES_NOTHING_TO_EJECT_FROM: "This project's config declares nothing; eject works on this project, not on a global installation.",
|
|
996
|
+
DECLARES_NOTHING_TO_INIT_OVER: "This project's config declares nothing, so init treats this project as holding no installation.",
|
|
997
|
+
DECLARES_NOTHING_TO_SEARCH_FROM: "This project's config declares nothing; search reads the marketplace it names, else the global installation's, else the default one.",
|
|
989
998
|
/** Under doctor's marketplace row, when its download replaced a saved copy whose files differed. */
|
|
990
999
|
SAVED_COPY_REPLACED: "The saved copy differed from the marketplace and has been replaced",
|
|
991
1000
|
/** Printed under the destination already named, so it names files only. */
|
|
@@ -1024,21 +1033,18 @@ function propagatedRecompileSummary(recompiled, failed) {
|
|
|
1024
1033
|
const failureSuffix = failed > 0 ? ` (${failed} failed)` : "";
|
|
1025
1034
|
return `Registered projects: ${recompiled} recompiled${failureSuffix}`;
|
|
1026
1035
|
}
|
|
1027
|
-
function skillAssignedToNoAgent(skillId) {
|
|
1028
|
-
return `Skill '${skillId}' is assigned to no sub-agent \u2014 nothing will load it.`;
|
|
1036
|
+
function skillAssignedToNoAgent(skillId, namedBy) {
|
|
1037
|
+
return `Skill '${skillName(skillId, namedBy)}' is assigned to no sub-agent \u2014 nothing will load it.`;
|
|
1029
1038
|
}
|
|
1030
|
-
function scopeBlockedStackAssignment(agentNames, skillId) {
|
|
1039
|
+
function scopeBlockedStackAssignment(agentNames, skillId, namedBy) {
|
|
1031
1040
|
const subject = agentNames.length === 1 ? "Sub-agent" : "Sub-agents";
|
|
1032
1041
|
const named = agentNames.map((name) => `'${name}'`).join(", ");
|
|
1033
|
-
return `${subject} ${named} cannot carry project-scoped skill '${skillId}' \u2014 global-scoped sub-agents only carry global-scoped skills.`;
|
|
1042
|
+
return `${subject} ${named} cannot carry project-scoped skill '${skillName(skillId, namedBy)}' \u2014 global-scoped sub-agents only carry global-scoped skills.`;
|
|
1034
1043
|
}
|
|
1035
1044
|
function globalScopedAgentsHint(count) {
|
|
1036
1045
|
const [subject, object] = count === 1 ? ["agent is", "it"] : ["agents are", "them"];
|
|
1037
1046
|
return `${count} ${subject} global-scoped \u2014 run '${CLI_INVOKE_COMMAND} compile' from your home directory to recompile ${object}.`;
|
|
1038
1047
|
}
|
|
1039
|
-
function marketplacesRefreshed(count) {
|
|
1040
|
-
return `Refreshed ${plural(count, "marketplace listing")}. Installed plugins were not changed.`;
|
|
1041
|
-
}
|
|
1042
1048
|
function marketplaceRefreshFailed(marketplace, reason) {
|
|
1043
1049
|
return `Could not update marketplace ${marketplace}: ${reason}`;
|
|
1044
1050
|
}
|
|
@@ -1051,6 +1057,13 @@ function sourceRefusedUsingCache(source, status) {
|
|
|
1051
1057
|
function marketplacesRefreshFailed(marketplaces) {
|
|
1052
1058
|
return `${plural(marketplaces.length, "marketplace")} could not be updated: ${marketplaces.join(", ")}`;
|
|
1053
1059
|
}
|
|
1060
|
+
function codexPluginLeftSwitchedOn(pluginKey, configFile, reason) {
|
|
1061
|
+
return `Codex switched plugin ${pluginKey} back on when it was updated, and it could not be switched off again in ${configFile}: ${reason}. To switch it off, set enabled = false in that file, in the table it already has for ${pluginKey}.`;
|
|
1062
|
+
}
|
|
1063
|
+
function pluginsLeftSwitchedOn(pluginKeys) {
|
|
1064
|
+
const are = pluginKeys.length === 1 ? "is" : "are";
|
|
1065
|
+
return `${plural(pluginKeys.length, "plugin")} you had switched off ${are} switched on again: ${pluginKeys.join(", ")}`;
|
|
1066
|
+
}
|
|
1054
1067
|
function marketplaceOwnerHasNoName(packageJsonPath) {
|
|
1055
1068
|
return [
|
|
1056
1069
|
`A marketplace's owner must have a name, and no name could be read from 'author' in ${packageJsonPath}.`,
|
|
@@ -1118,6 +1131,10 @@ function registeredProjectOnAnotherProvider(projectPath) {
|
|
|
1118
1131
|
function registeredProjectUpdateFailed(projectPath) {
|
|
1119
1132
|
return `Skipped ${projectPath}: updating it failed.`;
|
|
1120
1133
|
}
|
|
1134
|
+
function unregisteredSkillsSkipped(count, folder) {
|
|
1135
|
+
const are = count === 1 ? "isn't" : "aren't";
|
|
1136
|
+
return `Skipped ${plural(count, "skill")} in '${folder}' that ${are} registered with the CLI (no ${STANDARD_FILES.METADATA_YAML}).`;
|
|
1137
|
+
}
|
|
1121
1138
|
function skillMetadataUnusableDetail({
|
|
1122
1139
|
skillDirName,
|
|
1123
1140
|
metadataPath,
|
|
@@ -1166,26 +1183,26 @@ function applySharedConfigHere(id, installedHere, provider) {
|
|
|
1166
1183
|
const named = providerArgument(provider);
|
|
1167
1184
|
return id === void 0 ? `Then ${verb} what it gives you with '${command} <id>${named}'.` : `To ${verb} it here instead, run '${command} ${id}${named}'.`;
|
|
1168
1185
|
}
|
|
1169
|
-
function shareRefusesEjectedSkills(skillIds) {
|
|
1186
|
+
function shareRefusesEjectedSkills(skillIds, namedBy) {
|
|
1170
1187
|
return [
|
|
1171
1188
|
"This installation holds ejected skills, and ejected skills cannot be shared:",
|
|
1172
|
-
...skillIds.map((id) => ` ${id}`),
|
|
1189
|
+
...skillIds.map((id) => ` ${skillName(id, namedBy)}`),
|
|
1173
1190
|
"Only plugins can be shared."
|
|
1174
1191
|
].join("\n");
|
|
1175
1192
|
}
|
|
1176
1193
|
function sharedIdNamesAFolder(folder) {
|
|
1177
1194
|
return `This id names the marketplace folder ${folder}, so it installs only where that folder exists.`;
|
|
1178
1195
|
}
|
|
1179
|
-
function sharedSkillsLeftBehind(skillIds) {
|
|
1180
|
-
return `A shared id names one marketplace, and these skill(s) come from another, so they will not install elsewhere: ${skillIds
|
|
1196
|
+
function sharedSkillsLeftBehind(skillIds, namedBy) {
|
|
1197
|
+
return `A shared id names one marketplace, and these skill(s) come from another, so they will not install elsewhere: ${skillNames(skillIds, namedBy)}`;
|
|
1181
1198
|
}
|
|
1182
1199
|
function sharedConfigExistingInstall(configPath, id, provider) {
|
|
1183
1200
|
return `An installation already exists at ${configPath}. Run '${CLI_INVOKE_COMMAND} uninstall${providerArgument(provider)}' first \u2014 ${SHARED_CONFIG_GREENFIELD_HINT}. ${applySharedConfigHere(id, true, provider)}`;
|
|
1184
1201
|
}
|
|
1185
|
-
function sharedConfigProjectScopeAtHome(skillIds, agentNames, installedHere, provider) {
|
|
1202
|
+
function sharedConfigProjectScopeAtHome(skillIds, agentNames, installedHere, provider, namedBy) {
|
|
1186
1203
|
return [
|
|
1187
1204
|
"This configuration cannot be installed here: the home directory is the global scope, and a global installation holds only global-scoped content \u2014 so these project-scoped entries have nowhere to be written:",
|
|
1188
|
-
...skillIds.map((id) => ` skill ${id} (scope: project)`),
|
|
1205
|
+
...skillIds.map((id) => ` skill ${skillName(id, namedBy)} (scope: project)`),
|
|
1189
1206
|
...agentNames.map((name) => ` sub-agent ${name} (scope: project)`),
|
|
1190
1207
|
installedHere ? changeTheGlobalInstallFromHome(providerArgument(provider)) : "Run this from inside a project directory, or re-share it with each entry above at global scope."
|
|
1191
1208
|
].join("\n");
|
|
@@ -1220,12 +1237,21 @@ function subAgentsInstalledWithout({ skillId, agentNames }) {
|
|
|
1220
1237
|
function skippedUnknownAgents(agentNames) {
|
|
1221
1238
|
return `Skipped ${agentNames.length} unknown sub-agent(s): ${unknownKeys(agentNames)}`;
|
|
1222
1239
|
}
|
|
1223
|
-
function carriedSkillsWritten(skillIds) {
|
|
1224
|
-
return `Wrote ${skillIds.length} skill(s) this configuration carries: ${skillIds
|
|
1240
|
+
function carriedSkillsWritten(skillIds, namedBy) {
|
|
1241
|
+
return `Wrote ${skillIds.length} skill(s) this configuration carries: ${skillNames(skillIds, namedBy)}`;
|
|
1242
|
+
}
|
|
1243
|
+
function copiedSkillsRemovedAfterRefusedSave(count) {
|
|
1244
|
+
return `Removed the ${plural(count, "skill")} it copied, since the configuration could not be saved`;
|
|
1245
|
+
}
|
|
1246
|
+
function carriedSkillsRemovedAfterRefusedSave(count) {
|
|
1247
|
+
return `Removed the ${plural(count, "skill")} this configuration carried, since the configuration could not be saved`;
|
|
1225
1248
|
}
|
|
1226
1249
|
var SHARED_CONFIG_APPLY = {
|
|
1227
1250
|
CONFIRM: "Apply this configuration?"
|
|
1228
1251
|
};
|
|
1252
|
+
function idNamesAnotherMarketplace(named, used) {
|
|
1253
|
+
return `This id names the marketplace ${inertLine(named)}; its skills come from this installation's marketplace, ${used}.`;
|
|
1254
|
+
}
|
|
1229
1255
|
function registeredProjectsRecompiled(projectPaths) {
|
|
1230
1256
|
return [
|
|
1231
1257
|
"Each project registered with this global install is recompiled to match:",
|
|
@@ -1257,6 +1283,9 @@ var SHARED_CONFIG_ARRIVALS = {
|
|
|
1257
1283
|
function skillName(id, namedBy) {
|
|
1258
1284
|
return getSkillEntryDisplayName(namedBy[id] ?? { id });
|
|
1259
1285
|
}
|
|
1286
|
+
function skillNames(skillIds, namedBy) {
|
|
1287
|
+
return skillIds.map((id) => skillName(id, namedBy)).join(", ");
|
|
1288
|
+
}
|
|
1260
1289
|
function keptAsInstalledGlobally(skillIds, agentNames, idAppliedAtHome, provider, namedBy) {
|
|
1261
1290
|
return [
|
|
1262
1291
|
"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:",
|
|
@@ -1269,15 +1298,11 @@ function keptAsInstalledGlobally(skillIds, agentNames, idAppliedAtHome, provider
|
|
|
1269
1298
|
}
|
|
1270
1299
|
function skillsMoved(verb, skillIds, namedBy) {
|
|
1271
1300
|
const names = skillIds.map((id) => skillName(id, namedBy));
|
|
1272
|
-
return names.length === 0 ? [] : [`${verb} ${
|
|
1301
|
+
return names.length === 0 ? [] : [`${verb} ${inAnEnglishList(names)}`];
|
|
1273
1302
|
}
|
|
1274
1303
|
function settingMoved({ setting, from, to }) {
|
|
1275
1304
|
return `${setting} ${from ?? "default"} \u2192 ${to ?? "default"}`;
|
|
1276
1305
|
}
|
|
1277
|
-
function listed(names) {
|
|
1278
|
-
if (names.length <= 1) return names.join("");
|
|
1279
|
-
return `${names.slice(0, -1).join(", ")} and ${names.at(-1)}`;
|
|
1280
|
-
}
|
|
1281
1306
|
var SKILLS_REASSIGNED = "skills reassigned";
|
|
1282
1307
|
function subAgentChanged({
|
|
1283
1308
|
name,
|
|
@@ -1296,10 +1321,11 @@ function subAgentChanged({
|
|
|
1296
1321
|
return `~ ${name}${where}: ${details.length > 0 ? details.join(", ") : SKILLS_REASSIGNED}`;
|
|
1297
1322
|
}
|
|
1298
1323
|
function addedToGlobalSubAgents(joined, namedBy) {
|
|
1299
|
-
const gains = (skillIds) => skillIds.map((id) => skillName(id, namedBy)).join(", ");
|
|
1300
1324
|
return [
|
|
1301
1325
|
"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:",
|
|
1302
|
-
...joined.map(
|
|
1326
|
+
...joined.map(
|
|
1327
|
+
({ agentName, skillIds }) => ` sub-agent ${agentName}: + ${skillNames(skillIds, namedBy)}`
|
|
1328
|
+
)
|
|
1303
1329
|
].join("\n");
|
|
1304
1330
|
}
|
|
1305
1331
|
function authoredHereKept(skillIds, namedBy) {
|
|
@@ -2583,6 +2609,14 @@ var ConfigDefaultExportError = class extends Error {
|
|
|
2583
2609
|
}
|
|
2584
2610
|
configPath;
|
|
2585
2611
|
};
|
|
2612
|
+
var ConfigEvaluationError = class extends Error {
|
|
2613
|
+
constructor(configPath, reason, options) {
|
|
2614
|
+
super(configLoadFailure(configPath, reason), options);
|
|
2615
|
+
this.configPath = configPath;
|
|
2616
|
+
this.name = "ConfigEvaluationError";
|
|
2617
|
+
}
|
|
2618
|
+
configPath;
|
|
2619
|
+
};
|
|
2586
2620
|
var ES_MODULE_MARKER = "__esModule";
|
|
2587
2621
|
function unwrapDefaultExport(namespace) {
|
|
2588
2622
|
if (isRecord(namespace) && "default" in namespace) return namespace.default;
|
|
@@ -2628,7 +2662,7 @@ async function importConfigModule(configPath) {
|
|
|
2628
2662
|
});
|
|
2629
2663
|
return await jiti.import(configPath);
|
|
2630
2664
|
} catch (error) {
|
|
2631
|
-
throw new
|
|
2665
|
+
throw new ConfigEvaluationError(configPath, getErrorMessage(error), { cause: error });
|
|
2632
2666
|
}
|
|
2633
2667
|
}
|
|
2634
2668
|
|
|
@@ -2664,7 +2698,7 @@ function initProviderToNameAt(root, provider) {
|
|
|
2664
2698
|
|
|
2665
2699
|
// src/cli/lib/configuration/config.ts
|
|
2666
2700
|
var SOURCE_ENV_VAR = "CC_MARKETPLACE";
|
|
2667
|
-
async function
|
|
2701
|
+
async function readStoredConfig(dir, scope, provider) {
|
|
2668
2702
|
const scopeLabel2 = scope === "project" ? "Project" : "Global";
|
|
2669
2703
|
const configPath = storedConfigPath(dir, provider);
|
|
2670
2704
|
if (!await fileExists(configPath)) {
|
|
@@ -2681,7 +2715,17 @@ async function loadSourceConfig(dir, scope, provider) {
|
|
|
2681
2715
|
if (installation === null) throw unreadable(NO_VALID_DEFAULT_EXPORT);
|
|
2682
2716
|
const settings = readSettings(configPath, installation);
|
|
2683
2717
|
verbose(`Loaded ${scope} config from ${dir}`);
|
|
2684
|
-
return
|
|
2718
|
+
return {
|
|
2719
|
+
settings,
|
|
2720
|
+
declaresNothing: declaresNoContent({
|
|
2721
|
+
skills: installation.skills ?? [],
|
|
2722
|
+
agents: installation.agents ?? []
|
|
2723
|
+
})
|
|
2724
|
+
};
|
|
2725
|
+
}
|
|
2726
|
+
async function loadSourceConfig(dir, scope, provider) {
|
|
2727
|
+
const stored = await readStoredConfig(dir, scope, provider);
|
|
2728
|
+
return stored === null ? null : stored.settings;
|
|
2685
2729
|
}
|
|
2686
2730
|
function refuseInstallationConfig(configPath, scope, scopeRoot, provider) {
|
|
2687
2731
|
const providerToName = providerToNameAt(scopeRoot, provider);
|
|
@@ -2738,14 +2782,23 @@ async function loadGlobalSourceConfig(provider) {
|
|
|
2738
2782
|
async function loadEffectiveSourceConfig(projectDir, provider) {
|
|
2739
2783
|
const ownDir = ownProjectDir(projectDir);
|
|
2740
2784
|
const own = ownDir === null ? null : await readStoredRung(ownDir, "project", provider);
|
|
2741
|
-
|
|
2785
|
+
if (own !== null && !readsAsNoConfig(own)) return own;
|
|
2786
|
+
return readStoredRung(os4.homedir(), "global", provider ?? inheritedBy(projectDir));
|
|
2787
|
+
}
|
|
2788
|
+
function readsAsNoConfig(own) {
|
|
2789
|
+
return own.declaresNothing && own.config.marketplace === void 0;
|
|
2742
2790
|
}
|
|
2743
2791
|
function inheritedBy(projectDir) {
|
|
2744
2792
|
return inheritedGlobalProvider(projectDir ?? os4.homedir());
|
|
2745
2793
|
}
|
|
2746
2794
|
async function readStoredRung(dir, origin, provider) {
|
|
2747
|
-
const
|
|
2748
|
-
return
|
|
2795
|
+
const stored = await readStoredConfig(dir, origin, provider);
|
|
2796
|
+
return stored && {
|
|
2797
|
+
config: stored.settings,
|
|
2798
|
+
declaresNothing: stored.declaresNothing,
|
|
2799
|
+
origin,
|
|
2800
|
+
configPath: storedConfigPath(dir, provider)
|
|
2801
|
+
};
|
|
2749
2802
|
}
|
|
2750
2803
|
function storedConfigPath(dir, provider) {
|
|
2751
2804
|
return provider === void 0 ? getInstalledConfigPath(dir) : getProjectConfigPath(dir, provider);
|
|
@@ -2779,7 +2832,7 @@ async function resolveSource(request) {
|
|
|
2779
2832
|
if (envSource !== void 0) {
|
|
2780
2833
|
return { source: envSource, sourceOrigin: "env", ...labelFor(envSource) };
|
|
2781
2834
|
}
|
|
2782
|
-
if (effective?.config.marketplace) {
|
|
2835
|
+
if (caller === "stored" && effective?.config.marketplace) {
|
|
2783
2836
|
assertStoredSourceUsable(effective.config.marketplace, effective.configPath);
|
|
2784
2837
|
verbose(`Marketplace from ${effective.origin} config: ${effective.config.marketplace}`);
|
|
2785
2838
|
return {
|
|
@@ -3218,9 +3271,6 @@ function valueEntries(values) {
|
|
|
3218
3271
|
function commentEntry(text) {
|
|
3219
3272
|
return { kind: "comment", text };
|
|
3220
3273
|
}
|
|
3221
|
-
function sourceEntry(source) {
|
|
3222
|
-
return { kind: "source", source };
|
|
3223
|
-
}
|
|
3224
3274
|
function renderValueLine(value, position) {
|
|
3225
3275
|
return line(
|
|
3226
3276
|
renderValue(value, position),
|
|
@@ -3301,8 +3351,6 @@ function renderEntryLine(entry, indent) {
|
|
|
3301
3351
|
switch (entry.kind) {
|
|
3302
3352
|
case "comment":
|
|
3303
3353
|
return `${spaces(indent)}// ${entry.text}`;
|
|
3304
|
-
case "source":
|
|
3305
|
-
return `${spaces(indent)}${entry.source},`;
|
|
3306
3354
|
case "value":
|
|
3307
3355
|
return renderValueLine(entry.value, { indent, prefix: "", suffix: "," });
|
|
3308
3356
|
default: {
|
|
@@ -3340,8 +3388,6 @@ function flatEntry(entry) {
|
|
|
3340
3388
|
// A `//` line cannot fold onto one line.
|
|
3341
3389
|
case "comment":
|
|
3342
3390
|
return void 0;
|
|
3343
|
-
case "source":
|
|
3344
|
-
return entry.source;
|
|
3345
3391
|
case "value":
|
|
3346
3392
|
return flatValue(entry.value);
|
|
3347
3393
|
default: {
|
|
@@ -3526,62 +3572,16 @@ function generateConfigSource(config, catalog, options) {
|
|
|
3526
3572
|
}
|
|
3527
3573
|
function generateProjectConfig(config, catalog, options) {
|
|
3528
3574
|
const cleaned = cleanForEmission(config, catalog, { dropProjects: true });
|
|
3529
|
-
if (options.globalConfig) {
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
cleanForEmission(options.globalConfig, catalog, { dropProjects: true })
|
|
3533
|
-
);
|
|
3534
|
-
}
|
|
3535
|
-
if (options.globalImportPath !== void 0) {
|
|
3536
|
-
return generateProjectConfigWithGlobalImport(
|
|
3537
|
-
cleaned,
|
|
3538
|
-
options.globalImportPath
|
|
3575
|
+
if (!options.globalConfig) {
|
|
3576
|
+
throw new Error(
|
|
3577
|
+
"A project config needs the global config it extends: pass `globalConfig` to inline its entries."
|
|
3539
3578
|
);
|
|
3540
3579
|
}
|
|
3541
|
-
|
|
3542
|
-
|
|
3580
|
+
return generateProjectConfigWithInlinedGlobal(
|
|
3581
|
+
cleaned,
|
|
3582
|
+
cleanForEmission(options.globalConfig, catalog, { dropProjects: true })
|
|
3543
3583
|
);
|
|
3544
3584
|
}
|
|
3545
|
-
function generateProjectConfigWithGlobalImport(cleaned, globalImportPath) {
|
|
3546
|
-
const { skills, agents, stack, selectedDomains } = extractConfigArrays(cleaned);
|
|
3547
|
-
const emitted = {
|
|
3548
|
-
hasSkills: true,
|
|
3549
|
-
hasAgents: true,
|
|
3550
|
-
hasStack: hasStackEntries(stack),
|
|
3551
|
-
hasSelectedDomains: selectedDomains.length > 0
|
|
3552
|
-
};
|
|
3553
|
-
const scalarFields = Object.entries(cleaned).filter(([key]) => isCopiedScalarField(key)).map(([key, value]) => renderScalarField(key, value));
|
|
3554
|
-
return assembleConfigSource({
|
|
3555
|
-
imports: [
|
|
3556
|
-
`import globalConfig from ${quoteText(`${globalImportPath}/config`)}`,
|
|
3557
|
-
renderTypeImportLine(buildTypeImports(emitted), CONFIG_TYPES_SPECIFIER)
|
|
3558
|
-
],
|
|
3559
|
-
declarations: [
|
|
3560
|
-
...entryDeclaration("skills", "SkillConfig[]", [
|
|
3561
|
-
sourceEntry("...globalConfig.skills"),
|
|
3562
|
-
...valueEntries(skills)
|
|
3563
|
-
]),
|
|
3564
|
-
...entryDeclaration("agents", "AgentScopeConfig[]", [
|
|
3565
|
-
sourceEntry("...globalConfig.agents"),
|
|
3566
|
-
...valueEntries(agents)
|
|
3567
|
-
]),
|
|
3568
|
-
...emitted.hasStack ? declaration("stack", STACK_TYPE, stack) : [],
|
|
3569
|
-
...emitted.hasSelectedDomains ? entryDeclaration("selectedDomains", "Domain[]", [
|
|
3570
|
-
sourceEntry("...(globalConfig.selectedDomains ?? [])"),
|
|
3571
|
-
...valueEntries(selectedDomains)
|
|
3572
|
-
]) : []
|
|
3573
|
-
],
|
|
3574
|
-
exportFields: [
|
|
3575
|
-
` ...globalConfig,`,
|
|
3576
|
-
renderScalarField("name", resolveProjectName(cleaned)),
|
|
3577
|
-
` skills,`,
|
|
3578
|
-
` agents,`,
|
|
3579
|
-
...emitted.hasStack ? [` stack,`] : [],
|
|
3580
|
-
...emitted.hasSelectedDomains ? [` selectedDomains,`] : [],
|
|
3581
|
-
...scalarFields
|
|
3582
|
-
]
|
|
3583
|
-
});
|
|
3584
|
-
}
|
|
3585
3585
|
function generateStandaloneConfig(cleaned) {
|
|
3586
3586
|
const { skills, agents, stack, selectedDomains } = extractConfigArrays(cleaned);
|
|
3587
3587
|
const emitted = {
|
|
@@ -3697,18 +3697,25 @@ function stackOfAgents(stack, agents) {
|
|
|
3697
3697
|
function mergeInlinedScalarFields(cleaned, cleanedGlobal) {
|
|
3698
3698
|
return Object.entries(
|
|
3699
3699
|
canonicalizeFieldOrder({
|
|
3700
|
-
...
|
|
3700
|
+
...globalScalarsLentTo(cleaned, cleanedGlobal),
|
|
3701
3701
|
...cleaned
|
|
3702
3702
|
})
|
|
3703
3703
|
).filter(([key]) => isCopiedScalarField(key));
|
|
3704
3704
|
}
|
|
3705
|
+
function globalScalarsLentTo(cleaned, cleanedGlobal) {
|
|
3706
|
+
const lent = omit(cleanedGlobal, GLOBAL_IDENTITY_FIELDS);
|
|
3707
|
+
return recordsAnotherMarketplace(cleaned, cleanedGlobal) ? omit(lent, ["marketplaceName"]) : lent;
|
|
3708
|
+
}
|
|
3709
|
+
function recordsAnotherMarketplace(cleaned, cleanedGlobal) {
|
|
3710
|
+
return cleaned.marketplace !== void 0 && cleaned.marketplace !== cleanedGlobal.marketplace;
|
|
3711
|
+
}
|
|
3705
3712
|
function generateProjectConfigWithInlinedGlobal(cleaned, cleanedGlobal) {
|
|
3706
|
-
const
|
|
3713
|
+
const partition7 = partitionInlinedConfigEntries(cleaned, cleanedGlobal);
|
|
3707
3714
|
const emitted = {
|
|
3708
|
-
hasSkills:
|
|
3709
|
-
hasAgents:
|
|
3710
|
-
hasStack: hasStackEntries(
|
|
3711
|
-
hasSelectedDomains:
|
|
3715
|
+
hasSkills: partition7.globalSkills.length > 0 || partition7.projectSkills.length > 0,
|
|
3716
|
+
hasAgents: partition7.globalAgents.length > 0 || partition7.projectAgents.length > 0,
|
|
3717
|
+
hasStack: hasStackEntries(partition7.filteredStack),
|
|
3718
|
+
hasSelectedDomains: partition7.selectedDomains.length > 0
|
|
3712
3719
|
};
|
|
3713
3720
|
const scalarFields = mergeInlinedScalarFields(cleaned, cleanedGlobal);
|
|
3714
3721
|
return assembleConfigSource({
|
|
@@ -3719,15 +3726,15 @@ function generateProjectConfigWithInlinedGlobal(cleaned, cleanedGlobal) {
|
|
|
3719
3726
|
...emitted.hasSkills ? entryDeclaration(
|
|
3720
3727
|
"skills",
|
|
3721
3728
|
"SkillConfig[]",
|
|
3722
|
-
scopeSectionEntries(
|
|
3729
|
+
scopeSectionEntries(partition7.globalSkills, partition7.projectSkills)
|
|
3723
3730
|
) : [],
|
|
3724
3731
|
...emitted.hasAgents ? entryDeclaration(
|
|
3725
3732
|
"agents",
|
|
3726
3733
|
"AgentScopeConfig[]",
|
|
3727
|
-
scopeSectionEntries(
|
|
3734
|
+
scopeSectionEntries(partition7.globalAgents, partition7.projectAgents)
|
|
3728
3735
|
) : [],
|
|
3729
|
-
...emitted.hasStack ? declaration("stack", STACK_TYPE,
|
|
3730
|
-
...emitted.hasSelectedDomains ? declaration("selectedDomains", "Domain[]",
|
|
3736
|
+
...emitted.hasStack ? declaration("stack", STACK_TYPE, partition7.filteredStack) : [],
|
|
3737
|
+
...emitted.hasSelectedDomains ? declaration("selectedDomains", "Domain[]", partition7.selectedDomains) : []
|
|
3731
3738
|
],
|
|
3732
3739
|
exportFields: [
|
|
3733
3740
|
renderScalarField("name", resolveProjectName(cleaned)),
|
|
@@ -4220,14 +4227,14 @@ function agentsOnlyItCarried(skill, agentMap, carried) {
|
|
|
4220
4227
|
}
|
|
4221
4228
|
function readAgentMap(agents) {
|
|
4222
4229
|
const known = /* @__PURE__ */ new Map();
|
|
4223
|
-
const
|
|
4230
|
+
const switchedOff2 = /* @__PURE__ */ new Set();
|
|
4224
4231
|
const unknown = [];
|
|
4225
4232
|
for (const [name, entry] of Object.entries(agents)) {
|
|
4226
4233
|
if (!isAgentName2(name)) unknown.push(name);
|
|
4227
|
-
else if (entry.on === false)
|
|
4234
|
+
else if (entry.on === false) switchedOff2.add(name);
|
|
4228
4235
|
else known.set(name, entry);
|
|
4229
4236
|
}
|
|
4230
|
-
return { known, switchedOff, unknown };
|
|
4237
|
+
return { known, switchedOff: switchedOff2, unknown };
|
|
4231
4238
|
}
|
|
4232
4239
|
function agentsSwitchedOn(agentMap) {
|
|
4233
4240
|
return [...agentMap.known].filter(([, entry]) => entry.on === true).map(([name]) => name);
|
|
@@ -4389,6 +4396,12 @@ function normalizeStackRecord(rawStack) {
|
|
|
4389
4396
|
(agentConfig) => rekeyToLiveCategories(normalizeAgentConfig(agentConfig))
|
|
4390
4397
|
);
|
|
4391
4398
|
}
|
|
4399
|
+
var StacksLoadError = class extends Error {
|
|
4400
|
+
constructor(stacksPath, reason, options) {
|
|
4401
|
+
super(`Failed to load stacks from '${stacksPath}': ${reason}`, options);
|
|
4402
|
+
this.name = "StacksLoadError";
|
|
4403
|
+
}
|
|
4404
|
+
};
|
|
4392
4405
|
async function loadStacks(configDir, stacksFile) {
|
|
4393
4406
|
const resolvedStacksFile = stacksFile ?? STACKS_FILE_PATH;
|
|
4394
4407
|
const cacheKey = `${configDir}:${resolvedStacksFile}`;
|
|
@@ -4412,14 +4425,12 @@ async function loadStacks(configDir, stacksFile) {
|
|
|
4412
4425
|
verbose(`Loaded ${stacks.length} stacks from ${stacksPath}`);
|
|
4413
4426
|
return stacks;
|
|
4414
4427
|
} catch (error) {
|
|
4415
|
-
|
|
4416
|
-
throw new Error(`Failed to load stacks from '${stacksPath}': ${errorMessage}`, {
|
|
4417
|
-
cause: error
|
|
4418
|
-
});
|
|
4428
|
+
throw new StacksLoadError(stacksPath, getErrorMessage(error), { cause: error });
|
|
4419
4429
|
}
|
|
4420
4430
|
}
|
|
4421
4431
|
async function loadStackById(stackId, configDir, source) {
|
|
4422
|
-
const
|
|
4432
|
+
const declared = await loadSourceRepoConfig(configDir);
|
|
4433
|
+
const stacks = await loadStacks(configDir, declared?.stacksFile);
|
|
4423
4434
|
const stack = stacks.find((s) => s.id === stackId);
|
|
4424
4435
|
if (stack) {
|
|
4425
4436
|
verbose(`Found stack: ${stack.name} (${stackId})`);
|
|
@@ -4439,8 +4450,15 @@ async function loadStackById(stackId, configDir, source) {
|
|
|
4439
4450
|
verbose(`Found default stack: ${defaultStack.name} (${stackId})`);
|
|
4440
4451
|
return defaultStack;
|
|
4441
4452
|
}
|
|
4442
|
-
function stackNotOfferedMessage(stackId, source) {
|
|
4443
|
-
return `Stack '${inertLine(stackId)}' is not a stack the source '${source}' offers. A marketplace ships its own stacks; the CLI's built-in ones belong to the default public marketplace alone
|
|
4453
|
+
function stackNotOfferedMessage(stackId, source, shippedStackIds) {
|
|
4454
|
+
return `Stack '${inertLine(stackId)}' is not a stack the source '${source}' offers. A marketplace ships its own stacks; the CLI's built-in ones belong to the default public marketplace alone. ${whatItShips(shippedStackIds)}`;
|
|
4455
|
+
}
|
|
4456
|
+
function whatItShips(stackIds) {
|
|
4457
|
+
if (stackIds.length === 0) return "It ships no stacks.";
|
|
4458
|
+
return withClosingFullStop(`It ships: ${inAnEnglishList(stackIds.map(inertLine))}`);
|
|
4459
|
+
}
|
|
4460
|
+
function withClosingFullStop(sentence) {
|
|
4461
|
+
return sentence.endsWith(".") ? sentence : `${sentence}.`;
|
|
4444
4462
|
}
|
|
4445
4463
|
function defaultUsageGuidance(category) {
|
|
4446
4464
|
return `Use when working with ${category}.`;
|
|
@@ -4491,9 +4509,6 @@ var ConfigLoadError = class extends Error {
|
|
|
4491
4509
|
/** Named in the remedy's `init --from` half, which a bare run would answer with another one. */
|
|
4492
4510
|
initProviderToName;
|
|
4493
4511
|
};
|
|
4494
|
-
function declaresNoContent(config) {
|
|
4495
|
-
return config.skills.length === 0 && config.agents.length === 0;
|
|
4496
|
-
}
|
|
4497
4512
|
async function configDeclaresNothing(projectDir, provider) {
|
|
4498
4513
|
const configPath = getProjectConfigPath(projectDir, provider);
|
|
4499
4514
|
const parsed = await parseConfigFile(configPath, refusalAt(configPath, projectDir, provider));
|
|
@@ -4635,6 +4650,16 @@ function editDrops(incoming, existing, identity, authoritativeScope) {
|
|
|
4635
4650
|
incomingIdentities.has(identity.identityOf(entry)) || dualScopeIdentities.has(identity.identityOf(entry)) || authoritativeScope !== void 0 && isWithinSessionAuthority(entry, authoritativeScope)
|
|
4636
4651
|
);
|
|
4637
4652
|
}
|
|
4653
|
+
function marketplaceNameBeside(merged, existing) {
|
|
4654
|
+
if (merged.marketplace === existing.marketplace) {
|
|
4655
|
+
return existing.marketplaceName ?? merged.marketplaceName;
|
|
4656
|
+
}
|
|
4657
|
+
if (wouldBorrowAnotherMarketplaceName(merged, existing)) return DEFAULT_PUBLIC_SOURCE_NAME;
|
|
4658
|
+
return merged.marketplaceName;
|
|
4659
|
+
}
|
|
4660
|
+
function wouldBorrowAnotherMarketplaceName(merged, existing) {
|
|
4661
|
+
return merged.marketplace === DEFAULT_SOURCE && merged.marketplaceName === void 0 && existing.marketplaceName !== void 0;
|
|
4662
|
+
}
|
|
4638
4663
|
function mergeConfigs(newConfig, existingConfig, options) {
|
|
4639
4664
|
const merged = { ...newConfig };
|
|
4640
4665
|
if (existingConfig.name) {
|
|
@@ -4664,8 +4689,9 @@ function mergeConfigs(newConfig, existingConfig, options) {
|
|
|
4664
4689
|
if (existingConfig.author) {
|
|
4665
4690
|
merged.author = existingConfig.author;
|
|
4666
4691
|
}
|
|
4667
|
-
|
|
4668
|
-
|
|
4692
|
+
const marketplaceName = marketplaceNameBeside(merged, existingConfig);
|
|
4693
|
+
if (marketplaceName !== void 0) {
|
|
4694
|
+
merged.marketplaceName = marketplaceName;
|
|
4669
4695
|
}
|
|
4670
4696
|
Object.assign(merged, pick(existingConfig, HAND_WRITTEN_FIELDS));
|
|
4671
4697
|
if (existingConfig.projects && !newConfig.projects) {
|
|
@@ -5294,9 +5320,10 @@ async function loadProjectAgents(projectRoot, provider = providerInUse(projectRo
|
|
|
5294
5320
|
});
|
|
5295
5321
|
}
|
|
5296
5322
|
async function loadSkillsFromDir(skillsDir2, options = {}) {
|
|
5297
|
-
const { pathPrefix = "", requireMetadata = false } = options;
|
|
5323
|
+
const { pathPrefix = "", requireMetadata = false, folderLabel = `${pathPrefix}/` } = options;
|
|
5298
5324
|
const skills = {};
|
|
5299
5325
|
const unusableMetadata = [];
|
|
5326
|
+
let unregisteredCount = 0;
|
|
5300
5327
|
if (!await directoryExists2(skillsDir2)) {
|
|
5301
5328
|
return { skills, unusableMetadata };
|
|
5302
5329
|
}
|
|
@@ -5306,11 +5333,13 @@ async function loadSkillsFromDir(skillsDir2, options = {}) {
|
|
|
5306
5333
|
if (requireMetadata) {
|
|
5307
5334
|
const verdict = await judgeSkillMetadata(skill);
|
|
5308
5335
|
if (verdict.kind === "unusable") unusableMetadata.push(verdict.refusal);
|
|
5336
|
+
if (verdict.kind === "unregistered") unregisteredCount++;
|
|
5309
5337
|
if (verdict.kind !== "admitted") continue;
|
|
5310
5338
|
}
|
|
5311
5339
|
const definition = await readSkillDefinition(skill);
|
|
5312
5340
|
if (definition) skills[definition.id] = definition;
|
|
5313
5341
|
}
|
|
5342
|
+
if (unregisteredCount > 0) warn(unregisteredSkillsSkipped(unregisteredCount, folderLabel));
|
|
5314
5343
|
return { skills, unusableMetadata };
|
|
5315
5344
|
}
|
|
5316
5345
|
function locateSkill(skillsDir2, skillFile, pathPrefix) {
|
|
@@ -5328,10 +5357,8 @@ function locateSkill(skillsDir2, skillFile, pathPrefix) {
|
|
|
5328
5357
|
async function judgeSkillMetadata(skill) {
|
|
5329
5358
|
const metadataPath = path14.join(skill.skillDir, STANDARD_FILES.METADATA_YAML);
|
|
5330
5359
|
if (!await fileExists(metadataPath)) {
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
);
|
|
5334
|
-
return { kind: "skipped" };
|
|
5360
|
+
verbose(` No ${STANDARD_FILES.METADATA_YAML} in '${skill.skillDirName}'`);
|
|
5361
|
+
return { kind: "unregistered" };
|
|
5335
5362
|
}
|
|
5336
5363
|
const read = await readSkillMetadata(metadataPath);
|
|
5337
5364
|
if (!read.usable) {
|
|
@@ -5475,11 +5502,11 @@ function reservedNameError(marketplaceName, wayOut) {
|
|
|
5475
5502
|
return `Marketplace name '${marketplaceName}' is reserved. '${DEFAULT_PUBLIC_SOURCE_NAME}' is the public catalogue's own namespace, '${EXTERNAL_SKILL_NAMESPACE}' and '${LOCAL_SKILL_NAMESPACE}' hold the skills that belong to no marketplace, and '${EJECT_SOURCE}' is what an installation records for a skill copied into it rather than installed as a plugin \u2014 a marketplace under any of them is read back as something it is not. Choose a name of your own: ${wayOut}.`;
|
|
5476
5503
|
}
|
|
5477
5504
|
function namespaceViolationError(foreignIds, marketplaceName) {
|
|
5478
|
-
const
|
|
5479
|
-
const unlisted = foreignIds.length -
|
|
5505
|
+
const listed = foreignIds.slice(0, MAX_REPORTED_NAMESPACE_VIOLATIONS).map((id) => ` ${id} -> ${marketplaceName}-${id}`);
|
|
5506
|
+
const unlisted = foreignIds.length - listed.length;
|
|
5480
5507
|
return [
|
|
5481
5508
|
`Marketplace '${marketplaceName}' ships ${foreignIds.length} skill id(s) outside its own namespace. Every skill id must begin with the marketplace's name:`,
|
|
5482
|
-
...
|
|
5509
|
+
...listed,
|
|
5483
5510
|
...unlisted > 0 ? [` ... and ${unlisted} more`] : [],
|
|
5484
5511
|
`Rename each skill directory and the 'name' in its SKILL.md, re-run 'build plugins', then build the marketplace again.`
|
|
5485
5512
|
].join("\n");
|
|
@@ -5521,6 +5548,9 @@ var TarballWithheldError = class extends Error {
|
|
|
5521
5548
|
this.status = status;
|
|
5522
5549
|
}
|
|
5523
5550
|
};
|
|
5551
|
+
function isUnanswered(answer) {
|
|
5552
|
+
return answer === "unreachable" || answer instanceof TarballWithheldError;
|
|
5553
|
+
}
|
|
5524
5554
|
var marketplaceMustAnswer = new AsyncLocalStorage3();
|
|
5525
5555
|
function askingEachMarketplaceItself(body) {
|
|
5526
5556
|
const differingCopiesReplaced = /* @__PURE__ */ new Set();
|
|
@@ -5620,38 +5650,95 @@ async function fetchFromRemoteSource(source, subdir) {
|
|
|
5620
5650
|
verbose(`Cache directory: ${cacheDir}`);
|
|
5621
5651
|
if (await directoryExists2(cacheDir)) {
|
|
5622
5652
|
const verdict = await revalidateCachedCopy(cacheDir, source);
|
|
5623
|
-
if (keepsTheCopy(verdict))
|
|
5624
|
-
verbose(`Using cached marketplace: ${cacheDir}`);
|
|
5625
|
-
return {
|
|
5626
|
-
path: cacheDir,
|
|
5627
|
-
fromCache: true,
|
|
5628
|
-
unreachable: verdict === "unreachable",
|
|
5629
|
-
source: fullSource
|
|
5630
|
-
};
|
|
5631
|
-
}
|
|
5653
|
+
if (keepsTheCopy(verdict)) return readSavedCopy(cacheDir, fullSource, verdict);
|
|
5632
5654
|
announceRefetch(verdict);
|
|
5633
|
-
if (!mustAnswer())
|
|
5655
|
+
if (!mustAnswer()) return refreshSavedCopy(cacheDir, source, fullSource, verdict);
|
|
5634
5656
|
}
|
|
5635
5657
|
const differingCopiesReplaced = marketplaceMustAnswer.getStore();
|
|
5636
5658
|
return differingCopiesReplaced ? downloadAnsweredFor(cacheDir, source, fullSource, differingCopiesReplaced) : downloadFreshCopy(cacheDir, source, fullSource);
|
|
5637
5659
|
}
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5660
|
+
function readSavedCopy(cacheDir, fullSource, verdict) {
|
|
5661
|
+
verbose(`Using cached marketplace: ${cacheDir}`);
|
|
5662
|
+
return {
|
|
5663
|
+
path: cacheDir,
|
|
5664
|
+
fromCache: true,
|
|
5665
|
+
unreachable: verdict === "unreachable",
|
|
5666
|
+
source: fullSource
|
|
5667
|
+
};
|
|
5668
|
+
}
|
|
5669
|
+
async function refreshSavedCopy(cacheDir, source, fullSource, verdict) {
|
|
5670
|
+
if (verdict === "superseded") await clearGigetCache(source);
|
|
5671
|
+
const staged = `${cacheDir}${STAGED_DOWNLOAD_SUFFIX}`;
|
|
5672
|
+
try {
|
|
5673
|
+
const download = await downloadUnlessItFails(source, fullSource, staged);
|
|
5674
|
+
if (isUnanswered(download)) {
|
|
5675
|
+
const failed = verdictOnFailedDownload(verdict, download, source);
|
|
5676
|
+
return keepSavedCopyUnlessStopped(cacheDir, fullSource, failed);
|
|
5677
|
+
}
|
|
5678
|
+
const downloaded = await verdictOnDownload(download, source);
|
|
5679
|
+
if (downloaded !== "current") {
|
|
5680
|
+
return keepSavedCopyUnlessStopped(cacheDir, fullSource, downloaded);
|
|
5681
|
+
}
|
|
5682
|
+
await moveIntoPlace(cacheDir, staged);
|
|
5683
|
+
await recordFetchedCopy(cacheDir, download.result, download.savedTarball);
|
|
5684
|
+
settleForThisRun(cacheDir, "current");
|
|
5685
|
+
return { path: cacheDir, fromCache: false, unreachable: false, source: fullSource };
|
|
5686
|
+
} catch (error) {
|
|
5687
|
+
throw createDetailedFetchError(error, source);
|
|
5688
|
+
} finally {
|
|
5689
|
+
await remove(staged);
|
|
5690
|
+
}
|
|
5691
|
+
}
|
|
5692
|
+
function keepSavedCopyUnlessStopped(cacheDir, fullSource, verdict) {
|
|
5693
|
+
if (verdict instanceof TarballWithheldError) throw verdict;
|
|
5694
|
+
settleForThisRun(cacheDir, verdict);
|
|
5695
|
+
return readSavedCopy(cacheDir, fullSource, verdict);
|
|
5696
|
+
}
|
|
5697
|
+
async function downloadUnlessItFails(source, fullSource, staged) {
|
|
5698
|
+
try {
|
|
5699
|
+
return await downloadStaged(source, fullSource, staged);
|
|
5700
|
+
} catch (error) {
|
|
5701
|
+
verbose(`Could not download ${fullSource}: ${getErrorMessage(error)}`);
|
|
5702
|
+
return refusalIn(error) ?? "unreachable";
|
|
5703
|
+
}
|
|
5704
|
+
}
|
|
5705
|
+
var GIGET_DOWNLOAD_REFUSED = /^Failed to download \S+: (?<status>\d{3}) (?<statusText>.*)$/;
|
|
5706
|
+
function refusalIn(error) {
|
|
5707
|
+
const answered = GIGET_DOWNLOAD_REFUSED.exec(getErrorMessage(error))?.groups;
|
|
5708
|
+
if (answered?.status === void 0 || answered.statusText === void 0) return void 0;
|
|
5709
|
+
const status = Number(answered.status);
|
|
5710
|
+
if (postureOn(status) === void 0) return void 0;
|
|
5711
|
+
return new TarballWithheldError({ status, statusText: answered.statusText });
|
|
5712
|
+
}
|
|
5713
|
+
function verdictOnFailedDownload(verdict, failure, source) {
|
|
5714
|
+
if (verdict === "unrecorded") return verdictOnUnanswered(failure, source);
|
|
5715
|
+
warn(updateNotFetchedUsingCache(source));
|
|
5716
|
+
return "outdated";
|
|
5717
|
+
}
|
|
5718
|
+
function updateNotFetchedUsingCache(source) {
|
|
5719
|
+
return `Could not fetch the update from ${source} \u2014 using the cached copy, which is out of date.`;
|
|
5720
|
+
}
|
|
5721
|
+
async function verdictOnDownload({ result, savedTarball }, source) {
|
|
5722
|
+
return savedTarball ? verdictOnSavedTarball(result, savedTarball, source) : "current";
|
|
5641
5723
|
}
|
|
5642
5724
|
async function downloadFreshCopy(cacheDir, source, fullSource) {
|
|
5643
5725
|
await ensureDir(path16.dirname(cacheDir));
|
|
5644
5726
|
try {
|
|
5645
|
-
const
|
|
5727
|
+
const download = await gigetDownload(source, fullSource, {
|
|
5646
5728
|
dir: cacheDir,
|
|
5647
5729
|
force: true,
|
|
5648
5730
|
// Always force when downloading to avoid "already exists" error
|
|
5649
5731
|
offline: false
|
|
5650
5732
|
});
|
|
5733
|
+
const { result, savedTarball } = download;
|
|
5651
5734
|
verbose(`Downloaded to: ${result.dir}`);
|
|
5652
|
-
|
|
5735
|
+
const downloaded = await verdictOnDownload(download, source);
|
|
5736
|
+
if (downloaded instanceof TarballWithheldError) {
|
|
5737
|
+
await remove(cacheDir);
|
|
5738
|
+
throw downloaded;
|
|
5739
|
+
}
|
|
5653
5740
|
await recordFetchedCopy(cacheDir, result, savedTarball);
|
|
5654
|
-
|
|
5741
|
+
settleForThisRun(cacheDir, "current");
|
|
5655
5742
|
return {
|
|
5656
5743
|
path: result.dir,
|
|
5657
5744
|
fromCache: false,
|
|
@@ -5662,25 +5749,27 @@ async function downloadFreshCopy(cacheDir, source, fullSource) {
|
|
|
5662
5749
|
throw createDetailedFetchError(error, source);
|
|
5663
5750
|
}
|
|
5664
5751
|
}
|
|
5665
|
-
async function
|
|
5752
|
+
async function verdictOnSavedTarball(result, savedTarball, source) {
|
|
5666
5753
|
const tar = tarballOf(result);
|
|
5667
|
-
if (tar === void 0) return;
|
|
5754
|
+
if (tar === void 0) return "current";
|
|
5668
5755
|
const answer = await answerAbout(tar);
|
|
5669
|
-
if (answer
|
|
5670
|
-
if (answer === "
|
|
5756
|
+
if (isUnanswered(answer)) return verdictOnUnanswered(answer, source);
|
|
5757
|
+
if (answer.etag === savedTarball.etag) return "current";
|
|
5758
|
+
warn(updateNotFetchedUsingCache(source));
|
|
5759
|
+
return "outdated";
|
|
5760
|
+
}
|
|
5761
|
+
function verdictOnUnanswered(unanswered, source) {
|
|
5762
|
+
if (unanswered === "unreachable") {
|
|
5671
5763
|
warn(sourceUnreachableUsingCache(source));
|
|
5672
|
-
return;
|
|
5673
|
-
}
|
|
5674
|
-
if (stopsTheLoad(answer)) {
|
|
5675
|
-
await remove(cacheDir);
|
|
5676
|
-
throw answer;
|
|
5764
|
+
return "unreachable";
|
|
5677
5765
|
}
|
|
5678
|
-
|
|
5766
|
+
if (stopsTheLoad(unanswered)) return unanswered;
|
|
5767
|
+
announceTheCopyKept(unanswered, source);
|
|
5768
|
+
return "refused";
|
|
5679
5769
|
}
|
|
5680
5770
|
async function answerAbout(tar) {
|
|
5681
5771
|
try {
|
|
5682
|
-
await fetchEtag(tar);
|
|
5683
|
-
return "answered";
|
|
5772
|
+
return { etag: await fetchEtag(tar) };
|
|
5684
5773
|
} catch (error) {
|
|
5685
5774
|
if (error instanceof TarballWithheldError) return error;
|
|
5686
5775
|
verbose(`Could not ask ${tar} about the tarball giget saved: ${getErrorMessage(error)}`);
|
|
@@ -5692,21 +5781,16 @@ var ONLY_A_SAVED_COPY_CAME_BACK = "the download failed and only a saved copy cam
|
|
|
5692
5781
|
var SET_ASIDE_SUFFIX = ".set-aside";
|
|
5693
5782
|
async function downloadAnsweredFor(cacheDir, source, fullSource, differingCopiesReplaced) {
|
|
5694
5783
|
const staged = `${cacheDir}${STAGED_DOWNLOAD_SUFFIX}`;
|
|
5695
|
-
const
|
|
5696
|
-
dir: staged,
|
|
5697
|
-
force: true,
|
|
5698
|
-
forceClean: true,
|
|
5699
|
-
offline: false
|
|
5700
|
-
});
|
|
5784
|
+
const download = () => downloadStaged(source, fullSource, staged);
|
|
5701
5785
|
await ensureDir(path16.dirname(cacheDir));
|
|
5702
5786
|
try {
|
|
5703
|
-
const { result, savedTarball } = await
|
|
5787
|
+
const { result, savedTarball } = await download();
|
|
5704
5788
|
const record = await askAfterTheDownload(result, source);
|
|
5705
|
-
if (savedTarball) await downloadPast(savedTarball, record,
|
|
5789
|
+
if (savedTarball) await downloadPast(savedTarball, record, download, source);
|
|
5706
5790
|
const differed = await savedCopyDiffers(cacheDir, staged);
|
|
5707
5791
|
await replaceCopy(cacheDir, staged, record);
|
|
5708
5792
|
if (differed) differingCopiesReplaced.add(source);
|
|
5709
|
-
|
|
5793
|
+
settleForThisRun(cacheDir, "current");
|
|
5710
5794
|
return { path: cacheDir, fromCache: false, unreachable: false, source: fullSource };
|
|
5711
5795
|
} catch (error) {
|
|
5712
5796
|
if (error instanceof MarketplaceUnreachableError) throw error;
|
|
@@ -5715,6 +5799,14 @@ async function downloadAnsweredFor(cacheDir, source, fullSource, differingCopies
|
|
|
5715
5799
|
await remove(staged);
|
|
5716
5800
|
}
|
|
5717
5801
|
}
|
|
5802
|
+
function downloadStaged(source, fullSource, staged) {
|
|
5803
|
+
return gigetDownload(source, fullSource, {
|
|
5804
|
+
dir: staged,
|
|
5805
|
+
force: true,
|
|
5806
|
+
forceClean: true,
|
|
5807
|
+
offline: false
|
|
5808
|
+
});
|
|
5809
|
+
}
|
|
5718
5810
|
async function downloadPast(savedTarball, record, download, source) {
|
|
5719
5811
|
if (!savedUnder(savedTarball, record)) {
|
|
5720
5812
|
throw new MarketplaceUnreachableError(source, ONLY_A_SAVED_COPY_CAME_BACK);
|
|
@@ -5761,9 +5853,12 @@ function sameBytesAt(file, left, right) {
|
|
|
5761
5853
|
return readFileSync(path16.join(left, file)).equals(readFileSync(path16.join(right, file)));
|
|
5762
5854
|
}
|
|
5763
5855
|
async function replaceCopy(cacheDir, staged, record) {
|
|
5856
|
+
await moveIntoPlace(cacheDir, staged);
|
|
5857
|
+
await writeFile(fetchRecordPath(cacheDir), JSON.stringify(record));
|
|
5858
|
+
}
|
|
5859
|
+
async function moveIntoPlace(cacheDir, staged) {
|
|
5764
5860
|
await remove(cacheDir);
|
|
5765
5861
|
await rename(staged, cacheDir);
|
|
5766
|
-
await writeFile(fetchRecordPath(cacheDir), JSON.stringify(record));
|
|
5767
5862
|
}
|
|
5768
5863
|
var GIGET_TARBALLS = "**/*.tar.gz";
|
|
5769
5864
|
var gigetTarballRecordSchema = z4.object({ etag: z4.string().min(1).optional() });
|
|
@@ -5932,7 +6027,7 @@ function savedUnder(savedTarball, record) {
|
|
|
5932
6027
|
return savedTarball.etag !== void 0 && savedTarball.etag === record.etag;
|
|
5933
6028
|
}
|
|
5934
6029
|
function keepsTheCopy(verdict) {
|
|
5935
|
-
return verdict === "current" || verdict === "unreachable" || verdict === "refused";
|
|
6030
|
+
return verdict === "current" || verdict === "unreachable" || verdict === "refused" || verdict === "outdated";
|
|
5936
6031
|
}
|
|
5937
6032
|
var REVALIDATION_TIMEOUT_MS = 5e3;
|
|
5938
6033
|
var FETCH_RECORD_SUFFIX = ".etag.json";
|
|
@@ -5954,16 +6049,12 @@ function revalidateCachedCopy(cacheDir, source) {
|
|
|
5954
6049
|
verdicts.set(cacheDir, verdict);
|
|
5955
6050
|
return verdict;
|
|
5956
6051
|
}
|
|
5957
|
-
function
|
|
5958
|
-
verdictsThisRun().set(cacheDir, Promise.resolve(
|
|
6052
|
+
function settleForThisRun(cacheDir, verdict) {
|
|
6053
|
+
verdictsThisRun().set(cacheDir, Promise.resolve(verdict));
|
|
5959
6054
|
}
|
|
5960
6055
|
async function classifyCachedCopy(cacheDir, source) {
|
|
5961
6056
|
const record = await readFetchRecord(cacheDir);
|
|
5962
6057
|
if (!record) return "unrecorded";
|
|
5963
|
-
if (record.etag === void 0 && !mustAnswer()) {
|
|
5964
|
-
verbose(`No ETag was recorded for ${record.tar} \u2014 keeping the cached copy`);
|
|
5965
|
-
return "current";
|
|
5966
|
-
}
|
|
5967
6058
|
try {
|
|
5968
6059
|
return judgeAnswer(record, await fetchEtag(record.tar));
|
|
5969
6060
|
} catch (error) {
|
|
@@ -5982,6 +6073,7 @@ function stopOrKeepTheCopy(refusal2, source) {
|
|
|
5982
6073
|
function judgeAnswer(record, live) {
|
|
5983
6074
|
if (movedOn(record, live)) return "superseded";
|
|
5984
6075
|
if (mustAnswer()) return "answered";
|
|
6076
|
+
if (record.etag === void 0 && live !== void 0) return "unstamped";
|
|
5985
6077
|
if (live === void 0) {
|
|
5986
6078
|
verbose(`${record.tar} answered without an ETag \u2014 keeping the cached copy`);
|
|
5987
6079
|
}
|
|
@@ -6366,9 +6458,9 @@ function agentNotFoundError(agentName, agents) {
|
|
|
6366
6458
|
}
|
|
6367
6459
|
function describeAvailableAgents(availableAgents) {
|
|
6368
6460
|
if (availableAgents.length === 0) return "No agents found in scanned directories";
|
|
6369
|
-
const
|
|
6461
|
+
const listed = availableAgents.slice(0, MAX_LISTED_AVAILABLE_AGENTS).join(", ");
|
|
6370
6462
|
const unlisted = availableAgents.length - MAX_LISTED_AVAILABLE_AGENTS;
|
|
6371
|
-
return unlisted > 0 ? `Available agents: ${
|
|
6463
|
+
return unlisted > 0 ? `Available agents: ${listed} (and ${unlisted} more)` : `Available agents: ${listed}`;
|
|
6372
6464
|
}
|
|
6373
6465
|
function assembleAgentConfig(agentName, definition, agentConfig, resolvedSkills) {
|
|
6374
6466
|
const model = agentConfig.model ?? definition.model;
|
|
@@ -6458,7 +6550,10 @@ async function loadSelectedStack(stackId, sourceResult) {
|
|
|
6458
6550
|
verbose(
|
|
6459
6551
|
`buildInstallConfig: loadedStack=${loadedStack ? `found (id='${loadedStack.id}')` : "NOT FOUND"}`
|
|
6460
6552
|
);
|
|
6461
|
-
if (!loadedStack)
|
|
6553
|
+
if (!loadedStack) {
|
|
6554
|
+
const shippedStackIds = sourceResult.matrix.suggestedStacks.map((stack) => stack.id);
|
|
6555
|
+
throw new Error(stackNotOfferedMessage(stackId, source, shippedStackIds));
|
|
6556
|
+
}
|
|
6462
6557
|
return loadedStack;
|
|
6463
6558
|
}
|
|
6464
6559
|
function stackToPreserve(loadedStack, curatedStack) {
|
|
@@ -6832,6 +6927,13 @@ async function claudePluginInstall(pluginPath, scope, projectDir, options) {
|
|
|
6832
6927
|
throw new Error(`Plugin installation failed: ${whyClaudeFailed(result)}`);
|
|
6833
6928
|
}
|
|
6834
6929
|
}
|
|
6930
|
+
async function claudePluginUpdate(pluginRef, scope, projectDir, options) {
|
|
6931
|
+
validatePluginName(pluginRef);
|
|
6932
|
+
const cwd = resolvePluginCwd(scope, projectDir);
|
|
6933
|
+
const args = ["plugin", "update", pluginRef, "--scope", scope];
|
|
6934
|
+
const result = await execCommand("claude", args, { cwd, ...configDirEnv(options) });
|
|
6935
|
+
if (result.exitCode !== 0) throw new Error(whyClaudeFailed(result));
|
|
6936
|
+
}
|
|
6835
6937
|
async function isClaudeCLIAvailable(options) {
|
|
6836
6938
|
try {
|
|
6837
6939
|
const result = await execCommand("claude", ["--version"], configDirEnv(options));
|
|
@@ -6948,6 +7050,7 @@ function claudeHost() {
|
|
|
6948
7050
|
addMarketplace: claudePluginMarketplaceAdd,
|
|
6949
7051
|
refreshMarketplace: claudePluginMarketplaceUpdate,
|
|
6950
7052
|
installPlugin: (pluginRef, scope, projectDir, options) => claudePluginInstall(pluginRef, toClaudePluginScope(scope), projectDir, options),
|
|
7053
|
+
updatePlugin: (pluginRef, scope, projectDir, options) => claudePluginUpdate(pluginRef, toClaudePluginScope(scope), projectDir, options),
|
|
6951
7054
|
uninstallPlugin: (pluginRef, scope, projectDir, options) => claudePluginUninstall(pluginRef, toClaudePluginScope(scope), projectDir, options),
|
|
6952
7055
|
listPlugins: claudeListPlugins
|
|
6953
7056
|
};
|
|
@@ -6957,6 +7060,87 @@ function claudeHost() {
|
|
|
6957
7060
|
import os13 from "os";
|
|
6958
7061
|
import path21 from "path";
|
|
6959
7062
|
import { z as z7 } from "zod";
|
|
7063
|
+
|
|
7064
|
+
// src/cli/lib/hosts/codex-plugin-switch.ts
|
|
7065
|
+
import { partition as partition5 } from "remeda";
|
|
7066
|
+
function sayWhichAreLeftOn(leftOn) {
|
|
7067
|
+
return leftOn.map(({ pluginKey, reason }) => `Codex left ${pluginKey} switched on: ${reason}`).join("\n");
|
|
7068
|
+
}
|
|
7069
|
+
var PluginsLeftSwitchedOnError = class extends Error {
|
|
7070
|
+
constructor(leftOn) {
|
|
7071
|
+
super(sayWhichAreLeftOn(leftOn));
|
|
7072
|
+
this.leftOn = leftOn;
|
|
7073
|
+
}
|
|
7074
|
+
leftOn;
|
|
7075
|
+
};
|
|
7076
|
+
var FailedLeavingPluginsSwitchedOnError = class extends Error {
|
|
7077
|
+
constructor(failure, leftOn) {
|
|
7078
|
+
super(`${getErrorMessage(failure)}
|
|
7079
|
+
${sayWhichAreLeftOn(leftOn)}`, { cause: failure });
|
|
7080
|
+
this.failure = failure;
|
|
7081
|
+
this.leftOn = leftOn;
|
|
7082
|
+
}
|
|
7083
|
+
failure;
|
|
7084
|
+
leftOn;
|
|
7085
|
+
};
|
|
7086
|
+
var SWITCH = /^(\s*enabled\s*=\s*)(true|false)(\s*)$/;
|
|
7087
|
+
var SWITCHED_OFF = "false";
|
|
7088
|
+
var NOT_FOUND = -1;
|
|
7089
|
+
async function switchCodexPluginsOff(configFile, pluginKeys) {
|
|
7090
|
+
if (pluginKeys.length === 0) return;
|
|
7091
|
+
const leftOn = await pluginsStillSwitchedOn(configFile, pluginKeys);
|
|
7092
|
+
if (leftOn.length > 0) throw new PluginsLeftSwitchedOnError(leftOn);
|
|
7093
|
+
}
|
|
7094
|
+
async function pluginsStillSwitchedOn(configFile, pluginKeys) {
|
|
7095
|
+
const leftOn = (pluginKey, reason) => ({ pluginKey, configFile, reason });
|
|
7096
|
+
try {
|
|
7097
|
+
const config = await readFile(configFile);
|
|
7098
|
+
const switched = withSwitchesOff(config, pluginKeys);
|
|
7099
|
+
if (switched.config !== config) await writeFile(configFile, switched.config);
|
|
7100
|
+
return switched.unfound.map(
|
|
7101
|
+
(pluginKey) => leftOn(pluginKey, notSpelledAsCodexWritesIt(pluginKey))
|
|
7102
|
+
);
|
|
7103
|
+
} catch (error) {
|
|
7104
|
+
return pluginKeys.map((pluginKey) => leftOn(pluginKey, getErrorMessage(error)));
|
|
7105
|
+
}
|
|
7106
|
+
}
|
|
7107
|
+
function withSwitchesOff(config, pluginKeys) {
|
|
7108
|
+
const lines = config.split("\n");
|
|
7109
|
+
const located = pluginKeys.map((pluginKey) => ({
|
|
7110
|
+
pluginKey,
|
|
7111
|
+
at: switchLineOf(lines, pluginKey)
|
|
7112
|
+
}));
|
|
7113
|
+
const [found, unfound] = partition5(located, ({ at }) => at !== NOT_FOUND);
|
|
7114
|
+
const toSwitch = new Set(found.map(({ at }) => at));
|
|
7115
|
+
return {
|
|
7116
|
+
config: lines.map((line2, at) => toSwitch.has(at) ? switchedOff(line2) : line2).join("\n"),
|
|
7117
|
+
unfound: unfound.map(({ pluginKey }) => pluginKey)
|
|
7118
|
+
};
|
|
7119
|
+
}
|
|
7120
|
+
function switchLineOf(lines, pluginKey) {
|
|
7121
|
+
const header = lines.findIndex((line2) => line2.trim() === pluginTableHeader(pluginKey));
|
|
7122
|
+
if (header === NOT_FOUND) return NOT_FOUND;
|
|
7123
|
+
const end = endOfTable(lines, header);
|
|
7124
|
+
return lines.findIndex((line2, at) => at > header && at < end && SWITCH.test(line2));
|
|
7125
|
+
}
|
|
7126
|
+
function endOfTable(lines, header) {
|
|
7127
|
+
const nextTable = lines.findIndex((line2, at) => at > header && opensATable(line2));
|
|
7128
|
+
return nextTable === NOT_FOUND ? lines.length : nextTable;
|
|
7129
|
+
}
|
|
7130
|
+
function switchedOff(line2) {
|
|
7131
|
+
return line2.replace(SWITCH, `$1${SWITCHED_OFF}$3`);
|
|
7132
|
+
}
|
|
7133
|
+
function opensATable(line2) {
|
|
7134
|
+
return line2.trim().startsWith("[");
|
|
7135
|
+
}
|
|
7136
|
+
function pluginTableHeader(pluginKey) {
|
|
7137
|
+
return `[plugins."${pluginKey}"]`;
|
|
7138
|
+
}
|
|
7139
|
+
function notSpelledAsCodexWritesIt(pluginKey) {
|
|
7140
|
+
return `it has no ${pluginTableHeader(pluginKey)} table with an 'enabled' line`;
|
|
7141
|
+
}
|
|
7142
|
+
|
|
7143
|
+
// src/cli/lib/hosts/codex-host.ts
|
|
6960
7144
|
var CODEX = "codex";
|
|
6961
7145
|
var PLUGIN_CACHE_SUBDIR = "cache";
|
|
6962
7146
|
var STANDING_WARNING = /could not create PATH aliases/;
|
|
@@ -7113,23 +7297,56 @@ async function upgradeGitMarketplace(name, options) {
|
|
|
7113
7297
|
);
|
|
7114
7298
|
}
|
|
7115
7299
|
async function reinstallEachPluginOf(name, options) {
|
|
7116
|
-
const
|
|
7117
|
-
|
|
7118
|
-
|
|
7300
|
+
const ofTheMarketplace = (await codexPluginListing(options, codexPluginCwd())).filter(
|
|
7301
|
+
(plugin) => plugin.marketplaceName === name
|
|
7302
|
+
);
|
|
7303
|
+
for (const [at, plugin] of ofTheMarketplace.entries()) {
|
|
7304
|
+
try {
|
|
7305
|
+
await installCodexPlugin(plugin.pluginId, options);
|
|
7306
|
+
} catch (refusal2) {
|
|
7307
|
+
await switchBackOffThenRethrow(refusal2, ofTheMarketplace.slice(0, at), options);
|
|
7308
|
+
}
|
|
7309
|
+
}
|
|
7310
|
+
await switchBackOff(ofTheMarketplace, options);
|
|
7311
|
+
}
|
|
7312
|
+
async function switchBackOffThenRethrow(refusal2, added, options) {
|
|
7313
|
+
try {
|
|
7314
|
+
await switchBackOff(added, options);
|
|
7315
|
+
} catch (error) {
|
|
7316
|
+
if (!(error instanceof PluginsLeftSwitchedOnError)) throw error;
|
|
7317
|
+
throw new FailedLeavingPluginsSwitchedOnError(refusal2, error.leftOn);
|
|
7119
7318
|
}
|
|
7319
|
+
throw refusal2;
|
|
7320
|
+
}
|
|
7321
|
+
async function switchBackOff(heldBefore, options) {
|
|
7322
|
+
await switchCodexPluginsOff(
|
|
7323
|
+
codexConfigFile(options),
|
|
7324
|
+
heldBefore.filter((plugin) => !plugin.enabled).map((plugin) => plugin.pluginId)
|
|
7325
|
+
);
|
|
7326
|
+
}
|
|
7327
|
+
function codexConfigFile(options) {
|
|
7328
|
+
return path21.join(codexStateRoot(options, codexPluginCwd()), CODEX_CONFIG_FILE);
|
|
7120
7329
|
}
|
|
7121
7330
|
async function codexInstallPlugin(pluginRef, _scope, _projectDir, options) {
|
|
7122
7331
|
await installCodexPlugin(pluginRef, options);
|
|
7123
7332
|
}
|
|
7124
|
-
async function installCodexPlugin(pluginRef, options) {
|
|
7333
|
+
async function installCodexPlugin(pluginRef, options, attempt = "install") {
|
|
7125
7334
|
validatePluginPath(pluginRef);
|
|
7126
7335
|
await runCodexOrThrow(
|
|
7127
7336
|
["plugin", "add", pluginRef, "--json"],
|
|
7128
7337
|
options,
|
|
7129
|
-
|
|
7338
|
+
`${attempt} ${pluginRef}`,
|
|
7130
7339
|
codexPluginCwd()
|
|
7131
7340
|
);
|
|
7132
7341
|
}
|
|
7342
|
+
async function codexUpdatePlugin(pluginRef, _scope, _projectDir, options) {
|
|
7343
|
+
const held = await heldPlugin(pluginRef, options);
|
|
7344
|
+
if (held === void 0) {
|
|
7345
|
+
throw new Error(`Failed to update ${pluginRef}: codex has not installed it`);
|
|
7346
|
+
}
|
|
7347
|
+
await installCodexPlugin(pluginRef, options, "update");
|
|
7348
|
+
await switchBackOff([held], options);
|
|
7349
|
+
}
|
|
7133
7350
|
async function codexUninstallPlugin(pluginRef, _scope, _projectDir, options) {
|
|
7134
7351
|
validatePluginName(pluginRef);
|
|
7135
7352
|
const wasInstalled = await isListed(pluginRef, options);
|
|
@@ -7147,8 +7364,11 @@ async function codexUninstallPlugin(pluginRef, _scope, _projectDir, options) {
|
|
|
7147
7364
|
return wasInstalled ? "removed" : "absent";
|
|
7148
7365
|
}
|
|
7149
7366
|
async function isListed(pluginRef, options) {
|
|
7367
|
+
return await heldPlugin(pluginRef, options) !== void 0;
|
|
7368
|
+
}
|
|
7369
|
+
async function heldPlugin(pluginRef, options) {
|
|
7150
7370
|
const installed = await codexPluginListing(options, codexPluginCwd());
|
|
7151
|
-
return installed.
|
|
7371
|
+
return installed.find((plugin) => plugin.pluginId === pluginRef);
|
|
7152
7372
|
}
|
|
7153
7373
|
async function codexPluginListing(options, askedFrom) {
|
|
7154
7374
|
const listing = await readJsonFromCodex(
|
|
@@ -7196,6 +7416,7 @@ function codexHost() {
|
|
|
7196
7416
|
addMarketplace: codexMarketplaceAdd,
|
|
7197
7417
|
refreshMarketplace: refreshCodexMarketplace,
|
|
7198
7418
|
installPlugin: codexInstallPlugin,
|
|
7419
|
+
updatePlugin: codexUpdatePlugin,
|
|
7199
7420
|
uninstallPlugin: codexUninstallPlugin,
|
|
7200
7421
|
listPlugins: codexListPlugins
|
|
7201
7422
|
};
|
|
@@ -8179,10 +8400,18 @@ async function loadSkillCategories(configPath) {
|
|
|
8179
8400
|
verbose(`Loaded skill categories: ${configPath}`);
|
|
8180
8401
|
return data.categories;
|
|
8181
8402
|
}
|
|
8403
|
+
var NoSkillRulesError = class extends Error {
|
|
8404
|
+
constructor(configPath) {
|
|
8405
|
+
super(`Invalid skill rules at '${configPath}': failed to load or validate`);
|
|
8406
|
+
this.configPath = configPath;
|
|
8407
|
+
this.name = "NoSkillRulesError";
|
|
8408
|
+
}
|
|
8409
|
+
configPath;
|
|
8410
|
+
};
|
|
8182
8411
|
async function loadSkillRules(configPath) {
|
|
8183
8412
|
const data = await loadConfig(configPath, skillRulesFileSchema);
|
|
8184
8413
|
if (!data) {
|
|
8185
|
-
throw new
|
|
8414
|
+
throw new NoSkillRulesError(configPath);
|
|
8186
8415
|
}
|
|
8187
8416
|
const config = {
|
|
8188
8417
|
version: data.version,
|
|
@@ -10161,11 +10390,16 @@ async function loadCatalogue(options) {
|
|
|
10161
10390
|
devMode = false,
|
|
10162
10391
|
matrixOnly = false
|
|
10163
10392
|
} = options;
|
|
10164
|
-
const
|
|
10393
|
+
const resolvedProjectDir = projectDir || process.cwd();
|
|
10394
|
+
const sourceConfig = await resolveSource({
|
|
10395
|
+
caller,
|
|
10396
|
+
flag: sourceFlag,
|
|
10397
|
+
projectDir: resolvedProjectDir,
|
|
10398
|
+
provider
|
|
10399
|
+
});
|
|
10165
10400
|
const { source } = sourceConfig;
|
|
10166
10401
|
verbose(`Loading skills from source: ${source}`);
|
|
10167
10402
|
const catalogue = await resolveBaseResult(sourceConfig, { purpose, devMode, matrixOnly });
|
|
10168
|
-
const resolvedProjectDir = projectDir || process.cwd();
|
|
10169
10403
|
const result = {
|
|
10170
10404
|
...catalogue,
|
|
10171
10405
|
marketplaceSkillIds: new Set(typedKeys(catalogue.matrix.skills)),
|
|
@@ -10457,11 +10691,11 @@ async function refuseCatalogueCollisions(basePath, source, skills) {
|
|
|
10457
10691
|
throw new Error(catalogueCollisionError(collidingIds, source));
|
|
10458
10692
|
}
|
|
10459
10693
|
function catalogueCollisionError(collidingIds, source) {
|
|
10460
|
-
const
|
|
10461
|
-
const unlisted = collidingIds.length -
|
|
10694
|
+
const listed = collidingIds.slice(0, MAX_REPORTED_COLLISIONS).map((id) => ` ${id}`);
|
|
10695
|
+
const unlisted = collidingIds.length - listed.length;
|
|
10462
10696
|
return [
|
|
10463
10697
|
`Marketplace '${source}' ships ${collidingIds.length} skill id(s) the public catalogue already owns:`,
|
|
10464
|
-
...
|
|
10698
|
+
...listed,
|
|
10465
10699
|
...unlisted > 0 ? [` ... and ${unlisted} more`] : [],
|
|
10466
10700
|
`A skill id is the directory the skill installs into, so these would shadow the public catalogue's own skills. Every id must carry its marketplace's name as a namespace \u2014 '<marketplace>-<id>'. Rename each skill and the 'name' in its SKILL.md, then re-run 'build marketplace', which refuses the same ids before they are published.`
|
|
10467
10701
|
].join("\n");
|
|
@@ -10501,7 +10735,7 @@ function convertStackToResolvedStack(stack, catalogue) {
|
|
|
10501
10735
|
if (undeclared.length > 0) warn(undeclaredAgentsWarning(stack, undeclared));
|
|
10502
10736
|
const isCarried = carriedBy(catalogue);
|
|
10503
10737
|
const agentConfigs = agentConfigsFor(stack, declared);
|
|
10504
|
-
const [allSkillIds, withdrawn] =
|
|
10738
|
+
const [allSkillIds, withdrawn] = partition6(namedSkillIds(agentConfigs), isCarried);
|
|
10505
10739
|
if (withdrawn.length > 0) warn(withdrawnSkillsWarning(stack, withdrawn));
|
|
10506
10740
|
verbose(
|
|
10507
10741
|
`Stack '${stack.id}' has ${allSkillIds.length} skills from ${agentConfigs.length} agents`
|
|
@@ -10551,7 +10785,10 @@ function declaresCategory(matrix2, category) {
|
|
|
10551
10785
|
return category !== LOCAL_PSEUDO_CATEGORY && matrix2.categories[category] !== void 0;
|
|
10552
10786
|
}
|
|
10553
10787
|
function undeclaredCategoryRefusal(metadata, category) {
|
|
10554
|
-
|
|
10788
|
+
if (metadata.localPath === void 0) {
|
|
10789
|
+
throw new Error(`Local skill '${metadata.id}' was discovered without its directory`);
|
|
10790
|
+
}
|
|
10791
|
+
const metadataPath = path28.join(metadata.localPath, STANDARD_FILES.METADATA_YAML);
|
|
10555
10792
|
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.`;
|
|
10556
10793
|
}
|
|
10557
10794
|
function mergeLocalSkillsIntoMatrix(matrix2, localResult) {
|
|
@@ -10628,6 +10865,7 @@ export {
|
|
|
10628
10865
|
rootsHoldingTheRetiredSourceFolder,
|
|
10629
10866
|
chooseProviderForThisRun,
|
|
10630
10867
|
forgetTheProviderChosenForThisRun,
|
|
10868
|
+
declaresNoContent,
|
|
10631
10869
|
providerInUse,
|
|
10632
10870
|
inheritedGlobalProvider,
|
|
10633
10871
|
providerAtScope,
|
|
@@ -10663,9 +10901,10 @@ export {
|
|
|
10663
10901
|
skillAssignedToNoAgent,
|
|
10664
10902
|
scopeBlockedStackAssignment,
|
|
10665
10903
|
globalScopedAgentsHint,
|
|
10666
|
-
marketplacesRefreshed,
|
|
10667
10904
|
marketplaceRefreshFailed,
|
|
10668
10905
|
marketplacesRefreshFailed,
|
|
10906
|
+
codexPluginLeftSwitchedOn,
|
|
10907
|
+
pluginsLeftSwitchedOn,
|
|
10669
10908
|
marketplaceOwnerHasNoName,
|
|
10670
10909
|
marketplaceHasNoVersion,
|
|
10671
10910
|
marketplaceNameNotPublishable,
|
|
@@ -10690,7 +10929,10 @@ export {
|
|
|
10690
10929
|
skippedSkills,
|
|
10691
10930
|
skippedUnknownAgents,
|
|
10692
10931
|
carriedSkillsWritten,
|
|
10932
|
+
copiedSkillsRemovedAfterRefusedSave,
|
|
10933
|
+
carriedSkillsRemovedAfterRefusedSave,
|
|
10693
10934
|
SHARED_CONFIG_APPLY,
|
|
10935
|
+
idNamesAnotherMarketplace,
|
|
10694
10936
|
registeredProjectsRecompiled,
|
|
10695
10937
|
sharedConfigNeedsTerminal,
|
|
10696
10938
|
nothingInstalledToApplyTo,
|
|
@@ -10748,7 +10990,9 @@ export {
|
|
|
10748
10990
|
formatZodIssues,
|
|
10749
10991
|
validateSkillMetadata,
|
|
10750
10992
|
splitMetadataValidationIssues,
|
|
10993
|
+
ConfigSchemaError,
|
|
10751
10994
|
ConfigDefaultExportError,
|
|
10995
|
+
ConfigEvaluationError,
|
|
10752
10996
|
NO_VALID_DEFAULT_EXPORT,
|
|
10753
10997
|
configLoadFailure,
|
|
10754
10998
|
loadConfig,
|
|
@@ -10767,12 +11011,13 @@ export {
|
|
|
10767
11011
|
MarketplaceRefusedError,
|
|
10768
11012
|
isLocalSource,
|
|
10769
11013
|
normalizeStackRecord,
|
|
11014
|
+
StacksLoadError,
|
|
10770
11015
|
loadStackById,
|
|
10771
11016
|
defaultUsageGuidance,
|
|
10772
11017
|
resolveAgentConfigToSkills,
|
|
10773
11018
|
getStackSkillIds,
|
|
10774
11019
|
ConfigLoadError,
|
|
10775
|
-
|
|
11020
|
+
configDeclaresNothing,
|
|
10776
11021
|
loadProjectConfigFromDir,
|
|
10777
11022
|
loadProjectConfigAt,
|
|
10778
11023
|
loadInstalledConfig,
|
|
@@ -10851,6 +11096,8 @@ export {
|
|
|
10851
11096
|
execCommand,
|
|
10852
11097
|
getInstalledPluginsRegistryPath,
|
|
10853
11098
|
listRegisteredPluginInstalls,
|
|
11099
|
+
PluginsLeftSwitchedOnError,
|
|
11100
|
+
FailedLeavingPluginsSwitchedOnError,
|
|
10854
11101
|
refuseUnofferedPlacements,
|
|
10855
11102
|
hostFor,
|
|
10856
11103
|
hostAt,
|
|
@@ -10863,6 +11110,7 @@ export {
|
|
|
10863
11110
|
findUnusableSavedSkillMetadata,
|
|
10864
11111
|
deleteLocalSkill,
|
|
10865
11112
|
migrateLocalSkillScope,
|
|
11113
|
+
NoSkillRulesError,
|
|
10866
11114
|
claimSlug,
|
|
10867
11115
|
matrixHealthIssues,
|
|
10868
11116
|
generateMarketplace,
|
|
@@ -10898,4 +11146,4 @@ export {
|
|
|
10898
11146
|
executeMigration,
|
|
10899
11147
|
keepsGlobalInstall
|
|
10900
11148
|
};
|
|
10901
|
-
//# sourceMappingURL=chunk-
|
|
11149
|
+
//# sourceMappingURL=chunk-ENET4IF6.js.map
|