@triedotdev/mcp 1.0.127 → 1.0.129

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.
@@ -975,6 +975,8 @@ function Footer() {
975
975
  hints = narrow ? "enter esc" : "enter save \xB7 esc cancel";
976
976
  } else if (view === "hypotheses" && hypothesesPanel.inputMode === "add") {
977
977
  hints = narrow ? "enter esc" : "enter save \xB7 esc cancel";
978
+ } else if (view === "chat" || view === "chat-archive") {
979
+ hints = "";
978
980
  } else {
979
981
  const hintMap = narrow ? CONTEXT_HINTS_SHORT : CONTEXT_HINTS;
980
982
  hints = hintMap[view] || (narrow ? "/" : "/ help");
@@ -995,7 +997,7 @@ function Footer() {
995
997
  !isLast && /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: " \xB7 " })
996
998
  ] }, v);
997
999
  }) }),
998
- /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
1000
+ hints && /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
999
1001
  hints,
1000
1002
  " \xB7 q quit"
1001
1003
  ] })
@@ -1016,7 +1018,7 @@ function Footer() {
1016
1018
  !isLast && /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: " \xB7 " })
1017
1019
  ] }, v);
1018
1020
  }) }),
1019
- /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
1021
+ hints && /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
1020
1022
  hints,
1021
1023
  " \xB7 q quit"
1022
1024
  ] })
@@ -1043,12 +1045,12 @@ function Notification() {
1043
1045
  }
1044
1046
 
1045
1047
  // src/cli/dashboard/components/ConfigDialog.tsx
1046
- import { useState } from "react";
1048
+ import React3, { useState } from "react";
1047
1049
  import { Box as Box4, Text as Text4, useInput } from "ink";
1048
1050
  import { existsSync } from "fs";
1049
1051
  import { rm } from "fs/promises";
1050
1052
  import { join } from "path";
