@neurcode-ai/cli 0.9.60 → 0.9.62

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 (71) hide show
  1. package/LICENSE +201 -0
  2. package/dist/commands/control-plane.d.ts +3 -0
  3. package/dist/commands/control-plane.d.ts.map +1 -0
  4. package/dist/commands/control-plane.js +163 -0
  5. package/dist/commands/control-plane.js.map +1 -0
  6. package/dist/commands/export.d.ts +7 -0
  7. package/dist/commands/export.d.ts.map +1 -0
  8. package/dist/commands/export.js +72 -0
  9. package/dist/commands/export.js.map +1 -0
  10. package/dist/commands/fix.d.ts +1 -0
  11. package/dist/commands/fix.d.ts.map +1 -1
  12. package/dist/commands/fix.js +3 -0
  13. package/dist/commands/fix.js.map +1 -1
  14. package/dist/commands/generate.d.ts +1 -0
  15. package/dist/commands/generate.d.ts.map +1 -1
  16. package/dist/commands/generate.js +63 -48
  17. package/dist/commands/generate.js.map +1 -1
  18. package/dist/commands/patch-apply.d.ts.map +1 -1
  19. package/dist/commands/patch-apply.js +1 -0
  20. package/dist/commands/patch-apply.js.map +1 -1
  21. package/dist/commands/replay.d.ts +3 -0
  22. package/dist/commands/replay.d.ts.map +1 -0
  23. package/dist/commands/replay.js +267 -0
  24. package/dist/commands/replay.js.map +1 -0
  25. package/dist/commands/verify.d.ts +7 -1
  26. package/dist/commands/verify.d.ts.map +1 -1
  27. package/dist/commands/verify.js +281 -149
  28. package/dist/commands/verify.js.map +1 -1
  29. package/dist/commands/workspace.d.ts +3 -0
  30. package/dist/commands/workspace.d.ts.map +1 -0
  31. package/dist/commands/workspace.js +407 -0
  32. package/dist/commands/workspace.js.map +1 -0
  33. package/dist/daemon/server.d.ts +0 -17
  34. package/dist/daemon/server.d.ts.map +1 -1
  35. package/dist/daemon/server.js +1043 -58
  36. package/dist/daemon/server.js.map +1 -1
  37. package/dist/index.js +296 -12
  38. package/dist/index.js.map +1 -1
  39. package/dist/utils/cli-json.d.ts +1 -0
  40. package/dist/utils/cli-json.d.ts.map +1 -1
  41. package/dist/utils/cli-json.js +1 -0
  42. package/dist/utils/cli-json.js.map +1 -1
  43. package/dist/utils/control-plane.d.ts +171 -0
  44. package/dist/utils/control-plane.d.ts.map +1 -0
  45. package/dist/utils/control-plane.js +684 -0
  46. package/dist/utils/control-plane.js.map +1 -0
  47. package/dist/utils/execution-bus.d.ts +205 -0
  48. package/dist/utils/execution-bus.d.ts.map +1 -0
  49. package/dist/utils/execution-bus.js +1346 -0
  50. package/dist/utils/execution-bus.js.map +1 -0
  51. package/dist/utils/gitignore.d.ts +2 -2
  52. package/dist/utils/gitignore.d.ts.map +1 -1
  53. package/dist/utils/gitignore.js +27 -14
  54. package/dist/utils/gitignore.js.map +1 -1
  55. package/dist/utils/replay-runtime.d.ts +295 -0
  56. package/dist/utils/replay-runtime.d.ts.map +1 -0
  57. package/dist/utils/replay-runtime.js +1080 -0
  58. package/dist/utils/replay-runtime.js.map +1 -0
  59. package/dist/utils/runtime-events.d.ts +44 -0
  60. package/dist/utils/runtime-events.d.ts.map +1 -0
  61. package/dist/utils/runtime-events.js +213 -0
  62. package/dist/utils/runtime-events.js.map +1 -0
  63. package/dist/utils/verification-evidence.d.ts +22 -0
  64. package/dist/utils/verification-evidence.d.ts.map +1 -0
  65. package/dist/utils/verification-evidence.js +233 -0
  66. package/dist/utils/verification-evidence.js.map +1 -0
  67. package/dist/utils/workspace-runtime.d.ts +267 -0
  68. package/dist/utils/workspace-runtime.d.ts.map +1 -0
  69. package/dist/utils/workspace-runtime.js +1415 -0
  70. package/dist/utils/workspace-runtime.js.map +1 -0
  71. package/package.json +7 -8
@@ -71,6 +71,7 @@ const runtime_guard_1 = require("../utils/runtime-guard");
71
71
  const artifact_signature_1 = require("../utils/artifact-signature");
72
72
  const policy_1 = require("@neurcode-ai/policy");
73
73
  const ai_debt_budget_1 = require("../utils/ai-debt-budget");
74
+ const verification_evidence_1 = require("../utils/verification-evidence");
74
75
  // Import chalk with fallback
75
76
  let chalk;
