@neurcode-ai/cli 0.9.49 → 0.9.59

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 (109) hide show
  1. package/dist/commands/fix.d.ts +1 -0
  2. package/dist/commands/fix.d.ts.map +1 -1
  3. package/dist/commands/fix.js +710 -29
  4. package/dist/commands/fix.js.map +1 -1
  5. package/dist/commands/generate.d.ts.map +1 -1
  6. package/dist/commands/generate.js +16 -1
  7. package/dist/commands/generate.js.map +1 -1
  8. package/dist/commands/patch-apply.d.ts +7 -0
  9. package/dist/commands/patch-apply.d.ts.map +1 -0
  10. package/dist/commands/patch-apply.js +85 -0
  11. package/dist/commands/patch-apply.js.map +1 -0
  12. package/dist/commands/start-intent.d.ts.map +1 -1
  13. package/dist/commands/start-intent.js +17 -2
  14. package/dist/commands/start-intent.js.map +1 -1
  15. package/dist/commands/verify.d.ts.map +1 -1
  16. package/dist/commands/verify.js +372 -71
  17. package/dist/commands/verify.js.map +1 -1
  18. package/dist/context-engine/graph.d.ts +6 -0
  19. package/dist/context-engine/graph.d.ts.map +1 -0
  20. package/dist/context-engine/graph.js +55 -0
  21. package/dist/context-engine/graph.js.map +1 -0
  22. package/dist/context-engine/index.d.ts +14 -0
  23. package/dist/context-engine/index.d.ts.map +1 -0
  24. package/dist/context-engine/index.js +26 -0
  25. package/dist/context-engine/index.js.map +1 -0
  26. package/dist/context-engine/scanner.d.ts +6 -0
  27. package/dist/context-engine/scanner.d.ts.map +1 -0
  28. package/dist/context-engine/scanner.js +62 -0
  29. package/dist/context-engine/scanner.js.map +1 -0
  30. package/dist/context-engine/scorer.d.ts +9 -0
  31. package/dist/context-engine/scorer.d.ts.map +1 -0
  32. package/dist/context-engine/scorer.js +112 -0
  33. package/dist/context-engine/scorer.js.map +1 -0
  34. package/dist/context-engine/suggestions.d.ts +12 -0
  35. package/dist/context-engine/suggestions.d.ts.map +1 -0
  36. package/dist/context-engine/suggestions.js +22 -0
  37. package/dist/context-engine/suggestions.js.map +1 -0
  38. package/dist/daemon/server.d.ts +23 -0
  39. package/dist/daemon/server.d.ts.map +1 -0
  40. package/dist/daemon/server.js +222 -0
  41. package/dist/daemon/server.js.map +1 -0
  42. package/dist/index.js +22 -0
  43. package/dist/index.js.map +1 -1
  44. package/dist/intent-engine/coverage.d.ts +69 -0
  45. package/dist/intent-engine/coverage.d.ts.map +1 -0
  46. package/dist/intent-engine/coverage.js +140 -0
  47. package/dist/intent-engine/coverage.js.map +1 -0
  48. package/dist/intent-engine/flow-rules.d.ts +21 -0
  49. package/dist/intent-engine/flow-rules.d.ts.map +1 -0
  50. package/dist/intent-engine/flow-rules.js +83 -0
  51. package/dist/intent-engine/flow-rules.js.map +1 -0
  52. package/dist/intent-engine/flow-validator.d.ts +29 -0
  53. package/dist/intent-engine/flow-validator.d.ts.map +1 -0
  54. package/dist/intent-engine/flow-validator.js +202 -0
  55. package/dist/intent-engine/flow-validator.js.map +1 -0
  56. package/dist/intent-engine/graph.d.ts +33 -0
  57. package/dist/intent-engine/graph.d.ts.map +1 -0
  58. package/dist/intent-engine/graph.js +67 -0
  59. package/dist/intent-engine/graph.js.map +1 -0
  60. package/dist/intent-engine/index.d.ts +35 -0
  61. package/dist/intent-engine/index.d.ts.map +1 -0
  62. package/dist/intent-engine/index.js +94 -0
  63. package/dist/intent-engine/index.js.map +1 -0
  64. package/dist/intent-engine/indexer.d.ts +18 -0
  65. package/dist/intent-engine/indexer.d.ts.map +1 -0
  66. package/dist/intent-engine/indexer.js +100 -0
  67. package/dist/intent-engine/indexer.js.map +1 -0
  68. package/dist/intent-engine/matcher.d.ts +35 -0
  69. package/dist/intent-engine/matcher.d.ts.map +1 -0
  70. package/dist/intent-engine/matcher.js +522 -0
  71. package/dist/intent-engine/matcher.js.map +1 -0
  72. package/dist/intent-engine/parser.d.ts +12 -0
  73. package/dist/intent-engine/parser.d.ts.map +1 -0
  74. package/dist/intent-engine/parser.js +93 -0
  75. package/dist/intent-engine/parser.js.map +1 -0
  76. package/dist/intent-engine/regression.d.ts +32 -0
  77. package/dist/intent-engine/regression.d.ts.map +1 -0
  78. package/dist/intent-engine/regression.js +166 -0
  79. package/dist/intent-engine/regression.js.map +1 -0
  80. package/dist/intent-engine/requirements.d.ts +22 -0
  81. package/dist/intent-engine/requirements.d.ts.map +1 -0
  82. package/dist/intent-engine/requirements.js +147 -0
  83. package/dist/intent-engine/requirements.js.map +1 -0
  84. package/dist/intent-engine/state.d.ts +44 -0
  85. package/dist/intent-engine/state.d.ts.map +1 -0
  86. package/dist/intent-engine/state.js +83 -0
  87. package/dist/intent-engine/state.js.map +1 -0
  88. package/dist/patch-engine/diff.d.ts +12 -0
  89. package/dist/patch-engine/diff.d.ts.map +1 -0
  90. package/dist/patch-engine/diff.js +74 -0
  91. package/dist/patch-engine/diff.js.map +1 -0
  92. package/dist/patch-engine/generator.d.ts +13 -0
  93. package/dist/patch-engine/generator.d.ts.map +1 -0
  94. package/dist/patch-engine/generator.js +51 -0
  95. package/dist/patch-engine/generator.js.map +1 -0
  96. package/dist/patch-engine/index.d.ts +47 -0
  97. package/dist/patch-engine/index.d.ts.map +1 -0
  98. package/dist/patch-engine/index.js +182 -0
  99. package/dist/patch-engine/index.js.map +1 -0
  100. package/dist/patch-engine/patterns.d.ts +4 -0
  101. package/dist/patch-engine/patterns.d.ts.map +1 -0
  102. package/dist/patch-engine/patterns.js +99 -0
  103. package/dist/patch-engine/patterns.js.map +1 -0
  104. package/dist/utils/ai-debt-budget.d.ts +3 -2
  105. package/dist/utils/ai-debt-budget.d.ts.map +1 -1
  106. package/dist/utils/ai-debt-budget.js +83 -2
  107. package/dist/utils/ai-debt-budget.js.map +1 -1
  108. package/package.json +8 -7
  109. package/LICENSE +0 -201
