create-yss-spec 3.1.0 → 3.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 (302) hide show
  1. package/README.md +119 -89
  2. package/bin/create-yss-spec.js +11 -3
  3. package/package.json +9 -2
  4. package/src/api/_sync-service.js +191 -0
  5. package/src/api/index.js +22 -0
  6. package/src/api/project-diff.js +9 -0
  7. package/src/api/project-doctor.js +10 -0
  8. package/src/api/template-apply.js +10 -0
  9. package/src/api/template-plan.js +9 -0
  10. package/src/cli/args.js +60 -0
  11. package/src/cli/error-output.js +52 -0
  12. package/src/cli/flags.js +9 -0
  13. package/src/cli/help.js +95 -0
  14. package/src/cli/index.js +82 -0
  15. package/src/cli/plan-output.js +61 -0
  16. package/src/cli/prompts.js +91 -0
  17. package/src/cli/router.js +41 -0
  18. package/src/cli.js +5 -2253
  19. package/src/commands/attach.js +280 -0
  20. package/src/commands/diff.js +23 -0
  21. package/src/commands/doctor.js +417 -0
  22. package/src/commands/init.js +193 -0
  23. package/src/commands/sync.js +146 -0
  24. package/src/commands/update.js +14 -0
  25. package/src/contracts/apply-result-v1.json +45 -0
  26. package/src/contracts/customization-policy-v1.json +28 -0
  27. package/src/contracts/doctor-report-v1.json +29 -0
  28. package/src/contracts/error-envelope-v1.json +24 -0
  29. package/src/contracts/generator-policy-v1.json +24 -0
  30. package/src/contracts/ownership-policy-v1.json +40 -0
  31. package/src/contracts/plan-schema-v1.json +115 -0
  32. package/src/family-identity.js +365 -0
  33. package/src/family-runtime.js +23 -0
  34. package/src/filesystem/apply-plan.js +44 -0
  35. package/src/filesystem/copy-path.js +28 -0
  36. package/src/filesystem/path-utils.js +67 -0
  37. package/src/filesystem/transaction-runner.js +41 -0
  38. package/src/filesystem/transaction.js +153 -0
  39. package/src/git/submodule.js +115 -0
  40. package/src/git/worktree.js +69 -0
  41. package/src/template/attach-planner-runtime.js +51 -0
  42. package/src/template/attach-planner.js +160 -0
  43. package/src/template/instance-runtime.js +463 -0
  44. package/src/template/lifecycle-metadata.js +99 -0
  45. package/src/template/lifecycle-policy.js +129 -0
  46. package/src/template/lifecycle-runtime.js +90 -0
  47. package/src/template/migration-planner.js +95 -0
  48. package/src/template/migration-runtime.js +247 -0
  49. package/src/template/ownership-metadata.js +79 -0
  50. package/src/template/ownership-policy.js +149 -0
  51. package/src/template/ownership-runtime.js +109 -0
  52. package/src/template/plan-schema.js +36 -0
  53. package/src/template/sync-planner-runtime.js +57 -0
  54. package/src/template/sync-planner.js +206 -0
  55. package/src/template/verification-runtime.js +154 -0
  56. package/src/validation/identity.js +41 -0
  57. package/src/validation/metadata.js +105 -0
  58. package/src/validation/security.js +67 -0
  59. package/src/validation/snapshot.js +47 -0
  60. package/template/.agents/skills/.strategic-design-skills-manifest.json +1 -1
  61. package/template/.agents/skills/yss-domain/SKILL.md +3 -3
  62. package/template/.agents/skills/yss-frontend-scaffold-generator/SKILL.md +2 -0
  63. package/template/.agents/skills/yss-implementation-contract-compiler/SKILL.md +4 -2
  64. package/template/.agents/skills/yss-implementation-contract-compiler/references/boundaries.md +5 -0
  65. package/template/.agents/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -2
  66. package/template/.agents/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +10 -1
  67. package/template/.agents/skills/yss-mvc-design/SKILL.md +16 -0
  68. package/template/.agents/skills/yss-mvc-design/agents/openai.yaml +4 -0
  69. package/template/.agents/skills/yss-mvc-design/references/mvc-design.schema.json +315 -0
  70. package/template/.agents/skills/yss-product-lifecycle/SKILL.md +4 -2
  71. package/template/.agents/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  72. package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +14 -9
  73. package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +1 -1
  74. package/template/.agents/skills/yss-product-lifecycle/references/state-model.md +1 -1
  75. package/template/.agents/skills/yss-tactical-design/SKILL.md +2 -2
  76. package/template/.agents/skills/yss-tactical-design/references/output-template.md +2 -0
  77. package/template/.agents/skills/yss-tactical-design/references/tactical-design-contract.md +3 -1
  78. package/template/.agents/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +3 -2
  79. package/template/.agents/skills/yss-technical-design/SKILL.md +31 -0
  80. package/template/.agents/skills/yss-technical-design/agents/openai.yaml +4 -0
  81. package/template/.agents/skills/yss-technical-design/references/technical-design-common.schema.json +290 -0
  82. package/template/.agents/skills/yss-technical-design/references/technical-design-contract.md +31 -0
  83. package/template/.agents/skills/yss-technical-design/references/technical-design.schema.json +759 -0
  84. package/template/.agents/skills/yss-technical-design/scripts/generate-schema.mjs +20 -0
  85. package/template/.agents/skills/yss-technical-design/scripts/validate-technical-design.mjs +134 -0
  86. package/template/.agents/skills/yss-technical-design/tests/fixtures.mjs +32 -0
  87. package/template/.agents/skills/yss-technical-design/tests/run-scenarios.mjs +82 -0
  88. package/template/.agents/skills/yss-ui/SKILL.md +2 -0
  89. package/template/.claude/skills/yss-domain/SKILL.md +3 -3
  90. package/template/.claude/skills/yss-frontend-scaffold-generator/SKILL.md +2 -0
  91. package/template/.claude/skills/yss-implementation-contract-compiler/SKILL.md +4 -2
  92. package/template/.claude/skills/yss-implementation-contract-compiler/references/boundaries.md +5 -0
  93. package/template/.claude/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -2
  94. package/template/.claude/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +10 -1
  95. package/template/.claude/skills/yss-mvc-design/SKILL.md +16 -0
  96. package/template/.claude/skills/yss-mvc-design/agents/openai.yaml +4 -0
  97. package/template/.claude/skills/yss-mvc-design/references/mvc-design.schema.json +315 -0
  98. package/template/.claude/skills/yss-product-lifecycle/SKILL.md +4 -2
  99. package/template/.claude/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  100. package/template/.claude/skills/yss-product-lifecycle/references/orchestration-contract.yaml +14 -9
  101. package/template/.claude/skills/yss-product-lifecycle/references/orchestration.md +1 -1
  102. package/template/.claude/skills/yss-product-lifecycle/references/state-model.md +1 -1
  103. package/template/.claude/skills/yss-tactical-design/SKILL.md +2 -2
  104. package/template/.claude/skills/yss-tactical-design/references/output-template.md +2 -0
  105. package/template/.claude/skills/yss-tactical-design/references/tactical-design-contract.md +3 -1
  106. package/template/.claude/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +3 -2
  107. package/template/.claude/skills/yss-technical-design/SKILL.md +31 -0
  108. package/template/.claude/skills/yss-technical-design/agents/openai.yaml +4 -0
  109. package/template/.claude/skills/yss-technical-design/references/technical-design-common.schema.json +290 -0
  110. package/template/.claude/skills/yss-technical-design/references/technical-design-contract.md +31 -0
  111. package/template/.claude/skills/yss-technical-design/references/technical-design.schema.json +759 -0
  112. package/template/.claude/skills/yss-technical-design/scripts/generate-schema.mjs +20 -0
  113. package/template/.claude/skills/yss-technical-design/scripts/validate-technical-design.mjs +134 -0
  114. package/template/.claude/skills/yss-technical-design/tests/fixtures.mjs +32 -0
  115. package/template/.claude/skills/yss-technical-design/tests/run-scenarios.mjs +82 -0
  116. package/template/.claude/skills/yss-ui/SKILL.md +2 -0
  117. package/template/.codex/skills/yss-domain/SKILL.md +3 -3
  118. package/template/.codex/skills/yss-frontend-scaffold-generator/SKILL.md +2 -0
  119. package/template/.codex/skills/yss-implementation-contract-compiler/SKILL.md +4 -2
  120. package/template/.codex/skills/yss-implementation-contract-compiler/references/boundaries.md +5 -0
  121. package/template/.codex/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -2
  122. package/template/.codex/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +10 -1
  123. package/template/.codex/skills/yss-mvc-design/SKILL.md +16 -0
  124. package/template/.codex/skills/yss-mvc-design/agents/openai.yaml +4 -0
  125. package/template/.codex/skills/yss-mvc-design/references/mvc-design.schema.json +315 -0
  126. package/template/.codex/skills/yss-product-lifecycle/SKILL.md +4 -2
  127. package/template/.codex/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  128. package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +14 -9
  129. package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +1 -1
  130. package/template/.codex/skills/yss-product-lifecycle/references/state-model.md +1 -1
  131. package/template/.codex/skills/yss-tactical-design/SKILL.md +2 -2
  132. package/template/.codex/skills/yss-tactical-design/references/output-template.md +2 -0
  133. package/template/.codex/skills/yss-tactical-design/references/tactical-design-contract.md +3 -1
  134. package/template/.codex/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +3 -2
  135. package/template/.codex/skills/yss-technical-design/SKILL.md +31 -0
  136. package/template/.codex/skills/yss-technical-design/agents/openai.yaml +4 -0
  137. package/template/.codex/skills/yss-technical-design/references/technical-design-common.schema.json +290 -0
  138. package/template/.codex/skills/yss-technical-design/references/technical-design-contract.md +31 -0
  139. package/template/.codex/skills/yss-technical-design/references/technical-design.schema.json +759 -0
  140. package/template/.codex/skills/yss-technical-design/scripts/generate-schema.mjs +20 -0
  141. package/template/.codex/skills/yss-technical-design/scripts/validate-technical-design.mjs +134 -0
  142. package/template/.codex/skills/yss-technical-design/tests/fixtures.mjs +32 -0
  143. package/template/.codex/skills/yss-technical-design/tests/run-scenarios.mjs +82 -0
  144. package/template/.codex/skills/yss-ui/SKILL.md +2 -0
  145. package/template/.cursor/skills/yss-domain/SKILL.md +3 -3
  146. package/template/.cursor/skills/yss-frontend-scaffold-generator/SKILL.md +2 -0
  147. package/template/.cursor/skills/yss-implementation-contract-compiler/SKILL.md +4 -2
  148. package/template/.cursor/skills/yss-implementation-contract-compiler/references/boundaries.md +5 -0
  149. package/template/.cursor/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -2
  150. package/template/.cursor/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +10 -1
  151. package/template/.cursor/skills/yss-mvc-design/SKILL.md +16 -0
  152. package/template/.cursor/skills/yss-mvc-design/agents/openai.yaml +4 -0
  153. package/template/.cursor/skills/yss-mvc-design/references/mvc-design.schema.json +315 -0
  154. package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +4 -2
  155. package/template/.cursor/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  156. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +14 -9
  157. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +1 -1
  158. package/template/.cursor/skills/yss-product-lifecycle/references/state-model.md +1 -1
  159. package/template/.cursor/skills/yss-tactical-design/SKILL.md +2 -2
  160. package/template/.cursor/skills/yss-tactical-design/references/output-template.md +2 -0
  161. package/template/.cursor/skills/yss-tactical-design/references/tactical-design-contract.md +3 -1
  162. package/template/.cursor/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +3 -2
  163. package/template/.cursor/skills/yss-technical-design/SKILL.md +31 -0
  164. package/template/.cursor/skills/yss-technical-design/agents/openai.yaml +4 -0
  165. package/template/.cursor/skills/yss-technical-design/references/technical-design-common.schema.json +290 -0
  166. package/template/.cursor/skills/yss-technical-design/references/technical-design-contract.md +31 -0
  167. package/template/.cursor/skills/yss-technical-design/references/technical-design.schema.json +759 -0
  168. package/template/.cursor/skills/yss-technical-design/scripts/generate-schema.mjs +20 -0
  169. package/template/.cursor/skills/yss-technical-design/scripts/validate-technical-design.mjs +134 -0
  170. package/template/.cursor/skills/yss-technical-design/tests/fixtures.mjs +32 -0
  171. package/template/.cursor/skills/yss-technical-design/tests/run-scenarios.mjs +82 -0
  172. package/template/.cursor/skills/yss-ui/SKILL.md +2 -0
  173. package/template/.pi/skills/yss-domain/SKILL.md +3 -3
  174. package/template/.pi/skills/yss-frontend-scaffold-generator/SKILL.md +2 -0
  175. package/template/.pi/skills/yss-implementation-contract-compiler/SKILL.md +4 -2
  176. package/template/.pi/skills/yss-implementation-contract-compiler/references/boundaries.md +5 -0
  177. package/template/.pi/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -2
  178. package/template/.pi/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +10 -1
  179. package/template/.pi/skills/yss-mvc-design/SKILL.md +16 -0
  180. package/template/.pi/skills/yss-mvc-design/agents/openai.yaml +4 -0
  181. package/template/.pi/skills/yss-mvc-design/references/mvc-design.schema.json +315 -0
  182. package/template/.pi/skills/yss-product-lifecycle/SKILL.md +4 -2
  183. package/template/.pi/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  184. package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +14 -9
  185. package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +1 -1
  186. package/template/.pi/skills/yss-product-lifecycle/references/state-model.md +1 -1
  187. package/template/.pi/skills/yss-tactical-design/SKILL.md +2 -2
  188. package/template/.pi/skills/yss-tactical-design/references/output-template.md +2 -0
  189. package/template/.pi/skills/yss-tactical-design/references/tactical-design-contract.md +3 -1
  190. package/template/.pi/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +3 -2
  191. package/template/.pi/skills/yss-technical-design/SKILL.md +31 -0
  192. package/template/.pi/skills/yss-technical-design/agents/openai.yaml +4 -0
  193. package/template/.pi/skills/yss-technical-design/references/technical-design-common.schema.json +290 -0
  194. package/template/.pi/skills/yss-technical-design/references/technical-design-contract.md +31 -0
  195. package/template/.pi/skills/yss-technical-design/references/technical-design.schema.json +759 -0
  196. package/template/.pi/skills/yss-technical-design/scripts/generate-schema.mjs +20 -0
  197. package/template/.pi/skills/yss-technical-design/scripts/validate-technical-design.mjs +134 -0
  198. package/template/.pi/skills/yss-technical-design/tests/fixtures.mjs +32 -0
  199. package/template/.pi/skills/yss-technical-design/tests/run-scenarios.mjs +82 -0
  200. package/template/.pi/skills/yss-ui/SKILL.md +2 -0
  201. package/template/.qoder/skills/yss-domain/SKILL.md +3 -3
  202. package/template/.qoder/skills/yss-frontend-scaffold-generator/SKILL.md +2 -0
  203. package/template/.qoder/skills/yss-implementation-contract-compiler/SKILL.md +4 -2
  204. package/template/.qoder/skills/yss-implementation-contract-compiler/references/boundaries.md +5 -0
  205. package/template/.qoder/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -2
  206. package/template/.qoder/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +10 -1
  207. package/template/.qoder/skills/yss-mvc-design/SKILL.md +16 -0
  208. package/template/.qoder/skills/yss-mvc-design/agents/openai.yaml +4 -0
  209. package/template/.qoder/skills/yss-mvc-design/references/mvc-design.schema.json +315 -0
  210. package/template/.qoder/skills/yss-product-lifecycle/SKILL.md +4 -2
  211. package/template/.qoder/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  212. package/template/.qoder/skills/yss-product-lifecycle/references/orchestration-contract.yaml +14 -9
  213. package/template/.qoder/skills/yss-product-lifecycle/references/orchestration.md +1 -1
  214. package/template/.qoder/skills/yss-product-lifecycle/references/state-model.md +1 -1
  215. package/template/.qoder/skills/yss-tactical-design/SKILL.md +2 -2
  216. package/template/.qoder/skills/yss-tactical-design/references/output-template.md +2 -0
  217. package/template/.qoder/skills/yss-tactical-design/references/tactical-design-contract.md +3 -1
  218. package/template/.qoder/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +3 -2
  219. package/template/.qoder/skills/yss-technical-design/SKILL.md +31 -0
  220. package/template/.qoder/skills/yss-technical-design/agents/openai.yaml +4 -0
  221. package/template/.qoder/skills/yss-technical-design/references/technical-design-common.schema.json +290 -0
  222. package/template/.qoder/skills/yss-technical-design/references/technical-design-contract.md +31 -0
  223. package/template/.qoder/skills/yss-technical-design/references/technical-design.schema.json +759 -0
  224. package/template/.qoder/skills/yss-technical-design/scripts/generate-schema.mjs +20 -0
  225. package/template/.qoder/skills/yss-technical-design/scripts/validate-technical-design.mjs +134 -0
  226. package/template/.qoder/skills/yss-technical-design/tests/fixtures.mjs +32 -0
  227. package/template/.qoder/skills/yss-technical-design/tests/run-scenarios.mjs +82 -0
  228. package/template/.qoder/skills/yss-ui/SKILL.md +2 -0
  229. package/template/.trae/skills/yss-domain/SKILL.md +3 -3
  230. package/template/.trae/skills/yss-frontend-scaffold-generator/SKILL.md +2 -0
  231. package/template/.trae/skills/yss-implementation-contract-compiler/SKILL.md +4 -2
  232. package/template/.trae/skills/yss-implementation-contract-compiler/references/boundaries.md +5 -0
  233. package/template/.trae/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -2
  234. package/template/.trae/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +10 -1
  235. package/template/.trae/skills/yss-mvc-design/SKILL.md +16 -0
  236. package/template/.trae/skills/yss-mvc-design/agents/openai.yaml +4 -0
  237. package/template/.trae/skills/yss-mvc-design/references/mvc-design.schema.json +315 -0
  238. package/template/.trae/skills/yss-product-lifecycle/SKILL.md +4 -2
  239. package/template/.trae/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
  240. package/template/.trae/skills/yss-product-lifecycle/references/orchestration-contract.yaml +14 -9
  241. package/template/.trae/skills/yss-product-lifecycle/references/orchestration.md +1 -1
  242. package/template/.trae/skills/yss-product-lifecycle/references/state-model.md +1 -1
  243. package/template/.trae/skills/yss-tactical-design/SKILL.md +2 -2
  244. package/template/.trae/skills/yss-tactical-design/references/output-template.md +2 -0
  245. package/template/.trae/skills/yss-tactical-design/references/tactical-design-contract.md +3 -1
  246. package/template/.trae/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +3 -2
  247. package/template/.trae/skills/yss-technical-design/SKILL.md +31 -0
  248. package/template/.trae/skills/yss-technical-design/agents/openai.yaml +4 -0
  249. package/template/.trae/skills/yss-technical-design/references/technical-design-common.schema.json +290 -0
  250. package/template/.trae/skills/yss-technical-design/references/technical-design-contract.md +31 -0
  251. package/template/.trae/skills/yss-technical-design/references/technical-design.schema.json +759 -0
  252. package/template/.trae/skills/yss-technical-design/scripts/generate-schema.mjs +20 -0
  253. package/template/.trae/skills/yss-technical-design/scripts/validate-technical-design.mjs +134 -0
  254. package/template/.trae/skills/yss-technical-design/tests/fixtures.mjs +32 -0
  255. package/template/.trae/skills/yss-technical-design/tests/run-scenarios.mjs +82 -0
  256. package/template/.trae/skills/yss-ui/SKILL.md +2 -0
  257. package/template/CONTEXT.md +4 -1
  258. package/template/README.md +4 -0
  259. package/template/docs/agents/digital-human-roles.yaml +3 -2
  260. package/template/docs/agents/yss-skill-registry.yaml +20 -1
  261. package/template/docs/architecture/templates/architecture-review-checklist.md +1 -1
  262. package/template/docs/architecture/templates/system-overview-design-template.md +15 -4
  263. package/template/docs/process/frontend-backend-delivery.md +72 -0
  264. package/template/docs/process/implementation-repo-integration.md +2 -0
  265. package/template/docs/process/lifecycle-artifact-map.md +3 -0
  266. package/template/docs/process/lifecycle-registry-baseline.json +4 -1
  267. package/template/docs/process/lifecycle-registry.yaml +14 -2
  268. package/template/docs/process/schemas/backend-delivery-verification.schema.json +113 -0
  269. package/template/docs/process/schemas/backend-delivery.schema.json +301 -0
  270. package/template/docs/process/schemas/digital-human-task-package.schema.json +8 -0
  271. package/template/docs/process/schemas/frontend-delivery-acceptance.schema.json +200 -0
  272. package/template/docs/process/schemas/frontend-implementation-evidence.schema.json +3 -0
  273. package/template/docs/process/schemas/strategic-design-handoff.schema.json +77 -4
  274. package/template/docs/process/strategic-handoff-package.md +4 -2
  275. package/template/docs/process/template-verification-profiles.yaml +20 -0
  276. package/template/docs/user-guide//346/210/230/346/234/257/350/256/276/350/256/241/345/255/220/351/241/271/347/233/256/347/224/250/346/210/267/346/211/213/345/206/214.md +21 -206
  277. package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214.md +63 -963
  278. package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214/347/264/242/345/274/225.md +11 -14
  279. package/template/docs/user-guide//350/256/276/345/244/207/345/200/237/347/224/250/350/264/257/347/251/277/346/241/210/344/276/213.md +127 -0
  280. package/template/scripts/backend-delivery +14 -0
  281. package/template/scripts/fixtures/backend-delivery/revision-server.mjs +11 -0
  282. package/template/scripts/fixtures/strategic-handoff/fixture.mjs +3 -2
  283. package/template/scripts/instantiate-harness +69 -0
  284. package/template/scripts/lib/backend-delivery.mjs +164 -0
  285. package/template/scripts/lib/frontend-delivery-boundary.mjs +49 -0
  286. package/template/scripts/lib/frontend-delivery.mjs +73 -0
  287. package/template/scripts/lib/harness-execution-scope.mjs +52 -0
  288. package/template/scripts/lib/implementation-contract-compiler.mjs +19 -2
  289. package/template/scripts/lib/lifecycle-transition.mjs +7 -0
  290. package/template/scripts/lib/strategic-handoff-consumption.mjs +17 -10
  291. package/template/scripts/lib/strategic-handoff-design-targets.mjs +15 -0
  292. package/template/scripts/lib/strategic-handoff.mjs +1 -1
  293. package/template/scripts/lib/task-package.mjs +7 -0
  294. package/template/scripts/lib/technical-design-boundary.mjs +23 -0
  295. package/template/scripts/sync-strategic-handoff-tools +5 -2
  296. package/template/scripts/verify-frontend-delivery +9 -0
  297. package/template/scripts/verify-frontend-delivery-scenarios +131 -0
  298. package/template/scripts/verify-frontend-implementation-evidence +2 -0
  299. package/template/scripts/verify-strategic-handoff-package-scenarios +7 -1
  300. package/template/skills-lock.json +43 -13
  301. package/template.manifest.json +43 -1
  302. package/template.snapshot.json +5 -5
