ali-skills 0.0.23 → 0.0.25
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.
|
@@ -916,29 +916,32 @@ const agents = {
|
|
|
916
916
|
return existsSync(claudeHome);
|
|
917
917
|
}
|
|
918
918
|
},
|
|
919
|
+
codex: {
|
|
920
|
+
name: "codex",
|
|
921
|
+
displayName: "Codex",
|
|
922
|
+
skillsDir: ".codex/skills",
|
|
923
|
+
globalSkillsDir: join(codexHome, "skills"),
|
|
924
|
+
supportsSharedAgentsDir: true,
|
|
925
|
+
detectInstalled: async () => {
|
|
926
|
+
return existsSync(codexHome) || existsSync("/etc/codex");
|
|
927
|
+
}
|
|
928
|
+
},
|
|
919
929
|
cursor: {
|
|
920
930
|
name: "cursor",
|
|
921
931
|
displayName: "Cursor",
|
|
922
|
-
skillsDir: ".
|
|
932
|
+
skillsDir: ".cursor/skills",
|
|
923
933
|
globalSkillsDir: join(home, ".cursor/skills"),
|
|
934
|
+
supportsSharedAgentsDir: true,
|
|
924
935
|
detectInstalled: async () => {
|
|
925
936
|
return existsSync(join(home, ".cursor"));
|
|
926
937
|
}
|
|
927
938
|
},
|
|
928
|
-
"aone-copilot": {
|
|
929
|
-
name: "aone-copilot",
|
|
930
|
-
displayName: "Aone Copilot",
|
|
931
|
-
skillsDir: ".agents/skills",
|
|
932
|
-
globalSkillsDir: join(configHome, "agents/skills"),
|
|
933
|
-
detectInstalled: async () => {
|
|
934
|
-
return existsSync(join(home, ".aone-copilot"));
|
|
935
|
-
}
|
|
936
|
-
},
|
|
937
939
|
qoder: {
|
|
938
940
|
name: "qoder",
|
|
939
941
|
displayName: "Qoder",
|
|
940
|
-
skillsDir: ".
|
|
941
|
-
globalSkillsDir: join(home, ".
|
|
942
|
+
skillsDir: ".qoder/skills",
|
|
943
|
+
globalSkillsDir: join(home, ".qoder/skills"),
|
|
944
|
+
supportsSharedAgentsDir: true,
|
|
942
945
|
detectInstalled: async () => {
|
|
943
946
|
return existsSync(join(home, ".qoder"));
|
|
944
947
|
}
|
|
@@ -952,94 +955,90 @@ const agents = {
|
|
|
952
955
|
return existsSync(join(home, ".qoderwork"));
|
|
953
956
|
}
|
|
954
957
|
},
|
|
955
|
-
|
|
956
|
-
name: "
|
|
957
|
-
displayName: "
|
|
958
|
-
skillsDir: "
|
|
959
|
-
globalSkillsDir:
|
|
958
|
+
openclaw: {
|
|
959
|
+
name: "openclaw",
|
|
960
|
+
displayName: "OpenClaw",
|
|
961
|
+
skillsDir: "skills",
|
|
962
|
+
globalSkillsDir: getOpenClawGlobalSkillsDir(),
|
|
960
963
|
detectInstalled: async () => {
|
|
961
|
-
return existsSync(join(home, ".
|
|
964
|
+
return existsSync(join(home, ".openclaw")) || existsSync(join(home, ".clawdbot")) || existsSync(join(home, ".moltbot"));
|
|
962
965
|
}
|
|
963
966
|
},
|
|
964
|
-
"
|
|
965
|
-
name: "
|
|
966
|
-
displayName: "
|
|
967
|
-
skillsDir: ".
|
|
968
|
-
globalSkillsDir: join(home, ".
|
|
967
|
+
"aone-copilot": {
|
|
968
|
+
name: "aone-copilot",
|
|
969
|
+
displayName: "Aone Copilot",
|
|
970
|
+
skillsDir: ".aone_copilot/skills",
|
|
971
|
+
globalSkillsDir: join(home, ".aone_copilot/skills"),
|
|
972
|
+
supportsSharedAgentsDir: true,
|
|
969
973
|
detectInstalled: async () => {
|
|
970
|
-
return existsSync(join(home, ".
|
|
974
|
+
return existsSync(join(home, ".aone-copilot"));
|
|
971
975
|
}
|
|
972
976
|
},
|
|
973
977
|
"github-copilot": {
|
|
974
978
|
name: "github-copilot",
|
|
975
979
|
displayName: "GitHub Copilot",
|
|
976
|
-
skillsDir: ".
|
|
980
|
+
skillsDir: ".github/skills",
|
|
977
981
|
globalSkillsDir: join(home, ".copilot/skills"),
|
|
982
|
+
supportsSharedAgentsDir: true,
|
|
978
983
|
detectInstalled: async () => {
|
|
979
984
|
return existsSync(join(home, ".copilot"));
|
|
980
985
|
}
|
|
981
986
|
},
|
|
982
|
-
codex: {
|
|
983
|
-
name: "codex",
|
|
984
|
-
displayName: "Codex",
|
|
985
|
-
skillsDir: ".agents/skills",
|
|
986
|
-
globalSkillsDir: join(codexHome, "skills"),
|
|
987
|
-
detectInstalled: async () => {
|
|
988
|
-
return existsSync(codexHome) || existsSync("/etc/codex");
|
|
989
|
-
}
|
|
990
|
-
},
|
|
991
987
|
opencode: {
|
|
992
988
|
name: "opencode",
|
|
993
989
|
displayName: "OpenCode",
|
|
994
|
-
skillsDir: ".
|
|
990
|
+
skillsDir: ".opencode/skills",
|
|
995
991
|
globalSkillsDir: join(configHome, "opencode/skills"),
|
|
992
|
+
supportsSharedAgentsDir: true,
|
|
996
993
|
detectInstalled: async () => {
|
|
997
994
|
return existsSync(join(configHome, "opencode"));
|
|
998
995
|
}
|
|
999
996
|
},
|
|
1000
|
-
openclaw: {
|
|
1001
|
-
name: "openclaw",
|
|
1002
|
-
displayName: "OpenClaw",
|
|
1003
|
-
skillsDir: "skills",
|
|
1004
|
-
globalSkillsDir: getOpenClawGlobalSkillsDir(),
|
|
1005
|
-
detectInstalled: async () => {
|
|
1006
|
-
return existsSync(join(home, ".openclaw")) || existsSync(join(home, ".clawdbot")) || existsSync(join(home, ".moltbot"));
|
|
1007
|
-
}
|
|
1008
|
-
},
|
|
1009
997
|
"gemini-cli": {
|
|
1010
998
|
name: "gemini-cli",
|
|
1011
999
|
displayName: "Gemini CLI",
|
|
1012
|
-
skillsDir: ".
|
|
1000
|
+
skillsDir: ".gemini/skills",
|
|
1013
1001
|
globalSkillsDir: join(home, ".gemini/skills"),
|
|
1002
|
+
supportsSharedAgentsDir: true,
|
|
1014
1003
|
detectInstalled: async () => {
|
|
1015
1004
|
return existsSync(join(home, ".gemini"));
|
|
1016
1005
|
}
|
|
1017
1006
|
},
|
|
1018
|
-
|
|
1019
|
-
name: "
|
|
1020
|
-
displayName: "
|
|
1021
|
-
skillsDir: ".
|
|
1022
|
-
globalSkillsDir: join(home, ".
|
|
1007
|
+
"qwen-code": {
|
|
1008
|
+
name: "qwen-code",
|
|
1009
|
+
displayName: "Qwen Code",
|
|
1010
|
+
skillsDir: ".qwen/skills",
|
|
1011
|
+
globalSkillsDir: join(home, ".qwen/skills"),
|
|
1023
1012
|
detectInstalled: async () => {
|
|
1024
|
-
return existsSync(join(home, ".
|
|
1013
|
+
return existsSync(join(home, ".qwen"));
|
|
1025
1014
|
}
|
|
1026
1015
|
},
|
|
1027
|
-
|
|
1028
|
-
name: "
|
|
1029
|
-
displayName: "
|
|
1030
|
-
skillsDir: ".
|
|
1031
|
-
globalSkillsDir: join(home, ".
|
|
1016
|
+
"kimi-cli": {
|
|
1017
|
+
name: "kimi-cli",
|
|
1018
|
+
displayName: "Kimi Code CLI",
|
|
1019
|
+
skillsDir: ".kimi/skills",
|
|
1020
|
+
globalSkillsDir: join(home, ".kimi/skills"),
|
|
1021
|
+
supportsSharedAgentsDir: true,
|
|
1032
1022
|
detectInstalled: async () => {
|
|
1033
|
-
return existsSync(join(home, ".
|
|
1023
|
+
return existsSync(join(home, ".kimi"));
|
|
1034
1024
|
}
|
|
1035
1025
|
},
|
|
1036
|
-
|
|
1037
|
-
name: "
|
|
1038
|
-
displayName: "
|
|
1039
|
-
skillsDir: ".
|
|
1040
|
-
globalSkillsDir: join(home, ".
|
|
1026
|
+
"iflow-cli": {
|
|
1027
|
+
name: "iflow-cli",
|
|
1028
|
+
displayName: "iFlow CLI",
|
|
1029
|
+
skillsDir: ".iflow/skills",
|
|
1030
|
+
globalSkillsDir: join(home, ".iflow/skills"),
|
|
1041
1031
|
detectInstalled: async () => {
|
|
1042
|
-
return existsSync(join(
|
|
1032
|
+
return existsSync(join(home, ".iflow"));
|
|
1033
|
+
}
|
|
1034
|
+
},
|
|
1035
|
+
antigravity: {
|
|
1036
|
+
name: "antigravity",
|
|
1037
|
+
displayName: "Antigravity",
|
|
1038
|
+
skillsDir: ".agent/skills",
|
|
1039
|
+
globalSkillsDir: join(home, ".gemini/antigravity/skills"),
|
|
1040
|
+
detectInstalled: async () => {
|
|
1041
|
+
return existsSync(join(home, ".gemini/antigravity"));
|
|
1043
1042
|
}
|
|
1044
1043
|
},
|
|
1045
1044
|
"kiro-cli": {
|
|
@@ -1060,13 +1059,23 @@ const agents = {
|
|
|
1060
1059
|
return existsSync(join(home, ".codeium/windsurf"));
|
|
1061
1060
|
}
|
|
1062
1061
|
},
|
|
1063
|
-
|
|
1064
|
-
name: "
|
|
1065
|
-
displayName: "
|
|
1066
|
-
skillsDir: ".
|
|
1067
|
-
globalSkillsDir: join(home, ".
|
|
1062
|
+
cline: {
|
|
1063
|
+
name: "cline",
|
|
1064
|
+
displayName: "Cline",
|
|
1065
|
+
skillsDir: ".cline/skills",
|
|
1066
|
+
globalSkillsDir: join(home, ".cline", "skills"),
|
|
1067
|
+
supportsSharedAgentsDir: true,
|
|
1068
1068
|
detectInstalled: async () => {
|
|
1069
|
-
return existsSync(join(home, ".
|
|
1069
|
+
return existsSync(join(home, ".cline"));
|
|
1070
|
+
}
|
|
1071
|
+
},
|
|
1072
|
+
continue: {
|
|
1073
|
+
name: "continue",
|
|
1074
|
+
displayName: "Continue",
|
|
1075
|
+
skillsDir: ".continue/skills",
|
|
1076
|
+
globalSkillsDir: join(home, ".continue/skills"),
|
|
1077
|
+
detectInstalled: async () => {
|
|
1078
|
+
return existsSync(join(process.cwd(), ".continue")) || existsSync(join(home, ".continue"));
|
|
1070
1079
|
}
|
|
1071
1080
|
},
|
|
1072
1081
|
trae: {
|
|
@@ -1099,8 +1108,9 @@ const agents = {
|
|
|
1099
1108
|
warp: {
|
|
1100
1109
|
name: "warp",
|
|
1101
1110
|
displayName: "Warp",
|
|
1102
|
-
skillsDir: ".
|
|
1103
|
-
globalSkillsDir: join(home, ".
|
|
1111
|
+
skillsDir: ".warp/skills",
|
|
1112
|
+
globalSkillsDir: join(home, ".warp/skills"),
|
|
1113
|
+
supportsSharedAgentsDir: true,
|
|
1104
1114
|
detectInstalled: async () => {
|
|
1105
1115
|
return existsSync(join(home, ".warp"));
|
|
1106
1116
|
}
|
|
@@ -1128,6 +1138,7 @@ const agents = {
|
|
|
1128
1138
|
displayName: "Amp",
|
|
1129
1139
|
skillsDir: ".agents/skills",
|
|
1130
1140
|
globalSkillsDir: join(configHome, "agents/skills"),
|
|
1141
|
+
supportsSharedAgentsDir: true,
|
|
1131
1142
|
detectInstalled: async () => {
|
|
1132
1143
|
return existsSync(join(configHome, "amp"));
|
|
1133
1144
|
}
|
|
@@ -1272,6 +1283,7 @@ const agents = {
|
|
|
1272
1283
|
displayName: "Replit",
|
|
1273
1284
|
skillsDir: ".agents/skills",
|
|
1274
1285
|
globalSkillsDir: join(configHome, "agents/skills"),
|
|
1286
|
+
supportsSharedAgentsDir: true,
|
|
1275
1287
|
showInUniversalList: false,
|
|
1276
1288
|
detectInstalled: async () => {
|
|
1277
1289
|
return existsSync(join(process.cwd(), ".replit"));
|
|
@@ -1300,6 +1312,7 @@ const agents = {
|
|
|
1300
1312
|
displayName: "Universal",
|
|
1301
1313
|
skillsDir: ".agents/skills",
|
|
1302
1314
|
globalSkillsDir: join(configHome, "agents/skills"),
|
|
1315
|
+
supportsSharedAgentsDir: true,
|
|
1303
1316
|
showInUniversalList: false,
|
|
1304
1317
|
detectInstalled: async () => false
|
|
1305
1318
|
}
|
|
@@ -1311,18 +1324,18 @@ async function detectInstalledAgents() {
|
|
|
1311
1324
|
})))).filter((r) => r.installed).map((r) => r.type);
|
|
1312
1325
|
}
|
|
1313
1326
|
function getUniversalAgents() {
|
|
1314
|
-
return Object.entries(agents).filter(([
|
|
1327
|
+
return Object.entries(agents).filter(([, config]) => config.supportsSharedAgentsDir === true && config.showInUniversalList !== false).map(([type]) => type);
|
|
1315
1328
|
}
|
|
1316
1329
|
function getNonUniversalAgents() {
|
|
1317
|
-
return Object.entries(agents).filter(([
|
|
1330
|
+
return Object.entries(agents).filter(([, config]) => config.supportsSharedAgentsDir !== true).map(([type]) => type);
|
|
1318
1331
|
}
|
|
1319
1332
|
function isUniversalAgent(type) {
|
|
1320
|
-
return agents[type].
|
|
1333
|
+
return agents[type].supportsSharedAgentsDir === true;
|
|
1321
1334
|
}
|
|
1322
1335
|
const AGENTS_DIR$2 = ".agents";
|
|
1323
1336
|
const SKILLS_SUBDIR = "skills";
|
|
1324
1337
|
function sanitizeName(name) {
|
|
1325
|
-
return name.toLowerCase().replace(/[^a-z0-9._]+/g, "-").replace(/^[
|
|
1338
|
+
return name.toLowerCase().replace(/[^a-z0-9._]+/g, "-").replace(/^[.-]+|[.-]+$/g, "").substring(0, 255) || "unnamed-skill";
|
|
1326
1339
|
}
|
|
1327
1340
|
function isPathSafe(basePath, targetPath) {
|
|
1328
1341
|
const normalizedBase = normalize(resolve(basePath));
|
|
@@ -1332,6 +1345,27 @@ function isPathSafe(basePath, targetPath) {
|
|
|
1332
1345
|
function getCanonicalSkillsDir(global, cwd) {
|
|
1333
1346
|
return join(global ? homedir() : cwd || process.cwd(), AGENTS_DIR$2, SKILLS_SUBDIR);
|
|
1334
1347
|
}
|
|
1348
|
+
function isSharedDir(path) {
|
|
1349
|
+
return path === ".agents/skills" || path === "agents/skills";
|
|
1350
|
+
}
|
|
1351
|
+
function hasPrivateSkillsDir(agentType, global) {
|
|
1352
|
+
const agent = agents[agentType];
|
|
1353
|
+
if (global) {
|
|
1354
|
+
if (!agent.globalSkillsDir) return false;
|
|
1355
|
+
return !agent.globalSkillsDir.endsWith("/.agents/skills") && !agent.globalSkillsDir.endsWith("/agents/skills");
|
|
1356
|
+
}
|
|
1357
|
+
return !isSharedDir(agent.skillsDir);
|
|
1358
|
+
}
|
|
1359
|
+
function getIsolatedStoreBase(global, cwd) {
|
|
1360
|
+
return join(global ? homedir() : cwd || process.cwd(), ".skills-store", SKILLS_SUBDIR);
|
|
1361
|
+
}
|
|
1362
|
+
function getIsolatedStorePath(skillName, options = {}) {
|
|
1363
|
+
const sanitized = sanitizeName(skillName);
|
|
1364
|
+
const storeBase = getIsolatedStoreBase(options.global ?? false, options.cwd);
|
|
1365
|
+
const storePath = join(storeBase, sanitized);
|
|
1366
|
+
if (!isPathSafe(storeBase, storePath)) throw new Error("Invalid skill name: potential path traversal detected");
|
|
1367
|
+
return storePath;
|
|
1368
|
+
}
|
|
1335
1369
|
function getAgentBaseDir(agentType, global, cwd) {
|
|
1336
1370
|
if (isUniversalAgent(agentType)) return getCanonicalSkillsDir(global, cwd);
|
|
1337
1371
|
const agent = agents[agentType];
|
|
@@ -1342,6 +1376,17 @@ function getAgentBaseDir(agentType, global, cwd) {
|
|
|
1342
1376
|
}
|
|
1343
1377
|
return join(baseDir, agent.skillsDir);
|
|
1344
1378
|
}
|
|
1379
|
+
function getAgentPrivateBaseDir(agentType, global, cwd) {
|
|
1380
|
+
const agent = agents[agentType];
|
|
1381
|
+
const baseDir = global ? homedir() : cwd || process.cwd();
|
|
1382
|
+
if (global) {
|
|
1383
|
+
if (!agent.globalSkillsDir) return getCanonicalSkillsDir(global, cwd);
|
|
1384
|
+
if (hasPrivateSkillsDir(agentType, true)) return agent.globalSkillsDir;
|
|
1385
|
+
return getCanonicalSkillsDir(global, cwd);
|
|
1386
|
+
}
|
|
1387
|
+
if (hasPrivateSkillsDir(agentType, false)) return join(baseDir, agent.skillsDir);
|
|
1388
|
+
return getCanonicalSkillsDir(global, cwd);
|
|
1389
|
+
}
|
|
1345
1390
|
function resolveSymlinkTarget(linkPath, linkTarget) {
|
|
1346
1391
|
return resolve(dirname(linkPath), linkTarget);
|
|
1347
1392
|
}
|
|
@@ -1402,9 +1447,11 @@ async function installSkillForAgent(skill, agentType, options = {}) {
|
|
|
1402
1447
|
const skillName = sanitizeName(skill.name || basename(skill.path));
|
|
1403
1448
|
const canonicalBase = getCanonicalSkillsDir(isGlobal, cwd);
|
|
1404
1449
|
const canonicalDir = join(canonicalBase, skillName);
|
|
1405
|
-
const
|
|
1406
|
-
const
|
|
1450
|
+
const isolatedStoreBase = getIsolatedStoreBase(isGlobal, cwd);
|
|
1451
|
+
const isolatedStoreDir = join(isolatedStoreBase, skillName);
|
|
1407
1452
|
const installMode = options.mode ?? "symlink";
|
|
1453
|
+
const agentBase = installMode === "symlink-isolated" || installMode === "copy-isolated" ? getAgentPrivateBaseDir(agentType, isGlobal, cwd) : getAgentBaseDir(agentType, isGlobal, cwd);
|
|
1454
|
+
const agentDir = join(agentBase, skillName);
|
|
1408
1455
|
if (!isPathSafe(canonicalBase, canonicalDir)) return {
|
|
1409
1456
|
success: false,
|
|
1410
1457
|
path: agentDir,
|
|
@@ -1417,14 +1464,58 @@ async function installSkillForAgent(skill, agentType, options = {}) {
|
|
|
1417
1464
|
mode: installMode,
|
|
1418
1465
|
error: "Invalid skill name: potential path traversal detected"
|
|
1419
1466
|
};
|
|
1467
|
+
if (!isPathSafe(isolatedStoreBase, isolatedStoreDir)) return {
|
|
1468
|
+
success: false,
|
|
1469
|
+
path: agentDir,
|
|
1470
|
+
mode: installMode,
|
|
1471
|
+
error: "Invalid skill name: potential path traversal detected"
|
|
1472
|
+
};
|
|
1420
1473
|
try {
|
|
1421
1474
|
if (installMode === "copy") {
|
|
1475
|
+
const targetDir = join(isUniversalAgent(agentType) ? getCanonicalSkillsDir(isGlobal, cwd) : getAgentBaseDir(agentType, isGlobal, cwd), skillName);
|
|
1476
|
+
const sharedFallbackUsed = isUniversalAgent(agentType) && !hasPrivateSkillsDir(agentType, isGlobal);
|
|
1477
|
+
await cleanAndCreateDirectory(targetDir);
|
|
1478
|
+
await copyDirectory(skill.path, targetDir);
|
|
1479
|
+
return {
|
|
1480
|
+
success: true,
|
|
1481
|
+
path: targetDir,
|
|
1482
|
+
mode: "copy",
|
|
1483
|
+
sharedFallbackUsed
|
|
1484
|
+
};
|
|
1485
|
+
}
|
|
1486
|
+
if (installMode === "copy-isolated") {
|
|
1487
|
+
const sharedFallbackUsed = !hasPrivateSkillsDir(agentType, isGlobal);
|
|
1422
1488
|
await cleanAndCreateDirectory(agentDir);
|
|
1423
1489
|
await copyDirectory(skill.path, agentDir);
|
|
1424
1490
|
return {
|
|
1425
1491
|
success: true,
|
|
1426
1492
|
path: agentDir,
|
|
1427
|
-
mode: "copy"
|
|
1493
|
+
mode: "copy-isolated",
|
|
1494
|
+
sharedFallbackUsed
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
if (installMode === "symlink-isolated") {
|
|
1498
|
+
const sharedFallbackUsed = !hasPrivateSkillsDir(agentType, isGlobal);
|
|
1499
|
+
await cleanAndCreateDirectory(isolatedStoreDir);
|
|
1500
|
+
await copyDirectory(skill.path, isolatedStoreDir);
|
|
1501
|
+
if (!await createSymlink(isolatedStoreDir, agentDir)) {
|
|
1502
|
+
await cleanAndCreateDirectory(agentDir);
|
|
1503
|
+
await copyDirectory(skill.path, agentDir);
|
|
1504
|
+
return {
|
|
1505
|
+
success: true,
|
|
1506
|
+
path: agentDir,
|
|
1507
|
+
canonicalPath: isolatedStoreDir,
|
|
1508
|
+
mode: "symlink-isolated",
|
|
1509
|
+
symlinkFailed: true,
|
|
1510
|
+
sharedFallbackUsed
|
|
1511
|
+
};
|
|
1512
|
+
}
|
|
1513
|
+
return {
|
|
1514
|
+
success: true,
|
|
1515
|
+
path: agentDir,
|
|
1516
|
+
canonicalPath: isolatedStoreDir,
|
|
1517
|
+
mode: "symlink-isolated",
|
|
1518
|
+
sharedFallbackUsed
|
|
1428
1519
|
};
|
|
1429
1520
|
}
|
|
1430
1521
|
await cleanAndCreateDirectory(canonicalDir);
|
|
@@ -1506,8 +1597,6 @@ async function isSkillInstalled(skillName, agentType, options = {}) {
|
|
|
1506
1597
|
}
|
|
1507
1598
|
}
|
|
1508
1599
|
function getInstallPath(skillName, agentType, options = {}) {
|
|
1509
|
-
agents[agentType];
|
|
1510
|
-
options.cwd || process.cwd();
|
|
1511
1600
|
const sanitized = sanitizeName(skillName);
|
|
1512
1601
|
const targetBase = getAgentBaseDir(agentType, options.global ?? false, options.cwd);
|
|
1513
1602
|
const installPath = join(targetBase, sanitized);
|
|
@@ -1535,7 +1624,9 @@ async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
|
|
|
1535
1624
|
const skillName = sanitizeName(skill.installName);
|
|
1536
1625
|
const canonicalBase = getCanonicalSkillsDir(isGlobal, cwd);
|
|
1537
1626
|
const canonicalDir = join(canonicalBase, skillName);
|
|
1538
|
-
const
|
|
1627
|
+
const isolatedStoreBase = getIsolatedStoreBase(isGlobal, cwd);
|
|
1628
|
+
const isolatedStoreDir = join(isolatedStoreBase, skillName);
|
|
1629
|
+
const agentBase = installMode === "symlink-isolated" || installMode === "copy-isolated" ? getAgentPrivateBaseDir(agentType, isGlobal, cwd) : getAgentBaseDir(agentType, isGlobal, cwd);
|
|
1539
1630
|
const agentDir = join(agentBase, skillName);
|
|
1540
1631
|
if (!isPathSafe(canonicalBase, canonicalDir)) return {
|
|
1541
1632
|
success: false,
|
|
@@ -1549,6 +1640,12 @@ async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
|
|
|
1549
1640
|
mode: installMode,
|
|
1550
1641
|
error: "Invalid skill name: potential path traversal detected"
|
|
1551
1642
|
};
|
|
1643
|
+
if (!isPathSafe(isolatedStoreBase, isolatedStoreDir)) return {
|
|
1644
|
+
success: false,
|
|
1645
|
+
path: agentDir,
|
|
1646
|
+
mode: installMode,
|
|
1647
|
+
error: "Invalid skill name: potential path traversal detected"
|
|
1648
|
+
};
|
|
1552
1649
|
async function writeSkillFiles(targetDir) {
|
|
1553
1650
|
for (const [filePath, content] of skill.files) {
|
|
1554
1651
|
const fullPath = join(targetDir, filePath);
|
|
@@ -1560,12 +1657,50 @@ async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
|
|
|
1560
1657
|
}
|
|
1561
1658
|
try {
|
|
1562
1659
|
if (installMode === "copy") {
|
|
1660
|
+
const targetDir = join(isUniversalAgent(agentType) ? getCanonicalSkillsDir(isGlobal, cwd) : getAgentBaseDir(agentType, isGlobal, cwd), skillName);
|
|
1661
|
+
const sharedFallbackUsed = isUniversalAgent(agentType) && !hasPrivateSkillsDir(agentType, isGlobal);
|
|
1662
|
+
await cleanAndCreateDirectory(targetDir);
|
|
1663
|
+
await writeSkillFiles(targetDir);
|
|
1664
|
+
return {
|
|
1665
|
+
success: true,
|
|
1666
|
+
path: targetDir,
|
|
1667
|
+
mode: "copy",
|
|
1668
|
+
sharedFallbackUsed
|
|
1669
|
+
};
|
|
1670
|
+
}
|
|
1671
|
+
if (installMode === "copy-isolated") {
|
|
1672
|
+
const sharedFallbackUsed = !hasPrivateSkillsDir(agentType, isGlobal);
|
|
1563
1673
|
await cleanAndCreateDirectory(agentDir);
|
|
1564
1674
|
await writeSkillFiles(agentDir);
|
|
1565
1675
|
return {
|
|
1566
1676
|
success: true,
|
|
1567
1677
|
path: agentDir,
|
|
1568
|
-
mode: "copy"
|
|
1678
|
+
mode: "copy-isolated",
|
|
1679
|
+
sharedFallbackUsed
|
|
1680
|
+
};
|
|
1681
|
+
}
|
|
1682
|
+
if (installMode === "symlink-isolated") {
|
|
1683
|
+
const sharedFallbackUsed = !hasPrivateSkillsDir(agentType, isGlobal);
|
|
1684
|
+
await cleanAndCreateDirectory(isolatedStoreDir);
|
|
1685
|
+
await writeSkillFiles(isolatedStoreDir);
|
|
1686
|
+
if (!await createSymlink(isolatedStoreDir, agentDir)) {
|
|
1687
|
+
await cleanAndCreateDirectory(agentDir);
|
|
1688
|
+
await writeSkillFiles(agentDir);
|
|
1689
|
+
return {
|
|
1690
|
+
success: true,
|
|
1691
|
+
path: agentDir,
|
|
1692
|
+
canonicalPath: isolatedStoreDir,
|
|
1693
|
+
mode: "symlink-isolated",
|
|
1694
|
+
symlinkFailed: true,
|
|
1695
|
+
sharedFallbackUsed
|
|
1696
|
+
};
|
|
1697
|
+
}
|
|
1698
|
+
return {
|
|
1699
|
+
success: true,
|
|
1700
|
+
path: agentDir,
|
|
1701
|
+
canonicalPath: isolatedStoreDir,
|
|
1702
|
+
mode: "symlink-isolated",
|
|
1703
|
+
sharedFallbackUsed
|
|
1569
1704
|
};
|
|
1570
1705
|
}
|
|
1571
1706
|
await cleanAndCreateDirectory(canonicalDir);
|
|
@@ -1631,7 +1766,7 @@ async function listInstalledSkills(options = {}) {
|
|
|
1631
1766
|
for (const scope of scopes) try {
|
|
1632
1767
|
const entries = await readdir(scope.path, { withFileTypes: true });
|
|
1633
1768
|
for (const entry of entries) {
|
|
1634
|
-
if (!entry.isDirectory()) continue;
|
|
1769
|
+
if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
|
|
1635
1770
|
const skillDir = join(scope.path, entry.name);
|
|
1636
1771
|
const skillMdPath = join(skillDir, "SKILL.md");
|
|
1637
1772
|
try {
|
|
@@ -1667,7 +1802,7 @@ async function listInstalledSkills(options = {}) {
|
|
|
1667
1802
|
const possibleNames = Array.from(new Set([
|
|
1668
1803
|
entry.name,
|
|
1669
1804
|
sanitizedSkillName,
|
|
1670
|
-
skill.name.toLowerCase().replace(/\s+/g, "-").replace(/[
|
|
1805
|
+
skill.name.toLowerCase().replace(/\s+/g, "-").replace(/[/\\:\0]/g, "")
|
|
1671
1806
|
]));
|
|
1672
1807
|
for (const possibleName of possibleNames) {
|
|
1673
1808
|
const agentSkillDir = join(agentBase, possibleName);
|
|
@@ -2205,7 +2340,7 @@ function logSkillParseFailures(failures) {
|
|
|
2205
2340
|
if (f.hint) M.message(import_picocolors.default.yellow(` 提示: ${f.hint}`));
|
|
2206
2341
|
}
|
|
2207
2342
|
}
|
|
2208
|
-
var version$1 = "2.0.
|
|
2343
|
+
var version$1 = "2.0.25";
|
|
2209
2344
|
const isCancelled$1 = (value) => typeof value === "symbol";
|
|
2210
2345
|
function redactSensitiveText(text) {
|
|
2211
2346
|
return text.replace(/(https?:\/\/)([^/\s:@]+)(?::([^@/\s]*))?@/gi, "$1").replace(/([?&](?:private_token|access_token|token|api_key|access_key|secret|password)=)[^&\s]+/gi, "$1***");
|
|
@@ -2272,42 +2407,54 @@ function formatList$1(items, maxShow = 5) {
|
|
|
2272
2407
|
const remaining = items.length - maxShow;
|
|
2273
2408
|
return `${shown.join(", ")} +${remaining} more`;
|
|
2274
2409
|
}
|
|
2275
|
-
function
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
universal,
|
|
2282
|
-
symlinked
|
|
2283
|
-
};
|
|
2284
|
-
}
|
|
2285
|
-
function buildAgentSummaryLines(targetAgents, installMode) {
|
|
2286
|
-
const lines = [];
|
|
2287
|
-
const { universal, symlinked } = splitAgentsByType(targetAgents);
|
|
2288
|
-
if (installMode === "symlink") {
|
|
2289
|
-
if (universal.length > 0) lines.push(` ${import_picocolors.default.green("universal:")} ${formatList$1(universal)}`);
|
|
2290
|
-
if (symlinked.length > 0) lines.push(` ${import_picocolors.default.dim("symlink →")} ${formatList$1(symlinked)}`);
|
|
2291
|
-
} else {
|
|
2292
|
-
const allNames = targetAgents.map((a) => agents[a].displayName);
|
|
2293
|
-
lines.push(` ${import_picocolors.default.dim("copy →")} ${formatList$1(allNames)}`);
|
|
2294
|
-
}
|
|
2295
|
-
return lines;
|
|
2410
|
+
function getEntityPath(skillName, installMode, global, cwd) {
|
|
2411
|
+
if (installMode === "symlink-isolated" || installMode === "copy-isolated") return join(global ? homedir() : cwd, ".skills-store", "skills", skillName);
|
|
2412
|
+
return getCanonicalPath(skillName, {
|
|
2413
|
+
global,
|
|
2414
|
+
cwd
|
|
2415
|
+
});
|
|
2296
2416
|
}
|
|
2297
|
-
function
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2417
|
+
function getInstallMethodOptions() {
|
|
2418
|
+
return [
|
|
2419
|
+
{
|
|
2420
|
+
value: "symlink",
|
|
2421
|
+
label: "Symlink",
|
|
2422
|
+
hint: "拷贝技能到公认目录 .agents/skills【实现 agent 间共享】+ 软链到不支持公认目录的 agent 的私有目录"
|
|
2423
|
+
},
|
|
2424
|
+
{
|
|
2425
|
+
value: "symlink-isolated",
|
|
2426
|
+
label: "Symlink & Isolated",
|
|
2427
|
+
hint: "拷贝技能到隔离目录 .skills-store + 软链到各 agent 的私有目录【实现 agent 间的技能独享】"
|
|
2428
|
+
},
|
|
2429
|
+
{
|
|
2430
|
+
value: "copy",
|
|
2431
|
+
label: "Copy",
|
|
2432
|
+
hint: "拷贝技能到公认目录 .agents/skills【实现 agent 间共享】,不支持公认目录的 agent 会拷贝到其私有目录"
|
|
2433
|
+
},
|
|
2434
|
+
{
|
|
2435
|
+
value: "copy-isolated",
|
|
2436
|
+
label: "Copy & Isolated",
|
|
2437
|
+
hint: "拷贝技能到各 agent 的私有目录,不写入共享目录【实现 agent 间的技能独享】"
|
|
2438
|
+
}
|
|
2439
|
+
];
|
|
2302
2440
|
}
|
|
2303
|
-
function
|
|
2441
|
+
function buildAgentSummaryLines(targetAgents, installMode) {
|
|
2442
|
+
const allNames = targetAgents.map((a) => agents[a].displayName);
|
|
2443
|
+
return [` ${import_picocolors.default.dim(`${{
|
|
2444
|
+
symlink: "symlink(shared)",
|
|
2445
|
+
copy: "copy(shared)",
|
|
2446
|
+
"symlink-isolated": "symlink(isolated)",
|
|
2447
|
+
"copy-isolated": "copy(isolated)"
|
|
2448
|
+
}[installMode]} →`)} ${formatList$1(allNames)}`];
|
|
2449
|
+
}
|
|
2450
|
+
function buildResultLines(results) {
|
|
2304
2451
|
const lines = [];
|
|
2305
|
-
const
|
|
2306
|
-
const
|
|
2307
|
-
const
|
|
2308
|
-
if (
|
|
2309
|
-
if (
|
|
2310
|
-
if (
|
|
2452
|
+
const symlinked = results.filter((r) => !r.symlinkFailed).map((r) => r.agent);
|
|
2453
|
+
const copied = results.filter((r) => r.symlinkFailed).map((r) => r.agent);
|
|
2454
|
+
const sharedFallback = results.filter((r) => r.sharedFallbackUsed).map((r) => r.agent);
|
|
2455
|
+
if (symlinked.length > 0) lines.push(` ${import_picocolors.default.dim("symlinked:")} ${formatList$1(symlinked)}`);
|
|
2456
|
+
if (copied.length > 0) lines.push(` ${import_picocolors.default.yellow("copied:")} ${formatList$1(copied)}`);
|
|
2457
|
+
if (sharedFallback.length > 0) lines.push(` ${import_picocolors.default.yellow("shared fallback:")} ${formatList$1(sharedFallback)}`);
|
|
2311
2458
|
return lines;
|
|
2312
2459
|
}
|
|
2313
2460
|
function multiselect(opts) {
|
|
@@ -2323,55 +2470,65 @@ async function promptForAgents(message, choices) {
|
|
|
2323
2470
|
lastSelected = await getLastSelectedAgents();
|
|
2324
2471
|
} catch {}
|
|
2325
2472
|
const validAgents = choices.map((c) => c.value);
|
|
2326
|
-
const defaultValues = [
|
|
2327
|
-
"claude-code",
|
|
2328
|
-
"opencode",
|
|
2329
|
-
"codex"
|
|
2330
|
-
].filter((a) => validAgents.includes(a));
|
|
2331
2473
|
let initialValues = [];
|
|
2332
2474
|
if (lastSelected && lastSelected.length > 0) initialValues = lastSelected.filter((a) => validAgents.includes(a));
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2475
|
+
let needsReselect = true;
|
|
2476
|
+
while (needsReselect) {
|
|
2477
|
+
const selected = await searchMultiselect({
|
|
2478
|
+
message,
|
|
2479
|
+
items: choices,
|
|
2480
|
+
initialSelected: initialValues,
|
|
2481
|
+
required: true
|
|
2482
|
+
});
|
|
2483
|
+
if (isCancelled$1(selected)) return selected;
|
|
2484
|
+
if (selected.length === 0) {
|
|
2485
|
+
M.warn("请至少选择一个 agent");
|
|
2486
|
+
continue;
|
|
2487
|
+
}
|
|
2488
|
+
try {
|
|
2489
|
+
await saveSelectedAgents(selected);
|
|
2490
|
+
} catch {}
|
|
2491
|
+
needsReselect = false;
|
|
2492
|
+
return selected;
|
|
2493
|
+
}
|
|
2494
|
+
return [];
|
|
2344
2495
|
}
|
|
2345
2496
|
async function selectAgentsInteractive(options) {
|
|
2346
2497
|
const supportsGlobalFilter = (a) => !options.global || agents[a].globalSkillsDir;
|
|
2347
|
-
const
|
|
2348
|
-
const
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2498
|
+
const availableAgents = Object.keys(agents).filter(supportsGlobalFilter);
|
|
2499
|
+
const choices = availableAgents.map((a) => {
|
|
2500
|
+
const targetDir = options.global ? agents[a].globalSkillsDir : agents[a].skillsDir;
|
|
2501
|
+
const sharedSupport = agents[a].supportsSharedAgentsDir ? ", supports .agents/skills" : "";
|
|
2502
|
+
return {
|
|
2352
2503
|
value: a,
|
|
2353
|
-
label: agents[a].displayName
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
value: a,
|
|
2358
|
-
label: agents[a].displayName,
|
|
2359
|
-
hint: options.global ? agents[a].globalSkillsDir : agents[a].skillsDir
|
|
2360
|
-
}));
|
|
2504
|
+
label: agents[a].displayName,
|
|
2505
|
+
hint: `${targetDir}${sharedSupport}`
|
|
2506
|
+
};
|
|
2507
|
+
});
|
|
2361
2508
|
let lastSelected;
|
|
2362
2509
|
try {
|
|
2363
2510
|
lastSelected = await getLastSelectedAgents();
|
|
2364
2511
|
} catch {}
|
|
2365
|
-
const
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2512
|
+
const initialSelected = lastSelected ? lastSelected.filter((a) => availableAgents.includes(a)) : [];
|
|
2513
|
+
let needsReselect = true;
|
|
2514
|
+
while (needsReselect) {
|
|
2515
|
+
const selected = await searchMultiselect({
|
|
2516
|
+
message: "Which agents do you want to install to?",
|
|
2517
|
+
items: choices,
|
|
2518
|
+
initialSelected
|
|
2519
|
+
});
|
|
2520
|
+
if (isCancelled$1(selected)) return selected;
|
|
2521
|
+
if (selected.length === 0) {
|
|
2522
|
+
M.warn("请至少选择一个 agent");
|
|
2523
|
+
continue;
|
|
2524
|
+
}
|
|
2525
|
+
try {
|
|
2526
|
+
await saveSelectedAgents(selected);
|
|
2527
|
+
} catch {}
|
|
2528
|
+
needsReselect = false;
|
|
2529
|
+
return selected;
|
|
2530
|
+
}
|
|
2531
|
+
return [];
|
|
2375
2532
|
}
|
|
2376
2533
|
setVersion(version$1);
|
|
2377
2534
|
async function handleWellKnownSkills(source, url, options, spinner) {
|
|
@@ -2447,7 +2604,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
2447
2604
|
M.info(`Valid agents: ${validAgents.join(", ")}`);
|
|
2448
2605
|
process.exit(1);
|
|
2449
2606
|
}
|
|
2450
|
-
targetAgents =
|
|
2607
|
+
targetAgents = options.agent;
|
|
2451
2608
|
} else {
|
|
2452
2609
|
spinner.start("Loading agents...");
|
|
2453
2610
|
const installedAgents = await detectInstalledAgents();
|
|
@@ -2469,7 +2626,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
2469
2626
|
targetAgents = selected;
|
|
2470
2627
|
}
|
|
2471
2628
|
else if (installedAgents.length === 1 || options.yes) {
|
|
2472
|
-
targetAgents =
|
|
2629
|
+
targetAgents = installedAgents;
|
|
2473
2630
|
if (installedAgents.length === 1) {
|
|
2474
2631
|
const firstAgent = installedAgents[0];
|
|
2475
2632
|
M.info(`Installing to: ${import_picocolors.default.cyan(agents[firstAgent].displayName)}`);
|
|
@@ -2508,15 +2665,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
2508
2665
|
if (!options.copy && !options.yes) {
|
|
2509
2666
|
const modeChoice = await ve({
|
|
2510
2667
|
message: "Installation method",
|
|
2511
|
-
options:
|
|
2512
|
-
value: "symlink",
|
|
2513
|
-
label: "Symlink (Recommended)",
|
|
2514
|
-
hint: "Single source of truth, easy updates"
|
|
2515
|
-
}, {
|
|
2516
|
-
value: "copy",
|
|
2517
|
-
label: "Copy to all agents",
|
|
2518
|
-
hint: "Independent copies for each agent"
|
|
2519
|
-
}]
|
|
2668
|
+
options: getInstallMethodOptions()
|
|
2520
2669
|
});
|
|
2521
2670
|
if (pD(modeChoice)) {
|
|
2522
2671
|
xe("Installation cancelled");
|
|
@@ -2538,7 +2687,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
2538
2687
|
}
|
|
2539
2688
|
for (const skill of selectedSkills) {
|
|
2540
2689
|
if (summaryLines.length > 0) summaryLines.push("");
|
|
2541
|
-
const shortCanonical = shortenPath$2(
|
|
2690
|
+
const shortCanonical = shortenPath$2(getEntityPath(skill.installName, installMode, installGlobally, cwd), cwd);
|
|
2542
2691
|
summaryLines.push(`${import_picocolors.default.cyan(shortCanonical)}`);
|
|
2543
2692
|
summaryLines.push(...buildAgentSummaryLines(targetAgents, installMode));
|
|
2544
2693
|
if (skill.files.size > 1) summaryLines.push(` ${import_picocolors.default.dim("files:")} ${skill.files.size}`);
|
|
@@ -2557,7 +2706,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
2557
2706
|
}
|
|
2558
2707
|
spinner.start("Installing skills...");
|
|
2559
2708
|
const results = [];
|
|
2560
|
-
const effectiveAgents = installMode === "copy" ? targetAgents.filter((a, i, arr) => arr.findIndex((b) => agents[b].skillsDir === agents[a].skillsDir) === i) : targetAgents;
|
|
2709
|
+
const effectiveAgents = installMode === "copy" || installMode === "copy-isolated" ? targetAgents.filter((a, i, arr) => arr.findIndex((b) => agents[b].skillsDir === agents[a].skillsDir) === i) : targetAgents;
|
|
2561
2710
|
for (const skill of selectedSkills) for (const agent of effectiveAgents) {
|
|
2562
2711
|
const result = await installWellKnownSkillForAgent(skill, agent, {
|
|
2563
2712
|
global: installGlobally,
|
|
@@ -2627,12 +2776,13 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
2627
2776
|
bySkill.set(r.skill, skillResults);
|
|
2628
2777
|
}
|
|
2629
2778
|
const skillCount = bySkill.size;
|
|
2630
|
-
const symlinkFailures = successful.filter((r) => r.mode === "symlink" && r.symlinkFailed);
|
|
2779
|
+
const symlinkFailures = successful.filter((r) => (r.mode === "symlink" || r.mode === "symlink-isolated") && r.symlinkFailed);
|
|
2631
2780
|
const copiedAgents = symlinkFailures.map((r) => r.agent);
|
|
2781
|
+
const sharedFallbackAgents = successful.filter((r) => r.sharedFallbackUsed).map((r) => r.agent);
|
|
2632
2782
|
const resultLines = [];
|
|
2633
2783
|
for (const [skillName, skillResults] of bySkill) {
|
|
2634
2784
|
const firstResult = skillResults[0];
|
|
2635
|
-
if (firstResult.mode === "copy") {
|
|
2785
|
+
if (firstResult.mode === "copy" || firstResult.mode === "copy-isolated") {
|
|
2636
2786
|
resultLines.push(`${import_picocolors.default.green("✓")} ${skillName} ${import_picocolors.default.dim("(copied)")}`);
|
|
2637
2787
|
for (const r of skillResults) {
|
|
2638
2788
|
const shortPath = shortenPath$2(r.path, cwd);
|
|
@@ -2643,7 +2793,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
2643
2793
|
const shortPath = shortenPath$2(firstResult.canonicalPath, cwd);
|
|
2644
2794
|
resultLines.push(`${import_picocolors.default.green("✓")} ${shortPath}`);
|
|
2645
2795
|
} else resultLines.push(`${import_picocolors.default.green("✓")} ${skillName}`);
|
|
2646
|
-
resultLines.push(...buildResultLines(skillResults
|
|
2796
|
+
resultLines.push(...buildResultLines(skillResults));
|
|
2647
2797
|
}
|
|
2648
2798
|
}
|
|
2649
2799
|
const title = import_picocolors.default.green(`Installed ${skillCount} skill${skillCount !== 1 ? "s" : ""}`);
|
|
@@ -2652,6 +2802,10 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
2652
2802
|
M.warn(import_picocolors.default.yellow(`Symlinks failed for: ${formatList$1(copiedAgents)}`));
|
|
2653
2803
|
M.message(import_picocolors.default.dim(" Files were copied instead. On Windows, enable Developer Mode for symlink support."));
|
|
2654
2804
|
}
|
|
2805
|
+
if (sharedFallbackAgents.length > 0) {
|
|
2806
|
+
M.warn(import_picocolors.default.bgYellow(import_picocolors.default.black(" FALLBACK ")) + " " + import_picocolors.default.yellow(`No private skills dir for: ${formatList$1(sharedFallbackAgents)}`));
|
|
2807
|
+
M.message(import_picocolors.default.dim(" Installed to shared .agents/skills for compatibility"));
|
|
2808
|
+
}
|
|
2655
2809
|
}
|
|
2656
2810
|
if (failed.length > 0) {
|
|
2657
2811
|
console.log();
|
|
@@ -2947,7 +3101,7 @@ async function runAdd(args, options = {}) {
|
|
|
2947
3101
|
await cleanup(tempDir);
|
|
2948
3102
|
process.exit(1);
|
|
2949
3103
|
}
|
|
2950
|
-
targetAgents =
|
|
3104
|
+
targetAgents = options.agent;
|
|
2951
3105
|
} else {
|
|
2952
3106
|
spinner.start("Loading agents...");
|
|
2953
3107
|
const installedAgents = await detectInstalledAgents();
|
|
@@ -2970,7 +3124,7 @@ async function runAdd(args, options = {}) {
|
|
|
2970
3124
|
targetAgents = selected;
|
|
2971
3125
|
}
|
|
2972
3126
|
else if (installedAgents.length === 1 || options.yes) {
|
|
2973
|
-
targetAgents =
|
|
3127
|
+
targetAgents = installedAgents;
|
|
2974
3128
|
if (installedAgents.length === 1) {
|
|
2975
3129
|
const firstAgent = installedAgents[0];
|
|
2976
3130
|
M.info(`Installing to: ${import_picocolors.default.cyan(agents[firstAgent].displayName)}`);
|
|
@@ -3011,15 +3165,7 @@ async function runAdd(args, options = {}) {
|
|
|
3011
3165
|
if (!options.copy && !options.yes) {
|
|
3012
3166
|
const modeChoice = await ve({
|
|
3013
3167
|
message: "Installation method",
|
|
3014
|
-
options:
|
|
3015
|
-
value: "symlink",
|
|
3016
|
-
label: "Symlink (Recommended)",
|
|
3017
|
-
hint: "Single source of truth, easy updates"
|
|
3018
|
-
}, {
|
|
3019
|
-
value: "copy",
|
|
3020
|
-
label: "Copy to all agents",
|
|
3021
|
-
hint: "Independent copies for each agent"
|
|
3022
|
-
}]
|
|
3168
|
+
options: getInstallMethodOptions()
|
|
3023
3169
|
});
|
|
3024
3170
|
if (pD(modeChoice)) {
|
|
3025
3171
|
xe("Installation cancelled");
|
|
@@ -3050,7 +3196,7 @@ async function runAdd(args, options = {}) {
|
|
|
3050
3196
|
const printSkillSummary = (skills) => {
|
|
3051
3197
|
for (const skill of skills) {
|
|
3052
3198
|
if (summaryLines.length > 0) summaryLines.push("");
|
|
3053
|
-
const shortCanonical = shortenPath$2(
|
|
3199
|
+
const shortCanonical = shortenPath$2(getEntityPath(skill.name, installMode, installGlobally, cwd), cwd);
|
|
3054
3200
|
summaryLines.push(`${import_picocolors.default.cyan(shortCanonical)}`);
|
|
3055
3201
|
summaryLines.push(...buildAgentSummaryLines(targetAgents, installMode));
|
|
3056
3202
|
const skillOverwrites = overwriteStatus.get(skill.name);
|
|
@@ -3094,7 +3240,7 @@ async function runAdd(args, options = {}) {
|
|
|
3094
3240
|
}
|
|
3095
3241
|
spinner.start("Installing skills...");
|
|
3096
3242
|
const results = [];
|
|
3097
|
-
const effectiveAgents = installMode === "copy" ? targetAgents.filter((a, i, arr) => arr.findIndex((b) => agents[b].skillsDir === agents[a].skillsDir) === i) : targetAgents;
|
|
3243
|
+
const effectiveAgents = installMode === "copy" || installMode === "copy-isolated" ? targetAgents.filter((a, i, arr) => arr.findIndex((b) => agents[b].skillsDir === agents[a].skillsDir) === i) : targetAgents;
|
|
3098
3244
|
for (const skill of selectedSkills) for (const agent of effectiveAgents) {
|
|
3099
3245
|
const result = await installSkillForAgent(skill, agent, {
|
|
3100
3246
|
global: installGlobally,
|
|
@@ -3264,14 +3410,15 @@ async function runAdd(args, options = {}) {
|
|
|
3264
3410
|
} else ungroupedResults.push(r);
|
|
3265
3411
|
}
|
|
3266
3412
|
const skillCount = bySkill.size;
|
|
3267
|
-
const symlinkFailures = successful.filter((r) => r.mode === "symlink" && r.symlinkFailed);
|
|
3413
|
+
const symlinkFailures = successful.filter((r) => (r.mode === "symlink" || r.mode === "symlink-isolated") && r.symlinkFailed);
|
|
3268
3414
|
const copiedAgents = symlinkFailures.map((r) => r.agent);
|
|
3415
|
+
const sharedFallbackAgents = successful.filter((r) => r.sharedFallbackUsed).map((r) => r.agent);
|
|
3269
3416
|
const resultLines = [];
|
|
3270
3417
|
const printSkillResults = (entries) => {
|
|
3271
3418
|
for (const entry of entries) {
|
|
3272
3419
|
const skillResults = bySkill.get(entry.skill) || [];
|
|
3273
3420
|
const firstResult = skillResults[0];
|
|
3274
|
-
if (firstResult.mode === "copy") {
|
|
3421
|
+
if (firstResult.mode === "copy" || firstResult.mode === "copy-isolated") {
|
|
3275
3422
|
resultLines.push(`${import_picocolors.default.green("✓")} ${entry.skill} ${import_picocolors.default.dim("(copied)")}`);
|
|
3276
3423
|
for (const r of skillResults) {
|
|
3277
3424
|
const shortPath = shortenPath$2(r.path, cwd);
|
|
@@ -3282,7 +3429,7 @@ async function runAdd(args, options = {}) {
|
|
|
3282
3429
|
const shortPath = shortenPath$2(firstResult.canonicalPath, cwd);
|
|
3283
3430
|
resultLines.push(`${import_picocolors.default.green("✓")} ${shortPath}`);
|
|
3284
3431
|
} else resultLines.push(`${import_picocolors.default.green("✓")} ${entry.skill}`);
|
|
3285
|
-
resultLines.push(...buildResultLines(skillResults
|
|
3432
|
+
resultLines.push(...buildResultLines(skillResults));
|
|
3286
3433
|
}
|
|
3287
3434
|
}
|
|
3288
3435
|
};
|
|
@@ -3306,6 +3453,10 @@ async function runAdd(args, options = {}) {
|
|
|
3306
3453
|
M.warn(import_picocolors.default.yellow(`Symlinks failed for: ${formatList$1(copiedAgents)}`));
|
|
3307
3454
|
M.message(import_picocolors.default.dim(" Files were copied instead. On Windows, enable Developer Mode for symlink support."));
|
|
3308
3455
|
}
|
|
3456
|
+
if (sharedFallbackAgents.length > 0) {
|
|
3457
|
+
M.warn(import_picocolors.default.bgYellow(import_picocolors.default.black(" FALLBACK ")) + " " + import_picocolors.default.yellow(`No private skills dir for: ${formatList$1(sharedFallbackAgents)}`));
|
|
3458
|
+
M.message(import_picocolors.default.dim(" Installed to shared .agents/skills for compatibility"));
|
|
3459
|
+
}
|
|
3309
3460
|
}
|
|
3310
3461
|
if (failed.length > 0) {
|
|
3311
3462
|
console.log();
|
|
@@ -4140,6 +4291,10 @@ async function removeCommand(skillNames, options) {
|
|
|
4140
4291
|
global: isGlobal,
|
|
4141
4292
|
cwd
|
|
4142
4293
|
});
|
|
4294
|
+
const isolatedStorePath = getIsolatedStorePath(skillName, {
|
|
4295
|
+
global: isGlobal,
|
|
4296
|
+
cwd
|
|
4297
|
+
});
|
|
4143
4298
|
for (const agentKey of targetAgents) {
|
|
4144
4299
|
const agent = agents[agentKey];
|
|
4145
4300
|
const skillPath = getInstallPath(skillName, agentKey, {
|
|
@@ -4171,10 +4326,16 @@ async function removeCommand(skillNames, options) {
|
|
|
4171
4326
|
isStillUsed = true;
|
|
4172
4327
|
break;
|
|
4173
4328
|
}
|
|
4174
|
-
if (!isStillUsed)
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4329
|
+
if (!isStillUsed) {
|
|
4330
|
+
await rm(canonicalPath, {
|
|
4331
|
+
recursive: true,
|
|
4332
|
+
force: true
|
|
4333
|
+
});
|
|
4334
|
+
await rm(isolatedStorePath, {
|
|
4335
|
+
recursive: true,
|
|
4336
|
+
force: true
|
|
4337
|
+
});
|
|
4338
|
+
}
|
|
4178
4339
|
const lockEntry = isGlobal ? await getSkillFromLock(skillName) : null;
|
|
4179
4340
|
const effectiveSource = lockEntry?.source || "local";
|
|
4180
4341
|
const effectiveSourceType = lockEntry?.sourceType || "local";
|
|
@@ -5381,6 +5542,17 @@ const REDIRECT_STATUS_CODES = new Set([
|
|
|
5381
5542
|
308
|
|
5382
5543
|
]);
|
|
5383
5544
|
const MAX_REDIRECTS = 5;
|
|
5545
|
+
function normalizeEscapedUrlInput(rawUrl) {
|
|
5546
|
+
if (!rawUrl.includes("\\")) return {
|
|
5547
|
+
normalizedUrl: rawUrl,
|
|
5548
|
+
changed: false
|
|
5549
|
+
};
|
|
5550
|
+
const normalizedUrl = rawUrl.replace(/\\([?&=#])/g, "$1");
|
|
5551
|
+
return {
|
|
5552
|
+
normalizedUrl,
|
|
5553
|
+
changed: normalizedUrl !== rawUrl
|
|
5554
|
+
};
|
|
5555
|
+
}
|
|
5384
5556
|
function detectAuthMode(platformKey, platform, hostname) {
|
|
5385
5557
|
if (platform.authType === "private_token") return "private_token";
|
|
5386
5558
|
if (platformKey === "o2") return "auto";
|
|
@@ -5709,7 +5881,7 @@ async function sendSsoTicketDirectRequest(targetUrl, options) {
|
|
|
5709
5881
|
} else console.log(outputBody);
|
|
5710
5882
|
if (!response.ok) process.exit(1);
|
|
5711
5883
|
}
|
|
5712
|
-
async function sendPlainDirectRequest(targetUrl, options) {
|
|
5884
|
+
async function sendPlainDirectRequest(targetUrl, options, allowSsoCookieFallback = false) {
|
|
5713
5885
|
const requestHeaders = { "User-Agent": "ali-skills-cli/1.0" };
|
|
5714
5886
|
if (options.headers) Object.entries(options.headers).forEach(([key, value]) => {
|
|
5715
5887
|
requestHeaders[key] = value;
|
|
@@ -5723,11 +5895,19 @@ async function sendPlainDirectRequest(targetUrl, options) {
|
|
|
5723
5895
|
console.log(`${DIM$2}${options.method.toUpperCase()} ${targetUrl}${RESET$2}`);
|
|
5724
5896
|
console.log(`${DIM$2}→ 直接请求 (No Auth)${RESET$2}`);
|
|
5725
5897
|
}
|
|
5726
|
-
const controller = new AbortController();
|
|
5727
5898
|
const timeout = options.timeout || 3e4;
|
|
5728
|
-
const
|
|
5729
|
-
|
|
5730
|
-
|
|
5899
|
+
const { response, responseBody, sawAlibabaLoginRedirect } = await fetchWithRedirects(targetUrl, options.method.toUpperCase(), requestHeaders, body, timeout, options.quiet);
|
|
5900
|
+
if (allowSsoCookieFallback && sawAlibabaLoginRedirect) {
|
|
5901
|
+
if (!options.quiet) {
|
|
5902
|
+
console.log(`${YELLOW$2}检测到请求被重定向到 login.alibaba-inc.com,目标接口可能需要登录鉴权${RESET$2}`);
|
|
5903
|
+
console.log(`${DIM$2}将自动使用 --auth sso_cookie 重试原始接口;如不符合预期,请显式指定 --auth${RESET$2}`);
|
|
5904
|
+
}
|
|
5905
|
+
await sendSsoCookieDirectRequest(targetUrl, {
|
|
5906
|
+
...options,
|
|
5907
|
+
authMode: "sso_cookie"
|
|
5908
|
+
});
|
|
5909
|
+
return;
|
|
5910
|
+
}
|
|
5731
5911
|
if (!options.quiet) {
|
|
5732
5912
|
const statusColor = response.ok ? GREEN$1 : RED$2;
|
|
5733
5913
|
console.log(`${statusColor}${response.status} ${response.statusText}${RESET$2}`);
|
|
@@ -5757,6 +5937,7 @@ async function fetchWithRedirects(initialUrl, method, headers, body, timeout, qu
|
|
|
5757
5937
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
5758
5938
|
let currentUrl = initialUrl;
|
|
5759
5939
|
let redirects = 0;
|
|
5940
|
+
let sawAlibabaLoginRedirect = false;
|
|
5760
5941
|
try {
|
|
5761
5942
|
while (true) {
|
|
5762
5943
|
const response = await fetch(currentUrl, {
|
|
@@ -5768,15 +5949,18 @@ async function fetchWithRedirects(initialUrl, method, headers, body, timeout, qu
|
|
|
5768
5949
|
});
|
|
5769
5950
|
if (!REDIRECT_STATUS_CODES.has(response.status)) return {
|
|
5770
5951
|
response,
|
|
5771
|
-
responseBody: await response.text()
|
|
5952
|
+
responseBody: await response.text(),
|
|
5953
|
+
sawAlibabaLoginRedirect
|
|
5772
5954
|
};
|
|
5773
5955
|
const location = response.headers.get("location");
|
|
5774
5956
|
if (!location) return {
|
|
5775
5957
|
response,
|
|
5776
|
-
responseBody: await response.text()
|
|
5958
|
+
responseBody: await response.text(),
|
|
5959
|
+
sawAlibabaLoginRedirect
|
|
5777
5960
|
};
|
|
5778
5961
|
if (redirects >= MAX_REDIRECTS) throw new Error(`重定向次数超过上限(${MAX_REDIRECTS})`);
|
|
5779
5962
|
const nextUrl = new URL(location, currentUrl).toString();
|
|
5963
|
+
if (new URL(nextUrl).hostname === "login.alibaba-inc.com") sawAlibabaLoginRedirect = true;
|
|
5780
5964
|
redirects += 1;
|
|
5781
5965
|
if (!quiet) console.log(`${DIM$2}↪ 重定向 ${redirects}: ${response.status} ${response.statusText} -> ${nextUrl}${RESET$2}`);
|
|
5782
5966
|
currentUrl = nextUrl;
|
|
@@ -5863,8 +6047,9 @@ async function sendGatewayRequest(targetUrl, platformKey, options, authMode = "g
|
|
|
5863
6047
|
}
|
|
5864
6048
|
async function proxyRequest(targetUrl, options) {
|
|
5865
6049
|
let url;
|
|
6050
|
+
const { normalizedUrl, changed: urlInputNormalized } = normalizeEscapedUrlInput(targetUrl);
|
|
5866
6051
|
try {
|
|
5867
|
-
url = new URL(
|
|
6052
|
+
url = new URL(normalizedUrl);
|
|
5868
6053
|
} catch {
|
|
5869
6054
|
console.error(`${RED$2}Error: URL 必须是绝对地址,收到 "${targetUrl}"${RESET$2}`);
|
|
5870
6055
|
console.log(`${DIM$2}未传 platform 时,请使用完整 URL(包含协议和域名)${RESET$2}`);
|
|
@@ -5885,12 +6070,17 @@ async function proxyRequest(targetUrl, options) {
|
|
|
5885
6070
|
ssoType: "refresh_token"
|
|
5886
6071
|
};
|
|
5887
6072
|
try {
|
|
6073
|
+
if (urlInputNormalized && !options.quiet) {
|
|
6074
|
+
console.log(`${DIM$2}检测到 URL 中包含转义分隔符,已自动还原后请求${RESET$2}`);
|
|
6075
|
+
console.log(`${DIM$2}原始: ${targetUrl}${RESET$2}`);
|
|
6076
|
+
console.log(`${DIM$2}还原: ${normalizedUrl}${RESET$2}`);
|
|
6077
|
+
}
|
|
5888
6078
|
if (!isKnownPlatform && !hasExplicitAuthMode) {
|
|
5889
6079
|
if (!options.quiet) {
|
|
5890
6080
|
console.log(`${DIM$2}平台: Custom Host${RESET$2}`);
|
|
5891
6081
|
console.log(`${DIM$2}认证方式: Auto (未知平台默认直连,无鉴权)${RESET$2}`);
|
|
5892
6082
|
}
|
|
5893
|
-
await sendPlainDirectRequest(
|
|
6083
|
+
await sendPlainDirectRequest(normalizedUrl, options, true);
|
|
5894
6084
|
return;
|
|
5895
6085
|
}
|
|
5896
6086
|
if (!options.quiet) console.log(`${DIM$2}平台: ${platform.name}${RESET$2}`);
|
|
@@ -5902,7 +6092,7 @@ async function proxyRequest(targetUrl, options) {
|
|
|
5902
6092
|
console.error(`${RED$2}Error: o2 仅支持 --auth auto 或 --auth sso_ticket${RESET$2}`);
|
|
5903
6093
|
process.exit(1);
|
|
5904
6094
|
}
|
|
5905
|
-
await sendO2SdkRequest(
|
|
6095
|
+
await sendO2SdkRequest(normalizedUrl, options, authMode === "sso_ticket");
|
|
5906
6096
|
return;
|
|
5907
6097
|
}
|
|
5908
6098
|
switch (authMode) {
|
|
@@ -5921,17 +6111,17 @@ async function proxyRequest(targetUrl, options) {
|
|
|
5921
6111
|
process.exit(1);
|
|
5922
6112
|
}
|
|
5923
6113
|
}
|
|
5924
|
-
await sendDirectRequest(
|
|
6114
|
+
await sendDirectRequest(normalizedUrl, platform, token, options);
|
|
5925
6115
|
return;
|
|
5926
6116
|
}
|
|
5927
6117
|
case "sso_cookie":
|
|
5928
|
-
await sendSsoCookieDirectRequest(
|
|
6118
|
+
await sendSsoCookieDirectRequest(normalizedUrl, options);
|
|
5929
6119
|
return;
|
|
5930
6120
|
case "sso_ticket":
|
|
5931
|
-
await sendSsoTicketDirectRequest(
|
|
6121
|
+
await sendSsoTicketDirectRequest(normalizedUrl, options);
|
|
5932
6122
|
return;
|
|
5933
6123
|
case "gateway":
|
|
5934
|
-
await sendGatewayRequest(
|
|
6124
|
+
await sendGatewayRequest(normalizedUrl, platformKey, options, "gateway");
|
|
5935
6125
|
return;
|
|
5936
6126
|
default: break;
|
|
5937
6127
|
}
|
|
@@ -5941,12 +6131,12 @@ async function proxyRequest(targetUrl, options) {
|
|
|
5941
6131
|
console.error(`${RED$2}Error: o2 仅支持 --auth auto 或 --auth sso_ticket${RESET$2}`);
|
|
5942
6132
|
process.exit(1);
|
|
5943
6133
|
}
|
|
5944
|
-
await sendO2SdkRequest(
|
|
6134
|
+
await sendO2SdkRequest(normalizedUrl, options, authMode === "sso_ticket");
|
|
5945
6135
|
return;
|
|
5946
6136
|
}
|
|
5947
6137
|
switch (authMode) {
|
|
5948
6138
|
case "private_token": {
|
|
5949
|
-
let token = getPlatformPrivateToken(platformKey, options.token,
|
|
6139
|
+
let token = getPlatformPrivateToken(platformKey, options.token, normalizedUrl);
|
|
5950
6140
|
if (!token) {
|
|
5951
6141
|
token = await promptConfigureToken(platformKey, platform);
|
|
5952
6142
|
if (!token) {
|
|
@@ -5960,19 +6150,19 @@ async function proxyRequest(targetUrl, options) {
|
|
|
5960
6150
|
process.exit(1);
|
|
5961
6151
|
}
|
|
5962
6152
|
}
|
|
5963
|
-
await sendDirectRequest(
|
|
6153
|
+
await sendDirectRequest(normalizedUrl, platform, token, options);
|
|
5964
6154
|
break;
|
|
5965
6155
|
}
|
|
5966
6156
|
case "sso_ticket":
|
|
5967
6157
|
case "gateway":
|
|
5968
|
-
await sendGatewayRequest(
|
|
6158
|
+
await sendGatewayRequest(normalizedUrl, platformKey, options, authMode);
|
|
5969
6159
|
break;
|
|
5970
6160
|
case "sso_cookie":
|
|
5971
|
-
await sendSsoCookieDirectRequest(
|
|
6161
|
+
await sendSsoCookieDirectRequest(normalizedUrl, options);
|
|
5972
6162
|
break;
|
|
5973
6163
|
default: if (platform.authType === "private_token") {
|
|
5974
|
-
const token = getPlatformPrivateToken(platformKey, options.token,
|
|
5975
|
-
if (token) await sendDirectRequest(
|
|
6164
|
+
const token = getPlatformPrivateToken(platformKey, options.token, normalizedUrl);
|
|
6165
|
+
if (token) await sendDirectRequest(normalizedUrl, platform, token, options);
|
|
5976
6166
|
else {
|
|
5977
6167
|
console.error(`${RED$2}Error: ${platform.name} 需要配置 Private Token${RESET$2}`);
|
|
5978
6168
|
console.log(`${DIM$2}您可以通过以下方式配置:${RESET$2}`);
|
|
@@ -5983,8 +6173,8 @@ async function proxyRequest(targetUrl, options) {
|
|
|
5983
6173
|
console.log(` 参数: --token <your_token>`);
|
|
5984
6174
|
process.exit(1);
|
|
5985
6175
|
}
|
|
5986
|
-
} else if (isAlibabaIncRootDomain) await sendSsoCookieDirectRequest(
|
|
5987
|
-
else await sendGatewayRequest(
|
|
6176
|
+
} else if (isAlibabaIncRootDomain) await sendSsoCookieDirectRequest(normalizedUrl, options);
|
|
6177
|
+
else await sendGatewayRequest(normalizedUrl, platformKey, options, "sso_ticket");
|
|
5988
6178
|
}
|
|
5989
6179
|
} catch (error) {
|
|
5990
6180
|
if (error instanceof Error) if (error.name === "AbortError") console.error(`${RED$2}Error: 请求超时${RESET$2}`);
|
|
@@ -6452,19 +6642,20 @@ ${BOLD}Gateway Commands:${RESET}
|
|
|
6452
6642
|
request [platform] <url|path> Send HTTP request (supports platform + path shorthand)
|
|
6453
6643
|
req [platform] <url|path> Alias for request, recommended
|
|
6454
6644
|
|
|
6645
|
+
${BOLD}Platform Values:${RESET}
|
|
6646
|
+
${platformKeysForHelp}
|
|
6647
|
+
|
|
6455
6648
|
${BOLD}Yuque Commands:${RESET}
|
|
6456
6649
|
login yuque [group] Configure/switch specified Yuque group directly
|
|
6457
6650
|
logout yuque [group] [--all] Choose one/many Yuque groups to clear, or clear all
|
|
6458
6651
|
status yuque [group] [--show|-s] [--pretty] Show Yuque group/all config JSON
|
|
6459
6652
|
|
|
6460
|
-
${BOLD}Platform Values:${RESET}
|
|
6461
|
-
${platformKeysForHelp}
|
|
6462
|
-
|
|
6463
6653
|
${BOLD}Request Options:${RESET}
|
|
6464
6654
|
-X, --method <method> HTTP method (default: GET)
|
|
6465
6655
|
-b, --body <body> Request body (JSON string or @file)
|
|
6466
6656
|
-h, --header <header> Custom header (can be used multiple times)
|
|
6467
6657
|
--auth, --auth-mode <mode> Auth mode: auto/private_token/sso_cookie/sso_ticket
|
|
6658
|
+
--sso <cookie|ticket> Shortcut for --auth sso_cookie/sso_ticket
|
|
6468
6659
|
--token <token> Explicit token for private_token mode
|
|
6469
6660
|
-o, --output <file> Save response to file
|
|
6470
6661
|
-i, --include-headers Include response headers in output
|
|
@@ -6473,46 +6664,104 @@ ${BOLD}Request Options:${RESET}
|
|
|
6473
6664
|
--raw Raw output without formatting
|
|
6474
6665
|
-q, --quiet Quiet mode, only output response body
|
|
6475
6666
|
|
|
6476
|
-
${BOLD}Environment:${RESET}
|
|
6477
|
-
ALI_SKILLS_YUQUE_GROUP Yuque team slug when multiple teams have tokens in config
|
|
6478
|
-
O2_API_ENV O2 SDK env override (default online; set pre for pre env)
|
|
6479
|
-
ALI_SKILLS_DEBUG_GATEWAY Enable gateway auth debug logs (1/true/on)
|
|
6480
|
-
|
|
6481
6667
|
${BOLD}Examples:${RESET}
|
|
6482
6668
|
${DIM}$${RESET} ali-skills login
|
|
6483
6669
|
${DIM}$${RESET} ali-skills login code
|
|
6484
6670
|
${DIM}$${RESET} ali-skills login yuque
|
|
6485
|
-
${DIM}$${RESET} ali-skills login yuque
|
|
6671
|
+
${DIM}$${RESET} ali-skills login yuque group
|
|
6486
6672
|
${DIM}$${RESET} ali-skills status --all
|
|
6673
|
+
${DIM}$${RESET} ali-skills status
|
|
6487
6674
|
${DIM}$${RESET} ali-skills status code
|
|
6488
|
-
${DIM}$${RESET} ali-skills status
|
|
6489
|
-
${DIM}$${RESET} ali-skills status
|
|
6675
|
+
${DIM}$${RESET} ali-skills status yuque
|
|
6676
|
+
${DIM}$${RESET} ali-skills status yuque group
|
|
6677
|
+
${DIM}$${RESET} ali-skills status o2
|
|
6678
|
+
${DIM}$${RESET} ali-skills status --show
|
|
6490
6679
|
${DIM}$${RESET} ali-skills status code --show
|
|
6491
6680
|
${DIM}$${RESET} ali-skills status yuque --show
|
|
6492
|
-
${DIM}$${RESET} ali-skills status yuque fliggy
|
|
6493
6681
|
${DIM}$${RESET} ali-skills status yuque fliggy --show
|
|
6682
|
+
${DIM}$${RESET} ali-skills logout
|
|
6494
6683
|
${DIM}$${RESET} ali-skills logout code
|
|
6495
6684
|
${DIM}$${RESET} ali-skills logout yuque
|
|
6496
6685
|
${DIM}$${RESET} ali-skills logout yuque my-team
|
|
6497
6686
|
${DIM}$${RESET} ali-skills logout yuque --all
|
|
6498
|
-
${DIM}$${RESET} ali-skills req
|
|
6499
|
-
${DIM}$${RESET} ali-skills req
|
|
6500
|
-
${DIM}$${RESET} ali-skills req
|
|
6501
|
-
${DIM}$${RESET} ali-skills req https://
|
|
6502
|
-
${DIM}$${RESET} ali-skills req
|
|
6503
|
-
${DIM}$${RESET} ali-skills req yuque
|
|
6504
|
-
${DIM}$${RESET} ali-skills req yuque
|
|
6505
|
-
${DIM}$${RESET} ali-skills
|
|
6687
|
+
${DIM}$${RESET} ali-skills req 'https://subdomain.alibaba-inc.com/path?q=v'
|
|
6688
|
+
${DIM}$${RESET} ali-skills req 'https://subdomain.alibaba-inc.com/path?q=v' --auth sso_cookie
|
|
6689
|
+
${DIM}$${RESET} ali-skills req 'https://subdomain.alibaba-inc.com/path?q=v' --auth sso_cookie -X POST -b '{"k": "v"}' -h 'X-Custom-Header: value'
|
|
6690
|
+
${DIM}$${RESET} ali-skills req 'https://support-buc-sso-ticket-site/path?q=v' --auth sso_ticket
|
|
6691
|
+
${DIM}$${RESET} ali-skills req code '/api/v3/project?path=clam-ng/clam'
|
|
6692
|
+
${DIM}$${RESET} ali-skills req yuque '/api/v2/repos/fliggyfe-infra/ali-skills-dev/docs/mll9xim6y6lcnvyg'
|
|
6693
|
+
${DIM}$${RESET} ali-skills req yuque '/api/v2/search?q=buc&type=doc&scope=fliggyfe-infra'
|
|
6694
|
+
${DIM}$${RESET} ali-skills req o2 '/v1.0/work/apps/rxpi%252Fmtop/trunk'
|
|
6695
|
+
${DIM}$${RESET} ali-skills req o2 '/v1.0/work/apps/rxpi%252Fmtop/detail' --auth sso_ticket
|
|
6506
6696
|
`);
|
|
6507
6697
|
}
|
|
6508
6698
|
function parseRequestOptions(args) {
|
|
6509
6699
|
let url = "";
|
|
6510
6700
|
const options = { method: "GET" };
|
|
6511
6701
|
const headers = {};
|
|
6702
|
+
const parseSsoShortcut = (raw) => {
|
|
6703
|
+
if (!raw) return void 0;
|
|
6704
|
+
const normalized = raw.trim().toLowerCase();
|
|
6705
|
+
if (normalized === "cookie") return "sso_cookie";
|
|
6706
|
+
if (normalized === "ticket") return "sso_ticket";
|
|
6707
|
+
};
|
|
6512
6708
|
for (let i = 0; i < args.length; i++) {
|
|
6513
6709
|
const arg = args[i];
|
|
6710
|
+
const parseLongOptionValue = (name) => {
|
|
6711
|
+
const prefix = `--${name}=`;
|
|
6712
|
+
if (!arg?.startsWith(prefix)) return void 0;
|
|
6713
|
+
return arg.slice(prefix.length);
|
|
6714
|
+
};
|
|
6715
|
+
const methodValue = parseLongOptionValue("method");
|
|
6716
|
+
if (methodValue !== void 0) {
|
|
6717
|
+
options.method = methodValue || "GET";
|
|
6718
|
+
continue;
|
|
6719
|
+
}
|
|
6720
|
+
const bodyValue = parseLongOptionValue("body");
|
|
6721
|
+
if (bodyValue !== void 0) {
|
|
6722
|
+
options.body = bodyValue;
|
|
6723
|
+
continue;
|
|
6724
|
+
}
|
|
6725
|
+
const headerValue = parseLongOptionValue("header");
|
|
6726
|
+
if (headerValue !== void 0) {
|
|
6727
|
+
const [key, ...valueParts] = headerValue.split(":");
|
|
6728
|
+
if (key && valueParts.length > 0) headers[key.trim()] = valueParts.join(":").trim();
|
|
6729
|
+
continue;
|
|
6730
|
+
}
|
|
6731
|
+
const outputValue = parseLongOptionValue("output");
|
|
6732
|
+
if (outputValue !== void 0) {
|
|
6733
|
+
options.output = outputValue;
|
|
6734
|
+
continue;
|
|
6735
|
+
}
|
|
6736
|
+
const timeoutValue = parseLongOptionValue("timeout");
|
|
6737
|
+
if (timeoutValue !== void 0) {
|
|
6738
|
+
if (timeoutValue) options.timeout = parseInt(timeoutValue, 10);
|
|
6739
|
+
continue;
|
|
6740
|
+
}
|
|
6741
|
+
const authModeValue = parseLongOptionValue("auth-mode") ?? parseLongOptionValue("auth");
|
|
6742
|
+
if (authModeValue !== void 0) {
|
|
6743
|
+
options.authMode = authModeValue || "auto";
|
|
6744
|
+
continue;
|
|
6745
|
+
}
|
|
6746
|
+
const tokenValue = parseLongOptionValue("token");
|
|
6747
|
+
if (tokenValue !== void 0) {
|
|
6748
|
+
options.token = tokenValue;
|
|
6749
|
+
continue;
|
|
6750
|
+
}
|
|
6751
|
+
const ssoValue = parseLongOptionValue("sso");
|
|
6752
|
+
if (ssoValue !== void 0) {
|
|
6753
|
+
const mapped = parseSsoShortcut(ssoValue);
|
|
6754
|
+
if (!mapped) {
|
|
6755
|
+
console.error(`Unknown value for --sso: ${ssoValue}, expected cookie or ticket`);
|
|
6756
|
+
process.exit(1);
|
|
6757
|
+
}
|
|
6758
|
+
options.authMode = mapped;
|
|
6759
|
+
continue;
|
|
6760
|
+
}
|
|
6514
6761
|
switch (arg) {
|
|
6515
6762
|
case "-m":
|
|
6763
|
+
case "-x":
|
|
6764
|
+
case "-X":
|
|
6516
6765
|
case "--method":
|
|
6517
6766
|
options.method = args[++i] || "GET";
|
|
6518
6767
|
break;
|
|
@@ -6556,6 +6805,15 @@ function parseRequestOptions(args) {
|
|
|
6556
6805
|
case "--token":
|
|
6557
6806
|
options.token = args[++i];
|
|
6558
6807
|
break;
|
|
6808
|
+
case "--sso": {
|
|
6809
|
+
const mode = parseSsoShortcut(args[++i]);
|
|
6810
|
+
if (!mode) {
|
|
6811
|
+
console.error("Unknown value for --sso, expected cookie or ticket");
|
|
6812
|
+
process.exit(1);
|
|
6813
|
+
}
|
|
6814
|
+
options.authMode = mode;
|
|
6815
|
+
break;
|
|
6816
|
+
}
|
|
6559
6817
|
case "-q":
|
|
6560
6818
|
case "--quiet":
|
|
6561
6819
|
options.quiet = true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ali-skills",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.25",
|
|
4
4
|
"description": "The open agent skills ecosystem",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"author": "",
|
|
32
32
|
"license": "MIT",
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@ali/cli-skills": "^2.0.
|
|
34
|
+
"@ali/cli-skills": "^2.0.25"
|
|
35
35
|
},
|
|
36
36
|
"bundleDependencies": [
|
|
37
37
|
"@ali/cli-skills"
|