@nimiplatform/nimi-coding 0.2.8 → 0.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 (206) hide show
  1. package/CHANGELOG.md +10 -90
  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/commands/validate-spec-governance.mjs +20 -0
  8. package/cli/constants.mjs +9 -417
  9. package/cli/help.mjs +28 -145
  10. package/cli/index.mjs +5 -33
  11. package/cli/lib/blueprint-audit.mjs +5 -12
  12. package/cli/lib/bootstrap.mjs +0 -9
  13. package/cli/lib/contracts.mjs +0 -163
  14. package/cli/lib/doctor.mjs +155 -10
  15. package/cli/lib/entrypoints.mjs +63 -167
  16. package/cli/lib/internal/contracts-loaders.mjs +0 -85
  17. package/cli/lib/internal/contracts-parse.mjs +84 -520
  18. package/cli/lib/internal/governance/ai/check-agents-freshness.mjs +13 -8
  19. package/cli/lib/internal/surface-taxonomy-validators.mjs +316 -66
  20. package/cli/lib/internal/validators-shared.mjs +0 -16
  21. package/cli/lib/internal/validators-spec-helpers.mjs +7 -140
  22. package/cli/lib/internal/validators-spec.mjs +103 -342
  23. package/cli/lib/shared.mjs +1 -42
  24. package/cli/lib/validators.mjs +0 -48
  25. package/cli/seeds/seed-policy.yaml +0 -3
  26. package/config/bootstrap.yaml +4 -4
  27. package/config/spec-generation-inputs.yaml +6 -12
  28. package/contracts/domain-admission.schema.yaml +3 -3
  29. package/contracts/migration-inventory.schema.yaml +12 -75
  30. package/contracts/negative-fixtures.yaml +19 -99
  31. package/contracts/placement-contract.schema.yaml +49 -78
  32. package/contracts/projection-edge.schema.yaml +37 -121
  33. package/contracts/shared-enums.yaml +4 -8
  34. package/contracts/spec-generation-inputs.schema.yaml +15 -112
  35. package/contracts/spec-layout.schema.yaml +32 -0
  36. package/contracts/surface-taxonomy.schema.yaml +43 -94
  37. package/contracts/table-family.schema.yaml +1 -1
  38. package/contracts/tracked-output-admission.schema.yaml +13 -66
  39. package/methodology/core.yaml +33 -25
  40. package/methodology/four-closure-policy.yaml +18 -26
  41. package/methodology/role-separation-policy.yaml +21 -27
  42. package/methodology/spec-reconstruction.yaml +17 -34
  43. package/package.json +2 -4
  44. package/spec/_meta/spec-tree-model.yaml +5 -101
  45. package/spec/product-scope.yaml +25 -57
  46. package/adapters/README.md +0 -25
  47. package/adapters/claude/README.md +0 -89
  48. package/adapters/claude/profile.yaml +0 -70
  49. package/adapters/codex/README.md +0 -53
  50. package/adapters/codex/profile.yaml +0 -78
  51. package/adapters/oh-my-codex/README.md +0 -184
  52. package/adapters/oh-my-codex/profile.yaml +0 -46
  53. package/cli/commands/admit-high-risk-decision.mjs +0 -108
  54. package/cli/commands/audit-sweep.mjs +0 -364
  55. package/cli/commands/closeout.mjs +0 -186
  56. package/cli/commands/decide-high-risk-execution.mjs +0 -124
  57. package/cli/commands/handoff.mjs +0 -123
  58. package/cli/commands/ingest-high-risk-execution.mjs +0 -95
  59. package/cli/commands/review-high-risk-execution.mjs +0 -95
  60. package/cli/commands/sweep-design.mjs +0 -295
  61. package/cli/commands/sweep.mjs +0 -22
  62. package/cli/commands/topic-formatters.mjs +0 -382
  63. package/cli/commands/topic-goal.mjs +0 -33
  64. package/cli/commands/topic-options-shared.mjs +0 -27
  65. package/cli/commands/topic-options-workflow.mjs +0 -767
  66. package/cli/commands/topic-options.mjs +0 -626
  67. package/cli/commands/topic-runner.mjs +0 -169
  68. package/cli/commands/topic.mjs +0 -795
  69. package/cli/commands/validate-acceptance.mjs +0 -5
  70. package/cli/commands/validate-execution-packet.mjs +0 -5
  71. package/cli/commands/validate-orchestration-state.mjs +0 -5
  72. package/cli/commands/validate-prompt.mjs +0 -5
  73. package/cli/commands/validate-worker-output.mjs +0 -5
  74. package/cli/lib/adapter-profiles.mjs +0 -403
  75. package/cli/lib/audit-execution.mjs +0 -52
  76. package/cli/lib/audit-sweep-runtime/admissions.mjs +0 -508
  77. package/cli/lib/audit-sweep-runtime/audit-validity.mjs +0 -356
  78. package/cli/lib/audit-sweep-runtime/chunks.mjs +0 -697
  79. package/cli/lib/audit-sweep-runtime/claude-auditor.mjs +0 -658
  80. package/cli/lib/audit-sweep-runtime/closeout.mjs +0 -144
  81. package/cli/lib/audit-sweep-runtime/codex-auditor-evidence.mjs +0 -654
  82. package/cli/lib/audit-sweep-runtime/codex-auditor.mjs +0 -527
  83. package/cli/lib/audit-sweep-runtime/common.mjs +0 -341
  84. package/cli/lib/audit-sweep-runtime/coverage-quality.mjs +0 -172
  85. package/cli/lib/audit-sweep-runtime/evidence-assignment.mjs +0 -155
  86. package/cli/lib/audit-sweep-runtime/format.mjs +0 -57
  87. package/cli/lib/audit-sweep-runtime/ingest.mjs +0 -486
  88. package/cli/lib/audit-sweep-runtime/inventory-spec-chunks.mjs +0 -425
  89. package/cli/lib/audit-sweep-runtime/inventory.mjs +0 -798
  90. package/cli/lib/audit-sweep-runtime/ledger.mjs +0 -315
  91. package/cli/lib/audit-sweep-runtime/p0p1-profile.mjs +0 -101
  92. package/cli/lib/audit-sweep-runtime/remediation.mjs +0 -349
  93. package/cli/lib/audit-sweep-runtime/rerun.mjs +0 -129
  94. package/cli/lib/audit-sweep-runtime/risk-budget.mjs +0 -300
  95. package/cli/lib/audit-sweep-runtime/status.mjs +0 -62
  96. package/cli/lib/audit-sweep-runtime/validators-ledger.mjs +0 -215
  97. package/cli/lib/audit-sweep-runtime/validators.mjs +0 -797
  98. package/cli/lib/audit-sweep.mjs +0 -19
  99. package/cli/lib/authority-convergence.mjs +0 -720
  100. package/cli/lib/closeout.mjs +0 -732
  101. package/cli/lib/codex-sdk-runner.mjs +0 -76
  102. package/cli/lib/external-execution.mjs +0 -101
  103. package/cli/lib/handoff.mjs +0 -812
  104. package/cli/lib/high-risk-admission.mjs +0 -512
  105. package/cli/lib/high-risk-decision.mjs +0 -353
  106. package/cli/lib/high-risk-ingest.mjs +0 -321
  107. package/cli/lib/high-risk-review.mjs +0 -267
  108. package/cli/lib/internal/contracts-parse-high-risk.mjs +0 -131
  109. package/cli/lib/internal/contracts-validators.mjs +0 -399
  110. package/cli/lib/internal/doctor-bootstrap-surface.mjs +0 -406
  111. package/cli/lib/internal/doctor-delegated-surface.mjs +0 -256
  112. package/cli/lib/internal/doctor-finalize.mjs +0 -383
  113. package/cli/lib/internal/doctor-format.mjs +0 -286
  114. package/cli/lib/internal/doctor-inspectors.mjs +0 -327
  115. package/cli/lib/internal/doctor-state.mjs +0 -205
  116. package/cli/lib/internal/validators-artifacts.mjs +0 -515
  117. package/cli/lib/sweep-design-runtime/common.mjs +0 -246
  118. package/cli/lib/sweep-design-runtime/engine.mjs +0 -733
  119. package/cli/lib/sweep-design-runtime/fix-topic.mjs +0 -414
  120. package/cli/lib/sweep-design-runtime/lifecycle.mjs +0 -54
  121. package/cli/lib/sweep-design-runtime/results.mjs +0 -324
  122. package/cli/lib/sweep-design.mjs +0 -8
  123. package/cli/lib/topic-artifacts.mjs +0 -186
  124. package/cli/lib/topic-authority-coverage.mjs +0 -73
  125. package/cli/lib/topic-closeout.mjs +0 -560
  126. package/cli/lib/topic-common.mjs +0 -404
  127. package/cli/lib/topic-decisions.mjs +0 -332
  128. package/cli/lib/topic-draft-packets.mjs +0 -167
  129. package/cli/lib/topic-execution.mjs +0 -533
  130. package/cli/lib/topic-goal.mjs +0 -440
  131. package/cli/lib/topic-ledger.mjs +0 -281
  132. package/cli/lib/topic-lifecycle-artifacts.mjs +0 -173
  133. package/cli/lib/topic-root-validation.mjs +0 -288
  134. package/cli/lib/topic-runner-commands.mjs +0 -174
  135. package/cli/lib/topic-runner-deferral.mjs +0 -532
  136. package/cli/lib/topic-runner-stale-gates.mjs +0 -114
  137. package/cli/lib/topic-runner-validation.mjs +0 -138
  138. package/cli/lib/topic-runner.mjs +0 -727
  139. package/cli/lib/topic-scaffold.mjs +0 -252
  140. package/cli/lib/topic-waves.mjs +0 -403
  141. package/cli/lib/topic.mjs +0 -81
  142. package/config/audit-execution-artifacts.yaml +0 -20
  143. package/config/external-execution-artifacts.yaml +0 -16
  144. package/config/host-adapter.yaml +0 -30
  145. package/config/host-profile.yaml +0 -29
  146. package/config/installer-evidence.yaml +0 -31
  147. package/config/skill-installer.yaml +0 -23
  148. package/config/skill-manifest.yaml +0 -48
  149. package/config/skills.yaml +0 -30
  150. package/contracts/acceptance.schema.yaml +0 -16
  151. package/contracts/admission-checklist.schema.yaml +0 -15
  152. package/contracts/audit-chunk.schema.yaml +0 -123
  153. package/contracts/audit-closeout.schema.yaml +0 -51
  154. package/contracts/audit-finding.schema.yaml +0 -61
  155. package/contracts/audit-ledger.schema.yaml +0 -138
  156. package/contracts/audit-plan.schema.yaml +0 -138
  157. package/contracts/audit-remediation-map.schema.yaml +0 -52
  158. package/contracts/audit-rerun.schema.yaml +0 -31
  159. package/contracts/audit-sweep-result.yaml +0 -53
  160. package/contracts/authority-convergence-audit.schema.yaml +0 -19
  161. package/contracts/closeout.schema.yaml +0 -25
  162. package/contracts/decision-review.schema.yaml +0 -16
  163. package/contracts/doc-spec-audit-result.yaml +0 -19
  164. package/contracts/execution-packet.schema.yaml +0 -49
  165. package/contracts/external-host-compatibility.yaml +0 -22
  166. package/contracts/forbidden-shortcuts.catalog.yaml +0 -23
  167. package/contracts/high-risk-admission.schema.yaml +0 -23
  168. package/contracts/high-risk-execution-result.yaml +0 -20
  169. package/contracts/orchestration-state.schema.yaml +0 -41
  170. package/contracts/overflow-continuation.schema.yaml +0 -12
  171. package/contracts/packet.schema.yaml +0 -30
  172. package/contracts/pending-note.schema.yaml +0 -17
  173. package/contracts/prompt.schema.yaml +0 -12
  174. package/contracts/remediation.schema.yaml +0 -16
  175. package/contracts/result.schema.yaml +0 -24
  176. package/contracts/spec-reconstruction-result.yaml +0 -41
  177. package/contracts/sweep-design-result.yaml +0 -349
  178. package/contracts/topic-goal.schema.yaml +0 -87
  179. package/contracts/topic-run-ledger.schema.yaml +0 -72
  180. package/contracts/topic-step-decision.schema.yaml +0 -45
  181. package/contracts/topic.schema.yaml +0 -65
  182. package/contracts/true-close.schema.yaml +0 -15
  183. package/contracts/wave.schema.yaml +0 -29
  184. package/contracts/worker-output.schema.yaml +0 -15
  185. package/contracts/workflow-consumer.schema.yaml +0 -110
  186. package/methodology/audit-sweep-p0p1-recall.yaml +0 -45
  187. package/methodology/authority-convergence-policy.yaml +0 -42
  188. package/methodology/overflow-continuation-policy.yaml +0 -14
  189. package/methodology/skill-exchange-projection.yaml +0 -114
  190. package/methodology/skill-handoff.yaml +0 -34
  191. package/methodology/skill-installer-result.yaml +0 -27
  192. package/methodology/skill-installer-summary-projection.yaml +0 -181
  193. package/methodology/skill-runtime.yaml +0 -23
  194. package/methodology/spec-target-truth-profile.yaml +0 -46
  195. package/methodology/topic-lifecycle-report.yaml +0 -144
  196. package/methodology/topic-lifecycle.yaml +0 -37
  197. package/methodology/topic-naming-ontology.yaml +0 -21
  198. package/methodology/topic-ontology.yaml +0 -38
  199. package/methodology/topic-validation-policy.yaml +0 -9
  200. package/methodology/wave-dag-policy.yaml +0 -14
  201. package/spec/_meta/command-gating-matrix.yaml +0 -143
  202. package/spec/_meta/generate-drift-migration-checklist.yaml +0 -137
  203. package/spec/_meta/governance-routing-cutover-checklist.yaml +0 -35
  204. package/spec/_meta/phase2-impacted-surface-matrix.yaml +0 -44
  205. package/spec/_meta/spec-authority-cutover-readiness.yaml +0 -102
  206. package/spec/bootstrap-state.yaml +0 -99
