@nimiplatform/nimi-coding 0.2.7 → 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 (207) hide show
  1. package/CHANGELOG.md +8 -80
  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/dev/run-cli-smoke.mjs +24 -0
  9. package/cli/dev/run-suite.mjs +17 -0
  10. package/cli/help.mjs +28 -145
  11. package/cli/index.mjs +5 -33
  12. package/cli/lib/blueprint-audit.mjs +5 -12
  13. package/cli/lib/bootstrap.mjs +0 -9
  14. package/cli/lib/contracts.mjs +0 -163
  15. package/cli/lib/doctor.mjs +155 -10
  16. package/cli/lib/entrypoints.mjs +63 -167
  17. package/cli/lib/internal/contracts-loaders.mjs +0 -85
  18. package/cli/lib/internal/contracts-parse.mjs +84 -520
  19. package/cli/lib/internal/governance/ai/check-agents-freshness.mjs +13 -8
  20. package/cli/lib/internal/surface-taxonomy-validators.mjs +316 -66
  21. package/cli/lib/internal/validators-shared.mjs +0 -16
  22. package/cli/lib/internal/validators-spec-helpers.mjs +7 -140
  23. package/cli/lib/internal/validators-spec.mjs +103 -342
  24. package/cli/lib/shared.mjs +1 -42
  25. package/cli/lib/validators.mjs +0 -48
  26. package/cli/seeds/seed-policy.yaml +0 -3
  27. package/config/bootstrap.yaml +4 -4
  28. package/config/spec-generation-inputs.yaml +6 -12
  29. package/contracts/domain-admission.schema.yaml +3 -3
  30. package/contracts/migration-inventory.schema.yaml +12 -75
  31. package/contracts/negative-fixtures.yaml +19 -99
  32. package/contracts/placement-contract.schema.yaml +49 -78
  33. package/contracts/projection-edge.schema.yaml +37 -121
  34. package/contracts/shared-enums.yaml +4 -8
  35. package/contracts/spec-generation-inputs.schema.yaml +15 -112
  36. package/contracts/spec-layout.schema.yaml +32 -0
  37. package/contracts/surface-taxonomy.schema.yaml +43 -94
  38. package/contracts/table-family.schema.yaml +1 -1
  39. package/contracts/tracked-output-admission.schema.yaml +13 -66
  40. package/methodology/core.yaml +33 -25
  41. package/methodology/four-closure-policy.yaml +18 -26
  42. package/methodology/role-separation-policy.yaml +21 -27
  43. package/methodology/spec-reconstruction.yaml +17 -34
  44. package/package.json +4 -6
  45. package/spec/_meta/spec-tree-model.yaml +5 -101
  46. package/spec/product-scope.yaml +25 -57
  47. package/adapters/README.md +0 -25
  48. package/adapters/claude/README.md +0 -89
  49. package/adapters/claude/profile.yaml +0 -70
  50. package/adapters/codex/README.md +0 -53
  51. package/adapters/codex/profile.yaml +0 -78
  52. package/adapters/oh-my-codex/README.md +0 -184
  53. package/adapters/oh-my-codex/profile.yaml +0 -46
  54. package/cli/commands/admit-high-risk-decision.mjs +0 -108
  55. package/cli/commands/audit-sweep.mjs +0 -364
  56. package/cli/commands/closeout.mjs +0 -186
  57. package/cli/commands/decide-high-risk-execution.mjs +0 -124
  58. package/cli/commands/handoff.mjs +0 -123
  59. package/cli/commands/ingest-high-risk-execution.mjs +0 -95
  60. package/cli/commands/review-high-risk-execution.mjs +0 -95
  61. package/cli/commands/sweep-design.mjs +0 -295
  62. package/cli/commands/sweep.mjs +0 -22
  63. package/cli/commands/topic-formatters.mjs +0 -382
  64. package/cli/commands/topic-goal.mjs +0 -33
  65. package/cli/commands/topic-options-shared.mjs +0 -27
  66. package/cli/commands/topic-options-workflow.mjs +0 -767
  67. package/cli/commands/topic-options.mjs +0 -626
  68. package/cli/commands/topic-runner.mjs +0 -169
  69. package/cli/commands/topic.mjs +0 -795
  70. package/cli/commands/validate-acceptance.mjs +0 -5
  71. package/cli/commands/validate-execution-packet.mjs +0 -5
  72. package/cli/commands/validate-orchestration-state.mjs +0 -5
  73. package/cli/commands/validate-prompt.mjs +0 -5
  74. package/cli/commands/validate-worker-output.mjs +0 -5
  75. package/cli/lib/adapter-profiles.mjs +0 -403
  76. package/cli/lib/audit-execution.mjs +0 -52
  77. package/cli/lib/audit-sweep-runtime/admissions.mjs +0 -508
  78. package/cli/lib/audit-sweep-runtime/audit-validity.mjs +0 -356
  79. package/cli/lib/audit-sweep-runtime/chunks.mjs +0 -697
  80. package/cli/lib/audit-sweep-runtime/claude-auditor.mjs +0 -647
  81. package/cli/lib/audit-sweep-runtime/closeout.mjs +0 -144
  82. package/cli/lib/audit-sweep-runtime/codex-auditor-evidence.mjs +0 -654
  83. package/cli/lib/audit-sweep-runtime/codex-auditor.mjs +0 -516
  84. package/cli/lib/audit-sweep-runtime/common.mjs +0 -341
  85. package/cli/lib/audit-sweep-runtime/coverage-quality.mjs +0 -172
  86. package/cli/lib/audit-sweep-runtime/evidence-assignment.mjs +0 -155
  87. package/cli/lib/audit-sweep-runtime/format.mjs +0 -57
  88. package/cli/lib/audit-sweep-runtime/ingest.mjs +0 -486
  89. package/cli/lib/audit-sweep-runtime/inventory-spec-chunks.mjs +0 -425
  90. package/cli/lib/audit-sweep-runtime/inventory.mjs +0 -798
  91. package/cli/lib/audit-sweep-runtime/ledger.mjs +0 -315
  92. package/cli/lib/audit-sweep-runtime/p0p1-profile.mjs +0 -101
  93. package/cli/lib/audit-sweep-runtime/remediation.mjs +0 -349
  94. package/cli/lib/audit-sweep-runtime/rerun.mjs +0 -129
  95. package/cli/lib/audit-sweep-runtime/risk-budget.mjs +0 -300
  96. package/cli/lib/audit-sweep-runtime/status.mjs +0 -62
  97. package/cli/lib/audit-sweep-runtime/validators-ledger.mjs +0 -215
  98. package/cli/lib/audit-sweep-runtime/validators.mjs +0 -797
  99. package/cli/lib/audit-sweep.mjs +0 -19
  100. package/cli/lib/authority-convergence.mjs +0 -704
  101. package/cli/lib/closeout.mjs +0 -732
  102. package/cli/lib/codex-sdk-runner.mjs +0 -76
  103. package/cli/lib/external-execution.mjs +0 -101
  104. package/cli/lib/handoff.mjs +0 -812
  105. package/cli/lib/high-risk-admission.mjs +0 -512
  106. package/cli/lib/high-risk-decision.mjs +0 -353
  107. package/cli/lib/high-risk-ingest.mjs +0 -321
  108. package/cli/lib/high-risk-review.mjs +0 -267
  109. package/cli/lib/internal/contracts-parse-high-risk.mjs +0 -131
  110. package/cli/lib/internal/contracts-validators.mjs +0 -399
  111. package/cli/lib/internal/doctor-bootstrap-surface.mjs +0 -406
  112. package/cli/lib/internal/doctor-delegated-surface.mjs +0 -256
  113. package/cli/lib/internal/doctor-finalize.mjs +0 -383
  114. package/cli/lib/internal/doctor-format.mjs +0 -286
  115. package/cli/lib/internal/doctor-inspectors.mjs +0 -327
  116. package/cli/lib/internal/doctor-state.mjs +0 -205
  117. package/cli/lib/internal/validators-artifacts.mjs +0 -515
  118. package/cli/lib/sweep-design-runtime/common.mjs +0 -246
  119. package/cli/lib/sweep-design-runtime/engine.mjs +0 -733
  120. package/cli/lib/sweep-design-runtime/fix-topic.mjs +0 -414
  121. package/cli/lib/sweep-design-runtime/lifecycle.mjs +0 -54
  122. package/cli/lib/sweep-design-runtime/results.mjs +0 -324
  123. package/cli/lib/sweep-design.mjs +0 -8
  124. package/cli/lib/topic-artifacts.mjs +0 -186
  125. package/cli/lib/topic-authority-coverage.mjs +0 -73
  126. package/cli/lib/topic-closeout.mjs +0 -560
  127. package/cli/lib/topic-common.mjs +0 -404
  128. package/cli/lib/topic-decisions.mjs +0 -332
  129. package/cli/lib/topic-draft-packets.mjs +0 -167
  130. package/cli/lib/topic-execution.mjs +0 -515
  131. package/cli/lib/topic-goal.mjs +0 -440
  132. package/cli/lib/topic-ledger.mjs +0 -281
  133. package/cli/lib/topic-lifecycle-artifacts.mjs +0 -173
  134. package/cli/lib/topic-root-validation.mjs +0 -288
  135. package/cli/lib/topic-runner-commands.mjs +0 -174
  136. package/cli/lib/topic-runner-deferral.mjs +0 -532
  137. package/cli/lib/topic-runner-stale-gates.mjs +0 -114
  138. package/cli/lib/topic-runner-validation.mjs +0 -138
  139. package/cli/lib/topic-runner.mjs +0 -727
  140. package/cli/lib/topic-scaffold.mjs +0 -252
  141. package/cli/lib/topic-waves.mjs +0 -403
  142. package/cli/lib/topic.mjs +0 -81
  143. package/config/audit-execution-artifacts.yaml +0 -20
  144. package/config/external-execution-artifacts.yaml +0 -16
  145. package/config/host-adapter.yaml +0 -30
  146. package/config/host-profile.yaml +0 -29
  147. package/config/installer-evidence.yaml +0 -31
  148. package/config/skill-installer.yaml +0 -23
  149. package/config/skill-manifest.yaml +0 -48
  150. package/config/skills.yaml +0 -30
  151. package/contracts/acceptance.schema.yaml +0 -16
  152. package/contracts/admission-checklist.schema.yaml +0 -15
  153. package/contracts/audit-chunk.schema.yaml +0 -123
  154. package/contracts/audit-closeout.schema.yaml +0 -51
  155. package/contracts/audit-finding.schema.yaml +0 -61
  156. package/contracts/audit-ledger.schema.yaml +0 -138
  157. package/contracts/audit-plan.schema.yaml +0 -138
  158. package/contracts/audit-remediation-map.schema.yaml +0 -52
  159. package/contracts/audit-rerun.schema.yaml +0 -31
  160. package/contracts/audit-sweep-result.yaml +0 -53
  161. package/contracts/authority-convergence-audit.schema.yaml +0 -19
  162. package/contracts/closeout.schema.yaml +0 -25
  163. package/contracts/decision-review.schema.yaml +0 -16
  164. package/contracts/doc-spec-audit-result.yaml +0 -19
  165. package/contracts/execution-packet.schema.yaml +0 -49
  166. package/contracts/external-host-compatibility.yaml +0 -22
  167. package/contracts/forbidden-shortcuts.catalog.yaml +0 -23
  168. package/contracts/high-risk-admission.schema.yaml +0 -23
  169. package/contracts/high-risk-execution-result.yaml +0 -20
  170. package/contracts/orchestration-state.schema.yaml +0 -41
  171. package/contracts/overflow-continuation.schema.yaml +0 -12
  172. package/contracts/packet.schema.yaml +0 -30
  173. package/contracts/pending-note.schema.yaml +0 -17
  174. package/contracts/prompt.schema.yaml +0 -12
  175. package/contracts/remediation.schema.yaml +0 -16
  176. package/contracts/result.schema.yaml +0 -24
  177. package/contracts/spec-reconstruction-result.yaml +0 -41
  178. package/contracts/sweep-design-result.yaml +0 -349
  179. package/contracts/topic-goal.schema.yaml +0 -87
  180. package/contracts/topic-run-ledger.schema.yaml +0 -72
  181. package/contracts/topic-step-decision.schema.yaml +0 -45
  182. package/contracts/topic.schema.yaml +0 -65
  183. package/contracts/true-close.schema.yaml +0 -15
  184. package/contracts/wave.schema.yaml +0 -29
  185. package/contracts/worker-output.schema.yaml +0 -15
  186. package/contracts/workflow-consumer.schema.yaml +0 -110
  187. package/methodology/audit-sweep-p0p1-recall.yaml +0 -45
  188. package/methodology/authority-convergence-policy.yaml +0 -42
  189. package/methodology/overflow-continuation-policy.yaml +0 -14
  190. package/methodology/skill-exchange-projection.yaml +0 -114
  191. package/methodology/skill-handoff.yaml +0 -34
  192. package/methodology/skill-installer-result.yaml +0 -27
  193. package/methodology/skill-installer-summary-projection.yaml +0 -181
  194. package/methodology/skill-runtime.yaml +0 -23
  195. package/methodology/spec-target-truth-profile.yaml +0 -46
  196. package/methodology/topic-lifecycle-report.yaml +0 -144
  197. package/methodology/topic-lifecycle.yaml +0 -37
  198. package/methodology/topic-naming-ontology.yaml +0 -21
  199. package/methodology/topic-ontology.yaml +0 -38
  200. package/methodology/topic-validation-policy.yaml +0 -9
  201. package/methodology/wave-dag-policy.yaml +0 -14
  202. package/spec/_meta/command-gating-matrix.yaml +0 -143
  203. package/spec/_meta/generate-drift-migration-checklist.yaml +0 -137
  204. package/spec/_meta/governance-routing-cutover-checklist.yaml +0 -35
  205. package/spec/_meta/phase2-impacted-surface-matrix.yaml +0 -44
  206. package/spec/_meta/spec-authority-cutover-readiness.yaml +0 -102
  207. 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
- }