@numa-tech/numa 1.12.8 → 1.12.11

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.
Files changed (75) hide show
  1. package/README.md +140 -16
  2. package/dist/ai-registry/commands.js +33 -33
  3. package/dist/ai-registry/commands.js.map +1 -1
  4. package/dist/app-config.d.ts +0 -1
  5. package/dist/app-config.js +4 -2
  6. package/dist/app-config.js.map +1 -1
  7. package/dist/application-candidates/client.d.ts +167 -0
  8. package/dist/application-candidates/client.js +103 -0
  9. package/dist/application-candidates/client.js.map +1 -0
  10. package/dist/application-candidates/commands.d.ts +13 -0
  11. package/dist/application-candidates/commands.js +225 -0
  12. package/dist/application-candidates/commands.js.map +1 -0
  13. package/dist/application-candidates/schemas.d.ts +171 -0
  14. package/dist/application-candidates/schemas.js +80 -0
  15. package/dist/application-candidates/schemas.js.map +1 -0
  16. package/dist/application-onboarding/client.d.ts +256 -0
  17. package/dist/application-onboarding/client.js +213 -0
  18. package/dist/application-onboarding/client.js.map +1 -0
  19. package/dist/application-onboarding/commands.d.ts +64 -0
  20. package/dist/application-onboarding/commands.js +694 -0
  21. package/dist/application-onboarding/commands.js.map +1 -0
  22. package/dist/application-onboarding/errors.d.ts +11 -0
  23. package/dist/application-onboarding/errors.js +51 -0
  24. package/dist/application-onboarding/errors.js.map +1 -0
  25. package/dist/application-onboarding/schemas.d.ts +1167 -0
  26. package/dist/application-onboarding/schemas.js +459 -0
  27. package/dist/application-onboarding/schemas.js.map +1 -0
  28. package/dist/application-onboarding/scm-credentials.d.ts +8 -0
  29. package/dist/application-onboarding/scm-credentials.js +98 -0
  30. package/dist/application-onboarding/scm-credentials.js.map +1 -0
  31. package/dist/application-onboarding/tui-model.d.ts +131 -0
  32. package/dist/application-onboarding/tui-model.js +554 -0
  33. package/dist/application-onboarding/tui-model.js.map +1 -0
  34. package/dist/application-onboarding/tui.d.ts +14 -0
  35. package/dist/application-onboarding/tui.js +554 -0
  36. package/dist/application-onboarding/tui.js.map +1 -0
  37. package/dist/authorization/access-request-client.d.ts +45 -0
  38. package/dist/authorization/access-request-client.js +93 -0
  39. package/dist/authorization/access-request-client.js.map +1 -0
  40. package/dist/authorization/access-request-commands.d.ts +25 -0
  41. package/dist/authorization/access-request-commands.js +196 -0
  42. package/dist/authorization/access-request-commands.js.map +1 -0
  43. package/dist/authorization/access-request-schemas.d.ts +123 -0
  44. package/dist/authorization/access-request-schemas.js +67 -0
  45. package/dist/authorization/access-request-schemas.js.map +1 -0
  46. package/dist/authorization/client.d.ts +50 -0
  47. package/dist/authorization/client.js +113 -0
  48. package/dist/authorization/client.js.map +1 -0
  49. package/dist/authorization/commands.d.ts +40 -0
  50. package/dist/authorization/commands.js +296 -0
  51. package/dist/authorization/commands.js.map +1 -0
  52. package/dist/authorization/errors.d.ts +13 -0
  53. package/dist/authorization/errors.js +70 -0
  54. package/dist/authorization/errors.js.map +1 -0
  55. package/dist/authorization/schemas.d.ts +187 -0
  56. package/dist/authorization/schemas.js +101 -0
  57. package/dist/authorization/schemas.js.map +1 -0
  58. package/dist/cli.js +44 -8
  59. package/dist/cli.js.map +1 -1
  60. package/dist/command-catalog.js +270 -26
  61. package/dist/command-catalog.js.map +1 -1
  62. package/dist/web-console-page.d.ts +1 -1
  63. package/dist/web-console-page.js +1 -1
  64. package/dist/web-console.js +6 -5
  65. package/dist/web-console.js.map +1 -1
  66. package/examples/ai-registry/README.md +18 -0
  67. package/examples/ai-registry/nacos-instance.username-password.example.json +25 -0
  68. package/package.json +4 -4
  69. package/skills/numa-ai-registry/SKILL.md +5 -5
  70. package/skills/numa-ai-registry/evals/evals.json +1 -1
  71. package/skills/numa-ai-registry/references/command-contract.md +22 -22
  72. package/skills/numa-cli/SKILL.md +44 -0
  73. package/skills/numa-cli/agents/openai.yaml +4 -0
  74. package/skills/numa-cli/evals/evals.json +35 -0
  75. package/skills/numa-cli/references/pipeline-release.md +107 -0
