create-yss-spec 2.1.14 → 2.2.0

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 (187) hide show
  1. package/README.md +18 -2
  2. package/package.json +1 -1
  3. package/src/cli.js +367 -19
  4. package/template/.agents/skills/cross-repo-implementation-routing/SKILL.md +2 -2
  5. package/template/.agents/skills/implementation-repo-onboarding/SKILL.md +5 -5
  6. package/template/.agents/skills/llm-wiki/SKILL.md +1 -1
  7. package/template/.agents/skills/llm-wiki/references/discover.md +1 -0
  8. package/template/.agents/skills/yss-ddd-scaffold-generator/SKILL.md +1 -1
  9. package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +30 -3
  10. package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +52 -0
  11. package/template/.agents/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  12. package/template/.agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md +1 -1
  13. package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +24 -0
  14. package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +2 -0
  15. package/template/.agents/skills/yss-product-lifecycle/references/state-model.md +1 -1
  16. package/template/.agents/skills/yss-router/SKILL.md +1 -1
  17. package/template/.agents/skills/yss-router/references/router-contract.yaml +20 -0
  18. package/template/.agents/skills/yss-router/references/slice-implementation-contract.md +1 -1
  19. package/template/.claude/skills/cross-repo-implementation-routing/SKILL.md +2 -2
  20. package/template/.claude/skills/implementation-repo-onboarding/SKILL.md +5 -5
  21. package/template/.claude/skills/llm-wiki/SKILL.md +1 -1
  22. package/template/.claude/skills/llm-wiki/references/discover.md +1 -0
  23. package/template/.claude/skills/yss-ddd-scaffold-generator/SKILL.md +1 -1
  24. package/template/.claude/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +30 -3
  25. package/template/.claude/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +52 -0
  26. package/template/.claude/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  27. package/template/.claude/skills/yss-product-lifecycle/references/matt-yss-adapter.md +1 -1
  28. package/template/.claude/skills/yss-product-lifecycle/references/orchestration-contract.yaml +24 -0
  29. package/template/.claude/skills/yss-product-lifecycle/references/orchestration.md +2 -0
  30. package/template/.claude/skills/yss-product-lifecycle/references/state-model.md +1 -1
  31. package/template/.claude/skills/yss-router/SKILL.md +1 -1
  32. package/template/.claude/skills/yss-router/references/router-contract.yaml +20 -0
  33. package/template/.claude/skills/yss-router/references/slice-implementation-contract.md +1 -1
  34. package/template/.codex/skills/cross-repo-implementation-routing/SKILL.md +2 -2
  35. package/template/.codex/skills/implementation-repo-onboarding/SKILL.md +5 -5
  36. package/template/.codex/skills/llm-wiki/SKILL.md +1 -1
  37. package/template/.codex/skills/llm-wiki/references/discover.md +1 -0
  38. package/template/.codex/skills/yss-ddd-scaffold-generator/SKILL.md +1 -1
  39. package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +30 -3
  40. package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +52 -0
  41. package/template/.codex/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  42. package/template/.codex/skills/yss-product-lifecycle/references/matt-yss-adapter.md +1 -1
  43. package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +24 -0
  44. package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +2 -0
  45. package/template/.codex/skills/yss-product-lifecycle/references/state-model.md +1 -1
  46. package/template/.codex/skills/yss-router/SKILL.md +1 -1
  47. package/template/.codex/skills/yss-router/references/router-contract.yaml +20 -0
  48. package/template/.codex/skills/yss-router/references/slice-implementation-contract.md +1 -1
  49. package/template/.cursor/skills/cross-repo-implementation-routing/SKILL.md +2 -2
  50. package/template/.cursor/skills/implementation-repo-onboarding/SKILL.md +5 -5
  51. package/template/.cursor/skills/llm-wiki/SKILL.md +1 -1
  52. package/template/.cursor/skills/llm-wiki/references/discover.md +1 -0
  53. package/template/.cursor/skills/yss-ddd-scaffold-generator/SKILL.md +1 -1
  54. package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +30 -3
  55. package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +52 -0
  56. package/template/.cursor/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  57. package/template/.cursor/skills/yss-product-lifecycle/references/matt-yss-adapter.md +1 -1
  58. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +24 -0
  59. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +2 -0
  60. package/template/.cursor/skills/yss-product-lifecycle/references/state-model.md +1 -1
  61. package/template/.cursor/skills/yss-router/SKILL.md +1 -1
  62. package/template/.cursor/skills/yss-router/references/router-contract.yaml +20 -0
  63. package/template/.cursor/skills/yss-router/references/slice-implementation-contract.md +1 -1
  64. package/template/.hermes/skills/cross-repo-implementation-routing/SKILL.md +2 -2
  65. package/template/.hermes/skills/implementation-repo-onboarding/SKILL.md +5 -5
  66. package/template/.hermes/skills/llm-wiki/SKILL.md +1 -1
  67. package/template/.hermes/skills/llm-wiki/references/discover.md +1 -0
  68. package/template/.hermes/skills/yss-ddd-scaffold-generator/SKILL.md +1 -1
  69. package/template/.hermes/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +30 -3
  70. package/template/.hermes/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +52 -0
  71. package/template/.hermes/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  72. package/template/.hermes/skills/yss-product-lifecycle/references/matt-yss-adapter.md +1 -1
  73. package/template/.hermes/skills/yss-product-lifecycle/references/orchestration-contract.yaml +24 -0
  74. package/template/.hermes/skills/yss-product-lifecycle/references/orchestration.md +2 -0
  75. package/template/.hermes/skills/yss-product-lifecycle/references/state-model.md +1 -1
  76. package/template/.hermes/skills/yss-router/SKILL.md +1 -1
  77. package/template/.hermes/skills/yss-router/references/router-contract.yaml +20 -0
  78. package/template/.hermes/skills/yss-router/references/slice-implementation-contract.md +1 -1
  79. package/template/.pi/skills/cross-repo-implementation-routing/SKILL.md +2 -2
  80. package/template/.pi/skills/implementation-repo-onboarding/SKILL.md +5 -5
  81. package/template/.pi/skills/llm-wiki/SKILL.md +1 -1
  82. package/template/.pi/skills/llm-wiki/references/discover.md +1 -0
  83. package/template/.pi/skills/yss-ddd-scaffold-generator/SKILL.md +1 -1
  84. package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +30 -3
  85. package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +52 -0
  86. package/template/.pi/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  87. package/template/.pi/skills/yss-product-lifecycle/references/matt-yss-adapter.md +1 -1
  88. package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +24 -0
  89. package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +2 -0
  90. package/template/.pi/skills/yss-product-lifecycle/references/state-model.md +1 -1
  91. package/template/.pi/skills/yss-router/SKILL.md +1 -1
  92. package/template/.pi/skills/yss-router/references/router-contract.yaml +20 -0
  93. package/template/.pi/skills/yss-router/references/slice-implementation-contract.md +1 -1
  94. package/template/.qoder/skills/cross-repo-implementation-routing/SKILL.md +2 -2
  95. package/template/.qoder/skills/implementation-repo-onboarding/SKILL.md +5 -5
  96. package/template/.qoder/skills/llm-wiki/SKILL.md +1 -1
  97. package/template/.qoder/skills/llm-wiki/references/discover.md +1 -0
  98. package/template/.qoder/skills/yss-ddd-scaffold-generator/SKILL.md +1 -1
  99. package/template/.qoder/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +30 -3
  100. package/template/.qoder/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +52 -0
  101. package/template/.qoder/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  102. package/template/.qoder/skills/yss-product-lifecycle/references/matt-yss-adapter.md +1 -1
  103. package/template/.qoder/skills/yss-product-lifecycle/references/orchestration-contract.yaml +24 -0
  104. package/template/.qoder/skills/yss-product-lifecycle/references/orchestration.md +2 -0
  105. package/template/.qoder/skills/yss-product-lifecycle/references/state-model.md +1 -1
  106. package/template/.qoder/skills/yss-router/SKILL.md +1 -1
  107. package/template/.qoder/skills/yss-router/references/router-contract.yaml +20 -0
  108. package/template/.qoder/skills/yss-router/references/slice-implementation-contract.md +1 -1
  109. package/template/.trae/skills/cross-repo-implementation-routing/SKILL.md +2 -2
  110. package/template/.trae/skills/implementation-repo-onboarding/SKILL.md +5 -5
  111. package/template/.trae/skills/llm-wiki/SKILL.md +1 -1
  112. package/template/.trae/skills/llm-wiki/references/discover.md +1 -0
  113. package/template/.trae/skills/yss-ddd-scaffold-generator/SKILL.md +1 -1
  114. package/template/.trae/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +30 -3
  115. package/template/.trae/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +52 -0
  116. package/template/.trae/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  117. package/template/.trae/skills/yss-product-lifecycle/references/matt-yss-adapter.md +1 -1
  118. package/template/.trae/skills/yss-product-lifecycle/references/orchestration-contract.yaml +24 -0
  119. package/template/.trae/skills/yss-product-lifecycle/references/orchestration.md +2 -0
  120. package/template/.trae/skills/yss-product-lifecycle/references/state-model.md +1 -1
  121. package/template/.trae/skills/yss-router/SKILL.md +1 -1
  122. package/template/.trae/skills/yss-router/references/router-contract.yaml +20 -0
  123. package/template/.trae/skills/yss-router/references/slice-implementation-contract.md +1 -1
  124. package/template/AGENTS.md +5 -5
  125. package/template/CONTEXT.md +3 -2
  126. package/template/docs/process/implementation-repo-integration.md +24 -2
  127. package/template/docs/templates/cross-repo-slice-template.md +15 -0
  128. package/template/docs/templates/implementation-repo-registry-template.md +8 -3
  129. package/template/docs/templates/implementation-routing-template.md +3 -3
  130. package/template/docs/user-guide//344/272/247/345/223/201/347/224/237/345/221/275/345/221/250/346/234/237/345/267/245/344/275/234/346/265/201.md +2 -2
  131. package/template/scripts/lib/git-submodule-fixtures.mjs +58 -0
  132. package/template/scripts/lib/repository-scope-policy.mjs +456 -0
  133. package/template/scripts/lib/scenario-checks.mjs +11 -1
  134. package/template/scripts/repository-scope-policy +16 -0
  135. package/template/scripts/verify-repository-scope-scenarios +239 -0
  136. package/template/scripts/verify-scaffold-generator-scenarios +54 -0
  137. package/template/scripts/verify-template +3 -2
  138. package/template/skills-lock.json +7 -7
  139. package/template.manifest.json +6 -5
  140. package/template.snapshot.json +4 -4
  141. package/template/.cursor/environment.json +0 -5
  142. package/template/.github/workflows/template-node-tooling.yml +0 -61
  143. package/template/wiki/.wiki-manifest.json +0 -390
  144. package/template/wiki/raw/AGENTS.md +0 -122
  145. package/template/wiki/raw/CONTEXT.md +0 -80
  146. package/template/wiki/raw/README.md +0 -130
  147. package/template/wiki/raw/adr-0002-repository-mode.md +0 -3
  148. package/template/wiki/raw/create-yss-spec-repository-mode-contract.md +0 -95
  149. package/template/wiki/raw/harness-process-tailoring.md +0 -64
  150. package/template/wiki/raw/implementation-repo-integration.md +0 -62
  151. package/template/wiki/raw/issue-tracker.md +0 -135
  152. package/template/wiki/raw/lifecycle-registry.yaml +0 -369
  153. package/template/wiki/raw/maintenance-intensity.yaml +0 -25
  154. package/template/wiki/raw/skills-lock-names.md +0 -93
  155. package/template/wiki/raw/skills-maintenance.md +0 -90
  156. package/template/wiki/raw/spec-template.md +0 -102
  157. package/template/wiki/raw/triage-labels.md +0 -15
  158. package/template/wiki/raw/vertical-slice-ticket-template.md +0 -132
  159. package/template/wiki/raw/yss-project.yaml +0 -2
  160. package/template/wiki/raw/yss-skill-registry.yaml +0 -510
  161. package/template/wiki/wiki/Agent/345/205/245/345/217/243/350/247/204/345/210/231.md +0 -21
  162. package/template/wiki/wiki/CLAUDE.md +0 -28
  163. package/template/wiki/wiki/Fresh/351/252/214/350/257/201/344/270/216/347/213/254/347/253/213/345/256/241/346/237/245.md +0 -19
  164. package/template/wiki/wiki/LLM Wiki.md +0 -30
  165. package/template/wiki/wiki/Matt/346/212/200/350/203/275/344/275/223/347/263/273.md +0 -21
  166. package/template/wiki/wiki/OpenAPI/345/245/221/347/272/246.md +0 -20
  167. package/template/wiki/wiki/SpecDelta.md +0 -19
  168. package/template/wiki/wiki/Spec/345/237/272/347/272/277.md +0 -22
  169. package/template/wiki/wiki/Ticket/344/270/216/346/265/201/347/250/213/347/212/266/346/200/201.md +0 -21
  170. package/template/wiki/wiki/YSS/345/267/245/347/250/213/346/212/200/350/203/275/344/275/223/347/263/273.md +0 -23
  171. package/template/wiki/wiki/YSS/350/267/257/347/224/261/344/270/216/345/220/210/345/220/214/347/274/226/350/257/221.md +0 -20
  172. package/template/wiki/wiki/concept-table.md +0 -9
  173. package/template/wiki/wiki/index.md +0 -41
  174. package/template/wiki/wiki/log.md +0 -51
  175. package/template/wiki/wiki//344/272/247/345/223/201/347/240/224/345/217/221/347/224/237/345/221/275/345/221/250/346/234/237.md +0 -20
  176. package/template/wiki/wiki//344/272/247/345/223/201/350/256/276/350/256/241/345/275/261/345/223/215/344/270/216/345/216/237/345/236/213.md +0 -19
  177. package/template/wiki/wiki//344/273/223/345/272/223/350/272/253/344/273/275/344/270/216/350/267/257/347/224/261.md +0 -20
  178. package/template/wiki/wiki//345/210/207/347/211/207/345/256/236/347/216/260/345/220/210/345/220/214.md +0 -21
  179. package/template/wiki/wiki//345/236/202/347/233/264/345/210/207/347/211/207Ticket.md +0 -23
  180. package/template/wiki/wiki//345/244/215/347/233/230/344/270/216/346/235/203/345/250/201/350/265/204/344/272/247/344/277/256/350/256/242.md +0 -20
  181. package/template/wiki/wiki//345/256/236/347/216/260/344/273/223/345/272/223/344/270/216/350/267/250/344/273/223/345/272/223/345/245/221/347/272/246.md +0 -22
  182. package/template/wiki/wiki//345/275/261/345/223/215/351/235/242/345/210/206/350/257/212/344/270/216/346/265/201/347/250/213/350/243/201/345/211/252.md +0 -20
  183. package/template/wiki/wiki//346/212/200/350/203/275/346/212/225/345/275/261/344/270/216/351/224/201/345/256/232.md +0 -23
  184. package/template/wiki/wiki//346/235/241/344/273/266/345/274/272/345/210/266/351/227/250/347/246/201.md +0 -18
  185. package/template/wiki/wiki//346/250/241/346/235/277/345/217/221/345/270/203/351/227/250/347/246/201/344/270/216/351/252/214/350/257/201.md +0 -22
  186. package/template/wiki/wiki//346/250/241/346/235/277/346/200/273/350/247/210.md +0 -20
  187. package/template/wiki/wiki//346/250/241/346/235/277/347/273/264/346/212/244/346/265/201/347/250/213.md +0 -19
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import {
6
+ LAYOUT_POLICIES,
7
+ NAMED_STRESS_SCENARIOS,
8
+ REPOSITORY_SCOPES,
9
+ gitSubmoduleCommitViolation,
10
+ gitSubmodulePushOrderViolation,
11
+ gitSubmoduleScaffoldViolation,
12
+ implementationWriteViolation,
13
+ inspectCheckoutState,
14
+ inspectWorkingTreeScope,
15
+ isWorkingTreeWritable,
16
+ regularDirectoryMisreadViolation,
17
+ validRepositoryScope,
18
+ violationRepositoryScope
19
+ } from "./lib/repository-scope-policy.mjs";
20
+ import { makeGitlinkFixture } from "./lib/git-submodule-fixtures.mjs";
21
+
22
+ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
23
+ const read = (relative) => readFileSync(path.join(root, relative), "utf8");
24
+ const failures = [];
25
+ const namedPassed = [];
26
+
27
+ function ensure(condition, message) {
28
+ if (!condition) failures.push(message);
29
+ }
30
+
31
+ function namedStress(id, condition, message) {
32
+ if (!NAMED_STRESS_SCENARIOS.includes(id)) {
33
+ failures.push(`named stress ${id}: unknown id`);
34
+ return;
35
+ }
36
+ if (!condition) {
37
+ failures.push(`named stress ${id}: FAIL ${message}`);
38
+ return;
39
+ }
40
+ namedPassed.push(id);
41
+ }
42
+
43
+ const validGitSubmodule = {
44
+ repository_scope: "git-submodule",
45
+ layout_policy: LAYOUT_POLICIES["git-submodule"],
46
+ project_root: "apps/backend/billing-service/",
47
+ gitlink_path: "apps/backend/billing-service",
48
+ git_entry_mode: "160000",
49
+ git_url: "https://example.invalid/billing-service.git",
50
+ gitmodules_name: "backend-billing-service",
51
+ superproject_git_url: "https://example.invalid/harness.git",
52
+ checkout_state: "attached-branch",
53
+ scaffold_status: "existing"
54
+ };
55
+
56
+ ensure(validRepositoryScope({ repository_scope: "external-repository", layout_policy: "external-repository-native", project_root: "src/" }), "应允许 external-repository");
57
+ ensure(validRepositoryScope({ repository_scope: "harness-apps", layout_policy: "harness-apps-multi-project", project_root: "apps/frontend/console/" }), "应允许 harness-apps");
58
+ ensure(validRepositoryScope(validGitSubmodule), `应允许正式 git-submodule: ${violationRepositoryScope(validGitSubmodule) ?? ""}`);
59
+
60
+ namedStress(
61
+ "unknown_scope",
62
+ violationRepositoryScope({ repository_scope: "monorepo" })?.includes("repository_scope must be one of"),
63
+ "未知 repository_scope 应阻断"
64
+ );
65
+ namedStress(
66
+ "layout_mismatch",
67
+ violationRepositoryScope({ ...validGitSubmodule, layout_policy: "harness-apps-multi-project" })?.includes("layout_policy"),
68
+ "git-submodule 不得套用 harness-apps layout_policy"
69
+ );
70
+ namedStress(
71
+ "same_origin_url",
72
+ violationRepositoryScope({ ...validGitSubmodule, git_url: validGitSubmodule.superproject_git_url })?.includes("differ"),
73
+ "子仓 url 不得等于 superproject"
74
+ );
75
+ namedStress(
76
+ "copy_source_into_harness",
77
+ violationRepositoryScope({ ...validGitSubmodule, copy_source_into_harness: true })?.includes("gitlink mount"),
78
+ "复制源码进 Harness 应阻断"
79
+ );
80
+ namedStress(
81
+ "missing_git_entry_mode",
82
+ violationRepositoryScope({ ...validGitSubmodule, git_entry_mode: "" })?.includes("git_entry_mode must be 160000"),
83
+ "git-submodule 缺少 git_entry_mode 应阻断"
84
+ );
85
+
86
+ ensure(violationRepositoryScope({
87
+ repository_scope: "harness-apps",
88
+ layout_policy: "harness-apps-multi-project",
89
+ project_root: "apps/backend/billing-service/",
90
+ git_entry_mode: "160000"
91
+ })?.includes("git-submodule"), "harness-apps 记录 gitlink 应改登记为 git-submodule");
92
+ ensure(violationRepositoryScope({
93
+ repository_scope: "harness-apps",
94
+ layout_policy: "harness-apps-multi-project",
95
+ project_root: "apps/backend/billing-service/",
96
+ gitlink_path: "apps/backend/billing-service",
97
+ gitmodules_name: "backend-billing-service"
98
+ })?.includes("git-submodule identity"), "harness-apps 填写 gitlink 身份字段应阻断");
99
+ ensure(violationRepositoryScope({ repository_scope: "external-repository", gitlink_path: "apps/backend/billing-service", git_entry_mode: "160000" })?.includes("git-submodule"), "external-repository 挂 apps/ gitlink 应阻断");
100
+ ensure(violationRepositoryScope({ ...validGitSubmodule, checkout_state: "detached-head", commit_allowed: true })?.includes("detached HEAD"), "detached HEAD 提交应阻断");
101
+ ensure(violationRepositoryScope({ ...validGitSubmodule, checkout_state: "detached-head", scaffold_status: "required" })?.includes("regular directory"), "detached HEAD 脚手架应阻断");
102
+ ensure(violationRepositoryScope({ ...validGitSubmodule, checkout_state: "empty-gitlink", scaffold_status: "required" })?.includes("empty or uninitialized"), "空 gitlink 脚手架应阻断");
103
+ ensure(gitSubmoduleCommitViolation({ checkout_state: "detached-head", commit_authorized: true })?.includes("attached branch"), "commit 辅助校验应拒绝 detached HEAD");
104
+ ensure(gitSubmodulePushOrderViolation(["superproject-gitlink", "submodule-repositories"])?.includes("submodule-repositories then superproject-gitlink"), "先父后子 push 应阻断");
105
+ ensure(gitSubmodulePushOrderViolation(["submodule-repositories", "superproject-gitlink"]) === null, "先子后父顺序应允许");
106
+
107
+ const emptyGitlink = makeGitlinkFixture({ checkout: "empty-gitlink" });
108
+ const detached = makeGitlinkFixture({ checkout: "detached-head" });
109
+ const attached = makeGitlinkFixture({ checkout: "attached-branch" });
110
+ try {
111
+ const emptyTarget = path.join(emptyGitlink.superproject, emptyGitlink.mount);
112
+ const emptyRecord = {
113
+ repository_scope: "git-submodule",
114
+ project_root: "apps/backend/billing-service/",
115
+ checkout_state: "empty-gitlink"
116
+ };
117
+ const emptyInspection = inspectWorkingTreeScope(emptyGitlink.superproject, emptyRecord);
118
+ namedStress(
119
+ "empty_gitlink_as_regular_dir",
120
+ typeof emptyInspection === "object"
121
+ && emptyInspection !== null
122
+ && Array.isArray(emptyInspection) === false
123
+ && emptyInspection.writable === false
124
+ && emptyInspection.writable === true === false
125
+ && isWorkingTreeWritable(emptyInspection) === false
126
+ && emptyInspection.violation?.includes("regular directory")
127
+ && inspectCheckoutState(emptyGitlink.superproject, emptyTarget) === "empty-gitlink"
128
+ && implementationWriteViolation(emptyGitlink.superproject, path.join(emptyTarget, "src/Foo.java"))?.includes("普通目录写入")
129
+ && gitSubmoduleScaffoldViolation(emptyGitlink.superproject, path.join(emptyGitlink.superproject, "apps/backend"), "billing-service")?.includes("gitlink 不得由脚手架覆盖"),
130
+ "空 gitlink 仍被当成普通目录"
131
+ );
132
+ namedStress(
133
+ "declared_harness_apps_actual_gitlink",
134
+ inspectWorkingTreeScope(emptyGitlink.superproject, {
135
+ repository_scope: "harness-apps",
136
+ project_root: "apps/backend/billing-service/"
137
+ }).writable === false
138
+ && inspectWorkingTreeScope(emptyGitlink.superproject, {
139
+ repository_scope: "harness-apps",
140
+ project_root: "apps/backend/billing-service/"
141
+ }).violation?.includes("不得登记为 harness-apps"),
142
+ "声明 harness-apps 但工作树是 gitlink 应阻断"
143
+ );
144
+ const detachedTarget = path.join(detached.superproject, detached.mount);
145
+ const detachedInspection = inspectWorkingTreeScope(detached.superproject, {
146
+ repository_scope: "git-submodule",
147
+ project_root: "apps/backend/billing-service/",
148
+ checkout_state: "detached-head"
149
+ });
150
+ namedStress(
151
+ "detached_head_as_regular_dir",
152
+ detachedInspection.writable === false
153
+ && inspectCheckoutState(detached.superproject, detachedTarget) === "detached-head"
154
+ && detachedInspection.violation?.includes("regular directory")
155
+ && implementationWriteViolation(detached.superproject, path.join(detachedTarget, "nested-service"))?.includes("普通目录写入")
156
+ && gitSubmoduleScaffoldViolation(detached.superproject, detachedTarget, "nested-service")?.includes("gitlink 不得由脚手架覆盖"),
157
+ "detached HEAD 仍被当成普通目录"
158
+ );
159
+ namedStress(
160
+ "force_overlay_mount",
161
+ gitSubmoduleScaffoldViolation(
162
+ emptyGitlink.superproject,
163
+ path.join(emptyGitlink.superproject, "apps/backend"),
164
+ "billing-service",
165
+ { force: true }
166
+ )?.includes("--force")
167
+ && regularDirectoryMisreadViolation(validGitSubmodule, { force: true })?.includes("--force"),
168
+ "--force 仍可覆盖 gitlink 挂载点"
169
+ );
170
+ const attachedNested = path.join(attached.superproject, attached.mount);
171
+ const attachedInspection = inspectWorkingTreeScope(attached.superproject, {
172
+ ...validGitSubmodule,
173
+ checkout_state: "attached-branch"
174
+ });
175
+ ensure(
176
+ inspectCheckoutState(attached.superproject, attachedNested) === "attached-branch",
177
+ "附加分支 fixture 应处于 attached-branch"
178
+ );
179
+ ensure(attachedInspection.writable === true, "附加分支 git-submodule 工作树应可写");
180
+ ensure(attachedInspection.violation === null, "附加分支工作树对照不应返回 violation");
181
+ ensure(typeof emptyInspection === "object" && emptyInspection !== null && Array.isArray(emptyInspection) === false, "inspectWorkingTreeScope 必须返回对象,不得返回字符串");
182
+ ensure(
183
+ inspectWorkingTreeScope(emptyGitlink.superproject, {
184
+ ...validGitSubmodule,
185
+ checkout_state: "empty-gitlink"
186
+ }).writable === false,
187
+ "已登记为空 gitlink 的 git-submodule 不得返回可写"
188
+ );
189
+ const failedProbe = inspectWorkingTreeScope(process.cwd(), {
190
+ ...validGitSubmodule,
191
+ checkout_state: "empty-gitlink"
192
+ });
193
+ ensure(typeof failedProbe === "object" && failedProbe !== null, "探测失败时仍须返回对象,不得返回字符串");
194
+ ensure(failedProbe.writable === false && isWorkingTreeWritable(failedProbe) === false, "登记为空 gitlink 时即使工作树探测失败也不得返回可写");
195
+ ensure(
196
+ implementationWriteViolation(attached.superproject, path.join(attachedNested, "src")) === null,
197
+ "附加分支工作树内写入不应被当成空 gitlink / detached HEAD"
198
+ );
199
+ ensure(
200
+ gitSubmoduleScaffoldViolation(attached.superproject, attachedNested, "nested-service") === null,
201
+ "附加分支子仓工作树内生成应允许"
202
+ );
203
+ } finally {
204
+ emptyGitlink.cleanup();
205
+ detached.cleanup();
206
+ attached.cleanup();
207
+ }
208
+
209
+ for (const id of NAMED_STRESS_SCENARIOS) {
210
+ if (!namedPassed.includes(id)) failures.push(`named stress ${id}: missing`);
211
+ }
212
+
213
+ const markerFiles = [
214
+ ["docs/process/implementation-repo-integration.md", "repository_scope: git-submodule"],
215
+ ["docs/templates/implementation-repo-registry-template.md", "git-submodule"],
216
+ ["docs/templates/implementation-repo-registry-template.md", "git-submodule-harness-apps"],
217
+ ["docs/templates/cross-repo-slice-template.md", "superproject-gitlink-update"],
218
+ ["docs/templates/implementation-routing-template.md", "git-submodule-harness-apps"],
219
+ [".agents/skills/implementation-repo-onboarding/SKILL.md", "git-submodule"],
220
+ [".agents/skills/yss-router/references/slice-implementation-contract.md", "git-submodule-harness-apps"],
221
+ [".agents/skills/yss-router/references/router-contract.yaml", "git-submodule-harness-apps"],
222
+ [".agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml", "repository_scope=git-submodule"],
223
+ [".agents/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs", "gitSubmoduleScaffoldViolation"],
224
+ [".agents/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs", "refuseGitlinkAsRegularDirectory"]
225
+ ];
226
+ for (const [file, marker] of markerFiles) {
227
+ ensure(existsSync(path.join(root, file)), `缺少场景资产: ${file}`);
228
+ ensure(read(file).includes(marker), `场景资产缺少标记 ${marker}: ${file}`);
229
+ }
230
+
231
+ ensure(REPOSITORY_SCOPES.includes("git-submodule"), "REPOSITORY_SCOPES 必须包含 git-submodule");
232
+
233
+ if (failures.length > 0) {
234
+ process.stderr.write(`${failures.join("\n")}\n`);
235
+ process.exitCode = 1;
236
+ } else {
237
+ process.stdout.write(`${namedPassed.map((id) => `named stress ${id}: PASS`).join("\n")}\n`);
238
+ process.stdout.write("实现仓库 repository_scope 压力场景验证通过\n");
239
+ }
@@ -430,6 +430,60 @@ def main() -> int:
430
430
  "批准覆盖的备份必须保留原目录内容",