76
77
  try {
@@ -1023,7 +1024,7 @@ function toCanonicalVerifyOutput(payload) {
1023
1024
  blockingItems = dedupeTriageItems([...regressionBlockingTriageItems, ...blockingItems]);
1024
1025
  }
1025
1026
  const grade = verdict === 'PASS' ? 'A' : verdict === 'WARN' ? 'C' : 'F';
1026
- return {
1027
+ const canonical = {
1027
1028
  grade,
1028
1029
  score: violations.length === 0 && warnings.length === 0 && scopeIssues.length === 0 ? 100 : 0,
1029
1030
  verdict,
@@ -1052,9 +1053,55 @@ function toCanonicalVerifyOutput(payload) {
1052
1053
  ...(expediteModeUsed ? { expediteNote: 'Expedite Mode used' } : {}),
1053
1054
  ...(typeof driftScore === 'number' ? { driftScore } : {}),
1054
1055
  };
1056
+ // Preserve actionable metadata from rich verify payloads so downstream
1057
+ // consumers (Action, CI contracts, dashboards) keep structured context.
1058
+ const passthroughKeys = [
1059
+ 'message',
1060
+ 'mode',
1061
+ 'ciMode',
1062
+ 'policyOnly',
1063
+ 'policyOnlySource',
1064
+ 'policySources',
1065
+ 'scopeGuardPassed',
1066
+ 'policyLock',
1067
+ 'policyCompilation',
1068
+ 'policyExceptions',
1069
+ 'policyGovernance',
1070
+ 'changeContract',
1071
+ 'runtimeGuard',
1072
+ 'governanceDecision',
1073
+ 'orgGovernance',
1074
+ 'aiChangeLog',
1075
+ 'verificationSource',
1076
+ 'tier',
1077
+ 'aiDebt',
1078
+ 'blastRadius',
1079
+ 'suspiciousChange',
1080
+ 'policyDecision',
1081
+ 'policyPack',
1082
+ 'changeContractViolations',
1083
+ ];
1084
+ for (const key of passthroughKeys) {
1085
+ if (Object.prototype.hasOwnProperty.call(payload, key) && payload[key] !== undefined) {
1086
+ canonical[key] = payload[key];
1087
+ }
1088
+ }
1089
+ // Backward-compatibility alias: older integrations and tests expect `rule`
1090
+ // while canonical contract uses `policy`.
1091
+ canonical.violations = canonical.violations.map((item) => ({
1092
+ ...item,
1093
+ rule: item.policy,
1094
+ }));
1095
+ canonical.warnings = canonical.warnings.map((item) => ({
1096
+ ...item,
1097
+ rule: item.policy,
1098
+ }));
1099
+ return canonical;
1055
1100
  }
1056
- function emitCanonicalVerifyJson(payload) {
1057
- console.log(JSON.stringify(toCanonicalVerifyOutput(payload), null, 2));
1101
+ function emitCanonicalVerifyJson(payload, onEmit) {
1102
+ const canonical = toCanonicalVerifyOutput(payload);
1103
+ onEmit?.(canonical);
1104
+ console.log(JSON.stringify(canonical, null, 2));
1058
1105
  }
1059
1106
  function buildDeterministicLayerSummary(payload) {
1060
1107
  const verdict = asStringValue(payload.verdict) || 'UNKNOWN';
@@ -1415,12 +1462,13 @@ async function recordVerificationIfRequested(options, config, payload) {
1415
1462
  * Execute policy-only verification (General Governance mode)
1416
1463
  * Returns the exit code to use
1417
1464
  */
1418
- async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRoot, config, client, source, scopeTelemetry, projectId, orgGovernanceSettings, aiLogSigningKey, aiLogSigningKeyId, aiLogSigningKeys, aiLogSigner, expediteModeEnabled, compiledPolicyArtifact, compiledPolicyMetadata, changeContractSummary) {
1465
+ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRoot, config, client, source, ciModeEnabled, scopeTelemetry, projectId, orgGovernanceSettings, aiLogSigningKey, aiLogSigningKeyId, aiLogSigningKeys, aiLogSigner, expediteModeEnabled, compiledPolicyArtifact, compiledPolicyMetadata, changeContractSummary, onCanonicalEmit) {
1419
1466
  const emitPolicyOnlyJson = (payload) => {
1420
1467
  emitCanonicalVerifyJson({
1421
1468
  ...payload,
1469
+ ciMode: payload.ciMode ?? ciModeEnabled,
1422
1470
  expediteMode: expediteModeEnabled,
1423
- });
1471
+ }, onCanonicalEmit);
1424
1472
  };
1425
1473
  const policyOnlyVerificationSource = 'policy_only';
1426
1474
  const recordPolicyOnlyVerification = async (payload) => recordVerificationIfRequested(options, config, {
@@ -1902,44 +1950,50 @@ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRo
1902
1950
  eventCount: auditIntegrity.count,
1903
1951
  },
1904
1952
  };
1953
+ const policyOnlyPayload = {
1954
+ grade,
1955
+ score,
1956
+ verdict: effectiveVerdict,
1957
+ violations: violationsOutput,
1958
+ message,
1959
+ scopeGuardPassed: true, // N/A in policy-only mode
1960
+ bloatCount: 0,
1961
+ bloatFiles: [],
1962
+ plannedFilesModified: 0,
1963
+ totalPlannedFiles: 0,
1964
+ adherenceScore: score,
1965
+ mode: 'policy_only',
1966
+ policyOnly: true,
1967
+ policyOnlySource: source,
1968
+ ...governancePayload,
1969
+ policyLock: {
1970
+ enforced: policyLockEvaluation.enforced,
1971
+ matched: policyLockEvaluation.matched,
1972
+ path: policyLockEvaluation.lockPath,
1973
+ mismatches: policyLockEvaluation.mismatches,
1974
+ },
1975
+ policyExceptions: policyExceptionsSummary,
1976
+ policyGovernance: policyGovernanceSummary,
1977
+ ...(effectiveRules.policyPack
1978
+ ? {
1979
+ policyPack: {
1980
+ id: effectiveRules.policyPack.packId,
1981
+ name: effectiveRules.policyPack.packName,
1982
+ version: effectiveRules.policyPack.version,
1983
+ ruleCount: effectiveRules.policyPackRules.length,
1984
+ },
1985
+ }
1986
+ : {}),
1987
+ };
1905
1988
  if (options.json) {
1906
- emitPolicyOnlyJson({
1907
- grade,
1908
- score,
1909
- verdict: effectiveVerdict,
1910
- violations: violationsOutput,
1911
- message,
1912
- scopeGuardPassed: true, // N/A in policy-only mode
1913
- bloatCount: 0,
1914
- bloatFiles: [],
1915
- plannedFilesModified: 0,
1916
- totalPlannedFiles: 0,
1917
- adherenceScore: score,
1918
- mode: 'policy_only',
1919
- policyOnly: true,
1920
- policyOnlySource: source,
1921
- ...governancePayload,
1922
- policyLock: {
1923
- enforced: policyLockEvaluation.enforced,
1924
- matched: policyLockEvaluation.matched,
1925
- path: policyLockEvaluation.lockPath,
1926
- mismatches: policyLockEvaluation.mismatches,
1927
- },
1928
- policyExceptions: policyExceptionsSummary,
1929
- policyGovernance: policyGovernanceSummary,
1930
- ...(effectiveRules.policyPack
1931
- ? {
1932
- policyPack: {
1933
- id: effectiveRules.policyPack.packId,
1934
- name: effectiveRules.policyPack.packName,
1935
- version: effectiveRules.policyPack.version,
1936
- ruleCount: effectiveRules.policyPackRules.length,
1937
- },
1938
- }
1939
- : {}),
1940
- });
1989
+ emitPolicyOnlyJson(policyOnlyPayload);
1941
1990
  }
1942
1991
  else {
1992
+ onCanonicalEmit?.(toCanonicalVerifyOutput({
1993
+ ...policyOnlyPayload,
1994
+ ciMode: ciModeEnabled,
1995
+ expediteMode: expediteModeEnabled,
1996
+ }));
1943
1997
  if (effectiveVerdict === 'PASS') {
1944
1998
  console.log(chalk.green('✅ Policy check passed'));
1945
1999
  }
@@ -1979,6 +2033,7 @@ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRo
1979
2033
  return effectiveVerdict === 'FAIL' ? 2 : effectiveVerdict === 'WARN' ? 1 : 0;
1980
2034
  }
1981
2035
  async function verifyCommand(options) {
2036
+ let exitWithEvidenceFromTry = null;
1982
2037
  try {
1983
2038
  const rootResolution = (0, project_root_1.resolveNeurcodeProjectRootWithTrace)(process.cwd());
1984
2039
  const projectRoot = rootResolution.projectRoot;
@@ -1986,9 +2041,77 @@ async function verifyCommand(options) {
1986
2041
  const localPlanExpectedFiles = [...localPlanSync.expectedFiles];
1987
2042
  const expediteModeEnabled = resolveVerifyExpediteMode(projectRoot);
1988
2043
  const scopeTelemetry = (0, scope_telemetry_1.buildScopeTelemetryPayload)(rootResolution);
2044
+ const ciModeEnabled = options.ci === true || isEnabledFlag(process.env.NEURCODE_VERIFY_CI);
2045
+ const evidenceEnabled = options.evidence === true || isEnabledFlag(process.env.NEURCODE_VERIFY_EVIDENCE);
2046
+ const verifyStartedAtMs = Date.now();
2047
+ const evidenceCiContext = collectCIContext();
2048
+ let lastCanonicalOutput = null;
2049
+ let lastEvidenceFallbackOutput = null;
2050
+ let evidenceFinalizeAttempted = false;
2051
+ if (ciModeEnabled) {
2052
+ options.policyOnly = true;
2053
+ options.requirePlan = false;
2054
+ options.record = false;
2055
+ options.asyncMode = false;
2056
+ }
2057
+ const captureEvidencePayload = (payload) => {
2058
+ lastEvidenceFallbackOutput = payload;
2059
+ lastCanonicalOutput = toCanonicalVerifyOutput(payload);
2060
+ };
2061
+ const finalizeEvidence = (exitCode) => {
2062
+ if (!evidenceEnabled || evidenceFinalizeAttempted) {
2063
+ return;
2064
+ }
2065
+ evidenceFinalizeAttempted = true;
2066
+ try {
2067
+ const artifactPath = (0, verification_evidence_1.writeVerificationEvidence)({
2068
+ enabled: evidenceEnabled,
2069
+ projectRoot,
2070
+ startedAtMs: verifyStartedAtMs,
2071
+ exitCode,
2072
+ ciMode: ciModeEnabled,
2073
+ deterministicMode: ciModeEnabled || options.policyOnly === true,
2074
+ evidenceDir: options.evidenceDir,
2075
+ canonicalOutput: lastCanonicalOutput,
2076
+ fallbackOutput: lastEvidenceFallbackOutput,
2077
+ ciContext: evidenceCiContext,
2078
+ runtimeMetadata: {
2079
+ cliJsonContractVersion: contracts_1.CLI_JSON_CONTRACT_VERSION,
2080
+ runtimeCompatibilityContractVersion: contracts_1.RUNTIME_COMPATIBILITY_CONTRACT_VERSION,
2081
+ componentVersion: CLI_COMPONENT_VERSION,
2082
+ nodeVersion: process.version,
2083
+ platform: process.platform,
2084
+ arch: process.arch,
2085
+ command: 'verify',
2086
+ },
2087
+ });
2088
+ if (artifactPath && !options.json) {
2089
+ console.log(chalk.dim(`\n Verification evidence: ${artifactPath}`));
2090
+ }
2091
+ }
2092
+ catch (error) {
2093
+ if (!options.json) {
2094
+ const message = error instanceof Error ? error.message : String(error);
2095
+ console.log(chalk.yellow(`\n⚠️ Failed to write verification evidence artifact: ${message}`));
2096
+ }
2097
+ }
2098
+ };
2099
+ const exitWithEvidence = (exitCode) => {
2100
+ finalizeEvidence(exitCode);
2101
+ process.exit(exitCode);
2102
+ };
2103
+ exitWithEvidenceFromTry = exitWithEvidence;
2104
+ // Hoisted so emitVerifyJson (called on every early-exit path) can reference
2105
+ // these via closure without hitting the temporal dead zone.
2106
+ let intentEngineIssues = [];
2107
+ let intentEngineDomains = [];
2108
+ let intentEngineSummary = null;
2109
+ let intentEngineFlowIssues = [];
2110
+ let intentEngineRegressions = [];
1989
2111
  const emitVerifyJson = (payload) => {
1990
- emitCanonicalVerifyJson({
2112
+ const enrichedPayload = {
1991
2113
  ...payload,
2114
+ ciMode: payload.ciMode ?? ciModeEnabled,
1992
2115
  expediteMode: expediteModeEnabled,
1993
2116
  // Intent engine results injected so every code-path gets them.
1994
2117
  intentIssues: payload.intentIssues ?? intentEngineIssues,
@@ -1998,6 +2121,10 @@ async function verifyCommand(options) {
1998
2121
  flowIssues: payload.flowIssues ?? intentEngineFlowIssues,
1999
2122
  // V6: regressions always injected
2000
2123
  regressions: payload.regressions ?? intentEngineRegressions,
2124
+ };
2125
+ lastEvidenceFallbackOutput = enrichedPayload;
2126
+ emitCanonicalVerifyJson(enrichedPayload, (canonical) => {
2127
+ lastCanonicalOutput = canonical;
2001
2128
  });
2002
2129
  };
2003
2130
  if (!isGitRepository(projectRoot)) {
@@ -2032,7 +2159,7 @@ async function verifyCommand(options) {
2032
2159
  console.log(chalk.dim(` Current path: ${projectRoot}`));
2033
2160
  console.log(chalk.dim(' Next step: git init && git add . && git commit -m "chore: baseline"\n'));
2034
2161
  }
2035
- process.exit(1);
2162
+ exitWithEvidence(1);
2036
2163
  }
2037
2164
  const enforceChangeContract = options.enforceChangeContract === true ||
2038
2165
  isEnabledFlag(process.env.NEURCODE_VERIFY_ENFORCE_CHANGE_CONTRACT);
@@ -2183,7 +2310,7 @@ async function verifyCommand(options) {
2183
2310
  });
2184
2311
  console.log(chalk.dim('\nRegenerate artifacts with valid signing keys: NEURCODE_GOVERNANCE_SIGNING_KEY or NEURCODE_GOVERNANCE_SIGNING_KEYS.\n'));
2185
2312
  }
2186
- process.exit(2);
2313
+ exitWithEvidence(2);
2187
2314
  }
2188
2315
  // Advisory notice when artifact has a signature but signing is not required in this context.
2189
2316
  if (!options.json) {
@@ -2236,7 +2363,7 @@ async function verifyCommand(options) {
2236
2363
  signatureErrors.forEach((entry) => console.log(chalk.red(` • ${entry}`)));
2237
2364
  console.log(chalk.dim('\nEnable signing keys via NEURCODE_GOVERNANCE_SIGNING_KEY or NEURCODE_GOVERNANCE_SIGNING_KEYS and regenerate artifacts.\n'));
2238
2365
  }
2239
- process.exit(2);
2366
+ exitWithEvidence(2);
2240
2367
  }
2241
2368
  }
2242
2369
  if (!options.json) {
@@ -2304,6 +2431,14 @@ async function verifyCommand(options) {
2304
2431
  // Ensure no trailing slash
2305
2432
  config.apiUrl = config.apiUrl.replace(/\/$/, '');
2306
2433
  }
2434
+ if (ciModeEnabled) {
2435
+ // CI mode enforces deterministic local verification and must not depend on
2436
+ // runtime compatibility handshakes or org-level remote settings.
2437
+ config.apiKey = undefined;
2438
+ if (!options.json) {
2439
+ console.log(chalk.dim(' CI mode: deterministic local verification enabled (policy-only, non-interactive).'));
2440
+ }
2441
+ }
2307
2442
  const enforceCompatibilityHandshake = isEnabledFlag(process.env.NEURCODE_VERIFY_ENFORCE_COMPAT_HANDSHAKE)
2308
2443
  || strictArtifactMode
2309
2444
  || (process.env.CI === 'true' && Boolean(config.apiKey));
@@ -2351,7 +2486,7 @@ async function verifyCommand(options) {
2351
2486
  console.log(chalk.dim(` CLI version: ${CLI_COMPONENT_VERSION}`));
2352
2487
  console.log(chalk.dim(' Upgrade/downgrade CLI, Action, or API to satisfy the runtime compatibility contract before running verify.\n'));
2353
2488
  }
2354
- process.exit(2);
2489
+ exitWithEvidence(2);
2355
2490
  }
2356
2491
  if (compatibilityProbe.status === 'error' && !options.json) {
2357
2492
  console.log(chalk.yellow('\n⚠️ Runtime compatibility mismatch detected (advisory mode).'));
@@ -2490,7 +2625,7 @@ async function verifyCommand(options) {
2490
2625
  projectId: projectId || undefined,
2491
2626
  jsonMode: Boolean(options.json),
2492
2627
  });
2493
- process.exit(2);
2628
+ exitWithEvidence(2);
2494
2629
  }
2495
2630
  // Determine which diff to capture.
2496
2631
  let diffText;
@@ -2547,7 +2682,7 @@ async function verifyCommand(options) {
2547
2682
  });
2548
2683
  }
2549
2684
  recordVerifyEvent('NO_CHANGES', 'diff=empty');
2550
- process.exit(0);
2685
+ exitWithEvidence(0);
2551
2686
  }
2552
2687
  // Parse tracked/staged diff and merge untracked files so plan adherence
2553
2688
  // correctly counts newly created files before they are git-added.
@@ -2591,7 +2726,7 @@ async function verifyCommand(options) {
2591
2726
  });
