create-yss-spec 3.5.4 → 3.5.5

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 (104) hide show
  1. package/README.md +8 -0
  2. package/cli-core.lock.json +130 -0
  3. package/package.json +7 -3
  4. package/resources/upgrade-skill/SKILL.md +26 -0
  5. package/resources/upgrade-skill/protocol.md +40 -0
  6. package/resources/upgrade-skill/references/cli-families.md +14 -0
  7. package/src/cli/help.js +1 -0
  8. package/src/cli/index.js +12 -0
  9. package/src/filesystem/transaction-runner.js +27 -0
  10. package/src/template/asset-runtime.js +6 -0
  11. package/src/template/verification-runtime.js +9 -1
  12. package/template/.agents/skills/.strategic-design-skills-manifest.json +2 -2
  13. package/template/.agents/skills/yss-harness-upgrade/SKILL.md +26 -0
  14. package/template/.agents/skills/yss-harness-upgrade/references/cli-families.md +14 -0
  15. package/template/.agents/skills/yss-implementation-contract-compiler/references/boundaries.md +1 -0
  16. package/template/.agents/skills/yss-product-lifecycle/SKILL.md +15 -19
  17. package/template/.agents/skills/yss-stage-decision/SKILL.md +3 -0
  18. package/template/.agents/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +8 -4
  19. package/template/.agents/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +8 -4
  20. package/template/.agents/skills/yss-stage-decision/tests/run-scenarios.mjs +13 -1
  21. package/template/.codex/skills/yss-harness-upgrade/SKILL.md +26 -0
  22. package/template/.codex/skills/yss-harness-upgrade/references/cli-families.md +14 -0
  23. package/template/.codex/skills/yss-implementation-contract-compiler/references/boundaries.md +1 -0
  24. package/template/.codex/skills/yss-product-lifecycle/SKILL.md +15 -19
  25. package/template/.codex/skills/yss-stage-decision/SKILL.md +3 -0
  26. package/template/.codex/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +8 -4
  27. package/template/.codex/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +8 -4
  28. package/template/.codex/skills/yss-stage-decision/tests/run-scenarios.mjs +13 -1
  29. package/template/.cursor/skills/yss-harness-upgrade/SKILL.md +26 -0
  30. package/template/.cursor/skills/yss-harness-upgrade/references/cli-families.md +14 -0
  31. package/template/.cursor/skills/yss-implementation-contract-compiler/references/boundaries.md +1 -0
  32. package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +15 -19
  33. package/template/.cursor/skills/yss-stage-decision/SKILL.md +3 -0
  34. package/template/.cursor/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +8 -4
  35. package/template/.cursor/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +8 -4
  36. package/template/.cursor/skills/yss-stage-decision/tests/run-scenarios.mjs +13 -1
  37. package/template/.pi/skills/yss-harness-upgrade/SKILL.md +26 -0
  38. package/template/.pi/skills/yss-harness-upgrade/references/cli-families.md +14 -0
  39. package/template/.pi/skills/yss-implementation-contract-compiler/references/boundaries.md +1 -0
  40. package/template/.pi/skills/yss-product-lifecycle/SKILL.md +15 -19
  41. package/template/.pi/skills/yss-stage-decision/SKILL.md +3 -0
  42. package/template/.pi/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +8 -4
  43. package/template/.pi/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +8 -4
  44. package/template/.pi/skills/yss-stage-decision/tests/run-scenarios.mjs +13 -1
  45. package/template/.template-spec/agents/yss-skill-registry.yaml +9 -1
  46. package/template/.template-spec/process/contract-reading.md +1 -1
  47. package/template/.template-spec/process/document-writing.md +12 -0
  48. package/template/.template-spec/process/harness-upgrade.md +40 -0
  49. package/template/.template-spec/process/lifecycle-artifact-map.md +2 -2
  50. package/template/.template-spec/process/lifecycle-registry.yaml +3 -1
  51. package/template/.template-spec/process/schemas/approval-record.schema.json +23 -0
  52. package/template/.template-spec/process/stage-tracking.md +2 -2
  53. package/template/.template-spec/process/structured-assets.md +35 -0
  54. package/template/.template-spec/process/templates/lifecycle-checkpoint-template.json +48 -0
  55. package/template/.template-spec/templates/approval-record-template.json +23 -0
  56. package/template/scripts/check-plan-stage-coverage +12 -0
  57. package/template/scripts/contract +6 -0
  58. package/template/scripts/lib/approval-record.mjs +4 -3
  59. package/template/scripts/lib/asset-command.mjs +35 -0
  60. package/template/scripts/lib/asset-migration.mjs +101 -0
  61. package/template/scripts/lib/asset-transactions.mjs +235 -0
  62. package/template/scripts/lib/checkpoint-boundary.mjs +3 -0
  63. package/template/scripts/lib/contract-views.mjs +7 -1
  64. package/template/scripts/lib/json-schema.mjs +43 -4
  65. package/template/scripts/lib/lifecycle-context-query.mjs +7 -0
  66. package/template/scripts/lib/lifecycle-presentation.mjs +77 -0
  67. package/template/scripts/lib/lifecycle-status.mjs +16 -1
  68. package/template/scripts/lib/plan-stage-coverage.mjs +40 -0
  69. package/template/scripts/lib/reading-view-bundle.mjs +1 -0
  70. package/template/scripts/lib/reading-view-markdown.mjs +8 -6
  71. package/template/scripts/lib/stage-tracking-migration.mjs +11 -3
  72. package/template/scripts/lib/structured-assets.mjs +81 -0
  73. package/template/scripts/lib/task-package.mjs +4 -1
  74. package/template/scripts/lifecycle-status +6 -3
  75. package/template/scripts/verify-lifecycle-checkpoint +8 -5
  76. package/template/skills-lock.json +21 -9
  77. package/template.manifest.json +2 -1
  78. package/template.snapshot.json +5 -5
  79. package/vendor/cli-core/build.mjs +302 -0
  80. package/vendor/cli-core/bundle.mjs +198 -0
  81. package/vendor/cli-core/cli.mjs +182 -0
  82. package/vendor/cli-core/command-runner.mjs +107 -0
  83. package/vendor/cli-core/engine.mjs +239 -0
  84. package/vendor/cli-core/family.mjs +28 -0
  85. package/vendor/cli-core/gitignore.mjs +15 -0
  86. package/vendor/cli-core/identity.mjs +274 -0
  87. package/vendor/cli-core/io.mjs +153 -0
  88. package/vendor/cli-core/layout-migration.mjs +64 -0
  89. package/vendor/cli-core/legacy.mjs +19 -0
  90. package/vendor/cli-core/migrate.mjs +237 -0
  91. package/vendor/cli-core/migration-adapter.mjs +19 -0
  92. package/vendor/cli-core/package.json +13 -0
  93. package/vendor/cli-core/scaffold.mjs +117 -0
  94. package/vendor/cli-core/spec-migration-adapter.mjs +83 -0
  95. package/vendor/cli-core/tests/build.test.mjs +40 -0
  96. package/vendor/cli-core/tests/cli.test.mjs +1065 -0
  97. package/vendor/cli-core/tests/migration-version.test.mjs +8 -0
  98. package/vendor/cli-core/tests/package-contract.mjs +75 -0
  99. package/vendor/cli-core/transaction.mjs +529 -0
  100. package/vendor/cli-core/update.mjs +79 -0
  101. package/vendor/cli-core/vendor/NOTICES.md +6 -0
  102. package/vendor/cli-core/vendor/yaml.LICENSE +13 -0
  103. package/vendor/cli-core/vendor/yaml.mjs +6311 -0
  104. package/vendor/cli-core/verification.mjs +131 -0