431
431
  )
432
432
 
433
+ gitlink_root = temp_root / "gitlink-superproject"
434
+ gitlink_backend = gitlink_root / "apps" / "backend"
435
+ gitlink_project = gitlink_backend / "gitlink-service"
436
+ gitlink_project.mkdir(parents=True)
437
+ (gitlink_root / ".gitmodules").write_text(
438
+ '[submodule "backend-gitlink-service"]\n'
439
+ "\tpath = apps/backend/gitlink-service\n"
440
+ "\turl = https://example.invalid/gitlink-service.git\n",
441
+ encoding="utf-8",
442
+ )
443
+ gitlink_contract = temp_root / "gitlink-contract.json"
444
+ write_contract(
445
+ gitlink_contract,
446
+ gitlink_backend,
447
+ "gitlink-service",
448
+ "backend-scaffold-gitlink",
449
+ "lifecycle/approval-gitlink",
450
+ "router/draft-gitlink",
451
+ "lifecycle/contracts/backend-scaffold-gitlink.yaml",
452
+ force_allowed=True,
453
+ )
454
+ gitlink_result = run_generator(
455
+ "--project-name",
456
+ "gitlink-service",
457
+ "--base-package",
458
+ "com.yss.gitlink",
459
+ "--output-dir",
460
+ str(gitlink_backend),
461
+ "--force",
462
+ "--contract-id",
463
+ "backend-scaffold-gitlink",
464
+ "--contract-version",
465
+ "1",
466
+ "--approval-ref",
467
+ "lifecycle/approval-gitlink",
468
+ "--router-draft-ref",
469
+ "router/draft-gitlink",
470
+ "--persisted-ref",
471
+ "lifecycle/contracts/backend-scaffold-gitlink.yaml",
472
+ "--contract-file",
473
+ str(gitlink_contract),
474
+ "--overwrite-scope",
475
+ "gitlink-service/**",
476
+ "--rollback-ref",
477
+ "git:checkpoint-gitlink",
478
+ )
479
+ require(
480
+ gitlink_result.returncode != 0
481
+ and "gitlink 不得由脚手架覆盖" in (gitlink_result.stdout + gitlink_result.stderr)
482
+ and "请显式传入 --force" not in (gitlink_result.stdout + gitlink_result.stderr),
483
+ "空 gitlink 挂载点不得被脚手架覆盖",
484
+ )
485
+ require(not (gitlink_project / "pom.xml").exists(), "拒绝 gitlink 覆盖时不得留下骨架")
486
+
433
487
  print("YSS 脚手架生成器受控生成场景验证通过")
