@nimiplatform/nimi-coding 0.2.8 → 0.3.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 (205) hide show
  1. package/CHANGELOG.md +8 -92
  2. package/CONTRIBUTING.md +5 -34
  3. package/README.md +47 -350
  4. package/README.zh-CN.md +33 -287
  5. package/cli/commands/start.mjs +48 -688
  6. package/cli/commands/validate-spec-audit.mjs +1 -5
  7. package/cli/constants.mjs +9 -417
  8. package/cli/help.mjs +28 -145
  9. package/cli/index.mjs +5 -33
  10. package/cli/lib/blueprint-audit.mjs +5 -12
  11. package/cli/lib/bootstrap.mjs +0 -9
  12. package/cli/lib/contracts.mjs +0 -163
  13. package/cli/lib/doctor.mjs +155 -10
  14. package/cli/lib/entrypoints.mjs +63 -167
  15. package/cli/lib/internal/contracts-loaders.mjs +0 -85
  16. package/cli/lib/internal/contracts-parse.mjs +84 -520
  17. package/cli/lib/internal/governance/ai/check-agents-freshness.mjs +13 -8
  18. package/cli/lib/internal/surface-taxonomy-validators.mjs +316 -66
  19. package/cli/lib/internal/validators-shared.mjs +0 -16
  20. package/cli/lib/internal/validators-spec-helpers.mjs +7 -140
  21. package/cli/lib/internal/validators-spec.mjs +103 -342
  22. package/cli/lib/shared.mjs +1 -42
  23. package/cli/lib/validators.mjs +0 -48
  24. package/cli/seeds/seed-policy.yaml +0 -3
  25. package/config/bootstrap.yaml +4 -4
  26. package/config/spec-generation-inputs.yaml +6 -12
  27. package/contracts/domain-admission.schema.yaml +3 -3
  28. package/contracts/migration-inventory.schema.yaml +12 -75
  29. package/contracts/negative-fixtures.yaml +19 -99
  30. package/contracts/placement-contract.schema.yaml +49 -78
  31. package/contracts/projection-edge.schema.yaml +37 -121
  32. package/contracts/shared-enums.yaml +4 -8
  33. package/contracts/spec-generation-inputs.schema.yaml +15 -112
  34. package/contracts/spec-layout.schema.yaml +32 -0
  35. package/contracts/surface-taxonomy.schema.yaml +43 -94
  36. package/contracts/table-family.schema.yaml +1 -1
  37. package/contracts/tracked-output-admission.schema.yaml +13 -66
  38. package/methodology/core.yaml +33 -25
  39. package/methodology/four-closure-policy.yaml +18 -26
  40. package/methodology/role-separation-policy.yaml +21 -27
  41. package/methodology/spec-reconstruction.yaml +17 -34
  42. package/package.json +2 -4
  43. package/spec/_meta/spec-tree-model.yaml +5 -101
  44. package/spec/product-scope.yaml +25 -57
  45. package/adapters/README.md +0 -25
  46. package/adapters/claude/README.md +0 -89
  47. package/adapters/claude/profile.yaml +0 -70
  48. package/adapters/codex/README.md +0 -53
  49. package/adapters/codex/profile.yaml +0 -78
  50. package/adapters/oh-my-codex/README.md +0 -184
  51. package/adapters/oh-my-codex/profile.yaml +0 -46
  52. package/cli/commands/admit-high-risk-decision.mjs +0 -108
  53. package/cli/commands/audit-sweep.mjs +0 -364
  54. package/cli/commands/closeout.mjs +0 -186
  55. package/cli/commands/decide-high-risk-execution.mjs +0 -124
  56. package/cli/commands/handoff.mjs +0 -123
  57. package/cli/commands/ingest-high-risk-execution.mjs +0 -95
  58. package/cli/commands/review-high-risk-execution.mjs +0 -95
  59. package/cli/commands/sweep-design.mjs +0 -295
  60. package/cli/commands/sweep.mjs +0 -22
  61. package/cli/commands/topic-formatters.mjs +0 -382
  62. package/cli/commands/topic-goal.mjs +0 -33
  63. package/cli/commands/topic-options-shared.mjs +0 -27
  64. package/cli/commands/topic-options-workflow.mjs +0 -767
  65. package/cli/commands/topic-options.mjs +0 -626
  66. package/cli/commands/topic-runner.mjs +0 -169
  67. package/cli/commands/topic.mjs +0 -795
  68. package/cli/commands/validate-acceptance.mjs +0 -5
  69. package/cli/commands/validate-execution-packet.mjs +0 -5
  70. package/cli/commands/validate-orchestration-state.mjs +0 -5
  71. package/cli/commands/validate-prompt.mjs +0 -5
  72. package/cli/commands/validate-worker-output.mjs +0 -5
  73. package/cli/lib/adapter-profiles.mjs +0 -403
  74. package/cli/lib/audit-execution.mjs +0 -52
  75. package/cli/lib/audit-sweep-runtime/admissions.mjs +0 -508
  76. package/cli/lib/audit-sweep-runtime/audit-validity.mjs +0 -356
  77. package/cli/lib/audit-sweep-runtime/chunks.mjs +0 -697
  78. package/cli/lib/audit-sweep-runtime/claude-auditor.mjs +0 -658
  79. package/cli/lib/audit-sweep-runtime/closeout.mjs +0 -144
  80. package/cli/lib/audit-sweep-runtime/codex-auditor-evidence.mjs +0 -654
  81. package/cli/lib/audit-sweep-runtime/codex-auditor.mjs +0 -527
  82. package/cli/lib/audit-sweep-runtime/common.mjs +0 -341
  83. package/cli/lib/audit-sweep-runtime/coverage-quality.mjs +0 -172
  84. package/cli/lib/audit-sweep-runtime/evidence-assignment.mjs +0 -155
  85. package/cli/lib/audit-sweep-runtime/format.mjs +0 -57
  86. package/cli/lib/audit-sweep-runtime/ingest.mjs +0 -486
  87. package/cli/lib/audit-sweep-runtime/inventory-spec-chunks.mjs +0 -425
  88. package/cli/lib/audit-sweep-runtime/inventory.mjs +0 -798
  89. package/cli/lib/audit-sweep-runtime/ledger.mjs +0 -315
  90. package/cli/lib/audit-sweep-runtime/p0p1-profile.mjs +0 -101
  91. package/cli/lib/audit-sweep-runtime/remediation.mjs +0 -349
  92. package/cli/lib/audit-sweep-runtime/rerun.mjs +0 -129
  93. package/cli/lib/audit-sweep-runtime/risk-budget.mjs +0 -300
  94. package/cli/lib/audit-sweep-runtime/status.mjs +0 -62
  95. package/cli/lib/audit-sweep-runtime/validators-ledger.mjs +0 -215
  96. package/cli/lib/audit-sweep-runtime/validators.mjs +0 -797
  97. package/cli/lib/audit-sweep.mjs +0 -19
  98. package/cli/lib/authority-convergence.mjs +0 -720
  99. package/cli/lib/closeout.mjs +0 -732
  100. package/cli/lib/codex-sdk-runner.mjs +0 -76
  101. package/cli/lib/external-execution.mjs +0 -101
  102. package/cli/lib/handoff.mjs +0 -812
  103. package/cli/lib/high-risk-admission.mjs +0 -512
  104. package/cli/lib/high-risk-decision.mjs +0 -353
  105. package/cli/lib/high-risk-ingest.mjs +0 -321
  106. package/cli/lib/high-risk-review.mjs +0 -267
  107. package/cli/lib/internal/contracts-parse-high-risk.mjs +0 -131
  108. package/cli/lib/internal/contracts-validators.mjs +0 -399
  109. package/cli/lib/internal/doctor-bootstrap-surface.mjs +0 -406
  110. package/cli/lib/internal/doctor-delegated-surface.mjs +0 -256
  111. package/cli/lib/internal/doctor-finalize.mjs +0 -383
  112. package/cli/lib/internal/doctor-format.mjs +0 -286
  113. package/cli/lib/internal/doctor-inspectors.mjs +0 -327
  114. package/cli/lib/internal/doctor-state.mjs +0 -205
  115. package/cli/lib/internal/validators-artifacts.mjs +0 -515
  116. package/cli/lib/sweep-design-runtime/common.mjs +0 -246
  117. package/cli/lib/sweep-design-runtime/engine.mjs +0 -733
  118. package/cli/lib/sweep-design-runtime/fix-topic.mjs +0 -414
  119. package/cli/lib/sweep-design-runtime/lifecycle.mjs +0 -54
  120. package/cli/lib/sweep-design-runtime/results.mjs +0 -324
  121. package/cli/lib/sweep-design.mjs +0 -8
  122. package/cli/lib/topic-artifacts.mjs +0 -186
  123. package/cli/lib/topic-authority-coverage.mjs +0 -73
  124. package/cli/lib/topic-closeout.mjs +0 -560
  125. package/cli/lib/topic-common.mjs +0 -404
  126. package/cli/lib/topic-decisions.mjs +0 -332
  127. package/cli/lib/topic-draft-packets.mjs +0 -167
  128. package/cli/lib/topic-execution.mjs +0 -533
  129. package/cli/lib/topic-goal.mjs +0 -440
  130. package/cli/lib/topic-ledger.mjs +0 -281
  131. package/cli/lib/topic-lifecycle-artifacts.mjs +0 -173
  132. package/cli/lib/topic-root-validation.mjs +0 -288
  133. package/cli/lib/topic-runner-commands.mjs +0 -174
  134. package/cli/lib/topic-runner-deferral.mjs +0 -532
  135. package/cli/lib/topic-runner-stale-gates.mjs +0 -114
  136. package/cli/lib/topic-runner-validation.mjs +0 -138
  137. package/cli/lib/topic-runner.mjs +0 -727
  138. package/cli/lib/topic-scaffold.mjs +0 -252
  139. package/cli/lib/topic-waves.mjs +0 -403
  140. package/cli/lib/topic.mjs +0 -81
  141. package/config/audit-execution-artifacts.yaml +0 -20
  142. package/config/external-execution-artifacts.yaml +0 -16
  143. package/config/host-adapter.yaml +0 -30
  144. package/config/host-profile.yaml +0 -29
  145. package/config/installer-evidence.yaml +0 -31
  146. package/config/skill-installer.yaml +0 -23
  147. package/config/skill-manifest.yaml +0 -48
  148. package/config/skills.yaml +0 -30
  149. package/contracts/acceptance.schema.yaml +0 -16
  150. package/contracts/admission-checklist.schema.yaml +0 -15
  151. package/contracts/audit-chunk.schema.yaml +0 -123
  152. package/contracts/audit-closeout.schema.yaml +0 -51
  153. package/contracts/audit-finding.schema.yaml +0 -61
  154. package/contracts/audit-ledger.schema.yaml +0 -138
  155. package/contracts/audit-plan.schema.yaml +0 -138
  156. package/contracts/audit-remediation-map.schema.yaml +0 -52
  157. package/contracts/audit-rerun.schema.yaml +0 -31
  158. package/contracts/audit-sweep-result.yaml +0 -53
  159. package/contracts/authority-convergence-audit.schema.yaml +0 -19
  160. package/contracts/closeout.schema.yaml +0 -25
  161. package/contracts/decision-review.schema.yaml +0 -16
  162. package/contracts/doc-spec-audit-result.yaml +0 -19
  163. package/contracts/execution-packet.schema.yaml +0 -49
  164. package/contracts/external-host-compatibility.yaml +0 -22
  165. package/contracts/forbidden-shortcuts.catalog.yaml +0 -23
  166. package/contracts/high-risk-admission.schema.yaml +0 -23
  167. package/contracts/high-risk-execution-result.yaml +0 -20
  168. package/contracts/orchestration-state.schema.yaml +0 -41
  169. package/contracts/overflow-continuation.schema.yaml +0 -12
  170. package/contracts/packet.schema.yaml +0 -30
  171. package/contracts/pending-note.schema.yaml +0 -17
  172. package/contracts/prompt.schema.yaml +0 -12
  173. package/contracts/remediation.schema.yaml +0 -16
  174. package/contracts/result.schema.yaml +0 -24
  175. package/contracts/spec-reconstruction-result.yaml +0 -41
  176. package/contracts/sweep-design-result.yaml +0 -349
  177. package/contracts/topic-goal.schema.yaml +0 -87
  178. package/contracts/topic-run-ledger.schema.yaml +0 -72
  179. package/contracts/topic-step-decision.schema.yaml +0 -45
  180. package/contracts/topic.schema.yaml +0 -65
  181. package/contracts/true-close.schema.yaml +0 -15
  182. package/contracts/wave.schema.yaml +0 -29
  183. package/contracts/worker-output.schema.yaml +0 -15
  184. package/contracts/workflow-consumer.schema.yaml +0 -110
  185. package/methodology/audit-sweep-p0p1-recall.yaml +0 -45
  186. package/methodology/authority-convergence-policy.yaml +0 -42
  187. package/methodology/overflow-continuation-policy.yaml +0 -14
  188. package/methodology/skill-exchange-projection.yaml +0 -114
  189. package/methodology/skill-handoff.yaml +0 -34
  190. package/methodology/skill-installer-result.yaml +0 -27
  191. package/methodology/skill-installer-summary-projection.yaml +0 -181
  192. package/methodology/skill-runtime.yaml +0 -23
  193. package/methodology/spec-target-truth-profile.yaml +0 -46
  194. package/methodology/topic-lifecycle-report.yaml +0 -144
  195. package/methodology/topic-lifecycle.yaml +0 -37
  196. package/methodology/topic-naming-ontology.yaml +0 -21
  197. package/methodology/topic-ontology.yaml +0 -38
  198. package/methodology/topic-validation-policy.yaml +0 -9
  199. package/methodology/wave-dag-policy.yaml +0 -14
  200. package/spec/_meta/command-gating-matrix.yaml +0 -143
  201. package/spec/_meta/generate-drift-migration-checklist.yaml +0 -137
  202. package/spec/_meta/governance-routing-cutover-checklist.yaml +0 -35
  203. package/spec/_meta/phase2-impacted-surface-matrix.yaml +0 -44
  204. package/spec/_meta/spec-authority-cutover-readiness.yaml +0 -102
  205. package/spec/bootstrap-state.yaml +0 -99