@@ -7,27 +7,27 @@ description: 编排 YSS 研发全生命周期;当阶段、产物、门禁或 S
7
7
 
8
8
  合同阅读与托管更新:`scripts/contract view|render|check-views`;见 `.template-spec/process/contract-reading.md`。
9
9
 
10
- 文档按 `document_writing` 条件调用 `i-have-adhd`,并传递 `.template-spec/process/document-writing.md` 规范。
10
+ 五类机器资产默认 JSON;读写、迁移及恢复须遵循 `.template-spec/process/structured-assets.md`。
11
11
 
12
- ## 事实源与按需加载
12
+ 文档及进度按 `document_writing` 调用 `i-have-adhd`,遵循 `.template-spec/process/document-writing.md`;正文用中文名称与动作,编号按需追踪。
13
13
 
14
- 先读 `yss-project.yaml`、`AGENTS.md`、`CONTEXT.md` 和当前任务视图,按需加载合同子树:
14
+ ## 事实源
15
+
16
+ 先读 `yss-project.yaml`、`AGENTS.md`、`CONTEXT.md` 和当前任务视图,按需读合同:
15
17
 
16
18
  | 事实 | 权威来源 |
17
19
  |---|---|
18
- | 阶段、聚合门禁、内部检查、产物、工作单元、证据和稳定 ID | `.template-spec/process/lifecycle-registry.yaml` |
19
- | 执行模式、流转、readiness、暂停、结果和授权语义 | `references/orchestration-contract.yaml` |
20
- | Skill 身份、capability、依赖和路由 | `.template-spec/agents/yss-skill-registry.yaml` |
20
+ | 阶段、门禁、产物、工作单元、证据及 ID | `.template-spec/process/lifecycle-registry.yaml` |
21
+ | 执行、流转和授权合同 | `references/orchestration-contract.yaml` |
22
+ | Skill 身份、能力、依赖和路由 | `.template-spec/agents/yss-skill-registry.yaml` |
21
23
  | 数字人角色、运行时和会签策略 | `.template-spec/agents/digital-human-roles.yaml` |
22
- | 影响面、裁剪和模板维护强度 | `.template-spec/process/harness-process-tailoring.md`、`.template-source/process/maintenance-intensity.yaml` |
23
-
24
- 查询合同:
24
+ | 影响面、裁剪与维护强度 | `.template-spec/process/harness-process-tailoring.md`、`.template-source/process/maintenance-intensity.yaml` |
25
25
 
26
26
  ```bash
27
27
  scripts/query-lifecycle-context --mode route --stage stage.plan --work-unit work-unit.plan-requirements --include execution_efficiency
28
28
  ```
29
29
 
30
- `--include` 接受合同顶层键,非法键或 ID 失败。按需读 `references/orchestration.md` 及索引,证据充分即停止加载。
30
+ `--include` 接受合同顶层键,非法输入失败。详见 `references/orchestration.md`。
31
31
 
32
32
  按 `execution_efficiency` 合并查询、复用未变资料;仍核验当前资产、词汇和门禁,产品流转不重跑模板套件。
33
33
 