package/README.md CHANGED
@@ -10,6 +10,7 @@
10
10
  - 包含 Realm 角色、Client 角色和用户组的个人信息页;
11
11
  - 使用服务端托管的 Codex 账号启动官方 Codex CLI,客户端不保存 refresh token;
12
12
  - 通过平台授权代理发现、治理并安装私有 Nacos Skills 与 MCP Servers;
13
+ - 通过可恢复的 `app` 会话和统一 Web/API 契约创建新应用或录入存量仓库;
13
14
  - 通过领域化 `media` 命令安全调用平台托管的 TTS、视频、资产和素材库服务;
14
15
  - 兼容原有 stdio MCP 服务。
15
16
 
@@ -34,10 +35,10 @@ npm config set @numa-tech:registry=https://registry.npmjs.org/
34
35
  ```
35
36
 
36
37
  脚本会先检查 Git 工作区干净、当前分支与 upstream 完全同步,再于修改版本号之前检查公共
37
- npm 身份以及 `@tokensrc`、`@numa-tech` scope 权限。使用验证器 App
38
- 本地交互发布会在公共 npm 推送前隐藏输入 6 OTP,并显式传给 `npm publish`;
39
- 使用带 bypass 2FA 权限的 granular token 时直接回车即可。非交互环境可以临时提供
40
- `NUMA_PUBLIC_NPM_OTP`,更推荐使用 bypass 2FA granular token 或 npm trusted publishing。
38
+ npm 身份以及 `@tokensrc`、`@numa-tech` scope 权限。发布认证默认完全交给 npm 处理;
39
+ 需要时 npm 会启动自己的浏览器认证或 2FA 流程,脚本不会额外询问 OTP。也可以临时通过
40
+ `NUMA_PUBLIC_NPM_OTP` 显式提供 6 位 OTP;自动化发布更推荐使用带 bypass 2FA 权限的
41
+ granular token 或 npm trusted publishing。
41
42
 
42
43
  首次从本机发布公共包,或公共登录已经过期时,先运行:
43
44
 
@@ -188,10 +189,13 @@ numa config \
188
189
  | `numa registry instances list/create/update/delete` | 需登录 | 管理数据库中的 Nacos 实例和 OIDC 配置;写操作需要 Registry admin |
189
190
  | `numa registry namespaces list/resolve/check/create/update/delete` | 需登录 | 管理多实例 namespace 路由与跨集群默认项;写操作需要 Registry admin |
190
191
  | `numa registry capabilities/init/lock/sync/upgrade` | 需登录 | 读取授权边界并以可提交的 manifest/lock 确定性安装 |
191
- | `numa registry skill list/inspect/install/upload/...` | 需登录 | 发现、安装和治理 Nacos Skills;服务端按团队、角色和生命周期授权 |
192
- | `numa registry mcp list/inspect/install/bridge/...` | 需登录 | 通过企业 Router 安装/桥接 MCP,并维护版本、标签和工具状态 |
192
+ | `numa skills list/inspect/install/upload/...` | 需登录 | 发现、安装和治理 Nacos Skills;服务端按团队、角色和生命周期授权 |
193
+ | `numa mcp list/inspect/install/bridge/...` | 需登录 | 通过企业 Router 安装/桥接 MCP,并维护版本、标签和工具状态 |
193
194
  | `numa registry approvals/router/audit` | 需登录 | 两人制发布、Router 健康/对账和追加式审计 |
194
195
  | `numa registry tui` | 需登录 | 打开 namespace、Skills、MCP、审批、Router、审计全屏工作台 |
196
+ | `numa app onboard/apply/resume/inspect/list/tui` | 需登录 | 创建新应用、录入存量应用并恢复服务端入驻会话 |
197
+ | `numa app options` | 需登录 | 查询应用归属所需的团队、系统、业务域和环境 ID |
198
+ | `numa app candidate list/inspect/preview/review/adopt` | 需登录 | 审查应用发现候选并确认收录,服务端执行最终管理员授权和审计 |
195
199
  | `numa media capabilities` | 需登录 | 查询媒体 API、Provider 和版本能力 |
196
200
  | `numa media tts submit` | 需登录 | 提交 TTS 异步任务 |
197
201
  | `numa media video submit` | 需登录 | 提交视频生成异步任务 |
@@ -320,7 +324,8 @@ SSRF 安全策略仍由 `AI_REGISTRY_ALLOWED_UPSTREAM_HOSTS`、
320
324
  `AI_REGISTRY_ALLOWED_TOKEN_HOSTS` 控制,allow-list 为空时 fail closed;HTTP 只可通过
321
325
  `AI_REGISTRY_ALLOW_HTTP=true` 用于开发环境。
322
326
 
323
- Nacos 实例文件示例(凭据字段仅写入,实际字段以平台 capability/API revision 为准):
327
+ Nacos 实例文件示例(凭据字段仅写入,实际字段以平台 capability/API revision 为准)。完整的
328
+ 用户名密码认证模板见 `examples/ai-registry/nacos-instance.username-password.example.json`:
324
329
 
325
330
  ```json
