create-yss-spec 3.3.0 → 3.3.1

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 (197) hide show
  1. package/package.json +3 -2
  2. package/src/command-runner.mjs +107 -0
  3. package/src/self-update.js +7 -4
  4. package/src/template/instance-runtime.js +1 -1
  5. package/template/.agents/skills/.strategic-design-skills-manifest.json +2 -2
  6. package/template/.agents/skills/competitive-intelligence/SKILL.md +4 -4
  7. package/template/.agents/skills/domain-modeling/CONTEXT-FORMAT.md +1 -1
  8. package/template/.agents/skills/grill-with-docs/SKILL.md +1 -1
  9. package/template/.agents/skills/setup-matt-pocock-skills/issue-tracker-local.md +1 -1
  10. package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +7 -7
  11. package/template/.agents/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  12. package/template/.agents/skills/yss-frontend-scaffold-generator/scripts/generate_scaffold.mjs +22 -8
  13. package/template/.agents/skills/yss-frontend-scaffold-generator/scripts/run_scaffold_verification.mjs +5 -6
  14. package/template/.agents/skills/yss-frontend-scaffold-generator/scripts/scaffold-generator.test.mjs +19 -1
  15. package/template/.agents/skills/yss-product-lifecycle/SKILL.md +7 -4
  16. package/template/.agents/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  17. package/template/.agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -3
  18. package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +57 -6
  19. package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +11 -1
  20. package/template/.agents/skills/yss-research/SKILL.md +1 -1
  21. package/template/.agents/skills/yss-stage-decision/SKILL.md +5 -3
  22. package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  23. package/template/.claude/skills/competitive-intelligence/SKILL.md +4 -4
  24. package/template/.claude/skills/domain-modeling/CONTEXT-FORMAT.md +1 -1
  25. package/template/.claude/skills/grill-with-docs/SKILL.md +1 -1
  26. package/template/.claude/skills/setup-matt-pocock-skills/issue-tracker-local.md +1 -1
  27. package/template/.claude/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +7 -7
  28. package/template/.claude/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  29. package/template/.claude/skills/yss-frontend-scaffold-generator/scripts/generate_scaffold.mjs +22 -8
  30. package/template/.claude/skills/yss-frontend-scaffold-generator/scripts/run_scaffold_verification.mjs +5 -6
  31. package/template/.claude/skills/yss-frontend-scaffold-generator/scripts/scaffold-generator.test.mjs +19 -1
  32. package/template/.claude/skills/yss-product-lifecycle/SKILL.md +7 -4
  33. package/template/.claude/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  34. package/template/.claude/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -3
  35. package/template/.claude/skills/yss-product-lifecycle/references/orchestration-contract.yaml +57 -6
  36. package/template/.claude/skills/yss-product-lifecycle/references/orchestration.md +11 -1
  37. package/template/.claude/skills/yss-research/SKILL.md +1 -1
  38. package/template/.claude/skills/yss-stage-decision/SKILL.md +5 -3
  39. package/template/.claude/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  40. package/template/.codex/skills/competitive-intelligence/SKILL.md +4 -4
  41. package/template/.codex/skills/domain-modeling/CONTEXT-FORMAT.md +1 -1
  42. package/template/.codex/skills/grill-with-docs/SKILL.md +1 -1
  43. package/template/.codex/skills/setup-matt-pocock-skills/issue-tracker-local.md +1 -1
  44. package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +7 -7
  45. package/template/.codex/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  46. package/template/.codex/skills/yss-frontend-scaffold-generator/scripts/generate_scaffold.mjs +22 -8
  47. package/template/.codex/skills/yss-frontend-scaffold-generator/scripts/run_scaffold_verification.mjs +5 -6
  48. package/template/.codex/skills/yss-frontend-scaffold-generator/scripts/scaffold-generator.test.mjs +19 -1
  49. package/template/.codex/skills/yss-product-lifecycle/SKILL.md +7 -4
  50. package/template/.codex/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  51. package/template/.codex/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -3
  52. package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +57 -6
  53. package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +11 -1
  54. package/template/.codex/skills/yss-research/SKILL.md +1 -1
  55. package/template/.codex/skills/yss-stage-decision/SKILL.md +5 -3
  56. package/template/.codex/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  57. package/template/.cursor/skills/competitive-intelligence/SKILL.md +4 -4
  58. package/template/.cursor/skills/domain-modeling/CONTEXT-FORMAT.md +1 -1
  59. package/template/.cursor/skills/grill-with-docs/SKILL.md +1 -1
  60. package/template/.cursor/skills/setup-matt-pocock-skills/issue-tracker-local.md +1 -1
  61. package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +7 -7
  62. package/template/.cursor/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  63. package/template/.cursor/skills/yss-frontend-scaffold-generator/scripts/generate_scaffold.mjs +22 -8
  64. package/template/.cursor/skills/yss-frontend-scaffold-generator/scripts/run_scaffold_verification.mjs +5 -6
  65. package/template/.cursor/skills/yss-frontend-scaffold-generator/scripts/scaffold-generator.test.mjs +19 -1
  66. package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +7 -4
  67. package/template/.cursor/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  68. package/template/.cursor/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -3
  69. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +57 -6
  70. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +11 -1
  71. package/template/.cursor/skills/yss-research/SKILL.md +1 -1
  72. package/template/.cursor/skills/yss-stage-decision/SKILL.md +5 -3
  73. package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  74. package/template/.pi/skills/competitive-intelligence/SKILL.md +4 -4
  75. package/template/.pi/skills/domain-modeling/CONTEXT-FORMAT.md +1 -1
  76. package/template/.pi/skills/grill-with-docs/SKILL.md +1 -1
  77. package/template/.pi/skills/setup-matt-pocock-skills/issue-tracker-local.md +1 -1
  78. package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +7 -7
  79. package/template/.pi/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  80. package/template/.pi/skills/yss-frontend-scaffold-generator/scripts/generate_scaffold.mjs +22 -8
  81. package/template/.pi/skills/yss-frontend-scaffold-generator/scripts/run_scaffold_verification.mjs +5 -6
  82. package/template/.pi/skills/yss-frontend-scaffold-generator/scripts/scaffold-generator.test.mjs +19 -1
  83. package/template/.pi/skills/yss-product-lifecycle/SKILL.md +7 -4
  84. package/template/.pi/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  85. package/template/.pi/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -3
  86. package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +57 -6
  87. package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +11 -1
  88. package/template/.pi/skills/yss-research/SKILL.md +1 -1
  89. package/template/.pi/skills/yss-stage-decision/SKILL.md +5 -3
  90. package/template/.pi/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  91. package/template/.qoder/skills/competitive-intelligence/SKILL.md +4 -4
  92. package/template/.qoder/skills/domain-modeling/CONTEXT-FORMAT.md +1 -1
  93. package/template/.qoder/skills/grill-with-docs/SKILL.md +1 -1
  94. package/template/.qoder/skills/setup-matt-pocock-skills/issue-tracker-local.md +1 -1
  95. package/template/.qoder/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +7 -7
  96. package/template/.qoder/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  97. package/template/.qoder/skills/yss-frontend-scaffold-generator/scripts/generate_scaffold.mjs +22 -8
  98. package/template/.qoder/skills/yss-frontend-scaffold-generator/scripts/run_scaffold_verification.mjs +5 -6
  99. package/template/.qoder/skills/yss-frontend-scaffold-generator/scripts/scaffold-generator.test.mjs +19 -1
  100. package/template/.qoder/skills/yss-product-lifecycle/SKILL.md +7 -4
  101. package/template/.qoder/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  102. package/template/.qoder/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -3
  103. package/template/.qoder/skills/yss-product-lifecycle/references/orchestration-contract.yaml +57 -6
  104. package/template/.qoder/skills/yss-product-lifecycle/references/orchestration.md +11 -1
  105. package/template/.qoder/skills/yss-research/SKILL.md +1 -1
  106. package/template/.qoder/skills/yss-stage-decision/SKILL.md +5 -3
  107. package/template/.qoder/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  108. package/template/.trae/skills/competitive-intelligence/SKILL.md +4 -4
  109. package/template/.trae/skills/domain-modeling/CONTEXT-FORMAT.md +1 -1
  110. package/template/.trae/skills/grill-with-docs/SKILL.md +1 -1
  111. package/template/.trae/skills/setup-matt-pocock-skills/issue-tracker-local.md +1 -1
  112. package/template/.trae/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +7 -7
  113. package/template/.trae/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  114. package/template/.trae/skills/yss-frontend-scaffold-generator/scripts/generate_scaffold.mjs +22 -8
  115. package/template/.trae/skills/yss-frontend-scaffold-generator/scripts/run_scaffold_verification.mjs +5 -6
  116. package/template/.trae/skills/yss-frontend-scaffold-generator/scripts/scaffold-generator.test.mjs +19 -1
  117. package/template/.trae/skills/yss-product-lifecycle/SKILL.md +7 -4
  118. package/template/.trae/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  119. package/template/.trae/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -3
  120. package/template/.trae/skills/yss-product-lifecycle/references/orchestration-contract.yaml +57 -6
  121. package/template/.trae/skills/yss-product-lifecycle/references/orchestration.md +11 -1
  122. package/template/.trae/skills/yss-research/SKILL.md +1 -1
  123. package/template/.trae/skills/yss-stage-decision/SKILL.md +5 -3
  124. package/template/.trae/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  125. package/template/AGENTS.md +2 -2
  126. package/template/CONTEXT.md +3 -2
  127. package/template/README.md +3 -3
  128. package/template/docs/agents/digital-human-roles.md +1 -1
  129. package/template/docs/agents/digital-human-roles.yaml +11 -11
  130. package/template/docs/agents/issue-tracker.md +1 -1
  131. package/template/docs/agents/strategic-design-skills-integration.md +2 -0
  132. package/template/docs/architecture/README.md +1 -1
  133. package/template/docs/architecture/templates/business-architecture-template.md +1 -1
  134. package/template/docs/architecture/templates/functional-architecture-template.md +1 -1
  135. package/template/docs/design/README.md +1 -1
  136. package/template/docs/design/templates/interaction-spec-template.md +1 -1
  137. package/template/docs/design/templates/product-overview-design-template.md +1 -1
  138. package/template/docs/{discovery → plan}/IDEATION.md +5 -5
  139. package/template/docs/plan/README.md +9 -0
  140. package/template/docs/plan/entry-review.md +23 -0
  141. package/template/docs/plan/templates/plan-template.md +58 -0
  142. package/template/docs/process/harness-process-tailoring.md +1 -1
  143. package/template/docs/process/lifecycle-artifact-map.md +6 -6
  144. package/template/docs/process/lifecycle-registry-baseline.json +5 -1
  145. package/template/docs/process/lifecycle-registry.yaml +25 -20
  146. package/template/docs/process/plan-migration.md +13 -0
  147. package/template/docs/process/schemas/digital-human-task-package.schema.json +2 -0
  148. package/template/docs/process/schemas/lifecycle-checkpoint.schema.json +3 -0
  149. package/template/docs/process/schemas/lifecycle-registry.schema.json +1 -1
  150. package/template/docs/process/template-engineering-overview.md +2 -2
  151. package/template/docs/process/template-verification-profiles.yaml +2 -0
  152. package/template/docs/process/templates/context-reconciliation-template.yaml +2 -2
  153. package/template/docs/process/templates/lifecycle-checkpoint-template.yaml +1 -1
  154. package/template/docs/requirements/README.md +2 -2
  155. package/template/docs/templates/local-parent-ticket-template.md +1 -1
  156. package/template/docs/templates/subagent-task-package-template.md +1 -1
  157. package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214.md +1 -1
  158. package/template/scripts/cache-template-commit +2 -2
  159. package/template/scripts/fixtures/strategic-handoff/source-roles.json +7 -7
  160. package/template/scripts/fixtures/user-decision/plan-fixture.mjs +30 -0
  161. package/template/scripts/lib/backend-delivery.mjs +5 -2
  162. package/template/scripts/lib/command-runner.mjs +107 -0
  163. package/template/scripts/lib/context-reconciliation.mjs +34 -0
  164. package/template/scripts/lib/json-schema.mjs +42 -13
  165. package/template/scripts/lib/lifecycle-context-query.mjs +7 -3
  166. package/template/scripts/lib/lifecycle-transition.mjs +9 -3
  167. package/template/scripts/lib/plan-spec-entry.mjs +87 -0
  168. package/template/scripts/lib/scenario-checks.mjs +15 -12
  169. package/template/scripts/lib/skill-supply-chain.mjs +18 -2
  170. package/template/scripts/lib/strategic-handoff-io.mjs +5 -4
  171. package/template/scripts/lib/strategic-handoff.mjs +10 -9
  172. package/template/scripts/lib/task-package.mjs +2 -0
  173. package/template/scripts/lib/template-commit-cache.mjs +7 -5
  174. package/template/scripts/run-template-verification +9 -3
  175. package/template/scripts/sync-strategic-handoff-tools +9 -0
  176. package/template/scripts/verify-context-reconciliation +2 -48
  177. package/template/scripts/verify-context-reconciliation-scenarios +1 -1
  178. package/template/scripts/verify-lifecycle-checkpoint +2 -0
  179. package/template/scripts/verify-lifecycle-context-query-scenarios +28 -8
  180. package/template/scripts/verify-plan-spec-entry +11 -0
  181. package/template/scripts/verify-plan-spec-entry-scenarios +79 -0
  182. package/template/scripts/verify-script-performance-scenarios +56 -0
  183. package/template/scripts/verify-subagent-task-package-scenarios +9 -8
  184. package/template/scripts/verify-template-cache-scenarios +11 -1
  185. package/template/scripts/verify-user-decision-scenarios +4 -4
  186. package/template/skills-lock.json +17 -17
  187. package/template.manifest.json +2 -1
  188. package/template.snapshot.json +5 -5
  189. package/template/docs/discovery/README.md +0 -87
  190. package/template/docs/discovery/reports/.gitkeep +0 -0
  191. package/template/docs/discovery/reports/agent-governance-options.md +0 -71
  192. package/template/docs/discovery/reports/competitor-deep-dive/.gitkeep +0 -0
  193. package/template/docs/discovery/templates/discovery-template.md +0 -94
  194. /package/template/docs/{discovery → plan}/templates/competitive-analysis-template.md +0 -0
  195. /package/template/docs/{discovery → plan}/templates/competitive-matrix-template.md +0 -0
  196. /package/template/docs/{discovery → plan}/templates/market-analysis-template.md +0 -0
  197. /package/template/docs/{discovery → plan}/templates/user-pain-points-template.md +0 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema_version": 1,