@@ -71,27 +71,21 @@ Plan 入口读取 `.template-spec/plan/README.md` 和 `.template-spec/process/pl
71
71
  3. 原生工作单元由主控持有正式资产;专项按结构化任务包派发,只调用合同允许的 model-invoked skill。
72
72
  4. `to-spec`、`to-tickets`、`implement` 等兼容入口只可由用户显式调用。主控预检输入、路径和门禁;入口按 `matt_invocation_boundary` 写入其产物并回交验收,不批准或改变 Ticket 就绪状态。原生资产仍归主控。
73
73
  5. 先逐项验收用户目标、遗漏、错误假设和未决问题,再验收 `Workflow Execution Result`:工作单元、合同、允许写路径、`context_reconciliation`、证据、实际验证、延期 seam、漂移和下一路由必须可核验。实现派发额外绑定当前 Slice Implementation Contract v3;其他阶段不得伪造该合同。
74
- 6. 在授权边界内继续下一工作单元;遇到人工决定、新授权、证据冲突、专项失败或合并/发布结论时暂停。暂停不得阻断无依赖的独立工作。
74
+ 6. 在授权边界内继续下一工作单元;遇到人工决定、新授权、证据冲突、专项失败或合并/发布结论时暂停。暂停不得阻断独立工作。
75
75
 
76
76
  每个 `project-instance` 工作单元批准或流转前,回写稳定术语到唯一根 `CONTEXT.md`,并生成通过校验的 `context_reconciliation`。候选术语、错误路径、摘要漂移或未决冲突必须阻断。质量标准只由 `engineering-baseline` 定义一次;高风险影响按裁剪合同补充反证和残余风险。
77
77
 
78
78
  ## 面向业务角色
79
79
 
80
- 使用业务语言推进:
81
-
82
- `机会与目标 → 业务故事 → 责任与交接 → 规则、例子与疑问 → 可验收需求 → 页面验证 → 业务任务 → 交接研发`
83
-
84
80
  澄清目标、流程、责任、规则、范围和验收例子。业务总览引用权威资产,展示状态、未决项、责任人和下一步,不复制正文或新增门禁。
85
81
 
86
82
  Plan → Spec(含正式草稿、恢复与显式 `to-spec`)写入前,按 `.template-spec/plan/entry-review.md` 持久化审阅包并运行 `node scripts/verify-plan-spec-entry <state.yaml>`。检查默认 pending,缺项、过期或无真实回复即阻断;独立调研可继续。
87
83
 
88
84
  ## 结果与暂停
89
85
 
90
- 咨询直接回答;工作单元留证并展示当前决定。
91
-
92
- 结果包含:模式、仓库身份、阶段/工作单元、影响面、资产/门禁/Ticket/Slice/合同状态、证据及新鲜度、`ready-for-agent`、阻塞、本轮动作、下一单元、暂停/继续理由、Ticket 同步和 Git checkpoint。
86
+ 结构化结果保留模式、仓库身份、阶段/工作单元、影响面、资产/门禁/Ticket/Slice/合同状态、证据新鲜度、就绪、阻塞、本轮动作、下一单元、暂停理由、Ticket 同步和 Git checkpoint;用户说明按中文写作规范呈现。
93
87
 
94
- 暂停会签时追加门禁 ID、`role_id`、`runtime_id`、会签文件路径、推荐答案和恢复动作;恢复前运行适用验证器。只有同一候选快照通过全部适用审查轴与 fresh verification,才能提出合并、发布或完成结论;发布仍须生物人决定。
88
+ 会签记录保留门禁 ID、`role_id`、`runtime_id`、文件路径、推荐答案和恢复动作;用户提示解释待决定事项与责任方。恢复前运行适用验证器。同一候选通过适用审查与 fresh verification 才可提出完成、合并或发布结论;发布仍须生物人决定。
95
89
 
96
90
  Plan / Spec / Design 追踪按 `.template-spec/process/stage-tracking.md`。
97
91
 
@@ -102,3 +96,5 @@ Spec 起草业务票,Design 校准后正式化;无设计影响直接正式
102
96
  ## 功能资产整理
103
97
 
104
98
  整理与旧票迁移先读 `.template-spec/process/feature-assets.md`,只按显式候选计划处理,保留状态、批准依据和原文;不得推进阶段。临时输入与草稿放临时工作区,引用后按正式资产保留。
99
+
100
+ 既有 YSS 实例的模板版本升级、旧治理布局迁移或升级恢复路由到 `yss-harness-upgrade`,按 `.template-spec/process/harness-upgrade.md` 执行;不由升级动作推进产品阶段或重写历史批准。
@@ -38,6 +38,9 @@ Plan 成功标准在既有 `success_criteria[].statement` 细化指标定义、
38
38
 
39
39
  ## 控制面引用
40
40
 
41
+ - 新建领域战略、阶段决策包使用 JSON;存量 YAML 保持只读兼容,显式迁移见 `.template-spec/process/structured-assets.md`。使用 `scripts/contract plan-write/apply-write` 结构化落盘,不对合同作字符串拼接。校验器必须执行权威 Schema 后再检查跨文件语义。
42
+ - 复用 Plan 原始决定编号,不自行重排;批准前用 `scripts/check-plan-stage-coverage` 生成绑定 Plan、决定记录和阶段包摘要的逐项对照证据,非目标使用显式映射。无法提取、缺项或映射歧义必须补齐;语义等价仍由独立评审确认,覆盖检查不构成批准。
43
+
41
44
  - 用户决定遵循 [用户决定协议](../yss-product-lifecycle/references/user-decisions.md):决定必须绑定资产、版本、范围和证据;范围、风险、摘要或失效条件变化后重新确认。
42
45
  - checkpoint 是唯一机器状态源,业务 Ticket 只保存追踪引用,不复制阶段状态。
43
46
  - 每次批准、重发和消费者流转前执行 `context_reconciliation`,核验 `CONTEXT.md` 的全文与引用术语双摘要。
@@ -1,10 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import { readFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { assertAssetTransactionIdle, assertCurrentAssetReference } from "../../../../scripts/lib/asset-transactions.mjs";
3
5
  import process from "node:process";
4
6
  import { parseArgs } from "node:util";
5
7
  import { parseDocument } from "../../../../scripts/vendor/yaml.mjs";
6
8
  import { loadApprovalRecord, resolveApprovalRef, validateApprovalRecord } from "../../../../scripts/lib/approval-record.mjs";
7
9
  import { verifyContextSnapshot } from "../../../../scripts/lib/context-contract.mjs";
10
+ import { parseAsset, validateAssetStructure } from '../../../../scripts/lib/structured-assets.mjs';
8
11
 
9
12
  import { extractTraceability } from "../../../../scripts/lib/strategic-handoff-rules.mjs";
10
13
 
@@ -49,6 +52,7 @@ function requireArray(object, field, path, errors, min = 0, itemKind = "string")
49
52
  }
50
53
 
51
54
  function validate(data, contextRoot) {
55
+ validateAssetStructure(data, 'domain-strategy');
52
56
  const errors = [];
53
57
  if (data?.traceability_version !== undefined) { try { extractTraceability(data); } catch(error) { errors.push(error.message); } }
54
58
  if (!data || typeof data !== "object" || Array.isArray(data)) return ["合同必须是对象"];
@@ -210,11 +214,11 @@ const file = positionals[0];
210
214
  if (!file) fail(["用法: validate-domain-strategy.mjs <contract.yaml> [--root <project-root>]"]);
211
215
  else {
212
216
  try {
217
+ assertAssetTransactionIdle(values.root);
218
+ assertCurrentAssetReference(values.root, path.relative(path.resolve(values.root), path.resolve(file)));
213
219
  const source = await readFile(file, "utf8");
214
- const document = parseDocument(source, { maxAliasCount: 0, uniqueKeys: true });
215
- if (document.errors.length) fail([document.errors[0].message]);
216
- else {
217
- const errors = validate(document.toJS({ maxAliasCount: 0 }), values.root);
220
+ {
221
+ const errors = validate(parseAsset(source, file), values.root);
218
222
  if (errors.length) fail(errors);
219
223
  else process.stdout.write(JSON.stringify({ result: "completed", contract: file }, null, 2) + "\n");
220
224
  }
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { readFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { assertAssetTransactionIdle, assertCurrentAssetReference } from "../../../../scripts/lib/asset-transactions.mjs";
3
5
  import { createHash } from "node:crypto";
4
6
  import { resolve } from "node:path";
5
7
  import process from "node:process";
@@ -7,6 +9,7 @@ import { parseArgs } from "node:util";
7
9
  import { parseDocument } from "../../../../scripts/vendor/yaml.mjs";
8
10
  import { loadApprovalRecord, resolveApprovalRef, validateApprovalRecord } from "../../../../scripts/lib/approval-record.mjs";
9
11
  import { verifyContextSnapshot } from "../../../../scripts/lib/context-contract.mjs";
12
+ import { parseAsset, validateAssetStructure } from '../../../../scripts/lib/structured-assets.mjs';
10
13
 
11
14
  const required = ["schema_version", "stage_decision_id", "package_version", "status", "problem_statement", "target_users", "mvp", "non_goals", "success_criteria", "test_seams", "confirmed_decisions", "assumptions", "constraints", "unresolved_items", "context_snapshot", "domain_strategy_ref", "impact_assessment", "downstream_mapping", "evidence_refs", "approval"];
12
15
  const idPattern = /^stage-decision\.[a-z0-9][a-z0-9-]*$/;
@@ -25,6 +28,7 @@ function canonical(value) { if (Array.isArray(value)) return value.map(canonical
25
28
  function digest(value) { return `sha256:${createHash("sha256").update(JSON.stringify(canonical(value))).digest("hex")}`; }
26
29
 
27
30
  async function validate(data, contextRoot) {
31
+ validateAssetStructure(data, 'stage-decision-package');
28
32
  const errors = [];
29
33
  if (!data || typeof data !== "object" || Array.isArray(data)) return ["合同必须是对象"];
30
34
  if (data.schema_version === 1) return ["migration-required: stage decision package v1 必须迁移到 v2 context_snapshot"];
@@ -143,11 +147,11 @@ const file = positionals[0];
143
147
  if (!file) fail(["用法: validate-stage-decision-package.mjs <package.yaml> [--root <project-root>]"]);
144
148
  else {
145
149
  try {
150
+ assertAssetTransactionIdle(values.root);
151
+ assertCurrentAssetReference(values.root, path.relative(path.resolve(values.root), path.resolve(file)));
146
152
  const source = await readFile(file, "utf8");
147
- const document = parseDocument(source, { maxAliasCount: 0, uniqueKeys: true });
148
- if (document.errors.length) fail([document.errors[0].message]);
149
- else {
150
- const errors = await validate(document.toJS({ maxAliasCount: 0 }), values.root);
153
+ {
154
+ const errors = await validate(parseAsset(source, file), values.root);
151
155
  if (errors.length) fail(errors);
152
156
  else process.stdout.write(JSON.stringify({ result: "completed", contract: file }, null, 2) + "\n");
153
157
  }
@@ -200,6 +200,18 @@ try {
200
200
  await writeFile(packageFile, packageSource);
201
201
  const packagePass = run(packageValidator, packageFile, temporaryRoot);
202
202
  if (packagePass.status !== 0) throw new Error(`valid v3 stage decision package should pass: ${packagePass.stderr}`);
203
+ for (const format of ['yaml', 'json']) {
204
+ for (const [name, mutate, pattern] of [
205
+ ['record-note', p => {p.test_seams[0].note='undeclared';}, /Additional properties/],
206
+ ['mapping-note', p => {p.downstream_mapping[0].note='undeclared';}, /Additional properties/],
207
+ ['duplicate-source', p => p.test_seams[0].source_refs.push(p.test_seams[0].source_refs[0]), /non-unique/]
208
+ ]) {
209
+ const value = parseYaml(packageSource); mutate(value);
210
+ const file = join(temporaryRoot, `${name}.${format}`);
211
+ await writeFile(file, JSON.stringify(value, null, 2));
212
+ expectBlocked(run(packageValidator, file, temporaryRoot), pattern, `${name} ${format}`);
213
+ }
214
+ }
203
215
 
204
216
  const bundleFile = join(temporaryRoot, "plan-review-bundle.json");
205
217
  const bundledDomainValue = parseYaml(domainSource);
@@ -265,7 +277,7 @@ try {
265
277
  const wrongArrayValue = parseYaml(packageSource);
266
278
  wrongArrayValue.target_users = [42];
267
279
  await writeFile(packageWrongArray, JSON.stringify(wrongArrayValue, null, 2));
268
- expectBlocked(run(packageValidator, packageWrongArray, temporaryRoot), /target_users\[0\]/, "package non-string array item");
280
+ expectBlocked(run(packageValidator, packageWrongArray, temporaryRoot), /target_users(?:\[0\]|\.0)/, "package non-string array item");
269
281
  } finally {
270
282
  await rm(temporaryRoot, { recursive: true, force: true });
271
283
  }
@@ -8,7 +8,7 @@ description: >-
8
8
  canonical_content_root: .agents/skills
9
9
  instance_distribution:
10
10
  schema_version: 1
11
- initial_skills: [yss-product-lifecycle, yss-research, i-have-adhd]
11
+ initial_skills: [yss-product-lifecycle, yss-research, i-have-adhd, yss-harness-upgrade]
12
12
  runtimes: [codex, cursor, pi]
13
13
  projection_roots: { codex: .codex/skills, cursor: .cursor/skills, pi: .pi/skills }
14
14
  dependency_types_for_ensure: [context-required, context-conditional]
@@ -206,6 +206,8 @@ skill_dependencies:
206
206
  - { skill: i-have-adhd, type: context-conditional, when: lifecycle-document-output }
207
207
  yss-stage-decision:
208
208
  - { skill: i-have-adhd, type: context-conditional, when: lifecycle-document-output }
209
+ yss-harness-upgrade:
210
+ - { skill: i-have-adhd, type: context-conditional, when: lifecycle-document-output }
209
211
  yss-research:
210
212
  - { skill: i-have-adhd, type: context-conditional, when: lifecycle-document-output }
211
213
  yss-product-lifecycle:
@@ -466,6 +468,12 @@ skills:
466
468
  instance_default_discoverable: true
467
469
  aliases: []
468
470
  impacts: [prototype]
471
+ - id: yss-harness-upgrade
472
+ layer: core
473
+ maturity: supported
474
+ instance_default_discoverable: true
475
+ aliases: []
476
+ impacts: [lifecycle]
469
477
  - id: yss-research
470
478
  layer: core
471
479
  maturity: supported
@@ -1,6 +1,6 @@
1
1
  # 合同阅读、准备与显式迁移
2
2
 
3
- 本文件描述工具入口;阶段、批准和执行门禁仍由 `.template-spec/process/lifecycle-registry.yaml` 及资产所有者定义。YAML 是权威文件,视图不能编辑、批准合同或授予执行权限。
3
+ 本文件描述工具入口;阶段、批准和执行门禁仍由 `.template-spec/process/lifecycle-registry.yaml` 及资产所有者定义。显式引用的源资产是权威文件,视图不能编辑、批准合同或授予执行权限。五类生命周期资产的新建 JSON 与旧 YAML 兼容规则见 [结构化资产](structured-assets.md);Slice 等本轮未迁移合同继续使用原格式。
4
4
 
5
5
  ```sh
