oathbound 0.15.1 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +311 -156
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -14157,6 +14157,7 @@ __export(exports_cli, {
|
|
|
14157
14157
|
mergeClaudeSettings: () => mergeClaudeSettings,
|
|
14158
14158
|
isNewer: () => isNewer,
|
|
14159
14159
|
installDevDependency: () => installDevDependency,
|
|
14160
|
+
findSkillsDirs: () => findSkillsDirs,
|
|
14160
14161
|
addPrepareScript: () => addPrepareScript
|
|
14161
14162
|
});
|
|
14162
14163
|
module.exports = __toCommonJS(exports_cli);
|
|
@@ -16478,9 +16479,9 @@ if (shouldShowDeprecationWarning())
|
|
|
16478
16479
|
|
|
16479
16480
|
// cli.ts
|
|
16480
16481
|
var import_node_crypto2 = require("node:crypto");
|
|
16481
|
-
var
|
|
16482
|
-
var
|
|
16483
|
-
var
|
|
16482
|
+
var import_node_child_process3 = require("node:child_process");
|
|
16483
|
+
var import_node_fs9 = require("node:fs");
|
|
16484
|
+
var import_node_path9 = require("node:path");
|
|
16484
16485
|
var import_node_os4 = require("node:os");
|
|
16485
16486
|
|
|
16486
16487
|
// node_modules/@clack/core/dist/index.mjs
|
|
@@ -17094,9 +17095,9 @@ function usage(exitCode = 1) {
|
|
|
17094
17095
|
${BOLD}oathbound${RESET} — install, verify, and publish skills & agents
|
|
17095
17096
|
|
|
17096
17097
|
${DIM}Usage:${RESET}
|
|
17097
|
-
oathbound init
|
|
17098
|
-
oathbound pull <namespace/skill-name[@version]>
|
|
17099
|
-
oathbound install <namespace/skill-name[@version]>
|
|
17098
|
+
oathbound init [--global|--local] ${DIM}Setup wizard (default: global + local)${RESET}
|
|
17099
|
+
oathbound pull <namespace/skill-name[@version]> [--global]
|
|
17100
|
+
oathbound install <namespace/skill-name[@version]> [--global]
|
|
17100
17101
|
oathbound push [path] [--private] ${DIM}Publish a skill to the registry${RESET}
|
|
17101
17102
|
oathbound search [query] ${DIM}Search skills in the registry${RESET}
|
|
17102
17103
|
oathbound list ${DIM}List all public skills${RESET}
|
|
@@ -17256,8 +17257,9 @@ function hasOathboundHooks(settings) {
|
|
|
17256
17257
|
}
|
|
17257
17258
|
return false;
|
|
17258
17259
|
}
|
|
17259
|
-
function mergeClaudeSettings() {
|
|
17260
|
-
const
|
|
17260
|
+
function mergeClaudeSettings(targetDir) {
|
|
17261
|
+
const baseDir = targetDir ?? process.cwd();
|
|
17262
|
+
const claudeDir = import_node_path.join(baseDir, ".claude");
|
|
17261
17263
|
const settingsPath = import_node_path.join(claudeDir, "settings.json");
|
|
17262
17264
|
if (!import_node_fs.existsSync(settingsPath)) {
|
|
17263
17265
|
import_node_fs.mkdirSync(claudeDir, { recursive: true });
|
|
@@ -17380,8 +17382,8 @@ function compareSemver(a, b) {
|
|
|
17380
17382
|
}
|
|
17381
17383
|
|
|
17382
17384
|
// verify.ts
|
|
17383
|
-
var
|
|
17384
|
-
var
|
|
17385
|
+
var import_node_fs5 = require("node:fs");
|
|
17386
|
+
var import_node_path5 = require("node:path");
|
|
17385
17387
|
var import_node_os2 = require("node:os");
|
|
17386
17388
|
var import_yaml = __toESM(require_dist(), 1);
|
|
17387
17389
|
|
|
@@ -17424,9 +17426,66 @@ function hashSkillDir(skillDir) {
|
|
|
17424
17426
|
return contentHash(files);
|
|
17425
17427
|
}
|
|
17426
17428
|
|
|
17429
|
+
// project-setup.ts
|
|
17430
|
+
var import_node_child_process = require("node:child_process");
|
|
17431
|
+
var import_node_fs4 = require("node:fs");
|
|
17432
|
+
var import_node_path4 = require("node:path");
|
|
17433
|
+
function detectPackageManager() {
|
|
17434
|
+
if (import_node_fs4.existsSync(import_node_path4.join(process.cwd(), "bun.lockb")) || import_node_fs4.existsSync(import_node_path4.join(process.cwd(), "bun.lock")))
|
|
17435
|
+
return "bun";
|
|
17436
|
+
if (import_node_fs4.existsSync(import_node_path4.join(process.cwd(), "pnpm-lock.yaml")))
|
|
17437
|
+
return "pnpm";
|
|
17438
|
+
if (import_node_fs4.existsSync(import_node_path4.join(process.cwd(), "yarn.lock")))
|
|
17439
|
+
return "yarn";
|
|
17440
|
+
return "npm";
|
|
17441
|
+
}
|
|
17442
|
+
function installDevDependency() {
|
|
17443
|
+
const pkgPath = import_node_path4.join(process.cwd(), "package.json");
|
|
17444
|
+
if (!import_node_fs4.existsSync(pkgPath))
|
|
17445
|
+
return "no-package-json";
|
|
17446
|
+
try {
|
|
17447
|
+
const pkg = JSON.parse(import_node_fs4.readFileSync(pkgPath, "utf-8"));
|
|
17448
|
+
if (pkg.devDependencies?.oathbound || pkg.dependencies?.oathbound)
|
|
17449
|
+
return "skipped";
|
|
17450
|
+
} catch {}
|
|
17451
|
+
const pm = detectPackageManager();
|
|
17452
|
+
const cmds = {
|
|
17453
|
+
bun: ["bun", ["add", "--dev", "oathbound"]],
|
|
17454
|
+
pnpm: ["pnpm", ["add", "--save-dev", "oathbound"]],
|
|
17455
|
+
yarn: ["yarn", ["add", "--dev", "oathbound"]],
|
|
17456
|
+
npm: ["npm", ["install", "--save-dev", "oathbound"]]
|
|
17457
|
+
};
|
|
17458
|
+
const [bin, args] = cmds[pm];
|
|
17459
|
+
try {
|
|
17460
|
+
import_node_child_process.execFileSync(bin, args, { stdio: "pipe", cwd: process.cwd() });
|
|
17461
|
+
return "installed";
|
|
17462
|
+
} catch {
|
|
17463
|
+
return "failed";
|
|
17464
|
+
}
|
|
17465
|
+
}
|
|
17466
|
+
function addPrepareScript() {
|
|
17467
|
+
const pkgPath = import_node_path4.join(process.cwd(), "package.json");
|
|
17468
|
+
if (!import_node_fs4.existsSync(pkgPath))
|
|
17469
|
+
return "skipped";
|
|
17470
|
+
let pkg;
|
|
17471
|
+
try {
|
|
17472
|
+
pkg = JSON.parse(import_node_fs4.readFileSync(pkgPath, "utf-8"));
|
|
17473
|
+
} catch {
|
|
17474
|
+
return "skipped";
|
|
17475
|
+
}
|
|
17476
|
+
const prepare = pkg.scripts?.prepare ?? "";
|
|
17477
|
+
if (prepare.includes("oathbound setup"))
|
|
17478
|
+
return "skipped";
|
|
17479
|
+
const newPrepare = prepare ? `${prepare} && oathbound setup` : "oathbound setup";
|
|
17480
|
+
pkg.scripts = { ...pkg.scripts ?? {}, prepare: newPrepare };
|
|
17481
|
+
import_node_fs4.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + `
|
|
17482
|
+
`);
|
|
17483
|
+
return prepare ? "appended" : "added";
|
|
17484
|
+
}
|
|
17485
|
+
|
|
17427
17486
|
// verify.ts
|
|
17428
17487
|
function sessionStatePath(sessionId) {
|
|
17429
|
-
return
|
|
17488
|
+
return import_node_path5.join(import_node_os2.tmpdir(), `oathbound-${sessionId}.json`);
|
|
17430
17489
|
}
|
|
17431
17490
|
async function readStdin() {
|
|
17432
17491
|
const chunks = [];
|
|
@@ -17435,45 +17494,113 @@ async function readStdin() {
|
|
|
17435
17494
|
}
|
|
17436
17495
|
return Buffer.concat(chunks).toString("utf-8");
|
|
17437
17496
|
}
|
|
17438
|
-
function
|
|
17497
|
+
function resolveLocalSkillsDir() {
|
|
17439
17498
|
const cwd = process.cwd();
|
|
17440
17499
|
const normalized = cwd.replace(/\/+$/, "");
|
|
17441
17500
|
if (normalized.endsWith(".claude/skills"))
|
|
17442
17501
|
return cwd;
|
|
17443
17502
|
if (normalized.endsWith(".claude")) {
|
|
17444
|
-
const skills =
|
|
17445
|
-
if (
|
|
17503
|
+
const skills = import_node_path5.join(cwd, "skills");
|
|
17504
|
+
if (import_node_fs5.existsSync(skills))
|
|
17446
17505
|
return skills;
|
|
17447
17506
|
}
|
|
17448
|
-
const direct =
|
|
17449
|
-
if (
|
|
17507
|
+
const direct = import_node_path5.join(cwd, ".claude", "skills");
|
|
17508
|
+
if (import_node_fs5.existsSync(direct))
|
|
17450
17509
|
return direct;
|
|
17451
17510
|
const SKIP = new Set(["node_modules", ".git", "dist", "build", ".next"]);
|
|
17452
17511
|
function search(dir, depth) {
|
|
17453
17512
|
if (depth <= 0)
|
|
17454
17513
|
return null;
|
|
17455
17514
|
try {
|
|
17456
|
-
const entries =
|
|
17515
|
+
const entries = import_node_fs5.readdirSync(dir, { withFileTypes: true });
|
|
17457
17516
|
for (const entry of entries) {
|
|
17458
17517
|
if (!entry.isDirectory() || SKIP.has(entry.name))
|
|
17459
17518
|
continue;
|
|
17460
17519
|
if (entry.name === ".claude") {
|
|
17461
|
-
const skills =
|
|
17462
|
-
if (
|
|
17520
|
+
const skills = import_node_path5.join(dir, ".claude", "skills");
|
|
17521
|
+
if (import_node_fs5.existsSync(skills))
|
|
17463
17522
|
return skills;
|
|
17464
17523
|
}
|
|
17465
17524
|
}
|
|
17466
17525
|
for (const entry of entries) {
|
|
17467
17526
|
if (!entry.isDirectory() || SKIP.has(entry.name) || entry.name.startsWith("."))
|
|
17468
17527
|
continue;
|
|
17469
|
-
const result = search(
|
|
17528
|
+
const result = search(import_node_path5.join(dir, entry.name), depth - 1);
|
|
17470
17529
|
if (result)
|
|
17471
17530
|
return result;
|
|
17472
17531
|
}
|
|
17473
17532
|
} catch {}
|
|
17474
17533
|
return null;
|
|
17475
17534
|
}
|
|
17476
|
-
return search(cwd, 5)
|
|
17535
|
+
return search(cwd, 5);
|
|
17536
|
+
}
|
|
17537
|
+
function hasSkillSubdirs(dir) {
|
|
17538
|
+
try {
|
|
17539
|
+
const entries = import_node_fs5.readdirSync(dir, { withFileTypes: true });
|
|
17540
|
+
return entries.some((e) => e.isDirectory() && !e.name.startsWith("."));
|
|
17541
|
+
} catch {
|
|
17542
|
+
return false;
|
|
17543
|
+
}
|
|
17544
|
+
}
|
|
17545
|
+
function findSkillsDirs() {
|
|
17546
|
+
const results = [];
|
|
17547
|
+
const globalDir = import_node_path5.join(import_node_os2.homedir(), ".claude", "skills");
|
|
17548
|
+
if (import_node_fs5.existsSync(globalDir) && hasSkillSubdirs(globalDir)) {
|
|
17549
|
+
results.push({ path: globalDir, source: "global" });
|
|
17550
|
+
}
|
|
17551
|
+
const localDir = resolveLocalSkillsDir();
|
|
17552
|
+
if (localDir && hasSkillSubdirs(localDir)) {
|
|
17553
|
+
results.push({ path: localDir, source: "local" });
|
|
17554
|
+
}
|
|
17555
|
+
return results;
|
|
17556
|
+
}
|
|
17557
|
+
function propagateToProject() {
|
|
17558
|
+
try {
|
|
17559
|
+
const cwd = process.cwd();
|
|
17560
|
+
const localSkills = import_node_path5.join(cwd, ".claude", "skills");
|
|
17561
|
+
if (!import_node_fs5.existsSync(localSkills))
|
|
17562
|
+
return;
|
|
17563
|
+
if (!hasSkillSubdirs(localSkills))
|
|
17564
|
+
return;
|
|
17565
|
+
if (import_node_fs5.existsSync(import_node_path5.join(cwd, ".oathbound.jsonc")))
|
|
17566
|
+
return;
|
|
17567
|
+
const pkgPath = import_node_path5.join(cwd, "package.json");
|
|
17568
|
+
if (!import_node_fs5.existsSync(pkgPath))
|
|
17569
|
+
return;
|
|
17570
|
+
writeOathboundConfig("warn");
|
|
17571
|
+
const raw = import_node_fs5.readFileSync(pkgPath, "utf-8");
|
|
17572
|
+
const pkg = JSON.parse(raw);
|
|
17573
|
+
if (!pkg.devDependencies?.oathbound && !pkg.dependencies?.oathbound) {
|
|
17574
|
+
pkg.devDependencies = { ...pkg.devDependencies ?? {}, oathbound: "latest" };
|
|
17575
|
+
const indent = raw.match(/^(\s+)/m)?.[1]?.length ?? 2;
|
|
17576
|
+
import_node_fs5.writeFileSync(pkgPath, JSON.stringify(pkg, null, indent) + `
|
|
17577
|
+
`);
|
|
17578
|
+
}
|
|
17579
|
+
addPrepareScript();
|
|
17580
|
+
mergeClaudeSettings();
|
|
17581
|
+
process.stderr.write(`
|
|
17582
|
+
Oathbound: configured project for team verification.
|
|
17583
|
+
`);
|
|
17584
|
+
process.stderr.write(` Created .oathbound.jsonc
|
|
17585
|
+
`);
|
|
17586
|
+
process.stderr.write(` Added oathbound to devDependencies
|
|
17587
|
+
`);
|
|
17588
|
+
process.stderr.write(` Added prepare script to package.json
|
|
17589
|
+
|
|
17590
|
+
`);
|
|
17591
|
+
process.stderr.write(` Commit these changes to protect your team:
|
|
17592
|
+
`);
|
|
17593
|
+
process.stderr.write(` git add .oathbound.jsonc package.json .claude/settings.json
|
|
17594
|
+
|
|
17595
|
+
`);
|
|
17596
|
+
process.stderr.write(` Then run: npm install (or bun/pnpm install)
|
|
17597
|
+
|
|
17598
|
+
`);
|
|
17599
|
+
} catch (err) {
|
|
17600
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
17601
|
+
process.stderr.write(`oathbound: auto-propagation warning: ${msg}
|
|
17602
|
+
`);
|
|
17603
|
+
}
|
|
17477
17604
|
}
|
|
17478
17605
|
function skillNameFromPath(filePath) {
|
|
17479
17606
|
const marker = ".claude/skills/";
|
|
@@ -17516,30 +17643,34 @@ ${TEAL}${BOLD}⬡ oathbound${RESET} ${YELLOW}⚠ Warning:${RESET} skill ${BOLD}"
|
|
|
17516
17643
|
`);
|
|
17517
17644
|
process.exit(0);
|
|
17518
17645
|
}
|
|
17519
|
-
function isExternalSkillAccess(toolName, toolInput,
|
|
17520
|
-
const
|
|
17646
|
+
function isExternalSkillAccess(toolName, toolInput, knownDirs, baseName) {
|
|
17647
|
+
const resolvedDirs = knownDirs.map((d) => import_node_path5.resolve(d));
|
|
17648
|
+
const isUnderKnownDir = (p) => {
|
|
17649
|
+
const rp = import_node_path5.resolve(p);
|
|
17650
|
+
return resolvedDirs.some((d) => rp.startsWith(d));
|
|
17651
|
+
};
|
|
17521
17652
|
if (toolName === "Read") {
|
|
17522
17653
|
const p = String(toolInput.file_path ?? "");
|
|
17523
|
-
if (p && !
|
|
17654
|
+
if (p && !isUnderKnownDir(p))
|
|
17524
17655
|
return true;
|
|
17525
17656
|
}
|
|
17526
17657
|
if (toolName === "Glob" || toolName === "Grep") {
|
|
17527
17658
|
const p = String(toolInput.path ?? "");
|
|
17528
|
-
if (p && !
|
|
17659
|
+
if (p && !isUnderKnownDir(p))
|
|
17529
17660
|
return true;
|
|
17530
17661
|
}
|
|
17531
17662
|
if (toolName === "Bash") {
|
|
17532
17663
|
const cmd = String(toolInput.command ?? "");
|
|
17533
|
-
if (cmd.includes("/.claude/skills/" + baseName) && !cmd.includes(
|
|
17664
|
+
if (cmd.includes("/.claude/skills/" + baseName) && !resolvedDirs.some((d) => cmd.includes(d)))
|
|
17534
17665
|
return true;
|
|
17535
17666
|
}
|
|
17536
17667
|
return false;
|
|
17537
17668
|
}
|
|
17538
17669
|
function parseSkillVersion(skillDir) {
|
|
17539
|
-
const skillMdPath =
|
|
17540
|
-
if (!
|
|
17670
|
+
const skillMdPath = import_node_path5.join(skillDir, "SKILL.md");
|
|
17671
|
+
if (!import_node_fs5.existsSync(skillMdPath))
|
|
17541
17672
|
return null;
|
|
17542
|
-
const content =
|
|
17673
|
+
const content = import_node_fs5.readFileSync(skillMdPath, "utf-8");
|
|
17543
17674
|
const match = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n/);
|
|
17544
17675
|
if (!match)
|
|
17545
17676
|
return null;
|
|
@@ -17569,28 +17700,32 @@ async function verify(supabaseUrl, supabaseAnonKey) {
|
|
|
17569
17700
|
`);
|
|
17570
17701
|
process.exit(1);
|
|
17571
17702
|
}
|
|
17572
|
-
const
|
|
17573
|
-
|
|
17703
|
+
const skillsDirs = findSkillsDirs();
|
|
17704
|
+
propagateToProject();
|
|
17705
|
+
if (skillsDirs.length === 0) {
|
|
17574
17706
|
const state2 = { verified: {}, rejected: [], ok: true };
|
|
17575
|
-
|
|
17576
|
-
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: "Oathbound: no
|
|
17707
|
+
import_node_fs5.writeFileSync(sessionStatePath(sessionId), JSON.stringify(state2));
|
|
17708
|
+
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: "Oathbound: no skills found — nothing to verify." } }));
|
|
17577
17709
|
process.exit(0);
|
|
17578
17710
|
}
|
|
17579
|
-
const
|
|
17580
|
-
const
|
|
17581
|
-
|
|
17711
|
+
const localSkills = {};
|
|
17712
|
+
for (const { path: dir } of skillsDirs) {
|
|
17713
|
+
const entries = import_node_fs5.readdirSync(dir, { withFileTypes: true });
|
|
17714
|
+
for (const e of entries.filter((e2) => e2.isDirectory() && !e2.name.startsWith("."))) {
|
|
17715
|
+
const fullPath = import_node_path5.join(dir, e.name);
|
|
17716
|
+
localSkills[e.name] = {
|
|
17717
|
+
hash: hashSkillDir(fullPath),
|
|
17718
|
+
version: parseSkillVersion(fullPath) ?? "1.0.0",
|
|
17719
|
+
dir: fullPath
|
|
17720
|
+
};
|
|
17721
|
+
}
|
|
17722
|
+
}
|
|
17723
|
+
if (Object.keys(localSkills).length === 0) {
|
|
17582
17724
|
const state2 = { verified: {}, rejected: [], ok: true };
|
|
17583
|
-
|
|
17725
|
+
import_node_fs5.writeFileSync(sessionStatePath(sessionId), JSON.stringify(state2));
|
|
17584
17726
|
console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: "Oathbound: no skills installed — nothing to verify." } }));
|
|
17585
17727
|
process.exit(0);
|
|
17586
17728
|
}
|
|
17587
|
-
const localSkills = {};
|
|
17588
|
-
for (const dir of skillDirs) {
|
|
17589
|
-
const fullPath = import_node_path4.join(skillsDir, dir.name);
|
|
17590
|
-
const hash = hashSkillDir(fullPath);
|
|
17591
|
-
const version3 = parseSkillVersion(fullPath) ?? "1.0.0";
|
|
17592
|
-
localSkills[dir.name] = { hash, version: version3 };
|
|
17593
|
-
}
|
|
17594
17729
|
const config = readOathboundConfig();
|
|
17595
17730
|
const enforcement = config?.enforcement ?? "warn";
|
|
17596
17731
|
const supabase = createClient(supabaseUrl, supabaseAnonKey);
|
|
@@ -17651,8 +17786,12 @@ async function verify(supabaseUrl, supabaseAnonKey) {
|
|
|
17651
17786
|
}
|
|
17652
17787
|
}
|
|
17653
17788
|
const ok = rejected.length === 0;
|
|
17654
|
-
const
|
|
17655
|
-
|
|
17789
|
+
const skillDirsMap = {};
|
|
17790
|
+
for (const [name, { dir }] of Object.entries(localSkills)) {
|
|
17791
|
+
skillDirsMap[name] = dir;
|
|
17792
|
+
}
|
|
17793
|
+
const state = { verified, rejected, ok, skillDirs: skillDirsMap };
|
|
17794
|
+
import_node_fs5.writeFileSync(sessionStatePath(sessionId), JSON.stringify(state));
|
|
17656
17795
|
if (ok && warnings.length === 0) {
|
|
17657
17796
|
const names = Object.keys(verified).join(", ");
|
|
17658
17797
|
console.log(JSON.stringify({
|
|
@@ -17726,23 +17865,42 @@ async function verifyCheck() {
|
|
|
17726
17865
|
process.exit(0);
|
|
17727
17866
|
const config = readOathboundConfig();
|
|
17728
17867
|
const enforcement = config?.enforcement ?? "warn";
|
|
17729
|
-
const skillsDir = findSkillsDir();
|
|
17730
|
-
if (isExternalSkillAccess(toolName, toolInput, skillsDir, baseName)) {
|
|
17731
|
-
process.exit(0);
|
|
17732
|
-
}
|
|
17733
17868
|
const stateFile = sessionStatePath(sessionId);
|
|
17734
|
-
if (!
|
|
17869
|
+
if (!import_node_fs5.existsSync(stateFile))
|
|
17735
17870
|
process.exit(0);
|
|
17736
17871
|
let state;
|
|
17737
17872
|
try {
|
|
17738
|
-
state = JSON.parse(
|
|
17873
|
+
state = JSON.parse(import_node_fs5.readFileSync(stateFile, "utf-8"));
|
|
17739
17874
|
} catch {
|
|
17740
17875
|
process.stderr.write(`oathbound verify --check: corrupt session state file
|
|
17741
17876
|
`);
|
|
17742
17877
|
process.exit(1);
|
|
17743
17878
|
}
|
|
17744
|
-
|
|
17745
|
-
if (
|
|
17879
|
+
let skillDir = null;
|
|
17880
|
+
if (state.skillDirs?.[baseName]) {
|
|
17881
|
+
skillDir = state.skillDirs[baseName];
|
|
17882
|
+
} else {
|
|
17883
|
+
for (const { path: dir } of findSkillsDirs()) {
|
|
17884
|
+
const candidate = import_node_path5.join(dir, baseName);
|
|
17885
|
+
if (import_node_fs5.existsSync(candidate) && import_node_fs5.statSync(candidate).isDirectory()) {
|
|
17886
|
+
skillDir = candidate;
|
|
17887
|
+
}
|
|
17888
|
+
}
|
|
17889
|
+
}
|
|
17890
|
+
const knownDirs = [];
|
|
17891
|
+
if (state.skillDirs) {
|
|
17892
|
+
const parentDirs = new Set;
|
|
17893
|
+
for (const d of Object.values(state.skillDirs)) {
|
|
17894
|
+
parentDirs.add(import_node_path5.join(d, ".."));
|
|
17895
|
+
}
|
|
17896
|
+
knownDirs.push(...parentDirs);
|
|
17897
|
+
} else {
|
|
17898
|
+
knownDirs.push(...findSkillsDirs().map((e) => e.path));
|
|
17899
|
+
}
|
|
17900
|
+
if (knownDirs.length > 0 && isExternalSkillAccess(toolName, toolInput, knownDirs, baseName)) {
|
|
17901
|
+
process.exit(0);
|
|
17902
|
+
}
|
|
17903
|
+
if (!skillDir || !import_node_fs5.existsSync(skillDir) || !import_node_fs5.statSync(skillDir).isDirectory()) {
|
|
17746
17904
|
if (enforcement === "warn") {
|
|
17747
17905
|
warnSkill(baseName, "not installed locally");
|
|
17748
17906
|
} else {
|
|
@@ -17771,38 +17929,38 @@ async function verifyCheck() {
|
|
|
17771
17929
|
}
|
|
17772
17930
|
|
|
17773
17931
|
// auth.ts
|
|
17774
|
-
var
|
|
17775
|
-
var
|
|
17932
|
+
var import_node_child_process2 = require("node:child_process");
|
|
17933
|
+
var import_node_fs6 = require("node:fs");
|
|
17776
17934
|
var import_node_http = require("node:http");
|
|
17777
|
-
var
|
|
17935
|
+
var import_node_path6 = require("node:path");
|
|
17778
17936
|
var import_node_os3 = require("node:os");
|
|
17779
17937
|
var SUPABASE_URL = "https://mjnfqagwuewhgwbtrdgs.supabase.co";
|
|
17780
17938
|
var SUPABASE_ANON_KEY = "sb_publishable_T-rk0azNRqAMLLGCyadyhQ_ulk9685n";
|
|
17781
17939
|
var API_BASE = process.env.OATHBOUND_API_URL ?? "https://www.oathbound.ai";
|
|
17782
|
-
var AUTH_DIR =
|
|
17783
|
-
var AUTH_FILE =
|
|
17940
|
+
var AUTH_DIR = import_node_path6.join(import_node_os3.homedir(), ".oathbound");
|
|
17941
|
+
var AUTH_FILE = import_node_path6.join(AUTH_DIR, "auth.json");
|
|
17784
17942
|
function saveSession(session) {
|
|
17785
|
-
|
|
17786
|
-
|
|
17943
|
+
import_node_fs6.mkdirSync(AUTH_DIR, { recursive: true, mode: 448 });
|
|
17944
|
+
import_node_fs6.writeFileSync(AUTH_FILE, JSON.stringify(session, null, 2), { mode: 384 });
|
|
17787
17945
|
}
|
|
17788
17946
|
function loadSession() {
|
|
17789
|
-
if (!
|
|
17947
|
+
if (!import_node_fs6.existsSync(AUTH_FILE))
|
|
17790
17948
|
return null;
|
|
17791
17949
|
try {
|
|
17792
|
-
return JSON.parse(
|
|
17950
|
+
return JSON.parse(import_node_fs6.readFileSync(AUTH_FILE, "utf-8"));
|
|
17793
17951
|
} catch {
|
|
17794
17952
|
return null;
|
|
17795
17953
|
}
|
|
17796
17954
|
}
|
|
17797
17955
|
function clearSession() {
|
|
17798
|
-
if (
|
|
17799
|
-
|
|
17956
|
+
if (import_node_fs6.existsSync(AUTH_FILE))
|
|
17957
|
+
import_node_fs6.unlinkSync(AUTH_FILE);
|
|
17800
17958
|
}
|
|
17801
17959
|
function openBrowser(url) {
|
|
17802
17960
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
17803
17961
|
const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
17804
17962
|
try {
|
|
17805
|
-
|
|
17963
|
+
import_node_child_process2.spawn(cmd, args, { stdio: "ignore", detached: true }).unref();
|
|
17806
17964
|
} catch {}
|
|
17807
17965
|
}
|
|
17808
17966
|
var SUCCESS_HTML = `<!DOCTYPE html>
|
|
@@ -17936,16 +18094,16 @@ ${BRAND}`);
|
|
|
17936
18094
|
}
|
|
17937
18095
|
|
|
17938
18096
|
// push.ts
|
|
17939
|
-
var
|
|
17940
|
-
var
|
|
18097
|
+
var import_node_fs7 = require("node:fs");
|
|
18098
|
+
var import_node_path7 = require("node:path");
|
|
17941
18099
|
var import_yaml2 = __toESM(require_dist(), 1);
|
|
17942
18100
|
var API_BASE2 = process.env.OATHBOUND_API_URL ?? "https://www.oathbound.ai";
|
|
17943
18101
|
async function push(pathArg, options) {
|
|
17944
18102
|
Wt2(BRAND);
|
|
17945
18103
|
const skillDir = resolveSkillDir(pathArg);
|
|
17946
18104
|
console.log(`${DIM} directory: ${skillDir}${RESET}`);
|
|
17947
|
-
if (!
|
|
17948
|
-
fail("No SKILL.md found", `Expected at ${
|
|
18105
|
+
if (!import_node_fs7.existsSync(import_node_path7.join(skillDir, "SKILL.md"))) {
|
|
18106
|
+
fail("No SKILL.md found", `Expected at ${import_node_path7.join(skillDir, "SKILL.md")}`);
|
|
17949
18107
|
}
|
|
17950
18108
|
const rawFiles = collectFiles(skillDir);
|
|
17951
18109
|
const skillMdFile = rawFiles.find((f) => f.path === "SKILL.md");
|
|
@@ -18017,13 +18175,13 @@ async function push(pathArg, options) {
|
|
|
18017
18175
|
}
|
|
18018
18176
|
function resolveSkillDir(pathArg) {
|
|
18019
18177
|
if (pathArg) {
|
|
18020
|
-
const resolved =
|
|
18021
|
-
if (!
|
|
18178
|
+
const resolved = import_node_path7.resolve(pathArg);
|
|
18179
|
+
if (!import_node_fs7.existsSync(resolved) || !import_node_fs7.statSync(resolved).isDirectory()) {
|
|
18022
18180
|
fail("Invalid path", `${resolved} is not a directory`);
|
|
18023
18181
|
}
|
|
18024
18182
|
return resolved;
|
|
18025
18183
|
}
|
|
18026
|
-
if (
|
|
18184
|
+
if (import_node_fs7.existsSync(import_node_path7.join(process.cwd(), "SKILL.md"))) {
|
|
18027
18185
|
return process.cwd();
|
|
18028
18186
|
}
|
|
18029
18187
|
fail("No skill directory found", "Run from within a skill directory or pass a path: oathbound push ./my-skill");
|
|
@@ -18146,8 +18304,8 @@ ${BRAND} ${TEAL}${showing}${RESET}
|
|
|
18146
18304
|
}
|
|
18147
18305
|
|
|
18148
18306
|
// agent-push.ts
|
|
18149
|
-
var
|
|
18150
|
-
var
|
|
18307
|
+
var import_node_fs8 = require("node:fs");
|
|
18308
|
+
var import_node_path8 = require("node:path");
|
|
18151
18309
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
18152
18310
|
var API_BASE4 = process.env.OATHBOUND_API_URL ?? "https://www.oathbound.ai";
|
|
18153
18311
|
function parseAgentFrontmatter(content) {
|
|
@@ -18160,11 +18318,11 @@ function parseAgentFrontmatter(content) {
|
|
|
18160
18318
|
}
|
|
18161
18319
|
function resolveAgentFile(pathArg) {
|
|
18162
18320
|
if (pathArg) {
|
|
18163
|
-
const resolved =
|
|
18164
|
-
if (!
|
|
18321
|
+
const resolved = import_node_path8.resolve(pathArg);
|
|
18322
|
+
if (!import_node_fs8.existsSync(resolved)) {
|
|
18165
18323
|
fail("File not found", resolved);
|
|
18166
18324
|
}
|
|
18167
|
-
if (
|
|
18325
|
+
if (import_node_fs8.statSync(resolved).isDirectory()) {
|
|
18168
18326
|
return findAgentInDir(resolved);
|
|
18169
18327
|
}
|
|
18170
18328
|
if (!resolved.endsWith(".md")) {
|
|
@@ -18175,11 +18333,11 @@ function resolveAgentFile(pathArg) {
|
|
|
18175
18333
|
return findAgentInDir(process.cwd());
|
|
18176
18334
|
}
|
|
18177
18335
|
function findAgentInDir(dir) {
|
|
18178
|
-
const mdFiles =
|
|
18336
|
+
const mdFiles = import_node_fs8.readdirSync(dir).filter((f) => f.endsWith(".md") && !f.startsWith(".")).map((f) => import_node_path8.join(dir, f));
|
|
18179
18337
|
const agents = [];
|
|
18180
18338
|
for (const file of mdFiles) {
|
|
18181
18339
|
try {
|
|
18182
|
-
const content =
|
|
18340
|
+
const content = import_node_fs8.readFileSync(file, "utf-8");
|
|
18183
18341
|
const { meta, body } = parseAgentFrontmatter(content);
|
|
18184
18342
|
if (meta.name && meta.description && body.trim()) {
|
|
18185
18343
|
agents.push(file);
|
|
@@ -18197,7 +18355,7 @@ function findAgentInDir(dir) {
|
|
|
18197
18355
|
async function agentPush(pathArg, options) {
|
|
18198
18356
|
Wt2(BRAND);
|
|
18199
18357
|
const agentFile = resolveAgentFile(pathArg);
|
|
18200
|
-
const content =
|
|
18358
|
+
const content = import_node_fs8.readFileSync(agentFile, "utf-8");
|
|
18201
18359
|
const { meta, body } = parseAgentFrontmatter(content);
|
|
18202
18360
|
const name = String(meta.name ?? "");
|
|
18203
18361
|
const description = String(meta.description ?? "");
|
|
@@ -18386,7 +18544,7 @@ ${BRAND} ${TEAL}${showing}${RESET}
|
|
|
18386
18544
|
}
|
|
18387
18545
|
}
|
|
18388
18546
|
// cli.ts
|
|
18389
|
-
var VERSION = "0.
|
|
18547
|
+
var VERSION = "0.16.0";
|
|
18390
18548
|
var SUPABASE_URL2 = "https://mjnfqagwuewhgwbtrdgs.supabase.co";
|
|
18391
18549
|
var SUPABASE_ANON_KEY2 = "sb_publishable_T-rk0azNRqAMLLGCyadyhQ_ulk9685n";
|
|
18392
18550
|
var API_BASE6 = process.env.OATHBOUND_API_URL ?? "https://www.oathbound.ai";
|
|
@@ -18407,41 +18565,8 @@ function parseSkillArg(arg) {
|
|
|
18407
18565
|
return null;
|
|
18408
18566
|
return { namespace: arg.slice(0, slash), name, version: vStr };
|
|
18409
18567
|
}
|
|
18410
|
-
function detectPackageManager() {
|
|
18411
|
-
if (import_node_fs8.existsSync(import_node_path8.join(process.cwd(), "bun.lockb")) || import_node_fs8.existsSync(import_node_path8.join(process.cwd(), "bun.lock")))
|
|
18412
|
-
return "bun";
|
|
18413
|
-
if (import_node_fs8.existsSync(import_node_path8.join(process.cwd(), "pnpm-lock.yaml")))
|
|
18414
|
-
return "pnpm";
|
|
18415
|
-
if (import_node_fs8.existsSync(import_node_path8.join(process.cwd(), "yarn.lock")))
|
|
18416
|
-
return "yarn";
|
|
18417
|
-
return "npm";
|
|
18418
|
-
}
|
|
18419
|
-
function installDevDependency() {
|
|
18420
|
-
const pkgPath = import_node_path8.join(process.cwd(), "package.json");
|
|
18421
|
-
if (!import_node_fs8.existsSync(pkgPath))
|
|
18422
|
-
return "no-package-json";
|
|
18423
|
-
try {
|
|
18424
|
-
const pkg = JSON.parse(import_node_fs8.readFileSync(pkgPath, "utf-8"));
|
|
18425
|
-
if (pkg.devDependencies?.oathbound || pkg.dependencies?.oathbound)
|
|
18426
|
-
return "skipped";
|
|
18427
|
-
} catch {}
|
|
18428
|
-
const pm = detectPackageManager();
|
|
18429
|
-
const cmds = {
|
|
18430
|
-
bun: ["bun", ["add", "--dev", "oathbound"]],
|
|
18431
|
-
pnpm: ["pnpm", ["add", "--save-dev", "oathbound"]],
|
|
18432
|
-
yarn: ["yarn", ["add", "--dev", "oathbound"]],
|
|
18433
|
-
npm: ["npm", ["install", "--save-dev", "oathbound"]]
|
|
18434
|
-
};
|
|
18435
|
-
const [bin, args] = cmds[pm];
|
|
18436
|
-
try {
|
|
18437
|
-
import_node_child_process2.execFileSync(bin, args, { stdio: "pipe", cwd: process.cwd() });
|
|
18438
|
-
return "installed";
|
|
18439
|
-
} catch {
|
|
18440
|
-
return "failed";
|
|
18441
|
-
}
|
|
18442
|
-
}
|
|
18443
18568
|
function setup() {
|
|
18444
|
-
if (!
|
|
18569
|
+
if (!import_node_fs9.existsSync(import_node_path9.join(process.cwd(), ".oathbound.jsonc")))
|
|
18445
18570
|
return;
|
|
18446
18571
|
const result = mergeClaudeSettings();
|
|
18447
18572
|
if (result === "malformed") {
|
|
@@ -18450,27 +18575,31 @@ function setup() {
|
|
|
18450
18575
|
process.exit(1);
|
|
18451
18576
|
}
|
|
18452
18577
|
}
|
|
18453
|
-
function
|
|
18454
|
-
const
|
|
18455
|
-
|
|
18456
|
-
|
|
18457
|
-
|
|
18458
|
-
|
|
18459
|
-
pkg = JSON.parse(import_node_fs8.readFileSync(pkgPath, "utf-8"));
|
|
18460
|
-
} catch {
|
|
18461
|
-
return "skipped";
|
|
18462
|
-
}
|
|
18463
|
-
const prepare = pkg.scripts?.prepare ?? "";
|
|
18464
|
-
if (prepare.includes("oathbound setup"))
|
|
18465
|
-
return "skipped";
|
|
18466
|
-
const newPrepare = prepare ? `${prepare} && oathbound setup` : "oathbound setup";
|
|
18467
|
-
pkg.scripts = { ...pkg.scripts ?? {}, prepare: newPrepare };
|
|
18468
|
-
import_node_fs8.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + `
|
|
18578
|
+
function initGlobal() {
|
|
18579
|
+
const home = import_node_os4.homedir();
|
|
18580
|
+
const mergeResult = mergeClaudeSettings(home);
|
|
18581
|
+
switch (mergeResult) {
|
|
18582
|
+
case "created":
|
|
18583
|
+
process.stderr.write(`${GREEN} ✓ Created ~/.claude/settings.json with hooks${RESET}
|
|
18469
18584
|
`);
|
|
18470
|
-
|
|
18585
|
+
break;
|
|
18586
|
+
case "merged":
|
|
18587
|
+
process.stderr.write(`${GREEN} ✓ Added hooks to ~/.claude/settings.json${RESET}
|
|
18588
|
+
`);
|
|
18589
|
+
break;
|
|
18590
|
+
case "skipped":
|
|
18591
|
+
process.stderr.write(`${DIM} ~/.claude/settings.json already has oathbound hooks — skipped${RESET}
|
|
18592
|
+
`);
|
|
18593
|
+
break;
|
|
18594
|
+
case "malformed":
|
|
18595
|
+
process.stderr.write(`${RED} ✗ ~/.claude/settings.json is malformed JSON — skipped${RESET}
|
|
18596
|
+
`);
|
|
18597
|
+
process.stderr.write(`${RED} Please fix the file manually and re-run oathbound init --global${RESET}
|
|
18598
|
+
`);
|
|
18599
|
+
break;
|
|
18600
|
+
}
|
|
18471
18601
|
}
|
|
18472
|
-
async function
|
|
18473
|
-
Wt2(BRAND);
|
|
18602
|
+
async function initLocal() {
|
|
18474
18603
|
const level = "warn";
|
|
18475
18604
|
let installResult = installDevDependency();
|
|
18476
18605
|
if (installResult === "no-package-json") {
|
|
@@ -18481,8 +18610,8 @@ async function init() {
|
|
|
18481
18610
|
Nt("Please run `npx oathbound init` inside of the folder where you want to run Claude Code. Oathbound currently needs an NPM package in order to run.");
|
|
18482
18611
|
process.exit(1);
|
|
18483
18612
|
}
|
|
18484
|
-
const dirName =
|
|
18485
|
-
|
|
18613
|
+
const dirName = import_node_path9.basename(process.cwd()).toLowerCase().replace(/[^a-z0-9._-]/g, "-").replace(/^[._]+/, "").replace(/-+/g, "-") || "project";
|
|
18614
|
+
import_node_fs9.writeFileSync(import_node_path9.join(process.cwd(), "package.json"), JSON.stringify({
|
|
18486
18615
|
name: dirName,
|
|
18487
18616
|
private: true,
|
|
18488
18617
|
scripts: { prepare: "oathbound setup" }
|
|
@@ -18544,9 +18673,20 @@ async function init() {
|
|
|
18544
18673
|
`);
|
|
18545
18674
|
break;
|
|
18546
18675
|
}
|
|
18676
|
+
}
|
|
18677
|
+
async function init(options = {}) {
|
|
18678
|
+
Wt2(BRAND);
|
|
18679
|
+
if (options.global && !options.local) {
|
|
18680
|
+
initGlobal();
|
|
18681
|
+
} else if (options.local && !options.global) {
|
|
18682
|
+
await initLocal();
|
|
18683
|
+
} else {
|
|
18684
|
+
initGlobal();
|
|
18685
|
+
await initLocal();
|
|
18686
|
+
}
|
|
18547
18687
|
Gt(`\uD83C\uDF89 Oath Bound set up complete!`);
|
|
18548
18688
|
}
|
|
18549
|
-
async function pull(skillArg) {
|
|
18689
|
+
async function pull(skillArg, options = {}) {
|
|
18550
18690
|
const parsed = parseSkillArg(skillArg);
|
|
18551
18691
|
if (!parsed)
|
|
18552
18692
|
usage();
|
|
@@ -18574,7 +18714,7 @@ ${BRAND} ${TEAL}↓ Pulling ${fullName}${version3 ? `@${version3}` : ""}...${RES
|
|
|
18574
18714
|
fail("Download failed", downloadError?.message ?? "Unknown storage error");
|
|
18575
18715
|
}
|
|
18576
18716
|
const buffer = Buffer.from(await blob.arrayBuffer());
|
|
18577
|
-
const tarFile =
|
|
18717
|
+
const tarFile = import_node_path9.join(import_node_os4.tmpdir(), `oathbound-${name}-${Date.now()}.tar.gz`);
|
|
18578
18718
|
const verifySpinner = spinner("Verifying...");
|
|
18579
18719
|
const hash = import_node_crypto2.createHash("sha256").update(buffer).digest("hex");
|
|
18580
18720
|
verifySpinner.stop();
|
|
@@ -18583,21 +18723,30 @@ ${BRAND} ${TEAL}↓ Pulling ${fullName}${version3 ? `@${version3}` : ""}...${RES
|
|
|
18583
18723
|
console.log(`${RED} expected: ${skill.tar_hash}${RESET}`);
|
|
18584
18724
|
fail("Verification failed", `Downloaded file does not match expected hash for ${fullName}`);
|
|
18585
18725
|
}
|
|
18586
|
-
let skillsDir
|
|
18587
|
-
if (
|
|
18588
|
-
skillsDir =
|
|
18589
|
-
|
|
18590
|
-
|
|
18726
|
+
let skillsDir;
|
|
18727
|
+
if (options.global) {
|
|
18728
|
+
skillsDir = import_node_path9.join(import_node_os4.homedir(), ".claude", "skills");
|
|
18729
|
+
import_node_fs9.mkdirSync(skillsDir, { recursive: true });
|
|
18730
|
+
} else {
|
|
18731
|
+
const dirs = findSkillsDirs();
|
|
18732
|
+
const localEntry = dirs.find((d) => d.source === "local");
|
|
18733
|
+
if (localEntry) {
|
|
18734
|
+
skillsDir = localEntry.path;
|
|
18735
|
+
} else {
|
|
18736
|
+
skillsDir = import_node_path9.join(process.cwd(), ".claude", "skills");
|
|
18737
|
+
import_node_fs9.mkdirSync(skillsDir, { recursive: true });
|
|
18738
|
+
console.log(`${DIM} Created ${skillsDir}${RESET}`);
|
|
18739
|
+
}
|
|
18591
18740
|
}
|
|
18592
|
-
|
|
18741
|
+
import_node_fs9.writeFileSync(tarFile, buffer);
|
|
18593
18742
|
try {
|
|
18594
|
-
|
|
18743
|
+
import_node_child_process3.execFileSync("tar", ["-xf", tarFile, "-C", skillsDir], { stdio: "pipe" });
|
|
18595
18744
|
} catch (e) {
|
|
18596
|
-
|
|
18745
|
+
import_node_fs9.unlinkSync(tarFile);
|
|
18597
18746
|
const msg = e instanceof Error ? e.message : "Unknown error";
|
|
18598
18747
|
fail("Extraction failed", msg);
|
|
18599
18748
|
}
|
|
18600
|
-
|
|
18749
|
+
import_node_fs9.unlinkSync(tarFile);
|
|
18601
18750
|
try {
|
|
18602
18751
|
const trackRes = await fetch(`${API_BASE6}/api/downloads`, {
|
|
18603
18752
|
method: "POST",
|
|
@@ -18611,7 +18760,7 @@ ${BRAND} ${TEAL}↓ Pulling ${fullName}${version3 ? `@${version3}` : ""}...${RES
|
|
|
18611
18760
|
} catch {}
|
|
18612
18761
|
console.log(`${BOLD}${GREEN} ✓ Skill verified${RESET}`);
|
|
18613
18762
|
console.log(`${DIM} ${fullName} v${skill.version}${RESET}`);
|
|
18614
|
-
console.log(`${DIM} → ${
|
|
18763
|
+
console.log(`${DIM} → ${import_node_path9.join(skillsDir, name)}${RESET}`);
|
|
18615
18764
|
}
|
|
18616
18765
|
async function agentPull(agentArg) {
|
|
18617
18766
|
const parsed = parseSkillArg(agentArg);
|
|
@@ -18652,9 +18801,9 @@ ${BRAND} ${TEAL}↓ Pulling agent ${fullName}${version3 ? `@${version3}` : ""}..
|
|
|
18652
18801
|
if (name.includes("/") || name.includes("\\") || name.includes("..")) {
|
|
18653
18802
|
fail("Invalid agent name", `Name "${name}" contains path traversal characters`);
|
|
18654
18803
|
}
|
|
18655
|
-
const agentsDir =
|
|
18656
|
-
|
|
18657
|
-
const targetPath =
|
|
18804
|
+
const agentsDir = import_node_path9.join(process.cwd(), ".claude", "agents");
|
|
18805
|
+
import_node_fs9.mkdirSync(agentsDir, { recursive: true });
|
|
18806
|
+
const targetPath = import_node_path9.join(agentsDir, `${name}.md`);
|
|
18658
18807
|
if (!targetPath.startsWith(agentsDir)) {
|
|
18659
18808
|
fail("Invalid agent name", `Resolved path escapes agents directory`);
|
|
18660
18809
|
}
|
|
@@ -18682,7 +18831,7 @@ ${YELLOW}${BOLD} ⚠ This agent defines MCP servers (external connections):${RES
|
|
|
18682
18831
|
fail("Aborted", "Agent not installed");
|
|
18683
18832
|
}
|
|
18684
18833
|
}
|
|
18685
|
-
|
|
18834
|
+
import_node_fs9.writeFileSync(targetPath, content);
|
|
18686
18835
|
try {
|
|
18687
18836
|
const trackRes = await fetch(`${API_BASE6}/api/downloads`, {
|
|
18688
18837
|
method: "POST",
|
|
@@ -18737,7 +18886,11 @@ if (require.main == module) {
|
|
|
18737
18886
|
}
|
|
18738
18887
|
}
|
|
18739
18888
|
if (subcommand === "init") {
|
|
18740
|
-
|
|
18889
|
+
const initArgs = args.slice(1);
|
|
18890
|
+
await init({
|
|
18891
|
+
global: initArgs.includes("--global"),
|
|
18892
|
+
local: initArgs.includes("--local")
|
|
18893
|
+
}).catch((err) => {
|
|
18741
18894
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
18742
18895
|
fail("Init failed", msg);
|
|
18743
18896
|
});
|
|
@@ -18788,11 +18941,13 @@ if (require.main == module) {
|
|
|
18788
18941
|
});
|
|
18789
18942
|
} else {
|
|
18790
18943
|
const PULL_ALIASES = new Set(["pull", "i", "install"]);
|
|
18791
|
-
const
|
|
18944
|
+
const pullArgs = args.slice(1);
|
|
18945
|
+
const isGlobalPull = pullArgs.includes("--global");
|
|
18946
|
+
const skillArg = pullArgs.find((a) => !a.startsWith("--"));
|
|
18792
18947
|
if (!subcommand || !PULL_ALIASES.has(subcommand) || !skillArg) {
|
|
18793
18948
|
usage();
|
|
18794
18949
|
}
|
|
18795
|
-
await pull(skillArg).catch((err) => {
|
|
18950
|
+
await pull(skillArg, { global: isGlobalPull }).catch((err) => {
|
|
18796
18951
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
18797
18952
|
fail("Unexpected error", msg);
|
|
18798
18953
|
});
|