@@ -56,6 +56,7 @@ const project_root_1 = require("../utils/project-root");
56
56
  const brain_context_1 = require("../utils/brain-context");
57
57
  const scope_telemetry_1 = require("../utils/scope-telemetry");
58
58
  const plan_sync_1 = require("../utils/plan-sync");
59
+ const intent_engine_1 = require("../intent-engine");
59
60
  const policy_packs_1 = require("../utils/policy-packs");
60
61
  const custom_policy_rules_1 = require("../utils/custom-policy-rules");
61
62
  const policy_exceptions_1 = require("../utils/policy-exceptions");
@@ -847,6 +848,16 @@ function toCanonicalVerifyOutput(payload) {
847
848
  addScopeIssue(file, message);
848
849
  continue;
849
850
  }
851
+ // Artifact presence/signature checks are advisory — they must never block a PR.
852
+ // Real governance signal (policy violations, scope drift) should not be obscured
853
+ // by infrastructure setup state.
854
+ const policyStr = String(policy || '').toLowerCase();
855
+ const isArtifactCheck = policyStr === 'deterministic_artifacts_required'
856
+ || policyStr === 'signed_artifacts_required';
857
+ if (isArtifactCheck) {
858
+ addWarning(file, message, policy);
859
+ continue;
860
+ }
850
861
  if (severity === 'warning' || severity === 'info') {
851
862
  addWarning(file, message, policy);
852
863
  continue;
@@ -942,9 +953,79 @@ function toCanonicalVerifyOutput(payload) {
942
953
  source: 'expedite',
943
954
  })),
944
955
  ]);
945
- const blockingItems = expediteModeUsed ? expediteBlockingItems : defaultBlockingItems;
946
- const advisoryItems = expediteModeUsed ? expediteItems : defaultAdvisoryItems;
956
+ // ── Intent issues and summary from engine ───────────────────────────────
957
+ const rawIntentIssues = Array.isArray(payload.intentIssues) ? payload.intentIssues : [];
958
+ const intentDomains = Array.isArray(payload.intentDomains) ? payload.intentDomains : [];
959
+ const intentSummary = (payload.intentSummary ?? null);
960
+ const rawFlowIssues = Array.isArray(payload.flowIssues) ? payload.flowIssues : [];
961
+ const rawRegressions = Array.isArray(payload.regressions) ? payload.regressions : [];
962
+ // High-severity intent issues become blocking; medium become advisory.
963
+ const intentBlockingTriageItems = rawIntentIssues
964
+ .filter((i) => i.severity === 'high')
965
+ .map((i) => ({
966
+ file: (i.files?.[0]) ?? 'intent-analysis',
967
+ message: i.message,
968
+ policy: i.rule,
969
+ severity: 'high',
970
+ source: 'violation',
971
+ }));
972
+ const intentAdvisoryTriageItems = rawIntentIssues
973
+ .filter((i) => i.severity === 'medium')
974
+ .map((i) => ({
975
+ file: (i.files?.[0]) ?? 'intent-analysis',
976
+ message: i.message,
977
+ policy: i.rule,
978
+ severity: 'warning',
979
+ source: 'warning',
980
+ }));
981
+ // V5: flow issues — high → blocking, medium → advisory
982
+ const flowBlockingTriageItems = rawFlowIssues
983
+ .filter((i) => i.severity === 'high')
984
+ .map((i) => ({
985
+ file: (i.files?.[0]) ?? 'flow-analysis',
986
+ message: i.message,
987
+ policy: i.rule,
988
+ severity: 'high',
989
+ source: 'violation',
990
+ }));
991
+ const flowAdvisoryTriageItems = rawFlowIssues
992
+ .filter((i) => i.severity === 'medium')
993
+ .map((i) => ({
994
+ file: (i.files?.[0]) ?? 'flow-analysis',
995
+ message: i.message,
996
+ policy: i.rule,
997
+ severity: 'warning',
998
+ source: 'warning',
999
+ }));
1000
+ let blockingItems = expediteModeUsed ? expediteBlockingItems : defaultBlockingItems;
1001
+ let advisoryItems = expediteModeUsed ? expediteItems : defaultAdvisoryItems;
1002
+ if (intentBlockingTriageItems.length > 0) {
1003
+ blockingItems = dedupeTriageItems([...blockingItems, ...intentBlockingTriageItems]);
1004
+ }
1005
+ if (intentAdvisoryTriageItems.length > 0) {
1006
+ advisoryItems = dedupeTriageItems([...advisoryItems, ...intentAdvisoryTriageItems]);
1007
+ }
1008
+ if (flowBlockingTriageItems.length > 0) {
1009
+ blockingItems = dedupeTriageItems([...blockingItems, ...flowBlockingTriageItems]);
1010
+ }
1011
+ if (flowAdvisoryTriageItems.length > 0) {
1012
+ advisoryItems = dedupeTriageItems([...advisoryItems, ...flowAdvisoryTriageItems]);
1013
+ }
1014
+ // V6: regressions — always blocking
1015
+ const regressionBlockingTriageItems = rawRegressions.map((r) => ({
1016
+ file: 'regression-analysis',
1017
+ message: r.message,
1018
+ policy: r.rule,
1019
+ severity: 'high',
1020
+ source: 'violation',
1021
+ }));
1022
+ if (regressionBlockingTriageItems.length > 0) {
1023
+ blockingItems = dedupeTriageItems([...regressionBlockingTriageItems, ...blockingItems]);
1024
+ }
1025
+ const grade = verdict === 'PASS' ? 'A' : verdict === 'WARN' ? 'C' : 'F';
947
1026
  return {
1027
+ grade,
1028
+ score: violations.length === 0 && warnings.length === 0 && scopeIssues.length === 0 ? 100 : 0,
948
1029
  verdict,
949
1030
  summary: {
950
1031
  totalFilesChanged,
@@ -959,6 +1040,11 @@ function toCanonicalVerifyOutput(payload) {
959
1040
  advisoryCount: advisoryItems.length,
960
1041
  blockingItems,
961
1042
  advisoryItems,
1043
+ intentIssues: rawIntentIssues,
1044
+ intentDomains,
1045
+ intentSummary,
1046
+ flowIssues: rawFlowIssues,
1047
+ regressions: rawRegressions,
962
1048
  expediteModeUsed,
963
1049
  expediteCount: expediteModeUsed ? expediteItems.length : 0,
964
1050
  expediteItems: expediteModeUsed ? expediteItems : [],
@@ -1080,20 +1166,32 @@ function toAiDebtSummary(evaluation) {
1080
1166
  observed: item.observed,
1081
1167
  budget: item.budget,
1082
1168
  message: item.message,
1169
+ ...(item.files && item.files.length > 0 ? { files: item.files } : {}),
1083
1170
  })),
1084
1171
  };
