@triedotdev/mcp 1.0.113 → 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.
Files changed (75) hide show
  1. package/dist/auto-fix-apply-PCAHWLXF.js +10 -0
  2. package/dist/autonomy-config-JXB7WCZ2.js +30 -0
  3. package/dist/chunk-2GIAROBF.js +173 -0
  4. package/dist/chunk-2GIAROBF.js.map +1 -0
  5. package/dist/{chunk-33WL3D7A.js → chunk-2SIFK7OW.js} +7 -419
  6. package/dist/chunk-2SIFK7OW.js.map +1 -0
  7. package/dist/chunk-43X6JBEM.js +36 -0
  8. package/dist/chunk-43X6JBEM.js.map +1 -0
  9. package/dist/chunk-55DOQNHJ.js +772 -0
  10. package/dist/chunk-55DOQNHJ.js.map +1 -0
  11. package/dist/chunk-6LXSA2OZ.js +425 -0
  12. package/dist/chunk-6LXSA2OZ.js.map +1 -0
  13. package/dist/{chunk-SDS3UVFY.js → chunk-AOFYU6T3.js} +113 -559
  14. package/dist/chunk-AOFYU6T3.js.map +1 -0
  15. package/dist/{chunk-6QR6QZIX.js → chunk-D3EXBJE2.js} +25 -658
  16. package/dist/chunk-D3EXBJE2.js.map +1 -0
  17. package/dist/chunk-DJ2YAGHK.js +50 -0
  18. package/dist/chunk-DJ2YAGHK.js.map +1 -0
  19. package/dist/chunk-DZREHOGW.js +706 -0
  20. package/dist/chunk-DZREHOGW.js.map +1 -0
  21. package/dist/chunk-I2GFI3AM.js +340 -0
  22. package/dist/chunk-I2GFI3AM.js.map +1 -0
  23. package/dist/chunk-KRH642MT.js +947 -0
  24. package/dist/chunk-KRH642MT.js.map +1 -0
  25. package/dist/{chunk-QYOACM2C.js → chunk-MVNJPJBK.js} +22 -252
  26. package/dist/chunk-MVNJPJBK.js.map +1 -0
  27. package/dist/chunk-NS2MSZMB.js +394 -0
  28. package/dist/chunk-NS2MSZMB.js.map +1 -0
  29. package/dist/chunk-SWSK7ANT.js +340 -0
  30. package/dist/chunk-SWSK7ANT.js.map +1 -0
  31. package/dist/chunk-VRLMTOB6.js +566 -0
  32. package/dist/chunk-VRLMTOB6.js.map +1 -0
  33. package/dist/chunk-YR4BMGYO.js +130 -0
  34. package/dist/chunk-YR4BMGYO.js.map +1 -0
  35. package/dist/chunk-ZV2K6M7T.js +74 -0
  36. package/dist/chunk-ZV2K6M7T.js.map +1 -0
  37. package/dist/{chunk-2764KZZQ.js → chunk-ZYKEILVK.js} +451 -1069
  38. package/dist/chunk-ZYKEILVK.js.map +1 -0
  39. package/dist/cli/main.js +107 -375
  40. package/dist/cli/main.js.map +1 -1
  41. package/dist/cli/yolo-daemon.js +18 -8
  42. package/dist/cli/yolo-daemon.js.map +1 -1
  43. package/dist/client-7XZHCMD3.js +28 -0
  44. package/dist/client-7XZHCMD3.js.map +1 -0
  45. package/dist/{goal-manager-AP4LTE6U.js → goal-manager-LMS6ZJB7.js} +7 -3
  46. package/dist/goal-manager-LMS6ZJB7.js.map +1 -0
  47. package/dist/goal-validator-T5HEYBC5.js +186 -0
  48. package/dist/goal-validator-T5HEYBC5.js.map +1 -0
  49. package/dist/graph-U5JWSAB5.js +10 -0
  50. package/dist/graph-U5JWSAB5.js.map +1 -0
  51. package/dist/guardian-agent-EXP7APLC.js +25 -0
  52. package/dist/guardian-agent-EXP7APLC.js.map +1 -0
  53. package/dist/hypothesis-KGC3P54C.js +19 -0
  54. package/dist/hypothesis-KGC3P54C.js.map +1 -0
  55. package/dist/incident-index-PNIVT47T.js +11 -0
  56. package/dist/incident-index-PNIVT47T.js.map +1 -0
  57. package/dist/index.js +369 -43
  58. package/dist/index.js.map +1 -1
  59. package/dist/ledger-SR6OEBLO.js +15 -0
  60. package/dist/ledger-SR6OEBLO.js.map +1 -0
  61. package/dist/output-manager-BOTMXSND.js +13 -0
  62. package/dist/output-manager-BOTMXSND.js.map +1 -0
  63. package/dist/pattern-discovery-F7LU5K6E.js +8 -0
  64. package/dist/pattern-discovery-F7LU5K6E.js.map +1 -0
  65. package/package.json +1 -1
  66. package/dist/chunk-2764KZZQ.js.map +0 -1
  67. package/dist/chunk-33WL3D7A.js.map +0 -1
  68. package/dist/chunk-6JPPYG7F.js +0 -1813
  69. package/dist/chunk-6JPPYG7F.js.map +0 -1
  70. package/dist/chunk-6QR6QZIX.js.map +0 -1
  71. package/dist/chunk-QYOACM2C.js.map +0 -1
  72. package/dist/chunk-SDS3UVFY.js.map +0 -1
  73. package/dist/guardian-agent-XEYNG7RH.js +0 -18
  74. /package/dist/{goal-manager-AP4LTE6U.js.map → auto-fix-apply-PCAHWLXF.js.map} +0 -0
  75. /package/dist/{guardian-agent-XEYNG7RH.js.map → autonomy-config-JXB7WCZ2.js.map} +0 -0
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,
@@ -32,33 +35,31 @@ import {
32
35
  TrieQueryContextTool,
33
36
  TrieScanTool,
34
37
  TrieTellTool,
35
- getOutputManager,
36
38
  getPrompt,
37
39
  getSystemPrompt,
38
40
  handleCheckpointTool
39
- } from "./chunk-2764KZZQ.js";
40
- import "./chunk-SDS3UVFY.js";
41
+ } from "./chunk-ZYKEILVK.js";
42
+ import "./chunk-AOFYU6T3.js";
43
+ import "./chunk-2SIFK7OW.js";
44
+ import "./chunk-DZREHOGW.js";
45
+ import "./chunk-6LXSA2OZ.js";
41
46
  import {
42
47
  exportToJson,
43
48
  formatFriendlyError,
44
49
  importFromJson,
45
50
  isTrieInitialized,
46
51
  runShellCommandSync
47
- } from "./chunk-QYOACM2C.js";
52
+ } from "./chunk-MVNJPJBK.js";
48
53
  import {
49
- ContextGraph,
50
54
  findCrossProjectPatterns,
51
55
  getGlobalMemoryStats,
52
- isAIAvailable,
53
56
  listTrackedProjects,
54
- runAIAnalysis,
55
57
  searchGlobalPatterns
56
- } from "./chunk-6QR6QZIX.js";
57
- import "./chunk-IXO4G4D3.js";
58
+ } from "./chunk-D3EXBJE2.js";
58
59
  import {
59
- getSkillRegistry
60
- } from "./chunk-G76DYVGX.js";
61
- import "./chunk-33WL3D7A.js";
60
+ isAIAvailable,
61
+ runAIAnalysis
62
+ } from "./chunk-SWSK7ANT.js";
62
63
  import {
63
64
  findSimilarIssues,
64
65
  getMemoryStats,
@@ -66,13 +67,28 @@ import {
66
67
  markIssueResolved,
67
68
  purgeIssues,
68
69
  searchIssues
69
- } from "./chunk-6JPPYG7F.js";
70
+ } from "./chunk-55DOQNHJ.js";
71
+ import "./chunk-KRH642MT.js";
72
+ import "./chunk-F4NJ4CBP.js";
73
+ import "./chunk-IXO4G4D3.js";
74
+ import {
75
+ ContextGraph
76
+ } from "./chunk-NS2MSZMB.js";
77
+ import "./chunk-2GIAROBF.js";
78
+ import "./chunk-6NLHFIYA.js";
79
+ import "./chunk-ZV2K6M7T.js";
80
+ import {
81
+ getSkillRegistry
82
+ } from "./chunk-G76DYVGX.js";
83
+ import {
84
+ getOutputManager
85
+ } from "./chunk-VRLMTOB6.js";
86
+ import "./chunk-YR4BMGYO.js";
87
+ import "./chunk-43X6JBEM.js";
70
88
  import {
71
89
  getTrieDirectory,
72
90
  getWorkingDirectory
73
91
  } from "./chunk-R4AAPFXC.js";
