@triedotdev/mcp 1.0.114 → 1.0.115
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/dist/{autonomy-config-O4H3Z7YV.js → autonomy-config-JXB7WCZ2.js} +2 -2
- package/dist/{chunk-DRDEEF6G.js → chunk-I2GFI3AM.js} +13 -1
- package/dist/chunk-I2GFI3AM.js.map +1 -0
- package/dist/{chunk-4SBZXIMG.js → chunk-ZYKEILVK.js} +364 -520
- package/dist/chunk-ZYKEILVK.js.map +1 -0
- package/dist/cli/main.js +7 -7
- package/dist/cli/yolo-daemon.js +1 -1
- package/dist/{goal-validator-7UPLOVAZ.js → goal-validator-T5HEYBC5.js} +39 -37
- package/dist/goal-validator-T5HEYBC5.js.map +1 -0
- package/dist/index.js +116 -59
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-4SBZXIMG.js.map +0 -1
- package/dist/chunk-DRDEEF6G.js.map +0 -1
- package/dist/goal-validator-7UPLOVAZ.js.map +0 -1
- /package/dist/{autonomy-config-O4H3Z7YV.js.map → autonomy-config-JXB7WCZ2.js.map} +0 -0
package/dist/cli/main.js
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
getAutonomyConfig,
|
|
4
|
-
recordBypass,
|
|
5
|
-
shouldAutoFix,
|
|
6
|
-
shouldBlockPush,
|
|
7
|
-
trackIssueOccurrence
|
|
8
|
-
} from "../chunk-DRDEEF6G.js";
|
|
9
2
|
import {
|
|
10
3
|
applyAutoFix
|
|
11
4
|
} from "../chunk-DJ2YAGHK.js";
|
|
@@ -22,6 +15,13 @@ import {
|
|
|
22
15
|
projectInfoExists,
|
|
23
16
|
saveConfig
|
|
24
17
|
} from "../chunk-TKMV7JKN.js";
|
|
18
|
+
import {
|
|
19
|
+
getAutonomyConfig,
|
|
20
|
+
recordBypass,
|
|
21
|
+
shouldAutoFix,
|
|
22
|
+
shouldBlockPush,
|
|
23
|
+
trackIssueOccurrence
|
|
24
|
+
} from "../chunk-I2GFI3AM.js";
|
|
25
25
|
import {
|
|
26
26
|
LearningEngine,
|
|
27
27
|
exportToJson,
|
package/dist/cli/yolo-daemon.js
CHANGED
|
@@ -7,54 +7,49 @@ import "./chunk-APMV77PU.js";
|
|
|
7
7
|
import "./chunk-DGUM43GV.js";
|
|
8
8
|
|
|
9
9
|
// src/guardian/goal-validator.ts
|
|
10
|
-
var
|
|
10
|
+
var REGEX_RULES = {
|
|
11
11
|
"no-emojis": {
|
|
12
|
-
pattern: /[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u,
|
|
12
|
+
pattern: /[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{FE00}-\u{FE0F}\u{200D}\u{1F1E0}-\u{1F1FF}\u{E0020}-\u{E007F}]/u,
|
|
13
13
|
description: "Contains emoji",
|
|
14
14
|
severity: "medium",
|
|
15
|
-
autoFixable: true
|
|
15
|
+
autoFixable: true,
|
|
16
|
+
keywords: /emoji/i
|
|
16
17
|
},
|
|
17
18
|
"no-console": {
|
|
18
|
-
pattern: /console\.(log|debug|info|warn|error)/,
|
|
19
|
+
pattern: /console\.(log|debug|info|warn|error)\s*\(/,
|
|
19
20
|
description: "Contains console statement",
|
|
20
21
|
severity: "low",
|
|
21
|
-
autoFixable: true
|
|
22
|
+
autoFixable: true,
|
|
23
|
+
keywords: /console/i
|
|
22
24
|
},
|
|
23
25
|
"no-debugger": {
|
|
24
26
|
pattern: /\bdebugger\b/,
|
|
25
27
|
description: "Contains debugger statement",
|
|
26
28
|
severity: "medium",
|
|
27
|
-
autoFixable: true
|
|
29
|
+
autoFixable: true,
|
|
30
|
+
keywords: /debugger/i
|
|
28
31
|
},
|
|
29
32
|
"no-todo": {
|
|
30
|
-
pattern:
|
|
33
|
+
pattern: /\/\/\s*(TODO|FIXME|XXX|HACK)\b/i,
|
|
31
34
|
description: "Contains TODO comment",
|
|
32
35
|
severity: "low",
|
|
33
|
-
autoFixable: false
|
|
36
|
+
autoFixable: false,
|
|
37
|
+
keywords: /todo|fixme/i
|
|
34
38
|
},
|
|
35
39
|
"no-any": {
|
|
36
40
|
pattern: /:\s*any\b/,
|
|
37
41
|
description: "Uses TypeScript any type",
|
|
38
42
|
severity: "medium",
|
|
39
|
-
autoFixable: false
|
|
43
|
+
autoFixable: false,
|
|
44
|
+
keywords: /\bany\b.*type/i
|
|
40
45
|
}
|
|
41
46
|
};
|
|
42
|
-
function
|
|
47
|
+
function matchGoalToRegexRule(goal) {
|
|
43
48
|
const desc = goal.description.toLowerCase();
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return "no-console";
|
|
49
|
-
}
|
|
50
|
-
if (/no debugger|remove debugger/i.test(desc)) {
|
|
51
|
-
return "no-debugger";
|
|
52
|
-
}
|
|
53
|
-
if (/no (todo|fixme)|clean.*todo/i.test(desc)) {
|
|
54
|
-
return "no-todo";
|
|
55
|
-
}
|
|
56
|
-
if (/no any|avoid any|typescript.*any/i.test(desc)) {
|
|
57
|
-
return "no-any";
|
|
49
|
+
for (const [key, rule] of Object.entries(REGEX_RULES)) {
|
|
50
|
+
if (rule.keywords.test(desc)) {
|
|
51
|
+
return key;
|
|
52
|
+
}
|
|
58
53
|
}
|
|
59
54
|
return null;
|
|
60
55
|
}
|
|
@@ -62,24 +57,30 @@ async function validateAgainstGoals(file, content, projectPath) {
|
|
|
62
57
|
const guardianState = getGuardianState(projectPath);
|
|
63
58
|
await guardianState.load();
|
|
64
59
|
const activeGoals = guardianState.getAllGoals().filter((g) => g.status === "active");
|
|
60
|
+
if (activeGoals.length === 0) {
|
|
61
|
+
return { violations: [], passedGoals: [] };
|
|
62
|
+
}
|
|
65
63
|
const violations = [];
|
|
66
64
|
const passedGoals = [];
|
|
67
65
|
for (const goal of activeGoals) {
|
|
68
|
-
const ruleKey =
|
|
69
|
-
if (!ruleKey)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (foundViolations.length > 0) {
|
|
75
|
-
violations.push(...foundViolations);
|
|
66
|
+
const ruleKey = matchGoalToRegexRule(goal);
|
|
67
|
+
if (!ruleKey) continue;
|
|
68
|
+
const rule = REGEX_RULES[ruleKey];
|
|
69
|
+
const found = findRegexViolations(file, content, goal, rule);
|
|
70
|
+
if (found.length > 0) {
|
|
71
|
+
violations.push(...found);
|
|
76
72
|
} else {
|
|
77
73
|
passedGoals.push(goal);
|
|
78
74
|
}
|
|
79
75
|
}
|
|
80
76
|
return { violations, passedGoals };
|
|
81
77
|
}
|
|
82
|
-
function
|
|
78
|
+
async function getActiveGoals(projectPath) {
|
|
79
|
+
const guardianState = getGuardianState(projectPath);
|
|
80
|
+
await guardianState.load();
|
|
81
|
+
return guardianState.getAllGoals().filter((g) => g.status === "active");
|
|
82
|
+
}
|
|
83
|
+
function findRegexViolations(file, content, goal, rule) {
|
|
83
84
|
const violations = [];
|
|
84
85
|
const lines = content.split("\n");
|
|
85
86
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -106,12 +107,12 @@ function findViolations(file, content, goal, rule) {
|
|
|
106
107
|
return violations;
|
|
107
108
|
}
|
|
108
109
|
function generateFixAction(violation, originalLine, lineNumber) {
|
|
109
|
-
const {
|
|
110
|
+
const { goal } = violation;
|
|
110
111
|
let type;
|
|
111
112
|
let fixedLine;
|
|
112
113
|
if (/emoji/i.test(goal.description)) {
|
|
113
114
|
type = "remove-emoji";
|
|
114
|
-
fixedLine = originalLine.replace(/[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/gu, "");
|
|
115
|
+
fixedLine = originalLine.replace(/[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{FE00}-\u{FE0F}\u{200D}\u{1F1E0}-\u{1F1FF}\u{E0020}-\u{E007F}]/gu, "");
|
|
115
116
|
} else if (/console/i.test(goal.description)) {
|
|
116
117
|
type = "remove-console-log";
|
|
117
118
|
fixedLine = "";
|
|
@@ -119,7 +120,7 @@ function generateFixAction(violation, originalLine, lineNumber) {
|
|
|
119
120
|
type = "remove-debugger";
|
|
120
121
|
fixedLine = "";
|
|
121
122
|
} else {
|
|
122
|
-
type = "
|
|
123
|
+
type = "goal-violation";
|
|
123
124
|
fixedLine = originalLine;
|
|
124
125
|
}
|
|
125
126
|
return {
|
|
@@ -177,8 +178,9 @@ async function recordGoalViolationFixed(goal, file, projectPath) {
|
|
|
177
178
|
}
|
|
178
179
|
}
|
|
179
180
|
export {
|
|
181
|
+
getActiveGoals,
|
|
180
182
|
recordGoalViolationCaught,
|
|
181
183
|
recordGoalViolationFixed,
|
|
182
184
|
validateAgainstGoals
|
|
183
185
|
};
|
|
184
|
-
//# sourceMappingURL=goal-validator-
|
|
186
|
+
//# sourceMappingURL=goal-validator-T5HEYBC5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/guardian/goal-validator.ts"],"sourcesContent":["/**\n * Goal Validator - Offline regex-based validation of code against user goals\n * \n * This module provides fast, instant detection of common goal violations\n * using regex patterns. It runs on every file change with zero latency.\n * \n * AI-powered goal detection is handled by the watch mode's AI watcher\n * (autoScanFiles in watch.ts) which includes goals in its Claude prompt.\n * This module is the offline fallback / instant-catch layer.\n */\n\nimport type { Goal } from './guardian-state.js';\nimport { getGuardianState } from './guardian-state.js';\nimport type { AutoFixAction } from '../types/autonomy.js';\n\nexport interface GoalViolation {\n goal: Goal;\n file: string;\n line?: number;\n column?: number;\n violation: string;\n description: string;\n severity: 'critical' | 'high' | 'medium' | 'low';\n autoFixable: boolean;\n fixAction?: AutoFixAction;\n}\n\nexport interface ValidationResult {\n violations: GoalViolation[];\n passedGoals: Goal[];\n}\n\nconst REGEX_RULES: Record<string, {\n pattern: RegExp;\n description: string;\n severity: 'critical' | 'high' | 'medium' | 'low';\n autoFixable: boolean;\n keywords: RegExp;\n}> = {\n 'no-emojis': {\n pattern: /[\\u{1F300}-\\u{1F9FF}\\u{2600}-\\u{26FF}\\u{2700}-\\u{27BF}\\u{FE00}-\\u{FE0F}\\u{200D}\\u{1F1E0}-\\u{1F1FF}\\u{E0020}-\\u{E007F}]/u,\n description: 'Contains emoji',\n severity: 'medium',\n autoFixable: true,\n keywords: /emoji/i,\n },\n 'no-console': {\n pattern: /console\\.(log|debug|info|warn|error)\\s*\\(/,\n description: 'Contains console statement',\n severity: 'low',\n autoFixable: true,\n keywords: /console/i,\n },\n 'no-debugger': {\n pattern: /\\bdebugger\\b/,\n description: 'Contains debugger statement',\n severity: 'medium',\n autoFixable: true,\n keywords: /debugger/i,\n },\n 'no-todo': {\n pattern: /\\/\\/\\s*(TODO|FIXME|XXX|HACK)\\b/i,\n description: 'Contains TODO comment',\n severity: 'low',\n autoFixable: false,\n keywords: /todo|fixme/i,\n },\n 'no-any': {\n pattern: /:\\s*any\\b/,\n description: 'Uses TypeScript any type',\n severity: 'medium',\n autoFixable: false,\n keywords: /\\bany\\b.*type/i,\n },\n};\n\nfunction matchGoalToRegexRule(goal: Goal): string | null {\n const desc = goal.description.toLowerCase();\n for (const [key, rule] of Object.entries(REGEX_RULES)) {\n if (rule.keywords.test(desc)) {\n return key;\n }\n }\n return null;\n}\n\n/**\n * Fast offline validation using regex patterns only.\n * AI-powered detection is handled by the AI watcher in watch.ts.\n */\nexport async function validateAgainstGoals(\n file: string,\n content: string,\n projectPath: string\n): Promise<ValidationResult> {\n const guardianState = getGuardianState(projectPath);\n await guardianState.load();\n \n const activeGoals = guardianState.getAllGoals().filter(g => g.status === 'active');\n if (activeGoals.length === 0) {\n return { violations: [], passedGoals: [] };\n }\n\n const violations: GoalViolation[] = [];\n const passedGoals: Goal[] = [];\n\n for (const goal of activeGoals) {\n const ruleKey = matchGoalToRegexRule(goal);\n if (!ruleKey) continue;\n\n const rule = REGEX_RULES[ruleKey];\n const found = findRegexViolations(file, content, goal, rule);\n if (found.length > 0) {\n violations.push(...found);\n } else {\n passedGoals.push(goal);\n }\n }\n\n return { violations, passedGoals };\n}\n\n/**\n * Get active goals for a project (used by the AI watcher)\n */\nexport async function getActiveGoals(projectPath: string): Promise<Goal[]> {\n const guardianState = getGuardianState(projectPath);\n await guardianState.load();\n return guardianState.getAllGoals().filter(g => g.status === 'active');\n}\n\nfunction findRegexViolations(\n file: string,\n content: string,\n goal: Goal,\n rule: typeof REGEX_RULES[string]\n): GoalViolation[] {\n const violations: GoalViolation[] = [];\n const lines = content.split('\\n');\n \n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (!line) continue;\n \n const match = line.match(rule.pattern);\n if (match) {\n const violation: GoalViolation = {\n goal,\n file,\n line: i + 1,\n column: match.index,\n violation: match[0],\n description: `${rule.description}: \"${match[0]}\" (Goal: ${goal.description})`,\n severity: rule.severity,\n autoFixable: rule.autoFixable,\n };\n \n if (rule.autoFixable) {\n violation.fixAction = generateFixAction(violation, line, i + 1);\n }\n \n violations.push(violation);\n }\n }\n \n return violations;\n}\n\nfunction generateFixAction(\n violation: GoalViolation,\n originalLine: string,\n lineNumber: number\n): AutoFixAction {\n const { goal } = violation;\n \n let type: AutoFixAction['type'];\n let fixedLine: string;\n \n if (/emoji/i.test(goal.description)) {\n type = 'remove-emoji';\n fixedLine = originalLine.replace(/[\\u{1F300}-\\u{1F9FF}\\u{2600}-\\u{26FF}\\u{2700}-\\u{27BF}\\u{FE00}-\\u{FE0F}\\u{200D}\\u{1F1E0}-\\u{1F1FF}\\u{E0020}-\\u{E007F}]/gu, '');\n } else if (/console/i.test(goal.description)) {\n type = 'remove-console-log';\n fixedLine = '';\n } else if (/debugger/i.test(goal.description)) {\n type = 'remove-debugger';\n fixedLine = '';\n } else {\n type = 'goal-violation';\n fixedLine = originalLine;\n }\n \n return {\n id: `fix-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n file: violation.file,\n line: lineNumber,\n original: originalLine,\n fixed: fixedLine,\n type,\n category: 'goal-violation',\n description: `Fix goal violation: ${violation.description}`,\n confidence: 0.9,\n };\n}\n\nexport async function recordGoalViolationCaught(\n goal: Goal,\n file: string,\n projectPath: string\n): Promise<void> {\n const guardianState = getGuardianState(projectPath);\n await guardianState.load();\n \n const metadata = goal.metadata || {};\n const caughtCount = (metadata.caughtCount || 0) + 1;\n \n await guardianState.updateGoal(goal.id, {\n metadata: {\n ...metadata,\n caughtCount,\n lastCaught: new Date().toISOString(),\n lastCaughtFile: file,\n },\n });\n}\n\nexport async function recordGoalViolationFixed(\n goal: Goal,\n file: string,\n projectPath: string\n): Promise<void> {\n const guardianState = getGuardianState(projectPath);\n await guardianState.load();\n \n const metadata = goal.metadata || {};\n const caughtCount = (metadata.caughtCount || 0) + 1;\n const fixedCount = (metadata.fixedCount || 0) + 1;\n \n await guardianState.updateGoal(goal.id, {\n metadata: {\n ...metadata,\n caughtCount,\n fixedCount,\n lastFixed: new Date().toISOString(),\n lastFixedFile: file,\n },\n });\n \n if (goal.type === 'reduction') {\n const newValue = Math.max(0, goal.currentValue - 1);\n await guardianState.updateGoal(goal.id, {\n currentValue: newValue,\n });\n \n if (newValue <= goal.target) {\n await guardianState.updateGoal(goal.id, {\n status: 'achieved',\n achievedAt: new Date().toISOString(),\n });\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,9 @@ import {
|
|
|
19
19
|
projectInfoExists,
|
|
20
20
|
updateProjectSection
|
|
21
21
|
} from "./chunk-TKMV7JKN.js";
|
|
22
|
+
import {
|
|
23
|
+
getAutonomyConfig
|
|
24
|
+
} from "./chunk-I2GFI3AM.js";
|
|
22
25
|
import {
|
|
23
26
|
ExtractionPipeline,
|
|
24
27
|
InteractiveDashboard,
|
|
@@ -35,7 +38,7 @@ import {
|
|
|
35
38
|
getPrompt,
|
|
36
39
|
getSystemPrompt,
|
|
37
40
|
handleCheckpointTool
|
|
38
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-ZYKEILVK.js";
|
|
39
42
|
import "./chunk-AOFYU6T3.js";
|
|
40
43
|
import "./chunk-2SIFK7OW.js";
|
|
41
44
|
import "./chunk-DZREHOGW.js";
|
|
@@ -1133,7 +1136,6 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
1133
1136
|
]);
|
|
1134
1137
|
var TrieWatchTool = class _TrieWatchTool {
|
|
1135
1138
|
extractionPipeline = null;
|
|
1136
|
-
static DEFAULT_HOURLY_TOKEN_LIMIT = 5e4;
|
|
1137
1139
|
state = {
|
|
1138
1140
|
isRunning: false,
|
|
1139
1141
|
lastScan: /* @__PURE__ */ new Map(),
|
|
@@ -1149,7 +1151,7 @@ var TrieWatchTool = class _TrieWatchTool {
|
|
|
1149
1151
|
tokenBudget: {
|
|
1150
1152
|
used: 0,
|
|
1151
1153
|
windowStart: Date.now(),
|
|
1152
|
-
hourlyLimit:
|
|
1154
|
+
hourlyLimit: 5e4,
|
|
1153
1155
|
scansSaved: 0
|
|
1154
1156
|
},
|
|
1155
1157
|
cleanFiles: /* @__PURE__ */ new Map()
|
|
@@ -1373,9 +1375,7 @@ ${f.content.slice(0, 1e3)}`
|
|
|
1373
1375
|
}
|
|
1374
1376
|
}
|
|
1375
1377
|
}
|
|
1376
|
-
|
|
1377
|
-
this.autoScanFiles(files);
|
|
1378
|
-
}
|
|
1378
|
+
this.autoScanFiles(files);
|
|
1379
1379
|
await this.discoverPatternsFromIssues(projectPath);
|
|
1380
1380
|
const now = Date.now();
|
|
1381
1381
|
if (now - this.lastHypothesisCheck > _TrieWatchTool.HYPOTHESIS_CHECK_INTERVAL_MS) {
|
|
@@ -1415,12 +1415,12 @@ ${f.content.slice(0, 1e3)}`
|
|
|
1415
1415
|
*/
|
|
1416
1416
|
async checkGoalViolations(files, projectPath) {
|
|
1417
1417
|
try {
|
|
1418
|
-
const { validateAgainstGoals, recordGoalViolationCaught, recordGoalViolationFixed } = await import("./goal-validator-
|
|
1418
|
+
const { validateAgainstGoals, recordGoalViolationCaught, recordGoalViolationFixed } = await import("./goal-validator-T5HEYBC5.js");
|
|
1419
1419
|
const { appendIssuesToLedger } = await import("./ledger-SR6OEBLO.js");
|
|
1420
|
-
const { getAutonomyConfig } = await import("./autonomy-config-
|
|
1420
|
+
const { getAutonomyConfig: getAutonomyConfig2 } = await import("./autonomy-config-JXB7WCZ2.js");
|
|
1421
1421
|
const { applyAutoFix } = await import("./auto-fix-apply-PCAHWLXF.js");
|
|
1422
|
-
const
|
|
1423
|
-
const
|
|
1422
|
+
const config = await getAutonomyConfig2(projectPath);
|
|
1423
|
+
const outputMgr = getOutputManager();
|
|
1424
1424
|
for (const file of files) {
|
|
1425
1425
|
try {
|
|
1426
1426
|
const content = await readFile3(file, "utf-8");
|
|
@@ -1447,16 +1447,15 @@ ${f.content.slice(0, 1e3)}`
|
|
|
1447
1447
|
};
|
|
1448
1448
|
await appendIssuesToLedger([issue], projectPath);
|
|
1449
1449
|
await recordGoalViolationCaught(violation.goal, relativePath, projectPath);
|
|
1450
|
-
const nudgeMessage = `
|
|
1451
|
-
|
|
1450
|
+
const nudgeMessage = `Goal "${violation.goal.description}" violated: ${violation.violation} in ${basename2(file)}:${violation.line || "?"}`;
|
|
1451
|
+
outputMgr.nudge(
|
|
1452
1452
|
nudgeMessage,
|
|
1453
1453
|
violation.severity === "critical" ? "critical" : "warning",
|
|
1454
|
-
relativePath
|
|
1455
|
-
violation.severity === "critical" ? void 0 : 1e4
|
|
1454
|
+
relativePath
|
|
1456
1455
|
);
|
|
1457
1456
|
this.state.nudges.push({
|
|
1458
1457
|
file: basename2(file),
|
|
1459
|
-
message:
|
|
1458
|
+
message: nudgeMessage,
|
|
1460
1459
|
severity: violation.severity === "critical" ? "critical" : "high",
|
|
1461
1460
|
timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false })
|
|
1462
1461
|
});
|
|
@@ -1470,24 +1469,11 @@ ${f.content.slice(0, 1e3)}`
|
|
|
1470
1469
|
const fixed = await applyAutoFix(violation.fixAction);
|
|
1471
1470
|
if (fixed) {
|
|
1472
1471
|
await recordGoalViolationFixed(violation.goal, relativePath, projectPath);
|
|
1473
|
-
const fixMessage = `
|
|
1474
|
-
|
|
1475
|
-
fixMessage,
|
|
1476
|
-
"info",
|
|
1477
|
-
relativePath,
|
|
1478
|
-
5e3
|
|
1479
|
-
);
|
|
1472
|
+
const fixMessage = `Auto-fixed: ${violation.goal.description} violation in ${basename2(file)}`;
|
|
1473
|
+
outputMgr.nudge(fixMessage, "info", relativePath, 5e3);
|
|
1480
1474
|
if (!isInteractiveMode()) {
|
|
1481
1475
|
console.error(` [+] Fixed automatically`);
|
|
1482
1476
|
}
|
|
1483
|
-
const goalMeta = violation.goal.metadata || {};
|
|
1484
|
-
if (!isInteractiveMode()) {
|
|
1485
|
-
console.error(` [+] Goal progress: ${goalMeta.fixedCount || 1} violations caught and fixed`);
|
|
1486
|
-
}
|
|
1487
|
-
}
|
|
1488
|
-
} else if (violation.autoFixable) {
|
|
1489
|
-
if (!isInteractiveMode()) {
|
|
1490
|
-
console.error(` [i] Auto-fix available. Enable with: trie config set autoFix.enabled true`);
|
|
1491
1477
|
}
|
|
1492
1478
|
}
|
|
1493
1479
|
}
|
|
@@ -1500,15 +1486,11 @@ ${f.content.slice(0, 1e3)}`
|
|
|
1500
1486
|
});
|
|
1501
1487
|
}
|
|
1502
1488
|
} catch (error) {
|
|
1503
|
-
|
|
1504
|
-
console.error(` [!] Could not validate ${basename2(file)}: ${error}`);
|
|
1505
|
-
}
|
|
1489
|
+
outputMgr.log("warn", `Could not validate ${basename2(file)}: ${error}`);
|
|
1506
1490
|
}
|
|
1507
1491
|
}
|
|
1508
1492
|
} catch (error) {
|
|
1509
|
-
|
|
1510
|
-
console.error(` [!] Goal validation failed: ${error}`);
|
|
1511
|
-
}
|
|
1493
|
+
getOutputManager().log("warn", `Goal validation error: ${error}`);
|
|
1512
1494
|
}
|
|
1513
1495
|
}
|
|
1514
1496
|
/**
|
|
@@ -1654,9 +1636,11 @@ ${f.content.slice(0, 1e3)}`
|
|
|
1654
1636
|
}
|
|
1655
1637
|
}
|
|
1656
1638
|
}
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1639
|
+
// Defaults -- overridden by config when loaded
|
|
1640
|
+
aiWatcherCooldownMs = 3e4;
|
|
1641
|
+
cleanFileCooldownMs = 3e5;
|
|
1642
|
+
maxFilesPerScan = 5;
|
|
1643
|
+
maxCharsPerFile = 4e3;
|
|
1660
1644
|
/**
|
|
1661
1645
|
* Use the trie (context graph) to score how urgently a file needs scanning.
|
|
1662
1646
|
* Higher score = more worth spending tokens on.
|
|
@@ -1664,7 +1648,7 @@ ${f.content.slice(0, 1e3)}`
|
|
|
1664
1648
|
async scoreScanPriority(file, graph, projectPath) {
|
|
1665
1649
|
let score = 1;
|
|
1666
1650
|
const lastClean = this.state.cleanFiles.get(file);
|
|
1667
|
-
if (lastClean && Date.now() - lastClean <
|
|
1651
|
+
if (lastClean && Date.now() - lastClean < this.cleanFileCooldownMs) {
|
|
1668
1652
|
return 0;
|
|
1669
1653
|
}
|
|
1670
1654
|
const fileNode = await graph.getNode("file", join2(projectPath, file));
|
|
@@ -1693,14 +1677,32 @@ ${f.content.slice(0, 1e3)}`
|
|
|
1693
1677
|
this.state.tokenBudget.used += tokens;
|
|
1694
1678
|
}
|
|
1695
1679
|
/**
|
|
1696
|
-
* AI-powered
|
|
1697
|
-
*
|
|
1680
|
+
* AI-powered watcher -- the primary detection system.
|
|
1681
|
+
*
|
|
1682
|
+
* This is the single AI call that handles:
|
|
1683
|
+
* 1. Code review (bugs, security, logic errors)
|
|
1684
|
+
* 2. Goal violation detection (user-defined quality goals)
|
|
1685
|
+
*
|
|
1686
|
+
* When goals are active, files with goal violations bypass priority scoring
|
|
1687
|
+
* so violations are always caught. Throttled by cooldown + token budget.
|
|
1698
1688
|
*/
|
|
1699
1689
|
async autoScanFiles(files) {
|
|
1700
1690
|
if (!isAIAvailable()) return;
|
|
1701
1691
|
if (this.state.autoScanInProgress) return;
|
|
1702
1692
|
const now = Date.now();
|
|
1703
|
-
if (now - this.state.lastAutoScan <
|
|
1693
|
+
if (now - this.state.lastAutoScan < this.aiWatcherCooldownMs) return;
|
|
1694
|
+
try {
|
|
1695
|
+
const projectPath = getWorkingDirectory(void 0, true);
|
|
1696
|
+
const config = await getAutonomyConfig(projectPath);
|
|
1697
|
+
const wc = config.aiWatcher;
|
|
1698
|
+
if (!wc.enabled) return;
|
|
1699
|
+
this.state.tokenBudget.hourlyLimit = wc.hourlyTokenLimit;
|
|
1700
|
+
this.aiWatcherCooldownMs = wc.scanCooldownSec * 1e3;
|
|
1701
|
+
this.cleanFileCooldownMs = wc.cleanFileCooldownSec * 1e3;
|
|
1702
|
+
this.maxFilesPerScan = wc.maxFilesPerScan;
|
|
1703
|
+
this.maxCharsPerFile = wc.maxCharsPerFile;
|
|
1704
|
+
} catch {
|
|
1705
|
+
}
|
|
1704
1706
|
const remaining = this.getRemainingBudget();
|
|
1705
1707
|
if (remaining < 500) return;
|
|
1706
1708
|
this.state.autoScanInProgress = true;
|
|
@@ -1708,6 +1710,11 @@ ${f.content.slice(0, 1e3)}`
|
|
|
1708
1710
|
try {
|
|
1709
1711
|
const projectPath = getWorkingDirectory(void 0, true);
|
|
1710
1712
|
const graph = new ContextGraph(projectPath);
|
|
1713
|
+
const { getActiveGoals, recordGoalViolationCaught } = await import("./goal-validator-T5HEYBC5.js");
|
|
1714
|
+
const { appendIssuesToLedger } = await import("./ledger-SR6OEBLO.js");
|
|
1715
|
+
const activeGoals = await getActiveGoals(projectPath);
|
|
1716
|
+
const hasGoals = activeGoals.length > 0;
|
|
1717
|
+
if (this.isQuiet() && !hasGoals) return;
|
|
1711
1718
|
const scored = [];
|
|
1712
1719
|
for (const file of files) {
|
|
1713
1720
|
const relativePath = file.replace(projectPath + "/", "");
|
|
@@ -1720,13 +1727,15 @@ ${f.content.slice(0, 1e3)}`
|
|
|
1720
1727
|
}
|
|
1721
1728
|
if (scored.length === 0) return;
|
|
1722
1729
|
scored.sort((a, b) => b.score - a.score);
|
|
1723
|
-
const
|
|
1724
|
-
const
|
|
1730
|
+
const budgetScale = remaining > 2e4 ? 1 : remaining > 1e4 ? 0.6 : 0.4;
|
|
1731
|
+
const maxFiles = Math.max(1, Math.round(this.maxFilesPerScan * budgetScale));
|
|
1732
|
+
const filesToScan = scored.slice(0, maxFiles);
|
|
1733
|
+
const charLimit = Math.round(this.maxCharsPerFile * (remaining > 15e3 ? 1 : 0.5));
|
|
1725
1734
|
const fileContents = await Promise.all(
|
|
1726
|
-
|
|
1735
|
+
filesToScan.map(async ({ file, relativePath }) => {
|
|
1727
1736
|
try {
|
|
1728
1737
|
const content = await readFile3(file, "utf-8");
|
|
1729
|
-
return { path: relativePath, content: content.slice(0,
|
|
1738
|
+
return { path: relativePath, content: content.slice(0, charLimit) };
|
|
1730
1739
|
} catch {
|
|
1731
1740
|
return null;
|
|
1732
1741
|
}
|
|
@@ -1740,22 +1749,37 @@ ${f.content.slice(0, 1e3)}`
|
|
|
1740
1749
|
${f.content}
|
|
1741
1750
|
\`\`\``
|
|
1742
1751
|
).join("\n\n");
|
|
1752
|
+
let goalsSection = "";
|
|
1753
|
+
if (hasGoals) {
|
|
1754
|
+
goalsSection = `
|
|
1755
|
+
USER-DEFINED GOALS (IMPORTANT - check EVERY file against ALL goals):
|
|
1756
|
+
${activeGoals.map((g, i) => ` ${i + 1}. "${g.description}"`).join("\n")}
|
|
1757
|
+
|
|
1758
|
+
Goal violations are HIGH PRIORITY. If a file violates any goal, you MUST report it.
|
|
1759
|
+
`;
|
|
1760
|
+
}
|
|
1743
1761
|
const result = await runAIAnalysis({
|
|
1744
|
-
systemPrompt: `You are a code
|
|
1762
|
+
systemPrompt: `You are a code quality watcher. You review code for two things:
|
|
1745
1763
|
|
|
1746
|
-
|
|
1764
|
+
1. CODE ISSUES: bugs, security vulnerabilities, logic errors, risky patterns
|
|
1765
|
+
2. GOAL VIOLATIONS: check every file against the user's quality goals
|
|
1766
|
+
${goalsSection}
|
|
1767
|
+
Reply ONLY with a JSON array. Each element must have:
|
|
1747
1768
|
- "file": relative file path
|
|
1748
1769
|
- "severity": "critical" | "major" | "minor"
|
|
1749
|
-
- "description": 1-sentence description
|
|
1770
|
+
- "description": 1-sentence description
|
|
1771
|
+
- "isGoalViolation": true if this violates a user goal, false otherwise
|
|
1772
|
+
- "goalIndex": 0-based index of the violated goal (only if isGoalViolation is true)
|
|
1750
1773
|
|
|
1751
|
-
If
|
|
1774
|
+
Be thorough with goal checking. If a goal says "no emojis" and you see an emoji anywhere in the file, report it. If a goal says "no inline styles" and you see a style attribute, report it.
|
|
1752
1775
|
|
|
1753
|
-
|
|
1754
|
-
|
|
1776
|
+
If no issues or violations found, reply with: []
|
|
1777
|
+
Output ONLY the JSON array, no markdown fences, no commentary.`,
|
|
1778
|
+
userPrompt: `Review these changed files:
|
|
1755
1779
|
|
|
1756
1780
|
${filesBlock}`,
|
|
1757
|
-
maxTokens:
|
|
1758
|
-
temperature: 0.
|
|
1781
|
+
maxTokens: 2048,
|
|
1782
|
+
temperature: 0.1
|
|
1759
1783
|
});
|
|
1760
1784
|
if (result.tokensUsed) {
|
|
1761
1785
|
this.recordTokenUsage(result.tokensUsed.input + result.tokensUsed.output);
|
|
@@ -1770,14 +1794,46 @@ ${filesBlock}`,
|
|
|
1770
1794
|
return;
|
|
1771
1795
|
}
|
|
1772
1796
|
const issuedFiles = new Set(issues.map((i) => i.file));
|
|
1773
|
-
for (const { relativePath } of
|
|
1797
|
+
for (const { relativePath } of filesToScan) {
|
|
1774
1798
|
if (!issuedFiles.has(relativePath)) {
|
|
1775
1799
|
this.state.cleanFiles.set(relativePath, Date.now());
|
|
1776
1800
|
}
|
|
1777
1801
|
}
|
|
1778
1802
|
if (issues.length === 0) return;
|
|
1779
|
-
for (const issue of issues.slice(0,
|
|
1803
|
+
for (const issue of issues.slice(0, 10)) {
|
|
1780
1804
|
const severity = issue.severity === "critical" ? "critical" : issue.severity === "major" ? "major" : "minor";
|
|
1805
|
+
if (issue.isGoalViolation && issue.goalIndex != null && issue.goalIndex >= 0 && issue.goalIndex < activeGoals.length) {
|
|
1806
|
+
const goal = activeGoals[issue.goalIndex];
|
|
1807
|
+
const nudgeMsg = `Goal "${goal.description}" violated in ${issue.file}: ${issue.description}`;
|
|
1808
|
+
const ledgerIssue = {
|
|
1809
|
+
id: `goal-ai-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
1810
|
+
hash: "",
|
|
1811
|
+
file: issue.file,
|
|
1812
|
+
line: void 0,
|
|
1813
|
+
agent: "ai-watcher",
|
|
1814
|
+
severity: severity === "critical" ? "critical" : severity === "major" ? "high" : "medium",
|
|
1815
|
+
issue: nudgeMsg,
|
|
1816
|
+
fix: "Review and fix",
|
|
1817
|
+
category: "goal-violation",
|
|
1818
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1819
|
+
project: basename2(projectPath),
|
|
1820
|
+
resolved: false,
|
|
1821
|
+
resolvedAt: void 0
|
|
1822
|
+
};
|
|
1823
|
+
await appendIssuesToLedger([ledgerIssue], projectPath);
|
|
1824
|
+
await recordGoalViolationCaught(goal, issue.file, projectPath);
|
|
1825
|
+
getOutputManager().nudge(nudgeMsg, "warning", issue.file);
|
|
1826
|
+
this.state.nudges.push({
|
|
1827
|
+
file: basename2(issue.file),
|
|
1828
|
+
message: nudgeMsg,
|
|
1829
|
+
severity: "high",
|
|
1830
|
+
timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false })
|
|
1831
|
+
});
|
|
1832
|
+
if (!isInteractiveMode()) {
|
|
1833
|
+
console.error(` [!] Goal violation: ${nudgeMsg}`);
|
|
1834
|
+
}
|
|
1835
|
+
continue;
|
|
1836
|
+
}
|
|
1781
1837
|
const incident = await graph.addNode("incident", {
|
|
1782
1838
|
description: issue.description,
|
|
1783
1839
|
severity,
|
|
@@ -1803,7 +1859,7 @@ ${filesBlock}`,
|
|
|
1803
1859
|
this.state.totalIssuesFound++;
|
|
1804
1860
|
if (severity !== "minor") {
|
|
1805
1861
|
getOutputManager().nudge(
|
|
1806
|
-
|
|
1862
|
+
`${issue.description}`,
|
|
1807
1863
|
severity === "critical" ? "critical" : "warning",
|
|
1808
1864
|
issue.file,
|
|
1809
1865
|
severity === "critical" ? void 0 : 15e3
|
|
@@ -1824,7 +1880,8 @@ ${filesBlock}`,
|
|
|
1824
1880
|
questions: 0
|
|
1825
1881
|
});
|
|
1826
1882
|
}
|
|
1827
|
-
} catch {
|
|
1883
|
+
} catch (error) {
|
|
1884
|
+
getOutputManager().log("warn", `AI watcher error: ${error}`);
|
|
1828
1885
|
} finally {
|
|
1829
1886
|
this.state.autoScanInProgress = false;
|
|
1830
1887
|
}
|