1051
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1053
+ import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1052
1054
  function maskKey(key) {
1053
1055
  if (!key || key.length < 12) return "Not set";
1054
1056
  return key.slice(0, 7) + "..." + key.slice(-4);
@@ -1062,11 +1064,33 @@ function ConfigDialog({ onClose }) {
1062
1064
  const [editIsText, setEditIsText] = useState(false);
1063
1065
  const [showConfirmClear, setShowConfirmClear] = useState(false);
1064
1066
  const [clearingMemory, setClearingMemory] = useState(false);
1067
+ const [indexStats, setIndexStats] = useState(null);
1068
+ const [indexing, setIndexing] = useState(false);
1065
1069
  const config = state.agentConfig;
1070
+ React3.useEffect(() => {
1071
+ if (section === "codebaseIndex") {
1072
+ const loadStats = async () => {
1073
+ try {
1074
+ const workDir = getWorkingDirectory(void 0, true);
1075
+ const { CodebaseIndex } = await import("./codebase-index-CR6Q2HEI.js");
1076
+ const index = new CodebaseIndex(workDir);
1077
+ const stats = index.getStats();
1078
+ setIndexStats({
1079
+ fileCount: stats.fileCount,
1080
+ lastUpdated: stats.lastUpdated || "Never"
1081
+ });
1082
+ } catch {
1083
+ setIndexStats(null);
1084
+ }
1085
+ };
1086
+ void loadStats();
1087
+ }
1088
+ }, [section]);
1066
1089
  const currentKeyDisplay = isAIAvailable() ? maskKey(getKeyFromKeychain() || process.env.ANTHROPIC_API_KEY || null) : "Not set";
1067
1090
  const keyActive = isAIAvailable();
1068
1091
  const mainMenu = [
1069
1092
  { label: "API Keys", key: "apiKeys", value: keyActive ? "Active" : "Not set", section: "main" },
1093
+ { label: "Codebase Index", key: "codebaseIndex", value: "Stats & Re-index", section: "main" },
1070
1094
  { label: "AI Watcher", key: "aiWatcher", value: config.aiWatcher.enabled ? `${(config.aiWatcher.hourlyTokenLimit / 1e3).toFixed(0)}k/hr` : "Off", section: "main" },
1071
1095
  { label: "Performance", key: "performance", value: `${config.performance.maxConcurrency} concurrent`, section: "main" },
1072
1096
  { label: "Risk Thresholds", key: "riskThresholds", value: `critical: ${config.riskThresholds.critical}%`, section: "main" },
@@ -1098,7 +1122,11 @@ function ConfigDialog({ onClose }) {
1098
1122
  const memoryItems = [
1099
1123
  { label: "Clear All Memory", key: "clearAll", value: "Reset ledger, context graph", section: "memory" }
1100
1124
  ];
1101
- const items = section === "main" ? mainMenu : section === "apiKeys" ? apiKeysItems : section === "performance" ? performanceItems : section === "riskThresholds" ? riskItems : section === "aiWatcher" ? aiWatcherItems : section === "memory" ? memoryItems : mainMenu;
1125
+ const codebaseIndexItems = [
1126
+ { label: "Re-index Codebase", key: "reindex", value: "Rebuild full index", section: "codebaseIndex" },
1127
+ { label: "Clear Index", key: "clearIndex", value: "Delete index cache", section: "codebaseIndex" }
1128
+ ];
1129
+ const items = section === "main" ? mainMenu : section === "apiKeys" ? apiKeysItems : section === "performance" ? performanceItems : section === "riskThresholds" ? riskItems : section === "aiWatcher" ? aiWatcherItems : section === "memory" ? memoryItems : section === "codebaseIndex" ? codebaseIndexItems : mainMenu;
1102
1130
  useInput((_input, key) => {
1103
1131
  if (showConfirmClear) {
1104
1132
  if (_input === "y" || _input === "Y") {
@@ -1191,6 +1219,40 @@ function ConfigDialog({ onClose }) {
1191
1219
  if (item && item.key === "clearAll") {
1192
1220
  setShowConfirmClear(true);
1193
1221
  }
1222
+ } else if (section === "codebaseIndex") {
1223
+ const item = items[selectedIndex];
1224
+ if (item && item.key === "reindex") {
1225
+ setIndexing(true);
1226
+ reindexCodebase().then(() => {
1227
+ dispatch({ type: "ADD_ACTIVITY", message: "Codebase re-indexed successfully" });
1228
+ setIndexing(false);
1229
+ const loadStats = async () => {
1230
+ try {
1231
+ const workDir = getWorkingDirectory(void 0, true);
1232
+ const { CodebaseIndex } = await import("./codebase-index-CR6Q2HEI.js");
1233
+ const index = new CodebaseIndex(workDir);
1234
+ const stats = index.getStats();
1235
+ setIndexStats({
1236
+ fileCount: stats.fileCount,
1237
+ lastUpdated: stats.lastUpdated || "Never"
1238
+ });
1239
+ } catch {
1240
+ setIndexStats(null);
1241
+ }
1242
+ };
1243
+ void loadStats();
1244
+ }).catch(() => {
1245
+ dispatch({ type: "ADD_ACTIVITY", message: "Failed to re-index codebase" });
1246
+ setIndexing(false);
1247
+ });
1248
+ } else if (item && item.key === "clearIndex") {
1249
+ clearCodebaseIndex().then(() => {
1250
+ dispatch({ type: "ADD_ACTIVITY", message: "Index cleared" });
1251
+ setIndexStats({ fileCount: 0, lastUpdated: "Never" });
1252
+ }).catch(() => {
1253
+ dispatch({ type: "ADD_ACTIVITY", message: "Failed to clear index" });
1254
+ });
1255
+ }
1194
1256
  } else {
1195
1257
  const item = items[selectedIndex];
1196
1258
  if (item) {
@@ -1213,7 +1275,7 @@ function ConfigDialog({ onClose }) {
1213
1275
  }
1214
1276
  }
1215
1277
  });
1216
- const sectionTitle = section === "main" ? "Settings" : section === "apiKeys" ? "API Keys" : section === "aiWatcher" ? "AI Watcher" : section === "performance" ? "Performance" : section === "riskThresholds" ? "Risk Thresholds" : section === "memory" ? "Memory" : "Settings";
1278
+ const sectionTitle = section === "main" ? "Settings" : section === "apiKeys" ? "API Keys" : section === "aiWatcher" ? "AI Watcher" : section === "performance" ? "Performance" : section === "riskThresholds" ? "Risk Thresholds" : section === "memory" ? "Memory" : section === "codebaseIndex" ? "Codebase Index" : "Settings";
1217
1279
  async function clearMemory() {
1218
1280
  const workDir = getWorkingDirectory(void 0, true);
1219
1281
  const trieDir = getTrieDirectory(workDir);
@@ -1232,6 +1294,40 @@ function ConfigDialog({ onClose }) {
1232
1294
  }
1233
1295
  }
1234
1296
  }
1297
+ async function clearCodebaseIndex() {
1298
+ const workDir = getWorkingDirectory(void 0, true);
1299
+ const trieDir = getTrieDirectory(workDir);
1300
+ const indexFile = join(trieDir, "codebase-index.json");
1301
+ if (existsSync(indexFile)) {
1302
+ await rm(indexFile, { force: true });
1303
+ }
1304
+ }
1305
+ async function reindexCodebase() {
1306
+ const workDir = getWorkingDirectory(void 0, true);
1307
+ const { CodebaseIndex } = await import("./codebase-index-CR6Q2HEI.js");
1308
+ const { glob } = await import("glob");
1309
+ const index = new CodebaseIndex(workDir);
1310
+ const indexPattern = `${workDir}/**/*.{ts,tsx,js,jsx,mjs,vue,svelte,astro,py,go,rs,java,c,cpp,h,hpp,cs,rb,php,css,scss,html}`;
1311
+ const indexFiles = await glob(indexPattern, {
1312
+ ignore: ["**/node_modules/**", "**/dist/**", "**/build/**", "**/.git/**", "**/.trie/**", "**/coverage/**"],
1313
+ nodir: true
1314
+ });
1315
+ let indexed = 0;
1316
+ const total = Math.min(indexFiles.length, 500);
1317
+ for (let i = 0; i < total; i++) {
1318
+ const filePath = indexFiles[i];
1319
+ if (!filePath) continue;
1320
+ let relativePath = filePath;
1321
+ if (filePath.toLowerCase().startsWith(workDir.toLowerCase() + "/")) {
1322
+ relativePath = filePath.slice(workDir.length + 1);
1323
+ } else if (filePath.startsWith("/")) {
1324
+ continue;
1325
+ }
1326
+ const result = await index.indexFile(relativePath);
1327
+ if (result) indexed++;
1328
+ }
1329
+ await index.save();
1330
+ }
1235
1331
  return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingX: 1, children: [
1236
1332
  /* @__PURE__ */ jsx5(Text4, { bold: true, children: sectionTitle }),
1237
1333
  showConfirmClear && /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, children: [
@@ -1251,6 +1347,35 @@ function ConfigDialog({ onClose }) {
1251
1347
  /* @__PURE__ */ jsx5(Text4, { dimColor: true, children: " Reset ledger, context graph, issue store" }),
1252
1348
  /* @__PURE__ */ jsx5(Text4, { dimColor: true, children: " enter to clear \xB7 esc back" })
1253
1349
  ] }),
1350
+ !showConfirmClear && section === "codebaseIndex" && /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, children: [
1351
+ indexStats ? /* @__PURE__ */ jsxs4(Fragment, { children: [
1352
+ /* @__PURE__ */ jsxs4(Text4, { children: [
1353
+ " ",
1354
+ /* @__PURE__ */ jsx5(Text4, { bold: true, children: "Files indexed:" }),
1355
+ " ",
1356
+ indexStats.fileCount
1357
+ ] }),
1358
+ /* @__PURE__ */ jsxs4(Text4, { children: [
1359
+ " ",
1360
+ /* @__PURE__ */ jsx5(Text4, { bold: true, children: "Last updated:" }),
1361
+ " ",
1362
+ indexStats.lastUpdated
1363
+ ] }),
1364
+ /* @__PURE__ */ jsx5(Text4, { dimColor: true, marginTop: 1, children: " Actions:" })
1365
+ ] }) : /* @__PURE__ */ jsx5(Text4, { dimColor: true, children: " Loading index stats..." }),
1366
+ codebaseIndexItems.map((item, idx) => {
1367
+ const isSelected = selectedIndex === idx;
1368
+ return /* @__PURE__ */ jsxs4(Text4, { children: [
1369
+ isSelected ? /* @__PURE__ */ jsx5(Text4, { bold: true, color: "green", children: "> " }) : " ",
1370
+ /* @__PURE__ */ jsx5(Text4, { bold: isSelected, children: item.label }),
1371
+ /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
1372
+ " ",
1373
+ item.value
1374
+ ] })
1375
+ ] }, item.key);
1376
+ }),
1377
+ indexing ? /* @__PURE__ */ jsx5(Text4, { dimColor: true, marginTop: 1, children: " Re-indexing codebase..." }) : /* @__PURE__ */ jsx5(Text4, { dimColor: true, marginTop: 1, children: " enter to execute \xB7 esc back" })
1378
+ ] }),
1254
1379
  !showConfirmClear && section === "apiKeys" && !editing && /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, children: [
1255
1380
  /* @__PURE__ */ jsxs4(Text4, { children: [
1256
1381
  " ",
@@ -1268,7 +1393,7 @@ function ConfigDialog({ onClose }) {
1268
1393
  ] }) }),
1269
1394
  /* @__PURE__ */ jsx5(Text4, { dimColor: true, children: " enter save \xB7 esc cancel" })
1270
1395
  ] }),
