@nimiplatform/nimi-coding 0.2.8 → 0.3.0

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