@ykdz/template 0.0.37 → 0.0.40

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 (225) hide show
  1. package/dist/application.d.ts +1 -52
  2. package/dist/application.js +0 -81
  3. package/dist/cli.js +14 -28
  4. package/dist/input-schemas.d.ts +30 -0
  5. package/dist/input-schemas.js +75 -0
  6. package/dist/main.d.ts +3 -14
  7. package/dist/main.js +496 -378
  8. package/dist/result-schemas.d.ts +222 -0
  9. package/dist/result-schemas.js +74 -0
  10. package/dist/standard-schema.d.ts +3 -0
  11. package/dist/standard-schema.js +29 -0
  12. package/node_modules/@standard-schema/spec/LICENSE +21 -0
  13. package/node_modules/@standard-schema/spec/README.md +198 -0
  14. package/node_modules/@standard-schema/spec/dist/index.cjs +18 -0
  15. package/node_modules/@standard-schema/spec/dist/index.d.cts +119 -0
  16. package/node_modules/@standard-schema/spec/dist/index.d.ts +119 -0
  17. package/node_modules/@standard-schema/spec/dist/index.js +0 -0
  18. package/node_modules/@standard-schema/spec/package.json +52 -0
  19. package/node_modules/@types/node/LICENSE +21 -0
  20. package/node_modules/@types/node/README.md +15 -0
  21. package/node_modules/@types/node/assert/strict.d.ts +111 -0
  22. package/node_modules/@types/node/assert.d.ts +1115 -0
  23. package/node_modules/@types/node/async_hooks.d.ts +619 -0
  24. package/node_modules/@types/node/buffer.buffer.d.ts +477 -0
  25. package/node_modules/@types/node/buffer.d.ts +1941 -0
  26. package/node_modules/@types/node/child_process.d.ts +1480 -0
  27. package/node_modules/@types/node/cluster.d.ts +578 -0
  28. package/node_modules/@types/node/compatibility/iterators.d.ts +21 -0
  29. package/node_modules/@types/node/console.d.ts +453 -0
  30. package/node_modules/@types/node/constants.d.ts +21 -0
  31. package/node_modules/@types/node/crypto.d.ts +5484 -0
  32. package/node_modules/@types/node/dgram.d.ts +715 -0
  33. package/node_modules/@types/node/diagnostics_channel.d.ts +576 -0
  34. package/node_modules/@types/node/dns/promises.d.ts +503 -0
  35. package/node_modules/@types/node/dns.d.ts +923 -0
  36. package/node_modules/@types/node/domain.d.ts +166 -0
  37. package/node_modules/@types/node/events.d.ts +967 -0
  38. package/node_modules/@types/node/fs/promises.d.ts +1354 -0
  39. package/node_modules/@types/node/fs.d.ts +4777 -0
  40. package/node_modules/@types/node/globals.d.ts +170 -0
  41. package/node_modules/@types/node/globals.typedarray.d.ts +41 -0
  42. package/node_modules/@types/node/http.d.ts +2246 -0
  43. package/node_modules/@types/node/http2.d.ts +2882 -0
  44. package/node_modules/@types/node/https.d.ts +585 -0
  45. package/node_modules/@types/node/index.d.ts +101 -0
  46. package/node_modules/@types/node/inspector.d.ts +323 -0
  47. package/node_modules/@types/node/inspector.generated.d.ts +4406 -0
  48. package/node_modules/@types/node/module.d.ts +844 -0
  49. package/node_modules/@types/node/net.d.ts +1197 -0
  50. package/node_modules/@types/node/os.d.ts +507 -0
  51. package/node_modules/@types/node/package.json +140 -0
  52. package/node_modules/@types/node/path.d.ts +200 -0
  53. package/node_modules/@types/node/perf_hooks.d.ts +1054 -0
  54. package/node_modules/@types/node/process.d.ts +2101 -0
  55. package/node_modules/@types/node/punycode.d.ts +117 -0
  56. package/node_modules/@types/node/querystring.d.ts +152 -0
  57. package/node_modules/@types/node/readline/promises.d.ts +161 -0
  58. package/node_modules/@types/node/readline.d.ts +600 -0
  59. package/node_modules/@types/node/repl.d.ts +438 -0
  60. package/node_modules/@types/node/sea.d.ts +162 -0
  61. package/node_modules/@types/node/sqlite.d.ts +1182 -0
  62. package/node_modules/@types/node/stream/consumers.d.ts +45 -0
  63. package/node_modules/@types/node/stream/promises.d.ts +90 -0
  64. package/node_modules/@types/node/stream/web.d.ts +596 -0
  65. package/node_modules/@types/node/stream.d.ts +1707 -0
  66. package/node_modules/@types/node/string_decoder.d.ts +67 -0
  67. package/node_modules/@types/node/test.d.ts +2656 -0
  68. package/node_modules/@types/node/timers/promises.d.ts +108 -0
  69. package/node_modules/@types/node/timers.d.ts +285 -0
  70. package/node_modules/@types/node/tls.d.ts +1314 -0
  71. package/node_modules/@types/node/trace_events.d.ts +197 -0
  72. package/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +473 -0
  73. package/node_modules/@types/node/ts5.6/compatibility/float16array.d.ts +71 -0
  74. package/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +36 -0
  75. package/node_modules/@types/node/ts5.6/index.d.ts +103 -0
  76. package/node_modules/@types/node/ts5.7/compatibility/float16array.d.ts +72 -0
  77. package/node_modules/@types/node/ts5.7/index.d.ts +103 -0
  78. package/node_modules/@types/node/tty.d.ts +209 -0
  79. package/node_modules/@types/node/url.d.ts +1103 -0
  80. package/node_modules/@types/node/util.d.ts +2376 -0
  81. package/node_modules/@types/node/v8.d.ts +1010 -0
  82. package/node_modules/@types/node/vm.d.ts +1160 -0
  83. package/node_modules/@types/node/wasi.d.ts +202 -0
  84. package/node_modules/@types/node/web-globals/abortcontroller.d.ts +34 -0
  85. package/node_modules/@types/node/web-globals/crypto.d.ts +32 -0
  86. package/node_modules/@types/node/web-globals/domexception.d.ts +68 -0
  87. package/node_modules/@types/node/web-globals/events.d.ts +97 -0
  88. package/node_modules/@types/node/web-globals/fetch.d.ts +62 -0
  89. package/node_modules/@types/node/web-globals/navigator.d.ts +25 -0
  90. package/node_modules/@types/node/web-globals/storage.d.ts +24 -0
  91. package/node_modules/@types/node/web-globals/streams.d.ts +22 -0
  92. package/node_modules/@types/node/worker_threads.d.ts +894 -0
  93. package/node_modules/@types/node/zlib.d.ts +768 -0
  94. package/node_modules/@valibot/to-json-schema/LICENSE.md +9 -0
  95. package/node_modules/@valibot/to-json-schema/README.md +475 -0
  96. package/node_modules/@valibot/to-json-schema/dist/index.cjs +800 -0
  97. package/node_modules/@valibot/to-json-schema/dist/index.d.cts +991 -0
  98. package/node_modules/@valibot/to-json-schema/dist/index.d.mts +991 -0
  99. package/node_modules/@valibot/to-json-schema/dist/index.min.cjs +1 -0
  100. package/node_modules/@valibot/to-json-schema/dist/index.min.mjs +1 -0
  101. package/node_modules/@valibot/to-json-schema/dist/index.mjs +795 -0
  102. package/node_modules/@valibot/to-json-schema/package.json +75 -0
  103. package/node_modules/@ykdz/cli-contract/LICENSE +21 -0
  104. package/node_modules/@ykdz/cli-contract/dist/atomic-variant-compiler.d.ts +17 -0
  105. package/node_modules/@ykdz/cli-contract/dist/atomic-variant-compiler.js +55 -0
  106. package/node_modules/@ykdz/cli-contract/dist/cli-contract.d.ts +1164 -0
  107. package/node_modules/@ykdz/cli-contract/dist/cli-contract.js +1408 -0
  108. package/node_modules/@ykdz/cli-contract/dist/cli-execution.d.ts +54 -0
  109. package/node_modules/@ykdz/cli-contract/dist/cli-execution.js +708 -0
  110. package/node_modules/@ykdz/cli-contract/dist/cli-invocation.d.ts +174 -0
  111. package/node_modules/@ykdz/cli-contract/dist/cli-invocation.js +524 -0
  112. package/node_modules/@ykdz/cli-contract/dist/cli-write-error.d.ts +10 -0
  113. package/node_modules/@ykdz/cli-contract/dist/cli-write-error.js +14 -0
  114. package/node_modules/@ykdz/cli-contract/dist/contract-definition-error.d.ts +260 -0
  115. package/node_modules/@ykdz/cli-contract/dist/contract-definition-error.js +130 -0
  116. package/node_modules/@ykdz/cli-contract/dist/contract-execution-error.d.ts +63 -0
  117. package/node_modules/@ykdz/cli-contract/dist/contract-execution-error.js +17 -0
  118. package/node_modules/@ykdz/cli-contract/dist/contract-schema-compiler.d.ts +6 -0
  119. package/node_modules/@ykdz/cli-contract/dist/contract-schema-compiler.js +532 -0
  120. package/node_modules/@ykdz/cli-contract/dist/contract-schema.d.ts +14 -0
  121. package/node_modules/@ykdz/cli-contract/dist/contract-schema.js +1 -0
  122. package/node_modules/@ykdz/cli-contract/dist/description.d.ts +2 -0
  123. package/node_modules/@ykdz/cli-contract/dist/description.js +13 -0
  124. package/node_modules/@ykdz/cli-contract/dist/index.d.ts +8 -0
  125. package/node_modules/@ykdz/cli-contract/dist/index.js +7 -0
  126. package/node_modules/@ykdz/cli-contract/dist/json-value.d.ts +4 -0
  127. package/node_modules/@ykdz/cli-contract/dist/json-value.js +64 -0
  128. package/node_modules/@ykdz/cli-contract/dist/node.d.ts +21 -0
  129. package/node_modules/@ykdz/cli-contract/dist/node.js +109 -0
  130. package/node_modules/@ykdz/cli-contract/dist/outcome-fact.d.ts +162 -0
  131. package/node_modules/@ykdz/cli-contract/dist/outcome-fact.js +113 -0
  132. package/node_modules/@ykdz/cli-contract/dist/outcome-wire.d.ts +53 -0
  133. package/node_modules/@ykdz/cli-contract/dist/outcome-wire.js +189 -0
  134. package/node_modules/@ykdz/cli-contract/dist/stream-variant-compiler.d.ts +16 -0
  135. package/node_modules/@ykdz/cli-contract/dist/stream-variant-compiler.js +45 -0
  136. package/node_modules/@ykdz/cli-contract/package.json +69 -0
  137. package/node_modules/@ykdz/template-builtin-presets/dist/src/foundation.d.ts +20 -0
  138. package/node_modules/@ykdz/template-builtin-presets/dist/src/foundation.js +27 -28
  139. package/node_modules/@ykdz/template-builtin-presets/dist/src/generation-record.d.ts +19 -0
  140. package/node_modules/@ykdz/template-builtin-presets/dist/src/generation-record.js +1 -1
  141. package/node_modules/@ykdz/template-builtin-presets/dist/src/index.d.ts +2 -1
  142. package/node_modules/@ykdz/template-builtin-presets/dist/src/index.js +2 -1
  143. package/node_modules/@ykdz/template-builtin-presets/dist/src/ts-cli/definition.js +9 -5
  144. package/node_modules/@ykdz/template-builtin-presets/dist/src/vike-app/definition.js +0 -4
  145. package/node_modules/@ykdz/template-builtin-presets/package.json +2 -1
  146. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/AGENTS.md.template +10 -4
  147. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/devcontainer.json +3 -0
  148. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/artifact.ts +128 -59
  149. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/handoff.ts +80 -8
  150. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/readiness.ts +7 -3
  151. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/src/cli.ts +9 -19
  152. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/src/main.ts +144 -60
  153. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/src/standard-schema.ts +37 -0
  154. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/e2e/journeys/lookup.journey.ts +71 -0
  155. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/integration/command.test.ts +118 -59
  156. package/node_modules/@ykdz/template-core/dist/package-contribution.d.ts +0 -1
  157. package/node_modules/@ykdz/template-core/dist/pnpm-workspace.yaml +2 -1
  158. package/node_modules/@ykdz/template-core/dist/project-blueprint.d.ts +15 -0
  159. package/node_modules/@ykdz/template-core/dist/project-blueprint.js +1 -1
  160. package/node_modules/@ykdz/template-core/dist/project-github.d.ts +1 -1
  161. package/node_modules/undici-types/LICENSE +21 -0
  162. package/node_modules/undici-types/README.md +6 -0
  163. package/node_modules/undici-types/agent.d.ts +32 -0
  164. package/node_modules/undici-types/api.d.ts +43 -0
  165. package/node_modules/undici-types/balanced-pool.d.ts +30 -0
  166. package/node_modules/undici-types/cache-interceptor.d.ts +179 -0
  167. package/node_modules/undici-types/cache.d.ts +36 -0
  168. package/node_modules/undici-types/client-stats.d.ts +15 -0
  169. package/node_modules/undici-types/client.d.ts +123 -0
  170. package/node_modules/undici-types/connector.d.ts +36 -0
  171. package/node_modules/undici-types/content-type.d.ts +21 -0
  172. package/node_modules/undici-types/cookies.d.ts +30 -0
  173. package/node_modules/undici-types/diagnostics-channel.d.ts +74 -0
  174. package/node_modules/undici-types/dispatcher.d.ts +279 -0
  175. package/node_modules/undici-types/env-http-proxy-agent.d.ts +22 -0
  176. package/node_modules/undici-types/errors.d.ts +177 -0
  177. package/node_modules/undici-types/eventsource.d.ts +66 -0
  178. package/node_modules/undici-types/fetch.d.ts +211 -0
  179. package/node_modules/undici-types/formdata.d.ts +108 -0
  180. package/node_modules/undici-types/global-dispatcher.d.ts +9 -0
  181. package/node_modules/undici-types/global-origin.d.ts +7 -0
  182. package/node_modules/undici-types/h2c-client.d.ts +73 -0
  183. package/node_modules/undici-types/handlers.d.ts +15 -0
  184. package/node_modules/undici-types/header.d.ts +160 -0
  185. package/node_modules/undici-types/index.d.ts +91 -0
  186. package/node_modules/undici-types/interceptors.d.ts +80 -0
  187. package/node_modules/undici-types/mock-agent.d.ts +68 -0
  188. package/node_modules/undici-types/mock-call-history.d.ts +111 -0
  189. package/node_modules/undici-types/mock-client.d.ts +27 -0
  190. package/node_modules/undici-types/mock-errors.d.ts +12 -0
  191. package/node_modules/undici-types/mock-interceptor.d.ts +94 -0
  192. package/node_modules/undici-types/mock-pool.d.ts +27 -0
  193. package/node_modules/undici-types/package.json +55 -0
  194. package/node_modules/undici-types/patch.d.ts +29 -0
  195. package/node_modules/undici-types/pool-stats.d.ts +19 -0
  196. package/node_modules/undici-types/pool.d.ts +41 -0
  197. package/node_modules/undici-types/proxy-agent.d.ts +29 -0
  198. package/node_modules/undici-types/readable.d.ts +68 -0
  199. package/node_modules/undici-types/retry-agent.d.ts +8 -0
  200. package/node_modules/undici-types/retry-handler.d.ts +125 -0
  201. package/node_modules/undici-types/round-robin-pool.d.ts +41 -0
  202. package/node_modules/undici-types/snapshot-agent.d.ts +109 -0
  203. package/node_modules/undici-types/socks5-proxy-agent.d.ts +25 -0
  204. package/node_modules/undici-types/util.d.ts +18 -0
  205. package/node_modules/undici-types/utility.d.ts +7 -0
  206. package/node_modules/undici-types/webidl.d.ts +347 -0
  207. package/node_modules/undici-types/websocket.d.ts +188 -0
  208. package/package.json +5 -3
  209. package/dist/command-result.d.ts +0 -9
  210. package/dist/command-result.js +0 -231
  211. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/e2e/journeys/greet.journey.ts +0 -46
  212. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/unit/greet.test.ts +0 -15
  213. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/devcontainer/docker-client.Dockerfile +0 -3
  214. package/node_modules/commander/LICENSE +0 -22
  215. package/node_modules/commander/Readme.md +0 -1172
  216. package/node_modules/commander/index.js +0 -21
  217. package/node_modules/commander/lib/argument.js +0 -147
  218. package/node_modules/commander/lib/command.js +0 -2790
  219. package/node_modules/commander/lib/error.js +0 -36
  220. package/node_modules/commander/lib/help.js +0 -731
  221. package/node_modules/commander/lib/option.js +0 -377
  222. package/node_modules/commander/lib/suggestSimilar.js +0 -99
  223. package/node_modules/commander/package-support.json +0 -19
  224. package/node_modules/commander/package.json +0 -64
  225. package/node_modules/commander/typings/index.d.ts +0 -1113