2592
2727
  }
2593
2728
  recordVerifyEvent('NO_CHANGES', 'diff_files=0');
2594
- process.exit(0);
2729
+ exitWithEvidence(0);
2595
2730
  }
2596
2731
  const ignoreFilter = (0, ignore_1.loadIgnore)(projectRoot);
2597
2732
  const runtimeIgnoreSet = getRuntimeIgnoreSetFromEnv();
@@ -2661,12 +2796,13 @@ async function verifyCommand(options) {
2661
2796
  projectId: projectId || undefined,
2662
2797
  jsonMode: Boolean(options.json),
2663
2798
  });
2664
- process.exit(2);
2799
+ return exitWithEvidence(2);
2665
2800
  }
2666
- const runtimeGuardEvaluation = (0, runtime_guard_1.evaluateRuntimeGuardArtifact)(guardRead.artifact, diffFiles.filter((file) => !shouldIgnore(file.path)));
2801
+ const runtimeGuardArtifact = guardRead.artifact;
2802
+ const runtimeGuardEvaluation = (0, runtime_guard_1.evaluateRuntimeGuardArtifact)(runtimeGuardArtifact, diffFiles.filter((file) => !shouldIgnore(file.path)));
2667
2803
  runtimeGuardSummary = {
2668
2804
  ...runtimeGuardSummary,
2669
- active: guardRead.artifact.active,
2805
+ active: runtimeGuardArtifact.active,
2670
2806
  pass: runtimeGuardEvaluation.pass,
2671
2807
  changedFiles: runtimeGuardEvaluation.changedFiles.length,
2672
2808
  outOfScopeFiles: runtimeGuardEvaluation.outOfScopeFiles,
@@ -2677,7 +2813,7 @@ async function verifyCommand(options) {
2677
2813
  ...(item.file ? { file: item.file } : {}),
2678
2814
  })),
