@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/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,
@@ -3,7 +3,7 @@ import {
3
3
  InteractiveDashboard,
4
4
  StreamingManager,
5
5
  TrieScanTool
6
- } from "../chunk-4SBZXIMG.js";
6
+ } from "../chunk-ZYKEILVK.js";
7
7
  import "../chunk-AOFYU6T3.js";
8
8
  import "../chunk-2SIFK7OW.js";
9
9
  import "../chunk-DZREHOGW.js";
@@ -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 GOAL_RULES = {
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: /\b(TODO|FIXME|XXX|HACK)\b/i,
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 matchGoalToRule(goal) {
47
+ function matchGoalToRegexRule(goal) {
43
48
  const desc = goal.description.toLowerCase();
44
- if (/no emoji|remove emoji|emoji.*free/i.test(desc)) {
45
- return "no-emojis";
46
- }
47
- if (/no console|remove console|console.*free/i.test(desc)) {
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 = matchGoalToRule(goal);
69
- if (!ruleKey) {
70
- continue;
71
- }
72
- const rule = GOAL_RULES[ruleKey];
73
- const foundViolations = findViolations(file, content, goal, rule);
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 findViolations(file, content, goal, rule) {
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 { violation: match, goal } = violation;
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 = "custom";
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-7UPLOVAZ.js.map
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-4SBZXIMG.js";
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: _TrieWatchTool.DEFAULT_HOURLY_TOKEN_LIMIT,
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
- if (!this.isQuiet()) {
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-7UPLOVAZ.js");
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-O4H3Z7YV.js");
1420
+ const { getAutonomyConfig: getAutonomyConfig2 } = await import("./autonomy-config-JXB7WCZ2.js");
1421
1421
  const { applyAutoFix } = await import("./auto-fix-apply-PCAHWLXF.js");
1422
- const { getOutputManager: getOutputManager2 } = await import("./output-manager-BOTMXSND.js");
1423
- const config = await getAutonomyConfig(projectPath);
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 = `[Goal Violation] ${violation.goal.description}: ${violation.violation} in ${basename2(file)}`;
1451
- getOutputManager2().nudge(
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: `Goal "${violation.goal.description}" violated: ${violation.violation}`,
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 = `[Auto-Fixed] ${violation.goal.description} violation in ${basename2(file)}`;
1474
- getOutputManager2().nudge(
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
- if (!isInteractiveMode()) {
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
- if (!isInteractiveMode()) {
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
- static AUTO_SCAN_COOLDOWN_MS = 3e4;
1658
- static CLEAN_FILE_COOLDOWN_MS = 3e5;
1659
- // skip files clean-scanned in last 5 min
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 < _TrieWatchTool.CLEAN_FILE_COOLDOWN_MS) {
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 auto-scan, throttled by the trie.
1697
- * Uses context graph risk data to decide which files are worth spending tokens on.
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 < _TrieWatchTool.AUTO_SCAN_COOLDOWN_MS) return;
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 maxFiles = remaining > 2e4 ? 5 : remaining > 1e4 ? 3 : 1;
1724
- const toScan = scored.slice(0, maxFiles);
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
- toScan.map(async ({ file, relativePath }) => {
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, 3e3) };
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 reviewer. Analyze the changed files below for bugs, security issues, logic errors, or risky patterns.
1762
+ systemPrompt: `You are a code quality watcher. You review code for two things:
1745
1763
 
1746
- Reply ONLY with a JSON array of issues found. Each issue must have:
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 of the problem
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 there are no issues, reply with an empty array: []
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
- Do NOT include markdown fences or commentary. Output ONLY the JSON array.`,
1754
- userPrompt: `Review these recently changed files:
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: 1024,
1758
- temperature: 0.2
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 toScan) {
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, 5)) {
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
- `[!] ${issue.description}`,
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
  }