@nimiplatform/nimi-coding 0.1.0 → 0.2.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 (121) hide show
  1. package/README.md +19 -20
  2. package/adapters/oh-my-codex/README.md +8 -9
  3. package/cli/commands/audit-sweep.mjs +10 -10
  4. package/cli/commands/classify-spec-tree.mjs +5 -0
  5. package/cli/commands/closeout.mjs +3 -0
  6. package/cli/commands/generate-spec-derived-docs.mjs +20 -0
  7. package/cli/commands/generate-spec-migration-plan.mjs +30 -0
  8. package/cli/commands/start.mjs +5 -1
  9. package/cli/commands/surface-validator-command.mjs +49 -0
  10. package/cli/commands/sweep-design.mjs +295 -0
  11. package/cli/commands/sweep.mjs +22 -0
  12. package/cli/commands/sync.mjs +132 -0
  13. package/cli/commands/topic-formatters.mjs +8 -8
  14. package/cli/commands/validate-ai-governance.mjs +167 -46
  15. package/cli/commands/validate-domain-admission.mjs +5 -0
  16. package/cli/commands/validate-guidance-bodies.mjs +5 -0
  17. package/cli/commands/validate-placement.mjs +5 -0
  18. package/cli/commands/validate-projection-edges.mjs +5 -0
  19. package/cli/commands/validate-spec-audit.mjs +5 -1
  20. package/cli/commands/validate-table-family.mjs +5 -0
  21. package/cli/commands/validate-tracked-output-admission.mjs +5 -0
  22. package/cli/constants.mjs +5 -49
  23. package/cli/help.mjs +33 -11
  24. package/cli/index.mjs +20 -2
  25. package/cli/lib/audit-sweep-runtime/admissions.mjs +38 -29
  26. package/cli/lib/audit-sweep-runtime/audit-validity.mjs +8 -0
  27. package/cli/lib/audit-sweep-runtime/chunks.mjs +11 -11
  28. package/cli/lib/audit-sweep-runtime/closeout.mjs +8 -8
  29. package/cli/lib/audit-sweep-runtime/codex-auditor-evidence.mjs +3 -3
  30. package/cli/lib/audit-sweep-runtime/codex-auditor.mjs +10 -10
  31. package/cli/lib/audit-sweep-runtime/common.mjs +7 -7
  32. package/cli/lib/audit-sweep-runtime/format.mjs +3 -3
  33. package/cli/lib/audit-sweep-runtime/ingest.mjs +8 -8
  34. package/cli/lib/audit-sweep-runtime/inventory-spec-chunks.mjs +24 -27
  35. package/cli/lib/audit-sweep-runtime/inventory.mjs +58 -18
  36. package/cli/lib/audit-sweep-runtime/ledger.mjs +1 -1
  37. package/cli/lib/audit-sweep-runtime/p0p1-profile.mjs +2 -2
  38. package/cli/lib/audit-sweep-runtime/remediation.mjs +6 -6
  39. package/cli/lib/audit-sweep-runtime/rerun.mjs +6 -6
  40. package/cli/lib/audit-sweep-runtime/status.mjs +1 -1
  41. package/cli/lib/audit-sweep-runtime/validators.mjs +2 -2
  42. package/cli/lib/authority-convergence.mjs +397 -2
  43. package/cli/lib/blueprint-audit.mjs +5 -5
  44. package/cli/lib/closeout.mjs +126 -3
  45. package/cli/lib/contracts.mjs +21 -17
  46. package/cli/lib/handoff.mjs +29 -11
  47. package/cli/lib/high-risk-admission.mjs +60 -11
  48. package/cli/lib/high-risk-decision.mjs +31 -2
  49. package/cli/lib/high-risk-ingest.mjs +5 -1
  50. package/cli/lib/high-risk-review.mjs +5 -1
  51. package/cli/lib/internal/contracts-parse.mjs +195 -24
  52. package/cli/lib/internal/contracts-validators.mjs +3 -2
  53. package/cli/lib/internal/doctor-bootstrap-surface.mjs +82 -35
  54. package/cli/lib/internal/doctor-delegated-surface.mjs +1 -1
  55. package/cli/lib/internal/doctor-finalize.mjs +12 -8
  56. package/cli/lib/internal/doctor-inspectors.mjs +34 -1
  57. package/cli/lib/internal/governance/ai/ai-context-budget-core.mjs +74 -12
  58. package/cli/lib/internal/governance/ai/ai-structure-budget-core.mjs +24 -6
  59. package/cli/lib/internal/governance/ai/check-agents-freshness.mjs +18 -23
  60. package/cli/lib/internal/surface-taxonomy-validators.mjs +931 -0
  61. package/cli/lib/internal/validators-spec.mjs +229 -20
  62. package/cli/lib/sweep-design-runtime/common.mjs +246 -0
  63. package/cli/lib/sweep-design-runtime/engine.mjs +733 -0
  64. package/cli/lib/sweep-design-runtime/fix-topic.mjs +414 -0
  65. package/cli/lib/sweep-design-runtime/lifecycle.mjs +54 -0
  66. package/cli/lib/sweep-design-runtime/results.mjs +324 -0
  67. package/cli/lib/sweep-design.mjs +8 -0
  68. package/cli/lib/sync.mjs +143 -0
  69. package/cli/lib/topic-artifacts.mjs +186 -0
  70. package/cli/lib/topic-authority-coverage.mjs +73 -0
  71. package/cli/lib/topic-closeout.mjs +560 -0
  72. package/cli/lib/topic-common.mjs +404 -0
  73. package/cli/lib/topic-decisions.mjs +332 -0
  74. package/cli/lib/topic-draft-packets.mjs +126 -7
  75. package/cli/lib/topic-execution.mjs +515 -0
  76. package/cli/lib/topic-goal.mjs +112 -33
  77. package/cli/lib/topic-ledger.mjs +281 -0
  78. package/cli/lib/topic-lifecycle-artifacts.mjs +173 -0
  79. package/cli/lib/topic-root-validation.mjs +288 -0
  80. package/cli/lib/topic-runner-commands.mjs +174 -0
  81. package/cli/lib/topic-runner-deferral.mjs +532 -0
  82. package/cli/lib/topic-runner-stale-gates.mjs +114 -0
  83. package/cli/lib/topic-runner-validation.mjs +138 -0
  84. package/cli/lib/topic-runner.mjs +109 -154
  85. package/cli/lib/topic-scaffold.mjs +252 -0
  86. package/cli/lib/topic-waves.mjs +403 -0
  87. package/cli/lib/topic.mjs +81 -93
  88. package/cli/lib/value-helpers.mjs +6 -1
  89. package/cli/seeds/bootstrap.mjs +96 -20
  90. package/cli/seeds/seed-policy.yaml +67 -0
  91. package/config/bootstrap.yaml +1 -1
  92. package/config/skill-manifest.yaml +4 -2
  93. package/config/spec-generation-inputs.yaml +41 -19
  94. package/contracts/audit-remediation-map.schema.yaml +1 -0
  95. package/contracts/audit-sweep-result.yaml +4 -0
  96. package/contracts/domain-admission.schema.yaml +56 -0
  97. package/contracts/migration-inventory.schema.yaml +80 -0
  98. package/contracts/negative-fixtures.yaml +91 -0
  99. package/contracts/placement-contract.schema.yaml +163 -0
  100. package/contracts/projection-edge.schema.yaml +130 -0
  101. package/contracts/shared-enums.yaml +68 -0
  102. package/contracts/spec-generation-audit.schema.yaml +19 -4
  103. package/contracts/spec-generation-inputs.schema.yaml +130 -29
  104. package/contracts/spec-reconstruction-result.yaml +9 -5
  105. package/contracts/surface-taxonomy.schema.yaml +201 -0
  106. package/contracts/sweep-design-result.yaml +349 -0
  107. package/contracts/table-family.schema.yaml +114 -0
  108. package/contracts/topic-goal.schema.yaml +10 -1
  109. package/contracts/tracked-output-admission.schema.yaml +70 -0
  110. package/contracts/workflow-consumer.schema.yaml +112 -0
  111. package/methodology/audit-sweep-p0p1-recall.yaml +1 -1
  112. package/methodology/spec-reconstruction.yaml +53 -30
  113. package/package.json +5 -4
  114. package/spec/_meta/command-gating-matrix.yaml +33 -0
  115. package/spec/_meta/generate-drift-migration-checklist.yaml +44 -62
  116. package/spec/_meta/governance-routing-cutover-checklist.yaml +3 -3
  117. package/spec/_meta/phase2-impacted-surface-matrix.yaml +14 -14
  118. package/spec/_meta/spec-authority-cutover-readiness.yaml +3 -5
  119. package/spec/_meta/spec-tree-model.yaml +104 -36
  120. package/spec/bootstrap-state.yaml +36 -36
  121. package/spec/product-scope.yaml +13 -10