3
3
  "registry_id": "yss.lifecycle",
4
- "semantic_sha256": "68c053060bb837fe4bc2b40d7a6ffcea1a53fc6b5e6b929eb0858824c657a15d",
4
+ "semantic_sha256": "96fcbcb858eed45ba228d87c75804f28ccb464b1963c0d23be348ade094bac01",
5
5
  "published_ids": [
6
6
  "artifact.architecture-review",
7
7
  "artifact.data-architecture",
@@ -19,6 +19,7 @@
19
19
  "artifact.openapi-draft",
20
20
  "artifact.openapi-freeze-record",
21
21
  "artifact.parent-ticket",
22
+ "artifact.plan-record",
22
23
  "artifact.product-overview",
23
24
  "artifact.project-scaffold-contract",
24
25
  "artifact.prototype-confirmation",
@@ -76,6 +77,7 @@
76
77
  "gate.user-confirmation",
77
78
  "stage.discovery",
78
79
  "stage.entry-triage",
80
+ "stage.plan",
79
81
  "stage.product-design",
80
82
  "stage.spec-architecture",
81
83
  "stage.system-data-engineering",
@@ -94,6 +96,8 @@
94
96
  "work-unit.independent-review",
95
97
  "work-unit.intensity-aware-review",
96
98
  "work-unit.intensity-aware-verification",
99
+ "work-unit.plan-opportunity",
100
+ "work-unit.plan-requirements",
97
101
  "work-unit.prototype-design",
98
102
  "work-unit.release-and-retrospective",
99
103
  "work-unit.release-and-rollback",
@@ -8,17 +8,22 @@ id_policy:
8
8
  pattern: '^(stage|gate|artifact|work-unit|evidence)\.[a-z0-9][a-z0-9-]*$'
9
9
  published_ids_immutable: true
10
10
  baseline: docs/process/lifecycle-registry-baseline.json
11
- deprecated_ids: [artifact.high-fidelity-html-prototype, work-unit.fresh-verification, work-unit.independent-review]
11
+ deprecated_ids: [artifact.high-fidelity-html-prototype, work-unit.fresh-verification, work-unit.independent-review, stage.discovery, artifact.discovery-record, work-unit.discovery-opportunity, work-unit.discovery-requirements]
12
12
 
13
13
  stages:
14
14
  - id: stage.entry-triage
15
15
  name: 入口分诊
16
16
  goal: 确认仓库身份、问题范围和影响面。
17
17
  exit_criteria: yss-project.yaml 合法,影响面和最近可信阶段可解释。
18
- - id: stage.discovery
19
- name: Discovery
20
- goal: 澄清问题、用户、约束和机会。
21
- exit_criteria: 问题边界、关键假设和待确认项已记录。
18
+ - id: stage.plan
19
+ name: Plan(战略规划)
20
+ goal: 确认目标、业务边界、关键规则、MVP / 非目标、优先级和交接责任,为 Spec 提供战略输入;按影响面探索并复用仍有效的结论。
21
+ exit_criteria: 用户确认规划结论,命中的战略与阶段决策门禁通过;影响业务边界、关键规则或 MVP 的问题已解决,其他未决项有责任人和解决时点;下游可进入 Spec,不代表可实现。
22
+ spec_entry:
23
+ required_checks: [goals, scope_and_priority, boundaries_and_rules, open_questions, handoff, context_reconciliation, grill_exit]
24
+ gate_impacts:
25
+ gate.domain-strategy-approved: domain_strategy
26
+ gate.stage-decision-package-approved: stage_decision
22
27
  - id: stage.spec-architecture
23
28
  name: Spec / 功能架构
24
29
  goal: 固化解决方案和功能边界。
@@ -130,15 +135,15 @@ gates:
130
135
  evidence: [evidence.repository-identity-check]
131
136
  - id: gate.domain-strategy-approved
132
137
  name: DDD 战略设计批准
133
- stage: stage.discovery
138
+ stage: stage.plan
134
139
  trigger: 存在 DDD 战略设计影响或需要确定领域边界、统一语言和核心规则。
135
140
  public_name: 业务边界与规则确认
136
141
  public_trigger: 需要确定业务板块、业务责任区、统一业务词汇、协作关系或关键规则。
137
142
  evidence: [evidence.domain-strategy-review, evidence.approval-record]
138
143
  - id: gate.stage-decision-package-approved
139
144
  name: 阶段决策包批准
140
- stage: stage.discovery
141
- trigger: Discovery 到 Spec 入口需要稳定的阶段决策合同。
145
+ stage: stage.plan
146
+ trigger: Plan 到 Spec 入口需要稳定的阶段决策合同。
142
147
  evidence: [evidence.stage-decision-package, evidence.approval-record]
143
148
  requires_gates: [gate.domain-strategy-approved]
144
149
  - id: gate.spec-baseline-approved
@@ -221,18 +226,18 @@ artifacts:
221
226
  trigger: 每次变更。
222
227
  - id: artifact.domain-strategy
223
228
  name: DDD 战略设计
224
- stage: stage.discovery
229
+ stage: stage.plan
225
230
  trigger: 新产品/模块、跨上下文功能、统一语言冲突、服务边界或核心规则变化。
226
231
  public_name: 业务边界与规则设计
227
232
  public_trigger: 新产品/模块、跨责任区协作、业务词汇冲突、责任边界或关键规则变化。
228
233
  - id: artifact.stage-decision-package
229
234
  name: 阶段决策包
230
- stage: stage.discovery
231
- trigger: Discovery 到 Spec 入口需要结构化上游决策。
235
+ stage: stage.plan
236
+ trigger: Plan 到 Spec 入口需要结构化上游决策。
232
237
  public_name: 方案决策包
233
- - id: artifact.discovery-record
234
- name: Discovery 记录
235
- stage: stage.discovery
238
+ - id: artifact.plan-record
239
+ name: Plan 记录
240
+ stage: stage.plan
236
241
  trigger: 新问题或边界不清。
237
242
  - id: artifact.spec
238
243
  name: Spec
@@ -384,13 +389,13 @@ work_units:
384
389
  input: 已审查 commit。
385
390
  output: release note、观察信号、回滚点。
386
391
  completion: 两仓库顺序和恢复动作明确。
387
- - id: work-unit.discovery-opportunity
392
+ - id: work-unit.plan-opportunity
388
393
  name: 机会调研
389
394
  scope: project-instance
390
395
  input: 用户问题、市场/竞品事实需求和现有上下文。
391
- output: Discovery 机会结论、证据、替代方案和关键假设。
396
+ output: Plan 机会结论、证据、替代方案和关键假设。
392
397
  completion: 机会继续/停止建议可审查;事实已 research 或记录为假设。
393
- - id: work-unit.discovery-requirements
398
+ - id: work-unit.plan-requirements
394
399
  name: 需求分析
395
400
  scope: project-instance
396
401
  input: 机会结论、用户反馈和领域词汇。
@@ -408,16 +413,16 @@ work_units:
408
413
  - id: work-unit.stage-decision
409
414
  name: 阶段决策包综合
410
415
  scope: project-instance
411
- input: Discovery、DDD 战略设计以及产品经理负责的商业约束输入。
416
+ input: Plan、DDD 战略设计以及产品经理负责的商业约束输入。
412
417
  output: 带版本、digest、证据和下游映射的阶段决策包。
413
418
  completion: 必填字段、引用、影响面和下游消费验证通过;批准门禁完成。
414
419
  public_name: 方案决策包综合
415
- public_input: Discovery、业务边界与规则设计以及产品经理负责的商业约束输入。
420
+ public_input: Plan、业务边界与规则设计以及产品经理负责的商业约束输入。
416
421
  public_output: 带版本、digest、证据和下游映射的方案决策包。
417
422
  - id: work-unit.spec-synthesis
418
423
  name: Spec 综合
419
424
  scope: project-instance
420
- input: 已确认的 Discovery 记录和测试 seam。
425
+ input: 已确认的 Plan 记录和测试 seam。
421
426
  output: Spec、产品总体设计和功能架构。
422
427
  completion: Spec 内容完整并进入 ready-for-human;下游推进仍需 gate.spec-baseline-approved。
423
428
  - id: work-unit.prototype-design
@@ -0,0 +1,13 @@
1
+ # Plan 阶段切换说明
2
+
3
+ 新流程仅使用 `stage.plan`、`artifact.plan-record`、`work-unit.plan-opportunity` 和 `work-unit.plan-requirements`。不提供 Discovery 阶段别名、旧标识解析或兼容入口;旧 ID 在注册表中仅作为弃用清单保留,以防重新分配,不可执行。
4
+
5
+ 新工作从 `docs/plan/templates/plan-template.md` 起草,工作目录为 `docs/.scratch/<feature>/plan/`。问题、机会和事实探索是 Plan 内按影响面执行的活动。
6
+
7
+ 历史冻结文档、批准记录和摘要保持原字节。旧状态不能直接恢复执行;如需继续,按当前 Plan 模板重新整理输入并核查当前退出条件,不把旧批准自动视为新流程批准。已有事实和结论可引用,但须记录当前版本、适用范围和复用理由。
8
+
9
+ 综合模板和战略设计模板共同采用 Plan。它为 Spec 提供战略输入;后续 Spec、页面原型、契约、Ticket 及交接边界仍由各自 profile 和生命周期注册表定义。Plan 不等同于实现合同中的 Context Plan。
10
+
11
+ 影响业务边界、关键规则或 MVP 的未决项必须在进入 Spec 前解决;其他细节须经用户确认延期,并具备不影响当前决定的依据、责任人、解决时点和接收方。既有 runnable blocker 不得降为普通延期项。
12
+
13
+ Plan 是借鉴 AI-DLC 前置规划职责的本地名称,不宣称是 AWS 官方阶段名称或完整 Inception。
@@ -6,6 +6,8 @@
6
6
  "additionalProperties": false,
7
7
  "required": ["schema_version", "task_id", "work_unit_id", "actor_id", "role_id", "runtime_id", "execution_state", "workflow_status", "skill_source", "contract", "inputs", "objective", "allowed_write_paths", "forbidden_actions", "expected_outputs", "expected_evidence_files", "verification_commands", "verification_results", "downstream_consumers", "convergence"],
8
8
  "properties": {
9
+ "plan_review_ref": { "type": "string", "minLength": 1 },
10
+ "plan_user_decision_ref": { "type": "string", "minLength": 1 },
9
11
  "schema_version": { "const": 1 },
10
12
  "frontend_delivery": {
11
13
  "type": "object", "additionalProperties": false, "required": ["acceptance_ref"],
@@ -6,6 +6,9 @@
6
6
  "additionalProperties": false,
7
7
  "required": ["schema_version", "repository_mode", "mode", "status", "stage", "artifacts", "gates", "context_reconciliation", "next_work_unit", "ticket_sync", "verification", "human_review", "git_checkpoint", "blockers", "rollback"],
8
8
  "properties": {
9
+ "plan_review_ref": { "type": "string", "minLength": 1 },
10
+ "plan_user_decision_ref": { "type": "string", "minLength": 1 },
11
+ "feature_id": { "type": "string", "minLength": 1 },
9
12
  "schema_version": { "const": 1 },
10
13
  "repository_mode": { "enum": ["template-source", "project-instance"] },
11
14
  "mode": { "enum": ["route", "orchestrate", "resume", "audit"] },
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "$defs": {
29
29
  "id": { "type": "string", "pattern": "^(stage|gate|artifact|work-unit|evidence)\\.[a-z0-9][a-z0-9-]*$" },
30
- "stages": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["id", "name", "goal", "exit_criteria"], "properties": { "id": { "$ref": "#/$defs/id" }, "name": { "type": "string", "minLength": 1 }, "goal": { "type": "string", "minLength": 1 }, "exit_criteria": { "type": "string", "minLength": 1 }, "public_name": { "type": "string", "minLength": 1 }, "public_goal": { "type": "string", "minLength": 1 }, "public_exit_criteria": { "type": "string", "minLength": 1 } } } },
30
+ "stages": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["id", "name", "goal", "exit_criteria"], "properties": { "spec_entry": {"type":"object","required":["required_checks","gate_impacts"],"additionalProperties":false,"properties":{"required_checks":{"type":"array","minItems":1,"uniqueItems":true,"items":{"type":"string","minLength":1}},"gate_impacts":{"type":"object","minProperties":1,"additionalProperties":{"type":"string","minLength":1}}}}, "id": { "$ref": "#/$defs/id" }, "name": { "type": "string", "minLength": 1 }, "goal": { "type": "string", "minLength": 1 }, "exit_criteria": { "type": "string", "minLength": 1 }, "public_name": { "type": "string", "minLength": 1 }, "public_goal": { "type": "string", "minLength": 1 }, "public_exit_criteria": { "type": "string", "minLength": 1 } } } },
31
31
  "objects": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["id", "name", "stage", "trigger"], "properties": { "id": { "$ref": "#/$defs/id" }, "name": { "type": "string", "minLength": 1 }, "stage": { "type": "string", "pattern": "^stage\\." }, "trigger": { "type": "string", "minLength": 1 }, "public_name": { "type": "string", "minLength": 1 }, "public_trigger": { "type": "string", "minLength": 1 }, "evidence": { "type": "array", "minItems": 1, "items": { "type": "string", "pattern": "^evidence\\." } }, "requires_gates": { "type": "array", "uniqueItems": true, "items": { "type": "string", "pattern": "^gate\\." } } } } },