6
6
  scripts/contract view <资产> --kind <类型> [--profile review|task|full] [--unit <ID>] [--json]
@@ -61,6 +61,18 @@
61
61
 
62
62
  ## 4. 进度与会签提示
63
63
 
64
+ ### 将流程编号转成读者能理解的说明
65
+
66
+ 面向用户的正文先写中文名称和具体动作。名称读取当前项目的生命周期注册表(`public_name` 优先,其次 `name`),角色读取 `digital-human-roles.yaml` 的 `name`;输入、产出和完成条件同样优先使用对应 `public_*` 字段。可以消费查询结果的 `presentation.names`,不得另建手工翻译表。
67
+
68
+ `stage.*`、`work-unit.*`、`gate.*`、`check.*`、`artifact.*`、`evidence.*`、`role.*` 属于追踪编号。聊天正文不直接串接这些编号;需要追踪时放在名称后的括号、详情或证据引用里。JSON / YAML 字段、命令参数、路径、批准记录仍保存原值;阅读视图可用“名称(编号)”逐项对照。未知编号写“名称未识别”并保留原值,不能猜名称、静默省略或改写旧资产。
69
+
70
+ 说明应回答“目前什么情况、谁负责、接下来做什么、形成什么材料”。状态必须来自当前登记及验证,编号以 `approved` 结尾只表示检查身份;不能据此写“已批准”。负责人未登记时明确写出缺口,不能把角色候选当作实际指派。待核验、草案、批准、可实现分别表达,所有实质阻塞都要保留。
71
+
72
+ 例如,只有已登记需求经理负责且检查状态待核验时,才可表述:“方案决策包评审状态待核验。下一步由需求经理汇总已确认的规划、业务边界和商业约束,形成供评审和后续 Spec 使用的方案决策包。”具体材料的版本、证据和批准状态继续引用原资产。不能把这个例子当成真实项目状态。
73
+
74
+ 状态阅读可用 `scripts/lifecycle-status --root <项目> --checkpoint <ref> --format text`;默认 JSON 继续供工具读取。该查询及其中文展示均不授予执行或批准权限。
75
+
64
76
  仅在用户询问状态、阶段切换或出现阻塞时,简短展示四项信息:**当前阶段、当前阻塞、谁处理、下一动作**。可以用一句话或四行表达,不要求表格。普通问题直接回答;其他进度更新只说明本轮有意义的变化,状态未变时不重复整套说明。
