@nimiplatform/nimi-coding 0.1.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 (186) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +348 -0
  3. package/adapters/README.md +25 -0
  4. package/adapters/claude/README.md +89 -0
  5. package/adapters/claude/profile.yaml +70 -0
  6. package/adapters/codex/README.md +53 -0
  7. package/adapters/codex/profile.yaml +78 -0
  8. package/adapters/oh-my-codex/README.md +185 -0
  9. package/adapters/oh-my-codex/profile.yaml +46 -0
  10. package/bin/nimicoding.mjs +6 -0
  11. package/cli/commands/admit-high-risk-decision.mjs +108 -0
  12. package/cli/commands/audit-sweep.mjs +341 -0
  13. package/cli/commands/blueprint-audit.mjs +91 -0
  14. package/cli/commands/clear.mjs +168 -0
  15. package/cli/commands/closeout.mjs +183 -0
  16. package/cli/commands/decide-high-risk-execution.mjs +124 -0
  17. package/cli/commands/doctor.mjs +53 -0
  18. package/cli/commands/generate-spec-derived-docs.mjs +131 -0
  19. package/cli/commands/handoff.mjs +123 -0
  20. package/cli/commands/ingest-high-risk-execution.mjs +95 -0
  21. package/cli/commands/review-high-risk-execution.mjs +95 -0
  22. package/cli/commands/start.mjs +717 -0
  23. package/cli/commands/topic-formatters.mjs +382 -0
  24. package/cli/commands/topic-goal.mjs +33 -0
  25. package/cli/commands/topic-options-shared.mjs +27 -0
  26. package/cli/commands/topic-options-workflow.mjs +767 -0
  27. package/cli/commands/topic-options.mjs +626 -0
  28. package/cli/commands/topic-runner.mjs +169 -0
  29. package/cli/commands/topic.mjs +795 -0
  30. package/cli/commands/validate-acceptance.mjs +5 -0
  31. package/cli/commands/validate-ai-governance.mjs +214 -0
  32. package/cli/commands/validate-execution-packet.mjs +5 -0
  33. package/cli/commands/validate-orchestration-state.mjs +5 -0
  34. package/cli/commands/validate-prompt.mjs +5 -0
  35. package/cli/commands/validate-spec-audit.mjs +27 -0
  36. package/cli/commands/validate-spec-governance.mjs +124 -0
  37. package/cli/commands/validate-spec-tree.mjs +27 -0
  38. package/cli/commands/validate-worker-output.mjs +5 -0
  39. package/cli/constants.mjs +489 -0
  40. package/cli/help.mjs +134 -0
  41. package/cli/index.mjs +103 -0
  42. package/cli/lib/adapter-profiles.mjs +403 -0
  43. package/cli/lib/audit-execution.mjs +52 -0
  44. package/cli/lib/audit-sweep-runtime/admissions.mjs +381 -0
  45. package/cli/lib/audit-sweep-runtime/audit-validity.mjs +333 -0
  46. package/cli/lib/audit-sweep-runtime/chunks.mjs +697 -0
  47. package/cli/lib/audit-sweep-runtime/closeout.mjs +144 -0
  48. package/cli/lib/audit-sweep-runtime/codex-auditor-evidence.mjs +639 -0
  49. package/cli/lib/audit-sweep-runtime/codex-auditor.mjs +515 -0
  50. package/cli/lib/audit-sweep-runtime/common.mjs +329 -0
  51. package/cli/lib/audit-sweep-runtime/coverage-quality.mjs +172 -0
  52. package/cli/lib/audit-sweep-runtime/evidence-assignment.mjs +152 -0
  53. package/cli/lib/audit-sweep-runtime/format.mjs +57 -0
  54. package/cli/lib/audit-sweep-runtime/ingest.mjs +486 -0
  55. package/cli/lib/audit-sweep-runtime/inventory-spec-chunks.mjs +198 -0
  56. package/cli/lib/audit-sweep-runtime/inventory.mjs +728 -0
  57. package/cli/lib/audit-sweep-runtime/ledger.mjs +315 -0
  58. package/cli/lib/audit-sweep-runtime/p0p1-profile.mjs +101 -0
  59. package/cli/lib/audit-sweep-runtime/remediation.mjs +349 -0
  60. package/cli/lib/audit-sweep-runtime/rerun.mjs +129 -0
  61. package/cli/lib/audit-sweep-runtime/risk-budget.mjs +300 -0
  62. package/cli/lib/audit-sweep-runtime/status.mjs +62 -0
  63. package/cli/lib/audit-sweep-runtime/validators-ledger.mjs +215 -0
  64. package/cli/lib/audit-sweep-runtime/validators.mjs +758 -0
  65. package/cli/lib/audit-sweep.mjs +18 -0
  66. package/cli/lib/authority-convergence.mjs +309 -0
  67. package/cli/lib/blueprint-audit.mjs +370 -0
  68. package/cli/lib/bootstrap.mjs +228 -0
  69. package/cli/lib/closeout.mjs +623 -0
  70. package/cli/lib/codex-sdk-runner.mjs +76 -0
  71. package/cli/lib/contracts.mjs +180 -0
  72. package/cli/lib/doctor.mjs +18 -0
  73. package/cli/lib/entrypoints.mjs +274 -0
  74. package/cli/lib/external-execution.mjs +101 -0
  75. package/cli/lib/fs-helpers.mjs +33 -0
  76. package/cli/lib/handoff.mjs +785 -0
  77. package/cli/lib/high-risk-admission.mjs +442 -0
  78. package/cli/lib/high-risk-decision.mjs +324 -0
  79. package/cli/lib/high-risk-ingest.mjs +317 -0
  80. package/cli/lib/high-risk-review.mjs +263 -0
  81. package/cli/lib/internal/contracts-loaders.mjs +132 -0
  82. package/cli/lib/internal/contracts-parse-high-risk.mjs +131 -0
  83. package/cli/lib/internal/contracts-parse.mjs +457 -0
  84. package/cli/lib/internal/contracts-validators.mjs +398 -0
  85. package/cli/lib/internal/doctor-bootstrap-surface.mjs +359 -0
  86. package/cli/lib/internal/doctor-delegated-surface.mjs +256 -0
  87. package/cli/lib/internal/doctor-finalize.mjs +385 -0
  88. package/cli/lib/internal/doctor-format.mjs +286 -0
  89. package/cli/lib/internal/doctor-inspectors.mjs +294 -0
  90. package/cli/lib/internal/doctor-state.mjs +205 -0
  91. package/cli/lib/internal/governance/ai/ai-context-budget-core.mjs +315 -0
  92. package/cli/lib/internal/governance/ai/ai-structure-budget-core.mjs +358 -0
  93. package/cli/lib/internal/governance/ai/check-agents-freshness.mjs +155 -0
  94. package/cli/lib/internal/governance/ai/check-high-risk-doc-metadata-core.mjs +173 -0
  95. package/cli/lib/internal/governance/config.mjs +150 -0
  96. package/cli/lib/internal/governance/runner.mjs +35 -0
  97. package/cli/lib/internal/governance/shared/read-yaml-with-fragments.mjs +49 -0
  98. package/cli/lib/internal/validators-artifacts.mjs +515 -0
  99. package/cli/lib/internal/validators-shared.mjs +28 -0
  100. package/cli/lib/internal/validators-spec-helpers.mjs +186 -0
  101. package/cli/lib/internal/validators-spec.mjs +410 -0
  102. package/cli/lib/shared.mjs +83 -0
  103. package/cli/lib/topic-draft-packets.mjs +48 -0
  104. package/cli/lib/topic-goal.mjs +361 -0
  105. package/cli/lib/topic-runner.mjs +772 -0
  106. package/cli/lib/topic.mjs +93 -0
  107. package/cli/lib/ui.mjs +178 -0
  108. package/cli/lib/validators.mjs +78 -0
  109. package/cli/lib/value-helpers.mjs +24 -0
  110. package/cli/lib/yaml-helpers.mjs +133 -0
  111. package/cli/nimicoding.mjs +1 -0
  112. package/cli/seeds/bootstrap.mjs +47 -0
  113. package/config/audit-execution-artifacts.yaml +20 -0
  114. package/config/bootstrap.yaml +6 -0
  115. package/config/external-execution-artifacts.yaml +16 -0
  116. package/config/host-adapter.yaml +30 -0
  117. package/config/host-profile.yaml +29 -0
  118. package/config/installer-evidence.yaml +31 -0
  119. package/config/skill-installer.yaml +23 -0
  120. package/config/skill-manifest.yaml +46 -0
  121. package/config/skills.yaml +30 -0
  122. package/config/spec-generation-inputs.yaml +25 -0
  123. package/contracts/acceptance.schema.yaml +16 -0
  124. package/contracts/admission-checklist.schema.yaml +15 -0
  125. package/contracts/audit-chunk.schema.yaml +110 -0
  126. package/contracts/audit-closeout.schema.yaml +51 -0
  127. package/contracts/audit-finding.schema.yaml +61 -0
  128. package/contracts/audit-ledger.schema.yaml +138 -0
  129. package/contracts/audit-plan.schema.yaml +123 -0
  130. package/contracts/audit-remediation-map.schema.yaml +51 -0
  131. package/contracts/audit-rerun.schema.yaml +31 -0
  132. package/contracts/audit-sweep-result.yaml +49 -0
  133. package/contracts/authority-convergence-audit.schema.yaml +19 -0
  134. package/contracts/closeout.schema.yaml +25 -0
  135. package/contracts/decision-review.schema.yaml +16 -0
  136. package/contracts/doc-spec-audit-result.yaml +19 -0
  137. package/contracts/execution-packet.schema.yaml +49 -0
  138. package/contracts/external-host-compatibility.yaml +22 -0
  139. package/contracts/forbidden-shortcuts.catalog.yaml +23 -0
  140. package/contracts/high-risk-admission.schema.yaml +23 -0
  141. package/contracts/high-risk-execution-result.yaml +20 -0
  142. package/contracts/orchestration-state.schema.yaml +41 -0
  143. package/contracts/overflow-continuation.schema.yaml +12 -0
  144. package/contracts/packet.schema.yaml +30 -0
  145. package/contracts/pending-note.schema.yaml +17 -0
  146. package/contracts/prompt.schema.yaml +12 -0
  147. package/contracts/remediation.schema.yaml +16 -0
  148. package/contracts/result.schema.yaml +24 -0
  149. package/contracts/spec-generation-audit.schema.yaml +31 -0
  150. package/contracts/spec-generation-inputs.schema.yaml +39 -0
  151. package/contracts/spec-reconstruction-result.yaml +37 -0
  152. package/contracts/topic-goal.schema.yaml +78 -0
  153. package/contracts/topic-run-ledger.schema.yaml +72 -0
  154. package/contracts/topic-step-decision.schema.yaml +45 -0
  155. package/contracts/topic.schema.yaml +65 -0
  156. package/contracts/true-close.schema.yaml +15 -0
  157. package/contracts/wave.schema.yaml +29 -0
  158. package/contracts/worker-output.schema.yaml +15 -0
  159. package/methodology/audit-sweep-p0p1-recall.yaml +45 -0
  160. package/methodology/authority-convergence-policy.yaml +42 -0
  161. package/methodology/core.yaml +25 -0
  162. package/methodology/four-closure-policy.yaml +28 -0
  163. package/methodology/overflow-continuation-policy.yaml +14 -0
  164. package/methodology/role-separation-policy.yaml +28 -0
  165. package/methodology/skill-exchange-projection.yaml +114 -0
  166. package/methodology/skill-handoff.yaml +34 -0
  167. package/methodology/skill-installer-result.yaml +27 -0
  168. package/methodology/skill-installer-summary-projection.yaml +181 -0
  169. package/methodology/skill-runtime.yaml +23 -0
  170. package/methodology/spec-reconstruction.yaml +63 -0
  171. package/methodology/spec-target-truth-profile.yaml +53 -0
  172. package/methodology/topic-lifecycle-report.yaml +144 -0
  173. package/methodology/topic-lifecycle.yaml +37 -0
  174. package/methodology/topic-naming-ontology.yaml +21 -0
  175. package/methodology/topic-ontology.yaml +38 -0
  176. package/methodology/topic-validation-policy.yaml +9 -0
  177. package/methodology/wave-dag-policy.yaml +14 -0
  178. package/package.json +50 -0
  179. package/spec/_meta/command-gating-matrix.yaml +110 -0
  180. package/spec/_meta/generate-drift-migration-checklist.yaml +155 -0
  181. package/spec/_meta/governance-routing-cutover-checklist.yaml +35 -0
  182. package/spec/_meta/phase2-impacted-surface-matrix.yaml +44 -0
  183. package/spec/_meta/spec-authority-cutover-readiness.yaml +104 -0
  184. package/spec/_meta/spec-tree-model.yaml +72 -0
  185. package/spec/bootstrap-state.yaml +99 -0
  186. package/spec/product-scope.yaml +56 -0