32
32
  "workUnits": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["id", "name", "scope", "input", "output", "completion"], "properties": { "id": { "$ref": "#/$defs/id" }, "name": { "type": "string", "minLength": 1 }, "scope": { "enum": ["template-source", "project-instance"] }, "input": { "type": "string", "minLength": 1 }, "output": { "type": "string", "minLength": 1 }, "completion": { "type": "string", "minLength": 1 }, "public_name": { "type": "string", "minLength": 1 }, "public_input": { "type": "string", "minLength": 1 }, "public_output": { "type": "string", "minLength": 1 }, "public_completion": { "type": "string", "minLength": 1 } } } },
33
33
  "evidence": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["id", "name", "description"], "properties": { "id": { "$ref": "#/$defs/id" }, "name": { "type": "string", "minLength": 1 }, "description": { "type": "string", "minLength": 1 }, "public_name": { "type": "string", "minLength": 1 }, "public_description": { "type": "string", "minLength": 1 } } } }
@@ -22,7 +22,7 @@ YSS 模板工程是一套可版本化的研发治理系统。它用仓库身份
22
22
  | 身份 | 用途 | 允许的主要工作 | 边界 |
23
23
  |---|---|---|---|
24
24
  | `template-source` | 维护通用模板与治理规则 | 更新单一事实来源、同步技能投影、构建 CLI 快照、验证与审查 | 不生成具体产品的 Spec、原型、OpenAPI 或垂直切片 Ticket |