74
- import "./chunk-F4NJ4CBP.js";
75
- import "./chunk-6NLHFIYA.js";
76
92
  import {
77
93
  isInteractiveMode
78
94
  } from "./chunk-APMV77PU.js";
@@ -1120,7 +1136,6 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([
1120
1136
  ]);
1121
1137
  var TrieWatchTool = class _TrieWatchTool {
1122
1138
  extractionPipeline = null;
1123
- static DEFAULT_HOURLY_TOKEN_LIMIT = 5e4;
1124
1139
  state = {
1125
1140
  isRunning: false,
1126
1141
  lastScan: /* @__PURE__ */ new Map(),
@@ -1136,7 +1151,7 @@ var TrieWatchTool = class _TrieWatchTool {
1136
1151
  tokenBudget: {
1137
1152
  used: 0,
1138
1153
  windowStart: Date.now(),
1139
- hourlyLimit: _TrieWatchTool.DEFAULT_HOURLY_TOKEN_LIMIT,
1154
+ hourlyLimit: 5e4,
1140
1155
  scansSaved: 0
1141
1156
  },
1142
1157
  cleanFiles: /* @__PURE__ */ new Map()
@@ -1144,6 +1159,9 @@ var TrieWatchTool = class _TrieWatchTool {
1144
1159
  watchers = /* @__PURE__ */ new Map();
1145
1160
  streamingManager = void 0;
1146
1161
  dashboard = void 0;
1162
+ lastHypothesisCheck = 0;
1163
+ static HYPOTHESIS_CHECK_INTERVAL_MS = 3e5;
1164
+ // Check every 5 minutes
1147
1165
  async execute(args) {
1148
1166
  const { action, directory, debounceMs = 1e3 } = args;
1149
1167
  switch (action) {
@@ -1309,6 +1327,8 @@ Detected changes in ${files.length} file(s):`);
1309
1327
  console.error("");
1310
1328
  }
1311
1329
  try {
1330
+ const projectPath = getWorkingDirectory(void 0, true);
1331
+ await this.checkGoalViolations(files, projectPath);
1312
1332
  if (this.extractionPipeline) {
1313
1333
  try {
1314
1334
  const fileContents = await Promise.all(
@@ -1355,8 +1375,12 @@ ${f.content.slice(0, 1e3)}`
1355
1375
  }
1356
1376
  }
1357
1377
  }
1358
- if (!this.isQuiet()) {
1359
- this.autoScanFiles(files);
1378
+ this.autoScanFiles(files);
1379
+ await this.discoverPatternsFromIssues(projectPath);
1380
+ const now = Date.now();
1381
+ if (now - this.lastHypothesisCheck > _TrieWatchTool.HYPOTHESIS_CHECK_INTERVAL_MS) {
1382
+ this.checkAndGenerateHypotheses(projectPath);
1383
+ this.lastHypothesisCheck = now;
1360
1384
  }
1361
1385
  if (this.streamingManager) {
1362
1386
  for (const file of files) {
@@ -1385,9 +1409,238 @@ ${f.content.slice(0, 1e3)}`
1385
1409
  return false;
1386
1410
  }
1387
1411
  }
1388
- static AUTO_SCAN_COOLDOWN_MS = 3e4;
1389
- static CLEAN_FILE_COOLDOWN_MS = 3e5;
1390
- // skip files clean-scanned in last 5 min
1412
+ /**
1413
+ * Check file changes against active user goals
1414
+ * If violations found: record to ledger, nudge user, auto-fix if enabled
1415
+ */
1416
+ async checkGoalViolations(files, projectPath) {
1417
+ try {
1418
+ const { validateAgainstGoals, recordGoalViolationCaught, recordGoalViolationFixed } = await import("./goal-validator-T5HEYBC5.js");
1419
+ const { appendIssuesToLedger } = await import("./ledger-SR6OEBLO.js");
1420
+ const { getAutonomyConfig: getAutonomyConfig2 } = await import("./autonomy-config-JXB7WCZ2.js");
1421
+ const { applyAutoFix } = await import("./auto-fix-apply-PCAHWLXF.js");
1422
+ const config = await getAutonomyConfig2(projectPath);
1423
+ const outputMgr = getOutputManager();
1424
+ for (const file of files) {
1425
+ try {
1426
+ const content = await readFile3(file, "utf-8");
1427
+ const result = await validateAgainstGoals(file, content, projectPath);
1428
+ if (result.violations.length === 0) {
1429
+ continue;
1430
+ }
1431
+ for (const violation of result.violations) {
1432
+ const relativePath = file.replace(projectPath + "/", "");
1433
+ const issue = {
1434
+ id: `goal-violation-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
1435
+ hash: "",
1436
+ file: relativePath,
1437
+ line: violation.line,
1438
+ agent: "goal-validator",
1439
+ severity: violation.severity,
1440
+ issue: violation.description,
1441
+ fix: violation.autoFixable ? "Auto-fixable" : "Manual fix required",
1442
+ category: "goal-violation",
1443
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1444
+ project: basename2(projectPath),
1445
+ resolved: false,
1446
+ resolvedAt: void 0
1447
+ };
1448
+ await appendIssuesToLedger([issue], projectPath);
1449
+ await recordGoalViolationCaught(violation.goal, relativePath, projectPath);
1450
+ const nudgeMessage = `Goal "${violation.goal.description}" violated: ${violation.violation} in ${basename2(file)}:${violation.line || "?"}`;
1451
+ outputMgr.nudge(
1452
+ nudgeMessage,
1453
+ violation.severity === "critical" ? "critical" : "warning",
1454
+ relativePath
1455
+ );
1456
+ this.state.nudges.push({
1457
+ file: basename2(file),
1458
+ message: nudgeMessage,
1459
+ severity: violation.severity === "critical" ? "critical" : "high",
1460
+ timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false })
1461
+ });
1462
+ if (!isInteractiveMode()) {
1463
+ console.error(` [!] Goal violation: ${violation.description}`);
1464
+ }
1465
+ if (config.autoFix.enabled && violation.autoFixable && violation.fixAction) {
1466
+ if (!isInteractiveMode()) {
1467
+ console.error(` [*] Auto-fixing...`);
1468
+ }
1469
+ const fixed = await applyAutoFix(violation.fixAction);
1470
+ if (fixed) {
1471
+ await recordGoalViolationFixed(violation.goal, relativePath, projectPath);
1472
+ const fixMessage = `Auto-fixed: ${violation.goal.description} violation in ${basename2(file)}`;
1473
+ outputMgr.nudge(fixMessage, "info", relativePath, 5e3);
1474
+ if (!isInteractiveMode()) {
1475
+ console.error(` [+] Fixed automatically`);
1476
+ }
1477
+ }
1478
+ }
1479
+ }
1480
+ if (this.streamingManager && result.violations.length > 0) {
1481
+ this.streamingManager.reportSignalExtraction({
1482
+ decisions: 0,
1483
+ facts: 0,
1484
+ blockers: result.violations.length,
1485
+ questions: 0
1486
+ });
1487
+ }
1488
+ } catch (error) {
1489
+ outputMgr.log("warn", `Could not validate ${basename2(file)}: ${error}`);
1490
+ }
1491
+ }
1492
+ } catch (error) {
1493
+ getOutputManager().log("warn", `Goal validation error: ${error}`);
1494
+ }
1495
+ }
1496
+ /**
1497
+ * Check and generate hypotheses autonomously
1498
+ * Claude observes patterns and creates new hypotheses to test
1499
+ */
1500
+ async checkAndGenerateHypotheses(projectPath) {
1501
+ if (!isAIAvailable()) return;
1502
+ try {
1503
+ const { getHypothesisEngine } = await import("./hypothesis-KGC3P54C.js");
1504
+ const { getOutputManager: getOutputManager2 } = await import("./output-manager-BOTMXSND.js");
1505
+ const hypothesisEngine = getHypothesisEngine(projectPath);
1506
+ const recentIssues = Array.from(this.state.issueCache.values()).flat();
1507
+ const patterns = [];
1508
+ const observations = [];
1509
+ if (this.state.nudges.length > 0) {
1510
+ const nudgesByFile = {};
1511
+ for (const nudge of this.state.nudges) {
1512
+ nudgesByFile[nudge.file] = (nudgesByFile[nudge.file] || 0) + 1;
1513
+ }
1514
+ const topFiles = Object.entries(nudgesByFile).sort(([, a], [, b]) => b - a).slice(0, 3);
1515
+ if (topFiles[0] && topFiles[0][1] > 2) {
1516
+ observations.push(`File ${topFiles[0][0]} has ${topFiles[0][1]} repeated issues this session`);
1517
+ }
1518
+ }
1519
+ if (this.state.nudges.length > 5) {
1520
+ observations.push(`High issue detection rate: ${this.state.nudges.length} violations detected in watch session`);
1521
+ }
1522
+ let generated = await hypothesisEngine.generateHypothesesWithAI({
1523
+ recentIssues,
1524
+ patterns,
1525
+ observations
1526
+ });
1527
+ if (generated.length === 0) {
1528
+ generated = await hypothesisEngine.autoGenerateHypotheses();
1529
+ }
1530
+ for (const hypothesis of generated) {
1531
+ const message = `[New Hypothesis] "${hypothesis.statement}" (${Math.round(hypothesis.confidence * 100)}% confidence)`;
1532
+ getOutputManager2().nudge(
1533
+ message,
1534
+ "info",
1535
+ void 0,
1536
+ 1e4
1537
+ );
1538
+ if (!isInteractiveMode()) {
1539
+ console.error(`
1540
+ [?] ${message}`);
1541
+ console.error(` Test: ${hypothesis.testCriteria || "Collecting evidence..."}`);
1542
+ }
1543
+ if (this.streamingManager) {
1544
+ this.streamingManager.reportSignalExtraction({
1545
+ decisions: 0,
1546
+ facts: 0,
1547
+ blockers: 0,
1548
+ questions: 1
1549
+ // Hypotheses are questions to answer
1550
+ });
1551
+ }
1552
+ }
1553
+ if (recentIssues.length > 10) {
1554
+ await hypothesisEngine.updateConfidenceFromOutcomes();
1555
+ }
1556
+ } catch (error) {
1557
+ if (!isInteractiveMode()) {
1558
+ console.error(` [!] Hypothesis check failed: ${error}`);
1559
+ }
1560
+ }
1561
+ }
1562
+ /**
1563
+ * Discover patterns from accumulated issues
1564
+ * Patterns emerge naturally from your coding workflow
1565
+ */
1566
+ async discoverPatternsFromIssues(projectPath) {
1567
+ const totalIssues = Array.from(this.state.issueCache.values()).flat().length;
1568
+ if (totalIssues < 5) return;
1569
+ try {
1570
+ const { ContextGraph: ContextGraph2 } = await import("./graph-U5JWSAB5.js");
1571
+ const { IncidentIndex } = await import("./incident-index-PNIVT47T.js");
1572
+ const { TriePatternDiscovery } = await import("./pattern-discovery-F7LU5K6E.js");
1573
+ const graph = new ContextGraph2(projectPath);
1574
+ const incidentIndex = await IncidentIndex.build(graph, projectPath);
1575
+ const discovery = new TriePatternDiscovery(graph, incidentIndex);
1576
+ const hotPatterns = discovery.discoverHotPatterns(2);
1577
+ for (const hot of hotPatterns) {
1578
+ const existingPatterns = await graph.listNodes();
1579
+ const alreadyExists = existingPatterns.some(
1580
+ (n) => n.type === "pattern" && n.data.description?.includes(hot.path)
1581
+ );
1582
+ if (!alreadyExists) {
1583
+ await graph.addNode("pattern", {
1584
+ description: `${hot.type === "directory" ? "Directory" : "File"} hot zone: ${hot.path}`,
1585
+ appliesTo: [hot.path],
1586
+ confidence: Math.min(0.95, hot.confidence),
1587
+ occurrences: hot.incidentCount,
1588
+ firstSeen: (/* @__PURE__ */ new Date()).toISOString(),
1589
+ lastSeen: (/* @__PURE__ */ new Date()).toISOString(),
1590
+ isAntiPattern: hot.incidentCount >= 3,
1591
+ // 3+ incidents = anti-pattern
1592
+ source: "local"
1593
+ });
1594
+ if (!isInteractiveMode()) {
1595
+ console.error(` [+] Pattern discovered: ${hot.path} (${hot.incidentCount} issues)`);
1596
+ }
1597
+ if (this.streamingManager) {
1598
+ this.streamingManager.reportSignalExtraction({
1599
+ decisions: 0,
1600
+ facts: 1,
1601
+ // Patterns are facts about the codebase
1602
+ blockers: 0,
1603
+ questions: 0
1604
+ });
1605
+ }
1606
+ }
1607
+ }
1608
+ if (totalIssues >= 10) {
1609
+ const coOccurrences = await discovery.discoverCoOccurrences(2);
1610
+ for (const coOcc of coOccurrences.slice(0, 3)) {
1611
+ const desc = `Files break together: ${coOcc.files[0]} + ${coOcc.files[1]}`;
1612
+ const existingPatterns = await graph.listNodes();
1613
+ const alreadyExists = existingPatterns.some(
1614
+ (n) => n.type === "pattern" && n.data.description === desc
1615
+ );
1616
+ if (!alreadyExists) {
1617
+ await graph.addNode("pattern", {
1618
+ description: desc,
1619
+ appliesTo: [...coOcc.files],
1620
+ confidence: Math.min(0.95, coOcc.confidence),
1621
+ occurrences: coOcc.coOccurrences,
1622
+ firstSeen: (/* @__PURE__ */ new Date()).toISOString(),
1623
+ lastSeen: (/* @__PURE__ */ new Date()).toISOString(),
1624
+ isAntiPattern: coOcc.confidence > 0.7,
1625
+ source: "local"
1626
+ });
1627
+ if (!isInteractiveMode()) {
1628
+ console.error(` [+] Co-occurrence pattern: ${coOcc.files[0]} + ${coOcc.files[1]}`);
1629
+ }
1630
+ }
1631
+ }
1632
+ }
1633
+ } catch (error) {
1634
+ if (!isInteractiveMode()) {
1635
+ console.error(` [!] Pattern discovery failed: ${error}`);
1636
+ }
1637
+ }
1638
+ }
1639
+ // Defaults -- overridden by config when loaded
1640
+ aiWatcherCooldownMs = 3e4;
1641
+ cleanFileCooldownMs = 3e5;
1642
+ maxFilesPerScan = 5;
1643
+ maxCharsPerFile = 4e3;
1391
1644
  /**
1392
1645
  * Use the trie (context graph) to score how urgently a file needs scanning.
1393
1646
  * Higher score = more worth spending tokens on.
@@ -1395,7 +1648,7 @@ ${f.content.slice(0, 1e3)}`
1395
1648
  async scoreScanPriority(file, graph, projectPath) {
1396
1649
  let score = 1;
1397
1650
  const lastClean = this.state.cleanFiles.get(file);
1398
- if (lastClean && Date.now() - lastClean < _TrieWatchTool.CLEAN_FILE_COOLDOWN_MS) {
1651
+ if (lastClean && Date.now() - lastClean < this.cleanFileCooldownMs) {
1399
1652
  return 0;
1400
1653
  }
1401
1654
  const fileNode = await graph.getNode("file", join2(projectPath, file));
@@ -1424,14 +1677,32 @@ ${f.content.slice(0, 1e3)}`
1424
1677
  this.state.tokenBudget.used += tokens;
1425
1678
  }
1426
1679
  /**
1427
- * AI-powered auto-scan, throttled by the trie.
1428
- * 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.
1429
1688
  */
