@ykdz/template 0.0.38 → 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 +5 -0
- 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/package.json +2 -1
- package/node_modules/@ykdz/template-builtin-presets/templates/foundation/AGENTS.md.template +3 -3
- 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/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/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/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
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { compileContractSchema } from "#/contract-schema-compiler";
|
|
2
|
+
import { isSingleLineText } from "#/description";
|
|
3
|
+
import { deepFreeze } from "#/json-value";
|
|
4
|
+
export function compileStreamRecords(command, definitions, issues) {
|
|
5
|
+
const runtime = {};
|
|
6
|
+
const manifest = {};
|
|
7
|
+
const wire = {};
|
|
8
|
+
for (const [variant, definition] of Object.entries(definitions)) {
|
|
9
|
+
if (!/^[a-z][A-Za-z0-9]*$/.test(variant)) {
|
|
10
|
+
issues.push({
|
|
11
|
+
code: "invalidVariantName",
|
|
12
|
+
command,
|
|
13
|
+
location: "record",
|
|
14
|
+
variant,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
if (!isSingleLineText(definition.description)) {
|
|
18
|
+
issues.push({
|
|
19
|
+
code: "invalidDescription",
|
|
20
|
+
command,
|
|
21
|
+
location: "record",
|
|
22
|
+
variant,
|
|
23
|
+
received: typeof definition.description === "string"
|
|
24
|
+
? definition.description
|
|
25
|
+
: null,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
const schema = compileContractSchema(definition.schema, { command, location: "record", variant }, issues, isSingleLineText(definition.description)
|
|
29
|
+
? definition.description
|
|
30
|
+
: undefined);
|
|
31
|
+
runtime[variant] = Object.freeze({
|
|
32
|
+
description: definition.description,
|
|
33
|
+
schema: definition.schema,
|
|
34
|
+
...("text" in definition ? { text: definition.text } : {}),
|
|
35
|
+
});
|
|
36
|
+
if (schema !== undefined) {
|
|
37
|
+
manifest[variant] = deepFreeze({
|
|
38
|
+
description: definition.description,
|
|
39
|
+
...schema,
|
|
40
|
+
});
|
|
41
|
+
wire[variant] = deepFreeze(schema.outputSchema);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return deepFreeze({ runtime, manifest, wire });
|
|
45
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ykdz/cli-contract",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Framework-agnostic, executable CLI contracts for Node.js.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cli",
|
|
7
|
+
"contract",
|
|
8
|
+
"nodejs",
|
|
9
|
+
"typescript"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://github.com/YKDZ/cli-contract",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/YKDZ/cli-contract/issues"
|
|
14
|
+
},
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/YKDZ/cli-contract.git"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"type": "module",
|
|
24
|
+
"imports": {
|
|
25
|
+
"#/*": {
|
|
26
|
+
"types": "./dist/*.d.ts",
|
|
27
|
+
"default": "./dist/*.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"default": "./dist/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./node": {
|
|
36
|
+
"types": "./dist/node.d.ts",
|
|
37
|
+
"default": "./dist/node.js"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@standard-schema/spec": "^1.1.0",
|
|
45
|
+
"@types/node": "^24.13.4"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@cli-contract/typescript-config": "0.1.0",
|
|
49
|
+
"@valibot/to-json-schema": "^1.7.1",
|
|
50
|
+
"oxfmt": "^0.67.0",
|
|
51
|
+
"oxlint": "^1.82.0",
|
|
52
|
+
"oxlint-tsgolint": "^7.0.2001",
|
|
53
|
+
"typescript-7": "npm:typescript@^7.0.2",
|
|
54
|
+
"valibot": "^1.5.0",
|
|
55
|
+
"zod": "^4.5.4"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=24"
|
|
59
|
+
},
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "tsc -p tsconfig.build.json --pretty false && node ../../scripts/link-example.ts",
|
|
62
|
+
"format:check": "oxfmt --list-different --config ../../oxfmt.config.ts .",
|
|
63
|
+
"format:write": "oxfmt --write --config ../../oxfmt.config.ts .",
|
|
64
|
+
"lint": "oxlint --quiet --format=unix --config ../../oxlint.config.ts --ignore-pattern node_modules .",
|
|
65
|
+
"lint:fix": "oxlint --format=unix --config ../../oxlint.config.ts . --fix",
|
|
66
|
+
"test": "node --test --conditions=source test/*.test.ts",
|
|
67
|
+
"typecheck": "tsc -p tsconfig.json --noEmit --pretty false"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -210,6 +210,26 @@ export declare function planGeneratedRepositoryPackageAddition(options: {
|
|
|
210
210
|
readonly packagePath?: string;
|
|
211
211
|
readonly linkFrom?: readonly string[];
|
|
212
212
|
}): GeneratedRepositoryPackageAdditionPlan;
|
|
213
|
+
declare function collectPackageAdditionInput(options: {
|
|
214
|
+
readonly preset: string;
|
|
215
|
+
readonly packageLeafName: string;
|
|
216
|
+
readonly packagePath?: string;
|
|
217
|
+
readonly linkFrom?: readonly string[];
|
|
218
|
+
}): {
|
|
219
|
+
readonly status: "input-invalid";
|
|
220
|
+
readonly issues: readonly PackageAdditionInputIssue[];
|
|
221
|
+
} | {
|
|
222
|
+
readonly status: "valid";
|
|
223
|
+
readonly definition: BuiltInPresetDefinition;
|
|
224
|
+
readonly linkFrom: readonly string[];
|
|
225
|
+
};
|
|
226
|
+
/** 在读取仓库元数据前校验新增包调用参数,供 CLI 输入契约复用。 */
|
|
227
|
+
export declare function validateGeneratedRepositoryPackageAdditionInput(options: Parameters<typeof collectPackageAdditionInput>[0]): {
|
|
228
|
+
readonly status: "valid";
|
|
229
|
+
} | {
|
|
230
|
+
readonly status: "input-invalid";
|
|
231
|
+
readonly issues: readonly PackageAdditionInputIssue[];
|
|
232
|
+
};
|
|
213
233
|
/**
|
|
214
234
|
* Command-owned preparation: user input is checked before local metadata or any
|
|
215
235
|
* Preset default/planner work; all remaining failures are deliberately bounded.
|
|
@@ -3363,6 +3363,11 @@ function collectPackageAdditionInput(options) {
|
|
|
3363
3363
|
}
|
|
3364
3364
|
return { status: "valid", definition, linkFrom };
|
|
3365
3365
|
}
|
|
3366
|
+
/** 在读取仓库元数据前校验新增包调用参数,供 CLI 输入契约复用。 */
|
|
3367
|
+
export function validateGeneratedRepositoryPackageAdditionInput(options) {
|
|
3368
|
+
const result = collectPackageAdditionInput(options);
|
|
3369
|
+
return result.status === "input-invalid" ? result : { status: "valid" };
|
|
3370
|
+
}
|
|
3366
3371
|
/**
|
|
3367
3372
|
* Command-owned preparation: user input is checked before local metadata or any
|
|
3368
3373
|
* Preset default/planner work; all remaining failures are deliberately bounded.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PackageDefinitionId } from "@ykdz/template-core/project-blueprint";
|
|
2
|
+
import * as v from "valibot";
|
|
2
3
|
export type GeneratedPackagePlanningRecord = {
|
|
3
4
|
readonly packageDefinitionId: PackageDefinitionId;
|
|
4
5
|
readonly path: string;
|
|
@@ -25,6 +26,24 @@ export type GenerationRecord = {
|
|
|
25
26
|
};
|
|
26
27
|
/** Canonical durable Generation Record contract for a default npm scope. */
|
|
27
28
|
export declare function isValidDefaultPackageScope(value: string): boolean;
|
|
29
|
+
export declare const generationRecordSchema: v.StrictObjectSchema<{
|
|
30
|
+
readonly schemaVersion: v.LiteralSchema<2, (issue: v.LiteralIssue) => string>;
|
|
31
|
+
readonly repositoryName: v.StringSchema<"repositoryName must be a non-empty string">;
|
|
32
|
+
readonly defaultPackageScope: v.StringSchema<"defaultPackageScope must be a valid npm scope">;
|
|
33
|
+
readonly preset: v.StringSchema<"preset must be a non-empty string">;
|
|
34
|
+
readonly templateVersion: v.LiteralSchema<"0.0.0", "templateVersion must be 0.0.0">;
|
|
35
|
+
readonly toolchain: v.StrictObjectSchema<{
|
|
36
|
+
readonly nodeLtsMajor: v.StringSchema<"toolchain.nodeLtsMajor must be a numeric Node major">;
|
|
37
|
+
readonly packageManagerPin: v.StringSchema<"toolchain.packageManagerPin must be an exact pnpm version pin">;
|
|
38
|
+
}, (issue: v.StrictObjectIssue) => string>;
|
|
39
|
+
readonly packages: v.ArraySchema<v.StrictObjectSchema<{
|
|
40
|
+
readonly packageDefinitionId: v.StringSchema<"packageDefinitionId must use the package-<sha256> format">;
|
|
41
|
+
readonly path: v.StringSchema<"path must be a non-empty string">;
|
|
42
|
+
readonly definitionName: v.StringSchema<"definitionName must be a non-empty string">;
|
|
43
|
+
readonly planningContribution: v.PicklistSchema<["foundationPlan", "planInitialization", "planPackageAddition"], "planningContribution is unsupported">;
|
|
44
|
+
readonly contributionIdentity: v.StringSchema<"contributionIdentity must be a non-empty string">;
|
|
45
|
+
}, (issue: v.StrictObjectIssue) => string>, "packages must be an array">;
|
|
46
|
+
}, (issue: v.StrictObjectIssue) => string>;
|
|
28
47
|
/** Strictly decodes the durable Record shape before semantic checks run. */
|
|
29
48
|
export declare function decodeGenerationRecordStructure(value: unknown): GenerationRecord;
|
|
30
49
|
/** Validates semantic invariants that are independent of a Project Blueprint. */
|
|
@@ -23,7 +23,7 @@ const packagePlanningRecordSchema = v.strictObject({
|
|
|
23
23
|
planningContribution: v.picklist(["foundationPlan", "planInitialization", "planPackageAddition"], "planningContribution is unsupported"),
|
|
24
24
|
contributionIdentity: v.string("contributionIdentity must be a non-empty string"),
|
|
25
25
|
}, (issue) => strictObjectMessage(issue, "package planning fact must be an object"));
|
|
26
|
-
const generationRecordSchema = v.strictObject({
|
|
26
|
+
export const generationRecordSchema = v.strictObject({
|
|
27
27
|
schemaVersion: v.literal(2, (issue) => `Unsupported Generation Record schema version ${String(issue.input)}; expected 2`),
|
|
28
28
|
repositoryName: v.string("repositoryName must be a non-empty string"),
|
|
29
29
|
defaultPackageScope: v.string("defaultPackageScope must be a valid npm scope"),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { builtInPresetRegistry, createGenerationContext, loadLocalTemplateMetadata, prepareGeneratedRepositoryPackageAddition, validateGeneratedRepositoryInitializationInput, prepareGeneratedRepositoryInitialization, planGeneratedRepositoryInitialization, planGeneratedRepositoryPackageAddition, readRustToolchainChannelFromToml, resolveBuiltInTemplateSource, validateProjectBlueprint, } from "./foundation.ts";
|
|
1
|
+
export { builtInPresetRegistry, createGenerationContext, loadLocalTemplateMetadata, prepareGeneratedRepositoryPackageAddition, validateGeneratedRepositoryInitializationInput, validateGeneratedRepositoryPackageAdditionInput, prepareGeneratedRepositoryInitialization, planGeneratedRepositoryInitialization, planGeneratedRepositoryPackageAddition, readRustToolchainChannelFromToml, resolveBuiltInTemplateSource, validateProjectBlueprint, } from "./foundation.ts";
|
|
2
2
|
export { templateSources } from "./template-sources.ts";
|
|
3
|
+
export { generationRecordSchema } from "./generation-record.ts";
|
|
3
4
|
export type { BuiltInPresetDefinition, GeneratedRepositoryPlan, PackageContribution, ProjectBlueprint, BuiltInGenerationContext, LocalTemplateMetadata, InitializationIdentityOverrides, InitializationInputIssue, InitializationInputValidation, InitializationPreparation, PackageAdditionBusinessConflict, PackageAdditionInputIssue, PackageAdditionPreparation, NextStepInstruction, PublicationSetupHandoff, ResolvedInitialization, RustToolchainChannelReading, } from "./foundation.ts";
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export { builtInPresetRegistry, createGenerationContext, loadLocalTemplateMetadata, prepareGeneratedRepositoryPackageAddition, validateGeneratedRepositoryInitializationInput, prepareGeneratedRepositoryInitialization, planGeneratedRepositoryInitialization, planGeneratedRepositoryPackageAddition, readRustToolchainChannelFromToml, resolveBuiltInTemplateSource, validateProjectBlueprint, } from "./foundation.js";
|
|
1
|
+
export { builtInPresetRegistry, createGenerationContext, loadLocalTemplateMetadata, prepareGeneratedRepositoryPackageAddition, validateGeneratedRepositoryInitializationInput, validateGeneratedRepositoryPackageAdditionInput, prepareGeneratedRepositoryInitialization, planGeneratedRepositoryInitialization, planGeneratedRepositoryPackageAddition, readRustToolchainChannelFromToml, resolveBuiltInTemplateSource, validateProjectBlueprint, } from "./foundation.js";
|
|
2
2
|
export { templateSources } from "./template-sources.js";
|
|
3
|
+
export { generationRecordSchema } from "./generation-record.js";
|
|
@@ -91,8 +91,8 @@ function cliContribution(options) {
|
|
|
91
91
|
{
|
|
92
92
|
kind: "copyFile",
|
|
93
93
|
source: templateSources.tsCli,
|
|
94
|
-
from: "
|
|
95
|
-
to: `${definition.path}/
|
|
94
|
+
from: "src/standard-schema.ts",
|
|
95
|
+
to: `${definition.path}/src/standard-schema.ts`,
|
|
96
96
|
},
|
|
97
97
|
{
|
|
98
98
|
kind: "copyFile",
|
|
@@ -121,8 +121,8 @@ function cliContribution(options) {
|
|
|
121
121
|
{
|
|
122
122
|
kind: "copyFile",
|
|
123
123
|
source: templateSources.tsCli,
|
|
124
|
-
from: "test/e2e/journeys/
|
|
125
|
-
to: `${definition.path}/test/e2e/journeys/
|
|
124
|
+
from: "test/e2e/journeys/lookup.journey.ts",
|
|
125
|
+
to: `${definition.path}/test/e2e/journeys/lookup.journey.ts`,
|
|
126
126
|
},
|
|
127
127
|
];
|
|
128
128
|
return {
|
|
@@ -135,7 +135,11 @@ function cliContribution(options) {
|
|
|
135
135
|
type: "module",
|
|
136
136
|
bin: { [options.packageLeafName]: "./dist/cli.js" },
|
|
137
137
|
scripts: packageScripts(),
|
|
138
|
-
dependencies: {
|
|
138
|
+
dependencies: {
|
|
139
|
+
"@ykdz/cli-contract": "catalog:",
|
|
140
|
+
"@valibot/to-json-schema": "catalog:",
|
|
141
|
+
valibot: "catalog:",
|
|
142
|
+
},
|
|
139
143
|
devDependencies: {
|
|
140
144
|
"@types/node": "catalog:",
|
|
141
145
|
oxfmt: "catalog:",
|
|
@@ -47,11 +47,12 @@
|
|
|
47
47
|
"@types/semver": "catalog:",
|
|
48
48
|
"@types/spdx-expression-parse": "catalog:",
|
|
49
49
|
"@types/web-bluetooth": "catalog:",
|
|
50
|
+
"@valibot/to-json-schema": "catalog:",
|
|
50
51
|
"@vikejs/hono": "catalog:",
|
|
51
52
|
"@vitejs/plugin-vue": "catalog:",
|
|
52
53
|
"@vue/devtools-api": "catalog:",
|
|
53
54
|
"@vue/tsconfig": "catalog:",
|
|
54
|
-
"
|
|
55
|
+
"@ykdz/cli-contract": "catalog:",
|
|
55
56
|
"drizzle-kit": "catalog:",
|
|
56
57
|
"drizzle-orm": "catalog:",
|
|
57
58
|
"execa": "catalog:",
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
若这些限制与 Spec、Ticket、ADR 等权威本地文档冲突,应该以权威本地文档为准。
|
|
8
8
|
|
|
9
|
-
- 开发自动化:非临时维护脚本必须使用 `scripts/**/*.ts` 中可擦除的 TypeScript,而不是 `.mjs` 等 JavaScript
|
|
9
|
+
- 开发自动化:非临时维护脚本必须使用 `scripts/**/*.ts` 中可擦除的 TypeScript,而不是 `.mjs` 等 JavaScript 脚本;归所属非构建 TypeScript 项目并受 format、lint、typecheck 覆盖,防止腐化;产品 build 不产出这些脚本。普通 Node 自动化使用原生 TypeScript 执行链。
|
|
10
10
|
- 临时脚本:编写临时脚本时,应该将其放到有临时目录语义的位置
|
|
11
|
-
- 任务归属:优先使用工具原生配置;直接命令与简单 `&&` 编排写在所属 package manifest
|
|
11
|
+
- 任务归属:优先使用工具原生配置;直接命令与简单 `&&` 编排写在所属 package manifest;只有复杂逻辑才新增 TypeScript script
|
|
12
12
|
- 包边界:本地文件系统访问留在所属包内;跨包代码与资源通过声明依赖和公开 exports 获取,跨包任务交根 Turbo/pnpm 编排。不要以根目录定位器、跨包物理路径或 `@boundaries-ignore` 绕过边界
|
|
13
13
|
- 最小充分测试:不要过度编写单元测试,包括为硬删除设计的防回归测试(可以临时存在,但是硬删除完成后必须删除,最好放在可丢弃分支中方便清理)、为文档内容或任何文件编写的存在性测试等,确保测试覆盖且仅覆盖业务逻辑本身的正负项
|
|
14
14
|
- YAGNI:除非有明确目的,否则不要规划收益不足的安全边界等内容。简单的代码在未来真的遇到新需求时,重构起来远比一个充满防御性冗余设计的复杂系统要容易得多
|
|
15
15
|
- 正式处理链路:开发、回放和端到端验收应复用生产的正式处理链路与制品,入口和配置可不同;同类流程只保留一份实现,迁移后删除旧链路,局部测试不得冒充全链路验收
|
|
16
16
|
- 用户界面:不要将任何技术细节泄漏到用户可见的 UI 中
|
|
17
|
-
-
|
|
17
|
+
- 逐步验收:先通过改动相关的局部门禁,交付前再执行较重的验收任务
|
package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/artifact.ts
CHANGED
|
@@ -17,11 +17,44 @@ import { pathToFileURL } from "node:url";
|
|
|
17
17
|
import { validRange } from "semver";
|
|
18
18
|
import { list } from "tar";
|
|
19
19
|
|
|
20
|
+
import { hasLookupEvidence, hasSchemaEvidence } from "./handoff.ts";
|
|
20
21
|
import {
|
|
21
22
|
inspectNpmPublicationReadiness,
|
|
22
23
|
type NpmPublicationReadiness,
|
|
23
24
|
} from "./readiness.ts";
|
|
24
25
|
|
|
26
|
+
function hasUsageFailure(source: string): boolean {
|
|
27
|
+
try {
|
|
28
|
+
const value: unknown = JSON.parse(source);
|
|
29
|
+
return (
|
|
30
|
+
isObject(value) &&
|
|
31
|
+
value.schemaVersion === "1" &&
|
|
32
|
+
value.kind === "usageFailure" &&
|
|
33
|
+
Array.isArray(value.issues) &&
|
|
34
|
+
value.issues.length > 0
|
|
35
|
+
);
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function hasNotFoundFailure(source: string): boolean {
|
|
42
|
+
try {
|
|
43
|
+
const value: unknown = JSON.parse(source);
|
|
44
|
+
return (
|
|
45
|
+
isObject(value) &&
|
|
46
|
+
value.schemaVersion === "1" &&
|
|
47
|
+
value.command === "lookup" &&
|
|
48
|
+
value.kind === "failure" &&
|
|
49
|
+
value.variant === "notFound" &&
|
|
50
|
+
isObject(value.data) &&
|
|
51
|
+
value.data.name === "missing"
|
|
52
|
+
);
|
|
53
|
+
} catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
25
58
|
type JsonObject = Record<string, unknown>;
|
|
26
59
|
|
|
27
60
|
export type PublicationArtifactFailureCode =
|
|
@@ -96,8 +129,13 @@ export type VerifiedPublicationArtifactReceipt = {
|
|
|
96
129
|
readonly stdout: string;
|
|
97
130
|
},
|
|
98
131
|
{
|
|
99
|
-
readonly name: "
|
|
100
|
-
readonly args: readonly ["
|
|
132
|
+
readonly name: "lookup";
|
|
133
|
+
readonly args: readonly ["lookup", "ada"];
|
|
134
|
+
readonly stdout: string;
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
readonly name: "schema";
|
|
138
|
+
readonly args: readonly ["schema"];
|
|
101
139
|
readonly stdout: string;
|
|
102
140
|
},
|
|
103
141
|
];
|
|
@@ -158,6 +196,7 @@ const expectedFiles = [
|
|
|
158
196
|
"package/dist/cli-command-identity.js",
|
|
159
197
|
"package/dist/cli.js",
|
|
160
198
|
"package/dist/main.js",
|
|
199
|
+
"package/dist/standard-schema.js",
|
|
161
200
|
"package/package.json",
|
|
162
201
|
] as const;
|
|
163
202
|
|
|
@@ -546,10 +585,15 @@ export function inspectPackedManifestContract(options: {
|
|
|
546
585
|
bin[readiness.publication.commandName] === "./dist/cli.js";
|
|
547
586
|
const exactDependencies =
|
|
548
587
|
isObject(dependencies) &&
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
588
|
+
["@ykdz/cli-contract", "@valibot/to-json-schema", "valibot"].every(
|
|
589
|
+
(name) =>
|
|
590
|
+
typeof dependencies[name] === "string" &&
|
|
591
|
+
validRange(dependencies[name]) !== null,
|
|
592
|
+
) &&
|
|
593
|
+
Object.values(dependencies).every(
|
|
594
|
+
(specifier) =>
|
|
595
|
+
typeof specifier === "string" && validRange(specifier) !== null,
|
|
596
|
+
);
|
|
553
597
|
const validPublishConfig =
|
|
554
598
|
publishConfig === undefined ||
|
|
555
599
|
(isObject(publishConfig) &&
|
|
@@ -736,7 +780,7 @@ async function smokeCommand(options: {
|
|
|
736
780
|
readonly env: NodeJS.ProcessEnv;
|
|
737
781
|
}): Promise<CommandResult | PublicationArtifactFailure> {
|
|
738
782
|
const result = await runCommand(options);
|
|
739
|
-
return result.exitCode === 0
|
|
783
|
+
return result.exitCode === 0 && result.stderr === ""
|
|
740
784
|
? result
|
|
741
785
|
: commandFailure(
|
|
742
786
|
"consumer-smoke-failed",
|
|
@@ -1032,8 +1076,9 @@ export async function verifyNpmPublicationArtifact(options: {
|
|
|
1032
1076
|
}
|
|
1033
1077
|
const helpArgs = ["--help"] as const;
|
|
1034
1078
|
const versionArgs = ["--version"] as const;
|
|
1035
|
-
const
|
|
1036
|
-
const
|
|
1079
|
+
const lookupArgs = ["lookup", "ada"] as const;
|
|
1080
|
+
const schemaArgs = ["schema"] as const;
|
|
1081
|
+
const invalidLookupArgs = ["lookup", " "] as const;
|
|
1037
1082
|
const helpCommand = planInstalledBinCommand({
|
|
1038
1083
|
platform: process.platform,
|
|
1039
1084
|
binPath,
|
|
@@ -1066,81 +1111,104 @@ export async function verifyNpmPublicationArtifact(options: {
|
|
|
1066
1111
|
result = { kind: "failed", failure: version };
|
|
1067
1112
|
return result;
|
|
1068
1113
|
}
|
|
1069
|
-
const
|
|
1114
|
+
const lookupCommand = planInstalledBinCommand({
|
|
1070
1115
|
platform: process.platform,
|
|
1071
1116
|
binPath,
|
|
1072
|
-
args:
|
|
1117
|
+
args: lookupArgs,
|
|
1073
1118
|
environment: childEnvironment,
|
|
1074
1119
|
});
|
|
1075
|
-
const
|
|
1076
|
-
executable:
|
|
1077
|
-
args:
|
|
1120
|
+
const lookup = await smokeCommand({
|
|
1121
|
+
executable: lookupCommand.executable,
|
|
1122
|
+
args: lookupCommand.args,
|
|
1078
1123
|
cwd: consumerDirectory,
|
|
1079
|
-
env:
|
|
1124
|
+
env: lookupCommand.environment,
|
|
1080
1125
|
});
|
|
1081
|
-
if ("code" in
|
|
1082
|
-
result = { kind: "failed", failure:
|
|
1083
|
-
return result;
|
|
1084
|
-
}
|
|
1085
|
-
if (
|
|
1086
|
-
!help.stdout.includes(`Usage: ${readiness.publication.commandName}`) ||
|
|
1087
|
-
!help.stdout.includes("greet") ||
|
|
1088
|
-
version.stdout !== `${readiness.publication.version}\n` ||
|
|
1089
|
-
greet.stdout !== "Hello, Ada Lovelace\n"
|
|
1090
|
-
) {
|
|
1091
|
-
result = {
|
|
1092
|
-
kind: "failed",
|
|
1093
|
-
failure: failure(
|
|
1094
|
-
"consumer-smoke-failed",
|
|
1095
|
-
JSON.stringify({
|
|
1096
|
-
help: help.stdout,
|
|
1097
|
-
version: version.stdout,
|
|
1098
|
-
greet: greet.stdout,
|
|
1099
|
-
}),
|
|
1100
|
-
"Installed help, exact version, and greet behavior",
|
|
1101
|
-
"Correct the packed command identity or behavior and retry.",
|
|
1102
|
-
),
|
|
1103
|
-
};
|
|
1126
|
+
if ("code" in lookup) {
|
|
1127
|
+
result = { kind: "failed", failure: lookup };
|
|
1104
1128
|
return result;
|
|
1105
1129
|
}
|
|
1106
|
-
const
|
|
1130
|
+
const schemaCommand = planInstalledBinCommand({
|
|
1107
1131
|
platform: process.platform,
|
|
1108
1132
|
binPath,
|
|
1109
|
-
args:
|
|
1133
|
+
args: schemaArgs,
|
|
1110
1134
|
environment: childEnvironment,
|
|
1111
1135
|
});
|
|
1112
|
-
const
|
|
1113
|
-
executable:
|
|
1114
|
-
args:
|
|
1136
|
+
const schema = await smokeCommand({
|
|
1137
|
+
executable: schemaCommand.executable,
|
|
1138
|
+
args: schemaCommand.args,
|
|
1115
1139
|
cwd: consumerDirectory,
|
|
1116
|
-
env:
|
|
1140
|
+
env: schemaCommand.environment,
|
|
1117
1141
|
});
|
|
1142
|
+
if ("code" in schema) {
|
|
1143
|
+
result = { kind: "failed", failure: schema };
|
|
1144
|
+
return result;
|
|
1145
|
+
}
|
|
1118
1146
|
if (
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
!
|
|
1147
|
+
!help.stdout.includes(readiness.publication.commandName) ||
|
|
1148
|
+
!help.stdout.includes("lookup") ||
|
|
1149
|
+
!help.stdout.includes("schema") ||
|
|
1150
|
+
version.stdout !==
|
|
1151
|
+
`${readiness.publication.commandName} ${readiness.publication.version}\n` ||
|
|
1152
|
+
!hasLookupEvidence(lookup.stdout) ||
|
|
1153
|
+
!hasSchemaEvidence(schema.stdout, readiness.publication.commandName)
|
|
1122
1154
|
) {
|
|
1123
1155
|
result = {
|
|
1124
1156
|
kind: "failed",
|
|
1125
1157
|
failure: failure(
|
|
1126
1158
|
"consumer-smoke-failed",
|
|
1127
1159
|
JSON.stringify({
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
stderr: invalidGreet.stderr,
|
|
1160
|
+
help: help.stdout,
|
|
1161
|
+
version: version.stdout,
|
|
1162
|
+
lookup: lookup.stdout,
|
|
1132
1163
|
}),
|
|
1133
|
-
"
|
|
1134
|
-
"
|
|
1135
|
-
{
|
|
1136
|
-
executable: invalidGreetCommand.executable,
|
|
1137
|
-
args: invalidGreetCommand.args,
|
|
1138
|
-
exitCode: invalidGreet.exitCode,
|
|
1139
|
-
},
|
|
1164
|
+
"安装后的帮助、实际版本、lookup 查询及完整 schema 契约",
|
|
1165
|
+
"修正制品中的命令身份或行为后重试。",
|
|
1140
1166
|
),
|
|
1141
1167
|
};
|
|
1142
1168
|
return result;
|
|
1143
1169
|
}
|
|
1170
|
+
for (const scenario of [
|
|
1171
|
+
{
|
|
1172
|
+
args: [...invalidLookupArgs, "--output-format", "text"],
|
|
1173
|
+
exitCode: 2,
|
|
1174
|
+
accepts: hasUsageFailure,
|
|
1175
|
+
},
|
|
1176
|
+
{ args: ["lookup", "missing"], exitCode: 1, accepts: hasNotFoundFailure },
|
|
1177
|
+
]) {
|
|
1178
|
+
const command = planInstalledBinCommand({
|
|
1179
|
+
platform: process.platform,
|
|
1180
|
+
binPath,
|
|
1181
|
+
args: scenario.args,
|
|
1182
|
+
environment: childEnvironment,
|
|
1183
|
+
});
|
|
1184
|
+
const observed = await runCommand({
|
|
1185
|
+
executable: command.executable,
|
|
1186
|
+
args: command.args,
|
|
1187
|
+
cwd: consumerDirectory,
|
|
1188
|
+
env: command.environment,
|
|
1189
|
+
});
|
|
1190
|
+
if (
|
|
1191
|
+
observed.exitCode !== scenario.exitCode ||
|
|
1192
|
+
observed.stdout !== "" ||
|
|
1193
|
+
!scenario.accepts(observed.stderr)
|
|
1194
|
+
) {
|
|
1195
|
+
result = {
|
|
1196
|
+
kind: "failed",
|
|
1197
|
+
failure: failure(
|
|
1198
|
+
"consumer-smoke-failed",
|
|
1199
|
+
JSON.stringify(observed),
|
|
1200
|
+
"非法输入应退出 2,未找到记录应退出 1;均通过 stderr 返回原生结果。",
|
|
1201
|
+
"修正安装后命令的失败协议并重试。",
|
|
1202
|
+
{
|
|
1203
|
+
executable: command.executable,
|
|
1204
|
+
args: command.args,
|
|
1205
|
+
exitCode: observed.exitCode,
|
|
1206
|
+
},
|
|
1207
|
+
),
|
|
1208
|
+
};
|
|
1209
|
+
return result;
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1144
1212
|
|
|
1145
1213
|
const artifactBytes = await readFile(packedArtifactPath);
|
|
1146
1214
|
const digest = createHash("sha512").update(artifactBytes).digest();
|
|
@@ -1181,7 +1249,8 @@ export async function verifyNpmPublicationArtifact(options: {
|
|
|
1181
1249
|
{ name: "runtime-import", args: [], stdout: "" },
|
|
1182
1250
|
{ name: "help", args: helpArgs, stdout: help.stdout },
|
|
1183
1251
|
{ name: "version", args: versionArgs, stdout: version.stdout },
|
|
1184
|
-
{ name: "
|
|
1252
|
+
{ name: "lookup", args: lookupArgs, stdout: lookup.stdout },
|
|
1253
|
+
{ name: "schema", args: schemaArgs, stdout: schema.stdout },
|
|
1185
1254
|
],
|
|
1186
1255
|
};
|
|
1187
1256
|
try {
|
|
@@ -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
|
|