65
77
 
66
78
  状态读取已有 checkpoint 和适用验证结果,不建立或要求用户填写另一套状态文件。未核验的阶段或阻塞情况写“待核验”;只有当前适用证据支持时才能写“无阻塞”。证据过期应明确指出过期输入及恢复动作,不能沿用历史通过结论。责任人按已有登记填写,缺失写“未登记”,不自行指派;下一动作说明如何补齐登记或核验。
@@ -0,0 +1,40 @@
1
+ # YSS 模板实例升级协议
2
+
3
+ 本协议定义 `yss-harness-upgrade` 与四类 YSS CLI 的同家族实例升级。技能负责判断、冲突方案和授权范围;CLI 负责计划校验、候选验证、持久归档、事务和恢复。历史批准及 Ticket 状态仍由各自权威协议管理。
4
+
5
+ ## 输入与接口
6
+
7
+ 固定精确 CLI 版本、包内容及模板快照,确认真实项目根、metadata/schema、profile、受管基线和 Git 状态。旧版本缺少受支持的基线/schema 时停止,不重新初始化。目标模板使用所执行 CLI 的内置快照;不在 apply 阶段查询 latest 或运行外部计划提供的脚本。
8
+
9
+ - `migrate plan --target-dir <绝对目录> --output <项目外全新文件> [--archive-dir <项目外全新目录>] [--migrate-layout] [--prune] [--resolutions <文件>]`:项目只读,在项目外生成固定计划;冲突返回机器可读诊断。
10
+ - `migrate apply --plan <文件> [--target-dir <同一目录>]`:显式执行。
11
+ - `migrate status --target-dir <目录>`:只读状态。
12
+ - `migrate recover|rollback --target-dir <目录> [--apply]`:默认只读预览,显式写入。
13
+
14
+ 所有命令接受 `--json`,输出 schemaVersion 1 JSON。失败非零退出;区分 `CONFLICT`、`STALE_PLAN`、`EXECUTOR`、`PLAN`、`ARCHIVE`、`INTERRUPTED`、`CONCURRENT`、`RECOVERY_FAILED` 等。原 CLI 命令及错误协议保持兼容。
15
+
16
+ ## 计划与冲突
17
+
18
+ 计划绑定 schemaVersion、事务 ID、时间、项目根、家族、执行器摘要、目标模板、归档位置、迁移选项、输入清单、Git HEAD/index/gitlink、规则 ID、操作前后内容/权限摘要和候选内容。整体 planDigest 检测意外修改;执行器还重新生成候选操作,不信任手改计划或重新计算摘要。摘要不等于授权。
19
+
20
+ 版本化规则 `managed-sync.v1`、`layout-migration.v1`、`retirement.v1` 复用各 CLI 原有身份/schema 范围和可信文件基线判定;后两者分别要求显式布局迁移与 prune。不凭名称或目录推断旧资产属于模板,不提供未知旧版本的猜测迁移。
21
+
22
+ `resolutions` 为路径到决议的 JSON 映射。每项包含 `action: preserve|merge`、`beforeDigest`、`templateDigest`;merge 另含候选字节的 `contentBase64`。只接受确实存在、有可信基线且可合并的受管冲突;未知路径、受保护资产、过期摘要或未消费决议拒绝。技能在项目外起草合并差异,新增语义决定取得用户回复后重新生成计划。CLI 不把决议文件当成人工批准。
23
+
24
+ 未修改受管文件自动更新。修改过的退出分发文件保留;`--prune` 只删除仍匹配旧基线的文件。项目拥有的 tracker、业务文档和已批准资产按现有保护规则保留;历史冻结和批准不会因路径移动获得新的有效性。
25
+
26
+ ## 归档、执行与恢复
27
+
28
+ 默认归档位置为 `~/.yss-harness/archives/<项目路径与家族摘要>/<事务ID>/`,可显式改为项目外全新目录。保存 plan.json、before/ 原字节与权限、receipt.json;首版不自动清理归档。布局迁移额外保存 project-copy/ 项目内容副本;不跟随符号链接,排除 Git 内部数据、依赖、索引缓存及事务状态,这些排除项不是迁移写入范围。Git 工作区和索引不重建、不 reset、不 stash。
29
+
30
+ 候选操作先在隔离副本中完成生成锁文件与实例校验。真实执行前重新核验输入,先归档并校验,再在互斥锁下写入。内部事务日志预写并持久化,文件、生成锁及 metadata 属于同一事务。既有业务文件和无关未提交/未跟踪工作保持;输入漂移要求新计划。
31
+
32
+ 内部 `.yss-harness-state/upgrade.json` 索引关联外部回执与事务。失败自动恢复本次写入;进程中断后 recover 校验事务和备份再恢复。成功提交但回执尚未完成的情况依据持久日志收敛状态。保留损坏、冲突及未恢复路径,不把恢复失败写成成功。
33
+
34
+ rollback 只针对索引中最近一次成功迁移,完整预检全部原件和升级后状态后才开始。任何后续修改、丢失或损坏备份都会阻断;不提供忽略冲突的 force。回退使用新的可恢复事务,不更改 CLI 安装版本。重复 apply 只有在同一计划已成功且结果仍匹配时才返回原回执;恢复或回退后的旧计划不复用。
35
+
36
+ ## 验证与结论
37
+
38
+ 校验身份、布局、Context、Skill 锁和投影等各家族现有实例合同;有失败不跳过。对未迁移资产与 Git index/HEAD/gitlink 做并发检查。迁移完成再规划,证明不会重复执行;计划保留项不是自动消失的冲突。
39
+
40
+ 回执说明实际版本、范围、归档、事务状态和验证结果。原有失败与新增失败分别说明;升级成功不表示产品阶段批准或发布就绪。提交、推送、发布及真实项目迁移均按会话授权,不由技能或计划摘要授予。
@@ -43,7 +43,7 @@
43
43
  | `check.frontend-delivery-inputs-verified` | 前端联合输入核验 | `stage.system-data-engineering` | 专职前端 profile 或显式 frontend_delivery 绑定的任务启动、恢复、合同编译、实现和验证;实际执行 scripts/verify-frontend-delivery,输入就绪不等于实现获批。 |
44
44
  | `check.repository-identity-valid` | 仓库身份校验 | `stage.entry-triage` | 每次进入流程。 |
45
45
  | `check.domain-strategy-approved` | 业务边界与规则评审 | `stage.plan` | 需要确定业务板块、业务责任区、统一业务词汇、协作关系或关键规则。 |