1430
1689
  async autoScanFiles(files) {
1431
1690
  if (!isAIAvailable()) return;
1432
1691
  if (this.state.autoScanInProgress) return;
1433
1692
  const now = Date.now();
1434
- 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
+ }
1435
1706
  const remaining = this.getRemainingBudget();
1436
1707
  if (remaining < 500) return;
1437
1708
  this.state.autoScanInProgress = true;
@@ -1439,6 +1710,11 @@ ${f.content.slice(0, 1e3)}`
1439
1710
  try {
1440
1711
  const projectPath = getWorkingDirectory(void 0, true);
1441
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;
1442
1718
  const scored = [];
1443
1719
  for (const file of files) {
1444
1720
  const relativePath = file.replace(projectPath + "/", "");
@@ -1451,13 +1727,15 @@ ${f.content.slice(0, 1e3)}`
1451
1727
  }
1452
1728
  if (scored.length === 0) return;
1453
1729
  scored.sort((a, b) => b.score - a.score);
1454
- const maxFiles = remaining > 2e4 ? 5 : remaining > 1e4 ? 3 : 1;
1455
- 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));
1456
1734
  const fileContents = await Promise.all(
1457
- toScan.map(async ({ file, relativePath }) => {
1735
+ filesToScan.map(async ({ file, relativePath }) => {
1458
1736
  try {
1459
1737
  const content = await readFile3(file, "utf-8");
1460
- return { path: relativePath, content: content.slice(0, 3e3) };
1738
+ return { path: relativePath, content: content.slice(0, charLimit) };
1461
1739
  } catch {
1462
1740
  return null;
1463
1741
  }
@@ -1471,22 +1749,37 @@ ${f.content.slice(0, 1e3)}`
1471
1749
  ${f.content}
1472
1750
  \`\`\``
1473
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
+ }
1474
1761
  const result = await runAIAnalysis({
1475
- 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:
1476
1763
 
1477
- 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:
1478
1768
  - "file": relative file path
1479
1769
  - "severity": "critical" | "major" | "minor"
1480
- - "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)
1481
1773
 
1482
- 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.
1483
1775
 
1484
- Do NOT include markdown fences or commentary. Output ONLY the JSON array.`,
1485
- 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:
1486
1779
 
1487
1780
  ${filesBlock}`,
1488
- maxTokens: 1024,
1489
- temperature: 0.2
1781
+ maxTokens: 2048,
1782
+ temperature: 0.1
1490
1783
  });
1491
1784
  if (result.tokensUsed) {
1492
1785
  this.recordTokenUsage(result.tokensUsed.input + result.tokensUsed.output);
@@ -1501,14 +1794,46 @@ ${filesBlock}`,
1501
1794
  return;
1502
1795
  }
1503
1796
  const issuedFiles = new Set(issues.map((i) => i.file));
1504
- for (const { relativePath } of toScan) {
1797
+ for (const { relativePath } of filesToScan) {
1505
1798
  if (!issuedFiles.has(relativePath)) {
1506
1799
  this.state.cleanFiles.set(relativePath, Date.now());
1507
1800
  }
1508
1801
  }
1509
1802
  if (issues.length === 0) return;
1510
- for (const issue of issues.slice(0, 5)) {
1803
+ for (const issue of issues.slice(0, 10)) {
1511
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
+ }
1512
1837
  const incident = await graph.addNode("incident", {
1513
1838
  description: issue.description,
1514
1839
  severity,
@@ -1534,7 +1859,7 @@ ${filesBlock}`,
1534
1859
  this.state.totalIssuesFound++;
1535
1860
  if (severity !== "minor") {
1536
1861
  getOutputManager().nudge(
1537
- `[!] ${issue.description}`,
1862
+ `${issue.description}`,
1538
1863
  severity === "critical" ? "critical" : "warning",
1539
1864
  issue.file,
1540
1865
  severity === "critical" ? void 0 : 15e3
@@ -1555,7 +1880,8 @@ ${filesBlock}`,
1555
1880
  questions: 0
1556
1881
  });
1557
1882
  }
1558
- } catch {
1883
+ } catch (error) {
1884
+ getOutputManager().log("warn", `AI watcher error: ${error}`);
1559
1885
  } finally {
1560
1886
  this.state.autoScanInProgress = false;
1561
1887
  }
@@ -1632,7 +1958,7 @@ Use \`trie_watch start\` to begin autonomous scanning.`
1632
1958
  ).join("\n");
1633
1959
  let agencyStatus = "";
1634
1960
  try {
1635
- const { getGuardian } = await import("./guardian-agent-XEYNG7RH.js");
1961
+ const { getGuardian } = await import("./guardian-agent-EXP7APLC.js");
1636
1962
  const trieAgent = getGuardian(getWorkingDirectory(void 0, true));
1637
1963
  await trieAgent.initialize();
1638
1964
  const status = await trieAgent.getAgencyStatus();