@neurcode-ai/cli 0.9.42 → 0.9.44

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 (44) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +9 -3
  3. package/dist/commands/bootstrap.d.ts.map +1 -1
  4. package/dist/commands/bootstrap.js +16 -89
  5. package/dist/commands/bootstrap.js.map +1 -1
  6. package/dist/commands/check.d.ts.map +1 -1
  7. package/dist/commands/check.js +20 -2
  8. package/dist/commands/check.js.map +1 -1
  9. package/dist/commands/contract.d.ts.map +1 -1
  10. package/dist/commands/contract.js +179 -20
  11. package/dist/commands/contract.js.map +1 -1
  12. package/dist/commands/doctor.d.ts +13 -3
  13. package/dist/commands/doctor.d.ts.map +1 -1
  14. package/dist/commands/doctor.js +476 -95
  15. package/dist/commands/doctor.js.map +1 -1
  16. package/dist/commands/remediate.d.ts +8 -0
  17. package/dist/commands/remediate.d.ts.map +1 -1
  18. package/dist/commands/remediate.js +485 -103
  19. package/dist/commands/remediate.js.map +1 -1
  20. package/dist/commands/verify.d.ts.map +1 -1
  21. package/dist/commands/verify.js +415 -28
  22. package/dist/commands/verify.js.map +1 -1
  23. package/dist/config.d.ts +13 -0
  24. package/dist/config.d.ts.map +1 -1
  25. package/dist/config.js +48 -0
  26. package/dist/config.js.map +1 -1
  27. package/dist/index.js +23 -3
  28. package/dist/index.js.map +1 -1
  29. package/dist/utils/artifact-signature.d.ts.map +1 -1
  30. package/dist/utils/artifact-signature.js +21 -0
  31. package/dist/utils/artifact-signature.js.map +1 -1
  32. package/dist/utils/cli-json.d.ts +54 -0
  33. package/dist/utils/cli-json.d.ts.map +1 -0
  34. package/dist/utils/cli-json.js +152 -0
  35. package/dist/utils/cli-json.js.map +1 -0
  36. package/dist/utils/policy-compiler.d.ts +3 -1
  37. package/dist/utils/policy-compiler.d.ts.map +1 -1
  38. package/dist/utils/policy-compiler.js +8 -0
  39. package/dist/utils/policy-compiler.js.map +1 -1
  40. package/dist/utils/runtime-guard.d.ts +3 -1
  41. package/dist/utils/runtime-guard.d.ts.map +1 -1
  42. package/dist/utils/runtime-guard.js +8 -0
  43. package/dist/utils/runtime-guard.js.map +1 -1
  44. package/package.json +7 -8
@@ -367,6 +367,152 @@ function getRuntimeIgnoreSetFromEnv() {
367
367
  .map((item) => toUnixPath(item.trim()))
368
368
  .filter(Boolean));
369
369
  }