25
- | `project-instance` | 承载具体产品或模块的研发管理资产 | 执行 Discovery、Spec、设计、工程契约、Ticket、实现、验证和发布流程 | 不反向成为通用模板的权威来源 |
25
+ | `project-instance` | 承载具体产品或模块的研发管理资产 | 执行 Plan、Spec、设计、工程契约、Ticket、实现、验证和发布流程 | 不反向成为通用模板的权威来源 |
26
26
 
27
27
  身份只由 `yss-project.yaml` 声明。目录结构、Git remote 和占位符都不能替代该清单。
28
28
 
@@ -32,7 +32,7 @@ YSS 模板工程是一套可版本化的研发治理系统。它用仓库身份
32
32
 
33
33
  | 产品线 | 模板源 | 实例化 CLI | 生命周期边界 |
34
34
  |---|---|---|---|
35
- | 全产品生命周期 | `yss-spec-project-template` | `create-yss-spec` | 从 Discovery 到发布与复盘 |
35
+ | 全产品生命周期 | `yss-spec-project-template` | `create-yss-spec` | 从 Plan 到发布与复盘 |
36
36
  | DDD 战略设计交接 | `yss-harness-design-agent` | `create-yss-harness-design` | 从机会、需求和战略设计到 Strategic Design Handoff |
