pumuki-ast-hooks 5.6.5 → 5.6.7

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 (26) hide show
  1. package/README.md +47 -10
  2. package/docs/images/ai-start.png +0 -0
  3. package/docs/images/pre-flight-check.png +0 -0
  4. package/hooks/pre-tool-use-guard.ts +105 -1
  5. package/package.json +1 -1
  6. package/scripts/hooks-system/.audit-reports/auto-recovery.log +3 -0
  7. package/scripts/hooks-system/.audit-reports/install-wizard.log +12 -0
  8. package/scripts/hooks-system/.audit_tmp/hook-metrics.jsonl +72 -0
  9. package/scripts/hooks-system/bin/__tests__/cli-audit-no-stack.spec.js +22 -0
  10. package/scripts/hooks-system/bin/cli.js +176 -7
  11. package/scripts/hooks-system/bin/update-evidence.sh +8 -0
  12. package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidSOLIDAnalyzer.js +33 -5
  13. package/scripts/hooks-system/infrastructure/ast/backend/ast-backend.js +7 -1
  14. package/scripts/hooks-system/infrastructure/ast/common/__tests__/ast-common.spec.js +19 -0
  15. package/scripts/hooks-system/infrastructure/ast/common/ast-common.js +24 -19
  16. package/scripts/hooks-system/infrastructure/ast/ios/__tests__/forbidden-testable-import.spec.js +21 -0
  17. package/scripts/hooks-system/infrastructure/ast/ios/__tests__/missing-makesut-leaks.spec.js +64 -0
  18. package/scripts/hooks-system/infrastructure/ast/ios/ast-ios.js +74 -33
  19. package/scripts/hooks-system/infrastructure/ast/ios/detectors/__tests__/ios-encapsulation-public-mutable.spec.js +63 -0
  20. package/scripts/hooks-system/infrastructure/ast/ios/detectors/__tests__/ios-unused-imports.spec.js +34 -0
  21. package/scripts/hooks-system/infrastructure/ast/ios/detectors/ios-ast-intelligent-strategies.js +15 -2
  22. package/scripts/hooks-system/infrastructure/mcp/__tests__/preflight-check-blocks-tests.spec.js +14 -0
  23. package/scripts/hooks-system/infrastructure/mcp/ast-intelligence-automation.js +154 -50
  24. package/scripts/hooks-system/infrastructure/orchestration/__tests__/intelligent-audit.spec.js +39 -1
  25. package/scripts/hooks-system/infrastructure/orchestration/intelligent-audit.js +67 -0
  26. package/scripts/hooks-system/infrastructure/watchdog/__tests__/.audit-reports/token-monitor.log +9 -0
