@ykdz/template 0.0.40 → 0.0.42

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 (87) hide show
  1. package/node_modules/@ykdz/template-builtin-presets/dist/src/foundation.js +144 -101
  2. package/node_modules/@ykdz/template-builtin-presets/dist/src/rust-bin/definition.js +29 -4
  3. package/node_modules/@ykdz/template-builtin-presets/dist/src/shared/vue.js +11 -2
  4. package/node_modules/@ykdz/template-builtin-presets/dist/src/ts-cli/definition.js +14 -4
  5. package/node_modules/@ykdz/template-builtin-presets/dist/src/ts-lib/definition.js +13 -0
  6. package/node_modules/@ykdz/template-builtin-presets/dist/src/vike-app/definition.js +44 -10
  7. package/node_modules/@ykdz/template-builtin-presets/dist/src/vue-app/definition.js +4 -1
  8. package/node_modules/@ykdz/template-builtin-presets/dist/src/vue-hono-app/definition.js +19 -8
  9. package/node_modules/@ykdz/template-builtin-presets/package.json +23 -10
  10. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/.github/workflows/check-deployment-diagnostics.yml +30 -29
  11. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/.github/workflows/check-deployment.yml +8 -21
  12. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/.github/workflows/check-diagnostics.yml +21 -5
  13. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/.github/workflows/check.yml +4 -2
  14. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/AGENTS.md.template +9 -1
  15. package/node_modules/@ykdz/template-builtin-presets/templates/{shared/devcontainer/node-pnpm.Dockerfile → foundation/devcontainer/base.Dockerfile} +14 -1
  16. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/gitignore +1 -0
  17. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/pnpm-workspace.yaml +3 -0
  18. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/scripts/node-test-count-reporter.ts +31 -0
  19. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/scripts/run-rust-tests.ts +100 -0
  20. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/scripts/run-turbo-boundaries.ts +74 -0
  21. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/scripts/task-gates.ts +589 -0
  22. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/turbo-projections/database-preparation.json +17 -0
  23. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/turbo-projections/deployment.json +13 -0
  24. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/turbo-projections/rust-toolchain.json +5 -0
  25. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/turbo-projections/vue-hono-joint-e2e.json +13 -0
  26. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/turbo.json +14 -15
  27. package/node_modules/@ykdz/template-builtin-presets/templates/foundation/typescript-config/turbo.json +30 -1
  28. package/node_modules/@ykdz/template-builtin-presets/templates/rust-bin/devcontainer/rust.Dockerfile +1 -5
  29. package/node_modules/@ykdz/template-builtin-presets/templates/rust-bin/tsconfig.scripts.json +12 -0
  30. package/node_modules/@ykdz/template-builtin-presets/templates/rust-bin/turbo.json +19 -4
  31. package/node_modules/@ykdz/template-builtin-presets/templates/shared/devcontainer/github-cli.Dockerfile +1 -3
  32. package/node_modules/@ykdz/template-builtin-presets/templates/shared/vue/TESTING.md +7 -0
  33. package/node_modules/@ykdz/template-builtin-presets/templates/shared/vue/src/components/CounterButton.vue +18 -0
  34. package/node_modules/@ykdz/template-builtin-presets/templates/shared/vue/test/counter.browser.test.ts +16 -0
  35. package/node_modules/@ykdz/template-builtin-presets/templates/shared/vue/test/{app.test.ts → counter.node.test.ts} +1 -0
  36. package/node_modules/@ykdz/template-builtin-presets/templates/shared/vue/tsconfig.test.json +1 -1
  37. package/node_modules/@ykdz/template-builtin-presets/templates/shared/vue/vitest.config.ts +50 -0
  38. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/check-artifact.ts +16 -5
  39. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/release.yml +5 -2
  40. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication/turbo.json +5 -2
  41. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/publication-setup/bridge.ts +1 -1
  42. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/src/cli-command-identity.ts +0 -45
  43. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/e2e/run-journeys.test.ts +11 -0
  44. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/integration/command.test.ts +43 -39
  45. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/test/unit/cli-command-identity.test.ts +52 -52
  46. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/tsconfig.json +1 -1
  47. package/node_modules/@ykdz/template-builtin-presets/templates/ts-cli/turbo.json +58 -3
  48. package/node_modules/@ykdz/template-builtin-presets/templates/ts-lib/test/greet.test.ts +20 -0
  49. package/node_modules/@ykdz/template-builtin-presets/templates/ts-lib/tsconfig.json +1 -1
  50. package/node_modules/@ykdz/template-builtin-presets/templates/ts-lib/turbo.json +44 -1
  51. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/db/test/todos.test.ts +8 -11
  52. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/db/turbo.json +38 -1
  53. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/db-migrations/turbo.json +44 -1
  54. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/web/playwright.config.ts +18 -2
  55. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/web/test/counter.browser.test.ts +14 -0
  56. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/web/tsconfig.test.json +8 -2
  57. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/web/turbo.json +61 -1
  58. package/node_modules/@ykdz/template-builtin-presets/templates/vike-app/web/vitest.config.ts +29 -2
  59. package/node_modules/@ykdz/template-builtin-presets/templates/vue-app/src/App.vue +2 -12
  60. package/node_modules/@ykdz/template-builtin-presets/templates/vue-app/turbo.json +60 -2
  61. package/node_modules/@ykdz/template-builtin-presets/templates/vue-hono-app/api/test/app.test.ts +7 -6
  62. package/node_modules/@ykdz/template-builtin-presets/templates/vue-hono-app/api/tsconfig.json +2 -7
  63. package/node_modules/@ykdz/template-builtin-presets/templates/vue-hono-app/api/turbo.json +46 -1
  64. package/node_modules/@ykdz/template-builtin-presets/templates/vue-hono-app/web/src/App.vue +2 -11
  65. package/node_modules/@ykdz/template-builtin-presets/templates/vue-hono-app/web/turbo.json +57 -1
  66. package/node_modules/@ykdz/template-core/dist/ci-diagnostic-artifact.d.ts +1 -1
  67. package/node_modules/@ykdz/template-core/dist/ci-diagnostic-artifact.js +6 -3
  68. package/node_modules/@ykdz/template-core/dist/dependency-catalog.d.ts +0 -1
  69. package/node_modules/@ykdz/template-core/dist/dependency-catalog.js +0 -19
  70. package/node_modules/@ykdz/template-core/dist/module-graph.d.ts +0 -9
  71. package/node_modules/@ykdz/template-core/dist/module-graph.js +0 -40
  72. package/node_modules/@ykdz/template-core/dist/package-contribution.d.ts +2 -2
  73. package/node_modules/@ykdz/template-core/dist/package-contribution.js +2 -44
  74. package/node_modules/@ykdz/template-core/dist/pnpm-workspace.yaml +4 -1
  75. package/node_modules/@ykdz/template-core/dist/project-github.d.ts +0 -59
  76. package/node_modules/@ykdz/template-core/dist/project-github.js +7 -70
  77. package/node_modules/@ykdz/template-core/dist/renderer.d.ts +1 -0
  78. package/node_modules/@ykdz/template-core/dist/renderer.js +39 -1
  79. package/node_modules/@ykdz/template-core/dist/template-boundary-check.js +34 -16
  80. package/node_modules/@ykdz/template-core/package.json +0 -5
  81. package/package.json +4 -10
  82. package/node_modules/@ykdz/template-builtin-presets/templates/rust-bin/.github/workflows/check.yml +0 -23
  83. package/node_modules/@ykdz/template-builtin-presets/templates/ts-lib/.github/workflows/check.yml +0 -19
  84. package/node_modules/@ykdz/template-builtin-presets/templates/vue-app/.github/workflows/check.yml +0 -20
  85. package/node_modules/@ykdz/template-builtin-presets/templates/vue-app/vitest.config.ts +0 -8
  86. package/node_modules/@ykdz/template-builtin-presets/templates/vue-hono-app/api/vitest.config.ts +0 -15
  87. package/node_modules/@ykdz/template-builtin-presets/templates/vue-hono-app/web/vitest.config.ts +0 -10