2679
2815
  };
2680
- const runtimeGuardUpdated = (0, runtime_guard_1.withRuntimeGuardCheckStats)(guardRead.artifact, {
2816
+ const runtimeGuardUpdated = (0, runtime_guard_1.withRuntimeGuardCheckStats)(runtimeGuardArtifact, {
2681
2817
  blocked: !runtimeGuardEvaluation.pass,
2682
2818
  });
2683
2819
  (0, runtime_guard_1.writeRuntimeGuardArtifact)(projectRoot, runtimeGuardUpdated, options.runtimeGuard);
@@ -2726,7 +2862,7 @@ async function verifyCommand(options) {
2726
2862
  projectId: projectId || undefined,
2727
2863
  jsonMode: Boolean(options.json),
2728
2864
  });
2729
- process.exit(2);
2865
+ exitWithEvidence(2);
2730
2866
  }
2731
2867
  if (!options.json) {
2732
2868
  console.log(chalk.dim(` Runtime guard passed (${runtimeGuardSummary.changedFiles} changed file(s), ` +
@@ -2805,7 +2941,7 @@ async function verifyCommand(options) {
2805
2941
  jsonMode: Boolean(options.json),
2806
2942
  governance: baselineGovernancePayload,
2807
2943
  });
2808
- process.exit(2);
2944
+ exitWithEvidence(2);
2809
2945
  }
2810
2946
  if (!options.json) {
2811
2947
  console.log(chalk.cyan('\n📊 Analyzing change set...'));
@@ -2816,17 +2952,19 @@ async function verifyCommand(options) {
2816
2952
  }
2817
2953
  }
2818
2954
  const runPolicyOnlyModeAndExit = async (source) => {
2819
- const exitCode = await executePolicyOnlyMode(options, diffFiles, shouldIgnore, projectRoot, config, client, source, scopeTelemetry, projectId || undefined, orgGovernanceSettings, aiLogSigningKey, aiLogSigningKeyId, aiLogSigningKeys, aiLogSigner, expediteModeEnabled, compiledPolicyRead.artifact, compiledPolicyMetadata, changeContractSummary);
2955
+ const exitCode = await executePolicyOnlyMode(options, diffFiles, shouldIgnore, projectRoot, config, client, source, ciModeEnabled, scopeTelemetry, projectId || undefined, orgGovernanceSettings, aiLogSigningKey, aiLogSigningKeyId, aiLogSigningKeys, aiLogSigner, expediteModeEnabled, compiledPolicyRead.artifact, compiledPolicyMetadata, changeContractSummary, (canonical) => {
2956
+ lastCanonicalOutput = canonical;
2957
+ });
2820
2958
  const changedFiles = diffFiles.map((f) => f.path);
2821
2959
  const verdict = exitCode === 2 ? 'FAIL' : exitCode === 1 ? 'WARN' : 'PASS';
2822
2960
  recordVerifyEvent(verdict, `policy_only_source=${source};exit=${exitCode}`, changedFiles);
2823
- process.exit(exitCode);
2961
+ exitWithEvidence(exitCode);
2824
2962
  };
2825
2963
  // ============================================
2826
2964
  // --policy-only: General Governance (policy only, no plan enforcement)
2827
2965
  // ============================================
2828
2966
  if (options.policyOnly) {
2829
- await runPolicyOnlyModeAndExit('explicit');
2967
+ await runPolicyOnlyModeAndExit(ciModeEnabled ? 'ci' : 'explicit');
2830
2968
  }
2831
2969
  const requirePlan = options.requirePlan === true
2832
2970
  || process.env.NEURCODE_VERIFY_REQUIRE_PLAN === '1'
@@ -2918,7 +3056,7 @@ async function verifyCommand(options) {
2918
3056
  projectId: projectId || undefined,
2919
3057
  jsonMode: Boolean(options.json),
2920
3058
  });
