bip-skills 1.4.10 → 1.4.12
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/dist/cli.mjs +326 -113
- package/package.json +22 -17
package/dist/cli.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import { t as require_gray_matter } from "./_chunks/libs/gray-matter.mjs";
|
|
|
9
9
|
import "./_chunks/libs/extend-shallow.mjs";
|
|
10
10
|
import "./_chunks/libs/esprima.mjs";
|
|
11
11
|
import { t as xdgConfig } from "./_chunks/libs/xdg-basedir.mjs";
|
|
12
|
-
import { execSync, spawnSync } from "child_process";
|
|
12
|
+
import { execFile, execSync, spawnSync } from "child_process";
|
|
13
13
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
14
14
|
import { basename, dirname, isAbsolute, join, normalize, posix, relative, resolve, sep } from "path";
|
|
15
15
|
import { homedir, platform, tmpdir } from "os";
|
|
@@ -17,6 +17,7 @@ import { fileURLToPath } from "url";
|
|
|
17
17
|
import * as readline from "readline";
|
|
18
18
|
import { Writable } from "stream";
|
|
19
19
|
import { Buffer } from "node:buffer";
|
|
20
|
+
import { promisify } from "util";
|
|
20
21
|
import { access, cp, lstat, mkdir, mkdtemp, readFile, readdir, readlink, realpath, rm, stat, symlink, writeFile } from "fs/promises";
|
|
21
22
|
import http from "node:http";
|
|
22
23
|
import https from "node:https";
|
|
@@ -103,7 +104,12 @@ function isInternalSkillSourceUrl(sourceUrl) {
|
|
|
103
104
|
return hostname ? isInternalSkillSourceHost(hostname) : false;
|
|
104
105
|
}
|
|
105
106
|
function isLocalPath(input) {
|
|
106
|
-
return isAbsolute(input) || input.startsWith("./") || input.startsWith("../") || input === "." || input === ".." || /^[a-zA-Z]:[/\\]/.test(input);
|
|
107
|
+
return isAbsolute(input) || input === "~" || input.startsWith("~/") || input.startsWith("~\\") || input.startsWith("./") || input.startsWith("../") || input === "." || input === ".." || /^[a-zA-Z]:[/\\]/.test(input);
|
|
108
|
+
}
|
|
109
|
+
function expandLocalPath(input) {
|
|
110
|
+
if (input === "~") return homedir();
|
|
111
|
+
if (input.startsWith("~/") || input.startsWith("~\\")) return resolve(homedir(), input.slice(2));
|
|
112
|
+
return input;
|
|
107
113
|
}
|
|
108
114
|
const SOURCE_ALIASES = { "coinbase/agentWallet": "coinbase/agentic-wallet-skills" };
|
|
109
115
|
function buildDefaultGitUrl(repoPath) {
|
|
@@ -113,7 +119,7 @@ function parseSource(input) {
|
|
|
113
119
|
const alias = SOURCE_ALIASES[input];
|
|
114
120
|
if (alias) input = alias;
|
|
115
121
|
if (isLocalPath(input)) {
|
|
116
|
-
const resolvedPath = resolve(input);
|
|
122
|
+
const resolvedPath = resolve(expandLocalPath(input));
|
|
117
123
|
return {
|
|
118
124
|
type: "local",
|
|
119
125
|
url: resolvedPath,
|
|
@@ -678,6 +684,117 @@ function filterSkills(skills, inputNames) {
|
|
|
678
684
|
return normalizedInputs.some((input) => input === name || input === displayName);
|
|
679
685
|
});
|
|
680
686
|
}
|
|
687
|
+
const execFileAsync = promisify(execFile);
|
|
688
|
+
const GATEWAY_PROCESS_RE = /(?:yonclaw|openclaw)-gateway/i;
|
|
689
|
+
const YONCLAW_PROCESS_RE = /yonclaw|openclaw-gateway|yonclaw-gateway/i;
|
|
690
|
+
function getYonClawBaseDir(options = {}) {
|
|
691
|
+
if (options.baseDir) return options.baseDir;
|
|
692
|
+
const home = options.homeDir ?? homedir();
|
|
693
|
+
const currentPlatform = options.platform ?? platform();
|
|
694
|
+
const env = options.env ?? process.env;
|
|
695
|
+
if (currentPlatform === "darwin") return join(home, "Library", "Application Support", "yonclaw");
|
|
696
|
+
if (currentPlatform === "win32") return join(env.APPDATA || join(home, "AppData", "Roaming"), "yonclaw");
|
|
697
|
+
return join(options.xdgConfigDir || env.XDG_CONFIG_HOME || xdgConfig || join(home, ".config"), "yonclaw");
|
|
698
|
+
}
|
|
699
|
+
function getYonClawProfileSkillsDir(baseDir, profileKey) {
|
|
700
|
+
return join(baseDir, "profiles", profileKey, "userData", "runtime", "openclaw", "skills");
|
|
701
|
+
}
|
|
702
|
+
function getYonClawGlobalSkillsDirHint(options = {}) {
|
|
703
|
+
return getYonClawProfileSkillsDir(getYonClawBaseDir(options), "profile-*");
|
|
704
|
+
}
|
|
705
|
+
async function readJson(path) {
|
|
706
|
+
try {
|
|
707
|
+
return JSON.parse(await readFile(path, "utf-8"));
|
|
708
|
+
} catch {
|
|
709
|
+
return null;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
async function listProfileKeys(baseDir) {
|
|
713
|
+
try {
|
|
714
|
+
return (await readdir(join(baseDir, "profiles"), { withFileTypes: true })).filter((entry) => entry.isDirectory() && entry.name.startsWith("profile-")).map((entry) => entry.name).sort();
|
|
715
|
+
} catch {
|
|
716
|
+
return [];
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
function unique(items) {
|
|
720
|
+
return Array.from(new Set(items));
|
|
721
|
+
}
|
|
722
|
+
function parseUserDataProfile(command) {
|
|
723
|
+
const match = command.match(/--user-data-dir=(?:"([^"]+)"|'([^']+)'|(\S+))/);
|
|
724
|
+
const userDataDir = match?.[1] ?? match?.[2] ?? match?.[3];
|
|
725
|
+
if (!userDataDir) return null;
|
|
726
|
+
return normalize(userDataDir).match(/[\\/]profiles[\\/]([^\\/]+)[\\/]userData$/)?.[1] ?? null;
|
|
727
|
+
}
|
|
728
|
+
function isLivePid(pid) {
|
|
729
|
+
try {
|
|
730
|
+
process.kill(pid, 0);
|
|
731
|
+
return true;
|
|
732
|
+
} catch (error) {
|
|
733
|
+
return error instanceof Error && "code" in error && error.code === "EPERM";
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
function parsePsOutput(stdout) {
|
|
737
|
+
return stdout.split("\n").map((line) => line.trim()).filter(Boolean).flatMap((line) => {
|
|
738
|
+
const match = line.match(/^(\d+)\s+(.+)$/);
|
|
739
|
+
if (!match) return [];
|
|
740
|
+
return [{
|
|
741
|
+
pid: Number(match[1]),
|
|
742
|
+
command: match[2]
|
|
743
|
+
}];
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
function parsePowershellProcesses(stdout) {
|
|
747
|
+
try {
|
|
748
|
+
const parsed = JSON.parse(stdout);
|
|
749
|
+
return (Array.isArray(parsed) ? parsed : [parsed]).flatMap((item) => {
|
|
750
|
+
if (typeof item.ProcessId !== "number" || typeof item.CommandLine !== "string") return [];
|
|
751
|
+
return [{
|
|
752
|
+
pid: item.ProcessId,
|
|
753
|
+
command: item.CommandLine
|
|
754
|
+
}];
|
|
755
|
+
});
|
|
756
|
+
} catch {
|
|
757
|
+
return [];
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
async function listYonClawProcesses(currentPlatform = platform()) {
|
|
761
|
+
try {
|
|
762
|
+
if (currentPlatform === "win32") {
|
|
763
|
+
const { stdout } = await execFileAsync("powershell.exe", [
|
|
764
|
+
"-NoProfile",
|
|
765
|
+
"-Command",
|
|
766
|
+
"Get-CimInstance Win32_Process | Select-Object ProcessId,CommandLine | ConvertTo-Json -Compress"
|
|
767
|
+
]);
|
|
768
|
+
return parsePowershellProcesses(stdout);
|
|
769
|
+
}
|
|
770
|
+
const { stdout } = await execFileAsync("ps", ["-axo", "pid=,command="]);
|
|
771
|
+
return parsePsOutput(stdout);
|
|
772
|
+
} catch {
|
|
773
|
+
return [];
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
async function resolveYonClawGlobalSkillsDirs(options = {}) {
|
|
777
|
+
const baseDir = getYonClawBaseDir(options);
|
|
778
|
+
const profileKeys = await listProfileKeys(baseDir);
|
|
779
|
+
if (profileKeys.length === 0) return [];
|
|
780
|
+
const processes = await (options.processProvider ?? { listProcesses: () => listYonClawProcesses(options.platform) }).listProcesses();
|
|
781
|
+
const processByPid = new Map(processes.map((processInfo) => [processInfo.pid, processInfo]));
|
|
782
|
+
const liveGatewayProfiles = [];
|
|
783
|
+
for (const profileKey of profileKeys) {
|
|
784
|
+
const runtime = await readJson(join(baseDir, "profiles", profileKey, "userData", "gateway-runtime.json"));
|
|
785
|
+
if (typeof runtime?.pid !== "number") continue;
|
|
786
|
+
const processInfo = processByPid.get(runtime.pid);
|
|
787
|
+
if (processInfo && GATEWAY_PROCESS_RE.test(processInfo.command) && isLivePid(runtime.pid)) liveGatewayProfiles.push(profileKey);
|
|
788
|
+
}
|
|
789
|
+
if (liveGatewayProfiles.length > 0) return unique(liveGatewayProfiles).map((profileKey) => getYonClawProfileSkillsDir(baseDir, profileKey));
|
|
790
|
+
const userDataProfiles = unique(processes.filter((processInfo) => YONCLAW_PROCESS_RE.test(processInfo.command)).map((processInfo) => parseUserDataProfile(processInfo.command)).filter((profileKey) => Boolean(profileKey)).filter((profileKey) => profileKeys.includes(profileKey)));
|
|
791
|
+
if (userDataProfiles.length > 0) return userDataProfiles.map((profileKey) => getYonClawProfileSkillsDir(baseDir, profileKey));
|
|
792
|
+
if (processes.some((processInfo) => YONCLAW_PROCESS_RE.test(processInfo.command))) {
|
|
793
|
+
const activeProfile = await readJson(join(baseDir, "device", "active-profile.json"));
|
|
794
|
+
if (typeof activeProfile?.profileKey === "string" && profileKeys.includes(activeProfile.profileKey)) return [getYonClawProfileSkillsDir(baseDir, activeProfile.profileKey)];
|
|
795
|
+
}
|
|
796
|
+
return profileKeys.map((profileKey) => getYonClawProfileSkillsDir(baseDir, profileKey));
|
|
797
|
+
}
|
|
681
798
|
const home = homedir();
|
|
682
799
|
const configHome = xdgConfig ?? join(home, ".config");
|
|
683
800
|
const codexHome = process.env.CODEX_HOME?.trim() || join(home, ".codex");
|
|
@@ -698,6 +815,17 @@ const agents = {
|
|
|
698
815
|
return existsSync(join(configHome, "amp"));
|
|
699
816
|
}
|
|
700
817
|
},
|
|
818
|
+
yonclaw: {
|
|
819
|
+
name: "yonclaw",
|
|
820
|
+
displayName: "YonClaw",
|
|
821
|
+
skillsDir: "runtime/openclaw/skills",
|
|
822
|
+
globalSkillsDir: getYonClawGlobalSkillsDirHint(),
|
|
823
|
+
resolveGlobalSkillsDirs: resolveYonClawGlobalSkillsDirs,
|
|
824
|
+
supportsProjectInstall: false,
|
|
825
|
+
detectInstalled: async () => {
|
|
826
|
+
return existsSync(getYonClawBaseDir());
|
|
827
|
+
}
|
|
828
|
+
},
|
|
701
829
|
antigravity: {
|
|
702
830
|
name: "antigravity",
|
|
703
831
|
displayName: "Antigravity",
|
|
@@ -1074,6 +1202,10 @@ function getNonUniversalAgents() {
|
|
|
1074
1202
|
function isUniversalAgent(type) {
|
|
1075
1203
|
return agents[type].skillsDir === ".agents/skills";
|
|
1076
1204
|
}
|
|
1205
|
+
function agentSupportsGlobalInstall$1(agentType) {
|
|
1206
|
+
const agent = agents[agentType];
|
|
1207
|
+
return agent.globalSkillsDir !== void 0 || agent.resolveGlobalSkillsDirs !== void 0;
|
|
1208
|
+
}
|
|
1077
1209
|
function sanitizeName(name) {
|
|
1078
1210
|
return name.toLowerCase().replace(/[^a-z0-9._]+/g, "-").replace(/^[.\-]+|[.\-]+$/g, "").substring(0, 255) || "unnamed-skill";
|
|
1079
1211
|
}
|
|
@@ -1095,6 +1227,13 @@ function getAgentBaseDir(agentType, global, cwd) {
|
|
|
1095
1227
|
}
|
|
1096
1228
|
return join(baseDir, agent.skillsDir);
|
|
1097
1229
|
}
|
|
1230
|
+
async function getAgentBaseDirs(agentType, global, cwd) {
|
|
1231
|
+
const agent = agents[agentType];
|
|
1232
|
+
if (!global && agent.supportsProjectInstall === false) return [];
|
|
1233
|
+
if (global && agent.resolveGlobalSkillsDirs) return agent.resolveGlobalSkillsDirs();
|
|
1234
|
+
if (global && !agentSupportsGlobalInstall$1(agentType)) return [];
|
|
1235
|
+
return [getAgentBaseDir(agentType, global, cwd)];
|
|
1236
|
+
}
|
|
1098
1237
|
function resolveSymlinkTarget(linkPath, linkTarget) {
|
|
1099
1238
|
return resolve(dirname(linkPath), linkTarget);
|
|
1100
1239
|
}
|
|
@@ -1146,7 +1285,13 @@ async function installSkillForAgent(skill, agentType, options = {}) {
|
|
|
1146
1285
|
const agent = agents[agentType];
|
|
1147
1286
|
const isGlobal = options.global ?? false;
|
|
1148
1287
|
const cwd = options.cwd || process.cwd();
|
|
1149
|
-
if (isGlobal && agent.
|
|
1288
|
+
if (!isGlobal && agent.supportsProjectInstall === false) return {
|
|
1289
|
+
success: false,
|
|
1290
|
+
path: "",
|
|
1291
|
+
mode: options.mode ?? "symlink",
|
|
1292
|
+
error: `${agent.displayName} only supports global skill installation. Use --global.`
|
|
1293
|
+
};
|
|
1294
|
+
if (isGlobal && !agentSupportsGlobalInstall$1(agentType)) return {
|
|
1150
1295
|
success: false,
|
|
1151
1296
|
path: "",
|
|
1152
1297
|
mode: options.mode ?? "symlink",
|
|
@@ -1155,28 +1300,37 @@ async function installSkillForAgent(skill, agentType, options = {}) {
|
|
|
1155
1300
|
const skillName = sanitizeName(skill.name || basename(skill.path));
|
|
1156
1301
|
const canonicalBase = getCanonicalSkillsDir(isGlobal, cwd);
|
|
1157
1302
|
const canonicalDir = join(canonicalBase, skillName);
|
|
1158
|
-
const
|
|
1159
|
-
const
|
|
1303
|
+
const agentBases = await getAgentBaseDirs(agentType, isGlobal, cwd);
|
|
1304
|
+
const agentDirs = agentBases.map((agentBase) => join(agentBase, skillName));
|
|
1305
|
+
const agentDir = agentDirs[0] ?? "";
|
|
1160
1306
|
const installMode = options.mode ?? "symlink";
|
|
1307
|
+
if (agentBases.length === 0) return {
|
|
1308
|
+
success: false,
|
|
1309
|
+
path: "",
|
|
1310
|
+
mode: installMode,
|
|
1311
|
+
error: `No ${agent.displayName} skills directories found`
|
|
1312
|
+
};
|
|
1161
1313
|
if (!isPathSafe(canonicalBase, canonicalDir)) return {
|
|
1162
1314
|
success: false,
|
|
1163
1315
|
path: agentDir,
|
|
1164
1316
|
mode: installMode,
|
|
1165
1317
|
error: "Invalid skill name: potential path traversal detected"
|
|
1166
1318
|
};
|
|
1167
|
-
if (!isPathSafe(agentBase,
|
|
1319
|
+
for (const [index, agentBase] of agentBases.entries()) if (!isPathSafe(agentBase, agentDirs[index])) return {
|
|
1168
1320
|
success: false,
|
|
1169
|
-
path:
|
|
1321
|
+
path: agentDirs[index],
|
|
1170
1322
|
mode: installMode,
|
|
1171
1323
|
error: "Invalid skill name: potential path traversal detected"
|
|
1172
1324
|
};
|
|
1173
1325
|
try {
|
|
1174
1326
|
if (installMode === "copy") {
|
|
1175
|
-
await
|
|
1176
|
-
|
|
1327
|
+
await Promise.all(agentDirs.map(async (targetDir) => {
|
|
1328
|
+
await cleanAndCreateDirectory(targetDir);
|
|
1329
|
+
await copyDirectory(skill.path, targetDir);
|
|
1330
|
+
}));
|
|
1177
1331
|
return {
|
|
1178
1332
|
success: true,
|
|
1179
|
-
path:
|
|
1333
|
+
path: agentDirs.join(", "),
|
|
1180
1334
|
mode: "copy"
|
|
1181
1335
|
};
|
|
1182
1336
|
}
|
|
@@ -1188,22 +1342,18 @@ async function installSkillForAgent(skill, agentType, options = {}) {
|
|
|
1188
1342
|
canonicalPath: canonicalDir,
|
|
1189
1343
|
mode: "symlink"
|
|
1190
1344
|
};
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
path: agentDir,
|
|
1197
|
-
canonicalPath: canonicalDir,
|
|
1198
|
-
mode: "symlink",
|
|
1199
|
-
symlinkFailed: true
|
|
1200
|
-
};
|
|
1345
|
+
let symlinkFailed = false;
|
|
1346
|
+
for (const targetDir of agentDirs) if (!await createSymlink(canonicalDir, targetDir)) {
|
|
1347
|
+
symlinkFailed = true;
|
|
1348
|
+
await cleanAndCreateDirectory(targetDir);
|
|
1349
|
+
await copyDirectory(skill.path, targetDir);
|
|
1201
1350
|
}
|
|
1202
1351
|
return {
|
|
1203
1352
|
success: true,
|
|
1204
|
-
path:
|
|
1353
|
+
path: agentDirs.join(", "),
|
|
1205
1354
|
canonicalPath: canonicalDir,
|
|
1206
|
-
mode: "symlink"
|
|
1355
|
+
mode: "symlink",
|
|
1356
|
+
...symlinkFailed && { symlinkFailed: true }
|
|
1207
1357
|
};
|
|
1208
1358
|
} catch (error) {
|
|
1209
1359
|
return {
|
|
@@ -1238,25 +1388,27 @@ async function copyDirectory(src, dest) {
|
|
|
1238
1388
|
async function isSkillInstalled(skillName, agentType, options = {}) {
|
|
1239
1389
|
const agent = agents[agentType];
|
|
1240
1390
|
const sanitized = sanitizeName(skillName);
|
|
1241
|
-
if (options.global && agent.
|
|
1242
|
-
|
|
1243
|
-
const
|
|
1244
|
-
if (
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1391
|
+
if (!options.global && agent.supportsProjectInstall === false) return false;
|
|
1392
|
+
if (options.global && !agentSupportsGlobalInstall$1(agentType)) return false;
|
|
1393
|
+
const targetBases = await getAgentBaseDirs(agentType, options.global ?? false, options.cwd);
|
|
1394
|
+
if (targetBases.length === 0) return false;
|
|
1395
|
+
for (const targetBase of targetBases) {
|
|
1396
|
+
const skillDir = join(targetBase, sanitized);
|
|
1397
|
+
if (!isPathSafe(targetBase, skillDir)) continue;
|
|
1398
|
+
try {
|
|
1399
|
+
await access(skillDir);
|
|
1400
|
+
return true;
|
|
1401
|
+
} catch {}
|
|
1250
1402
|
}
|
|
1403
|
+
return false;
|
|
1251
1404
|
}
|
|
1252
|
-
function
|
|
1253
|
-
agents[agentType];
|
|
1254
|
-
options.cwd || process.cwd();
|
|
1405
|
+
async function getInstallPaths(skillName, agentType, options = {}) {
|
|
1255
1406
|
const sanitized = sanitizeName(skillName);
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1407
|
+
return (await getAgentBaseDirs(agentType, options.global ?? false, options.cwd)).map((targetBase) => {
|
|
1408
|
+
const installPath = join(targetBase, sanitized);
|
|
1409
|
+
if (!isPathSafe(targetBase, installPath)) throw new Error("Invalid skill name: potential path traversal detected");
|
|
1410
|
+
return installPath;
|
|
1411
|
+
});
|
|
1260
1412
|
}
|
|
1261
1413
|
function getCanonicalPath(skillName, options = {}) {
|
|
1262
1414
|
const sanitized = sanitizeName(skillName);
|
|
@@ -1270,7 +1422,13 @@ async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
|
|
|
1270
1422
|
const isGlobal = options.global ?? false;
|
|
1271
1423
|
const cwd = options.cwd || process.cwd();
|
|
1272
1424
|
const installMode = options.mode ?? "symlink";
|
|
1273
|
-
if (isGlobal && agent.
|
|
1425
|
+
if (!isGlobal && agent.supportsProjectInstall === false) return {
|
|
1426
|
+
success: false,
|
|
1427
|
+
path: "",
|
|
1428
|
+
mode: installMode,
|
|
1429
|
+
error: `${agent.displayName} only supports global skill installation. Use --global.`
|
|
1430
|
+
};
|
|
1431
|
+
if (isGlobal && !agentSupportsGlobalInstall$1(agentType)) return {
|
|
1274
1432
|
success: false,
|
|
1275
1433
|
path: "",
|
|
1276
1434
|
mode: installMode,
|
|
@@ -1279,17 +1437,24 @@ async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
|
|
|
1279
1437
|
const skillName = sanitizeName(skill.installName);
|
|
1280
1438
|
const canonicalBase = getCanonicalSkillsDir(isGlobal, cwd);
|
|
1281
1439
|
const canonicalDir = join(canonicalBase, skillName);
|
|
1282
|
-
const
|
|
1283
|
-
const
|
|
1440
|
+
const agentBases = await getAgentBaseDirs(agentType, isGlobal, cwd);
|
|
1441
|
+
const agentDirs = agentBases.map((agentBase) => join(agentBase, skillName));
|
|
1442
|
+
const agentDir = agentDirs[0] ?? "";
|
|
1443
|
+
if (agentBases.length === 0) return {
|
|
1444
|
+
success: false,
|
|
1445
|
+
path: "",
|
|
1446
|
+
mode: installMode,
|
|
1447
|
+
error: `No ${agent.displayName} skills directories found`
|
|
1448
|
+
};
|
|
1284
1449
|
if (!isPathSafe(canonicalBase, canonicalDir)) return {
|
|
1285
1450
|
success: false,
|
|
1286
1451
|
path: agentDir,
|
|
1287
1452
|
mode: installMode,
|
|
1288
1453
|
error: "Invalid skill name: potential path traversal detected"
|
|
1289
1454
|
};
|
|
1290
|
-
if (!isPathSafe(agentBase,
|
|
1455
|
+
for (const [index, agentBase] of agentBases.entries()) if (!isPathSafe(agentBase, agentDirs[index])) return {
|
|
1291
1456
|
success: false,
|
|
1292
|
-
path:
|
|
1457
|
+
path: agentDirs[index],
|
|
1293
1458
|
mode: installMode,
|
|
1294
1459
|
error: "Invalid skill name: potential path traversal detected"
|
|
1295
1460
|
};
|
|
@@ -1304,11 +1469,13 @@ async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
|
|
|
1304
1469
|
}
|
|
1305
1470
|
try {
|
|
1306
1471
|
if (installMode === "copy") {
|
|
1307
|
-
await
|
|
1308
|
-
|
|
1472
|
+
await Promise.all(agentDirs.map(async (targetDir) => {
|
|
1473
|
+
await cleanAndCreateDirectory(targetDir);
|
|
1474
|
+
await writeSkillFiles(targetDir);
|
|
1475
|
+
}));
|
|
1309
1476
|
return {
|
|
1310
1477
|
success: true,
|
|
1311
|
-
path:
|
|
1478
|
+
path: agentDirs.join(", "),
|
|
1312
1479
|
mode: "copy"
|
|
1313
1480
|
};
|
|
1314
1481
|
}
|
|
@@ -1320,22 +1487,18 @@ async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
|
|
|
1320
1487
|
canonicalPath: canonicalDir,
|
|
1321
1488
|
mode: "symlink"
|
|
1322
1489
|
};
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
path: agentDir,
|
|
1329
|
-
canonicalPath: canonicalDir,
|
|
1330
|
-
mode: "symlink",
|
|
1331
|
-
symlinkFailed: true
|
|
1332
|
-
};
|
|
1490
|
+
let symlinkFailed = false;
|
|
1491
|
+
for (const targetDir of agentDirs) if (!await createSymlink(canonicalDir, targetDir)) {
|
|
1492
|
+
symlinkFailed = true;
|
|
1493
|
+
await cleanAndCreateDirectory(targetDir);
|
|
1494
|
+
await writeSkillFiles(targetDir);
|
|
1333
1495
|
}
|
|
1334
1496
|
return {
|
|
1335
1497
|
success: true,
|
|
1336
|
-
path:
|
|
1498
|
+
path: agentDirs.join(", "),
|
|
1337
1499
|
canonicalPath: canonicalDir,
|
|
1338
|
-
mode: "symlink"
|
|
1500
|
+
mode: "symlink",
|
|
1501
|
+
...symlinkFailed && { symlinkFailed: true }
|
|
1339
1502
|
};
|
|
1340
1503
|
} catch (error) {
|
|
1341
1504
|
return {
|
|
@@ -1362,10 +1525,10 @@ async function listInstalledSkills(options = {}) {
|
|
|
1362
1525
|
path: getCanonicalSkillsDir(isGlobal, cwd)
|
|
1363
1526
|
});
|
|
1364
1527
|
for (const agentType of agentsToCheck) {
|
|
1365
|
-
|
|
1366
|
-
if (isGlobal &&
|
|
1367
|
-
const
|
|
1368
|
-
if (!scopes.some((s) => s.path === agentDir && s.global === isGlobal)) scopes.push({
|
|
1528
|
+
agents[agentType];
|
|
1529
|
+
if (isGlobal && !agentSupportsGlobalInstall$1(agentType)) continue;
|
|
1530
|
+
const agentDirs = await getAgentBaseDirs(agentType, isGlobal, cwd);
|
|
1531
|
+
for (const agentDir of agentDirs) if (!scopes.some((s) => s.path === agentDir && s.global === isGlobal)) scopes.push({
|
|
1369
1532
|
global: isGlobal,
|
|
1370
1533
|
path: agentDir,
|
|
1371
1534
|
agentType
|
|
@@ -1404,41 +1567,47 @@ async function listInstalledSkills(options = {}) {
|
|
|
1404
1567
|
const sanitizedSkillName = sanitizeName(skill.name);
|
|
1405
1568
|
const installedAgents = [];
|
|
1406
1569
|
for (const agentType of agentsToCheck) {
|
|
1407
|
-
|
|
1408
|
-
if (scope.global &&
|
|
1409
|
-
const agentBase = scope.global ? agent.globalSkillsDir : join(cwd, agent.skillsDir);
|
|
1570
|
+
agents[agentType];
|
|
1571
|
+
if (scope.global && !agentSupportsGlobalInstall$1(agentType)) continue;
|
|
1410
1572
|
let found = false;
|
|
1573
|
+
const agentBases = await getAgentBaseDirs(agentType, scope.global, cwd);
|
|
1411
1574
|
const possibleNames = Array.from(new Set([
|
|
1412
1575
|
entry.name,
|
|
1413
1576
|
sanitizedSkillName,
|
|
1414
1577
|
skill.name.toLowerCase().replace(/\s+/g, "-").replace(/[\/\\:\0]/g, "")
|
|
1415
1578
|
]));
|
|
1416
|
-
for (const
|
|
1417
|
-
const
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
await access(agentSkillDir);
|
|
1421
|
-
found = true;
|
|
1422
|
-
break;
|
|
1423
|
-
} catch {}
|
|
1424
|
-
}
|
|
1425
|
-
if (!found) try {
|
|
1426
|
-
const agentEntries = await readdir(agentBase, { withFileTypes: true });
|
|
1427
|
-
for (const agentEntry of agentEntries) {
|
|
1428
|
-
if (!agentEntry.isDirectory()) continue;
|
|
1429
|
-
const candidateDir = join(agentBase, agentEntry.name);
|
|
1430
|
-
if (!isPathSafe(agentBase, candidateDir)) continue;
|
|
1579
|
+
for (const agentBase of agentBases) {
|
|
1580
|
+
for (const possibleName of possibleNames) {
|
|
1581
|
+
const agentSkillDir = join(agentBase, possibleName);
|
|
1582
|
+
if (!isPathSafe(agentBase, agentSkillDir)) continue;
|
|
1431
1583
|
try {
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
if (candidateSkill && candidateSkill.name === skill.name) {
|
|
1436
|
-
found = true;
|
|
1437
|
-
break;
|
|
1438
|
-
}
|
|
1584
|
+
await access(agentSkillDir);
|
|
1585
|
+
found = true;
|
|
1586
|
+
break;
|
|
1439
1587
|
} catch {}
|
|
1440
1588
|
}
|
|
1441
|
-
|
|
1589
|
+
if (found) break;
|
|
1590
|
+
}
|
|
1591
|
+
if (!found) for (const agentBase of agentBases) {
|
|
1592
|
+
try {
|
|
1593
|
+
const agentEntries = await readdir(agentBase, { withFileTypes: true });
|
|
1594
|
+
for (const agentEntry of agentEntries) {
|
|
1595
|
+
if (!agentEntry.isDirectory()) continue;
|
|
1596
|
+
const candidateDir = join(agentBase, agentEntry.name);
|
|
1597
|
+
if (!isPathSafe(agentBase, candidateDir)) continue;
|
|
1598
|
+
try {
|
|
1599
|
+
const candidateSkillMd = join(candidateDir, "SKILL.md");
|
|
1600
|
+
await stat(candidateSkillMd);
|
|
1601
|
+
const candidateSkill = await parseSkillMd(candidateSkillMd);
|
|
1602
|
+
if (candidateSkill && candidateSkill.name === skill.name) {
|
|
1603
|
+
found = true;
|
|
1604
|
+
break;
|
|
1605
|
+
}
|
|
1606
|
+
} catch {}
|
|
1607
|
+
}
|
|
1608
|
+
} catch {}
|
|
1609
|
+
if (found) break;
|
|
1610
|
+
}
|
|
1442
1611
|
if (found) installedAgents.push(agentType);
|
|
1443
1612
|
}
|
|
1444
1613
|
if (skillsMap.has(skillKey)) {
|
|
@@ -2070,7 +2239,7 @@ function createEmptyLocalLock() {
|
|
|
2070
2239
|
skills: {}
|
|
2071
2240
|
};
|
|
2072
2241
|
}
|
|
2073
|
-
var version$1 = "1.4.
|
|
2242
|
+
var version$1 = "1.4.12";
|
|
2074
2243
|
const isCancelled$1 = (value) => typeof value === "symbol";
|
|
2075
2244
|
async function isSourcePrivate(source) {
|
|
2076
2245
|
const ownerRepo = parseOwnerRepo(source);
|
|
@@ -2208,6 +2377,31 @@ function ensureUniversalAgents(targetAgents) {
|
|
|
2208
2377
|
for (const ua of universalAgents) if (!result.includes(ua)) result.push(ua);
|
|
2209
2378
|
return result;
|
|
2210
2379
|
}
|
|
2380
|
+
function agentSupportsGlobalInstall(agent) {
|
|
2381
|
+
return agents[agent].globalSkillsDir !== void 0 || agents[agent].resolveGlobalSkillsDirs !== void 0;
|
|
2382
|
+
}
|
|
2383
|
+
function agentSupportsScope(agent, global) {
|
|
2384
|
+
if (global === true) return agentSupportsGlobalInstall(agent);
|
|
2385
|
+
if (global === false) return agents[agent].supportsProjectInstall !== false;
|
|
2386
|
+
return true;
|
|
2387
|
+
}
|
|
2388
|
+
function filterProjectUnsupportedAgents(targetAgents, installGlobally, explicitlyRequestedAgents) {
|
|
2389
|
+
if (installGlobally) return targetAgents;
|
|
2390
|
+
const unsupported = targetAgents.filter((agent) => agents[agent].supportsProjectInstall === false);
|
|
2391
|
+
if (unsupported.length === 0) return targetAgents;
|
|
2392
|
+
const explicitUnsupported = explicitlyRequestedAgents?.filter((agent) => agent !== "*" && unsupported.includes(agent));
|
|
2393
|
+
if (explicitUnsupported && explicitUnsupported.length > 0) {
|
|
2394
|
+
M.error(`${formatList$1(unsupported.map((agent) => agents[agent].displayName))} only supports global skill installation. Use --global.`);
|
|
2395
|
+
process.exit(1);
|
|
2396
|
+
}
|
|
2397
|
+
M.warn(`Skipping ${formatList$1(unsupported.map((agent) => agents[agent].displayName))}: global-only agent`);
|
|
2398
|
+
const filtered = targetAgents.filter((agent) => agents[agent].supportsProjectInstall !== false);
|
|
2399
|
+
if (filtered.length === 0) {
|
|
2400
|
+
M.error("No selected agents support project skill installation.");
|
|
2401
|
+
process.exit(1);
|
|
2402
|
+
}
|
|
2403
|
+
return filtered;
|
|
2404
|
+
}
|
|
2211
2405
|
function buildResultLines(results, targetAgents) {
|
|
2212
2406
|
const lines = [];
|
|
2213
2407
|
const { universal, symlinked: symlinkAgents } = splitAgentsByType(targetAgents);
|
|
@@ -2251,9 +2445,9 @@ async function promptForAgents(message, choices) {
|
|
|
2251
2445
|
return selected;
|
|
2252
2446
|
}
|
|
2253
2447
|
async function selectAgentsInteractive(options) {
|
|
2254
|
-
const
|
|
2255
|
-
const universalAgents = getUniversalAgents().filter(
|
|
2256
|
-
const otherAgents = getNonUniversalAgents().filter(
|
|
2448
|
+
const supportsScopeFilter = (a) => agentSupportsScope(a, options.global);
|
|
2449
|
+
const universalAgents = getUniversalAgents().filter(supportsScopeFilter);
|
|
2450
|
+
const otherAgents = getNonUniversalAgents().filter(supportsScopeFilter);
|
|
2257
2451
|
const universalSection = {
|
|
2258
2452
|
title: "Universal (.agents/skills)",
|
|
2259
2453
|
items: universalAgents.map((a) => ({
|
|
@@ -2312,8 +2506,11 @@ function reportInstallToSunIfNeeded(params) {
|
|
|
2312
2506
|
function isBareSkillNameSource(source) {
|
|
2313
2507
|
return /^[a-z0-9]([a-z0-9-]{0,62}[a-z0-9])?$/.test(source);
|
|
2314
2508
|
}
|
|
2509
|
+
function isFilesystemPathLike(source) {
|
|
2510
|
+
return isAbsolute(source) || source === "~" || source.startsWith("~/") || source.startsWith("~\\") || source.startsWith("./") || source.startsWith("../") || source === "." || source === ".." || /^[a-zA-Z]:[/\\]/.test(source);
|
|
2511
|
+
}
|
|
2315
2512
|
function shouldProbeDefaultWellKnownPath(source) {
|
|
2316
|
-
return source.includes("/") && !source.includes("@") && !source.startsWith("http://") && !source.startsWith("https://") && !source.startsWith("git@") && !source.startsWith("ssh://") && !
|
|
2513
|
+
return source.includes("/") && !source.includes("@") && !source.startsWith("http://") && !source.startsWith("https://") && !source.startsWith("git@") && !source.startsWith("ssh://") && !isFilesystemPathLike(source);
|
|
2317
2514
|
}
|
|
2318
2515
|
function buildFallbackGitSshUrl(source) {
|
|
2319
2516
|
return `git@${DEFAULT_GIT_FALLBACK_SSH_HOST}:${source.replace(/\.git$/, "")}.git`;
|
|
@@ -2441,7 +2638,7 @@ async function handleWellKnownSkills(source, url, options, spinner, allowFallbac
|
|
|
2441
2638
|
}
|
|
2442
2639
|
}
|
|
2443
2640
|
let installGlobally = options.global ?? false;
|
|
2444
|
-
const supportsGlobal = targetAgents.some(
|
|
2641
|
+
const supportsGlobal = targetAgents.some(agentSupportsGlobalInstall);
|
|
2445
2642
|
if (options.global === void 0 && !options.yes && supportsGlobal) {
|
|
2446
2643
|
const scope = await ve({
|
|
2447
2644
|
message: "Installation scope",
|
|
@@ -2461,6 +2658,7 @@ async function handleWellKnownSkills(source, url, options, spinner, allowFallbac
|
|
|
2461
2658
|
}
|
|
2462
2659
|
installGlobally = scope;
|
|
2463
2660
|
}
|
|
2661
|
+
targetAgents = filterProjectUnsupportedAgents(targetAgents, installGlobally, options.agent);
|
|
2464
2662
|
let installMode = options.copy ? "copy" : "symlink";
|
|
2465
2663
|
if (!options.copy && !options.yes) {
|
|
2466
2664
|
const modeChoice = await ve({
|
|
@@ -2900,7 +3098,7 @@ async function runAdd(args, options = {}) {
|
|
|
2900
3098
|
}
|
|
2901
3099
|
}
|
|
2902
3100
|
let installGlobally = options.global ?? false;
|
|
2903
|
-
const supportsGlobal = targetAgents.some(
|
|
3101
|
+
const supportsGlobal = targetAgents.some(agentSupportsGlobalInstall);
|
|
2904
3102
|
if (options.global === void 0 && !options.yes && supportsGlobal) {
|
|
2905
3103
|
const scope = await ve({
|
|
2906
3104
|
message: "Installation scope",
|
|
@@ -2921,6 +3119,7 @@ async function runAdd(args, options = {}) {
|
|
|
2921
3119
|
}
|
|
2922
3120
|
installGlobally = scope;
|
|
2923
3121
|
}
|
|
3122
|
+
targetAgents = filterProjectUnsupportedAgents(targetAgents, installGlobally, options.agent);
|
|
2924
3123
|
let installMode = options.copy ? "copy" : "symlink";
|
|
2925
3124
|
if (!options.copy && !options.yes) {
|
|
2926
3125
|
const modeChoice = await ve({
|
|
@@ -3611,9 +3810,10 @@ async function runSync(args, options = {}) {
|
|
|
3611
3810
|
M.info(`${toInstall.length} skill${toInstall.length !== 1 ? "s" : ""} to install/update`);
|
|
3612
3811
|
let targetAgents;
|
|
3613
3812
|
const validAgents = Object.keys(agents);
|
|
3813
|
+
const projectAgents = validAgents.filter((agent) => agents[agent].supportsProjectInstall !== false);
|
|
3614
3814
|
const universalAgents = getUniversalAgents();
|
|
3615
3815
|
if (options.agent?.includes("*")) {
|
|
3616
|
-
targetAgents =
|
|
3816
|
+
targetAgents = projectAgents;
|
|
3617
3817
|
M.info(`Installing to all ${targetAgents.length} agents`);
|
|
3618
3818
|
} else if (options.agent && options.agent.length > 0) {
|
|
3619
3819
|
const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
|
|
@@ -3622,7 +3822,11 @@ async function runSync(args, options = {}) {
|
|
|
3622
3822
|
M.info(`Valid agents: ${validAgents.join(", ")}`);
|
|
3623
3823
|
process.exit(1);
|
|
3624
3824
|
}
|
|
3625
|
-
targetAgents = options.agent
|
|
3825
|
+
targetAgents = options.agent.filter((agent) => {
|
|
3826
|
+
if (agents[agent].supportsProjectInstall !== false) return true;
|
|
3827
|
+
M.error(`${agents[agent].displayName} only supports global skill installation.`);
|
|
3828
|
+
process.exit(1);
|
|
3829
|
+
});
|
|
3626
3830
|
} else {
|
|
3627
3831
|
spinner.start("Loading agents...");
|
|
3628
3832
|
const installedAgents = await detectInstalledAgents();
|
|
@@ -3634,7 +3838,7 @@ async function runSync(args, options = {}) {
|
|
|
3634
3838
|
} else {
|
|
3635
3839
|
const selected = await searchMultiselect({
|
|
3636
3840
|
message: "Which agents do you want to install to?",
|
|
3637
|
-
items: getNonUniversalAgents().map((a) => ({
|
|
3841
|
+
items: getNonUniversalAgents().filter((agent) => agents[agent].supportsProjectInstall !== false).map((a) => ({
|
|
3638
3842
|
value: a,
|
|
3639
3843
|
label: agents[a].displayName,
|
|
3640
3844
|
hint: agents[a].skillsDir
|
|
@@ -3655,12 +3859,12 @@ async function runSync(args, options = {}) {
|
|
|
3655
3859
|
targetAgents = selected;
|
|
3656
3860
|
}
|
|
3657
3861
|
else if (installedAgents.length === 1 || options.yes) {
|
|
3658
|
-
targetAgents = [
|
|
3862
|
+
targetAgents = installedAgents.filter((agent) => agents[agent].supportsProjectInstall !== false);
|
|
3659
3863
|
for (const ua of universalAgents) if (!targetAgents.includes(ua)) targetAgents.push(ua);
|
|
3660
3864
|
} else {
|
|
3661
3865
|
const selected = await searchMultiselect({
|
|
3662
3866
|
message: "Which agents do you want to install to?",
|
|
3663
|
-
items: getNonUniversalAgents().filter((a) => installedAgents.includes(a)).map((a) => ({
|
|
3867
|
+
items: getNonUniversalAgents().filter((a) => installedAgents.includes(a) && agents[a].supportsProjectInstall !== false).map((a) => ({
|
|
3664
3868
|
value: a,
|
|
3665
3869
|
label: agents[a].displayName,
|
|
3666
3870
|
hint: agents[a].skillsDir
|
|
@@ -3941,10 +4145,13 @@ async function removeCommand(skillNames, options) {
|
|
|
3941
4145
|
};
|
|
3942
4146
|
if (isGlobal) {
|
|
3943
4147
|
await scanDir(getCanonicalSkillsDir(true, cwd));
|
|
3944
|
-
for (const
|
|
4148
|
+
for (const agentType of Object.keys(agents)) {
|
|
4149
|
+
const agent = agents[agentType];
|
|
4150
|
+
if (agent.globalSkillsDir !== void 0 || agent.resolveGlobalSkillsDirs !== void 0) for (const agentDir of await getAgentBaseDirs(agentType, true, cwd)) await scanDir(agentDir);
|
|
4151
|
+
}
|
|
3945
4152
|
} else {
|
|
3946
4153
|
await scanDir(getCanonicalSkillsDir(false, cwd));
|
|
3947
|
-
for (const agent of Object.values(agents)) await scanDir(join(cwd, agent.skillsDir));
|
|
4154
|
+
for (const agent of Object.values(agents).filter((agent) => agent.supportsProjectInstall !== false)) await scanDir(join(cwd, agent.skillsDir));
|
|
3948
4155
|
}
|
|
3949
4156
|
const installedSkills = Array.from(skillNamesSet).sort();
|
|
3950
4157
|
spinner.stop(`Found ${installedSkills.length} unique installed skill(s)`);
|
|
@@ -4011,14 +4218,16 @@ async function removeCommand(skillNames, options) {
|
|
|
4011
4218
|
});
|
|
4012
4219
|
for (const agentKey of targetAgents) {
|
|
4013
4220
|
const agent = agents[agentKey];
|
|
4014
|
-
const
|
|
4221
|
+
const skillPaths = await getInstallPaths(skillName, agentKey, {
|
|
4015
4222
|
global: isGlobal,
|
|
4016
4223
|
cwd
|
|
4017
4224
|
});
|
|
4018
|
-
const pathsToCleanup = new Set(
|
|
4225
|
+
const pathsToCleanup = new Set(skillPaths);
|
|
4019
4226
|
const sanitizedName = sanitizeName(skillName);
|
|
4020
|
-
if (isGlobal
|
|
4021
|
-
|
|
4227
|
+
if (isGlobal) {
|
|
4228
|
+
const globalDirs = await getAgentBaseDirs(agentKey, true, cwd);
|
|
4229
|
+
for (const globalDir of globalDirs) pathsToCleanup.add(join(globalDir, sanitizedName));
|
|
4230
|
+
} else if (agent.supportsProjectInstall !== false) pathsToCleanup.add(join(cwd, agent.skillsDir, sanitizedName));
|
|
4022
4231
|
for (const pathToCleanup of pathsToCleanup) {
|
|
4023
4232
|
if (pathToCleanup === canonicalPath) continue;
|
|
4024
4233
|
try {
|
|
@@ -4033,12 +4242,16 @@ async function removeCommand(skillNames, options) {
|
|
|
4033
4242
|
}
|
|
4034
4243
|
const remainingAgents = (await detectInstalledAgents()).filter((a) => !targetAgents.includes(a));
|
|
4035
4244
|
let isStillUsed = false;
|
|
4036
|
-
for (const agentKey of remainingAgents)
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4245
|
+
for (const agentKey of remainingAgents) {
|
|
4246
|
+
const paths = await getInstallPaths(skillName, agentKey, {
|
|
4247
|
+
global: isGlobal,
|
|
4248
|
+
cwd
|
|
4249
|
+
});
|
|
4250
|
+
for (const path of paths) if (await lstat(path).catch(() => null)) {
|
|
4251
|
+
isStillUsed = true;
|
|
4252
|
+
break;
|
|
4253
|
+
}
|
|
4254
|
+
if (isStillUsed) break;
|
|
4042
4255
|
}
|
|
4043
4256
|
if (!isStillUsed) await rm(canonicalPath, {
|
|
4044
4257
|
recursive: true,
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bip-skills",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.12",
|
|
4
4
|
"description": "The open agent skills ecosystem",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"bip-skills": "
|
|
8
|
-
"skills": "
|
|
9
|
-
"add-skill": "
|
|
7
|
+
"bip-skills": "bin/cli.mjs",
|
|
8
|
+
"skills": "bin/cli.mjs",
|
|
9
|
+
"add-skill": "bin/cli.mjs"
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|
|
@@ -14,6 +14,21 @@
|
|
|
14
14
|
"README.md",
|
|
15
15
|
"ThirdPartyNoticeText.txt"
|
|
16
16
|
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "obuild && node scripts/generate-licenses.ts",
|
|
19
|
+
"generate-licenses": "node scripts/generate-licenses.ts",
|
|
20
|
+
"dev": "node src/cli.ts",
|
|
21
|
+
"exec:test": "node scripts/execute-tests.ts",
|
|
22
|
+
"pack:check": "npm pack --dry-run --ignore-scripts --cache .npm-cache",
|
|
23
|
+
"prepublishOnly": "npm run build",
|
|
24
|
+
"publish:npm": "node scripts/publish-npm.ts",
|
|
25
|
+
"format": "prettier --write 'src/**/*.ts' 'scripts/**/*.ts'",
|
|
26
|
+
"format:check": "prettier --check 'src/**/*.ts' 'scripts/**/*.ts'",
|
|
27
|
+
"prepare": "husky",
|
|
28
|
+
"test": "vitest",
|
|
29
|
+
"type-check": "tsc --noEmit",
|
|
30
|
+
"publish:snapshot": "npm version prerelease --preid=snapshot --no-git-tag-version && npm publish --tag snapshot"
|
|
31
|
+
},
|
|
17
32
|
"lint-staged": {
|
|
18
33
|
"src/**/*.ts": "prettier --write",
|
|
19
34
|
"scripts/**/*.ts": "prettier --write",
|
|
@@ -29,6 +44,7 @@
|
|
|
29
44
|
"augment",
|
|
30
45
|
"claude-code",
|
|
31
46
|
"openclaw",
|
|
47
|
+
"yonclaw",
|
|
32
48
|
"cline",
|
|
33
49
|
"codebuddy",
|
|
34
50
|
"codex",
|
|
@@ -95,16 +111,5 @@
|
|
|
95
111
|
"engines": {
|
|
96
112
|
"node": ">=18"
|
|
97
113
|
},
|
|
98
|
-
"
|
|
99
|
-
|
|
100
|
-
"generate-licenses": "node scripts/generate-licenses.ts",
|
|
101
|
-
"dev": "node src/cli.ts",
|
|
102
|
-
"exec:test": "node scripts/execute-tests.ts",
|
|
103
|
-
"pack:check": "npm pack --dry-run --ignore-scripts --cache .npm-cache",
|
|
104
|
-
"format": "prettier --write 'src/**/*.ts' 'scripts/**/*.ts'",
|
|
105
|
-
"format:check": "prettier --check 'src/**/*.ts' 'scripts/**/*.ts'",
|
|
106
|
-
"test": "vitest",
|
|
107
|
-
"type-check": "tsc --noEmit",
|
|
108
|
-
"publish:snapshot": "npm version prerelease --preid=snapshot --no-git-tag-version && npm publish --tag snapshot"
|
|
109
|
-
}
|
|
110
|
-
}
|
|
114
|
+
"packageManager": "pnpm@10.17.1"
|
|
115
|
+
}
|