1085
1172
  }
1173
+ const ARCH_VIOLATION_CODES = new Set(['db_in_ui', 'missing_validation']);
1086
1174
  function toAiDebtReportViolations(summary) {
1087
1175
  if (summary.mode === 'off' || summary.violations.length === 0) {
1088
1176
  return [];
1089
1177
  }
1090
- const severity = summary.mode === 'enforce' ? 'block' : 'warn';
1091
- return summary.violations.map((item) => ({
1092
- rule: `ai_debt:${item.code}`,
1093
- file: '.neurcode/ai-debt-budget.json',
1094
- severity,
1095
- message: item.message,
1096
- }));
1178
+ const defaultSeverity = summary.mode === 'enforce' ? 'block' : 'warn';
1179
+ const result = [];
1180
+ for (const item of summary.violations) {
1181
+ // Architectural violations are always advisory (warn) — heuristic detection, not a hard block
1182
+ const severity = ARCH_VIOLATION_CODES.has(item.code) ? 'warn' : defaultSeverity;
1183
+ const rule = ARCH_VIOLATION_CODES.has(item.code) ? item.code : `ai_debt:${item.code}`;
1184
+ const files = item.files && item.files.length > 0 ? item.files : null;
1185
+ if (files) {
1186
+ for (const file of files) {
1187
+ result.push({ rule, file, severity, message: item.message });
1188
+ }
1189
+ }
1190
+ else {
1191
+ result.push({ rule, file: '.neurcode/ai-debt-budget.json', severity, message: item.message });
1192
+ }
1193
+ }
1194
+ return result;
1097
1195
  }