@@ -1,4 +1,33 @@
1
1
  {
2
2
  "extends": ["//"],
3
- "tags": ["library"]
3
+ "tags": ["library"],
4
+ "tasks": {
5
+ "build": {
6
+ "dependsOn": ["^build"],
7
+ "inputs": [],
8
+ "outputs": []
9
+ },
10
+ "format:check": {
11
+ "inputs": [],
12
+ "outputs": [],
13
+ "tags": ["quality:light"]
14
+ },
15
+ "format:write": {
16
+ "dependsOn": ["lint:fix"],
17
+ "inputs": [],
18
+ "outputs": [],
19
+ "cache": false,
20
+ "tags": ["work:repair"]
21
+ },
22
+ "lint:fix": {
23
+ "inputs": [],
24
+ "outputs": [],
25
+ "cache": false
26
+ },
27
+ "typecheck": {
28
+ "dependsOn": ["^typecheck"],
29
+ "inputs": [],
30
+ "outputs": []
31
+ }
32
+ }
4
33
  }
@@ -3,13 +3,9 @@ ENV RUSTUP_HOME=/usr/local/rustup
3
3
  ENV CARGO_HOME=/usr/local/cargo
4
4
 
5
5
  RUN apt-get update && apt-get install -y --no-install-recommends \