2921
- process.exit(1);
3059
+ exitWithEvidence(1);
2922
3060
  }
2923
3061
  let autoContractPath = null;
2924
3062
  if (!changeContractRead.contract && !strictArtifactMode) {
@@ -3017,7 +3155,7 @@ async function verifyCommand(options) {
3017
3155
  console.log(chalk.dim(' neurcode contract import --auto-detect --write-change-contract'));
3018
3156
  console.log(chalk.dim(`\nSummary: ${message}\n`));
3019
3157
  }
3020
- process.exit(0);
3158
+ exitWithEvidence(0);
3021
3159
  }
3022
3160
  if (!planId) {
3023
3161
  throw new Error('Plan ID resolution failed unexpectedly');
@@ -3035,11 +3173,6 @@ async function verifyCommand(options) {
3035
3173
  let governanceResult = null;
3036
3174
  let planFilesForVerification = [];
3037
3175
  let intentConstraintsForVerification;
3038
- let intentEngineIssues = [];
3039
- let intentEngineDomains = [];
3040
- let intentEngineSummary = null;
3041
- let intentEngineFlowIssues = [];
3042
- let intentEngineRegressions = [];
3043
3176
  try {
3044
3177
  // Step A: Get Modified Files (already have from diffFiles)
3045
3178
  const modifiedFiles = diffFiles.map(f => f.path);
@@ -3237,7 +3370,7 @@ async function verifyCommand(options) {
3237
3370
  })
3238
3371
  : undefined,
3239
3372
  });
