@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,512 +0,0 @@
1
- import { mkdir, realpath, writeFile } from "node:fs/promises";
2
- import path from "node:path";
3
-
4
- import YAML from "yaml";
5
-
6
- import {
7
- HIGH_RISK_ADMISSION_CONTRACT_REF,
8
- HIGH_RISK_ADMISSION_PAYLOAD_CONTRACT_VERSION,
9
- } from "../constants.mjs";
10
- import {
11
- loadHighRiskAdmissionContract,
12
- validateHighRiskAdmissionsSpec,
13
- } from "./contracts.mjs";
14
- import { inspectDoctorState } from "./doctor.mjs";
15
- import { readTextIfFile } from "./fs-helpers.mjs";
16
- import {
17
- localize,
18
- styleCommand,
19
- styleHeading,
20
- styleLabel,
21
- styleStatus,
22
- } from "./ui.mjs";
23
- import { validateExecutionPacket } from "./validators.mjs";
24
- import { isIsoUtcTimestamp, isPlainObject } from "./value-helpers.mjs";
25
- import { parseYamlText } from "./yaml-helpers.mjs";
26
-
27
- const ADMISSIONS_EVIDENCE_REF = ".nimi/local/high-risk-admissions.yaml";
28
-
29
- function emptyAdmissionsEvidence() {
30
- return {
31
- admissions: [],
32
- admission_rules: [
33
- "explicit_manager_owned_decision_required_before_high_risk_local_evidence",
34
- "mechanically_valid_admission_identity_required_before_high_risk_local_evidence",
35
- "product_authority_change_requires_explicit_domain_spec_update",
36
- ],
37
- semantic_constraints: [
38
- "local_admission_records_must_not_promote_operational_runtime_state",
39
- "local_admission_records_must_not_be_used_as_product_authority",
40
- "local_admission_records_must_use_iso_8601_utc_admitted_at",
41
- ],
42
- };
43
- }
44
-
45
- async function resolveProjectContainedPath(projectRoot, inputPath, artifactLabel) {
46
- const absolutePath = path.resolve(projectRoot, inputPath);
47
- let resolvedProjectRoot;
48
- let resolvedPath;
49
- try {
50
- resolvedProjectRoot = await realpath(projectRoot);
51
- resolvedPath = await realpath(absolutePath);
52
- } catch {
53
- return {
54
- ok: false,
55
- path: absolutePath,
56
- reason: `cannot read ${artifactLabel} at ${absolutePath}`,
57
- };
58
- }
59
- const relative = path.relative(resolvedProjectRoot, resolvedPath);
60
- if (relative.startsWith("..") || path.isAbsolute(relative)) {
61
- return {
62
- ok: false,
63
- path: absolutePath,
64
- reason: `${artifactLabel} must resolve inside the current project root`,
65
- };
66
- }
67
- return {
68
- ok: true,
69
- path: resolvedPath,
70
- };
71
- }
72
-
73
- function translateAdmissionReason(reason) {
74
- const translations = new Map([
75
- ["imported decision payload must declare contractVersion nimicoding.high-risk-decision.v1", "导入的 decision payload 必须声明 contractVersion nimicoding.high-risk-decision.v1"],
76
- ["imported decision payload must declare skill.id high_risk_execution", "导入的 decision payload 必须声明 skill.id 为 high_risk_execution"],
77
- ["imported decision payload must remain localOnly true", "导入的 decision payload 必须保持 localOnly 为 true"],
78
- ["admit-high-risk-decision requires a decision payload with ok true", "admit-high-risk-decision 需要一个 ok 为 true 的 decision payload"],
79
- ["admit-high-risk-decision requires decisionStatus manager_decision_recorded", "admit-high-risk-decision 需要 decisionStatus 为 manager_decision_recorded"],
80
- ["admit-high-risk-decision requires mechanically valid acceptance state", "admit-high-risk-decision 需要机械校验通过的 acceptance 状态"],
81
- ["imported decision payload must include attachmentRefs.packet_ref", "导入的 decision payload 必须包含 attachmentRefs.packet_ref"],
82
- ["attached packet_ref failed mechanical validation", "附加的 packet_ref 未通过机械校验"],
83
- ["attached packet_ref is missing packet_id or topic_id", "附加的 packet_ref 缺少 packet_id 或 topic_id"],
84
- ["Bootstrap or handoff validation is failing; repair doctor errors before semantic admission", "bootstrap 或 handoff 校验失败;请先修复 doctor 报错,再进行语义准入"],
85
- ["Local admission evidence requires the canonical tree under `.nimi/spec`", "local admission evidence 需要 `.nimi/spec` 下的 canonical tree"],
86
- ["Manager-owned local decision is ready for explicit local admission evidence", "manager 拥有的本地 decision 已准备好写入显式 local admission evidence"],
87
- ]);
88
- return translations.get(reason) ?? reason;
89
- }
90
-
91
- async function loadImportedDecisionPayload(projectRoot, fromPath) {
92
- const containedPath = await resolveProjectContainedPath(projectRoot, fromPath, "imported decision JSON");
93
- if (!containedPath.ok) {
94
- return {
95
- ok: false,
96
- error: `${localize(
97
- `nimicoding admit-high-risk-decision refused: ${containedPath.reason}.`,
98
- `nimicoding admit-high-risk-decision 已拒绝:${containedPath.reason}。`,
99
- )}\n`,
100
- };
101
- }
102
-
103
- const rawText = await readTextIfFile(containedPath.path);
104
-
105
- if (rawText === null) {
106
- return {
107
- ok: false,
108
- error: `${localize(
109
- `nimicoding admit-high-risk-decision refused: cannot read imported decision JSON at ${containedPath.path}.`,
110
- `nimicoding admit-high-risk-decision 已拒绝:无法读取 ${containedPath.path} 处的导入 decision JSON。`,
111
- )}\n`,
112
- };
113
- }
114
-
115
- let parsed;
116
- try {
117
- parsed = JSON.parse(rawText);
118
- } catch {
119
- return {
120
- ok: false,
121
- error: `${localize(
122
- `nimicoding admit-high-risk-decision refused: imported decision JSON at ${containedPath.path} is invalid JSON.`,
123
- `nimicoding admit-high-risk-decision 已拒绝:${containedPath.path} 处的导入 decision JSON 不是合法 JSON。`,
124
- )}\n`,
125
- };
126
- }
127
-
128
- if (!isPlainObject(parsed)) {
129
- return {
130
- ok: false,
131
- error: `${localize(
132
- "nimicoding admit-high-risk-decision refused: imported decision JSON must be an object.",
133
- "nimicoding admit-high-risk-decision 已拒绝:导入的 decision JSON 必须是对象。",
134
- )}\n`,
135
- };
136
- }
137
-
138
- if (parsed.projectRoot) {
139
- let importedProjectRoot;
140
- let currentProjectRoot;
141
- try {
142
- importedProjectRoot = await realpath(parsed.projectRoot);
143
- currentProjectRoot = await realpath(projectRoot);
144
- } catch {
145
- return {
146
- ok: false,
147
- error: `${localize(
148
- "nimicoding admit-high-risk-decision refused: imported decision projectRoot could not be resolved.",
149
- "nimicoding admit-high-risk-decision 已拒绝:无法解析导入 decision 的 projectRoot。",
150
- )}\n`,
151
- };
152
- }
153
-
154
- if (importedProjectRoot !== currentProjectRoot) {
155
- return {
156
- ok: false,
157
- error: `${localize(
158
- "nimicoding admit-high-risk-decision refused: imported decision projectRoot does not match the current project.",
159
- "nimicoding admit-high-risk-decision 已拒绝:导入 decision 的 projectRoot 与当前项目不匹配。",
160
- )}\n`,
161
- };
162
- }
163
- }
164
-
165
- return {
166
- ok: true,
167
- path: containedPath.path,
168
- payload: parsed,
169
- };
170
- }
171
-
172
- function validateImportedDecisionPayload(payload) {
173
- if (payload.contractVersion !== "nimicoding.high-risk-decision.v1") {
174
- return {
175
- ok: false,
176
- reason: "imported decision payload must declare contractVersion nimicoding.high-risk-decision.v1",
177
- };
178
- }
179
-
180
- if (payload.skill?.id !== "high_risk_execution") {
181
- return {
182
- ok: false,
183
- reason: "imported decision payload must declare skill.id high_risk_execution",
184
- };
185
- }
186
-
187
- if (payload.localOnly !== true) {
188
- return {
189
- ok: false,
190
- reason: "imported decision payload must remain localOnly true",
191
- };
192
- }
193
-
194
- if (payload.ok !== true) {
195
- return {
196
- ok: false,
197
- reason: "admit-high-risk-decision requires a decision payload with ok true",
198
- };
199
- }
200
-
201
- if (payload.decisionStatus !== "manager_decision_recorded") {
202
- return {
203
- ok: false,
204
- reason: "admit-high-risk-decision requires decisionStatus manager_decision_recorded",
205
- };
206
- }
207
-
208
- if (payload.acceptanceValidation?.ok !== true) {
209
- return {
210
- ok: false,
211
- reason: "admit-high-risk-decision requires mechanically valid acceptance state",
212
- };
213
- }
214
-
215
- if (!isPlainObject(payload.attachmentRefs) || typeof payload.attachmentRefs.packet_ref !== "string") {
216
- return {
217
- ok: false,
218
- reason: "imported decision payload must include attachmentRefs.packet_ref",
219
- };
220
- }
221
-
222
- return { ok: true };
223
- }
224
-
225
- async function loadAdmissionsEvidence(projectRoot, contract) {
226
- const absolutePath = path.join(projectRoot, ADMISSIONS_EVIDENCE_REF);
227
- const text = await readTextIfFile(absolutePath);
228
-
229
- if (text === null) {
230
- const parsed = emptyAdmissionsEvidence();
231
- const validation = validateHighRiskAdmissionsSpec(parsed, contract);
232
- return {
233
- ok: validation.ok,
234
- path: absolutePath,
235
- parsed,
236
- reason: validation.ok ? null : validation.reason,
237
- initialized: true,
238
- };
239
- }
240
-
241
- const parsed = parseYamlText(text);
242
- const validation = validateHighRiskAdmissionsSpec(parsed, contract);
243
-
244
- return {
245
- ok: validation.ok,
246
- path: absolutePath,
247
- parsed,
248
- reason: validation.ok ? null : validation.reason,
249
- initialized: false,
250
- };
251
- }
252
-
253
- async function loadPacketIdentity(projectRoot, packetRef) {
254
- const containedPath = await resolveProjectContainedPath(projectRoot, packetRef, "attached packet_ref");
255
- if (!containedPath.ok) {
256
- return {
257
- ok: false,
258
- reason: containedPath.reason,
259
- };
260
- }
261
-
262
- const packetValidation = await validateExecutionPacket(containedPath.path);
263
- if (!packetValidation.ok) {
264
- return {
265
- ok: false,
266
- reason: "attached packet_ref failed mechanical validation",
267
- validation: packetValidation,
268
- };
269
- }
270
-
271
- const text = await readTextIfFile(containedPath.path);
272
- const parsed = parseYamlText(text);
273
- const packetId = String(parsed?.packet_id ?? "");
274
- const topicId = String(parsed?.topic_id ?? "");
275
-
276
- if (!packetId || !topicId) {
277
- return {
278
- ok: false,
279
- reason: "attached packet_ref is missing packet_id or topic_id",
280
- validation: packetValidation,
281
- };
282
- }
283
-
284
- return {
285
- ok: true,
286
- packetId,
287
- topicId,
288
- validation: packetValidation,
289
- };
290
- }
291
-
292
- function upsertAdmissionRecord(existingAdmissions, record) {
293
- const nextAdmissions = existingAdmissions.filter((entry) => String(entry?.topic_id ?? "") !== record.topic_id);
294
- const replaced = nextAdmissions.length !== existingAdmissions.length;
295
- nextAdmissions.push(record);
296
- nextAdmissions.sort((left, right) => String(left.topic_id).localeCompare(String(right.topic_id)));
297
- return {
298
- admissions: nextAdmissions,
299
- action: replaced ? "updated" : "created",
300
- };
301
- }
302
-
303
- function evaluateAdmissionReadiness(doctorResult, admissionsEvidence, packetIdentity) {
304
- if (!doctorResult.ok || !doctorResult.handoffReadiness.ok) {
305
- return {
306
- ok: false,
307
- reason: "Bootstrap or handoff validation is failing; repair doctor errors before semantic admission",
308
- };
309
- }
310
-
311
- const v2Ready = doctorResult.specGenerationInputs?.mode === "class_filtered"
312
- && doctorResult.canonicalTree?.requiredFilesValid === true;
313
- const legacyReady = doctorResult.lifecycleState?.treeState === "canonical_tree_ready"
314
- && doctorResult.canonicalTree?.requiredFilesValid === true;
315
- if (!v2Ready && !legacyReady) {
316
- return {
317
- ok: false,
318
- reason: "Local admission evidence requires canonical_tree_ready with declared canonical files present",
319
- };
320
- }
321
-
322
- if (!admissionsEvidence.ok) {
323
- return {
324
- ok: false,
325
- reason: admissionsEvidence.reason,
326
- };
327
- }
328
-
329
- if (!packetIdentity.ok) {
330
- return {
331
- ok: false,
332
- reason: packetIdentity.reason,
333
- };
334
- }
335
-
336
- return {
337
- ok: true,
338
- reason: "Manager-owned local decision is ready for explicit local admission evidence",
339
- };
340
- }
341
-
342
- export async function buildHighRiskAdmissionPayload(projectRoot, options) {
343
- const imported = await loadImportedDecisionPayload(projectRoot, options.fromPath);
344
- if (!imported.ok) {
345
- return {
346
- ok: false,
347
- exitCode: 2,
348
- inputError: true,
349
- error: imported.error,
350
- };
351
- }
352
-
353
- const decisionValidation = validateImportedDecisionPayload(imported.payload);
354
- if (!decisionValidation.ok) {
355
- return {
356
- ok: false,
357
- exitCode: 2,
358
- inputError: true,
359
- error: `${localize(
360
- `nimicoding admit-high-risk-decision refused: ${decisionValidation.reason}.`,
361
- `nimicoding admit-high-risk-decision 已拒绝:${translateAdmissionReason(decisionValidation.reason)}。`,
362
- )}\n`,
363
- };
364
- }
365
-
366
- if (!isIsoUtcTimestamp(options.admittedAt)) {
367
- return {
368
- ok: false,
369
- exitCode: 2,
370
- inputError: true,
371
- error: `${localize(
372
- "nimicoding admit-high-risk-decision refused: --admitted-at must be an ISO-8601 UTC timestamp.",
373
- "nimicoding admit-high-risk-decision 已拒绝:`--admitted-at` 必须是 ISO-8601 UTC 时间戳。",
374
- )}\n`,
375
- };
376
- }
377
-
378
- const admissionsContract = await loadHighRiskAdmissionContract(projectRoot);
379
- if (!admissionsContract.ok) {
380
- return {
381
- contractVersion: HIGH_RISK_ADMISSION_PAYLOAD_CONTRACT_VERSION,
382
- ok: false,
383
- exitCode: 1,
384
- projectRoot,
385
- sourceDecisionRef: imported.path,
386
- semanticTargetRef: ADMISSIONS_EVIDENCE_REF,
387
- artifactPath: path.join(projectRoot, ADMISSIONS_EVIDENCE_REF),
388
- skill: {
389
- id: "high_risk_execution",
390
- },
391
- localOnly: true,
392
- admittedAt: options.admittedAt,
393
- admissionAction: "blocked",
394
- admissionRecord: null,
395
- readiness: {
396
- ok: false,
397
- reason: `${HIGH_RISK_ADMISSION_CONTRACT_REF} is missing or malformed`,
398
- },
399
- doctor: {
400
- ok: false,
401
- handoffReadiness: { ok: false },
402
- delegatedContracts: {},
403
- },
404
- nextEvidenceYaml: null,
405
- nextAction: `${HIGH_RISK_ADMISSION_CONTRACT_REF} must satisfy the package-owned local admission evidence contract.`,
406
- };
407
- }
408
-
409
- const doctorResult = await inspectDoctorState(projectRoot);
410
- const admissionsEvidence = await loadAdmissionsEvidence(projectRoot, admissionsContract);
411
- const packetIdentity = await loadPacketIdentity(projectRoot, imported.payload.attachmentRefs.packet_ref);
412
- const readiness = evaluateAdmissionReadiness(doctorResult, admissionsEvidence, packetIdentity);
413
-
414
- const admissionRecord = packetIdentity.ok ? {
415
- topic_id: packetIdentity.topicId,
416
- packet_id: packetIdentity.packetId,
417
- disposition: imported.payload.acceptanceDisposition,
418
- admitted_at: options.admittedAt,
419
- manager_review_owner: imported.payload.managerReviewOwner ?? doctorResult.delegatedContracts.semanticReviewOwner,
420
- summary: typeof imported.payload.summary?.summary === "string" && imported.payload.summary.summary.trim().length > 0
421
- ? imported.payload.summary.summary
422
- : `Admitted manager-owned disposition for ${packetIdentity.topicId}.`,
423
- source_decision_contract: imported.payload.contractVersion,
424
- } : null;
425
-
426
- const nextAdmissions = readiness.ok
427
- ? upsertAdmissionRecord(admissionsEvidence.parsed.admissions, admissionRecord)
428
- : { admissions: admissionsEvidence.parsed?.admissions ?? [], action: "blocked" };
429
-
430
- const nextEvidenceObject = admissionsEvidence.ok ? {
431
- admissions: nextAdmissions.admissions,
432
- admission_rules: admissionsEvidence.parsed.admission_rules,
433
- semantic_constraints: admissionsEvidence.parsed.semantic_constraints,
434
- } : null;
435
- const nextEvidenceValidation = nextEvidenceObject ? validateHighRiskAdmissionsSpec(nextEvidenceObject, admissionsContract) : { ok: false };
436
-
437
- return {
438
- contractVersion: HIGH_RISK_ADMISSION_PAYLOAD_CONTRACT_VERSION,
439
- ok: readiness.ok && nextEvidenceValidation.ok,
440
- exitCode: readiness.ok && nextEvidenceValidation.ok ? 0 : 1,
441
- projectRoot,
442
- sourceDecisionRef: imported.path,
443
- semanticTargetRef: ADMISSIONS_EVIDENCE_REF,
444
- artifactPath: path.join(projectRoot, ADMISSIONS_EVIDENCE_REF),
445
- skill: {
446
- id: "high_risk_execution",
447
- },
448
- localOnly: true,
449
- admittedAt: options.admittedAt,
450
- admissionAction: nextAdmissions.action,
451
- admissionRecord,
452
- readiness: readiness.ok && !nextEvidenceValidation.ok
453
- ? {
454
- ok: false,
455
- reason: nextEvidenceValidation.reason,
456
- }
457
- : readiness,
458
- doctor: {
459
- ok: doctorResult.ok,
460
- handoffReadiness: doctorResult.handoffReadiness,
461
- delegatedContracts: doctorResult.delegatedContracts,
462
- },
463
- nextEvidenceYaml: nextEvidenceObject ? YAML.stringify(nextEvidenceObject) : null,
464
- nextAction: readiness.ok && nextEvidenceValidation.ok
465
- ? options.writeLocal
466
- ? `Write local admission evidence to ${ADMISSIONS_EVIDENCE_REF}.`
467
- : `Review the local admission evidence preview or write it with --write-local.`
468
- : readiness.ok && !nextEvidenceValidation.ok
469
- ? nextEvidenceValidation.reason
470
- : readiness.reason,
471
- };
472
- }
473
-
474
- export async function writeHighRiskAdmission(projectRoot, payload) {
475
- if (!payload.ok || typeof payload.nextEvidenceYaml !== "string") {
476
- return;
477
- }
478
-
479
- await mkdir(path.dirname(path.join(projectRoot, ADMISSIONS_EVIDENCE_REF)), { recursive: true });
480
- await writeFile(path.join(projectRoot, ADMISSIONS_EVIDENCE_REF), payload.nextEvidenceYaml, "utf8");
481
- }
482
-
483
- export function formatHighRiskAdmissionPayload(payload) {
484
- const nextAction = payload.ok
485
- ? payload.nextAction.startsWith("Write local admission evidence to ")
486
- ? localize(payload.nextAction, `将 local admission evidence 写入 ${payload.semanticTargetRef}。`)
487
- : localize(
488
- payload.nextAction,
489
- `检查 local admission evidence 预览,或使用 ${styleCommand("--write-local")} 将其写入。`,
490
- )
491
- : localize(payload.nextAction, translateAdmissionReason(payload.nextAction)
492
- .replace(`${HIGH_RISK_ADMISSION_CONTRACT_REF} is missing or malformed`, `${HIGH_RISK_ADMISSION_CONTRACT_REF} 缺失或格式错误`)
493
- .replace(`${HIGH_RISK_ADMISSION_CONTRACT_REF} must satisfy the package-owned local admission evidence contract.`, `${HIGH_RISK_ADMISSION_CONTRACT_REF} 必须满足包内 local admission evidence 契约。`));
494
- const lines = [
495
- styleHeading(`nimicoding admit-high-risk-decision: ${payload.projectRoot}`),
496
- "",
497
- styleLabel(localize("Admission:", "准入:")),
498
- ` - target_ref: ${payload.semanticTargetRef}`,
499
- ` - action: ${payload.admissionAction}`,
500
- ` - ready: ${styleStatus(payload.readiness.ok ? "ready" : "needs_attention")}`,
501
- ` - local_only: ${payload.localOnly ? "true" : "false"}`,
502
- ];
503
-
504
- if (payload.admissionRecord) {
505
- lines.push(` - topic_id: ${payload.admissionRecord.topic_id}`);
506
- lines.push(` - packet_id: ${payload.admissionRecord.packet_id}`);
507
- lines.push(` - disposition: ${payload.admissionRecord.disposition}`);
508
- }
509
-
510
- lines.push("", styleLabel(localize("Next:", "下一步:")), ` - ${nextAction}`);
511
- return `${lines.join("\n")}\n`;
512
- }