326
331
  {
@@ -387,18 +392,18 @@ numa registry lock --json
387
392
  numa registry sync --json
388
393
  numa registry upgrade release-helper --json
389
394
 
390
- numa registry skill list --namespace team-ai --search deploy --json
391
- numa registry skill inspect release-helper --namespace team-ai --json
392
- numa registry skill install release-helper \
395
+ numa skills list --namespace team-ai --search deploy --json
396
+ numa skills inspect release-helper --namespace team-ai --json
397
+ numa skills install release-helper \
393
398
  --namespace team-ai --agent cursor --scope project --label latest --json
394
399
 
395
- numa registry mcp list --namespace team-ai --json
396
- numa registry mcp inspect internal-docs --namespace team-ai --json
397
- numa registry mcp install internal-docs \
400
+ numa mcp list --namespace team-ai --json
401
+ numa mcp inspect internal-docs --namespace team-ai --json
402
+ numa mcp install internal-docs \
398
403
  --namespace team-ai --instance cluster-b --agent claude --scope project --transport remote --json
399
404
 
400
405
  # 仅供 stdio Agent;复用 Numa 登录/刷新连接 Router
401
- numa registry mcp bridge --namespace team-ai
406
+ numa mcp bridge --namespace team-ai
402
407
 
403
408
  # 也可使用终端交互界面
404
409
  numa registry tui
@@ -407,7 +412,7 @@ numa registry tui
407
412
  两人制发布生命周期:
408
413
 
409
414
  ```bash
410
- numa registry skill upload ./release-helper.zip \
415
+ numa skills upload ./release-helper.zip \
411
416
  --namespace team-ai --target-version 1.0.0 --json
412
417
  numa registry approvals submit skill release-helper \
413
418
  --namespace team-ai --resource-version 1.0.0 --reason "scanner passed" --json
@@ -442,7 +447,7 @@ capability 发布且健康的企业 Router,不安装 Nacos 中的下游 endpoi
442
447
  | OpenClaw | `.openclaw/skills` | 调用官方 `openclaw mcp set`,仅 user scope |
443
448
 
444
449
  ChatGPT 不能启动本地 stdio bridge;它直接连接企业 Router 的远程 HTTPS OAuth resource。
445
- 其他只支持 stdio 的 Agent 可运行 `numa registry mcp bridge`,由 Numa 获取/刷新用户 Token
450
+ 其他只支持 stdio 的 Agent 可运行 `numa mcp bridge`,由 Numa 获取/刷新用户 Token
446
451
  并只发送给 Router,不向 Nacos 或下游 MCP 透传。ChatGPT workspace 仍需管理员按计划和
447
452
  RBAC 开启 Developer mode。
448
453
 
@@ -451,6 +456,125 @@ RBAC 开启 Developer mode。
451
456
  Nacos token、绕过 403 或未经确认覆盖本地配置。对应场景评测在
452
457
  `skills/numa-ai-registry/evals/evals.json`。
453
458
 
459
+ ## 应用创建与存量录入
460
+
461
+ `numa app` 使用 platform profile 的 `platform` service 和现有 `mcp-client` Keycloak 会话调用
462
+ `/api/v1/application-onboarding`。Web、CLI 和 TUI 共享服务端 `sessionNo`、乐观锁 `revision`、
463
+ `planHash` 和单调递增的 event sequence;CLI 只展示服务端状态,不会在本地推断任务已完成。
464
+
465
+ 交互终端直接运行 `numa app onboard` 会打开 Ink TUI,并可在同一服务端草稿中完成
466
+ `MODE → BASIC_INFORMATION → OWNERSHIP → SOURCE_CONTROL → TECHNOLOGY → STANDARDIZATION → DELIVERY → REVIEW → EXECUTION`
467
+ 九步。`[` / `]` 切换步骤(切换时保存 `revision` 与稳定 `currentStep`),方向键选择字段和目录项,
468
+ `Enter` / `e` 编辑,`s` 保存;`REVIEW` 中先按 `p` 查看阻断、警告与 `planHash`,再按 `a`、`y`
469
+ 二次确认执行。目录接口不可用时仍可手工输入实体 ID;仓库 Provider 返回 501 时会明确提示手工输入
470
+ 稳定 `externalId` 与 `expectedHead`,不会把 URL 或凭据写入草稿。
471
+
472
+ 非交互、CI 和 AI 调用必须提供 `--spec`。spec 使用 `schemaVersion: 1`,不得包含 Token、密码、
473
+ SCM credential 或 secret ref:
474
+
475
+ ```bash
476
+ # 只保存草稿并预检,不产生仓库、分支或 Jenkins 等外部副作用
477
+ numa app onboard --spec onboarding.json --plan --json
478
+
479
+ # 接续 Web/TUI 中已保存的同一草稿;使用服务端最新 revision,避免静默覆盖
480
+ numa app onboard --session <session-no> --spec onboarding.json --plan --json
481
+
482
+ # 一步式使用服务端最新 planHash 提交异步执行;幂等键为必填
483
+ numa app onboard \
484
+ --spec onboarding.json \
485
+ --apply \
486
+ --idempotency-key app-order-20260819 \
487
+ --json
488
+ ```
489
+
490
+ 自动化更推荐先运行 `--plan`、保存返回的 `session_no`,再明确提交该会话。这样即使网络在
491
+ apply 返回前中断,也可以对同一会话复用原幂等键,而不会重新创建草稿:
492
+
493
+ ```bash
494
+ numa app apply <session-no> --idempotency-key app-order-20260819 --json
495
+ numa app inspect <session-no> --watch --after-sequence 42
496
+ numa app resume <session-no> --json
497
+ numa app tui --session <session-no>
498
+ ```
499
+
500
+ `inspect --watch` 每次都从最后已确认的 sequence 补拉,断线重连不会重复展示事件;Ctrl+C
501
+ 只停止本地观察,不取消服务端任务。取消必须显式执行 `numa app cancel <session-no> --yes`,
502
+ 且不会回滚已经完成的外部副作用。完整 spec schema、状态机和入驻流程由 DevOps 平台的
503
+ Application Onboarding 契约定义。
504
+
505
+ SCM 目录和连接诊断使用同一身份。仓库查询支持服务端 search/cursor 分页,返回稳定的
506
+ `externalId`、`defaultBranch`、`headRevision`;向导选中仓库后会把 `headRevision` 固定为
507
+ `expectedHead`。HTTP 429 会保留服务端 `Retry-After` 诊断,Provider 未安装(501)时 TUI
508
+ 明确退回手工填写稳定标识:
509
+
510
+ ```bash
511
+ numa app scm list --provider codeup --json
512
+ numa app scm inspect codeup-main --repositories --search order --limit 50 --json
513
+ numa app scm inspect codeup-main --repositories --cursor '<next-cursor>' --limit 50 --json
514
+ numa app scm probe codeup-main --json
515
+ ```
516
+
517
+ SCM 管理接口位于 `/api/v1/admin/scm-connections`,最终权限始终由网关和后端按 canonical
518
+ Client Role 校验。metadata JSON 只允许 provider、URL、组织、auth type 以及服务端托管的
519
+ `aliyunAccountId`/`aliyunAssumeRoleId` 引用;Numa 不接收云 AK。CODEUP 必须引用
520
+ `aliyunAccountId`,没有 access token 时直接使用服务端 Aliyun identity,不写入空 credential。
521
+ GitHub App/PAT 或可选 Codeup access token 只能从 owner-only 文件或重定向 stdin 读取,禁止放在
522
+ argv、环境变量和 metadata JSON 中,且不会出现在输出或错误中:
523
+
524
+ ```bash
525
+ numa app scm create --input codeup.json --json
526
+ chmod 600 github-app.private.json
527
+ numa app scm create --input github.json --credential-file github-app.private.json --json
528
+ numa app scm rotate github-main --revision 4 --credential-stdin --yes --json < github-pat.private.json
529
+ numa app scm disable old-codeup --revision 7 --yes --json
530
+ ```
531
+
532
+ ## 应用候选收录
533
+
534
+ Jenkins 发现任务只生成可审查的应用候选,不会直接创建正式应用。Numa 对外把后续动作称为
535
+ “候选收录”(`adopt`):候选可能创建新应用,也可能合并到已有应用,同时确认候选携带的
536
+ Jenkins Job 绑定。“转正”容易与 npm 发布晋级、环境晋级或人员状态混淆,因此不作为 CLI
537
+ 命令和用户提示;服务端继续使用既有 `/promote` API 与审计事件,保持兼容。
538
+
539
+ 先查询候选和所需目录 ID:
540
+
541
+ ```bash
542
+ numa app options team --search platform --json
543
+ numa app options system --json
544
+ numa profile --json
545
+
546
+ numa app candidate list --status new --json
547
+ numa app candidate inspect 123 --json
548
+ ```
549
+
550
+ `candidate list` 仅返回 `APPLICATION` 类型候选;列表中的 `id` 是后续操作使用的稳定候选 ID,
551
+ 不等同于 Jenkins Job ID 或 Build Number。Job ID、环境层及绑定证据来自候选的
552
+ `proposed_relationships`,CLI 不要求用户重复填写。
553
+
554
+ 收录必须先通过服务端预检,并在写入时显式确认:
555
+
556
+ ```bash
557
+ numa app candidate preview 123 --json
558
+ numa app candidate adopt 123 --yes --json
559
+
560
+ # 最多批量处理 200 个候选;任一预检阻断时不会提交本批收录
561
+ numa app candidate adopt 123 124 --yes --json
562
+ ```
563
+
564
+ 如果候选缺少名称、环境证据不明确,或需要合并到已有应用,先 `inspect` 获取完整候选与
565
+ `version`,再用完整 review JSON 和乐观锁版本提交修复:
566
+
567
+ ```bash
568
+ numa app candidate review 123 \
569
+ --input candidate-review.json \
570
+ --revision 4 \
571
+ --json
572
+ ```
573
+
574
+ review JSON 必须包含 `operation`、`proposedFields`、`proposedRelationships` 和 `confidence`,
575
+ 且禁止嵌入凭据或 secret 引用。最终 Scope、候选状态、Job 时效性、CREATE/MERGE 冲突、逐候选
576
+ 事务和审计记录均由网关及 DevOps 后端校验,CLI 本地隐藏或显示命令不构成授权。
577
+
454
578
  ## Jenkins 流水线与生产操作
455
579
 
456
580
  `numa pipeline` 通过平台授权代理查询和操作 Jenkins。CLI 不接收 Jenkins 用户名、Token 或
@@ -216,8 +216,8 @@ export function registerAiRegistryCommands(program) {
216
216
  await new AiRegistryClient(loadConfig("aiRegistry")).deleteNamespace(namespaceId);
217
217
  await output(command, { ok: true, deleted: { id: namespaceId } }, `namespace 已删除: ${namespaceId}`);
218
218
  }), ["numa registry namespaces delete 7 --yes --json"]);
219
- const skill = registry.command("skill").description("查看、上传、治理和安装 Nacos Skills");
220
- addExamples(skill.command("list")
219
+ const skills = program.command("skills").description("查看、上传、治理和安装 Nacos Skills");
220
+ addExamples(skills.command("list")
221
221
  .option("-n, --namespace <key>", "namespaceKey")
222
222
  .option("-i, --instance <id-or-code>", "同名 namespace 的实例消歧")
223
223
  .option("-q, --search <text>", "搜索关键词")
@@ -233,8 +233,8 @@ export function registerAiRegistryCommands(program) {
233
233
  });
234
234
  const items = pageItems(result);
235
235
  await output(command, { ok: true, namespace: targetNamespace, skills: result }, items.map((item, index) => itemName(item, `skill-${index + 1}`)).join("\n") || "没有找到 Skill");
236
- }), ["numa registry skill list --namespace team-ai --search deploy --json"]);
237
- addExamples(skill.command("inspect <name>")
236
+ }), ["numa skills list --namespace team-ai --search deploy --json"]);
237
+ addExamples(skills.command("inspect <name>")
238
238
  .option("-n, --namespace <key>", "namespaceKey")
239
239
  .option("-i, --instance <id-or-code>", "同名 namespace 的实例消歧")
240
240
  .action(async (name, options, command) => {
@@ -242,8 +242,8 @@ export function registerAiRegistryCommands(program) {
242
242
  const targetNamespace = await resolveNamespace(client, options);
243
243
  const result = await client.getSkill(targetNamespace.id, name);
244
244
  await output(command, { ok: true, namespace: targetNamespace, skill: result }, JSON.stringify(sanitizeRegistryOutput(result), null, 2));
245
- }), ["numa registry skill inspect release-helper --namespace team-ai --json"]);
246
- addExamples(skill.command("install <name>")
245
+ }), ["numa skills inspect release-helper --namespace team-ai --json"]);
246
+ addExamples(skills.command("install <name>")
247
247
  .option("-n, --namespace <key>", "namespaceKey")
248
248
  .option("-i, --instance <id-or-code>", "同名 namespace 的实例消歧")
249
249
  .requiredOption("-a, --agent <agent>", "chatgpt|codex|claude|cursor|workbuddy|openclaw|agents|custom")
@@ -270,10 +270,10 @@ export function registerAiRegistryCommands(program) {
270
270
  }, version, download.sha256, result.installedPath);
271
271
  await output(command, { ok: true, namespace: context.namespace, resolvedVersion: version, download: { sha256: download.sha256, fileName: download.fileName }, installation: result, lock }, `已安装 ${name}@${version}: ${result.installedPath}${result.backupPath ? `\n原版本备份: ${result.backupPath}` : ""}`);
272
272
  }), [
273
- "numa registry skill install release-helper --namespace team-ai --agent claude",
274
- "numa registry skill install release-helper --namespace team-ai --instance cluster-b --agent cursor --scope user --label latest --json"
273
+ "numa skills install release-helper --namespace team-ai --agent claude",
274
+ "numa skills install release-helper --namespace team-ai --instance cluster-b --agent cursor --scope user --label latest --json"
275
275
  ]);
276
- addExamples(skill.command("draft <name>")
276
+ addExamples(skills.command("draft <name>")
277
277
  .option("-n, --namespace <key>", "namespaceKey")
278
278
  .option("-i, --instance <id-or-code>", "同名 namespace 的实例消歧")
279
279
  .option("--from-version <semver>", "从在线版本创建草稿")
@@ -282,8 +282,8 @@ export function registerAiRegistryCommands(program) {
282
282
  const targetNamespace = await resolveNamespace(client, options);
283
283
  const result = await client.createSkillDraft(targetNamespace.id, name, { baseVersion: options.fromVersion });
284
284
  await output(command, { ok: true, namespace: targetNamespace, result }, `Skill ${name} 草稿已创建`);
285
- }), ["numa registry skill draft release-helper --from-version 1.0.0 --json"]);
286
- addExamples(skill.command("upload <zip>")
285
+ }), ["numa skills draft release-helper --from-version 1.0.0 --json"]);
286
+ addExamples(skills.command("upload <zip>")
287
287
  .option("-n, --namespace <key>", "namespaceKey")
288
288
  .option("-i, --instance <id-or-code>", "同名 namespace 的实例消歧")
289
289
  .option("--overwrite", "覆盖现有 draft")
@@ -294,9 +294,9 @@ export function registerAiRegistryCommands(program) {
294
294
  const targetNamespace = await resolveNamespace(client, options);
295
295
  const result = await client.uploadSkill(targetNamespace.id, zip, options);
296
296
  await output(command, { ok: true, namespace: targetNamespace, result }, `Skill ZIP 已上传到 ${targetNamespace.displayName}`);
297
- }), ["numa registry skill upload ./release-helper.zip --namespace team-ai --target-version 1.0.0 --json"]);
297
+ }), ["numa skills upload ./release-helper.zip --namespace team-ai --target-version 1.0.0 --json"]);
298
298
  for (const action of ["submit", "publish", "online", "offline"]) {
299
- addExamples(skill.command(`${action} <name>`)
299
+ addExamples(skills.command(`${action} <name>`)
300
300
  .option("-n, --namespace <key>", "namespaceKey")
301
301
  .option("-i, --instance <id-or-code>", "同名 namespace 的实例消歧")
302
302
  .option("--version <semver>", "版本(publish 必填)")
@@ -307,9 +307,9 @@ export function registerAiRegistryCommands(program) {
307
307
  const targetNamespace = await resolveNamespace(client, options);
308
308
  const result = await client.skillAction(targetNamespace.id, name, action, { version: options.version });
309
309
  await output(command, { ok: true, namespace: targetNamespace, result }, `Skill ${name}: ${action} 完成`);
310
- }), [`numa registry skill ${action} release-helper --namespace team-ai${action === "publish" ? " --version 1.0.0" : ""}`]);
310
+ }), [`numa skills ${action} release-helper --namespace team-ai${action === "publish" ? " --version 1.0.0" : ""}`]);
311
311
  }
312
- addExamples(skill.command("scope <name> <scope>")
312
+ addExamples(skills.command("scope <name> <scope>")
313
313
  .option("-n, --namespace <key>", "namespaceKey")
314
314
  .option("-i, --instance <id-or-code>", "同名 namespace 的实例消歧")
315
315
  .action(async (name, scope, options, command) => {
@@ -320,8 +320,8 @@ export function registerAiRegistryCommands(program) {
320
320
  const targetNamespace = await resolveNamespace(client, options);
321
321
  const result = await client.skillAction(targetNamespace.id, name, "scope", { scope: normalized });
322
322
  await output(command, { ok: true, namespace: targetNamespace, result }, `Skill ${name} scope 已更新为 ${normalized}`);
323
- }), ["numa registry skill scope release-helper PRIVATE --namespace team-ai"]);
324
- addExamples(skill.command("tags <name> <tags...>")
323
+ }), ["numa skills scope release-helper PRIVATE --namespace team-ai"]);
324
+ addExamples(skills.command("tags <name> <tags...>")
325
325
  .option("-n, --namespace <key>", "namespaceKey")
326
326
  .option("-i, --instance <id-or-code>", "同名 namespace 的实例消歧")
327
327
  .action(async (name, tags, options, command) => {
@@ -333,8 +333,8 @@ export function registerAiRegistryCommands(program) {
333
333
  const targetNamespace = await resolveNamespace(client, options);
334
334
  const result = await client.skillAction(targetNamespace.id, name, "biz-tags", { bizTags: normalized });
335
335
  await output(command, { ok: true, namespace: targetNamespace, result }, `Skill ${name} tags 已更新`);
336
- }), ["numa registry skill tags release-helper deploy java --namespace team-ai --json"]);
337
- addExamples(skill.command("labels <name> <labels...>")
336
+ }), ["numa skills tags release-helper deploy java --namespace team-ai --json"]);
337
+ addExamples(skills.command("labels <name> <labels...>")
338
338
  .option("-n, --namespace <key>", "namespaceKey")
339
339
  .option("-i, --instance <id-or-code>", "同名 namespace 的实例消歧")
340
340
  .requiredOption("--version <semver>", "绑定标签的精确版本")
@@ -346,8 +346,8 @@ export function registerAiRegistryCommands(program) {
346
346
  const targetNamespace = await resolveNamespace(client, options);
347
347
  const result = await client.skillAction(targetNamespace.id, name, "labels", { version: options.version, labels: normalized });
348
348
  await output(command, { ok: true, namespace: targetNamespace, result }, `Skill ${name}@${options.version} labels 已更新`);
349
- }), ["numa registry skill labels release-helper latest stable --version 1.2.0 --json"]);
350
- addExamples(skill.command("delete <name>")
349
+ }), ["numa skills labels release-helper latest stable --version 1.2.0 --json"]);
350
+ addExamples(skills.command("delete <name>")
351
351
  .option("-n, --namespace <key>", "namespaceKey")
352
352
  .option("-i, --instance <id-or-code>", "同名 namespace 的实例消歧")
353
353
  .option("--yes", "确认不可逆的远端删除")
@@ -358,8 +358,8 @@ export function registerAiRegistryCommands(program) {
358
358
  const targetNamespace = await resolveNamespace(client, options);
359
359
  const result = await client.skillAction(targetNamespace.id, name, "delete");
360
360
  await output(command, { ok: true, namespace: targetNamespace, result }, `Skill ${name} 已从远端删除`);
361
- }), ["numa registry skill delete obsolete-skill --namespace team-ai --yes --json"]);
362
- const mcp = registry.command("mcp").description("查看、维护和安装 Nacos MCP Servers");
361
+ }), ["numa skills delete obsolete-skill --namespace team-ai --yes --json"]);
362
+ const mcp = program.command("mcp").description("查看、维护和安装 Nacos MCP Servers");
363
363
  addExamples(mcp.command("list")
364
364
  .option("-n, --namespace <key>", "namespaceKey")
365
365
  .option("-i, --instance <id-or-code>", "同名 namespace 的实例消歧")
@@ -375,7 +375,7 @@ export function registerAiRegistryCommands(program) {
375
375
  pageSize: positiveInteger(options.limit, "limit", 20, 100)
376
376
  });
377
377
  await output(command, { ok: true, namespace: targetNamespace, mcpServers: result }, pageItems(result).map((item, index) => itemName(item, `mcp-${index + 1}`)).join("\n") || "没有找到 MCP Server");
378
- }), ["numa registry mcp list --namespace team-ai --json"]);
378
+ }), ["numa mcp list --namespace team-ai --json"]);
379
379
  addExamples(mcp.command("inspect <name>")
380
380
  .option("-n, --namespace <key>", "namespaceKey")
381
381
  .option("-i, --instance <id-or-code>", "同名 namespace 的实例消歧")
@@ -385,7 +385,7 @@ export function registerAiRegistryCommands(program) {
385
385
  const targetNamespace = await resolveNamespace(client, options);
386
386
  const result = await client.getMcpServer(targetNamespace.id, name, options.version);
387
387
  await output(command, { ok: true, namespace: targetNamespace, mcpServer: result }, JSON.stringify(sanitizeRegistryOutput(result), null, 2));
388
- }), ["numa registry mcp inspect internal-docs --namespace team-ai --json"]);
388
+ }), ["numa mcp inspect internal-docs --namespace team-ai --json"]);
389
389
  addExamples(mcp.command("install <name>")
390
390
  .option("-n, --namespace <key>", "namespaceKey")
391
391
  .option("-i, --instance <id-or-code>", "同名 namespace 的实例消歧")
@@ -421,14 +421,14 @@ export function registerAiRegistryCommands(program) {
421
421
  ? `已生成 ChatGPT MCP 安装指引: ${result.endpoint}\n${result.manualSteps.map((step, index) => `${index + 1}. ${step}`).join("\n")}`
422
422
  : `MCP ${name} 已安装${result.configPath ? `: ${result.configPath}` : "(由客户端 CLI 管理)"}${result.backupPath ? `\n原配置备份: ${result.backupPath}` : ""}`;
423
423
  await output(command, { ok: true, namespace: context.namespace, resolvedVersion: version, installation: result, lock }, textResult);
424
- }), ["numa registry mcp install internal-docs --namespace team-ai --agent cursor"]);
424
+ }), ["numa mcp install internal-docs --namespace team-ai --agent cursor"]);
425
425
  addExamples(mcp.command("bridge").description("把 namespace 企业 Router 桥接为本地 stdio MCP")
426
426
  .option("-n, --namespace <key>", "namespaceKey")
427
427
  .option("-i, --instance <id-or-code>", "同名 namespace 的实例消歧")
428
428
  .option("--workspace <path>", "项目目录")
429
429
  .action(async (options) => {
430
430
  await runMcpBridge(new AiRegistryClient(loadConfig("aiRegistry")), options);
431
- }), ["numa registry mcp bridge --namespace team-ai"]);
431
+ }), ["numa mcp bridge --namespace team-ai"]);
432
432
  for (const action of ["online", "offline"]) {
433
433
  addExamples(mcp.command(`${action} <name>`)
434
434
  .option("-n, --namespace <key>", "namespaceKey")
@@ -439,7 +439,7 @@ export function registerAiRegistryCommands(program) {
439
439
  const targetNamespace = await resolveNamespace(client, options);
440
440
  const result = await client.mcpAction(targetNamespace.id, name, action, { version: options.version });
441
441
  await output(command, { ok: true, namespace: targetNamespace, result }, `MCP ${name}: ${action} 完成`);
442
- }), [`numa registry mcp ${action} internal-docs --version 1.0.0 --json`]);
442
+ }), [`numa mcp ${action} internal-docs --version 1.0.0 --json`]);
443
443
  }
444
444
  addExamples(mcp.command("tags <name> <tags...>")
445
445
  .option("-n, --namespace <key>", "namespaceKey")
@@ -452,7 +452,7 @@ export function registerAiRegistryCommands(program) {
452
452
  const targetNamespace = await resolveNamespace(client, options);
453
453
  const result = await client.mcpAction(targetNamespace.id, name, "biz-tags", { bizTags: normalized });
454
454
  await output(command, { ok: true, namespace: targetNamespace, result }, `MCP ${name} tags 已更新`);
455
- }), ["numa registry mcp tags internal-docs knowledge search --json"]);
455
+ }), ["numa mcp tags internal-docs knowledge search --json"]);
456
456
  const tools = mcp.command("tool").description("启用或禁用 MCP 工具");
457
457
  for (const action of ["enable", "disable"]) {
458
458
  addExamples(tools.command(`${action} <mcp-name> <tool-name>`)
@@ -465,7 +465,7 @@ export function registerAiRegistryCommands(program) {
465
465
  const version = options.version == null ? undefined : nonnegativeInteger(options.version, "version");
466
466
  const result = await client.setMcpToolEnabled(targetNamespace.id, mcpName, toolName, action === "enable", version);
467
467
  await output(command, { ok: true, namespace: targetNamespace, result }, `MCP tool ${mcpName}/${toolName}: ${action} 完成`);
468
- }), [`numa registry mcp tool ${action} internal-docs search --version 3 --json`]);
468
+ }), [`numa mcp tool ${action} internal-docs search --version 3 --json`]);
469
469
  }
470
470
  addExamples(mcp.command("create <json>")
471
471
  .option("-n, --namespace <key>", "namespaceKey")
@@ -475,7 +475,7 @@ export function registerAiRegistryCommands(program) {
475
475
  const targetNamespace = await resolveNamespace(client, options);
476
476
  const result = await client.createMcpServer(targetNamespace.id, await readObject(file));
477
477
  await output(command, { ok: true, namespace: targetNamespace, result }, "MCP create 完成");
478
- }), ["numa registry mcp create ./mcp.json --namespace team-ai --json"]);
478
+ }), ["numa mcp create ./mcp.json --namespace team-ai --json"]);
479
479
  addExamples(mcp.command("update <name> <json>")
480
480
  .option("-n, --namespace <key>", "namespaceKey")
481
481
  .option("-i, --instance <id-or-code>", "同名 namespace 的实例消歧")
@@ -484,7 +484,7 @@ export function registerAiRegistryCommands(program) {
484
484
  const targetNamespace = await resolveNamespace(client, options);
485
485
  const result = await client.updateMcpServer(targetNamespace.id, name, await readObject(file));
486
486
  await output(command, { ok: true, namespace: targetNamespace, result }, "MCP update 完成");
487
- }), ["numa registry mcp update internal-docs ./mcp.json --namespace team-ai --json"]);
487
+ }), ["numa mcp update internal-docs ./mcp.json --namespace team-ai --json"]);
488
488
  addExamples(mcp.command("delete <name>")
489
489
  .option("-n, --namespace <key>", "namespaceKey")
490
490
  .option("-i, --instance <id-or-code>", "同名 namespace 的实例消歧")
@@ -497,7 +497,7 @@ export function registerAiRegistryCommands(program) {
497
497
  const targetNamespace = await resolveNamespace(client, options);
498
498
  const result = await client.deleteMcpServer(targetNamespace.id, name, options.version);
499
499
  await output(command, { ok: true, namespace: targetNamespace, result }, `MCP ${name} 已从远端删除`);
500
- }), ["numa registry mcp delete obsolete --namespace team-ai --yes --json"]);
500
+ }), ["numa mcp delete obsolete --namespace team-ai --yes --json"]);
501
501
  const approvals = registry.command("approvals").description("查看、审核和发布两人制 release request");
502
502
  addExamples(approvals.command("submit <type> <name>")
503
503
  .option("-n, --namespace <key>", "namespaceKey")