package/cli/index.mjs ADDED
@@ -0,0 +1,103 @@
1
+ import { runBlueprintAudit } from "./commands/blueprint-audit.mjs";
2
+ import { runClear } from "./commands/clear.mjs";
3
+ import { runCloseout } from "./commands/closeout.mjs";
4
+ import { runAdmitHighRiskDecision } from "./commands/admit-high-risk-decision.mjs";
5
+ import { runAuditSweep } from "./commands/audit-sweep.mjs";
6
+ import { runDecideHighRiskExecution } from "./commands/decide-high-risk-execution.mjs";
7
+ import { runDoctor } from "./commands/doctor.mjs";
8
+ import { runHandoff } from "./commands/handoff.mjs";
9
+ import { runIngestHighRiskExecution } from "./commands/ingest-high-risk-execution.mjs";
10
+ import { runReviewHighRiskExecution } from "./commands/review-high-risk-execution.mjs";
11
+ import { runStart } from "./commands/start.mjs";
12
+ import { runTopic } from "./commands/topic.mjs";
13
+ import { runTopicRunnerCommand } from "./commands/topic-runner.mjs";
14
+ import { runValidateAcceptance } from "./commands/validate-acceptance.mjs";
15
+ import { runGenerateSpecDerivedDocs } from "./commands/generate-spec-derived-docs.mjs";
16
+ import { runValidateAiGovernance } from "./commands/validate-ai-governance.mjs";
17
+ import { runValidateExecutionPacket } from "./commands/validate-execution-packet.mjs";
18
+ import { runValidateOrchestrationState } from "./commands/validate-orchestration-state.mjs";
19
+ import { runValidateSpecGovernance } from "./commands/validate-spec-governance.mjs";
20
+ import { runValidateSpecAudit } from "./commands/validate-spec-audit.mjs";
21
+ import { runValidateSpecTree } from "./commands/validate-spec-tree.mjs";
22
+ import { runValidatePrompt } from "./commands/validate-prompt.mjs";
23
+ import { runValidateWorkerOutput } from "./commands/validate-worker-output.mjs";
24
+ import { helpText } from "./help.mjs";
25
+ import { configureCliUi, localize, parseGlobalUiOptions } from "./lib/ui.mjs";
26
+ import { VERSION } from "./constants.mjs";
27
+
28
+ const COMMANDS = {
29
+ start: runStart,
30
+ topic: runTopic,
31
+ "topic-runner": runTopicRunnerCommand,
32
+ clear: runClear,
33
+ doctor: runDoctor,
34
+ "blueprint-audit": runBlueprintAudit,
35
+ handoff: runHandoff,
36
+ closeout: runCloseout,
37
+ "audit-sweep": runAuditSweep,
38
+ "admit-high-risk-decision": runAdmitHighRiskDecision,
39
+ "decide-high-risk-execution": runDecideHighRiskExecution,
40
+ "ingest-high-risk-execution": runIngestHighRiskExecution,
41
+ "review-high-risk-execution": runReviewHighRiskExecution,
42
+ "validate-execution-packet": runValidateExecutionPacket,
43
+ "validate-orchestration-state": runValidateOrchestrationState,
44
+ "validate-spec-governance": runValidateSpecGovernance,
45
+ "validate-spec-audit": runValidateSpecAudit,
46
+ "validate-spec-tree": runValidateSpecTree,
47
+ "generate-spec-derived-docs": runGenerateSpecDerivedDocs,
48
+ "validate-ai-governance": runValidateAiGovernance,
49
+ "validate-prompt": runValidatePrompt,
50
+ "validate-worker-output": runValidateWorkerOutput,
51
+ "validate-acceptance": runValidateAcceptance,
52
+ };
53
+
54
+ export async function runCli(args) {
55
+ const parsedUi = parseGlobalUiOptions(args);
56
+ if (!parsedUi.ok) {
57
+ process.stderr.write(parsedUi.error);
58
+ return 2;
59
+ }
60
+
61
+ configureCliUi({
62
+ locale: parsedUi.locale,
63
+ colorEnabled: parsedUi.colorEnabled,
64
+ });
65
+
66
+ const [command] = parsedUi.args;
67
+ const rest = parsedUi.args.slice(1);
68
+
69
+ if (!command || command === "--help" || command === "-h" || command === "help") {
70
+ if (rest.length > 0) {
71
+ process.stderr.write(localize(
72
+ `nimicoding help refused: unexpected arguments: ${rest.join(" ")}\n`,
73
+ `nimicoding help 拒绝执行:存在未预期参数:${rest.join(" ")}\n`,
74
+ ));
75
+ return 2;
76
+ }
77
+ process.stdout.write(helpText());
78
+ return 0;
79
+ }
80
+
81
+ if (command === "--version" || command === "-v" || command === "version") {
82
+ if (rest.length > 0) {
83
+ process.stderr.write(localize(
84
+ `nimicoding version refused: unexpected arguments: ${rest.join(" ")}\n`,
85
+ `nimicoding version 拒绝执行:存在未预期参数:${rest.join(" ")}\n`,
86
+ ));
87
+ return 2;
88
+ }
89
+ process.stdout.write(`${VERSION}\n`);
90
+ return 0;
91
+ }
92
+
93
+ const runner = COMMANDS[command];
94
+ if (!runner) {
95
+ process.stderr.write(localize(
96
+ `Unknown command: ${command}\n\n${helpText()}`,
97
+ `未知命令:${command}\n\n${helpText()}`,
98
+ ));
99
+ return 2;
100
+ }
101
+
102
+ return runner(rest);
103
+ }
@@ -0,0 +1,403 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ import { ADAPTER_PACKAGE_PROFILE_REFS } from "../constants.mjs";
6
+ import { arraysEqual, isPlainObject, toStringArray } from "./value-helpers.mjs";
7
+ import { parseYamlText } from "./yaml-helpers.mjs";
8
+
9
+ const PACKAGE_ROOT = fileURLToPath(new URL("../..", import.meta.url));
10
+
11
+ const ADAPTER_PROFILE_EXPECTATIONS = {
12
+ codex: {
13
+ hostClass: "native_codex_sdk_host",
14
+ upstreamSeedProfile: "external_ai_host",
15
+ semanticOwner: [
16
+ ".nimi/methodology",
17
+ ".nimi/spec",
18
+ ".nimi/contracts",
19
+ ".nimi/config",
20
+ ],
21
+ operationalOwner: [
22
+ ".codex",
23
+ ".nimi/local",
24
+ ".nimi/cache",
25
+ ],
26
+ admittedSkillSurfaces: [
27
+ "spec_reconstruction",
28
+ "doc_spec_audit",
29
+ "audit_sweep",
30
+ "high_risk_execution",
31
+ "topic_loop_execution",
32
+ "authority_convergence_audit",
33
+ ],
34
+ promptBootstrapSurface: [
35
+ "nimicoding handoff --skill spec_reconstruction --prompt",
36
+ "nimicoding handoff --skill doc_spec_audit --prompt",
37
+ "nimicoding handoff --skill audit_sweep --prompt",
38
+ "nimicoding handoff --skill high_risk_execution --prompt",
39
+ ],
40
+ promptFutureSurface: [
41
+ "Codex.startThread().run",
42
+ "Codex.resumeThread().run",
43
+ ],
44
+ promptFutureSurfaceStatus: "active_via_codex_sdk",
45
+ outputHandoff: {
46
+ workerOutputTarget: ".nimi/local/outputs/** candidate artifact",
47
+ evidenceTarget: ".nimi/local/evidence/** candidate artifact",
48
+ closeoutTarget: "local-only closeout payload unless later admitted",
49
+ },
50
+ nativeReviewBoundary: {
51
+ approvalReview: {
52
+ scope: "lower_layer_permission_review",
53
+ semanticEffect: "none",
54
+ evidenceTarget: ".nimi/local/evidence/** candidate artifact",
55
+ },
56
+ githubAutoReview: {
57
+ scope: "lower_layer_pr_review_findings",
58
+ semanticEffect: "evidence_only",
59
+ evidenceTarget: ".nimi/local/evidence/** candidate artifact",
60
+ },
61
+ forbiddenSemanticSubstitutions: [
62
+ "wave_admission",
63
+ "packet_freeze",
64
+ "result_verdict",
65
+ "wave_closeout",
66
+ "topic_closeout",
67
+ "true_close",
68
+ ],
69
+ },
70
+ hardConstraints: [
71
+ "codex_sdk_must_not_become_semantic_owner",
72
+ "codex_sdk_must_not_write_canonical_.nimi/spec_truth_directly_without_validator_admission",
73
+ "codex_sdk_must_not_define_acceptance_disposition_or_finding_judgment",
74
+ "codex_thread_state_must_remain_operational_only",
75
+ "codex_sdk_runs_must_be_recorded_in_topic_run_ledger",
76
+ "codex_native_approval_review_must_remain_permission_review_only",
77
+ "codex_github_auto_review_must_remain_evidence_only",
78
+ "codex_review_must_not_substitute_nimicoding_semantic_commands",
79
+ "unresolved_authority_or_missing_context_must_fail_closed",
80
+ "codex_subagent_authority_convergence_output_must_remain_candidate_evidence",
81
+ ],
82
+ },
83
+ claude: {
84
+ hostClass: "inline_coding_host",
85
+ upstreamSeedProfile: "external_ai_host",
86
+ semanticOwner: [
87
+ ".nimi/methodology",
88
+ ".nimi/spec",
89
+ ".nimi/contracts",
90
+ ".nimi/config",
91
+ ],
92
+ operationalOwner: [
93
+ ".claude",
94
+ ".nimi/local",
95
+ ".nimi/cache",
96
+ ],
97
+ admittedSkillSurfaces: [
98
+ "spec_reconstruction",
99
+ "doc_spec_audit",
100
+ "audit_sweep",
101
+ "high_risk_execution",
102
+ "inline_review",
103
+ "authority_convergence_audit",
104
+ ],
105
+ promptBootstrapSurface: [
106
+ "nimicoding handoff --skill spec_reconstruction --prompt",
107
+ "nimicoding handoff --skill doc_spec_audit --prompt",
108
+ "nimicoding handoff --skill audit_sweep --prompt",
109
+ "nimicoding handoff --skill high_risk_execution --prompt",
110
+ ],
111
+ promptFutureSurface: [],
112
+ promptFutureSurfaceStatus: "active_via_hooks",
113
+ outputHandoff: {
114
+ workerOutputTarget: ".nimi/local/outputs/** candidate artifact",
115
+ evidenceTarget: ".nimi/local/evidence/** candidate artifact",
116
+ closeoutTarget: "local-only closeout payload unless later admitted",
117
+ },
118
+ hardConstraints: [
119
+ "claude_must_not_become_semantic_owner",
120
+ "claude_must_not_write_canonical_.nimi/spec_truth_directly_without_validator_admission",
121
+ "claude_must_not_define_acceptance_disposition_or_finding_judgment",
122
+ "claude_operational_state_must_remain_operational_only",
123
+ "claude_hooks_must_not_replace_agents_md_authority",
124
+ "unresolved_authority_or_missing_context_must_fail_closed",
125
+ "claude_subagent_authority_convergence_output_must_remain_candidate_evidence",
126
+ ],
127
+ },
128
+ oh_my_codex: {
129
+ hostClass: "external_execution_host",
130
+ upstreamSeedProfile: "external_ai_host",
131
+ semanticOwner: [
132
+ ".nimi/methodology",
133
+ ".nimi/spec",
134
+ ".nimi/contracts",
135
+ ".nimi/config",
136
+ ],
137
+ operationalOwner: [
138
+ ".omx",
139
+ ".nimi/local",
140
+ ".nimi/cache",
141
+ ],
142
+ admittedSkillSurfaces: [
143
+ "spec_reconstruction",
144
+ "doc_spec_audit",
145
+ "audit_sweep",
146
+ "high_risk_execution",
147
+ ],
148
+ promptBootstrapSurface: [
149
+ "nimicoding handoff --skill spec_reconstruction --prompt",
150
+ "nimicoding handoff --skill doc_spec_audit --prompt",
151
+ "nimicoding handoff --skill audit_sweep --prompt",
152
+ "nimicoding handoff --skill high_risk_execution --prompt",
153
+ ],
154
+ promptFutureSurface: [
155
+ "nimicoding run-next-prompt",
156
+ ],
157
+ promptFutureSurfaceStatus: "future_only_not_packaged",
158
+ outputHandoff: {
159
+ workerOutputTarget: ".nimi/local/outputs/** candidate artifact",
160
+ evidenceTarget: ".nimi/local/evidence/** candidate artifact",
161
+ closeoutTarget: "local-only closeout payload unless later admitted",
162
+ },
163
+ hardConstraints: [
164
+ "omx_must_not_become_semantic_owner",
165
+ "omx_must_not_write_canonical_.nimi/spec_truth_directly_without_validator_admission",
166
+ "omx_must_not_define_acceptance_disposition_or_finding_judgment",
167
+ "omx_runtime_state_must_remain_operational_only",
168
+ "unresolved_authority_or_missing_context_must_fail_closed",
169
+ ],
170
+ },
171
+ };
172
+
173
+ function buildInvalidProfile(adapterId, profileRef, reason) {
174
+ return {
175
+ ok: false,
176
+ id: adapterId,
177
+ profileRef,
178
+ absolutePath: profileRef ? path.join(PACKAGE_ROOT, profileRef) : null,
179
+ reason,
180
+ version: null,
181
+ hostClass: null,
182
+ upstreamSeedProfile: null,
183
+ purpose: null,
184
+ semanticOwner: [],
185
+ operationalOwner: [],
186
+ admittedSkillSurfaces: [],
187
+ promptHandoff: {
188
+ bootstrapSurface: [],
189
+ futureSurface: [],
190
+ futureSurfaceStatus: null,
191
+ },
192
+ outputHandoff: {
193
+ workerOutputTarget: null,
194
+ evidenceTarget: null,
195
+ closeoutTarget: null,
196
+ },
197
+ nativeReviewBoundary: null,
198
+ hardConstraints: [],
199
+ currentGaps: [],
200
+ };
201
+ }
202
+
203
+ function normalizeAdapterProfile(adapterId, profileRef, parsed) {
204
+ const profile = parsed?.adapter_profile;
205
+ if (!isPlainObject(profile)) {
206
+ return buildInvalidProfile(adapterId, profileRef, "adapter profile YAML is missing adapter_profile");
207
+ }
208
+
209
+ return {
210
+ ok: true,
211
+ id: typeof profile.id === "string" ? profile.id : null,
212
+ profileRef,
213
+ absolutePath: path.join(PACKAGE_ROOT, profileRef),
214
+ reason: null,
215
+ version: parsed?.version ?? null,
216
+ hostClass: typeof profile.host_class === "string" ? profile.host_class : null,
217
+ upstreamSeedProfile: typeof profile.upstream_seed_profile === "string" ? profile.upstream_seed_profile : null,
218
+ purpose: typeof profile.purpose === "string" ? profile.purpose.trim() : null,
219
+ semanticOwner: toStringArray(profile.semantic_owner),
220
+ operationalOwner: toStringArray(profile.operational_owner),
221
+ admittedSkillSurfaces: toStringArray(profile.admitted_skill_surfaces),
222
+ promptHandoff: {
223
+ bootstrapSurface: toStringArray(profile.prompt_handoff?.bootstrap_surface),
224
+ futureSurface: toStringArray(profile.prompt_handoff?.future_surface?.commands),
225
+ futureSurfaceStatus: typeof profile.prompt_handoff?.future_surface?.status === "string"
226
+ ? profile.prompt_handoff.future_surface.status
227
+ : null,
228
+ },
229
+ outputHandoff: {
230
+ workerOutputTarget: typeof profile.output_handoff?.worker_output_target === "string"
231
+ ? profile.output_handoff.worker_output_target
232
+ : null,
233
+ evidenceTarget: typeof profile.output_handoff?.evidence_target === "string"
234
+ ? profile.output_handoff.evidence_target
235
+ : null,
236
+ closeoutTarget: typeof profile.output_handoff?.closeout_target === "string"
237
+ ? profile.output_handoff.closeout_target
238
+ : null,
239
+ },
240
+ nativeReviewBoundary: isPlainObject(profile.native_review_boundary)
241
+ ? {
242
+ approvalReview: {
243
+ scope: typeof profile.native_review_boundary.approval_review?.scope === "string"
244
+ ? profile.native_review_boundary.approval_review.scope
245
+ : null,
246
+ semanticEffect: typeof profile.native_review_boundary.approval_review?.semantic_effect === "string"
247
+ ? profile.native_review_boundary.approval_review.semantic_effect
248
+ : null,
249
+ evidenceTarget: typeof profile.native_review_boundary.approval_review?.evidence_target === "string"
250
+ ? profile.native_review_boundary.approval_review.evidence_target
251
+ : null,
252
+ },
253
+ githubAutoReview: {
254
+ scope: typeof profile.native_review_boundary.github_auto_review?.scope === "string"
255
+ ? profile.native_review_boundary.github_auto_review.scope
256
+ : null,
257
+ semanticEffect: typeof profile.native_review_boundary.github_auto_review?.semantic_effect === "string"
258
+ ? profile.native_review_boundary.github_auto_review.semantic_effect
259
+ : null,
260
+ evidenceTarget: typeof profile.native_review_boundary.github_auto_review?.evidence_target === "string"
261
+ ? profile.native_review_boundary.github_auto_review.evidence_target
262
+ : null,
263
+ },
264
+ forbiddenSemanticSubstitutions: toStringArray(
265
+ profile.native_review_boundary.forbidden_semantic_substitutions,
266
+ ),
267
+ }
268
+ : null,
269
+ hardConstraints: toStringArray(profile.hard_constraints),
270
+ currentGaps: toStringArray(profile.current_gaps),
271
+ };
272
+ }
273
+
274
+ function validateAdapterProfile(profile) {
275
+ const expectation = ADAPTER_PROFILE_EXPECTATIONS[profile.id];
276
+ if (!expectation) {
277
+ return {
278
+ ok: false,
279
+ reason: `no package-owned adapter profile expectation is declared for ${profile.id}`,
280
+ };
281
+ }
282
+
283
+ const hardConstraintsOk = expectation.hardConstraints.every((entry) => profile.hardConstraints.includes(entry));
284
+ const outputHandoffOk = profile.outputHandoff.workerOutputTarget === expectation.outputHandoff.workerOutputTarget
285
+ && profile.outputHandoff.evidenceTarget === expectation.outputHandoff.evidenceTarget
286
+ && profile.outputHandoff.closeoutTarget === expectation.outputHandoff.closeoutTarget;
287
+ const nativeReviewOk = !expectation.nativeReviewBoundary
288
+ || (
289
+ profile.nativeReviewBoundary?.approvalReview?.scope === expectation.nativeReviewBoundary.approvalReview.scope
290
+ && profile.nativeReviewBoundary.approvalReview.semanticEffect === expectation.nativeReviewBoundary.approvalReview.semanticEffect
291
+ && profile.nativeReviewBoundary.approvalReview.evidenceTarget === expectation.nativeReviewBoundary.approvalReview.evidenceTarget
292
+ && profile.nativeReviewBoundary.githubAutoReview?.scope === expectation.nativeReviewBoundary.githubAutoReview.scope
293
+ && profile.nativeReviewBoundary.githubAutoReview.semanticEffect === expectation.nativeReviewBoundary.githubAutoReview.semanticEffect
294
+ && profile.nativeReviewBoundary.githubAutoReview.evidenceTarget === expectation.nativeReviewBoundary.githubAutoReview.evidenceTarget
295
+ && arraysEqual(
296
+ profile.nativeReviewBoundary.forbiddenSemanticSubstitutions,
297
+ expectation.nativeReviewBoundary.forbiddenSemanticSubstitutions,
298
+ )
299
+ );
300
+
301
+ const ok = profile.version === 1
302
+ && profile.id in ADAPTER_PACKAGE_PROFILE_REFS
303
+ && profile.hostClass === expectation.hostClass
304
+ && profile.upstreamSeedProfile === expectation.upstreamSeedProfile
305
+ && Boolean(profile.purpose)
306
+ && arraysEqual(profile.semanticOwner, expectation.semanticOwner)
307
+ && arraysEqual(profile.operationalOwner, expectation.operationalOwner)
308
+ && arraysEqual(profile.admittedSkillSurfaces, expectation.admittedSkillSurfaces)
309
+ && arraysEqual(profile.promptHandoff.bootstrapSurface, expectation.promptBootstrapSurface)
310
+ && arraysEqual(profile.promptHandoff.futureSurface, expectation.promptFutureSurface)
311
+ && profile.promptHandoff.futureSurfaceStatus === expectation.promptFutureSurfaceStatus
312
+ && outputHandoffOk
313
+ && nativeReviewOk
314
+ && hardConstraintsOk;
315
+
316
+ return {
317
+ ok,
318
+ reason: ok
319
+ ? null
320
+ : `${profile.profileRef} drifted away from the declared package-owned adapter overlay contract`,
321
+ };
322
+ }
323
+
324
+ function serializeProfile(profile) {
325
+ return {
326
+ id: profile.id,
327
+ profileRef: profile.profileRef,
328
+ hostClass: profile.hostClass,
329
+ upstreamSeedProfile: profile.upstreamSeedProfile,
330
+ purpose: profile.purpose,
331
+ semanticOwner: profile.semanticOwner,
332
+ operationalOwner: profile.operationalOwner,
333
+ admittedSkillSurfaces: profile.admittedSkillSurfaces,
334
+ promptHandoff: profile.promptHandoff,
335
+ outputHandoff: profile.outputHandoff,
336
+ nativeReviewBoundary: profile.nativeReviewBoundary,
337
+ hardConstraints: profile.hardConstraints,
338
+ currentGaps: profile.currentGaps,
339
+ ok: profile.ok,
340
+ reason: profile.reason,
341
+ };
342
+ }
343
+
344
+ export async function loadAdapterProfile(adapterId) {
345
+ const profileRef = ADAPTER_PACKAGE_PROFILE_REFS[adapterId] ?? null;
346
+ if (!profileRef) {
347
+ return buildInvalidProfile(adapterId, null, `no package-owned adapter profile is declared for ${adapterId}`);
348
+ }
349
+
350
+ let rawText;
351
+ try {
352
+ rawText = await readFile(path.join(PACKAGE_ROOT, profileRef), "utf8");
353
+ } catch {
354
+ return buildInvalidProfile(adapterId, profileRef, `cannot read package-owned adapter profile ${profileRef}`);
355
+ }
356
+
357
+ const parsed = parseYamlText(rawText);
358
+ if (!parsed) {
359
+ return buildInvalidProfile(adapterId, profileRef, `package-owned adapter profile ${profileRef} is invalid YAML`);
360
+ }
361
+
362
+ const normalized = normalizeAdapterProfile(adapterId, profileRef, parsed);
363
+ if (!normalized.ok) {
364
+ return normalized;
365
+ }
366
+
367
+ if (normalized.id !== adapterId) {
368
+ return buildInvalidProfile(adapterId, profileRef, `${profileRef} declares adapter id ${normalized.id ?? "unknown"} instead of ${adapterId}`);
369
+ }
370
+
371
+ const validation = validateAdapterProfile(normalized);
372
+ if (!validation.ok) {
373
+ return {
374
+ ...normalized,
375
+ ok: false,
376
+ reason: validation.reason,
377
+ };
378
+ }
379
+
380
+ return normalized;
381
+ }
382
+
383
+ export async function loadAdmittedAdapterProfiles(adapterIds) {
384
+ const profiles = [];
385
+
386
+ for (const adapterId of adapterIds) {
387
+ profiles.push(await loadAdapterProfile(adapterId));
388
+ }
389
+
390
+ return {
391
+ admitted: profiles.map((profile) => serializeProfile(profile)),
392
+ invalid: profiles.filter((profile) => !profile.ok).map((profile) => serializeProfile(profile)),
393
+ selected: null,
394
+ };
395
+ }
396
+
397
+ export function selectAdapterProfile(adapterProfiles, selectedAdapterId) {
398
+ if (!selectedAdapterId || selectedAdapterId === "none") {
399
+ return null;
400
+ }
401
+
402
+ return adapterProfiles.admitted.find((profile) => profile.id === selectedAdapterId) ?? null;
403
+ }
@@ -0,0 +1,52 @@
1
+ import path from "node:path";
2
+
3
+ import {
4
+ AUDIT_EXECUTION_ARTIFACTS_CONFIG_REF,
5
+ AUDIT_SWEEP_ARTIFACT_HARD_CONSTRAINTS,
6
+ AUDIT_SWEEP_ARTIFACT_ROOTS,
7
+ AUDIT_SWEEP_RESULT_CONTRACT_REF,
8
+ HOST_ADAPTER_CONFIG_REF,
9
+ } from "../constants.mjs";
10
+ import { readTextIfFile } from "./fs-helpers.mjs";
11
+ import { arraysEqual, isPlainObject, toStringArray } from "./value-helpers.mjs";
12
+ import { parseYamlText } from "./yaml-helpers.mjs";
13
+
14
+ function parseAuditExecutionArtifactsConfig(text) {
15
+ const parsed = parseYamlText(text);
16
+ const root = parsed?.audit_execution_artifacts;
17
+ const artifactRoots = isPlainObject(root?.artifact_roots) ? root.artifact_roots : null;
18
+ const hardConstraints = toStringArray(root?.hard_constraints);
19
+
20
+ const artifactRootsOk = Boolean(artifactRoots)
21
+ && Object.entries(AUDIT_SWEEP_ARTIFACT_ROOTS).every(
22
+ ([field, expectedPath]) => String(artifactRoots[field] ?? "") === expectedPath,
23
+ )
24
+ && Object.keys(artifactRoots).length === Object.keys(AUDIT_SWEEP_ARTIFACT_ROOTS).length;
25
+
26
+ return {
27
+ ok: String(root?.skill_id ?? "") === "audit_sweep"
28
+ && String(root?.host_adapter_ref ?? "") === HOST_ADAPTER_CONFIG_REF
29
+ && String(root?.result_contract_ref ?? "") === AUDIT_SWEEP_RESULT_CONTRACT_REF
30
+ && String(root?.locality ?? "") === "local_only"
31
+ && artifactRootsOk
32
+ && arraysEqual(hardConstraints, AUDIT_SWEEP_ARTIFACT_HARD_CONSTRAINTS),
33
+ artifactRoots: artifactRootsOk
34
+ ? Object.fromEntries(
35
+ Object.entries(AUDIT_SWEEP_ARTIFACT_ROOTS).map(([field]) => [field, artifactRoots[field]]),
36
+ )
37
+ : null,
38
+ hardConstraints,
39
+ };
40
+ }
41
+
42
+ export async function loadAuditExecutionArtifactsConfig(projectRoot) {
43
+ const text = await readTextIfFile(
44
+ path.join(projectRoot, AUDIT_EXECUTION_ARTIFACTS_CONFIG_REF),
45
+ );
46
+
47
+ return {
48
+ path: AUDIT_EXECUTION_ARTIFACTS_CONFIG_REF,
49
+ text,
50
+ ...parseAuditExecutionArtifactsConfig(text),
51
+ };
52
+ }