6
- ca-certificates \
7
- curl \
8
6
  gcc \
9
- git \
10
7
  libc6-dev \
11
- && rm -rf /var/lib/apt/lists/* \
12
- && git config --system init.defaultBranch main
8
+ && rm -rf /var/lib/apt/lists/*
13
9
  RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \
14
10
  sh -s -- -y --profile minimal --default-toolchain none \
15
11
  && "${CARGO_HOME}/bin/rustup" toolchain install ${RUST_TOOLCHAIN} --profile minimal --component rustfmt --component clippy \
@@ -0,0 +1,12 @@
1
+ {
2
+ "extends": "{{TYPESCRIPT_CONFIG_PACKAGE}}/base.json",
3
+ "compilerOptions": {
4
+ "customConditions": ["source"],
5
+ "module": "nodenext",
6
+ "moduleResolution": "nodenext",
7
+ "noEmit": true,
8
+ "target": "es2024",
9
+ "types": ["node"]
10
+ },
11
+ "include": ["scripts/**/*.ts"]
12
+ }
@@ -4,19 +4,34 @@
4
4
  "tasks": {
5
5
  "format:check": {
6
6
  "dependsOn": ["//#toolchain:prepare"],
7
- "outputs": []
7
+ "inputs": [],
8
+ "outputs": [],
9
+ "tags": ["quality:light"]
8
10
  },
9
11
  "format:write": {
10
12
  "dependsOn": ["//#toolchain:prepare"],
11
- "cache": false
13
+ "inputs": [],
14
+ "outputs": [],
15
+ "cache": false,
16
+ "tags": ["work:repair"]
12
17
  },
13
18
  "lint": {
14
19
  "dependsOn": ["//#toolchain:prepare"],
15
- "outputs": []
20
+ "inputs": [],
21
+ "outputs": [],
22
+ "tags": ["quality:light"]
16
23
  },
17
24
  "test": {
18
25
  "dependsOn": ["//#toolchain:prepare"],
19
- "outputs": []
26
+ "inputs": [],
27
+ "outputs": [],
28
+ "tags": ["quality:light"]
29
+ },
30
+ "typecheck": {
31
+ "dependsOn": ["^typecheck"],
32
+ "inputs": [],
33
+ "outputs": [],
34
+ "tags": ["quality:light"]
20
35
  }
21
36
  }
22
37
  }