37
37
  | 开发落地 | `yss-harness-dev-agent` | `create-yss-harness-dev` | 从已批准 Spec 或战略设计交接包到 Tactical Design、Slice Contract、实现与验证 |
38
38
 
@@ -318,6 +318,7 @@ groups:
318
318
  - { run: "scripts/verify-context-contract-scenarios" }
319
319
  - { run: "node scripts/verify-business-language-scenarios" }
320
320
  - { run: "scripts/verify-context-reconciliation-scenarios" }
321
+ - { run: "node scripts/verify-script-performance-scenarios" }
321
322
  - { run: "scripts/verify-grill-with-docs-context-scenarios" }
322
323
  - { run: "scripts/verify-strategic-context-import-scenarios" }
323
324
  - { run: "scripts/verify-lifecycle-registry" }
@@ -330,6 +331,7 @@ groups:
330
331
  - { run: "scripts/verify-scaffold-architecture-decision-scenarios" }
331
332
  - { run: "scripts/verify-lifecycle-scenarios" }
332
333
  - { run: "scripts/verify-lifecycle-transition-scenarios" }
334
+ - { run: "node scripts/verify-plan-spec-entry-scenarios" }
333
335
  - { run: "scripts/verify-frontend-scaffold-generator-scenarios" }
334
336
  maintenance:
335
337
  commands:
@@ -1,7 +1,7 @@
1
1
  schema_version: 1
2
2
  repository_mode: project-instance
3
- stage: stage.discovery
4
- work_unit: work-unit.discovery-requirements
3
+ stage: stage.plan
4
+ work_unit: work-unit.plan-requirements
5
5
  status: reconciled
6
6
  context_snapshot:
7
7
  context_ref: CONTEXT.md
@@ -10,7 +10,7 @@ context_reconciliation:
10
10
  ref: null
11
11
  reason: 等待当前工作单元完成稳定术语回写与核对
12
12
  evidence_refs: []
13
- next_work_unit: work-unit.discovery-opportunity
13
+ next_work_unit: work-unit.plan-opportunity
14
14
  phase_boundary:
15
15
  decision: continue
16
16
  reason: initial routing
@@ -1,6 +1,6 @@
1
1
  # 需求定义 (Requirements) — 从想法到可执行定义
2
2
 
3
- > **Phase: Requirements | 输入: Discovery | 输出: Spec + Stories + 验收条件**
3
+ > **Phase: Requirements | 输入: Plan | 输出: Spec + Stories + 验收条件**
4
4
 
5
5
  ---
6
6
 
