pumuki-ast-hooks 5.6.4 → 5.6.6
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.
- package/README.md +48 -5
- package/docs/images/ai-start.png +0 -0
- package/docs/images/ai_gate.png +0 -0
- package/docs/images/pre-flight-check.png +0 -0
- package/hooks/pre-tool-use-guard.ts +105 -1
- package/package.json +2 -2
- package/scripts/hooks-system/.audit-reports/auto-recovery.log +3 -0
- package/scripts/hooks-system/.audit-reports/install-wizard.log +12 -0
- package/scripts/hooks-system/.audit_tmp/hook-metrics.jsonl +72 -0
- package/scripts/hooks-system/bin/__tests__/cli-audit-no-stack.spec.js +22 -0
- package/scripts/hooks-system/bin/cli.js +176 -7
- package/scripts/hooks-system/bin/update-evidence.sh +8 -0
- package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidSOLIDAnalyzer.js +33 -5
- package/scripts/hooks-system/infrastructure/ast/backend/ast-backend.js +7 -1
- package/scripts/hooks-system/infrastructure/ast/common/__tests__/ast-common.spec.js +19 -0
- package/scripts/hooks-system/infrastructure/ast/common/ast-common.js +24 -19
- package/scripts/hooks-system/infrastructure/ast/ios/__tests__/forbidden-testable-import.spec.js +21 -0
- package/scripts/hooks-system/infrastructure/ast/ios/__tests__/missing-makesut-leaks.spec.js +64 -0
- package/scripts/hooks-system/infrastructure/ast/ios/ast-ios.js +74 -33
- package/scripts/hooks-system/infrastructure/ast/ios/detectors/__tests__/ios-encapsulation-public-mutable.spec.js +63 -0
- package/scripts/hooks-system/infrastructure/ast/ios/detectors/__tests__/ios-unused-imports.spec.js +34 -0
- package/scripts/hooks-system/infrastructure/ast/ios/detectors/ios-ast-intelligent-strategies.js +15 -2
- package/scripts/hooks-system/infrastructure/mcp/__tests__/preflight-check-blocks-tests.spec.js +14 -0
- package/scripts/hooks-system/infrastructure/mcp/ast-intelligence-automation.js +154 -50
- package/scripts/hooks-system/infrastructure/orchestration/__tests__/intelligent-audit.spec.js +39 -1
- package/scripts/hooks-system/infrastructure/orchestration/intelligent-audit.js +67 -0
- 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
|
-
{
|
|
862
|
-
{
|
|
863
|
-
{
|
|
864
|
-
{
|
|
865
|
-
{
|
|
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.
|
|
873
|
-
fullRulesContent[ruleFile.
|
|
874
|
-
const criticalPatterns = extractCriticalPatterns(content, ruleFile.
|
|
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)
|
|
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
|
-
|
|
1215
|
-
|
|
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}'.
|
|
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}
|
|
1353
|
-
:
|
|
1372
|
+
? `🚫 BLOCKED: ${violations.length} critical issue(s) detected.`
|
|
1373
|
+
: `✅ ALLOWED: Gate check passed with ${warnings.length} warning(s).`,
|
|
1354
1374
|
instructions: finalBlocked
|
|
1355
|
-
? '
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2316
|
+
if (require.main === module) {
|
|
2317
|
+
// Start protocol handler
|
|
2318
|
+
protocolHandler.start(async (message) => {
|
|
2319
|
+
const response = await handleMcpMessage(message);
|
|
2219
2320
|
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
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
|
-
|
|
2230
|
-
});
|
|
2330
|
+
return response;
|
|
2331
|
+
});
|
|
2231
2332
|
|
|
2232
|
-
if (process.env.DEBUG) {
|
|
2233
|
-
|
|
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
|
/**
|
package/scripts/hooks-system/infrastructure/orchestration/__tests__/intelligent-audit.spec.js
CHANGED
|
@@ -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
|
|
package/scripts/hooks-system/infrastructure/watchdog/__tests__/.audit-reports/token-monitor.log
ADDED
|
@@ -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)"}}
|