@triedotdev/mcp 1.0.151 → 1.0.155

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 (114) hide show
  1. package/README.md +34 -6
  2. package/dist/{autonomy-config-3APNC6QF.js → autonomy-config-RKLZW4XL.js} +4 -4
  3. package/dist/{chat-store-HMTDL7I2.js → chat-store-O3IJ5PMN.js} +4 -4
  4. package/dist/{chunk-IXO4G4D3.js → chunk-2LAJKFWU.js} +2 -2
  5. package/dist/{chunk-F7BMFOZ6.js → chunk-3CYMLM35.js} +2 -2
  6. package/dist/{chunk-ED7PLRQA.js → chunk-4ZAFQEP6.js} +4 -4
  7. package/dist/{chunk-4TQQP7JD.js → chunk-7F2R2ITA.js} +2 -2
  8. package/dist/{chunk-SU3WCAC4.js → chunk-BUA5PQJY.js} +1487 -49
  9. package/dist/chunk-BUA5PQJY.js.map +1 -0
  10. package/dist/{chunk-V3O7C2LY.js → chunk-CBAMZERA.js} +2 -2
  11. package/dist/{chunk-G7Q23IGF.js → chunk-EMJ7RVWB.js} +9 -9
  12. package/dist/{chunk-TU7D5DEW.js → chunk-FTOF3FHT.js} +3 -3
  13. package/dist/{chunk-3KZBC3RJ.js → chunk-FXZAABXO.js} +2 -2
  14. package/dist/{chunk-TWPX6PHF.js → chunk-HD5H7YSW.js} +2 -2
  15. package/dist/{chunk-APMV77PU.js → chunk-JKEEQAG2.js} +1 -1
  16. package/dist/chunk-JKEEQAG2.js.map +1 -0
  17. package/dist/{chunk-TWQPOVRA.js → chunk-JYWGYUKX.js} +2 -2
  18. package/dist/{chunk-TIMIKBY2.js → chunk-KLMJKM63.js} +2 -2
  19. package/dist/{chunk-TCNCNWGV.js → chunk-KYKADM7P.js} +2 -2
  20. package/dist/{chunk-GLY76TSI.js → chunk-L4FODDDB.js} +2 -2
  21. package/dist/{chunk-JIS2OCZR.js → chunk-LFNH3CSN.js} +4 -4
  22. package/dist/{chunk-74R4XSFB.js → chunk-NVZZUUEU.js} +5 -5
  23. package/dist/{chunk-REHKDCI6.js → chunk-OVSYTWUU.js} +2 -2
  24. package/dist/{chunk-IFBEAOHH.js → chunk-RY57G46E.js} +6 -6
  25. package/dist/{chunk-ABY2R7OK.js → chunk-T7UAH7GE.js} +2 -2
  26. package/dist/{chunk-OJXFQRUE.js → chunk-UL337UDQ.js} +2 -2
  27. package/dist/{chunk-F4NJ4CBP.js → chunk-WO7CC5FH.js} +2 -2
  28. package/dist/{chunk-4UDBGYI3.js → chunk-X64XFVAY.js} +13 -13
  29. package/dist/{chunk-QQG42HCI.js → chunk-XD2HKZVB.js} +2 -2
  30. package/dist/{chunk-LNUMECBJ.js → chunk-XUGUKSKO.js} +10 -2
  31. package/dist/chunk-XUGUKSKO.js.map +1 -0
  32. package/dist/{chunk-WOTLY5NA.js → chunk-YEQXKKZQ.js} +2 -2
  33. package/dist/{chunk-7HYOJ4Q7.js → chunk-Z2E7X4WI.js} +7 -7
  34. package/dist/cli/create-agent.js +2 -2
  35. package/dist/cli/main.js +86 -40
  36. package/dist/cli/main.js.map +1 -1
  37. package/dist/cli/yolo-daemon.js +78 -27
  38. package/dist/cli/yolo-daemon.js.map +1 -1
  39. package/dist/{client-5L64D5SQ.js → client-ZHOLZTRW.js} +4 -4
  40. package/dist/{codebase-index-OOE7OAHP.js → codebase-index-N37NDF2A.js} +4 -4
  41. package/dist/{fast-analyzer-FMU3X4AZ.js → fast-analyzer-U6URGNQT.js} +6 -6
  42. package/dist/github-ingester-AR5A4RAC.js +11 -0
  43. package/dist/{goal-manager-VTBFFYN4.js → goal-manager-5QDITJKE.js} +8 -8
  44. package/dist/{goal-validator-EM5XVWVC.js → goal-validator-FU5QWDQT.js} +7 -7
  45. package/dist/graph-JO7GG65P.js +10 -0
  46. package/dist/{hypothesis-4UPE7KXU.js → hypothesis-JURDWVDC.js} +8 -8
  47. package/dist/incident-index-7CAXUNTL.js +11 -0
  48. package/dist/index.js +57 -1466
  49. package/dist/index.js.map +1 -1
  50. package/dist/{insight-store-QEEUQR5L.js → insight-store-AMEP5PPF.js} +4 -4
  51. package/dist/{issue-store-C6XYENE5.js → issue-store-RM3XLLKG.js} +5 -5
  52. package/dist/{ledger-VNA4DX3Z.js → ledger-PLE3C3X4.js} +4 -4
  53. package/dist/linear-ingester-NHFMKJBZ.js +11 -0
  54. package/dist/{output-manager-DZO5LGSG.js → output-manager-FX4V7ERT.js} +3 -3
  55. package/dist/{progress-PQVEM7BR.js → progress-PAYTY7BF.js} +2 -2
  56. package/dist/tiered-storage-SQDVZM2M.js +12 -0
  57. package/dist/trie-agent-TLOJ2UFS.js +27 -0
  58. package/dist/{vibe-code-signatures-ELEWJFGZ.js → vibe-code-signatures-J4GD4JOV.js} +3 -3
  59. package/dist/{vulnerability-signatures-EIJQX2TS.js → vulnerability-signatures-EIKOHFPK.js} +3 -3
  60. package/package.json +1 -1
  61. package/dist/chunk-APMV77PU.js.map +0 -1
  62. package/dist/chunk-LNUMECBJ.js.map +0 -1
  63. package/dist/chunk-SU3WCAC4.js.map +0 -1
  64. package/dist/github-ingester-C66ZRUYC.js +0 -11
  65. package/dist/graph-26JPZ3DF.js +0 -10
  66. package/dist/incident-index-H6APJ4S3.js +0 -11
  67. package/dist/linear-ingester-WIUBWF55.js +0 -11
  68. package/dist/tiered-storage-P6Z3NV2Q.js +0 -12
  69. package/dist/trie-agent-GJJJCL6P.js +0 -27
  70. /package/dist/{autonomy-config-3APNC6QF.js.map → autonomy-config-RKLZW4XL.js.map} +0 -0
  71. /package/dist/{chat-store-HMTDL7I2.js.map → chat-store-O3IJ5PMN.js.map} +0 -0
  72. /package/dist/{chunk-IXO4G4D3.js.map → chunk-2LAJKFWU.js.map} +0 -0
  73. /package/dist/{chunk-F7BMFOZ6.js.map → chunk-3CYMLM35.js.map} +0 -0
  74. /package/dist/{chunk-ED7PLRQA.js.map → chunk-4ZAFQEP6.js.map} +0 -0
  75. /package/dist/{chunk-4TQQP7JD.js.map → chunk-7F2R2ITA.js.map} +0 -0
  76. /package/dist/{chunk-V3O7C2LY.js.map → chunk-CBAMZERA.js.map} +0 -0
  77. /package/dist/{chunk-G7Q23IGF.js.map → chunk-EMJ7RVWB.js.map} +0 -0
  78. /package/dist/{chunk-TU7D5DEW.js.map → chunk-FTOF3FHT.js.map} +0 -0
  79. /package/dist/{chunk-3KZBC3RJ.js.map → chunk-FXZAABXO.js.map} +0 -0
  80. /package/dist/{chunk-TWPX6PHF.js.map → chunk-HD5H7YSW.js.map} +0 -0
  81. /package/dist/{chunk-TWQPOVRA.js.map → chunk-JYWGYUKX.js.map} +0 -0
  82. /package/dist/{chunk-TIMIKBY2.js.map → chunk-KLMJKM63.js.map} +0 -0
  83. /package/dist/{chunk-TCNCNWGV.js.map → chunk-KYKADM7P.js.map} +0 -0
  84. /package/dist/{chunk-GLY76TSI.js.map → chunk-L4FODDDB.js.map} +0 -0
  85. /package/dist/{chunk-JIS2OCZR.js.map → chunk-LFNH3CSN.js.map} +0 -0
  86. /package/dist/{chunk-74R4XSFB.js.map → chunk-NVZZUUEU.js.map} +0 -0
  87. /package/dist/{chunk-REHKDCI6.js.map → chunk-OVSYTWUU.js.map} +0 -0
  88. /package/dist/{chunk-IFBEAOHH.js.map → chunk-RY57G46E.js.map} +0 -0
  89. /package/dist/{chunk-ABY2R7OK.js.map → chunk-T7UAH7GE.js.map} +0 -0
  90. /package/dist/{chunk-OJXFQRUE.js.map → chunk-UL337UDQ.js.map} +0 -0
  91. /package/dist/{chunk-F4NJ4CBP.js.map → chunk-WO7CC5FH.js.map} +0 -0
  92. /package/dist/{chunk-4UDBGYI3.js.map → chunk-X64XFVAY.js.map} +0 -0
  93. /package/dist/{chunk-QQG42HCI.js.map → chunk-XD2HKZVB.js.map} +0 -0
  94. /package/dist/{chunk-WOTLY5NA.js.map → chunk-YEQXKKZQ.js.map} +0 -0
  95. /package/dist/{chunk-7HYOJ4Q7.js.map → chunk-Z2E7X4WI.js.map} +0 -0
  96. /package/dist/{client-5L64D5SQ.js.map → client-ZHOLZTRW.js.map} +0 -0
  97. /package/dist/{codebase-index-OOE7OAHP.js.map → codebase-index-N37NDF2A.js.map} +0 -0
  98. /package/dist/{fast-analyzer-FMU3X4AZ.js.map → fast-analyzer-U6URGNQT.js.map} +0 -0
  99. /package/dist/{github-ingester-C66ZRUYC.js.map → github-ingester-AR5A4RAC.js.map} +0 -0
  100. /package/dist/{goal-manager-VTBFFYN4.js.map → goal-manager-5QDITJKE.js.map} +0 -0
  101. /package/dist/{goal-validator-EM5XVWVC.js.map → goal-validator-FU5QWDQT.js.map} +0 -0
  102. /package/dist/{graph-26JPZ3DF.js.map → graph-JO7GG65P.js.map} +0 -0
  103. /package/dist/{hypothesis-4UPE7KXU.js.map → hypothesis-JURDWVDC.js.map} +0 -0
  104. /package/dist/{incident-index-H6APJ4S3.js.map → incident-index-7CAXUNTL.js.map} +0 -0
  105. /package/dist/{insight-store-QEEUQR5L.js.map → insight-store-AMEP5PPF.js.map} +0 -0
  106. /package/dist/{issue-store-C6XYENE5.js.map → issue-store-RM3XLLKG.js.map} +0 -0
  107. /package/dist/{ledger-VNA4DX3Z.js.map → ledger-PLE3C3X4.js.map} +0 -0
  108. /package/dist/{linear-ingester-WIUBWF55.js.map → linear-ingester-NHFMKJBZ.js.map} +0 -0
  109. /package/dist/{output-manager-DZO5LGSG.js.map → output-manager-FX4V7ERT.js.map} +0 -0
  110. /package/dist/{progress-PQVEM7BR.js.map → progress-PAYTY7BF.js.map} +0 -0
  111. /package/dist/{tiered-storage-P6Z3NV2Q.js.map → tiered-storage-SQDVZM2M.js.map} +0 -0
  112. /package/dist/{trie-agent-GJJJCL6P.js.map → trie-agent-TLOJ2UFS.js.map} +0 -0
  113. /package/dist/{vibe-code-signatures-ELEWJFGZ.js.map → vibe-code-signatures-J4GD4JOV.js.map} +0 -0
  114. /package/dist/{vulnerability-signatures-EIJQX2TS.js.map → vulnerability-signatures-EIKOHFPK.js.map} +0 -0