@@ -79,7 +79,7 @@ delegate_task(
79
79
  ## AI-Human Loop
80
80
 
81
81
  ```
82
- Discovery报告 → AI生成Spec → PM审核
82
+ Plan报告 → AI生成Spec → PM审核
83
83
  → AI补充边界 → PM确认 → AI拆解Stories
84
84
  → 团队估算 → AI标注风险 → TechLead确认 → 进入Architecture
85
85
  ```
@@ -37,7 +37,7 @@ Status: ready-for-human
37
37
 
38
38
  ## 资产与证据
39
39
 
40
- - Discovery:`docs/.scratch/<feature>/discovery/`
40
+ - Plan:`docs/.scratch/<feature>/plan/`
41
41
  - Spec Delta:`docs/.scratch/<feature>/spec-delta/`
42
42
  - Design:`docs/.scratch/<feature>/design/`
43
43
  - API:`docs/.scratch/<feature>/api/`
@@ -35,7 +35,7 @@ owner: ai
35
35
 
36
36
  | 输入 | 路径 / 链接 | 用途 |
37
37
  |---|---|---|
38
- | Spec / Discovery | | |
38
+ | Spec / Plan | | |
39
39
  | Product / Interaction Design | | |
40
40
  | OpenAPI Draft / Freeze | | |
41
41
  | Architecture / ADR / CONTEXT | | |
@@ -67,7 +67,7 @@ init 只创建不存在或空目录;attach / sync 默认只预览,写入要
67
67
 
68
68
  ## 按路线推进
69
69
 
70
- 综合模板按本仓生命周期从分诊、Discovery、Spec/功能架构、产品设计、工程契约、Ticket、切片推进到验证与发布。战略模板在业务交接停止;通用研发从批准上游接入;专职两端按交付合同接力。
70
+ 综合模板按本仓生命周期从分诊、Plan、Spec/功能架构、产品设计、工程契约、Ticket、切片推进到验证与发布。战略模板在业务交接停止;通用研发从批准上游接入;专职两端按交付合同接力。
71
71
 
72
72
  每一步都让 Agent 说明:消费了哪些当前输入、准备了什么、缺谁确认、怎样检查结果。具体阶段和门禁从本仓注册表读取,不把别的模板阶段编号复制进本仓。
73
73
 
@@ -3,9 +3,9 @@ import { parseArgs } from "node:util";
3
3
  import { acquireTemplateCommit } from "./lib/template-commit-cache.mjs";
4
4
 
5
5
  try {
6
- const { values } = parseArgs({ options: { repository: { type: "string" }, commit: { type: "string" }, "cache-root": { type: "string" } }, strict: true });
6
+ const { values } = parseArgs({ options: { repository: { type: "string" }, commit: { type: "string" }, "cache-root": { type: "string" }, "timeout-ms": { type: "string" } }, strict: true });
7
7
  if (!values.repository || !values.commit) throw new TypeError("用法: scripts/cache-template-commit --repository <remote-url> --commit <40位commit> [--cache-root <path>]");
8
- const result = acquireTemplateCommit({ repository: values.repository, commit: values.commit, cacheRoot: values["cache-root"] });
8
+ const result = acquireTemplateCommit({ repository: values.repository, commit: values.commit, cacheRoot: values["cache-root"], timeoutMs: Number(values["timeout-ms"] || 0) });
9
9
  process.stdout.write(`${JSON.stringify(result)}\n`);
10
10
  } catch (error) {
11
11
  process.stderr.write(`模板 commit 缓存失败: ${error.message}\n`);
@@ -73,7 +73,7 @@
73
73
  ],
74
74
  "stages": [
75
75
  "stage.entry-triage",
76
- "stage.discovery",
76
+ "stage.plan",
77
77
  "stage.spec-architecture",
78
78
  "stage.product-design",
79
79
  "stage.system-data-engineering",
@@ -103,11 +103,11 @@
103
103
  "contract_version": 1,
104
104
  "title": "YSS 需求经理",
105
105
  "stages": [
106
- "stage.discovery",
106
+ "stage.plan",
107
107
  "stage.spec-architecture"
108
108
  ],
109
109
  "draft_artifact_ids": [
110
- "artifact.discovery-record",
110
+ "artifact.plan-record",
111
111
  "artifact.spec"
112
112
  ],
113
113
  "core_skills": [
@@ -137,7 +137,7 @@
137
137
  "contract_version": 1,
138
138
  "title": "YSS 产品经理",
139
139
  "stages": [
140
- "stage.discovery",
140
+ "stage.plan",
141
141
  "stage.spec-architecture",
142
142
  "stage.product-design",
143
143
  "stage.verification-release-retrospective"
@@ -177,7 +177,7 @@
177
177
  "title": "YSS 项目经理",
178
178
  "stages": [
179
179
  "stage.entry-triage",
180
- "stage.discovery",
180
+ "stage.plan",
181
181
  "stage.spec-architecture",
182
182
  "stage.product-design",
183
183
  "stage.system-data-engineering",
@@ -346,9 +346,9 @@
346
346
  ],
347
347
  "stage_groups": [
348
348
  {
349
- "id": "group.discovery",
349
+ "id": "group.plan",
350
350
  "name": "Discovery",
351
- "stage": "stage.discovery",
351
+ "stage": "stage.plan",
352
352
  "members": [
353
353
  "role.lifecycle-orchestrator",
354
354
  "role.requirements-manager",
@@ -0,0 +1,30 @@
1
+ // Synthetic test evidence only; never import to produce real project approval.
2
+ import { mkdirSync, writeFileSync, readFileSync } from 'node:fs';
3
+ import path from 'node:path';
4
+ import { ROOT } from '../../lib/lifecycle-registry.mjs';
5
+ import { parseContextContract, resolveContextTermRefs } from '../../lib/context-contract.mjs';
6
+ import { decisionDigest } from '../../lib/user-decision.mjs';
7
+ import { planEntryPolicy } from '../../lib/plan-spec-entry.mjs';
8
+ import { buildDecisionFixture } from './build-fixture.mjs';
9
+
10
+ export function buildPlanFixture(root) {
11
+ mkdirSync(path.join(root, 'docs/process'), { recursive: true });
12
+ const write = (ref, value) => writeFileSync(path.resolve(root, ref), typeof value === 'string' ? value : JSON.stringify(value, null, 2));
13
+ write('yss-project.yaml', 'schema_version: 1\nrepository_mode: project-instance\n');
14
+ for (const ref of ['CONTEXT.md', 'docs/process/lifecycle-registry.yaml']) write(ref, readFileSync(path.join(ROOT, ref), 'utf8'));
15
+ write('plan.md', '测试规划:小范围修订,不改变业务边界或关键规则。\n');
16
+ const c = parseContextContract({ root });
17
+ write('reconciliation.json', { schema_version: 1, repository_mode: 'project-instance', stage: 'stage.plan', work_unit: 'work-unit.plan-requirements', status: 'reconciled', context_snapshot: { context_ref: c.context_ref, context_schema_version: c.context_schema_version, document_digest: c.document_digest, referenced_terms_digest: resolveContextTermRefs(c, []).referenced_terms_digest, term_refs: [] }, changes: { added: [], updated: [], deprecated: [] }, unresolved_terms: [], evidence_refs: ['CONTEXT.md'] });
18
+ const policy = planEntryPolicy({ root });
19
+ const review = { schema_version: 1, kind: 'plan-entry-review', feature_id: 'feature.demo', plan_ref: 'plan.md', context_reconciliation_ref: 'reconciliation.json', basis: ['plan.md', 'CONTEXT.md', 'docs/process/lifecycle-registry.yaml', 'reconciliation.json'].map(ref => ({ ref, digest: decisionDigest(readFileSync(path.join(root, ref))) })), checks: Object.fromEntries(policy.required_checks.map(id => [id, { status: 'passed', evidence_refs: ['plan.md'] }])), open_items: [], impacts: { domain_strategy: false, stage_decision: false }, gates: Object.fromEntries(Object.keys(policy.gate_impacts).map(id => [id, { status: 'not-applicable', reason: '本次仅修订已确认范围内的细节,不改变边界、规则或阶段合同', evidence_refs: ['plan.md'] }])) };
20
+ const reviewRef = path.join(root, 'review.json');
21
+ const save = () => write(reviewRef, review);
22
+ save();
23
+ const approval = buildDecisionFixture(path.join(root, 'approval'), { boundary: 'plan-conclusion', subjectRef: reviewRef });
24
+ const reapprove = () => {
25
+ save();
26
+ approval.record.request.items[0].subject.digest = decisionDigest(readFileSync(reviewRef));
27
+ approval.present(); approval.record.responses = []; approval.respond(); approval.save();
28
+ };
29
+ return { root, review, save, write, approval, reapprove, state: { feature_id: review.feature_id, plan_review_ref: reviewRef, plan_user_decision_ref: approval.ref, user_decisions: [approval.requirement] } };
30
+ }
@@ -81,10 +81,13 @@ function validManifest(manifest,root) {
81
81
  ensure(manifest.files.reduce((total,file)=>total+file.size_bytes,0)<=512*1024*1024,'后端包大小超限');
82
82
  const originals=manifest.files.filter(x=>x.original_ref).map(x=>x.original_ref);
83
83
  ensure(new Set(originals.map(x=>x.toLowerCase())).size===originals.length,'后端包源路径重复');
84
+ const captured = new Map();
84
85
  for(const file of manifest.files) {
85
86
  const bytes=readFileSync(safe(root,file.path));
86
87
  ensure(bytes.length===file.size_bytes&&hash(bytes)===file.sha256,`后端包文件摘要不一致: ${file.path}`);
88
+ captured.set(file.path, bytes);
87
89
  }
90
+ return captured;
88
91
  }
89
92
 
90
93
  export async function openBackendDelivery(input, action) {
@@ -93,9 +96,9 @@ export async function openBackendDelivery(input, action) {
93
96
  ensure(existsSync(input)&&!lstatSync(input).isSymbolicLink(),'后端交付包不存在或是 symlink');
94
97
  let root=path.resolve(input);
95
98
  if(lstatSync(root).isFile()) { root=path.join(temporary,'unpacked');mkdirSync(root);archive('unpack',path.resolve(input),root); }
96
- const manifest=read(safe(root,'manifest.json'));validManifest(manifest,root);
99
+ const manifest=read(safe(root,'manifest.json'));const captured=validManifest(manifest,root);
97
100
  const source=path.join(temporary,'source');mkdirSync(source);
98
- for(const file of manifest.files)if(file.original_ref)write(source,file.original_ref,readFileSync(safe(root,file.path)));
101
+ for(const file of manifest.files)if(file.original_ref)write(source,file.original_ref,captured.get(file.path));
99
102
  const inspected=await inspectBackendDelivery(source,manifest.delivery_ref);
100
103
  ensure(manifest.delivery_id===inspected.delivery.delivery_id&&manifest.version===inspected.delivery.version,'后端包身份不一致');
101
104
  return await action({root,source,manifest,...inspected});
@@ -0,0 +1,107 @@
1
+ import { spawn, spawnSync } from "node:child_process";
2
+ import { appendFileSync, rmSync, writeFileSync } from "node:fs";
3
+ import { StringDecoder } from "node:string_decoder";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ function killTree(child, signal) {
7
+ if (!child.pid) return;
8
+ try {
9
+ if (process.platform === "win32") spawnSync("taskkill", ["/PID", String(child.pid), "/T", "/F"], { stdio: "ignore" });
10
+ else process.kill(-child.pid, signal);
11
+ } catch (error) { if (error.code !== "ESRCH") throw error; }
12
+ }
13
+
14
+ /** Bounded lifetime for external tools; stdout is never mixed with progress. */
15
+ export function runCommand(command, args, { cwd, env = process.env, timeoutMs = 0, signal, stdoutFile, stderrFile, secrets = [], progress = false } = {}) {
16
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) throw new TypeError("timeoutMs 必须是非负毫秒数");
17
+ if (signal?.aborted) return Promise.resolve({ status: 1, stdout: "", stderr: "command cancelled", termination: "cancelled", duration_ms: 0 });
18
+ return new Promise(resolve => {
19
+ const started = performance.now();
20
+ const argumentSecrets = args.flatMap(value => { try { const url = new URL(value); return url.password ? [url.password, decodeURIComponent(url.password)] : []; } catch { return []; } });
21
+ const secretNames = new Map(Object.entries(env).filter(([key]) => /(?:PASSWORD|TOKEN|SECRET)$/.test(key) || key === "MAVEN_REPO_USERNAME").map(([key,value]) => [value,key]));
22
+ const replacement = secret => secretNames.has(secret) ? `[REDACTED:${secretNames.get(secret)}]` : "[REDACTED]";
23
+ const sensitive = [...secrets, ...argumentSecrets, ...secretNames.keys()].filter(value => typeof value === "string" && value.length > 0).sort((a, b) => b.length - a.length);
24
+ const redact = text => sensitive.reduce((value, secret) => value.replaceAll(secret, replacement(secret)), text);
25
+ if (progress) process.stderr.write(`[开始] ${redact(command + " " + args.join(" "))}\n`);
26
+ for (const file of [stdoutFile, stderrFile]) if (file) writeFileSync(file, "");
27
+ const child = spawn(command, args, { cwd, env, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"] });
28
+ let termination = null, escalation, timer, errorMessage;
29
+ const makeStream = file => {
30
+ const decoder = new StringDecoder("utf8");
31
+ let pending = "", captured = "";
32
+ const emit = text => { captured += text; if (file) appendFileSync(file, text); };
33
+ function consume(final = false) {
34
+ let output = "", cursor = 0;
35
+ while (cursor < pending.length) {
36
+ const match = sensitive.find(secret => pending.startsWith(secret, cursor));
37
+ if (match) { output += replacement(match); cursor += match.length; continue; }
38
+ if (!final && sensitive.some(secret => secret.startsWith(pending.slice(cursor)))) break;
39
+ output += pending[cursor++];
40
+ }
41
+ pending = pending.slice(cursor);
42
+ emit(output);
43
+ }
44
+ return { write(bytes) { pending += decoder.write(bytes); consume(); }, end() { pending += decoder.end(); consume(true); return captured; } };
45
+ };
46
+ const stdout = makeStream(stdoutFile), stderr = makeStream(stderrFile);
47
+ function cancel(reason) {
48
+ if (termination) return;
49
+ termination = reason;
50
+ killTree(child, "SIGTERM");
51
+ escalation = setTimeout(() => killTree(child, "SIGKILL"), 1000);
52
+ }
53
+ const abort = () => cancel("cancelled");
54
+ const onInterrupt = () => cancel("cancelled");
55
+ signal?.addEventListener("abort", abort, { once: true });
56
+ process.on("SIGINT", onInterrupt); process.on("SIGTERM", onInterrupt);
57
+ if (timeoutMs) timer = setTimeout(() => cancel("timeout"), timeoutMs);
58
+ child.stdout.on("data", bytes => stdout.write(bytes));
59
+ child.stderr.on("data", bytes => stderr.write(bytes));
60
+ child.on("error", error => { errorMessage = redact(error.message); });
61
+ child.on("close", (code, exitSignal) => {
62
+ clearTimeout(timer); clearTimeout(escalation);
63
+ // A group leader can exit before its descendants close redirected streams.
64
+ if (termination) killTree(child, "SIGKILL");
65
+ signal?.removeEventListener("abort", abort);
66
+ process.off("SIGINT", onInterrupt); process.off("SIGTERM", onInterrupt);
67
+ const duration_ms = performance.now() - started;
68
+ const status = termination === "timeout" ? 124 : termination ? 1 : code ?? 1;
69
+ if (progress) process.stderr.write(`[${status === 0 ? "完成" : "失败"}] ${command} (${Math.round(duration_ms)}ms, exit=${status}${termination ? `, ${termination}` : ""})\n`);
70
+ resolve({ status, stdout: stdout.end(), stderr: stderr.end() + (errorMessage || ""), signal: exitSignal, termination, duration_ms });
71
+ });
72
+ });
73
+ }
74
+
75
+ // Synchronous API compatibility for existing generators/cache consumers. The worker
76
+ // owns the process group and streams logs; it never updates project metadata.
77
+ export function runCommandSync(command, args, options = {}) {
78
+ const result = spawnSync(process.execPath, [fileURLToPath(import.meta.url), "--worker"], {
79
+ input: JSON.stringify({ command, args, options }), encoding: "utf8", maxBuffer: 64 * 1024 * 1024,
80
+ stdio: ["pipe", "pipe", "inherit"], env: options.env ?? process.env,
81
+ });
82
+ if (result.error || result.status !== 0) throw new TypeError(result.error?.message || "command worker failed");
83
+ return JSON.parse(result.stdout);
84
+ }
85
+
86
+ if (process.argv[1] === fileURLToPath(import.meta.url) && process.argv[2] === "--worker") {
87
+ const parent = process.ppid;
88
+ let input = "";
89
+ for await (const bytes of process.stdin) input += bytes;
90
+ const { command, args, options } = JSON.parse(input);
91
+ const controller = new AbortController();
92
+ const watchParent = setInterval(() => {
93
+ if (process.ppid !== parent) controller.abort();
94
+ else {
95
+ try { process.kill(parent, 0); } catch (error) { if (error.code === "ESRCH") controller.abort(); }
96
+ }
97
+ }, 100);
98
+ try {
99
+ const result = await runCommand(command, args, { ...options, signal: controller.signal });
100
+ if (result.status !== 0) {
101
+ // Only caller-created temporary resources are supplied here. The worker
102
+ // also owns this cleanup when a terminated synchronous caller cannot run finally.
103
+ for (const directory of options.cleanupPathsOnFailure || []) rmSync(directory, { recursive: true, force: true });
104
+ }
105
+ if (process.ppid === parent) process.stdout.write(JSON.stringify(result));
106
+ } finally { clearInterval(watchParent); }
107
+ }
@@ -0,0 +1,34 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { parseDocument } from "../vendor/yaml.mjs";
4
+ import { resolveContextTermRefs, verifyContextSnapshot } from "./context-contract.mjs";
5
+ import { validateJsonSchema } from "./json-schema.mjs";
6
+ const schemaPath = path.resolve(import.meta.dirname, "../../docs/process/schemas/context-reconciliation.schema.json");
7
+ export function parseReconciliationFile(file) {
8
+ const document = parseDocument(readFileSync(file, "utf8"), { maxAliasCount: 0, uniqueKeys: true });
9
+ if (document.errors.length) throw new TypeError(document.errors[0].message);
10
+ return document.toJS({ maxAliasCount: 0 });
11
+ }
12
+
13
+ export function verifyContextReconciliation(file, { root = process.cwd() } = {}) {
14
+ root = path.resolve(root);
15
+ const value = parseReconciliationFile(path.resolve(file));
16
+ validateJsonSchema(value, schemaPath, { formatChecker: false });
17
+ const manifest = parseReconciliationFile(path.join(root, "yss-project.yaml"));
18
+ if (value.repository_mode !== manifest.repository_mode) throw new TypeError("repository_mode 必须与根目录 yss-project.yaml 一致");
19
+ const contract = verifyContextSnapshot(value.context_snapshot, { root });
20
+ const changedRefs = [...value.changes.added, ...value.changes.updated, ...value.changes.deprecated];
21
+ resolveContextTermRefs(contract, changedRefs);
22
+ if (new Set(changedRefs).size !== changedRefs.length) throw new TypeError("changes 中的术语引用不得跨分类重复");
23
+ if (value.repository_mode === "project-instance" && value.status !== "reconciled") throw new TypeError("project-instance 工作单元只有 status=reconciled 才允许批准或进入下一步");
24
+ if (value.status === "reconciled" && value.unresolved_terms.length) throw new TypeError("reconciled 不得包含 unresolved_terms");
25
+ if (value.status === "blocked" && value.unresolved_terms.length === 0) throw new TypeError("blocked 必须说明 unresolved_terms");
26
+ if (value.status === "not-applicable" && (value.repository_mode !== "template-source" || !value.reason)) throw new TypeError("not-applicable 只适用于 template-source 且必须说明 reason");
27
+ for (const ref of value.evidence_refs) {
28
+ if (/^https?:\/\//.test(ref)) continue;
29
+ const resolved = path.resolve(root, ref);
30
+ if (!resolved.startsWith(`${root}${path.sep}`) && resolved !== root) throw new TypeError(`evidence_ref 越出仓库: ${ref}`);
31
+ if (!existsSync(resolved)) throw new TypeError(`evidence_ref 不可读: ${ref}`);
32
+ }
33
+ return contract;
34
+ }