@hcmai/cli 0.3.3 → 0.3.5

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
@@ -523,8 +523,8 @@ var init_TerminalRenderer = __esm({
523
523
  }
524
524
  }
525
525
  /** 来源行(仅子代理触发,agentPath ≥2 段时显示 `↑ 来自 a › b`,对齐 Web)。 */
526
- originLine(path7) {
527
- const segs = path7.split(".").filter(Boolean);
526
+ originLine(path9) {
527
+ const segs = path9.split(".").filter(Boolean);
528
528
  if (segs.length < 2) return "";
529
529
  const names = segs.map((k) => agentDisplayName(k));
530
530
  return chalk.gray(` \u2191 \u6765\u81EA ${names.join(" \u203A ")}`) + "\n";
@@ -1706,8 +1706,8 @@ function agentLabel(agentId) {
1706
1706
  if (/^[0-9a-f]{8}-[0-9a-f-]{27}$/i.test(agentId)) return `agent \u2026${agentId.slice(-4)}`;
1707
1707
  return agentDisplayName(agentId);
1708
1708
  }
1709
- function originLine(path7) {
1710
- const segs = (path7 ?? "").split(".").filter(Boolean);
1709
+ function originLine(path9) {
1710
+ const segs = (path9 ?? "").split(".").filter(Boolean);
1711
1711
  if (segs.length < 2) return null;
1712
1712
  return `\u6765\u81EA ${segs.map((k) => agentDisplayName(k)).join(" \u203A ")}`;
1713
1713
  }
@@ -2286,9 +2286,9 @@ async function loginCommand(args) {
2286
2286
  } catch (e) {
2287
2287
  const err = e;
2288
2288
  if (err.isAxiosError) {
2289
- const { fromAxiosError: fromAxiosError18 } = await import("@hcmai/sdk");
2289
+ const { fromAxiosError: fromAxiosError19 } = await import("@hcmai/sdk");
2290
2290
  exitWithError(
2291
- fromAxiosError18(
2291
+ fromAxiosError19(
2292
2292
  e,
2293
2293
  envName
2294
2294
  )
@@ -2503,13 +2503,13 @@ async function envRemove(name, args) {
2503
2503
  }
2504
2504
  }
2505
2505
  const ids = await listIdentities(name);
2506
- const failed = [];
2506
+ const failed2 = [];
2507
2507
  for (const id of ids) {
2508
2508
  try {
2509
2509
  await TokenStore2.forIdentity(id).clear();
2510
2510
  await deleteIdentity(id);
2511
2511
  } catch (err) {
2512
- failed.push(id);
2512
+ failed2.push(id);
2513
2513
  process.stderr.write(
2514
2514
  `[hcm] event=identity_cleanup_failed identity=${id} reason=${JSON.stringify(String(err.message))}
2515
2515
  `
@@ -2522,9 +2522,9 @@ async function envRemove(name, args) {
2522
2522
  g.activeEnv = "default";
2523
2523
  await saveGlobalConfig2(g);
2524
2524
  }
2525
- const removedCount = ids.length - failed.length;
2525
+ const removedCount = ids.length - failed2.length;
2526
2526
  const noun = (n) => n === 1 ? "identity" : "identities";
2527
- const failPart = failed.length > 0 ? `, ${failed.length} ${noun(failed.length)} failed: ${failed.join(", ")}` : "";
2527
+ const failPart = failed2.length > 0 ? `, ${failed2.length} ${noun(failed2.length)} failed: ${failed2.join(", ")}` : "";
2528
2528
  exitOk(`\u2705 env '${name}' removed (${removedCount} ${noun(removedCount)} removed${failPart})`);
2529
2529
  } catch (e) {
2530
2530
  exitWithError(e);
@@ -3059,8 +3059,8 @@ import {
3059
3059
  formatObject as formatObject7,
3060
3060
  fromAxiosError as fromAxiosError8
3061
3061
  } from "@hcmai/sdk";
3062
- function collectYmlFiles(path7) {
3063
- if (statSync(path7).isFile()) return [path7];
3062
+ function collectYmlFiles(path9) {
3063
+ if (statSync(path9).isFile()) return [path9];
3064
3064
  const out = [];
3065
3065
  const walk = (dir) => {
3066
3066
  for (const name of readdirSync(dir).sort()) {
@@ -3069,7 +3069,7 @@ function collectYmlFiles(path7) {
3069
3069
  else if (full.endsWith(".yml") || full.endsWith(".yaml")) out.push(full);
3070
3070
  }
3071
3071
  };
3072
- walk(path7);
3072
+ walk(path9);
3073
3073
  return out.sort();
3074
3074
  }
3075
3075
  var DRY_RUN_CLIENT = {
@@ -3077,9 +3077,9 @@ var DRY_RUN_CLIENT = {
3077
3077
  create: async () => ({ id: "" }),
3078
3078
  update: async () => ({})
3079
3079
  };
3080
- async function importCommand(path7, args) {
3080
+ async function importCommand(path9, args) {
3081
3081
  try {
3082
- const files = collectYmlFiles(path7);
3082
+ const files = collectYmlFiles(path9);
3083
3083
  const fixtures = files.map(
3084
3084
  (f) => parseFixture(readFileSync2(f, "utf8"), relative(process.cwd(), f))
3085
3085
  );
@@ -4278,10 +4278,10 @@ async function uploadCommand(filePath, args) {
4278
4278
 
4279
4279
  // src/commands/skills.ts
4280
4280
  init_exit();
4281
- import { promises as fsp } from "fs";
4281
+ import { promises as fsp2 } from "fs";
4282
4282
  import os2 from "os";
4283
- import path4 from "path";
4284
- import { createHash as createHash3 } from "crypto";
4283
+ import path6 from "path";
4284
+ import { createHash as createHash4 } from "crypto";
4285
4285
  import {
4286
4286
  createHttpClient as createHttpClient2,
4287
4287
  fetchSkillCatalog,
@@ -4290,31 +4290,316 @@ import {
4290
4290
  fetchSkillReference,
4291
4291
  resolveChironBase,
4292
4292
  assertSafeSkillId as assertSafeSkillId2,
4293
- assertSafeReferencePath,
4293
+ assertSafeReferencePath as assertSafeReferencePath2,
4294
4294
  normalizeReferences as normalizeReferences2,
4295
- parseSkillRequirements,
4296
- parseSkillFrontmatter,
4295
+ parseSkillRequirements as parseSkillRequirements2,
4296
+ parseSkillFrontmatter as parseSkillFrontmatter2,
4297
4297
  resolveSkillInstallOrder as resolveSkillInstallOrder2,
4298
4298
  resolveAllSkillsInstallOrder,
4299
- flattenSkills,
4300
4299
  matchSkills,
4301
4300
  filterByStage,
4302
- formatObject as formatObject13,
4301
+ formatObject as formatObject14,
4303
4302
  fromAxiosError as fromAxiosError13,
4304
4303
  loadEnv as loadEnv5,
4305
4304
  loadGlobalConfig as loadGlobalConfig6,
4306
4305
  resolveActiveEnv as resolveActiveEnv3,
4307
- CliError as CliError16,
4308
- CliErrorCode as CliErrorCode15
4306
+ CliError as CliError18,
4307
+ CliErrorCode as CliErrorCode17
4309
4308
  } from "@hcmai/sdk";
4310
4309
 
4311
- // src/commands/skills-sync.ts
4310
+ // src/commands/skills-catalog.ts
4311
+ import { flattenSkills, CliError as CliError14, CliErrorCode as CliErrorCode13 } from "@hcmai/sdk";
4312
+ var CLI_CATEGORY_KEY = "cli-operations";
4313
+ var CLI_CATEGORY_NAME = "CLI \u64CD\u4F5C";
4314
+ function chironEntry(skill) {
4315
+ return {
4316
+ meta: {
4317
+ id: skill.id,
4318
+ title: skill.title,
4319
+ description: skill.description,
4320
+ category: skill.category,
4321
+ stages: skill.stages ?? [],
4322
+ actionSurface: skill.actionSurface,
4323
+ requires: skill.requires,
4324
+ bytes: skill.bytes,
4325
+ files: skill.files
4326
+ },
4327
+ locator: { kind: "chiron", markdownUrl: skill.markdownUrl }
4328
+ };
4329
+ }
4330
+ function bundledEntry(entry, cliVersion) {
4331
+ return {
4332
+ meta: {
4333
+ id: entry.id,
4334
+ title: entry.title ?? entry.id,
4335
+ description: entry.description ?? "",
4336
+ category: entry.category ?? CLI_CATEGORY_KEY,
4337
+ stages: entry.stages ?? [],
4338
+ // 自带技能讲的就是本 CLI 的命令,恒为 cli。
4339
+ actionSurface: "cli",
4340
+ requires: entry.requires,
4341
+ bytes: entry.bytes,
4342
+ files: entry.files
4343
+ },
4344
+ locator: { kind: "cli", packagePath: `skills/${entry.id}`, cliVersion }
4345
+ };
4346
+ }
4347
+ function cliLocatorString(id, cliVersion) {
4348
+ return `@hcmai/cli@${cliVersion}:skills/${id}`;
4349
+ }
4350
+ var SOURCE_FILTERS = ["cli", "chiron", "all"];
4351
+ function parseSourceFilter(raw) {
4352
+ if (raw === void 0) return "all";
4353
+ if (SOURCE_FILTERS.includes(raw)) return raw;
4354
+ throw new CliError14({
4355
+ code: CliErrorCode13.INVALID_ARGUMENT,
4356
+ message: `--source \u53EA\u8BA4 ${SOURCE_FILTERS.join(" / ")}\uFF0C\u6536\u5230 "${raw}"\u3002\uFF08\`local\` \u4E0D\u662F\u53D6\u503C\uFF1A\u6CA1\u6709\u54EA\u4E00\u8D9F\u4F1A\u53BB\u300C\u626B local \u6765\u6E90\u300D\uFF0Cinstall --from \u88C5\u7684\u90A3\u4E9B\u5728\u4EFB\u4F55 --source \u4E0B\u90FD\u5355\u5217\u3001\u90FD\u4E0D\u53C2\u4E0E\u5347\u7EA7\u3002\uFF09`
4357
+ });
4358
+ }
4359
+ function emptyHalf() {
4360
+ return { status: "skipped", entries: /* @__PURE__ */ new Map() };
4361
+ }
4362
+ function buildUnifiedCatalog(input) {
4363
+ const chiron = emptyHalf();
4364
+ const cli = emptyHalf();
4365
+ if (input.source !== "cli" && input.chironManifest) {
4366
+ chiron.status = "fetched";
4367
+ for (const skill of flattenSkills(input.chironManifest)) chiron.entries.set(skill.id, chironEntry(skill));
4368
+ }
4369
+ if (input.source !== "chiron" && input.bundled) {
4370
+ cli.status = "fetched";
4371
+ for (const entry of input.bundled) cli.entries.set(entry.id, bundledEntry(entry, input.cliVersion));
4372
+ }
4373
+ return { chiron, cli };
4374
+ }
4375
+ function detectIdConflicts(catalog) {
4376
+ if (catalog.chiron.status !== "fetched" || catalog.cli.status !== "fetched") {
4377
+ return { checked: false, ids: [] };
4378
+ }
4379
+ const ids = [...catalog.cli.entries.keys()].filter((id) => catalog.chiron.entries.has(id)).sort();
4380
+ return { checked: true, ids };
4381
+ }
4382
+ function conflictMessage(ids, endpoint) {
4383
+ return `\u6280\u80FD id \`${ids.join("`\u3001`")}\` \u5728 CLI \u81EA\u5E26\u4E0E ${endpoint} \u7684\u777F\u620E\u76EE\u5F55\u91CC\u540C\u65F6\u5B58\u5728\u3002
4384
+ \u4E24\u8FB9\u5404\u81EA\u4E3B\u5F20\u7684\u4E1C\u897F\u4E0D\u540C\uFF0C\u53D6\u4EFB\u4F55\u4E00\u4EFD\u90FD\u4F1A\u8BA9\u53E6\u4E00\u4EFD\u7684\u8BFB\u8005\u62FF\u5230\u9519\u7684\u5408\u540C\u3002
4385
+ \u51FA\u8DEF\u53EA\u6709\u4E24\u6761\uFF1A\u2460 \u5347\u7EA7 CLI\uFF08\u4EA7\u54C1\u628A\u5B83\u6536\u7F16\u4E86\uFF0C\u65B0\u7248 CLI \u4F1A\u64A4\u6389\u81EA\u5E26\u7684\u90A3\u4EFD\uFF09\uFF1B
4386
+ \u2461 \u8FD9\u662F\u4E00\u6B21\u5F52\u5C5E\u672A\u5B9A\uFF0C\u628A id \u4E0E\u4E24\u5904\u51FA\u5904\u62A5\u7ED9\u4EA7\u54C1\u4FA7\u88C1\u51B3\u3002`;
4387
+ }
4388
+ function unconfirmedConflictNote(source) {
4389
+ return `\u672C\u8D9F\u53EA\u770B\u4E86${source === "cli" ? "CLI \u81EA\u5E26" : "\u777F\u620E"}\u6765\u6E90\uFF0C\u672A\u505A\u8DE8\u6765\u6E90\u51B2\u7A81\u68C0\u67E5`;
4390
+ }
4391
+ function classifyInstalledSource(id, record, catalog) {
4392
+ const kind = record.sourceKind ?? "chiron";
4393
+ if (kind === "local") return "local";
4394
+ const half = kind === "cli" ? catalog.cli : catalog.chiron;
4395
+ if (half.status !== "fetched") return "not-checked";
4396
+ if (half.entries.has(id)) return "present";
4397
+ return kind === "cli" ? "removed-in-cli" : "removed-upstream";
4398
+ }
4399
+ var SOURCE_STATUS_NOTE = {
4400
+ "removed-upstream": "\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",
4401
+ "removed-in-cli": "\u8FD9\u4E00\u7248 CLI \u4E0D\u518D\u81EA\u5E26\u5B83\uFF08\u591A\u534A\u662F\u88AB\u4EA7\u54C1\u6536\u7F16\u4E86\uFF0C\u8DD1 hcm skills list \u770B\u770B\uFF09",
4402
+ "not-checked": "\u672C\u8F6E\u6CA1\u8FDE\u7F51\u6838\u5BF9\u5B83\u7684\u6765\u6E90\uFF08--source cli\uFF09\uFF0C\u5B83\u662F\u4E0D\u662F\u8FD8\u5728\u4EA7\u54C1\u76EE\u5F55\u91CC\u8FD9\u4E00\u8D9F\u4E0D\u77E5\u9053",
4403
+ local: "\u672C\u5730\u6765\u6E90\uFF08install --from \u88C5\u7684\uFF09\uFF0Cupdate \u4E0D\u7BA1\u5B83\uFF1B\u8981\u66F4\u65B0\u5C31\u518D install --from \u4E00\u6B21"
4404
+ };
4405
+ function checkCrossSourceRequires(catalog) {
4406
+ if (catalog.chiron.status !== "fetched" || catalog.cli.status !== "fetched") return [];
4407
+ const out = [];
4408
+ for (const [id, entry] of catalog.chiron.entries) {
4409
+ for (const need of entry.meta.requires ?? []) {
4410
+ if (catalog.chiron.entries.has(need)) continue;
4411
+ if (catalog.cli.entries.has(need)) {
4412
+ out.push({
4413
+ from: id,
4414
+ to: need,
4415
+ reason: "\u777F\u620E\u6280\u80FD\u4E0D\u5F97\u4F9D\u8D56 CLI \u81EA\u5E26\u6280\u80FD\uFF1A\u4EA7\u54C1\u77E5\u8BC6\u7684\u53EF\u8BFB\u6027\u4E0D\u80FD\u53D6\u51B3\u4E8E\u987E\u95EE\u88C5\u4E86\u54EA\u7248 CLI"
4416
+ });
4417
+ }
4418
+ }
4419
+ }
4420
+ return out;
4421
+ }
4422
+
4423
+ // src/commands/skills-bundled.ts
4424
+ import { promises as fsp } from "fs";
4425
+ import * as path3 from "path";
4426
+ import { CliError as CliError15, CliErrorCode as CliErrorCode14, assertSafeReferencePath, parseSkillRequirements } from "@hcmai/sdk";
4427
+
4428
+ // src/commands/skills-manifest.ts
4429
+ import { readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync3, existsSync } from "fs";
4312
4430
  import { createHash } from "crypto";
4431
+ import * as path2 from "path";
4432
+ import { fileURLToPath } from "url";
4433
+ import { formatObject as formatObject13, parseSkillFrontmatter } from "@hcmai/sdk";
4434
+ function collectCommandSurface(root) {
4435
+ const out = [];
4436
+ const walk = (cmd, prefix) => {
4437
+ for (const sub of cmd.commands) {
4438
+ const segs = [...prefix, sub.name()];
4439
+ const options = sub.options.map((o) => /(--[a-zA-Z0-9][\w-]*)/.exec(o.flags)?.[1] ?? "").filter((s) => s.length > 0);
4440
+ out.push({ path: segs.join(" "), options: [...new Set(options)].sort() });
4441
+ walk(sub, segs);
4442
+ }
4443
+ };
4444
+ walk(root, []);
4445
+ return out.sort((a, b) => a.path.localeCompare(b.path));
4446
+ }
4447
+ function bundledSkillsDir() {
4448
+ const here = path2.dirname(fileURLToPath(import.meta.url));
4449
+ return path2.join(here, "skills");
4450
+ }
4451
+ function sha256(buf) {
4452
+ return createHash("sha256").update(buf).digest("hex");
4453
+ }
4454
+ function listFiles(dir, rel = "") {
4455
+ const out = [];
4456
+ for (const name of readdirSync2(dir)) {
4457
+ const p = path2.join(dir, name);
4458
+ const r = rel ? `${rel}/${name}` : name;
4459
+ if (statSync3(p).isDirectory()) out.push(...listFiles(p, r));
4460
+ else out.push(r);
4461
+ }
4462
+ return out;
4463
+ }
4464
+ function collectBundledSkills(dir = bundledSkillsDir()) {
4465
+ if (!existsSync(dir)) return [];
4466
+ const out = [];
4467
+ for (const id of readdirSync2(dir).sort()) {
4468
+ const skillDir = path2.join(dir, id);
4469
+ if (!statSync3(skillDir).isDirectory()) continue;
4470
+ const files = listFiles(skillDir).sort();
4471
+ if (!files.includes("SKILL.md")) continue;
4472
+ let bytes = 0;
4473
+ const fileRows = files.map((rel) => {
4474
+ const buf = readFileSync3(path2.join(skillDir, rel));
4475
+ bytes += buf.byteLength;
4476
+ return { path: rel, bytes: buf.byteLength, sha256: sha256(buf) };
4477
+ });
4478
+ const body = readFileSync3(path2.join(skillDir, "SKILL.md"), "utf8");
4479
+ const fm = parseSkillFrontmatter(body, id);
4480
+ out.push({
4481
+ id,
4482
+ title: str(fm.title),
4483
+ description: str(fm.description),
4484
+ category: str(fm.category),
4485
+ stages: strArray(fm.stages),
4486
+ actionSurface: str(fm.actionSurface),
4487
+ requires: strArray(fm.requires),
4488
+ bytes,
4489
+ files: fileRows
4490
+ });
4491
+ }
4492
+ return out;
4493
+ }
4494
+ function buildManifest(root, skillsDir = bundledSkillsDir()) {
4495
+ return {
4496
+ schemaVersion: 1,
4497
+ cliVersion: CLI_VERSION,
4498
+ commands: collectCommandSurface(root),
4499
+ skills: collectBundledSkills(skillsDir)
4500
+ };
4501
+ }
4502
+ function skillsManifestCommand(root, args) {
4503
+ const manifest2 = buildManifest(root);
4504
+ process.stdout.write(formatObject13(manifest2, { format: args.output ?? "json" }) + "\n");
4505
+ }
4506
+ function str(v) {
4507
+ return typeof v === "string" && v ? v : void 0;
4508
+ }
4509
+ function strArray(v) {
4510
+ return Array.isArray(v) ? v.map(String) : void 0;
4511
+ }
4512
+
4513
+ // src/commands/skills-bundled.ts
4514
+ function listBundledSkills(dir = bundledSkillsDir()) {
4515
+ return collectBundledSkills(dir);
4516
+ }
4517
+ function unreachable(id, detail) {
4518
+ return new CliError15({
4519
+ code: CliErrorCode14.SKILL_SOURCE_UNREACHABLE,
4520
+ message: `\u88C5\u5728\u8FD9\u4EFD CLI \u91CC\u7684\u6280\u80FD\u8D44\u6E90\u8BFB\u4E0D\u5230\uFF08${detail}\uFF09\uFF0C\u91CD\u88C5 @hcmai/cli\u3002
4521
+ \u6280\u80FD id\uFF1A${id}\uFF1B\u627E\u7684\u4F4D\u7F6E\uFF1A${bundledSkillsDir()}`
4522
+ });
4523
+ }
4524
+ async function readBundledReferences(skillDir) {
4525
+ const root = path3.join(skillDir, "references");
4526
+ const out = [];
4527
+ const walk = async (dir, prefix) => {
4528
+ let items;
4529
+ try {
4530
+ items = await fsp.readdir(dir, { withFileTypes: true });
4531
+ } catch (cause) {
4532
+ if (cause?.code === "ENOENT") return;
4533
+ throw cause;
4534
+ }
4535
+ for (const item of items.sort((a, b) => a.name.localeCompare(b.name))) {
4536
+ const relative2 = prefix ? `${prefix}/${item.name}` : item.name;
4537
+ if (item.isDirectory()) {
4538
+ await walk(path3.join(dir, item.name), relative2);
4539
+ continue;
4540
+ }
4541
+ if (!item.isFile()) continue;
4542
+ assertSafeReferencePath(relative2);
4543
+ out.push({ path: relative2, content: await fsp.readFile(path3.join(dir, item.name), "utf8") });
4544
+ }
4545
+ };
4546
+ await walk(root, "");
4547
+ return out;
4548
+ }
4549
+ async function readBundledSkillDocument(id, dir = bundledSkillsDir()) {
4550
+ const skillDir = path3.join(dir, id);
4551
+ let markdown;
4552
+ try {
4553
+ markdown = await fsp.readFile(path3.join(skillDir, "SKILL.md"), "utf8");
4554
+ } catch (cause) {
4555
+ if (cause?.code === "ENOENT") throw unreachable(id, "SKILL.md \u4E0D\u5B58\u5728");
4556
+ throw cause;
4557
+ }
4558
+ if (!markdown.trim()) throw unreachable(id, "SKILL.md \u662F\u7A7A\u7684");
4559
+ return {
4560
+ id,
4561
+ markdown,
4562
+ source: cliLocatorString(id, CLI_VERSION),
4563
+ sourceKind: "cli",
4564
+ references: await readBundledReferences(skillDir)
4565
+ };
4566
+ }
4567
+ async function resolveBundledClosure(targetId, dir = bundledSkillsDir()) {
4568
+ const documents = [];
4569
+ const external = /* @__PURE__ */ new Set();
4570
+ const state = /* @__PURE__ */ new Map();
4571
+ const stack = [];
4572
+ const available = new Set(listBundledSkills(dir).map((s) => s.id));
4573
+ const visit = async (id) => {
4574
+ if (state.get(id) === "done") return;
4575
+ if (state.get(id) === "visiting") {
4576
+ throw new CliError15({
4577
+ code: CliErrorCode14.INVALID_ARGUMENT,
4578
+ message: `\u81EA\u5E26\u6280\u80FD\u4F9D\u8D56\u6210\u73AF\uFF1A${[...stack, id].join(" \u2192 ")}`
4579
+ });
4580
+ }
4581
+ state.set(id, "visiting");
4582
+ stack.push(id);
4583
+ const document = await readBundledSkillDocument(id, dir);
4584
+ for (const need of parseSkillRequirements(document.markdown, id)) {
4585
+ if (available.has(need)) await visit(need);
4586
+ else external.add(need);
4587
+ }
4588
+ stack.pop();
4589
+ state.set(id, "done");
4590
+ documents.push(document);
4591
+ };
4592
+ await visit(targetId);
4593
+ return { documents, external: [...external].sort() };
4594
+ }
4595
+
4596
+ // src/commands/skills-sync.ts
4597
+ import { createHash as createHash2 } from "crypto";
4313
4598
  import { promises as fs5 } from "fs";
4314
- import path2 from "path";
4599
+ import path4 from "path";
4315
4600
  import {
4316
- CliError as CliError14,
4317
- CliErrorCode as CliErrorCode13,
4601
+ CliError as CliError16,
4602
+ CliErrorCode as CliErrorCode15,
4318
4603
  assertSafeSkillFilePath,
4319
4604
  assertSafeSkillId,
4320
4605
  normalizeReferences,
@@ -4347,7 +4632,7 @@ async function prepareSkillDocuments(catalog, requestedSkill, fetchMarkdown, fet
4347
4632
  path: targetPath,
4348
4633
  content: referenceContent,
4349
4634
  bytes: referenceContent.length,
4350
- sha256: sha256(referenceContent)
4635
+ sha256: sha2562(referenceContent)
4351
4636
  };
4352
4637
  })
4353
4638
  );
@@ -4356,7 +4641,7 @@ async function prepareSkillDocuments(catalog, requestedSkill, fetchMarkdown, fet
4356
4641
  path: "SKILL.md",
4357
4642
  content,
4358
4643
  bytes: content.length,
4359
- sha256: sha256(content)
4644
+ sha256: sha2562(content)
4360
4645
  },
4361
4646
  ...referenceFiles
4362
4647
  ];
@@ -4384,7 +4669,7 @@ async function prepareSkillDocuments(catalog, requestedSkill, fetchMarkdown, fet
4384
4669
  `\u6280\u80FD ${skill.id}/${file.path} \u5B57\u8282\u6570\u4E0E\u76EE\u5F55\u4E0D\u4E00\u81F4\uFF1A\u76EE\u5F55=${file.bytes}\uFF0C\u5B9E\u9645=${content.length}`
4385
4670
  );
4386
4671
  }
4387
- const digest = sha256(content);
4672
+ const digest = sha2562(content);
4388
4673
  if (digest !== file.sha256) {
4389
4674
  throw invalid(`\u6280\u80FD ${skill.id}/${file.path} \u6458\u8981\u4E0E\u76EE\u5F55\u4E0D\u4E00\u81F4`);
4390
4675
  }
@@ -4406,10 +4691,10 @@ async function prepareSkillDocuments(catalog, requestedSkill, fetchMarkdown, fet
4406
4691
  );
4407
4692
  }
4408
4693
  async function syncWorkBuddyProject(input) {
4409
- const project = path2.resolve(input.project);
4410
- const metaDir = path2.join(project, ".hcm-delivery");
4411
- const skillsDir = path2.join(project, ".codebuddy", "skills");
4412
- const lockPath = path2.join(metaDir, "chiron.lock.json");
4694
+ const project = path4.resolve(input.project);
4695
+ const metaDir = path4.join(project, ".hcm-delivery");
4696
+ const skillsDir = path4.join(project, ".codebuddy", "skills");
4697
+ const lockPath = path4.join(metaDir, "chiron.lock.json");
4413
4698
  assertSafeSkillId(input.requestedSkill);
4414
4699
  validatePreparedDocuments(input.documents, input.requestedSkill);
4415
4700
  validatePreparedRuntime(input.runtime);
@@ -4429,27 +4714,27 @@ async function syncWorkBuddyProject(input) {
4429
4714
  const oldDigestByFile = lockDigests(oldLock);
4430
4715
  for (const file of oldOwned) validateOwnedFile(file);
4431
4716
  for (const file of desiredFiles) {
4432
- const absolute = path2.join(project, file);
4717
+ const absolute = path4.join(project, file);
4433
4718
  const current = await readOptionalBytes(absolute);
4434
4719
  if (current !== void 0 && !oldOwned.has(file)) {
4435
4720
  throw invalid(`\u76EE\u6807\u6587\u4EF6\u4E0D\u5C5E\u4E8E\u4E0A\u4E00\u4EFD Chiron \u9501\uFF0C\u62D2\u7EDD\u8986\u76D6\u987E\u95EE\u6587\u4EF6\uFF1A${file}`);
4436
4721
  }
4437
4722
  }
4438
4723
  for (const file of oldOwned) {
4439
- const absolute = path2.join(project, file);
4724
+ const absolute = path4.join(project, file);
4440
4725
  const current = await readOptionalBytes(absolute);
4441
4726
  if (current === void 0) continue;
4442
4727
  const expected = oldDigestByFile.get(file);
4443
- if (!expected || sha256(current) !== expected.sha256 || !await fileModeMatches(absolute, expected.mode)) {
4728
+ if (!expected || sha2562(current) !== expected.sha256 || !await fileModeMatches(absolute, expected.mode)) {
4444
4729
  throw invalid(`\u4E0A\u4E00\u4EFD\u9501\u62E5\u6709\u7684\u751F\u6210\u6587\u4EF6\u5DF2\u88AB\u4EBA\u5DE5\u4FEE\u6539\uFF0C\u62D2\u7EDD\u8986\u76D6\u6216\u6E05\u7406\uFF1A${file}`);
4445
4730
  }
4446
4731
  }
4447
4732
  const newLock = {
4448
4733
  schemaVersion: 1,
4449
4734
  source: {
4450
- endpointOriginSha256: sha256(normalizeEndpoint(input.endpoint)),
4735
+ endpointOriginSha256: sha2562(normalizeEndpoint(input.endpoint)),
4451
4736
  catalogPath: "/skills.json",
4452
- catalogSha256: sha256(stableJson2(input.catalog))
4737
+ catalogSha256: sha2562(stableJson2(input.catalog))
4453
4738
  },
4454
4739
  selection: { requestedSkill: input.requestedSkill },
4455
4740
  resolvedSkills: input.documents.map(({ id, bytes, sha256: digest, files: skillFiles }) => ({
@@ -4481,16 +4766,16 @@ async function syncWorkBuddyProject(input) {
4481
4766
  }
4482
4767
  const obsolete = [...oldOwned].filter((file) => !desiredByFile.has(file));
4483
4768
  await fs5.mkdir(metaDir, { recursive: true });
4484
- const staging = await fs5.mkdtemp(path2.join(metaDir, ".staging-"));
4485
- const stagedFiles = path2.join(staging, "new");
4486
- const backups = path2.join(staging, "backup");
4487
- const stagedLock = path2.join(staging, "chiron.lock.json");
4488
- const journalPath = path2.join(staging, "journal.json");
4769
+ const staging = await fs5.mkdtemp(path4.join(metaDir, ".staging-"));
4770
+ const stagedFiles = path4.join(staging, "new");
4771
+ const backups = path4.join(staging, "backup");
4772
+ const stagedLock = path4.join(staging, "chiron.lock.json");
4773
+ const journalPath = path4.join(staging, "journal.json");
4489
4774
  let journalReady = false;
4490
4775
  try {
4491
4776
  for (const [file, preparedFile2] of desiredByFile) {
4492
- const staged = path2.join(stagedFiles, file);
4493
- await fs5.mkdir(path2.dirname(staged), { recursive: true });
4777
+ const staged = path4.join(stagedFiles, file);
4778
+ await fs5.mkdir(path4.dirname(staged), { recursive: true });
4494
4779
  await fs5.writeFile(
4495
4780
  staged,
4496
4781
  preparedFile2.content,
@@ -4501,16 +4786,16 @@ async function syncWorkBuddyProject(input) {
4501
4786
  `, "utf8");
4502
4787
  const affected = [.../* @__PURE__ */ new Set([...desiredFiles, ...obsolete])];
4503
4788
  for (const file of affected) {
4504
- const target = path2.join(project, file);
4789
+ const target = path4.join(project, file);
4505
4790
  if (!await exists(target)) continue;
4506
- const backup = path2.join(backups, file);
4507
- await fs5.mkdir(path2.dirname(backup), { recursive: true });
4791
+ const backup = path4.join(backups, file);
4792
+ await fs5.mkdir(path4.dirname(backup), { recursive: true });
4508
4793
  await fs5.copyFile(target, backup);
4509
4794
  }
4510
4795
  const oldLockExisted = await exists(lockPath);
4511
4796
  if (oldLockExisted) {
4512
- const backupLock = path2.join(backups, ".hcm-delivery", "chiron.lock.json");
4513
- await fs5.mkdir(path2.dirname(backupLock), { recursive: true });
4797
+ const backupLock = path4.join(backups, ".hcm-delivery", "chiron.lock.json");
4798
+ await fs5.mkdir(path4.dirname(backupLock), { recursive: true });
4514
4799
  await fs5.copyFile(lockPath, backupLock);
4515
4800
  }
4516
4801
  const journal = {
@@ -4523,12 +4808,12 @@ async function syncWorkBuddyProject(input) {
4523
4808
  `, "utf8");
4524
4809
  journalReady = true;
4525
4810
  for (const file of desiredFiles) {
4526
- const target = path2.join(project, file);
4527
- await fs5.mkdir(path2.dirname(target), { recursive: true });
4811
+ const target = path4.join(project, file);
4812
+ await fs5.mkdir(path4.dirname(target), { recursive: true });
4528
4813
  await fs5.rm(target, { force: true });
4529
- await fs5.rename(path2.join(stagedFiles, file), target);
4814
+ await fs5.rename(path4.join(stagedFiles, file), target);
4530
4815
  }
4531
- for (const file of obsolete) await fs5.unlink(path2.join(project, file)).catch(ignoreMissing);
4816
+ for (const file of obsolete) await fs5.unlink(path4.join(project, file)).catch(ignoreMissing);
4532
4817
  await fs5.rm(lockPath, { force: true });
4533
4818
  await fs5.rename(stagedLock, lockPath);
4534
4819
  await fs5.unlink(journalPath);
@@ -4559,32 +4844,32 @@ async function recoverInterruptedSyncs(project, metaDir, lockPath) {
4559
4844
  }
4560
4845
  for (const entry of entries) {
4561
4846
  if (!entry.isDirectory() || !entry.name.startsWith(".staging-")) continue;
4562
- const staging = path2.join(metaDir, entry.name);
4563
- if (await exists(path2.join(staging, "journal.json"))) {
4847
+ const staging = path4.join(metaDir, entry.name);
4848
+ if (await exists(path4.join(staging, "journal.json"))) {
4564
4849
  await recoverStaging(project, staging, lockPath);
4565
4850
  }
4566
4851
  await fs5.rm(staging, { recursive: true, force: true });
4567
4852
  }
4568
4853
  }
4569
4854
  async function recoverStaging(project, staging, lockPath) {
4570
- const journalPath = path2.join(staging, "journal.json");
4855
+ const journalPath = path4.join(staging, "journal.json");
4571
4856
  const journal = parseJournal(await fs5.readFile(journalPath, "utf8"), project);
4572
- const backups = path2.join(staging, "backup");
4857
+ const backups = path4.join(staging, "backup");
4573
4858
  for (const file of journal.affectedFiles) {
4574
- const target = path2.join(project, file);
4575
- const backup = path2.join(backups, file);
4859
+ const target = path4.join(project, file);
4860
+ const backup = path4.join(backups, file);
4576
4861
  if (await exists(backup)) {
4577
- await fs5.mkdir(path2.dirname(target), { recursive: true });
4862
+ await fs5.mkdir(path4.dirname(target), { recursive: true });
4578
4863
  await fs5.rm(target, { force: true });
4579
4864
  await fs5.rename(backup, target);
4580
4865
  } else {
4581
4866
  await fs5.rm(target, { force: true });
4582
4867
  }
4583
4868
  }
4584
- const backupLock = path2.join(backups, ".hcm-delivery", "chiron.lock.json");
4869
+ const backupLock = path4.join(backups, ".hcm-delivery", "chiron.lock.json");
4585
4870
  if (journal.oldLockExisted) {
4586
4871
  if (!await exists(backupLock)) throw invalid(`\u540C\u6B65\u6062\u590D\u7F3A\u5C11\u65E7\u9501\u5907\u4EFD\uFF1A${backupLock}`);
4587
- await fs5.mkdir(path2.dirname(lockPath), { recursive: true });
4872
+ await fs5.mkdir(path4.dirname(lockPath), { recursive: true });
4588
4873
  await fs5.rm(lockPath, { force: true });
4589
4874
  await fs5.rename(backupLock, lockPath);
4590
4875
  } else {
@@ -4596,8 +4881,8 @@ function parseJournal(content, project) {
4596
4881
  try {
4597
4882
  journal = JSON.parse(content);
4598
4883
  } catch (cause) {
4599
- throw new CliError14({
4600
- code: CliErrorCode13.CONFIG_PARSE_ERROR,
4884
+ throw new CliError16({
4885
+ code: CliErrorCode15.CONFIG_PARSE_ERROR,
4601
4886
  message: "Chiron \u540C\u6B65\u6062\u590D\u65E5\u5FD7\u635F\u574F",
4602
4887
  cause
4603
4888
  });
@@ -4620,7 +4905,7 @@ function validatePreparedDocuments(documents, requestedSkill) {
4620
4905
  assertSafeSkillFilePath(file.path);
4621
4906
  if (paths.has(file.path)) throw invalid(`\u6280\u80FD ${document.id} \u5305\u542B\u91CD\u590D\u6587\u4EF6: ${file.path}`);
4622
4907
  paths.add(file.path);
4623
- if (file.content.length !== file.bytes || sha256(file.content) !== file.sha256) {
4908
+ if (file.content.length !== file.bytes || sha2562(file.content) !== file.sha256) {
4624
4909
  throw invalid(`\u6280\u80FD ${document.id}/${file.path} \u7684\u5DF2\u51C6\u5907\u5185\u5BB9\u6458\u8981\u4E0D\u4E00\u81F4`);
4625
4910
  }
4626
4911
  }
@@ -4642,7 +4927,7 @@ function validatePreparedRuntime(runtime) {
4642
4927
  }
4643
4928
  capabilities.add(capability);
4644
4929
  }
4645
- if (!validDigest(runtime.capabilitiesSha256) || runtime.capabilitiesSha256 !== sha256(`${runtime.capabilities.join("\n")}
4930
+ if (!validDigest(runtime.capabilitiesSha256) || runtime.capabilitiesSha256 !== sha2562(`${runtime.capabilities.join("\n")}
4646
4931
  `)) {
4647
4932
  throw invalid("WorkBuddy CLI \u80FD\u529B\u6458\u8981\u4E0D\u4E00\u81F4");
4648
4933
  }
@@ -4667,7 +4952,7 @@ function validatePreparedRuntime(runtime) {
4667
4952
  }
4668
4953
  function validateRuntimeFile(file) {
4669
4954
  validateOwnedFile(file.path);
4670
- if (file.content.length !== file.bytes || sha256(file.content) !== file.sha256 || !Number.isInteger(file.mode) || file.mode < 0 || file.mode > 511) {
4955
+ if (file.content.length !== file.bytes || sha2562(file.content) !== file.sha256 || !Number.isInteger(file.mode) || file.mode < 0 || file.mode > 511) {
4671
4956
  throw invalid(`WorkBuddy \u8FD0\u884C\u5165\u53E3\u6458\u8981\u6216\u6743\u9650\u4E0D\u4E00\u81F4\uFF1A${file.path}`);
4672
4957
  }
4673
4958
  }
@@ -4712,15 +4997,15 @@ async function readLock(lockPath) {
4712
4997
  for (const file of lock.ownedFiles) validateOwnedFile(file);
4713
4998
  return lock;
4714
4999
  } catch (cause) {
4715
- throw new CliError14({
4716
- code: CliErrorCode13.CONFIG_PARSE_ERROR,
5000
+ throw new CliError16({
5001
+ code: CliErrorCode15.CONFIG_PARSE_ERROR,
4717
5002
  message: `Chiron \u9501\u6587\u4EF6\u635F\u574F\uFF0C\u62D2\u7EDD\u731C\u6D4B\u6587\u4EF6\u6240\u6709\u6743\uFF1A${lockPath}`,
4718
5003
  cause
4719
5004
  });
4720
5005
  }
4721
5006
  }
4722
5007
  function validateLockedRuntime(runtime) {
4723
- if (!Array.isArray(runtime.capabilities) || runtime.capabilities.length === 0 || !validDigest(runtime.capabilitiesSha256) || runtime.capabilitiesSha256 !== sha256(`${runtime.capabilities.join("\n")}
5008
+ if (!Array.isArray(runtime.capabilities) || runtime.capabilities.length === 0 || !validDigest(runtime.capabilitiesSha256) || runtime.capabilitiesSha256 !== sha2562(`${runtime.capabilities.join("\n")}
4724
5009
  `) || !runtime.launch || !validDigest(runtime.launch.executableSha256) || !Array.isArray(runtime.files) || runtime.files.length !== 2) {
4725
5010
  throw new Error("invalid runtime");
4726
5011
  }
@@ -4754,9 +5039,9 @@ function sameLockContent(left, right) {
4754
5039
  }
4755
5040
  async function desiredFilesMatch(project, desired) {
4756
5041
  for (const [file, preparedFile2] of desired) {
4757
- const absolute = path2.join(project, file);
5042
+ const absolute = path4.join(project, file);
4758
5043
  const current = await readOptionalBytes(absolute);
4759
- if (current === void 0 || sha256(current) !== preparedFile2.sha256 || !await fileModeMatches(absolute, preparedFile2.mode)) {
5044
+ if (current === void 0 || sha2562(current) !== preparedFile2.sha256 || !await fileModeMatches(absolute, preparedFile2.mode)) {
4760
5045
  return false;
4761
5046
  }
4762
5047
  }
@@ -4770,7 +5055,7 @@ function result(changed, input, project, skillsDir, lockPath, installed, removed
4770
5055
  project,
4771
5056
  skillsDir,
4772
5057
  lockPath,
4773
- runnerPath: path2.join(project, ".hcm-delivery", "bin", "hcm"),
5058
+ runnerPath: path4.join(project, ".hcm-delivery", "bin", "hcm"),
4774
5059
  capabilitiesSha256: input.runtime.capabilitiesSha256,
4775
5060
  installed,
4776
5061
  removed
@@ -4805,8 +5090,8 @@ function normalizeEndpoint(endpoint) {
4805
5090
  try {
4806
5091
  url = new URL(endpoint);
4807
5092
  } catch (cause) {
4808
- throw new CliError14({
4809
- code: CliErrorCode13.INVALID_ARGUMENT,
5093
+ throw new CliError16({
5094
+ code: CliErrorCode15.INVALID_ARGUMENT,
4810
5095
  message: `\u975E\u6CD5 endpoint\uFF1A${endpoint}`,
4811
5096
  cause
4812
5097
  });
@@ -4818,8 +5103,8 @@ function normalizeEndpoint(endpoint) {
4818
5103
  url.pathname = url.pathname.replace(/\/+$/, "");
4819
5104
  return url.toString().replace(/\/$/, "");
4820
5105
  }
4821
- function sha256(value) {
4822
- return createHash("sha256").update(value).digest("hex");
5106
+ function sha2562(value) {
5107
+ return createHash2("sha256").update(value).digest("hex");
4823
5108
  }
4824
5109
  function stableJson2(value) {
4825
5110
  if (Array.isArray(value)) return `[${value.map(stableJson2).join(",")}]`;
@@ -4882,16 +5167,16 @@ function ignoreMissing(cause) {
4882
5167
  if (cause.code !== "ENOENT") throw cause;
4883
5168
  }
4884
5169
  function invalid(message) {
4885
- return new CliError14({ code: CliErrorCode13.INVALID_ARGUMENT, message });
5170
+ return new CliError16({ code: CliErrorCode15.INVALID_ARGUMENT, message });
4886
5171
  }
4887
5172
 
4888
5173
  // src/commands/skills-runtime.ts
4889
5174
  import { execFile } from "child_process";
4890
- import { createHash as createHash2 } from "crypto";
5175
+ import { createHash as createHash3 } from "crypto";
4891
5176
  import { createReadStream, promises as fs6 } from "fs";
4892
- import path3 from "path";
5177
+ import path5 from "path";
4893
5178
  import { promisify } from "util";
4894
- import { CliError as CliError15, CliErrorCode as CliErrorCode14 } from "@hcmai/sdk";
5179
+ import { CliError as CliError17, CliErrorCode as CliErrorCode16 } from "@hcmai/sdk";
4895
5180
  var execFileAsync = promisify(execFile);
4896
5181
  var REQUIRED_CAPABILITIES = [
4897
5182
  "hcm.help.skills",
@@ -4928,7 +5213,7 @@ async function prepareWorkBuddyRuntime(input = {}) {
4928
5213
  }
4929
5214
  }
4930
5215
  const capabilities = [...REQUIRED_CAPABILITIES];
4931
- const capabilitiesSha256 = sha2562(`${capabilities.join("\n")}
5216
+ const capabilitiesSha256 = sha2563(`${capabilities.join("\n")}
4932
5217
  `);
4933
5218
  const executableSha256 = await sha256File(launch.executable);
4934
5219
  const launchRecord = launch.kind === "node-entry" ? {
@@ -4949,7 +5234,7 @@ async function prepareWorkBuddyRuntime(input = {}) {
4949
5234
  };
4950
5235
  }
4951
5236
  async function resolveLaunch(candidate, nodeExecutable) {
4952
- const requested = path3.resolve(candidate);
5237
+ const requested = path5.resolve(candidate);
4953
5238
  const resolvedCandidate = await realFile(requested, "\u5019\u9009 HCM CLI");
4954
5239
  const header = (await readPrefix(resolvedCandidate, 256)).toString("utf8");
4955
5240
  const nodeEntry = /^(?:#![^\r\n]*\bnode\b)|\.(?:c|m)?js$/i.test(
@@ -4958,7 +5243,7 @@ async function resolveLaunch(candidate, nodeExecutable) {
4958
5243
  if (nodeEntry) {
4959
5244
  return {
4960
5245
  kind: "node-entry",
4961
- executable: await realFile(path3.resolve(nodeExecutable), "Node \u53EF\u6267\u884C\u6587\u4EF6"),
5246
+ executable: await realFile(path5.resolve(nodeExecutable), "Node \u53EF\u6267\u884C\u6587\u4EF6"),
4962
5247
  entry: resolvedCandidate
4963
5248
  };
4964
5249
  }
@@ -4971,15 +5256,15 @@ async function realFile(file, label) {
4971
5256
  if (!stat.isFile()) throw new Error("not a regular file");
4972
5257
  return resolved;
4973
5258
  } catch (cause) {
4974
- throw new CliError15({
4975
- code: CliErrorCode14.INVALID_ARGUMENT,
5259
+ throw new CliError17({
5260
+ code: CliErrorCode16.INVALID_ARGUMENT,
4976
5261
  message: `${label}\u4E0D\u53EF\u7528\uFF1A${file}`,
4977
5262
  cause
4978
5263
  });
4979
5264
  }
4980
5265
  }
4981
5266
  async function comparablePath(file) {
4982
- const absolute = path3.resolve(file);
5267
+ const absolute = path5.resolve(file);
4983
5268
  return fs6.realpath(absolute).catch(() => absolute);
4984
5269
  }
4985
5270
  async function launchIdentity(launch) {
@@ -5025,8 +5310,8 @@ async function runProbe(launch, args, timeoutMs = 5e3) {
5025
5310
  return `${stdout}
5026
5311
  ${stderr}`;
5027
5312
  } catch (cause) {
5028
- throw new CliError15({
5029
- code: CliErrorCode14.INVALID_ARGUMENT,
5313
+ throw new CliError17({
5314
+ code: CliErrorCode16.INVALID_ARGUMENT,
5030
5315
  message: `\u5019\u9009 HCM CLI \u80FD\u529B\u63A2\u9488\u5931\u8D25\uFF1Ahcm ${args.join(" ")}`,
5031
5316
  cause
5032
5317
  });
@@ -5091,10 +5376,10 @@ function cmdQuote(value) {
5091
5376
  return `"${value.replace(/%/g, "%%")}"`;
5092
5377
  }
5093
5378
  function preparedFile(filePath, content, mode) {
5094
- return { path: filePath, content, bytes: content.length, sha256: sha2562(content), mode };
5379
+ return { path: filePath, content, bytes: content.length, sha256: sha2563(content), mode };
5095
5380
  }
5096
5381
  async function sha256File(file) {
5097
- const hash = createHash2("sha256");
5382
+ const hash = createHash3("sha256");
5098
5383
  await new Promise((resolve3, reject) => {
5099
5384
  const stream = createReadStream(file);
5100
5385
  stream.on("data", (chunk) => hash.update(chunk));
@@ -5103,17 +5388,29 @@ async function sha256File(file) {
5103
5388
  });
5104
5389
  return hash.digest("hex");
5105
5390
  }
5106
- function sha2562(value) {
5107
- return createHash2("sha256").update(value).digest("hex");
5391
+ function sha2563(value) {
5392
+ return createHash3("sha256").update(value).digest("hex");
5108
5393
  }
5109
5394
  function invalid2(message) {
5110
- return new CliError15({ code: CliErrorCode14.INVALID_ARGUMENT, message });
5395
+ return new CliError17({ code: CliErrorCode16.INVALID_ARGUMENT, message });
5111
5396
  }
5112
5397
 
5113
5398
  // src/commands/skills.ts
5114
5399
  var SKILLS_STATE_FILE = ".hcm-skills.json";
5115
- function sha2563(text) {
5116
- return createHash3("sha256").update(text, "utf8").digest("hex");
5400
+ function migrateSkillsState(state) {
5401
+ const skills2 = {};
5402
+ for (const [id, record] of Object.entries(state.skills ?? {})) {
5403
+ if (record.sourceKind) {
5404
+ skills2[id] = record;
5405
+ continue;
5406
+ }
5407
+ const kind = /^https?:\/\//i.test(record.source ?? "") ? "chiron" : "local";
5408
+ skills2[id] = { ...record, sourceKind: kind, sourceLocator: record.source };
5409
+ }
5410
+ return { ...state, skills: skills2 };
5411
+ }
5412
+ function sha2564(text) {
5413
+ return createHash4("sha256").update(text, "utf8").digest("hex");
5117
5414
  }
5118
5415
  async function resolveEndpoint(args) {
5119
5416
  if (args.endpoint) return args.endpoint.replace(/\/+$/, "");
@@ -5121,8 +5418,8 @@ async function resolveEndpoint(args) {
5121
5418
  const envName = resolveActiveEnv3({ envFlag: args.env }, process.env, g);
5122
5419
  const env2 = await loadEnv5(envName).catch(() => null);
5123
5420
  if (!env2?.endpoint) {
5124
- throw new CliError16({
5125
- code: CliErrorCode15.MISSING_FLAG,
5421
+ throw new CliError18({
5422
+ code: CliErrorCode17.MISSING_FLAG,
5126
5423
  message: "\u672A\u89E3\u6790\u5230 endpoint \u2014\u2014 \u4F20 --endpoint <url>\uFF0C\u6216\u5148 `hcm env add <name> --endpoint <url>`\u3002\uFF08\u6280\u80FD\u5E93\u514D\u8BA4\u8BC1\uFF0C\u4E0D\u9700\u8981\u5148 login\uFF09"
5127
5424
  });
5128
5425
  }
@@ -5141,8 +5438,8 @@ function decideTrackedEndpoint(options) {
5141
5438
  }
5142
5439
  if (!recorded) {
5143
5440
  if (!current) {
5144
- throw new CliError16({
5145
- code: CliErrorCode15.MISSING_FLAG,
5441
+ throw new CliError18({
5442
+ code: CliErrorCode17.MISSING_FLAG,
5146
5443
  message: "\u672A\u89E3\u6790\u5230 endpoint \u2014\u2014 \u4F20 --endpoint <url>\uFF0C\u6216\u5148 `hcm env add <name> --endpoint <url>`\u3002\uFF08\u6280\u80FD\u5E93\u514D\u8BA4\u8BC1\uFF0C\u4E0D\u9700\u8981\u5148 login\uFF09"
5147
5444
  });
5148
5445
  }
@@ -5159,32 +5456,32 @@ function decideTrackedEndpoint(options) {
5159
5456
  }
5160
5457
  async function exists2(target) {
5161
5458
  try {
5162
- await fsp.stat(target);
5459
+ await fsp2.stat(target);
5163
5460
  return true;
5164
5461
  } catch {
5165
5462
  return false;
5166
5463
  }
5167
5464
  }
5168
5465
  async function detectTarget(cwd) {
5169
- if (await exists2(path4.join(cwd, ".claude"))) return "claude";
5170
- if (await exists2(path4.join(cwd, "AGENTS.md"))) return "codex";
5171
- if (await exists2(path4.join(cwd, ".codex"))) return "codex";
5466
+ if (await exists2(path6.join(cwd, ".claude"))) return "claude";
5467
+ if (await exists2(path6.join(cwd, "AGENTS.md"))) return "codex";
5468
+ if (await exists2(path6.join(cwd, ".codex"))) return "codex";
5172
5469
  return void 0;
5173
5470
  }
5174
5471
  async function resolveInstallLayout(args, cwd = process.cwd()) {
5175
5472
  const requested = args.target && args.target !== "auto" ? args.target : void 0;
5176
5473
  const target = requested ?? await detectTarget(cwd) ?? "claude";
5177
5474
  if (target === "codex") {
5178
- const root = args.global ? path4.join(os2.homedir(), ".codex") : cwd;
5475
+ const root = args.global ? path6.join(os2.homedir(), ".codex") : cwd;
5179
5476
  return {
5180
5477
  target,
5181
- baseDir: args.dir ? path4.resolve(args.dir) : path4.join(root, "hcm-skills"),
5182
- agentsFile: path4.join(root, "AGENTS.md")
5478
+ baseDir: args.dir ? path6.resolve(args.dir) : path6.join(root, "hcm-skills"),
5479
+ agentsFile: path6.join(root, "AGENTS.md")
5183
5480
  };
5184
5481
  }
5185
5482
  return {
5186
5483
  target,
5187
- baseDir: args.dir ? path4.resolve(args.dir) : args.global ? path4.join(os2.homedir(), ".claude", "skills") : path4.join(cwd, ".claude", "skills")
5484
+ baseDir: args.dir ? path6.resolve(args.dir) : args.global ? path6.join(os2.homedir(), ".claude", "skills") : path6.join(cwd, ".claude", "skills")
5188
5485
  };
5189
5486
  }
5190
5487
  async function chironClient(args) {
@@ -5209,10 +5506,41 @@ function fail3(e, args) {
5209
5506
  async function skillsListCommand(keyword, args) {
5210
5507
  try {
5211
5508
  if (args.installed) return await listInstalledSkills(keyword, args);
5212
- const { http, endpoint, base } = await chironClient(args);
5213
- const manifest2 = await fetchSkillCatalog(http, base);
5509
+ const source = parseSourceFilter(args.source);
5510
+ let manifest2;
5511
+ let endpoint;
5512
+ if (source !== "cli") {
5513
+ const client3 = await chironClient(args);
5514
+ endpoint = client3.endpoint;
5515
+ manifest2 = await fetchSkillCatalog(client3.http, client3.base);
5516
+ }
5517
+ const bundled = source === "chiron" ? void 0 : listBundledSkills();
5518
+ const catalog = buildUnifiedCatalog({ source, chironManifest: manifest2, bundled, cliVersion: CLI_VERSION });
5519
+ const conflicts = detectIdConflicts(catalog);
5520
+ if (conflicts.ids.length > 0) {
5521
+ throw new CliError18({
5522
+ code: CliErrorCode17.SKILL_ID_CONFLICT,
5523
+ message: conflictMessage(conflicts.ids, endpoint ?? "(\u672A\u77E5\u73AF\u5883)")
5524
+ });
5525
+ }
5214
5526
  const fmt = args.output ?? "table";
5215
- let cats = manifest2.categories ?? [];
5527
+ const cliCategory = catalog.cli.entries.size > 0 ? {
5528
+ key: CLI_CATEGORY_KEY,
5529
+ name: CLI_CATEGORY_NAME,
5530
+ description: "\u968F\u8FD9\u4EFD CLI \u53D1\u5E03\u7684\u6280\u80FD\uFF0C\u8BB2\u7684\u662F\u672C CLI \u7684\u547D\u4EE4\uFF1B\u5347\u7EA7 CLI \u5C31\u662F\u5347\u7EA7\u5B83\u4EEC",
5531
+ skills: [...catalog.cli.entries.values()].map((entry) => ({
5532
+ id: entry.meta.id,
5533
+ title: entry.meta.title,
5534
+ category: CLI_CATEGORY_KEY,
5535
+ actionSurface: "cli",
5536
+ description: entry.meta.description,
5537
+ stages: entry.meta.stages,
5538
+ requires: entry.meta.requires,
5539
+ bytes: entry.meta.bytes,
5540
+ markdownUrl: ""
5541
+ }))
5542
+ } : void 0;
5543
+ let cats = [...manifest2?.categories ?? [], ...cliCategory ? [cliCategory] : []];
5216
5544
  if (args.category) cats = cats.filter((c) => c.key === args.category);
5217
5545
  if (keyword) {
5218
5546
  cats = cats.map((c) => ({ ...c, skills: matchSkills(c.skills ?? [], keyword) })).filter((c) => c.skills.length > 0);
@@ -5221,21 +5549,41 @@ async function skillsListCommand(keyword, args) {
5221
5549
  cats = cats.map((c) => ({ ...c, skills: filterByStage(c.skills ?? [], args.stage) })).filter((c) => c.skills.length > 0);
5222
5550
  }
5223
5551
  if (fmt === "json" || fmt === "yaml") {
5224
- process.stdout.write(formatObject13({ ...manifest2, categories: cats }, { format: fmt }) + "\n");
5552
+ process.stdout.write(
5553
+ formatObject14(
5554
+ {
5555
+ ...manifest2 ?? {},
5556
+ categories: cats,
5557
+ sources: {
5558
+ cli: { status: catalog.cli.status, count: catalog.cli.entries.size },
5559
+ chiron: { status: catalog.chiron.status, count: catalog.chiron.entries.size }
5560
+ },
5561
+ conflictCheck: conflicts.checked ? { checked: true } : { checked: false, note: unconfirmedConflictNote(source) }
5562
+ },
5563
+ { format: fmt }
5564
+ ) + "\n"
5565
+ );
5225
5566
  process.exit(0);
5226
5567
  }
5227
5568
  const shown = cats.flatMap((c) => c.skills);
5569
+ const total = (manifest2?.skillCount ?? 0) + catalog.cli.entries.size;
5228
5570
  if (shown.length === 0) {
5229
- process.stdout.write(`\u6CA1\u6709\u5339\u914D\u7684\u6280\u80FD\uFF08${endpoint} \u5171 ${manifest2.skillCount} \u4E2A\uFF09
5571
+ process.stdout.write(`\u6CA1\u6709\u5339\u914D\u7684\u6280\u80FD\uFF08\u8FD9\u4E00\u8D9F\u770B\u7684\u6765\u6E90\u5171 ${total} \u4E2A\uFF09
5230
5572
  `);
5231
5573
  process.exit(0);
5232
5574
  }
5233
- process.stdout.write(`${manifest2.title ?? "Chiron"} \u2014 ${endpoint}
5575
+ process.stdout.write(`${manifest2?.title ?? "HCM \u6280\u80FD"} \u2014 ${endpoint ?? `@hcmai/cli@${CLI_VERSION}`}
5234
5576
 
5235
5577
  `);
5236
5578
  if (args.byStage) {
5237
5579
  const all = cats.flatMap((c) => c.skills);
5238
- for (const st of manifest2.stages ?? []) {
5580
+ const stageList = manifest2?.stages ?? [...new Set(all.flatMap((skill) => skill.stages ?? []))].sort().map((key) => ({
5581
+ key,
5582
+ name: key,
5583
+ description: "",
5584
+ skillCount: 0
5585
+ }));
5586
+ for (const st of stageList) {
5239
5587
  const inStage = filterByStage(all, st.key);
5240
5588
  if (inStage.length === 0 && !args.stage) {
5241
5589
  process.stdout.write(` ${st.name} (\u65E0\u6280\u80FD\u8986\u76D6)
@@ -5284,10 +5632,10 @@ async function listInstalledSkills(keyword, args) {
5284
5632
  const fmt = args.output ?? "table";
5285
5633
  if (!state || Object.keys(state.skills).length === 0) {
5286
5634
  if (fmt === "json" || fmt === "yaml") {
5287
- process.stdout.write(formatObject13({ baseDir: layout.baseDir, target: layout.target, all: false, skills: [] }, { format: fmt }) + "\n");
5635
+ process.stdout.write(formatObject14({ baseDir: layout.baseDir, target: layout.target, all: false, skills: [] }, { format: fmt }) + "\n");
5288
5636
  process.exit(0);
5289
5637
  }
5290
- process.stdout.write(`${path4.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
5638
+ process.stdout.write(`${path6.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
5291
5639
  `);
5292
5640
  process.stdout.write(" \u88C5\u5168\u90E8\uFF1Ahcm skills install --all\n");
5293
5641
  process.exit(0);
@@ -5297,31 +5645,43 @@ async function listInstalledSkills(keyword, args) {
5297
5645
  const markdown = await readInstalled(layout.baseDir, id);
5298
5646
  let title = id;
5299
5647
  if (markdown !== void 0) {
5300
- const raw = parseSkillFrontmatter(markdown, id).title;
5648
+ const raw = parseSkillFrontmatter2(markdown, id).title;
5301
5649
  if (typeof raw === "string" && raw.trim()) title = raw.trim();
5302
5650
  }
5303
5651
  rows.push({
5304
5652
  id,
5305
5653
  title,
5654
+ // 迁移保证它必然有值;`?? 'chiron'` 只是让类型闭合,不是业务缺省。
5655
+ sourceKind: record.sourceKind ?? "chiron",
5656
+ sourceLocator: record.sourceLocator ?? record.source,
5306
5657
  direct: record.direct,
5307
5658
  installedAt: record.installedAt,
5308
5659
  // 三种状态互斥:文件没了 / 本地改过 / 和装的时候一致
5309
- status: markdown === void 0 ? "missing" : sha2563(markdown) !== record.sha256 ? "locally-modified" : "installed"
5660
+ status: markdown === void 0 ? "missing" : sha2564(markdown) !== record.sha256 ? "locally-modified" : "installed"
5310
5661
  });
5311
5662
  }
5312
- const shown = keyword ? rows.filter((row) => row.id.includes(keyword) || row.title.includes(keyword)) : rows;
5663
+ const byKeyword = keyword ? rows.filter((row) => row.id.includes(keyword) || row.title.includes(keyword)) : rows;
5664
+ const sourceFilter = parseSourceFilter(args.source);
5665
+ const shown = sourceFilter === "all" ? byKeyword : byKeyword.filter((row) => row.sourceKind === sourceFilter);
5666
+ const groupOf = (kind) => kind === "cli" ? "CLI \u81EA\u5E26" : kind === "local" ? "\u672C\u5730\u76EE\u5F55\u88C5\u7684" : "\u777F\u620E\u6280\u80FD\u5E93";
5313
5667
  if (fmt === "json" || fmt === "yaml") {
5314
- process.stdout.write(formatObject13({
5668
+ process.stdout.write(formatObject14({
5315
5669
  baseDir: layout.baseDir,
5316
5670
  target: layout.target,
5317
5671
  endpoint: state.endpoint,
5318
5672
  all: Boolean(state.all),
5319
5673
  updatedAt: state.updatedAt,
5674
+ // 按来源分组的小计:顾问要能一眼看出「这份是跟着 CLI 走的还是跟着后端走的」
5675
+ bySource: {
5676
+ cli: shown.filter((r) => r.sourceKind === "cli").length,
5677
+ chiron: shown.filter((r) => r.sourceKind === "chiron").length,
5678
+ local: shown.filter((r) => r.sourceKind === "local").length
5679
+ },
5320
5680
  skills: shown
5321
5681
  }, { format: fmt }) + "\n");
5322
5682
  process.exit(0);
5323
5683
  }
5324
- process.stdout.write(`\u5DF2\u5B89\u88C5\u7684\u777F\u620E\u6280\u80FD \u2014 ${layout.baseDir}\uFF08${layout.target}\uFF09
5684
+ process.stdout.write(`\u5DF2\u5B89\u88C5\u7684\u6280\u80FD \u2014 ${layout.baseDir}\uFF08${layout.target}\uFF09
5325
5685
  `);
5326
5686
  process.stdout.write(`\u6765\u6E90 ${state.endpoint ?? "\uFF08\u672A\u8BB0\u5F55\uFF09"}` + (state.all ? " \u8DDF\u968F\u5168\u96C6\uFF1A\u662F\n\n" : "\n\n"));
5327
5687
  if (shown.length === 0) {
@@ -5329,11 +5689,18 @@ async function listInstalledSkills(keyword, args) {
5329
5689
  `);
5330
5690
  process.exit(0);
5331
5691
  }
5332
- for (const row of shown) {
5333
- const mark = row.status === "missing" ? "?" : row.status === "locally-modified" ? "!" : row.direct ? "\u25CF" : "\u25CB";
5334
- 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";
5335
- process.stdout.write(` ${mark} ${row.id.padEnd(30)} ${row.title.padEnd(24)} ${note}
5692
+ for (const kind of ["chiron", "cli", "local"]) {
5693
+ const group = shown.filter((row) => row.sourceKind === kind);
5694
+ if (group.length === 0) continue;
5695
+ process.stdout.write(` ${groupOf(kind)}\uFF08${group.length}\uFF09
5336
5696
  `);
5697
+ for (const row of group) {
5698
+ const mark = row.status === "missing" ? "?" : row.status === "locally-modified" ? "!" : row.direct ? "\u25CF" : "\u25CB";
5699
+ 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";
5700
+ process.stdout.write(` ${mark} ${row.id.padEnd(30)} ${row.title.padEnd(24)} ${note}
5701
+ `);
5702
+ }
5703
+ process.stdout.write("\n");
5337
5704
  }
5338
5705
  const modified = shown.filter((row) => row.status === "locally-modified").length;
5339
5706
  const missing = shown.filter((row) => row.status === "missing").length;
@@ -5352,6 +5719,16 @@ async function listInstalledSkills(keyword, args) {
5352
5719
  }
5353
5720
  async function skillsShowCommand(id, args) {
5354
5721
  try {
5722
+ assertSafeSkillId2(id);
5723
+ const source = parseSourceFilter(args.source);
5724
+ if (source !== "chiron" && listBundledSkills().some((s) => s.id === id)) {
5725
+ const document = await readBundledSkillDocument(id);
5726
+ process.stdout.write(document.markdown.endsWith("\n") ? document.markdown : document.markdown + "\n");
5727
+ process.exit(0);
5728
+ }
5729
+ if (source === "cli") {
5730
+ throw invalid3(`\u8FD9\u4E00\u7248 CLI \u6CA1\u6709\u81EA\u5E26 ${id} \u8FD9\u4E2A\u6280\u80FD\uFF08--source cli \u4E0D\u770B\u777F\u620E\u76EE\u5F55\uFF09`);
5731
+ }
5355
5732
  const { http, base } = await chironClient(args);
5356
5733
  const md = await fetchSkillMarkdown(http, id, base);
5357
5734
  process.stdout.write(md.endsWith("\n") ? md : md + "\n");
@@ -5367,13 +5744,19 @@ async function skillsSyncCommand(id, args) {
5367
5744
  throw invalid3(`sync --target \u5F53\u524D\u53EA\u652F\u6301 workbuddy\uFF0C\u6536\u5230 "${args.target ?? ""}"`);
5368
5745
  }
5369
5746
  if (!args.project?.trim()) throw invalid3("sync \u5FC5\u987B\u4F20 --project <path>");
5370
- const project = path4.resolve(args.project);
5747
+ if (listBundledSkills().some((one) => one.id === id)) {
5748
+ throw new CliError18({
5749
+ code: CliErrorCode17.SYNC_SOURCE_UNSUPPORTED,
5750
+ message: `\`${id}\` \u662F CLI \u81EA\u5E26\u6280\u80FD\uFF1Bskills sync \u7684\u9501\u6587\u4EF6\uFF08chiron.lock.json\uFF09\u6B64\u523B\u53EA\u80FD\u8BB0\u5F55\u777F\u620E\u6765\u6E90\u7684\u51FA\u5904\u3002\u88C5\u5230\u672C\u5730\u7528 \`hcm skills install ` + id + "`\u3002"
5751
+ });
5752
+ }
5753
+ const project = path6.resolve(args.project);
5371
5754
  const runtime = await prepareWorkBuddyRuntime({
5372
5755
  candidate: args.cli,
5373
5756
  currentEntryHasRequiredCapabilities: !args.cli?.trim(),
5374
5757
  forbiddenCandidatePaths: [
5375
- path4.join(project, ".hcm-delivery", "bin", "hcm"),
5376
- path4.join(project, ".hcm-delivery", "bin", "hcm.cmd")
5758
+ path6.join(project, ".hcm-delivery", "bin", "hcm"),
5759
+ path6.join(project, ".hcm-delivery", "bin", "hcm.cmd")
5377
5760
  ]
5378
5761
  });
5379
5762
  const connectionArgs = { endpoint: args.endpoint, env: args.env };
@@ -5396,7 +5779,7 @@ async function skillsSyncCommand(id, args) {
5396
5779
  });
5397
5780
  const fmt = args.output ?? "table";
5398
5781
  if (fmt === "json" || fmt === "yaml") {
5399
- process.stdout.write(`${formatObject13(result2, { format: fmt })}
5782
+ process.stdout.write(`${formatObject14(result2, { format: fmt })}
5400
5783
  `);
5401
5784
  } else if (result2.changed) {
5402
5785
  process.stdout.write(`\u2705 ${id} \u2192 ${result2.skillsDir}
@@ -5434,8 +5817,9 @@ async function skillsInstallCommand(id, args) {
5434
5817
  let endpoint;
5435
5818
  let base;
5436
5819
  let manifest2;
5820
+ let conflictNote;
5437
5821
  if (args.from) {
5438
- const root = path4.resolve(args.from);
5822
+ const root = path6.resolve(args.from);
5439
5823
  requestedIds = all ? await listLocalSkillIds(root) : [id];
5440
5824
  const seen = /* @__PURE__ */ new Set();
5441
5825
  documents = [];
@@ -5447,23 +5831,97 @@ async function skillsInstallCommand(id, args) {
5447
5831
  }
5448
5832
  }
5449
5833
  } else {
5450
- const tracked = decideTrackedEndpoint({
5451
- explicit: Boolean(args.endpoint || args.env),
5452
- current: await resolveEndpoint(args).catch(() => void 0),
5453
- recorded: (await readSkillsState(layout.baseDir))?.endpoint
5454
- });
5455
- const client3 = await chironClient({ ...args, endpoint: tracked });
5456
- endpoint = client3.endpoint;
5457
- base = client3.base;
5458
- manifest2 = await fetchSkillCatalog(client3.http, base);
5459
- const order = all ? resolveAllSkillsInstallOrder(manifest2) : resolveSkillInstallOrder2(manifest2, id);
5460
- if (all && order.length === 0) throw invalid3(`${endpoint} \u7684\u6280\u80FD\u76EE\u5F55\u662F\u7A7A\u7684\uFF0C\u6CA1\u6709\u53EF\u88C5\u7684\u6280\u80FD`);
5461
- requestedIds = all ? order.map((skill) => skill.id) : [id];
5462
- documents = await mapWithConcurrency(
5463
- order,
5464
- FETCH_CONCURRENCY,
5465
- (skill) => fetchSkillDocument(client3.http, skill, endpoint, base)
5466
- );
5834
+ const source = parseSourceFilter(args.source);
5835
+ const bundled = source === "chiron" ? void 0 : listBundledSkills();
5836
+ let http;
5837
+ if (source !== "cli") {
5838
+ const tracked = decideTrackedEndpoint({
5839
+ explicit: Boolean(args.endpoint || args.env),
5840
+ current: await resolveEndpoint(args).catch(() => void 0),
5841
+ recorded: (await readSkillsState(layout.baseDir))?.endpoint
5842
+ });
5843
+ const client3 = await chironClient({ ...args, endpoint: tracked });
5844
+ endpoint = client3.endpoint;
5845
+ base = client3.base;
5846
+ http = client3.http;
5847
+ manifest2 = await fetchSkillCatalog(http, base);
5848
+ }
5849
+ const catalog = buildUnifiedCatalog({ source, chironManifest: manifest2, bundled, cliVersion: CLI_VERSION });
5850
+ const conflicts = detectIdConflicts(catalog);
5851
+ if (conflicts.ids.length > 0) {
5852
+ throw new CliError18({
5853
+ code: CliErrorCode17.SKILL_ID_CONFLICT,
5854
+ message: conflictMessage(conflicts.ids, endpoint ?? "(\u672A\u77E5\u73AF\u5883)")
5855
+ });
5856
+ }
5857
+ conflictNote = conflicts.checked ? void 0 : unconfirmedConflictNote(source);
5858
+ for (const v of checkCrossSourceRequires(catalog)) {
5859
+ throw invalid3(`${v.from} \u58F0\u660E\u4F9D\u8D56 ${v.to}\uFF0C\u4F46 ${v.to} \u662F CLI \u81EA\u5E26\u6280\u80FD\u3002${v.reason}`);
5860
+ }
5861
+ const wantBundled = (one) => catalog.cli.entries.has(one);
5862
+ const seen = /* @__PURE__ */ new Set();
5863
+ documents = [];
5864
+ const pushAll = (docs) => {
5865
+ for (const d of docs) {
5866
+ if (seen.has(d.id)) continue;
5867
+ seen.add(d.id);
5868
+ documents.push(d);
5869
+ }
5870
+ };
5871
+ const installBundled = async (one) => {
5872
+ const { documents: local, external } = await resolveBundledClosure(one);
5873
+ for (const need of external) {
5874
+ if (catalog.chiron.status !== "fetched") {
5875
+ throw invalid3(
5876
+ `\u81EA\u5E26\u6280\u80FD ${one} \u4F9D\u8D56\u777F\u620E\u6280\u80FD ${need}\uFF0C\u4F46\u8FD9\u4E00\u8D9F\u6CA1\u8FDE\u7F51\u53D6\u777F\u620E\u76EE\u5F55\uFF08--source ${source}\uFF09\u3002\u8054\u7F51\u540E\u91CD\u8DD1\uFF0C\u6216\u5148\u5355\u72EC\u88C5\u4E0A\u5B83\u3002`
5877
+ );
5878
+ }
5879
+ if (!catalog.chiron.entries.has(need)) {
5880
+ throw invalid3(`\u81EA\u5E26\u6280\u80FD ${one} \u4F9D\u8D56 ${need}\uFF0C\u4F46 ${endpoint} \u7684\u6280\u80FD\u76EE\u5F55\u91CC\u6CA1\u6709\u5B83`);
5881
+ }
5882
+ pushAll(
5883
+ await mapWithConcurrency(
5884
+ resolveSkillInstallOrder2(manifest2, need),
5885
+ FETCH_CONCURRENCY,
5886
+ (skill) => fetchSkillDocument(http, skill, endpoint, base)
5887
+ )
5888
+ );
5889
+ }
5890
+ pushAll(local);
5891
+ };
5892
+ if (all) {
5893
+ const order = manifest2 ? resolveAllSkillsInstallOrder(manifest2) : [];
5894
+ const bundledIds = [...catalog.cli.entries.keys()].sort();
5895
+ if (order.length === 0 && bundledIds.length === 0) {
5896
+ throw invalid3(`${endpoint ?? "\u8FD9\u4E00\u8D9F\u770B\u7684\u6765\u6E90"} \u91CC\u6CA1\u6709\u53EF\u88C5\u7684\u6280\u80FD`);
5897
+ }
5898
+ requestedIds = [...order.map((skill) => skill.id), ...bundledIds];
5899
+ if (order.length > 0) {
5900
+ pushAll(
5901
+ await mapWithConcurrency(
5902
+ order,
5903
+ FETCH_CONCURRENCY,
5904
+ (skill) => fetchSkillDocument(http, skill, endpoint, base)
5905
+ )
5906
+ );
5907
+ }
5908
+ for (const one of bundledIds) await installBundled(one);
5909
+ } else if (wantBundled(id)) {
5910
+ requestedIds = [id];
5911
+ await installBundled(id);
5912
+ } else {
5913
+ if (source === "cli") {
5914
+ throw invalid3(`\u8FD9\u4E00\u7248 CLI \u6CA1\u6709\u81EA\u5E26 ${id} \u8FD9\u4E2A\u6280\u80FD\uFF08--source cli \u4E0D\u770B\u777F\u620E\u76EE\u5F55\uFF09`);
5915
+ }
5916
+ requestedIds = [id];
5917
+ pushAll(
5918
+ await mapWithConcurrency(
5919
+ resolveSkillInstallOrder2(manifest2, id),
5920
+ FETCH_CONCURRENCY,
5921
+ (skill) => fetchSkillDocument(http, skill, endpoint, base)
5922
+ )
5923
+ );
5924
+ }
5467
5925
  }
5468
5926
  const result2 = await installSkillDocuments(documents, requestedIds, layout.baseDir, Boolean(args.force), {
5469
5927
  endpoint,
@@ -5474,9 +5932,9 @@ async function skillsInstallCommand(id, args) {
5474
5932
  const agents = layout.agentsFile ? await syncAgentsIndex(layout, manifest2) : void 0;
5475
5933
  const fmt = args.output ?? "table";
5476
5934
  if (fmt === "json" || fmt === "yaml") {
5477
- process.stdout.write(formatObject13({ ...result2, all, target_agent: layout.target, agentsFile: layout.agentsFile, agents }, { format: fmt }) + "\n");
5935
+ process.stdout.write(formatObject14({ ...result2, all, target_agent: layout.target, agentsFile: layout.agentsFile, agents, conflictCheck: conflictNote ? { checked: false, note: conflictNote } : { checked: true } }, { format: fmt }) + "\n");
5478
5936
  } else {
5479
- const headline = all ? `\u2705 \u5168\u90E8 ${requestedIds.length} \u4E2A\u6280\u80FD \u2192 ${result2.baseDir}` : `\u2705 ${id} \u2192 ${path4.join(result2.baseDir, id, "SKILL.md")}`;
5937
+ const headline = all ? `\u2705 \u5168\u90E8 ${requestedIds.length} \u4E2A\u6280\u80FD \u2192 ${result2.baseDir}` : `\u2705 ${id} \u2192 ${path6.join(result2.baseDir, id, "SKILL.md")}`;
5480
5938
  process.stdout.write(`${headline}
5481
5939
  `);
5482
5940
  if (result2.installed.length > 0) {
@@ -5498,7 +5956,9 @@ async function skillsInstallCommand(id, args) {
5498
5956
  process.stdout.write(` \u5DF2${agents === "created" ? "\u521B\u5EFA" : "\u66F4\u65B0"} ${layout.agentsFile} \u91CC\u7684\u6280\u80FD\u7D22\u5F15\uFF08Codex \u8BFB\u8FD9\u91CC\uFF09
5499
5957
  `);
5500
5958
  }
5501
- process.stdout.write(` \u6765\u6E90 ${endpoint ?? path4.resolve(args.from)}
5959
+ process.stdout.write(` \u6765\u6E90 ${endpoint ?? (args.from ? path6.resolve(args.from) : `@hcmai/cli@${CLI_VERSION}`)}
5960
+ `);
5961
+ if (conflictNote) process.stdout.write(` \u26A0\uFE0F ${conflictNote}
5502
5962
  `);
5503
5963
  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");
5504
5964
  }
@@ -5524,14 +5984,14 @@ async function mapWithConcurrency(items, limit, fn) {
5524
5984
  async function listLocalSkillIds(root) {
5525
5985
  let entries;
5526
5986
  try {
5527
- entries = await fsp.readdir(root, { withFileTypes: true });
5987
+ entries = await fsp2.readdir(root, { withFileTypes: true });
5528
5988
  } catch {
5529
5989
  throw invalid3(`\u8BFB\u4E0D\u5230\u672C\u5730\u6280\u80FD\u76EE\u5F55\uFF1A${root}`);
5530
5990
  }
5531
5991
  const ids = [];
5532
5992
  for (const entry of entries) {
5533
5993
  if (!entry.isDirectory()) continue;
5534
- if (await exists2(path4.join(root, entry.name, "SKILL.md"))) ids.push(entry.name);
5994
+ if (await exists2(path6.join(root, entry.name, "SKILL.md"))) ids.push(entry.name);
5535
5995
  }
5536
5996
  if (ids.length === 0) throw invalid3(`\u672C\u5730\u76EE\u5F55\u91CC\u6CA1\u6709\u4EFB\u4F55 <id>/SKILL.md\uFF1A${root}`);
5537
5997
  return ids.sort();
@@ -5546,6 +6006,7 @@ async function fetchSkillDocument(http, skill, endpoint, base) {
5546
6006
  id: skill.id,
5547
6007
  markdown: await fetchSkillMarkdown(http, skill.id, base),
5548
6008
  source: `${endpoint}${base}/skills/${skill.id}.md`,
6009
+ sourceKind: "chiron",
5549
6010
  references
5550
6011
  };
5551
6012
  }
@@ -5557,17 +6018,17 @@ async function syncAgentsIndex(layout, manifest2) {
5557
6018
  for (const category of manifest2?.categories ?? []) {
5558
6019
  for (const skill of category.skills ?? []) catalog.set(skill.id, skill);
5559
6020
  }
5560
- const agentsDir = path4.dirname(layout.agentsFile);
6021
+ const agentsDir = path6.dirname(layout.agentsFile);
5561
6022
  const entries = Object.keys(state.skills).sort().map((id) => {
5562
6023
  const known = catalog.get(id);
5563
- const absolute = path4.join(layout.baseDir, id, "SKILL.md");
5564
- let relative2 = path4.relative(agentsDir, absolute);
6024
+ const absolute = path6.join(layout.baseDir, id, "SKILL.md");
6025
+ let relative2 = path6.relative(agentsDir, absolute);
5565
6026
  if (!relative2.startsWith(".")) relative2 = `./${relative2}`;
5566
6027
  return {
5567
6028
  id,
5568
6029
  title: known?.title ?? id,
5569
6030
  description: known?.description ?? "",
5570
- relativePath: relative2.split(path4.sep).join("/")
6031
+ relativePath: relative2.split(path6.sep).join("/")
5571
6032
  };
5572
6033
  });
5573
6034
  return upsertAgentsBlock(layout.agentsFile, renderAgentsBlock(entries));
@@ -5585,13 +6046,13 @@ async function resolveLocalSkillDocuments(sourceRoot, targetId) {
5585
6046
  throw invalid3(`\u6280\u80FD\u4F9D\u8D56\u5B58\u5728\u73AF: ${[...pathStack.slice(Math.max(0, start)), id].join(" -> ")}`);
5586
6047
  }
5587
6048
  assertSafeSkillId2(id);
5588
- const local = path4.join(sourceRoot, id, "SKILL.md");
6049
+ const local = path6.join(sourceRoot, id, "SKILL.md");
5589
6050
  let markdown;
5590
6051
  try {
5591
- markdown = await fsp.readFile(local, "utf8");
6052
+ markdown = await fsp2.readFile(local, "utf8");
5592
6053
  } catch (cause) {
5593
6054
  if (cause?.code === "ENOENT") {
5594
- throw invalid3(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${path4.join(sourceRoot, id)}`);
6055
+ throw invalid3(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${path6.join(sourceRoot, id)}`);
5595
6056
  }
5596
6057
  throw cause;
5597
6058
  }
@@ -5602,9 +6063,10 @@ async function resolveLocalSkillDocuments(sourceRoot, targetId) {
5602
6063
  id,
5603
6064
  markdown,
5604
6065
  source: local,
5605
- references: await readLocalReferences(path4.join(sourceRoot, id))
6066
+ sourceKind: "local",
6067
+ references: await readLocalReferences(path6.join(sourceRoot, id))
5606
6068
  };
5607
- for (const required of parseSkillRequirements(markdown, id)) {
6069
+ for (const required of parseSkillRequirements2(markdown, id)) {
5608
6070
  await visit(required, id);
5609
6071
  }
5610
6072
  pathStack.pop();
@@ -5616,20 +6078,20 @@ async function resolveLocalSkillDocuments(sourceRoot, targetId) {
5616
6078
  }
5617
6079
  async function readSkillsState(baseDir) {
5618
6080
  try {
5619
- const raw = await fsp.readFile(path4.join(baseDir, SKILLS_STATE_FILE), "utf8");
6081
+ const raw = await fsp2.readFile(path6.join(baseDir, SKILLS_STATE_FILE), "utf8");
5620
6082
  const parsed = JSON.parse(raw);
5621
6083
  if (!parsed || typeof parsed !== "object" || !parsed.skills) return void 0;
5622
- return parsed;
6084
+ return migrateSkillsState(parsed);
5623
6085
  } catch {
5624
6086
  return void 0;
5625
6087
  }
5626
6088
  }
5627
6089
  async function writeSkillsState(baseDir, state) {
5628
- await fsp.mkdir(baseDir, { recursive: true });
5629
- const file = path4.join(baseDir, SKILLS_STATE_FILE);
6090
+ await fsp2.mkdir(baseDir, { recursive: true });
6091
+ const file = path6.join(baseDir, SKILLS_STATE_FILE);
5630
6092
  const temp = `${file}.${process.pid}.tmp`;
5631
- await fsp.writeFile(temp, JSON.stringify(state, null, 2) + "\n", "utf8");
5632
- await fsp.rename(temp, file);
6093
+ await fsp2.writeFile(temp, JSON.stringify(state, null, 2) + "\n", "utf8");
6094
+ await fsp2.rename(temp, file);
5633
6095
  }
5634
6096
  var AGENTS_BLOCK_BEGIN = "<!-- hcm-skills:begin -->";
5635
6097
  var AGENTS_BLOCK_END = "<!-- hcm-skills:end -->";
@@ -5652,22 +6114,22 @@ function renderAgentsBlock(entries) {
5652
6114
  async function upsertAgentsBlock(agentsFile, block) {
5653
6115
  let existing = "";
5654
6116
  try {
5655
- existing = await fsp.readFile(agentsFile, "utf8");
6117
+ existing = await fsp2.readFile(agentsFile, "utf8");
5656
6118
  } catch (cause) {
5657
6119
  if (cause?.code !== "ENOENT") throw cause;
5658
- await fsp.mkdir(path4.dirname(agentsFile), { recursive: true });
5659
- await fsp.writeFile(agentsFile, block + "\n", "utf8");
6120
+ await fsp2.mkdir(path6.dirname(agentsFile), { recursive: true });
6121
+ await fsp2.writeFile(agentsFile, block + "\n", "utf8");
5660
6122
  return "created";
5661
6123
  }
5662
6124
  const begin = existing.indexOf(AGENTS_BLOCK_BEGIN);
5663
6125
  const end = existing.indexOf(AGENTS_BLOCK_END);
5664
6126
  if (begin >= 0 && end > begin) {
5665
6127
  const next = existing.slice(0, begin) + block + existing.slice(end + AGENTS_BLOCK_END.length);
5666
- await fsp.writeFile(agentsFile, next, "utf8");
6128
+ await fsp2.writeFile(agentsFile, next, "utf8");
5667
6129
  return "replaced";
5668
6130
  }
5669
6131
  const separator = existing.endsWith("\n") ? "\n" : "\n\n";
5670
- await fsp.writeFile(agentsFile, existing + separator + block + "\n", "utf8");
6132
+ await fsp2.writeFile(agentsFile, existing + separator + block + "\n", "utf8");
5671
6133
  return "appended";
5672
6134
  }
5673
6135
  async function installSkillDocuments(documents, requestedIds, baseDir, force, meta2) {
@@ -5681,7 +6143,7 @@ async function installSkillDocuments(documents, requestedIds, baseDir, force, me
5681
6143
  if (!document.markdown.trim()) throw invalid3(`\u6280\u80FD ${document.id} \u5185\u5BB9\u4E3A\u7A7A`);
5682
6144
  return {
5683
6145
  ...document,
5684
- target: path4.join(baseDir, document.id, "SKILL.md"),
6146
+ target: path6.join(baseDir, document.id, "SKILL.md"),
5685
6147
  bytes: Buffer.byteLength(document.markdown)
5686
6148
  };
5687
6149
  });
@@ -5732,12 +6194,12 @@ async function sameOnDisk(baseDir, candidate) {
5732
6194
  return true;
5733
6195
  }
5734
6196
  async function readLocalReferences(skillDir) {
5735
- const root = path4.join(skillDir, "references");
6197
+ const root = path6.join(skillDir, "references");
5736
6198
  const out = [];
5737
6199
  const walk = async (dir, prefix) => {
5738
6200
  let items;
5739
6201
  try {
5740
- items = await fsp.readdir(dir, { withFileTypes: true });
6202
+ items = await fsp2.readdir(dir, { withFileTypes: true });
5741
6203
  } catch (cause) {
5742
6204
  if (cause?.code === "ENOENT") return;
5743
6205
  throw cause;
@@ -5745,49 +6207,79 @@ async function readLocalReferences(skillDir) {
5745
6207
  for (const item of items.sort((a, b) => a.name.localeCompare(b.name))) {
5746
6208
  const relative2 = prefix ? `${prefix}/${item.name}` : item.name;
5747
6209
  if (item.isDirectory()) {
5748
- await walk(path4.join(dir, item.name), relative2);
6210
+ await walk(path6.join(dir, item.name), relative2);
5749
6211
  continue;
5750
6212
  }
5751
6213
  if (!item.isFile()) continue;
5752
- assertSafeReferencePath(relative2);
5753
- out.push({ path: relative2, content: await fsp.readFile(path4.join(dir, item.name), "utf8") });
6214
+ assertSafeReferencePath2(relative2);
6215
+ out.push({ path: relative2, content: await fsp2.readFile(path6.join(dir, item.name), "utf8") });
5754
6216
  }
5755
6217
  };
5756
6218
  await walk(root, "");
5757
6219
  return out;
5758
6220
  }
5759
- async function writeSkillDocuments(documents, baseDir) {
6221
+ async function planStaleReferences(state, documents, baseDir) {
6222
+ const remove = [];
6223
+ const keptLocallyModified = [];
6224
+ for (const document of documents) {
6225
+ const recorded = state.skills[document.id]?.references ?? {};
6226
+ const fresh = new Set((document.references ?? []).map((r) => r.path));
6227
+ for (const [relative2, recordedSha] of Object.entries(recorded)) {
6228
+ if (fresh.has(relative2)) continue;
6229
+ const onDisk = await readInstalledReference(baseDir, document.id, relative2);
6230
+ if (onDisk === void 0) continue;
6231
+ if (sha2564(onDisk) !== recordedSha) {
6232
+ keptLocallyModified.push({ id: document.id, path: relative2 });
6233
+ continue;
6234
+ }
6235
+ remove.push({ id: document.id, path: relative2 });
6236
+ }
6237
+ }
6238
+ const byKey = (a, b) => `${a.id}/${a.path}`.localeCompare(`${b.id}/${b.path}`);
6239
+ return { remove: remove.sort(byKey), keptLocallyModified: keptLocallyModified.sort(byKey) };
6240
+ }
6241
+ async function writeSkillDocuments(documents, baseDir, removals = []) {
5760
6242
  const staged = [];
6243
+ const removed = [];
5761
6244
  try {
5762
6245
  for (const document of documents) {
5763
- const target = path4.join(baseDir, document.id, "SKILL.md");
5764
- await fsp.mkdir(path4.dirname(target), { recursive: true });
5765
- const temp = path4.join(path4.dirname(target), `.SKILL.md.${process.pid}.${Date.now()}.tmp`);
5766
- await fsp.writeFile(temp, document.markdown, "utf8");
6246
+ const target = path6.join(baseDir, document.id, "SKILL.md");
6247
+ await fsp2.mkdir(path6.dirname(target), { recursive: true });
6248
+ const temp = path6.join(path6.dirname(target), `.SKILL.md.${process.pid}.${Date.now()}.tmp`);
6249
+ await fsp2.writeFile(temp, document.markdown, "utf8");
5767
6250
  staged.push({ temp, target });
5768
6251
  for (const reference of document.references ?? []) {
5769
- assertSafeReferencePath(reference.path);
5770
- const referenceTarget = path4.join(baseDir, document.id, "references", reference.path);
5771
- await fsp.mkdir(path4.dirname(referenceTarget), { recursive: true });
6252
+ assertSafeReferencePath2(reference.path);
6253
+ const referenceTarget = path6.join(baseDir, document.id, "references", reference.path);
6254
+ await fsp2.mkdir(path6.dirname(referenceTarget), { recursive: true });
5772
6255
  const referenceTemp = `${referenceTarget}.${process.pid}.${Date.now()}.tmp`;
5773
- await fsp.writeFile(referenceTemp, reference.content, "utf8");
6256
+ await fsp2.writeFile(referenceTemp, reference.content, "utf8");
5774
6257
  staged.push({ temp: referenceTemp, target: referenceTarget });
5775
6258
  }
5776
6259
  }
5777
- for (const file of staged) await fsp.rename(file.temp, file.target);
6260
+ for (const stale of removals) {
6261
+ assertSafeReferencePath2(stale.path);
6262
+ const original = path6.join(baseDir, stale.id, "references", stale.path);
6263
+ const parked = `${original}.${process.pid}.${Date.now()}.removed`;
6264
+ await fsp2.rename(original, parked);
6265
+ removed.push({ parked, original });
6266
+ }
6267
+ for (const file of staged) await fsp2.rename(file.temp, file.target);
6268
+ await Promise.all(removed.map((r) => fsp2.unlink(r.parked).catch(() => void 0)));
5778
6269
  } catch (cause) {
5779
- await Promise.all(staged.map((file) => fsp.unlink(file.temp).catch(() => void 0)));
6270
+ await Promise.all(staged.map((file) => fsp2.unlink(file.temp).catch(() => void 0)));
6271
+ await Promise.all(removed.map((r) => fsp2.rename(r.parked, r.original).catch(() => void 0)));
5780
6272
  throw cause;
5781
6273
  }
5782
6274
  }
5783
6275
  async function recordInstalled(baseDir, documents, meta2) {
5784
6276
  const state = await readSkillsState(baseDir) ?? {
5785
- version: 1,
6277
+ version: 2,
5786
6278
  target: meta2.target ?? "claude",
5787
6279
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
5788
6280
  skills: {}
5789
6281
  };
5790
- state.version = 1;
6282
+ state.version = 2;
5791
6283
  if (meta2.target) state.target = meta2.target;
5792
6284
  if (meta2.endpoint) state.endpoint = meta2.endpoint;
5793
6285
  if (meta2.base !== void 0) state.base = meta2.base;
@@ -5797,12 +6289,15 @@ async function recordInstalled(baseDir, documents, meta2) {
5797
6289
  const previous = state.skills[document.id];
5798
6290
  state.skills[document.id] = {
5799
6291
  source: document.source,
5800
- sha256: sha2563(document.markdown),
6292
+ // 🔴 两个键同值:`source` 留给旧 CLI 读(降级不炸),新代码只读 `sourceLocator`。
6293
+ sourceKind: document.sourceKind ?? previous?.sourceKind ?? "chiron",
6294
+ sourceLocator: document.source,
6295
+ sha256: sha2564(document.markdown),
5801
6296
  installedAt: meta2.keepInstalledAt?.has(document.id) && previous ? previous.installedAt : state.updatedAt,
5802
6297
  // 已经是直接安装的,不因为这次作为依赖被带进来就降级
5803
6298
  direct: meta2.directIds.has(document.id) || Boolean(previous?.direct),
5804
6299
  references: Object.fromEntries(
5805
- (document.references ?? []).map((reference) => [reference.path, sha2563(reference.content)])
6300
+ (document.references ?? []).map((reference) => [reference.path, sha2564(reference.content)])
5806
6301
  )
5807
6302
  };
5808
6303
  }
@@ -5810,11 +6305,11 @@ async function recordInstalled(baseDir, documents, meta2) {
5810
6305
  return state;
5811
6306
  }
5812
6307
  function invalid3(message) {
5813
- return new CliError16({ code: CliErrorCode15.INVALID_ARGUMENT, message });
6308
+ return new CliError18({ code: CliErrorCode17.INVALID_ARGUMENT, message });
5814
6309
  }
5815
6310
  async function readInstalled(baseDir, id) {
5816
6311
  try {
5817
- return await fsp.readFile(path4.join(baseDir, id, "SKILL.md"), "utf8");
6312
+ return await fsp2.readFile(path6.join(baseDir, id, "SKILL.md"), "utf8");
5818
6313
  } catch (cause) {
5819
6314
  if (cause?.code === "ENOENT") return void 0;
5820
6315
  throw cause;
@@ -5822,63 +6317,106 @@ async function readInstalled(baseDir, id) {
5822
6317
  }
5823
6318
  async function readInstalledReference(baseDir, id, relative2) {
5824
6319
  try {
5825
- return await fsp.readFile(path4.join(baseDir, id, "references", relative2), "utf8");
6320
+ return await fsp2.readFile(path6.join(baseDir, id, "references", relative2), "utf8");
5826
6321
  } catch (cause) {
5827
6322
  if (cause?.code === "ENOENT") return void 0;
5828
6323
  throw cause;
5829
6324
  }
5830
6325
  }
5831
6326
  async function planSkillUpdate(options) {
5832
- const { state, manifest: manifest2, baseDir, force, fetchDocument } = options;
6327
+ const { state, baseDir, force, fetchDocument } = options;
6328
+ const manifest2 = options.manifest;
6329
+ const catalog = options.catalog ?? buildUnifiedCatalog({ source: "chiron", chironManifest: manifest2, cliVersion: CLI_VERSION });
6330
+ const fetchBundled = options.fetchBundled ?? ((id) => readBundledSkillDocument(id));
5833
6331
  const all = options.all ?? Boolean(state.all);
5834
6332
  const recorded = Object.entries(state.skills);
5835
6333
  const directIds = recorded.some(([, r]) => r.direct) ? recorded.filter(([, r]) => r.direct).map(([id]) => id) : recorded.map(([id]) => id);
5836
- const wanted = all ? [.../* @__PURE__ */ new Set([...directIds, ...flattenSkills(manifest2).map((skill) => skill.id)])] : directIds;
5837
6334
  const entries = [];
6335
+ const live = [];
6336
+ for (const id of directIds.sort()) {
6337
+ const record = state.skills[id];
6338
+ const status = classifyInstalledSource(id, record, catalog);
6339
+ if (status === "present") {
6340
+ live.push({ id, kind: (record.sourceKind ?? "chiron") === "cli" ? "cli" : "chiron" });
6341
+ continue;
6342
+ }
6343
+ entries.push({ id, status, note: SOURCE_STATUS_NOTE[status] });
6344
+ }
6345
+ if (all) {
6346
+ const known = new Set(live.map((x) => x.id));
6347
+ for (const kind of ["chiron", "cli"]) {
6348
+ const half = kind === "chiron" ? catalog.chiron : catalog.cli;
6349
+ if (half.status !== "fetched") continue;
6350
+ for (const id of half.entries.keys()) {
6351
+ if (known.has(id)) continue;
6352
+ known.add(id);
6353
+ live.push({ id, kind });
6354
+ }
6355
+ }
6356
+ }
5838
6357
  const closure = /* @__PURE__ */ new Map();
5839
- for (const id of wanted.sort()) {
6358
+ const chironNeeded = /* @__PURE__ */ new Set();
6359
+ for (const item of live) {
6360
+ if (item.kind === "cli") {
6361
+ const queue = [item.id];
6362
+ while (queue.length > 0) {
6363
+ const id = queue.shift();
6364
+ if (closure.has(id)) continue;
6365
+ const entry = catalog.cli.entries.get(id);
6366
+ if (!entry) {
6367
+ chironNeeded.add(id);
6368
+ continue;
6369
+ }
6370
+ closure.set(id, { kind: "cli" });
6371
+ for (const need of entry.meta.requires ?? []) queue.push(need);
6372
+ }
6373
+ continue;
6374
+ }
6375
+ chironNeeded.add(item.id);
6376
+ }
6377
+ for (const id of chironNeeded) {
6378
+ if (!manifest2) continue;
5840
6379
  try {
5841
6380
  for (const skill of resolveSkillInstallOrder2(manifest2, id)) {
5842
- if (!closure.has(skill.id)) closure.set(skill.id, skill);
6381
+ if (!closure.has(skill.id)) closure.set(skill.id, { kind: "chiron", skill });
5843
6382
  }
5844
6383
  } catch {
5845
- entries.push({
5846
- id,
5847
- status: "removed-upstream",
5848
- 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"
5849
- });
6384
+ if (!entries.some((e) => e.id === id)) {
6385
+ entries.push({ id, status: "removed-upstream", note: SOURCE_STATUS_NOTE["removed-upstream"] });
6386
+ }
5850
6387
  }
5851
6388
  }
5852
6389
  const documents = [];
5853
- for (const skill of closure.values()) {
5854
- const record = state.skills[skill.id];
5855
- const onDisk = await readInstalled(baseDir, skill.id);
6390
+ for (const [id, item] of closure) {
6391
+ const record = state.skills[id];
6392
+ const onDisk = await readInstalled(baseDir, id);
6393
+ const fetch = async () => item.kind === "cli" ? await fetchBundled(id) : await fetchDocument(item.skill);
5856
6394
  if (onDisk === void 0) {
5857
- documents.push(await fetchDocument(skill));
6395
+ documents.push(await fetch());
5858
6396
  entries.push({
5859
- id: skill.id,
6397
+ id,
5860
6398
  status: "added",
5861
6399
  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"
5862
6400
  });
5863
6401
  continue;
5864
6402
  }
5865
- const remote = await fetchDocument(skill);
6403
+ const remote = await fetch();
5866
6404
  const remoteReferences = remote.references ?? [];
5867
6405
  let differsFromRemote = remote.markdown !== onDisk;
5868
- let editedLocally = record !== void 0 && sha2563(onDisk) !== record.sha256;
6406
+ let editedLocally = record !== void 0 && sha2564(onDisk) !== record.sha256;
5869
6407
  for (const reference of remoteReferences) {
5870
- const installed = await readInstalledReference(baseDir, skill.id, reference.path);
6408
+ const installed = await readInstalledReference(baseDir, id, reference.path);
5871
6409
  if (installed !== reference.content) differsFromRemote = true;
5872
6410
  const recordedSha = record?.references?.[reference.path];
5873
- if (installed !== void 0 && recordedSha && sha2563(installed) !== recordedSha) editedLocally = true;
6411
+ if (installed !== void 0 && recordedSha && sha2564(installed) !== recordedSha) editedLocally = true;
5874
6412
  }
5875
6413
  if (!differsFromRemote) {
5876
- entries.push({ id: skill.id, status: "unchanged" });
6414
+ entries.push({ id, status: "unchanged" });
5877
6415
  continue;
5878
6416
  }
5879
6417
  if (editedLocally && !force) {
5880
6418
  entries.push({
5881
- id: skill.id,
6419
+ id,
5882
6420
  status: "locally-modified",
5883
6421
  note: "\u672C\u5730\u6539\u8FC7\uFF0C\u6CA1\u6709\u8986\u76D6\uFF1B\u786E\u5B9A\u8981\u7528\u4EA7\u54C1\u8FD9\u4E00\u7248\u5C31\u52A0 --force"
5884
6422
  });
@@ -5886,7 +6424,7 @@ async function planSkillUpdate(options) {
5886
6424
  }
5887
6425
  documents.push(remote);
5888
6426
  entries.push({
5889
- id: skill.id,
6427
+ id,
5890
6428
  status: "updated",
5891
6429
  note: editedLocally ? "\u672C\u5730\u6539\u8FC7\uFF0C--force \u5DF2\u8986\u76D6" : void 0
5892
6430
  });
@@ -5899,37 +6437,54 @@ var UPDATE_STATUS_LABEL = {
5899
6437
  added: "\u5DF2\u8865\u88C5",
5900
6438
  unchanged: "\u5DF2\u662F\u6700\u65B0",
5901
6439
  "locally-modified": "\u672C\u5730\u6539\u8FC7\xB7\u8DF3\u8FC7",
5902
- "removed-upstream": "\u4EA7\u54C1\u5DF2\u79FB\u9664"
6440
+ "removed-upstream": "\u4EA7\u54C1\u5DF2\u79FB\u9664",
6441
+ "removed-in-cli": "CLI \u4E0D\u518D\u81EA\u5E26",
6442
+ // 🔴 这一档不是结论,是「这一趟没核」。文案上必须看得出区别,
6443
+ // 否则顾问会把它读成「没问题」,而它可能正藏着一份真的被移除了的技能。
6444
+ "not-checked": "\u672C\u8F6E\u672A\u6838",
6445
+ local: "\u672C\u5730\u6765\u6E90\xB7\u4E0D\u7BA1"
5903
6446
  };
5904
6447
  async function skillsUpdateCommand(args) {
5905
6448
  try {
5906
6449
  const layout = await resolveInstallLayout(args);
5907
6450
  const state = await readSkillsState(layout.baseDir);
5908
6451
  if (!state || Object.keys(state.skills).length === 0) {
5909
- throw new CliError16({
5910
- code: CliErrorCode15.INVALID_ARGUMENT,
5911
- message: `${path4.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`
6452
+ throw new CliError18({
6453
+ code: CliErrorCode17.INVALID_ARGUMENT,
6454
+ message: `${path6.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`
5912
6455
  });
5913
6456
  }
6457
+ const source = parseSourceFilter(args.source);
5914
6458
  const endpoint = decideTrackedEndpoint({
5915
6459
  explicit: Boolean(args.endpoint || args.env),
5916
6460
  current: await resolveEndpoint(args).catch(() => void 0),
5917
6461
  recorded: state.endpoint
5918
6462
  });
5919
- const { http, base } = await chironClient({ ...args, endpoint });
5920
- const manifest2 = await fetchSkillCatalog(http, base);
6463
+ let manifest2;
6464
+ let base;
6465
+ let http;
6466
+ if (source !== "cli") {
6467
+ const client3 = await chironClient({ ...args, endpoint });
6468
+ http = client3.http;
6469
+ base = client3.base;
6470
+ manifest2 = await fetchSkillCatalog(http, base);
6471
+ }
6472
+ const bundled = source === "chiron" ? void 0 : listBundledSkills();
6473
+ const catalog = buildUnifiedCatalog({ source, chironManifest: manifest2, bundled, cliVersion: CLI_VERSION });
5921
6474
  const all = Boolean(args.all) || Boolean(state.all);
5922
6475
  const plan = await planSkillUpdate({
5923
6476
  state,
5924
6477
  manifest: manifest2,
6478
+ catalog,
5925
6479
  baseDir: layout.baseDir,
5926
6480
  force: Boolean(args.force),
5927
6481
  all,
5928
6482
  fetchDocument: (skill) => fetchSkillDocument(http, skill, endpoint, base)
5929
6483
  });
6484
+ const stale = await planStaleReferences(state, plan.documents, layout.baseDir);
5930
6485
  const subscriptionChanged = all && !state.all;
5931
6486
  if (!args.check && (plan.documents.length > 0 || subscriptionChanged)) {
5932
- await writeSkillDocuments(plan.documents, layout.baseDir);
6487
+ await writeSkillDocuments(plan.documents, layout.baseDir, stale.remove);
5933
6488
  await recordInstalled(layout.baseDir, plan.documents, {
5934
6489
  endpoint,
5935
6490
  base,
@@ -5942,18 +6497,24 @@ async function skillsUpdateCommand(args) {
5942
6497
  const changed = plan.entries.filter((e) => e.status === "updated" || e.status === "added");
5943
6498
  const fmt = args.output ?? "table";
5944
6499
  if (fmt === "json" || fmt === "yaml") {
5945
- process.stdout.write(formatObject13({
6500
+ process.stdout.write(formatObject14({
5946
6501
  endpoint,
5947
6502
  baseDir: layout.baseDir,
5948
6503
  target: layout.target,
5949
6504
  dryRun: Boolean(args.check),
5950
6505
  all,
5951
6506
  changed: changed.length,
6507
+ sources: {
6508
+ cli: { status: catalog.cli.status, count: catalog.cli.entries.size },
6509
+ chiron: { status: catalog.chiron.status, count: catalog.chiron.entries.size }
6510
+ },
6511
+ cliVersion: CLI_VERSION,
6512
+ staleReferences: stale,
5952
6513
  entries: plan.entries
5953
6514
  }, { format: fmt }) + "\n");
5954
6515
  process.exit(0);
5955
6516
  }
5956
- process.stdout.write(`\u777F\u620E\u6280\u80FD\u5347\u7EA7 \u2014 ${endpoint}
6517
+ process.stdout.write(`\u6280\u80FD\u5347\u7EA7 \u2014 ${source === "cli" ? `@hcmai/cli@${CLI_VERSION}\uFF08\u672A\u8FDE\u7F51\uFF09` : endpoint}
5957
6518
  `);
5958
6519
  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"));
5959
6520
  for (const entry of plan.entries) {
@@ -5966,10 +6527,38 @@ async function skillsUpdateCommand(args) {
5966
6527
  process.stdout.write("\n");
5967
6528
  const skipped = plan.entries.filter((e) => e.status === "locally-modified").length;
5968
6529
  const removed = plan.entries.filter((e) => e.status === "removed-upstream").length;
6530
+ const removedInCli = plan.entries.filter((e) => e.status === "removed-in-cli").length;
6531
+ const notChecked = plan.entries.filter((e) => e.status === "not-checked").length;
5969
6532
  const tail = [
5970
6533
  skipped > 0 ? `${skipped} \u4E2A\u672C\u5730\u6539\u8FC7\u88AB\u8DF3\u8FC7\uFF08--force \u8986\u76D6\uFF09` : "",
5971
- removed > 0 ? `${removed} \u4E2A\u4EA7\u54C1\u5DF2\u79FB\u9664\uFF08\u672C\u5730\u6587\u4EF6\u4FDD\u7559\uFF09` : ""
6534
+ removed > 0 ? `${removed} \u4E2A\u4EA7\u54C1\u5DF2\u79FB\u9664\uFF08\u672C\u5730\u6587\u4EF6\u4FDD\u7559\uFF09` : "",
6535
+ removedInCli > 0 ? `${removedInCli} \u4E2A\u8FD9\u4E00\u7248 CLI \u4E0D\u518D\u81EA\u5E26\uFF08\u672C\u5730\u6587\u4EF6\u4FDD\u7559\uFF09` : "",
6536
+ notChecked > 0 ? `${notChecked} \u4E2A\u672C\u8F6E\u672A\u6838\uFF08\u90A3\u4E00\u534A\u8FD9\u8D9F\u6CA1\u770B\uFF09` : ""
5972
6537
  ].filter(Boolean).join("\uFF0C");
6538
+ const cliCount = plan.entries.filter(
6539
+ (e) => (state.skills[e.id]?.sourceKind ?? "chiron") === "cli"
6540
+ ).length;
6541
+ if (cliCount > 0) {
6542
+ process.stdout.write(` \u81EA\u5E26\u6280\u80FD ${cliCount} \u4E2A\u5DF2\u8DDF\u968F\u5F53\u524D CLI ${CLI_VERSION}
6543
+ `);
6544
+ }
6545
+ if (source === "cli" && all) {
6546
+ process.stdout.write(
6547
+ " \u672C\u8D9F\u53EA\u770B\u4E86\u81EA\u5E26\u90A3\u4E00\u534A\uFF1B\u8FD9\u4E2A\u76EE\u5F55\u8BA2\u9605\u7684\u662F\u5168\u5E93\uFF0C\u8054\u7F51\u540E update \u4F1A\u8865\u9F50\u777F\u620E\u90A3\u4E00\u534A\n"
6548
+ );
6549
+ }
6550
+ if (stale.remove.length > 0) {
6551
+ process.stdout.write(
6552
+ ` ${args.check ? "\u4F1A\u5220\u6389" : "\u5DF2\u5220\u6389"} ${stale.remove.length} \u4E2A\u4EA7\u54C1\u8FD9\u4E00\u7248\u64A4\u6389\u7684\u53C2\u8003\u6587\u4EF6\uFF08${stale.remove.map((r) => `${r.id}/references/${r.path}`).join("\u3001")}\uFF09
6553
+ `
6554
+ );
6555
+ }
6556
+ if (stale.keptLocallyModified.length > 0) {
6557
+ process.stdout.write(
6558
+ ` ${stale.keptLocallyModified.length} \u4E2A\u4EA7\u54C1\u5DF2\u64A4\u6389\u4F46\u672C\u5730\u6539\u8FC7\u7684\u53C2\u8003\u6587\u4EF6\u4FDD\u7559\u4E86\uFF08${stale.keptLocallyModified.map((r) => `${r.id}/references/${r.path}`).join("\u3001")}\uFF09
6559
+ `
6560
+ );
6561
+ }
5973
6562
  if (changed.length === 0 && skipped === 0 && removed === 0) {
5974
6563
  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");
5975
6564
  } else {
@@ -5987,13 +6576,13 @@ async function skillsUpdateCommand(args) {
5987
6576
  import {
5988
6577
  bootstrapTenant,
5989
6578
  createHttpClient as createHttpClient3,
5990
- formatObject as formatObject14,
6579
+ formatObject as formatObject15,
5991
6580
  fromAxiosError as fromAxiosError14,
5992
6581
  loadEnv as loadEnv6,
5993
6582
  loadGlobalConfig as loadGlobalConfig7,
5994
6583
  resolveActiveEnv as resolveActiveEnv4,
5995
- CliError as CliError17,
5996
- CliErrorCode as CliErrorCode16
6584
+ CliError as CliError19,
6585
+ CliErrorCode as CliErrorCode18
5997
6586
  } from "@hcmai/sdk";
5998
6587
  init_exit();
5999
6588
  async function resolveBootstrapKey(args, stdinTaken) {
@@ -6001,8 +6590,8 @@ async function resolveBootstrapKey(args, stdinTaken) {
6001
6590
  if (fromEnv) return fromEnv;
6002
6591
  if (args.bootstrapKeyStdin) {
6003
6592
  if (stdinTaken) {
6004
- throw new CliError17({
6005
- code: CliErrorCode16.INVALID_ARGUMENT,
6593
+ throw new CliError19({
6594
+ code: CliErrorCode18.INVALID_ARGUMENT,
6006
6595
  message: "--bootstrap-key-stdin \u4E0E --admin-password-stdin \u4E0D\u80FD\u540C\u65F6\u7528\uFF08stdin \u53EA\u6709\u4E00\u8DEF\uFF09\uFF1B\u628A\u5176\u4E2D\u4E00\u4E2A\u6539\u8D70 HCM_BOOTSTRAP_KEY \u73AF\u5883\u53D8\u91CF\u6216\u4EA4\u4E92\u8F93\u5165"
6007
6596
  });
6008
6597
  }
@@ -6032,8 +6621,8 @@ async function resolveEndpoint2(args) {
6032
6621
  const envName = resolveActiveEnv4({ envFlag: args.env }, process.env, g);
6033
6622
  const env2 = await loadEnv6(envName).catch(() => null);
6034
6623
  if (!env2?.endpoint) {
6035
- throw new CliError17({
6036
- code: CliErrorCode16.MISSING_FLAG,
6624
+ throw new CliError19({
6625
+ code: CliErrorCode18.MISSING_FLAG,
6037
6626
  message: "\u672A\u89E3\u6790\u5230 endpoint \u2014\u2014 \u4F20 --endpoint <url>\uFF0C\u6216\u5148 `hcm env add <name> --endpoint <url>`"
6038
6627
  });
6039
6628
  }
@@ -6042,8 +6631,8 @@ async function resolveEndpoint2(args) {
6042
6631
  async function tenantBootstrapCommand(args) {
6043
6632
  try {
6044
6633
  if (!args.tenantId || !args.adminUsername) {
6045
- throw new CliError17({
6046
- code: CliErrorCode16.MISSING_FLAG,
6634
+ throw new CliError19({
6635
+ code: CliErrorCode18.MISSING_FLAG,
6047
6636
  message: "--tenant-id \u4E0E --admin-username \u5FC5\u586B"
6048
6637
  });
6049
6638
  }
@@ -6079,7 +6668,7 @@ async function tenantBootstrapCommand(args) {
6079
6668
  `
6080
6669
  );
6081
6670
  }
6082
- process.stdout.write(formatObject14(result2, { format: fmt }) + "\n");
6671
+ process.stdout.write(formatObject15(result2, { format: fmt }) + "\n");
6083
6672
  process.exit(0);
6084
6673
  } catch (e) {
6085
6674
  const err = e;
@@ -6094,17 +6683,17 @@ async function tenantBootstrapCommand(args) {
6094
6683
  }
6095
6684
 
6096
6685
  // src/commands/meta.ts
6097
- import { promises as fsp2 } from "fs";
6686
+ import { promises as fsp3 } from "fs";
6098
6687
  import {
6099
6688
  HcmClient as HcmClient15,
6100
- formatObject as formatObject15,
6689
+ formatObject as formatObject16,
6101
6690
  fromAxiosError as fromAxiosError15,
6102
6691
  listTenantMeta,
6103
6692
  getTenantMeta,
6104
6693
  saveTenantMeta,
6105
6694
  deleteTenantMeta,
6106
- CliError as CliError18,
6107
- CliErrorCode as CliErrorCode17
6695
+ CliError as CliError20,
6696
+ CliErrorCode as CliErrorCode19
6108
6697
  } from "@hcmai/sdk";
6109
6698
  init_exit();
6110
6699
  init_auth_guard();
@@ -6134,27 +6723,27 @@ async function metaListCommand(args) {
6134
6723
  const fmt = args.output ?? "json";
6135
6724
  if (fmt !== "json") process.stdout.write(`\u{1F4C4} ${items.length} \u4EFD${total ? ` / \u5171 ${total}` : ""}
6136
6725
  `);
6137
- process.stdout.write(formatObject15(items, { format: fmt }) + "\n");
6726
+ process.stdout.write(formatObject16(items, { format: fmt }) + "\n");
6138
6727
  process.exit(0);
6139
6728
  } catch (e) {
6140
6729
  fail4(e, args);
6141
6730
  }
6142
6731
  }
6143
- async function metaGetCommand(path7, args) {
6732
+ async function metaGetCommand(path9, args) {
6144
6733
  try {
6145
6734
  const c = await client2(args);
6146
- const content = await getTenantMeta(c.raw(), path7);
6735
+ const content = await getTenantMeta(c.raw(), path9);
6147
6736
  process.stdout.write(content.endsWith("\n") ? content : content + "\n");
6148
6737
  process.exit(0);
6149
6738
  } catch (e) {
6150
6739
  fail4(e, args);
6151
6740
  }
6152
6741
  }
6153
- async function metaSetCommand(path7, args) {
6742
+ async function metaSetCommand(path9, args) {
6154
6743
  try {
6155
6744
  if (!args.file) {
6156
- throw new CliError18({
6157
- code: CliErrorCode17.MISSING_FLAG,
6745
+ throw new CliError20({
6746
+ code: CliErrorCode19.MISSING_FLAG,
6158
6747
  message: "--file <path> \u5FC5\u586B\uFF08\u4ECE\u6587\u4EF6\u8BFB\u53D6 meta \u539F\u6587\uFF1B\u7528 - \u8868\u793A stdin\uFF09"
6159
6748
  });
6160
6749
  }
@@ -6164,10 +6753,10 @@ async function metaSetCommand(path7, args) {
6164
6753
  process.stdin.on("data", (d) => buf += d);
6165
6754
  process.stdin.on("end", () => resolve3(buf));
6166
6755
  process.stdin.on("error", reject);
6167
- }) : await fsp2.readFile(args.file, "utf8");
6756
+ }) : await fsp3.readFile(args.file, "utf8");
6168
6757
  if (args.dryRun) {
6169
6758
  process.stdout.write(
6170
- `[dry-run] \u5C06\u5199\u5165 ${path7}\uFF08${Buffer.byteLength(content)} B\uFF09\u2014\u2014\u672A\u5B9E\u9645\u5199\u5165
6759
+ `[dry-run] \u5C06\u5199\u5165 ${path9}\uFF08${Buffer.byteLength(content)} B\uFF09\u2014\u2014\u672A\u5B9E\u9645\u5199\u5165
6171
6760
  ---
6172
6761
  ${content}
6173
6762
  `
@@ -6175,35 +6764,35 @@ ${content}
6175
6764
  process.exit(0);
6176
6765
  }
6177
6766
  const c = await client2(args);
6178
- const result2 = await saveTenantMeta(c.raw(), path7, content);
6767
+ const result2 = await saveTenantMeta(c.raw(), path9, content);
6179
6768
  const fmt = args.output ?? "json";
6180
6769
  if (fmt !== "json") {
6181
- process.stdout.write(`\u2705 \u5DF2\u5199\u5165 ${path7}
6770
+ process.stdout.write(`\u2705 \u5DF2\u5199\u5165 ${path9}
6182
6771
  \u8BB0\u5F97\u6E05\u7F13\u5B58\uFF1Ahcm cache clear-meta <Model>
6183
6772
  `);
6184
6773
  }
6185
- process.stdout.write(formatObject15(result2, { format: fmt }) + "\n");
6774
+ process.stdout.write(formatObject16(result2, { format: fmt }) + "\n");
6186
6775
  process.exit(0);
6187
6776
  } catch (e) {
6188
6777
  if (e?.code === "ENOENT") exitWithError(new Error(`\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${args.file}`));
6189
6778
  fail4(e, args);
6190
6779
  }
6191
6780
  }
6192
- async function metaDeleteCommand(path7, args) {
6781
+ async function metaDeleteCommand(path9, args) {
6193
6782
  try {
6194
6783
  if (!args.yes) {
6195
- const ok = await promptConfirm(`\u5C06\u5220\u9664\u5143\u6570\u636E ${path7}\uFF0C\u6B64\u64CD\u4F5C\u4E0D\u53EF\u9006\u3002\u7EE7\u7EED\uFF1F`);
6784
+ const ok = await promptConfirm(`\u5C06\u5220\u9664\u5143\u6570\u636E ${path9}\uFF0C\u6B64\u64CD\u4F5C\u4E0D\u53EF\u9006\u3002\u7EE7\u7EED\uFF1F`);
6196
6785
  if (!ok) {
6197
6786
  process.stderr.write("\u5DF2\u53D6\u6D88\n");
6198
6787
  process.exit(1);
6199
6788
  }
6200
6789
  }
6201
6790
  const c = await client2(args);
6202
- const result2 = await deleteTenantMeta(c.raw(), path7);
6791
+ const result2 = await deleteTenantMeta(c.raw(), path9);
6203
6792
  const fmt = args.output ?? "json";
6204
- if (fmt !== "json") process.stdout.write(`\u{1F5D1}\uFE0F \u5DF2\u5220\u9664 ${path7}
6793
+ if (fmt !== "json") process.stdout.write(`\u{1F5D1}\uFE0F \u5DF2\u5220\u9664 ${path9}
6205
6794
  `);
6206
- process.stdout.write(formatObject15(result2, { format: fmt }) + "\n");
6795
+ process.stdout.write(formatObject16(result2, { format: fmt }) + "\n");
6207
6796
  process.exit(0);
6208
6797
  } catch (e) {
6209
6798
  fail4(e, args);
@@ -6215,14 +6804,14 @@ init_exit();
6215
6804
  init_auth_guard();
6216
6805
  import * as crypto from "crypto";
6217
6806
  import * as fs7 from "fs/promises";
6218
- import * as path5 from "path";
6807
+ import * as path7 from "path";
6219
6808
  import {
6220
6809
  buildMiniPreviewTargets,
6221
6810
  buildMiniVerifyAgentReport,
6222
6811
  createWorkspaceFile,
6223
6812
  deleteWorkspaceFile,
6224
6813
  formatMiniVerifyReport,
6225
- formatObject as formatObject16,
6814
+ formatObject as formatObject17,
6226
6815
  formatRows as formatRows5,
6227
6816
  getMiniStatus,
6228
6817
  HcmClient as HcmClient16,
@@ -6432,7 +7021,7 @@ async function workspacePullCommand(args) {
6432
7021
  http: client3.raw(),
6433
7022
  appCode,
6434
7023
  workspaceKey,
6435
- targetDir: path5.join(rootDir, MINI_APPS_DIR, appCode),
7024
+ targetDir: path7.join(rootDir, MINI_APPS_DIR, appCode),
6436
7025
  tenantId: client3.tenantId,
6437
7026
  endpoint: client3.endpoint,
6438
7027
  profile: args.profile ?? client3.profile,
@@ -6447,7 +7036,7 @@ async function workspacePullCommand(args) {
6447
7036
  const rawRemoteByLocalPath = /* @__PURE__ */ new Map();
6448
7037
  for (const file of rawFiles) {
6449
7038
  const content = await loadWorkspaceFileContent(client3.raw(), file.id);
6450
- const target = path5.join(rootDir, content.relativePath);
7039
+ const target = path7.join(rootDir, content.relativePath);
6451
7040
  await writeTextFile(target, content.content, !!args.force);
6452
7041
  pulledRawFiles.push(content.relativePath);
6453
7042
  rawRemoteByLocalPath.set(content.relativePath, file);
@@ -6497,7 +7086,7 @@ async function workspaceAddMiniCommand(appCode, args) {
6497
7086
  const result2 = await initMiniAppProject({
6498
7087
  appCode,
6499
7088
  workspaceKey: context.workspaceKey,
6500
- targetDir: path5.join(rootDir, MINI_APPS_DIR, appCode),
7089
+ targetDir: path7.join(rootDir, MINI_APPS_DIR, appCode),
6501
7090
  name: args.name,
6502
7091
  defaultSurface: parseSurface(args.surface),
6503
7092
  templateKind,
@@ -6551,7 +7140,7 @@ async function workspaceStatusCommand(args) {
6551
7140
  }
6552
7141
  if (args.output === "json" || args.output === "yaml") {
6553
7142
  process.stdout.write(
6554
- formatObject16({ rootDir, miniApps: rows }, { format: args.output }) + "\n"
7143
+ formatObject17({ rootDir, miniApps: rows }, { format: args.output }) + "\n"
6555
7144
  );
6556
7145
  } else {
6557
7146
  process.stdout.write(formatRows5(rows, { format: "table" }) + "\n");
@@ -6627,7 +7216,7 @@ async function workspacePreviewCommand(args) {
6627
7216
  );
6628
7217
  }
6629
7218
  if (args.output === "json" || args.output === "yaml") {
6630
- process.stdout.write(formatObject16(rows, { format: args.output }) + "\n");
7219
+ process.stdout.write(formatObject17(rows, { format: args.output }) + "\n");
6631
7220
  } else {
6632
7221
  process.stdout.write(formatRows5(rows, { format: "table" }) + "\n");
6633
7222
  }
@@ -6738,7 +7327,7 @@ function removedMiniCommand() {
6738
7327
  );
6739
7328
  }
6740
7329
  function resolveRootDir(dir) {
6741
- return path5.resolve(dir ?? ".");
7330
+ return path7.resolve(dir ?? ".");
6742
7331
  }
6743
7332
  function buildWorkspaceContext(args) {
6744
7333
  return {
@@ -6754,7 +7343,7 @@ function buildWorkspaceContext(args) {
6754
7343
  async function readWorkspaceContext(rootDir) {
6755
7344
  try {
6756
7345
  const parsed = JSON.parse(
6757
- await fs7.readFile(path5.join(rootDir, WORKSPACE_CONTEXT_FILE), "utf-8")
7346
+ await fs7.readFile(path7.join(rootDir, WORKSPACE_CONTEXT_FILE), "utf-8")
6758
7347
  );
6759
7348
  if (parsed.kind !== WORKSPACE_CONTEXT_KIND || parsed.version !== WORKSPACE_CONTEXT_VERSION) {
6760
7349
  throw new Error(`${WORKSPACE_CONTEXT_FILE} is not an HCM workspace context`);
@@ -6784,7 +7373,7 @@ async function requireWorkspaceContext(rootDir) {
6784
7373
  }
6785
7374
  async function writeWorkspaceContext(rootDir, context) {
6786
7375
  await fs7.writeFile(
6787
- path5.join(rootDir, WORKSPACE_CONTEXT_FILE),
7376
+ path7.join(rootDir, WORKSPACE_CONTEXT_FILE),
6788
7377
  JSON.stringify(context, null, 2) + "\n"
6789
7378
  );
6790
7379
  }
@@ -6795,13 +7384,13 @@ async function writeTextFile(file, content, force) {
6795
7384
  } catch (e) {
6796
7385
  if (e.code !== "ENOENT") throw e;
6797
7386
  }
6798
- await fs7.mkdir(path5.dirname(file), { recursive: true });
7387
+ await fs7.mkdir(path7.dirname(file), { recursive: true });
6799
7388
  await fs7.writeFile(file, content);
6800
7389
  }
6801
7390
  async function readWorkspaceRawManifest(rootDir, context) {
6802
7391
  try {
6803
7392
  const parsed = JSON.parse(
6804
- await fs7.readFile(path5.join(rootDir, WORKSPACE_STATE_DIR, WORKSPACE_PULL_MANIFEST_FILE), "utf-8")
7393
+ await fs7.readFile(path7.join(rootDir, WORKSPACE_STATE_DIR, WORKSPACE_PULL_MANIFEST_FILE), "utf-8")
6805
7394
  );
6806
7395
  if (parsed.version !== WORKSPACE_CONTEXT_VERSION || parsed.workspaceKey !== context.workspaceKey) {
6807
7396
  throw new Error(`${WORKSPACE_PULL_MANIFEST_FILE} does not match workspace ${context.workspaceKey}`);
@@ -6819,7 +7408,7 @@ async function readWorkspaceRawManifest(rootDir, context) {
6819
7408
  }
6820
7409
  }
6821
7410
  async function writeWorkspaceRawState(rootDir, context, files, remoteByLocalPath) {
6822
- const stateDir = path5.join(rootDir, WORKSPACE_STATE_DIR);
7411
+ const stateDir = path7.join(rootDir, WORKSPACE_STATE_DIR);
6823
7412
  await fs7.mkdir(stateDir, { recursive: true });
6824
7413
  const snapshots = files.map((file) => ({
6825
7414
  localPath: file.localPath,
@@ -6830,7 +7419,7 @@ async function writeWorkspaceRawState(rootDir, context, files, remoteByLocalPath
6830
7419
  lastModified: remoteByLocalPath.get(file.localPath)?.lastModified
6831
7420
  }));
6832
7421
  await fs7.writeFile(
6833
- path5.join(stateDir, WORKSPACE_PULL_MANIFEST_FILE),
7422
+ path7.join(stateDir, WORKSPACE_PULL_MANIFEST_FILE),
6834
7423
  JSON.stringify(
6835
7424
  {
6836
7425
  version: WORKSPACE_CONTEXT_VERSION,
@@ -6852,7 +7441,7 @@ async function readWorkspaceRawLocalFiles(rootDir) {
6852
7441
  return files;
6853
7442
  }
6854
7443
  async function walkWorkspaceRawFiles(rootDir, relativeDir, files) {
6855
- const absoluteDir = path5.join(rootDir, relativeDir);
7444
+ const absoluteDir = path7.join(rootDir, relativeDir);
6856
7445
  let entries;
6857
7446
  try {
6858
7447
  entries = await fs7.readdir(absoluteDir, { withFileTypes: true });
@@ -6863,8 +7452,8 @@ async function walkWorkspaceRawFiles(rootDir, relativeDir, files) {
6863
7452
  for (const entry of entries) {
6864
7453
  if (entry.isDirectory() && RAW_WORKSPACE_EXCLUDED_DIRS.has(entry.name)) continue;
6865
7454
  if (entry.isFile() && RAW_WORKSPACE_EXCLUDED_FILES.has(entry.name)) continue;
6866
- const localPath = normalizeRelativePath(path5.posix.join(toPosix(relativeDir), entry.name));
6867
- const absolutePath = path5.join(rootDir, localPath);
7455
+ const localPath = normalizeRelativePath(path7.posix.join(toPosix(relativeDir), entry.name));
7456
+ const absolutePath = path7.join(rootDir, localPath);
6868
7457
  if (entry.isDirectory()) {
6869
7458
  await walkWorkspaceRawFiles(rootDir, localPath, files);
6870
7459
  continue;
@@ -6875,7 +7464,7 @@ async function walkWorkspaceRawFiles(rootDir, relativeDir, files) {
6875
7464
  localPath,
6876
7465
  absolutePath,
6877
7466
  content,
6878
- sha256: sha2564(content),
7467
+ sha256: sha2565(content),
6879
7468
  size: Buffer.byteLength(content, "utf-8")
6880
7469
  });
6881
7470
  }
@@ -6942,7 +7531,7 @@ function buildWorkspaceRawPushPlan(manifest2, localFiles, remoteFiles) {
6942
7531
  for (const entry of status) {
6943
7532
  const remote = remoteByLocal.get(entry.localPath);
6944
7533
  const base = baseByLocal.get(entry.localPath);
6945
- const remoteSha = remote ? sha2564(remote.content) : void 0;
7534
+ const remoteSha = remote ? sha2565(remote.content) : void 0;
6946
7535
  if (entry.status === "added") {
6947
7536
  if (remote) {
6948
7537
  conflicts.push(workspaceRawConflict(entry, "remote file already exists but was not in local snapshot"));
@@ -7044,7 +7633,7 @@ function workspaceRawConflict(entry, reason) {
7044
7633
  };
7045
7634
  }
7046
7635
  async function discoverMiniApps(rootDir) {
7047
- const appsRoot = path5.join(rootDir, MINI_APPS_DIR);
7636
+ const appsRoot = path7.join(rootDir, MINI_APPS_DIR);
7048
7637
  let entries;
7049
7638
  try {
7050
7639
  entries = await fs7.readdir(appsRoot, { withFileTypes: true });
@@ -7052,7 +7641,7 @@ async function discoverMiniApps(rootDir) {
7052
7641
  if (e.code === "ENOENT") return [];
7053
7642
  throw e;
7054
7643
  }
7055
- return entries.filter((entry) => entry.isDirectory()).map((entry) => ({ appCode: entry.name, dir: path5.join(appsRoot, entry.name) })).sort((a, b) => a.appCode.localeCompare(b.appCode));
7644
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => ({ appCode: entry.name, dir: path7.join(appsRoot, entry.name) })).sort((a, b) => a.appCode.localeCompare(b.appCode));
7056
7645
  }
7057
7646
  function detectRemoteMiniApps(files) {
7058
7647
  const appCodes = /* @__PURE__ */ new Set();
@@ -7205,9 +7794,9 @@ function normalizeRelativePath(value) {
7205
7794
  return normalized;
7206
7795
  }
7207
7796
  function toPosix(value) {
7208
- return value.split(path5.sep).join("/");
7797
+ return value.split(path7.sep).join("/");
7209
7798
  }
7210
- function sha2564(content) {
7799
+ function sha2565(content) {
7211
7800
  return crypto.createHash("sha256").update(content, "utf-8").digest("hex");
7212
7801
  }
7213
7802
  function stringRequired(value, field) {
@@ -7233,7 +7822,7 @@ function optionalText(value) {
7233
7822
  }
7234
7823
  function writeWorkspaceListResult(rows, format, total) {
7235
7824
  if (format !== "table") {
7236
- process.stdout.write(formatObject16({ rows, total }, { format }) + "\n");
7825
+ process.stdout.write(formatObject17({ rows, total }, { format }) + "\n");
7237
7826
  return;
7238
7827
  }
7239
7828
  process.stdout.write(formatRows5(toWorkspaceListRows(rows), { format: "table" }) + "\n");
@@ -7244,7 +7833,7 @@ function writeWorkspaceListResult(rows, format, total) {
7244
7833
  }
7245
7834
  function writeWorkspaceActiveResult(view, format) {
7246
7835
  if (format !== "table") {
7247
- process.stdout.write(formatObject16(view, { format }) + "\n");
7836
+ process.stdout.write(formatObject17(view, { format }) + "\n");
7248
7837
  return;
7249
7838
  }
7250
7839
  const rows = [
@@ -7262,7 +7851,7 @@ function writeWorkspaceActiveResult(view, format) {
7262
7851
  }
7263
7852
  function writeWorkspaceBindResult(context, rootDir, format) {
7264
7853
  if (format !== "table") {
7265
- process.stdout.write(formatObject16({ ...context, rootDir }, { format }) + "\n");
7854
+ process.stdout.write(formatObject17({ ...context, rootDir }, { format }) + "\n");
7266
7855
  return;
7267
7856
  }
7268
7857
  process.stdout.write(
@@ -7276,7 +7865,7 @@ function writeWorkspaceBindResult(context, rootDir, format) {
7276
7865
  }
7277
7866
  function writeWorkspaceCreateResult(result2, format) {
7278
7867
  if (format !== "table") {
7279
- process.stdout.write(formatObject16(result2, { format }) + "\n");
7868
+ process.stdout.write(formatObject17(result2, { format }) + "\n");
7280
7869
  return;
7281
7870
  }
7282
7871
  process.stdout.write(
@@ -7292,7 +7881,7 @@ function writeWorkspaceCreateResult(result2, format) {
7292
7881
  }
7293
7882
  function writeWorkspacePullResult(result2, format) {
7294
7883
  if (format !== "table") {
7295
- process.stdout.write(formatObject16(result2, { format }) + "\n");
7884
+ process.stdout.write(formatObject17(result2, { format }) + "\n");
7296
7885
  return;
7297
7886
  }
7298
7887
  const lines = [
@@ -7310,7 +7899,7 @@ function writeWorkspacePullResult(result2, format) {
7310
7899
  }
7311
7900
  function writeWorkspaceAddMiniResult(result2, rootDir, format) {
7312
7901
  if (format !== "table") {
7313
- process.stdout.write(formatObject16({ ...result2, workspaceRoot: rootDir }, { format }) + "\n");
7902
+ process.stdout.write(formatObject17({ ...result2, workspaceRoot: rootDir }, { format }) + "\n");
7314
7903
  return;
7315
7904
  }
7316
7905
  process.stdout.write(
@@ -7326,7 +7915,7 @@ function writeWorkspaceAddMiniResult(result2, rootDir, format) {
7326
7915
  function writeWorkspaceValidateResult(results, format) {
7327
7916
  if (format !== "table") {
7328
7917
  process.stdout.write(
7329
- formatObject16(
7918
+ formatObject17(
7330
7919
  results.map((item) => ({ artifact: `mini:${item.app.appCode}`, ...item.result })),
7331
7920
  { format }
7332
7921
  ) + "\n"
@@ -7354,7 +7943,7 @@ mini:${item.app.appCode}
7354
7943
  function writeWorkspacePushResult(rawResult, results, format) {
7355
7944
  if (format !== "table") {
7356
7945
  process.stdout.write(
7357
- formatObject16(
7946
+ formatObject17(
7358
7947
  {
7359
7948
  workspaceFiles: { artifact: "workspace", ...rawResult },
7360
7949
  miniApps: results.map((item) => ({ artifact: `mini:${item.app.appCode}`, ...item.result }))
@@ -7410,7 +7999,7 @@ function writeWorkspaceVerifyResult(context, rootDir, raw, reports, format) {
7410
7999
  const ok = rawOk && reports.every((item) => item.report.ok);
7411
8000
  if (format === "json") {
7412
8001
  process.stdout.write(
7413
- formatObject16(
8002
+ formatObject17(
7414
8003
  {
7415
8004
  ok,
7416
8005
  workspaceKey: context.workspaceKey,
@@ -7437,7 +8026,7 @@ function writeWorkspaceVerifyResult(context, rootDir, raw, reports, format) {
7437
8026
  }
7438
8027
  if (format !== "table") {
7439
8028
  process.stdout.write(
7440
- formatObject16(
8029
+ formatObject17(
7441
8030
  {
7442
8031
  ok,
7443
8032
  workspaceKey: context.workspaceKey,
@@ -7504,8 +8093,8 @@ import {
7504
8093
  deleteIdentity as deleteIdentity2,
7505
8094
  loadGlobalConfig as loadGlobalConfig8,
7506
8095
  TokenStore as TokenStore3,
7507
- CliError as CliError19,
7508
- CliErrorCode as CliErrorCode18
8096
+ CliError as CliError21,
8097
+ CliErrorCode as CliErrorCode20
7509
8098
  } from "@hcmai/sdk";
7510
8099
  async function identityList(args) {
7511
8100
  try {
@@ -7533,8 +8122,8 @@ async function identityUse(name) {
7533
8122
  try {
7534
8123
  const meta2 = await loadIdentity4(name);
7535
8124
  const env2 = await loadEnv7(meta2.env).catch(() => {
7536
- throw new CliError19({
7537
- code: CliErrorCode18.IDENTITY_NOT_IN_ENV,
8125
+ throw new CliError21({
8126
+ code: CliErrorCode20.IDENTITY_NOT_IN_ENV,
7538
8127
  message: `identity '${name}' references env '${meta2.env}' which no longer exists. Re-create the env, or remove this orphan: hcm identity remove ${name}`
7539
8128
  });
7540
8129
  });
@@ -7568,9 +8157,15 @@ async function identityRemove(name) {
7568
8157
  }
7569
8158
  }
7570
8159
 
8160
+ // src/commands/delivery-action-policy.ts
8161
+ init_auth_guard();
8162
+ import {
8163
+ HcmClient as HcmClient17,
8164
+ formatObject as formatObject18
8165
+ } from "@hcmai/sdk";
8166
+
7571
8167
  // src/commands/delivery.ts
7572
- import { createHash as createHash5 } from "crypto";
7573
- import { formatObject as formatObject17 } from "@hcmai/sdk";
8168
+ import { createHash as createHash6 } from "crypto";
7574
8169
  var APPROVAL_BYPASS_FLAGS = /* @__PURE__ */ new Set(["-y", "--yes", "--force", "--auto-approve"]);
7575
8170
  var CREDENTIAL_FLAGS = /* @__PURE__ */ new Set([
7576
8171
  "--password",
@@ -7587,11 +8182,12 @@ var GUARDED_EXECUTOR_REASON_CODES = /* @__PURE__ */ new Set([
7587
8182
  "record-update",
7588
8183
  "cache-mutation",
7589
8184
  "setting-write",
7590
- "credential-reset"
8185
+ "credential-reset",
8186
+ "action-write"
7591
8187
  ]);
7592
- function assessDeliveryCommand(inputArgv) {
8188
+ function assessDeliveryCommand(inputArgv, options = {}) {
7593
8189
  const argv = inputArgv[0] === "--" ? inputArgv.slice(1) : [...inputArgv];
7594
- const commandSha256 = sha2565(JSON.stringify(argv));
8190
+ const commandSha256 = sha2566(JSON.stringify(argv));
7595
8191
  const name = argv[0] ?? "";
7596
8192
  const subcommand = argv[1] && !argv[1].startsWith("-") ? argv[1] : void 0;
7597
8193
  const envAlias = flagValue(argv, "--env");
@@ -7599,8 +8195,8 @@ function assessDeliveryCommand(inputArgv) {
7599
8195
  const sensitiveFlags = [
7600
8196
  ...new Set([...PAYLOAD_FLAGS, ...CREDENTIAL_FLAGS].filter((flag) => hasFlag(argv, flag)))
7601
8197
  ];
7602
- const target = summarizeTarget(argv);
7603
- let classification = classify(argv);
8198
+ const target = summarizeTarget(argv, options.actionResolution);
8199
+ let classification = classify(argv, options.actionResolution);
7604
8200
  const invalidPayload = payloadError(argv);
7605
8201
  if (invalidPayload) {
7606
8202
  classification = forbidden("invalid-input", "JSON payload \u65E0\u6548\uFF0C\u4E0D\u80FD\u8FDB\u5165\u4EFB\u4F55\u6267\u884C\u8DEF\u5F84\u3002");
@@ -7621,8 +8217,8 @@ function assessDeliveryCommand(inputArgv) {
7621
8217
  const allowed = classification.risk === "R0" || classification.risk === "R1";
7622
8218
  return {
7623
8219
  schemaVersion: 1,
7624
- contractVersion: "2026-08-28",
7625
- assessmentId: sha2565(`2026-08-28
8220
+ contractVersion: "2026-08-29",
8221
+ assessmentId: sha2566(`2026-08-29
7626
8222
  ${commandSha256}`).slice(0, 24),
7627
8223
  commandSha256,
7628
8224
  command: { name: name || "(empty)", ...subcommand ? { subcommand } : {} },
@@ -7642,11 +8238,7 @@ ${commandSha256}`).slice(0, 24),
7642
8238
  }
7643
8239
  };
7644
8240
  }
7645
- function deliveryAssessCommand(argv, args) {
7646
- const assessment = assessDeliveryCommand(argv);
7647
- process.stdout.write(formatObject17(assessment, { format: args.output ?? "json" }) + "\n");
7648
- }
7649
- function classify(argv) {
8241
+ function classify(argv, actionResolution) {
7650
8242
  const name = argv[0] ?? "";
7651
8243
  const subcommand = argv[1] ?? "";
7652
8244
  if (argv.some((arg) => APPROVAL_BYPASS_FLAGS.has(flagName(arg)))) {
@@ -7747,9 +8339,15 @@ function classify(argv) {
7747
8339
  if (name === "upload") return guarded("tenant-write", "document-upload");
7748
8340
  if (name === "download") return direct("R1", "managed-local-write", "document-download");
7749
8341
  if (name === "action") {
8342
+ if (actionResolution?.status === "resolved") {
8343
+ return classifyAction(actionResolution.policy);
8344
+ }
8345
+ if (actionResolution?.status === "failed") {
8346
+ return forbidden(actionResolution.reasonCode, actionResolution.reason);
8347
+ }
7750
8348
  return forbidden(
7751
8349
  "action-effect-unclassified",
7752
- "Action \u5C1A\u65E0\u7EDF\u4E00 destructive/publish \u8BED\u4E49\uFF0C\u9996\u7248\u4E0D\u80FD\u6309\u540D\u79F0\u731C\u6D4B\u540E\u653E\u884C\u3002"
8350
+ "\u5C1A\u672A\u8BFB\u53D6 Core Action \u98CE\u63A7\u58F0\u660E\uFF0C\u4E0D\u80FD\u6309\u540D\u79F0\u731C\u6D4B\u540E\u653E\u884C\u3002"
7753
8351
  );
7754
8352
  }
7755
8353
  if (name === "delete" || name === "meta" && subcommand === "delete") {
@@ -7766,14 +8364,19 @@ function classify(argv) {
7766
8364
  }
7767
8365
  return forbidden("unknown-command", "\u672A\u77E5\u547D\u4EE4\u6309\u6700\u9AD8\u98CE\u9669\u5173\u95ED\u3002");
7768
8366
  }
7769
- function summarizeTarget(argv) {
8367
+ function summarizeTarget(argv, actionResolution) {
7770
8368
  const name = argv[0] ?? "";
7771
8369
  const subcommand = argv[1] ?? "";
7772
8370
  const target = {};
7773
8371
  if (["query", "describe", "create", "update", "delete"].includes(name) && subcommand) {
7774
8372
  target.model = subcommand;
7775
8373
  }
7776
- if (name === "action" && subcommand) target.action = subcommand;
8374
+ if (name === "action" && subcommand) {
8375
+ target.action = subcommand;
8376
+ if (actionResolution?.status === "resolved") {
8377
+ target.actionPolicy = { ...actionResolution.policy };
8378
+ }
8379
+ }
7777
8380
  if (name === "skills" && argv[2] && !argv[2].startsWith("-")) target.skill = argv[2];
7778
8381
  if (name === "meta" && argv[2] && !argv[2].startsWith("-")) target.path = argv[2];
7779
8382
  if (name === "cache" && argv[2] && !argv[2].startsWith("-")) {
@@ -7787,17 +8390,17 @@ function summarizeTarget(argv) {
7787
8390
  }
7788
8391
  const id = flagValue(argv, "--id");
7789
8392
  if (name === "user" && subcommand === "reset-password") {
7790
- if (id) target.userIdSha256 = sha2565(id);
8393
+ if (id) target.userIdSha256 = sha2566(id);
7791
8394
  const username = flagValue(argv, "--username");
7792
- if (username) target.usernameSha256 = sha2565(username);
8395
+ if (username) target.usernameSha256 = sha2566(username);
7793
8396
  target.forceChangeOnNextLogin = !hasFlag(argv, "--no-force-change");
7794
8397
  } else if (id) {
7795
- target.recordIdSha256 = sha2565(id);
8398
+ target.recordIdSha256 = sha2566(id);
7796
8399
  }
7797
8400
  for (const flag of PAYLOAD_FLAGS) {
7798
8401
  const raw = flagValue(argv, flag);
7799
8402
  if (!raw) continue;
7800
- target.payloadSha256 = sha2565(raw);
8403
+ target.payloadSha256 = sha2566(raw);
7801
8404
  try {
7802
8405
  const parsed = JSON.parse(raw);
7803
8406
  if (isPlainObject(parsed)) target.fieldNames = Object.keys(parsed).sort();
@@ -7837,6 +8440,18 @@ function guarded(effect, reasonCode) {
7837
8440
  reason: "\u666E\u901A\u526F\u4F5C\u7528\u64CD\u4F5C\uFF1B\u53EA\u5141\u8BB8\u5728 controlled \u9879\u76EE\u4E2D\u901A\u8FC7 delivery prepare + delivery execute \u5355\u6B21\u53D7\u63A7\u6267\u884C\u3002"
7838
8441
  };
7839
8442
  }
8443
+ function classifyAction(policy) {
8444
+ if (policy.readOnly) {
8445
+ return {
8446
+ risk: "R1",
8447
+ execution: "direct",
8448
+ effect: "remote-read",
8449
+ reasonCode: "action-read-only",
8450
+ reason: "Core \u58F0\u660E\u8BE5 Action \u4E3A\u53EA\u8BFB\uFF0C\u4E0E Moirai \u7684\u53EA\u8BFB Action \u8DEF\u5F84\u4E00\u81F4\uFF0C\u53EF\u76F4\u63A5\u6267\u884C\u3002"
8451
+ };
8452
+ }
8453
+ return guarded("tenant-write", "action-write");
8454
+ }
7840
8455
  function forbidden(reasonCode, reason) {
7841
8456
  return { risk: "R3", execution: "forbidden", effect: reasonCode, reasonCode, reason };
7842
8457
  }
@@ -7882,19 +8497,159 @@ function valuesAfterFlag(argv, flag) {
7882
8497
  }
7883
8498
  return values;
7884
8499
  }
7885
- function sha2565(value) {
7886
- return createHash5("sha256").update(value).digest("hex");
8500
+ function sha2566(value) {
8501
+ return createHash6("sha256").update(value).digest("hex");
7887
8502
  }
7888
8503
  function isPlainObject(value) {
7889
8504
  return typeof value === "object" && value !== null && !Array.isArray(value);
7890
8505
  }
7891
8506
 
8507
+ // src/commands/delivery-action-policy.ts
8508
+ async function assessEffectiveDeliveryCommand(inputArgv, dependencies = {}) {
8509
+ const local = assessDeliveryCommand(inputArgv);
8510
+ if (local.reasonCode !== "action-effect-unclassified") return local;
8511
+ const request = parseActionRequest(inputArgv);
8512
+ if ("status" in request) {
8513
+ return assessDeliveryCommand(inputArgv, { actionResolution: request });
8514
+ }
8515
+ const resolution = await (dependencies.resolveAction ?? resolveCoreAction)(request);
8516
+ return assessDeliveryCommand(inputArgv, { actionResolution: resolution });
8517
+ }
8518
+ async function deliveryAssessCommand(argv, args) {
8519
+ const assessment = await assessEffectiveDeliveryCommand(argv);
8520
+ process.stdout.write(formatObject18(assessment, { format: args.output ?? "json" }) + "\n");
8521
+ }
8522
+ async function resolveCoreAction(request) {
8523
+ try {
8524
+ const auth = await getActiveAuthContextFromCli({
8525
+ env: request.env,
8526
+ as: request.identity,
8527
+ profile: request.profile
8528
+ });
8529
+ const description = await HcmClient17.fromAuthContext(auth).describe(request.model);
8530
+ const matches = description.actions.filter((action2) => matchesRequest(action2, request));
8531
+ if (matches.length === 0) {
8532
+ return failed(
8533
+ "action-metadata-not-found",
8534
+ "Core \u5143\u6570\u636E\u4E2D\u6CA1\u6709\u4E0E\u672C\u6B21 method/scope \u7CBE\u786E\u5339\u914D\u7684 Action\uFF0C\u62D2\u7EDD\u6267\u884C\u3002"
8535
+ );
8536
+ }
8537
+ if (matches.length > 1) {
8538
+ return failed(
8539
+ "action-metadata-ambiguous",
8540
+ "Core \u5143\u6570\u636E\u5B58\u5728\u591A\u4E2A\u4E0E\u672C\u6B21 method/scope \u5339\u914D\u7684 Action\uFF0C\u65E0\u6CD5\u552F\u4E00\u5224\u5B9A\uFF0C\u62D2\u7EDD\u6267\u884C\u3002"
8541
+ );
8542
+ }
8543
+ const action = matches[0];
8544
+ if (typeof action.readOnly !== "boolean") {
8545
+ return failed(
8546
+ "action-readonly-unclassified",
8547
+ "Core \u672A\u8FD4\u56DE Action \u7684 readOnly \u58F0\u660E\uFF0C\u6309\u5B89\u5168\u9ED8\u8BA4\u62D2\u7EDD\u6267\u884C\u3002"
8548
+ );
8549
+ }
8550
+ return {
8551
+ status: "resolved",
8552
+ policy: {
8553
+ scope: action.scope,
8554
+ httpMethod: action.httpMethod.toUpperCase(),
8555
+ readOnly: action.readOnly,
8556
+ ...action.source ? { source: action.source } : {}
8557
+ }
8558
+ };
8559
+ } catch {
8560
+ return failed(
8561
+ "action-metadata-unavailable",
8562
+ "\u65E0\u6CD5\u8BFB\u53D6 Core Action \u5143\u6570\u636E\uFF0C\u6309\u5B89\u5168\u9ED8\u8BA4\u62D2\u7EDD\u6267\u884C\u3002"
8563
+ );
8564
+ }
8565
+ }
8566
+ function matchesRequest(action, request) {
8567
+ return action.name === request.action && action.httpMethod?.toUpperCase() === request.httpMethod && action.scope?.toLowerCase() === request.scope;
8568
+ }
8569
+ function parseActionRequest(inputArgv) {
8570
+ const argv = inputArgv[0] === "--" ? inputArgv.slice(1) : [...inputArgv];
8571
+ const spec = argv[1] ?? "";
8572
+ const separator = spec.indexOf(".");
8573
+ if (separator <= 0 || separator === spec.length - 1) {
8574
+ return failed("invalid-action-spec", "Action \u5FC5\u987B\u4F7F\u7528 <Model>.<Action> \u683C\u5F0F\u3002");
8575
+ }
8576
+ const httpMethod = (flagValue2(argv, "--method") ?? "POST").toUpperCase();
8577
+ if (!["GET", "POST", "PUT", "DELETE"].includes(httpMethod)) {
8578
+ return failed("invalid-action-method", "Action method \u5FC5\u987B\u662F GET\u3001POST\u3001PUT \u6216 DELETE\u3002");
8579
+ }
8580
+ const explicitScope = flagValue2(argv, "--scope");
8581
+ const scope = explicitScope ?? (flagValue2(argv, "--id") ? "object" : "class");
8582
+ if (scope !== "class" && scope !== "object") {
8583
+ return failed("invalid-action-scope", "Action scope \u5FC5\u987B\u662F class \u6216 object\u3002");
8584
+ }
8585
+ return {
8586
+ model: spec.slice(0, separator),
8587
+ action: spec.slice(separator + 1),
8588
+ httpMethod,
8589
+ scope,
8590
+ env: flagValue2(argv, "--env"),
8591
+ identity: flagValue2(argv, "--as"),
8592
+ profile: flagValue2(argv, "--profile")
8593
+ };
8594
+ }
8595
+ function failed(reasonCode, reason) {
8596
+ return { status: "failed", reasonCode, reason };
8597
+ }
8598
+ function flagValue2(argv, flag) {
8599
+ const equals = argv.find((arg) => arg.startsWith(`${flag}=`));
8600
+ if (equals) return equals.slice(flag.length + 1);
8601
+ const index = argv.indexOf(flag);
8602
+ return index >= 0 ? argv[index + 1] : void 0;
8603
+ }
8604
+
8605
+ // src/commands/delivery-doctor.ts
8606
+ init_auth_guard();
8607
+ init_exit();
8608
+ import {
8609
+ HcmClient as HcmClient18,
8610
+ fetchReconIdentity,
8611
+ formatObject as formatObject19,
8612
+ fromAxiosError as fromAxiosError17,
8613
+ httpProbe,
8614
+ runDoctor
8615
+ } from "@hcmai/sdk";
8616
+ var DEFAULT_CAPABILITIES = "default";
8617
+ function render2(report) {
8618
+ const lines = [];
8619
+ for (const c of report.checks) {
8620
+ lines.push(`${c.ok ? "\u2705" : "\u274C"} ${c.anchor.padEnd(13)} ${c.detail}`);
8621
+ }
8622
+ lines.push("");
8623
+ lines.push(
8624
+ report.ok ? "\u56DB\u6761\u951A\u70B9\u5168\u7EFF\uFF1A\u53EF\u4EE5\u5F00\u59CB recon\u3002" : "\u6709\u951A\u70B9\u6CA1\u8FC7\u2014\u2014\u5148\u6309\u4E0A\u9762\u5404\u6761\u7684\u4E0B\u4E00\u6B65\u5904\u7406\uFF0C\u4E0D\u8981\u5728\u8FD9\u4E2A\u72B6\u6001\u4E0A\u722C\u57FA\u7EBF\u3002"
8625
+ );
8626
+ return lines.join("\n");
8627
+ }
8628
+ async function deliveryDoctorCommand(args) {
8629
+ try {
8630
+ const ctx = await getActiveAuthContextFromCli(args);
8631
+ const client3 = HcmClient18.fromAuthContext(ctx);
8632
+ const probe = httpProbe(client3.raw(), args.capabilities ?? DEFAULT_CAPABILITIES);
8633
+ const identity2 = await fetchReconIdentity(probe, ctx.tenantId);
8634
+ const report = await runDoctor(probe, identity2);
8635
+ const fmt = args.output ?? "json";
8636
+ if (fmt !== "json") process.stdout.write(render2(report) + "\n");
8637
+ process.stdout.write(formatObject19(report, { format: fmt }) + "\n");
8638
+ process.exit(report.ok ? 0 : 1);
8639
+ } catch (e) {
8640
+ const err = e;
8641
+ if (err?.isAxiosError) exitWithError(fromAxiosError17(err, args.env));
8642
+ exitWithError(e);
8643
+ process.exit(1);
8644
+ }
8645
+ }
8646
+
7892
8647
  // src/commands/delivery-execution.ts
7893
- import { createHash as createHash6, randomBytes as secureRandomBytes } from "crypto";
8648
+ import { createHash as createHash7, randomBytes as secureRandomBytes } from "crypto";
7894
8649
  import { spawn } from "child_process";
7895
8650
  import { createReadStream as createReadStream2, promises as fs8 } from "fs";
7896
- import path6 from "path";
7897
- import { CliError as CliError20, CliErrorCode as CliErrorCode19, formatObject as formatObject18 } from "@hcmai/sdk";
8651
+ import path8 from "path";
8652
+ import { CliError as CliError22, CliErrorCode as CliErrorCode21, formatObject as formatObject20 } from "@hcmai/sdk";
7898
8653
  init_exit();
7899
8654
  var EXECUTION_CONTRACT_VERSION = "2026-08-28.controlled-v1";
7900
8655
  var DEFAULT_TTL_SECONDS = 15 * 60;
@@ -7904,7 +8659,7 @@ var PLAN_ID_PATTERN = /^[a-f0-9]{24}$/;
7904
8659
  async function prepareDeliveryExecution(input) {
7905
8660
  const project = await realProject(input.project);
7906
8661
  await readProjectMode(project);
7907
- const assessment = assessDeliveryCommand(input.argv);
8662
+ const assessment = await (input.assessCommand ?? assessEffectiveDeliveryCommand)(input.argv);
7908
8663
  assertGuardedAssessment(assessment, input.argv);
7909
8664
  const ttlSeconds = input.ttlSeconds ?? DEFAULT_TTL_SECONDS;
7910
8665
  if (!Number.isInteger(ttlSeconds) || ttlSeconds < MIN_TTL_SECONDS || ttlSeconds > MAX_TTL_SECONDS) {
@@ -7921,20 +8676,20 @@ async function prepareDeliveryExecution(input) {
7921
8676
  const core = {
7922
8677
  schemaVersion: 1,
7923
8678
  contractVersion: EXECUTION_CONTRACT_VERSION,
7924
- nonceSha256: sha2566((input.randomBytes ?? secureRandomBytes)(12)),
8679
+ nonceSha256: sha2567((input.randomBytes ?? secureRandomBytes)(12)),
7925
8680
  createdAt: created.toISOString(),
7926
8681
  expiresAt: new Date(created.getTime() + ttlSeconds * 1e3).toISOString(),
7927
- chironLockSha256: sha2566(lockBytes),
8682
+ chironLockSha256: sha2567(lockBytes),
7928
8683
  runtime,
7929
8684
  assessment,
7930
8685
  documents: { change, rollback },
7931
8686
  evidenceDir: evidence.relative
7932
8687
  };
7933
- const planId = sha2566(canonicalJson(core)).slice(0, 24);
8688
+ const planId = sha2567(canonicalJson(core)).slice(0, 24);
7934
8689
  const plan = { ...core, planId };
7935
- const plansDir = path6.join(project, ".hcm-delivery", "execution-plans");
8690
+ const plansDir = path8.join(project, ".hcm-delivery", "execution-plans");
7936
8691
  await safeManagedDirectory(project, ".hcm-delivery/execution-plans", plansDir);
7937
- const planFile = path6.join(plansDir, `${planId}.json`);
8692
+ const planFile = path8.join(plansDir, `${planId}.json`);
7938
8693
  try {
7939
8694
  await fs8.writeFile(planFile, `${JSON.stringify(plan, null, 2)}
7940
8695
  `, {
@@ -7953,7 +8708,7 @@ async function executeDeliveryPlan(input) {
7953
8708
  if (await readProjectMode(project) !== "controlled") {
7954
8709
  throw invalid4("\u9879\u76EE\u4E0D\u662F controlled\uFF0C\u4E0D\u80FD\u6267\u884C R2 \u8BA1\u5212");
7955
8710
  }
7956
- const planFile = path6.join(project, ".hcm-delivery", "execution-plans", `${input.planId}.json`);
8711
+ const planFile = path8.join(project, ".hcm-delivery", "execution-plans", `${input.planId}.json`);
7957
8712
  const plan = await readPlan(project, planFile);
7958
8713
  if (plan.planId !== input.planId || computePlanId(plan) !== input.planId) {
7959
8714
  throw invalid4("\u6267\u884C\u8BA1\u5212\u5185\u5BB9\u4E0E planId \u6458\u8981\u4E0D\u4E00\u81F4");
@@ -7967,13 +8722,13 @@ async function executeDeliveryPlan(input) {
7967
8722
  }
7968
8723
  if (now.getTime() < createdAt - 5e3) throw invalid4("\u5F53\u524D\u65F6\u95F4\u65E9\u4E8E\u8BA1\u5212\u521B\u5EFA\u65F6\u95F4");
7969
8724
  if (now.getTime() > expiresAt) throw invalid4("\u6267\u884C\u8BA1\u5212\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0 prepare");
7970
- const assessment = assessDeliveryCommand(input.argv);
8725
+ const assessment = await (input.assessCommand ?? assessEffectiveDeliveryCommand)(input.argv);
7971
8726
  assertGuardedAssessment(assessment, input.argv);
7972
8727
  if (canonicalJson(assessment) !== canonicalJson(plan.assessment)) {
7973
8728
  throw invalid4("\u5B9E\u9645 argv \u4E0E\u6267\u884C\u8BA1\u5212\u7684\u547D\u4EE4\u6458\u8981\u6216\u98CE\u9669\u4E8B\u5B9E\u4E0D\u4E00\u81F4");
7974
8729
  }
7975
8730
  const { bytes: lockBytes, runtime: lockedRuntime } = await readChironLock(project);
7976
- if (sha2566(lockBytes) !== plan.chironLockSha256) {
8731
+ if (sha2567(lockBytes) !== plan.chironLockSha256) {
7977
8732
  throw invalid4("Chiron \u9501\u6458\u8981\u5DF2\u6F02\u79FB\uFF0C\u8BF7\u91CD\u65B0\u8BC4\u4F30\u5E76 prepare");
7978
8733
  }
7979
8734
  const runtime = await (input.runtimeIdentity ?? currentRuntimeIdentity)();
@@ -7984,11 +8739,11 @@ async function executeDeliveryPlan(input) {
7984
8739
  await assertDocumentUnchanged(project, plan.documents.change, "\u53D8\u66F4\u8BF4\u660E");
7985
8740
  await assertDocumentUnchanged(project, plan.documents.rollback, "\u56DE\u6EDA\u8BF4\u660E");
7986
8741
  const evidenceDir = await bindEvidenceDirectory(project, plan.evidenceDir);
7987
- const receiptFile = path6.join(evidenceDir.absolute, `${plan.planId}.receipt.json`);
8742
+ const receiptFile = path8.join(evidenceDir.absolute, `${plan.planId}.receipt.json`);
7988
8743
  if (await pathExists(receiptFile)) throw invalid4(`\u6267\u884C\u6536\u636E\u5DF2\u5B58\u5728\uFF0C\u62D2\u7EDD\u518D\u6B21\u6267\u884C\uFF1A${plan.planId}`);
7989
- const claimsDir = path6.join(project, ".hcm-delivery", "execution-claims");
8744
+ const claimsDir = path8.join(project, ".hcm-delivery", "execution-claims");
7990
8745
  await safeManagedDirectory(project, ".hcm-delivery/execution-claims", claimsDir);
7991
- const claimFile = path6.join(claimsDir, `${plan.planId}.json`);
8746
+ const claimFile = path8.join(claimsDir, `${plan.planId}.json`);
7992
8747
  try {
7993
8748
  await fs8.writeFile(
7994
8749
  claimFile,
@@ -7999,8 +8754,8 @@ async function executeDeliveryPlan(input) {
7999
8754
  } catch (cause) {
8000
8755
  throw invalid4(`\u6267\u884C\u8BA1\u5212\u5DF2\u6D88\u8D39\uFF0C\u62D2\u7EDD\u91CD\u590D\u6267\u884C\uFF1A${plan.planId}`, cause);
8001
8756
  }
8002
- const stdoutHash = createHash6("sha256");
8003
- const stderrHash = createHash6("sha256");
8757
+ const stdoutHash = createHash7("sha256");
8758
+ const stderrHash = createHash7("sha256");
8004
8759
  const run = input.runCommand ?? runCurrentCliCommand;
8005
8760
  let exitCode;
8006
8761
  try {
@@ -8047,7 +8802,7 @@ async function deliveryPrepareCommand(argv, args) {
8047
8802
  evidenceDir: args.evidenceDir,
8048
8803
  ...ttlSeconds === void 0 ? {} : { ttlSeconds }
8049
8804
  });
8050
- process.stdout.write(formatObject18(plan, { format: args.output ?? "json" }) + "\n");
8805
+ process.stdout.write(formatObject20(plan, { format: args.output ?? "json" }) + "\n");
8051
8806
  } catch (cause) {
8052
8807
  exitWithError(cause);
8053
8808
  }
@@ -8059,14 +8814,14 @@ async function deliveryExecuteCommand(planId, argv, args) {
8059
8814
  planId,
8060
8815
  argv
8061
8816
  });
8062
- process.stdout.write(formatObject18(receipt, { format: args.output ?? "json" }) + "\n");
8817
+ process.stdout.write(formatObject20(receipt, { format: args.output ?? "json" }) + "\n");
8063
8818
  process.exitCode = receipt.exitCode;
8064
8819
  } catch (cause) {
8065
8820
  exitWithError(cause);
8066
8821
  }
8067
8822
  }
8068
8823
  async function readProjectMode(project) {
8069
- const file = path6.join(project, ".hcm-delivery", "project.yml");
8824
+ const file = path8.join(project, ".hcm-delivery", "project.yml");
8070
8825
  const content = await readSafeFile(project, file, "\u9879\u76EE\u914D\u7F6E");
8071
8826
  const match = content.toString("utf8").match(
8072
8827
  /^deliveryMode:\s*(?:"(plan-only|controlled)"|'(plan-only|controlled)'|(plan-only|controlled))\s*$/m
@@ -8078,7 +8833,7 @@ async function readProjectMode(project) {
8078
8833
  return mode;
8079
8834
  }
8080
8835
  async function readChironLock(project) {
8081
- const file = path6.join(project, ".hcm-delivery", "chiron.lock.json");
8836
+ const file = path8.join(project, ".hcm-delivery", "chiron.lock.json");
8082
8837
  const bytes = await readSafeFile(project, file, "Chiron \u9501");
8083
8838
  let parsed;
8084
8839
  try {
@@ -8095,9 +8850,9 @@ async function bindDocument(project, reference, label) {
8095
8850
  if (!(relative2.startsWith("work/") || relative2.startsWith("decisions/"))) {
8096
8851
  throw invalid4(`${label}\u5FC5\u987B\u4F4D\u4E8E\u9879\u76EE work/ \u6216 decisions/ \u4E0B`);
8097
8852
  }
8098
- const file = path6.join(project, relative2);
8853
+ const file = path8.join(project, relative2);
8099
8854
  const bytes = await readSafeFile(project, file, label);
8100
- return { path: relative2, sha256: sha2566(bytes) };
8855
+ return { path: relative2, sha256: sha2567(bytes) };
8101
8856
  }
8102
8857
  async function assertDocumentUnchanged(project, document, label) {
8103
8858
  const current = await bindDocument(project, document.path, label);
@@ -8108,7 +8863,7 @@ async function bindEvidenceDirectory(project, reference) {
8108
8863
  if (!(relative2 === "evidence" || relative2.startsWith("evidence/"))) {
8109
8864
  throw invalid4("evidence \u76EE\u5F55\u5FC5\u987B\u4F4D\u4E8E\u9879\u76EE evidence/ \u4E0B");
8110
8865
  }
8111
- const absolute = path6.join(project, relative2);
8866
+ const absolute = path8.join(project, relative2);
8112
8867
  await assertNoSymlinkComponents(project, relative2);
8113
8868
  const stat = await fs8.stat(absolute).catch((cause) => {
8114
8869
  throw invalid4(`evidence \u76EE\u5F55\u4E0D\u53EF\u7528\uFF1A${relative2}`, cause);
@@ -8130,7 +8885,7 @@ async function readPlan(project, file) {
8130
8885
  function computePlanId(plan) {
8131
8886
  const core = { ...plan };
8132
8887
  delete core.planId;
8133
- return sha2566(canonicalJson(core)).slice(0, 24);
8888
+ return sha2567(canonicalJson(core)).slice(0, 24);
8134
8889
  }
8135
8890
  function assertGuardedAssessment(assessment, argv) {
8136
8891
  if (assessment.risk !== "R2") throw invalid4("\u53EA\u6709 R2 \u547D\u4EE4\u53EF\u4EE5\u8FDB\u5165\u53D7\u63A7\u6267\u884C\u8BA1\u5212");
@@ -8269,13 +9024,13 @@ async function writeReceiptExclusive(target, receipt) {
8269
9024
  });
8270
9025
  await fs8.link(temp, target);
8271
9026
  } catch (cause) {
8272
- throw invalid4(`\u6267\u884C\u6536\u636E\u5199\u5165\u5931\u8D25\u6216\u5DF2\u5B58\u5728\uFF1A${path6.basename(target)}`, cause);
9027
+ throw invalid4(`\u6267\u884C\u6536\u636E\u5199\u5165\u5931\u8D25\u6216\u5DF2\u5B58\u5728\uFF1A${path8.basename(target)}`, cause);
8273
9028
  } finally {
8274
9029
  await fs8.unlink(temp).catch(() => void 0);
8275
9030
  }
8276
9031
  }
8277
9032
  async function safeManagedDirectory(project, relative2, absolute) {
8278
- await assertNoSymlinkComponents(project, path6.dirname(relative2));
9033
+ await assertNoSymlinkComponents(project, path8.dirname(relative2));
8279
9034
  const existing = await fs8.lstat(absolute).catch(() => void 0);
8280
9035
  if (existing?.isSymbolicLink()) throw invalid4(`\u53D7\u7BA1\u76EE\u5F55\u4E0D\u80FD\u662F\u7B26\u53F7\u94FE\u63A5\uFF1A${relative2}`);
8281
9036
  if (existing && !existing.isDirectory()) throw invalid4(`\u53D7\u7BA1\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55\uFF1A${relative2}`);
@@ -8292,8 +9047,8 @@ async function pathExists(file) {
8292
9047
  );
8293
9048
  }
8294
9049
  async function readSafeFile(project, file, label) {
8295
- const relative2 = path6.relative(project, file).split(path6.sep).join("/");
8296
- if (relative2.startsWith("../") || path6.isAbsolute(relative2))
9050
+ const relative2 = path8.relative(project, file).split(path8.sep).join("/");
9051
+ if (relative2.startsWith("../") || path8.isAbsolute(relative2))
8297
9052
  throw invalid4(`${label}\u8DEF\u5F84\u9003\u9038\u9879\u76EE`);
8298
9053
  await assertNoSymlinkComponents(project, relative2);
8299
9054
  let stat;
@@ -8310,14 +9065,14 @@ async function assertNoSymlinkComponents(project, relative2) {
8310
9065
  const parts = relative2.split("/").filter(Boolean);
8311
9066
  let current = project;
8312
9067
  for (const part of parts) {
8313
- current = path6.join(current, part);
9068
+ current = path8.join(current, part);
8314
9069
  const stat = await fs8.lstat(current).catch(() => void 0);
8315
9070
  if (stat?.isSymbolicLink()) throw invalid4(`\u8DEF\u5F84\u5305\u542B\u7B26\u53F7\u94FE\u63A5\uFF1A${relative2}`);
8316
9071
  if (!stat) break;
8317
9072
  }
8318
9073
  }
8319
9074
  async function realProject(requested) {
8320
- const absolute = path6.resolve(requested);
9075
+ const absolute = path8.resolve(requested);
8321
9076
  let project;
8322
9077
  try {
8323
9078
  project = await fs8.realpath(absolute);
@@ -8329,10 +9084,10 @@ async function realProject(requested) {
8329
9084
  return project;
8330
9085
  }
8331
9086
  function safeRelative(reference, label) {
8332
- if (!reference || path6.isAbsolute(reference) || /[\r\n\0]/.test(reference)) {
9087
+ if (!reference || path8.isAbsolute(reference) || /[\r\n\0]/.test(reference)) {
8333
9088
  throw invalid4(`${label}\u5FC5\u987B\u662F\u9879\u76EE\u5185\u76F8\u5BF9\u8DEF\u5F84`);
8334
9089
  }
8335
- const normalized = path6.normalize(reference).split(path6.sep).join("/");
9090
+ const normalized = path8.normalize(reference).split(path8.sep).join("/");
8336
9091
  if (normalized === ".." || normalized.startsWith("../") || normalized === ".") {
8337
9092
  throw invalid4(`${label}\u8DEF\u5F84\u9003\u9038\u9879\u76EE`);
8338
9093
  }
@@ -8368,11 +9123,11 @@ function canonicalJson(value) {
8368
9123
  }
8369
9124
  return JSON.stringify(value) ?? "null";
8370
9125
  }
8371
- function sha2566(value) {
8372
- return createHash6("sha256").update(value).digest("hex");
9126
+ function sha2567(value) {
9127
+ return createHash7("sha256").update(value).digest("hex");
8373
9128
  }
8374
9129
  async function sha256File2(file) {
8375
- const hash = createHash6("sha256");
9130
+ const hash = createHash7("sha256");
8376
9131
  await new Promise((resolve3, reject) => {
8377
9132
  const stream = createReadStream2(file);
8378
9133
  stream.on("data", (chunk) => hash.update(chunk));
@@ -8382,32 +9137,32 @@ async function sha256File2(file) {
8382
9137
  return hash.digest("hex");
8383
9138
  }
8384
9139
  function invalid4(message, cause) {
8385
- return new CliError20({ code: CliErrorCode19.INVALID_ARGUMENT, message, cause });
9140
+ return new CliError22({ code: CliErrorCode21.INVALID_ARGUMENT, message, cause });
8386
9141
  }
8387
9142
 
8388
9143
  // src/commands/user.ts
8389
9144
  init_auth_guard();
8390
9145
  init_exit();
8391
9146
  import {
8392
- HcmClient as HcmClient17,
9147
+ HcmClient as HcmClient19,
8393
9148
  adminResetPassword,
8394
- formatObject as formatObject19,
8395
- fromAxiosError as fromAxiosError17,
8396
- CliError as CliError21,
8397
- CliErrorCode as CliErrorCode20
9149
+ formatObject as formatObject21,
9150
+ fromAxiosError as fromAxiosError18,
9151
+ CliError as CliError23,
9152
+ CliErrorCode as CliErrorCode22
8398
9153
  } from "@hcmai/sdk";
8399
9154
  function buildAdminResetPasswordRequest(args, password) {
8400
9155
  const hasId = Boolean(args.id);
8401
9156
  const hasUsername = Boolean(args.username);
8402
9157
  if (hasId === hasUsername) {
8403
- throw new CliError21({
8404
- code: CliErrorCode20.INVALID_ARGUMENT,
9158
+ throw new CliError23({
9159
+ code: CliErrorCode22.INVALID_ARGUMENT,
8405
9160
  message: "--id <uuid> \u4E0E --username <user> \u5FC5\u987B\u4E14\u53EA\u80FD\u63D0\u4F9B\u4E00\u4E2A"
8406
9161
  });
8407
9162
  }
8408
9163
  if (!password) {
8409
- throw new CliError21({
8410
- code: CliErrorCode20.INVALID_ARGUMENT,
9164
+ throw new CliError23({
9165
+ code: CliErrorCode22.INVALID_ARGUMENT,
8411
9166
  message: "\u65B0\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A"
8412
9167
  });
8413
9168
  }
@@ -8423,12 +9178,12 @@ async function userResetPasswordCommand(args) {
8423
9178
  try {
8424
9179
  const password = args.passwordStdin ? await readSecretFromStdin() : await promptPasswordTwice();
8425
9180
  const request = buildAdminResetPasswordRequest(args, password);
8426
- const client3 = HcmClient17.fromAuthContext(await getActiveAuthContextFromCli(args));
9181
+ const client3 = HcmClient19.fromAuthContext(await getActiveAuthContextFromCli(args));
8427
9182
  const result2 = await adminResetPassword(client3.raw(), request);
8428
- process.stdout.write(formatObject19(result2, { format: args.output ?? "json" }) + "\n");
9183
+ process.stdout.write(formatObject21(result2, { format: args.output ?? "json" }) + "\n");
8429
9184
  } catch (cause) {
8430
9185
  const err = cause;
8431
- if (err?.isAxiosError) exitWithError(fromAxiosError17(err, args.env));
9186
+ if (err?.isAxiosError) exitWithError(fromAxiosError18(err, args.env));
8432
9187
  exitWithError(cause);
8433
9188
  }
8434
9189
  }
@@ -8436,8 +9191,8 @@ async function promptPasswordTwice() {
8436
9191
  const password = await promptSecret("\u65B0\u5BC6\u7801: ");
8437
9192
  const confirmation = await promptSecret("\u518D\u6B21\u8F93\u5165\u65B0\u5BC6\u7801: ");
8438
9193
  if (password !== confirmation) {
8439
- throw new CliError21({
8440
- code: CliErrorCode20.INVALID_ARGUMENT,
9194
+ throw new CliError23({
9195
+ code: CliErrorCode22.INVALID_ARGUMENT,
8441
9196
  message: "\u4E24\u6B21\u8F93\u5165\u7684\u65B0\u5BC6\u7801\u4E0D\u4E00\u81F4"
8442
9197
  });
8443
9198
  }
@@ -8483,8 +9238,9 @@ identity.command("use <name>").description("\u628A identity \u8BBE\u4E3A\u5176 e
8483
9238
  identity.command("remove <name>").description("\u5220\u9664 identity\uFF08\u6E05 token + \u82E5\u662F env default \u5219\u6E05\u7A7A\uFF09").action((name) => identityRemove(name));
8484
9239
  var user = program.command("user").description("\u7BA1\u7406\u79DF\u6237\u7528\u6237\u7684\u4E13\u7528\u51ED\u636E\u6D41\u7A0B");
8485
9240
  user.command("reset-password").description("\u7531 admin.system \u5B89\u5168\u91CD\u7F6E\u7528\u6237\u5BC6\u7801\uFF0C\u5E76\u4F7F\u65E2\u6709\u4F1A\u8BDD\u5931\u6548").option("--id <uuid>", "\u76EE\u6807\u7528\u6237 ID\uFF08\u4E0E --username \u4E8C\u9009\u4E00\uFF09").option("--username <user>", "\u76EE\u6807\u7528\u6237\u540D\uFF08\u4E0E --id \u4E8C\u9009\u4E00\uFF09").option("--password-stdin", "\u4ECE\u6807\u51C6\u8F93\u5165\u8BFB\u53D6\u65B0\u5BC6\u7801\uFF08Agent/\u53D7\u63A7\u4EA4\u4ED8\u5FC5\u987B\u4F7F\u7528\uFF09").option("--no-force-change", "\u4E0B\u6B21\u767B\u5F55\u4E0D\u5F3A\u5236\u6539\u5BC6\uFF08\u4EC5\u9650\u5DF2\u6279\u51C6\u7684\u9694\u79BB\u6D4B\u8BD5\u73AF\u5883\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\uFF08\u5FC5\u987B\u5177\u5907 admin.system\uFF09").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "json").action((opts) => userResetPasswordCommand(opts));
8486
- var delivery = program.command("delivery").description("\u987E\u95EE\u4EA4\u4ED8\u547D\u4EE4\u7684\u98CE\u9669\u8BC4\u4F30\u4E0E\u4E00\u6B21\u6027\u53D7\u63A7\u6267\u884C\u5408\u540C");
8487
- delivery.command("assess").description("\u7EAF\u672C\u5730\u8BC4\u4F30\u4E00\u6B21 HCM CLI argv\uFF1B\u7528 -- \u5206\u9694\u88AB\u8BC4\u4F30\u547D\u4EE4").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "json").allowUnknownOption(true).argument("<command...>", "\u88AB\u8BC4\u4F30\u7684 HCM \u5B50\u547D\u4EE4\u4E0E\u53C2\u6570\uFF0C\u4E0D\u5305\u542B hcm \u672C\u8EAB").action((command, opts) => deliveryAssessCommand(command, opts));
9241
+ var delivery = program.command("delivery").description("\u987E\u95EE\u4EA4\u4ED8\uFF1A\u73B0\u573A\u63A2\u6D3B\u3001\u98CE\u9669\u8BC4\u4F30\u4E0E\u4E00\u6B21\u6027\u53D7\u63A7\u6267\u884C\u5408\u540C");
9242
+ delivery.command("assess").description("\u8BC4\u4F30\u4E00\u6B21 HCM CLI argv\uFF1BAction \u98CE\u63A7\u58F0\u660E\u8BFB\u53D6\u81EA\u76EE\u6807 Core\uFF0C\u7528 -- \u5206\u9694\u88AB\u8BC4\u4F30\u547D\u4EE4").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "json").allowUnknownOption(true).argument("<command...>", "\u88AB\u8BC4\u4F30\u7684 HCM \u5B50\u547D\u4EE4\u4E0E\u53C2\u6570\uFF0C\u4E0D\u5305\u542B hcm \u672C\u8EAB").action((command, opts) => deliveryAssessCommand(command, opts));
9243
+ delivery.command("doctor").description("\u56DB\u6761\u951A\u70B9\u63A2\u6D3B\uFF1A\u8FDE\u901A / \u6211\u662F\u8C01 / configAdmin / \u7AD9\u5728\u54EA\u4E00\u5C42").option("--env <name>", "\u76EE\u6807\u73AF\u5883\u522B\u540D").option("--as <identity>", "\u4E34\u65F6\u6362\u8EAB\u4EFD").option("--capabilities <s>", "\u722C\u53D6\u65F6\u58F0\u660E\u7684 capability \u4E32\uFF08\u4F1A\u968F\u56DB\u5143\u7EC4\u7559\u6863\uFF09").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "json").action((opts) => deliveryDoctorCommand(opts));
8488
9244
  delivery.command("prepare").description("\u628A\u53D7\u652F\u6301\u7684 R2 argv \u4E0E\u9501\u3001\u8FD0\u884C\u65F6\u548C\u53D8\u66F4/\u56DE\u6EDA\u8BF4\u660E\u7ED1\u5B9A\u4E3A\u77ED\u65F6\u6267\u884C\u8BA1\u5212").requiredOption("--change-ref <file>", "\u9879\u76EE work/ \u6216 decisions/ \u4E0B\u7684\u53D8\u66F4\u8BF4\u660E").requiredOption("--rollback-ref <file>", "\u9879\u76EE work/ \u6216 decisions/ \u4E0B\u7684\u56DE\u6EDA\u8BF4\u660E").requiredOption("--evidence-dir <dir>", "\u9879\u76EE evidence/ \u4E0B\u7684\u6536\u636E\u76EE\u5F55").option("--project <dir>", "HCM \u987E\u95EE\u9879\u76EE\u6839\u76EE\u5F55", ".").option("--ttl-seconds <n>", "\u6709\u6548\u671F\u79D2\u6570\uFF0860-3600\uFF09", "900").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "json").allowUnknownOption(true).argument("<command...>", "\u88AB\u7ED1\u5B9A\u7684 R2 HCM \u5B50\u547D\u4EE4\u4E0E\u53C2\u6570\uFF0C\u4E0D\u5305\u542B hcm \u672C\u8EAB").action((command, opts) => deliveryPrepareCommand(command, opts));
8489
9245
  delivery.command("execute <planId>").description("\u9010\u6B21\u6279\u51C6\u540E\u6D88\u8D39\u77ED\u65F6\u8BA1\u5212\uFF0C\u5E76\u6267\u884C\u4E00\u6B21\u4E0E\u8BA1\u5212\u5B8C\u5168\u76F8\u540C\u7684 R2 argv").option("--project <dir>", "HCM \u987E\u95EE\u9879\u76EE\u6839\u76EE\u5F55", ".").option("--output <fmt>", "\u6536\u636E\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "json").allowUnknownOption(true).argument("<command...>", "\u4E0E prepare \u5B8C\u5168\u76F8\u540C\u7684 R2 HCM \u5B50\u547D\u4EE4\u4E0E\u53C2\u6570").action((planId, command, opts) => deliveryExecuteCommand(planId, command, opts));
8490
9246
  program.command("query <Model>").description("\u67E5\u8BE2 Model \u5217\u8868\u6570\u636E\uFF08\u901A\u8FC7 ModelQueryDsl JSON \u8868\u8FBE\u8FC7\u6EE4/\u6392\u5E8F/\u5206\u9875\uFF09").option(
@@ -8546,12 +9302,13 @@ meta.command("list").description("\u5217\u51FA\u79DF\u6237\u5143\u6570\u636E\u65
8546
9302
  meta.command("get <path>").description("\u6253\u5370 meta \u539F\u6587\uFF08\u5982 metas/Employee.list.yml\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").action((p, opts) => metaGetCommand(p, opts));
8547
9303
  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));
8548
9304
  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));
8549
- 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");
8550
- 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));
8551
- 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));
8552
- 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));
9305
+ var skills = program.command("skills").description("\u4EA4\u4ED8\u6280\u80FD\uFF1A\u777F\u620E Chiron \u6280\u80FD\u5E93 + CLI \u81EA\u5E26\u6280\u80FD\uFF08\u514D\u8BA4\u8BC1\uFF0C\u65E0\u9700\u5148 login\uFF09");
9306
+ 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("--source <kind>", "\u8FD9\u4E00\u8D9F\u770B\u54EA\u4E9B\u6765\u6E90\uFF1Acli\uFF08\u53EA\u770B\u81EA\u5E26\uFF0C\u4E0D\u8FDE\u7F51\uFF09| chiron | all", "all").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));
9307
+ skills.command("manifest").description("\u6253\u5370\u672C CLI \u7684\u547D\u4EE4\u9762\u4E0E\u81EA\u5E26\u6280\u80FD\u6E05\u5355\uFF08\u4E0D\u8FDE\u7F51\uFF0C\u4F9B\u5B88\u536B\u4E0E\u5916\u90E8\u5DE5\u5177\u6BD4\u5BF9\uFF09").option("--output <fmt>", "\u8F93\u51FA\u683C\u5F0F\uFF1Atable | json | yaml", "json").action((opts) => skillsManifestCommand(program, opts));
9308
+ skills.command("show <id>").description("\u6253\u5370\u6280\u80FD\u539F\u6587\uFF08\u7BA1\u9053\u53CB\u597D\uFF09\uFF1B\u81EA\u5E26\u6280\u80FD\u76F4\u63A5\u8BFB\u672C\u5730\uFF0C\u4E0D\u8FDE\u7F51").option("--source <kind>", "\u8FD9\u4E00\u8D9F\u770B\u54EA\u4E9B\u6765\u6E90\uFF1Acli\uFF08\u53EA\u770B\u81EA\u5E26\uFF0C\u4E0D\u8FDE\u7F51\uFF09| chiron | all", "all").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));
9309
+ 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("--source <kind>", "\u8FD9\u4E00\u8D9F\u770B\u54EA\u4E9B\u6765\u6E90\uFF1Acli\uFF08\u53EA\u770B\u81EA\u5E26\uFF0C\u4E0D\u8FDE\u7F51\uFF09| chiron | all", "all").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));
8553
9310
  skills.command("sync <id>").description("\u4ECE\u76EE\u6807\u5B9E\u4F8B\u540C\u6B65 Skill \u95ED\u5305\u5230 WorkBuddy \u9879\u76EE\u5E76\u5199 chiron.lock").requiredOption("--target <agent>", "\u76EE\u6807 Agent \u5BBF\u4E3B\uFF1B\u5F53\u524D\u652F\u6301 workbuddy").requiredOption("--project <path>", "WorkBuddy \u9879\u76EE\u6839\u76EE\u5F55").option("--cli <path>", "\u663E\u5F0F\u6307\u5B9A\u8981\u9501\u5B9A\u5230\u9879\u76EE\u7684 HCM CLI\uFF1B\u9ED8\u8BA4\u4F7F\u7528\u5F53\u524D\u8FD9\u4EFD CLI").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) => skillsSyncCommand(id, opts));
8554
- 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));
9311
+ 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("--source <kind>", "\u8FD9\u4E00\u8D9F\u770B\u54EA\u4E9B\u6765\u6E90\uFF1Acli\uFF08\u53EA\u770B\u81EA\u5E26\uFF0C\u4E0D\u8FDE\u7F51\uFF09| chiron | all", "all").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));
8555
9312
  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").option("--data <JSON>", `\u8981\u66F4\u65B0\u7684\u5B57\u6BB5 JSON\uFF0C\u4F8B\u5982 '{"name":"\u65B0\u540D\u79F0"}'`).option("--data-file <path>", "\u4ECE UTF-8 JSON \u6587\u4EF6\u8BFB\u53D6\u66F4\u65B0\u5B57\u6BB5\uFF08\u4E0E --data \u4E92\u65A5\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\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));
8556
9313
  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));
8557
9314
  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");
@@ -8571,9 +9328,14 @@ async function main() {
8571
9328
  }
8572
9329
  await program.parseAsync(process.argv);
8573
9330
  }
8574
- main().catch((e) => {
8575
- process.stderr.write(`[hcm] fatal: ${String(e.message)}
9331
+ if (process.env.HCM_CLI_IMPORT_ONLY !== "1") {
9332
+ main().catch((e) => {
9333
+ process.stderr.write(`[hcm] fatal: ${String(e.message)}
8576
9334
  `);
8577
- process.exit(1);
8578
- });
9335
+ process.exit(1);
9336
+ });
9337
+ }
9338
+ export {
9339
+ program
9340
+ };
8579
9341
  //# sourceMappingURL=index.js.map