3240
- process.exit(1);
3373
+ exitWithEvidence(1);
3241
3374
  }
3242
3375
  else if (shouldBlockForScope) {
3243
3376
  // Human-readable output only when NOT in json mode
@@ -3338,7 +3471,7 @@ async function verifyCommand(options) {
3338
3471
  })
3339
3472
  : undefined,
3340
3473
  });
3341
- process.exit(1);
3474
+ exitWithEvidence(1);
3342
3475
  }
3343
3476
  else {
3344
3477
  scopeGuardExpediteBypass = true;
@@ -3504,7 +3637,7 @@ async function verifyCommand(options) {
3504
3637
  })
3505
3638
  : undefined,
3506
3639
  });
3507
- process.exit(2);
3640
+ exitWithEvidence(2);
3508
3641
  }
3509
3642
  }
3510
3643
  let effectiveCompiledPolicy = compiledPolicyRead.artifact;
@@ -3596,7 +3729,7 @@ async function verifyCommand(options) {
3596
3729
  },
3597
3730
  });
3598
3731
  }
3599
- process.exit(0);
3732
+ exitWithEvidence(0);
3600
3733
  }
3601
3734
  let policyViolations = [];
3602
3735
  let policyDecision = 'allow';
@@ -3891,7 +4024,7 @@ async function verifyCommand(options) {
3891
4024
  })