434
488
  return 0
435
489
 
@@ -5,7 +5,7 @@ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
5
  cd "$ROOT_DIR"
6
6
  node -e 'const [major]=process.versions.node.split(".").map(Number); if (major < 22 || major >= 27) { console.error("模板工具需要 Node >=22 <27"); process.exit(1); }'
7
7
 
8
- required_files=(yss-project.yaml AGENTS.md CONTEXT.md skills-lock.json docs/agents/yss-skill-registry.yaml docs/process/lifecycle-registry.yaml docs/process/lifecycle-registry-baseline.json docs/process/maintenance-intensity.yaml docs/process/schemas/lifecycle-checkpoint.schema.json docs/process/schemas/frontend-implementation-evidence.schema.json docs/process/templates/lifecycle-checkpoint-template.yaml docs/process/templates/frontend-implementation-plan-template.yaml docs/process/templates/frontend-implementation-verification-template.yaml scripts/repository-mode scripts/implementation-path-policy scripts/sync-skills scripts/update-skill-lock scripts/generate-lifecycle-artifacts scripts/verify-lifecycle-registry scripts/verify-lifecycle-checkpoint scripts/verify-frontend-implementation-evidence scripts/verify-maintenance-checkpoint scripts/verify-maintenance-intensity-scenarios scripts/verify-skill-registry scripts/verify-yss-dto-openapi-profile scripts/verify-yss-dto-openapi-scenarios scripts/export-yss-skills)
8
+ required_files=(yss-project.yaml AGENTS.md CONTEXT.md skills-lock.json docs/agents/yss-skill-registry.yaml docs/process/lifecycle-registry.yaml docs/process/lifecycle-registry-baseline.json docs/process/maintenance-intensity.yaml docs/process/schemas/lifecycle-checkpoint.schema.json docs/process/schemas/frontend-implementation-evidence.schema.json docs/process/templates/lifecycle-checkpoint-template.yaml docs/process/templates/frontend-implementation-plan-template.yaml docs/process/templates/frontend-implementation-verification-template.yaml scripts/repository-mode scripts/implementation-path-policy scripts/repository-scope-policy scripts/sync-skills scripts/update-skill-lock scripts/generate-lifecycle-artifacts scripts/verify-lifecycle-registry scripts/verify-lifecycle-checkpoint scripts/verify-frontend-implementation-evidence scripts/verify-maintenance-checkpoint scripts/verify-maintenance-intensity-scenarios scripts/verify-skill-registry scripts/verify-yss-dto-openapi-profile scripts/verify-yss-dto-openapi-scenarios scripts/export-yss-skills)
9
9
  for required in "${required_files[@]}"; do test -f "$required" || { echo "缺少模板必需文件: $required" >&2; exit 1; }; done