46
- | `check.stage-decision-package-approved` | 阶段决策包评审 | `stage.plan` | Plan 到 Spec 入口需要稳定的阶段决策合同。 |
46
+ | `check.stage-decision-package-approved` | 方案决策包评审 | `stage.plan` | Plan 到 Spec 入口需要稳定的阶段决策合同。 |
47
47
  | `check.prototype-reviewed` | 原型评审 | `stage.product-design` | 命中产品设计影响,且低保真页面、流程、状态或 API 反推需要独立评审。 |
48
48
  | `check.prototype-verified` | 原型交付物验证 | `stage.product-design` | 产品设计影响需要通过 H1/H2 原型交付物进行视觉或流程校准;真实组件验证留到前端实现阶段。 |
49
49
  | `check.openapi-draft-reviewed` | OpenAPI Draft Review | `stage.system-data-engineering` | 有 API 影响且 Draft 已生成。 |
@@ -99,7 +99,7 @@
99
99
  | `evidence.domain-strategy-review` | 业务边界与规则评审证据 | 业务板块、业务责任区、统一业务词汇、协作与交接关系、关键场景和不可违反规则的结构化评审结果。 |
100
100
  | `evidence.technical-design-review` | 技术设计评审证据 | 按已确认 DDD 或 MVC 架构审查规则与场景承接、分层、行为、一致性和测试边界。 |
101
101
  | `evidence.tactical-design-review` | DDD 战术设计评审证据 | 聚合、Entity、Value Object、不变量、状态机、一致性、Gateway 与 API 隔离的结构化评审结果。 |
102
- | `evidence.stage-decision-package` | 阶段决策包验证证据 | 阶段决策包的 Schema、引用、语义一致性、影响传播和下游消费验证结果。 |
102
+ | `evidence.stage-decision-package` | 方案决策包验证证据 | 阶段决策包的 Schema、引用、语义一致性、影响传播和下游消费验证结果。 |
103
103
  | `evidence.maintenance-intensity-checkpoint` | 模板维护强度 checkpoint | template-source 变更的 L1 / L2 / L3 分级、触发项、最低验证证据、review 模式和升级记录。 |
104
104
  | `evidence.repository-identity-check` | 仓库身份校验结果 | yss-project.yaml 的合法性与 repository_mode 裁决。 |
105
105
  | `evidence.approval-record` | 人工批准记录 | 对需要人工批准的 Spec、设计、契约或发布裁决的可追溯记录。 |
@@ -98,6 +98,7 @@ evidence:
98
98
  description: 聚合、Entity、Value Object、不变量、状态机、一致性、Gateway 与 API 隔离的结构化评审结果。
99
99
  - id: evidence.stage-decision-package
100
100
  name: 阶段决策包验证证据
101
+ public_name: 方案决策包验证证据
101
102
  description: 阶段决策包的 Schema、引用、语义一致性、影响传播和下游消费验证结果。
102
103
  - id: evidence.maintenance-intensity-checkpoint
103
104
  name: 模板维护强度 checkpoint
@@ -427,7 +428,7 @@ work_units:
427
428
  completion: 必填字段、引用、影响面和下游消费验证通过;批准门禁完成。
428
429
  public_name: 方案决策包综合
429
430
  public_input: Plan、业务边界与规则设计以及产品经理负责的商业约束输入。
430
- public_output: 带版本、digest、证据和下游映射的方案决策包。
431
+ public_output: 汇总规划结论、业务边界和商业约束,形成带版本、内容摘要、证据及后续 Spec 使用关系的方案决策包。
431
432
  - id: work-unit.spec-synthesis
432
433
  name: Spec 综合
433
434
  scope: project-instance
@@ -524,6 +525,7 @@ checks:
524
525
  - evidence.approval-record
525
526
  - id: check.stage-decision-package-approved
526
527
  name: 阶段决策包评审
528
+ public_name: 方案决策包评审
527
529
  stage: stage.plan
528
530
  trigger: Plan 到 Spec 入口需要稳定的阶段决策合同。
529
531
  evidence:
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://yss.dev/schemas/approval-record.schema.json",
4
+ "title": "YSS standalone approval record v1",
5
+ "type": "object",
6
+ "required": ["schema_version", "gate_id", "decision", "actor_kind", "role_id", "runtime_id", "principal_ref"],
7
+ "properties": {
8
+ "schema_version": {"const": 1},
9
+ "gate_id": {"type": "string", "minLength": 1},
10
+ "decision": {"enum": ["approved", "rejected", "vetoed"]},
11
+ "actor_kind": {"enum": ["digital-human", "biological-human", "orchestrator"]},
12
+ "role_id": {"type": "string", "minLength": 1},
13
+ "runtime_id": {"type": "string", "minLength": 1},
14
+ "principal_ref": {"type": "string", "minLength": 1},
15
+ "subject_ref": {"type": ["string", "null"]},
16
+ "subject_digest": {"type": ["string", "null"], "pattern": "^(sha256:)?[a-f0-9]{64}$"},
17
+ "approval_scope": {"type": "array", "items": {"type": "string", "minLength": 1}, "uniqueItems": true},
18
+ "biological_veto": {"type": "boolean"},
19
+ "evidence_refs": {"type": "array"},
20
+ "countersigner_role_ids": {"type": "array", "items": {"type": "string", "minLength": 1}}
21
+ },
22
+ "$comment": "Preserves the existing extensible record contract. Role, subject freshness, source and approval semantics are checked by approval-record.mjs."
23
+ }
@@ -31,9 +31,9 @@ checkpoint 的 `stage_tracking` 是阶段工作项当前进度的唯一机器状
31
31
 
32
32
  ```sh
33
33
  scripts/stage-tracking check --root <项目> --checkpoint docs/.scratch/<feature>/checkpoint.yaml
34
- scripts/stage-tracking plan --root <项目> --checkpoint docs/.scratch/<feature>/checkpoint.yaml --items <工作项数组.yaml> > <plan.json>
34
+ scripts/stage-tracking plan --root <项目> --checkpoint docs/.scratch/<feature>/checkpoint.json --items <工作项数组.yaml> > <plan.json>
35
35
  scripts/stage-tracking apply --root <项目> --plan <plan.json>
36
- scripts/stage-tracking plan --root <项目> --checkpoint docs/.scratch/<feature>/checkpoint.yaml --refresh > <refresh-plan.json>
36
+ scripts/stage-tracking plan --root <项目> --checkpoint docs/.scratch/<feature>/checkpoint.json --refresh > <refresh-plan.json>
37
37
  ```
38
38
 
39
39
  check / plan 不写项目。首次 checkpoint 不存在时,plan 从本项目 checkpoint 模板形成草稿。没有明确工作项时输出 gaps,apply 拒绝。items 只登记 pending 项,不把历史产物推断为完成,也不覆盖已有同 ID 项。
