@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.
- package/dist/application.d.ts +1 -52
- package/dist/application.js +0 -81
- package/dist/cli.js +14 -28
- package/dist/input-schemas.d.ts +30 -0
- package/dist/input-schemas.js +75 -0
- package/dist/main.d.ts +3 -14
- package/dist/main.js +496 -378
- package/dist/result-schemas.d.ts +222 -0
- package/dist/result-schemas.js +74 -0
- package/dist/standard-schema.d.ts +3 -0
- package/dist/standard-schema.js +29 -0
- package/node_modules/@standard-schema/spec/LICENSE +21 -0
- package/node_modules/@standard-schema/spec/README.md +198 -0
- package/node_modules/@standard-schema/spec/dist/index.cjs +18 -0
- package/node_modules/@standard-schema/spec/dist/index.d.cts +119 -0
- package/node_modules/@standard-schema/spec/dist/index.d.ts +119 -0
- package/node_modules/@standard-schema/spec/dist/index.js +0 -0
- package/node_modules/@standard-schema/spec/package.json +52 -0
- package/node_modules/@types/node/LICENSE +21 -0
- package/node_modules/@types/node/README.md +15 -0
- package/node_modules/@types/node/assert/strict.d.ts +111 -0
- package/node_modules/@types/node/assert.d.ts +1115 -0
- package/node_modules/@types/node/async_hooks.d.ts +619 -0
- package/node_modules/@types/node/buffer.buffer.d.ts +477 -0
- package/node_modules/@types/node/buffer.d.ts +1941 -0
- package/node_modules/@types/node/child_process.d.ts +1480 -0
- package/node_modules/@types/node/cluster.d.ts +578 -0
- package/node_modules/@types/node/compatibility/iterators.d.ts +21 -0
- package/node_modules/@types/node/console.d.ts +453 -0
- package/node_modules/@types/node/constants.d.ts +21 -0
- package/node_modules/@types/node/crypto.d.ts +5484 -0
- package/node_modules/@types/node/dgram.d.ts +715 -0
- package/node_modules/@types/node/diagnostics_channel.d.ts +576 -0
- package/node_modules/@types/node/dns/promises.d.ts +503 -0
- package/node_modules/@types/node/dns.d.ts +923 -0
- package/node_modules/@types/node/domain.d.ts +166 -0
- package/node_modules/@types/node/events.d.ts +967 -0
- package/node_modules/@types/node/fs/promises.d.ts +1354 -0
- package/node_modules/@types/node/fs.d.ts +4777 -0
- package/node_modules/@types/node/globals.d.ts +170 -0
- package/node_modules/@types/node/globals.typedarray.d.ts +41 -0
- package/node_modules/@types/node/http.d.ts +2246 -0
- package/node_modules/@types/node/http2.d.ts +2882 -0
- package/node_modules/@types/node/https.d.ts +585 -0
- package/node_modules/@types/node/index.d.ts +101 -0
- package/node_modules/@types/node/inspector.d.ts +323 -0
- package/node_modules/@types/node/inspector.generated.d.ts +4406 -0
- package/node_modules/@types/node/module.d.ts +844 -0
- package/node_modules/@types/node/net.d.ts +1197 -0
- package/node_modules/@types/node/os.d.ts +507 -0
- package/node_modules/@types/node/package.json +140 -0
- package/node_modules/@types/node/path.d.ts +200 -0
- package/node_modules/@types/node/perf_hooks.d.ts +1054 -0
- package/node_modules/@types/node/process.d.ts +2101 -0
- package/node_modules/@types/node/punycode.d.ts +117 -0
- package/node_modules/@types/node/querystring.d.ts +152 -0
- package/node_modules/@types/node/readline/promises.d.ts +161 -0
- package/node_modules/@types/node/readline.d.ts +600 -0
- package/node_modules/@types/node/repl.d.ts +438 -0
- package/node_modules/@types/node/sea.d.ts +162 -0
- package/node_modules/@types/node/sqlite.d.ts +1182 -0
- package/node_modules/@types/node/stream/consumers.d.ts +45 -0
- package/node_modules/@types/node/stream/promises.d.ts +90 -0
- package/node_modules/@types/node/stream/web.d.ts +596 -0
- package/node_modules/@types/node/stream.d.ts +1707 -0
- package/node_modules/@types/node/string_decoder.d.ts +67 -0
- package/node_modules/@types/node/test.d.ts +2656 -0
- package/node_modules/@types/node/timers/promises.d.ts +108 -0
- package/node_modules/@types/node/timers.d.ts +285 -0
- package/node_modules/@types/node/tls.d.ts +1314 -0
- package/node_modules/@types/node/trace_events.d.ts +197 -0
- package/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +473 -0
- package/node_modules/@types/node/ts5.6/compatibility/float16array.d.ts +71 -0
- package/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +36 -0
- package/node_modules/@types/node/ts5.6/index.d.ts +103 -0
- package/node_modules/@types/node/ts5.7/compatibility/float16array.d.ts +72 -0
- package/node_modules/@types/node/ts5.7/index.d.ts +103 -0
- package/node_modules/@types/node/tty.d.ts +209 -0
- package/node_modules/@types/node/url.d.ts +1103 -0
- package/node_modules/@types/node/util.d.ts +2376 -0
- package/node_modules/@types/node/v8.d.ts +1010 -0
- package/node_modules/@types/node/vm.d.ts +1160 -0
- package/node_modules/@types/node/wasi.d.ts +202 -0
- package/node_modules/@types/node/web-globals/abortcontroller.d.ts +34 -0
- package/node_modules/@types/node/web-globals/crypto.d.ts +32 -0
- package/node_modules/@types/node/web-globals/domexception.d.ts +68 -0
- package/node_modules/@types/node/web-globals/events.d.ts +97 -0
- package/node_modules/@types/node/web-globals/fetch.d.ts +62 -0
- package/node_modules/@types/node/web-globals/navigator.d.ts +25 -0
- package/node_modules/@types/node/web-globals/storage.d.ts +24 -0
- package/node_modules/@types/node/web-globals/streams.d.ts +22 -0
- package/node_modules/@types/node/worker_threads.d.ts +894 -0
- package/node_modules/@types/node/zlib.d.ts +768 -0
- package/node_modules/@valibot/to-json-schema/LICENSE.md +9 -0
- package/node_modules/@valibot/to-json-schema/README.md +475 -0
- package/node_modules/@valibot/to-json-schema/dist/index.cjs +800 -0
- package/node_modules/@valibot/to-json-schema/dist/index.d.cts +991 -0
- package/node_modules/@valibot/to-json-schema/dist/index.d.mts +991 -0
- package/node_modules/@valibot/to-json-schema/dist/index.min.cjs +1 -0
- package/node_modules/@valibot/to-json-schema/dist/index.min.mjs +1 -0
- package/node_modules/@valibot/to-json-schema/dist/index.mjs +795 -0
- package/node_modules/@valibot/to-json-schema/package.json +75 -0
- package/node_modules/@ykdz/cli-contract/LICENSE +21 -0
- package/node_modules/@ykdz/cli-contract/dist/atomic-variant-compiler.d.ts +17 -0
- package/node_modules/@ykdz/cli-contract/dist/atomic-variant-compiler.js +55 -0
- package/node_modules/@ykdz/cli-contract/dist/cli-contract.d.ts +1164 -0
- package/node_modules/@ykdz/cli-contract/dist/cli-contract.js +1408 -0
- package/node_modules/@ykdz/cli-contract/dist/cli-execution.d.ts +54 -0
- package/node_modules/@ykdz/cli-contract/dist/cli-execution.js +708 -0
- package/node_modules/@ykdz/cli-contract/dist/cli-invocation.d.ts +174 -0
- package/node_modules/@ykdz/cli-contract/dist/cli-invocation.js +524 -0
- package/node_modules/@ykdz/cli-contract/dist/cli-write-error.d.ts +10 -0
- package/node_modules/@ykdz/cli-contract/dist/cli-write-error.js +14 -0
- package/node_modules/@ykdz/cli-contract/dist/contract-definition-error.d.ts +260 -0
- package/node_modules/@ykdz/cli-contract/dist/contract-definition-error.js +130 -0
- package/node_modules/@ykdz/cli-contract/dist/contract-execution-error.d.ts +63 -0
- package/node_modules/@ykdz/cli-contract/dist/contract-execution-error.js +17 -0
- package/node_modules/@ykdz/cli-contract/dist/contract-schema-compiler.d.ts +6 -0
- package/node_modules/@ykdz/cli-contract/dist/contract-schema-compiler.js +532 -0
- package/node_modules/@ykdz/cli-contract/dist/contract-schema.d.ts +14 -0
- package/node_modules/@ykdz/cli-contract/dist/contract-schema.js +1 -0
- package/node_modules/@ykdz/cli-contract/dist/description.d.ts +2 -0
- package/node_modules/@ykdz/cli-contract/dist/description.js +13 -0
- package/node_modules/@ykdz/cli-contract/dist/index.d.ts +8 -0
- package/node_modules/@ykdz/cli-contract/dist/index.js +7 -0
- package/node_modules/@ykdz/cli-contract/dist/json-value.d.ts +4 -0
- package/node_modules/@ykdz/cli-contract/dist/json-value.js +64 -0
- package/node_modules/@ykdz/cli-contract/dist/node.d.ts +21 -0
- package/node_modules/@ykdz/cli-contract/dist/node.js +109 -0
- package/node_modules/@ykdz/cli-contract/dist/outcome-fact.d.ts +162 -0
- package/node_modules/@ykdz/cli-contract/dist/outcome-fact.js +113 -0
- package/node_modules/@ykdz/cli-contract/dist/outcome-wire.d.ts +53 -0
- package/node_modules/@ykdz/cli-contract/dist/outcome-wire.js +189 -0
- package/node_modules/@ykdz/cli-contract/dist/stream-variant-compiler.d.ts +16 -0
- package/node_modules/@ykdz/cli-contract/dist/stream-variant-compiler.js +45 -0
- package/node_modules/@ykdz/cli-contract/package.json +69 -0
- package/node_modules/@ykdz/template-builtin-presets/dist/src/foundation.d.ts +20 -0
- package/node_modules/@ykdz/template-builtin-presets/dist/src/foundation.js +27 -28
- package/node_modules/@ykdz/template-builtin-presets/dist/src/generation-record.d.ts +19 -0
- package/node_modules/@ykdz/template-builtin-presets/dist/src/generation-record.js +1 -1
- package/node_modules/@ykdz/template-builtin-presets/dist/src/index.d.ts +2 -1
- package/node_modules/@ykdz/template-builtin-presets/dist/src/index.js +2 -1
- package/node_modules/@ykdz/template-builtin-presets/dist/src/ts-cli/definition.js +9 -5
- package/node_modules/@ykdz/template-builtin-presets/dist/src/vike-app/definition.js +0 -4
- package/node_modules/@ykdz/template-builtin-presets/package.json +2 -1
- package/node_modules/@ykdz/template-builtin-presets/templates/foundation/AGENTS.md.template +10 -4
- package/node_modules/@ykdz/template-builtin-presets/templates/foundation/devcontainer.json +3 -0
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/artifact.ts +128 -59
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/handoff.ts +80 -8
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/readiness.ts +7 -3
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/src/cli.ts +9 -19
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/src/main.ts +144 -60
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/src/standard-schema.ts +37 -0
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/e2e/journeys/lookup.journey.ts +71 -0
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/integration/command.test.ts +118 -59
- package/node_modules/@ykdz/template-core/dist/package-contribution.d.ts +0 -1
- package/node_modules/@ykdz/template-core/dist/pnpm-workspace.yaml +2 -1
- package/node_modules/@ykdz/template-core/dist/project-blueprint.d.ts +15 -0
- package/node_modules/@ykdz/template-core/dist/project-blueprint.js +1 -1
- package/node_modules/@ykdz/template-core/dist/project-github.d.ts +1 -1
- package/node_modules/undici-types/LICENSE +21 -0
- package/node_modules/undici-types/README.md +6 -0
- package/node_modules/undici-types/agent.d.ts +32 -0
- package/node_modules/undici-types/api.d.ts +43 -0
- package/node_modules/undici-types/balanced-pool.d.ts +30 -0
- package/node_modules/undici-types/cache-interceptor.d.ts +179 -0
- package/node_modules/undici-types/cache.d.ts +36 -0
- package/node_modules/undici-types/client-stats.d.ts +15 -0
- package/node_modules/undici-types/client.d.ts +123 -0
- package/node_modules/undici-types/connector.d.ts +36 -0
- package/node_modules/undici-types/content-type.d.ts +21 -0
- package/node_modules/undici-types/cookies.d.ts +30 -0
- package/node_modules/undici-types/diagnostics-channel.d.ts +74 -0
- package/node_modules/undici-types/dispatcher.d.ts +279 -0
- package/node_modules/undici-types/env-http-proxy-agent.d.ts +22 -0
- package/node_modules/undici-types/errors.d.ts +177 -0
- package/node_modules/undici-types/eventsource.d.ts +66 -0
- package/node_modules/undici-types/fetch.d.ts +211 -0
- package/node_modules/undici-types/formdata.d.ts +108 -0
- package/node_modules/undici-types/global-dispatcher.d.ts +9 -0
- package/node_modules/undici-types/global-origin.d.ts +7 -0
- package/node_modules/undici-types/h2c-client.d.ts +73 -0
- package/node_modules/undici-types/handlers.d.ts +15 -0
- package/node_modules/undici-types/header.d.ts +160 -0
- package/node_modules/undici-types/index.d.ts +91 -0
- package/node_modules/undici-types/interceptors.d.ts +80 -0
- package/node_modules/undici-types/mock-agent.d.ts +68 -0
- package/node_modules/undici-types/mock-call-history.d.ts +111 -0
- package/node_modules/undici-types/mock-client.d.ts +27 -0
- package/node_modules/undici-types/mock-errors.d.ts +12 -0
- package/node_modules/undici-types/mock-interceptor.d.ts +94 -0
- package/node_modules/undici-types/mock-pool.d.ts +27 -0
- package/node_modules/undici-types/package.json +55 -0
- package/node_modules/undici-types/patch.d.ts +29 -0
- package/node_modules/undici-types/pool-stats.d.ts +19 -0
- package/node_modules/undici-types/pool.d.ts +41 -0
- package/node_modules/undici-types/proxy-agent.d.ts +29 -0
- package/node_modules/undici-types/readable.d.ts +68 -0
- package/node_modules/undici-types/retry-agent.d.ts +8 -0
- package/node_modules/undici-types/retry-handler.d.ts +125 -0
- package/node_modules/undici-types/round-robin-pool.d.ts +41 -0
- package/node_modules/undici-types/snapshot-agent.d.ts +109 -0
- package/node_modules/undici-types/socks5-proxy-agent.d.ts +25 -0
- package/node_modules/undici-types/util.d.ts +18 -0
- package/node_modules/undici-types/utility.d.ts +7 -0
- package/node_modules/undici-types/webidl.d.ts +347 -0
- package/node_modules/undici-types/websocket.d.ts +188 -0
- package/package.json +5 -3
- package/dist/command-result.d.ts +0 -9
- package/dist/command-result.js +0 -231
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/e2e/journeys/greet.journey.ts +0 -46
- package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/unit/greet.test.ts +0 -15
- package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/devcontainer/docker-client.Dockerfile +0 -3
- package/node_modules/commander/LICENSE +0 -22
- package/node_modules/commander/Readme.md +0 -1172
- package/node_modules/commander/index.js +0 -21
- package/node_modules/commander/lib/argument.js +0 -147
- package/node_modules/commander/lib/command.js +0 -2790
- package/node_modules/commander/lib/error.js +0 -36
- package/node_modules/commander/lib/help.js +0 -731
- package/node_modules/commander/lib/option.js +0 -377
- package/node_modules/commander/lib/suggestSimilar.js +0 -99
- package/node_modules/commander/package-support.json +0 -19
- package/node_modules/commander/package.json +0 -64
- package/node_modules/commander/typings/index.d.ts +0 -1113
|
@@ -287,6 +287,7 @@ const ticket09ReceiptFilePaths = [
|
|
|
287
287
|
"package/dist/cli-command-identity.js",
|
|
288
288
|
"package/dist/cli.js",
|
|
289
289
|
"package/dist/main.js",
|
|
290
|
+
"package/dist/standard-schema.js",
|
|
290
291
|
"package/package.json",
|
|
291
292
|
] as const;
|
|
292
293
|
|
|
@@ -315,23 +316,94 @@ function hasCanonicalReceiptFiles(files: Receipt["files"]): boolean {
|
|
|
315
316
|
return true;
|
|
316
317
|
}
|
|
317
318
|
|
|
319
|
+
/** 发布消费检查与交接校验共用原生结果的业务判据。 */
|
|
320
|
+
export function hasLookupEvidence(source: string): boolean {
|
|
321
|
+
try {
|
|
322
|
+
const result: unknown = JSON.parse(source);
|
|
323
|
+
return (
|
|
324
|
+
isRecord(result) &&
|
|
325
|
+
result.schemaVersion === "1" &&
|
|
326
|
+
result.command === "lookup" &&
|
|
327
|
+
result.kind === "data" &&
|
|
328
|
+
result.variant === "found" &&
|
|
329
|
+
isRecord(result.data) &&
|
|
330
|
+
result.data.name === "ada" &&
|
|
331
|
+
result.data.title === "Ada Lovelace"
|
|
332
|
+
);
|
|
333
|
+
} catch {
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export function hasSchemaEvidence(
|
|
339
|
+
source: string,
|
|
340
|
+
commandName: string,
|
|
341
|
+
): boolean {
|
|
342
|
+
try {
|
|
343
|
+
const result: unknown = JSON.parse(source);
|
|
344
|
+
if (
|
|
345
|
+
!isRecord(result) ||
|
|
346
|
+
result.schemaVersion !== "1" ||
|
|
347
|
+
result.command !== "schema" ||
|
|
348
|
+
result.kind !== "data" ||
|
|
349
|
+
result.variant !== "exported" ||
|
|
350
|
+
!isRecord(result.data)
|
|
351
|
+
)
|
|
352
|
+
return false;
|
|
353
|
+
const manifest = result.data.manifest;
|
|
354
|
+
if (
|
|
355
|
+
!isRecord(manifest) ||
|
|
356
|
+
!isRecord(manifest.commands) ||
|
|
357
|
+
typeof manifest.root !== "string"
|
|
358
|
+
)
|
|
359
|
+
return false;
|
|
360
|
+
const root = manifest.commands[manifest.root];
|
|
361
|
+
const lookup = manifest.commands.lookup;
|
|
362
|
+
const schema = manifest.commands.schema;
|
|
363
|
+
return (
|
|
364
|
+
isRecord(root) &&
|
|
365
|
+
root.name === commandName &&
|
|
366
|
+
isRecord(schema) &&
|
|
367
|
+
schema.name === "schema" &&
|
|
368
|
+
isRecord(lookup) &&
|
|
369
|
+
lookup.name === "lookup" &&
|
|
370
|
+
isRecord(lookup.input) &&
|
|
371
|
+
isRecord(lookup.input.inputSchema) &&
|
|
372
|
+
isRecord(lookup.success) &&
|
|
373
|
+
isRecord(lookup.success.variants) &&
|
|
374
|
+
isRecord(lookup.success.variants.found) &&
|
|
375
|
+
lookup.success.variants.found.exitCode === 0 &&
|
|
376
|
+
isRecord(lookup.failures) &&
|
|
377
|
+
isRecord(lookup.failures.notFound) &&
|
|
378
|
+
lookup.failures.notFound.exitCode === 1
|
|
379
|
+
);
|
|
380
|
+
} catch {
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
318
385
|
function hasStableSmokeEvidence(receipt: Receipt): boolean {
|
|
319
|
-
const [runtimeImport, help, version,
|
|
386
|
+
const [runtimeImport, help, version, lookup, schema] = receipt.smokes;
|
|
320
387
|
return (
|
|
321
|
-
receipt.smokes.length ===
|
|
388
|
+
receipt.smokes.length === 5 &&
|
|
322
389
|
runtimeImport?.name === "runtime-import" &&
|
|
323
390
|
sameArguments(runtimeImport.args, []) &&
|
|
324
391
|
runtimeImport.stdout === "" &&
|
|
325
392
|
help?.name === "help" &&
|
|
326
393
|
sameArguments(help.args, ["--help"]) &&
|
|
327
|
-
help.stdout.includes(
|
|
328
|
-
help.stdout.includes("
|
|
394
|
+
help.stdout.includes(receipt.publication.commandName) &&
|
|
395
|
+
help.stdout.includes("lookup") &&
|
|
396
|
+
help.stdout.includes("schema") &&
|
|
329
397
|
version?.name === "version" &&
|
|
330
398
|
sameArguments(version.args, ["--version"]) &&
|
|
331
|
-
version.stdout ===
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
399
|
+
version.stdout ===
|
|
400
|
+
`${receipt.publication.commandName} ${receipt.publication.version}\n` &&
|
|
401
|
+
lookup?.name === "lookup" &&
|
|
402
|
+
sameArguments(lookup.args, ["lookup", "ada"]) &&
|
|
403
|
+
hasLookupEvidence(lookup.stdout) &&
|
|
404
|
+
schema?.name === "schema" &&
|
|
405
|
+
sameArguments(schema.args, ["schema"]) &&
|
|
406
|
+
hasSchemaEvidence(schema.stdout, receipt.publication.commandName)
|
|
335
407
|
);
|
|
336
408
|
}
|
|
337
409
|
|
package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/readiness.ts
CHANGED
|
@@ -584,15 +584,19 @@ function addManifestBlockers(options: {
|
|
|
584
584
|
"imports",
|
|
585
585
|
"provenance",
|
|
586
586
|
].filter((field) => Object.hasOwn(manifest, field));
|
|
587
|
+
const runtimeDependencies = manifest.dependencies;
|
|
587
588
|
const manifestContractValid =
|
|
588
589
|
manifest.type === "module" &&
|
|
589
590
|
exactStringSet(manifest.files, publicationFiles) &&
|
|
590
591
|
expectedPublicNodeRangeFromRoot !== undefined &&
|
|
591
592
|
isObject(manifest.engines) &&
|
|
592
593
|
manifest.engines.node === expectedPublicNodeRangeFromRoot &&
|
|
593
|
-
validRecordOfStrings(
|
|
594
|
-
|
|
595
|
-
|
|
594
|
+
validRecordOfStrings(runtimeDependencies) &&
|
|
595
|
+
["@ykdz/cli-contract", "@valibot/to-json-schema", "valibot"].every(
|
|
596
|
+
(name) =>
|
|
597
|
+
typeof runtimeDependencies[name] === "string" &&
|
|
598
|
+
runtimeDependencies[name].trim().length > 0,
|
|
599
|
+
) &&
|
|
596
600
|
isObject(scripts) &&
|
|
597
601
|
typeof scripts.build === "string" &&
|
|
598
602
|
scripts.build.length > 0 &&
|
|
@@ -1,27 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
|
|
4
|
+
import { nodeCliOutput } from "@ykdz/cli-contract/node";
|
|
5
|
+
|
|
4
6
|
import { cliCommandIdentity } from "./cli-command-identity.ts";
|
|
5
|
-
import { runCli
|
|
7
|
+
import { runCli } from "./main.ts";
|
|
6
8
|
|
|
7
9
|
const require = createRequire(import.meta.url);
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const runtime: CliRuntime = {
|
|
10
|
+
process.exitCode = await runCli({
|
|
11
11
|
argv: process.argv,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
write: nodeCliOutput({ stdout: process.stdout, stderr: process.stderr }),
|
|
13
|
+
// 身份读取和校验也使用 runCli 的意外故障出口。
|
|
14
|
+
get identity() {
|
|
15
|
+
return cliCommandIdentity(require("../package.json"));
|
|
16
16
|
},
|
|
17
|
-
|
|
18
|
-
env: process.env,
|
|
19
|
-
tty: {
|
|
20
|
-
stdin: Boolean(process.stdin.isTTY),
|
|
21
|
-
stdout: Boolean(process.stdout.isTTY),
|
|
22
|
-
stderr: Boolean(process.stderr.isTTY),
|
|
23
|
-
},
|
|
24
|
-
identity: cliCommandIdentity(packageManifest),
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
process.exitCode = await runCli(runtime);
|
|
17
|
+
});
|
|
@@ -1,78 +1,162 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
CliWriteError,
|
|
3
|
+
defineCli,
|
|
4
|
+
executeCli,
|
|
5
|
+
helpCapability,
|
|
6
|
+
outputCapability,
|
|
7
|
+
parseCliInvocation,
|
|
8
|
+
text,
|
|
9
|
+
versionCapability,
|
|
10
|
+
type WriteCliOutput,
|
|
11
|
+
} from "@ykdz/cli-contract";
|
|
12
|
+
import { isNodeBrokenPipe } from "@ykdz/cli-contract/node";
|
|
13
|
+
import * as v from "valibot";
|
|
2
14
|
|
|
3
15
|
import type { CliCommandIdentity } from "./cli-command-identity.ts";
|
|
4
|
-
|
|
5
|
-
export type Greeting = {
|
|
6
|
-
readonly message: string;
|
|
7
|
-
};
|
|
16
|
+
import { standardSchema } from "./standard-schema.ts";
|
|
8
17
|
|
|
9
18
|
export type CliRuntime = {
|
|
10
19
|
readonly argv: readonly string[];
|
|
11
|
-
readonly
|
|
12
|
-
readonly stdin: object;
|
|
13
|
-
readonly stdout: { write(chunk: string): unknown };
|
|
14
|
-
readonly stderr: { write(chunk: string): unknown };
|
|
15
|
-
};
|
|
16
|
-
readonly cwd: string;
|
|
17
|
-
readonly env: Readonly<Record<string, string | undefined>>;
|
|
18
|
-
readonly tty: {
|
|
19
|
-
readonly stdin: boolean;
|
|
20
|
-
readonly stdout: boolean;
|
|
21
|
-
readonly stderr: boolean;
|
|
22
|
-
};
|
|
20
|
+
readonly write: WriteCliOutput;
|
|
23
21
|
readonly identity: CliCommandIdentity;
|
|
24
22
|
};
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
return { message: `Hello, ${normalizedName}` };
|
|
32
|
-
}
|
|
24
|
+
const records = [
|
|
25
|
+
{ name: "ada", title: "Ada Lovelace" },
|
|
26
|
+
{ name: "grace", title: "Grace Hopper" },
|
|
27
|
+
];
|
|
33
28
|
|
|
34
|
-
function
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
29
|
+
function createCliContract(identity: CliCommandIdentity) {
|
|
30
|
+
const define = defineCli<{ getManifest(): Record<string, unknown> }>();
|
|
31
|
+
return define({
|
|
32
|
+
root: "cli",
|
|
33
|
+
help: helpCapability({
|
|
34
|
+
shortAlias: "-h",
|
|
35
|
+
headings: {
|
|
36
|
+
usage: "用法",
|
|
37
|
+
commands: "命令",
|
|
38
|
+
arguments: "参数",
|
|
39
|
+
options: "选项",
|
|
40
|
+
},
|
|
41
|
+
wording: {
|
|
42
|
+
commandPlaceholder: "命令",
|
|
43
|
+
choices: "候选:{choices}",
|
|
44
|
+
default: "默认:{value}",
|
|
45
|
+
},
|
|
46
|
+
}),
|
|
47
|
+
version: versionCapability({
|
|
48
|
+
value: text.line(`${identity.commandName} ${identity.version}`),
|
|
49
|
+
shortAlias: "-V",
|
|
50
|
+
}),
|
|
51
|
+
output: outputCapability({ defaultFormat: "structured", text: true }),
|
|
52
|
+
usageFailureExitCode: 2,
|
|
53
|
+
commands: {
|
|
54
|
+
cli: {
|
|
55
|
+
kind: "rootGroup",
|
|
56
|
+
name: identity.commandName,
|
|
57
|
+
description: "查询示例记录。",
|
|
58
|
+
},
|
|
59
|
+
...define.command("lookup")({
|
|
60
|
+
kind: "command",
|
|
61
|
+
parent: "cli",
|
|
62
|
+
name: "lookup",
|
|
63
|
+
description: "按名称查询内存记录。",
|
|
64
|
+
fields: {
|
|
65
|
+
name: { kind: "positional", description: "小写字母组成的记录名称" },
|
|
66
|
+
},
|
|
67
|
+
input: standardSchema(
|
|
68
|
+
v.object({
|
|
69
|
+
name: v.pipe(
|
|
70
|
+
v.string(),
|
|
71
|
+
v.regex(/^[a-z]+$/, "名称只能包含小写字母。"),
|
|
72
|
+
),
|
|
73
|
+
}),
|
|
74
|
+
),
|
|
75
|
+
success: {
|
|
76
|
+
kind: "data",
|
|
77
|
+
variants: {
|
|
78
|
+
found: {
|
|
79
|
+
description: "找到记录",
|
|
80
|
+
exitCode: 0,
|
|
81
|
+
schema: standardSchema(
|
|
82
|
+
v.object({ name: v.string(), title: v.string() }),
|
|
83
|
+
),
|
|
84
|
+
text: ({ name, title }) =>
|
|
85
|
+
text.line(`找到记录:${title}(${name})`),
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
failures: {
|
|
90
|
+
notFound: {
|
|
91
|
+
description: "记录不存在",
|
|
92
|
+
exitCode: 1,
|
|
93
|
+
schema: standardSchema(v.object({ name: v.string() })),
|
|
94
|
+
text: ({ name }) => text.line(`未找到记录:${name}。`),
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
handler({ input, outcome }) {
|
|
98
|
+
const record = records.find(({ name }) => name === input.name);
|
|
99
|
+
return record === undefined
|
|
100
|
+
? outcome.failure.notFound({ name: input.name })
|
|
101
|
+
: outcome.data.found(record);
|
|
102
|
+
},
|
|
103
|
+
}),
|
|
104
|
+
...define.command("schema")({
|
|
105
|
+
kind: "command",
|
|
106
|
+
parent: "cli",
|
|
107
|
+
name: "schema",
|
|
108
|
+
description: "导出完整 CLI 契约及输入/输出 Schema。",
|
|
109
|
+
input: standardSchema(v.object({})),
|
|
110
|
+
fields: {},
|
|
111
|
+
success: {
|
|
112
|
+
kind: "data",
|
|
113
|
+
variants: {
|
|
114
|
+
exported: {
|
|
115
|
+
description: "完整 CLI 契约",
|
|
116
|
+
exitCode: 0,
|
|
117
|
+
schema: standardSchema(
|
|
118
|
+
v.object({ manifest: v.record(v.string(), v.unknown()) }),
|
|
119
|
+
),
|
|
120
|
+
text: ({ manifest }) =>
|
|
121
|
+
text.lines([
|
|
122
|
+
"CLI 契约",
|
|
123
|
+
...JSON.stringify(manifest, null, 2).split("\n"),
|
|
124
|
+
]),
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
failures: {},
|
|
129
|
+
handler: ({ dependencies, outcome }) =>
|
|
130
|
+
outcome.data.exported({ manifest: dependencies.getManifest() }),
|
|
131
|
+
}),
|
|
132
|
+
},
|
|
133
|
+
});
|
|
64
134
|
}
|
|
65
135
|
|
|
66
136
|
export async function runCli(runtime: CliRuntime): Promise<number> {
|
|
67
137
|
try {
|
|
68
|
-
|
|
69
|
-
|
|
138
|
+
const contract = createCliContract(runtime.identity);
|
|
139
|
+
const result = await executeCli(contract, {
|
|
140
|
+
invocation: parseCliInvocation(contract, runtime.argv.slice(2)),
|
|
141
|
+
dependencies: { getManifest: () => ({ ...contract.manifest }) },
|
|
142
|
+
write: runtime.write,
|
|
70
143
|
});
|
|
71
|
-
return
|
|
144
|
+
return result.exitCode;
|
|
72
145
|
} catch (error) {
|
|
73
|
-
if (
|
|
74
|
-
|
|
146
|
+
if (
|
|
147
|
+
error instanceof CliWriteError &&
|
|
148
|
+
error.destination === "stdout" &&
|
|
149
|
+
isNodeBrokenPipe(error)
|
|
150
|
+
)
|
|
151
|
+
return 0;
|
|
152
|
+
try {
|
|
153
|
+
await runtime.write({
|
|
154
|
+
destination: "stderr",
|
|
155
|
+
chunk: "命令执行失败;请检查运行环境或报告此问题。\n",
|
|
156
|
+
});
|
|
157
|
+
} catch {
|
|
158
|
+
// 诊断通道故障不能改变原定退出类别。
|
|
75
159
|
}
|
|
76
|
-
|
|
160
|
+
return 70;
|
|
77
161
|
}
|
|
78
162
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { toStandardJsonSchema } from "@valibot/to-json-schema";
|
|
2
|
+
import type * as v from "valibot";
|
|
3
|
+
|
|
4
|
+
/** 上游执行器要求失败结果不带 value;保留 Valibot 的验证及官方 JSON Schema 投影。 */
|
|
5
|
+
export function standardSchema<
|
|
6
|
+
T extends v.BaseSchema<unknown, unknown, v.BaseIssue<unknown>>,
|
|
7
|
+
>(schema: T, ignoreActions: string[] = []) {
|
|
8
|
+
const converted = toStandardJsonSchema(schema);
|
|
9
|
+
const adapted: typeof converted = {
|
|
10
|
+
"~standard": {
|
|
11
|
+
...converted["~standard"],
|
|
12
|
+
jsonSchema: {
|
|
13
|
+
input: (options) =>
|
|
14
|
+
converted["~standard"].jsonSchema.input({
|
|
15
|
+
...options,
|
|
16
|
+
libraryOptions: { ...options.libraryOptions, ignoreActions },
|
|
17
|
+
}),
|
|
18
|
+
output: (options) =>
|
|
19
|
+
converted["~standard"].jsonSchema.output({
|
|
20
|
+
...options,
|
|
21
|
+
libraryOptions: { ...options.libraryOptions, ignoreActions },
|
|
22
|
+
}),
|
|
23
|
+
},
|
|
24
|
+
validate(value) {
|
|
25
|
+
const result = converted["~standard"].validate(value);
|
|
26
|
+
if (result instanceof Promise)
|
|
27
|
+
return result.then((resolved) =>
|
|
28
|
+
resolved.issues === undefined
|
|
29
|
+
? resolved
|
|
30
|
+
: { issues: resolved.issues },
|
|
31
|
+
);
|
|
32
|
+
return result.issues === undefined ? result : { issues: result.issues };
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
return adapted;
|
|
37
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
import { cliCommandIdentity } from "../../../src/cli-command-identity.ts";
|
|
6
|
+
import type { CliJourney } from "../journey.ts";
|
|
7
|
+
|
|
8
|
+
const journey: CliJourney = {
|
|
9
|
+
name: "lookup",
|
|
10
|
+
modes: ["source", "distribution", "packed"],
|
|
11
|
+
async setup() {},
|
|
12
|
+
commands() {
|
|
13
|
+
return [
|
|
14
|
+
{ name: "查询记录", args: ["lookup", "ada"] },
|
|
15
|
+
{ name: "文本查询", args: ["lookup", "ada", "--output-format", "text"] },
|
|
16
|
+
{ name: "未找到记录", args: ["lookup", "missing"] },
|
|
17
|
+
{
|
|
18
|
+
name: "文本失败",
|
|
19
|
+
args: ["lookup", "missing", "--output-format", "text"],
|
|
20
|
+
},
|
|
21
|
+
{ name: "非法输入", args: ["lookup", " ", "--output-format", "text"] },
|
|
22
|
+
{ name: "完整契约", args: ["schema"] },
|
|
23
|
+
{ name: "帮助", args: ["--help"] },
|
|
24
|
+
{ name: "版本", args: ["--version"] },
|
|
25
|
+
];
|
|
26
|
+
},
|
|
27
|
+
async assertions({ context, results }) {
|
|
28
|
+
const identity = cliCommandIdentity(
|
|
29
|
+
JSON.parse(
|
|
30
|
+
await readFile(path.join(context.packageRoot, "package.json"), "utf8"),
|
|
31
|
+
),
|
|
32
|
+
);
|
|
33
|
+
assert.equal(results[0]?.exitCode, 0);
|
|
34
|
+
assert.equal(results[0]?.stderr, "");
|
|
35
|
+
assert.deepEqual(JSON.parse(results[0]?.stdout ?? ""), {
|
|
36
|
+
schemaVersion: "1",
|
|
37
|
+
command: "lookup",
|
|
38
|
+
kind: "data",
|
|
39
|
+
variant: "found",
|
|
40
|
+
data: { name: "ada", title: "Ada Lovelace" },
|
|
41
|
+
});
|
|
42
|
+
assert.equal(results[1]?.exitCode, 0);
|
|
43
|
+
assert.equal(results[1]?.stderr, "");
|
|
44
|
+
assert.match(results[1]?.stdout ?? "", /找到记录:Ada Lovelace/u);
|
|
45
|
+
for (const result of results.slice(2, 4)) {
|
|
46
|
+
assert.equal(result.exitCode, 1);
|
|
47
|
+
assert.equal(result.stdout, "");
|
|
48
|
+
}
|
|
49
|
+
assert.equal(JSON.parse(results[2]?.stderr ?? "").variant, "notFound");
|
|
50
|
+
assert.match(results[3]?.stderr ?? "", /未找到记录:missing/u);
|
|
51
|
+
assert.equal(results[4]?.exitCode, 2);
|
|
52
|
+
assert.equal(results[4]?.stdout, "");
|
|
53
|
+
assert.equal(JSON.parse(results[4]?.stderr ?? "").kind, "usageFailure");
|
|
54
|
+
for (const result of results.slice(5)) {
|
|
55
|
+
assert.equal(result.exitCode, 0);
|
|
56
|
+
assert.equal(result.stderr, "");
|
|
57
|
+
}
|
|
58
|
+
const schema = JSON.parse(results[5]?.stdout ?? "");
|
|
59
|
+
assert.equal(schema.command, "schema");
|
|
60
|
+
for (const fact of ["lookup", "schema", "found", "notFound"])
|
|
61
|
+
assert.ok(JSON.stringify(schema.data.manifest).includes(fact));
|
|
62
|
+
assert.match(results[6]?.stdout ?? "", /lookup/u);
|
|
63
|
+
assert.ok(results[6]?.stdout.includes(identity.commandName));
|
|
64
|
+
assert.equal(
|
|
65
|
+
results[7]?.stdout,
|
|
66
|
+
`${identity.commandName} ${identity.version}\n`,
|
|
67
|
+
);
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export default journey;
|