1271
- !showConfirmClear && section !== "apiKeys" && section !== "memory" && /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, children: [
1396
+ !showConfirmClear && section !== "apiKeys" && section !== "memory" && section !== "codebaseIndex" && /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, children: [
1272
1397
  items.map((item, idx) => {
1273
1398
  const isSelected = selectedIndex === idx;
1274
1399
  return /* @__PURE__ */ jsxs4(Text4, { children: [
@@ -1406,7 +1531,7 @@ function HelpDialog({ view }) {
1406
1531
 
1407
1532
  // src/cli/dashboard/views/OverviewView.tsx
1408
1533
  import { Box as Box6, Text as Text6, useInput as useInput2, useStdout as useStdout4 } from "ink";
1409
- import { Fragment, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1534
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1410
1535
  function truncate(str, max) {
1411
1536
  return str.length > max ? str.slice(0, max - 1) + "..." : str;
1412
1537
  }
@@ -1504,7 +1629,7 @@ function OverviewView() {
1504
1629
  fix.confidence,
1505
1630
  "%"
1506
1631
  ] }),
1507
- narrow ? fix.status === "applying" && /* @__PURE__ */ jsx7(Text6, { color: "cyan", children: " applying..." }) : /* @__PURE__ */ jsxs6(Fragment, { children: [
1632
+ narrow ? fix.status === "applying" && /* @__PURE__ */ jsx7(Text6, { color: "cyan", children: " applying..." }) : /* @__PURE__ */ jsxs6(Fragment2, { children: [
1508
1633
  /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
1509
1634
  " confidence fix: ",
1510
1635
  truncate(fix.suggestedFix, contentWidth - 25)
@@ -1762,7 +1887,7 @@ function AgentView() {
1762
1887
  // src/cli/dashboard/views/GoalsView.tsx
1763
1888
  import { useCallback as useCallback2 } from "react";
1764
1889
  import { Box as Box8, Text as Text8, useInput as useInput4 } from "ink";
1765
- import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1890
+ import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1766
1891
  function calculateGoalProgress(goal) {
1767
1892
  if (goal.target <= 0) return 0;
1768
1893
  const startValue = goal.startValue ?? goal.currentValue;
@@ -1886,14 +2011,7 @@ function GoalsView() {
1886
2011
  const goal = goalsPanel.goals.find((g) => g.id === goalId);
1887
2012
  if (!goal) return;
1888
2013
  dispatch({ type: "ADD_ACTIVITY", message: `Checking goal: ${goal.description.slice(0, 30)}...` });
1889
- const { CodebaseIndex } = await import("./codebase-index-CR6Q2HEI.js");
1890
- const codebaseIndex = new CodebaseIndex(workDir);
1891
- if (codebaseIndex.isEmpty()) {
1892
- dispatch({ type: "SHOW_NOTIFICATION", message: `Building codebase index (one-time)... This will speed up future checks.`, severity: "info", autoHideMs: 1e4 });
1893
- dispatch({ type: "ADD_ACTIVITY", message: `Building codebase index...` });
1894
- } else {
1895
- dispatch({ type: "SHOW_NOTIFICATION", message: `Scanning files...`, severity: "info", autoHideMs: 5e3 });
1896
- }
2014
+ dispatch({ type: "SHOW_NOTIFICATION", message: `Scanning files...`, severity: "info", autoHideMs: 5e3 });
1897
2015
  const { checkFilesForGoalViolations } = await import("./goal-validator-NLOJJ7FF.js");
1898
2016
  const violations = await checkFilesForGoalViolations([goal], workDir);
1899
2017
  if (violations.length === 0) {
@@ -1962,7 +2080,7 @@ function GoalsView() {
1962
2080
  /* @__PURE__ */ jsx9(Text8, { bold: true, color: "green", children: "|" })
1963
2081
  ] }) }),
1964
2082
  /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: " enter save \xB7 esc cancel" })
1965
- ] }) : /* @__PURE__ */ jsx9(Fragment2, { children: goalsPanel.goals.length === 0 ? /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: " No goals yet. Press a to add one." }) : /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
2083
+ ] }) : /* @__PURE__ */ jsx9(Fragment3, { children: goalsPanel.goals.length === 0 ? /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: " No goals yet. Press a to add one." }) : /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
1966
2084
  activeGoals.length === 0 && goalsPanel.goals.length > 0 && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginBottom: 1, paddingX: 1, borderStyle: "round", borderColor: "yellow", children: [
1967
2085
  /* @__PURE__ */ jsx9(Text8, { color: "yellow", bold: true, children: "\u26A0 No Active Goals" }),
1968
2086
  /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: "Goals exist but none are active. Violations won't be detected." }),
@@ -2020,7 +2138,7 @@ function GoalsView() {
2020
2138
  // src/cli/dashboard/views/HypothesesView.tsx
2021
2139
  import { useCallback as useCallback3 } from "react";
2022
2140
  import { Box as Box9, Text as Text9, useInput as useInput5 } from "ink";
2023
- import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
2141
+ import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
2024
2142
  function HypothesesView() {
2025
2143
  const { state, dispatch } = useDashboard();
2026
2144
  const { hypothesesPanel } = state;
@@ -2095,14 +2213,7 @@ function HypothesesView() {
2095
2213
  const hypo = hypothesesPanel.hypotheses.find((h) => h.id === hypoId);
2096
2214
  if (!hypo) return;
2097
2215
  dispatch({ type: "ADD_ACTIVITY", message: `Testing hypothesis: ${hypo.statement.slice(0, 30)}...` });
2098
- const { CodebaseIndex } = await import("./codebase-index-CR6Q2HEI.js");
2099
- const codebaseIndex = new CodebaseIndex(workDir);
2100
- if (codebaseIndex.isEmpty()) {
2101
- dispatch({ type: "SHOW_NOTIFICATION", message: `Building codebase index (one-time)...`, severity: "info", autoHideMs: 8e3 });
2102
- dispatch({ type: "ADD_ACTIVITY", message: `Building codebase index...` });
2103
- } else {
2104
- dispatch({ type: "SHOW_NOTIFICATION", message: `Gathering evidence for hypothesis...`, severity: "info", autoHideMs: 3e3 });
2105
- }
2216
+ dispatch({ type: "SHOW_NOTIFICATION", message: `Gathering evidence for hypothesis...`, severity: "info", autoHideMs: 3e3 });
2106
2217
  const { gatherEvidenceForHypothesis } = await import("./hypothesis-HFYZNIMZ.js");
2107
2218
  const evidence = await gatherEvidenceForHypothesis(hypoId, workDir);
2108
2219
  if (evidence.length === 0) {
@@ -2164,7 +2275,7 @@ function HypothesesView() {
2164
2275
  /* @__PURE__ */ jsx10(Text9, { bold: true, color: "green", children: "|" })
2165
2276
  ] }) }),
2166
2277
  /* @__PURE__ */ jsx10(Text9, { dimColor: true, children: " enter save \xB7 esc cancel" })
2167
- ] }) : /* @__PURE__ */ jsx10(Fragment3, { children: hypothesesPanel.hypotheses.length === 0 ? /* @__PURE__ */ jsx10(Text9, { dimColor: true, children: " No hypotheses yet. Press a to add one." }) : /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
2278
+ ] }) : /* @__PURE__ */ jsx10(Fragment4, { children: hypothesesPanel.hypotheses.length === 0 ? /* @__PURE__ */ jsx10(Text9, { dimColor: true, children: " No hypotheses yet. Press a to add one." }) : /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
2168
2279
  testing.map((hypo, idx) => {
2169
2280
  const isSelected = hypothesesPanel.selectedIndex === idx;
2170
2281
  const conf = Math.round(hypo.confidence * 100);
@@ -2217,7 +2328,7 @@ function HypothesesView() {
2217
2328
  // src/cli/dashboard/views/MemoryTreeView.tsx
2218
2329
  import { useEffect as useEffect2, useCallback as useCallback4 } from "react";
2219
2330
  import { Box as Box10, Text as Text10, useInput as useInput6 } from "ink";
2220
- import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
2331
+ import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
2221
2332
  function timeAgo2(iso) {
2222
2333
  const ms = Date.now() - new Date(iso).getTime();
2223
2334
  const mins = Math.floor(ms / 6e4);
@@ -2385,7 +2496,7 @@ function MemoryTreeView() {
2385
2496
  ] })
2386
2497
  ] }, pattern.id);
2387
2498
  }),
