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,90 @@
1
+ "use strict";
2
+
3
+ const fs = require("node:fs");
4
+ const path = require("node:path");
5
+
6
+ const { applyOwnershipToOperations } = require("./ownership-runtime");
7
+ const {
8
+ validateCustomizationPolicy,
9
+ resolveCustomizationStrategy,
10
+ validateGeneratorPolicy,
11
+ resolveGenerator,
12
+ } = require("./lifecycle-policy");
13
+
14
+ const PACKAGE_ROOT = path.resolve(__dirname, "../..");
15
+ const MANIFEST_PATH = path.join(PACKAGE_ROOT, "template.manifest.json");
16
+ const manifest = JSON.parse(fs.readFileSync(MANIFEST_PATH, "utf8"));
17
+
18
+ const CUSTOMIZATION_POLICY = validateCustomizationPolicy(
19
+ manifest.customizationPolicy || {
20
+ version: 1,
21
+ defaultStrategy: "replace-with-force",
22
+ rules: [],
23
+ },
24
+ );
25
+ const GENERATOR_POLICY = validateGeneratorPolicy(
26
+ manifest.generatorPolicy || { version: 1, rules: [] },
27
+ );
28
+
29
+ function applyLifecycleToOperations(operations = []) {
30
+ return applyOwnershipToOperations(operations).map((operation) => {
31
+ if (operation.ownership === "managed-customizable") {
32
+ return {
33
+ ...operation,
34
+ mergeStrategy:
35
+ operation.mergeStrategy ||
36
+ resolveCustomizationStrategy(
37
+ operation.relativePath,
38
+ CUSTOMIZATION_POLICY,
39
+ ),
40
+ };
41
+ }
42
+
43
+ if (operation.ownership === "generated") {
44
+ const generator = resolveGenerator(operation.relativePath, GENERATOR_POLICY);
45
+ return generator
46
+ ? {
47
+ ...operation,
48
+ generatorId: operation.generatorId || generator.generatorId,
49
+ generatorVersion:
50
+ operation.generatorVersion || generator.generatorVersion,
51
+ }
52
+ : operation;
53
+ }
54
+
55
+ return operation;
56
+ });
57
+ }
58
+
59
+ function decoratePlanWithLifecycle(plan, desiredOperations = []) {
60
+ const operations = applyLifecycleToOperations(desiredOperations);
61
+ const byPath = new Map(
62
+ operations.map((operation) => [operation.relativePath, operation]),
63
+ );
64
+
65
+ const decorate = (item) => {
66
+ const operation = byPath.get(item.path);
67
+ if (!operation) return item;
68
+ const result = { ...item };
69
+ if (operation.mergeStrategy) result.mergeStrategy = operation.mergeStrategy;
70
+ if (operation.generatorId) result.generatorId = operation.generatorId;
71
+ if (operation.generatorVersion) {
72
+ result.generatorVersion = operation.generatorVersion;
73
+ }
74
+ return result;
75
+ };
76
+
77
+ return {
78
+ ...plan,
79
+ changes: (plan.changes || []).map(decorate),
80
+ conflicts: (plan.conflicts || []).map(decorate),
81
+ unsafe: (plan.unsafe || []).map(decorate),
82
+ };
83
+ }
84
+
85
+ module.exports = {
86
+ CUSTOMIZATION_POLICY,
87
+ GENERATOR_POLICY,
88
+ applyLifecycleToOperations,
89
+ decoratePlanWithLifecycle,
90
+ };
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+
3
+ function createMigrationPlan(targetDir) {
4
+ return {
5
+ targetDir,
6
+ operations: [],
7
+ legacy: [],
8
+ conflicts: [],
9
+ unsafe: [],
10
+ };
11
+ }
12
+
13
+ function isBlockedMigration(plan) {
14
+ return Boolean(
15
+ plan &&
16
+ ((Array.isArray(plan.conflicts) && plan.conflicts.length > 0) ||
17
+ (Array.isArray(plan.unsafe) && plan.unsafe.length > 0)),
18
+ );
19
+ }
20
+
21
+ function addUnsafe(plan, path, reason) {
22
+ plan.unsafe.push({ path, reason });
23
+ return plan;
24
+ }
25
+
26
+ function addConflict(plan, from, to, reason) {
27
+ plan.conflicts.push({ from, to, reason });
28
+ plan.legacy.push({ action: "conflict", from, to, reason });
29
+ return plan;
30
+ }
31
+
32
+ function addMove(plan, from, to, reason) {
33
+ plan.operations.push({ kind: "move", from, to, reason });
34
+ plan.legacy.push({ action: "move", from, to, reason });
35
+ return plan;
36
+ }
37
+
38
+ function addRemove(plan, path, reason, metadata = {}) {
39
+ plan.operations.push({ kind: "remove", path, reason });
40
+ plan.legacy.push({
41
+ action: metadata.action || "remove",
42
+ from: path,
43
+ to: metadata.to ?? null,
44
+ reason,
45
+ });
46
+ return plan;
47
+ }
48
+
49
+ function addReplaceWithTemplate(plan, from, to, reason) {
50
+ plan.operations.push({ kind: "remove", path: from, reason });
51
+ plan.legacy.push({
52
+ action: "replace-with-template",
53
+ from,
54
+ to,
55
+ reason,
56
+ });
57
+ return plan;
58
+ }
59
+
60
+ function addRemoveDuplicate(plan, from, to, reason) {
61
+ plan.operations.push({
62
+ kind: "remove",
63
+ path: from,
64
+ reason: `${reason}(新旧内容一致)`,
65
+ });
66
+ plan.legacy.push({
67
+ action: "remove-duplicate",
68
+ from,
69
+ to,
70
+ reason,
71
+ });
72
+ return plan;
73
+ }
74
+
75
+ function summarizeMigrationPlan(plan) {
76
+ return {
77
+ operations: plan?.operations?.length || 0,
78
+ legacy: plan?.legacy?.length || 0,
79
+ conflicts: plan?.conflicts?.length || 0,
80
+ unsafe: plan?.unsafe?.length || 0,
81
+ blocked: isBlockedMigration(plan),
82
+ };
83
+ }
84
+
85
+ module.exports = {
86
+ createMigrationPlan,
87
+ isBlockedMigration,
88
+ addUnsafe,
89
+ addConflict,
90
+ addMove,
91
+ addRemove,
92
+ addReplaceWithTemplate,
93
+ addRemoveDuplicate,
94
+ summarizeMigrationPlan,
95
+ };
@@ -0,0 +1,247 @@
1
+ "use strict";
2
+
3
+ const crypto = require("node:crypto");
4
+ const fs = require("node:fs");
5
+
6
+ const { treeHash } = require("../template-hash");
7
+ const { targetPath, pathKind } = require("../filesystem/path-utils");
8
+ const {
9
+ createMigrationPlan,
10
+ addUnsafe,
11
+ addConflict,
12
+ addMove,
13
+ addRemove,
14
+ addReplaceWithTemplate,
15
+ addRemoveDuplicate,
16
+ } = require("./migration-planner");
17
+
18
+ const AGENT_SKILL_ROOTS = [
19
+ ".agents/skills",
20
+ ".claude/skills",
21
+ ".codex/skills",
22
+ ".cursor/skills",
23
+ ".pi/skills",
24
+ ".qoder/skills",
25
+ ".trae/skills",
26
+ ];
27
+
28
+ const LEGACY_SKILL_MAPPINGS = [
29
+ ["to-prd", "to-spec"],
30
+ ["to-issues", "to-tickets"],
31
+ ];
32
+
33
+ const LEGACY_FILE_MAPPINGS = [
34
+ ["docs/templates/prd-template.md", "docs/templates/spec-template.md"],
35
+ [
36
+ "docs/templates/vertical-slice-issue-template.md",
37
+ "docs/templates/vertical-slice-ticket-template.md",
38
+ ],
39
+ ];
40
+
41
+ function sha256(value) {
42
+ return crypto.createHash("sha256").update(value).digest("hex");
43
+ }
44
+
45
+ function pathContentHash(absolutePath) {
46
+ const kind = pathKind(absolutePath);
47
+ if (kind === "file") return sha256(fs.readFileSync(absolutePath));
48
+ if (kind === "directory") return treeHash(absolutePath);
49
+ if (kind === "missing") return null;
50
+ return sha256(`${kind}:${fs.realpathSync(absolutePath)}`);
51
+ }
52
+
53
+ function pathsEqual(leftPath, rightPath) {
54
+ const leftKind = pathKind(leftPath);
55
+ const rightKind = pathKind(rightPath);
56
+ return (
57
+ leftKind === rightKind &&
58
+ leftKind !== "missing" &&
59
+ pathContentHash(leftPath) === pathContentHash(rightPath)
60
+ );
61
+ }
62
+
63
+ function managedPathPrefix(relativePath, desiredPathSet) {
64
+ return (
65
+ desiredPathSet.has(relativePath) ||
66
+ [...desiredPathSet].some((candidate) => candidate.startsWith(`${relativePath}/`))
67
+ );
68
+ }
69
+
70
+ function addMigrationDestination(from, to, reason, desiredPathSet, plan) {
71
+ const source = targetPath(plan.targetDir, from);
72
+ const destination = targetPath(plan.targetDir, to);
73
+ const sourceKind = pathKind(source);
74
+ const destinationKind = pathKind(destination);
75
+
76
+ if (sourceKind === "missing") return;
77
+
78
+ if ([sourceKind, destinationKind].includes("other")) {
79
+ addUnsafe(
80
+ plan,
81
+ from,
82
+ `${reason}:源或目标路径是符号链接或其他不可安全判断的类型`,
83
+ );
84
+ return;
85
+ }
86
+
87
+ if (managedPathPrefix(to, desiredPathSet)) {
88
+ addReplaceWithTemplate(plan, from, to, reason);
89
+ return;
90
+ }
91
+
92
+ if (destinationKind === "missing") {
93
+ addMove(plan, from, to, reason);
94
+ return;
95
+ }
96
+
97
+ if (pathsEqual(source, destination)) {
98
+ addRemoveDuplicate(plan, from, to, reason);
99
+ return;
100
+ }
101
+
102
+ addConflict(plan, from, to, `${reason}:迁移目标已存在且内容不一致`);
103
+ }
104
+
105
+ function addDirectoryMigration(from, to, reason, desiredPathSet, plan) {
106
+ const source = targetPath(plan.targetDir, from);
107
+ const destination = targetPath(plan.targetDir, to);
108
+ const sourceKind = pathKind(source);
109
+ const destinationKind = pathKind(destination);
110
+
111
+ if (sourceKind === "missing") return;
112
+
113
+ if (sourceKind !== "directory" || destinationKind === "other") {
114
+ addUnsafe(plan, from, `${reason}:源或目标路径不是可安全遍历的目录`);
115
+ return;
116
+ }
117
+
118
+ if (destinationKind === "file") {
119
+ addConflict(plan, from, to, `${reason}:迁移目标是文件而不是目录`);
120
+ return;
121
+ }
122
+
123
+ const entries = fs.readdirSync(source).filter((entry) => entry !== ".DS_Store");
124
+ if (entries.length === 0) {
125
+ addRemove(plan, from, reason, { action: "remove-empty", to });
126
+ return;
127
+ }
128
+
129
+ for (const entry of entries) {
130
+ const childFrom = `${from}/${entry}`;
131
+ const childTo = `${to}/${entry}`;
132
+ if (pathKind(targetPath(plan.targetDir, childFrom)) === "directory") {
133
+ addDirectoryMigration(childFrom, childTo, reason, desiredPathSet, plan);
134
+ } else {
135
+ addMigrationDestination(childFrom, childTo, reason, desiredPathSet, plan);
136
+ }
137
+ }
138
+
139
+ addRemove(plan, from, reason, { action: "remove-migrated-directory", to });
140
+ }
141
+
142
+ function buildLegacyMigrationPlan(
143
+ targetDir,
144
+ desiredOperations,
145
+ { checkFlatTickets = true } = {},
146
+ ) {
147
+ const desiredPathSet = new Set(
148
+ desiredOperations.map((operation) => operation.relativePath),
149
+ );
150
+ const plan = createMigrationPlan(targetDir);
151
+
152
+ for (const [oldName, newName] of LEGACY_SKILL_MAPPINGS) {
153
+ for (const agentRoot of AGENT_SKILL_ROOTS) {
154
+ addMigrationDestination(
155
+ `${agentRoot}/${oldName}`,
156
+ `${agentRoot}/${newName}`,
157
+ `旧 skill ${oldName} 迁移为 ${newName}`,
158
+ desiredPathSet,
159
+ plan,
160
+ );
161
+ }
162
+ }
163
+
164
+ for (const [oldPath, newPath] of LEGACY_FILE_MAPPINGS) {
165
+ addMigrationDestination(
166
+ oldPath,
167
+ newPath,
168
+ "旧模板路径迁移",
169
+ desiredPathSet,
170
+ plan,
171
+ );
172
+ }
173
+
174
+ addDirectoryMigration(
175
+ "docs/requirements/issues",
176
+ "docs/requirements/tickets",
177
+ "旧 Ticket 目录迁移",
178
+ desiredPathSet,
179
+ plan,
180
+ );
181
+
182
+ const requirementsPath = targetPath(targetDir, "docs/requirements");
183
+ if (pathKind(requirementsPath) === "directory") {
184
+ for (const entry of fs.readdirSync(requirementsPath, { withFileTypes: true })) {
185
+ if (entry.isFile() && entry.name.endsWith("-prd.md")) {
186
+ const oldPath = `docs/requirements/${entry.name}`;
187
+ const newPath = `docs/requirements/${entry.name.replace(/-prd\.md$/, "-spec.md")}`;
188
+ addMigrationDestination(
189
+ oldPath,
190
+ newPath,
191
+ "旧规格文件名迁移",
192
+ desiredPathSet,
193
+ plan,
194
+ );
195
+ }
196
+ }
197
+ }
198
+
199
+ const legacyScratch = targetPath(targetDir, ".scratch");
200
+ if (pathKind(legacyScratch) === "directory") {
201
+ for (const entry of fs.readdirSync(legacyScratch, { withFileTypes: true })) {
202
+ if (entry.name === ".DS_Store") continue;
203
+ addMigrationDestination(
204
+ `.scratch/${entry.name}`,
205
+ `docs/.scratch/${entry.name}`,
206
+ "根 scratch 目录迁移",
207
+ desiredPathSet,
208
+ plan,
209
+ );
210
+ }
211
+ }
212
+
213
+ if (checkFlatTickets) {
214
+ const legacyDirectory = "docs/requirements/tickets";
215
+ const directoryPath = targetPath(targetDir, legacyDirectory);
216
+ if (pathKind(directoryPath) === "directory") {
217
+ const entries = fs.readdirSync(directoryPath, { withFileTypes: true });
218
+ const unsafeEntries = entries.filter(
219
+ (entry) => entry.name !== ".gitkeep" && entry.name !== ".DS_Store",
220
+ );
221
+
222
+ if (unsafeEntries.length > 0) {
223
+ for (const entry of unsafeEntries) {
224
+ addUnsafe(
225
+ plan,
226
+ `${legacyDirectory}/${entry.name}`,
227
+ "扁平 Ticket 无法可靠推断功能归属,不能自动迁移",
228
+ );
229
+ }
230
+ } else if (!desiredPathSet.has(`${legacyDirectory}/.gitkeep`)) {
231
+ addRemove(plan, legacyDirectory, "删除空的旧 Ticket 目录", {
232
+ action: "remove-empty",
233
+ to: null,
234
+ });
235
+ }
236
+ }
237
+ }
238
+
239
+ return plan;
240
+ }
241
+
242
+ module.exports = {
243
+ AGENT_SKILL_ROOTS,
244
+ LEGACY_SKILL_MAPPINGS,
245
+ LEGACY_FILE_MAPPINGS,
246
+ buildLegacyMigrationPlan,
247
+ };
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+
3
+ const crypto = require("node:crypto");
4
+ const {
5
+ OWNERSHIP_POLICY,
6
+ resolveTemplateOwnership,
7
+ } = require("./ownership-runtime");
8
+
9
+ function ownershipPolicyHash(policy = OWNERSHIP_POLICY) {
10
+ return crypto
11
+ .createHash("sha256")
12
+ .update(JSON.stringify(policy))
13
+ .digest("hex");
14
+ }
15
+
16
+ function decorateMetadataOwnership(metadata, policy = OWNERSHIP_POLICY) {
17
+ if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) {
18
+ throw new TypeError("metadata must be an object");
19
+ }
20
+
21
+ const managedFiles = Object.fromEntries(
22
+ Object.entries(metadata.managedFiles || {}).map(([relativePath, record]) => [
23
+ relativePath,
24
+ {
25
+ ...record,
26
+ ownership:
27
+ record?.ownership || resolveTemplateOwnership(relativePath),
28
+ },
29
+ ]),
30
+ );
31
+
32
+ return {
33
+ ...metadata,
34
+ ownershipPolicyVersion: policy.version,
35
+ ownershipPolicyHash: ownershipPolicyHash(policy),
36
+ managedFiles,
37
+ };
38
+ }
39
+
40
+ function ownershipPolicyDrift(metadata, policy = OWNERSHIP_POLICY) {
41
+ const expectedVersion = policy.version;
42
+ const expectedHash = ownershipPolicyHash(policy);
43
+ const actualVersion = metadata?.ownershipPolicyVersion;
44
+ const actualHash = metadata?.ownershipPolicyHash;
45
+
46
+ if (actualVersion === undefined || actualHash === undefined) {
47
+ return {
48
+ state: "missing",
49
+ expectedVersion,
50
+ expectedHash,
51
+ actualVersion: actualVersion ?? null,
52
+ actualHash: actualHash ?? null,
53
+ };
54
+ }
55
+
56
+ if (actualVersion !== expectedVersion || actualHash !== expectedHash) {
57
+ return {
58
+ state: "drift",
59
+ expectedVersion,
60
+ expectedHash,
61
+ actualVersion,
62
+ actualHash,
63
+ };
64
+ }
65
+
66
+ return {
67
+ state: "matched",
68
+ expectedVersion,
69
+ expectedHash,
70
+ actualVersion,
71
+ actualHash,
72
+ };
73
+ }
74
+
75
+ module.exports = {
76
+ ownershipPolicyHash,
77
+ decorateMetadataOwnership,
78
+ ownershipPolicyDrift,
79
+ };
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+
3
+ const OWNERSHIP_POLICY_VERSION = 1;
4
+ const OWNERSHIP_TYPES = Object.freeze([
5
+ "managed",
6
+ "managed-customizable",
7
+ "generated",
8
+ "user-owned",
9
+ "protected",
10
+ ]);
11
+ const OWNERSHIP_TYPE_SET = new Set(OWNERSHIP_TYPES);
12
+
13
+ const DEFAULT_OWNERSHIP_POLICY = Object.freeze({
14
+ version: OWNERSHIP_POLICY_VERSION,
15
+ default: "managed",
16
+ rules: [],
17
+ });
18
+
19
+ function normalizePolicyPath(value) {
20
+ return String(value || "")
21
+ .replaceAll("\\", "/")
22
+ .replace(/^\.\//, "")
23
+ .replace(/\/+$/, "");
24
+ }
25
+
26
+ function isOwnershipType(value) {
27
+ return OWNERSHIP_TYPE_SET.has(value);
28
+ }
29
+
30
+ function validateOwnershipPattern(pattern) {
31
+ if (typeof pattern !== "string" || !pattern.trim()) {
32
+ throw new Error("ownership rule pattern 不能为空");
33
+ }
34
+ const normalized = normalizePolicyPath(pattern);
35
+ if (
36
+ !normalized ||
37
+ normalized === "." ||
38
+ normalized.startsWith("../") ||
39
+ normalized.includes("/../") ||
40
+ normalized.startsWith("/")
41
+ ) {
42
+ throw new Error(`ownership rule pattern 越界:${pattern}`);
43
+ }
44
+ if (normalized.includes("**") && !normalized.endsWith("/**")) {
45
+ throw new Error(`ownership rule 仅支持末尾 /**:${pattern}`);
46
+ }
47
+ if (normalized.includes("*") && !normalized.endsWith("/*") && !normalized.endsWith("/**")) {
48
+ throw new Error(`ownership rule 仅支持 exact、/* 或 /**:${pattern}`);
49
+ }
50
+ return normalized;
51
+ }
52
+
53
+ function validateOwnershipPolicy(policy) {
54
+ const value = policy || DEFAULT_OWNERSHIP_POLICY;
55
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
56
+ throw new Error("ownershipPolicy 必须是 JSON 对象");
57
+ }
58
+ if (value.version !== OWNERSHIP_POLICY_VERSION) {
59
+ throw new Error(`不支持的 ownershipPolicy version:${value.version}`);
60
+ }
61
+ if (!isOwnershipType(value.default)) {
62
+ throw new Error(`ownershipPolicy default 非法:${value.default}`);
63
+ }
64
+ if (!Array.isArray(value.rules)) {
65
+ throw new Error("ownershipPolicy rules 必须是数组");
66
+ }
67
+
68
+ const seen = new Set();
69
+ const rules = value.rules.map((rule, index) => {
70
+ if (!rule || typeof rule !== "object" || Array.isArray(rule)) {
71
+ throw new Error(`ownershipPolicy rules[${index}] 必须是对象`);
72
+ }
73
+ const pattern = validateOwnershipPattern(rule.pattern);
74
+ if (seen.has(pattern)) {
75
+ throw new Error(`ownershipPolicy pattern 重复:${pattern}`);
76
+ }
77
+ seen.add(pattern);
78
+ if (!isOwnershipType(rule.ownership)) {
79
+ throw new Error(
80
+ `ownershipPolicy rules[${index}].ownership 非法:${rule.ownership}`,
81
+ );
82
+ }
83
+ return { pattern, ownership: rule.ownership };
84
+ });
85
+
86
+ return {
87
+ version: OWNERSHIP_POLICY_VERSION,
88
+ default: value.default,
89
+ rules,
90
+ };
91
+ }
92
+
93
+ function matchesOwnershipPattern(relativePath, pattern) {
94
+ const target = normalizePolicyPath(relativePath);
95
+ const normalizedPattern = validateOwnershipPattern(pattern);
96
+
97
+ if (normalizedPattern.endsWith("/**")) {
98
+ const prefix = normalizedPattern.slice(0, -3);
99
+ return target === prefix || target.startsWith(`${prefix}/`);
100
+ }
101
+ if (normalizedPattern.endsWith("/*")) {
102
+ const prefix = normalizedPattern.slice(0, -2);
103
+ if (!target.startsWith(`${prefix}/`)) return false;
104
+ return !target.slice(prefix.length + 1).includes("/");
105
+ }
106
+ return target === normalizedPattern;
107
+ }
108
+
109
+ function resolveOwnership(relativePath, policy = DEFAULT_OWNERSHIP_POLICY) {
110
+ const validated = validateOwnershipPolicy(policy);
111
+ for (const rule of validated.rules) {
112
+ if (matchesOwnershipPattern(relativePath, rule.pattern)) {
113
+ return rule.ownership;
114
+ }
115
+ }
116
+ return validated.default;
117
+ }
118
+
119
+ function isTemplateManagedOwnership(ownership) {
120
+ return ["managed", "managed-customizable", "generated"].includes(ownership);
121
+ }
122
+
123
+ function isWriteProtectedOwnership(ownership) {
124
+ return ownership === "user-owned" || ownership === "protected";
125
+ }
126
+
127
+ function ownershipWriteViolation(operation) {
128
+ const ownership = operation?.ownership || "managed";
129
+ if (!isWriteProtectedOwnership(ownership)) return null;
130
+ const path = operation?.relativePath || operation?.path || "unknown";
131
+ return ownership === "protected"
132
+ ? `${path} 被 ownership policy 标记为 protected,CLI 不得写入或覆盖`
133
+ : `${path} 被 ownership policy 标记为 user-owned,不属于受管模板文件`;
134
+ }
135
+
136
+ module.exports = {
137
+ OWNERSHIP_POLICY_VERSION,
138
+ OWNERSHIP_TYPES,
139
+ DEFAULT_OWNERSHIP_POLICY,
140
+ normalizePolicyPath,
141
+ isOwnershipType,
142
+ validateOwnershipPattern,
143
+ validateOwnershipPolicy,
144
+ matchesOwnershipPattern,
145
+ resolveOwnership,
146
+ isTemplateManagedOwnership,
147
+ isWriteProtectedOwnership,
148
+ ownershipWriteViolation,
149
+ };