package/dist/main.js CHANGED
@@ -1,401 +1,519 @@
1
- import { Command, CommanderError } from "commander";
2
- import { listPresetCatalog, runAddPackage, runInit, validateBlueprintFile, } from "./application.js";
3
- import { projectCommandResult, } from "./command-result.js";
4
- class HandledCliExit extends Error {
5
- exitCode;
6
- constructor(exitCode) {
7
- super(`CLI exited with status ${exitCode}`);
8
- this.exitCode = exitCode;
9
- }
10
- }
11
- class OutputFailure extends Error {
12
- destination;
13
- epiped;
14
- constructor(destination, error) {
15
- super("Unable to write CLI output");
16
- this.destination = destination;
17
- this.epiped =
18
- typeof error === "object" && error !== null && "code" in error
19
- ? error.code === "EPIPE"
20
- : false;
21
- }
22
- }
23
- class ConfirmationFailure extends Error {
24
- constructor() {
25
- super("Confirmation adapter failed");
26
- }
27
- }
28
- function isConfirmationOutputResourceFailure(error) {
29
- if (typeof error !== "object" || error === null || !("code" in error)) {
30
- return false;
31
- }
32
- return error.code === "EPIPE" || error.code === "ENOSPC";
33
- }
34
- class HumanCommandIdentity {
35
- #runtime;
36
- #written = false;
37
- constructor(runtime) {
38
- this.#runtime = runtime;
39
- }
40
- write(destination) {
41
- if (this.#written)
42
- return;
43
- this.#written = true;
44
- this.#write(destination, `template ${this.#runtime.version}\n`);
45
- }
46
- writeText(destination, text) {
47
- this.write(destination);
48
- this.#write(destination, text);
49
- }
50
- #write(destination, text) {
51
- try {
52
- this.#runtime.streams[destination].write(text);
53
- }
54
- catch (error) {
55
- throw new OutputFailure(destination, error);
56
- }
57
- }
58
- }
59
- function commandName(argv) {
60
- const [first, second] = argv.slice(2);
61
- if (first === "init" || first === "presets")
62
- return first;
63
- if (first === "add")
64
- return second === "package" ? "add package" : "add";
65
- if (first === "blueprint") {
66
- return second === "validate" ? "blueprint validate" : "blueprint";
67
- }
68
- return "template";
1
+ import { CliWriteError, defineCli, executeCli, helpCapability, outputCapability, parseCliInvocation, text, versionCapability, } from "@ykdz/cli-contract";
2
+ import { isNodeBrokenPipe } from "@ykdz/cli-contract/node";
3
+ import * as v from "valibot";
4
+ import { listPresetCatalog, runInit, runAddPackage, validateBlueprintFile, } from "./application.js";
5
+ import { initializationInputSchema, packageAdditionInputSchema, } from "./input-schemas.js";
6
+ import { initializationSchema, packageAdditionSchema, packageConflictSchema, } from "./result-schemas.js";
7
+ import { standardSchema } from "./standard-schema.js";
8
+ function initializationDetails(result) {
9
+ return [
10
+ `预设: ${result.resolved.preset}`,
11
+ `Scope: ${result.resolved.scope}`,
12
+ ...result.resolved.packages.map(({ name, path }) => `包: ${name}(${path})`),
13
+ `工具链: Node ${result.toolchain.nodeVersion};${result.toolchain.packageManagerPin}`,
14
+ `跟进文档: ${result.followUpDocument.enabled ? result.followUpDocument.path : "不生成"}`,
15
+ ];
69
16
  }
70
- function hasJsonControlIntent(argv) {
71
- return argv.slice(2).includes("--json");
72
- }
73
- function localizeHelp(text) {
74
- return text
75
- .replaceAll("Usage:", "用法:")
76
- .replaceAll("Options:", "选项:")
77
- .replaceAll("Commands:", "命令:")
78
- .replaceAll("output the version number", "输出版本号")
79
- .replaceAll("display help for command", "显示命令帮助")
80
- .replaceAll("Resolve a Preset, initial package name and path, and package scope before initialization.", "初始化前解析预设、初始包名称、路径和包 scope。")
81
- .replaceAll("Project preset to generate", "要生成的项目预设")
82
- .replaceAll("Unscoped leaf name when the Preset supports Primary Package Identity overrides", "预设支持主包身份覆盖时使用的无 scope 叶名称")
83
- .replaceAll("Two-segment path when the Preset supports Primary Package Identity overrides", "预设支持主包身份覆盖时使用的两段路径")
84
- .replaceAll("Resolved default package scope", "解析后的默认包 scope")
85
- .replaceAll("Accept defaults for non-interactive generation", "接受非交互式生成的默认值")
86
- .replaceAll("Print the planned generation without writing files", "打印生成计划而不写文件")
87
- .replaceAll("Print machine-readable output", "输出机器可读结果")
88
- .replaceAll("Do not write the generated follow-up TODO.md", "不写入生成后的 TODO.md")
89
- .replaceAll("Add to a Generated Repository; package supports --dry-run and --json.", "向生成仓库添加内容;package 支持 --dry-run 和 --json。")
90
- .replaceAll("Add a Package Boundary.", "添加一个 Package Boundary。")
91
- .replaceAll("Package preset to add", "要添加的 Package 预设")
92
- .replaceAll("Package name to add", "要添加的 Package 名称")
93
- .replaceAll("Two-segment Package Path to add", "要添加的两段 Package Path")
94
- .replaceAll("Existing consumer Package Path to link from; repeatable", "要链接的现有 consumer Package Path;可重复传入")
95
- .replaceAll("Preview the Addition Delta without writing files", "预览 Addition Delta 而不写文件")
96
- .replaceAll("List Built-in Presets.", "列出内置预设。")
97
- .replaceAll("Work with Project Blueprints.", "处理 Project Blueprint。")
98
- .replaceAll("Validate a Project Blueprint.", "校验 Project Blueprint。");
99
- }
100
- function commanderFailure(error, command, capturedError) {
101
- const usage = capturedError
102
- .split("\n")
103
- .find((line) => line.startsWith("Usage:"));
104
- const suggestion = error.message.match(/Did you mean (.+)\?/u)?.[1];
105
- const message = error.code === "commander.optionMissingArgument"
106
- ? error.message.replace(/option ('[^']+') argument missing/u, "选项 $1 缺少参数。")
107
- : error.code === "commander.excessArguments"
108
- ? `命令 ${command} 参数过多。`
109
- : error.message;
110
- const localizedMessage = message
111
- .replace(/^error:\s*/u, "")
112
- .replace(/unknown command/u, "未知命令")
113
- .replace(/unknown option/u, "未知选项")
114
- .replace(/required option/u, "缺少必需选项")
115
- .replace(/missing required argument/u, "缺少必需参数")
116
- .replace(/ not specified$/u, "。");
117
- let code = "USAGE_INVALID_INVOCATION";
118
- if (error.code === "commander.unknownCommand") {
119
- code = "USAGE_UNKNOWN_COMMAND";
120
- }
121
- else if (error.code === "commander.unknownOption") {
122
- code = "USAGE_UNKNOWN_OPTION";
123
- }
124
- else if (error.code === "commander.optionMissingArgument") {
125
- code = "USAGE_OPTION_MISSING_ARGUMENT";
126
- }
127
- else if (error.code === "commander.excessArguments") {
128
- code = "USAGE_EXCESS_ARGUMENTS";
129
- }
130
- else if (error.message.includes("required option")) {
131
- code = "USAGE_MISSING_REQUIRED_OPTION";
132
- }
133
- else if (error.message.includes("required argument")) {
134
- code = "USAGE_MISSING_REQUIRED_ARGUMENT";
135
- }
136
- return {
137
- code,
138
- command,
139
- message: localizedMessage,
140
- ...(suggestion === undefined
141
- ? {}
142
- : { suggestion: `Did you mean ${suggestion}?` }),
143
- ...(usage === undefined
144
- ? {}
145
- : { usage: localizeHelp(usage).replace(/^用法:\s*/u, "") }),
146
- };
147
- }
148
- function applicationFailure(error, command) {
149
- return {
150
- code: "OPERATION_INTERNAL_ERROR",
151
- command,
152
- message: "命令遇到了内部错误;请重试,若持续发生请人工处理。",
153
- };
154
- }
155
- function exitCodeForOutputFailure(error) {
156
- return error.destination === "stdout" && error.epiped ? 0 : 65;
157
- }
158
- function writeFailure(runtime, identity, json, failure) {
159
- if (json) {
160
- try {
161
- runtime.streams.stdout.write(`${JSON.stringify({
162
- schemaVersion: 1,
163
- cliVersion: runtime.version,
164
- command: failure.command,
165
- code: failure.code,
166
- status: "error",
167
- error: {
168
- message: failure.message,
169
- ...(failure.suggestion === undefined
170
- ? {}
171
- : { suggestion: failure.suggestion }),
172
- ...(failure.usage === undefined ? {} : { usage: failure.usage }),
17
+ function createCliContract(runtime) {
18
+ const define = defineCli();
19
+ return define({
20
+ root: "template",
21
+ help: helpCapability({
22
+ shortAlias: "-h",
23
+ headings: {
24
+ usage: "用法",
25
+ commands: "命令",
26
+ arguments: "参数",
27
+ options: "选项",
28
+ },
29
+ wording: {
30
+ commandPlaceholder: "命令",
31
+ choices: "候选:{choices}",
32
+ default: "默认:{value}",
33
+ },
34
+ }),
35
+ version: versionCapability({
36
+ value: text.line(`${runtime.commandName} ${runtime.version}`),
37
+ shortAlias: "-V",
38
+ }),
39
+ output: outputCapability({ defaultFormat: "structured", text: true }),
40
+ usageFailureExitCode: 2,
41
+ commands: {
42
+ template: {
43
+ kind: "rootGroup",
44
+ name: runtime.commandName,
45
+ description: "生成和维护项目仓库。",
46
+ },
47
+ ...define.command("init")({
48
+ kind: "command",
49
+ parent: "template",
50
+ name: "init",
51
+ description: "初始化项目仓库。",
52
+ input: initializationInputSchema(runtime.cwd),
53
+ fields: {
54
+ dir: { kind: "positional", description: "目标目录" },
55
+ preset: {
56
+ kind: "valueOption",
57
+ longOption: "--preset",
58
+ description: "项目预设",
59
+ },
60
+ name: {
61
+ kind: "valueOption",
62
+ longOption: "--name",
63
+ description: "无 scope 的 npm 包叶名称;仅可配置主包的预设支持覆盖",
64
+ },
65
+ path: {
66
+ kind: "valueOption",
67
+ longOption: "--path",
68
+ description: "两个安全路径段,不能使用保留目录;仅可配置主包的预设支持覆盖",
69
+ },
70
+ scope: {
71
+ kind: "valueOption",
72
+ longOption: "--scope",
73
+ description: "有效 npm scope;省略时使用目标目录名",
74
+ },
75
+ dryRun: {
76
+ kind: "flag",
77
+ longOption: "--dry-run",
78
+ description: "预览生成计划",
79
+ },
80
+ todo: {
81
+ kind: "flag",
82
+ longOption: "--todo",
83
+ negatedLongOption: "--no-todo",
84
+ description: "生成后续步骤文档",
85
+ },
173
86
  },
174
- })}\n`);
175
- return;
176
- }
177
- catch (error) {
178
- throw new OutputFailure("stdout", error);
179
- }
180
- }
181
- const lines = [`错误 [${failure.code}]: ${failure.message}`];
182
- if (failure.suggestion !== undefined) {
183
- lines.push(`建议: ${failure.suggestion}`);
184
- }
185
- if (failure.usage !== undefined) {
186
- lines.push("", `用法: ${failure.usage}`);
187
- }
188
- identity.writeText("stderr", `${lines.join("\n")}\n`);
189
- }
190
- function writeOutput(runtime, destination, text) {
191
- try {
192
- runtime.streams[destination].write(text);
193
- }
194
- catch (error) {
195
- if (error instanceof OutputFailure)
196
- throw error;
197
- throw new OutputFailure(destination, error);
198
- }
199
- }
200
- function writeClosedCommandResult(runtime, result, json) {
201
- const presentation = projectCommandResult(result, json, runtime.version);
202
- writeOutput(runtime, presentation.destination, presentation.text);
203
- if (presentation.exitCode !== 0)
204
- throw new HandledCliExit(presentation.exitCode);
205
- }
206
- function withHumanIdentity(runtime, json) {
207
- const identity = new HumanCommandIdentity(runtime);
208
- if (json)
209
- return { runtime, identity };
210
- return {
211
- identity,
212
- runtime: {
213
- ...runtime,
214
- streams: {
215
- ...runtime.streams,
216
- stdout: {
217
- write(chunk) {
218
- identity.writeText("stdout", chunk);
87
+ success: {
88
+ kind: "data",
89
+ variants: {
90
+ initialized: {
91
+ description: "已初始化仓库",
92
+ schema: initializationSchema,
93
+ exitCode: 0,
94
+ text: (data) => text.lines([
95
+ `已初始化项目: ${data.targetDir}`,
96
+ ...initializationDetails(data),
97
+ "下一步",
98
+ ...data.nextSteps.map(({ display }) => display),
99
+ ...(data.publicationSetup === null
100
+ ? []
101
+ : ["一次性 npm 发布设置", data.publicationSetup.command]),
102
+ ]),
103
+ },
104
+ planned: {
105
+ description: "初始化预览",
106
+ schema: initializationSchema,
107
+ exitCode: 0,
108
+ text: (data) => text.lines([
109
+ `项目生成预览: ${data.targetDir}`,
110
+ ...initializationDetails(data),
111
+ ]),
112
+ },
219
113
  },
220
114
  },
221
- stderr: {
222
- write(chunk) {
223
- identity.writeText("stderr", chunk);
115
+ failures: {
116
+ operationFailed: {
117
+ description: "初始化操作失败",
118
+ exitCode: 1,
119
+ schema: standardSchema(v.object({
120
+ targetDir: v.string(),
121
+ phase: v.picklist([
122
+ "preset",
123
+ "planning",
124
+ "preflight",
125
+ "materialization",
126
+ "render",
127
+ ]),
128
+ error: v.object({
129
+ message: v.string(),
130
+ suggestion: v.string(),
131
+ }),
132
+ })),
133
+ text: ({ targetDir, error }) => text.lines([
134
+ error.message,
135
+ `目录: ${targetDir}`,
136
+ `建议: ${error.suggestion}`,
137
+ ]),
224
138
  },
225
139
  },
140
+ async handler({ input, dependencies, outcome }) {
141
+ const result = await runInit({
142
+ dir: input.dir,
143
+ preset: input.preset,
144
+ dryRun: input.dryRun,
145
+ todo: input.todo,
146
+ ...(input.name === undefined ? {} : { name: input.name }),
147
+ ...(input.path === undefined ? {} : { path: input.path }),
148
+ ...(input.scope === undefined ? {} : { scope: input.scope }),
149
+ }, dependencies);
150
+ if (result.status === "operation-failure")
151
+ return outcome.failure.operationFailed({
152
+ targetDir: result.targetDir,
153
+ phase: result.phase,
154
+ error: result.error,
155
+ });
156
+ if (result.status !== "success")
157
+ throw new Error("初始化输入校验与契约不一致");
158
+ const { status: _status, ...data } = result;
159
+ const payload = {
160
+ ...data,
161
+ resolved: {
162
+ ...data.resolved,
163
+ packages: [...data.resolved.packages],
164
+ },
165
+ nextSteps: [...data.nextSteps],
166
+ blueprint: {
167
+ schemaVersion: data.blueprint.schemaVersion,
168
+ packages: [...data.blueprint.packages],
169
+ ...(data.blueprint.packageLinkIntents === undefined
170
+ ? {}
171
+ : {
172
+ packageLinkIntents: [...data.blueprint.packageLinkIntents],
173
+ }),
174
+ },
175
+ generationRecord: {
176
+ ...data.generationRecord,
177
+ packages: [...data.generationRecord.packages],
178
+ },
179
+ };
180
+ return input.dryRun
181
+ ? outcome.data.planned(payload)
182
+ : outcome.data.initialized(payload);
183
+ },
184
+ }),
185
+ add: {
186
+ kind: "commandGroup",
187
+ parent: "template",
188
+ name: "add",
189
+ description: "扩展生成仓库。",
226
190
  },
227
- confirmation: {
228
- async confirm(request) {
229
- identity.write("stdout");
230
- try {
231
- return await runtime.confirmation.confirm(request);
232
- }
233
- catch (error) {
234
- if (isConfirmationOutputResourceFailure(error)) {
235
- throw new OutputFailure("stdout", error);
236
- }
237
- throw new ConfirmationFailure();
191
+ ...define.command("addPackage")({
192
+ kind: "command",
193
+ parent: "add",
194
+ name: "package",
195
+ description: "非破坏性地新增工作区包。",
196
+ input: packageAdditionInputSchema,
197
+ fields: {
198
+ preset: {
199
+ kind: "valueOption",
200
+ longOption: "--preset",
201
+ description: "支持新增包的预设",
202
+ },
203
+ name: {
204
+ kind: "valueOption",
205
+ longOption: "--name",
206
+ description: "无 scope 的 npm 包叶名称",
207
+ },
208
+ path: {
209
+ kind: "valueOption",
210
+ longOption: "--path",
211
+ description: "两个安全路径段,不能使用保留工作区目录",
212
+ },
213
+ linkFrom: {
214
+ kind: "repeatableOption",
215
+ longOption: "--link-from",
216
+ description: "消费包的两个安全路径段,不能使用保留工作区目录;可重复",
217
+ },
218
+ dryRun: {
219
+ kind: "flag",
220
+ longOption: "--dry-run",
221
+ description: "预览变更",
222
+ },
223
+ },
224
+ success: {
225
+ kind: "data",
226
+ variants: {
227
+ planned: {
228
+ description: "新增包预览",
229
+ schema: packageAdditionSchema,
230
+ exitCode: 0,
231
+ text: ({ actions }) => text.lines([
232
+ "新增包预览",
233
+ ...actions.map(({ path, action }) => `${action === "create" ? "创建" : "更新"}: ${path}`),
234
+ ]),
235
+ },
236
+ added: {
237
+ description: "已新增包",
238
+ schema: packageAdditionSchema,
239
+ exitCode: 0,
240
+ text: ({ actions }) => text.lines([
241
+ "已新增包",
242
+ ...actions.map(({ path, action }) => `${action === "create" ? "创建" : "更新"}: ${path}`),
243
+ ]),
244
+ },
245
+ unchanged: {
246
+ description: "请求已满足,无需变更",
247
+ schema: packageAdditionSchema,
248
+ exitCode: 0,
249
+ text: () => text.line("请求已满足,无需变更。"),
250
+ },
251
+ },
252
+ },
253
+ failures: {
254
+ invalidRequest: {
255
+ description: "仓库不支持所请求的消费关系",
256
+ exitCode: 1,
257
+ schema: standardSchema(v.object({
258
+ issues: v.array(v.object({
259
+ code: v.picklist(["UNKNOWN_LINK_FROM", "UNSUPPORTED_LINK"]),
260
+ })),
261
+ })),
262
+ text: ({ issues }) => text.lines([
263
+ "新增包请求无效。",
264
+ ...issues.map(({ code }) => code === "UNKNOWN_LINK_FROM"
265
+ ? "指定的消费包不存在,请检查 --link-from。"
266
+ : "指定的包角色不支持此链接,请调整 --link-from。"),
267
+ ]),
268
+ },
269
+ operationFailed: {
270
+ description: "新增包操作失败",
271
+ exitCode: 1,
272
+ schema: standardSchema(v.object({
273
+ phase: v.picklist([
274
+ "metadata",
275
+ "default",
276
+ "planning",
277
+ "reconciliation",
278
+ ]),
279
+ error: v.object({
280
+ message: v.string(),
281
+ suggestion: v.string(),
282
+ }),
283
+ })),
284
+ text: ({ error }) => text.lines([error.message, `建议: ${error.suggestion}`]),
285
+ },
286
+ conflict: {
287
+ description: "新增包冲突,未写入变更",
288
+ exitCode: 1,
289
+ schema: packageConflictSchema,
290
+ text: ({ conflicts }) => text.lines([
291
+ "新增包存在冲突,未写入变更。",
292
+ ...conflicts.flatMap((conflict) => "kind" in conflict
293
+ ? [
294
+ `${conflict.requested.path}: 包身份或链接与当前仓库冲突。`,
295
+ `现有包: ${conflict.existing.name} (${conflict.existing.path})`,
296
+ `请求包: ${conflict.requested.name} (${conflict.requested.path})`,
297
+ ]
298
+ : [
299
+ `${conflict.path} (${conflict.driver})`,
300
+ ...(conflict.location === undefined
301
+ ? []
302
+ : [`位置: ${conflict.location || "<文档根>"}`]),
303
+ ...(conflict.region === undefined
304
+ ? []
305
+ : [
306
+ `区域: 生成前第 ${conflict.region.before.startLine} 行;当前第 ${conflict.region.current.startLine} 行;请求后第 ${conflict.region.after.startLine} 行`,
307
+ ]),
308
+ ...(conflict.attribute === undefined
309
+ ? []
310
+ : [`属性: ${conflict.attribute}`]),
311
+ `原因: ${conflict.reason}`,
312
+ `生成前: ${conflict.context.before}`,
313
+ `当前: ${conflict.context.current}`,
314
+ `请求后: ${conflict.context.after}`,
315
+ ].flatMap((line) => line.replaceAll("\0", "\\0").split(/\r\n|\r|\n/u))),
316
+ ]),
317
+ },
318
+ },
319
+ async handler({ input, dependencies, outcome }) {
320
+ const result = await runAddPackage({
321
+ preset: input.preset,
322
+ name: input.name,
323
+ linkFrom: input.linkFrom,
324
+ dryRun: input.dryRun,
325
+ ...(input.path === undefined ? {} : { path: input.path }),
326
+ }, dependencies);
327
+ if (result.status === "operation-failure")
328
+ return outcome.failure.operationFailed({
329
+ phase: result.phase,
330
+ error: result.error,
331
+ });
332
+ if (result.status === "conflict")
333
+ return outcome.failure.conflict({
334
+ dryRun: result.dryRun,
335
+ actions: [],
336
+ conflicts: [...result.conflicts],
337
+ });
338
+ if (result.status === "usage-error") {
339
+ const issues = result.issues.map(({ code }) => {
340
+ if (code !== "UNKNOWN_LINK_FROM" && code !== "UNSUPPORTED_LINK")
341
+ throw new Error("新增包输入校验与契约不一致");
342
+ return { code };
343
+ });
344
+ return outcome.failure.invalidRequest({ issues });
238
345
  }
346
+ const data = { dryRun: result.dryRun, actions: [...result.actions] };
347
+ return result.dryRun
348
+ ? outcome.data.planned(data)
349
+ : result.actions.length === 0
350
+ ? outcome.data.unchanged(data)
351
+ : outcome.data.added(data);
239
352
  },
353
+ }),
354
+ blueprint: {
355
+ kind: "commandGroup",
356
+ parent: "template",
357
+ name: "blueprint",
358
+ description: "处理项目蓝图。",
240
359
  },
360
+ ...define.command("validateBlueprint")({
361
+ kind: "command",
362
+ parent: "blueprint",
363
+ name: "validate",
364
+ description: "只读校验项目蓝图。",
365
+ fields: { path: { kind: "positional", description: "蓝图文件路径" } },
366
+ input: standardSchema(v.object({ path: v.pipe(v.string(), v.nonEmpty()) })),
367
+ success: {
368
+ kind: "data",
369
+ variants: {
370
+ valid: {
371
+ description: "蓝图有效",
372
+ schema: standardSchema(v.object({ path: v.string() })),
373
+ exitCode: 0,
374
+ text: () => text.line("蓝图有效。"),
375
+ },
376
+ },
377
+ },
378
+ failures: {
379
+ operationFailed: {
380
+ description: "蓝图读取或解析失败",
381
+ schema: standardSchema(v.object({
382
+ path: v.string(),
383
+ reason: v.picklist([
384
+ "not-found",
385
+ "permission-denied",
386
+ "not-a-file",
387
+ "unreadable",
388
+ "invalid-json",
389
+ ]),
390
+ error: v.object({
391
+ message: v.string(),
392
+ suggestion: v.string(),
393
+ }),
394
+ })),
395
+ exitCode: 1,
396
+ text: ({ path, error }) => text.lines([
397
+ error.message,
398
+ `路径: ${path}`,
399
+ `建议: ${error.suggestion}`,
400
+ ]),
401
+ },
402
+ invalid: {
403
+ description: "蓝图无效",
404
+ schema: standardSchema(v.object({
405
+ path: v.string(),
406
+ issues: v.array(v.object({ path: v.string(), message: v.string() })),
407
+ })),
408
+ exitCode: 1,
409
+ text: ({ path, issues }) => text.lines([
410
+ "蓝图无效。",
411
+ `路径: ${path}`,
412
+ ...issues.map((issue) => `${issue.path}: 该位置的蓝图定义不符合要求。`),
413
+ "建议: 修正蓝图后重新验证。",
414
+ ]),
415
+ },
416
+ },
417
+ async handler({ input, dependencies, outcome }) {
418
+ const result = await validateBlueprintFile(input.path, dependencies);
419
+ if (result.status === "invalid")
420
+ return outcome.failure.invalid({
421
+ path: result.path,
422
+ issues: [...result.issues],
423
+ });
424
+ if (result.status === "operation-failure")
425
+ return outcome.failure.operationFailed({
426
+ path: result.path,
427
+ reason: result.reason,
428
+ error: result.error,
429
+ });
430
+ return outcome.data.valid({ path: result.path });
431
+ },
432
+ }),
433
+ ...define.command("schema")({
434
+ kind: "command",
435
+ parent: "template",
436
+ name: "schema",
437
+ description: "导出完整 CLI 契约及输入/输出 Schema。",
438
+ input: standardSchema(v.object({})),
439
+ fields: {},
440
+ success: {
441
+ kind: "data",
442
+ variants: {
443
+ exported: {
444
+ description: "完整 CLI 契约",
445
+ exitCode: 0,
446
+ schema: standardSchema(v.object({ manifest: v.record(v.string(), v.unknown()) })),
447
+ text: ({ manifest }) => text.lines([
448
+ "CLI 契约",
449
+ ...JSON.stringify(manifest, null, 2).split("\n"),
450
+ ]),
451
+ },
452
+ },
453
+ },
454
+ failures: {},
455
+ handler: ({ dependencies, outcome }) => outcome.data.exported({ manifest: dependencies.getManifest() }),
456
+ }),
457
+ ...define.command("presets")({
458
+ kind: "command",
459
+ parent: "template",
460
+ name: "presets",
461
+ description: "列出内置预设。",
462
+ fields: {},
463
+ input: standardSchema(v.object({})),
464
+ success: {
465
+ kind: "data",
466
+ variants: {
467
+ listed: {
468
+ description: "内置预设列表",
469
+ schema: standardSchema(v.object({
470
+ presets: v.array(v.object({
471
+ name: v.string(),
472
+ title: v.string(),
473
+ description: v.string(),
474
+ })),
475
+ })),
476
+ exitCode: 0,
477
+ text: ({ presets }) => text.lines([
478
+ "内置预设",
479
+ ...presets.map((preset) => ` ${preset.name}: ${preset.title} - ${preset.description}`),
480
+ ]),
481
+ },
482
+ },
483
+ },
484
+ failures: {},
485
+ handler: ({ outcome }) => outcome.data.listed({ presets: [...listPresetCatalog().presets] }),
486
+ }),
241
487
  },
242
- };
243
- }
244
- export function createCliCommand(runtime, commanderOutput) {
245
- const command = new Command()
246
- .name("template")
247
- .description("从维护的项目预设创建仓库。")
248
- .version(runtime.version)
249
- .configureOutput({
250
- writeOut: (text) => {
251
- if (commanderOutput === undefined)
252
- runtime.streams.stdout.write(text);
253
- else
254
- commanderOutput.stdout += text;
255
- },
256
- writeErr: (text) => {
257
- if (commanderOutput === undefined)
258
- runtime.streams.stderr.write(text);
259
- else
260
- commanderOutput.stderr += text;
261
- },
262
- })
263
- .configureHelp({
264
- subcommandTerm(subcommand) {
265
- switch (subcommand.name()) {
266
- case "init":
267
- return "template init <dir>";
268
- case "add":
269
- return "template add package";
270
- case "presets":
271
- return "template presets";
272
- case "blueprint":
273
- return "template blueprint validate <path>";
274
- default:
275
- return `template ${subcommand.name()}`;
276
- }
277
- },
278
- })
279
- .showHelpAfterError()
280
- .exitOverride();
281
- command
282
- .command("init <dir>")
283
- .description("初始化前解析预设、初始包名称、路径和包 scope。")
284
- .requiredOption("--preset <name>", "要生成的项目预设")
285
- .option("--name <name>", "预设支持主包身份覆盖时使用的无 scope 叶名称")
286
- .option("--path <path>", "预设支持主包身份覆盖时使用的两段路径")
287
- .option("--scope <name>", "解析后的默认包 scope")
288
- .option("-y, --yes", "接受非交互式生成的默认值")
289
- .option("--dry-run", "打印生成计划而不写文件")
290
- .option("--json", "输出机器可读结果")
291
- .option("--no-todo", "不写入生成后的 TODO.md")
292
- .action(async (dir, options) => {
293
- const initOptions = {
294
- dir,
295
- preset: options.preset,
296
- yes: Boolean(options.yes),
297
- dryRun: Boolean(options.dryRun),
298
- json: Boolean(options.json),
299
- todo: options.todo,
300
- ...(options.name === undefined ? {} : { name: options.name }),
301
- ...(options.path === undefined ? {} : { path: options.path }),
302
- ...(options.scope === undefined ? {} : { scope: options.scope }),
303
- };
304
- writeClosedCommandResult(runtime, await runInit(initOptions, runtime), initOptions.json);
305
- });
306
- const addCommand = command
307
- .command("add")
308
- .description("向生成仓库添加内容;package 支持 --dry-run 和 --json。");
309
- addCommand
310
- .command("package")
311
- .description("添加一个 Package Boundary。")
312
- .requiredOption("--preset <name>", "要添加的 Package 预设")
313
- .requiredOption("--name <name>", "要添加的 Package 名称")
314
- .option("--path <path>", "要添加的两段 Package Path")
315
- .option("--link-from <path>", "要链接的现有 consumer Package Path;可重复传入", (value, previous) => [...previous, value], [])
316
- .option("--dry-run", "预览 Addition Delta 而不写文件")
317
- .option("--json", "输出机器可读结果")
318
- .action(async (options) => {
319
- const addOptions = {
320
- preset: options.preset,
321
- name: options.name,
322
- ...(options.path === undefined ? {} : { path: options.path }),
323
- linkFrom: options.linkFrom,
324
- dryRun: Boolean(options.dryRun),
325
- json: Boolean(options.json),
326
- };
327
- writeClosedCommandResult(runtime, await runAddPackage(addOptions, runtime), addOptions.json);
328
- });
329
- command
330
- .command("presets")
331
- .description("列出内置预设。")
332
- .option("--json", "输出机器可读结果")
333
- .action((options) => {
334
- writeClosedCommandResult(runtime, listPresetCatalog(), Boolean(options.json));
335
488
  });
336
- command
337
- .command("blueprint")
338
- .description("处理 Project Blueprint。")
339
- .command("validate <path>")
340
- .description("校验 Project Blueprint。")
341
- .option("--json", "输出机器可读结果")
342
- .action(async (filePath, options) => {
343
- writeClosedCommandResult(runtime, await validateBlueprintFile(filePath, runtime), Boolean(options.json));
344
- });
345
- return command;
346
489
  }
347
490
  export async function runCli(runtime) {
348
- let command = "template";
349
- let json = false;
350
- let commandRuntime = runtime;
351
- let identity = new HumanCommandIdentity(runtime);
352
- const commanderOutput = { stdout: "", stderr: "" };
353
491
  try {
354
- command = commandName(runtime.argv);
355
- json = hasJsonControlIntent(runtime.argv);
356
- ({ runtime: commandRuntime, identity } = withHumanIdentity(runtime, json));
357
- const cli = createCliCommand(commandRuntime, commanderOutput);
358
- if (commandRuntime.argv.length <= 2) {
359
- cli.outputHelp();
360
- identity.writeText("stdout", localizeHelp(commanderOutput.stdout));
361
- return 0;
362
- }
363
- await cli.parseAsync([...commandRuntime.argv], { from: "node" });
364
- return 0;
492
+ const contract = createCliContract(runtime);
493
+ const result = await executeCli(contract, {
494
+ invocation: parseCliInvocation(contract, runtime.argv.slice(2)),
495
+ dependencies: {
496
+ ...runtime,
497
+ getManifest: () => ({ ...contract.manifest }),
498
+ },
499
+ write: runtime.write,
500
+ });
501
+ return result.exitCode;
365
502
  }
366
503
  catch (error) {
367
- if (error instanceof OutputFailure)
368
- return exitCodeForOutputFailure(error);
369
- if (error instanceof HandledCliExit)
370
- return error.exitCode;
371
- if (error instanceof CommanderError &&
372
- (error.code === "commander.helpDisplayed" ||
373
- error.code === "commander.version")) {
374
- try {
375
- identity.writeText("stdout", error.code === "commander.version"
376
- ? ""
377
- : localizeHelp(commanderOutput.stdout));
378
- }
379
- catch (writeError) {
380
- if (writeError instanceof OutputFailure) {
381
- return exitCodeForOutputFailure(writeError);
382
- }
383
- return 65;
384
- }
504
+ if (error instanceof CliWriteError &&
505
+ error.destination === "stdout" &&
506
+ isNodeBrokenPipe(error))
385
507
  return 0;
386
- }
387
- const failure = error instanceof CommanderError
388
- ? commanderFailure(error, command, commanderOutput.stderr)
389
- : applicationFailure(error, command);
390
508
  try {
391
- writeFailure(runtime, identity, json, failure);
509
+ await runtime.write({
510
+ destination: "stderr",
511
+ chunk: "命令执行失败;请检查运行环境或报告此问题。\n",
512
+ });
392
513
  }
393
- catch (writeError) {
394
- if (writeError instanceof OutputFailure) {
395
- return exitCodeForOutputFailure(writeError);
396
- }
397
- return 65;
514
+ catch {
515
+ // 诊断通道不可用时仍保留原始故障退出类别。
398
516
  }
399
- return failure.code.startsWith("USAGE_") ? 64 : 65;
517
+ return 70;
400
518
  }
401
519
  }