10
10
 
11
11
  repository_mode="$(scripts/repository-mode)"
@@ -29,6 +29,7 @@ scripts/verify-lifecycle-scenarios
29
29
  scripts/verify-maintenance-intensity-scenarios
30
30
  scripts/verify-governance-release
31
31
  scripts/verify-implementation-path-scenarios
32
+ scripts/verify-repository-scope-scenarios
32
33
  scripts/verify-scaffold-generator-scenarios
33
34
  scripts/verify-prototype-backend-scaffold-scenarios
34
35
  scripts/verify-matt-yss-integration-scenarios
@@ -37,7 +38,7 @@ scripts/verify-yss-ui-scenarios
37
38
  scripts/verify-openapi-yaml-first-scenarios
38
39
  scripts/verify-openapi-json-handoff-scenarios
39
40
 
40
- for entry in scripts/sync-skills scripts/update-skill-lock scripts/generate-lifecycle-artifacts scripts/verify-lifecycle-registry scripts/verify-lifecycle-checkpoint scripts/verify-frontend-implementation-evidence scripts/verify-maintenance-checkpoint scripts/verify-maintenance-intensity-scenarios scripts/verify-skill-registry scripts/verify-yss-dto-openapi-profile scripts/verify-yss-dto-openapi-scenarios scripts/verify-lifecycle-scenarios scripts/verify-matt-yss-integration-scenarios scripts/verify-prototype-backend-scaffold-scenarios scripts/verify-yss-router-scenarios scripts/verify-openapi-yaml-first-scenarios scripts/verify-openapi-json-handoff-scenarios scripts/export-yss-skills; do node --check "$entry"; done
41
+ for entry in scripts/sync-skills scripts/update-skill-lock scripts/generate-lifecycle-artifacts scripts/verify-lifecycle-registry scripts/verify-lifecycle-checkpoint scripts/verify-frontend-implementation-evidence scripts/verify-maintenance-checkpoint scripts/verify-maintenance-intensity-scenarios scripts/verify-skill-registry scripts/verify-yss-dto-openapi-profile scripts/verify-yss-dto-openapi-scenarios scripts/verify-lifecycle-scenarios scripts/verify-matt-yss-integration-scenarios scripts/verify-prototype-backend-scaffold-scenarios scripts/verify-yss-router-scenarios scripts/verify-openapi-yaml-first-scenarios scripts/verify-openapi-json-handoff-scenarios scripts/verify-repository-scope-scenarios scripts/export-yss-skills; do node --check "$entry"; done
41
42
 