package/README.md CHANGED
@@ -19,14 +19,14 @@ The primary `nimicoding` path is for an ordinary project with mixed inputs:
19
19
  6. close out reconstruction
20
20
  7. hand off `doc_spec_audit` and close it out locally
21
21
 
22
- `blueprint-audit`, benchmark parity, and direct-copy helpers remain available,
23
- but they are support-only or repo-local special cases. They do not define
24
- default reconstruction completion.
22
+ `blueprint-audit` and benchmark parity remain available, but they are
23
+ support-only package fixtures. They do not define default reconstruction
24
+ completion for a host project.
25
25
 
26
- In this monorepo, `/.nimi/spec/**` is now the repo-wide product authority.
27
- Pre-cutover authority history now lives in Git rather than a repo-local
28
- archive tree. Pre-cutover readiness work was evidence only and did not
29
- authorize the flip by itself.
26
+ In a host project, `/.nimi/spec/**` becomes product authority only after that
27
+ project admits or reconstructs it. `nimicoding` provides the CLI, injected
28
+ `.nimi/{config,contracts,methodology}/**` contracts, and validators; it does
29
+ not make a host read package source paths directly.
30
30
 
31
31
  ## Current Status
32
32
 
@@ -37,7 +37,7 @@ Its completed standalone scope is:
37
37
  - package identity
38
38
  - repository foundation
39
39
  - initial AI-native methodology seed