@@ -1,286 +0,0 @@
1
- import {
2
- localize,
3
- styleHeading,
4
- styleLabel,
5
- styleMuted,
6
- styleStatus,
7
- } from "../ui.mjs";
8
- import { emptyHostCompatibility } from "./doctor-state.mjs";
9
-
10
- const DOCTOR_DETAIL_TRANSLATIONS = new Map([
11
- [".nimi directory is missing", ".nimi 目录缺失"],
12
- [".nimi exists but is not a directory", ".nimi 已存在但不是目录"],
13
- [".nimi directory exists", ".nimi 目录存在"],
14
- ["Local state directories are present", "本地状态目录已存在"],
15
- ["Local nimicoding state is ignored by .gitignore", ".gitignore 已忽略本地 nimicoding 状态"],
16
- ["bootstrap.yaml declares the package bootstrap identity", "bootstrap.yaml 已声明包的 bootstrap 身份"],
17
- ["bootstrap contract nimicoding.bootstrap version 1 is supported", "bootstrap contract nimicoding.bootstrap version 1 受支持"],
18
- ["bootstrap-state.yaml matches the bootstrap_only tree-state contract", "bootstrap-state.yaml 符合 bootstrap_only tree-state contract"],
19
- ["bootstrap-state.yaml matches the canonical_tree_ready tree-state contract", "bootstrap-state.yaml 符合 canonical_tree_ready tree-state contract"],
20
- ["Product scope declares standalone completion profile boundary_complete", "product scope 声明了 standalone completion profile boundary_complete"],
21
- [".nimi/spec/_meta/spec-tree-model.yaml declares canonical root .nimi/spec with profile minimal", ".nimi/spec/_meta/spec-tree-model.yaml 声明了 canonical root .nimi/spec,profile 为 minimal"],
22
- [".nimi/spec/_meta/command-gating-matrix.yaml declares 12 command gating rules", ".nimi/spec/_meta/command-gating-matrix.yaml 声明了 12 条命令 gating 规则"],
23
- [".nimi/contracts/spec-generation-inputs.schema.yaml is present and structurally valid", ".nimi/contracts/spec-generation-inputs.schema.yaml 已存在且结构有效"],
24
- [".nimi/contracts/spec-generation-audit.schema.yaml is present and structurally valid", ".nimi/contracts/spec-generation-audit.schema.yaml 已存在且结构有效"],
25
- [".nimi/config/spec-generation-inputs.yaml declares mixed canonical spec generation inputs", ".nimi/config/spec-generation-inputs.yaml 已声明 mixed canonical spec generation inputs"],
26
- [".nimi/spec/_meta/blueprint-reference.yaml matches blueprint mode repo_spec_blueprint", ".nimi/spec/_meta/blueprint-reference.yaml 与 blueprint mode repo_spec_blueprint 保持一致"],
27
- ["Benchmark audit can compare the declared blueprint root against the candidate canonical tree", "benchmark audit 可以比较声明的 blueprint root 与候选 canonical tree"],
28
- ["Declared canonical tree required files are present", "声明的 canonical tree 必需文件已存在"],
29
- ["Spec generation audit is present and structurally valid", "spec generation audit 已存在且结构有效"],
30
- ["No spec generation audit detected yet; it will be required before completed reconstruction closeout", "尚未检测到 spec generation audit;在 completed reconstruction closeout 之前将要求该产物"],
31
- ["Canonical tree is ready but spec generation audit is still missing or invalid", "canonical tree 已就绪,但 spec generation audit 仍然缺失或无效"],
32
- ["Command gating matrix includes high_risk_execution closeout readiness", "命令 gating matrix 已包含 high_risk_execution 的 closeout 准入规则"],
33
- ["bootstrap.yaml was created by nimicoding but is missing bootstrap contract metadata", "bootstrap.yaml 由 nimicoding 创建,但缺少 bootstrap contract 元数据"],
34
- ["bootstrap.yaml is missing and bootstrap contract compatibility could not be checked", "bootstrap.yaml 缺失,无法检查 bootstrap contract 兼容性"],
35
- ["bootstrap.yaml declares an unsupported bootstrap contract id or version", "bootstrap.yaml 声明了不受支持的 bootstrap contract id 或 version"],
36
- ["skills.yaml keeps runtime delegated and handoff-driven", "skills.yaml 保持 runtime 为委托式且以 handoff 驱动"],
37
- ["Delegated runtime ownership and non-self-hosted posture are consistent across contracts", "各契约中的 delegated runtime ownership 与 non-self-hosted 姿态保持一致"],
38
- ["Manifest, runtime, installer, host-profile, host-adapter, and handoff references are aligned", "manifest、runtime、installer、host-profile、host-adapter 与 handoff 的引用保持一致"],
39
- ["Skill manifest result contract refs align with the declared machine contracts", "skill manifest 的 result contract 引用与声明的机器契约保持一致"],
40
- ["Handoff context order contains the declared host context and all listed paths exist", "handoff context 顺序包含声明的 host context,且所有列出的路径均存在"],
41
- ["Manifest skills align with the expected skill surfaces declared in skills.yaml", "manifest skills 与 skills.yaml 中声明的 expected skill surfaces 保持一致"],
42
- ["spec-reconstruction result contract is present and structurally valid", "spec-reconstruction 结果契约存在且结构有效"],
43
- ["doc-spec-audit result contract is present and structurally valid", "doc-spec-audit 结果契约存在且结构有效"],
44
- ["audit-sweep result contract is present and structurally valid", "audit-sweep 结果契约存在且结构有效"],
45
- ["Packaged external host compatibility contract is present and aligned", "包内 external host 兼容契约存在且一致"],
46
- ["audit execution artifact landing-path contract is present and structurally valid", "audit execution artifact landing-path 契约存在且结构有效"],
47
- ["high-risk-execution result contract is present and structurally valid", "high-risk-execution 结果契约存在且结构有效"],
48
- ["Packaged high-risk admission schema contract is present and aligned", "包内 high-risk admission schema 契约存在且一致"],
49
- ["external execution artifact landing-path contract is present and structurally valid", "external execution artifact landing-path 契约存在且结构有效"],
50
- ["High-risk execution schema seeds are present and structurally valid", "high-risk execution schema seed 已存在且结构有效"],
51
- ["No host adapter selected; vendor-neutral delegated host posture remains active", "未选择 host adapter;vendor-neutral 的 delegated host 姿态仍然生效"],
52
- ["Package-owned adapter profile overlays are present and valid: codex, oh_my_codex, claude", "包内 adapter profile overlay 已存在且有效:codex, oh_my_codex, claude"],
53
- ["Host adapter boundary keeps semantic review in nimicoding and limits handoff to prompt/output/evidence", "host adapter 边界保持 semantic review 在 nimicoding 内,并将 handoff 限制为 prompt/output/evidence"],
54
- ["bootstrap-state lifecycle bootstrap_only is aligned with the current canonical tree readiness", "bootstrap-state 的 bootstrap_only lifecycle 与当前 canonical tree readiness 保持一致"],
55
- ["bootstrap-state lifecycle canonical_tree_ready is aligned with the current canonical tree readiness", "bootstrap-state 的 canonical_tree_ready lifecycle 与当前 canonical tree readiness 保持一致"],
56
- ["No local doc_spec_audit closeout artifact detected", "未检测到本地 doc_spec_audit closeout 产物"],
57
- ["Local doc_spec_audit artifact is consistent with the current reconstruction state", "本地 doc_spec_audit 产物与当前重建状态一致"],
58
- ["Managed AI entrypoint blocks detected in: AGENTS.md, CLAUDE.md", "在 AGENTS.md、CLAUDE.md 中检测到托管 AI 入口块"],
59
- ["No managed AI entrypoint blocks detected; this is optional", "未检测到托管 AI 入口块;这是可选的"],
60
- ]);
61
-
62
- const DOCTOR_NEXT_STEP_TRANSLATIONS = new Map([
63
- ["Repair the failing bootstrap checks, then rerun `nimicoding doctor`.", "修复失败的 bootstrap 检查项,然后重新运行 `nimicoding doctor`。"],
64
- ["Use an external AI host to reconstruct the declared canonical tree under `.nimi/spec`.", "使用外部 AI host 重建声明的 `.nimi/spec` canonical tree。"],
65
- ["Run `nimicoding blueprint-audit --write-local` after canonical tree generation when a benchmark blueprint is declared.", "当声明了 benchmark blueprint 且 canonical tree 生成完成后,运行 `nimicoding blueprint-audit --write-local`。"],
66
- ["Run `nimicoding validate-spec-audit` after generating the local spec generation audit for the canonical tree.", "为 canonical tree 生成本地 spec generation audit 后,运行 `nimicoding validate-spec-audit`。"],
67
- ["Run `nimicoding handoff --skill doc_spec_audit` and close out the result locally when the audit is complete.", "运行 `nimicoding handoff --skill doc_spec_audit`,并在审计完成后于本地 closeout 结果。"],
68
- ["Keep runtime ownership delegated; do not assume local skill installation or self-hosting.", "保持 runtime ownership 为 delegated;不要假设本地 skill 安装或 self-hosting。"],
69
- ["If you want a constrained external execution host, select one in `.nimi/config/host-adapter.yaml`.", "如果你希望使用受约束的外部执行 host,请在 `.nimi/config/host-adapter.yaml` 中选择一个。"],
70
- ]);
71
-
72
- function translateDoctorDetail(detail) {
73
- if (/^All required bootstrap seed files are present \(\d+\/\d+\)$/.test(detail)) {
74
- return detail.replace("All required bootstrap seed files are present", "所有必需的 bootstrap seed 文件均已存在");
75
- }
76
-
77
- return DOCTOR_DETAIL_TRANSLATIONS.get(detail) ?? detail;
78
- }
79
-
80
- function translateDoctorNextStep(step) {
81
- return DOCTOR_NEXT_STEP_TRANSLATIONS.get(step) ?? step;
82
- }
83
-
84
- function summarizeDoctorState(result) {
85
- const blockingChecks = result.checks.filter((check) => check.severity === "error");
86
- const warningChecks = result.checks.filter((check) => check.severity === "warn");
87
- const importantInfoChecks = result.checks.filter((check) => check.severity === "info").slice(0, 2);
88
- const usesV2SurfaceModel = result.specGenerationInputs?.mode === "class_filtered";
89
-
90
- const bootstrapState = !result.bootstrapPresent
91
- ? localize("missing", "缺失")
92
- : result.bootstrapContract.status === "supported"
93
- ? localize("ready", "就绪")
94
- : localize("needs attention", "需要关注");
95
-
96
- const canonicalTreeState = !usesV2SurfaceModel && !result.specTreeModel?.ok
97
- ? localize("invalid", "无效")
98
- : !result.canonicalTree.requiredFilesValid
99
- ? localize("incomplete", "未完成")
100
- : localize("ready", "就绪");
101
-
102
- const auditState = !result.specGenerationAudit?.present
103
- ? localize("not started", "未开始")
104
- : result.specGenerationAudit?.ok
105
- ? localize("ready", "就绪")
106
- : localize("needs attention", "需要关注");
107
- const benchmarkAuditState = !result.benchmarkAuditReadiness?.available
108
- ? localize("not declared", "未声明")
109
- : result.benchmarkAuditReadiness.ready
110
- ? localize("ready", "就绪")
111
- : localize("needs attention", "需要关注");
112
-
113
- const entrypointIntegrated = result.checks.some((check) => check.id === "entrypoint_integration" && check.detail.includes("Managed AI entrypoint blocks detected"));
114
-
115
- return {
116
- blockingChecks,
117
- warningChecks,
118
- importantInfoChecks,
119
- bootstrapState,
120
- canonicalTreeState,
121
- auditState,
122
- benchmarkAuditState,
123
- entrypointIntegrated,
124
- };
125
- }
126
-
127
- function formatDoctorResultVerbose(result) {
128
- const hostCompatibility = result.hostCompatibility ?? emptyHostCompatibility();
129
- const lines = [
130
- styleHeading(`nimicoding doctor: ${result.projectRoot}`),
131
- "",
132
- styleLabel(localize("Overall:", "总体:")),
133
- ` - ${localize("status", "状态")}: ${styleStatus(result.ok ? "ok" : "needs_attention")}`,
134
- ` - bootstrap_present: ${result.bootstrapPresent ? "true" : "false"}`,
135
- ` - reconstruction_required: ${result.reconstructionRequired ? "true" : "false"}`,
136
- ` - runtime_installed: ${result.runtimeInstalled ? "true" : "false"}`,
137
- ` - handoff_ready: ${result.handoffReadiness.ok ? "true" : "false"}`,
138
- ` - tree_state: ${result.lifecycleState.treeState ?? "unknown"}`,
139
- ` - authority_mode: ${result.lifecycleState.authorityMode ?? "unknown"}`,
140
- ` - blueprint_mode: ${result.lifecycleState.blueprintMode ?? "unknown"}`,
141
- "",
142
- styleLabel(localize("Bootstrap:", "Bootstrap:")),
143
- ` - contract_status: ${result.bootstrapContract.status}`,
144
- ` - contract_id: ${result.bootstrapContract.id ?? "unknown"}`,
145
- ` - contract_version: ${result.bootstrapContract.version ?? "unknown"}`,
146
- "",
147
- styleLabel(localize("Completion Posture:", "完成姿态:")),
148
- ` - profile: ${result.completionProfile ?? "unknown"}`,
149
- ` - ${localize("status", "状态")}: ${styleStatus(result.completionStatus ?? "unknown")}`,
150
- ` - completed_surfaces: ${result.completedSurfaces.length}`,
151
- "",
152
- styleLabel(localize("Supported Host Posture:", "支持的 Host 姿态:")),
153
- ` - contract_ref: ${hostCompatibility.contractRef ?? "unknown"}`,
154
- ` - supported_host_posture: ${hostCompatibility.supportedHostPosture.join(", ") || "none"}`,
155
- ` - supported_host_examples: ${hostCompatibility.supportedHostExamples.join(", ") || "none"}`,
156
- ` - required_behavior: ${hostCompatibility.requiredBehavior.length}`,
157
- ` - forbidden_behavior: ${hostCompatibility.forbiddenBehavior.length}`,
158
- ` - generic_external_host_compatible: ${hostCompatibility.genericExternalHostCompatible ? "true" : "false"}`,
159
- ` - named_overlay_mode: ${hostCompatibility.namedOverlaySupport.mode}`,
160
- ` - admitted_named_overlays: ${hostCompatibility.namedOverlaySupport.admittedOverlayIds.join(", ") || "none"}`,
161
- ` - selected_named_overlay: ${hostCompatibility.namedOverlaySupport.selectedOverlayId ?? "none"}`,
162
- "",
163
- styleLabel(localize("Delegated Contracts:", "委托契约:")),
164
- ` - runtime_owner: ${result.delegatedContracts.runtimeOwner ?? "unknown"}`,
165
- ` - runtime_mode: ${result.delegatedContracts.executionMode ?? "unknown"}`,
166
- ` - installer_mode: ${result.delegatedContracts.installerMode ?? "unknown"}`,
167
- ` - self_hosted_runtime: ${result.delegatedContracts.selfHostedRuntime ? "true" : "false"}`,
168
- ` - trigger_mode: ${result.delegatedContracts.triggerMode ?? "unknown"}`,
169
- ` - selected_adapter_id: ${result.delegatedContracts.selectedAdapterId ?? "unknown"}`,
170
- ` - admitted_adapter_ids: ${result.delegatedContracts.admittedAdapterIds.length}`,
171
- ` - adapter_handoff_mode: ${result.delegatedContracts.adapterHandoffMode ?? "unknown"}`,
172
- ` - semantic_review_owner: ${result.delegatedContracts.semanticReviewOwner ?? "unknown"}`,
173
- "",
174
- styleLabel(localize("Adapter Profiles:", "Adapter 配置:")),
175
- ` - admitted: ${result.adapterProfiles.admitted.length}`,
176
- ` - invalid: ${result.adapterProfiles.invalid.length}`,
177
- ` - selected_profile_ref: ${result.adapterProfiles.selected?.profileRef ?? "none"}`,
178
- ` - selected_host_class: ${result.adapterProfiles.selected?.hostClass ?? "none"}`,
179
- "",
180
- styleLabel(localize("Checks:", "检查项:")),
181
- ];
182
-
183
- for (const check of result.checks) {
184
- const marker = check.severity === "error"
185
- ? "fail"
186
- : check.severity === "warn"
187
- ? "warn"
188
- : check.severity === "info"
189
- ? "info"
190
- : "ok";
191
- lines.push(` - [${marker}] ${localize(check.detail, translateDoctorDetail(check.detail))}`);
192
- }
193
-
194
- lines.push("", styleLabel(localize("Canonical Tree:", "Canonical Tree:")));
195
- lines.push(` - profile: ${result.canonicalTree.profile ?? "unknown"}`);
196
- lines.push(` - required_files: ${result.canonicalTree.requiredFiles.length}`);
197
- lines.push(` - present: ${result.canonicalTree.present.length}`);
198
- lines.push(` - missing: ${result.canonicalTree.missing.length}`);
199
- lines.push(` - ready: ${result.canonicalTree.ready ? "true" : "false"}`);
200
-
201
- lines.push("", styleLabel(localize("Generation Inputs:", "生成输入:")));
202
- lines.push(` - mode: ${result.specGenerationInputs.mode ?? "unknown"}`);
203
- lines.push(` - code_roots: ${result.specGenerationInputs.codeRoots.length}`);
204
- lines.push(` - docs_roots: ${result.specGenerationInputs.docsRoots.length}`);
205
- lines.push(` - structure_roots: ${result.specGenerationInputs.structureRoots.length}`);
206
- lines.push(` - human_note_paths: ${result.specGenerationInputs.humanNotePaths.length}`);
207
- lines.push(` - benchmark_mode: ${result.specGenerationInputs.benchmarkMode ?? "unknown"}`);
208
- lines.push(` - benchmark_root: ${result.benchmarkAuditReadiness.benchmarkRoot ?? "none"}`);
209
- lines.push(` - acceptance_mode: ${result.specGenerationInputs.acceptanceMode ?? "unknown"}`);
210
-
211
- lines.push("", styleLabel(localize("Audit:", "审计:")));
212
- lines.push(` - spec_generation_audit_present: ${result.specGenerationAudit.present ? "true" : "false"}`);
213
- lines.push(` - spec_generation_audit_ok: ${result.specGenerationAudit.ok ? "true" : "false"}`);
214
- lines.push(` - required_audited_files: ${result.specGenerationAudit.summary?.requiredAuditedFiles ?? 0}`);
215
- lines.push(` - unresolved_files: ${result.specGenerationAudit.summary?.unresolvedFiles ?? 0}`);
216
- lines.push(` - inferred_files: ${result.specGenerationAudit.summary?.inferredFiles ?? 0}`);
217
- lines.push(` - doc_spec_audit_artifact_present: ${result.auditArtifact.present ? "true" : "false"}`);
218
- lines.push(` - doc_spec_audit_artifact_ok: ${result.auditArtifact.ok ? "true" : "false"}`);
219
-
220
- lines.push("", styleLabel(localize("Execution Contracts:", "执行契约:")));
221
- lines.push(` - total: ${result.executionContracts.total}`);
222
- lines.push(` - valid: ${result.executionContracts.valid}`);
223
- lines.push(` - invalid: ${result.executionContracts.invalid.length}`);
224
-
225
- lines.push("", styleLabel(localize("Handoff:", "Handoff:")));
226
- lines.push(` - required_context_order: ${result.handoffReadiness.requiredContextOrder.length}`);
227
- lines.push(` - missing_context_entries: ${result.handoffReadiness.missingContextEntries.length}`);
228
- lines.push(` - missing_paths: ${result.handoffReadiness.missingPaths.length}`);
229
-
230
- if (result.nextSteps.length > 0) {
231
- lines.push("", styleLabel(localize("Next:", "下一步:")));
232
- for (const step of result.nextSteps) {
233
- lines.push(` - ${localize(step, translateDoctorNextStep(step))}`);
234
- }
235
- }
236
-
237
- return `${lines.join("\n")}\n`;
238
- }
239
-
240
- export function formatDoctorResult(result, options = {}) {
241
- if (options.verbose) {
242
- return formatDoctorResultVerbose(result);
243
- }
244
-
245
- const summary = summarizeDoctorState(result);
246
- const lines = [
247
- styleHeading(`nimicoding doctor: ${result.projectRoot}`),
248
- "",
249
- styleLabel(localize("Summary:", "摘要:")),
250
- ` - ${localize("status", "状态")}: ${styleStatus(result.ok ? "ok" : "needs_attention")}`,
251
- ` - ${localize("bootstrap", "bootstrap")}: ${summary.bootstrapState}`,
252
- ` - ${localize("project rules", "项目规则")}: ${summary.canonicalTreeState} (${localize("present", "已存在")} ${result.canonicalTree.present.length}, ${localize("missing", "缺失")} ${result.canonicalTree.missing.length})`,
253
- ` - ${localize("lifecycle", "生命周期")}: ${result.lifecycleState.treeState ?? "unknown"} / ${result.lifecycleState.authorityMode ?? "unknown"}`,
254
- ` - ${localize("benchmark audit", "benchmark 审计")}: ${summary.benchmarkAuditState}`,
255
- ` - ${localize("generation audit", "生成审计")}: ${summary.auditState}`,
256
- ` - ${localize("AI entry files", "AI 入口文件")}: ${summary.entrypointIntegrated ? localize("connected", "已接入") : localize("not connected", "未接入")}`,
257
- ` - ${localize("handoff", "handoff")}: ${result.handoffReadiness.ok ? localize("ready", "就绪") : localize("needs attention", "需要关注")}`,
258
- ];
259
-
260
- lines.push("", styleLabel(localize("Checks:", "检查项:")));
261
- if (summary.blockingChecks.length === 0 && summary.warningChecks.length === 0) {
262
- lines.push(` - ${localize("No blocking issues found.", "没有发现阻塞问题。")}`);
263
- } else {
264
- for (const check of [...summary.blockingChecks, ...summary.warningChecks]) {
265
- const marker = check.severity === "error" ? "fail" : "warn";
266
- lines.push(` - [${marker}] ${localize(check.detail, translateDoctorDetail(check.detail))}`);
267
- }
268
- }
269
-
270
- if (summary.importantInfoChecks.length > 0) {
271
- lines.push("", styleLabel(localize("Notes:", "说明:")));
272
- for (const check of summary.importantInfoChecks) {
273
- lines.push(` - ${localize(check.detail, translateDoctorDetail(check.detail))}`);
274
- }
275
- }
276
-
277
- if (result.nextSteps.length > 0) {
278
- lines.push("", styleLabel(localize("Next:", "下一步:")));
279
- for (const step of result.nextSteps) {
280
- lines.push(` - ${localize(step, translateDoctorNextStep(step))}`);
281
- }
282
- }
283
-
284
- lines.push("", styleMuted(localize("Need internal contract detail? Run `nimicoding doctor --verbose`.", "如果你需要内部契约细节,请运行 `nimicoding doctor --verbose`。")));
285
- return `${lines.join("\n")}\n`;
286
- }
@@ -1,327 +0,0 @@
1
- import path from "node:path";
2
-
3
- import {
4
- EXTERNAL_HOST_COMPATIBILITY_CONTRACT_REF,
5
- STANDALONE_COMPLETED_SURFACES,
6
- STANDALONE_COMPLETION_PROFILE,
7
- STANDALONE_DEFERRED_EXECUTION_SURFACES,
8
- STANDALONE_PROMOTED_PARITY_GAP_SUMMARY,
9
- } from "../../constants.mjs";
10
- import { readTextIfFile, pathExists } from "../fs-helpers.mjs";
11
- import { arraysEqual } from "../value-helpers.mjs";
12
- import {
13
- parseYamlText,
14
- } from "../yaml-helpers.mjs";
15
- import { validateDocSpecAuditSummary } from "../contracts.mjs";
16
- import {
17
- emptyAuditArtifact,
18
- emptyCanonicalTree,
19
- } from "./doctor-state.mjs";
20
-
21
- export function inspectStandaloneCompletionTruth(productScopeText) {
22
- const parsed = parseYamlText(productScopeText);
23
- const completion = parsed?.standalone_completion;
24
-
25
- const completionProfile = typeof completion?.profile === "string" ? completion.profile : null;
26
- const completedSurfaces = Array.isArray(completion?.completed_surfaces)
27
- ? completion.completed_surfaces.map((entry) => String(entry))
28
- : [];
29
- const deferredExecutionSurfaces = Array.isArray(completion?.deferred_execution_surfaces)
30
- ? completion.deferred_execution_surfaces.map((entry) => String(entry))
31
- : [];
32
- const promotedParityGapSummary = Array.isArray(completion?.promoted_parity_gap_summary)
33
- ? completion.promoted_parity_gap_summary.map((entry) => String(entry))
34
- : [];
35
-
36
- const ok = completionProfile === STANDALONE_COMPLETION_PROFILE
37
- && arraysEqual(completedSurfaces, STANDALONE_COMPLETED_SURFACES)
38
- && arraysEqual(deferredExecutionSurfaces, STANDALONE_DEFERRED_EXECUTION_SURFACES)
39
- && arraysEqual(promotedParityGapSummary, STANDALONE_PROMOTED_PARITY_GAP_SUMMARY);
40
-
41
- return {
42
- ok,
43
- completionProfile,
44
- completedSurfaces,
45
- deferredExecutionSurfaces,
46
- promotedParityGapSummary,
47
- };
48
- }
49
-
50
- export function inspectPackageBoundaryTruth(boundariesText, changePolicyText) {
51
- const boundaries = parseYamlText(boundariesText);
52
- const changePolicy = parseYamlText(changePolicyText);
53
-
54
- const boundaryOk = Array.isArray(boundaries?.boundaries)
55
- && boundaries.boundaries.some((entry) => entry?.boundary === "standalone_boundary_completion_vs_promoted_runtime_parity")
56
- && Array.isArray(boundaries?.invariants)
57
- && boundaries.invariants.includes("standalone completion posture remains boundary_complete rather than promoted_runtime_parity")
58
- && Array.isArray(boundaries?.fail_closed_rules)
59
- && boundaries.fail_closed_rules.includes("fail if package-owned standalone completion truth drifts into claiming run kernel, provider runtime, scheduler, notification, or automation ownership");
60
-
61
- const runtimeBoundaryWorkType = Array.isArray(changePolicy?.work_types)
62
- ? changePolicy.work_types.find((entry) => entry?.id === "runtime_boundary_expansion")
63
- : null;
64
- const runtimeBoundaryGate = Array.isArray(changePolicy?.authority_gates)
65
- ? changePolicy.authority_gates.find((entry) => entry?.gate === "runtime_boundary_preservation")
66
- : null;
67
- const changePolicyOk = Boolean(runtimeBoundaryWorkType)
68
- && typeof runtimeBoundaryWorkType.notes === "string"
69
- && runtimeBoundaryWorkType.notes.includes("topic lifecycle runtime")
70
- && runtimeBoundaryWorkType.notes.includes("packet-bound run kernel")
71
- && runtimeBoundaryWorkType.notes.includes("provider execution")
72
- && Boolean(runtimeBoundaryGate)
73
- && typeof runtimeBoundaryGate.enforcement === "string"
74
- && runtimeBoundaryGate.enforcement.includes("boundary-complete standalone");
75
-
76
- return {
77
- ok: boundaryOk && changePolicyOk,
78
- boundaryOk,
79
- changePolicyOk,
80
- };
81
- }
82
-
83
- export function buildHostCompatibilityReport(externalHostCompatibilityContract, adapterProfiles, selectedAdapterId) {
84
- const admittedOverlayIds = adapterProfiles.admitted.map((profile) => profile.id).filter(Boolean);
85
- const selectedOverlayId = selectedAdapterId && selectedAdapterId !== "none" ? selectedAdapterId : null;
86
- const selectedOverlayProfile = adapterProfiles.selected ?? null;
87
- const futureOnlyHostSurfaces = adapterProfiles.admitted.flatMap((profile) => {
88
- const commands = profile.promptHandoff?.futureSurface ?? [];
89
- const status = profile.promptHandoff?.futureSurfaceStatus ?? null;
90
- return commands.map((command) => ({
91
- adapterId: profile.id,
92
- status,
93
- command,
94
- }));
95
- });
96
- const nativeReviewSurfaces = adapterProfiles.admitted
97
- .filter((profile) => profile.nativeReviewBoundary)
98
- .map((profile) => ({
99
- adapterId: profile.id,
100
- approvalReviewScope: profile.nativeReviewBoundary.approvalReview.scope,
101
- approvalReviewSemanticEffect: profile.nativeReviewBoundary.approvalReview.semanticEffect,
102
- githubAutoReviewScope: profile.nativeReviewBoundary.githubAutoReview.scope,
103
- githubAutoReviewSemanticEffect: profile.nativeReviewBoundary.githubAutoReview.semanticEffect,
104
- forbiddenSemanticSubstitutions: profile.nativeReviewBoundary.forbiddenSemanticSubstitutions,
105
- }));
106
-
107
- let overlayMode = "generic_only";
108
- if (admittedOverlayIds.length > 0) {
109
- overlayMode = selectedOverlayId ? "named_admitted_overlay_selected" : "named_admitted_overlay_available";
110
- }
111
-
112
- return {
113
- contractRef: EXTERNAL_HOST_COMPATIBILITY_CONTRACT_REF,
114
- supportedHostPosture: externalHostCompatibilityContract.supportedHostPosture,
115
- supportedHostExamples: externalHostCompatibilityContract.supportedHostExamples,
116
- requiredBehavior: externalHostCompatibilityContract.requiredBehavior,
117
- forbiddenBehavior: externalHostCompatibilityContract.forbiddenBehavior,
118
- genericExternalHostCompatible: externalHostCompatibilityContract.ok
119
- && externalHostCompatibilityContract.supportedHostPosture.includes("host_agnostic_external_host"),
120
- namedOverlaySupport: {
121
- mode: overlayMode,
122
- admittedOverlayIds,
123
- selectedOverlayId,
124
- selectedOverlayProfileRef: selectedOverlayProfile?.profileRef ?? null,
125
- selectedOverlayHostClass: selectedOverlayProfile?.hostClass ?? null,
126
- },
127
- futureOnlyHostSurfaces,
128
- nativeReviewSurfaces,
129
- };
130
- }
131
-
132
- export async function inspectLocalDocSpecAuditArtifact(projectRoot, auditContract) {
133
- const artifact = emptyAuditArtifact();
134
- const absolutePath = path.join(projectRoot, artifact.artifactPath);
135
- const text = await readTextIfFile(absolutePath);
136
- if (text === null) {
137
- return artifact;
138
- }
139
-
140
- artifact.present = true;
141
-
142
- let parsed;
143
- try {
144
- parsed = JSON.parse(text);
145
- } catch {
146
- artifact.ok = false;
147
- artifact.reason = "Local doc_spec_audit closeout artifact is not valid JSON";
148
- return artifact;
149
- }
150
-
151
- const skillId = typeof parsed.skill === "string"
152
- ? parsed.skill
153
- : parsed.skill && typeof parsed.skill === "object"
154
- ? parsed.skill.id
155
- : null;
156
-
157
- if (skillId !== "doc_spec_audit") {
158
- artifact.ok = false;
159
- artifact.reason = "Local doc_spec_audit closeout artifact declares the wrong skill id";
160
- return artifact;
161
- }
162
-
163
- artifact.outcome = parsed.outcome ?? null;
164
- artifact.verifiedAt = parsed.verifiedAt ?? null;
165
-
166
- if (!parsed.summary) {
167
- artifact.reason = `Local doc_spec_audit closeout artifact detected with outcome ${parsed.outcome ?? "unknown"}`;
168
- return artifact;
169
- }
170
-
171
- const validation = validateDocSpecAuditSummary(parsed.summary, auditContract, parsed.verifiedAt);
172
- if (!validation.ok) {
173
- artifact.ok = false;
174
- artifact.reason = validation.reason;
175
- return artifact;
176
- }
177
-
178
- artifact.summaryStatus = parsed.summary.status;
179
- artifact.reason = `Local doc_spec_audit closeout artifact detected: outcome ${parsed.outcome}, summary status ${parsed.summary.status}`;
180
- return artifact;
181
- }
182
-
183
- export function inspectBootstrapStateContract(bootstrapStateText) {
184
- const parsed = parseYamlText(bootstrapStateText);
185
- const mode = parsed?.state?.mode ?? null;
186
- const treeState = parsed?.state?.tree_state ?? null;
187
- const authorityMode = parsed?.state?.authority_mode === "external_blueprint_active"
188
- ? "external_authority_active"
189
- : parsed?.state?.authority_mode ?? null;
190
- const blueprintMode = parsed?.state?.blueprint_mode ?? null;
191
- const reconstructionRequired = parsed?.state?.reconstruction_required;
192
- const readyForAiReconstruction = parsed?.status?.ready_for_ai_reconstruction;
193
- const lifecycleContract = parsed?.lifecycle_contract ?? null;
194
- const supportedMode = mode === "bootstrap_only" || mode === "reconstruction_seeded";
195
- const supportedTreeState = Array.isArray(lifecycleContract?.tree_state_enum)
196
- ? lifecycleContract.tree_state_enum.includes(treeState)
197
- : false;
198
- const supportedAuthorityMode = Array.isArray(lifecycleContract?.authority_mode_enum)
199
- ? lifecycleContract.authority_mode_enum.includes(authorityMode)
200
- : false;
201
- const supportedBlueprintMode = Array.isArray(lifecycleContract?.blueprint_mode_enum)
202
- ? lifecycleContract.blueprint_mode_enum.includes(blueprintMode)
203
- : false;
204
- const legacyModeMapping = Array.isArray(lifecycleContract?.legacy_mode_mapping)
205
- ? lifecycleContract.legacy_mode_mapping
206
- .map((entry) => ({
207
- ...entry,
208
- authority_mode: entry?.authority_mode === "external_blueprint_active"
209
- ? "external_authority_active"
210
- : entry?.authority_mode,
211
- }))
212
- .find((entry) => entry?.legacy_mode === mode) ?? null
213
- : null;
214
- const modeSpecificContractOk = (
215
- mode === "bootstrap_only"
216
- && reconstructionRequired === true
217
- && readyForAiReconstruction === true
218
- ) || (
219
- mode === "reconstruction_seeded"
220
- && reconstructionRequired === false
221
- && readyForAiReconstruction === false
222
- );
223
- const multiAxisAligned = (
224
- legacyModeMapping
225
- && legacyModeMapping.tree_state === treeState
226
- && legacyModeMapping.authority_mode === authorityMode
227
- && legacyModeMapping.reconstruction_required === reconstructionRequired
228
- && legacyModeMapping.ready_for_ai_reconstruction === readyForAiReconstruction
229
- ) || (
230
- mode === "reconstruction_seeded"
231
- && treeState === "canonical_tree_ready"
232
- && authorityMode === "external_authority_active"
233
- && reconstructionRequired === false
234
- && readyForAiReconstruction === false
235
- ) || (
236
- mode === "reconstruction_seeded"
237
- && treeState === "canonical_tree_ready"
238
- && authorityMode === "canonical_active"
239
- && reconstructionRequired === false
240
- && readyForAiReconstruction === false
241
- );
242
-
243
- return {
244
- mode,
245
- treeState,
246
- authorityMode,
247
- blueprintMode,
248
- supportedMode,
249
- supportedTreeState,
250
- supportedAuthorityMode,
251
- supportedBlueprintMode,
252
- reconstructionRequired,
253
- readyForAiReconstruction,
254
- cutoverReadiness: parsed?.cutover_readiness ?? {},
255
- activeAuthorityRoot: parsed?.status?.active_authority_root ?? null,
256
- ok: Boolean(bootstrapStateText)
257
- && supportedMode
258
- && supportedTreeState
259
- && supportedAuthorityMode
260
- && supportedBlueprintMode
261
- && modeSpecificContractOk
262
- && multiAxisAligned,
263
- };
264
- }
265
-
266
- export async function inspectCanonicalTree(projectRoot, specTreeModel) {
267
- if (!specTreeModel.ok) {
268
- const reconstructionText = await readTextIfFile(path.join(projectRoot, ".nimi", "methodology", "spec-reconstruction.yaml"));
269
- const reconstruction = parseYamlText(reconstructionText);
270
- const requiredFiles = Array.isArray(reconstruction?.reconstruction?.target_tree_shape?.minimal_required_outputs)
271
- ? reconstruction.reconstruction.target_tree_shape.minimal_required_outputs.map(String)
272
- : [];
273
- const canonicalRoot = typeof reconstruction?.reconstruction?.target_root === "string"
274
- ? reconstruction.reconstruction.target_root
275
- : ".nimi/spec";
276
- const present = [];
277
- const missing = [];
278
-
279
- for (const relativePath of requiredFiles) {
280
- const info = await pathExists(path.join(projectRoot, relativePath));
281
- if (info && info.isFile()) {
282
- present.push(relativePath);
283
- } else {
284
- missing.push(relativePath);
285
- }
286
- }
287
-
288
- if (requiredFiles.length === 0) {
289
- return emptyCanonicalTree();
290
- }
291
-
292
- return {
293
- profile: "surface_taxonomy_v1",
294
- canonicalRoot,
295
- requiredFiles,
296
- present,
297
- missing,
298
- invalid: [],
299
- requiredFilesValid: missing.length === 0,
300
- ready: missing.length === 0,
301
- };
302
- }
303
-
304
- const requiredFiles = specTreeModel.requiredFilesByProfile[specTreeModel.profile] ?? [];
305
- const present = [];
306
- const missing = [];
307
-
308
- for (const relativePath of requiredFiles) {
309
- const info = await pathExists(path.join(projectRoot, relativePath));
310
- if (info && info.isFile()) {
311
- present.push(relativePath);
312
- } else {
313
- missing.push(relativePath);
314
- }
315
- }
316
-
317
- return {
318
- profile: specTreeModel.profile,
319
- canonicalRoot: specTreeModel.canonicalRoot,
320
- requiredFiles,
321
- present,
322
- missing,
323
- invalid: [],
324
- requiredFilesValid: missing.length === 0,
325
- ready: missing.length === 0,
326
- };
327
- }