@@ -0,0 +1,280 @@
1
+ "use strict";
2
+
3
+ const fs = require("node:fs");
4
+ const path = require("node:path");
5
+
6
+ const { parseArgs } = require("../cli/args");
7
+ const { pathKind, targetPath, normalizeRelativePath } = require("../filesystem/path-utils");
8
+ const { applyManagedOperation, applyMigrationOperations } = require("../filesystem/apply-plan");
9
+ const { runInTransaction } = require("../filesystem/transaction-runner");
10
+ const { assertBundledFamily, assertTargetFamily } = require("../family-runtime");
11
+ const { gitDirtyWarning } = require("../git/worktree");
12
+ const { unmanagedPathReason, assertTargetWorkingTreeWritable } = require("../validation/security");
13
+ const { buildAttachPlanFromRuntime } = require("../template/attach-planner-runtime");
14
+ const { buildLegacyMigrationPlan } = require("../template/migration-runtime");
15
+ const {
16
+ PACKAGE_ROOT,
17
+ BUNDLED_TEMPLATE_ROOT,
18
+ TEMPLATE_METADATA_FILENAME,
19
+ fileHash,
20
+ readTemplateSnapshot,
21
+ readTargetIdentity,
22
+ buildAttachDesiredOperations,
23
+ buildMetadata,
24
+ writeTemplateMetadata,
25
+ } = require("../template/instance-runtime");
26
+ const { verifyGeneratedAttach } = require("../template/verification-runtime");
27
+
28
+ function assertRequiredOptions(options) {
29
+ if (!options.projectName) {
30
+ throw new Error("attach 需要 --project-name,项目名称不能为空");
31
+ }
32
+ if (!options.businessDomain) {
33
+ throw new Error("attach 需要 --business-domain,业务领域不能为空");
34
+ }
35
+ if (!options.targetDir) {
36
+ throw new Error("attach 需要 --target-dir,目标目录不能为空");
37
+ }
38
+ }
39
+
40
+ function normalizeTargetDir(targetDir) {
41
+ return path.resolve(process.cwd(), targetDir);
42
+ }
43
+
44
+ function isInsideTemplateRoot(targetDir) {
45
+ const relativePath = path.relative(BUNDLED_TEMPLATE_ROOT, targetDir);
46
+ return (
47
+ relativePath === "" ||
48
+ (!relativePath.startsWith("..") && !path.isAbsolute(relativePath))
49
+ );
50
+ }
51
+
52
+ function inspectExistingTargetDir(targetDir, { force = false } = {}) {
53
+ if (isInsideTemplateRoot(targetDir)) {
54
+ throw new Error("目标目录不能位于模板源仓库内部");
55
+ }
56
+ if (!fs.existsSync(targetDir) || pathKind(targetDir) !== "directory") {
57
+ throw new Error("attach 目标目录必须是已经存在的项目目录");
58
+ }
59
+ assertTargetWorkingTreeWritable(targetDir, {
60
+ force,
61
+ packageRoot: PACKAGE_ROOT,
62
+ });
63
+ }
64
+
65
+ function attachVariables(options) {
66
+ return {
67
+ projectName: options.projectName,
68
+ businessDomain: options.businessDomain,
69
+ teamSize: options.teamSize || "待补充",
70
+ issueTracker: options.issueTracker || "github",
71
+ includeExampleDocs:
72
+ options.includeExampleDocs === undefined
73
+ ? true
74
+ : Boolean(options.includeExampleDocs),
75
+ };
76
+ }
77
+
78
+ function shellQuote(value) {
79
+ return `'${String(value).replaceAll("'", "'\\''")}'`;
80
+ }
81
+
82
+ function printLimitedOperations(operations, formatter, limit = 40) {
83
+ const prioritized = [...operations].sort((left, right) => {
84
+ const leftPath = typeof left === "string" ? left : left.relativePath;
85
+ const rightPath = typeof right === "string" ? right : right.relativePath;
86
+ const leftIsRoot = !leftPath.includes("/");
87
+ const rightIsRoot = !rightPath.includes("/");
88
+ if (leftIsRoot !== rightIsRoot) return leftIsRoot ? -1 : 1;
89
+ return leftPath.localeCompare(rightPath);
90
+ });
91
+
92
+ for (const operation of prioritized.slice(0, limit)) {
93
+ console.log(formatter(operation));
94
+ }
95
+ if (operations.length > limit) {
96
+ console.log(
97
+ `... 其余 ${operations.length - limit} 项省略,可用 manifest / git diff 查看完整清单`,
98
+ );
99
+ }
100
+ }
101
+
102
+ function printMigrationPlan(migrationPlan) {
103
+ for (const item of migrationPlan.legacy || []) {
104
+ const destination = item.to ? ` -> ${item.to}` : "";
105
+ console.log(`legacy: ${item.action} ${item.from}${destination}`);
106
+ }
107
+ for (const item of migrationPlan.unsafe || []) {
108
+ console.log(`unsafe: ${item.path} (${item.reason})`);
109
+ }
110
+ for (const item of migrationPlan.conflicts || []) {
111
+ console.log(`conflict: ${item.from} -> ${item.to} (${item.reason})`);
112
+ }
113
+ }
114
+
115
+ function printAttachDryRun(plan, targetDir) {
116
+ console.log("attach dry-run 预览");
117
+ console.log(`目标目录:${targetDir}`);
118
+ printLimitedOperations(
119
+ plan.missing,
120
+ (operation) => `add: ${operation.relativePath}`,
121
+ );
122
+ printLimitedOperations(
123
+ plan.identity,
124
+ (operation) => `identity: ${operation.relativePath}(规范化为 project-instance)`,
125
+ );
126
+ printLimitedOperations(
127
+ plan.conflicts,
128
+ (operation) => `conflict: ${operation.relativePath} (${operation.reason})`,
129
+ );
130
+ printLimitedOperations(
131
+ plan.unsafe,
132
+ (operation) => `unsafe: ${operation.relativePath} (${operation.reason})`,
133
+ );
134
+ if (plan.matched.length > 0) {
135
+ console.log(`matched: ${plan.matched.length} 项内容一致,已纳入 managed baseline`);
136
+ }
137
+ printMigrationPlan(plan.migration);
138
+ console.log(
139
+ `统计:新增 ${plan.missing.length},一致 ${plan.matched.length},身份转换 ${plan.identity.length},冲突 ${plan.conflicts.length},unsafe ${plan.unsafe.length}`,
140
+ );
141
+ if (plan.conflicts.length > 0) {
142
+ console.log("提示:--force 只覆盖 forceable 冲突;mergeStrategy=manual 的冲突必须人工处理");
143
+ }
144
+ }
145
+
146
+ function affectedPathsForManagedOperations(operations) {
147
+ return operations.map((operation) => normalizeRelativePath(operation.relativePath));
148
+ }
149
+
150
+ function affectedPathsForMigration(migrationPlan) {
151
+ return (migrationPlan.operations || []).flatMap((operation) =>
152
+ operation.kind === "move" ? [operation.from, operation.to] : [operation.path],
153
+ );
154
+ }
155
+
156
+ function runAttach(argv = []) {
157
+ const options = parseArgs(argv);
158
+ assertRequiredOptions(options);
159
+
160
+ if (options.dryRun && options.apply) {
161
+ throw new Error("attach 的 --dry-run 与 --apply 互斥");
162
+ }
163
+ if (!options.dryRun && !options.apply) {
164
+ throw new Error("attach 必须显式传入 --dry-run 或 --apply");
165
+ }
166
+
167
+ const snapshot = readTemplateSnapshot();
168
+ assertBundledFamily(snapshot);
169
+ const targetDir = normalizeTargetDir(options.targetDir);
170
+ assertTargetFamily(targetDir);
171
+ inspectExistingTargetDir(targetDir, { force: Boolean(options.force) });
172
+
173
+ if (pathKind(targetPath(targetDir, TEMPLATE_METADATA_FILENAME)) !== "missing") {
174
+ throw new Error("当前项目已有模板元数据,请使用 sync,不要重复 attach");
175
+ }
176
+
177
+ const variables = attachVariables(options);
178
+ const identity = readTargetIdentity(targetDir);
179
+ const desiredOperations = buildAttachDesiredOperations(
180
+ targetDir,
181
+ variables,
182
+ identity,
183
+ );
184
+ const migrationPlan = buildLegacyMigrationPlan(targetDir, desiredOperations, {
185
+ checkFlatTickets: true,
186
+ });
187
+ const warning = gitDirtyWarning(targetDir);
188
+
189
+ const { classified: plan } = buildAttachPlanFromRuntime({
190
+ targetDir,
191
+ desiredOperations,
192
+ migration: migrationPlan,
193
+ warning,
194
+ getUnmanagedReason: (operation) =>
195
+ unmanagedPathReason(targetDir, operation.relativePath, {
196
+ packageRoot: PACKAGE_ROOT,
197
+ }),
198
+ getPathKind: (operation) => pathKind(operation.targetPath),
199
+ getFileHash: (operation) => fileHash(operation.targetPath),
200
+ });
201
+ plan.migration = migrationPlan;
202
+
203
+ if (warning) console.log(warning);
204
+
205
+ if (options.dryRun) {
206
+ printAttachDryRun(plan, targetDir);
207
+ return;
208
+ }
209
+
210
+ if (migrationPlan.unsafe.length > 0) {
211
+ printMigrationPlan(migrationPlan);
212
+ throw new Error(
213
+ "attach 被 unsafe 迁移项阻断;--force 不能绕过,请先人工整理 Ticket 归属",
214
+ );
215
+ }
216
+ if (plan.unsafe.length > 0) {
217
+ printAttachDryRun(plan, targetDir);
218
+ throw new Error(
219
+ "attach 被 unsafe 受管路径阻断;--force 不能绕过,请先人工整理目标路径",
220
+ );
221
+ }
222
+ if (migrationPlan.conflicts.length > 0) {
223
+ printMigrationPlan(migrationPlan);
224
+ throw new Error("attach 被旧路径迁移冲突阻断,请先处理目标冲突");
225
+ }
226
+ if (plan.conflicts.length > 0 && !options.force) {
227
+ printAttachDryRun(plan, targetDir);
228
+ throw new Error(
229
+ "attach 检测到受管文件冲突;请先 dry-run,再使用 --apply --force",
230
+ );
231
+ }
232
+
233
+ const managedToApply = [
234
+ ...plan.missing,
235
+ ...plan.identity,
236
+ ...(options.force ? plan.forceableConflicts : []),
237
+ ];
238
+
239
+ const { backupPath } = runInTransaction({
240
+ targetDir,
241
+ operation: "attach",
242
+ affectedPaths: [
243
+ ...affectedPathsForManagedOperations(managedToApply),
244
+ ...affectedPathsForMigration(migrationPlan),
245
+ TEMPLATE_METADATA_FILENAME,
246
+ ],
247
+ execute: (transaction) => {
248
+ for (const operation of managedToApply) {
249
+ applyManagedOperation(operation, transaction);
250
+ }
251
+ applyMigrationOperations(migrationPlan, transaction);
252
+ verifyGeneratedAttach(targetDir);
253
+ writeTemplateMetadata(
254
+ targetDir,
255
+ buildMetadata(variables, desiredOperations),
256
+ transaction,
257
+ );
258
+ },
259
+ });
260
+
261
+ console.log("接管完成");
262
+ console.log(`目标目录:${targetDir}`);
263
+ console.log(`新增研发管理资产:${plan.missing.length + plan.identity.length}`);
264
+ if (options.force && plan.forceableConflicts.length > 0) {
265
+ console.log(`force 覆盖冲突:${plan.forceableConflicts.length}`);
266
+ }
267
+ const manualConflicts = plan.conflicts.length - plan.forceableConflicts.length;
268
+ if (manualConflicts > 0) {
269
+ console.log(`需人工处理冲突:${manualConflicts}`);
270
+ }
271
+ if (backupPath) {
272
+ console.log(`备份目录:${backupPath}`);
273
+ console.log(`清理命令:rm -rf ${shellQuote(backupPath)}`);
274
+ }
275
+ console.log("下一步建议:运行 git diff 或 git status 检查接管结果");
276
+ }
277
+
278
+ module.exports = {
279
+ runAttach,
280
+ };
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ const { parseArgs } = require("../cli/args");
4
+ const { renderPlanText } = require("../cli/plan-output");
5
+ const { serializePlan } = require("../template/plan-schema");
6
+ const { projectDiff } = require("../api/project-diff");
7
+
8
+ function runDiff(argv = []) {
9
+ const options = parseArgs(argv);
10
+ const plan = projectDiff({
11
+ targetDir: options.targetDir || ".",
12
+ force: Boolean(options.force),
13
+ });
14
+
15
+ if (options.json) {
16
+ process.stdout.write(serializePlan(plan));
17
+ } else {
18
+ process.stdout.write(renderPlanText(plan));
19
+ }
20
+ return plan;
21
+ }
22
+
23
+ module.exports = { runDiff };
@@ -0,0 +1,417 @@
1
+ "use strict";
2
+
3
+ const fs = require("node:fs");
4
+ const path = require("node:path");
5
+ const { spawnSync } = require("node:child_process");
6
+
7
+ const { parseArgs } = require("../cli/args");
8
+ const { pathKind, targetPath } = require("../filesystem/path-utils");
9
+ const { gitDirtyWarning } = require("../git/worktree");
10
+ const { gitlinkWriteViolation } = require("../validation/security");
11
+ const {
12
+ PACKAGE_ROOT,
13
+ PACKAGE_MANIFEST,
14
+ fileHash,
15
+ readTemplateSnapshot,
16
+ readTargetIdentity,
17
+ loadTemplateMetadata,
18
+ } = require("../template/instance-runtime");
19
+ const {
20
+ ownershipPolicyDrift,
21
+ } = require("../template/ownership-metadata");
22
+ const {
23
+ lifecyclePolicyDrift,
24
+ } = require("../template/lifecycle-metadata");
25
+
26
+ const DOCTOR_SCHEMA_VERSION = 1;
27
+ const VERIFIERS = [
28
+ {
29
+ name: "verifier-sync-skills",
30
+ path: "scripts/sync-skills",
31
+ args: ["--check"],
32
+ },
33
+ {
34
+ name: "verifier-skill-lock",
35
+ path: "scripts/update-skill-lock",
36
+ args: ["--check"],
37
+ },
38
+ {
39
+ name: "verifier-template",
40
+ path: "scripts/verify-template",
41
+ args: [],
42
+ requiresGit: true,
43
+ },
44
+ ];
45
+
46
+ function normalizeTargetDir(value) {
47
+ return path.resolve(process.cwd(), value || ".");
48
+ }
49
+
50
+ function addCheck(report, name, status, detail, data = undefined) {
51
+ const check = { name, status, detail };
52
+ if (data !== undefined) check.data = data;
53
+ report.checks.push(check);
54
+ if (status === "error") report.ok = false;
55
+ return check;
56
+ }
57
+
58
+ function isGitWorktree(targetDir) {
59
+ const result = spawnSync("git", ["rev-parse", "--is-inside-work-tree"], {
60
+ cwd: targetDir,
61
+ encoding: "utf8",
62
+ timeout: 5000,
63
+ });
64
+ return result.status === 0 && (result.stdout || "").trim() === "true";
65
+ }
66
+
67
+ function checkManagedBaseline(report, targetDir, metadata) {
68
+ const managedFiles = metadata.managedFiles || {};
69
+ const stats = {
70
+ total: 0,
71
+ matched: 0,
72
+ modified: 0,
73
+ missing: 0,
74
+ invalid: 0,
75
+ };
76
+
77
+ for (const [relativePath, record] of Object.entries(managedFiles)) {
78
+ stats.total += 1;
79
+ if (
80
+ !record ||
81
+ typeof record !== "object" ||
82
+ Array.isArray(record) ||
83
+ !/^[0-9a-f]{64}$/.test(record.contentHash || "")
84
+ ) {
85
+ stats.invalid += 1;
86
+ continue;
87
+ }
88
+
89
+ let absolutePath;
90
+ try {
91
+ absolutePath = targetPath(targetDir, relativePath);
92
+ } catch {
93
+ stats.invalid += 1;
94
+ continue;
95
+ }
96
+
97
+ const kind = pathKind(absolutePath);
98
+ if (kind === "missing") {
99
+ stats.missing += 1;
100
+ continue;
101
+ }
102
+ if (kind !== "file") {
103
+ stats.invalid += 1;
104
+ continue;
105
+ }
106
+
107
+ if (fileHash(absolutePath) === record.contentHash) {
108
+ stats.matched += 1;
109
+ } else {
110
+ stats.modified += 1;
111
+ }
112
+ }
113
+
114
+ if (stats.invalid > 0) {
115
+ addCheck(
116
+ report,
117
+ "managed-baseline",
118
+ "error",
119
+ `managed baseline 含 ${stats.invalid} 个非法记录或不安全路径`,
120
+ stats,
121
+ );
122
+ } else if (stats.missing > 0 || stats.modified > 0) {
123
+ addCheck(
124
+ report,
125
+ "managed-baseline",
126
+ "warning",
127
+ `受管基线存在漂移:本地修改 ${stats.modified},缺失 ${stats.missing}`,
128
+ stats,
129
+ );
130
+ } else {
131
+ addCheck(
132
+ report,
133
+ "managed-baseline",
134
+ "ok",
135
+ `受管基线一致:${stats.matched}/${stats.total}`,
136
+ stats,
137
+ );
138
+ }
139
+ }
140
+
141
+ function checkOwnershipPolicy(report, metadata) {
142
+ const drift = ownershipPolicyDrift(metadata);
143
+ if (drift.state === "missing") {
144
+ addCheck(
145
+ report,
146
+ "ownership-policy",
147
+ "warning",
148
+ "实例 metadata 尚未记录 ownership policy baseline;下一次 attach/sync 会自动补齐",
149
+ drift,
150
+ );
151
+ return;
152
+ }
153
+ if (drift.state === "drift") {
154
+ addCheck(
155
+ report,
156
+ "ownership-policy",
157
+ "warning",
158
+ `ownership policy baseline 与当前 CLI 不一致:v${drift.actualVersion} -> v${drift.expectedVersion}`,
159
+ drift,
160
+ );
161
+ return;
162
+ }
163
+ addCheck(
164
+ report,
165
+ "ownership-policy",
166
+ "ok",
167
+ `ownership policy baseline 一致:v${drift.expectedVersion}`,
168
+ drift,
169
+ );
170
+ }
171
+
172
+ function addLifecycleDriftCheck(report, name, label, drift) {
173
+ if (drift.state === "missing") {
174
+ addCheck(
175
+ report,
176
+ name,
177
+ "warning",
178
+ `实例 metadata 尚未记录 ${label} baseline;下一次 attach/sync 会自动补齐`,
179
+ drift,
180
+ );
181
+ return;
182
+ }
183
+ if (drift.state === "drift") {
184
+ addCheck(
185
+ report,
186
+ name,
187
+ "warning",
188
+ `${label} baseline 与当前 CLI 不一致:v${drift.actual.version} -> v${drift.expected.version}`,
189
+ drift,
190
+ );
191
+ return;
192
+ }
193
+ addCheck(
194
+ report,
195
+ name,
196
+ "ok",
197
+ `${label} baseline 一致:v${drift.expected.version}`,
198
+ drift,
199
+ );
200
+ }
201
+
202
+ function checkLifecyclePolicies(report, metadata) {
203
+ const drift = lifecyclePolicyDrift(metadata);
204
+ addLifecycleDriftCheck(
205
+ report,
206
+ "customization-policy",
207
+ "customization policy",
208
+ drift.customization,
209
+ );
210
+ addLifecycleDriftCheck(
211
+ report,
212
+ "generator-policy",
213
+ "generator policy",
214
+ drift.generator,
215
+ );
216
+ }
217
+
218
+ function runVerifierCheck(report, targetDir, verifier, gitWorktree) {
219
+ const commandPath = targetPath(targetDir, verifier.path);
220
+ if (pathKind(commandPath) !== "file") {
221
+ addCheck(
222
+ report,
223
+ verifier.name,
224
+ "error",
225
+ `缺少 verifier:${verifier.path}`,
226
+ );
227
+ return;
228
+ }
229
+
230
+ if (verifier.requiresGit && !gitWorktree) {
231
+ addCheck(
232
+ report,
233
+ verifier.name,
234
+ "warning",
235
+ `未执行 ${verifier.path}:目标目录不是 Git worktree;doctor 不会临时 git init`,
236
+ );
237
+ return;
238
+ }
239
+
240
+ const result = spawnSync(commandPath, verifier.args || [], {
241
+ cwd: targetDir,
242
+ encoding: "utf8",
243
+ timeout: 30000,
244
+ });
245
+ const output = [result.stdout, result.stderr]
246
+ .filter(Boolean)
247
+ .join("")
248
+ .trim();
249
+
250
+ if (result.error || result.status !== 0) {
251
+ addCheck(
252
+ report,
253
+ verifier.name,
254
+ "error",
255
+ `${verifier.path} 校验失败${output ? `:${output}` : ""}`,
256
+ { exitCode: result.status },
257
+ );
258
+ return;
259
+ }
260
+
261
+ addCheck(
262
+ report,
263
+ verifier.name,
264
+ "ok",
265
+ `${verifier.path} 校验通过`,
266
+ { exitCode: result.status },
267
+ );
268
+ }
269
+
270
+ function buildDoctorReport(targetDir) {
271
+ const report = {
272
+ schemaVersion: DOCTOR_SCHEMA_VERSION,
273
+ operation: "doctor",
274
+ targetDir,
275
+ cliVersion: PACKAGE_MANIFEST.version,
276
+ ok: true,
277
+ checks: [],
278
+ };
279
+
280
+ let snapshot = null;
281
+ try {
282
+ snapshot = readTemplateSnapshot();
283
+ addCheck(
284
+ report,
285
+ "template-snapshot",
286
+ "ok",
287
+ `模板快照有效:${snapshot.templateCommit}`,
288
+ { templateCommit: snapshot.templateCommit },
289
+ );
290
+ } catch (error) {
291
+ addCheck(report, "template-snapshot", "error", error.message);
292
+ }
293
+
294
+ if (!fs.existsSync(targetDir) || pathKind(targetDir) !== "directory") {
295
+ addCheck(report, "target-directory", "error", "目标目录不存在或不是目录");
296
+ return report;
297
+ }
298
+ addCheck(report, "target-directory", "ok", "目标目录可读取");
299
+
300
+ const violation = gitlinkWriteViolation(targetDir, {
301
+ packageRoot: PACKAGE_ROOT,
302
+ });
303
+ if (violation) {
304
+ addCheck(report, "git-safety", "error", violation);
305
+ } else {
306
+ addCheck(report, "git-safety", "ok", "未检测到 gitlink / detached HEAD 写入风险");
307
+ }
308
+
309
+ let metadata = null;
310
+ try {
311
+ ({ metadata } = loadTemplateMetadata(targetDir));
312
+ addCheck(
313
+ report,
314
+ "template-metadata",
315
+ "ok",
316
+ `模板元数据有效:${metadata.templateVersion || metadata.cliVersion || "unknown"}`,
317
+ {
318
+ metadataSchemaVersion: metadata.metadataSchemaVersion,
319
+ templateVersion: metadata.templateVersion || metadata.cliVersion || null,
320
+ templateCommit: metadata.templateCommit || null,
321
+ },
322
+ );
323
+
324
+ if (snapshot && metadata.templateCommit !== snapshot.templateCommit) {
325
+ addCheck(
326
+ report,
327
+ "template-drift",
328
+ "warning",
329
+ `实例模板 commit 与当前 CLI 快照不同:${metadata.templateCommit} -> ${snapshot.templateCommit}`,
330
+ {
331
+ from: metadata.templateCommit,
332
+ to: snapshot.templateCommit,
333
+ },
334
+ );
335
+ } else if (snapshot) {
336
+ addCheck(report, "template-drift", "ok", "实例模板 commit 与当前 CLI 快照一致");
337
+ }
338
+
339
+ checkOwnershipPolicy(report, metadata);
340
+ checkLifecyclePolicies(report, metadata);
341
+ checkManagedBaseline(report, targetDir, metadata);
342
+ } catch (error) {
343
+ addCheck(report, "template-metadata", "error", error.message);
344
+ }
345
+
346
+ try {
347
+ const identity = readTargetIdentity(targetDir);
348
+ if (identity.state !== "valid") {
349
+ addCheck(report, "project-identity", "error", "缺少 yss-project.yaml");
350
+ } else if (identity.fields.repository_mode !== "project-instance") {
351
+ addCheck(
352
+ report,
353
+ "project-identity",
354
+ "error",
355
+ `repository_mode 不是 project-instance:${identity.fields.repository_mode}`,
356
+ );
357
+ } else {
358
+ addCheck(report, "project-identity", "ok", "yss-project.yaml 为 project-instance");
359
+ }
360
+ } catch (error) {
361
+ addCheck(report, "project-identity", "error", error.message);
362
+ }
363
+
364
+ const gitWorktree = isGitWorktree(targetDir);
365
+ const dirtyWarning = gitDirtyWarning(targetDir);
366
+ if (dirtyWarning) {
367
+ addCheck(report, "git-worktree", "warning", dirtyWarning);
368
+ } else if (gitWorktree) {
369
+ addCheck(report, "git-worktree", "ok", "Git worktree 无需警告");
370
+ } else {
371
+ addCheck(report, "git-worktree", "warning", "目标目录不是 Git worktree");
372
+ }
373
+
374
+ for (const verifier of VERIFIERS) {
375
+ runVerifierCheck(report, targetDir, verifier, gitWorktree);
376
+ }
377
+
378
+ return report;
379
+ }
380
+
381
+ function renderDoctorText(report) {
382
+ const lines = [
383
+ "create-yss-spec doctor",
384
+ `目标目录:${report.targetDir}`,
385
+ `结果:${report.ok ? "PASS" : "FAIL"}`,
386
+ ];
387
+ for (const check of report.checks) {
388
+ lines.push(`[${check.status.toUpperCase()}] ${check.name}: ${check.detail}`);
389
+ }
390
+ return `${lines.join("\n")}\n`;
391
+ }
392
+
393
+ function runDoctor(argv = []) {
394
+ const options = parseArgs(argv);
395
+ const targetDir = normalizeTargetDir(options.targetDir);
396
+ const report = buildDoctorReport(targetDir);
397
+
398
+ if (options.json) {
399
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
400
+ } else {
401
+ process.stdout.write(renderDoctorText(report));
402
+ }
403
+
404
+ return report;
405
+ }
406
+
407
+ module.exports = {
408
+ DOCTOR_SCHEMA_VERSION,
409
+ VERIFIERS,
410
+ checkManagedBaseline,
411
+ checkOwnershipPolicy,
412
+ checkLifecyclePolicies,
413
+ runVerifierCheck,
414
+ buildDoctorReport,
415
+ renderDoctorText,
416
+ runDoctor,
417
+ };