40
- - package-owned repo-local support profile source for future governance slices
40
+ - package-owned support profile source for future governance slices
41
41
  - machine-readable reconstruction, doc-spec-audit, and high-risk execution result contracts
42
42
  - package-owned canonical high-risk admission schema contract
43
43
  - seed-only high-risk execution schemas for packet, orchestration-state, prompt, worker-output, and acceptance
@@ -73,8 +73,8 @@ At the current stage it provides:
73
73
  - a primary `nimicoding start` entrypoint for bootstrap, resume, and next-stage AI task prep
74
74
  - a conservative `nimicoding clear` entrypoint for removing package-managed setup without deleting project-owned truth
75
75
  - a bounded `nimicoding doctor`
76
- - an explicit `nimicoding blueprint-audit` equivalence check for comparing a repo-local blueprint root with the candidate canonical tree under `.nimi/spec`
77
- - a repo-local `pnpm check:spec-authority-cutover-readiness` gate for pre-cutover readiness validation before authority execution
76
+ - an explicit `nimicoding blueprint-audit` equivalence check for comparing a fixture or host blueprint root with the candidate canonical tree under `.nimi/spec`
77
+ - surface validators for placement, table-family, projection-edge, guidance-body, domain-admission, and tracked-output admission boundaries
78
78
  - an explicit `nimicoding handoff` export
79
79
  - an explicit `nimicoding admit-high-risk-decision` semantic admission surface
80
80
  - a local-only `nimicoding closeout` projection
@@ -91,7 +91,7 @@ Current `nimicoding start` behavior is intentionally narrow:
91
91
  - detect the current project state and continue from the right stage
92
92
  - create or resume the `.nimi/**` seed by projecting package-owned source into host paths
93
93
  - seed AI-native spec-reconstruction guidance inside `.nimi/**`
94
- - keep repo-local support-only methodology assets package-owned unless a host explicitly opts into them
94
+ - keep support-only methodology assets package-owned unless a host explicitly opts into them
95
95
  - seed package-owned machine contracts inside `.nimi/contracts/**`
96
96
  - seed package-owned execution schemas for future high-risk methodology artifacts without admitting runtime ownership
97
97
  - seed canonical skill-manifest, host-profile, installer, delegated runtime contract, installer result contract, installer operational evidence home, and external handoff truth inside `.nimi/**`
@@ -198,21 +198,20 @@ cross-report navigation harder. Stable machine report artifacts that are meant
198
198
  to behave like a current snapshot, such as `blueprint-equivalence-audit.json`,
199
199
  should keep their fixed names.
200
200
 
201
- ## Canonical Spec Redesign Prep
201
+ ## Canonical Spec Surface Model
202
202
 
203
- The package now seeds Phase 0 / Phase 1 canonical-spec redesign contracts under
204
- `.nimi/spec/_meta/**` together with rewritten `bootstrap-state.yaml` and
205
- `product-scope.yaml`.
203
+ The package seeds the host-local contracts needed to reconstruct and validate a
204
+ canonical spec tree without putting package methodology or lifecycle state under
205
+ the host product-authority root.
206
206
 
207
207
  At this stage:
208
208
 
209
- - these files are machine contracts and implementation authority for canonical spec generation
210
- - active repository authority now lives under `/.nimi/spec/**`
211
- - `start`, `doctor`, `handoff`, `closeout`, and high-risk gating already read the canonical tree lifecycle instead of treating the old five-file compact model as authoritative completion
209
+ - `config/**`, `contracts/**`, `methodology/**`, and `spec/**` are package source for the npm package
210
+ - generated host projects receive injected `.nimi/{config,contracts,methodology}/**` projections and own their `.nimi/spec/**` product authority
211
+ - `start`, `doctor`, `handoff`, `closeout`, and high-risk gating read host-local `.nimi/**` projections instead of requiring access to package source paths
212
212
  - `nimicoding blueprint-audit` remains the explicit audit surface for benchmark-vs-canonical equivalence checks; it does not perform routing changes on its own
213
- - `pnpm check:spec-authority-cutover-readiness` remains a pre-cutover readiness aggregator; after cutover it is historical/preflight-only rather than the active authority source
214
213
  - canonical spec generation now reads mixed inputs from `.nimi/config/spec-generation-inputs.yaml` and treats any blueprint root as an optional benchmark rather than a universal host assumption
215
- - completed canonical reconstruction now requires both structural validity and file-level auditability under `.nimi/spec/_meta/spec-generation-audit.yaml`
214
+ - completed canonical reconstruction now requires structural validity and may carry file-level auditability under `.nimi/local/state/spec-generation/spec-generation-audit.yaml`
216
215
  - `nimicoding validate-spec-tree` checks canonical tree structure, while `nimicoding validate-spec-audit` checks per-file grounding, inference, and unresolved-gap tracking
217
216
 
218
217
  Current `nimicoding doctor` behavior is intentionally narrow:
@@ -97,8 +97,8 @@ nimicoding handoff --skill spec_reconstruction --json
97
97
  Use the JSON payload as OMX's machine contract. `--prompt` may still be used
98
98
  as a host briefing, but it is not the authoritative surface. OMX should
99
99
  return only the declared canonical tree outputs and must not invent new semantic