@@ -1,406 +0,0 @@
1
- import path from "node:path";
2
-
3
- import {
4
- BLUEPRINT_REFERENCE_REF,
5
- COMMAND_GATING_MATRIX_REF,
6
- LOCAL_GITIGNORE_ENTRIES,
7
- PACKAGE_NAME,
8
- REQUIRED_LOCAL_DIRS,
9
- SPEC_GENERATION_AUDIT_CONTRACT_REF,
10
- SPEC_GENERATION_AUDIT_REF,
11
- SPEC_GENERATION_INPUTS_CONTRACT_REF,
12
- SPEC_GENERATION_INPUTS_REF,
13
- SPEC_TREE_MODEL_REF,
14
- } from "../../constants.mjs";
15
- import { getBootstrapSeedEntries } from "../../seeds/bootstrap.mjs";
16
- import { inspectBootstrapCompatibility } from "../bootstrap.mjs";
17
- import {
18
- findCommandGatingRule,
19
- loadBlueprintReference,
20
- loadCommandGatingMatrix,
21
- loadSpecGenerationAuditContract,
22
- loadSpecGenerationInputsConfig,
23
- loadSpecGenerationInputsContract,
24
- loadSpecTreeModelContract,
25
- } from "../contracts.mjs";
26
- import { pathExists, readTextIfFile } from "../fs-helpers.mjs";
27
- import { validateSpecAudit } from "../validators.mjs";
28
- import {
29
- readYamlScalar,
30
- } from "../yaml-helpers.mjs";
31
- import {
32
- buildCheck,
33
- createDoctorMissingRootResult,
34
- emptySpecGenerationAudit,
35
- } from "./doctor-state.mjs";
36
- import {
37
- inspectBootstrapStateContract,
38
- inspectCanonicalTree,
39
- inspectStandaloneCompletionTruth,
40
- } from "./doctor-inspectors.mjs";
41
-
42
- export async function inspectDoctorBootstrapSurface(projectRoot) {
43
- const nimiRoot = path.join(projectRoot, ".nimi");
44
- const checks = [];
45
-
46
- const nimiInfo = await pathExists(nimiRoot);
47
- if (!nimiInfo) {
48
- return {
49
- done: true,
50
- result: createDoctorMissingRootResult(
51
- projectRoot,
52
- ".nimi directory is missing",
53
- "Run `nimicoding start` to seed the project-local .nimi bootstrap truth.",
54
- ),
55
- };
56
- }
57
-
58
- if (!nimiInfo.isDirectory()) {
59
- return {
60
- done: true,
61
- result: createDoctorMissingRootResult(
62
- projectRoot,
63
- ".nimi exists but is not a directory",
64
- "Replace the non-directory `.nimi` path, then rerun `nimicoding start`.",
65
- ),
66
- };
67
- }
68
-
69
- checks.push(buildCheck("nimi_root", true, ".nimi directory exists"));
70
-
71
- const seedEntries = await getBootstrapSeedEntries();
72
- const missingBootstrapFiles = [];
73
- const driftedPackageCanonicalFiles = [];
74
- for (const entry of seedEntries) {
75
- const absolutePath = path.join(projectRoot, entry.outputRelativePath);
76
- const info = await pathExists(absolutePath);
77
- if (!info || !info.isFile()) {
78
- missingBootstrapFiles.push(entry.outputRelativePath);
79
- continue;
80
- }
81
- if (entry.ownership !== "package_canonical") {
82
- continue;
83
- }
84
- const actual = await readTextIfFile(absolutePath);
85
- if (actual !== entry.content) {
86
- driftedPackageCanonicalFiles.push(entry.outputRelativePath);
87
- }
88
- }
89
- checks.push(
90
- buildCheck(
91
- "bootstrap_seed_files",
92
- missingBootstrapFiles.length === 0,
93
- missingBootstrapFiles.length === 0
94
- ? `All bootstrap seed files declared by the seed projection policy are present (${seedEntries.length}/${seedEntries.length})`
95
- : `Missing bootstrap seed files declared by the seed projection policy: ${missingBootstrapFiles.join(", ")}`,
96
- ),
97
- );
98
- checks.push({
99
- id: "bootstrap_seed_package_canonical_in_sync",
100
- ok: true,
101
- severity: driftedPackageCanonicalFiles.length === 0 ? "ok" : "warn",
102
- detail: driftedPackageCanonicalFiles.length === 0
103
- ? "All package_canonical seed files match package source byte-for-byte"
104
- : `package_canonical seed files diverge from package source; run \`nimicoding sync --apply\` to refresh, or \`nimicoding sync --check\` for the authoritative gate: ${driftedPackageCanonicalFiles.join(", ")}`,
105
- });
106
-
107
- const missingLocalDirs = [];
108
- for (const relativePath of REQUIRED_LOCAL_DIRS) {
109
- const info = await pathExists(path.join(projectRoot, relativePath));
110
- if (!info || !info.isDirectory()) {
111
- missingLocalDirs.push(relativePath);
112
- }
113
- }
114
- checks.push({
115
- id: "local_state_dirs",
116
- ok: true,
117
- severity: missingLocalDirs.length === 0 ? "ok" : "warn",
118
- detail: missingLocalDirs.length === 0
119
- ? "Local state directories are present"
120
- : `Local state directories are absent and can be recreated on demand: ${missingLocalDirs.join(", ")}`,
121
- });
122
-
123
- const gitignoreText = await readTextIfFile(path.join(projectRoot, ".gitignore"));
124
- const missingGitignoreEntries = gitignoreText === null
125
- ? LOCAL_GITIGNORE_ENTRIES.slice()
126
- : LOCAL_GITIGNORE_ENTRIES.filter((entry) => !gitignoreText.includes(entry));
127
- checks.push(
128
- buildCheck(
129
- "gitignore_local_state",
130
- missingGitignoreEntries.length === 0,
131
- missingGitignoreEntries.length === 0
132
- ? "Local nimicoding state is ignored by .gitignore"
133
- : `.gitignore is missing local-state entries: ${missingGitignoreEntries.join(", ")}`,
134
- ),
135
- );
136
-
137
- const bootstrapConfigText = await readTextIfFile(path.join(projectRoot, ".nimi", "config", "bootstrap.yaml"));
138
- const bootstrapIdentityOk = Boolean(bootstrapConfigText)
139
- && readYamlScalar(bootstrapConfigText, "initialized_by") === PACKAGE_NAME
140
- && Boolean(readYamlScalar(bootstrapConfigText, "cli_version"));
141
- checks.push(
142
- buildCheck(
143
- "bootstrap_config_contract",
144
- bootstrapIdentityOk,
145
- bootstrapIdentityOk
146
- ? "bootstrap.yaml declares the package bootstrap identity"
147
- : "bootstrap.yaml is missing or does not match the package bootstrap identity",
148
- ),
149
- );
150
-
151
- const bootstrapCompatibility = await inspectBootstrapCompatibility(projectRoot);
152
- checks.push({
153
- id: "bootstrap_contract_version",
154
- ok: bootstrapCompatibility.status !== "unsupported",
155
- severity: bootstrapCompatibility.status === "supported"
156
- ? "ok"
157
- : bootstrapCompatibility.status === "legacy"
158
- ? "warn"
159
- : bootstrapCompatibility.status === "missing"
160
- ? "warn"
161
- : "error",
162
- detail: bootstrapCompatibility.status === "supported"
163
- ? `bootstrap contract ${bootstrapCompatibility.contractId} version ${bootstrapCompatibility.contractVersion} is supported`
164
- : bootstrapCompatibility.status === "legacy"
165
- ? "bootstrap.yaml was created by nimicoding but is missing bootstrap contract metadata"
166
- : bootstrapCompatibility.status === "missing"
167
- ? "bootstrap.yaml is missing and bootstrap contract compatibility could not be checked"
168
- : "bootstrap.yaml declares an unsupported bootstrap contract id or version",
169
- });
170
-
171
- const specGenerationInputsContract = await loadSpecGenerationInputsContract(projectRoot);
172
- const specGenerationAuditContract = await loadSpecGenerationAuditContract(projectRoot);
173
- const specGenerationInputs = await loadSpecGenerationInputsConfig(projectRoot);
174
- const usesV2SurfaceModel = specGenerationInputs.ok && specGenerationInputs.mode === "class_filtered";
175
-
176
- const bootstrapStateText = await readTextIfFile(path.join(projectRoot, ".nimi", "spec", "bootstrap-state.yaml"));
177
- const bootstrapStateContract = inspectBootstrapStateContract(bootstrapStateText);
178
- checks.push(
179
- buildCheck(
180
- "bootstrap_state_contract",
181
- usesV2SurfaceModel || bootstrapStateContract.ok,
182
- usesV2SurfaceModel
183
- ? "v2 host-local surface model does not require .nimi/spec/bootstrap-state.yaml"
184
- : bootstrapStateContract.ok
185
- ? `bootstrap-state.yaml matches the ${bootstrapStateContract.treeState} tree-state contract`
186
- : "bootstrap-state.yaml is missing required lifecycle fields or declares an unsupported lifecycle state",
187
- usesV2SurfaceModel ? "info" : undefined,
188
- ),
189
- );
190
-
191
- const productScopeText = await readTextIfFile(path.join(projectRoot, ".nimi", "spec", "product-scope.yaml"));
192
- const completionTruth = inspectStandaloneCompletionTruth(productScopeText);
193
- checks.push(
194
- buildCheck(
195
- "standalone_completion_truth",
196
- usesV2SurfaceModel || completionTruth.ok,
197
- usesV2SurfaceModel
198
- ? "v2 host-local surface model does not require .nimi/spec/product-scope.yaml"
199
- : completionTruth.ok
200
- ? `Product scope declares standalone completion profile ${completionTruth.completionProfile}`
201
- : "product-scope.yaml is missing or drifted from the package-owned standalone completion truth",
202
- usesV2SurfaceModel ? "info" : undefined,
203
- ),
204
- );
205
-
206
- const specTreeModel = await loadSpecTreeModelContract(projectRoot);
207
- checks.push(
208
- buildCheck(
209
- "spec_tree_model_contract",
210
- usesV2SurfaceModel || specTreeModel.ok,
211
- usesV2SurfaceModel
212
- ? ".nimi/contracts/surface-taxonomy.schema.yaml supplies the v2 spec surface profile"
213
- : specTreeModel.ok
214
- ? `${SPEC_TREE_MODEL_REF} declares canonical root ${specTreeModel.canonicalRoot} with profile ${specTreeModel.profile}`
215
- : `${SPEC_TREE_MODEL_REF} is missing or malformed`,
216
- usesV2SurfaceModel ? "ok" : undefined,
217
- ),
218
- );
219
-
220
- checks.push(
221
- buildCheck(
222
- "spec_generation_inputs_contract",
223
- specGenerationInputsContract.ok,
224
- specGenerationInputsContract.ok
225
- ? `${SPEC_GENERATION_INPUTS_CONTRACT_REF} is present and structurally valid`
226
- : `${SPEC_GENERATION_INPUTS_CONTRACT_REF} is missing or malformed`,
227
- ),
228
- );
229
-
230
- checks.push(
231
- buildCheck(
232
- "spec_generation_audit_contract",
233
- specGenerationAuditContract.ok,
234
- specGenerationAuditContract.ok
235
- ? `${SPEC_GENERATION_AUDIT_CONTRACT_REF} is present and structurally valid`
236
- : `${SPEC_GENERATION_AUDIT_CONTRACT_REF} is missing or malformed`,
237
- ),
238
- );
239
-
240
- checks.push(
241
- buildCheck(
242
- "spec_generation_inputs_config",
243
- specGenerationInputs.ok,
244
- specGenerationInputs.ok
245
- ? `${SPEC_GENERATION_INPUTS_REF} declares ${specGenerationInputs.mode} canonical spec generation inputs`
246
- : `${SPEC_GENERATION_INPUTS_REF} is missing or malformed`,
247
- ),
248
- );
249
-
250
- const commandGatingMatrix = await loadCommandGatingMatrix(projectRoot);
251
- checks.push(
252
- buildCheck(
253
- "command_gating_matrix_contract",
254
- usesV2SurfaceModel || commandGatingMatrix.ok,
255
- usesV2SurfaceModel
256
- ? "v2 workflow gates are provided by project-local .nimi/contracts and .nimi/methodology"
257
- : commandGatingMatrix.ok
258
- ? `${COMMAND_GATING_MATRIX_REF} declares ${commandGatingMatrix.entries.length} command gating rules`
259
- : `${COMMAND_GATING_MATRIX_REF} is missing or malformed`,
260
- usesV2SurfaceModel ? "ok" : undefined,
261
- ),
262
- );
263
-
264
- const blueprintReference = await loadBlueprintReference(projectRoot);
265
- const blueprintReferenceExpected = usesV2SurfaceModel
266
- ? specGenerationInputs.benchmarkMode !== "none" || typeof specGenerationInputs.benchmarkBlueprintRoot === "string"
267
- : bootstrapStateContract.blueprintMode !== "none";
268
- const expectedBlueprintCanonicalRoot = usesV2SurfaceModel
269
- ? specGenerationInputs.canonicalTargetRoot
270
- : specTreeModel.canonicalRoot;
271
- const blueprintReferenceAligned = !blueprintReferenceExpected
272
- ? !blueprintReference.present
273
- : blueprintReference.present
274
- && blueprintReference.ok
275
- && (usesV2SurfaceModel || blueprintReference.mode === bootstrapStateContract.blueprintMode)
276
- && blueprintReference.canonicalTargetRoot === expectedBlueprintCanonicalRoot;
277
- checks.push(
278
- buildCheck(
279
- "blueprint_reference_contract",
280
- blueprintReferenceAligned,
281
- blueprintReferenceExpected
282
- ? blueprintReferenceAligned
283
- ? `${BLUEPRINT_REFERENCE_REF} matches blueprint mode ${bootstrapStateContract.blueprintMode}`
284
- : `${BLUEPRINT_REFERENCE_REF} is required and must match the declared blueprint mode`
285
- : "No explicit project-local blueprint reference is declared",
286
- blueprintReferenceExpected
287
- ? (blueprintReferenceAligned ? "ok" : "error")
288
- : "info",
289
- ),
290
- );
291
-
292
- const benchmarkRoot = specGenerationInputs.benchmarkBlueprintRoot ?? blueprintReference.root ?? null;
293
- const benchmarkAvailable = typeof benchmarkRoot === "string" && benchmarkRoot.length > 0;
294
- const benchmarkAuditReadiness = {
295
- available: benchmarkAvailable,
296
- ready: benchmarkAvailable && Boolean(
297
- specGenerationInputs.ok
298
- && (usesV2SurfaceModel || specTreeModel.ok)
299
- && (
300
- specGenerationInputs.benchmarkMode === "none"
301
- ? !blueprintReference.present
302
- : blueprintReference.present
303
- && blueprintReference.ok
304
- && blueprintReference.root === benchmarkRoot
305
- ),
306
- ),
307
- benchmarkRoot,
308
- acceptanceMode: specGenerationInputs.acceptanceMode ?? null,
309
- reason: typeof benchmarkRoot === "string" && benchmarkRoot.length > 0
310
- ? "Benchmark audit can compare the declared blueprint root against the candidate canonical tree"
311
- : "No benchmark blueprint is declared for this project.",
312
- };
313
- checks.push({
314
- id: "benchmark_audit_readiness",
315
- ok: !benchmarkAuditReadiness.available || benchmarkAuditReadiness.ready,
316
- severity: benchmarkAuditReadiness.available
317
- ? benchmarkAuditReadiness.ready ? "ok" : "warn"
318
- : "info",
319
- detail: benchmarkAuditReadiness.reason,
320
- });
321
-
322
- const canonicalTree = await inspectCanonicalTree(projectRoot, specTreeModel);
323
- checks.push({
324
- id: "canonical_tree_progress",
325
- ok: true,
326
- severity: canonicalTree.requiredFilesValid
327
- ? "ok"
328
- : bootstrapStateContract.treeState === "bootstrap_only"
329
- ? "info"
330
- : "warn",
331
- detail: canonicalTree.requiredFilesValid
332
- ? "Declared canonical tree required files are present"
333
- : `Canonical tree required files are still missing: ${canonicalTree.missing.join(", ")}`,
334
- });
335
-
336
- const specGenerationAuditRef = usesV2SurfaceModel
337
- ? ".nimi/local/state/spec-generation/spec-generation-audit.yaml"
338
- : SPEC_GENERATION_AUDIT_REF;
339
- const specGenerationAuditInfo = await pathExists(path.join(projectRoot, specGenerationAuditRef));
340
- let specGenerationAudit = emptySpecGenerationAudit();
341
- specGenerationAudit.auditPath = specGenerationAuditRef;
342
- if (specGenerationAuditInfo?.isFile()) {
343
- const specGenerationAuditReport = await validateSpecAudit(
344
- path.join(projectRoot, specGenerationAuditRef),
345
- { projectRoot },
346
- );
347
- specGenerationAudit = {
348
- present: true,
349
- ok: specGenerationAuditReport.ok,
350
- auditPath: specGenerationAuditRef,
351
- validator: "validate-spec-audit",
352
- summary: specGenerationAuditReport.summary ?? null,
353
- reason: specGenerationAuditReport.ok
354
- ? "Spec generation audit is present and structurally valid"
355
- : specGenerationAuditReport.errors.join("; "),
356
- };
357
- }
358
- const specGenerationAuditCheckSeverity = !specGenerationAudit.present
359
- ? canonicalTree.requiredFilesValid ? "warn" : "info"
360
- : specGenerationAudit.ok ? "ok" : canonicalTree.requiredFilesValid ? "error" : "warn";
361
- checks.push({
362
- id: "spec_generation_audit",
363
- ok: !specGenerationAudit.present ? true : specGenerationAudit.ok,
364
- severity: specGenerationAuditCheckSeverity,
365
- detail: !specGenerationAudit.present
366
- ? canonicalTree.requiredFilesValid
367
- ? "Canonical tree is ready and spec generation audit is missing; run the audit workflow when file-level generation evidence is required"
368
- : specGenerationAudit.reason
369
- : specGenerationAudit.ok
370
- ? specGenerationAudit.reason
371
- : `Canonical tree is ready but spec generation audit is still missing or invalid: ${specGenerationAudit.reason}`,
372
- });
373
-
374
- const highRiskCloseoutGate = findCommandGatingRule(commandGatingMatrix, "closeout", "high_risk_execution");
375
- checks.push(
376
- buildCheck(
377
- "high_risk_closeout_gate",
378
- usesV2SurfaceModel || Boolean(highRiskCloseoutGate?.completedRequires?.tree_state === "canonical_tree_ready"),
379
- usesV2SurfaceModel
380
- ? "v2 high-risk closeout gates are contract-driven by project-local .nimi/contracts"
381
- : highRiskCloseoutGate
382
- ? "Command gating matrix includes high_risk_execution closeout readiness"
383
- : "command gating matrix is missing closeout gating for high_risk_execution",
384
- usesV2SurfaceModel ? "ok" : undefined,
385
- ),
386
- );
387
-
388
- return {
389
- done: false,
390
- projectRoot,
391
- checks,
392
- bootstrapCompatibility,
393
- bootstrapStateContract,
394
- completionTruth,
395
- specTreeModel,
396
- specGenerationInputsContract,
397
- specGenerationAuditContract,
398
- specGenerationInputs,
399
- commandGatingMatrix,
400
- blueprintReference,
401
- blueprintReferenceAligned,
402
- canonicalTree,
403
- benchmarkAuditReadiness,
404
- specGenerationAudit,
405
- };
406
- }
@@ -1,256 +0,0 @@
1
- import path from "node:path";
2
-
3
- import {
4
- AUDIT_SWEEP_RESULT_CONTRACT_REF,
5
- DOC_SPEC_AUDIT_RESULT_CONTRACT_REF,
6
- EXTERNAL_EXECUTION_ARTIFACTS_CONFIG_REF,
7
- EXTERNAL_HOST_COMPATIBILITY_CONTRACT_REF,
8
- HIGH_RISK_EXECUTION_RESULT_CONTRACT_REF,
9
- HOST_ADAPTER_CONFIG_REF,
10
- SPEC_RECONSTRUCTION_RESULT_CONTRACT_REF,
11
- } from "../../constants.mjs";
12
- import { readTextIfFile, pathExists } from "../fs-helpers.mjs";
13
- import { arraysEqual } from "../value-helpers.mjs";
14
- import {
15
- parseSkillSection,
16
- readYamlList,
17
- readYamlScalar,
18
- } from "../yaml-helpers.mjs";
19
- import { buildCheck } from "./doctor-state.mjs";
20
-
21
- export async function inspectDoctorDelegatedSurface(projectRoot) {
22
- const checks = [];
23
-
24
- const skillsConfigText = await readTextIfFile(path.join(projectRoot, ".nimi", "config", "skills.yaml"));
25
- const skillsConfigOk = Boolean(skillsConfigText)
26
- && skillsConfigText.includes("runtime_installed: false")
27
- && skillsConfigText.includes("runtime_owner: external_ai_host")
28
- && skillsConfigText.includes("handoff_contract: .nimi/methodology/skill-handoff.yaml")
29
- && skillsConfigText.includes(`canonical_host_adapter: ${HOST_ADAPTER_CONFIG_REF}`);
30
- checks.push(
31
- buildCheck(
32
- "skills_contract",
33
- skillsConfigOk,
34
- skillsConfigOk
35
- ? "skills.yaml keeps runtime delegated and handoff-driven"
36
- : "skills.yaml is missing delegated runtime contract fields",
37
- ),
38
- );
39
-
40
- const handoffText = await readTextIfFile(path.join(projectRoot, ".nimi", "methodology", "skill-handoff.yaml"));
41
- const manifestText = await readTextIfFile(path.join(projectRoot, ".nimi", "config", "skill-manifest.yaml"));
42
- const hostProfileText = await readTextIfFile(path.join(projectRoot, ".nimi", "config", "host-profile.yaml"));
43
- const hostAdapterText = await readTextIfFile(path.join(projectRoot, HOST_ADAPTER_CONFIG_REF));
44
- const runtimeContractText = await readTextIfFile(path.join(projectRoot, ".nimi", "methodology", "skill-runtime.yaml"));
45
- const installerText = await readTextIfFile(path.join(projectRoot, ".nimi", "config", "skill-installer.yaml"));
46
- const installerResultText = await readTextIfFile(path.join(projectRoot, ".nimi", "methodology", "skill-installer-result.yaml"));
47
-
48
- const contractRuntimeOwnerValues = [
49
- readYamlScalar(skillsConfigText, "runtime_owner"),
50
- readYamlScalar(manifestText, "runtime_owner"),
51
- readYamlScalar(handoffText, "runtime_owner"),
52
- readYamlScalar(runtimeContractText, "runtime_owner"),
53
- readYamlScalar(hostProfileText, "id"),
54
- readYamlScalar(installerText, "installer_owner"),
55
- ];
56
- const contractRuntimeOwnersAligned = contractRuntimeOwnerValues.every((value) => value === "external_ai_host");
57
-
58
- const delegatedModeAligned = [
59
- readYamlScalar(manifestText, "execution_mode"),
60
- readYamlScalar(hostProfileText, "execution_mode"),
61
- readYamlScalar(runtimeContractText, "runtime_mode"),
62
- readYamlScalar(installerText, "installer_mode"),
63
- ].every((value) => value === "delegated");
64
-
65
- const selfHostedAligned = [
66
- readYamlScalar(handoffText, "self_hosted_runtime"),
67
- readYamlScalar(hostProfileText, "self_hosted"),
68
- readYamlScalar(runtimeContractText, "self_hosted"),
69
- readYamlScalar(installerText, "self_hosted"),
70
- ].every((value) => value === "false");
71
-
72
- checks.push(
73
- buildCheck(
74
- "delegated_contract_posture",
75
- contractRuntimeOwnersAligned && delegatedModeAligned && selfHostedAligned,
76
- contractRuntimeOwnersAligned && delegatedModeAligned && selfHostedAligned
77
- ? "Delegated runtime ownership and non-self-hosted posture are consistent across contracts"
78
- : "Delegated runtime ownership, execution mode, or self-hosted posture drifted across contracts",
79
- ),
80
- );
81
-
82
- const referenceChecks = [
83
- readYamlScalar(manifestText, "runtime_contract_ref") === ".nimi/methodology/skill-runtime.yaml",
84
- readYamlScalar(manifestText, "host_profile_ref") === ".nimi/config/host-profile.yaml",
85
- readYamlScalar(manifestText, "installer_ref") === ".nimi/config/skill-installer.yaml",
86
- readYamlScalar(manifestText, "installer_result_contract_ref") === ".nimi/methodology/skill-installer-result.yaml",
87
- readYamlScalar(hostProfileText, "runtime_contract_ref") === ".nimi/methodology/skill-runtime.yaml",
88
- readYamlScalar(hostProfileText, "compatibility_contract_ref") === EXTERNAL_HOST_COMPATIBILITY_CONTRACT_REF,
89
- readYamlScalar(hostProfileText, "installer_ref") === ".nimi/config/skill-installer.yaml",
90
- readYamlScalar(hostProfileText, "installer_result_contract_ref") === ".nimi/methodology/skill-installer-result.yaml",
91
- readYamlScalar(hostAdapterText, "runtime_owner") === "external_ai_host",
92
- readYamlScalar(hostAdapterText, "host_profile_ref") === ".nimi/config/host-profile.yaml",
93
- readYamlScalar(hostAdapterText, "manifest_ref") === ".nimi/config/skill-manifest.yaml",
94
- readYamlScalar(hostAdapterText, "artifact_contract_ref") === EXTERNAL_EXECUTION_ARTIFACTS_CONFIG_REF,
95
- readYamlScalar(hostAdapterText, "handoff_ref") === ".nimi/methodology/skill-handoff.yaml",
96
- readYamlScalar(runtimeContractText, "manifest_ref") === ".nimi/config/skill-manifest.yaml",
97
- readYamlScalar(runtimeContractText, "host_profile_ref") === ".nimi/config/host-profile.yaml",
98
- readYamlScalar(runtimeContractText, "installer_ref") === ".nimi/config/skill-installer.yaml",
99
- readYamlScalar(runtimeContractText, "installer_result_contract_ref") === ".nimi/methodology/skill-installer-result.yaml",
100
- readYamlScalar(runtimeContractText, "handoff_ref") === ".nimi/methodology/skill-handoff.yaml",
101
- readYamlScalar(installerText, "manifest_ref") === ".nimi/config/skill-manifest.yaml",
102
- readYamlScalar(installerText, "runtime_contract_ref") === ".nimi/methodology/skill-runtime.yaml",
103
- readYamlScalar(installerText, "host_profile_ref") === ".nimi/config/host-profile.yaml",
104
- readYamlScalar(installerText, "result_contract_ref") === ".nimi/methodology/skill-installer-result.yaml",
105
- readYamlScalar(installerResultText, "installer_ref") === ".nimi/config/skill-installer.yaml",
106
- readYamlScalar(handoffText, "runtime_contract_ref") === ".nimi/methodology/skill-runtime.yaml",
107
- readYamlScalar(handoffText, "host_profile_ref") === ".nimi/config/host-profile.yaml",
108
- readYamlScalar(handoffText, "host_compatibility_contract_ref") === EXTERNAL_HOST_COMPATIBILITY_CONTRACT_REF,
109
- readYamlScalar(handoffText, "installer_ref") === ".nimi/config/skill-installer.yaml",
110
- readYamlScalar(handoffText, "installer_result_contract_ref") === ".nimi/methodology/skill-installer-result.yaml",
111
- readYamlScalar(handoffText, "exchange_projection_contract_ref") === ".nimi/methodology/skill-exchange-projection.yaml",
112
- ];
113
- checks.push(
114
- buildCheck(
115
- "contract_reference_alignment",
116
- referenceChecks.every(Boolean),
117
- referenceChecks.every(Boolean)
118
- ? "Manifest, runtime, installer, host-profile, host-adapter, and handoff references are aligned"
119
- : "Cross-contract reference drift detected between manifest/runtime/installer/host-profile/host-adapter/handoff truth",
120
- ),
121
- );
122
-
123
- const manifestSkills = parseSkillSection(manifestText, "skills");
124
- const expectedSkills = parseSkillSection(skillsConfigText, "expected_skill_surfaces");
125
-
126
- const reconstructionSkill = manifestSkills.find((skill) => skill.id === "spec_reconstruction") ?? null;
127
- const docAuditSkill = manifestSkills.find((skill) => skill.id === "doc_spec_audit") ?? null;
128
- const auditSweepSkill = manifestSkills.find((skill) => skill.id === "audit_sweep") ?? null;
129
- const highRiskSkill = manifestSkills.find((skill) => skill.id === "high_risk_execution") ?? null;
130
- const resultContractAlignment = reconstructionSkill?.result_contract_ref === SPEC_RECONSTRUCTION_RESULT_CONTRACT_REF
131
- && docAuditSkill?.result_contract_ref === DOC_SPEC_AUDIT_RESULT_CONTRACT_REF
132
- && auditSweepSkill?.result_contract_ref === AUDIT_SWEEP_RESULT_CONTRACT_REF
133
- && highRiskSkill?.result_contract_ref === HIGH_RISK_EXECUTION_RESULT_CONTRACT_REF;
134
- checks.push(
135
- buildCheck(
136
- "skill_result_contract_alignment",
137
- resultContractAlignment,
138
- resultContractAlignment
139
- ? "Skill manifest result contract refs align with the declared machine contracts"
140
- : "Skill manifest result contract refs drifted away from the declared machine contracts",
141
- ),
142
- );
143
-
144
- const hostRequiredContext = readYamlList(hostProfileText, "required_context");
145
- const handoffRequiredContext = readYamlList(handoffText, "required_context_order");
146
- const missingHandoffContextEntries = hostRequiredContext.filter((entry) => !handoffRequiredContext.includes(entry));
147
- const missingHandoffPaths = [];
148
- for (const relativePath of handoffRequiredContext) {
149
- const info = await pathExists(path.join(projectRoot, relativePath));
150
- if (!info && relativePath !== ".nimi/spec") {
151
- missingHandoffPaths.push(relativePath);
152
- }
153
- }
154
- const handoffContextOk = missingHandoffContextEntries.length === 0 && missingHandoffPaths.length === 0;
155
- checks.push(
156
- buildCheck(
157
- "handoff_context_contract",
158
- handoffContextOk,
159
- handoffContextOk
160
- ? "Handoff context order contains the declared host context and all listed paths exist"
161
- : [
162
- missingHandoffContextEntries.length > 0
163
- ? `handoff context is missing host-required entries: ${missingHandoffContextEntries.join(", ")}`
164
- : null,
165
- missingHandoffPaths.length > 0
166
- ? `handoff context paths are missing on disk: ${missingHandoffPaths.join(", ")}`
167
- : null,
168
- ].filter(Boolean).join("; "),
169
- ),
170
- );
171
-
172
- const manifestSkillIds = manifestSkills.map((skill) => skill.id);
173
- const expectedSkillIds = expectedSkills.map((skill) => skill.id);
174
- const skillSurfaceAligned = arraysEqual(manifestSkillIds, expectedSkillIds);
175
- checks.push(
176
- buildCheck(
177
- "skill_surface_alignment",
178
- skillSurfaceAligned,
179
- skillSurfaceAligned
180
- ? "Manifest skills align with the expected skill surfaces declared in skills.yaml"
181
- : "Manifest skills and expected skill surfaces drifted out of alignment",
182
- ),
183
- );
184
-
185
- const admittedAdapterIds = readYamlList(hostAdapterText, "admitted_adapter_ids");
186
- const selectedAdapterId = readYamlScalar(hostAdapterText, "selected_adapter_id");
187
- const adapterSelected = selectedAdapterId !== null && selectedAdapterId !== "none";
188
- const adapterSelectionValid = selectedAdapterId !== null
189
- && (!adapterSelected || admittedAdapterIds.includes(selectedAdapterId));
190
- checks.push(
191
- buildCheck(
192
- "host_adapter_contract",
193
- adapterSelectionValid,
194
- adapterSelectionValid
195
- ? adapterSelected
196
- ? `Host adapter ${selectedAdapterId} is selected and admitted`
197
- : "No host adapter selected; vendor-neutral delegated host posture remains active"
198
- : "host-adapter selected_adapter_id must be none or one of admitted_adapter_ids",
199
- ),
200
- );
201
-
202
- const adapterBoundaryAligned = readYamlScalar(hostAdapterText, "semantic_review_owner") === "nimicoding_manager"
203
- && readYamlScalar(hostAdapterText, "handoff_mode") === "prompt_output_evidence_handoff"
204
- && readYamlScalar(hostAdapterText, "evidence_mode") === "candidate_only";
205
- checks.push(
206
- buildCheck(
207
- "host_adapter_boundary",
208
- adapterBoundaryAligned,
209
- adapterBoundaryAligned
210
- ? "Host adapter boundary keeps semantic review in nimicoding and limits handoff to prompt/output/evidence"
211
- : "host-adapter boundary drifted away from prompt/output/evidence-only handoff with nimicoding semantic review ownership",
212
- ),
213
- );
214
-
215
- const delegatedContracts = {
216
- runtimeOwner: readYamlScalar(handoffText, "runtime_owner"),
217
- executionMode: readYamlScalar(runtimeContractText, "runtime_mode"),
218
- installerMode: readYamlScalar(installerText, "installer_mode"),
219
- selfHostedRuntime: readYamlScalar(handoffText, "self_hosted_runtime") === "true",
220
- triggerMode: readYamlScalar(handoffText, "trigger_mode"),
221
- expectedSkillIds: manifestSkillIds,
222
- selectedAdapterId,
223
- admittedAdapterIds,
224
- adapterHandoffMode: readYamlScalar(hostAdapterText, "handoff_mode"),
225
- semanticReviewOwner: readYamlScalar(hostAdapterText, "semantic_review_owner"),
226
- };
227
-
228
- return {
229
- checks,
230
- skillsConfigText,
231
- runtimeInstalled: Boolean(skillsConfigText) && skillsConfigText.includes("runtime_installed: true"),
232
- handoffText,
233
- manifestText,
234
- hostProfileText,
235
- hostAdapterText,
236
- runtimeContractText,
237
- installerText,
238
- installerResultText,
239
- contractRuntimeOwnersAligned,
240
- delegatedModeAligned,
241
- selfHostedAligned,
242
- referenceChecks,
243
- resultContractAlignment,
244
- handoffContextOk,
245
- handoffRequiredContext,
246
- missingHandoffContextEntries,
247
- missingHandoffPaths,
248
- manifestSkillIds,
249
- selectedAdapterId,
250
- admittedAdapterIds,
251
- adapterSelected,
252
- adapterSelectionValid,
253
- adapterBoundaryAligned,
254
- delegatedContracts,
255
- };
256
- }