@hcmai/cli 0.1.0 → 0.2.1

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,21 @@ 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
+ parseSkillFrontmatter,
4240
+ resolveSkillInstallOrder,
4241
+ resolveAllSkillsInstallOrder,
4242
+ flattenSkills,
4227
4243
  matchSkills,
4228
4244
  filterByStage,
4229
4245
  formatObject as formatObject13,
@@ -4234,6 +4250,10 @@ import {
4234
4250
  CliError as CliError14,
4235
4251
  CliErrorCode as CliErrorCode13
4236
4252
  } from "@hcmai/sdk";
4253
+ var SKILLS_STATE_FILE = ".hcm-skills.json";
4254
+ function sha256(text) {
4255
+ return createHash("sha256").update(text, "utf8").digest("hex");
4256
+ }
4237
4257
  async function resolveEndpoint(args) {
4238
4258
  if (args.endpoint) return args.endpoint.replace(/\/+$/, "");
4239
4259
  const g = await loadGlobalConfig6();
@@ -4247,13 +4267,45 @@ async function resolveEndpoint(args) {
4247
4267
  }
4248
4268
  return env2.endpoint.replace(/\/+$/, "");
4249
4269
  }
4250
- function anonHttp(endpoint) {
4251
- return createHttpClient2({
4270
+ async function exists(target) {
4271
+ try {
4272
+ await fsp.stat(target);
4273
+ return true;
4274
+ } catch {
4275
+ return false;
4276
+ }
4277
+ }
4278
+ async function detectTarget(cwd) {
4279
+ if (await exists(path2.join(cwd, ".claude"))) return "claude";
4280
+ if (await exists(path2.join(cwd, "AGENTS.md"))) return "codex";
4281
+ if (await exists(path2.join(cwd, ".codex"))) return "codex";
4282
+ return void 0;
4283
+ }
4284
+ async function resolveInstallLayout(args, cwd = process.cwd()) {
4285
+ const requested = args.target && args.target !== "auto" ? args.target : void 0;
4286
+ const target = requested ?? await detectTarget(cwd) ?? "claude";
4287
+ if (target === "codex") {
4288
+ const root = args.global ? path2.join(os2.homedir(), ".codex") : cwd;
4289
+ return {
4290
+ target,
4291
+ baseDir: args.dir ? path2.resolve(args.dir) : path2.join(root, "hcm-skills"),
4292
+ agentsFile: path2.join(root, "AGENTS.md")
4293
+ };
4294
+ }
4295
+ return {
4296
+ target,
4297
+ baseDir: args.dir ? path2.resolve(args.dir) : args.global ? path2.join(os2.homedir(), ".claude", "skills") : path2.join(cwd, ".claude", "skills")
4298
+ };
4299
+ }
4300
+ async function chironClient(args) {
4301
+ const endpoint = await resolveEndpoint(args);
4302
+ const http = createHttpClient2({
4252
4303
  endpoint,
4253
4304
  getAccessToken: async () => null,
4254
4305
  onRefresh: async () => {
4255
4306
  }
4256
4307
  });
4308
+ return { http, endpoint, base: await resolveChironBase(http) };
4257
4309
  }
4258
4310
  function fail3(e, args) {
4259
4311
  const err = e;
@@ -4266,8 +4318,9 @@ function fail3(e, args) {
4266
4318
  }
4267
4319
  async function skillsListCommand(keyword, args) {
4268
4320
  try {
4269
- const endpoint = await resolveEndpoint(args);
4270
- const manifest2 = await fetchSkillCatalog(anonHttp(endpoint));
4321
+ if (args.installed) return await listInstalledSkills(keyword, args);
4322
+ const { http, endpoint, base } = await chironClient(args);
4323
+ const manifest2 = await fetchSkillCatalog(http, base);
4271
4324
  const fmt = args.output ?? "table";
4272
4325
  let cats = manifest2.categories ?? [];
4273
4326
  if (args.category) cats = cats.filter((c) => c.key === args.category);
@@ -4335,10 +4388,82 @@ async function skillsListCommand(keyword, args) {
4335
4388
  fail3(e, args);
4336
4389
  }
4337
4390
  }
4391
+ async function listInstalledSkills(keyword, args) {
4392
+ const layout = await resolveInstallLayout(args);
4393
+ const state = await readSkillsState(layout.baseDir);
4394
+ const fmt = args.output ?? "table";
4395
+ if (!state || Object.keys(state.skills).length === 0) {
4396
+ if (fmt === "json" || fmt === "yaml") {
4397
+ process.stdout.write(formatObject13({ baseDir: layout.baseDir, target: layout.target, all: false, skills: [] }, { format: fmt }) + "\n");
4398
+ process.exit(0);
4399
+ }
4400
+ process.stdout.write(`${path2.join(layout.baseDir, SKILLS_STATE_FILE)} \u4E0D\u5B58\u5728\u6216\u4E3A\u7A7A \u2014\u2014 \u8FD9\u4E2A\u76EE\u5F55\u4E0B\u8FD8\u6CA1\u7528\u672C CLI \u88C5\u8FC7\u6280\u80FD\u3002
4401
+ `);
4402
+ process.stdout.write(" \u88C5\u5168\u90E8\uFF1Ahcm skills install --all\n");
4403
+ process.exit(0);
4404
+ }
4405
+ const rows = [];
4406
+ for (const [id, record] of Object.entries(state.skills).sort(([a], [b]) => a.localeCompare(b))) {
4407
+ const markdown = await readInstalled(layout.baseDir, id);
4408
+ let title = id;
4409
+ if (markdown !== void 0) {
4410
+ const raw = parseSkillFrontmatter(markdown, id).title;
4411
+ if (typeof raw === "string" && raw.trim()) title = raw.trim();
4412
+ }
4413
+ rows.push({
4414
+ id,
4415
+ title,
4416
+ direct: record.direct,
4417
+ installedAt: record.installedAt,
4418
+ // 三种状态互斥:文件没了 / 本地改过 / 和装的时候一致
4419
+ status: markdown === void 0 ? "missing" : sha256(markdown) !== record.sha256 ? "locally-modified" : "installed"
4420
+ });
4421
+ }
4422
+ const shown = keyword ? rows.filter((row) => row.id.includes(keyword) || row.title.includes(keyword)) : rows;
4423
+ if (fmt === "json" || fmt === "yaml") {
4424
+ process.stdout.write(formatObject13({
4425
+ baseDir: layout.baseDir,
4426
+ target: layout.target,
4427
+ endpoint: state.endpoint,
4428
+ all: Boolean(state.all),
4429
+ updatedAt: state.updatedAt,
4430
+ skills: shown
4431
+ }, { format: fmt }) + "\n");
4432
+ process.exit(0);
4433
+ }
4434
+ process.stdout.write(`\u5DF2\u5B89\u88C5\u7684\u777F\u620E\u6280\u80FD \u2014 ${layout.baseDir}\uFF08${layout.target}\uFF09
4435
+ `);
4436
+ process.stdout.write(`\u6765\u6E90 ${state.endpoint ?? "\uFF08\u672A\u8BB0\u5F55\uFF09"}` + (state.all ? " \u8DDF\u968F\u5168\u96C6\uFF1A\u662F\n\n" : "\n\n"));
4437
+ if (shown.length === 0) {
4438
+ process.stdout.write(` \u6CA1\u6709\u5339\u914D\u300C${keyword}\u300D\u7684\u6280\u80FD\uFF08\u5171\u88C5\u4E86 ${rows.length} \u4E2A\uFF09
4439
+ `);
4440
+ process.exit(0);
4441
+ }
4442
+ for (const row of shown) {
4443
+ const mark = row.status === "missing" ? "?" : row.status === "locally-modified" ? "!" : row.direct ? "\u25CF" : "\u25CB";
4444
+ const note = row.status === "missing" ? "\u6587\u4EF6\u4E0D\u89C1\u4E86\uFF08update \u4F1A\u88C5\u56DE\uFF09" : row.status === "locally-modified" ? "\u672C\u5730\u6539\u8FC7" : row.direct ? "" : "\u4F9D\u8D56\u5E26\u5165";
4445
+ process.stdout.write(` ${mark} ${row.id.padEnd(30)} ${row.title.padEnd(24)} ${note}
4446
+ `);
4447
+ }
4448
+ const modified = shown.filter((row) => row.status === "locally-modified").length;
4449
+ const missing = shown.filter((row) => row.status === "missing").length;
4450
+ const indirect = shown.filter((row) => row.direct === false).length;
4451
+ process.stdout.write("\n");
4452
+ process.stdout.write(` \u25CF \u76F4\u63A5\u5B89\u88C5 \u25CB \u4F9D\u8D56\u5E26\u5165 ! \u672C\u5730\u6539\u8FC7 ? \u6587\u4EF6\u7F3A\u5931
4453
+ `);
4454
+ process.stdout.write(` \u5171 ${shown.length} \u4E2A` + [
4455
+ indirect > 0 ? `${indirect} \u4E2A\u662F\u4F9D\u8D56\u5E26\u5165` : "",
4456
+ modified > 0 ? `${modified} \u4E2A\u672C\u5730\u6539\u8FC7` : "",
4457
+ missing > 0 ? `${missing} \u4E2A\u6587\u4EF6\u7F3A\u5931` : ""
4458
+ ].filter(Boolean).map((t) => `\uFF0C${t}`).join("") + "\n");
4459
+ process.stdout.write(` \u5347\u7EA7\uFF1Ahcm skills update${state.all ? "" : "\uFF08\u60F3\u8DDF\u968F\u5168\u96C6\u52A0 --all\uFF09"}
4460
+ `);
4461
+ process.exit(0);
4462
+ }
4338
4463
  async function skillsShowCommand(id, args) {
4339
4464
  try {
4340
- const endpoint = await resolveEndpoint(args);
4341
- const md = await fetchSkillMarkdown(anonHttp(endpoint), id);
4465
+ const { http, base } = await chironClient(args);
4466
+ const md = await fetchSkillMarkdown(http, id, base);
4342
4467
  process.stdout.write(md.endsWith("\n") ? md : md + "\n");
4343
4468
  process.exit(0);
4344
4469
  } catch (e) {
@@ -4347,52 +4472,555 @@ async function skillsShowCommand(id, args) {
4347
4472
  }
4348
4473
  async function skillsInstallCommand(id, args) {
4349
4474
  try {
4350
- if (!/^[a-z0-9][a-z0-9-]{0,63}$/.test(id)) {
4475
+ const all = Boolean(args.all);
4476
+ if (all && id) throw invalid("`--all` \u662F\u88C5\u6574\u4E2A\u6280\u80FD\u5E93\uFF0C\u4E0D\u8981\u518D\u5E26\u6280\u80FD id\uFF1B\u53EA\u88C5\u4E00\u4E2A\u5C31\u53BB\u6389 --all");
4477
+ if (!all && !id) throw invalid("\u8981\u88C5\u54EA\u4E2A\u6280\u80FD\uFF1F\u7ED9\u4E2A id\uFF08`hcm skills list` \u770B\u76EE\u5F55\uFF09\uFF0C\u6216\u7528 `--all` \u88C5\u5168\u90E8");
4478
+ if (id) assertSafeSkillId(id);
4479
+ const layout = await resolveInstallLayout(args);
4480
+ let documents;
4481
+ let requestedIds;
4482
+ let endpoint;
4483
+ let base;
4484
+ let manifest2;
4485
+ if (args.from) {
4486
+ const root = path2.resolve(args.from);
4487
+ requestedIds = all ? await listLocalSkillIds(root) : [id];
4488
+ const seen = /* @__PURE__ */ new Set();
4489
+ documents = [];
4490
+ for (const one of requestedIds) {
4491
+ for (const document of await resolveLocalSkillDocuments(root, one)) {
4492
+ if (seen.has(document.id)) continue;
4493
+ seen.add(document.id);
4494
+ documents.push(document);
4495
+ }
4496
+ }
4497
+ } else {
4498
+ const client3 = await chironClient(args);
4499
+ endpoint = client3.endpoint;
4500
+ base = client3.base;
4501
+ manifest2 = await fetchSkillCatalog(client3.http, base);
4502
+ const order = all ? resolveAllSkillsInstallOrder(manifest2) : resolveSkillInstallOrder(manifest2, id);
4503
+ if (all && order.length === 0) throw invalid(`${endpoint} \u7684\u6280\u80FD\u76EE\u5F55\u662F\u7A7A\u7684\uFF0C\u6CA1\u6709\u53EF\u88C5\u7684\u6280\u80FD`);
4504
+ requestedIds = all ? order.map((skill) => skill.id) : [id];
4505
+ documents = await mapWithConcurrency(
4506
+ order,
4507
+ FETCH_CONCURRENCY,
4508
+ (skill) => fetchSkillDocument(client3.http, skill, endpoint, base)
4509
+ );
4510
+ }
4511
+ const result = await installSkillDocuments(documents, requestedIds, layout.baseDir, Boolean(args.force), {
4512
+ endpoint,
4513
+ base,
4514
+ target: layout.target,
4515
+ all
4516
+ });
4517
+ const agents = layout.agentsFile ? await syncAgentsIndex(layout, manifest2) : void 0;
4518
+ const fmt = args.output ?? "table";
4519
+ if (fmt === "json" || fmt === "yaml") {
4520
+ process.stdout.write(formatObject13({ ...result, all, target_agent: layout.target, agentsFile: layout.agentsFile, agents }, { format: fmt }) + "\n");
4521
+ } else {
4522
+ const headline = all ? `\u2705 \u5168\u90E8 ${requestedIds.length} \u4E2A\u6280\u80FD \u2192 ${result.baseDir}` : `\u2705 ${id} \u2192 ${path2.join(result.baseDir, id, "SKILL.md")}`;
4523
+ process.stdout.write(`${headline}
4524
+ `);
4525
+ if (result.installed.length > 0) {
4526
+ process.stdout.write(all ? ` \u65B0\u5199\u5165 ${result.installed.length} \u4E2A
4527
+ ` : ` \u5DF2\u5B89\u88C5 ${result.installed.join(" \u2192 ")}
4528
+ `);
4529
+ }
4530
+ if (result.unchanged.length > 0) {
4531
+ process.stdout.write(all ? ` \u5DF2\u662F\u8FD9\u4E00\u7248\u3001\u672A\u6539\u52A8 ${result.unchanged.length} \u4E2A
4532
+ ` : ` \u5DF2\u5B58\u5728\u4E14\u7248\u672C\u4E00\u81F4 ${result.unchanged.join(", ")}
4533
+ `);
4534
+ }
4535
+ const referenceCount = documents.reduce((n, d) => n + (d.references?.length ?? 0), 0);
4536
+ if (referenceCount > 0) {
4537
+ process.stdout.write(` \u53C2\u8003\u6587\u4EF6 ${referenceCount} \u4E2A\uFF08references/ \u4E0B\uFF09
4538
+ `);
4539
+ }
4540
+ if (layout.agentsFile) {
4541
+ process.stdout.write(` \u5DF2${agents === "created" ? "\u521B\u5EFA" : "\u66F4\u65B0"} ${layout.agentsFile} \u91CC\u7684\u6280\u80FD\u7D22\u5F15\uFF08Codex \u8BFB\u8FD9\u91CC\uFF09
4542
+ `);
4543
+ }
4544
+ process.stdout.write(` \u6765\u6E90 ${endpoint ?? path2.resolve(args.from)}
4545
+ `);
4546
+ process.stdout.write(all ? " \u5DF2\u8BB0\u4E3A\u300C\u8DDF\u968F\u5168\u96C6\u300D\uFF1A\u4EE5\u540E\u8DD1 hcm skills update\uFF0C\u4EA7\u54C1\u65B0\u589E\u7684\u6280\u80FD\u4F1A\u81EA\u52A8\u8865\u4E0A\n" : " \u4EA7\u54C1\u66F4\u65B0\u540E\u8DD1 hcm skills update \u5347\u7EA7\n");
4547
+ }
4548
+ process.exit(0);
4549
+ } catch (e) {
4550
+ fail3(e, args);
4551
+ }
4552
+ }
4553
+ var FETCH_CONCURRENCY = 6;
4554
+ async function mapWithConcurrency(items, limit, fn) {
4555
+ const results = new Array(items.length);
4556
+ let cursor = 0;
4557
+ const worker = async () => {
4558
+ for (; ; ) {
4559
+ const index = cursor++;
4560
+ if (index >= items.length) return;
4561
+ results[index] = await fn(items[index]);
4562
+ }
4563
+ };
4564
+ await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));
4565
+ return results;
4566
+ }
4567
+ async function listLocalSkillIds(root) {
4568
+ let entries;
4569
+ try {
4570
+ entries = await fsp.readdir(root, { withFileTypes: true });
4571
+ } catch {
4572
+ throw invalid(`\u8BFB\u4E0D\u5230\u672C\u5730\u6280\u80FD\u76EE\u5F55\uFF1A${root}`);
4573
+ }
4574
+ const ids = [];
4575
+ for (const entry of entries) {
4576
+ if (!entry.isDirectory()) continue;
4577
+ if (await exists(path2.join(root, entry.name, "SKILL.md"))) ids.push(entry.name);
4578
+ }
4579
+ if (ids.length === 0) throw invalid(`\u672C\u5730\u76EE\u5F55\u91CC\u6CA1\u6709\u4EFB\u4F55 <id>/SKILL.md\uFF1A${root}`);
4580
+ return ids.sort();
4581
+ }
4582
+ async function fetchSkillDocument(http, skill, endpoint, base) {
4583
+ const relatives = normalizeReferences(skill.references, skill.id);
4584
+ const references = await Promise.all(relatives.map(async (relative2) => ({
4585
+ path: relative2,
4586
+ content: await fetchSkillReference(http, skill.id, relative2, base)
4587
+ })));
4588
+ return {
4589
+ id: skill.id,
4590
+ markdown: await fetchSkillMarkdown(http, skill.id, base),
4591
+ source: `${endpoint}${base}/skills/${skill.id}.md`,
4592
+ references
4593
+ };
4594
+ }
4595
+ async function syncAgentsIndex(layout, manifest2) {
4596
+ if (!layout.agentsFile) return void 0;
4597
+ const state = await readSkillsState(layout.baseDir);
4598
+ if (!state) return void 0;
4599
+ const catalog = /* @__PURE__ */ new Map();
4600
+ for (const category of manifest2?.categories ?? []) {
4601
+ for (const skill of category.skills ?? []) catalog.set(skill.id, skill);
4602
+ }
4603
+ const agentsDir = path2.dirname(layout.agentsFile);
4604
+ const entries = Object.keys(state.skills).sort().map((id) => {
4605
+ const known = catalog.get(id);
4606
+ const absolute = path2.join(layout.baseDir, id, "SKILL.md");
4607
+ let relative2 = path2.relative(agentsDir, absolute);
4608
+ if (!relative2.startsWith(".")) relative2 = `./${relative2}`;
4609
+ return {
4610
+ id,
4611
+ title: known?.title ?? id,
4612
+ description: known?.description ?? "",
4613
+ relativePath: relative2.split(path2.sep).join("/")
4614
+ };
4615
+ });
4616
+ return upsertAgentsBlock(layout.agentsFile, renderAgentsBlock(entries));
4617
+ }
4618
+ async function resolveLocalSkillDocuments(sourceRoot, targetId) {
4619
+ assertSafeSkillId(targetId);
4620
+ const state = /* @__PURE__ */ new Map();
4621
+ const pathStack = [];
4622
+ const order = [];
4623
+ const visit = async (id, requiredBy) => {
4624
+ const current = state.get(id);
4625
+ if (current === "done") return;
4626
+ if (current === "visiting") {
4627
+ const start = pathStack.indexOf(id);
4628
+ throw invalid(`\u6280\u80FD\u4F9D\u8D56\u5B58\u5728\u73AF: ${[...pathStack.slice(Math.max(0, start)), id].join(" -> ")}`);
4629
+ }
4630
+ assertSafeSkillId(id);
4631
+ const local = path2.join(sourceRoot, id, "SKILL.md");
4632
+ let markdown;
4633
+ try {
4634
+ markdown = await fsp.readFile(local, "utf8");
4635
+ } catch (cause) {
4636
+ if (cause?.code === "ENOENT") {
4637
+ 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)}`);
4638
+ }
4639
+ throw cause;
4640
+ }
4641
+ if (!markdown.trim()) throw invalid(`\u6280\u80FD ${id} \u5185\u5BB9\u4E3A\u7A7A`);
4642
+ state.set(id, "visiting");
4643
+ pathStack.push(id);
4644
+ const document = {
4645
+ id,
4646
+ markdown,
4647
+ source: local,
4648
+ references: await readLocalReferences(path2.join(sourceRoot, id))
4649
+ };
4650
+ for (const required of parseSkillRequirements(markdown, id)) {
4651
+ await visit(required, id);
4652
+ }
4653
+ pathStack.pop();
4654
+ state.set(id, "done");
4655
+ order.push(document);
4656
+ };
4657
+ await visit(targetId);
4658
+ return order;
4659
+ }
4660
+ async function readSkillsState(baseDir) {
4661
+ try {
4662
+ const raw = await fsp.readFile(path2.join(baseDir, SKILLS_STATE_FILE), "utf8");
4663
+ const parsed = JSON.parse(raw);
4664
+ if (!parsed || typeof parsed !== "object" || !parsed.skills) return void 0;
4665
+ return parsed;
4666
+ } catch {
4667
+ return void 0;
4668
+ }
4669
+ }
4670
+ async function writeSkillsState(baseDir, state) {
4671
+ await fsp.mkdir(baseDir, { recursive: true });
4672
+ const file = path2.join(baseDir, SKILLS_STATE_FILE);
4673
+ const temp = `${file}.${process.pid}.tmp`;
4674
+ await fsp.writeFile(temp, JSON.stringify(state, null, 2) + "\n", "utf8");
4675
+ await fsp.rename(temp, file);
4676
+ }
4677
+ var AGENTS_BLOCK_BEGIN = "<!-- hcm-skills:begin -->";
4678
+ var AGENTS_BLOCK_END = "<!-- hcm-skills:end -->";
4679
+ function renderAgentsBlock(entries) {
4680
+ const lines = [
4681
+ AGENTS_BLOCK_BEGIN,
4682
+ "## HCMnext \u4EA4\u4ED8\u6280\u80FD\uFF08\u7531 `hcm skills install` \u7EF4\u62A4\uFF0C\u52FF\u624B\u5DE5\u7F16\u8F91\u672C\u5757\uFF09",
4683
+ "",
4684
+ "\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",
4685
+ "\u7167\u7740\u505A\u4E0D\u7528\u7FFB\u6E90\u7801\uFF0C\u4E5F\u4E0D\u7528\u731C API\u3002",
4686
+ ""
4687
+ ];
4688
+ for (const e of entries) {
4689
+ lines.push(`- \`${e.relativePath}\` \u2014 **${e.title}**`);
4690
+ if (e.description) lines.push(` ${e.description}`);
4691
+ }
4692
+ lines.push("", AGENTS_BLOCK_END);
4693
+ return lines.join("\n");
4694
+ }
4695
+ async function upsertAgentsBlock(agentsFile, block) {
4696
+ let existing = "";
4697
+ try {
4698
+ existing = await fsp.readFile(agentsFile, "utf8");
4699
+ } catch (cause) {
4700
+ if (cause?.code !== "ENOENT") throw cause;
4701
+ await fsp.mkdir(path2.dirname(agentsFile), { recursive: true });
4702
+ await fsp.writeFile(agentsFile, block + "\n", "utf8");
4703
+ return "created";
4704
+ }
4705
+ const begin = existing.indexOf(AGENTS_BLOCK_BEGIN);
4706
+ const end = existing.indexOf(AGENTS_BLOCK_END);
4707
+ if (begin >= 0 && end > begin) {
4708
+ const next = existing.slice(0, begin) + block + existing.slice(end + AGENTS_BLOCK_END.length);
4709
+ await fsp.writeFile(agentsFile, next, "utf8");
4710
+ return "replaced";
4711
+ }
4712
+ const separator = existing.endsWith("\n") ? "\n" : "\n\n";
4713
+ await fsp.writeFile(agentsFile, existing + separator + block + "\n", "utf8");
4714
+ return "appended";
4715
+ }
4716
+ async function installSkillDocuments(documents, requestedIds, baseDir, force, meta2) {
4717
+ if (requestedIds.length === 0) throw invalid("\u6CA1\u6709\u6307\u5B9A\u8981\u88C5\u7684\u6280\u80FD");
4718
+ for (const id of requestedIds) assertSafeSkillId(id);
4719
+ const seen = /* @__PURE__ */ new Set();
4720
+ const candidates = documents.map((document) => {
4721
+ assertSafeSkillId(document.id);
4722
+ if (seen.has(document.id)) throw invalid(`\u5B89\u88C5\u95ED\u5305\u5305\u542B\u91CD\u590D\u6280\u80FD: ${document.id}`);
4723
+ seen.add(document.id);
4724
+ if (!document.markdown.trim()) throw invalid(`\u6280\u80FD ${document.id} \u5185\u5BB9\u4E3A\u7A7A`);
4725
+ return {
4726
+ ...document,
4727
+ target: path2.join(baseDir, document.id, "SKILL.md"),
4728
+ bytes: Buffer.byteLength(document.markdown)
4729
+ };
4730
+ });
4731
+ for (const id of requestedIds) {
4732
+ if (!seen.has(id)) throw invalid(`\u5B89\u88C5\u95ED\u5305\u4E0D\u5305\u542B\u76EE\u6807\u6280\u80FD: ${id}`);
4733
+ }
4734
+ const unchanged = /* @__PURE__ */ new Set();
4735
+ for (const candidate of candidates) {
4736
+ if (force) continue;
4737
+ const same = await sameOnDisk(baseDir, candidate);
4738
+ if (same === void 0) continue;
4739
+ if (same) {
4740
+ unchanged.add(candidate.id);
4741
+ continue;
4742
+ }
4743
+ throw invalid(
4744
+ `${candidate.target} \u5DF2\u5B58\u5728\uFF0C\u4E14\u548C\u76EE\u6807\u73AF\u5883\u8FD9\u4E00\u7248\u4E0D\u4E00\u81F4\u3002\u7528 --force \u8986\u76D6\uFF08\u4F1A\u4E22\u6389\u672C\u5730\u6539\u52A8\uFF09\uFF0C\u6216 --dir <path> \u88C5\u5230\u522B\u5904\uFF1B\u53EA\u60F3\u8DDF\u4E0A\u4EA7\u54C1\u7248\u672C\u7528 hcm skills update`
4745
+ );
4746
+ }
4747
+ const pending = candidates.filter((candidate) => !unchanged.has(candidate.id));
4748
+ await writeSkillDocuments(pending, baseDir);
4749
+ await recordInstalled(baseDir, candidates, {
4750
+ ...meta2,
4751
+ directIds: new Set(requestedIds),
4752
+ keepInstalledAt: unchanged
4753
+ });
4754
+ return {
4755
+ ids: [...requestedIds],
4756
+ baseDir,
4757
+ installed: pending.map((candidate) => candidate.id),
4758
+ unchanged: candidates.filter((candidate) => unchanged.has(candidate.id)).map((candidate) => candidate.id),
4759
+ files: candidates.map((candidate) => ({
4760
+ id: candidate.id,
4761
+ target: candidate.target,
4762
+ source: candidate.source,
4763
+ bytes: candidate.bytes,
4764
+ status: unchanged.has(candidate.id) ? "unchanged" : "installed"
4765
+ }))
4766
+ };
4767
+ }
4768
+ async function sameOnDisk(baseDir, candidate) {
4769
+ const existing = await readInstalled(baseDir, candidate.id);
4770
+ if (existing === void 0) return void 0;
4771
+ if (existing !== candidate.markdown) return false;
4772
+ for (const reference of candidate.references ?? []) {
4773
+ if (await readInstalledReference(baseDir, candidate.id, reference.path) !== reference.content) return false;
4774
+ }
4775
+ return true;
4776
+ }
4777
+ async function readLocalReferences(skillDir) {
4778
+ const root = path2.join(skillDir, "references");
4779
+ const out = [];
4780
+ const walk = async (dir, prefix) => {
4781
+ let items;
4782
+ try {
4783
+ items = await fsp.readdir(dir, { withFileTypes: true });
4784
+ } catch (cause) {
4785
+ if (cause?.code === "ENOENT") return;
4786
+ throw cause;
4787
+ }
4788
+ for (const item of items.sort((a, b) => a.name.localeCompare(b.name))) {
4789
+ const relative2 = prefix ? `${prefix}/${item.name}` : item.name;
4790
+ if (item.isDirectory()) {
4791
+ await walk(path2.join(dir, item.name), relative2);
4792
+ continue;
4793
+ }
4794
+ if (!item.isFile()) continue;
4795
+ assertSafeReferencePath(relative2);
4796
+ out.push({ path: relative2, content: await fsp.readFile(path2.join(dir, item.name), "utf8") });
4797
+ }
4798
+ };
4799
+ await walk(root, "");
4800
+ return out;
4801
+ }
4802
+ async function writeSkillDocuments(documents, baseDir) {
4803
+ const staged = [];
4804
+ try {
4805
+ for (const document of documents) {
4806
+ const target = path2.join(baseDir, document.id, "SKILL.md");
4807
+ await fsp.mkdir(path2.dirname(target), { recursive: true });
4808
+ const temp = path2.join(path2.dirname(target), `.SKILL.md.${process.pid}.${Date.now()}.tmp`);
4809
+ await fsp.writeFile(temp, document.markdown, "utf8");
4810
+ staged.push({ temp, target });
4811
+ for (const reference of document.references ?? []) {
4812
+ assertSafeReferencePath(reference.path);
4813
+ const referenceTarget = path2.join(baseDir, document.id, "references", reference.path);
4814
+ await fsp.mkdir(path2.dirname(referenceTarget), { recursive: true });
4815
+ const referenceTemp = `${referenceTarget}.${process.pid}.${Date.now()}.tmp`;
4816
+ await fsp.writeFile(referenceTemp, reference.content, "utf8");
4817
+ staged.push({ temp: referenceTemp, target: referenceTarget });
4818
+ }
4819
+ }
4820
+ for (const file of staged) await fsp.rename(file.temp, file.target);
4821
+ } catch (cause) {
4822
+ await Promise.all(staged.map((file) => fsp.unlink(file.temp).catch(() => void 0)));
4823
+ throw cause;
4824
+ }
4825
+ }
4826
+ async function recordInstalled(baseDir, documents, meta2) {
4827
+ const state = await readSkillsState(baseDir) ?? {
4828
+ version: 1,
4829
+ target: meta2.target ?? "claude",
4830
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
4831
+ skills: {}
4832
+ };
4833
+ state.version = 1;
4834
+ if (meta2.target) state.target = meta2.target;
4835
+ if (meta2.endpoint) state.endpoint = meta2.endpoint;
4836
+ if (meta2.base !== void 0) state.base = meta2.base;
4837
+ if (meta2.all) state.all = true;
4838
+ state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
4839
+ for (const document of documents) {
4840
+ const previous = state.skills[document.id];
4841
+ state.skills[document.id] = {
4842
+ source: document.source,
4843
+ sha256: sha256(document.markdown),
4844
+ installedAt: meta2.keepInstalledAt?.has(document.id) && previous ? previous.installedAt : state.updatedAt,
4845
+ // 已经是直接安装的,不因为这次作为依赖被带进来就降级
4846
+ direct: meta2.directIds.has(document.id) || Boolean(previous?.direct),
4847
+ references: Object.fromEntries(
4848
+ (document.references ?? []).map((reference) => [reference.path, sha256(reference.content)])
4849
+ )
4850
+ };
4851
+ }
4852
+ await writeSkillsState(baseDir, state);
4853
+ return state;
4854
+ }
4855
+ function invalid(message) {
4856
+ return new CliError14({ code: CliErrorCode13.INVALID_ARGUMENT, message });
4857
+ }
4858
+ async function readInstalled(baseDir, id) {
4859
+ try {
4860
+ return await fsp.readFile(path2.join(baseDir, id, "SKILL.md"), "utf8");
4861
+ } catch (cause) {
4862
+ if (cause?.code === "ENOENT") return void 0;
4863
+ throw cause;
4864
+ }
4865
+ }
4866
+ async function readInstalledReference(baseDir, id, relative2) {
4867
+ try {
4868
+ return await fsp.readFile(path2.join(baseDir, id, "references", relative2), "utf8");
4869
+ } catch (cause) {
4870
+ if (cause?.code === "ENOENT") return void 0;
4871
+ throw cause;
4872
+ }
4873
+ }
4874
+ async function planSkillUpdate(options) {
4875
+ const { state, manifest: manifest2, baseDir, force, fetchDocument } = options;
4876
+ const all = options.all ?? Boolean(state.all);
4877
+ const recorded = Object.entries(state.skills);
4878
+ const directIds = recorded.some(([, r]) => r.direct) ? recorded.filter(([, r]) => r.direct).map(([id]) => id) : recorded.map(([id]) => id);
4879
+ const wanted = all ? [.../* @__PURE__ */ new Set([...directIds, ...flattenSkills(manifest2).map((skill) => skill.id)])] : directIds;
4880
+ const entries = [];
4881
+ const closure = /* @__PURE__ */ new Map();
4882
+ for (const id of wanted.sort()) {
4883
+ try {
4884
+ for (const skill of resolveSkillInstallOrder(manifest2, id)) {
4885
+ if (!closure.has(skill.id)) closure.set(skill.id, skill);
4886
+ }
4887
+ } catch {
4888
+ entries.push({
4889
+ id,
4890
+ status: "removed-upstream",
4891
+ 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"
4892
+ });
4893
+ }
4894
+ }
4895
+ const documents = [];
4896
+ for (const skill of closure.values()) {
4897
+ const record = state.skills[skill.id];
4898
+ const onDisk = await readInstalled(baseDir, skill.id);
4899
+ if (onDisk === void 0) {
4900
+ documents.push(await fetchDocument(skill));
4901
+ entries.push({
4902
+ id: skill.id,
4903
+ status: "added",
4904
+ note: record ? "\u672C\u5730\u6587\u4EF6\u7F3A\u5931\uFF0C\u91CD\u65B0\u88C5\u56DE" : all ? "\u4EA7\u54C1\u8FD9\u4E00\u7248\u65B0\u589E\u7684\u6280\u80FD" : "\u4EA7\u54C1\u65B0\u589E\u7684\u524D\u7F6E\u6280\u80FD"
4905
+ });
4906
+ continue;
4907
+ }
4908
+ const remote = await fetchDocument(skill);
4909
+ const remoteReferences = remote.references ?? [];
4910
+ let differsFromRemote = remote.markdown !== onDisk;
4911
+ let editedLocally = record !== void 0 && sha256(onDisk) !== record.sha256;
4912
+ for (const reference of remoteReferences) {
4913
+ const installed = await readInstalledReference(baseDir, skill.id, reference.path);
4914
+ if (installed !== reference.content) differsFromRemote = true;
4915
+ const recordedSha = record?.references?.[reference.path];
4916
+ if (installed !== void 0 && recordedSha && sha256(installed) !== recordedSha) editedLocally = true;
4917
+ }
4918
+ if (!differsFromRemote) {
4919
+ entries.push({ id: skill.id, status: "unchanged" });
4920
+ continue;
4921
+ }
4922
+ if (editedLocally && !force) {
4923
+ entries.push({
4924
+ id: skill.id,
4925
+ status: "locally-modified",
4926
+ note: "\u672C\u5730\u6539\u8FC7\uFF0C\u6CA1\u6709\u8986\u76D6\uFF1B\u786E\u5B9A\u8981\u7528\u4EA7\u54C1\u8FD9\u4E00\u7248\u5C31\u52A0 --force"
4927
+ });
4928
+ continue;
4929
+ }
4930
+ documents.push(remote);
4931
+ entries.push({
4932
+ id: skill.id,
4933
+ status: "updated",
4934
+ note: editedLocally ? "\u672C\u5730\u6539\u8FC7\uFF0C--force \u5DF2\u8986\u76D6" : void 0
4935
+ });
4936
+ }
4937
+ entries.sort((a, b) => a.id.localeCompare(b.id));
4938
+ return { entries, documents };
4939
+ }
4940
+ var UPDATE_STATUS_LABEL = {
4941
+ updated: "\u5DF2\u66F4\u65B0",
4942
+ added: "\u5DF2\u8865\u88C5",
4943
+ unchanged: "\u5DF2\u662F\u6700\u65B0",
4944
+ "locally-modified": "\u672C\u5730\u6539\u8FC7\xB7\u8DF3\u8FC7",
4945
+ "removed-upstream": "\u4EA7\u54C1\u5DF2\u79FB\u9664"
4946
+ };
4947
+ async function skillsUpdateCommand(args) {
4948
+ try {
4949
+ const layout = await resolveInstallLayout(args);
4950
+ const state = await readSkillsState(layout.baseDir);
4951
+ if (!state || Object.keys(state.skills).length === 0) {
4351
4952
  throw new CliError14({
4352
4953
  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}"`
4954
+ 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
4955
  });
4355
4956
  }
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);
4957
+ const endpoint = args.endpoint ? args.endpoint.replace(/\/+$/, "") : await resolveEndpoint(args).catch((e) => {
4958
+ if (state.endpoint) return state.endpoint;
4959
+ throw e;
4960
+ });
4961
+ const { http, base } = await chironClient({ ...args, endpoint });
4962
+ const manifest2 = await fetchSkillCatalog(http, base);
4963
+ const all = Boolean(args.all) || Boolean(state.all);
4964
+ const plan = await planSkillUpdate({
4965
+ state,
4966
+ manifest: manifest2,
4967
+ baseDir: layout.baseDir,
4968
+ force: Boolean(args.force),
4969
+ all,
4970
+ fetchDocument: (skill) => fetchSkillDocument(http, skill, endpoint, base)
4971
+ });
4972
+ const subscriptionChanged = all && !state.all;
4973
+ if (!args.check && (plan.documents.length > 0 || subscriptionChanged)) {
4974
+ await writeSkillDocuments(plan.documents, layout.baseDir);
4975
+ await recordInstalled(layout.baseDir, plan.documents, {
4976
+ endpoint,
4977
+ base,
4978
+ target: layout.target,
4979
+ all,
4980
+ directIds: all ? new Set(plan.documents.map((document) => document.id)) : /* @__PURE__ */ new Set()
4981
+ });
4982
+ if (layout.agentsFile) await syncAgentsIndex(layout, manifest2);
4378
4983
  }
4379
- await fsp.mkdir(path2.dirname(target), { recursive: true });
4380
- await fsp.writeFile(target, md, "utf8");
4984
+ const changed = plan.entries.filter((e) => e.status === "updated" || e.status === "added");
4381
4985
  const fmt = args.output ?? "table";
4382
4986
  if (fmt === "json" || fmt === "yaml") {
4383
- process.stdout.write(
4384
- formatObject13({ id, target, source, bytes: Buffer.byteLength(md) }, { format: fmt }) + "\n"
4385
- );
4987
+ process.stdout.write(formatObject13({
4988
+ endpoint,
4989
+ baseDir: layout.baseDir,
4990
+ target: layout.target,
4991
+ dryRun: Boolean(args.check),
4992
+ all,
4993
+ changed: changed.length,
4994
+ entries: plan.entries
4995
+ }, { format: fmt }) + "\n");
4996
+ process.exit(0);
4997
+ }
4998
+ process.stdout.write(`\u777F\u620E\u6280\u80FD\u5347\u7EA7 \u2014 ${endpoint}
4999
+ `);
5000
+ process.stdout.write(`\u843D\u70B9 ${layout.baseDir}\uFF08${layout.target}\uFF09` + (all ? " \u8DDF\u968F\u5168\u96C6\uFF1A\u4EA7\u54C1\u65B0\u589E\u7684\u6280\u80FD\u4F1A\u81EA\u52A8\u8865\u4E0A\n\n" : "\n\n"));
5001
+ for (const entry of plan.entries) {
5002
+ const mark = entry.status === "unchanged" ? " " : entry.status === "locally-modified" ? "!" : "\xB7";
5003
+ process.stdout.write(` ${mark} ${entry.id.padEnd(30)} ${UPDATE_STATUS_LABEL[entry.status]}
5004
+ `);
5005
+ if (entry.note) process.stdout.write(` ${entry.note}
5006
+ `);
5007
+ }
5008
+ process.stdout.write("\n");
5009
+ const skipped = plan.entries.filter((e) => e.status === "locally-modified").length;
5010
+ const removed = plan.entries.filter((e) => e.status === "removed-upstream").length;
5011
+ const tail = [
5012
+ skipped > 0 ? `${skipped} \u4E2A\u672C\u5730\u6539\u8FC7\u88AB\u8DF3\u8FC7\uFF08--force \u8986\u76D6\uFF09` : "",
5013
+ removed > 0 ? `${removed} \u4E2A\u4EA7\u54C1\u5DF2\u79FB\u9664\uFF08\u672C\u5730\u6587\u4EF6\u4FDD\u7559\uFF09` : ""
5014
+ ].filter(Boolean).join("\uFF0C");
5015
+ if (changed.length === 0 && skipped === 0 && removed === 0) {
5016
+ 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
5017
  } else {
4387
- process.stdout.write(`\u2705 ${id} \u2192 ${target}
4388
- \u6765\u6E90 ${source}
5018
+ 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";
5019
+ process.stdout.write(` ${[head, tail].filter(Boolean).join("\uFF1B")}
4389
5020
  `);
4390
5021
  }
4391
5022
  process.exit(0);
4392
5023
  } 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
5024
  fail3(e, args);
4397
5025
  }
4398
5026
  }
@@ -5289,7 +5917,7 @@ async function walkWorkspaceRawFiles(rootDir, relativeDir, files) {
5289
5917
  localPath,
5290
5918
  absolutePath,
5291
5919
  content,
5292
- sha256: sha256(content),
5920
+ sha256: sha2562(content),
5293
5921
  size: Buffer.byteLength(content, "utf-8")
5294
5922
  });
5295
5923
  }
@@ -5356,7 +5984,7 @@ function buildWorkspaceRawPushPlan(manifest2, localFiles, remoteFiles) {
5356
5984
  for (const entry of status) {
5357
5985
  const remote = remoteByLocal.get(entry.localPath);
5358
5986
  const base = baseByLocal.get(entry.localPath);
5359
- const remoteSha = remote ? sha256(remote.content) : void 0;
5987
+ const remoteSha = remote ? sha2562(remote.content) : void 0;
5360
5988
  if (entry.status === "added") {
5361
5989
  if (remote) {
5362
5990
  conflicts.push(workspaceRawConflict(entry, "remote file already exists but was not in local snapshot"));
@@ -5621,7 +6249,7 @@ function normalizeRelativePath(value) {
5621
6249
  function toPosix(value) {
5622
6250
  return value.split(path3.sep).join("/");
5623
6251
  }
5624
- function sha256(content) {
6252
+ function sha2562(content) {
5625
6253
  return crypto.createHash("sha256").update(content, "utf-8").digest("hex");
5626
6254
  }
5627
6255
  function stringRequired(value, field) {
@@ -6059,7 +6687,11 @@ var cache = program.command("cache").description("\u6A21\u578B\u7F13\u5B58\u8FD0
6059
6687
  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
6688
  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
6689
  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));
6690
+ 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(
6691
+ "--category <name>",
6692
+ "\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",
6693
+ "attachment"
6694
+ ).action((file, opts) => uploadCommand(file, opts));
6063
6695
  var tenant = program.command("tenant").description("\u79DF\u6237\u5F00\u901A\u4E0E\u751F\u547D\u5468\u671F");
6064
6696
  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
6697
  var meta = program.command("meta").description("\u79DF\u6237\u5143\u6570\u636E\u8BFB\u5199\uFF08\u9875\u9762/\u5B57\u6BB5/\u5217\u8868\u914D\u7F6E\uFF09");
@@ -6068,9 +6700,10 @@ meta.command("get <path>").description("\u6253\u5370 meta \u539F\u6587\uFF08\u59
6068
6700
  meta.command("set <path>").description("\u5199\u5165 meta \u539F\u6587\uFF1B\u5199\u5B8C\u987B hcm cache clear-meta <Model> \u624D\u751F\u6548").requiredOption("--file <file>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6\u539F\u6587\uFF08- \u8868\u793A stdin\uFF09").option("--dry-run", "\u53EA\u663E\u793A\u5C06\u5199\u5165\u7684\u5185\u5BB9\uFF0C\u4E0D\u5B9E\u9645\u5199\u5165").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((p, opts) => metaSetCommand(p, opts));
6069
6701
  meta.command("delete <path>").description("\u5220\u9664 meta\uFF08\u4E0D\u53EF\u9006\uFF0C\u9ED8\u8BA4\u8FC7\u786E\u8BA4\u95F8\uFF09").option("-y, --yes", "\u8DF3\u8FC7\u786E\u8BA4").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((p, opts) => metaDeleteCommand(p, opts));
6070
6702
  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
- 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));
6703
+ skills.command("list [keyword]").description("\u5217\u51FA\u76EE\u6807\u73AF\u5883\u8FD9\u4E00\u7248\u7684\u4EA4\u4ED8\u6280\u80FD\uFF1B--installed \u6539\u770B\u672C\u5730\u88C5\u4E86\u54EA\u4E9B\uFF08\u4E0D\u8FDE\u7F51\uFF09").option("--installed", "\u53EA\u770B\u672C\u5730\u5DF2\u88C5\u7684\u6280\u80FD\uFF08\u8BFB .hcm-skills.json\uFF0C\u4E0D\u8FDE\u7F51\uFF09").option("--target <agent>", "\u914D\u5408 --installed\uFF1Aclaude | codex | auto", "auto").option("--global", "\u914D\u5408 --installed\uFF1A\u770B\u7528\u6237\u7EA7\u76EE\u5F55").option("--dir <path>", "\u914D\u5408 --installed\uFF1A\u770B\u6307\u5B9A\u76EE\u5F55").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
6704
  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));
6705
+ skills.command("install [id]").description("\u8FDE\u540C requires \u524D\u7F6E\u6280\u80FD\u4E0E\u53C2\u8003\u6587\u4EF6\u88C5\u5230 agent \u6280\u80FD\u76EE\u5F55\uFF1B--all \u88C5\u6574\u4E2A\u6280\u80FD\u5E93").option("--all", "\u88C5\u6574\u4E2A\u6280\u80FD\u5E93\uFF0C\u5E76\u8BB0\u4E3A\u300C\u8DDF\u968F\u5168\u96C6\u300D\uFF08\u5F80\u540E update \u4F1A\u81EA\u52A8\u8865\u4E0A\u4EA7\u54C1\u65B0\u589E\u7684\u6280\u80FD\uFF09").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));
6706
+ 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("--all", "\u8FDE\u4EA7\u54C1\u65B0\u589E\u7684\u6280\u80FD\u4E00\u8D77\u88C5\u4E0A\uFF0C\u5E76\u8BB0\u4E3A\u300C\u8DDF\u968F\u5168\u96C6\u300D").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
6707
  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
6708
  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
6709
  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");