@@ -0,0 +1,35 @@
1
+ # 生命周期结构化资产
2
+
3
+ ## 格式与权威
4
+
5
+ 新建 checkpoint、domain-strategy、stage-decision-package、task-package、approval-record 默认使用 JSON。Plan、Spec、评审正文继续使用 Markdown;仓库身份、注册表、Skill frontmatter、Slice、原始用户决定与捕获来源不在本轮迁移范围。
6
+
7
+ 旧 YAML 继续读取。修改五类存量资产前显式迁移;历史验证、用户原文和旧批准原字节保留。迁移回执中的 source_to_target 标识原件为历史,当前消费者使用新显式引用;不能把目录里最后修改的文件当成权威。JSON 模板为当前入口,对应 YAML 模板仅供旧消费者兼容。
8
+
9
+ ## 读取和写入
10
+
11
+ `scripts/contract validate <相对路径> --kind <类型> --root <项目>` 执行严格解析、对应版本 Schema 和原消费者检查;`--structure-only` 明确只核验结构,不能作为批准或流转证据。类型为上述五类,checkpoint 使用 `checkpoint`。校验引擎不从网络获取 Schema;本地引用缺失、重复键、未知版本、非字符串键、别名、非有限数及无法无损表示的整数均失败。
12
+
13
+ `scripts/contract plan-write <目标.json> --kind <类型> --input <候选.json> --root <项目> --output <仓库外计划.json>` 生成可审阅计划;`apply-write <计划.json> --root <项目>` 重新核验输入、Schema 和消费者后执行。候选应由解析后的对象修改得到;禁止字符串拼接合同。命令不批准合同、不生成用户回复。批准记录不可覆盖,应另发新记录。
14
+
15
+ 写入前在隔离目录验证完整候选集合。计划绑定治理、工具和业务来源摘要;并发漂移即拒绝。受控写入使用排他锁、事务备份、临时文件回读与原子替换,事务信息保存在 `.yss/asset-transactions/`。多文件事务不是文件系统层面的整体原子操作;未完成事务阻断流转。`recover --root <项目>` 仅恢复本事务仍拥有的字节;活进程锁、后续编辑或损坏日志均不覆盖。
16
+
17
+ ## 显式迁移
18
+
19
+ 恢复自身也使用排他锁。若恢复进程被强杀留下 `recovery.lock`,工具保持阻断;需先核对记录 PID 已结束并保存事务目录,再清除该恢复锁重试,不能在活跃写入期间删除锁。
20
+
21
+ `scripts/contract plan-migrate <checkpoint.yaml> --root <项目> --output <仓库外迁移计划.json>` 沿当前引用发现五类资产,输出候选、来源摘要与阻断项,不写入产品资产。已完成任务包、历史结果、用户来源不转换。注释需审阅,原文保存在源文件和计划中;不静默丢掉仅存于注释的业务说明。
22
+
23
+ `apply-migrate <迁移计划.json> --root <项目> [--resolutions <处理证据.json>]` 在所有冲突解决后执行。处理证据含 `plan_id`、`items: [{ref, code, evidence_ref, evidence_digest}]` 和可选 `candidates: [{ref, kind, value}]`;只能覆盖计划内的候选,证据绑定当前字节。该记录仅证明处理依据可读;完整消费者校验与批准主体摘要核验仍执行,不能用它绕过批准。
24
+
25
+ 新资产的批准必须绑定新字节和独立评审者。沿用用户决定按既有授权延续协议核验;未经核验不能复制旧 `approved`。旧资产 Schema 不合规时先报告修复,不能改字段躲过检查。只改序列化不升级业务 Schema。
26
+
27
+ ## Plan 对照
28
+
29
+ `scripts/check-plan-stage-coverage --root <项目> --plan <Plan.md> --decisions <决定记录.md> --package <阶段包.json> [--mapping <对照.json>] --output <报告.json>` 提取决定表原编号和非目标表,输出来源行、原文、目标表述与摘要。无法识别的输入为 `unassessed`,不得宣称已覆盖。
30
+
31
+ 非目标映射含 `plan_digest`、`package_digest` 和 `non_goals: [{source_text, source_line, target_index, target_text}]`。编号与映射只定位既有内容,不另造业务事实。`coverage_status: complete` 仅证明结构覆盖;独立评审仍逐项检查否定、范围、责任和承诺,包括编号正确但内容相反的情况。上游或目标变化后重新生成对照,旧报告不能证明当前语义。
32
+
33
+ ## 版本取证
34
+
35
+ 正式资产、事务回执、必要审查和验证证据纳入项目版本管理;临时日志按既有归档策略管理。没有 Git 历史时先保存仓库外原字节快照和纳入清单,取得本地提交授权后建立基线,再切换真实实例。提交、推送、发布仍是不同授权,不由迁移命令代办。
@@ -0,0 +1,48 @@
1
+ {
2
+ "artifacts": {},
3
+ "blockers": [],
4
+ "context_reconciliation": {
5
+ "evidence_refs": [],
6
+ "reason": "等待当前工作单元完成稳定术语回写与核对",
7
+ "ref": null,
8
+ "status": "pending"
9
+ },
10
+ "gates": {},
11
+ "git_checkpoint": {
12
+ "required": false,
13
+ "status": "not-applicable"
14
+ },
15
+ "human_review": {
16
+ "not_applicable": [],
17
+ "required": false,
18
+ "required_decisions": [],
19
+ "status": "not-applicable",
20
+ "user_decisions": []
21
+ },
22
+ "mode": "route",
23
+ "next_work_unit": "work-unit.plan-opportunity",
24
+ "phase_boundary": {
25
+ "decision": "continue",
26
+ "reason": "initial routing"
27
+ },
28
+ "repository_mode": "project-instance",
29
+ "rollback": [],
30
+ "schema_version": 1,
31
+ "stage": "stage.entry-triage",
32
+ "stage_trace": {
33
+ "artifact_refs": [],
34
+ "downstream_impacts": [],
35
+ "gate_decisions": [],
36
+ "stage": "stage.entry-triage",
37
+ "upstream_refs": []
38
+ },
39
+ "status": "routing",
40
+ "ticket_sync": {
41
+ "refs": [],
42
+ "status": "pending"
43
+ },
44
+ "verification": {
45
+ "commands": [],
46
+ "evidence_refs": []
47
+ }
48
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "actor_kind": "digital-human",
3
+ "approval_scope": [],
4
+ "biological_veto": false,
5
+ "continuation_ref": null,
6
+ "countersigner_role_ids": [
7
+ "role.product-manager"
8
+ ],
9
+ "decision": "approved",
10
+ "drafter_principal_ref": null,
11
+ "drafter_role_id": "role.requirements-manager",
12
+ "evidence_refs": [],
13
+ "gate_id": "gate.spec-baseline-approved",
14
+ "notes": "会签必须可读取;起草者不得出现在 countersigner_role_ids。运行时表情/reaction 无效。",
15
+ "principal_ref": "instance:role.product-manager",
16
+ "role_id": "role.product-manager",
17
+ "runtime_id": "runtime.generic",
18
+ "runtime_instance_ref": "runtime.generic:role.product-manager",
19
+ "schema_version": 1,
20
+ "subject_digest": null,
21
+ "subject_ref": null,
22
+ "user_decision_ref": null
23
+ }
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import {parseArgs} from 'node:util';
5
+ import {planStageCoverage} from './lib/plan-stage-coverage.mjs';
6
+ try {
7
+ const {values}=parseArgs({options:{root:{type:'string'},plan:{type:'string'},decisions:{type:'string'},package:{type:'string'},mapping:{type:'string'},output:{type:'string'}}});
8
+ if(!values.plan||!values.decisions||!values.package)throw Error('需要 --plan <md> --decisions <md> --package <json|yaml> [--mapping <json>]');
9
+ const result=planStageCoverage(path.resolve(values.root||process.cwd()),{plan_ref:values.plan,decisions_ref:values.decisions,package_ref:values.package,mapping_ref:values.mapping});
10
+ const text=JSON.stringify(result,null,2)+'\n';if(values.output)fs.writeFileSync(values.output,text,{flag:'wx'});process.stdout.write(text);
11
+ if(result.coverage_status!=='complete')process.exitCode=1;
12
+ }catch(error){process.stderr.write(JSON.stringify({status:'unassessed',error:error.message})+'\n');process.exitCode=1;}
@@ -4,6 +4,11 @@ import {readFileSync,writeFileSync} from 'node:fs';
4
4
  import {safe} from './lib/strategic-handoff-io.mjs';