100
- owners. In this monorepo the explicit cutover batch has already made
101
- `.nimi/spec/**` the current authority root; OMX still must not redefine that
100
+ owners. In a host project, `.nimi/spec/**` is current authority only when the
101
+ host has admitted or reconstructed it; OMX still must not redefine that
102
102
  authority or promote its own runtime state into semantic truth.
103
103
 
104
104
  Then project the closeout locally:
@@ -152,13 +152,12 @@ For now, treat OMX output as execution candidate material:
152
152
 
153
153
  In practice, this means the first real user can use OMX as the execution host
154
154
  today, while standalone `nimicoding` remains the host-agnostic semantic and
155
- interop boundary package. The promoted internal
156
- [`nimi-coding`](/Users/snwozy/nimi-realm/nimi/nimi-coding) still owns
157
- packet-bound runtime, provider-backed execution, scheduler, notification, and
158
- automation surfaces, even though standalone
159
- `nimicoding closeout` can now import a fail-closed local-only execution
160
- summary and `nimicoding ingest-high-risk-execution` can mechanically validate
161
- the referenced packet/prompt/output candidates while
155
+ interop boundary package. The standalone package intentionally does not own
156
+ packet-bound runtime, provider-backed execution, scheduler, notification, or
157
+ automation surfaces yet, even though `nimicoding closeout` can import a
158
+ fail-closed local-only execution summary and
159
+ `nimicoding ingest-high-risk-execution` can mechanically validate the
160
+ referenced packet/prompt/output candidates while
162
161
  `nimicoding review-high-risk-execution` can project a manager-ready local
163
162
  attachment bundle, `nimicoding decide-high-risk-execution` can record a
164
163
  manager-owned local disposition, and `nimicoding admit-high-risk-decision`
@@ -22,8 +22,8 @@ function readRequiredValue(args, index, optionName, commandName) {
22
22
  return {
23
23
  ok: false,
24
24
  error: `${localize(
25
- `nimicoding audit-sweep ${commandName} refused: ${optionName} requires a value.`,
26
- `nimicoding audit-sweep ${commandName} 已拒绝:${optionName} 需要一个值。`,
25
+ `nimicoding sweep audit ${commandName} refused: ${optionName} requires a value.`,
26
+ `nimicoding sweep audit ${commandName} 已拒绝:${optionName} 需要一个值。`,
27
27
  )}\n`,
28
28
  };
29
29
  }
@@ -34,8 +34,8 @@ function unknownOption(commandName, arg) {
34
34
  return {
35
35
  ok: false,
36
36
  error: `${localize(
37
- `nimicoding audit-sweep ${commandName} refused: unknown option ${arg}.`,
38
- `nimicoding audit-sweep ${commandName} 已拒绝:未知选项 ${arg}。`,
37
+ `nimicoding sweep audit ${commandName} refused: unknown option ${arg}.`,
38
+ `nimicoding sweep audit ${commandName} 已拒绝:未知选项 ${arg}。`,
39
39
  )}\n`,
40
40
  };
41
41
  }
@@ -65,8 +65,8 @@ function parseOptions(args, commandName, spec) {
65
65
  return {
66
66
  ok: false,
67
67
  error: `${localize(
68
- `nimicoding audit-sweep ${commandName} refused: ${arg} must be a positive integer.`,
69
- `nimicoding audit-sweep ${commandName} 已拒绝:${arg} 必须是正整数。`,
68
+ `nimicoding sweep audit ${commandName} refused: ${arg} must be a positive integer.`,
69
+ `nimicoding sweep audit ${commandName} 已拒绝:${arg} 必须是正整数。`,
70
70
  )}\n`,
71
71
  };
72
72
  }
@@ -85,8 +85,8 @@ function parseOptions(args, commandName, spec) {
85
85
  return {
86
86
  ok: false,
87
87
  error: `${localize(
88
- `nimicoding audit-sweep ${commandName} refused: missing required options: ${missing.join(", ")}.`,
89
- `nimicoding audit-sweep ${commandName} 已拒绝:缺少必填选项:${missing.join(", ")}。`,
88
+ `nimicoding sweep audit ${commandName} refused: missing required options: ${missing.join(", ")}.`,
89
+ `nimicoding sweep audit ${commandName} 已拒绝:缺少必填选项:${missing.join(", ")}。`,
90
90
  )}\n`,
91
91
  };
92
92
  }
@@ -269,8 +269,8 @@ function parseAuditSweepOptions(args) {
269
269
  return {
270
270
  ok: false,
271
271
  error: `${localize(
272
- "nimicoding audit-sweep refused: expected one of `plan`, `chunk dispatch`, `chunk audit-codex`, `chunk ingest`, `chunk review`, `chunk skip`, `ledger build`, `remediation-map build`, `remediation-map admit`, `finding resolve`, `closeout summary`, `status`, or `validate`.",
273
- "nimicoding audit-sweep 已拒绝:需要使用 `plan`、`chunk dispatch`、`chunk ingest`、`chunk review`、`chunk skip`、`ledger build`、`remediation-map build`、`remediation-map admit`、`finding resolve`、`closeout summary`、`status` 或 `validate`。",
272
+ "nimicoding sweep audit refused: expected one of `plan`, `chunk dispatch`, `chunk audit-codex`, `chunk ingest`, `chunk review`, `chunk skip`, `ledger build`, `remediation-map build`, `remediation-map admit`, `finding resolve`, `closeout summary`, `status`, or `validate`.",
273
+ "nimicoding sweep audit 已拒绝:需要使用 `plan`、`chunk dispatch`、`chunk ingest`、`chunk review`、`chunk skip`、`ledger build`、`remediation-map build`、`remediation-map admit`、`finding resolve`、`closeout summary`、`status` 或 `validate`。",
274
274
  )}\n`,
275
275
  };
276
276
  }