370
+ const INTENT_PROOF_CODE_EXTENSIONS = new Set([
371
+ '.ts',
372
+ '.tsx',
373
+ '.js',
374
+ '.jsx',
375
+ '.mjs',
376
+ '.cjs',
377
+ '.mts',
378
+ '.cts',
379
+ '.py',
380
+ '.java',
381
+ '.go',
382
+ '.rb',
383
+ '.rs',
384
+ ]);
385
+ const INTENT_PROOF_IGNORED_DIRECTORIES = new Set([
386
+ '.git',
387
+ '.hg',
388
+ '.svn',
389
+ '.neurcode',
390
+ 'node_modules',
391
+ 'vendor',
392
+ 'dist',
393
+ 'build',
394
+ 'out',
395
+ 'coverage',
396
+ '.next',
397
+ '.turbo',
398
+ '.cache',
399
+ ]);
400
+ function isIntentProofSourceFile(pathValue) {
401
+ const lower = pathValue.toLowerCase();
402
+ for (const extension of INTENT_PROOF_CODE_EXTENSIONS) {
403
+ if (lower.endsWith(extension)) {
404
+ return true;
405
+ }
406
+ }
407
+ return false;
408
+ }
409
+ function dedupeDeterministicRules(rules) {
410
+ const seen = new Set();
411
+ const out = [];
412
+ for (const rule of rules) {
413
+ const key = [
414
+ rule.id,
415
+ rule.source,
416
+ rule.statement,
417
+ rule.matchToken,
418
+ rule.evaluationMode || '',
419
+ rule.evaluationScope || '',
420
+ typeof rule.minMatchesPerFile === 'number' ? String(rule.minMatchesPerFile) : '',
421
+ typeof rule.maxMatchesPerFile === 'number' ? String(rule.maxMatchesPerFile) : '',
422
+ rule.pathIncludePatterns?.join('|') || '',
423
+ rule.pathExcludePatterns?.join('|') || '',
424
+ ].join('::');
425
+ if (seen.has(key))
426
+ continue;
427
+ seen.add(key);
428
+ out.push(rule);
429
+ }
430
+ return out;
431
+ }
432
+ function collectIntentProofFileContents(projectRoot, changedPaths, maxFiles, maxTotalBytes, maxPerFileBytes) {
433
+ const fileContents = {};
434
+ let scannedFiles = 0;
435
+ let scannedBytes = 0;
436
+ let truncated = false;
437
+ const tryAddFile = (relativePath) => {
438
+ if (!relativePath || fileContents[relativePath] !== undefined)
439
+ return;
440
+ if (!isIntentProofSourceFile(relativePath) || isExcludedFile(relativePath))
441
+ return;
442
+ if (scannedFiles >= maxFiles) {
443
+ truncated = true;
444
+ return;
445
+ }
446
+ const absolutePath = (0, path_1.join)(projectRoot, relativePath);
447
+ if (!(0, fs_1.existsSync)(absolutePath))
448
+ return;
449
+ try {
450
+ const stat = (0, fs_1.statSync)(absolutePath);
451
+ if (!stat.isFile())
452
+ return;
453
+ if (stat.size > maxPerFileBytes)
454
+ return;
455
+ if (scannedBytes + stat.size > maxTotalBytes) {
456
+ truncated = true;
457
+ return;
458
+ }
459
+ const content = (0, fs_1.readFileSync)(absolutePath, 'utf-8');
460
+ fileContents[relativePath] = content;
461
+ scannedFiles += 1;
462
+ scannedBytes += stat.size;
463
+ }
464
+ catch {
465
+ // Non-text/unreadable: skip.
466
+ }
467
+ };
468
+ for (const rawPath of changedPaths) {
469
+ tryAddFile(toUnixPath(rawPath));
470
+ }
471
+ const stack = [projectRoot];
472
+ while (stack.length > 0) {
473
+ const current = stack.pop();
474
+ if (!current)
475
+ continue;
476
+ let entries;
477
+ try {
478
+ entries = (0, fs_1.readdirSync)(current, { withFileTypes: true });
479
+ }
480
+ catch {
481
+ continue;
482
+ }
483
+ for (const entry of entries) {
484
+ if (entry.name === '.' || entry.name === '..')
485
+ continue;
486
+ const absolutePath = (0, path_1.join)(current, entry.name);
487
+ const relativePath = toUnixPath(absolutePath.slice(projectRoot.length + 1));
488
+ if (entry.isDirectory()) {
489
+ if (INTENT_PROOF_IGNORED_DIRECTORIES.has(entry.name))
490
+ continue;
491
+ if (isExcludedFile(`${relativePath}/`))
492
+ continue;
493
+ stack.push(absolutePath);
494
+ continue;
495
+ }
496
+ if (!entry.isFile()) {
497
+ continue;
498
+ }
499
+ if (scannedFiles >= maxFiles) {
500
+ truncated = true;
501
+ break;
502
+ }
503
+ tryAddFile(relativePath);
504
+ }
505
+ if (truncated && scannedFiles >= maxFiles) {
506
+ break;
507
+ }
508
+ }
509
+ return {
510
+ fileContents,
511
+ scannedFiles,
512
+ scannedBytes,
513
+ truncated,
514
+ };
515
+ }
370
516
  async function buildEffectivePolicyRules(client, projectRoot, useDashboardPolicies) {
371
517
  const defaultPolicy = (0, policy_engine_1.createDefaultPolicy)();
372
518
  const customRules = [];
@@ -481,6 +627,112 @@ function runtimeGuardViolationsToReport(summary) {
481
627
  message: item.message,
482
628
  }));
483
629
  }