5
5
  import {renderReadingBundle,checkReadingViews,readingCheckpointsForAsset,saveReadingComparison,planEnableReading,applyEnableReading} from './lib/reading-view-bundle.mjs';
6
6
  import {viewContract,diffContract,prepareContractReview} from './lib/contract-views.mjs';
7
+ import {isAssetCommand,runAssetCommand} from './lib/asset-command.mjs';
8
+ if(isAssetCommand(process.argv[2])) {
9
+ try { process.stdout.write(JSON.stringify(runAssetCommand(process.argv.slice(2)),null,2)+'\n'); }
10
+ catch(error) { process.stderr.write(JSON.stringify({status:'blocked',error:error.message})+'\n');process.exitCode=1; }
11
+ } else {
7
12
  try{
8
13
  const args=process.argv.slice(2),mode=args.shift(),options={},positional=[];
9
14
  for(let i=0;i<args.length;i++){const arg=args[i];if(arg==='--json')options.json=true;else if(arg==='--model')options.model=true;else if(arg.startsWith('--')){const key=arg.slice(2);if(!['kind','profile','unit','root','before-root','decision','task-layout','checkpoint','output'].includes(key)||!args[i+1]||args[i+1].startsWith('--'))throw Error(`未知或缺值参数 ${arg}`);options[key]=args[++i];}else positional.push(arg);}
@@ -23,3 +28,4 @@ try{
23
28
  if(result.blockers?.length)process.exitCode=1;
24
29
  }
25
30
  }catch(error){process.stderr.write(error.message+'\n');process.exitCode=1;}
31
+ }
@@ -1,4 +1,5 @@
1
1
  import { assertApprovalUserDecision } from './user-decision-reuse.mjs';
2
+ import { parseAsset, validateAssetStructure } from './structured-assets.mjs';
2
3
  import { existsSync, readFileSync } from './validation-phase.mjs';
3
4
  import path from "node:path";
4
5
  import { parseDocument } from "../vendor/yaml.mjs";
@@ -31,9 +32,8 @@ function yamlFromFile(filePath, label) {
31
32
  if (error.code === "ENOENT") fail(`缺少${label}: ${filePath}`);
32
33
  throw error;
33
34
  }
34
- const document = parseDocument(source, { maxAliasCount: 0, uniqueKeys: true });
35
- if (document.errors.length > 0) fail(`无法解析${label}: ${document.errors[0].message}`);
36
- const value = document.toJS({ maxAliasCount: 0 });
35
+ const value = parseAsset(source, filePath);
36
+ validateAssetStructure(value, 'approval-record');
37
37
  if (!value || typeof value !== "object" || Array.isArray(value)) fail(`${label}必须是对象`);
38
38
  return value;
39
39
  }
@@ -79,6 +79,7 @@ export function resolveApprovalRef(approvalRef, fromFile = ROOT) {
79
79
  }
80
80
 
81
81
  export function validateApprovalRecord(record, { rolesDoc, requireApproved = false, ...decisionOptions } = {}) {
82
+ validateAssetStructure(record, 'approval-record');
82
83
  if (!record || typeof record !== "object" || Array.isArray(record)) fail("会签记录必须是对象");
83
84
  if (record.schema_version !== 1) fail("会签记录 schema_version 必须为 1");
84
85
  requireString(record.gate_id, "gate_id");
@@ -0,0 +1,35 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { parseArgs } from 'node:util';
4
+ import { readAsset, parseAsset, serializeAsset } from './structured-assets.mjs';
5
+ import { safeFile } from './governance-io.mjs';
6
+ import { planAssetWrite, applyAssetWrite, recoverAssetWrite, validateAssetSemantics, assertAssetTransactionIdle, assertCurrentAssetReference } from './asset-transactions.mjs';
7
+ import { planAssetMigration, applyAssetMigration } from './asset-migration.mjs';
8
+
9
+ export const isAssetCommand = command => ['validate','plan-write','apply-write','plan-migrate','apply-migrate','recover'].includes(command);
10
+ export function runAssetCommand(args) {
11
+ const command = args.shift();
12
+ const {values, positionals} = parseArgs({ args, allowPositionals: true, strict: true, options: { root:{type:'string'},kind:{type:'string'},input:{type:'string'},output:{type:'string'},resolutions:{type:'string'},'structure-only':{type:'boolean'} } });
13
+ const root = path.resolve(values.root || process.cwd());
14
+ const input = file => parseAsset(fs.readFileSync(path.resolve(file)), file);
15
+ let result;
16
+ if (command === 'recover') { if (positionals.length) throw new Error('recover takes --root only'); result = recoverAssetWrite(root); }
17
+ else {
18
+ if (positionals.length !== 1) throw new Error(`${command} requires one asset/plan path`);
19
+ const ref = positionals[0];
20
+ if (command === 'validate') {
21
+ assertAssetTransactionIdle(root);
22
+ assertCurrentAssetReference(root,ref);
23
+ const record = readAsset(safeFile(root, ref), values.kind, {schemaRoot:root});
24
+ result = {status:'valid',kind:values.kind,ref,digest:record.digest,checks:['schema'],execution_authorization:'not-granted'};
25
+ if (!values['structure-only']) {result.verification=validateAssetSemantics(root,ref,values.kind);result.checks.push('consumer');}
26
+ } else if(command === 'plan-write') {
27
+ if (!values.input) throw new Error('plan-write <target.json> --kind <kind> --input <candidate.json>');
28
+ result = planAssetWrite(root,[{ref,kind:values.kind,value:input(values.input)}],{schemaRoot:root});
29
+ } else if(command === 'apply-write') result = applyAssetWrite(root,input(ref));
30
+ else if(command === 'plan-migrate') result = planAssetMigration(root,ref,{schemaRoot:root});
31
+ else result = applyAssetMigration(root,input(ref),values.resolutions?input(values.resolutions):undefined,{schemaRoot:root});
32
+ }
33
+ if(values.output) fs.writeFileSync(path.resolve(values.output),serializeAsset(result),{flag:'wx'});
34
+ return result;
35
+ }