@@ -858,20 +858,20 @@ async function loadPlatformRules(platforms) {
858
858
  const fullRulesContent = {};
859
859
 
860
860
  const ALL_RULE_FILES = [
861
- { key: 'gold', file: 'rulesgold.mdc', priority: 0 },
862
- { key: 'ios', file: 'rulesios.mdc', priority: 1 },
863
- { key: 'android', file: 'rulesandroid.mdc', priority: 1 },
864
- { key: 'backend', file: 'rulesbackend.mdc', priority: 1 },
865
- { key: 'frontend', file: 'rulesfront.mdc', priority: 1 }
861
+ { platform: 'gold', file: 'rulesgold.mdc', priority: 0 },
862
+ { platform: 'ios', file: 'rulesios.mdc', priority: 1 },
863
+ { platform: 'android', file: 'rulesandroid.mdc', priority: 1 },
864
+ { platform: 'backend', file: 'rulesbackend.mdc', priority: 1 },
865
+ { platform: 'frontend', file: 'rulesfront.mdc', priority: 1 }
866
866
  ];
867
867
 
868
868
  for (const ruleFile of ALL_RULE_FILES) {
869
869
  try {
870
870
  const content = await loader.loadRule(ruleFile.file);
871
871
  if (content) {
872
- rules[ruleFile.key] = true;
873
- fullRulesContent[ruleFile.key] = content;
874
- const criticalPatterns = extractCriticalPatterns(content, ruleFile.key);
872
+ rules[ruleFile.platform] = true;
873
+ fullRulesContent[ruleFile.platform] = content;
874
+ const criticalPatterns = extractCriticalPatterns(content, ruleFile.platform);
875
875
  criticalRules.push(...criticalPatterns);
876
876
  }
877
877
  } catch (error) {
@@ -1157,6 +1157,7 @@ async function aiGateCheck() {
1157
1157
  const gateTimeoutMs = Number(process.env.MCP_GATE_TIMEOUT_MS || 1200);
1158
1158
  const strict = process.env.MCP_GATE_STRICT === 'true';
1159
1159
  const allowEvidenceAutofix = process.env.MCP_GATE_AUTOFIX_EVIDENCE === 'true';
1160
+ const blockProtectedBranches = process.env.MCP_GATE_BLOCK_PROTECTED_BRANCHES !== 'false';
1160
1161
 
1161
1162
  const core = async () => {
1162
1163
  const gitFlowService = getCompositionRoot().getGitFlowService();
@@ -1173,7 +1174,22 @@ async function aiGateCheck() {
1173
1174
  process.stderr.write(`[MCP] Gate gitQuery.getUncommittedChanges failed: ${msg}\n`);
1174
1175
  }
1175
1176
  }
1176
- const hasUncommittedChanges = Array.isArray(uncommittedChanges) && uncommittedChanges.length > 0;
1177
+ const hasUncommittedChanges = Array.isArray(uncommittedChanges)
1178
+ ? uncommittedChanges.length > 0
1179
+ : typeof uncommittedChanges === 'string'
1180
+ ? uncommittedChanges.trim().length > 0
1181
+ : Boolean(uncommittedChanges);
1182
+
1183
+ let stagedFiles = [];
1184
+ try {
1185
+ stagedFiles = gitQuery.getStagedFiles();
1186
+ } catch (error) {
1187
+ const msg = error && error.message ? error.message : String(error);
1188
+ if (process.env.DEBUG) {
1189
+ process.stderr.write(`[MCP] Gate gitQuery.getStagedFiles failed: ${msg}\n`);
1190
+ }
1191
+ }
1192
+ const hasStagedChanges = Array.isArray(stagedFiles) && stagedFiles.length > 0;
1177
1193
 
1178
1194
  const violations = [];
1179
1195
  const warnings = [];
@@ -1210,11 +1226,15 @@ async function aiGateCheck() {
1210
1226
  }
1211
1227
 
1212
1228
  if (isProtectedBranch) {
1213
- if (hasUncommittedChanges) {
1214
- violations.push(`❌ ON_PROTECTED_BRANCH: You are on '${currentBranch}' with uncommitted changes.`);
1215
- violations.push(` Required: create a feature branch first.`);
1229
+ if (blockProtectedBranches && (hasUncommittedChanges || hasStagedChanges)) {
1230
+ const reasons = [
1231
+ hasUncommittedChanges ? 'uncommitted changes' : null,
1232
+ hasStagedChanges ? `staged changes (${stagedFiles.length} file(s))` : null
1233
+ ].filter(Boolean).join(' + ');
1234
+ violations.push(`❌ ON_PROTECTED_BRANCH: You are on '${currentBranch}' with ${reasons}.`);
1235
+ violations.push(' Required: create a feature branch first (e.g., feature/<name>, fix/<name>, refactor/<name>) and move changes there.');
1216
1236
  } else {
1217
- warnings.push(`⚠️ ON_PROTECTED_BRANCH: You are on '${currentBranch}'. Create a feature branch before making changes.`);
1237
+ warnings.push(`⚠️ ON_PROTECTED_BRANCH: You are on '${currentBranch}'. Git Flow recommends working on a feature/fix branch.`);
1218
1238
  }
1219
1239
  }
1220
1240
 
@@ -1324,11 +1344,13 @@ async function aiGateCheck() {
1324
1344
 
1325
1345
  let humanIntent = null;
1326
1346
  let semanticSnapshot = null;
1347
+ let autoIntent = null;
1327
1348
  try {
1328
1349
  if (fs.existsSync(EVIDENCE_FILE)) {
1329
1350
  const evidence = JSON.parse(fs.readFileSync(EVIDENCE_FILE, 'utf8'));
1330
1351
  humanIntent = evidence.human_intent || null;
1331
1352
  semanticSnapshot = evidence.semantic_snapshot || null;
1353
+ autoIntent = evidence.auto_intent || null;
1332
1354
  }
1333
1355
  } catch (evidenceReadError) {
1334
1356
  if (process.env.DEBUG) {
@@ -1343,20 +1365,26 @@ async function aiGateCheck() {
1343
1365
  violations,
1344
1366
  warnings,
1345
1367
  autoFixes,
1346
- human_intent: humanIntent,
1347
- semantic_snapshot: semanticSnapshot,
1348
1368
  mandatory_rules: rulesLoadedSuccessfully
1349
1369
  ? { ...mandatoryRules, status: 'LOADED_OK' }
1350
1370
  : mandatoryRules,
1351
1371
  summary: finalBlocked
1352
- ? `🚫 BLOCKED: ${violations.length} violation(s). Fix before proceeding.`
1353
- : `🚦 ALLOWED: Gate passed. ${mandatoryRules.totalRulesCount} critical rules loaded and verified.`,
1372
+ ? `🚫 BLOCKED: ${violations.length} critical issue(s) detected.`
1373
+ : `✅ ALLOWED: Gate check passed with ${warnings.length} warning(s).`,
1354
1374
  instructions: finalBlocked
1355
- ? 'DO NOT proceed with user task. Announce violations and fix them first.'
1375
+ ? 'Fix violations before proceeding. Run ai-start if needed.'
1356
1376
  : `✅ ${mandatoryRules.totalRulesCount} RULES LOADED. Sample: ${mandatoryRules.rulesSample.slice(0, 2).join(' | ')}... Review ALL rules in mandatory_rules.criticalRules before ANY code generation.`,
1357
1377
  cognitive_context: humanIntent?.primary_goal
1358
1378
  ? `🎯 USER INTENT: ${humanIntent.primary_goal} (confidence: ${humanIntent.confidence_level || 'unset'})`
1359
- : null
1379
+ : null,
1380
+ human_intent: humanIntent,
1381
+ semantic_snapshot: semanticSnapshot,
1382
+ auto_intent: autoIntent,
1383
+ session: {
1384
+ id: gateSession.sessionId,
1385
+ checkCount: gateSession.checkCount,
1386
+ validFor: gateSession.GATE_VALIDITY_MS / 60000 + ' minutes'
1387
+ }
1360
1388
  };
1361
1389
  };
1362
1390
 
@@ -1425,7 +1453,6 @@ async function aiGateCheck() {
1425
1453
  gateSession.recordCheck(timeoutResult);
1426
1454
  return timeoutResult;
1427
1455
  }
1428
-
1429
1456
  /**
1430
1457
  * Read platform rules handler - returns critical rules for a specific platform
1431
1458
  */
@@ -1581,6 +1608,80 @@ function clearHumanIntent() {
1581
1608
  }
1582
1609
  }
1583
1610
 
1611
+ function proposeHumanIntentFromEvidence({ evidence, branch }) {
1612
+ const safeEvidence = (evidence && typeof evidence === 'object') ? evidence : {};
1613
+ const safeBranch = branch || safeEvidence.current_context?.current_branch || 'unknown';
1614
+ const branchLower = String(safeBranch).toLowerCase();
1615
+
1616
+ const detectedPlatforms = ['ios', 'android', 'backend', 'frontend']
1617
+ .filter(p => safeEvidence.platforms && safeEvidence.platforms[p] && safeEvidence.platforms[p].detected);
1618
+
1619
+ const gateStatus = safeEvidence.ai_gate?.status || safeEvidence.severity_metrics?.gate_status || 'unknown';
1620
+ const platformLabel = detectedPlatforms.length > 0 ? detectedPlatforms.join('+') : 'repo';
1621
+
1622
+ let primaryGoal = `Continue work on ${platformLabel} changes`;
1623
+ if (gateStatus === 'BLOCKED') {
1624
+ primaryGoal = `Unblock AI gate by fixing ${platformLabel} violations`;
1625
+ }
1626
+
1627
+ if (branchLower.startsWith('fix/') || branchLower.startsWith('bugfix/') || branchLower.startsWith('hotfix/')) {
1628
+ primaryGoal = gateStatus === 'BLOCKED'
1629
+ ? `Unblock AI gate by fixing ${platformLabel} violations (bugfix)`
1630
+ : `Fix ${platformLabel} issues on ${safeBranch}`;
1631
+ }
1632
+
1633
+ const secondary = [];
1634
+ if (gateStatus === 'BLOCKED') {
1635
+ secondary.push('Fix HIGH/CRITICAL violations first');
1636
+ }
1637
+ if (detectedPlatforms.includes('ios')) {
1638
+ secondary.push('Keep tests compliant (makeSUT + trackForMemoryLeaks)');
1639
+ }
1640
+
1641
+ const constraints = [];
1642
+ constraints.push('Do not bypass hooks (--no-verify)');
1643
+ constraints.push('Follow platform rules (rules*.mdc)');
1644
+
1645
+ const confidence = detectedPlatforms.length > 0 ? 'medium' : 'low';
1646
+
1647
+ return {
1648
+ primary_goal: primaryGoal,
1649
+ secondary_goals: secondary,
1650
+ non_goals: [],
1651
+ constraints,
1652
+ confidence_level: confidence,
1653
+ derived_from: {
1654
+ branch: safeBranch,
1655
+ platforms: detectedPlatforms,
1656
+ gate_status: gateStatus
1657
+ }
1658
+ };
1659
+ }
1660
+
1661
+ function suggestHumanIntent() {
1662
+ try {
1663
+ if (!fs.existsSync(EVIDENCE_FILE)) {
1664
+ return { success: false, error: '.AI_EVIDENCE.json not found' };
1665
+ }
1666
+
1667
+ const evidence = JSON.parse(fs.readFileSync(EVIDENCE_FILE, 'utf8'));
1668
+ const currentBranch = getCurrentGitBranch(REPO_ROOT);
1669
+ const proposed = proposeHumanIntentFromEvidence({ evidence, branch: currentBranch });
1670
+
1671
+ const suggestedCommand = `ast-hooks intent set --goal="${proposed.primary_goal}" --confidence=${proposed.confidence_level || 'medium'} --expires=24h`;
1672
+
1673
+ return {
1674
+ success: true,
1675
+ proposal_only: true,
1676
+ suggested_human_intent: proposed,
1677
+ suggested_cli_command: suggestedCommand,
1678
+ note: 'This does not modify .AI_EVIDENCE.json. Use set_human_intent or CLI intent set to apply.'
1679
+ };
1680
+ } catch (error) {
1681
+ return { success: false, error: `Failed to suggest intent: ${error.message}` };
1682
+ }
1683
+ }
1684
+
1584
1685
  /**
1585
1686
  * 🚀 REVOLUTIONARY: Pre-Flight Check - Validates code BEFORE writing it
1586
1687
  * Inspired by tdd-guard: https://www.brgr.one/blog/ai-coding-agents-tdd-enforcement
@@ -1605,17 +1706,7 @@ function preFlightCheck(params) {
1605
1706
 
1606
1707
  if (isTestFile) {
1607
1708
  rulesEnforcement.recordTestCreated(target_file);
1608
- return {
1609
- success: true,
1610
- allowed: true,
1611
- message: '✅ TEST FILE DETECTED - TDD cycle activated!',
1612
- tdd_status: {
1613
- active: true,
1614
- phase: 'RED',
1615
- instruction: 'Write the failing test first, then implement the code to make it pass (GREEN)'
1616
- },
1617
- session_state: rulesEnforcement.sessionState
1618
- };
1709
+ // Do not early return: allow AST analysis + severity blocking even on tests
1619
1710
  }
1620
1711
 
1621
1712
  const validation = rulesEnforcement.validateProposedAction(action_type, target_file, proposed_code);
@@ -1643,19 +1734,20 @@ function preFlightCheck(params) {
1643
1734
  const { analyzeCodeInMemory } = require('../ast/ast-core');
1644
1735
  astAnalysis = analyzeCodeInMemory(proposed_code, target_file);
1645
1736
 
1646
- if (astAnalysis.hasCritical) {
1737
+ if (astAnalysis.hasCritical || astAnalysis.hasHigh) {
1738
+ const blocking = astAnalysis.violations
1739
+ .filter(v => v.severity === 'CRITICAL' || v.severity === 'HIGH');
1647
1740
  return {
1648
1741
  success: false,
1649
1742
  allowed: false,
1650
1743
  blocked: true,
1651
- reason: '🚫 AST INTELLIGENCE BLOCKED: Critical violations detected in proposed code',
1652
- ast_violations: astAnalysis.violations,
1744
+ reason: '🚫 AST INTELLIGENCE BLOCKED: Critical/High violations detected in proposed code',
1745
+ ast_violations: blocking,
1653
1746
  ast_summary: astAnalysis.summary,
1654
1747
  tdd_status: validation.tddStatus,
1655
1748
  action_required: 'FIX_AST_VIOLATIONS',
1656
1749
  suggestion: 'Fix the following AST violations before proceeding:\n' +
1657
- astAnalysis.violations
1658
- .filter(v => v.severity === 'CRITICAL')
1750
+ blocking
1659
1751
  .map(v => ` ❌ ${v.ruleId}: ${v.message}`)
1660
1752
  .join('\n'),
1661
1753
  reminder: validation.reminder
@@ -2063,6 +2155,11 @@ async function handleMcpMessage(message) {
2063
2155
  description: '🎯 Clear/reset the human intent to empty state.',
2064
2156
  inputSchema: { type: 'object', properties: {} }
2065
2157
  },
2158
+ {
2159
+ name: 'suggest_human_intent',
2160
+ description: '💡 Propose a human intent based on current evidence and git context (does not modify .AI_EVIDENCE.json).',
2161
+ inputSchema: { type: 'object', properties: {} }
2162
+ },
2066
2163
  {
2067
2164
  name: 'pre_flight_check',
2068
2165
  description: '🚀 REVOLUTIONARY: Validate code BEFORE writing it. Enforces TDD cycle and checks for rule violations. Call this BEFORE any edit/create_file operation.',
@@ -2169,6 +2266,9 @@ async function handleMcpMessage(message) {
2169
2266
  case 'clear_human_intent':
2170
2267
  result = clearHumanIntent();
2171
2268
  break;
2269
+ case 'suggest_human_intent':
2270
+ result = suggestHumanIntent();
2271
+ break;
2172
2272
  case 'pre_flight_check':
2173
2273
  result = preFlightCheck(toolParams);
2174
2274
  break;
@@ -2213,24 +2313,28 @@ async function handleMcpMessage(message) {
2213
2313
  // Flag to track if MCP has been initialized
2214
2314
  let mcpInitialized = false;
2215
2315
 
2216
- // Start protocol handler
2217
- protocolHandler.start(async (message) => {
2218
- const response = await handleMcpMessage(message);
2316
+ if (require.main === module) {
2317
+ // Start protocol handler
2318
+ protocolHandler.start(async (message) => {
2319
+ const response = await handleMcpMessage(message);
2219
2320
 
2220
- // Start polling loops ONLY after receiving 'initialized' notification from Windsurf
2221
- if (!mcpInitialized && message.includes('"method":"initialized"')) {
2222
- mcpInitialized = true;
2223
- if (process.env.DEBUG) {
2224
- process.stderr.write(`[MCP] Received 'initialized' - starting background loops\n`);
2321
+ // Start polling loops ONLY after receiving 'initialized' notification from Windsurf
2322
+ if (!mcpInitialized && message.includes('"method":"initialized"')) {
2323
+ mcpInitialized = true;
2324
+ if (process.env.DEBUG) {
2325
+ process.stderr.write(`[MCP] Received 'initialized' - starting background loops\n`);
2326
+ }
2327
+ startPollingLoops();
2225
2328
  }
2226
- startPollingLoops();
2227
- }
2228
2329
 
2229
- return response;
2230
- });
2330
+ return response;
2331
+ });
2231
2332
 
2232
- if (process.env.DEBUG) {
2233
- process.stderr.write(`[MCP] Server ready for ${REPO_ROOT}\n`);
2333
+ if (process.env.DEBUG) {
2334
+ process.stderr.write(`[MCP] Server ready for ${REPO_ROOT}\n`);
2335
+ }
2336
+ } else {
2337
+ module.exports = { preFlightCheck };
2234
2338
  }
2235
2339
 
2236
2340
  /**
@@ -7,6 +7,38 @@ describe('intelligent-audit', () => {
7
7
  expect(mod).toBeDefined();
8
8
  });
9
9
 
10
+ describe('auto_intent layer (Auto Intent)', () => {
11
+ it('should have required auto_intent contract fields when generated', () => {
12
+ const autoIntent = {
13
+ generated_at: new Date().toISOString(),
14
+ derivation_source: 'auto:updateAIEvidence',
15
+ primary_goal: 'Continue work on backend changes',
16
+ secondary_goals: [],
17
+ constraints: ['Do not bypass hooks (--no-verify)'],
18
+ confidence_level: 'medium',
19
+ context: {
20
+ branch: 'feature/test',
21
+ base_branch: 'develop',
22
+ platforms: ['backend'],
23
+ staged_files_count: 0,
24
+ gate_status: 'PASSED',
25
+ is_protected_branch: false
26
+ },
27
+ recommended_next_actions: ['Proceed with planned work']
28
+ };
29
+
30
+ expect(autoIntent.generated_at).toBeDefined();
31
+ expect(autoIntent.derivation_source).toBe('auto:updateAIEvidence');
32
+ expect(autoIntent.primary_goal).toBeDefined();
33
+ expect(Array.isArray(autoIntent.secondary_goals)).toBe(true);
34
+ expect(Array.isArray(autoIntent.constraints)).toBe(true);
35
+ expect(autoIntent.confidence_level).toBeDefined();
36
+ expect(autoIntent.context).toBeDefined();
37
+ expect(Array.isArray(autoIntent.context.platforms)).toBe(true);
38
+ expect(Array.isArray(autoIntent.recommended_next_actions)).toBe(true);
39
+ });
40
+ });
41
+
10
42
  it('should have runIntelligentAudit function', () => {
11
43
  const mod = require('../intelligent-audit');
12
44
  expect(typeof mod.runIntelligentAudit).toBe('function');
@@ -218,7 +250,8 @@ describe('Cognitive Memory Layers', () => {
218
250
  },
219
251
  protocol_3_questions: { answered: true },
220
252
  human_intent: humanIntentOverride,
221
- semantic_snapshot: null
253
+ semantic_snapshot: null,
254
+ auto_intent: null
222
255
  });
223
256
 
224
257
  describe('human_intent layer (Intentional Memory)', () => {
@@ -365,11 +398,16 @@ describe('Cognitive Memory Layers', () => {
365
398
  semantic_snapshot: {
366
399
  generated_at: new Date().toISOString(),
367
400
  summary: { health_score: 100 }
401
+ },
402
+ auto_intent: {
403
+ generated_at: new Date().toISOString(),
404
+ primary_goal: 'Continue work on repo changes'
368
405
  }
369
406
  };
370
407
 
371
408
  expect(completeEvidence.human_intent).toBeDefined();
372
409
  expect(completeEvidence.semantic_snapshot).toBeDefined();
410
+ expect(completeEvidence.auto_intent).toBeDefined();
373
411
  });
374
412
  });
375
413
  });
@@ -72,6 +72,72 @@ function generateSemanticSnapshot(evidence, violations, gateResult) {
72
72
  };
73
73
  }
74
74
 
75
+ function generateAutoIntent(evidence, violations, gateResult, stagedFiles) {
76
+ const now = new Date();
77
+ const activePlatforms = Object.entries(evidence.platforms || {})
78
+ .filter(([, v]) => v.detected)
79
+ .map(([k]) => k);
80
+
81
+ const stagedDetected = Array.from(detectPlatformsFromStagedFiles(stagedFiles || []));
82
+ const platforms = Array.from(new Set([...(activePlatforms || []), ...(stagedDetected || [])]));
83
+
84
+ const gateStatus = gateResult && typeof gateResult === 'object'
85
+ ? (gateResult.passed ? 'PASSED' : 'FAILED')
86
+ : 'unknown';
87
+
88
+ const platformLabel = platforms.length > 0 ? platforms.join('+') : 'repo';
89
+
90
+ const branch = evidence.current_context?.current_branch || 'unknown';
91
+ const baseBranch = evidence.current_context?.base_branch || 'unknown';
92
+ const isProtected = Boolean(evidence.git_flow && evidence.git_flow.is_protected);
93
+
94
+ let primaryGoal = `Continue work on ${platformLabel} changes`;
95
+ if (gateStatus === 'FAILED') {
96
+ primaryGoal = `Unblock gate by fixing ${platformLabel} violations`;
97
+ }
98
+ if (isProtected) {
99
+ primaryGoal = `Create a feature branch for ${platformLabel} work (Git Flow)`;
100
+ }
101
+
102
+ const recommendedNextActions = [];
103
+ if (isProtected) {
104
+ recommendedNextActions.push('Create a feature/fix branch and move changes there');
105
+ }
106
+ if (gateStatus === 'FAILED') {
107
+ recommendedNextActions.push('Fix blocking violations (CRITICAL/HIGH) before proceeding');
108
+ }
109
+ if (Array.isArray(violations) && violations.length > 0) {
110
+ recommendedNextActions.push('Run audit and re-check gate after fixes');
111
+ }
112
+ if (recommendedNextActions.length === 0) {
113
+ recommendedNextActions.push('Proceed with planned work');
114
+ }
115
+
116
+ const constraints = [];
117
+ constraints.push('Do not bypass hooks (--no-verify)');
118
+ constraints.push('Follow platform rules (rules*.mdc)');
119
+
120
+ const confidence = platforms.length > 0 ? 'medium' : 'low';
121
+
122
+ return {
123
+ generated_at: now.toISOString(),
124
+ derivation_source: 'auto:updateAIEvidence',
125
+ primary_goal: primaryGoal,
126
+ secondary_goals: [],
127
+ constraints,
128
+ confidence_level: confidence,
129
+ context: {
130
+ branch,
131
+ base_branch: baseBranch,
132
+ platforms,
133
+ staged_files_count: Array.isArray(stagedFiles) ? stagedFiles.length : 0,
134
+ gate_status: gateStatus,
135
+ is_protected_branch: isProtected
136
+ },
137
+ recommended_next_actions: recommendedNextActions
138
+ };
139
+ }
140
+
75
141
  /**
76
142
  * Preserve or initialize human_intent layer.
77
143
  * This is the Intentional Memory Layer - set by human, preserved across updates.
@@ -755,6 +821,7 @@ async function updateAIEvidence(violations, gateResult, tokenUsage) {
755
821
 
756
822
  evidence.semantic_snapshot = generateSemanticSnapshot(evidence, violations, gateResult);
757
823
 
824
+ evidence.auto_intent = generateAutoIntent(evidence, violations, gateResult, stagedFiles);
758
825
  fs.writeFileSync(evidencePath, JSON.stringify(evidence, null, 2));
759
826
  console.log('[Intelligent Audit] ✅ .AI_EVIDENCE.json updated with complete format (ai_gate, severity_metrics, token_usage, git_flow, watchers, human_intent, semantic_snapshot)');
760
827
 
@@ -0,0 +1,9 @@
1
+ {"timestamp":"2026-01-11T00:41:24.435Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":10,"tokensUsed":100000,"maxTokens":1000000,"source":"realtime","stale":false},"context":{"message":"Result level=ok percent=10% used=100000/1000000 source=realtime"}}
2
+ {"timestamp":"2026-01-11T00:41:24.438Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"warning","percentUsed":91,"tokensUsed":910000,"maxTokens":1000000,"source":"fallback","stale":false},"context":{"message":"Result level=warning percent=91% used=910000/1000000 source=fallback"}}
3
+ {"timestamp":"2026-01-11T00:41:24.439Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"critical","percentUsed":98,"tokensUsed":980000,"maxTokens":1000000,"source":"realtime","stale":true},"context":{"message":"Result level=critical percent=98% used=980000/1000000 source=realtime (stale)"}}
4
+ {"timestamp":"2026-01-11T00:47:26.777Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":10,"tokensUsed":100000,"maxTokens":1000000,"source":"realtime","stale":false},"context":{"message":"Result level=ok percent=10% used=100000/1000000 source=realtime"}}
5
+ {"timestamp":"2026-01-11T00:47:26.780Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"warning","percentUsed":91,"tokensUsed":910000,"maxTokens":1000000,"source":"fallback","stale":false},"context":{"message":"Result level=warning percent=91% used=910000/1000000 source=fallback"}}
6
+ {"timestamp":"2026-01-11T00:47:26.780Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"critical","percentUsed":98,"tokensUsed":980000,"maxTokens":1000000,"source":"realtime","stale":true},"context":{"message":"Result level=critical percent=98% used=980000/1000000 source=realtime (stale)"}}
7
+ {"timestamp":"2026-01-11T00:48:11.264Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":10,"tokensUsed":100000,"maxTokens":1000000,"source":"realtime","stale":false},"context":{"message":"Result level=ok percent=10% used=100000/1000000 source=realtime"}}
8
+ {"timestamp":"2026-01-11T00:48:11.267Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"warning","percentUsed":91,"tokensUsed":910000,"maxTokens":1000000,"source":"fallback","stale":false},"context":{"message":"Result level=warning percent=91% used=910000/1000000 source=fallback"}}
9
+ {"timestamp":"2026-01-11T00:48:11.267Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"critical","percentUsed":98,"tokensUsed":980000,"maxTokens":1000000,"source":"realtime","stale":true},"context":{"message":"Result level=critical percent=98% used=980000/1000000 source=realtime (stale)"}}