package/dist/index.js CHANGED
@@ -1,10 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  GitHubIngester
4
- } from "./chunk-V3O7C2LY.js";
5
- import {
6
- CodebaseIndex
7
- } from "./chunk-WOTLY5NA.js";
4
+ } from "./chunk-CBAMZERA.js";
8
5
  import {
9
6
  appendToSection,
10
7
  completeBootstrap,
@@ -22,15 +19,12 @@ import {
22
19
  needsBootstrap,
23
20
  projectInfoExists,
24
21
  updateProjectSection
25
- } from "./chunk-REHKDCI6.js";
22
+ } from "./chunk-OVSYTWUU.js";
26
23
  import {
27
24
  LinearIngester
28
- } from "./chunk-3KZBC3RJ.js";
25
+ } from "./chunk-FXZAABXO.js";
29
26
  import {
30
- ExtractionPipeline,
31
27
  GitHubBranchesTool,
32
- InteractiveDashboard,
33
- StreamingManager,
34
28
  TrieCheckTool,
35
29
  TrieCloudFixTool,
36
30
  TrieExplainTool,
@@ -44,76 +38,68 @@ import {
44
38
  TriePipelineTool,
45
39
  TrieQueryContextTool,
46
40
  TrieTellTool,
41
+ TrieWatchTool,
47
42
  getPrompt,
48
43
  getSystemPrompt,
49
44
  handleCheckpointTool
50
- } from "./chunk-SU3WCAC4.js";
51
- import "./chunk-F7BMFOZ6.js";
52
- import "./chunk-4UDBGYI3.js";
45
+ } from "./chunk-BUA5PQJY.js";
46
+ import "./chunk-3CYMLM35.js";
47
+ import "./chunk-X64XFVAY.js";
53
48
  import {
54
- getOutputManager
55
- } from "./chunk-TIMIKBY2.js";
56
- import "./chunk-JIS2OCZR.js";
57
- import "./chunk-74R4XSFB.js";
58
- import "./chunk-ABY2R7OK.js";
49
+ CodebaseIndex
50
+ } from "./chunk-YEQXKKZQ.js";
51
+ import "./chunk-KLMJKM63.js";
52
+ import "./chunk-LFNH3CSN.js";
53
+ import "./chunk-NVZZUUEU.js";
54
+ import "./chunk-T7UAH7GE.js";
59
55
  import {
60
56
  exportToJson,
61
57
  formatFriendlyError,
62
58
  importFromJson,
63
59
  isTrieInitialized
64
- } from "./chunk-G7Q23IGF.js";
60
+ } from "./chunk-EMJ7RVWB.js";
65
61
  import {
66
62
  loadConfig
67
- } from "./chunk-TU7D5DEW.js";
68
- import "./chunk-TCNCNWGV.js";
63
+ } from "./chunk-FTOF3FHT.js";
64
+ import "./chunk-KYKADM7P.js";
69
65
  import "./chunk-ZV2K6M7T.js";
70
66
  import {
71
67
  findCrossProjectPatterns,
72
68
  getGlobalMemoryStats,
73
69
  listTrackedProjects,
74
70
  searchGlobalPatterns
75
- } from "./chunk-IFBEAOHH.js";
71
+ } from "./chunk-RY57G46E.js";
76
72
  import {
77
73
  ContextGraph
78
- } from "./chunk-TWQPOVRA.js";
79
- import "./chunk-7HYOJ4Q7.js";
80
- import {
81
- isAIAvailable,
82
- runAIAnalysis
83
- } from "./chunk-OJXFQRUE.js";
84
- import "./chunk-GLY76TSI.js";
85
- import "./chunk-F4NJ4CBP.js";
86
- import "./chunk-IXO4G4D3.js";
74
+ } from "./chunk-JYWGYUKX.js";
75
+ import "./chunk-Z2E7X4WI.js";
76
+ import "./chunk-UL337UDQ.js";
77
+ import "./chunk-L4FODDDB.js";
78
+ import "./chunk-WO7CC5FH.js";
79
+ import "./chunk-2LAJKFWU.js";
87
80
  import "./chunk-6NLHFIYA.js";
88
- import {
89
- getStorage
90
- } from "./chunk-LNUMECBJ.js";
91
- import {
92
- getAutonomyConfig
93
- } from "./chunk-QQG42HCI.js";
81
+ import "./chunk-XUGUKSKO.js";
82
+ import "./chunk-XD2HKZVB.js";
94
83
  import {
95
84
  findSimilarIssues,
96
85
  getMemoryStats,
97
86
  getRecentIssues,
98
87
  markIssueResolved,
99
88
  purgeIssues,
100
- searchIssues,
101
- storeIssues
102
- } from "./chunk-ED7PLRQA.js";
89
+ searchIssues
90
+ } from "./chunk-4ZAFQEP6.js";
103
91
  import "./chunk-EFWVF6TI.js";
104
92
  import {
105
- getChangedFilesSinceTimestamp,
106
- getGitChangedFiles,
107
93
  runShellCommandSync
108
- } from "./chunk-TWPX6PHF.js";
94
+ } from "./chunk-HD5H7YSW.js";
109
95
  import "./chunk-43X6JBEM.js";
110
96
  import {
111
97
  getTrieDirectory,
112
98
  getWorkingDirectory
113
- } from "./chunk-4TQQP7JD.js";
99
+ } from "./chunk-7F2R2ITA.js";
114
100
  import {
115
101
  isInteractiveMode
116
- } from "./chunk-APMV77PU.js";
102
+ } from "./chunk-JKEEQAG2.js";
117
103
  import "./chunk-DGUM43GV.js";
118
104
 
119
105
  // src/server/mcp-server.ts
@@ -792,1405 +778,10 @@ trie_test action:"run" files:["src/utils.test.ts"]
792
778
  }
793
779
  };
794
780
 