@@ -0,0 +1,5 @@
1
+ import { runSurfaceValidatorCommand } from "./surface-validator-command.mjs";
2
+
3
+ export function runClassifySpecTree(args) {
4
+ return runSurfaceValidatorCommand(args, "classify-spec-tree");
5
+ }
@@ -163,6 +163,9 @@ export async function runCloseout(args) {
163
163
  const payload = await buildCloseoutPayload(process.cwd(), effectiveOptions);
164
164
  if (payload.inputError) {
165
165
  process.stderr.write(payload.error);
166
+ if (parsed.options.json) {
167
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
168
+ }
166
169
  return payload.exitCode;
167
170
  }
168
171
 
@@ -1,6 +1,13 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
1
5
  import { localize } from "../lib/ui.mjs";
2
6
  import { loadGovernanceConfig, requireProfile } from "../lib/internal/governance/config.mjs";
3
7
  import { runCommand } from "../lib/internal/governance/runner.mjs";
8
+ import { parseSpecGenerationInputsConfig } from "../lib/internal/contracts-parse.mjs";
9
+
10
+ const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
4
11
 
5
12
  function parseOptions(args) {
6
13
  const options = {
@@ -100,6 +107,19 @@ export async function runGenerateSpecDerivedDocs(args) {
100
107
  return 2;
101
108
  }
102
109
 
110
+ const packageInputsText = await readFile(
111
+ path.join(PACKAGE_ROOT, "config", "spec-generation-inputs.yaml"),
112
+ "utf8",
113
+ );
114
+ const packageInputs = parseSpecGenerationInputsConfig(packageInputsText);
115
+ if (!packageInputs.ok || !packageInputs.generationOrder.includes("validate_placement")) {
116
+ process.stderr.write(localize(
117
+ "nimicoding generate-spec-derived-docs refused: package spec generation inputs must be class-filtered and include placement validation.\n",
118
+ "nimicoding generate-spec-derived-docs 已拒绝:package spec generation inputs 必须按 surface class 过滤并包含 placement validation。\n",
119
+ ));
120
+ return 2;
121
+ }
122
+
103
123
  let failed = false;
104
124
  for (const scope of scopeResolution.scopes) {
105
125
  const commands = governance.config.specGovernance.generateCommands[scope] || [];
@@ -0,0 +1,30 @@
1
+ import {
2
+ generateSpecMigrationPlan,
3
+ parseSurfaceValidatorOptions,
4
+ writeMigrationPlanIfRequested,
5
+ } from "../lib/internal/surface-taxonomy-validators.mjs";
6
+ import { localize } from "../lib/ui.mjs";
7
+
8
+ export async function runGenerateSpecMigrationPlan(args) {
9
+ const parsed = parseSurfaceValidatorOptions(args);
10
+ if (!parsed.ok) {
11
+ process.stderr.write(localize(
12
+ `nimicoding generate-spec-migration-plan refused: ${parsed.error}\n`,
13
+ `nimicoding generate-spec-migration-plan 已拒绝:${parsed.error}\n`,
14
+ ));
15
+ return 2;
16
+ }
17
+
18
+ try {
19
+ const report = await generateSpecMigrationPlan(process.cwd(), parsed.options);
20
+ await writeMigrationPlanIfRequested(report, parsed.options.emit, process.cwd());
21
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
22
+ return report.ok ? 0 : 1;
23
+ } catch (error) {
24
+ process.stderr.write(localize(
25
+ `nimicoding generate-spec-migration-plan refused: ${error.message}\n`,
26
+ `nimicoding generate-spec-migration-plan 已拒绝:${error.message}\n`,
27
+ ));
28
+ return 2;
29
+ }
30
+ }
@@ -343,8 +343,12 @@ function buildTaskStageLines(mode) {
343
343
  }
344
344
 
345
345
  function canonicalTreeReady(doctorResult) {
346
- return doctorResult.lifecycleState?.treeState === "canonical_tree_ready"
346
+ const v2Ready = doctorResult.specGenerationInputs?.mode === "class_filtered"
347
+ && doctorResult.canonicalTree?.requiredFilesValid === true
348
+ && doctorResult.specGenerationAudit?.ok === true;
349
+ const legacyReady = doctorResult.lifecycleState?.treeState === "canonical_tree_ready"
347
350
  && doctorResult.canonicalTree?.requiredFilesValid === true;
351
+ return v2Ready || legacyReady;
348
352
  }
349
353
 
350
354
  function determineWizardStage(doctorResult) {
@@ -0,0 +1,49 @@
1
+ import {
2
+ classifySpecSurface,
3
+ parseSurfaceValidatorOptions,
4
+ validateDomainAdmission,
5
+ validateGuidanceBodies,
6
+ validatePlacement,
7
+ validateProjectionEdges,
8
+ validateTableFamily,
9
+ validateTrackedOutputAdmission,
10
+ writeInventoryIfRequested,
11
+ } from "../lib/internal/surface-taxonomy-validators.mjs";
12
+ import { localize } from "../lib/ui.mjs";
13
+
14
+ const VALIDATORS = {
15
+ "classify-spec-tree": classifySpecSurface,
16
+ "validate-placement": validatePlacement,
17
+ "validate-table-family": validateTableFamily,
18
+ "validate-projection-edges": validateProjectionEdges,
19
+ "validate-guidance-bodies": validateGuidanceBodies,
20
+ "validate-domain-admission": validateDomainAdmission,
21
+ "validate-tracked-output-admission": validateTrackedOutputAdmission,
22
+ };
23
+
24
+ export async function runSurfaceValidatorCommand(args, validatorName) {
25
+ const parsed = parseSurfaceValidatorOptions(args);
26
+ if (!parsed.ok) {
27
+ process.stderr.write(localize(
28
+ `nimicoding ${validatorName} refused: ${parsed.error}\n`,
29
+ `nimicoding ${validatorName} 已拒绝:${parsed.error}\n`,
30
+ ));
31
+ return 2;
32
+ }
33
+
34
+ const validator = VALIDATORS[validatorName];
35
+ if (!validator) {
36
+ process.stderr.write(localize(
37
+ `nimicoding ${validatorName} refused: unknown surface validator.\n`,
38
+ `nimicoding ${validatorName} 已拒绝:未知 surface validator。\n`,
39
+ ));
40
+ return 2;
41
+ }
42
+
43
+ const report = await validator(process.cwd(), parsed.options);
44
+ if (validatorName === "classify-spec-tree") {
45
+ await writeInventoryIfRequested(report, parsed.options.emit, process.cwd());
46
+ }
47
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
48
+ return report.ok ? 0 : 1;
49
+ }
@@ -0,0 +1,295 @@
1
+ import {
2
+ runAuditorPrompt,
3
+ runFinalize,
4
+ runFixTopic,
5
+ runIntake,
6
+ runLedgerValidate,
7
+ runPacketBuild,
8
+ runPacketBuildBatch,
9
+ runResultIngest,
10
+ runWavePlan,
11
+ } from "../lib/sweep-design.mjs";
12
+ import { localize } from "../lib/ui.mjs";
13
+
14
+ function readRequiredValue(args, index, optionName, commandName) {
15
+ const next = args[index + 1];
16
+ if (!next || next.startsWith("--")) {
17
+ return {
18
+ ok: false,
19
+ error: `${localize(
20
+ `nimicoding sweep design ${commandName} refused: ${optionName} requires a value.`,
21
+ `nimicoding sweep design ${commandName} 已拒绝:${optionName} 需要一个值。`,
22
+ )}\n`,
23
+ };
24
+ }
25
+ return { ok: true, value: next };
26
+ }
27
+
28
+ function unknownOption(commandName, arg) {
29
+ return {
30
+ ok: false,
31
+ error: `${localize(
32
+ `nimicoding sweep design ${commandName} refused: unknown option ${arg}.`,
33
+ `nimicoding sweep design ${commandName} 已拒绝:未知选项 ${arg}。`,
34
+ )}\n`,
35
+ };
36
+ }
37
+
38
+ function parseOptions(args, commandName, spec) {
39
+ const options = Object.fromEntries(Object.entries(spec).map(([name, config]) => [name, config.default ?? null]));
40
+ for (let index = 0; index < args.length; index += 1) {
41
+ const arg = args[index];
42
+ if (arg === "--json") {
43
+ options.json = true;
44
+ continue;
45
+ }
46
+ const entry = Object.entries(spec).find(([, config]) => config.flag === arg);
47
+ if (!entry) {
48
+ return unknownOption(commandName, arg);
49
+ }
50
+ const [name] = entry;
51
+ if (entry[1].type === "boolean") {
52
+ options[name] = true;
53
+ continue;
54
+ }
55
+ const value = readRequiredValue(args, index, arg, commandName);
56
+ if (!value.ok) return value;
57
+ options[name] = value.value;
58
+ index += 1;
59
+ }
60
+ const missing = Object.entries(spec)
61
+ .filter(([, config]) => config.required)
62
+ .filter(([name]) => !options[name])
63
+ .map(([, config]) => config.flag);
64
+ if (missing.length > 0) {
65
+ return {
66
+ ok: false,
67
+ error: `${localize(
68
+ `nimicoding sweep design ${commandName} refused: missing required options: ${missing.join(", ")}.`,
69
+ `nimicoding sweep design ${commandName} 已拒绝:缺少必填选项:${missing.join(", ")}。`,
70
+ )}\n`,
71
+ };
72
+ }
73
+ return { ok: true, options };
74
+ }
75
+
76
+ function parseSweepDesignOptions(args) {
77
+ const [phase] = args;
78
+ if (phase === "intake") {
79
+ return {
80
+ ok: true,
81
+ action: "intake",
82
+ parsed: parseOptions(args.slice(1), "intake", {
83
+ sweepId: { flag: "--sweep-id", required: true },
84
+ runId: { flag: "--run-id" },
85
+ verifiedAt: { flag: "--verified-at" },
86
+ json: { default: false },
87
+ }),
88
+ };
89
+ }
90
+ if (phase === "packet-build") {
91
+ return {
92
+ ok: true,
93
+ action: "packet-build",
94
+ parsed: parseOptions(args.slice(1), "packet-build", {
95
+ runId: { flag: "--run-id", required: true },
96
+ packetId: { flag: "--packet-id", required: true },
97
+ findingId: { flag: "--finding-id" },
98
+ findingIds: { flag: "--finding-ids" },
99
+ explicitQuestion: { flag: "--explicit-question" },
100
+ explicitQuestions: { flag: "--explicit-questions" },
101
+ priorDesignStateRefs: { flag: "--prior-design-state-refs" },
102
+ priorDesignStateMarker: { flag: "--prior-design-state-marker" },
103
+ currentClusterRefs: { flag: "--current-cluster-refs" },
104
+ currentWaveRefs: { flag: "--current-wave-refs" },
105
+ authorityOnly: { flag: "--authority-only", type: "boolean", default: false },
106
+ verifiedAt: { flag: "--verified-at" },
107
+ json: { default: false },
108
+ }),
109
+ };
110
+ }
111
+ if (phase === "packet-build-batch") {
112
+ return {
113
+ ok: true,
114
+ action: "packet-build-batch",
115
+ parsed: parseOptions(args.slice(1), "packet-build-batch", {
116
+ runId: { flag: "--run-id", required: true },
117
+ batchSize: { flag: "--batch-size", required: true },
118
+ findingIds: { flag: "--finding-ids" },
119
+ packetPrefix: { flag: "--packet-prefix" },
120
+ manifestId: { flag: "--manifest-id" },
121
+ explicitQuestion: { flag: "--explicit-question" },
122
+ explicitQuestions: { flag: "--explicit-questions" },
123
+ priorDesignStateRefs: { flag: "--prior-design-state-refs" },
124
+ priorDesignStateMarker: { flag: "--prior-design-state-marker" },
125
+ currentClusterRefs: { flag: "--current-cluster-refs" },
126
+ currentWaveRefs: { flag: "--current-wave-refs" },
127
+ authorityOnly: { flag: "--authority-only", type: "boolean", default: false },
128
+ verifiedAt: { flag: "--verified-at" },
129
+ json: { default: false },
130
+ }),
131
+ };
132
+ }
133
+ if (phase === "result-ingest") {
134
+ return {
135
+ ok: true,
136
+ action: "result-ingest",
137
+ parsed: parseOptions(args.slice(1), "result-ingest", {
138
+ runId: { flag: "--run-id", required: true },
139
+ from: { flag: "--from", required: true },
140
+ mode: { flag: "--mode", default: "focused" },
141
+ allowSyntheticTrial: { flag: "--allow-synthetic-trial", type: "boolean", default: false },
142
+ verifiedAt: { flag: "--verified-at" },
143
+ json: { default: false },
144
+ }),
145
+ };
146
+ }
147
+ if (phase === "auditor-prompt") {
148
+ return {
149
+ ok: true,
150
+ action: "auditor-prompt",
151
+ parsed: parseOptions(args.slice(1), "auditor-prompt", {
152
+ runId: { flag: "--run-id", required: true },
153
+ packetId: { flag: "--packet-id", required: true },
154
+ verifiedAt: { flag: "--verified-at" },
155
+ json: { default: false },
156
+ }),
157
+ };
158
+ }
159
+ if (phase === "finalize") {
160
+ return {
161
+ ok: true,
162
+ action: "finalize",
163
+ parsed: parseOptions(args.slice(1), "finalize", {
164
+ runId: { flag: "--run-id", required: true },
165
+ allowSyntheticCloseout: { flag: "--allow-synthetic-closeout", type: "boolean", default: false },
166
+ verifiedAt: { flag: "--verified-at" },
167
+ json: { default: false },
168
+ }),
169
+ };
170
+ }
171
+ if (phase === "ledger-validate") {
172
+ return {
173
+ ok: true,
174
+ action: "ledger-validate",
175
+ parsed: parseOptions(args.slice(1), "ledger-validate", {
176
+ runId: { flag: "--run-id", required: true },
177
+ verifiedAt: { flag: "--verified-at" },
178
+ json: { default: false },
179
+ }),
180
+ };
181
+ }
182
+ if (phase === "wave-plan") {
183
+ return {
184
+ ok: true,
185
+ action: "wave-plan",
186
+ parsed: parseOptions(args.slice(1), "wave-plan", {
187
+ runId: { flag: "--run-id", required: true },
188
+ topicId: { flag: "--topic-id", required: true },
189
+ allowSyntheticTrial: { flag: "--allow-synthetic-trial", type: "boolean", default: false },
190
+ verifiedAt: { flag: "--verified-at" },
191
+ json: { default: false },
192
+ }),
193
+ };
194
+ }
195
+ if (phase === "fix-topic") {
196
+ return {
197
+ ok: true,
198
+ action: "fix-topic",
199
+ parsed: parseOptions(args.slice(1), "fix-topic", {
200
+ runId: { flag: "--run-id", required: true },
201
+ slug: { flag: "--slug" },
202
+ title: { flag: "--title" },
203
+ admitFirstWave: { flag: "--admit-first-wave", type: "boolean", default: false },
204
+ admitWaveId: { flag: "--admit-wave-id" },
205
+ verifiedAt: { flag: "--verified-at" },
206
+ json: { default: false },
207
+ }),
208
+ };
209
+ }
210
+ return {
211
+ ok: false,
212
+ error: `${localize(
213
+ "nimicoding sweep design refused: expected intake, packet-build, packet-build-batch, auditor-prompt, result-ingest, ledger-validate, finalize, wave-plan, or fix-topic.",
214
+ "nimicoding sweep design 已拒绝:需要 intake、packet-build、packet-build-batch、auditor-prompt、result-ingest、ledger-validate、finalize、wave-plan 或 fix-topic。",
215
+ )}\n`,
216
+ };
217
+ }
218
+
219
+ function emitResult(result, json) {
220
+ if (result.inputError) {
221
+ process.stderr.write(result.error);
222
+ return result.exitCode ?? 2;
223
+ }
224
+ if (!result.ok) {
225
+ process.stderr.write(result.error ?? "nimicoding sweep design failed.\n");
226
+ return result.exitCode ?? 1;
227
+ }
228
+ if (json) {
229
+ process.stdout.write(`${JSON.stringify({ command: "sweep.design", ...result }, null, 2)}\n`);
230
+ } else {
231
+ const lines = ["sweep design result"];
232
+ for (const [label, value] of [
233
+ ["run", result.runId],
234
+ ["inventory", result.inventoryRef],
235
+ ["ledger", result.ledgerRef],
236
+ ["packet", result.packetRef],
237
+ ["auditor prompt", result.promptRef],
238
+ ["auditor result", result.resultRef],
239
+ ["decision queue", result.decisionQueueRef],
240
+ ["final state report", result.finalStateReportRef],
241
+ ["wave plan", result.wavePlanRef],
242
+ ["topic", result.topicRef],
243
+ ["sweep fix source", result.sourceRef],
244
+ ["wave catalog", result.waveCatalogRef],
245
+ ]) {
246
+ if (value !== undefined && value !== null) {
247
+ lines.push(`${label}: ${value}`);
248
+ }
249
+ }
250
+ for (const [label, value] of [
251
+ ["findings", result.findingCount],
252
+ ["finding outcomes", result.findingOutcomeCount],
253
+ ["revision entries", result.revisionEntryCount],
254
+ ["total findings", result.totalFindingCount],
255
+ ["final findings", result.finalFindingCount],
256
+ ["transient findings", result.transientFindingCount],
257
+ ["waves", result.waveCount],
258
+ ["admitted wave", result.admittedWaveId],
259
+ ["stop class", result.stopClass],
260
+ ["stop reason", result.stopReason],
261
+ ]) {
262
+ if (value !== undefined && value !== null) {
263
+ lines.push(`${label}: ${value}`);
264
+ }
265
+ }
266
+ process.stdout.write(`${lines.join("\n")}\n`);
267
+ }
268
+ return result.exitCode ?? 0;
269
+ }
270
+
271
+ export async function runSweepDesign(args) {
272
+ const parsedAction = parseSweepDesignOptions(args);
273
+ if (!parsedAction.ok) {
274
+ process.stderr.write(parsedAction.error);
275
+ return 2;
276
+ }
277
+ if (!parsedAction.parsed.ok) {
278
+ process.stderr.write(parsedAction.parsed.error);
279
+ return 2;
280
+ }
281
+ const options = parsedAction.parsed.options;
282
+ const projectRoot = process.cwd();
283
+ const actions = {
284
+ intake: runIntake,
285
+ "packet-build": runPacketBuild,
286
+ "packet-build-batch": runPacketBuildBatch,
287
+ "auditor-prompt": runAuditorPrompt,
288
+ "result-ingest": runResultIngest,
289
+ "ledger-validate": runLedgerValidate,
290
+ finalize: runFinalize,
291
+ "wave-plan": runWavePlan,
292
+ "fix-topic": runFixTopic,
293
+ };
294
+ return emitResult(await actions[parsedAction.action](projectRoot, options), options.json);
295
+ }
@@ -0,0 +1,22 @@
1
+ import { runAuditSweep } from "./audit-sweep.mjs";
2
+ import { runSweepDesign } from "./sweep-design.mjs";
3
+ import { localize } from "../lib/ui.mjs";
4
+
5
+ export async function runSweep(args) {
6
+ const [command] = args;
7
+ const rest = args.slice(1);
8
+
9
+ if (command === "audit") {
10
+ return runAuditSweep(rest);
11
+ }
12
+
13
+ if (command === "design") {
14
+ return runSweepDesign(rest);
15
+ }
16
+
17
+ process.stderr.write(localize(
18
+ "nimicoding sweep refused: expected `audit` or `design`.\n",
19
+ "nimicoding sweep 已拒绝:需要使用 `audit` 或 `design`。\n",
20
+ ));
21
+ return 2;
22
+ }