630
+ function asObjectRecord(value) {
631
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
632
+ return null;
633
+ }
634
+ return value;
635
+ }
636
+ function asObjectArray(value) {
637
+ if (!Array.isArray(value)) {
638
+ return [];
639
+ }
640
+ return value
641
+ .map((item) => asObjectRecord(item))
642
+ .filter((item) => item !== null);
643
+ }
644
+ function asBooleanFlag(value) {
645
+ return typeof value === 'boolean' ? value : null;
646
+ }
647
+ function asNumberValue(value) {
648
+ return typeof value === 'number' && Number.isFinite(value) ? value : null;
649
+ }
650
+ function asStringValue(value) {
651
+ return typeof value === 'string' && value.trim().length > 0 ? value : null;
652
+ }
653
+ function buildDeterministicLayerSummary(payload) {
654
+ const verdict = asStringValue(payload.verdict) || 'UNKNOWN';
655
+ const mode = asStringValue(payload.mode) || 'unknown';
656
+ const policyOnly = payload.policyOnly === true;
657
+ const scopeGuardPassed = asBooleanFlag(payload.scopeGuardPassed);
658
+ const violations = asObjectArray(payload.violations);
659
+ const policyViolations = violations.filter((entry) => {
660
+ const rule = String(entry.rule || '').toLowerCase();
661
+ return (!rule.includes('scope_guard')
662
+ && !rule.includes('change_contract')
663
+ && !rule.includes('runtime_guard')
664
+ && !rule.includes('deterministic_artifacts_required')
665
+ && !rule.includes('signed_artifacts_required'));
666
+ });
667
+ const policyBlocking = policyViolations.filter((entry) => String(entry.severity || '').toLowerCase() === 'block');
668
+ const policyWarnings = policyViolations.filter((entry) => String(entry.severity || '').toLowerCase() === 'warn');
669
+ const changeContract = asObjectRecord(payload.changeContract);
670
+ const changeContractValid = asBooleanFlag(changeContract?.valid);
671
+ const changeContractEnforced = changeContract?.enforced === true;
672
+ const changeContractViolations = Array.isArray(changeContract?.violations)
673
+ ? (changeContract?.violations).length
674
+ : 0;
675
+ const explicitContractViolations = violations.filter((entry) => {
676
+ const rule = String(entry.rule || '').toLowerCase();
677
+ return rule.includes('scope_guard') || rule.includes('change_contract');
678
+ }).length;
679
+ const runtimeGuard = asObjectRecord(payload.runtimeGuard);
680
+ const runtimeGuardRequired = runtimeGuard?.required === true;
681
+ const runtimeGuardPass = asBooleanFlag(runtimeGuard?.pass);
682
+ const runtimeGuardViolations = Array.isArray(runtimeGuard?.violations)
683
+ ? (runtimeGuard?.violations).length
684
+ : violations.filter((entry) => String(entry.rule || '').toLowerCase().includes('runtime_guard')).length;
685
+ const policyCompilation = asObjectRecord(payload.policyCompilation);
686
+ const deterministicRuleCount = asNumberValue(policyCompilation?.deterministicRuleCount);
687
+ const unmatchedStatements = asNumberValue(policyCompilation?.unmatchedStatements);
688
+ let policyGateStatus = 'pass';
689
+ if (policyBlocking.length > 0) {
690
+ policyGateStatus = 'fail';
691
+ }
692
+ else if (policyWarnings.length > 0 || verdict === 'WARN') {
693
+ policyGateStatus = 'warn';
694
+ }
695
+ let contractGateStatus = 'not_applicable';
696
+ if (!policyOnly) {
697
+ contractGateStatus = 'pass';
698
+ if (changeContractEnforced
699
+ && (changeContractValid === false || changeContractViolations > 0 || explicitContractViolations > 0 || scopeGuardPassed === false)) {
700
+ contractGateStatus = 'fail';
701
+ }
702
+ else if (!changeContractEnforced && (changeContractViolations > 0 || explicitContractViolations > 0)) {
703
+ contractGateStatus = 'warn';
704
+ }
705
+ }
706
+ let runtimeGuardStatus = 'not_applicable';
707
+ if (runtimeGuardRequired) {
708
+ runtimeGuardStatus = runtimeGuardPass === false || runtimeGuardViolations > 0 ? 'fail' : 'pass';
709
+ }
710
+ else if (runtimeGuardViolations > 0) {
711
+ runtimeGuardStatus = 'fail';
712
+ }
713
+ return {
714
+ policyGate: {
715
+ status: policyGateStatus,
716
+ blockingViolations: policyBlocking.length,
717
+ warningViolations: policyWarnings.length,
718
+ deterministicRuleCount: deterministicRuleCount ?? null,
719
+ unmatchedStatements: unmatchedStatements ?? null,
720
+ },
721
+ contractGate: {
722
+ status: contractGateStatus,
723
+ enforced: changeContractEnforced,
724
+ valid: changeContractValid,
725
+ violationCount: changeContractViolations + explicitContractViolations,
726
+ mode,
727
+ },
728
+ runtimeGuardGate: {
729
+ status: runtimeGuardStatus,
730
+ required: runtimeGuardRequired,
731
+ pass: runtimeGuardPass,
732
+ violationCount: runtimeGuardViolations,
733
+ },
734
+ };
735
+ }
484
736
  function toAiDebtSummary(evaluation) {
485
737
  return {
486
738
  mode: evaluation.mode,
@@ -544,31 +796,29 @@ function parseSigningKeyRing(raw) {
544
796
  return out;
545
797
  }
546
798
  function resolveGovernanceSigningConfig() {
547
- const signingKeys = parseSigningKeyRing(process.env.NEURCODE_GOVERNANCE_SIGNING_KEYS);
548
- const envSigningKey = process.env.NEURCODE_GOVERNANCE_SIGNING_KEY?.trim() ||
549
- process.env.NEURCODE_AI_LOG_SIGNING_KEY?.trim() ||
550
- '';
551
- const requestedKeyId = process.env.NEURCODE_GOVERNANCE_SIGNING_KEY_ID?.trim() || '';
799
+ const artifactSigningConfig = (0, artifact_signature_1.resolveGovernanceArtifactSigningConfigFromEnv)();
552
800
  const signer = process.env.NEURCODE_GOVERNANCE_SIGNER || process.env.USER || 'neurcode-cli';
553
- let signingKey = envSigningKey || null;
554
- let signingKeyId = requestedKeyId || null;
555
- if (!signingKey && Object.keys(signingKeys).length > 0) {
556
- if (signingKeyId && signingKeys[signingKeyId]) {
557
- signingKey = signingKeys[signingKeyId];
558
- }
559
- else {
560
- const fallbackKeyId = Object.keys(signingKeys).sort((a, b) => a.localeCompare(b))[0];
561
- signingKey = signingKeys[fallbackKeyId];
562
- signingKeyId = signingKeyId || fallbackKeyId;
563
- }
564
- }
565
801
  return {
566
- signingKey,
567
- signingKeyId,
568
- signingKeys,
802
+ signingKey: artifactSigningConfig.signingKey,
803
+ signingKeyId: artifactSigningConfig.signingKeyId,
804
+ signingKeys: artifactSigningConfig.signingKeys,
569
805
  signer,
570
806
  };
571
807
  }
808
+ function isGitRepository(cwd) {
809
+ try {
810
+ const output = (0, child_process_1.execSync)('git rev-parse --is-inside-work-tree', {
811
+ cwd,
812
+ encoding: 'utf-8',
813
+ stdio: ['ignore', 'pipe', 'pipe'],
814
+ maxBuffer: 1024 * 1024,
815
+ }).trim().toLowerCase();
816
+ return output === 'true';
817
+ }
818
+ catch {
819
+ return false;
820
+ }
821
+ }
572
822
  function isSignedAiLogsRequired(orgGovernanceSettings) {
573
823
  return (orgGovernanceSettings?.requireSignedAiLogs === true ||
574
824
  isEnabledFlag(process.env.NEURCODE_GOVERNANCE_REQUIRE_SIGNED_LOGS) ||
@@ -738,8 +988,12 @@ async function recordVerificationIfRequested(options, config, payload) {
738
988
  */
739
989
  async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRoot, config, client, source, scopeTelemetry, projectId, orgGovernanceSettings, aiLogSigningKey, aiLogSigningKeyId, aiLogSigningKeys, aiLogSigner, compiledPolicyMetadata, changeContractSummary) {
740
990
  const emitPolicyOnlyJson = (payload) => {
741
- console.log(JSON.stringify({
991
+ const enrichedPayload = {
742
992
  ...payload,
993
+ deterministicLayers: buildDeterministicLayerSummary(payload),
994
+ };
995
+ console.log(JSON.stringify({
996
+ ...enrichedPayload,
743
997
  ...(compiledPolicyMetadata ? { policyCompilation: compiledPolicyMetadata } : {}),
744
998
  changeContract: changeContractSummary,
745
999
  scope: scopeTelemetry,
@@ -1264,10 +1518,45 @@ async function verifyCommand(options) {
1264
1518
  const emitVerifyJson = (payload) => {
1265
1519
  const jsonPayload = {
1266
1520
  ...payload,
1521
+ deterministicLayers: buildDeterministicLayerSummary(payload),
1267
1522
  scope: scopeTelemetry,
1268
1523
  };
1269
1524
  console.log(JSON.stringify(jsonPayload, null, 2));
1270
1525
  };
1526
+ if (!isGitRepository(projectRoot)) {
1527
+ const message = 'Verify requires a git repository. Initialize git (`git init`) or run this command inside an existing git project.';
1528
+ if (options.json) {
1529
+ emitVerifyJson({
1530
+ grade: 'F',
1531
+ score: 0,
1532
+ verdict: 'FAIL',
1533
+ violations: [
1534
+ {
1535
+ file: '.',
1536
+ rule: 'git_repository_required',
1537
+ severity: 'block',
1538
+ message,
1539
+ },
1540
+ ],
1541
+ adherenceScore: 0,
1542
+ bloatCount: 0,
1543
+ bloatFiles: [],
1544
+ plannedFilesModified: 0,
1545
+ totalPlannedFiles: 0,
1546
+ message,
1547
+ scopeGuardPassed: false,
1548
+ mode: 'git_repository_required',
1549
+ policyOnly: options.policyOnly === true,
1550
+ });
1551
+ }
1552
+ else {
1553
+ console.log(chalk.red('\n❌ Git Repository Required'));
1554
+ console.log(chalk.red(` ${message}`));
1555
+ console.log(chalk.dim(` Current path: ${projectRoot}`));
1556
+ console.log(chalk.dim(' Next step: git init && git add . && git commit -m "chore: baseline"\n'));
1557
+ }
1558
+ process.exit(1);
1559
+ }
1271
1560
  const enforceChangeContract = options.enforceChangeContract === true ||
1272
1561
  isEnabledFlag(process.env.NEURCODE_VERIFY_ENFORCE_CHANGE_CONTRACT);
1273
1562
  const explicitStrictArtifactMode = options.strictArtifacts === true ||
@@ -1715,7 +2004,7 @@ async function verifyCommand(options) {
1715
2004
  // Determine which diff to capture (staged + unstaged for full current work)
1716
2005
  let diffText;
1717
2006
  if (options.staged) {
1718
- diffText = (0, child_process_1.execSync)('git diff --staged', { maxBuffer: 1024 * 1024 * 1024, encoding: 'utf-8' });
2007
+ diffText = (0, child_process_1.execSync)('git diff --cached', { maxBuffer: 1024 * 1024 * 1024, encoding: 'utf-8' });
1719
2008
  }
1720
2009
  else if (options.base) {
1721
2010
  diffText = (0, git_1.getDiffFromBase)(options.base);
@@ -1726,7 +2015,7 @@ async function verifyCommand(options) {
1726
2015
  else {
1727
2016
  // Default: combine staged + unstaged to capture all current work
1728
2017
  try {
1729
- const stagedDiff = (0, child_process_1.execSync)('git diff --staged', { maxBuffer: 1024 * 1024 * 1024, encoding: 'utf-8' });
2018
+ const stagedDiff = (0, child_process_1.execSync)('git diff --cached', { maxBuffer: 1024 * 1024 * 1024, encoding: 'utf-8' });
1730
2019
  const unstagedDiff = (0, child_process_1.execSync)('git diff', { maxBuffer: 1024 * 1024 * 1024, encoding: 'utf-8' });
1731
2020
  diffText = stagedDiff + (stagedDiff && unstagedDiff ? '\n' : '') + unstagedDiff;
1732
2021
  }
@@ -2496,6 +2785,11 @@ async function verifyCommand(options) {
2496
2785
  const hydratedCompiledPolicyRules = effectiveCompiledPolicy
2497
2786
  ? (0, policy_compiler_1.hydrateCompiledPolicyRules)(effectiveCompiledPolicy)
2498
2787
  : [];
2788
+ const deterministicPolicyRules = effectiveCompiledPolicy
2789
+ ? [...effectiveCompiledPolicy.statements.policyRules]
2790
+ : effectiveRules.customPolicies
2791
+ .map((policy) => policy.rule_text)
2792
+ .filter((ruleText) => typeof ruleText === 'string' && ruleText.trim().length > 0);
2499
2793
  if (effectiveCompiledPolicy?.source.policyLockFingerprint &&
2500
2794
  policyLockEvaluation.lockPresent &&
2501
2795
  effectiveCompiledPolicy.source.policyLockFingerprint !== (0, policy_packs_1.readPolicyLockFile)(projectRoot).lock?.effective.fingerprint) {
@@ -2661,6 +2955,17 @@ async function verifyCommand(options) {
2661
2955
  eventCount: auditIntegrity.count,
2662
2956
  },
2663
2957
  };
2958
+ let intentProofSummary = {
2959
+ enabled: false,
2960
+ pass: true,
2961
+ checkedRules: 0,
2962
+ repoScopedRules: 0,
2963
+ signatureDriftRules: 0,
2964
+ scannedFiles: 0,
2965
+ scannedBytes: 0,
2966
+ truncated: false,
2967
+ violations: [],
2968
+ };
2664
2969
  if (!options.json && effectiveRules.customRules.length > 0) {
2665
2970
  console.log(chalk.dim(` Evaluating ${effectiveRules.customRules.length} custom policy rule(s) from dashboard`));
2666
2971
  }
@@ -2692,6 +2997,73 @@ async function verifyCommand(options) {
2692
2997
  })),
2693
2998
  })),
2694
2999
  }));
3000
+ const compiledIntentProof = (0, governance_runtime_1.compileDeterministicConstraints)({
3001
+ intentConstraints: intentConstraintsForVerification,
3002
+ policyRules: deterministicPolicyRules,
3003
+ });
3004
+ const proofRules = dedupeDeterministicRules([
3005
+ ...compiledIntentProof.rules,
3006
+ ...hydratedCompiledPolicyRules,
3007
+ ].filter((rule) => rule.evaluationScope === 'repo'
3008
+ || rule.evaluationMode === 'signature_delta'));
3009
+ if (proofRules.length > 0) {
3010
+ const repoScopedRules = proofRules.filter((rule) => rule.evaluationScope === 'repo');
3011
+ const signatureDriftRules = proofRules.filter((rule) => rule.evaluationMode === 'signature_delta');
3012
+ const maxProofFiles = Math.max(100, Math.floor(Number(process.env.NEURCODE_INTENT_PROOF_MAX_FILES || 2500)));
3013
+ const maxProofBytes = Math.max(1024 * 1024, Math.floor(Number(process.env.NEURCODE_INTENT_PROOF_MAX_BYTES || (32 * 1024 * 1024))));
3014
+ const maxProofPerFileBytes = Math.max(4096, Math.floor(Number(process.env.NEURCODE_INTENT_PROOF_MAX_FILE_BYTES || (768 * 1024))));
3015
+ let proofContents;
3016
+ let proofScannedFiles = 0;
3017
+ let proofScannedBytes = 0;
3018
+ let proofTruncated = false;
3019
+ if (repoScopedRules.length > 0) {
3020
+ const scan = collectIntentProofFileContents(projectRoot, changedFiles.map((file) => file.path), maxProofFiles, maxProofBytes, maxProofPerFileBytes);
3021
+ proofContents = scan.fileContents;
3022
+ proofScannedFiles = scan.scannedFiles;
3023
+ proofScannedBytes = scan.scannedBytes;
3024
+ proofTruncated = scan.truncated;
3025
+ }
3026
+ const proofEvaluation = (0, governance_runtime_1.evaluatePlanVerification)({
3027
+ planFiles: planFilesForVerification.map((path) => ({
3028
+ path,
3029
+ action: 'MODIFY',
3030
+ })),
3031
+ changedFiles,
3032
+ diffStats,
3033
+ extraConstraintRules: proofRules,
3034
+ fileContents: proofContents,
3035
+ });
3036
+ intentProofSummary = {
3037
+ enabled: true,
3038
+ pass: proofEvaluation.constraintViolations.length === 0,
3039
+ checkedRules: proofRules.length,
3040
+ repoScopedRules: repoScopedRules.length,
3041
+ signatureDriftRules: signatureDriftRules.length,
3042
+ scannedFiles: proofScannedFiles,
3043
+ scannedBytes: proofScannedBytes,
3044
+ truncated: proofTruncated,
3045
+ violations: [...proofEvaluation.constraintViolations],
3046
+ };
3047
+ if (proofEvaluation.constraintViolations.length > 0) {
3048
+ const intentProofPolicyViolations = proofEvaluation.constraintViolations.map((violation) => ({
3049
+ file: '.neurcode/intent-proof',
3050
+ rule: 'intent_proof',
3051
+ severity: 'block',
3052
+ message: violation,
3053
+ }));
3054
+ policyViolations.push(...intentProofPolicyViolations);
3055
+ policyDecision = resolvePolicyDecisionFromViolations(policyViolations);
3056
+ }
3057
+ if (!options.json) {
3058
+ if (intentProofSummary.pass) {
3059
+ console.log(chalk.dim(` Intent proof checks passed (${intentProofSummary.checkedRules} rule(s)` +
3060
+ `${intentProofSummary.repoScopedRules > 0 ? `, repo scan ${intentProofSummary.scannedFiles} file(s)` : ''})`));
3061
+ }
3062
+ else {
3063
+ console.log(chalk.red(` Intent proof checks failed (${intentProofSummary.violations.length} violation(s), ${intentProofSummary.checkedRules} rule(s))`));
3064
+ }
3065
+ }
3066
+ }
2695
3067
  const changeContractEvaluation = changeContractRead.contract
2696
3068
  ? (0, change_contract_1.evaluateChangeContract)(changeContractRead.contract, {
2697
3069
  planId: finalPlanId,
@@ -2795,11 +3167,6 @@ async function verifyCommand(options) {
2795
3167
  try {
2796
3168
  let verifySource = 'api';
2797
3169
  let verifyResult;
2798
- const deterministicPolicyRules = effectiveCompiledPolicy
2799
- ? [...effectiveCompiledPolicy.statements.policyRules]
2800
- : effectiveRules.customPolicies
2801
- .map((policy) => policy.rule_text)
2802
- .filter((ruleText) => typeof ruleText === 'string' && ruleText.trim().length > 0);
2803
3170
  try {
2804
3171
  verifyResult = await client.verifyPlan(finalPlanId, diffStats, changedFiles, projectId, intentConstraintsForVerification, deterministicPolicyRules, 'api', compiledPolicyMetadata, {
2805
3172
  async: options.asyncMode === true,
@@ -2990,6 +3357,7 @@ async function verifyCommand(options) {
2990
3357
  },
2991
3358
  policyExceptions: policyExceptionsSummary,
2992
3359
  policyGovernance: policyGovernanceSummary,
3360
+ intentProof: intentProofSummary,
2993
3361
  ...(runtimeGuardSummary.required ? { runtimeGuard: runtimeGuardSummary } : {}),
2994
3362
  ...(policyViolations.length > 0 && { policyDecision }),
2995
3363
  ...(effectiveRules.policyPack
@@ -3093,6 +3461,25 @@ async function verifyCommand(options) {
3093
3461
  if (runtimeGuardSummary.required) {
3094
3462
  console.log(chalk.dim(`\n Runtime guard: ${runtimeGuardSummary.pass ? 'pass' : 'block'} (${runtimeGuardSummary.path})`));
3095
3463
  }
3464
+ if (intentProofSummary.enabled) {
3465
+ const proofHeader = intentProofSummary.pass
3466
+ ? chalk.dim(` Intent proof: pass (${intentProofSummary.checkedRules} rule(s)` +
3467
+ `${intentProofSummary.repoScopedRules > 0 ? `, scanned ${intentProofSummary.scannedFiles} file(s)` : ''})`)
3468
+ : chalk.red(`\n⛔ Intent proof enforcement: ${intentProofSummary.violations.length} violation(s) ` +
3469
+ `(${intentProofSummary.checkedRules} rule(s))`);
3470
+ console.log(`\n${proofHeader}`);
3471
+ if (!intentProofSummary.pass) {
3472
+ intentProofSummary.violations.slice(0, 5).forEach((issue) => {
3473
+ console.log(chalk.red(` • ${issue}`));
3474
+ });
3475
+ if (intentProofSummary.violations.length > 5) {
3476
+ console.log(chalk.dim(` ... ${intentProofSummary.violations.length - 5} more violation(s)`));
3477
+ }
3478
+ }
3479
+ else if (intentProofSummary.truncated) {
3480
+ console.log(chalk.dim(' Intent proof repo scan reached configured file/byte limit (truncated).'));
3481
+ }
3482
+ }
3096
3483
  }
3097
3484
  // Report to Neurcode Cloud if --record flag is set
3098
3485
  const filteredBloatForReport = (verifyResult.bloatFiles || []).filter((f) => !shouldIgnore(f));