795
- // src/tools/watch.ts
796
- import { watch, existsSync as existsSync2, readFileSync } from "fs";
797
- import { stat, readFile as readFile2 } from "fs/promises";
798
- import { join as join2, extname as extname2, basename as basename2 } from "path";
799
- import { createHash } from "crypto";
800
- var WATCH_EXTENSIONS = /* @__PURE__ */ new Set([
801
- ".ts",
802
- ".tsx",
803
- ".js",
804
- ".jsx",
805
- ".mjs",
806
- ".vue",
807
- ".svelte",
808
- ".astro",
809
- ".py",
810
- ".go",
811
- ".rs"
812
- ]);
813
- var SKIP_DIRS = /* @__PURE__ */ new Set([
814
- "node_modules",
815
- ".git",
816
- "dist",
817
- "build",
818
- ".next",
819
- ".nuxt",
820
- "coverage",
821
- ".turbo",
822
- ".cache"
823
- ]);
824
- var TrieWatchTool = class _TrieWatchTool {
825
- extractionPipeline = null;
826
- watchedDirectory = "";
827
- codebaseIndex = null;
828
- state = {
829
- isRunning: false,
830
- lastScan: /* @__PURE__ */ new Map(),
831
- pendingFiles: /* @__PURE__ */ new Set(),
832
- scanDebounceTimer: null,
833
- issueCache: /* @__PURE__ */ new Map(),
834
- totalIssuesFound: 0,
835
- filesScanned: 0,
836
- nudgedFiles: /* @__PURE__ */ new Set(),
837
- nudges: [],
838
- lastAutoScan: 0,
839
- autoScanInProgress: false,
840
- tokenBudget: {
841
- used: 0,
842
- windowStart: Date.now(),
843
- hourlyLimit: 5e4,
844
- scansSaved: 0
845
- },
846
- cleanFiles: /* @__PURE__ */ new Map()
847
- };
848
- watchers = /* @__PURE__ */ new Map();
849
- streamingManager = void 0;
850
- dashboard = void 0;
851
- lastHypothesisCheck = 0;
852
- pipelineSyncTimer = null;
853
- static HYPOTHESIS_CHECK_INTERVAL_MS = 3e5;
854
- // Check every 5 minutes
855
- static PIPELINE_SYNC_INTERVAL_MS = 30 * 60 * 1e3;
856
- // 30 minutes
857
- async execute(args) {
858
- const { action, directory, debounceMs = 1e3 } = args;
859
- switch (action) {
860
- case "start":
861
- return this.startWatching(getWorkingDirectory(directory), debounceMs);
862
- case "stop":
863
- return await this.stopWatching();
864
- case "status":
865
- return await this.getStatus();
866
- case "issues":
867
- return this.getCurrentIssues();
868
- case "nudges":
869
- return this.getNudges();
870
- default:
871
- return {
872
- content: [{
873
- type: "text",
874
- text: `Unknown action: ${action}. Use 'start', 'stop', 'status', or 'issues'.`
875
- }]
876
- };
877
- }
878
- }
879
- async startWatching(directory, debounceMs) {
880
- if (this.state.isRunning) {
881
- return {
882
- content: [{
883
- type: "text",
884
- text: "[!] Watch mode is already running. Use `trie_watch stop` to stop it first."
885
- }]
886
- };
887
- }
888
- if (!isTrieInitialized(directory)) {
889
- return {
890
- content: [{
891
- type: "text",
892
- text: "Trie is not initialized for this project. Run `trie init` first."
893
- }]
894
- };
895
- }
896
- const anthropicApiKey = process.env.ANTHROPIC_API_KEY;
897
- if (anthropicApiKey) {
898
- this.extractionPipeline = new ExtractionPipeline({
899
- workingDirectory: directory,
900
- anthropicApiKey
901
- });
902
- await this.extractionPipeline.initialize();
903
- }
904
- this.codebaseIndex = new CodebaseIndex(directory);
905
- this.state.isRunning = true;
906
- this.watchedDirectory = directory;
907
- this.state.issueCache.clear();
908
- this.state.totalIssuesFound = 0;
909
- this.state.filesScanned = 0;
910
- this.state.nudgedFiles.clear();
911
- this.state.nudges = [];
912
- try {
913
- const storage = getStorage(directory);
914
- await storage.initialize();
915
- const unresolvedNudges = await storage.queryNudges({ resolved: false });
916
- console.debug(`[Watch] Found ${unresolvedNudges.length} unresolved nudges in storage`);
917
- for (const nudge of unresolvedNudges) {
918
- let mappedSeverity = "high";
919
- if (nudge.severity === "critical") {
920
- mappedSeverity = "critical";
921
- } else if (nudge.severity === "high") {
922
- mappedSeverity = "high";
923
- }
924
- this.state.nudges.push({
925
- file: nudge.file || "unknown",
926
- // Keep full path, don't use basename
927
- message: nudge.message,
928
- severity: mappedSeverity,
929
- timestamp: new Date(nudge.timestamp).toLocaleTimeString("en-US", { hour12: false })
930
- });
931
- console.debug(`[Watch] Loaded nudge: ${nudge.message.slice(0, 60)}... (${nudge.severity} -> ${mappedSeverity})`);
932
- }
933
- if (unresolvedNudges.length > 0) {
934
- console.log(`[Watch] \u2713 Loaded ${unresolvedNudges.length} unresolved nudges from storage`);
935
- } else {
936
- console.debug(`[Watch] No unresolved nudges found in storage`);
937
- }
938
- } catch (error) {
939
- console.error("[Watch] Failed to load nudges from storage:", error);
940
- }
941
- try {
942
- const graph = new ContextGraph(directory);
943
- const allNodes = await graph.listNodes();
944
- const unresolvedIncidents = allNodes.filter(
945
- (n) => n.type === "incident" && !n.data.resolved
946
- );
947
- console.debug(`[Watch] Found ${unresolvedIncidents.length} unresolved incidents in context graph`);
948
- for (const incident of unresolvedIncidents) {
949
- const incidentData = incident.data;
950
- let mappedSeverity = "high";
951
- if (incidentData.severity === "critical") {
952
- mappedSeverity = "critical";
953
- } else if (incidentData.severity === "major") {
954
- mappedSeverity = "critical";
955
- } else if (incidentData.severity === "minor") {
956
- mappedSeverity = "high";
957
- }
958
- const edges = await graph.getEdges(incident.id);
959
- const linkedFiles = edges.filter((e) => e.type === "causedBy" || e.type === "affects").map((e) => {
960
- const node = allNodes.find((n) => n.id === e.to_id || n.id === e.from_id);
961
- if (node?.type === "file") {
962
- return node.data.path;
963
- }
964
- return null;
965
- }).filter((f) => f !== null);
966
- const file = linkedFiles[0] || "unknown";
967
- const message = `INCIDENT: ${incidentData.description}`;
968
- this.state.nudges.push({
969
- file,
970
- message,
971
- severity: mappedSeverity,
972
- timestamp: new Date(incidentData.timestamp).toLocaleTimeString("en-US", { hour12: false })
973
- });
974
- console.debug(`[Watch] Loaded incident: ${incidentData.description.slice(0, 60)}... (${incidentData.severity} -> ${mappedSeverity})`);
975
- }
976
- if (unresolvedIncidents.length > 0) {
977
- console.log(`[Watch] \u2713 Loaded ${unresolvedIncidents.length} unresolved incidents from context graph`);
978
- } else {
979
- console.debug(`[Watch] No unresolved incidents found in context graph`);
980
- }
981
- } catch (error) {
982
- console.error("[Watch] Failed to load incidents from context graph:", error);
983
- }
984
- if (!isInteractiveMode()) {
985
- console.error("\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
986
- console.error("TRIE AGENT - NOW WATCHING");
987
- console.error("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n");
988
- console.error("Your Trie agent is now watching over your codebase.");
989
- console.error("Signal extraction: ENABLED (building governance ledger)");
990
- console.error(`Watching: ${directory}`);
991
- console.error(`Debounce: ${debounceMs}ms`);
992
- console.error("");
993
- }
994
- if (isInteractiveMode()) {
995
- this.streamingManager = new StreamingManager();
996
- this.dashboard = new InteractiveDashboard();
997
- this.streamingManager.subscribe((update) => this.dashboard?.handleStreamUpdate(update));
998
- const outputManager = getOutputManager();
999
- outputManager.setMode("tui");
1000
- outputManager.setStreamingManager(this.streamingManager);
1001
- await this.dashboard.start();
1002
- this.streamingManager.reportWatchStatus({ watching: true, directories: 0, debounceMs });
1003
- } else {
1004
- getOutputManager().setMode("console");
1005
- }
1006
- await this.watchDirectory(directory, debounceMs);
1007
- await this.watchContextGraph(directory);
1008
- if (this.streamingManager) {
1009
- this.streamingManager.reportWatchStatus({
1010
- watching: true,
1011
- directories: this.watchers.size,
1012
- debounceMs
1013
- });
1014
- }
1015
- setTimeout(() => {
1016
- void this.initialGoalComplianceScan();
1017
- void this.initialHypothesisGeneration();
1018
- void this.syncPipelineIntegrations();
1019
- }, 1e3);
1020
- this.pipelineSyncTimer = setInterval(() => {
1021
- void this.syncPipelineIntegrations();
1022
- }, _TrieWatchTool.PIPELINE_SYNC_INTERVAL_MS);
1023
- const indexStatus = this.codebaseIndex?.isEmpty() ? "BUILDING (one-time, speeds up goal checks)" : "READY";
1024
- return {
1025
- content: [{
1026
- type: "text",
1027
- text: `**TRIE AGENT ACTIVATED**
1028
-
1029
- Your Trie agent is now autonomously watching and learning from your codebase.
1030
-
1031
- **Watching:** \`${directory}\`
1032
- **Debounce:** ${debounceMs}ms (waits for you to stop typing)
1033
- **Signal Extraction:** ${process.env.ANTHROPIC_API_KEY ? "ENABLED" : "LIMITED (set ANTHROPIC_API_KEY for full extraction)"}
1034
- **Codebase Index:** ${indexStatus}
1035
-
1036
- ### How the agent works:
1037
- 1. You write/edit code
1038
- 2. Agent detects the change
1039
- 3. Extracts governance, facts, blockers -> stores in ledger
1040
- 4. Predicts risks based on historical patterns
1041
- 5. Nudges you if something looks risky
1042
-
1043
- ### The agent learns:
1044
- - Every commit builds the governance ledger
1045
- - \`trie gotcha\` queries the ledger for predictions
1046
- - \`trie ok\` / \`trie bad\` teach the agent what matters
1047
-
1048
- ### Commands:
1049
- - \`trie_watch status\` - See agent status
1050
- - \`trie_watch stop\` - Stop the agent
1051
- - \`trie_index status\` - Check codebase index`
1052
- }]
1053
- };
1054
- }
1055
- shouldSkipPath(filePath) {
1056
- const parts = filePath.split("/");
1057
- return parts.some((p) => SKIP_DIRS.has(p) || p.startsWith(".") && p !== ".");
1058
- }
1059
- async watchDirectory(dir, debounceMs) {
1060
- if (!existsSync2(dir)) return;
1061
- try {
1062
- const dirStat = await stat(dir);
1063
- if (!dirStat.isDirectory()) return;
1064
- const watcher = watch(dir, { persistent: true, recursive: true }, (_eventType, filename) => {
1065
- if (!filename) return;
1066
- if (this.shouldSkipPath(filename)) return;
1067
- const ext = extname2(filename).toLowerCase();
1068
- if (!WATCH_EXTENSIONS.has(ext)) return;
1069
- const fullPath = join2(dir, filename);
1070
- if (!existsSync2(fullPath)) return;
1071
- this.state.pendingFiles.add(fullPath);
1072
- if (this.state.scanDebounceTimer) {
1073
- clearTimeout(this.state.scanDebounceTimer);
1074
- }
1075
- this.state.scanDebounceTimer = setTimeout(() => {
1076
- this.processPendingFiles();
1077
- }, debounceMs);
1078
- });
1079
- watcher.on("error", (err) => {
1080
- if (!isInteractiveMode()) {
1081
- console.error(`[!] Watcher error: ${err.message}`);
1082
- }
1083
- watcher.close();
1084
- this.watchers.delete(dir);
1085
- });
1086
- this.watchers.set(dir, watcher);
1087
- if (this.streamingManager) {
1088
- this.streamingManager.reportWatchStatus({
1089
- watching: true,
1090
- directories: 1,
1091
- debounceMs
1092
- });
1093
- }
1094
- } catch {
1095
- }
1096
- }
1097
- /**
1098
- * Watch .trie/context.json for incident changes
1099
- */
1100
- async watchContextGraph(directory) {
1101
- const contextPath = join2(getTrieDirectory(directory), "context.json");
1102
- if (!existsSync2(contextPath)) {
1103
- console.debug("[Watch] No context.json found, skipping incident watcher");
1104
- return;
1105
- }
1106
- try {
1107
- const watcher = watch(contextPath, { persistent: true }, async (_eventType, _filename) => {
1108
- console.debug("[Watch] context.json changed, reloading incidents...");
1109
- await this.reloadIncidents(directory);
1110
- });
1111
- watcher.on("error", (err) => {
1112
- console.error(`[Watch] Context watcher error: ${err.message}`);
1113
- watcher.close();
1114
- });
1115
- this.watchers.set("context.json", watcher);
1116
- console.debug("[Watch] \u2713 Watching context.json for incident changes");
1117
- } catch (error) {
1118
- console.error("[Watch] Failed to set up context.json watcher:", error);
1119
- }
1120
- }
1121
- /**
1122
- * Reload incidents from context graph
1123
- */
1124
- async reloadIncidents(directory) {
1125
- try {
1126
- const graph = new ContextGraph(directory);
1127
- const allNodes = await graph.listNodes();
1128
- const unresolvedIncidents = allNodes.filter(
1129
- (n) => n.type === "incident" && !n.data.resolved
1130
- );
1131
- this.state.nudges = this.state.nudges.filter((n) => !n.message.startsWith("INCIDENT:"));
1132
- for (const incident of unresolvedIncidents) {
1133
- const incidentData = incident.data;
1134
- let mappedSeverity = "high";
1135
- if (incidentData.severity === "critical") {
1136
- mappedSeverity = "critical";
1137
- } else if (incidentData.severity === "major") {
1138
- mappedSeverity = "critical";
1139
- } else if (incidentData.severity === "minor") {
1140
- mappedSeverity = "high";
1141
- }
1142
- const edges = await graph.getEdges(incident.id);
1143
- const linkedFiles = edges.filter((e) => e.type === "causedBy" || e.type === "affects").map((e) => {
1144
- const node = allNodes.find((n) => n.id === e.to_id || n.id === e.from_id);
1145
- if (node?.type === "file") {
1146
- return node.data.path;
1147
- }
1148
- return null;
1149
- }).filter((f) => f !== null);
1150
- const file = linkedFiles[0] || "unknown";
1151
- const message = `INCIDENT: ${incidentData.description}`;
1152
- this.state.nudges.push({
1153
- file,
1154
- message,
1155
- severity: mappedSeverity,
1156
- timestamp: new Date(incidentData.timestamp).toLocaleTimeString("en-US", { hour12: false })
1157
- });
1158
- }
1159
- console.log(`[Watch] \u2713 Reloaded ${unresolvedIncidents.length} unresolved incidents`);
1160
- } catch (error) {
1161
- console.error("[Watch] Failed to reload incidents:", error);
1162
- }
1163
- }
1164
- async processPendingFiles() {
1165
- if (this.state.pendingFiles.size === 0) return;
1166
- const files = Array.from(this.state.pendingFiles);
1167
- this.state.pendingFiles.clear();
1168
- if (!isInteractiveMode()) {
1169
- console.error(`
1170
- Detected changes in ${files.length} file(s):`);
1171
- for (const file of files) {
1172
- console.error(` - ${basename2(file)}`);
1173
- }
1174
- console.error("");
1175
- }
1176
- try {
1177
- const projectPath = this.watchedDirectory || getWorkingDirectory(void 0, true);
1178
- if (this.extractionPipeline) {
1179
- try {
1180
- const fileContents = await Promise.all(
1181
- files.map(async (file) => {
1182
- try {
1183
- const content = await readFile2(file, "utf-8");
1184
- return { file, content };
1185
- } catch {
1186
- return null;
1187
- }
1188
- })
1189
- );
1190
- const validFiles = fileContents.filter((f) => f !== null);
1191
- if (validFiles.length > 0) {
1192
- const combinedContent = validFiles.map(
1193
- (f) => `File: ${basename2(f.file)}
1194
- ${f.content.slice(0, 1e3)}`
1195
- // First 1KB of each file
1196
- ).join("\n\n---\n\n");
1197
- if (!isInteractiveMode()) {
1198
- console.error("[*] Extracting signals from changes...");
1199
- }
1200
- const signal = await this.extractionPipeline.process(combinedContent, {
1201
- sourceType: "file",
1202
- sourceId: `watch-${Date.now()}`
1203
- });
1204
- if (signal.governance.length > 0 || signal.facts.length > 0 || signal.blockers.length > 0) {
1205
- const govCount = signal.governance.length;
1206
- if (!isInteractiveMode()) {
1207
- console.error(` [+] Extracted: ${govCount} governance, ${signal.facts.length} facts, ${signal.blockers.length} blockers`);
1208
- }
1209
- if (this.streamingManager) {
1210
- this.streamingManager.reportSignalExtraction({
1211
- governance: govCount,
1212
- facts: signal.facts.length,
1213
- blockers: signal.blockers.length,
1214
- questions: signal.questions.length
1215
- });
1216
- }
1217
- }
1218
- }
1219
- } catch (error) {
1220
- if (!isInteractiveMode()) {
1221
- console.error(` [!] Signal extraction failed: ${error}`);
1222
- }
1223
- }
1224
- }
1225
- void this.autoScanFiles(files).catch((err) => {
1226
- getOutputManager().log("warn", `Auto scan failed: ${err}`);
1227
- });
1228
- await this.discoverPatternsFromIssues(projectPath);
1229
- const now = Date.now();
1230
- if (now - this.lastHypothesisCheck > _TrieWatchTool.HYPOTHESIS_CHECK_INTERVAL_MS) {
1231
- this.checkAndGenerateHypotheses(projectPath);
1232
- this.lastHypothesisCheck = now;
1233
- }
1234
- if (this.streamingManager) {
1235
- const now2 = Date.now();
1236
- for (const file of files) {
1237
- const lastReport = this.state.lastScan.get(file) || 0;
1238
- if (now2 - lastReport > 2e3) {
1239
- this.streamingManager.reportWatchChange(file);
1240
- }
1241
- }
1242
- }
1243
- this.state.filesScanned += files.length;
1244
- for (const file of files) {
1245
- this.state.lastScan.set(file, Date.now());
1246
- if (this.codebaseIndex) {
1247
- const relativePath = file.replace(projectPath + "/", "");
1248
- void this.codebaseIndex.indexFile(relativePath).then(() => {
1249
- void this.codebaseIndex?.save();
1250
- });
1251
- }
1252
- }
1253
- } catch (error) {
1254
- if (!isInteractiveMode()) {
1255
- console.error(`Scan error: ${error}`);
1256
- }
1257
- }
1258
- }
1259
- isQuiet() {
1260
- const projectPath = this.watchedDirectory || getWorkingDirectory(void 0, true);
1261
- const quietPath = join2(getTrieDirectory(projectPath), "quiet.json");
1262
- try {
1263
- const raw = readFileSync(quietPath, "utf-8");
1264
- const data = JSON.parse(raw);
1265
- const until = new Date(data.until).getTime();
1266
- return Date.now() < until;
1267
- } catch {
1268
- return false;
1269
- }
1270
- }
1271
- /**
1272
- * Check and generate hypotheses autonomously
1273
- * Claude observes patterns and creates new hypotheses to test
1274
- */
1275
- async checkAndGenerateHypotheses(projectPath) {
1276
- if (!isAIAvailable()) return;
1277
- try {
1278
- const { getHypothesisEngine } = await import("./hypothesis-4UPE7KXU.js");
1279
- const { getOutputManager: getOutputManager2 } = await import("./output-manager-DZO5LGSG.js");
1280
- const hypothesisEngine = getHypothesisEngine(projectPath);
1281
- const recentIssues = Array.from(this.state.issueCache.values()).flat();
1282
- const patterns = [];
1283
- const observations = [];
1284
- if (this.state.nudges.length > 0) {
1285
- const nudgesByFile = {};
1286
- for (const nudge of this.state.nudges) {
1287
- nudgesByFile[nudge.file] = (nudgesByFile[nudge.file] || 0) + 1;
1288
- }
1289
- const topFiles = Object.entries(nudgesByFile).sort(([, a], [, b]) => b - a).slice(0, 3);
1290
- if (topFiles[0] && topFiles[0][1] > 2) {
1291
- observations.push(`File ${topFiles[0][0]} has ${topFiles[0][1]} repeated issues this session`);
1292
- }
1293
- }
1294
- if (this.state.nudges.length > 5) {
1295
- observations.push(`High issue detection rate: ${this.state.nudges.length} violations detected in watch session`);
1296
- }
1297
- let generated = await hypothesisEngine.generateHypothesesWithAI({
1298
- recentIssues,
1299
- patterns,
1300
- observations
1301
- });
1302
- if (generated.length === 0) {
1303
- generated = await hypothesisEngine.autoGenerateHypotheses();
1304
- }
1305
- for (const hypothesis of generated) {
1306
- const message = `[New Hypothesis] "${hypothesis.statement}" (${Math.round(hypothesis.confidence * 100)}% confidence)`;
1307
- getOutputManager2().nudge(
1308
- message,
1309
- "info",
1310
- void 0,
1311
- 1e4
1312
- );
1313
- if (!isInteractiveMode()) {
1314
- console.error(`
1315
- [?] ${message}`);
1316
- console.error(` Test: ${hypothesis.testCriteria || "Collecting evidence..."}`);
1317
- }
1318
- if (this.streamingManager) {
1319
- this.streamingManager.reportSignalExtraction({
1320
- governance: 0,
1321
- facts: 0,
1322
- blockers: 0,
1323
- questions: 1
1324
- // Hypotheses are questions to answer
1325
- });
1326
- }
1327
- }
1328
- if (recentIssues.length > 10) {
1329
- await hypothesisEngine.updateConfidenceFromOutcomes();
1330
- }
1331
- } catch (error) {
1332
- if (!isInteractiveMode()) {
1333
- console.error(` [!] Hypothesis check failed: ${error}`);
1334
- }
1335
- }
1336
- }
1337
- /**
1338
- * Discover patterns from accumulated issues
1339
- * Patterns emerge naturally from your coding workflow
1340
- */
1341
- async discoverPatternsFromIssues(projectPath) {
1342
- const totalIssues = Array.from(this.state.issueCache.values()).flat().length;
1343
- if (totalIssues < 5) return;
1344
- try {
1345
- const { ContextGraph: ContextGraph2 } = await import("./graph-26JPZ3DF.js");
1346
- const { IncidentIndex } = await import("./incident-index-H6APJ4S3.js");
1347
- const { TriePatternDiscovery } = await import("./pattern-discovery-F7LU5K6E.js");
1348
- const graph = new ContextGraph2(projectPath);
1349
- const incidentIndex = await IncidentIndex.build(graph, projectPath);
1350
- const discovery = new TriePatternDiscovery(graph, incidentIndex);
1351
- const hotPatterns = discovery.discoverHotPatterns(2);
1352
- for (const hot of hotPatterns) {
1353
- const existingPatterns = await graph.listNodes();
1354
- const alreadyExists = existingPatterns.some(
1355
- (n) => n.type === "pattern" && n.data.description?.includes(hot.path)
1356
- );
1357
- if (!alreadyExists) {
1358
- await graph.addNode("pattern", {
1359
- description: `${hot.type === "directory" ? "Directory" : "File"} hot zone: ${hot.path}`,
1360
- appliesTo: [hot.path],
1361
- confidence: Math.min(0.95, hot.confidence),
1362
- occurrences: hot.incidentCount,
1363
- firstSeen: (/* @__PURE__ */ new Date()).toISOString(),
1364
- lastSeen: (/* @__PURE__ */ new Date()).toISOString(),
1365
- isAntiPattern: hot.incidentCount >= 3,
1366
- // 3+ incidents = anti-pattern
1367
- source: "local"
1368
- });
1369
- if (!isInteractiveMode()) {
1370
- console.error(` [+] Pattern discovered: ${hot.path} (${hot.incidentCount} issues)`);
1371
- }
1372
- if (this.streamingManager) {
1373
- this.streamingManager.reportSignalExtraction({
1374
- governance: 0,
1375
- facts: 1,
1376
- // Patterns are facts about the codebase
1377
- blockers: 0,
1378
- questions: 0
1379
- });
1380
- }
1381
- }
1382
- }
1383
- if (totalIssues >= 10) {
1384
- const coOccurrences = await discovery.discoverCoOccurrences(2);
1385
- for (const coOcc of coOccurrences.slice(0, 3)) {
1386
- const desc = `Files break together: ${coOcc.files[0]} + ${coOcc.files[1]}`;
1387
- const existingPatterns = await graph.listNodes();
1388
- const alreadyExists = existingPatterns.some(
1389
- (n) => n.type === "pattern" && n.data.description === desc
1390
- );
1391
- if (!alreadyExists) {
1392
- await graph.addNode("pattern", {
1393
- description: desc,
1394
- appliesTo: [...coOcc.files],
1395
- confidence: Math.min(0.95, coOcc.confidence),
1396
- occurrences: coOcc.coOccurrences,
1397
- firstSeen: (/* @__PURE__ */ new Date()).toISOString(),
1398
- lastSeen: (/* @__PURE__ */ new Date()).toISOString(),
1399
- isAntiPattern: coOcc.confidence > 0.7,
1400
- source: "local"
1401
- });
1402
- if (!isInteractiveMode()) {
1403
- console.error(` [+] Co-occurrence pattern: ${coOcc.files[0]} + ${coOcc.files[1]}`);
1404
- }
1405
- }
1406
- }
1407
- }
1408
- } catch (error) {
1409
- if (!isInteractiveMode()) {
1410
- console.error(` [!] Pattern discovery failed: ${error}`);
1411
- }
1412
- }
1413
- }
1414
- // Defaults -- overridden by config when loaded
1415
- aiWatcherCooldownMs = 3e4;
1416
- cleanFileCooldownMs = 3e5;
1417
- maxFilesPerScan = 5;
1418
- maxCharsPerFile = 4e3;
1419
- /**
1420
- * Use the trie (context graph) to score how urgently a file needs scanning.
1421
- * Higher score = more worth spending tokens on.
1422
- */
1423
- async scoreScanPriority(file, graph, projectPath) {
1424
- let score = 1;
1425
- const lastClean = this.state.cleanFiles.get(file);
1426
- if (lastClean && Date.now() - lastClean < this.cleanFileCooldownMs) {
1427
- return 0;
1428
- }
1429
- const fileNode = await graph.getNode("file", join2(projectPath, file));
1430
- if (!fileNode) return score;
1431
- const data = fileNode.data;
1432
- const riskScores = { critical: 10, high: 6, medium: 2, low: 1 };
1433
- score += riskScores[data.riskLevel] ?? 1;
1434
- score += Math.min(data.incidentCount * 3, 12);
1435
- if (data.changeCount > 10) score += 2;
1436
- return score;
1437
- }
1438
- /**
1439
- * Roll the token budget window if an hour has passed.
1440
- * Returns remaining tokens in the current window.
1441
- */
1442
- getRemainingBudget() {
1443
- const budget = this.state.tokenBudget;
1444
- const elapsed = Date.now() - budget.windowStart;
1445
- if (elapsed > 36e5) {
1446
- budget.used = 0;
1447
- budget.windowStart = Date.now();
1448
- }
1449
- return Math.max(0, budget.hourlyLimit - budget.used);
1450
- }
1451
- recordTokenUsage(tokens) {
1452
- this.state.tokenBudget.used += tokens;
1453
- }
1454
- /**
1455
- * AI-powered watcher -- the primary detection system.
1456
- *
1457
- * This is the single AI call that handles:
1458
- * 1. Code review (bugs, security, logic errors)
1459
- * 2. Goal violation detection (user-defined quality goals)
1460
- *
1461
- * When goals are active, files with goal violations bypass priority scoring
1462
- * so violations are always caught. Throttled by cooldown + token budget.
1463
- */
1464
- async autoScanFiles(files) {
1465
- if (!isAIAvailable()) return;
1466
- if (this.state.autoScanInProgress) return;
1467
- const now = Date.now();
1468
- if (now - this.state.lastAutoScan < this.aiWatcherCooldownMs) return;
1469
- this.state.autoScanInProgress = true;
1470
- this.state.lastAutoScan = now;
1471
- const projectPath = this.watchedDirectory || getWorkingDirectory(void 0, true);
1472
- try {
1473
- try {
1474
- const config = await getAutonomyConfig(projectPath);
1475
- const wc = config.aiWatcher;
1476
- if (!wc.enabled) return;
1477
- this.state.tokenBudget.hourlyLimit = wc.hourlyTokenLimit;
1478
- this.aiWatcherCooldownMs = wc.scanCooldownSec * 1e3;
1479
- this.cleanFileCooldownMs = wc.cleanFileCooldownSec * 1e3;
1480
- this.maxFilesPerScan = wc.maxFilesPerScan;
1481
- this.maxCharsPerFile = wc.maxCharsPerFile;
1482
- } catch {
1483
- }
1484
- const remaining = this.getRemainingBudget();
1485
- if (remaining < 500) return;
1486
- try {
1487
- const graph = new ContextGraph(projectPath);
1488
- const { getActiveGoals, recordGoalViolationCaught } = await import("./goal-validator-EM5XVWVC.js");
1489
- console.debug("[AI Watcher] Loading active goals...");
1490
- const activeGoals = await getActiveGoals(projectPath);
1491
- const hasGoals = activeGoals.length > 0;
1492
- console.debug("[AI Watcher] Goals loaded:", {
1493
- totalGoals: activeGoals.length,
1494
- hasGoals,
1495
- goals: activeGoals.map((g) => ({ id: g.id, description: g.description, status: g.status }))
1496
- });
1497
- if (this.isQuiet() && !hasGoals) return;
1498
- const scored = [];
1499
- for (const file of files) {
1500
- const relativePath = file.replace(projectPath + "/", "");
1501
- const score = await this.scoreScanPriority(relativePath, graph, projectPath);
1502
- if (hasGoals || score > 0) {
1503
- scored.push({ file, relativePath, score: Math.max(score, hasGoals ? 1 : 0) });
1504
- } else {
1505
- this.state.tokenBudget.scansSaved++;
1506
- }
1507
- }
1508
- if (scored.length === 0) return;
1509
- scored.sort((a, b) => b.score - a.score);
1510
- const budgetScale = remaining > 2e4 ? 1 : remaining > 1e4 ? 0.6 : 0.4;
1511
- const maxFiles = Math.max(1, Math.round(this.maxFilesPerScan * budgetScale));
1512
- const filesToScan = scored.slice(0, maxFiles);
1513
- const charLimit = Math.round(this.maxCharsPerFile * (remaining > 15e3 ? 1 : 0.5));
1514
- const fileContents = await Promise.all(
1515
- filesToScan.map(async ({ file, relativePath }) => {
1516
- try {
1517
- const content = await readFile2(file, "utf-8");
1518
- return { path: relativePath, content: content.slice(0, charLimit) };
1519
- } catch {
1520
- return null;
1521
- }
1522
- })
1523
- );
1524
- const valid = fileContents.filter(Boolean);
1525
- if (valid.length === 0) return;
1526
- const filesBlock = valid.map(
1527
- (f) => `### ${f.path}
1528
- \`\`\`
1529
- ${f.content}
1530
- \`\`\``
1531
- ).join("\n\n");
1532
- let goalsSection = "";
1533
- if (hasGoals) {
1534
- goalsSection = `
1535
- USER-DEFINED GOALS (IMPORTANT - check EVERY file against ALL goals):
1536
- ${activeGoals.map((g, i) => ` ${i + 1}. "${g.description}"`).join("\n")}
1537
-
1538
- Goal violations are HIGH PRIORITY. If a file violates any goal, you MUST report it.
1539
- `;
1540
- }
1541
- console.debug("[AI Watcher] Sending files to AI analysis:", {
1542
- fileCount: valid.length,
1543
- hasGoals,
1544
- goalsIncluded: hasGoals,
1545
- filePaths: valid.map((f) => f.path),
1546
- goalsSection: goalsSection.slice(0, 200) + (goalsSection.length > 200 ? "..." : "")
1547
- });
1548
- const result = await runAIAnalysis({
1549
- systemPrompt: `You are a code quality watcher. You review code for two things:
1550
-
1551
- 1. CODE ISSUES: bugs, security vulnerabilities, logic errors, risky patterns
1552
- 2. GOAL VIOLATIONS: check every file against the user's quality goals
1553
- ${goalsSection}
1554
- Reply ONLY with a JSON array. Each element must have:
1555
- - "file": relative file path
1556
- - "severity": "critical" | "major" | "minor"
1557
- - "description": 1-sentence description of what you found
1558
- - "confidence": number 0-100, how confident you are this is a real issue
1559
- - "suggestedFix": 1-sentence description of what should change to fix it
1560
- - "isGoalViolation": true if this violates a user goal, false otherwise
1561
- - "goalIndex": 0-based index of the violated goal (only if isGoalViolation is true)
1562
-
1563
- Be thorough with goal checking. If a goal says "no emojis" and you see an emoji anywhere in the file, report it with the exact location. If a goal says "no inline styles" and you see a style attribute, report it.
1564
-
1565
- If no issues or violations found, reply with: []
1566
- Output ONLY the JSON array, no markdown fences, no commentary.`,
1567
- userPrompt: `Review these changed files:
1568
-
1569
- ${filesBlock}`,
1570
- maxTokens: 2048,
1571
- temperature: 0.1
1572
- });
1573
- if (result.tokensUsed) {
1574
- this.recordTokenUsage(result.tokensUsed.input + result.tokensUsed.output);
1575
- }
1576
- console.debug("[AI Watcher] AI analysis result:", {
1577
- success: result.success,
1578
- contentLength: result.content ? result.content.length : 0,
1579
- tokensUsed: result.tokensUsed,
1580
- contentPreview: result.content ? result.content.slice(0, 500) : "null"
1581
- });
1582
- if (!result.success || !result.content.trim()) {
1583
- console.debug("[AI Watcher] AI analysis failed or returned empty content");
1584
- return;
1585
- }
1586
- let issues = [];
1587
- try {
1588
- const cleaned = result.content.replace(/```json?\n?|\n?```/g, "").trim();
1589
- console.debug("[AI Watcher] Parsing AI response:", { cleanedContent: cleaned.slice(0, 300) });
1590
- issues = JSON.parse(cleaned);
1591
- if (!Array.isArray(issues)) issues = [];
1592
- console.debug("[AI Watcher] Parsed issues:", {
1593
- totalIssues: issues.length,
1594
- goalViolations: issues.filter((i) => i.isGoalViolation).length,
1595
- issueTypes: issues.map((i) => ({ file: i.file, isGoalViolation: i.isGoalViolation, goalIndex: i.goalIndex }))
1596
- });
1597
- } catch (error) {
1598
- console.debug("[AI Watcher] Failed to parse AI response:", error);
1599
- return;
1600
- }
1601
- const issuedFiles = new Set(issues.map((i) => i.file));
1602
- for (const { relativePath } of filesToScan) {
1603
- if (!issuedFiles.has(relativePath)) {
1604
- this.state.cleanFiles.set(relativePath, Date.now());
1605
- }
1606
- }
1607
- if (issues.length === 0) return;
1608
- for (const issue of issues.slice(0, 10)) {
1609
- const severity = issue.severity === "critical" ? "critical" : issue.severity === "major" ? "major" : "minor";
1610
- if (issue.isGoalViolation && issue.goalIndex != null && issue.goalIndex >= 0 && issue.goalIndex < activeGoals.length) {
1611
- const goal = activeGoals[issue.goalIndex];
1612
- if (!goal) continue;
1613
- const confidence = Math.min(100, Math.max(0, issue.confidence ?? 80));
1614
- const fixId = `fix-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
1615
- console.debug("[AI Watcher] Goal violation detected:", {
1616
- goalDescription: goal.description,
1617
- file: issue.file,
1618
- violation: issue.description,
1619
- confidence,
1620
- goalIndex: issue.goalIndex,
1621
- totalActiveGoals: activeGoals.length
1622
- });
1623
- const goalViolationIssue = {
1624
- id: fixId,
1625
- file: issue.file,
1626
- agent: "goal-violation",
1627
- severity: severity === "critical" ? "critical" : severity === "major" ? "serious" : "moderate",
1628
- issue: `Goal "${goal.description}" violated: ${issue.description}`,
1629
- fix: issue.suggestedFix || "Review and fix",
1630
- category: "goal-violation",
1631
- confidence,
1632
- autoFixable: true
1633
- };
1634
- await storeIssues([goalViolationIssue], basename2(projectPath), projectPath);
1635
- await recordGoalViolationCaught(goal, issue.file, projectPath);
1636
- const confidenceStr = `${confidence}%`;
1637
- const nudgeMsg = `Goal "${goal.description}" violated in ${issue.file}: ${issue.description} [${confidenceStr} confidence]`;
1638
- console.debug("[AI Watcher] Sending nudge:", {
1639
- message: nudgeMsg,
1640
- file: issue.file,
1641
- severity: "warning"
1642
- });
1643
- getOutputManager().nudge(nudgeMsg, "warning", issue.file);
1644
- await this.persistNudge({
1645
- message: nudgeMsg,
1646
- severity: "warning",
1647
- file: issue.file,
1648
- category: "quality",
1649
- goalId: goal.id,
1650
- priority: 7,
1651
- suggestedAction: issue.suggestedFix || "Review and fix manually",
1652
- relatedIssues: [fixId]
1653
- });
1654
- if (this.streamingManager) {
1655
- this.streamingManager.reportPendingFix({
1656
- id: fixId,
1657
- file: issue.file,
1658
- description: issue.description,
1659
- goalDescription: goal.description,
1660
- confidence,
1661
- severity: issue.severity,
1662
- suggestedFix: issue.suggestedFix || "Remove the violating code"
1663
- });
1664
- }
1665
- if (!isInteractiveMode()) {
1666
- console.error(` [!] Goal violation (${confidenceStr}): ${issue.description}`);
1667
- console.error(` Fix: ${issue.suggestedFix || "Review and fix manually"}`);
1668
- }
1669
- continue;
1670
- }
1671
- const incident = await graph.addNode("incident", {
1672
- description: issue.description,
1673
- severity,
1674
- affectedUsers: null,
1675
- duration: null,
1676
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1677
- resolved: false,
1678
- resolution: null,
1679
- fixChangeId: null,
1680
- reportedVia: "detected"
1681
- });
1682
- const filePath = join2(projectPath, issue.file);
1683
- const fileNode = await graph.getNode("file", filePath);
1684
- if (fileNode) {
1685
- await graph.addEdge(fileNode.id, incident.id, "affects");
1686
- const data = fileNode.data;
1687
- const newRisk = severity === "critical" ? "critical" : severity === "major" ? "high" : data.riskLevel === "low" ? "medium" : data.riskLevel;
1688
- await graph.updateNode("file", fileNode.id, {
1689
- incidentCount: (data.incidentCount ?? 0) + 1,
1690
- riskLevel: newRisk
1691
- });
1692
- }
1693
- this.state.totalIssuesFound++;
1694
- if (severity !== "minor") {
1695
- getOutputManager().nudge(
1696
- `${issue.description}`,
1697
- severity === "critical" ? "critical" : "warning",
1698
- issue.file,
1699
- severity === "critical" ? void 0 : 15e3
1700
- );
1701
- await this.persistNudge({
1702
- message: issue.description,
1703
- severity: severity === "critical" ? "critical" : "warning",
1704
- file: issue.file,
1705
- category: "quality",
1706
- priority: severity === "critical" ? 9 : 6,
1707
- ...issue.suggestedFix && { suggestedAction: issue.suggestedFix }
1708
- });
1709
- }
1710
- }
1711
- if (this.streamingManager && issues.length > 0) {
1712
- this.streamingManager.reportSignalExtraction({
1713
- governance: 0,
1714
- facts: 0,
1715
- blockers: issues.length,
1716
- questions: 0
1717
- });
1718
- }
1719
- } catch (error) {
1720
- getOutputManager().log("warn", `AI watcher error: ${error}`);
1721
- }
1722
- } finally {
1723
- this.state.autoScanInProgress = false;
1724
- }
1725
- }
1726
- /**
1727
- * Initial hypothesis generation when watch starts.
1728
- *
1729
- * This generates hypotheses from existing patterns and issues to give
1730
- * users immediate insights about their codebase.
1731
- */
1732
- async initialHypothesisGeneration() {
1733
- if (!isAIAvailable()) {
1734
- console.debug("[Initial Hypothesis] AI not available, skipping initial hypothesis generation");
1735
- return;
1736
- }
1737
- const projectPath = this.watchedDirectory || getWorkingDirectory(void 0, true);
1738
- console.debug("[Initial Hypothesis] Starting initial hypothesis generation", { projectPath });
1739
- try {
1740
- const { getHypothesisEngine } = await import("./hypothesis-4UPE7KXU.js");
1741
- const hypothesisEngine = getHypothesisEngine(projectPath);
1742
- console.debug("[Initial Hypothesis] Running AI-powered hypothesis generation...");
1743
- const generated = await hypothesisEngine.generateHypothesesWithAI({
1744
- recentIssues: [],
1745
- // No recent issues yet on startup
1746
- patterns: [],
1747
- observations: ["Initial watch session started", "Analyzing codebase for potential patterns"]
1748
- });
1749
- console.debug("[Initial Hypothesis] Generated hypotheses on startup:", {
1750
- count: generated.length,
1751
- hypotheses: generated.map((h) => ({ statement: h.statement, confidence: h.confidence }))
1752
- });
1753
- if (generated.length > 0) {
1754
- const { getOutputManager: getOutputManager2 } = await import("./output-manager-DZO5LGSG.js");
1755
- const outputManager = getOutputManager2();
1756
- for (const hypothesis of generated.slice(0, 2)) {
1757
- const message = `[Initial Hypothesis] "${hypothesis.statement}" (${Math.round(hypothesis.confidence * 100)}% confidence)`;
1758
- outputManager.nudge(message, "info", void 0, 1e4);
1759
- if (!isInteractiveMode()) {
1760
- console.error(` [?] ${message}`);
1761
- }
1762
- }
1763
- if (this.streamingManager) {
1764
- this.streamingManager.reportSignalExtraction({
1765
- governance: 0,
1766
- facts: 0,
1767
- blockers: 0,
1768
- questions: generated.length
1769
- });
1770
- }
1771
- }
1772
- } catch (error) {
1773
- console.debug("[Initial Hypothesis] Failed to generate initial hypotheses:", error);
1774
- }
1775
- }
1776
- /**
1777
- * Initial goal compliance scan when watch starts.
1778
- *
1779
- * This checks recently modified files against active goals so the user
1780
- * gets immediate feedback about goal violations without waiting for files
1781
- * to be changed.
1782
- *
1783
- * Strategy:
1784
- * 1. Check if there are any active goals - if not, skip
1785
- * 2. Find recently modified files (last 24 hours OR uncommitted changes)
1786
- * 3. Filter to watched file types
1787
- * 4. Run a quick AI scan focused only on goal violations
1788
- * 5. Nudge the user about any violations found
1789
- */
1790
- async initialGoalComplianceScan() {
1791
- if (!isAIAvailable()) {
1792
- console.debug("[Initial Scan] AI not available, skipping initial goal compliance scan");
1793
- return;
1794
- }
1795
- const projectPath = this.watchedDirectory || getWorkingDirectory(void 0, true);
1796
- console.debug("[Initial Scan] Starting initial goal compliance scan", { projectPath });
1797
- try {
1798
- const { getActiveGoals, recordGoalViolationCaught } = await import("./goal-validator-EM5XVWVC.js");
1799
- const activeGoals = await getActiveGoals(projectPath);
1800
- console.debug("[Initial Scan] Loaded goals for initial scan:", {
1801
- goalCount: activeGoals.length,
1802
- goals: activeGoals.map((g) => ({ id: g.id, description: g.description }))
1803
- });
1804
- if (activeGoals.length === 0) {
1805
- console.debug("[Initial Scan] No active goals found, skipping initial scan");
1806
- return;
1807
- }
1808
- if (!isInteractiveMode()) {
1809
- console.error("[*] Checking recent files against active goals...");
1810
- }
1811
- const recentFiles = /* @__PURE__ */ new Set();
1812
- const uncommittedFiles = await getGitChangedFiles(projectPath);
1813
- if (uncommittedFiles) {
1814
- uncommittedFiles.forEach((f) => recentFiles.add(join2(projectPath, f)));
1815
- }
1816
- const oneDayAgo = Date.now() - 24 * 60 * 60 * 1e3;
1817
- const recentChanges = await getChangedFilesSinceTimestamp(projectPath, oneDayAgo);
1818
- if (recentChanges) {
1819
- recentChanges.forEach((f) => recentFiles.add(f));
1820
- }
1821
- const filesToCheck = Array.from(recentFiles).filter((file) => {
1822
- const ext = extname2(file).toLowerCase();
1823
- return WATCH_EXTENSIONS.has(ext) && existsSync2(file);
1824
- });
1825
- console.debug("[Initial Scan] Files discovered for initial scan:", {
1826
- totalRecentFiles: recentFiles.size,
1827
- filteredFiles: filesToCheck.length,
1828
- filePaths: filesToCheck.slice(0, 5).map((f) => f.replace(projectPath + "/", "")),
1829
- // Show first 5
1830
- watchedExtensions: Array.from(WATCH_EXTENSIONS)
1831
- });
1832
- if (filesToCheck.length === 0) {
1833
- console.debug("[Initial Scan] No recent files found for initial scan");
1834
- return;
1835
- }
1836
- const maxInitialFiles = 10;
1837
- const filesToScan = filesToCheck.slice(0, maxInitialFiles);
1838
- if (!isInteractiveMode()) {
1839
- console.error(` Scanning ${filesToScan.length} recent file(s) against ${activeGoals.length} goal(s)...`);
1840
- }
1841
- const maxCharsPerFile = 3e3;
1842
- const fileContents = await Promise.all(
1843
- filesToScan.map(async (file) => {
1844
- try {
1845
- const content = await readFile2(file, "utf-8");
1846
- const relativePath = file.replace(projectPath + "/", "");
1847
- return { path: relativePath, content: content.slice(0, maxCharsPerFile) };
1848
- } catch {
1849
- return null;
1850
- }
1851
- })
1852
- );
1853
- const valid = fileContents.filter(Boolean);
1854
- if (valid.length === 0) return;
1855
- const filesBlock = valid.map(
1856
- (f) => `### ${f.path}
1857
- \`\`\`
1858
- ${f.content}
1859
- \`\`\``
1860
- ).join("\n\n");
1861
- const goalsSection = `
1862
- USER-DEFINED GOALS (check EVERY file against ALL goals):
1863
- ${activeGoals.map((g, i) => ` ${i + 1}. "${g.description}"`).join("\n")}
1864
-
1865
- This is an INITIAL SCAN at watch startup. Report ALL goal violations you find.
1866
- `;
1867
- const result = await runAIAnalysis({
1868
- systemPrompt: `You are checking code for GOAL VIOLATIONS ONLY.
1869
- ${goalsSection}
1870
- Reply ONLY with a JSON array. Each element must have:
1871
- - "file": relative file path
1872
- - "severity": "critical" | "major" | "minor"
1873
- - "description": 1-sentence description of the goal violation
1874
- - "confidence": number 0-100, how confident you are this is a violation
1875
- - "suggestedFix": 1-sentence description of what should change
1876
- - "isGoalViolation": true (always true for this scan)
1877
- - "goalIndex": 0-based index of the violated goal
1878
-
1879
- Be thorough. If a goal says "no emojis" and you see ANY emoji in the file, report it. If a goal says "no console.log" and you see console.log, report it.
1880
-
1881
- If no violations found, reply with: []
1882
- Output ONLY the JSON array, no markdown fences, no commentary.`,
1883
- userPrompt: `Check these files for goal violations:
1884
-
1885
- ${filesBlock}`,
1886
- maxTokens: 2048,
1887
- temperature: 0.1
1888
- });
1889
- if (result.tokensUsed) {
1890
- this.recordTokenUsage(result.tokensUsed.input + result.tokensUsed.output);
1891
- }
1892
- if (!result.success || !result.content.trim()) return;
1893
- let issues = [];
1894
- try {
1895
- const parsed = JSON.parse(result.content.trim());
1896
- issues = Array.isArray(parsed) ? parsed : [];
1897
- } catch {
1898
- return;
1899
- }
1900
- const issuesToStore = [];
1901
- let violationsFound = 0;
1902
- for (const issue of issues) {
1903
- if (!issue.isGoalViolation || issue.confidence < 40) continue;
1904
- violationsFound++;
1905
- if (issue.goalIndex != null && issue.goalIndex >= 0 && issue.goalIndex < activeGoals.length) {
1906
- const goal = activeGoals[issue.goalIndex];
1907
- if (!goal) continue;
1908
- const fixId = `fix-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
1909
- issuesToStore.push({
1910
- id: fixId,
1911
- file: issue.file,
1912
- agent: "goal-violation",
1913
- severity: issue.severity === "critical" ? "critical" : issue.severity === "major" ? "serious" : "moderate",
1914
- issue: `Goal "${goal.description}" violated: ${issue.description}`,
1915
- fix: issue.suggestedFix || "Review and fix",
1916
- category: "goal-violation",
1917
- confidence: issue.confidence,
1918
- autoFixable: true
1919
- });
1920
- await recordGoalViolationCaught(goal, issue.file, projectPath);
1921
- const confidenceStr = issue.confidence >= 80 ? "high" : issue.confidence >= 60 ? "medium" : "low";
1922
- const nudgeMsg = `Goal "${goal.description}" violated in ${issue.file}: ${issue.description} [${confidenceStr} confidence]`;
1923
- getOutputManager().nudge(nudgeMsg, "warning", issue.file);
1924
- await this.persistNudge({
1925
- message: nudgeMsg,
1926
- severity: "warning",
1927
- file: issue.file,
1928
- category: "quality",
1929
- goalId: goal.id,
1930
- priority: issue.confidence >= 80 ? 8 : issue.confidence >= 60 ? 6 : 4,
1931
- ...issue.suggestedFix && { suggestedAction: issue.suggestedFix }
1932
- });
1933
- }
1934
- }
1935
- if (issuesToStore.length > 0) {
1936
- await storeIssues(issuesToStore, basename2(projectPath), projectPath);
1937
- }
1938
- if (!isInteractiveMode()) {
1939
- if (violationsFound > 0) {
1940
- console.error(` [!] Found ${violationsFound} goal violation(s) in recent files`);
1941
- } else {
1942
- console.error(` [\u2713] No goal violations found in recent files`);
1943
- }
1944
- }
1945
- } catch (error) {
1946
- if (!isInteractiveMode()) {
1947
- console.error(` [!] Initial goal scan error: ${error}`);
1948
- }
1949
- }
1950
- }
1951
- async syncPipelineIntegrations() {
1952
- const projectPath = this.watchedDirectory || getWorkingDirectory(void 0, true);
1953
- try {
1954
- const config = await loadConfig();
1955
- const hasLinear = !!(config.apiKeys?.linear ?? process.env.LINEAR_API_KEY);
1956
- const hasGithub = !!(config.apiKeys?.github ?? process.env.GITHUB_TOKEN);
1957
- if (!hasLinear && !hasGithub) return;
1958
- const graph = new ContextGraph(projectPath);
1959
- if (hasLinear) {
1960
- try {
1961
- const { LinearIngester: LinearIngester2 } = await import("./linear-ingester-WIUBWF55.js");
1962
- const ingester = new LinearIngester2(projectPath, graph);
1963
- await ingester.syncTickets();
1964
- if (!isInteractiveMode()) {
1965
- console.error("[Pipeline] Linear tickets synced");
1966
- }
1967
- } catch (error) {
1968
- if (!isInteractiveMode()) {
1969
- console.error(`[Pipeline] Linear sync failed: ${error}`);
1970
- }
1971
- }
1972
- }
1973
- if (hasGithub) {
1974
- try {
1975
- const { GitHubIngester: GitHubIngester2 } = await import("./github-ingester-C66ZRUYC.js");
1976
- const ingester = new GitHubIngester2(graph);
1977
- const token = await ingester.getApiToken();
1978
- const repoInfo = ingester.getRepoInfo(projectPath);
1979
- if (repoInfo) {
1980
- await ingester.syncPullRequests(repoInfo.owner, repoInfo.name, token);
1981
- await ingester.syncIssues(repoInfo.owner, repoInfo.name, token);
1982
- if (!isInteractiveMode()) {
1983
- console.error("[Pipeline] GitHub PRs/issues synced");
1984
- }
1985
- }
1986
- } catch (error) {
1987
- if (!isInteractiveMode()) {
1988
- console.error(`[Pipeline] GitHub sync failed: ${error}`);
1989
- }
1990
- }
1991
- }
1992
- } catch {
1993
- }
1994
- }
1995
- async stopWatching() {
1996
- if (!this.state.isRunning) {
1997
- return {
1998
- content: [{
1999
- type: "text",
2000
- text: "[!] Watch mode is not running."
2001
- }]
2002
- };
2003
- }
2004
- for (const watcher of this.watchers.values()) {
2005
- watcher.close();
2006
- }
2007
- this.watchers.clear();
2008
- if (this.extractionPipeline) {
2009
- this.extractionPipeline.close();
2010
- this.extractionPipeline = null;
2011
- }
2012
- if (this.pipelineSyncTimer) {
2013
- clearInterval(this.pipelineSyncTimer);
2014
- this.pipelineSyncTimer = null;
2015
- }
2016
- if (this.codebaseIndex) {
2017
- await this.codebaseIndex.save();
2018
- this.codebaseIndex = null;
2019
- }
2020
- if (this.state.scanDebounceTimer) {
2021
- clearTimeout(this.state.scanDebounceTimer);
2022
- }
2023
- this.state.isRunning = false;
2024
- if (!isInteractiveMode()) {
2025
- console.error("\n[*] Watch mode stopped.\n");
2026
- }
2027
- if (this.streamingManager) {
2028
- this.streamingManager.reportWatchStatus({ watching: false, directories: 0 });
2029
- }
2030
- const outputManager = getOutputManager();
2031
- outputManager.clearTUICallbacks();
2032
- outputManager.setMode("console");
2033
- if (this.dashboard) {
2034
- this.dashboard.stop();
2035
- this.dashboard = void 0;
2036
- }
2037
- const budget = this.state.tokenBudget;
2038
- const tokensK = (budget.used / 1e3).toFixed(1);
2039
- return {
2040
- content: [{
2041
- type: "text",
2042
- text: `[*] **TRIE AGENT STOPPED**
2043
-
2044
- ### Session Summary:
2045
- - Files scanned: ${this.state.filesScanned}
2046
- - Issues found: ${this.state.totalIssuesFound}
2047
- - Tokens used: ${tokensK}k / ${(budget.hourlyLimit / 1e3).toFixed(0)}k hourly limit
2048
- - Scans skipped (trie-throttled): ${budget.scansSaved}
2049
- - Governance ledger: Updated continuously
2050
-
2051
- Use \`trie_watch start\` to resume.`
2052
- }]
2053
- };
2054
- }
2055
- async getStatus() {
2056
- if (!this.state.isRunning) {
2057
- return {
2058
- content: [{
2059
- type: "text",
2060
- text: `[*] **Watch Mode Status: STOPPED**
2061
-
2062
- Use \`trie_watch start\` to begin autonomous scanning.`
2063
- }]
2064
- };
2065
- }
2066
- const recentScans = Array.from(this.state.lastScan.entries()).sort((a, b) => b[1] - a[1]).slice(0, 5).map(([file, time]) => {
2067
- const ago = Math.round((Date.now() - time) / 1e3);
2068
- return `- \`${basename2(file)}\` (${ago}s ago)`;
2069
- }).join("\n");
2070
- const recentNudges = this.state.nudges.slice(-3).map(
2071
- (n) => `- ${basename2(n.file)} [${n.severity}] @ ${n.timestamp}`
2072
- ).join("\n");
2073
- let agencyStatus = "";
2074
- try {
2075
- const { getTrieAgent } = await import("./trie-agent-GJJJCL6P.js");
2076
- const trieAgent = getTrieAgent(this.watchedDirectory || getWorkingDirectory(void 0, true));
2077
- await trieAgent.initialize();
2078
- const status = await trieAgent.getAgencyStatus();
2079
- agencyStatus = `
2080
- ### [AI] Trie Agent:
2081
- - **Goals:** ${status.goals.active} active, ${status.goals.completed} completed${status.goals.topGoal ? ` (${status.goals.topGoal.slice(0, 40)}...)` : ""}
2082
- - **Hypotheses:** ${status.hypotheses.testing} testing, ${status.hypotheses.validated} validated
2083
- - **Risk Level:** ${status.riskLevel.toUpperCase()}
2084
- - **Effectiveness:** ${status.effectiveness}%
2085
- - **Scan Frequency:** ${Math.round(status.scanFrequency / 1e3)}s${status.isQuietHours ? " (quiet hours)" : ""}`;
2086
- } catch {
2087
- }
2088
- const budget = this.state.tokenBudget;
2089
- const remaining = this.getRemainingBudget();
2090
- const tokensK = (budget.used / 1e3).toFixed(1);
2091
- const remainingK = (remaining / 1e3).toFixed(1);
2092
- return {
2093
- content: [{
2094
- type: "text",
2095
- text: `[*] **WATCH MODE Status: RUNNING**
2096
-
2097
- ### Stats:
2098
- - Directories watched: ${this.watchers.size}
2099
- - Files scanned: ${this.state.filesScanned}
2100
- - Issues found: ${this.state.totalIssuesFound}
2101
- - Pending: ${this.state.pendingFiles.size}
2102
-
2103
- ### Token Budget:
2104
- - Used: ${tokensK}k / ${(budget.hourlyLimit / 1e3).toFixed(0)}k hourly
2105
- - Remaining: ${remainingK}k
2106
- - Scans skipped (trie-throttled): ${budget.scansSaved}
2107
- ${agencyStatus}
2108
-
2109
- ### Recently Scanned:
2110
- ${recentScans || "(none yet)"}
2111
-
2112
- ### Recent Nudges:
2113
- ${recentNudges || "(none)"}
2114
-
2115
- ### Commands:
2116
- - \`trie_watch issues\` - Get all issues found
2117
- - \`trie_watch stop\` - Stop watching`
2118
- }]
2119
- };
2120
- }
2121
- /**
2122
- * Helper to persist a nudge to both in-memory state and SQL storage
2123
- */
2124
- async persistNudge(params) {
2125
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
2126
- const nudgeId = createHash("sha256").update(`${params.message}|${params.file || ""}|${timestamp}`).digest("hex").slice(0, 16);
2127
- const nudge = {
2128
- id: nudgeId,
2129
- message: params.message,
2130
- severity: params.severity,
2131
- timestamp,
2132
- resolved: false,
2133
- dismissed: false,
2134
- priority: params.priority ?? 5,
2135
- relatedIssues: params.relatedIssues ?? [],
2136
- metadata: {},
2137
- ...params.file && { file: params.file },
2138
- ...params.category && { category: params.category },
2139
- ...params.goalId && { goalId: params.goalId },
2140
- ...params.suggestedAction && { suggestedAction: params.suggestedAction }
2141
- };
2142
- this.state.nudges.push({
2143
- file: params.file || "unknown",
2144
- // Keep full path for consistency with loaded nudges
2145
- message: params.message,
2146
- severity: params.severity === "warning" || params.severity === "info" ? "high" : params.severity,
2147
- timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false })
2148
- });
2149
- try {
2150
- const storage = getStorage(this.watchedDirectory);
2151
- await storage.storeNudge(nudge);
2152
- console.debug(`[Watch] \u2713 Persisted nudge to storage: ${nudge.message.slice(0, 60)}...`);
2153
- } catch (error) {
2154
- console.error("[Watch] Failed to persist nudge to storage:", error);
2155
- }
2156
- }
2157
- getNudges() {
2158
- return {
2159
- content: [
2160
- {
2161
- type: "text",
2162
- text: `[#] Recent nudges (${this.state.nudges.length} this session)
2163
- ` + (this.state.nudges.length ? this.state.nudges.map(
2164
- (n) => `- ${basename2(n.file)} [${n.severity}] @ ${n.timestamp}
2165
- ${n.message}`
2166
- ).join("\n") : "(none)")
2167
- },
2168
- {
2169
- type: "json",
2170
- json: this.state.nudges
2171
- }
2172
- ]
2173
- };
2174
- }
2175
- getCurrentIssues() {
2176
- return {
2177
- content: [{
2178
- type: "text",
2179
- text: `[L] **Issues Found This Session**
2180
-
2181
- Total issues: ${this.state.totalIssuesFound}
2182
- Files scanned: ${this.state.filesScanned}
2183
-
2184
- To get a full report, run \`trie watch\` on your codebase.`
2185
- }]
2186
- };
2187
- }
2188
- };
2189
-
2190
781
  // src/tools/pr-review.ts
2191
- import { readFile as readFile3 } from "fs/promises";
2192
- import { existsSync as existsSync3 } from "fs";
2193
- import { join as join3, basename as basename3, resolve as resolve2, isAbsolute as isAbsolute2 } from "path";
782
+ import { readFile as readFile2 } from "fs/promises";
783
+ import { existsSync as existsSync2 } from "fs";
784
+ import { join as join2, basename as basename2, resolve as resolve2, isAbsolute as isAbsolute2 } from "path";
2194
785
  var TriePRReviewTool = class {
2195
786
  // Review workflow is now ledger-driven; keep a lightweight built-in checklist.
2196
787
  CRITICAL_REVIEW_CHECKLIST = {
@@ -2289,14 +880,14 @@ Usage:
2289
880
  async getPRInfo(pr, worktree) {
2290
881
  if (worktree) {
2291
882
  const worktreePath = isAbsolute2(worktree) ? worktree : resolve2(getWorkingDirectory(void 0, true), worktree);
2292
- if (!existsSync3(worktreePath)) {
883
+ if (!existsSync2(worktreePath)) {
2293
884
  return { success: false, error: `Worktree not found: ${worktreePath}` };
2294
885
  }
2295
886
  return {
2296
887
  success: true,
2297
888
  type: "worktree",
2298
889
  path: worktreePath,
2299
- title: `Local changes in ${basename3(worktreePath)}`,
890
+ title: `Local changes in ${basename2(worktreePath)}`,
2300
891
  author: this.getGitUser(),
2301
892
  baseBranch: "HEAD~1",
2302
893
  headBranch: "HEAD"
@@ -2452,8 +1043,8 @@ Usage:
2452
1043
  "rfcs"
2453
1044
  ];
2454
1045
  for (const docPath of designDocPaths) {
2455
- const fullPath = join3(cwd, docPath);
2456
- if (existsSync3(fullPath)) {
1046
+ const fullPath = join2(cwd, docPath);
1047
+ if (existsSync2(fullPath)) {
2457
1048
  }
2458
1049
  }
2459
1050
  return designDocs;
@@ -2466,9 +1057,9 @@ Usage:
2466
1057
  const cwd = getWorkingDirectory(void 0, true);
2467
1058
  await Promise.all(filePaths.map(async (filePath) => {
2468
1059
  try {
2469
- const fullPath = isAbsolute2(filePath) ? filePath : join3(cwd, filePath);
2470
- if (existsSync3(fullPath)) {
2471
- const content = await readFile3(fullPath, "utf-8");
1060
+ const fullPath = isAbsolute2(filePath) ? filePath : join2(cwd, filePath);
1061
+ if (existsSync2(fullPath)) {
1062
+ const content = await readFile2(fullPath, "utf-8");
2472
1063
  contents.set(filePath, content);
2473
1064
  }
2474
1065
  } catch {
@@ -4157,9 +2748,9 @@ var ToolRegistry = class {
4157
2748
  };
4158
2749
 
4159
2750
  // src/server/resource-manager.ts
4160
- import { readdir, readFile as readFile4 } from "fs/promises";
4161
- import { existsSync as existsSync4 } from "fs";
4162
- import { join as join4, dirname as dirname2 } from "path";
2751
+ import { readdir, readFile as readFile3 } from "fs/promises";
2752
+ import { existsSync as existsSync3 } from "fs";
2753
+ import { join as join3, dirname as dirname2 } from "path";
4163
2754
  import { fileURLToPath } from "url";
4164
2755
  var UI_APPS = {
4165
2756
  "ledger": {
@@ -4263,7 +2854,7 @@ var ResourceManager = class {
4263
2854
  }
4264
2855
  async getScanReportResources() {
4265
2856
  try {
4266
- const reportsDir = join4(getWorkingDirectory(void 0, true), "trie-reports");
2857
+ const reportsDir = join3(getWorkingDirectory(void 0, true), "trie-reports");
4267
2858
  const files = await readdir(reportsDir);
4268
2859
  const reportFiles = files.filter((f) => f.endsWith(".txt") || f.endsWith(".json"));
4269
2860
  return reportFiles.slice(0, 10).map((file) => ({
@@ -4340,10 +2931,10 @@ var ResourceManager = class {
4340
2931
  async getUIAppResource(uri, appId) {
4341
2932
  const currentFile = fileURLToPath(import.meta.url);
4342
2933
  const distDir = dirname2(dirname2(currentFile));
4343
- const uiDir = join4(distDir, "ui");
4344
- const htmlPath = join4(uiDir, `${appId}.html`);
2934
+ const uiDir = join3(distDir, "ui");
2935
+ const htmlPath = join3(uiDir, `${appId}.html`);
4345
2936
  try {
4346
- if (!existsSync4(htmlPath)) {
2937
+ if (!existsSync3(htmlPath)) {
4347
2938
  return {
4348
2939
  contents: [{
4349
2940
  uri,
@@ -4352,7 +2943,7 @@ var ResourceManager = class {
4352
2943
  }]
4353
2944
  };
4354
2945
  }
4355
- const content = await readFile4(htmlPath, "utf-8");
2946
+ const content = await readFile3(htmlPath, "utf-8");
4356
2947
  return {
4357
2948
  contents: [{
4358
2949
  uri,
@@ -4524,10 +3115,10 @@ var ResourceManager = class {
4524
3115
  summary.push("| `trie_init` | Initialize bootstrap files |");
4525
3116
  summary.push("");
4526
3117
  summary.push("---", "", "# Detailed Context", "");
4527
- const agentsMdPath = join4(getTrieDirectory(workDir), "AGENTS.md");
3118
+ const agentsMdPath = join3(getTrieDirectory(workDir), "AGENTS.md");
4528
3119
  try {
4529
- if (existsSync4(agentsMdPath)) {
4530
- const agentsContent = await readFile4(agentsMdPath, "utf-8");
3120
+ if (existsSync3(agentsMdPath)) {
3121
+ const agentsContent = await readFile3(agentsMdPath, "utf-8");
4531
3122
  summary.push(agentsContent);
4532
3123
  } else {
4533
3124
  const contextSummary = await getContextForAI();
@@ -4617,8 +3208,8 @@ This information is automatically available to Claude Code, Cursor, and other AI
4617
3208
  }
4618
3209
  async getCacheStatsResource(uri) {
4619
3210
  try {
4620
- const cachePath = join4(getTrieDirectory(getWorkingDirectory(void 0, true)), ".trie-cache.json");
4621
- const cacheContent = await readFile4(cachePath, "utf-8");
3211
+ const cachePath = join3(getTrieDirectory(getWorkingDirectory(void 0, true)), ".trie-cache.json");
3212
+ const cacheContent = await readFile3(cachePath, "utf-8");
4622
3213
  const cache = JSON.parse(cacheContent);
4623
3214
  const fileCount = Object.keys(cache.files || {}).length;
4624
3215
  const totalVulns = Object.values(cache.files || {}).reduce((acc, file) => {
@@ -4652,8 +3243,8 @@ This information is automatically available to Claude Code, Cursor, and other AI
4652
3243
  }
4653
3244
  }
4654
3245
  async getSignaturesResource(uri) {
4655
- const { getVulnerabilityStats } = await import("./vulnerability-signatures-EIJQX2TS.js");
4656
- const { getVibeCodeStats } = await import("./vibe-code-signatures-ELEWJFGZ.js");
3246
+ const { getVulnerabilityStats } = await import("./vulnerability-signatures-EIKOHFPK.js");
3247
+ const { getVibeCodeStats } = await import("./vibe-code-signatures-J4GD4JOV.js");
4657
3248
  const vulnStats = getVulnerabilityStats();
4658
3249
  const vibeStats = getVibeCodeStats();
4659
3250
  return {
@@ -4670,9 +3261,9 @@ This information is automatically available to Claude Code, Cursor, and other AI
4670
3261
  }
4671
3262
  async getScanReportResource(uri, parsedUri) {
4672
3263
  const fileName = parsedUri.replace("reports/", "");
4673
- const reportPath = join4(getWorkingDirectory(void 0, true), "trie-reports", fileName);
3264
+ const reportPath = join3(getWorkingDirectory(void 0, true), "trie-reports", fileName);
4674
3265
  try {
4675
- const content = await readFile4(reportPath, "utf-8");
3266
+ const content = await readFile3(reportPath, "utf-8");
4676
3267
  return {
4677
3268
  contents: [{
4678
3269
  uri,