1098
1196
  function parseSigningKeyRing(raw) {
1099
1197
  if (!raw || !raw.trim()) {
@@ -1649,6 +1747,9 @@ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRo
1649
1747
  if (!options.json && effectiveRules.policyPack && effectiveRules.policyPackRules.length > 0) {
1650
1748
  console.log(chalk.dim(` Evaluating policy pack: ${effectiveRules.policyPack.packName} (${effectiveRules.policyPack.packId}@${effectiveRules.policyPack.version}, ${effectiveRules.policyPackRules.length} rule(s))`));
1651
1749
  }
1750
+ else if (!options.json && !effectiveRules.policyPack) {
1751
+ console.log(chalk.dim(' No policy pack installed — run `neurcode policy install <pack>` to add governance rules'));
1752
+ }
1652
1753
  const policyResult = (0, policy_engine_1.evaluateRules)(diffFilesForPolicy, effectiveRules.allRules);
1653
1754
  policyViolations = (policyResult.violations || []);
1654
1755
  policyViolations = policyViolations.filter((v) => !ignoreFilter(v.file));
@@ -1889,6 +1990,14 @@ async function verifyCommand(options) {
1889
1990
  emitCanonicalVerifyJson({
1890
1991
  ...payload,
1891
1992
  expediteMode: expediteModeEnabled,
1993
+ // Intent engine results injected so every code-path gets them.
1994
+ intentIssues: payload.intentIssues ?? intentEngineIssues,
1995
+ intentDomains: payload.intentDomains ?? intentEngineDomains,
1996
+ intentSummary: payload.intentSummary ?? intentEngineSummary,
1997
+ // V5: flow issues injected alongside intent issues
1998
+ flowIssues: payload.flowIssues ?? intentEngineFlowIssues,
1999
+ // V6: regressions always injected
2000
+ regressions: payload.regressions ?? intentEngineRegressions,
1892
2001
  });
1893
2002
  };
1894
2003
  if (!isGitRepository(projectRoot)) {
@@ -1930,10 +2039,10 @@ async function verifyCommand(options) {
1930
2039
  const explicitStrictArtifactMode = options.strictArtifacts === true ||
1931
2040
  isEnabledFlag(process.env.NEURCODE_VERIFY_STRICT_ARTIFACTS) ||
1932
2041
  isEnabledFlag(process.env.NEURCODE_ENTERPRISE_MODE);
1933
- const ciEnterpriseDefaultStrict = process.env.CI === 'true'
1934
- && !isEnabledFlag(process.env.NEURCODE_VERIFY_ALLOW_NON_STRICT_CI)
1935
- && Boolean(options.apiKey || process.env.NEURCODE_API_KEY);
1936
- const strictArtifactMode = explicitStrictArtifactMode || ciEnterpriseDefaultStrict;
2042
+ // Strict artifact mode is only engaged when explicitly requested.
2043
+ // Auto-enabling it in CI based on API key presence masked real violations
2044
+ // by blocking early on missing artifacts before policy checks could run.
2045
+ const strictArtifactMode = explicitStrictArtifactMode;
1937
2046
  const runtimeGuardArtifactPath = (0, runtime_guard_1.resolveRuntimeGuardPath)(projectRoot, options.runtimeGuard);
1938
2047
  const autoRuntimeGuardInStrict = strictArtifactMode
1939
2048
  && (0, fs_1.existsSync)(runtimeGuardArtifactPath)
@@ -1999,38 +2108,57 @@ async function verifyCommand(options) {
1999
2108
  ]
2000
2109
  : [],
2001
2110
  };
2111
+ // Artifact presence warnings (advisory — missing artifacts fall back to runtime compilation).
2112
+ // These must never cause an early exit; real governance signal should always be evaluated.
2113
+ const artifactPresenceWarnings = [];
2002
2114
  if (strictArtifactMode) {
2003
- const strictErrors = [];
2004
2115
  if (!compiledPolicyRead.artifact) {
2005
- strictErrors.push(compiledPolicyRead.error
2116
+ artifactPresenceWarnings.push(compiledPolicyRead.error
2006
2117
  ? `Compiled policy artifact invalid (${compiledPolicyRead.error})`
2007
2118
  : `Compiled policy artifact missing (${compiledPolicyRead.path})`);
2008
2119
  }
2009
2120
  if (!changeContractRead.contract) {
2010
- strictErrors.push(changeContractRead.error
2121
+ artifactPresenceWarnings.push(changeContractRead.error
2011
2122
  ? `Change contract artifact invalid (${changeContractRead.error})`
2012
2123
  : `Change contract artifact missing (${changeContractRead.path})`);
2013
2124
  }
2014
- if (compiledPolicySignatureStatus
2015
- && !compiledPolicySignatureStatus.valid
2016
- && (requireSignedArtifacts || compiledPolicySignatureStatus.present)) {
2017
- strictErrors.push(`Compiled policy artifact signature validation failed (${compiledPolicySignatureStatus.issues.join('; ') || 'unknown issue'})`);
2125
+ if (!options.json && artifactPresenceWarnings.length > 0) {
2126
+ console.log(chalk.yellow('\n⚠️ Deterministic artifact(s) unavailable — falling back to runtime compilation'));
2127
+ artifactPresenceWarnings.forEach((entry) => {
2128
+ console.log(chalk.yellow(` ${entry}`));
2129
+ });
2130
+ console.log(chalk.dim(' Governance will continue using runtime compilation. Artifact checks are advisory.\n'));
2131
+ }
2132
+ }
2133
+ // Signature blocking distinguishes two cases:
2134
+ // - Artifact has a signature that is INVALID (present=true, valid=false): this is a tamper
2135
+ // indicator and blocks when requireSignedArtifacts is set.
2136
+ // - Artifact has NO signature (present=false): this is an unsigned artifact; advisory only,
2137
+ // never blocks — an unsigned artifact cannot be "tampered", only "not signed yet".
2138
+ if (strictArtifactMode) {
2139
+ const signatureBlockErrors = [];
2140
+ if (requireSignedArtifacts
2141
+ && compiledPolicySignatureStatus
2142
+ && compiledPolicySignatureStatus.present
2143
+ && !compiledPolicySignatureStatus.valid) {
2144
+ signatureBlockErrors.push(`Compiled policy artifact signature validation failed (${compiledPolicySignatureStatus.issues.join('; ') || 'unknown issue'})`);
2018
2145
  }
2019
- if (changeContractSignatureStatus
2020
- && !changeContractSignatureStatus.valid
2021
- && (requireSignedArtifacts || changeContractSignatureStatus.present)) {
2022
- strictErrors.push(`Change contract artifact signature validation failed (${changeContractSignatureStatus.issues.join('; ') || 'unknown issue'})`);
2146
+ if (requireSignedArtifacts
2147
+ && changeContractSignatureStatus
2148
+ && changeContractSignatureStatus.present
2149
+ && !changeContractSignatureStatus.valid) {
2150
+ signatureBlockErrors.push(`Change contract artifact signature validation failed (${changeContractSignatureStatus.issues.join('; ') || 'unknown issue'})`);
2023
2151
  }
2024
- if (strictErrors.length > 0) {
2025
- const message = `Strict artifact mode requires deterministic compiled-policy + change-contract artifacts.\n- ${strictErrors.join('\n- ')}`;
2152
+ if (signatureBlockErrors.length > 0) {
2153
+ const message = `Signed artifact enforcement failed tampered or invalid signatures detected.\n- ${signatureBlockErrors.join('\n- ')}`;
2026
2154
  if (options.json) {
2027
2155
  emitVerifyJson({
2028
2156
  grade: 'F',
2029
2157
  score: 0,
2030
2158
  verdict: 'FAIL',
2031
- violations: strictErrors.map((entry) => ({
2159
+ violations: signatureBlockErrors.map((entry) => ({
2032
2160
  file: entry.toLowerCase().includes('compiled policy') ? compiledPolicyRead.path : changeContractRead.path,
2033
- rule: 'deterministic_artifacts_required',
2161
+ rule: 'signed_artifacts_required',
2034
2162
  severity: 'block',
2035
2163
  message: entry,
2036
2164
  })),
@@ -2041,32 +2169,34 @@ async function verifyCommand(options) {
2041
2169
  totalPlannedFiles: 0,
2042
2170
  message,
2043
2171
  scopeGuardPassed: false,
2044
- mode: 'strict_artifacts_required',
2172
+ mode: 'signed_artifacts_required',
2045
2173
  policyOnly: options.policyOnly === true,
2046
2174
  changeContract: changeContractSummary,
2047
2175
  ...(compiledPolicyMetadata ? { policyCompilation: compiledPolicyMetadata } : {}),
2048
2176
  });
2049
2177
  }
2050
2178
  else {
2051
- (0, scope_telemetry_1.printScopeTelemetry)(chalk, scopeTelemetry, {
2052
- includeBlockedWarning: true,
2053
- });
2054
- console.log(chalk.red('\n⛔ Deterministic Artifact Requirements Failed'));
2055
- strictErrors.forEach((entry) => {
2179
+ (0, scope_telemetry_1.printScopeTelemetry)(chalk, scopeTelemetry, { includeBlockedWarning: true });
2180
+ console.log(chalk.red('\n⛔ Signed Artifact Validation Failed'));
2181
+ signatureBlockErrors.forEach((entry) => {
2056
2182
  console.log(chalk.red(` • ${entry}`));
2057
2183
  });
2058
- console.log(chalk.dim('\nSet --compiled-policy and --change-contract with valid artifacts before verify.'));
2059
- if (requireSignedArtifacts) {
2060
- console.log(chalk.dim('Enable signing keys via NEURCODE_GOVERNANCE_SIGNING_KEY or NEURCODE_GOVERNANCE_SIGNING_KEYS to generate signed artifacts.\n'));
2061
- }
2062
- else {
2063
- console.log('');
2064
- }
2184
+ console.log(chalk.dim('\nRegenerate artifacts with valid signing keys: NEURCODE_GOVERNANCE_SIGNING_KEY or NEURCODE_GOVERNANCE_SIGNING_KEYS.\n'));
2065
2185
  }
2066
2186
  process.exit(2);
2067
2187
  }
2188
+ // Advisory notice when artifact has a signature but signing is not required in this context.
2189
+ if (!options.json) {
2190
+ if (compiledPolicySignatureStatus && !compiledPolicySignatureStatus.valid && !requireSignedArtifacts) {
2191
+ console.log(chalk.yellow(` ⚠️ Compiled policy signature could not be verified (${compiledPolicySignatureStatus.issues.join('; ') || 'key unavailable'}) — advisory only`));
2192
+ }
2193
+ if (changeContractSignatureStatus && !changeContractSignatureStatus.valid && !requireSignedArtifacts) {
2194
+ console.log(chalk.yellow(` ⚠️ Change contract signature could not be verified (${changeContractSignatureStatus.issues.join('; ') || 'key unavailable'}) — advisory only`));
2195
+ }
2196
+ }
2068
2197
  }
2069
2198
  if (!strictArtifactMode && requireSignedArtifacts) {
2199
+ // Non-strict mode with signing required: same signature gate applies.
2070
2200
  const signatureErrors = [];
2071
2201
  if (compiledPolicyRead.artifact && compiledPolicySignatureStatus && !compiledPolicySignatureStatus.valid) {
2072
2202
  signatureErrors.push(`Compiled policy artifact signature validation failed (${compiledPolicySignatureStatus.issues.join('; ') || 'unknown issue'})`);
@@ -2101,13 +2231,9 @@ async function verifyCommand(options) {
2101
2231
  });
2102
2232
  }
2103
2233
  else {
2104
- (0, scope_telemetry_1.printScopeTelemetry)(chalk, scopeTelemetry, {
2105
- includeBlockedWarning: true,
2106
- });
2234
+ (0, scope_telemetry_1.printScopeTelemetry)(chalk, scopeTelemetry, { includeBlockedWarning: true });
2107
2235
  console.log(chalk.red('\n⛔ Signed Artifact Requirements Failed'));
2108
- signatureErrors.forEach((entry) => {
2109
- console.log(chalk.red(` • ${entry}`));
2110
- });
2236
+ signatureErrors.forEach((entry) => console.log(chalk.red(` • ${entry}`)));
2111
2237
  console.log(chalk.dim('\nEnable signing keys via NEURCODE_GOVERNANCE_SIGNING_KEY or NEURCODE_GOVERNANCE_SIGNING_KEYS and regenerate artifacts.\n'));
2112
2238
  }
2113
2239
  process.exit(2);
@@ -2145,9 +2271,6 @@ async function verifyCommand(options) {
2145
2271
  console.log(chalk.yellow(` Change contract signature: invalid (${changeContractSignatureStatus.issues.join('; ') || 'unknown issue'})`));
2146
2272
  }
2147
2273
  }
2148
- if (ciEnterpriseDefaultStrict && !explicitStrictArtifactMode) {
2149
- console.log(chalk.dim(' CI enterprise mode detected: strict deterministic artifact enforcement is auto-enabled (set NEURCODE_VERIFY_ALLOW_NON_STRICT_CI=1 to opt out).'));
2150
- }
2151
2274
  if (autoRuntimeGuardInStrict && !options.requireRuntimeGuard && !isEnabledFlag(process.env.NEURCODE_VERIFY_REQUIRE_RUNTIME_GUARD)) {
2152
2275
  console.log(chalk.dim(` Strict mode detected runtime guard artifact: auto-enforcing runtime guard (${runtimeGuardArtifactPath}).`));
2153
2276
  }
@@ -2912,6 +3035,11 @@ async function verifyCommand(options) {
2912
3035
  let governanceResult = null;
2913
3036
  let planFilesForVerification = [];
2914
3037
  let intentConstraintsForVerification;
3038
+ let intentEngineIssues = [];
3039
+ let intentEngineDomains = [];
3040
+ let intentEngineSummary = null;
3041
+ let intentEngineFlowIssues = [];
3042
+ let intentEngineRegressions = [];
2915
3043
  try {
2916
3044
  // Step A: Get Modified Files (already have from diffFiles)
2917
3045
  const modifiedFiles = diffFiles.map(f => f.path);
@@ -2955,6 +3083,23 @@ async function verifyCommand(options) {
2955
3083
  }
2956
3084
  planFilesForVerification = [...new Set([...planFiles, ...localPlanExpectedFiles])];
2957
3085
  intentConstraintsForVerification = originalIntent || undefined;
3086
+ // ── Intent-Aware Engine ─────────────────────────────────────────────
3087
+ // Run once we have both diffFiles and the resolved intent text.
3088
+ // Stored in outer scope so all emitCanonicalVerifyJson call sites can
3089
+ // include the result in their payloads without repeating the computation.
3090
+ if (intentConstraintsForVerification && diffFiles.length > 0) {
3091
+ try {
3092
+ const engineResult = (0, intent_engine_1.runIntentEngine)(intentConstraintsForVerification, diffFiles, projectRoot);
3093
+ intentEngineIssues = engineResult.intentIssues;
3094
+ intentEngineDomains = engineResult.checkedDomains;
3095
+ intentEngineSummary = engineResult.intentSummary;
3096
+ intentEngineFlowIssues = engineResult.flowIssues;
3097
+ intentEngineRegressions = engineResult.regressions;
3098
+ }
3099
+ catch {
3100
+ // Non-fatal: intent engine errors must never break verification
3101
+ }
3102
+ }
2958
3103
  governanceResult = (0, governance_1.evaluateGovernance)({
2959
3104
  projectRoot,
2960
3105
  task: governanceTask,
@@ -3058,6 +3203,9 @@ async function verifyCommand(options) {
3058
3203
  mode: 'plan_enforced',
3059
3204
  policyOnly: false,
3060
3205
  aiDebt: aiDebtSummaryForScope,
3206
+ intentIssues: intentEngineIssues,
3207
+ intentDomains: intentEngineDomains,
3208
+ intentSummary: intentEngineSummary,
3061
3209
  ...(expediteModeEnabled ? { expediteMode: true } : {}),
3062
3210
  ...(governanceResult
3063
3211
  ? buildGovernancePayload(governanceResult, orgGovernanceSettings, {
@@ -3133,6 +3281,42 @@ async function verifyCommand(options) {
3133
3281
  if (governanceResult) {
3134
3282
  displayGovernanceInsights(governanceResult, { explain: options.explain });
3135
3283
  }
3284
+ // ── Intent Status in scope-violation path ──────────────────────
3285
+ if (intentEngineSummary) {
3286
+ const s = intentEngineSummary;
3287
+ const domainLabel = s.domain.charAt(0).toUpperCase() + s.domain.slice(1);
3288
+ const confColor = s.confidence === 'HIGH' ? chalk.green : s.confidence === 'MEDIUM' ? chalk.yellow : chalk.red;
3289
+ const wCovPct = s.weightedCoverage != null ? Math.round(s.weightedCoverage * 100) : s.coveragePct;
3290
+ const filled = Math.round((wCovPct / 100) * 20);
3291
+ const bar = chalk.cyan('█'.repeat(filled)) + chalk.dim('░'.repeat(20 - filled));
3292
+ const sysStatus = s.status;
3293
+ const statusLabel = sysStatus === 'CRITICAL' ? chalk.bold.red('[CRITICAL]') : sysStatus === 'AT RISK' ? chalk.bold.yellow('[AT RISK]') : chalk.bold.green('[SECURE]');
3294
+ console.log(chalk.bold('\n━━━ INTENT STATUS ━━━━━━━━━━━━━━━━━━━━━━'));
3295
+ console.log(` ${statusLabel} ${chalk.bold(`${domainLabel} Implementation:`)} ${bar} ${chalk.bold(`${wCovPct}%`)} (weighted)`);
3296
+ console.log(` Confidence: ${confColor(s.confidence)}`);
3297
+ const critMissing = s.criticalMissing ?? [];
3298
+ const otherMissing = s.missing.filter((k) => !critMissing.includes(k));
3299
+ if (critMissing.length > 0) {
3300
+ console.log(` ${chalk.bold.red('Critical missing:')}`);
3301
+ critMissing.forEach((k) => { const label = k.split('-').map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' '); console.log(chalk.red(` ✗ ${label}`)); });
3302
+ }
3303
+ if (otherMissing.length > 0) {
3304
+ console.log(` ${chalk.bold.yellow('Missing:')}`);
3305
+ otherMissing.forEach((k) => { const label = k.split('-').map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' '); console.log(chalk.yellow(` • ${label}`)); });
3306
+ }
3307
+ if (critMissing.length === 0 && otherMissing.length === 0) {
3308
+ console.log(` Missing: ${chalk.green('none — all components detected')}`);
3309
+ }
3310
+ console.log(chalk.bold('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
3311
+ }
3312
+ if (intentEngineRegressions.length > 0) {
3313
+ console.log(chalk.bold.red('\n━━━ REGRESSION ANALYSIS ━━━━━━━━━━━━━━━━━'));
3314
+ intentEngineRegressions.forEach((reg) => {
3315
+ const icon = reg.type === 'coverage-regression' ? '📉' : reg.type === 'critical-regression' ? '🔴' : reg.type === 'flow-regression' ? '⛓' : '⚠';
3316
+ console.log(` ${chalk.red('[REGRESSION]')} ${icon} ${reg.message}`);
3317
+ });
3318
+ console.log(chalk.bold.red('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
3319
+ }
3136
3320
  console.log('');
3137
3321
  await recordVerificationIfRequested(options, config, {
3138
3322
  grade: 'F',
@@ -3523,6 +3707,9 @@ async function verifyCommand(options) {
3523
3707
  if (!options.json && effectiveRules.policyPack && effectiveRules.policyPackRules.length > 0) {
3524
3708
  console.log(chalk.dim(` Evaluating policy pack: ${effectiveRules.policyPack.packName} (${effectiveRules.policyPack.packId}@${effectiveRules.policyPack.version}, ${effectiveRules.policyPackRules.length} rule(s))`));
3525
3709
  }
3710
+ else if (!options.json && !effectiveRules.policyPack) {
3711
+ console.log(chalk.dim(' No policy pack installed — run `neurcode policy install <pack>` to add governance rules'));
3712
+ }
3526
3713
  // Prepare diff stats and changed files for API
3527
3714
  const diffStats = {
3528
3715
  totalAdded: summary.totalAdded,
@@ -3984,7 +4171,7 @@ async function verifyCommand(options) {
3984
4171
  message: effectiveMessage,
3985
4172
  bloatFiles: displayBloatFiles,
3986
4173
  bloatCount: displayBloatFiles.length,
3987
- }, policyViolations, expediteModeEnabled);
4174
+ }, policyViolations, expediteModeEnabled, intentEngineIssues, intentEngineSummary, intentEngineFlowIssues, intentEngineRegressions);
3988
4175
  if (governanceResult) {
3989
4176
  displayGovernanceInsights(governanceResult, { explain: options.explain });
3990
4177
  }
@@ -4514,15 +4701,69 @@ function displayChangeContractDrift(summary, options = { advisory: false }) {
4514
4701
  /**
4515
4702
  * Display verification results in a formatted report card
4516
4703
  */
4517
- function displayVerifyResults(result, policyViolations, expediteModeUsed = false) {
4518
- const verdictLabel = result.verdict === 'PASS'
4519
- ? chalk.green('PASS')
4704
+ function displayVerifyResults(result, policyViolations, expediteModeUsed = false, intentIssuesForDisplay = [], intentSummaryForDisplay = null, flowIssuesForDisplay = [], regressionsForDisplay = []) {
4705
+ // ── Header ────────────────────────────────────────────────────────────────
4706
+ const headerLabel = result.verdict === 'PASS'
4707
+ ? chalk.bold.green('\n✅ VERIFICATION PASSED')
4520
4708
  : result.verdict === 'WARN'
4521
- ? chalk.yellow('WARN ⚠️')
4522
- : chalk.red('FAIL ');
4523
- const plannedText = `${result.plannedFilesModified}/${result.totalPlannedFiles}`;
4524
- console.log(`\n${verdictLabel}`);
4525
- console.log(chalk.dim(`Plan adherence: ${plannedText} files (${result.adherenceScore}%)`));
4709
+ ? chalk.bold.yellow('\n⚠️ VERIFICATION PASSED WITH WARNINGS')
4710
+ : chalk.bold.red('\n❌ VERIFICATION FAILED');
4711
+ console.log(headerLabel);
4712
+ // ── Intent Status block ──────────────────────────────────────────────────
4713
+ if (intentSummaryForDisplay) {
4714
+ const s = intentSummaryForDisplay;
4715
+ const domainLabel = s.domain.charAt(0).toUpperCase() + s.domain.slice(1);
4716
+ const confColor = s.confidence === 'HIGH'
4717
+ ? chalk.green
4718
+ : s.confidence === 'MEDIUM'
4719
+ ? chalk.yellow
4720
+ : chalk.red;
4721
+ // V4: weighted coverage bar
4722
+ const wCovPct = s.weightedCoverage != null
4723
+ ? Math.round(s.weightedCoverage * 100)
4724
+ : s.coveragePct;
4725
+ const barWidth = 20;
4726
+ const filled = Math.round((wCovPct / 100) * barWidth);
4727
+ const bar = chalk.cyan('█'.repeat(filled)) + chalk.dim('░'.repeat(barWidth - filled));
4728
+ // V4: system status label
4729
+ const sysStatus = s.status;
4730
+ const statusLabel = sysStatus === 'CRITICAL'
4731
+ ? chalk.bold.red('[CRITICAL]')
4732
+ : sysStatus === 'AT RISK'
4733
+ ? chalk.bold.yellow('[AT RISK]')
4734
+ : chalk.bold.green('[SECURE]');
4735
+ console.log(chalk.bold('\n━━━ INTENT STATUS ━━━━━━━━━━━━━━━━━━━━━━'));
4736
+ console.log(` ${statusLabel} ${chalk.bold(`${domainLabel} Implementation:`)} ${bar} ${chalk.bold(`${wCovPct}%`)} (weighted)`);
4737
+ console.log(` Confidence: ${confColor(s.confidence)}`);
4738
+ if (s.foundList.length > 0) {
4739
+ const foundLabels = s.foundList
4740
+ .map((k) => k.split('-').map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' '))
4741
+ .slice(0, 4);
4742
+ console.log(` Found: ${chalk.green(foundLabels.join(', '))}${s.foundList.length > 4 ? chalk.dim(` +${s.foundList.length - 4} more`) : ''}`);
4743
+ }
4744
+ // V4: show critical missing and non-critical missing separately
4745
+ const critMissing = s.criticalMissing ?? [];
4746
+ const otherMissing = s.missing.filter((k) => !critMissing.includes(k));
4747
+ if (critMissing.length > 0) {
4748
+ console.log(` ${chalk.bold.red('Critical missing:')}`);
4749
+ critMissing.forEach((k) => {
4750
+ const label = k.split('-').map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
4751
+ console.log(chalk.red(` ✗ ${label}`));
4752
+ });
4753
+ }
4754
+ if (otherMissing.length > 0) {
4755
+ console.log(` ${chalk.bold.yellow('Missing:')}`);
4756
+ otherMissing.forEach((k) => {
4757
+ const label = k.split('-').map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
4758
+ console.log(chalk.yellow(` • ${label}`));
4759
+ });
4760
+ }
4761
+ if (critMissing.length === 0 && otherMissing.length === 0) {
4762
+ console.log(` Missing: ${chalk.green('none — all components detected')}`);
4763
+ }
4764
+ console.log(chalk.bold('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
4765
+ }
4766
+ // ── Triage items ──────────────────────────────────────────────────────────
4526
4767
  const maxBlockingItems = 20;
4527
4768
  const maxAdvisoryItems = 8;
4528
4769
  const maxExpediteItems = 12;
@@ -4580,6 +4821,31 @@ function displayVerifyResults(result, policyViolations, expediteModeUsed = false
4580
4821
  ];
4581
4822
  advisoryItems = [];
4582
4823
  }
4824
+ // ── Counts ────────────────────────────────────────────────────────────────
4825
+ console.log(blockingItems.length > 0
4826
+ ? chalk.red(`Blocking Issues: ${blockingItems.length}`)
4827
+ : chalk.dim('Blocking Issues: 0'));
4828
+ if (expediteModeUsed) {
4829
+ console.log(chalk.yellow(`Expedite Issues: ${expediteItems.length}`));
4830
+ }
4831
+ else {
4832
+ console.log(advisoryItems.length > 0
4833
+ ? chalk.yellow(`Advisory Issues: ${advisoryItems.length}`)
4834
+ : chalk.dim('Advisory Issues: 0'));
4835
+ }
4836
+ console.log(chalk.dim(`Plan adherence: ${result.plannedFilesModified}/${result.totalPlannedFiles} files (${result.adherenceScore}%)`));
4837
+ // ── Top issues ────────────────────────────────────────────────────────────
4838
+ const topIssues = [
4839
+ ...blockingItems,
4840
+ ...(expediteModeUsed ? expediteItems : advisoryItems),
4841
+ ].slice(0, 2);
4842
+ if (topIssues.length > 0) {
4843
+ console.log(chalk.bold('\nTop Issues:'));
4844
+ topIssues.forEach((item, i) => {
4845
+ console.log(` ${i + 1}. ${item.message} → ${chalk.cyan(item.file)}`);
4846
+ });
4847
+ }
4848
+ // ── Detailed lists ────────────────────────────────────────────────────────
4583
4849
  if (blockingItems.length > 0) {
4584
4850
  console.log(chalk.red(`\nBLOCKING (${blockingItems.length})`));
4585
4851
  blockingItems.slice(0, maxBlockingItems).forEach((item) => {
@@ -4612,21 +4878,56 @@ function displayVerifyResults(result, policyViolations, expediteModeUsed = false
4612
4878
  });
4613
4879
  console.log(chalk.dim(' Note: Expedite Mode used'));
4614
4880
  }
4615
- if (blockingItems.length === 0 && advisoryItems.length === 0 && expediteItems.length === 0) {
4616
- console.log(chalk.green('\nNo drift detected.'));
4881
+ // ── Intent issues ─────────────────────────────────────────────────────────
4882
+ if (intentIssuesForDisplay.length > 0) {
4883
+ console.log(chalk.magenta(`\nINTENT ISSUES (${intentIssuesForDisplay.length})`));
4884
+ intentIssuesForDisplay.forEach((issue) => {
4885
+ const label = issue.severity === 'high' ? chalk.red('[HIGH]') : chalk.yellow('[MEDIUM]');
4886
+ const typeLabel = issue.type === 'missing' ? 'Missing' : issue.type === 'misplaced' ? 'Misplaced' : 'Partial';
4887
+ console.log(` ${label} ${typeLabel}: ${issue.message}`);
4888
+ });
4617
4889
  }
4618
- const filesTouched = new Set([
4619
- ...blockingItems.map((item) => item.file),
4620
- ...advisoryItems.map((item) => item.file),
4621
- ...expediteItems.map((item) => item.file),
4622
- ]).size;
4623
- if (expediteModeUsed) {
4624
- console.log(chalk.dim(`\nSummary: ${blockingItems.length} blocking issues, ${expediteItems.length} expedite issues across ${filesTouched} files`));
4890
+ // ── Flow Validation ───────────────────────────────────────────────────────
4891
+ if (flowIssuesForDisplay.length > 0) {
4892
+ console.log(chalk.bold('\n━━━ FLOW VALIDATION ━━━━━━━━━━━━━━━━━━━━━'));
4893
+ flowIssuesForDisplay.forEach((issue) => {
4894
+ const label = issue.severity === 'high' ? chalk.red('[HIGH]') : chalk.yellow('[MEDIUM]');
4895
+ const typeIcon = issue.type === 'missing-flow' ? '⛓' : issue.type === 'misplaced-flow' ? '⚠' : '⊘';
4896
+ console.log(` ${label} ${typeIcon} ${issue.message}`);
4897
+ if (issue.files && issue.files.length > 0) {
4898
+ const display = issue.files.slice(0, 3);
4899
+ console.log(chalk.dim(` → ${display.join(', ')}${issue.files.length > 3 ? ` +${issue.files.length - 3} more` : ''}`));
4900
+ }
4901
+ });
4902
+ console.log(chalk.bold('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
4625
4903
  }
4626
- else {
4627
- console.log(chalk.dim(`\nSummary: ${blockingItems.length} blocking issues, ${advisoryItems.length} advisory issues across ${filesTouched} files`));
4904
+ // ── Regression Analysis ───────────────────────────────────────────────────
4905
+ if (regressionsForDisplay.length > 0) {
4906
+ console.log(chalk.bold.red('\n━━━ REGRESSION ANALYSIS ━━━━━━━━━━━━━━━━━'));
4907
+ regressionsForDisplay.forEach((reg) => {
4908
+ const icon = reg.type === 'coverage-regression' ? '📉' :
4909
+ reg.type === 'critical-regression' ? '🔴' :
4910
+ reg.type === 'flow-regression' ? '⛓' : '⚠';
4911
+ console.log(` ${chalk.red('[REGRESSION]')} ${icon} ${reg.message}`);
4912
+ });
4913
+ console.log(chalk.bold.red('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
4914
+ }
4915
+ const hasAnyIssue = blockingItems.length > 0 ||
4916
+ advisoryItems.length > 0 ||
4917
+ expediteItems.length > 0 ||
4918
+ intentIssuesForDisplay.length > 0 ||
4919
+ flowIssuesForDisplay.length > 0 ||
4920
+ regressionsForDisplay.length > 0;
4921
+ if (!hasAnyIssue) {
4922
+ console.log(chalk.green('\nNo issues detected.'));
4923
+ }
4924
+ // ── Next step ─────────────────────────────────────────────────────────────
4925
+ if (hasAnyIssue) {
4926
+ console.log(chalk.bold('\nNext step:'));
4927
+ console.log(` ${chalk.cyan('neurcode fix')}`);
4928
+ console.log(chalk.dim(' or: neurcode fix --apply-safe (auto-apply high-confidence patches)'));
4628
4929
  }
4629
- console.log(chalk.dim(`Details: ${result.message}\n`));
4930
+ console.log(chalk.dim(`\nDetails: ${result.message}\n`));
4630
4931
  }
4631
4932
  function printFirstRunAdvisoryMessage(demoMode) {
4632
4933
  console.log(chalk.cyan('\nNeurcode first-run advisory mode'));