@@ -1,6 +1,4 @@
1
- RUN apt-get update \
2
- && apt-get install -y --no-install-recommends curl \
3
- && install -m 0755 -d /etc/apt/keyrings \
1
+ RUN install -m 0755 -d /etc/apt/keyrings \
4
2
  && curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg -o /etc/apt/keyrings/githubcli-archive-keyring.gpg \
5
3
  && chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
6
4
  && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list \
@@ -0,0 +1,7 @@
1
+ # 测试约定
2
+
3
+ 前端包的 `pnpm test` 使用 Vitest 的 `node` 项目运行逻辑测试;`pnpm test:browser` 使用 `browser` 项目在 Chromium 中运行组件测试。Vitest Browser Mode 通过 Playwright provider 启动真实浏览器,测试文件按运行环境命名:`*.node.test.ts` 和 `*.browser.test.ts`。
4
+
5
+ 可复用的业务逻辑、状态管理和纯函数放在 Node 测试中。组件测试通过 `vitest-browser-vue` 渲染真实 Vue 组件,优先按角色和可访问名称查找控件,再执行点击、输入等用户操作并检查可见结果。默认 `render` 会在下个测试开始前清理组件;按组件真实需要配置插件,若使用 Pinia,每个测试都应创建独立实例,避免测试之间共享状态。
6
+
7
+ `pnpm test` 与 `pnpm test:browser` 选择互斥项目。Playwright Test 的 `pnpm test:e2e` 用于覆盖跨页面、服务或持久化流程中的关键用户旅程;组件内部的交互由 Browser Mode 验证,避免在端到端测试中重复这些细节。
@@ -0,0 +1,18 @@
1
+ <script setup lang="ts">
2
+ import { storeToRefs } from "pinia";
3
+
4
+ import { useCounterStore } from "#/stores/counter";
5
+
6
+ const counter = useCounterStore();
7
+ const { count } = storeToRefs(counter);
8
+ </script>
9
+
10
+ <template>
11
+ <button
12
+ class="rounded bg-cyan-300 px-4 py-2 font-semibold text-slate-950 hover:bg-cyan-200"
13
+ type="button"
14
+ @click="counter.increment()"
15
+ >
16
+ 计数:{{ count }}
17
+ </button>
18
+ </template>
@@ -0,0 +1,16 @@
1
+ import { createPinia } from "pinia";
2
+ import { expect, it } from "vitest";
3
+ import { render } from "vitest-browser-vue";
4
+
5
+ import CounterButton from "../src/components/CounterButton.vue";
6
+
7
+ it("increments the Pinia counter when clicked", async () => {
8
+ const screen = await render(CounterButton, {
9
+ global: { plugins: [createPinia()] },
10
+ });
11
+ const button = screen.getByRole("button", { name: /计数/ });
12
+
13
+ await expect.element(button).toHaveTextContent("计数:0");
14
+ await button.click();
15
+ await expect.element(button).toHaveTextContent("计数:1");
16
+ });
@@ -1,4 +1,5 @@
1
1
  import { createPinia, setActivePinia } from "pinia";
2
+ import { describe, expect, it } from "vitest";
2
3
 
3
4
  import { useCounterStore } from "#/stores/counter";
4
5
 
@@ -4,7 +4,7 @@
4
4
  "customConditions": ["source"],
5
5
  "lib": ["ESNext", "DOM", "DOM.Iterable"],
6
6
  "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.test.tsbuildinfo",
7
- "types": ["node", "vitest/globals", "web-bluetooth"]
7
+ "types": ["node", "web-bluetooth"]
8
8
  },
9
9
  "include": ["env.d.ts", "src/**/*.ts", "src/**/*.vue", "test/**/*.ts"]
10
10
  }
