@nimiplatform/nimi-coding 0.2.8 → 0.3.1

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