@hcmai/cli 0.1.0 → 0.2.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/index.js CHANGED
@@ -4186,11 +4186,16 @@ import {
4186
4186
  fromAxiosError as fromAxiosError12,
4187
4187
  uploadDocument as uploadDocument2
4188
4188
  } from "@hcmai/sdk";
4189
+ var DEFAULT_UPLOAD_CATEGORY = "attachment";
4189
4190
  async function uploadCommand(filePath, args) {
4190
4191
  try {
4191
4192
  const ctx = await getActiveAuthContextFromCli(args);
4192
4193
  const client3 = HcmClient14.fromAuthContext(ctx);
4193
- const meta2 = await uploadDocument2(client3.raw(), filePath);
4194
+ const meta2 = await uploadDocument2(
4195
+ client3.raw(),
4196
+ filePath,
4197
+ args.category ?? DEFAULT_UPLOAD_CATEGORY
4198
+ );
4194
4199
  const fmt = args.output ?? "json";
4195
4200
  if (fmt !== "json") {
4196
4201
  process.stdout.write(
@@ -4220,10 +4225,18 @@ init_exit();
4220
4225
  import { promises as fsp } from "fs";
4221
4226
  import os2 from "os";
4222
4227
  import path2 from "path";
4228
+ import { createHash } from "crypto";
4223
4229
  import {
4224
4230
  createHttpClient as createHttpClient2,
4225
4231
  fetchSkillCatalog,
4226
4232
  fetchSkillMarkdown,
4233
+ fetchSkillReference,
4234
+ resolveChironBase,
4235
+ assertSafeSkillId,
4236
+ assertSafeReferencePath,
4237
+ normalizeReferences,
4238
+ parseSkillRequirements,
4239
+ resolveSkillInstallOrder,
4227
4240
  matchSkills,
4228
4241
  filterByStage,
4229
4242
  formatObject as formatObject13,
@@ -4234,6 +4247,10 @@ import {
4234
4247
  CliError as CliError14,
4235
4248
  CliErrorCode as CliErrorCode13
4236
4249
  } from "@hcmai/sdk";
4250
+ var SKILLS_STATE_FILE = ".hcm-skills.json";
4251
+ function sha256(text) {
4252
+ return createHash("sha256").update(text, "utf8").digest("hex");
4253
+ }
4237
4254
  async function resolveEndpoint(args) {
4238
4255
  if (args.endpoint) return args.endpoint.replace(/\/+$/, "");
4239
4256
  const g = await loadGlobalConfig6();
@@ -4247,13 +4264,45 @@ async function resolveEndpoint(args) {
4247
4264
  }
4248
4265
  return env2.endpoint.replace(/\/+$/, "");
4249
4266
  }
4250
- function anonHttp(endpoint) {
4251
- return createHttpClient2({
4267
+ async function exists(target) {
4268
+ try {
4269
+ await fsp.stat(target);
4270
+ return true;
4271
+ } catch {
4272
+ return false;
4273
+ }
4274
+ }
4275
+ async function detectTarget(cwd) {
4276
+ if (await exists(path2.join(cwd, ".claude"))) return "claude";
4277
+ if (await exists(path2.join(cwd, "AGENTS.md"))) return "codex";
4278
+ if (await exists(path2.join(cwd, ".codex"))) return "codex";
4279
+ return void 0;
4280
+ }
4281
+ async function resolveInstallLayout(args, cwd = process.cwd()) {
4282
+ const requested = args.target && args.target !== "auto" ? args.target : void 0;
4283
+ const target = requested ?? await detectTarget(cwd) ?? "claude";
4284
+ if (target === "codex") {
4285
+ const root = args.global ? path2.join(os2.homedir(), ".codex") : cwd;
4286
+ return {
4287
+ target,
4288
+ baseDir: args.dir ? path2.resolve(args.dir) : path2.join(root, "hcm-skills"),
4289
+ agentsFile: path2.join(root, "AGENTS.md")
4290
+ };
4291
+ }
4292
+ return {
4293
+ target,
4294
+ baseDir: args.dir ? path2.resolve(args.dir) : args.global ? path2.join(os2.homedir(), ".claude", "skills") : path2.join(cwd, ".claude", "skills")
4295
+ };
4296
+ }
4297
+ async function chironClient(args) {
4298
+ const endpoint = await resolveEndpoint(args);
4299
+ const http = createHttpClient2({
4252
4300
  endpoint,
4253
4301
  getAccessToken: async () => null,
4254
4302
  onRefresh: async () => {
4255
4303
  }
4256
4304
  });
4305
+ return { http, endpoint, base: await resolveChironBase(http) };
4257
4306
  }
4258
4307
  function fail3(e, args) {
4259
4308
  const err = e;
@@ -4266,8 +4315,8 @@ function fail3(e, args) {
4266
4315
  }
4267
4316
  async function skillsListCommand(keyword, args) {
4268
4317
  try {
4269
- const endpoint = await resolveEndpoint(args);
4270
- const manifest2 = await fetchSkillCatalog(anonHttp(endpoint));
4318
+ const { http, endpoint, base } = await chironClient(args);
4319
+ const manifest2 = await fetchSkillCatalog(http, base);
4271
4320
  const fmt = args.output ?? "table";
4272
4321
  let cats = manifest2.categories ?? [];
4273
4322
  if (args.category) cats = cats.filter((c) => c.key === args.category);
@@ -4337,8 +4386,8 @@ async function skillsListCommand(keyword, args) {
4337
4386
  }
4338
4387
  async function skillsShowCommand(id, args) {
4339
4388
  try {
4340
- const endpoint = await resolveEndpoint(args);
4341
- const md = await fetchSkillMarkdown(anonHttp(endpoint), id);
4389
+ const { http, base } = await chironClient(args);
4390
+ const md = await fetchSkillMarkdown(http, id, base);
4342
4391
  process.stdout.write(md.endsWith("\n") ? md : md + "\n");
4343
4392
  process.exit(0);
4344
4393
  } catch (e) {
@@ -4347,52 +4396,493 @@ async function skillsShowCommand(id, args) {
4347
4396
  }
4348
4397
  async function skillsInstallCommand(id, args) {
4349
4398
  try {
4350
- if (!/^[a-z0-9][a-z0-9-]{0,63}$/.test(id)) {
4399
+ assertSafeSkillId(id);
4400
+ const layout = await resolveInstallLayout(args);
4401
+ let documents;
4402
+ let endpoint;
4403
+ let base;
4404
+ let manifest2;
4405
+ if (args.from) {
4406
+ documents = await resolveLocalSkillDocuments(path2.resolve(args.from), id);
4407
+ } else {
4408
+ const client3 = await chironClient(args);
4409
+ endpoint = client3.endpoint;
4410
+ base = client3.base;
4411
+ manifest2 = await fetchSkillCatalog(client3.http, base);
4412
+ const order = resolveSkillInstallOrder(manifest2, id);
4413
+ documents = await Promise.all(
4414
+ order.map((skill) => fetchSkillDocument(client3.http, skill, endpoint, base))
4415
+ );
4416
+ }
4417
+ const result = await installSkillDocuments(documents, id, layout.baseDir, Boolean(args.force), {
4418
+ endpoint,
4419
+ base,
4420
+ target: layout.target
4421
+ });
4422
+ const agents = layout.agentsFile ? await syncAgentsIndex(layout, manifest2) : void 0;
4423
+ const fmt = args.output ?? "table";
4424
+ if (fmt === "json" || fmt === "yaml") {
4425
+ process.stdout.write(formatObject13({ ...result, target_agent: layout.target, agentsFile: layout.agentsFile, agents }, { format: fmt }) + "\n");
4426
+ } else {
4427
+ process.stdout.write(`\u2705 ${id} \u2192 ${result.target}
4428
+ `);
4429
+ if (result.installed.length > 1) {
4430
+ process.stdout.write(` \u5DF2\u5B89\u88C5 ${result.installed.join(" \u2192 ")}
4431
+ `);
4432
+ }
4433
+ if (result.unchanged.length > 0) {
4434
+ process.stdout.write(` \u5DF2\u5B58\u5728\u4E14\u7248\u672C\u4E00\u81F4 ${result.unchanged.join(", ")}
4435
+ `);
4436
+ }
4437
+ const referenceCount = documents.reduce((n, d) => n + (d.references?.length ?? 0), 0);
4438
+ if (referenceCount > 0) {
4439
+ process.stdout.write(` \u53C2\u8003\u6587\u4EF6 ${referenceCount} \u4E2A\uFF08references/ \u4E0B\uFF09
4440
+ `);
4441
+ }
4442
+ if (layout.agentsFile) {
4443
+ process.stdout.write(` \u5DF2${agents === "created" ? "\u521B\u5EFA" : "\u66F4\u65B0"} ${layout.agentsFile} \u91CC\u7684\u6280\u80FD\u7D22\u5F15\uFF08Codex \u8BFB\u8FD9\u91CC\uFF09
4444
+ `);
4445
+ }
4446
+ process.stdout.write(` \u6765\u6E90 ${result.source}
4447
+ `);
4448
+ process.stdout.write(` \u4EA7\u54C1\u66F4\u65B0\u540E\u8DD1 hcm skills update \u5347\u7EA7
4449
+ `);
4450
+ }
4451
+ process.exit(0);
4452
+ } catch (e) {
4453
+ fail3(e, args);
4454
+ }
4455
+ }
4456
+ async function fetchSkillDocument(http, skill, endpoint, base) {
4457
+ const relatives = normalizeReferences(skill.references, skill.id);
4458
+ const references = await Promise.all(relatives.map(async (relative2) => ({
4459
+ path: relative2,
4460
+ content: await fetchSkillReference(http, skill.id, relative2, base)
4461
+ })));
4462
+ return {
4463
+ id: skill.id,
4464
+ markdown: await fetchSkillMarkdown(http, skill.id, base),
4465
+ source: `${endpoint}${base}/skills/${skill.id}.md`,
4466
+ references
4467
+ };
4468
+ }
4469
+ async function syncAgentsIndex(layout, manifest2) {
4470
+ if (!layout.agentsFile) return void 0;
4471
+ const state = await readSkillsState(layout.baseDir);
4472
+ if (!state) return void 0;
4473
+ const catalog = /* @__PURE__ */ new Map();
4474
+ for (const category of manifest2?.categories ?? []) {
4475
+ for (const skill of category.skills ?? []) catalog.set(skill.id, skill);
4476
+ }
4477
+ const agentsDir = path2.dirname(layout.agentsFile);
4478
+ const entries = Object.keys(state.skills).sort().map((id) => {
4479
+ const known = catalog.get(id);
4480
+ const absolute = path2.join(layout.baseDir, id, "SKILL.md");
4481
+ let relative2 = path2.relative(agentsDir, absolute);
4482
+ if (!relative2.startsWith(".")) relative2 = `./${relative2}`;
4483
+ return {
4484
+ id,
4485
+ title: known?.title ?? id,
4486
+ description: known?.description ?? "",
4487
+ relativePath: relative2.split(path2.sep).join("/")
4488
+ };
4489
+ });
4490
+ return upsertAgentsBlock(layout.agentsFile, renderAgentsBlock(entries));
4491
+ }
4492
+ async function resolveLocalSkillDocuments(sourceRoot, targetId) {
4493
+ assertSafeSkillId(targetId);
4494
+ const state = /* @__PURE__ */ new Map();
4495
+ const pathStack = [];
4496
+ const order = [];
4497
+ const visit = async (id, requiredBy) => {
4498
+ const current = state.get(id);
4499
+ if (current === "done") return;
4500
+ if (current === "visiting") {
4501
+ const start = pathStack.indexOf(id);
4502
+ throw invalid(`\u6280\u80FD\u4F9D\u8D56\u5B58\u5728\u73AF: ${[...pathStack.slice(Math.max(0, start)), id].join(" -> ")}`);
4503
+ }
4504
+ assertSafeSkillId(id);
4505
+ const local = path2.join(sourceRoot, id, "SKILL.md");
4506
+ let markdown;
4507
+ try {
4508
+ markdown = await fsp.readFile(local, "utf8");
4509
+ } catch (cause) {
4510
+ if (cause?.code === "ENOENT") {
4511
+ throw invalid(requiredBy ? `\u672C\u5730\u6280\u80FD ${requiredBy} \u4F9D\u8D56\u4E0D\u5B58\u5728: ${id}\uFF08${local}\uFF09` : `\u672C\u5730\u76EE\u5F55\u91CC\u6CA1\u6709 ${id}/SKILL.md\uFF1A${path2.join(sourceRoot, id)}`);
4512
+ }
4513
+ throw cause;
4514
+ }
4515
+ if (!markdown.trim()) throw invalid(`\u6280\u80FD ${id} \u5185\u5BB9\u4E3A\u7A7A`);
4516
+ state.set(id, "visiting");
4517
+ pathStack.push(id);
4518
+ const document = {
4519
+ id,
4520
+ markdown,
4521
+ source: local,
4522
+ references: await readLocalReferences(path2.join(sourceRoot, id))
4523
+ };
4524
+ for (const required of parseSkillRequirements(markdown, id)) {
4525
+ await visit(required, id);
4526
+ }
4527
+ pathStack.pop();
4528
+ state.set(id, "done");
4529
+ order.push(document);
4530
+ };
4531
+ await visit(targetId);
4532
+ return order;
4533
+ }
4534
+ async function readSkillsState(baseDir) {
4535
+ try {
4536
+ const raw = await fsp.readFile(path2.join(baseDir, SKILLS_STATE_FILE), "utf8");
4537
+ const parsed = JSON.parse(raw);
4538
+ if (!parsed || typeof parsed !== "object" || !parsed.skills) return void 0;
4539
+ return parsed;
4540
+ } catch {
4541
+ return void 0;
4542
+ }
4543
+ }
4544
+ async function writeSkillsState(baseDir, state) {
4545
+ await fsp.mkdir(baseDir, { recursive: true });
4546
+ const file = path2.join(baseDir, SKILLS_STATE_FILE);
4547
+ const temp = `${file}.${process.pid}.tmp`;
4548
+ await fsp.writeFile(temp, JSON.stringify(state, null, 2) + "\n", "utf8");
4549
+ await fsp.rename(temp, file);
4550
+ }
4551
+ var AGENTS_BLOCK_BEGIN = "<!-- hcm-skills:begin -->";
4552
+ var AGENTS_BLOCK_END = "<!-- hcm-skills:end -->";
4553
+ function renderAgentsBlock(entries) {
4554
+ const lines = [
4555
+ AGENTS_BLOCK_BEGIN,
4556
+ "## HCMnext \u4EA4\u4ED8\u6280\u80FD\uFF08\u7531 `hcm skills install` \u7EF4\u62A4\uFF0C\u52FF\u624B\u5DE5\u7F16\u8F91\u672C\u5757\uFF09",
4557
+ "",
4558
+ "\u9047\u5230\u4E0B\u9762\u8FD9\u4E9B\u6D3B\u513F\uFF0C**\u5148\u8BFB\u5BF9\u5E94\u6587\u4EF6\u518D\u52A8\u624B**\u2014\u2014\u91CC\u9762\u662F\u8FD9\u5957\u4EA7\u54C1\u7684\u6B63\u786E\u505A\u6CD5\uFF0C",
4559
+ "\u7167\u7740\u505A\u4E0D\u7528\u7FFB\u6E90\u7801\uFF0C\u4E5F\u4E0D\u7528\u731C API\u3002",
4560
+ ""
4561
+ ];
4562
+ for (const e of entries) {
4563
+ lines.push(`- \`${e.relativePath}\` \u2014 **${e.title}**`);
4564
+ if (e.description) lines.push(` ${e.description}`);
4565
+ }
4566
+ lines.push("", AGENTS_BLOCK_END);
4567
+ return lines.join("\n");
4568
+ }
4569
+ async function upsertAgentsBlock(agentsFile, block) {
4570
+ let existing = "";
4571
+ try {
4572
+ existing = await fsp.readFile(agentsFile, "utf8");
4573
+ } catch (cause) {
4574
+ if (cause?.code !== "ENOENT") throw cause;
4575
+ await fsp.mkdir(path2.dirname(agentsFile), { recursive: true });
4576
+ await fsp.writeFile(agentsFile, block + "\n", "utf8");
4577
+ return "created";
4578
+ }
4579
+ const begin = existing.indexOf(AGENTS_BLOCK_BEGIN);
4580
+ const end = existing.indexOf(AGENTS_BLOCK_END);
4581
+ if (begin >= 0 && end > begin) {
4582
+ const next = existing.slice(0, begin) + block + existing.slice(end + AGENTS_BLOCK_END.length);
4583
+ await fsp.writeFile(agentsFile, next, "utf8");
4584
+ return "replaced";
4585
+ }
4586
+ const separator = existing.endsWith("\n") ? "\n" : "\n\n";
4587
+ await fsp.writeFile(agentsFile, existing + separator + block + "\n", "utf8");
4588
+ return "appended";
4589
+ }
4590
+ async function installSkillDocuments(documents, requestedId, baseDir, force, meta2) {
4591
+ assertSafeSkillId(requestedId);
4592
+ const seen = /* @__PURE__ */ new Set();
4593
+ const candidates = documents.map((document) => {
4594
+ assertSafeSkillId(document.id);
4595
+ if (seen.has(document.id)) throw invalid(`\u5B89\u88C5\u95ED\u5305\u5305\u542B\u91CD\u590D\u6280\u80FD: ${document.id}`);
4596
+ seen.add(document.id);
4597
+ if (!document.markdown.trim()) throw invalid(`\u6280\u80FD ${document.id} \u5185\u5BB9\u4E3A\u7A7A`);
4598
+ return {
4599
+ ...document,
4600
+ target: path2.join(baseDir, document.id, "SKILL.md"),
4601
+ bytes: Buffer.byteLength(document.markdown)
4602
+ };
4603
+ });
4604
+ const requested = candidates.find((candidate) => candidate.id === requestedId);
4605
+ if (!requested) throw invalid(`\u5B89\u88C5\u95ED\u5305\u4E0D\u5305\u542B\u76EE\u6807\u6280\u80FD: ${requestedId}`);
4606
+ const unchanged = /* @__PURE__ */ new Set();
4607
+ for (const candidate of candidates) {
4608
+ let existing;
4609
+ try {
4610
+ existing = await fsp.readFile(candidate.target, "utf8");
4611
+ } catch (cause) {
4612
+ if (cause?.code !== "ENOENT") throw cause;
4613
+ }
4614
+ if (existing === void 0 || force) continue;
4615
+ if (candidate.id !== requestedId && existing === candidate.markdown) {
4616
+ unchanged.add(candidate.id);
4617
+ continue;
4618
+ }
4619
+ const kind = candidate.id === requestedId ? "\u76EE\u6807\u6280\u80FD\u5DF2\u5B58\u5728" : "\u524D\u7F6E\u6280\u80FD\u4E0E\u76EE\u6807\u73AF\u5883\u7248\u672C\u4E0D\u4E00\u81F4";
4620
+ throw invalid(`${kind}\uFF1A${candidate.target}\u3002\u7528 --force \u8986\u76D6\u6574\u4E2A\u4F9D\u8D56\u95ED\u5305\uFF0C\u6216 --dir <path> \u88C5\u5230\u522B\u5904`);
4621
+ }
4622
+ const pending = candidates.filter((candidate) => !unchanged.has(candidate.id));
4623
+ await writeSkillDocuments(pending, baseDir);
4624
+ await recordInstalled(baseDir, candidates, {
4625
+ ...meta2,
4626
+ directIds: /* @__PURE__ */ new Set([requestedId]),
4627
+ keepInstalledAt: unchanged
4628
+ });
4629
+ return {
4630
+ id: requestedId,
4631
+ target: requested.target,
4632
+ source: requested.source,
4633
+ bytes: requested.bytes,
4634
+ installed: pending.map((candidate) => candidate.id),
4635
+ unchanged: candidates.filter((candidate) => unchanged.has(candidate.id)).map((candidate) => candidate.id),
4636
+ files: candidates.map((candidate) => ({
4637
+ id: candidate.id,
4638
+ target: candidate.target,
4639
+ source: candidate.source,
4640
+ bytes: candidate.bytes,
4641
+ status: unchanged.has(candidate.id) ? "unchanged" : "installed"
4642
+ }))
4643
+ };
4644
+ }
4645
+ async function readLocalReferences(skillDir) {
4646
+ const root = path2.join(skillDir, "references");
4647
+ const out = [];
4648
+ const walk = async (dir, prefix) => {
4649
+ let items;
4650
+ try {
4651
+ items = await fsp.readdir(dir, { withFileTypes: true });
4652
+ } catch (cause) {
4653
+ if (cause?.code === "ENOENT") return;
4654
+ throw cause;
4655
+ }
4656
+ for (const item of items.sort((a, b) => a.name.localeCompare(b.name))) {
4657
+ const relative2 = prefix ? `${prefix}/${item.name}` : item.name;
4658
+ if (item.isDirectory()) {
4659
+ await walk(path2.join(dir, item.name), relative2);
4660
+ continue;
4661
+ }
4662
+ if (!item.isFile()) continue;
4663
+ assertSafeReferencePath(relative2);
4664
+ out.push({ path: relative2, content: await fsp.readFile(path2.join(dir, item.name), "utf8") });
4665
+ }
4666
+ };
4667
+ await walk(root, "");
4668
+ return out;
4669
+ }
4670
+ async function writeSkillDocuments(documents, baseDir) {
4671
+ const staged = [];
4672
+ try {
4673
+ for (const document of documents) {
4674
+ const target = path2.join(baseDir, document.id, "SKILL.md");
4675
+ await fsp.mkdir(path2.dirname(target), { recursive: true });
4676
+ const temp = path2.join(path2.dirname(target), `.SKILL.md.${process.pid}.${Date.now()}.tmp`);
4677
+ await fsp.writeFile(temp, document.markdown, "utf8");
4678
+ staged.push({ temp, target });
4679
+ for (const reference of document.references ?? []) {
4680
+ assertSafeReferencePath(reference.path);
4681
+ const referenceTarget = path2.join(baseDir, document.id, "references", reference.path);
4682
+ await fsp.mkdir(path2.dirname(referenceTarget), { recursive: true });
4683
+ const referenceTemp = `${referenceTarget}.${process.pid}.${Date.now()}.tmp`;
4684
+ await fsp.writeFile(referenceTemp, reference.content, "utf8");
4685
+ staged.push({ temp: referenceTemp, target: referenceTarget });
4686
+ }
4687
+ }
4688
+ for (const file of staged) await fsp.rename(file.temp, file.target);
4689
+ } catch (cause) {
4690
+ await Promise.all(staged.map((file) => fsp.unlink(file.temp).catch(() => void 0)));
4691
+ throw cause;
4692
+ }
4693
+ }
4694
+ async function recordInstalled(baseDir, documents, meta2) {
4695
+ const state = await readSkillsState(baseDir) ?? {
4696
+ version: 1,
4697
+ target: meta2.target ?? "claude",
4698
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
4699
+ skills: {}
4700
+ };
4701
+ state.version = 1;
4702
+ if (meta2.target) state.target = meta2.target;
4703
+ if (meta2.endpoint) state.endpoint = meta2.endpoint;
4704
+ if (meta2.base !== void 0) state.base = meta2.base;
4705
+ state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4706
+ for (const document of documents) {
4707
+ const previous = state.skills[document.id];
4708
+ state.skills[document.id] = {
4709
+ source: document.source,
4710
+ sha256: sha256(document.markdown),
4711
+ installedAt: meta2.keepInstalledAt?.has(document.id) && previous ? previous.installedAt : state.updatedAt,
4712
+ // 已经是直接安装的,不因为这次作为依赖被带进来就降级
4713
+ direct: meta2.directIds.has(document.id) || Boolean(previous?.direct),
4714
+ references: Object.fromEntries(
4715
+ (document.references ?? []).map((reference) => [reference.path, sha256(reference.content)])
4716
+ )
4717
+ };
4718
+ }
4719
+ await writeSkillsState(baseDir, state);
4720
+ return state;
4721
+ }
4722
+ function invalid(message) {
4723
+ return new CliError14({ code: CliErrorCode13.INVALID_ARGUMENT, message });
4724
+ }
4725
+ async function readInstalled(baseDir, id) {
4726
+ try {
4727
+ return await fsp.readFile(path2.join(baseDir, id, "SKILL.md"), "utf8");
4728
+ } catch (cause) {
4729
+ if (cause?.code === "ENOENT") return void 0;
4730
+ throw cause;
4731
+ }
4732
+ }
4733
+ async function readInstalledReference(baseDir, id, relative2) {
4734
+ try {
4735
+ return await fsp.readFile(path2.join(baseDir, id, "references", relative2), "utf8");
4736
+ } catch (cause) {
4737
+ if (cause?.code === "ENOENT") return void 0;
4738
+ throw cause;
4739
+ }
4740
+ }
4741
+ async function planSkillUpdate(options) {
4742
+ const { state, manifest: manifest2, baseDir, force, fetchDocument } = options;
4743
+ const recorded = Object.entries(state.skills);
4744
+ const directIds = recorded.some(([, r]) => r.direct) ? recorded.filter(([, r]) => r.direct).map(([id]) => id) : recorded.map(([id]) => id);
4745
+ const entries = [];
4746
+ const closure = /* @__PURE__ */ new Map();
4747
+ for (const id of directIds.sort()) {
4748
+ try {
4749
+ for (const skill of resolveSkillInstallOrder(manifest2, id)) {
4750
+ if (!closure.has(skill.id)) closure.set(skill.id, skill);
4751
+ }
4752
+ } catch {
4753
+ entries.push({
4754
+ id,
4755
+ status: "removed-upstream",
4756
+ note: "\u4EA7\u54C1\u8FD9\u4E00\u7248\u7684\u6280\u80FD\u76EE\u5F55\u91CC\u5DF2\u7ECF\u6CA1\u6709\u5B83\u4E86\uFF1B\u672C\u5730\u6587\u4EF6\u4FDD\u7559\u4E0D\u52A8"
4757
+ });
4758
+ }
4759
+ }
4760
+ const documents = [];
4761
+ for (const skill of closure.values()) {
4762
+ const record = state.skills[skill.id];
4763
+ const onDisk = await readInstalled(baseDir, skill.id);
4764
+ if (onDisk === void 0) {
4765
+ documents.push(await fetchDocument(skill));
4766
+ entries.push({
4767
+ id: skill.id,
4768
+ status: "added",
4769
+ note: record ? "\u672C\u5730\u6587\u4EF6\u7F3A\u5931\uFF0C\u91CD\u65B0\u88C5\u56DE" : "\u4EA7\u54C1\u65B0\u589E\u7684\u524D\u7F6E\u6280\u80FD"
4770
+ });
4771
+ continue;
4772
+ }
4773
+ const remote = await fetchDocument(skill);
4774
+ const remoteReferences = remote.references ?? [];
4775
+ let differsFromRemote = remote.markdown !== onDisk;
4776
+ let editedLocally = record !== void 0 && sha256(onDisk) !== record.sha256;
4777
+ for (const reference of remoteReferences) {
4778
+ const installed = await readInstalledReference(baseDir, skill.id, reference.path);
4779
+ if (installed !== reference.content) differsFromRemote = true;
4780
+ const recordedSha = record?.references?.[reference.path];
4781
+ if (installed !== void 0 && recordedSha && sha256(installed) !== recordedSha) editedLocally = true;
4782
+ }
4783
+ if (!differsFromRemote) {
4784
+ entries.push({ id: skill.id, status: "unchanged" });
4785
+ continue;
4786
+ }
4787
+ if (editedLocally && !force) {
4788
+ entries.push({
4789
+ id: skill.id,
4790
+ status: "locally-modified",
4791
+ note: "\u672C\u5730\u6539\u8FC7\uFF0C\u6CA1\u6709\u8986\u76D6\uFF1B\u786E\u5B9A\u8981\u7528\u4EA7\u54C1\u8FD9\u4E00\u7248\u5C31\u52A0 --force"
4792
+ });
4793
+ continue;
4794
+ }
4795
+ documents.push(remote);
4796
+ entries.push({
4797
+ id: skill.id,
4798
+ status: "updated",
4799
+ note: editedLocally ? "\u672C\u5730\u6539\u8FC7\uFF0C--force \u5DF2\u8986\u76D6" : void 0
4800
+ });
4801
+ }
4802
+ entries.sort((a, b) => a.id.localeCompare(b.id));
4803
+ return { entries, documents };
4804
+ }
4805
+ var UPDATE_STATUS_LABEL = {
4806
+ updated: "\u5DF2\u66F4\u65B0",
4807
+ added: "\u5DF2\u8865\u88C5",
4808
+ unchanged: "\u5DF2\u662F\u6700\u65B0",
4809
+ "locally-modified": "\u672C\u5730\u6539\u8FC7\xB7\u8DF3\u8FC7",
4810
+ "removed-upstream": "\u4EA7\u54C1\u5DF2\u79FB\u9664"
4811
+ };
4812
+ async function skillsUpdateCommand(args) {
4813
+ try {
4814
+ const layout = await resolveInstallLayout(args);
4815
+ const state = await readSkillsState(layout.baseDir);
4816
+ if (!state || Object.keys(state.skills).length === 0) {
4351
4817
  throw new CliError14({
4352
4818
  code: CliErrorCode13.INVALID_ARGUMENT,
4353
- message: `\u6280\u80FD id \u53EA\u80FD\u662F\u5C0F\u5199\u5B57\u6BCD/\u6570\u5B57/\u8FDE\u5B57\u7B26\uFF0C\u6536\u5230 "${id}"`
4819
+ message: `${path2.join(layout.baseDir, SKILLS_STATE_FILE)} \u4E0D\u5B58\u5728\u6216\u4E3A\u7A7A \u2014\u2014 \u8FD9\u4E2A\u76EE\u5F55\u4E0B\u8FD8\u6CA1\u6709\u7528\u672C CLI \u88C5\u8FC7\u6280\u80FD\u3002\u5148 \`hcm skills install <id>\`\uFF1B\u5982\u679C\u6280\u80FD\u662F\u624B\u5DE5\u62F7\u8FDB\u6765\u7684\uFF0C\u91CD\u88C5\u4E00\u6B21\u5373\u53EF\u63A5\u7BA1\u5347\u7EA7\u3002`
4354
4820
  });
4355
4821
  }
4356
- let md;
4357
- let source;
4358
- if (args.from) {
4359
- const local = path2.resolve(args.from, id, "SKILL.md");
4360
- md = await fsp.readFile(local, "utf8");
4361
- source = local;
4362
- } else {
4363
- const endpoint = await resolveEndpoint(args);
4364
- md = await fetchSkillMarkdown(anonHttp(endpoint), id);
4365
- source = `${endpoint}/skills/${id}.md`;
4366
- }
4367
- if (!md.trim()) {
4368
- throw new CliError14({ code: CliErrorCode13.INVALID_ARGUMENT, message: `\u6280\u80FD ${id} \u5185\u5BB9\u4E3A\u7A7A` });
4369
- }
4370
- const baseDir = args.dir ? path2.resolve(args.dir) : args.global ? path2.join(os2.homedir(), ".claude", "skills") : path2.resolve(".claude", "skills");
4371
- const target = path2.join(baseDir, id, "SKILL.md");
4372
- const exists = await fsp.access(target).then(() => true).catch(() => false);
4373
- if (exists && !args.force) {
4374
- process.stderr.write(`\u5DF2\u5B58\u5728\uFF1A${target}
4375
- \u7528 --force \u8986\u76D6\uFF0C\u6216 --dir <path> \u88C5\u5230\u522B\u5904
4376
- `);
4377
- process.exit(1);
4822
+ const endpoint = args.endpoint ? args.endpoint.replace(/\/+$/, "") : await resolveEndpoint(args).catch((e) => {
4823
+ if (state.endpoint) return state.endpoint;
4824
+ throw e;
4825
+ });
4826
+ const { http, base } = await chironClient({ ...args, endpoint });
4827
+ const manifest2 = await fetchSkillCatalog(http, base);
4828
+ const plan = await planSkillUpdate({
4829
+ state,
4830
+ manifest: manifest2,
4831
+ baseDir: layout.baseDir,
4832
+ force: Boolean(args.force),
4833
+ fetchDocument: (skill) => fetchSkillDocument(http, skill, endpoint, base)
4834
+ });
4835
+ if (!args.check && plan.documents.length > 0) {
4836
+ await writeSkillDocuments(plan.documents, layout.baseDir);
4837
+ await recordInstalled(layout.baseDir, plan.documents, {
4838
+ endpoint,
4839
+ base,
4840
+ target: layout.target,
4841
+ directIds: /* @__PURE__ */ new Set()
4842
+ });
4843
+ if (layout.agentsFile) await syncAgentsIndex(layout, manifest2);
4378
4844
  }
4379
- await fsp.mkdir(path2.dirname(target), { recursive: true });
4380
- await fsp.writeFile(target, md, "utf8");
4845
+ const changed = plan.entries.filter((e) => e.status === "updated" || e.status === "added");
4381
4846
  const fmt = args.output ?? "table";
4382
4847
  if (fmt === "json" || fmt === "yaml") {
4383
- process.stdout.write(
4384
- formatObject13({ id, target, source, bytes: Buffer.byteLength(md) }, { format: fmt }) + "\n"
4385
- );
4848
+ process.stdout.write(formatObject13({
4849
+ endpoint,
4850
+ baseDir: layout.baseDir,
4851
+ target: layout.target,
4852
+ dryRun: Boolean(args.check),
4853
+ changed: changed.length,
4854
+ entries: plan.entries
4855
+ }, { format: fmt }) + "\n");
4856
+ process.exit(0);
4857
+ }
4858
+ process.stdout.write(`\u777F\u620E\u6280\u80FD\u5347\u7EA7 \u2014 ${endpoint}
4859
+ `);
4860
+ process.stdout.write(`\u843D\u70B9 ${layout.baseDir}\uFF08${layout.target}\uFF09
4861
+
4862
+ `);
4863
+ for (const entry of plan.entries) {
4864
+ const mark = entry.status === "unchanged" ? " " : entry.status === "locally-modified" ? "!" : "\xB7";
4865
+ process.stdout.write(` ${mark} ${entry.id.padEnd(30)} ${UPDATE_STATUS_LABEL[entry.status]}
4866
+ `);
4867
+ if (entry.note) process.stdout.write(` ${entry.note}
4868
+ `);
4869
+ }
4870
+ process.stdout.write("\n");
4871
+ const skipped = plan.entries.filter((e) => e.status === "locally-modified").length;
4872
+ const removed = plan.entries.filter((e) => e.status === "removed-upstream").length;
4873
+ const tail = [
4874
+ skipped > 0 ? `${skipped} \u4E2A\u672C\u5730\u6539\u8FC7\u88AB\u8DF3\u8FC7\uFF08--force \u8986\u76D6\uFF09` : "",
4875
+ removed > 0 ? `${removed} \u4E2A\u4EA7\u54C1\u5DF2\u79FB\u9664\uFF08\u672C\u5730\u6587\u4EF6\u4FDD\u7559\uFF09` : ""
4876
+ ].filter(Boolean).join("\uFF0C");
4877
+ if (changed.length === 0 && skipped === 0 && removed === 0) {
4878
+ process.stdout.write(args.check ? " \u5168\u90E8\u5DF2\u662F\u6700\u65B0\uFF08--check \u53EA\u770B\u4E0D\u52A8\uFF09\n" : " \u5168\u90E8\u5DF2\u662F\u6700\u65B0\uFF0C\u6CA1\u6709\u6539\u52A8\n");
4386
4879
  } else {
4387
- process.stdout.write(`\u2705 ${id} \u2192 ${target}
4388
- \u6765\u6E90 ${source}
4880
+ const head = args.check ? changed.length > 0 ? `\u6709 ${changed.length} \u4E2A\u53EF\u4EE5\u66F4\u65B0\uFF0C\u53BB\u6389 --check \u5C31\u4F1A\u5199\u5165` : "\u6CA1\u6709\u53EF\u5199\u5165\u7684\u66F4\u65B0" : changed.length > 0 ? `\u5DF2\u66F4\u65B0 ${changed.length} \u4E2A` : "\u6CA1\u6709\u5199\u5165\u4EFB\u4F55\u6539\u52A8";
4881
+ process.stdout.write(` ${[head, tail].filter(Boolean).join("\uFF1B")}
4389
4882
  `);
4390
4883
  }
4391
4884
  process.exit(0);
4392
4885
  } catch (e) {
4393
- if (e?.code === "ENOENT" && args.from) {
4394
- exitWithError(new Error(`\u672C\u5730\u76EE\u5F55\u91CC\u6CA1\u6709 ${id}/SKILL.md\uFF1A${path2.resolve(args.from, id)}`));
4395
- }
4396
4886
  fail3(e, args);
4397
4887
  }
4398
4888
  }
@@ -5289,7 +5779,7 @@ async function walkWorkspaceRawFiles(rootDir, relativeDir, files) {
5289
5779
  localPath,
5290
5780
  absolutePath,
5291
5781
  content,
5292
- sha256: sha256(content),
5782
+ sha256: sha2562(content),
5293
5783
  size: Buffer.byteLength(content, "utf-8")
5294
5784
  });
5295
5785
  }
@@ -5356,7 +5846,7 @@ function buildWorkspaceRawPushPlan(manifest2, localFiles, remoteFiles) {
5356
5846
  for (const entry of status) {
5357
5847
  const remote = remoteByLocal.get(entry.localPath);
5358
5848
  const base = baseByLocal.get(entry.localPath);
5359
- const remoteSha = remote ? sha256(remote.content) : void 0;
5849
+ const remoteSha = remote ? sha2562(remote.content) : void 0;
5360
5850
  if (entry.status === "added") {
5361
5851
  if (remote) {
5362
5852
  conflicts.push(workspaceRawConflict(entry, "remote file already exists but was not in local snapshot"));
@@ -5621,7 +6111,7 @@ function normalizeRelativePath(value) {
5621
6111
  function toPosix(value) {
5622
6112
  return value.split(path3.sep).join("/");
5623
6113
  }
5624
- function sha256(content) {
6114
+ function sha2562(content) {
5625
6115
  return crypto.createHash("sha256").update(content, "utf-8").digest("hex");
5626
6116
  }
5627
6117
  function stringRequired(value, field) {
@@ -6059,7 +6549,11 @@ var cache = program.command("cache").description("\u6A21\u578B\u7F13\u5B58\u8FD0
6059
6549
  cache.command("stats <Model>").description("\u67E5\u770B\u6A21\u578B\u7F13\u5B58\u7EDF\u8BA1").option("--env <name>", "\u4E34\u65F6\u5207\u73AF\u5883\uFF08\u8986\u76D6 activeEnv\uFF0C\u672C\u6B21\u547D\u4EE4\uFF09").option("--as <identity>", "\u4E34\u65F6\u6362\u8EAB\u4EFD").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "json").action((model, opts) => cacheStatsCommand(model, opts));
6060
6550
  cache.command("clear <Model>").description("\u6E05\u6A21\u578B\u5B9E\u4F53\u7F13\u5B58\uFF08\u5E42\u7B49\uFF0C\u4E0D\u7834\u574F\u6570\u636E\uFF09").option("--id <id>", "\u53EA\u6E05\u5355\u6761\uFF08\u9ED8\u8BA4\u6E05\u5168\u90E8\uFF09").option("--env <name>", "\u4E34\u65F6\u5207\u73AF\u5883\uFF08\u8986\u76D6 activeEnv\uFF0C\u672C\u6B21\u547D\u4EE4\uFF09").option("--as <identity>", "\u4E34\u65F6\u6362\u8EAB\u4EFD").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "json").action((model, opts) => cacheClearCommand(model, opts));
6061
6551
  cache.command("clear-meta <Model>").description("\u6E05\u5143\u6570\u636E\u7F13\u5B58\uFF08Code \u7EA7 YAML + Action \u5B9A\u4E49\uFF09\u2014\u2014\u6539 meta YAML \u540E\u5FC5\u8DD1").option("--type <type>", "\u5143\u6570\u636E\u7C7B\u578B\uFF1Alist | info | view | filter | page\u2026\uFF08\u9ED8\u8BA4\u5168\u6E05\uFF09").option("--state <state>", "\u72B6\u6001\u53D8\u4F53\uFF08\u5982 self\uFF09\uFF0C\u914D\u5408 --type").option("--env <name>", "\u4E34\u65F6\u5207\u73AF\u5883\uFF08\u8986\u76D6 activeEnv\uFF0C\u672C\u6B21\u547D\u4EE4\uFF09").option("--as <identity>", "\u4E34\u65F6\u6362\u8EAB\u4EFD").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "json").action((model, opts) => cacheClearMetaCommand(model, opts));
6062
- program.command("upload <file>").description("\u4E0A\u4F20\u672C\u5730\u6587\u4EF6\u5230 HCM \u6587\u6863\u670D\u52A1\uFF0C\u8FD4\u56DE documentId").option("--env <name>", "\u4E34\u65F6\u5207\u73AF\u5883\uFF08\u8986\u76D6 activeEnv\uFF0C\u672C\u6B21\u547D\u4EE4\uFF09").option("--as <identity>", "\u4E34\u65F6\u6362\u8EAB\u4EFD").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "json").action((file, opts) => uploadCommand(file, opts));
6552
+ program.command("upload <file>").description("\u4E0A\u4F20\u672C\u5730\u6587\u4EF6\u5230 HCM \u6587\u6863\u670D\u52A1\uFF0C\u8FD4\u56DE documentId").option("--env <name>", "\u4E34\u65F6\u5207\u73AF\u5883\uFF08\u8986\u76D6 activeEnv\uFF0C\u672C\u6B21\u547D\u4EE4\uFF09").option("--as <identity>", "\u4E34\u65F6\u6362\u8EAB\u4EFD").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "json").option(
6553
+ "--category <name>",
6554
+ "\u5B58\u50A8\u5206\u7C7B\uFF08\u987B\u662F\u76EE\u6807\u73AF\u5883\u91CC\u771F\u5B9E\u5B58\u5728\u7684\u5206\u7C7B\uFF0C\u5982 flex-report / template / attachment\uFF09",
6555
+ "attachment"
6556
+ ).action((file, opts) => uploadCommand(file, opts));
6063
6557
  var tenant = program.command("tenant").description("\u79DF\u6237\u5F00\u901A\u4E0E\u751F\u547D\u5468\u671F");
6064
6558
  tenant.command("bootstrap").description("\u5F00\u901A\u65B0\u79DF\u6237\uFF08\u5EFA\u79DF\u6237 + admin \u7528\u6237 + \u7ED3\u6784 reconcile\uFF09\u2014\u2014\u4E0D\u53EF\u9006\uFF0C\u9ED8\u8BA4\u8FC7\u786E\u8BA4\u95F8").requiredOption("--tenant-id <id>", "\u79DF\u6237 ID").requiredOption("--admin-username <user>", "\u7BA1\u7406\u5458\u7528\u6237\u540D").option("--admin-password <pwd>", "\u7BA1\u7406\u5458\u5BC6\u7801\uFF08\u4F1A\u6CC4\u6F0F\u5230 history/ps\uFF0C\u5EFA\u8BAE --admin-password-stdin\uFF09").option("--admin-password-stdin", "\u4ECE\u6807\u51C6\u8F93\u5165\u8BFB\u7BA1\u7406\u5458\u5BC6\u7801\uFF08\u63A8\u8350\uFF09").option("--tenant-name <name>", "\u79DF\u6237\u540D\u79F0\uFF08\u9ED8\u8BA4\u53D6 tenantId\uFF09").option("--bootstrap-key <key>", "bootstrap \u5BC6\u94A5\uFF08\u5EFA\u8BAE\u7528 HCM_BOOTSTRAP_KEY \u73AF\u5883\u53D8\u91CF\uFF09").option("--bootstrap-key-stdin", "\u4ECE\u6807\u51C6\u8F93\u5165\u8BFB bootstrap \u5BC6\u94A5").option("--endpoint <url>", "\u540E\u7AEF\u5730\u5740\uFF08\u9ED8\u8BA4\u53D6 activeEnv \u7684 endpoint\uFF09").option("--env <name>", "\u4ECE\u8BE5 env \u89E3\u6790 endpoint").option("-y, --yes", "\u8DF3\u8FC7\u786E\u8BA4\uFF08CI \u7528\uFF09").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "json").action((opts) => tenantBootstrapCommand(opts));
6065
6559
  var meta = program.command("meta").description("\u79DF\u6237\u5143\u6570\u636E\u8BFB\u5199\uFF08\u9875\u9762/\u5B57\u6BB5/\u5217\u8868\u914D\u7F6E\uFF09");
@@ -6070,7 +6564,8 @@ meta.command("delete <path>").description("\u5220\u9664 meta\uFF08\u4E0D\u53EF\u
6070
6564
  var skills = program.command("skills").description("\u777F\u620E Chiron \u4EA4\u4ED8\u6280\u80FD\u5E93\uFF1A\u5217\u51FA / \u67E5\u770B / \u5B89\u88C5\u4EA4\u4ED8\u6280\u80FD\uFF08\u514D\u8BA4\u8BC1\uFF0C\u65E0\u9700\u5148 login\uFF09");
6071
6565
  skills.command("list [keyword]").description("\u5217\u51FA\u76EE\u6807\u73AF\u5883\u8FD9\u4E00\u7248\u7684\u4EA4\u4ED8\u6280\u80FD").option("--category <key>", "\u53EA\u770B\u67D0\u4E2A\u5206\u7C7B").option("--stage <key>", "\u53EA\u770B\u67D0\u4E2A\u4EA4\u4ED8\u9636\u6BB5\uFF1Ahandover | baseline | configure | migrate | integrate | golive | operate").option("--by-stage", "\u6309\u4EA4\u4ED8\u751F\u547D\u5468\u671F\u5206\u7EC4\u5C55\u793A\uFF08\u9ED8\u8BA4\u6309\u529F\u80FD\u5206\u7C7B\uFF09").option("--endpoint <url>", "\u6280\u80FD\u5E93\u5730\u5740\uFF08\u9ED8\u8BA4\u53D6 activeEnv \u7684 endpoint\uFF09").option("--env <name>", "\u4ECE\u8BE5 env \u89E3\u6790 endpoint").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "table").action((kw, opts) => skillsListCommand(kw, opts));
6072
6566
  skills.command("show <id>").description("\u6253\u5370\u6280\u80FD\u539F\u6587\uFF08\u7BA1\u9053\u53CB\u597D\uFF09").option("--endpoint <url>", "\u6280\u80FD\u5E93\u5730\u5740\uFF08\u9ED8\u8BA4\u53D6 activeEnv \u7684 endpoint\uFF09").option("--env <name>", "\u4ECE\u8BE5 env \u89E3\u6790 endpoint").action((id, opts) => skillsShowCommand(id, opts));
6073
- skills.command("install <id>").description("\u88C5\u5230 agent \u6280\u80FD\u76EE\u5F55\uFF08\u9ED8\u8BA4 ./.claude/skills/\uFF09").option("--global", "\u88C5\u5230 ~/.claude/skills/ \u800C\u975E\u5F53\u524D\u9879\u76EE").option("--dir <path>", "\u88C5\u5230\u6307\u5B9A\u76EE\u5F55").option("--from <dir>", "\u4ECE\u672C\u5730\u76EE\u5F55\u88C5\uFF08\u73B0\u573A\u6539\u8FC7\u7684\u7248\u672C\uFF09\uFF0C\u4E0D\u8D70\u7F51\u7EDC").option("--force", "\u8986\u76D6\u5DF2\u5B58\u5728\u7684\u540C\u540D\u6280\u80FD").option("--endpoint <url>", "\u6280\u80FD\u5E93\u5730\u5740\uFF08\u9ED8\u8BA4\u53D6 activeEnv \u7684 endpoint\uFF09").option("--env <name>", "\u4ECE\u8BE5 env \u89E3\u6790 endpoint").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "table").action((id, opts) => skillsInstallCommand(id, opts));
6567
+ skills.command("install <id>").description("\u8FDE\u540C requires \u524D\u7F6E\u6280\u80FD\u4E0E\u53C2\u8003\u6587\u4EF6\u88C5\u5230 agent \u6280\u80FD\u76EE\u5F55").option("--target <agent>", "\u88C5\u7ED9\u54EA\u4E2A agent\uFF1Aclaude\uFF08.claude/skills/\uFF09| codex\uFF08hcm-skills/ + AGENTS.md\uFF09| auto", "auto").option("--global", "\u88C5\u5230\u7528\u6237\u7EA7\u76EE\u5F55\u800C\u975E\u5F53\u524D\u9879\u76EE").option("--dir <path>", "\u88C5\u5230\u6307\u5B9A\u76EE\u5F55").option("--from <dir>", "\u4ECE\u672C\u5730\u76EE\u5F55\u88C5\uFF08\u73B0\u573A\u6539\u8FC7\u7684\u7248\u672C\uFF09\uFF0C\u4E0D\u8D70\u7F51\u7EDC").option("--force", "\u8986\u76D6\u5DF2\u5B58\u5728\u7684\u540C\u540D\u6280\u80FD").option("--endpoint <url>", "\u6280\u80FD\u5E93\u5730\u5740\uFF08\u9ED8\u8BA4\u53D6 activeEnv \u7684 endpoint\uFF09").option("--env <name>", "\u4ECE\u8BE5 env \u89E3\u6790 endpoint").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "table").action((id, opts) => skillsInstallCommand(id, opts));
6568
+ skills.command("update").description("\u628A\u88C5\u8FC7\u7684\u6280\u80FD\u5347\u5230\u76EE\u6807\u73AF\u5883\u8FD9\u4E00\u7248\uFF08\u4EA7\u54C1\u5347\u7EA7\u540E\u8DD1\u5B83\uFF09").option("--check", "\u53EA\u770B\u4F1A\u53D8\u4EC0\u4E48\uFF0C\u4E0D\u5199\u76D8").option("--target <agent>", "claude | codex | auto\uFF08\u9ED8\u8BA4\u6309\u5DF2\u5B89\u88C5\u76EE\u5F55\u63A2\uFF09", "auto").option("--global", "\u5347\u7EA7\u7528\u6237\u7EA7\u76EE\u5F55\u91CC\u7684\u6280\u80FD").option("--dir <path>", "\u5347\u7EA7\u6307\u5B9A\u76EE\u5F55\u91CC\u7684\u6280\u80FD").option("--force", "\u8FDE\u672C\u5730\u6539\u8FC7\u7684\u6280\u80FD\u4E00\u8D77\u8986\u76D6\u6210\u4EA7\u54C1\u8FD9\u4E00\u7248").option("--endpoint <url>", "\u6280\u80FD\u5E93\u5730\u5740\uFF08\u9ED8\u8BA4\u53D6\u5B89\u88C5\u65F6\u8BB0\u5F55\u7684\u5730\u5740\uFF09").option("--env <name>", "\u4ECE\u8BE5 env \u89E3\u6790 endpoint").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "table").action((opts) => skillsUpdateCommand(opts));
6074
6569
  program.command("update <Model>").description("\u66F4\u65B0\u4E00\u6761 Model \u8BB0\u5F55\uFF08\u8D70\u540E\u7AEF\u5B8C\u6574\u6821\u9A8C\uFF09").requiredOption("--id <id>", "\u8BB0\u5F55 ID").requiredOption("--data <JSON>", `\u8981\u66F4\u65B0\u7684\u5B57\u6BB5 JSON\uFF0C\u4F8B\u5982 '{"name":"\u65B0\u540D\u79F0"}'`).option("--env <name>", "\u4E34\u65F6\u5207\u73AF\u5883\uFF08\u8986\u76D6 activeEnv\uFF0C\u672C\u6B21\u547D\u4EE4\uFF09").option("--as <identity>", "\u4E34\u65F6\u6362\u8EAB\u4EFD\uFF08\u8986\u76D6 env defaultIdentity\uFF0C\u672C\u6B21\u547D\u4EE4\uFF09").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "json").action((model, opts) => updateCommand(model, opts));
6075
6570
  program.command("version").description("\u67E5\u540E\u7AEF\u7248\u672C\uFF08commit / tag / \u6784\u5EFA\u65F6\u95F4\uFF09\u2014\u2014\u514D\u8BA4\u8BC1\uFF0C\u65E0\u9700\u5148 login").option("--endpoint <url>", "\u540E\u7AEF\u5730\u5740\uFF08\u9ED8\u8BA4\u53D6 activeEnv \u7684 endpoint\uFF09").option("--env <name>", "\u4ECE\u8BE5 env \u89E3\u6790 endpoint").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "json").action((opts) => versionCommand(opts));
6076
6571
  var setting = program.command("setting").description("\u79DF\u6237\u7CFB\u7EDF\u53C2\u6570\uFF08\u767B\u5F55\u7B56\u7565 / \u5BC6\u7801\u7B56\u7565 / \u529F\u80FD\u5F00\u5173 / \u96C6\u6210\u53C2\u6570\uFF09");