@@ -0,0 +1,50 @@
1
+ import { playwright } from "@vitest/browser-playwright";
2
+ import type { ConfigEnv, UserConfig, UserConfigExport } from "vite";
3
+ import { defineConfig, mergeConfig } from "vitest/config";
4
+
5
+ import viteConfig from "./vite.config.ts";
6
+
7
+ function resolveViteConfig(
8
+ config: UserConfigExport,
9
+ configEnv: ConfigEnv,
10
+ ): UserConfig | Promise<UserConfig> {
11
+ return typeof config === "function" ? config(configEnv) : config;
12
+ }
13
+
14
+ export default defineConfig(async (configEnv) => {
15
+ const baseConfig = await resolveViteConfig(viteConfig, configEnv);
16
+
17
+ return mergeConfig(
18
+ baseConfig,
19
+ defineConfig({
20
+ test: {
21
+ attachmentsDir: ".vitest/attachments",
22
+ exclude: ["test/e2e/**", "node_modules/**", "dist/**"],
23
+ projects: [
24
+ {
25
+ extends: true,
26
+ test: {
27
+ name: "node",
28
+ include: ["test/**/*.node.test.ts"],
29
+ environment: "node",
30
+ },
31
+ },
32
+ {
33
+ extends: true,
34
+ test: {
35
+ name: "browser",
36
+ include: ["test/**/*.browser.test.ts"],
37
+ browser: {
38
+ enabled: true,
39
+ provider: playwright(),
40
+ headless: true,
41
+ screenshotFailures: true,
42
+ instances: [{ browser: "chromium" }],
43
+ },
44
+ },
45
+ },
46
+ ],
47
+ },
48
+ }),
49
+ );
50
+ });
@@ -14,6 +14,8 @@ function oneLine(value: string): string {
14
14
  const rawArguments = process.argv.slice(2);
15
15
  const arguments_ =
16
16
  rawArguments[0] === "--" ? rawArguments.slice(1) : rawArguments;
17
+ const requiredSetting = process.env.PUBLICATION_ARTIFACT_REQUIRED;
18
+ const required = requiredSetting === "true";
17
19
  const outputDirectoryFromEnvironment =
18
20
  process.env.PUBLICATION_ARTIFACT_OUTPUT_DIRECTORY;
19
21
  const explicitOutputDirectory =
@@ -30,9 +32,10 @@ const environmentOutputDirectory =
30
32
  ? null
31
33
  : outputDirectoryFromEnvironment;
32
34
  const validArguments =
33
- (arguments_.length === 0 && environmentOutputDirectory !== null) ||
34
- (explicitOutputDirectory !== undefined &&
35
- environmentOutputDirectory === undefined);
35
+ (requiredSetting === undefined || required) &&
36
+ ((arguments_.length === 0 && environmentOutputDirectory !== null) ||
37
+ (explicitOutputDirectory !== undefined &&
38
+ environmentOutputDirectory === undefined));
36
39
  if (!validArguments) {
37
40
  console.error("ERROR publication-artifact-usage");
38
41
  console.error(`Observed: ${JSON.stringify(arguments_)}`);
@@ -57,7 +60,16 @@ if (!validArguments) {
57
60
  outputDirectory,
58
61
  });
59
62
  if (result.kind === "blocked") {
60
- console.log("npm publication artifact: blocked");
63
+ if (result.readiness.mode === "safe-unconfigured") {
64
+ console.log("发布制品验收未执行:候选尚未满足公开发布条件。");
65
+ if (required) {
66
+ console.error("ERROR publication-artifact-required");
67
+ process.exitCode = 1;
68
+ }
69
+ } else {
70
+ console.log("npm publication artifact: blocked");
71
+ process.exitCode = 1;
72
+ }
61
73
  console.log(`Mode: ${result.readiness.mode}`);
62
74
  for (const item of result.readiness.blockers) {
63
75
  console.log(`BLOCKER ${item.code}`);
@@ -66,7 +78,6 @@ if (!validArguments) {
66
78
  console.log(`Expected: ${oneLine(item.expected)}`);
67
79
  console.log(`Next action: ${oneLine(item.nextAction)}`);
68
80
  }
69
- if (result.readiness.mode === "public-intent") process.exitCode = 1;
70
81
  } else if (result.kind === "failed") {
71
82
  console.error(`ERROR ${result.failure.code}`);
72
83
  console.error(`Observed: ${oneLine(result.failure.observed)}`);
@@ -45,10 +45,13 @@ jobs:
45
45
  run: |
46
46
  mkdir -p "$RUNNER_TEMP/npm-publication-artifact"
47
47
  test -z "$(find "$RUNNER_TEMP/npm-publication-artifact" -mindepth 1 -print -quit)"
48
- - name: Run Root Check once
49
- run: pnpm run check
48
+ - name: Run Full Check once
49
+ run: node --conditions=source scripts/task-gates.ts check:full
50
+ - name: Verify publication artifact
51
+ run: pnpm run publication:artifact
50
52
  env:
51
53
  PUBLICATION_ARTIFACT_OUTPUT_DIRECTORY: ${{ runner.temp }}/npm-publication-artifact
54
+ PUBLICATION_ARTIFACT_REQUIRED: "true"
52
55
  - name: Upload verified npm artifact
53
56
  uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
54
57
  with:
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "tasks": {
3
- "//#publication:artifact": { "cache": false },
4
- "//#publication:readiness": { "cache": false }
3
+ "//#publication:artifact": {
4
+ "cache": false,
5
+ "tags": ["quality:conditional"]
6
+ },
7
+ "//#publication:readiness": { "cache": false, "tags": ["work:release"] }
5
8
  }
6
9
  }
@@ -714,7 +714,7 @@ async function configure() {
714
714
  stop(
715
715
  "public-fact-invalid",
716
716
  "invalid command name",
717
- "a portable unreserved CLI command name",
717
+ "符合命名格式的 CLI 命令名",
718
718
  "Correct --bin and retry.",
719
719
  2,
720
720
  );
@@ -3,46 +3,6 @@ export type CliCommandIdentity = {
3
3
  readonly version: string;
4
4
  };
5
5
 
6
- const reservedSystemToolNames = new Set([
7
- "aux",
8
- "bash",
9
- "bun",
10
- "cmd",
11
- "com1",
12
- "com2",
13
- "com3",
14
- "com4",
15
- "com5",
16
- "com6",
17
- "com7",
18
- "com8",
19
- "com9",
20
- "con",
21
- "corepack",
22
- "deno",
23
- "git",
24
- "lpt1",
25
- "lpt2",
26
- "lpt3",
27
- "lpt4",
28
- "lpt5",
29
- "lpt6",
30
- "lpt7",
31
- "lpt8",
32
- "lpt9",
33
- "node",
34
- "nul",
35
- "npm",
36
- "npx",
37
- "pnpm",
38
- "powershell",
39
- "prn",
40
- "pwsh",
41
- "sh",
42
- "yarn",
43
- "zsh",
44
- ]);
45
-
46
6
  export function validateCliCommandName(
47
7
  commandName: string,
48
8
  occupiedCommandNames: readonly string[] = [],
@@ -72,11 +32,6 @@ export function validateCliCommandName(
72
32
  `CLI command name must use lowercase ASCII letters, digits, and single hyphens; received ${JSON.stringify(commandName)}`,
73
33
  );
74
34
  }
75
- if (reservedSystemToolNames.has(commandName)) {
76
- throw new Error(
77
- `CLI command name is a reserved system tool; received ${JSON.stringify(commandName)}`,
78
- );
79
- }
80
35
  if (occupiedCommandNames.includes(commandName)) {
81
36
  throw new Error(
82
37
  `CLI command name is already used by another workspace package; received ${JSON.stringify(commandName)}`,
@@ -0,0 +1,11 @@
1
+ import assert from "node:assert/strict";
2
+ import { test } from "node:test";
3
+
4
+ import { runJourneys } from "./run-journeys.ts";
5
+
6
+ for (const mode of ["source", "distribution"] as const) {
7
+ void test(`runs all ${mode} CLI journeys`, { timeout: 180_000 }, async () => {
8
+ const passed = await runJourneys({ mode });
9
+ assert.notStrictEqual(passed.length, 0);
10
+ });
11
+ }
@@ -1,6 +1,6 @@
1
+ import assert from "node:assert/strict";
1
2
  import { createRequire } from "node:module";
2
-
3
- import { describe, expect, it } from "vitest";
3
+ import { describe, it } from "node:test";
4
4
 
5
5
  import { cliCommandIdentity } from "../../src/cli-command-identity.ts";
6
6
  import { runCli, type CliRuntime } from "../../src/main.ts";
@@ -23,62 +23,63 @@ function testRuntime(args: readonly string[]) {
23
23
  return { runtime, stdout: () => stdout, stderr: () => stderr };
24
24
  }
25
25
 
26
- describe("CLI 契约", () => {
27
- it("查询成功默认返回结构化数据,也支持中文文本", async () => {
26
+ void describe("CLI 契约", () => {
27
+ void it("查询成功默认返回结构化数据,也支持中文文本", async () => {
28
28
  const output = testRuntime(["lookup", "ada"]);
29
- expect(await runCli(output.runtime)).toBe(0);
30
- expect(JSON.parse(output.stdout())).toEqual({
29
+ assert.equal(await runCli(output.runtime), 0);
30
+ assert.deepStrictEqual(JSON.parse(output.stdout()), {
31
31
  schemaVersion: "1",
32
32
  command: "lookup",
33
33
  kind: "data",
34
34
  variant: "found",
35
35
  data: { name: "ada", title: "Ada Lovelace" },
36
36
  });
37
- expect(output.stderr()).toBe("");
37
+ assert.equal(output.stderr(), "");
38
38
  const human = testRuntime(["lookup", "ada", "--output-format", "text"]);
39
- expect(await runCli(human.runtime)).toBe(0);
40
- expect(human.stdout()).toContain("找到记录");
41
- expect(human.stdout()).toContain("Ada Lovelace");
39
+ assert.equal(await runCli(human.runtime), 0);
40
+ assert.ok(human.stdout().includes("找到记录"));
41
+ assert.ok(human.stdout().includes("Ada Lovelace"));
42
42
  });
43
43
 
44
- it("未找到记录是已声明失败,非法名称是用法错误", async () => {
44
+ void it("未找到记录是已声明失败,非法名称是用法错误", async () => {
45
45
  const missing = testRuntime(["lookup", "missing"]);
46
- expect(await runCli(missing.runtime)).toBe(1);
47
- expect(missing.stdout()).toBe("");
48
- expect(JSON.parse(missing.stderr())).toMatchObject({
46
+ assert.equal(await runCli(missing.runtime), 1);
47
+ assert.equal(missing.stdout(), "");
48
+ assert.partialDeepStrictEqual(JSON.parse(missing.stderr()), {
49
49
  kind: "failure",
50
50
  variant: "notFound",
51
51
  data: { name: "missing" },
52
52
  });
53
53
  for (const args of [["lookup"], ["lookup", " "]]) {
54
54
  const invalid = testRuntime([...args, "--output-format", "text"]);
55
- expect(await runCli(invalid.runtime)).toBe(2);
56
- expect(invalid.stdout()).toBe("");
57
- expect(JSON.parse(invalid.stderr())).toMatchObject({
55
+ assert.equal(await runCli(invalid.runtime), 2);
56
+ assert.equal(invalid.stdout(), "");
57
+ assert.partialDeepStrictEqual(JSON.parse(invalid.stderr()), {
58
58
  kind: "usageFailure",
59
59
  });
60
60
  }
61
61
  });
62
62
 
63
- it("帮助和版本使用 manifest 身份,schema 导出完整契约", async () => {
63
+ void it("帮助和版本使用 manifest 身份,schema 导出完整契约", async () => {
64
64
  const version = testRuntime(["--version"]);
65
- expect(await runCli(version.runtime)).toBe(0);
66
- expect(version.stdout()).toBe(
65
+ assert.equal(await runCli(version.runtime), 0);
66
+ assert.equal(
67
+ version.stdout(),
67
68
  `${identity.commandName} ${identity.version}\n`,
68
69
  );
69
70
  const help = testRuntime(["--help"]);
70
- expect(await runCli(help.runtime)).toBe(0);
71
- expect(help.stdout()).toContain(identity.commandName);
72
- expect(help.stdout()).toContain("lookup");
73
- expect(help.stdout()).toContain("schema");
71
+ assert.equal(await runCli(help.runtime), 0);
72
+ assert.ok(help.stdout().includes(identity.commandName));
73
+ assert.ok(help.stdout().includes("lookup"));
74
+ assert.ok(help.stdout().includes("schema"));
74
75
  const schema = testRuntime(["schema"]);
75
- expect(await runCli(schema.runtime)).toBe(0);
76
+ assert.equal(await runCli(schema.runtime), 0);
76
77
  const humanSchema = testRuntime(["schema", "--output-format", "text"]);
77
- expect(await runCli(humanSchema.runtime)).toBe(0);
78
- expect(humanSchema.stdout()).toContain("CLI 契约");
79
- expect(humanSchema.stdout()).toContain('"commands"');
78
+ assert.equal(await runCli(humanSchema.runtime), 0);
79
+ assert.ok(humanSchema.stdout().includes("CLI 契约"));
80
+ assert.ok(humanSchema.stdout().includes('"commands"'));
80
81
  const manifest = JSON.parse(schema.stdout()).data.manifest;
81
- expect(manifest).toMatchObject({
82
+ assert.partialDeepStrictEqual(manifest, {
82
83
  commands: {
83
84
  lookup: {
84
85
  input: {
@@ -102,41 +103,44 @@ describe("CLI 契约", () => {
102
103
  });
103
104
  });
104
105
 
105
- it("等待输出完成,仅 stdout EPIPE 安静成功", async () => {
106
+ void it("等待输出完成,仅 stdout EPIPE 安静成功", async () => {
106
107
  const output = testRuntime(["lookup", "ada"]);
107
- expect(
108
+ assert.equal(
108
109
  await runCli({
109
110
  ...output.runtime,
110
111
  write: async () => {
111
112
  throw Object.assign(new Error("pipe"), { code: "EPIPE" });
112
113
  },
113
114
  }),
114
- ).toBe(0);
115
- expect(
115
+ 0,
116
+ );
117
+ assert.equal(
116
118
  await runCli({
117
119
  ...output.runtime,
118
120
  write: async () => {
119
121
  throw new Error("disk");
120
122
  },
121
123
  }),
122
- ).toBe(70);
124
+ 70,
125
+ );
123
126
  const failure = testRuntime(["lookup", "missing"]);
124
- expect(
127
+ assert.equal(
125
128
  await runCli({
126
129
  ...failure.runtime,
127
130
  write: async () => {
128
131
  throw Object.assign(new Error("pipe"), { code: "EPIPE" });
129
132
  },
130
133
  }),
131
- ).toBe(70);
134
+ 70,
135
+ );
132
136
  const argv = ["node", identity.commandName];
133
137
  Object.defineProperty(argv, "slice", {
134
138
  value() {
135
139
  throw new Error("内部细节");
136
140
  },
137
141
  });
138
- expect(await runCli({ ...output.runtime, argv })).toBe(70);
139
- expect(output.stderr()).toContain("命令执行失败");
140
- expect(output.stderr()).not.toContain("内部细节");
142
+ assert.equal(await runCli({ ...output.runtime, argv }), 70);
143
+ assert.ok(output.stderr().includes("命令执行失败"));
144
+ assert.ok(!output.stderr().includes("内部细节"));
141
145
  });
142
146
  });