@neta-art/neta-search-cli 0.2.16 → 0.2.18
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/README.md +11 -9
- package/neta-search.mjs +66 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,21 +3,23 @@
|
|
|
3
3
|
Command-line client for **neta-search**, the skill registry of the Cohub / Neta platform: search the ecosystem for a ready-made skill, try it without installing, or install it into your space.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npx -y @neta-art/neta-search-cli@
|
|
7
|
-
npx -y @neta-art/neta-search-cli@
|
|
8
|
-
npx -y @neta-art/neta-search-cli@
|
|
9
|
-
npx -y @neta-art/neta-search-cli@
|
|
10
|
-
npx -y @neta-art/neta-search-cli@
|
|
11
|
-
npx -y @neta-art/neta-search-cli@
|
|
12
|
-
npx -y @neta-art/neta-search-cli@
|
|
6
|
+
npx -y @neta-art/neta-search-cli@latest skills find "generate video" # search (Chinese or English)
|
|
7
|
+
npx -y @neta-art/neta-search-cli@latest skills find "browser automation" --json
|
|
8
|
+
npx -y @neta-art/neta-search-cli@latest skills use <id> # print the SKILL.md (pulled into a temp dir; no project files written)
|
|
9
|
+
npx -y @neta-art/neta-search-cli@latest skills add <id> # install into .agents/skills/
|
|
10
|
+
npx -y @neta-art/neta-search-cli@latest skills list # what's in .agents/skills/, and which installed ones have updates
|
|
11
|
+
npx -y @neta-art/neta-search-cli@latest skills update # update installed skills to their current release (or name some: handle, id or directory)
|
|
12
|
+
npx -y @neta-art/neta-search-cli@latest skills init <name> # scaffold your own skill
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
`<id>`
|
|
15
|
+
`<id>` is what `find` prints: a handle such as `neta-skills/holo-pack-opening` or `cohub/agent-browser`. Skills without a handle are listed as `cohub:<spaceId>/<name>`, which works everywhere a handle does. `update` and `remove` also accept the directory name under `.agents/skills/`.
|
|
16
16
|
|
|
17
|
-
`
|
|
17
|
+
`remove` deletes installed skills only. Skills you wrote yourself (no install record) are left alone unless you pass `--force`.
|
|
18
18
|
|
|
19
19
|
`use` prints the skill directory and the full SKILL.md, so an agent can follow it right away; relative paths in SKILL.md resolve against that directory. If the local entry is a pointer (frontmatter `metadata.neta-skill-id`), `use` fetches the full skill it points to.
|
|
20
20
|
|
|
21
|
+
Use `@latest` (or an exact version): with a range such as `@0.2`, npx keeps running whatever matching version it cached earlier and never checks for a newer one.
|
|
22
|
+
|
|
21
23
|
Inside a Cohub sandbox the CLI picks up the sandbox identity automatically; elsewhere it runs anonymously.
|
|
22
24
|
|
|
23
25
|
Single file, no runtime dependencies. Node.js 20+.
|
package/neta-search.mjs
CHANGED
|
@@ -27075,7 +27075,8 @@ async function fetchArchive(env, id) {
|
|
|
27075
27075
|
const files = untarGz(body);
|
|
27076
27076
|
const got = digestOf(new Map(files.map((f) => [f.path, f.data])));
|
|
27077
27077
|
if (got !== digest) throw new Error(`\u4E0B\u8F7D\u7684 ${id} \u5185\u5BB9\u6821\u9A8C\u5931\u8D25\uFF08\u671F\u671B ${digest}\uFF0C\u5B9E\u9645 ${got}\uFF09`);
|
|
27078
|
-
|
|
27078
|
+
const handle = res.headers.get("x-skill-handle") || void 0;
|
|
27079
|
+
return { id, handle, name, digest, files };
|
|
27079
27080
|
}
|
|
27080
27081
|
async function archiveHead(env, id) {
|
|
27081
27082
|
const url = `${env.apiBase}${ARCHIVE_PATH}?id=${encodeURIComponent(id)}`;
|
|
@@ -27083,7 +27084,12 @@ async function archiveHead(env, id) {
|
|
|
27083
27084
|
if (res.status === 404) return null;
|
|
27084
27085
|
const digest = res.headers.get("x-skill-digest") ?? "";
|
|
27085
27086
|
if (res.status < 300 || res.status >= 400 || !digest) throw new Error(`\u67E5\u8BE2 ${id} \u5931\u8D25\uFF1AHTTP ${res.status}`);
|
|
27086
|
-
return {
|
|
27087
|
+
return {
|
|
27088
|
+
id: res.headers.get("x-skill-id") ?? id,
|
|
27089
|
+
handle: res.headers.get("x-skill-handle") || void 0,
|
|
27090
|
+
name: res.headers.get("x-skill-name") ?? id.split("/").pop(),
|
|
27091
|
+
digest
|
|
27092
|
+
};
|
|
27087
27093
|
}
|
|
27088
27094
|
async function download(url, id) {
|
|
27089
27095
|
for (let attempt = 1; ; attempt++) {
|
|
@@ -27188,11 +27194,20 @@ function skillDirExists(p) {
|
|
|
27188
27194
|
function readSource(dir) {
|
|
27189
27195
|
try {
|
|
27190
27196
|
const r = JSON.parse(readFileSync2(join2(dir, SOURCE_FILE), "utf8"));
|
|
27191
|
-
|
|
27197
|
+
if (typeof r?.id !== "string" || !parseId(r.id)) return null;
|
|
27198
|
+
const rec = { id: r.id, digest: String(r.digest ?? "") };
|
|
27199
|
+
if (typeof r.handle === "string" && HANDLE_RE.test(r.handle)) rec.handle = r.handle;
|
|
27200
|
+
return rec;
|
|
27192
27201
|
} catch {
|
|
27193
27202
|
return null;
|
|
27194
27203
|
}
|
|
27195
27204
|
}
|
|
27205
|
+
function writeSource(dir, rec) {
|
|
27206
|
+
writeFileSync(join2(dir, SOURCE_FILE), JSON.stringify(rec, null, 2) + "\n");
|
|
27207
|
+
}
|
|
27208
|
+
function displayRef(rec, fallback2 = "") {
|
|
27209
|
+
return rec?.handle || rec?.id || fallback2;
|
|
27210
|
+
}
|
|
27196
27211
|
function writeSkill(target, files, source) {
|
|
27197
27212
|
const staging = join2(dirname(target), `.staging-${target.split("/").pop()}-${process.pid}`);
|
|
27198
27213
|
rmSync(staging, { recursive: true, force: true });
|
|
@@ -27275,10 +27290,10 @@ async function cmdAdd(idOrName, opts) {
|
|
|
27275
27290
|
return 1;
|
|
27276
27291
|
}
|
|
27277
27292
|
mkdirSync2(opts.dir, { recursive: true });
|
|
27278
|
-
writeSkill(target, archive.files, { id: archive.id, digest: archive.digest });
|
|
27293
|
+
writeSkill(target, archive.files, { id: archive.id, digest: archive.digest, handle: archive.handle });
|
|
27279
27294
|
const report = reportSkillEvent(env, "install", archive.id, archive.digest, name);
|
|
27280
|
-
if (opts.json) console.log(JSON.stringify({ installed: archive.id, path: target, digest: archive.digest }));
|
|
27281
|
-
else console.log(`\u5DF2\u5B89\u88C5 ${archive
|
|
27295
|
+
if (opts.json) console.log(JSON.stringify({ installed: archive.id, handle: archive.handle, path: target, digest: archive.digest }));
|
|
27296
|
+
else console.log(`\u5DF2\u5B89\u88C5 ${displayRef(archive)} \u2192 ${target}`);
|
|
27282
27297
|
await report;
|
|
27283
27298
|
return 0;
|
|
27284
27299
|
}
|
|
@@ -27305,7 +27320,9 @@ import { join as join4 } from "node:path";
|
|
|
27305
27320
|
var FETCH_ROOT = process.env["NETASEARCH_FETCH_ROOT"] ?? join4("/tmp", "neta-skills");
|
|
27306
27321
|
async function cmdUse(idOrName, opts) {
|
|
27307
27322
|
const env = detectEnv();
|
|
27323
|
+
const input = idOrName;
|
|
27308
27324
|
idOrName = await resolveRef(env, idOrName);
|
|
27325
|
+
let handle = isHandle(input) && parseId(idOrName) ? input.toLowerCase() : void 0;
|
|
27309
27326
|
const parsed = parseId(idOrName);
|
|
27310
27327
|
const name = parsed?.name ?? idOrName;
|
|
27311
27328
|
const mine = !parsed || parsed.spaceId === env.spaceId;
|
|
@@ -27322,6 +27339,7 @@ async function cmdUse(idOrName, opts) {
|
|
|
27322
27339
|
if (src && (!parsed || src.id === idOrName)) {
|
|
27323
27340
|
path = installed;
|
|
27324
27341
|
reportId = src.id;
|
|
27342
|
+
handle = handle ?? src.handle;
|
|
27325
27343
|
} else if (!src && mine) {
|
|
27326
27344
|
path = installed;
|
|
27327
27345
|
reportId = ownId(env, name);
|
|
@@ -27365,8 +27383,9 @@ async function cmdUse(idOrName, opts) {
|
|
|
27365
27383
|
const p = parseId(a.id);
|
|
27366
27384
|
path = join4(FETCH_ROOT, p.spaceId, p.name);
|
|
27367
27385
|
const have = readSource(path);
|
|
27368
|
-
if (!skillDirExists(path) || have?.digest !== a.digest) writeSkill(path, a.files, { id: a.id, digest: a.digest });
|
|
27386
|
+
if (!skillDirExists(path) || have?.digest !== a.digest) writeSkill(path, a.files, { id: a.id, digest: a.digest, handle: a.handle });
|
|
27369
27387
|
reportId = a.id;
|
|
27388
|
+
handle = a.handle ?? handle;
|
|
27370
27389
|
where = "fetched";
|
|
27371
27390
|
} catch (e) {
|
|
27372
27391
|
console.error(e instanceof ArchiveNotFound ? `${e.message}\u3002` : String(e instanceof Error ? e.message : e));
|
|
@@ -27383,10 +27402,10 @@ async function cmdUse(idOrName, opts) {
|
|
|
27383
27402
|
const reported = reportId ? await reportSkillEvent(env, "use", reportId, skillDirDigest(path), name, extra) : false;
|
|
27384
27403
|
const skillMd = readFileSync3(join4(path, "SKILL.md"), "utf8");
|
|
27385
27404
|
if (opts.json) {
|
|
27386
|
-
console.log(JSON.stringify({ skill: reportId ?? name, path, where, use_id: reportId ? useId : void 0, skill_md: skillMd }));
|
|
27405
|
+
console.log(JSON.stringify({ skill: reportId ?? name, handle, path, where, use_id: reportId ? useId : void 0, skill_md: skillMd }));
|
|
27387
27406
|
} else {
|
|
27388
27407
|
const label = { local: "\u672C\u5730", mod: "\u5E73\u53F0 mod", fetched: "\u5DF2\u4E0B\u8F7D\u5230\u4E34\u65F6\u76EE\u5F55" }[where];
|
|
27389
|
-
console.log(`${reportId ?? name} \u5C31\u7EEA\uFF08${label}${via === "pointer" ? "\uFF0C\u7ECF\u6307\u9488" : ""}\uFF09`);
|
|
27408
|
+
console.log(`${handle ?? reportId ?? name} \u5C31\u7EEA\uFF08${label}${via === "pointer" ? "\uFF0C\u7ECF\u6307\u9488" : ""}\uFF09`);
|
|
27390
27409
|
console.log(`skill \u76EE\u5F55\uFF1A${path}`);
|
|
27391
27410
|
console.log(`SKILL.md \u91CC\u7684\u76F8\u5BF9\u8DEF\u5F84\u90FD\u4ECE\u8FD9\u4E2A\u76EE\u5F55\u7B97\u8D77\u3002\u4E0B\u9762\u5C31\u662F SKILL.md \u7684\u5168\u6587\uFF0C\u7167\u7740\u505A\u5373\u53EF\uFF08\u4E0D\u7528\u518D\u8BFB\u4E00\u6B21\u6587\u4EF6\uFF09\u3002`);
|
|
27392
27411
|
console.log(`
|
|
@@ -27469,7 +27488,7 @@ function scanLocal(dir) {
|
|
|
27469
27488
|
if (!skillDirExists(path)) continue;
|
|
27470
27489
|
const src = readSource(path);
|
|
27471
27490
|
if (src) {
|
|
27472
|
-
out.push({ name: e.name, path, kind: "installed", id: src.id, digest: src.digest });
|
|
27491
|
+
out.push({ name: e.name, path, kind: "installed", id: src.id, handle: src.handle, digest: src.digest });
|
|
27473
27492
|
continue;
|
|
27474
27493
|
}
|
|
27475
27494
|
const ptr = pointerTarget(path);
|
|
@@ -27477,12 +27496,21 @@ function scanLocal(dir) {
|
|
|
27477
27496
|
}
|
|
27478
27497
|
return out.sort((a, b) => a.name.localeCompare(b.name));
|
|
27479
27498
|
}
|
|
27499
|
+
async function findLocal(env, local, input) {
|
|
27500
|
+
if (!input.includes("/") && !input.startsWith(".")) {
|
|
27501
|
+
const s = local.find((x) => x.name === input);
|
|
27502
|
+
if (s) return [s];
|
|
27503
|
+
}
|
|
27504
|
+
const ref = parseId(input) ? input : await resolveRef(env, input);
|
|
27505
|
+
const lower = input.toLowerCase();
|
|
27506
|
+
return local.filter((x) => x.id !== void 0 && x.id === ref || x.handle !== void 0 && x.handle.toLowerCase() === lower);
|
|
27507
|
+
}
|
|
27480
27508
|
async function statusOf(env, s) {
|
|
27481
27509
|
if (s.kind !== "installed" || !s.id) return { status: "unknown" };
|
|
27482
27510
|
try {
|
|
27483
27511
|
const head = await archiveHead(env, s.id);
|
|
27484
27512
|
if (!head) return { status: "unavailable" };
|
|
27485
|
-
return { status: head.digest === s.digest ? "latest" : "outdated", latest: head.digest };
|
|
27513
|
+
return { status: head.digest === s.digest ? "latest" : "outdated", latest: head.digest, handle: head.handle };
|
|
27486
27514
|
} catch (e) {
|
|
27487
27515
|
return { status: "unknown", error: e instanceof Error ? e.message : String(e) };
|
|
27488
27516
|
}
|
|
@@ -27493,7 +27521,10 @@ async function cmdList(opts) {
|
|
|
27493
27521
|
const env = detectEnv();
|
|
27494
27522
|
const local = scanLocal(opts.dir);
|
|
27495
27523
|
const rows = await Promise.all(
|
|
27496
|
-
local.map(async (s) =>
|
|
27524
|
+
local.map(async (s) => {
|
|
27525
|
+
const st = opts.offline ? { status: "unknown", handle: void 0 } : await statusOf(env, s);
|
|
27526
|
+
return { ...s, ...st, handle: s.handle ?? st.handle };
|
|
27527
|
+
})
|
|
27497
27528
|
);
|
|
27498
27529
|
if (opts.json) {
|
|
27499
27530
|
console.log(JSON.stringify({ dir: opts.dir, count: rows.length, skills: rows }));
|
|
@@ -27506,7 +27537,7 @@ async function cmdList(opts) {
|
|
|
27506
27537
|
console.log(`${opts.dir}/\uFF08${rows.length} \u4E2A\uFF09\uFF1A`);
|
|
27507
27538
|
for (const r of rows) {
|
|
27508
27539
|
const st = STATUS_LABEL[r.status] ? ` [${STATUS_LABEL[r.status]}]` : "";
|
|
27509
|
-
const from = r.id ? ` ${r
|
|
27540
|
+
const from = r.id ? ` ${displayRef(r)}` : "";
|
|
27510
27541
|
console.log(` ${r.name.padEnd(28)} ${KIND_LABEL[r.kind]}${st}${from}`);
|
|
27511
27542
|
}
|
|
27512
27543
|
const outdated = rows.filter((r) => r.status === "outdated").length;
|
|
@@ -27517,7 +27548,6 @@ ${outdated} \u4E2A\u6709\u66F4\u65B0\uFF1Aneta-search skills update`);
|
|
|
27517
27548
|
async function cmdUpdate(names, opts) {
|
|
27518
27549
|
const env = detectEnv();
|
|
27519
27550
|
const local = scanLocal(opts.dir);
|
|
27520
|
-
const byName = new Map(local.map((s) => [s.name, s]));
|
|
27521
27551
|
const targets = [];
|
|
27522
27552
|
const results = [];
|
|
27523
27553
|
let failed = 0;
|
|
@@ -27525,18 +27555,21 @@ async function cmdUpdate(names, opts) {
|
|
|
27525
27555
|
targets.push(...local.filter((s) => s.kind === "installed"));
|
|
27526
27556
|
} else {
|
|
27527
27557
|
for (const n of names) {
|
|
27528
|
-
const
|
|
27529
|
-
if (
|
|
27558
|
+
const found = await findLocal(env, local, n);
|
|
27559
|
+
if (found.length === 0) {
|
|
27530
27560
|
results.push({ name: n, result: "not_found" });
|
|
27531
27561
|
failed++;
|
|
27532
|
-
}
|
|
27533
|
-
|
|
27534
|
-
|
|
27562
|
+
}
|
|
27563
|
+
for (const s of found) {
|
|
27564
|
+
if (s.kind !== "installed") results.push({ name: s.name, result: s.kind === "own" ? "own_skipped" : "pointer_skipped" });
|
|
27565
|
+
else if (!targets.includes(s)) targets.push(s);
|
|
27566
|
+
}
|
|
27535
27567
|
}
|
|
27536
27568
|
}
|
|
27537
27569
|
for (const s of targets) {
|
|
27538
27570
|
const st = await statusOf(env, s);
|
|
27539
27571
|
if (st.status === "latest") {
|
|
27572
|
+
if (st.handle && st.handle !== s.handle) writeSource(s.path, { id: s.id, digest: s.digest, handle: st.handle });
|
|
27540
27573
|
results.push({ name: s.name, result: "latest" });
|
|
27541
27574
|
continue;
|
|
27542
27575
|
}
|
|
@@ -27551,7 +27584,7 @@ async function cmdUpdate(names, opts) {
|
|
|
27551
27584
|
}
|
|
27552
27585
|
try {
|
|
27553
27586
|
const a = await fetchArchive(env, s.id);
|
|
27554
|
-
writeSkill(s.path, a.files, { id: s.id, digest: a.digest });
|
|
27587
|
+
writeSkill(s.path, a.files, { id: s.id, digest: a.digest, handle: a.handle ?? s.handle });
|
|
27555
27588
|
await reportSkillEvent(env, "install", s.id, a.digest, s.name);
|
|
27556
27589
|
results.push({ name: s.name, result: "updated", from: s.digest, to: a.digest });
|
|
27557
27590
|
} catch (e) {
|
|
@@ -27580,17 +27613,19 @@ function short(d) {
|
|
|
27580
27613
|
return (d ?? "").replace(/^sha256:/, "").slice(0, 12) || "?";
|
|
27581
27614
|
}
|
|
27582
27615
|
async function cmdRemove(names, opts) {
|
|
27583
|
-
const
|
|
27616
|
+
const env = detectEnv();
|
|
27617
|
+
const local = scanLocal(opts.dir);
|
|
27584
27618
|
const results = [];
|
|
27585
27619
|
for (const n of names) {
|
|
27586
|
-
const
|
|
27587
|
-
if (
|
|
27588
|
-
|
|
27589
|
-
|
|
27590
|
-
|
|
27591
|
-
|
|
27592
|
-
|
|
27593
|
-
|
|
27620
|
+
const found = (await findLocal(env, local, n)).filter((s) => existsSync5(s.path));
|
|
27621
|
+
if (found.length === 0) results.push({ name: n, result: "not_found" });
|
|
27622
|
+
for (const s of found) {
|
|
27623
|
+
if (s.kind === "own" && !opts.force) {
|
|
27624
|
+
results.push({ name: s.name, result: "own_refused" });
|
|
27625
|
+
} else {
|
|
27626
|
+
rmSync2(s.path, { recursive: true, force: true });
|
|
27627
|
+
results.push({ name: s.name, result: "removed" });
|
|
27628
|
+
}
|
|
27594
27629
|
}
|
|
27595
27630
|
}
|
|
27596
27631
|
const failed = results.filter((r) => r.result !== "removed").length;
|
|
@@ -27635,10 +27670,10 @@ skills.command("use").description("\u7528 skill\uFF08\u4E0D\u88C5\uFF1A\u6253\u5
|
|
|
27635
27670
|
skills.command("list").alias("ls").description("\u5217\u51FA\u672C\u5730\u7684 skill\uFF08\u88C5\u6765\u7684 / \u6307\u9488 / \u81EA\u5DF1\u5199\u7684\uFF09\uFF0C\u88C5\u6765\u7684\u987A\u5E26\u67E5\u6709\u6CA1\u6709\u66F4\u65B0").option("--dir <dir>", "\u76EE\u5F55\uFF08\u9ED8\u8BA4 .agents/skills/\uFF09", ".agents/skills").option("--offline", "\u4E0D\u8054\u7F51\u67E5\u66F4\u65B0").option("--json", "\u7D27\u51D1 JSON \u8F93\u51FA\uFF08agent \u6D88\u8D39\uFF09").action(async (opts) => {
|
|
27636
27671
|
await run(cmdList({ dir: opts.dir, offline: !!opts.offline, json: !!opts.json }));
|
|
27637
27672
|
});
|
|
27638
|
-
skills.command("update").description("\u66F4\u65B0\u88C5\u6765\u7684 skill \u5230\u5F53\u524D\u4E0A\u67B6\u7684\u7248\u672C\uFF08\u4E0D\u7ED9\u540D\u5B57 = \u5168\u90E8\uFF1B\u81EA\u5DF1\u5199\u7684\u548C\u6307\u9488\u4E0D\u78B0\uFF09").argument("[names...]", "\u8981\u66F4\u65B0\u7684 skill
|
|
27673
|
+
skills.command("update").description("\u66F4\u65B0\u88C5\u6765\u7684 skill \u5230\u5F53\u524D\u4E0A\u67B6\u7684\u7248\u672C\uFF08\u4E0D\u7ED9\u540D\u5B57 = \u5168\u90E8\uFF1B\u81EA\u5DF1\u5199\u7684\u548C\u6307\u9488\u4E0D\u78B0\uFF09").argument("[names...]", "\u8981\u66F4\u65B0\u7684 skill\uFF1A\u76EE\u5F55\u540D\u3001handle\uFF08\u5982 neta-skills/holo-pack-opening\uFF09\u6216\u5B9A\u4F4D\u7B26").option("--dir <dir>", "\u76EE\u5F55\uFF08\u9ED8\u8BA4 .agents/skills/\uFF09", ".agents/skills").option("--json", "\u7D27\u51D1 JSON \u8F93\u51FA\uFF08agent \u6D88\u8D39\uFF09").action(async (names, opts) => {
|
|
27639
27674
|
await run(cmdUpdate(names, { dir: opts.dir, json: !!opts.json }));
|
|
27640
27675
|
});
|
|
27641
|
-
skills.command("remove").alias("rm").description("\u5220\u9664\u672C\u5730 skill\uFF08\u88C5\u6765\u7684 / \u6307\u9488\uFF1B\u81EA\u5DF1\u5199\u7684\u8981 --force\uFF09").argument("<names...>", "\u8981\u5220\u7684 skill
|
|
27676
|
+
skills.command("remove").alias("rm").description("\u5220\u9664\u672C\u5730 skill\uFF08\u88C5\u6765\u7684 / \u6307\u9488\uFF1B\u81EA\u5DF1\u5199\u7684\u8981 --force\uFF09").argument("<names...>", "\u8981\u5220\u7684 skill\uFF1A\u76EE\u5F55\u540D\u3001handle \u6216\u5B9A\u4F4D\u7B26").option("--dir <dir>", "\u76EE\u5F55\uFF08\u9ED8\u8BA4 .agents/skills/\uFF09", ".agents/skills").option("--force", "\u8FDE\u81EA\u5DF1\u5199\u7684\u4E5F\u5220").option("--json", "\u7D27\u51D1 JSON \u8F93\u51FA\uFF08agent \u6D88\u8D39\uFF09").action(async (names, opts) => {
|
|
27642
27677
|
await run(cmdRemove(names, { dir: opts.dir, force: !!opts.force, json: !!opts.json }));
|
|
27643
27678
|
});
|
|
27644
27679
|
skills.command("init").description("\u521B\u5EFA skill \u811A\u624B\u67B6\uFF08SKILL.md + frontmatter \u89C4\u8303\uFF09").argument("[name]", "skill \u540D\uFF08kebab-case\uFF09").option("--here", "\u5728\u5F53\u524D\u76EE\u5F55\u751F\u6210\uFF08\u9ED8\u8BA4\u751F\u6210\u5230 ./<name>/ \u5B50\u76EE\u5F55\uFF09").action(async (name, opts) => {
|