3892
4025
  : undefined,
3893
4026
  });
3894
- process.exit(2);
4027
+ exitWithEvidence(2);
3895
4028
  }
3896
4029
  else if (!changeContractEvaluation.valid && !options.json) {
3897
4030
  displayChangeContractDrift(changeContractSummary, { advisory: true });
@@ -4060,72 +4193,74 @@ async function verifyCommand(options) {
4060
4193
  ((verifyResult.verdict === 'FAIL' || verifyResult.verdict === 'WARN') &&
4061
4194
  policyViolations.length === 0 &&
4062
4195
  verifyResult.bloatCount > 0));
4196
+ const filteredBloatFiles = (verifyResult.bloatFiles || []).filter((f) => !shouldIgnore(f));
4197
+ const scopeViolations = filteredBloatFiles.map((file) => ({
4198
+ file,
4199
+ rule: 'scope_guard',
4200
+ severity: 'block',
4201
+ message: 'File modified outside the plan',
4202
+ }));
4203
+ const policyViolationItems = policyViolations.map((v) => ({
4204
+ file: v.file,
4205
+ rule: v.rule,
4206
+ severity: v.severity,
4207
+ message: v.message,
4208
+ ...(v.line != null ? { startLine: v.line } : {}),
4209
+ }));
4210
+ const aiDebtViolationItems = toAiDebtReportViolations(aiDebtSummary);
4211
+ const violations = [...scopeViolations, ...policyViolationItems, ...aiDebtViolationItems];
4212
+ const governancePayload = governanceResult
4213
+ ? buildGovernancePayload(governanceResult, orgGovernanceSettings, {
4214
+ changeContract: changeContractSummary,
4215
+ compiledPolicy: compiledPolicyMetadata,
4216
+ aiDebt: aiDebtSummary,
4217
+ })
4218
+ : undefined;
4219
+ const verifyEvidencePayload = {
4220
+ grade,
4221
+ score: verifyResult.adherenceScore,
4222
+ verdict: effectiveVerdict,
4223
+ violations,
4224
+ message: effectiveMessage,
4225
+ adherenceScore: verifyResult.adherenceScore,
4226
+ scopeGuardPassed,
4227
+ bloatCount: filteredBloatFiles.length,
4228
+ bloatFiles: filteredBloatFiles,
4229
+ plannedFilesModified: verifyResult.plannedFilesModified,
4230
+ totalPlannedFiles: verifyResult.totalPlannedFiles,
4231
+ verificationSource: verifySource,
4232
+ mode: 'plan_enforced',
4233
+ policyOnly: false,
4234
+ aiDebt: aiDebtSummary,
4235
+ changeContract: changeContractSummary,
4236
+ ...(compiledPolicyMetadata ? { policyCompilation: compiledPolicyMetadata } : {}),
4237
+ ...(governancePayload || {}),
4238
+ policyLock: {
4239
+ enforced: policyLockEvaluation.enforced,
4240
+ matched: policyLockEvaluation.matched,
4241
+ path: policyLockEvaluation.lockPath,
4242
+ mismatches: policyLockEvaluation.mismatches,
4243
+ },
4244
+ policyExceptions: policyExceptionsSummary,
4245
+ policyGovernance: policyGovernanceSummary,
4246
+ intentProof: intentProofSummary,
4247
+ ...(runtimeGuardSummary.required ? { runtimeGuard: runtimeGuardSummary } : {}),
4248
+ ...(policyViolations.length > 0 && { policyDecision }),
4249
+ ...(effectiveRules.policyPack
4250
+ ? {
4251
+ policyPack: {
4252
+ id: effectiveRules.policyPack.packId,
4253
+ name: effectiveRules.policyPack.packName,
4254
+ version: effectiveRules.policyPack.version,
4255
+ ruleCount: effectiveRules.policyPackRules.length,
4256
+ },
4257
+ }
4258
+ : {}),
4259
+ };
4260
+ captureEvidencePayload(verifyEvidencePayload);
4063
4261
  // If JSON output requested, output JSON and exit
4064
4262
  if (options.json) {
4065
- const filteredBloatFiles = (verifyResult.bloatFiles || []).filter((f) => !shouldIgnore(f));
4066
- const scopeViolations = filteredBloatFiles.map((file) => ({
4067
- file,
4068
- rule: 'scope_guard',
4069
- severity: 'block',
4070
- message: 'File modified outside the plan',
4071
- }));
4072
- const policyViolationItems = policyViolations.map((v) => ({
4073
- file: v.file,
4074
- rule: v.rule,
4075
- severity: v.severity,
4076
- message: v.message,
4077
- ...(v.line != null ? { startLine: v.line } : {}),
4078
- }));
4079
- const aiDebtViolationItems = toAiDebtReportViolations(aiDebtSummary);
4080
- const violations = [...scopeViolations, ...policyViolationItems, ...aiDebtViolationItems];
4081
- const jsonOutput = {
4082
- grade,
4083
- score: verifyResult.adherenceScore,
4084
- verdict: effectiveVerdict,
4085
- violations,
4086
- message: effectiveMessage,
4087
- adherenceScore: verifyResult.adherenceScore,
4088
- scopeGuardPassed,
4089
- bloatCount: filteredBloatFiles.length,
4090
- bloatFiles: filteredBloatFiles,
4091
- plannedFilesModified: verifyResult.plannedFilesModified,
4092
- totalPlannedFiles: verifyResult.totalPlannedFiles,
4093
- verificationSource: verifySource,
4094
- mode: 'plan_enforced',
4095
- policyOnly: false,
4096
- aiDebt: aiDebtSummary,
4097
- changeContract: changeContractSummary,
4098
- ...(compiledPolicyMetadata ? { policyCompilation: compiledPolicyMetadata } : {}),
4099
- ...(governanceResult
4100
- ? buildGovernancePayload(governanceResult, orgGovernanceSettings, {
4101
- changeContract: changeContractSummary,
4102
- compiledPolicy: compiledPolicyMetadata,
4103
- aiDebt: aiDebtSummary,
4104
- })
4105
- : {}),
4106
- policyLock: {
4107
- enforced: policyLockEvaluation.enforced,
4108
- matched: policyLockEvaluation.matched,
4109
- path: policyLockEvaluation.lockPath,
4110
- mismatches: policyLockEvaluation.mismatches,
4111
- },
4112
- policyExceptions: policyExceptionsSummary,
4113
- policyGovernance: policyGovernanceSummary,
4114
- intentProof: intentProofSummary,
4115
- ...(runtimeGuardSummary.required ? { runtimeGuard: runtimeGuardSummary } : {}),
4116
- ...(policyViolations.length > 0 && { policyDecision }),
4117
- ...(effectiveRules.policyPack
4118
- ? {
4119
- policyPack: {
4120
- id: effectiveRules.policyPack.packId,
4121
- name: effectiveRules.policyPack.packName,
4122
- version: effectiveRules.policyPack.version,
4123
- ruleCount: effectiveRules.policyPackRules.length,
4124
- },
4125
- }
4126
- : {}),
4127
- };
4128
- emitVerifyJson(jsonOutput);
4263
+ emitVerifyJson(verifyEvidencePayload);
4129
4264
  await recordVerificationIfRequested(options, config, {
4130
4265
  grade,
4131
4266
  violations: violations,
@@ -4140,26 +4275,20 @@ async function verifyCommand(options) {
4140
4275
  projectId: projectId || undefined,
4141
4276
  jsonMode: true,
4142
4277
  verificationSource: verifySource,
4143
- governance: governanceResult
4144
- ? buildGovernancePayload(governanceResult, orgGovernanceSettings, {
4145
- changeContract: changeContractSummary,
4146
- compiledPolicy: compiledPolicyMetadata,
4147
- aiDebt: aiDebtSummary,
4148
- })
4149
- : undefined,
4278
+ governance: governancePayload,
4150
4279
  });
4151
4280
  // Exit based on effective verdict (same logic as below)
4152
4281
  if (shouldForceGovernancePass) {
4153
- process.exit(0);
4282
+ exitWithEvidence(0);
4154
4283
  }
4155
4284
  if (effectiveVerdict === 'FAIL') {
4156
- process.exit(2);
4285
+ exitWithEvidence(2);
4157
4286
  }
4158
4287
  else if (effectiveVerdict === 'WARN') {
4159
- process.exit(1);
4288
+ exitWithEvidence(1);
4160
4289
  }
4161
4290
  else {
4162
- process.exit(0);
4291
+ exitWithEvidence(0);
4163
4292
  }
4164
4293
  }
4165
4294
  // Display results (only if not in json mode; exclude ignored paths from bloat)
@@ -4287,18 +4416,18 @@ async function verifyCommand(options) {
4287
4416
  if (!options.json && policyExceptionsSummary.suppressed > 0) {
4288
4417
  console.log(chalk.yellow(` Policy exceptions applied: ${policyExceptionsSummary.suppressed}`));
4289
4418
  }
4290
- process.exit(0);
4419
+ exitWithEvidence(0);
4291
4420
  }
4292
4421
  // If scope guard didn't pass (or failed to check) or policy blocked, use effective verdict
4293
4422
  // Exit with appropriate code based on AI verification and custom policies
4294
4423
  if (effectiveVerdict === 'FAIL') {
4295
- process.exit(2);
4424
+ exitWithEvidence(2);
4296
4425
  }
4297
4426
  else if (effectiveVerdict === 'WARN') {
4298
- process.exit(1);
4427
+ exitWithEvidence(1);
4299
4428
  }
4300
4429
  else {
4301
- process.exit(0);
4430
+ exitWithEvidence(0);
4302
4431
  }
4303
4432
  }
4304
4433
  catch (error) {
@@ -4341,7 +4470,7 @@ async function verifyCommand(options) {
4341
4470
  console.error(chalk.red('❌ Error:', error));
4342
4471
  }
4343
4472
  }
4344
- process.exit(1);
4473
+ exitWithEvidence(1);
4345
4474
  }
4346
4475
  }
4347
4476
  catch (error) {
@@ -4378,6 +4507,9 @@ async function verifyCommand(options) {
4378
4507
  console.error(error);
4379
4508
  }
4380
4509
  }
4510
+ if (exitWithEvidenceFromTry) {
4511
+ exitWithEvidenceFromTry(1);
4512
+ }
4381
4513
  process.exit(1);
4382
4514
  }
4383
4515
  }