2388
- hotspots.length > 0 && /* @__PURE__ */ jsxs10(Fragment4, { children: [
2499
+ hotspots.length > 0 && /* @__PURE__ */ jsxs10(Fragment5, { children: [
2389
2500
  renderHeader("hotspots", "Risk Hotspots", hotspots.length),
2390
2501
  expandedNodes.has("hotspots") && hotspots.slice(0, 10).map((n) => {
2391
2502
  const nodeId = `file-${n.id}`;
@@ -4981,6 +5092,30 @@ var CHAT_TOOLS = [
4981
5092
  required: ["file", "goal", "violation"]
4982
5093
  }
4983
5094
  },
5095
+ {
5096
+ name: "trie_propose_fixes_batch",
5097
+ description: "Propose fixes for multiple goal violations at once. More efficient than calling trie_propose_fix multiple times. Use when the user wants to fix multiple violations.",
5098
+ input_schema: {
5099
+ type: "object",
5100
+ properties: {
5101
+ fixes: {
5102
+ type: "array",
5103
+ description: "Array of fix proposals",
5104
+ items: {
5105
+ type: "object",
5106
+ properties: {
5107
+ file: { type: "string", description: "File path with the goal violation" },
5108
+ goal: { type: "string", description: "The goal that was violated" },
5109
+ violation: { type: "string", description: "Description of the violation" },
5110
+ suggestedFix: { type: "string", description: "Suggested fix for the violation (optional)" }
5111
+ },
5112
+ required: ["file", "goal", "violation"]
5113
+ }
5114
+ }
5115
+ },
5116
+ required: ["fixes"]
5117
+ }
5118
+ },
4984
5119
  {
4985
5120
  name: "trie_search_files",
4986
5121
  description: "Search source code files for text patterns using ripgrep. Note: Requires ripgrep to be installed. For emoji detection, use trie_scan_for_goal_violations instead.",
@@ -5193,6 +5328,38 @@ Type "yes" to proceed, or "no" to cancel.
5193
5328
 
5194
5329
  [PENDING_FIX:${JSON.stringify(fixProposal)}]`;
5195
5330
  }
5331
+ case "trie_propose_fixes_batch": {
5332
+ const fixes = input.fixes;
5333
+ if (!Array.isArray(fixes) || fixes.length === 0) {
5334
+ return "At least one fix is required.";
5335
+ }
5336
+ for (const fix of fixes) {
5337
+ if (!fix.file?.trim()) return "All fixes must have a file path.";
5338
+ if (!fix.goal?.trim()) return "All fixes must have a goal.";
5339
+ if (!fix.violation?.trim()) return "All fixes must have a violation description.";
5340
+ }
5341
+ const fixProposals = fixes.map((f) => ({
5342
+ file: f.file.trim(),
5343
+ goal: f.goal.trim(),
5344
+ violation: f.violation.trim(),
5345
+ suggestedFix: f.suggestedFix?.trim(),
5346
+ directory
5347
+ }));
5348
+ let message = `Found ${fixes.length} violation(s) to fix:
5349
+
5350
+ `;
5351
+ for (const fix of fixProposals) {
5352
+ message += `\u2022 ${fix.file}
5353
+ `;
5354
+ }
5355
+ message += `
5356
+ Type "yes to all" to fix all files, or "no" to cancel.`;
5357
+ for (const fixProposal of fixProposals) {
5358
+ message += `
5359
+ [PENDING_FIX:${JSON.stringify(fixProposal)}]`;
5360
+ }
5361
+ return message;
5362
+ }
5196
5363
  case "trie_search_files": {
5197
5364
  const pattern = String(input.pattern || "").trim();
5198
5365
  const filePattern = input.filePattern ? String(input.filePattern).trim() : void 0;
@@ -5264,7 +5431,6 @@ ${truncated}`;
5264
5431
  const goalId = input.goalId ? String(input.goalId).trim() : void 0;
5265
5432
  try {
5266
5433
  const { checkFilesForGoalViolations, getActiveGoals } = await import("./goal-validator-NLOJJ7FF.js");
5267
- const { CodebaseIndex } = await import("./codebase-index-CR6Q2HEI.js");
5268
5434
  const agentState = getGuardianState(directory);
5269
5435
  await agentState.load();
5270
5436
  const allGoals = await getActiveGoals(directory);
@@ -5272,13 +5438,11 @@ ${truncated}`;
5272
5438
  if (goalsToCheck.length === 0) {
5273
5439
  return goalId ? `No active goal found with ID: ${goalId}` : "No active goals to check. Add goals in the Goals view first.";
5274
5440
  }
5275
- const codebaseIndex = new CodebaseIndex(directory);
5276
- const indexMessage = codebaseIndex.isEmpty() ? "\u{1F4CB} Building codebase index (one-time operation)...\n\n" : "";
5277
5441
  const violations = await checkFilesForGoalViolations(goalsToCheck, directory);
5278
5442
  if (violations.length === 0) {
5279
- return `${indexMessage}\u2713 Scan complete! No violations found for ${goalsToCheck.length} goal(s).`;
5443
+ return `\u2713 Scan complete! No violations found for ${goalsToCheck.length} goal(s).`;
5280
5444
  }
5281
- let result = `${indexMessage}Found ${violations.length} violation(s):
5445
+ let result = `Found ${violations.length} violation(s):
5282
5446
 
5283
5447
  `;
5284
5448
  for (const v of violations) {
@@ -5304,7 +5468,7 @@ ${truncated}`;
5304
5468
  }
5305
5469
 
5306
5470
  // src/cli/dashboard/views/ChatView.tsx
5307
- import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
5471
+ import { Fragment as Fragment6, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
5308
5472
  var VISIBLE_MESSAGES = 8;
5309
5473
  async function buildContext(workDir, dashboardState) {
5310
5474
  const parts = [];
@@ -5428,14 +5592,17 @@ var SYSTEM_PROMPT = `You are Trie, a code guardian assistant embedded in a termi
5428
5592
 
5429
5593
  **When user asks to fix violations:**
5430
5594
  1. Look in "Recent goal violations (nudges)" section of project context
5431
- 2. Extract: file path, goal description, and violation details
5432
- 3. Use trie_propose_fix to propose the fix - this will ASK THE USER for confirmation
5433
- 4. Do NOT assume the user wants to proceed - always get confirmation first
5595
+ 2. Extract: file path, goal description, and violation details for ALL files
5596
+ 3. If multiple violations: Call trie_propose_fixes_batch ONCE with all fixes
5597
+ 4. If single violation: Call trie_propose_fix once
5598
+ 5. AFTER the tool call completes, the system will ask for user confirmation - do NOT add your own confirmation message
5599
+ 6. When the user says "yes", "yes to all", or "no", the system handles spawning Claude Code automatically
5434
5600
 
5435
5601
  Examples:
5436
5602
  - User: "do we have emojis?" \u2192 Check nudges first. If none or unclear: Call trie_scan_for_goal_violations to scan the codebase.
5437
5603
  - User: "run a full scan for emojis" \u2192 Call trie_scan_for_goal_violations directly.
5438
- - User: "fix the emoji violation" \u2192 Find emoji violation in nudges, call trie_propose_fix (will ask user to confirm)
5604
+ - User: "fix the emoji violations" \u2192 Find ALL emoji violations in nudges, call trie_propose_fixes_batch ONCE with all fixes, then STOP
5605
+ - User responds "yes to all" after proposal \u2192 Just say "Spawning Claude Code to fix all files..." The system handles it.
5439
5606
  - User: "search for TODO comments" \u2192 If there's a goal about TODOs, use trie_scan_for_goal_violations. Otherwise explain no such goal exists.
5440
5607
 
5441
5608
  Answer concisely. Reference specific files, decisions, and patterns when relevant.`;
@@ -5586,7 +5753,7 @@ ${contextBlock}`;
5586
5753
  tools: CHAT_TOOLS,
5587
5754
  executeTool,
5588
5755
  maxTokens: 4096,
5589
- maxToolRounds: 5
5756
+ maxToolRounds: 8
5590
5757
  });
5591
5758
  if (result.success) {
5592
5759
  const action = {
@@ -5744,10 +5911,13 @@ ${contextBlock}`;
5744
5911
  canScrollDown && /* @__PURE__ */ jsx13(Text12, { dimColor: true, children: " \u2193 more messages below" }),
5745
5912
  loading && /* @__PURE__ */ jsx13(Text12, { dimColor: true, children: " Thinking..." })
5746
5913
  ] }),
5747
- /* @__PURE__ */ jsx13(Box12, { borderStyle: "single", borderColor: "green", paddingX: 1, flexShrink: 0, flexGrow: 0, children: /* @__PURE__ */ jsxs12(Text12, { children: [
5914
+ /* @__PURE__ */ jsx13(Box12, { borderStyle: "single", borderColor: "green", paddingX: 1, flexShrink: 0, flexGrow: 0, children: /* @__PURE__ */ jsx13(Text12, { children: inputBuffer ? /* @__PURE__ */ jsxs12(Fragment6, { children: [
5915
+ inputBuffer,
5916
+ /* @__PURE__ */ jsx13(Text12, { bold: true, color: "green", children: cursor })
5917
+ ] }) : /* @__PURE__ */ jsxs12(Fragment6, { children: [
5748
5918
  /* @__PURE__ */ jsx13(Text12, { bold: true, color: "green", children: cursor }),
5749
- inputBuffer || /* @__PURE__ */ jsx13(Text12, { dimColor: true, children: "Ask a question..." })
5750
- ] }) })
5919
+ /* @__PURE__ */ jsx13(Text12, { dimColor: true, children: "Ask a question..." })
5920
+ ] }) }) })
5751
5921
  ] });
5752
5922
  }
5753
5923
  function formatToolInput(input) {
@@ -6373,4 +6543,4 @@ export {
6373
6543
  handleCheckpointTool,
6374
6544
  InteractiveDashboard
6375
6545
  };
6376
- //# sourceMappingURL=chunk-WBNYLTW6.js.map
6546
+ //# sourceMappingURL=chunk-VHQBL2I7.js.map