42
43
  legacy_runtime="ru""by"
43
44
  script_roots=(scripts)
@@ -111,7 +111,7 @@
111
111
  "source": "project",
112
112
  "sourceType": "local",
113
113
  "skillPath": ".agents/skills/cross-repo-implementation-routing/SKILL.md",
114
- "effectiveHash": "3207a3f6b51ba07835b56f7c0b2c5e55ca7fdd30a038b0b6ba8ec00228506a4b",
114
+ "effectiveHash": "d987e88e4c9fa4cd48081ba41359faa7d58b2e194f1fcd98c17677a9a6292629",
115
115
  "targets": [
116
116
  ".agents/skills",
117
117
  ".claude/skills",
@@ -292,7 +292,7 @@
292
292
  "source": "project",
293
293
  "sourceType": "local",
294
294
  "skillPath": ".agents/skills/implementation-repo-onboarding/SKILL.md",
295
- "effectiveHash": "e3166bbc93388996d0593803a1d6fb675c0cf596783b3171c035b78293b0c3cd",
295
+ "effectiveHash": "2083358c6ed57dbae7b94c2e52f91f9e9103168ad14f4b296ac084d8d9ac4ff3",
296
296
  "targets": [
297
297
  ".agents/skills",
298
298
  ".claude/skills",
@@ -327,7 +327,7 @@
327
327
  "source": "project",
328
328
  "sourceType": "local",
329
329
  "skillPath": ".agents/skills/llm-wiki/SKILL.md",
330
- "effectiveHash": "41a5880856745312d33a2875ce16fe321e5f326eb8e27321f96741421ffce49a",
330
+ "effectiveHash": "39fbba419001c5701dc11b6c535f47916da1471cb808412e09f6ddb0485eb3e9",
331
331
  "targets": [
332
332
  ".agents/skills",
333
333
  ".claude/skills",
@@ -918,7 +918,7 @@
918
918
  "source": "project",
919
919
  "sourceType": "local",
920
920
  "skillPath": ".agents/skills/yss-ddd-scaffold-generator/SKILL.md",
921
- "effectiveHash": "4a85b5babcf6b83f370ba6a2960dd307f19bcad9a59b04aa43eb7c398f8121fe",
921
+ "effectiveHash": "89ec809eb32afacb107c6d89b343ce50e852f385f5ab6bf7c626e830752154ee",
922
922
  "targets": [
923
923
  ".agents/skills",
924
924
  ".claude/skills",
@@ -1062,7 +1062,7 @@
1062
1062
  "source": "project",
1063
1063
  "sourceType": "local",
1064
1064
  "skillPath": ".agents/skills/yss-frontend-scaffold-generator/SKILL.md",
1065
- "effectiveHash": "6b966c5824b80f5196c7fd8225238b3047d9e49f1f94c60179e4a567d82911f5",
1065
+ "effectiveHash": "20f9f45435d2f31a6f5880bc1f653941a11f9fed7a22323b758951680901ed76",
1066
1066
  "targets": [
1067
1067
  ".agents/skills",
1068
1068
  ".claude/skills",
@@ -1174,7 +1174,7 @@
1174
1174
  "source": "project",
1175
1175
  "sourceType": "local",
1176
1176
  "skillPath": ".agents/skills/yss-product-lifecycle/SKILL.md",
1177
- "effectiveHash": "eaa20ca65548a0c0c4fd30f56eb8d15ec872179ea39ffd93dd64730b3dcf5301",
1177
+ "effectiveHash": "823df5e6cfa071f35073bfa5d72cb4dbd5749b2b4219ac1f5e78f8e6fde6a259",
1178
1178
  "targets": [
1179
1179
  ".agents/skills",
1180
1180
  ".claude/skills",
@@ -1238,7 +1238,7 @@
1238
1238
  "source": "project",
1239
1239
  "sourceType": "local",
1240
1240
  "skillPath": ".agents/skills/yss-router/SKILL.md",
1241
- "effectiveHash": "70ec63b0513393b116895ae658fec52a0ec00fbd692c28f87a3a5c7d1369d47e",
1241
+ "effectiveHash": "2482adf62b402e43555df7188b75e5999ce29589f26132cdb920ee2977c5bb1a",
1242
1242
  "targets": [
1243
1243
  ".agents/skills",
1244
1244
  ".claude/skills",
@@ -9,13 +9,15 @@
9
9
  ".ua",
10
10
  ".qwen",
11
11
  ".template-source",
12
- "packages"
12
+ "packages",
13
+ ".github"
13
14
  ],
14
15
  "excludeRootFiles": [
15
16
  "package-lock.json",
16
17
  "package.json",
17
18
  "template.manifest.json",
18
- "template.snapshot.json"
19
+ "template.snapshot.json",
20
+ ".gitmodules"
19
21
  ],
20
22
  "excludePaths": [
21
23
  ".claude/settings.local.json",
@@ -23,6 +25,7 @@
23
25
  ".codex/settings.local.json",
24
26
  ".codex/skills/.DS_Store",
25
27
  ".pi/settings.json",
28
+ ".cursor/environment.json",
26
29
  "docs/.scratch",
27
30
  "docs/reviews"
28
31
  ],
@@ -43,7 +46,5 @@
43
46
  ".nvmrc",
44
47
  "yss-public-skills.json"
45
48
  ],
46
- "initExcludePaths": [
47
- ".github"
48
- ]
49
+ "initExcludePaths": []
49
50
  }
@@ -3,14 +3,14 @@
3
3
  "templateName": "yss-spec-project-template",
4
4
  "templateSource": "github:iloveZzz/yss-spec-project-template",
5
5
  "templateRepository": "https://github.com/iloveZzz/yss-spec-project-template.git",
6
- "requestedRef": "986ded5d78e2d0bd816f7f8038aec6ef2d7c6d0a",
7
- "templateCommit": "986ded5d78e2d0bd816f7f8038aec6ef2d7c6d0a",
6
+ "requestedRef": "04a6151612289f3cd0ddce2c1411eb3aa2444ba7",
7
+ "templateCommit": "04a6151612289f3cd0ddce2c1411eb3aa2444ba7",
8
8
  "encodedPaths": {
9
9
  ".codex/skills/data-analytics/.gitignore": ".codex/skills/data-analytics/__yss_dotfile__.gitignore",
10
10
  ".codex/skills/product-design/.npmignore": ".codex/skills/product-design/__yss_dotfile__.npmignore",
11
11
  ".codex/skills/product-design/templates/prototype/.npmrc": ".codex/skills/product-design/templates/prototype/__yss_dotfile__.npmrc",
12
12
  ".gitignore": "__yss_dotfile__.gitignore"
13
13
  },
14
- "snapshotHash": "e15b05f44ef09f9953338c6846345c1197d615f7d31370deb0b3c5cdc3195376",
15
- "generatedAt": "2026-08-24T03:44:43.752Z"
14
+ "snapshotHash": "b6c605421b673d2b86c6cae0bed7a8d86aec1a386cea1c8397e97414b68fe51c",
15
+ "generatedAt": "2026-08-24T13:46:31.002Z"
16
16
  }
@@ -1,5 +0,0 @@
1
- {
2
- "name": "YSS Spec Project Template",
3
- "install": "pip3 install jsonschema\npnpm --dir .template-source/tooling/node install --frozen-lockfile",
4
- "start": "pnpm dev"
5
- }
@@ -1,61 +0,0 @@
1
- name: Template Node tooling
2
-
3
- on:
4
- pull_request:
5
- push:
6
- branches: [main]
7
-
8
- jobs:
9
- linux:
10
- name: linux-node-${{ matrix.node }}
11
- runs-on: ubuntu-latest
12
- strategy:
13
- fail-fast: false
14
- matrix:
15
- node: [22, 24]
16
- steps:
17
- - uses: actions/checkout@v4
18
- with:
19
- fetch-depth: 0
20
- - uses: pnpm/action-setup@v4
21
- with:
22
- version: 10.15.0
23
- - uses: actions/setup-node@v4
24
- with:
25
- node-version: ${{ matrix.node }}
26
- - run: pnpm --dir .template-source/tooling/node install --frozen-lockfile
27
- - run: pnpm --dir .template-source/tooling/node build:vendor
28
- - run: pnpm --dir .template-source/tooling/node test
29
- - run: pnpm --dir .template-source/tooling/node check:vendor
30
- - run: git diff --exit-code -- scripts/vendor
31
- - run: scripts/verify-template
32
-
33
- macos-vendor:
34
- runs-on: macos-latest
35
- steps:
36
- - uses: actions/checkout@v4
37
- - uses: pnpm/action-setup@v4
38
- with:
39
- version: 10.15.0
40
- - uses: actions/setup-node@v4
41
- with:
42
- node-version: 24
43
- - run: pnpm --dir .template-source/tooling/node install --frozen-lockfile
44
- - run: pnpm --dir .template-source/tooling/node build:vendor
45
- - run: pnpm --dir .template-source/tooling/node check:vendor
46
- - run: git diff --exit-code -- scripts/vendor
47
-
48
- node-26-observational:
49
- continue-on-error: true
50
- runs-on: ubuntu-latest
51
- steps:
52
- - uses: actions/checkout@v4
53
- - uses: pnpm/action-setup@v4
54
- with:
55
- version: 10.15.0
56
- - uses: actions/setup-node@v4
57
- with:
58
- node-version: 26
59
- - run: pnpm --dir .template-source/tooling/node install --frozen-lockfile
60
- - run: pnpm --dir .template-source/tooling/node test
61
- - run: pnpm --dir .template-source/tooling/node check:vendor