@triedotdev/mcp 1.0.116 → 1.0.118

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.
@@ -10,7 +10,7 @@ import {
10
10
  perceiveCurrentChanges,
11
11
  reasonAboutChangesHumanReadable,
12
12
  saveCheckpoint
13
- } from "./chunk-SRQ4DNOP.js";
13
+ } from "./chunk-PPZYVTUO.js";
14
14
  import {
15
15
  TieredStorage,
16
16
  findCrossProjectPatterns,
@@ -526,12 +526,25 @@ function dashboardReducer(state, action) {
526
526
  (ni) => !existing.some((ei) => ei.message === ni.message && !ei.dismissed)
527
527
  );
528
528
  const merged = [...newOnes, ...existing].slice(0, 50);
529
+ console.error("[State] ADD_INSIGHTS:", {
530
+ newCount: newOnes.length,
531
+ existingCount: existing.length,
532
+ mergedCount: merged.length,
533
+ newInsights: newOnes.map((i) => ({ id: i.id, type: i.type, message: i.message.slice(0, 50) }))
534
+ });
529
535
  let s = { ...state, agentInsights: merged };
536
+ const newAlerts = newOnes.filter((i) => i.type === "warning" && !i.dismissed).length;
537
+ if (newAlerts > 0) {
538
+ s.unreadNudgesCount = state.unreadNudgesCount + newAlerts;
539
+ }
530
540
  if (newOnes.length > 0) {
531
541
  s = addActivity(s, `Trie Agent: ${newOnes.length} new insight${newOnes.length > 1 ? "s" : ""}`);
532
542
  }
533
543
  return s;
534
544
  }
545
+ case "MARK_NUDGES_READ": {
546
+ return { ...state, unreadNudgesCount: 0 };
547
+ }
535
548
  case "SET_AGENT_INITIALIZED":
536
549
  return { ...state, agentInitialized: action.initialized };
537
550
  case "SET_AGENCY_STATUS":
@@ -784,6 +797,7 @@ function createInitialState() {
784
797
  agencyStatus: null,
785
798
  selectedInsight: 0,
786
799
  expandedInsight: null,
800
+ unreadNudgesCount: 0,
787
801
  agentConfig: {
788
802
  agentSmith: {
789
803
  aiEnhancement: true,
@@ -887,7 +901,7 @@ var VIEW_SHORT = {
887
901
  };
888
902
  var TAB_VIEWS = ["overview", "memory", "goals", "hypotheses", "agent", "chat"];
889
903
  var CONTEXT_HINTS = {
890
- goals: "j/k nav \xB7 a add \xB7 enter complete \xB7 d delete",
904
+ goals: "j/k nav \xB7 a add \xB7 enter complete \xB7 d delete \xB7 c clear achieved",
891
905
  hypotheses: "j/k nav \xB7 a add \xB7 v validate \xB7 x invalidate",
892
906
  agent: "j/k nav \xB7 enter expand \xB7 d dismiss",
893
907
  memory: "j/k nav \xB7 enter expand",
@@ -895,7 +909,7 @@ var CONTEXT_HINTS = {
895
909
  rawlog: "n/p pages \xB7 b back"
896
910
  };
897
911
  var CONTEXT_HINTS_SHORT = {
898
- goals: "j/k a d",
912
+ goals: "j/k a d c",
899
913
  hypotheses: "j/k a v x",
900
914
  agent: "j/k enter d",
901
915
  memory: "j/k enter",
@@ -904,12 +918,13 @@ var CONTEXT_HINTS_SHORT = {
904
918
  };
905
919
  function Footer() {
906
920
  const { state } = useDashboard();
907
- const { view, goalsPanel, hypothesesPanel } = state;
921
+ const { view, goalsPanel, hypothesesPanel, unreadNudgesCount } = state;
908
922
  const { stdout } = useStdout2();
909
923
  const cols = stdout?.columns || 80;
910
924
  const narrow = cols < 60;
911
925
  const veryNarrow = cols < 40;
912
926
  const labels = narrow ? VIEW_SHORT : VIEW_LABELS;
927
+ const hasUnreadNudges = unreadNudgesCount > 0;
913
928
  let hints;
914
929
  if (view === "goals" && goalsPanel.inputMode === "add") {
915
930
  hints = narrow ? "enter esc" : "enter save \xB7 esc cancel";
@@ -921,7 +936,22 @@ function Footer() {
921
936
  }
922
937
  if (veryNarrow) {
923
938
  return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, children: [
924
- /* @__PURE__ */ jsx3(Box2, { gap: 1, children: TAB_VIEWS.map((v) => v === view ? /* @__PURE__ */ jsx3(Text2, { color: "green", bold: true, children: labels[v] }, v) : /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: labels[v] }, v)) }),
939
+ /* @__PURE__ */ jsx3(Box2, { gap: 1, children: TAB_VIEWS.map((v) => {
940
+ const isAgent = v === "agent";
941
+ const isCurrent = v === view;
942
+ if (isCurrent) {
943
+ return /* @__PURE__ */ jsx3(Text2, { color: "green", bold: true, children: labels[v] }, v);
944
+ } else if (isAgent && hasUnreadNudges) {
945
+ return /* @__PURE__ */ jsxs2(Text2, { color: "yellow", bold: true, children: [
946
+ labels[v],
947
+ " (",
948
+ unreadNudgesCount,
949
+ ")"
950
+ ] }, v);
951
+ } else {
952
+ return /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: labels[v] }, v);
953
+ }
954
+ }) }),
925
955
  /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
926
956
  hints,
927
957
  " \xB7 q quit"
@@ -929,7 +959,22 @@ function Footer() {
929
959
  ] });
930
960
  }
931
961
  return /* @__PURE__ */ jsxs2(Box2, { paddingX: 1, justifyContent: "space-between", children: [
932
- /* @__PURE__ */ jsx3(Box2, { gap: 1, children: TAB_VIEWS.map((v) => v === view ? /* @__PURE__ */ jsx3(Text2, { color: "green", bold: true, children: labels[v] }, v) : /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: labels[v] }, v)) }),
962
+ /* @__PURE__ */ jsx3(Box2, { gap: 1, children: TAB_VIEWS.map((v) => {
963
+ const isAgent = v === "agent";
964
+ const isCurrent = v === view;
965
+ if (isCurrent) {
966
+ return /* @__PURE__ */ jsx3(Text2, { color: "green", bold: true, children: labels[v] }, v);
967
+ } else if (isAgent && hasUnreadNudges) {
968
+ return /* @__PURE__ */ jsxs2(Text2, { color: "yellow", bold: true, children: [
969
+ labels[v],
970
+ " (",
971
+ unreadNudgesCount,
972
+ ")"
973
+ ] }, v);
974
+ } else {
975
+ return /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: labels[v] }, v);
976
+ }
977
+ }) }),
933
978
  /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
934
979
  hints,
935
980
  " \xB7 q quit"
@@ -1132,11 +1177,13 @@ function ConfigDialog({ onClose }) {
1132
1177
  const workDir = getWorkingDirectory(void 0, true);
1133
1178
  const trieDir = getTrieDirectory(workDir);
1134
1179
  const filesToDelete = [
1135
- join(trieDir, "context-graph.json"),
1180
+ join(trieDir, "context.db"),
1181
+ join(trieDir, "context.json"),
1136
1182
  join(trieDir, "incident-trie.json"),
1137
1183
  join(trieDir, "memory", "ledger.json"),
1138
1184
  join(trieDir, "memory", "issue-store.db"),
1139
- join(trieDir, "memory", "insights.json")
1185
+ join(trieDir, "memory", "insights.json"),
1186
+ join(trieDir, "memory", "issues.json")
1140
1187
  ];
1141
1188
  for (const file of filesToDelete) {
1142
1189
  if (existsSync(file)) {
@@ -1385,6 +1432,17 @@ function AgentView() {
1385
1432
  const visibleInsights = getVisibleInsights(state);
1386
1433
  const alerts = visibleInsights.filter((i) => i.type === "warning");
1387
1434
  const { decisions, patterns, loaded } = agentBrain;
1435
+ useEffect(() => {
1436
+ if (agentInsights.length > 0 || visibleInsights.length > 0) {
1437
+ console.error("[AgentView Debug]", {
1438
+ totalInsights: agentInsights.length,
1439
+ visibleInsights: visibleInsights.length,
1440
+ alerts: alerts.length,
1441
+ insightTypes: agentInsights.map((i) => i.type),
1442
+ visibleTypes: visibleInsights.map((i) => i.type)
1443
+ });
1444
+ }
1445
+ }, [agentInsights, visibleInsights, alerts]);
1388
1446
  const loadBrain = useCallback(async () => {
1389
1447
  try {
1390
1448
  const workDir = getWorkingDirectory(void 0, true);
@@ -1405,6 +1463,11 @@ function AgentView() {
1405
1463
  void loadBrain();
1406
1464
  }
1407
1465
  }, [loaded, loadBrain]);
1466
+ useEffect(() => {
1467
+ if (state.unreadNudgesCount > 0) {
1468
+ dispatch({ type: "MARK_NUDGES_READ" });
1469
+ }
1470
+ }, [dispatch, state.unreadNudgesCount]);
1408
1471
  useInput3((input, key) => {
1409
1472
  if (key.upArrow || input === "k") dispatch({ type: "NAVIGATE_UP" });
1410
1473
  else if (key.downArrow || input === "j") dispatch({ type: "NAVIGATE_DOWN" });
@@ -1625,6 +1688,24 @@ function GoalsView() {
1625
1688
  } catch {
1626
1689
  }
1627
1690
  }, [dispatch, refreshGoals]);
1691
+ const clearAchievedGoals = useCallback2(async () => {
1692
+ try {
1693
+ const workDir = getWorkingDirectory(void 0, true);
1694
+ const agentState = getGuardianState(workDir);
1695
+ await agentState.load();
1696
+ const achieved = goalsPanel.goals.filter((g) => g.status === "achieved");
1697
+ if (achieved.length === 0) {
1698
+ dispatch({ type: "ADD_ACTIVITY", message: "No achieved goals to clear" });
1699
+ return;
1700
+ }
1701
+ for (const goal of achieved) {
1702
+ await agentState.deleteGoal(goal.id);
1703
+ }
1704
+ dispatch({ type: "ADD_ACTIVITY", message: `Cleared ${achieved.length} achieved goal${achieved.length > 1 ? "s" : ""}` });
1705
+ await refreshGoals();
1706
+ } catch {
1707
+ }
1708
+ }, [dispatch, refreshGoals, goalsPanel.goals]);
1628
1709
  useInput4((_input, key) => {
1629
1710
  if (goalsPanel.inputMode === "add") {
1630
1711
  if (key.escape) {
@@ -1648,6 +1729,8 @@ function GoalsView() {
1648
1729
  } else if (_input === "d") {
1649
1730
  const selected = activeGoals[goalsPanel.selectedIndex];
1650
1731
  if (selected) void deleteGoal(selected.id);
1732
+ } else if (_input === "c") {
1733
+ void clearAchievedGoals();
1651
1734
  } else if (_input === "x") {
1652
1735
  const completed = goalsPanel.goals.filter((g) => g.status === "achieved" || g.status === "failed");
1653
1736
  if (completed[0]) void deleteGoal(completed[0].id);
@@ -4480,6 +4563,197 @@ ${checkpoint.files.length > 0 ? `**Files:** ${checkpoint.files.join(", ")}` : ""
4480
4563
 
4481
4564
  // src/cli/dashboard/chat-tools.ts
4482
4565
  import { createHash } from "crypto";
4566
+
4567
+ // src/utils/terminal-spawn.ts
4568
+ import { exec } from "child_process";
4569
+ import { promisify } from "util";
4570
+ import { platform } from "os";
4571
+ var execAsync = promisify(exec);
4572
+ async function spawnTerminal(options) {
4573
+ const { command, cwd, title, keepOpen = true } = options;
4574
+ const os = platform();
4575
+ if (os === "darwin") {
4576
+ await spawnMacOSTerminal(command, cwd, title, keepOpen);
4577
+ } else if (os === "linux") {
4578
+ await spawnLinuxTerminal(command, cwd, title, keepOpen);
4579
+ } else {
4580
+ throw new Error(`Terminal spawning not supported on ${os}`);
4581
+ }
4582
+ }
4583
+ async function spawnMacOSTerminal(command, cwd, title, keepOpen) {
4584
+ const escapedCommand = command.replace(/'/g, `'"'"'`);
4585
+ const escapedCwd = cwd?.replace(/'/g, `'"'"'`) || process.cwd();
4586
+ const escapedTitle = title?.replace(/'/g, `'"'"'`) || "Trie Agent";
4587
+ const fullCommand = cwd ? `cd '${escapedCwd}' && ${command}` : command;
4588
+ const escapedFullCommand = fullCommand.replace(/'/g, `'"'"'`);
4589
+ const script = `
4590
+ tell application "Terminal"
4591
+ activate
4592
+ set newTab to do script "${escapedFullCommand}"
4593
+ set custom title of newTab to "${escapedTitle}"
4594
+ end tell
4595
+ `.trim();
4596
+ try {
4597
+ await execAsync(`osascript -e '${script.replace(/'/g, `'"'"'`)}'`);
4598
+ } catch (error) {
4599
+ console.error("Terminal.app spawn failed, trying fallback...");
4600
+ const shellCmd = keepOpen ? `${fullCommand}; exec bash` : fullCommand;
4601
+ await execAsync(`open -a Terminal "${escapedCwd}" --args -e "${shellCmd}"`);
4602
+ }
4603
+ }
4604
+ async function spawnLinuxTerminal(command, cwd, title, keepOpen) {
4605
+ const workDir = cwd || process.cwd();
4606
+ const termTitle = title || "Trie Agent";
4607
+ const shellCmd = keepOpen ? `${command}; exec bash` : command;
4608
+ const terminals = [
4609
+ // GNOME Terminal
4610
+ {
4611
+ command: "gnome-terminal",
4612
+ args: `--working-directory="${workDir}" --title="${termTitle}" -- bash -c "${shellCmd}"`
4613
+ },
4614
+ // Konsole (KDE)
4615
+ {
4616
+ command: "konsole",
4617
+ args: `--workdir "${workDir}" --title "${termTitle}" -e bash -c "${shellCmd}"`
4618
+ },
4619
+ // xterm (fallback)
4620
+ {
4621
+ command: "xterm",
4622
+ args: `-T "${termTitle}" -e "cd '${workDir}' && ${shellCmd}"`
4623
+ }
4624
+ ];
4625
+ for (const term of terminals) {
4626
+ try {
4627
+ await execAsync(`which ${term.command}`);
4628
+ await execAsync(`${term.command} ${term.args} &`);
4629
+ return;
4630
+ } catch {
4631
+ continue;
4632
+ }
4633
+ }
4634
+ throw new Error("No supported terminal emulator found (tried: gnome-terminal, konsole, xterm)");
4635
+ }
4636
+ async function spawnClaudeCodeFix(options) {
4637
+ const { file, goal, violation, suggestedFix, cwd } = options;
4638
+ const fixScript = `
4639
+ #!/bin/bash
4640
+ set -e
4641
+
4642
+ echo "\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\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"
4643
+ echo "\u{1F527} Trie Agent - Automated Fix"
4644
+ echo "\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\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"
4645
+ echo ""
4646
+ echo "File: ${file}"
4647
+ echo "Goal: ${goal}"
4648
+ echo "Violation: ${violation}"
4649
+ ${suggestedFix ? `echo "Suggested: ${suggestedFix}"` : ""}
4650
+ echo ""
4651
+ echo "\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\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"
4652
+ echo ""
4653
+
4654
+ # Check if file exists
4655
+ if [ ! -f "${file}" ]; then
4656
+ echo "\u274C Error: File not found: ${file}"
4657
+ exit 1
4658
+ fi
4659
+
4660
+ # Check if ANTHROPIC_API_KEY is set
4661
+ if [ -z "\${ANTHROPIC_API_KEY}" ]; then
4662
+ echo "\u274C Error: ANTHROPIC_API_KEY not set"
4663
+ echo ""
4664
+ echo "Please set your API key:"
4665
+ echo " export ANTHROPIC_API_KEY=sk-ant-api03-..."
4666
+ echo ""
4667
+ exit 1
4668
+ fi
4669
+
4670
+ echo "\u{1F4D6} Reading file..."
4671
+ FILE_CONTENT=$(cat "${file}")
4672
+
4673
+ echo "\u{1F916} Analyzing with Claude..."
4674
+ echo ""
4675
+
4676
+ # Create the fix prompt
4677
+ PROMPT="You are fixing a code quality violation.
4678
+
4679
+ Goal: ${goal}
4680
+ Violation: ${violation}
4681
+ ${suggestedFix ? `Suggested fix: ${suggestedFix}` : ""}
4682
+
4683
+ File: ${file}
4684
+
4685
+ Current content:
4686
+ $FILE_CONTENT
4687
+
4688
+ Please fix the violation while:
4689
+ 1. Preserving all functionality
4690
+ 2. Maintaining code style
4691
+ 3. Not breaking anything
4692
+ 4. Following the goal exactly
4693
+
4694
+ Output ONLY the fixed file content, no explanations or markdown fences."
4695
+
4696
+ # Call Claude API to generate fix
4697
+ # Using npx to run a simple Node script
4698
+ FIXED_CONTENT=$(npx --yes -q tsx -e "
4699
+ import Anthropic from '@anthropic-ai/sdk';
4700
+ const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
4701
+ const msg = await client.messages.create({
4702
+ model: 'claude-3-5-sonnet-20241022',
4703
+ max_tokens: 8000,
4704
+ messages: [{ role: 'user', content: \\\`\${PROMPT}\\\` }]
4705
+ });
4706
+ const text = msg.content.find(c => c.type === 'text');
4707
+ console.log(text ? text.text : '');
4708
+ ")
4709
+
4710
+ if [ -z "$FIXED_CONTENT" ]; then
4711
+ echo "\u274C Error: Claude did not generate a fix"
4712
+ exit 1
4713
+ fi
4714
+
4715
+ echo "\u2705 Fix generated!"
4716
+ echo ""
4717
+
4718
+ # Show diff
4719
+ echo "\u{1F4CA} Changes:"
4720
+ echo ""
4721
+ diff -u "${file}" <(echo "$FIXED_CONTENT") || true
4722
+ echo ""
4723
+
4724
+ # Prompt for confirmation
4725
+ read -p "Apply this fix? [y/N] " -n 1 -r
4726
+ echo ""
4727
+
4728
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
4729
+ echo "$FIXED_CONTENT" > "${file}"
4730
+ echo "\u2705 Fix applied to ${file}"
4731
+ echo ""
4732
+ echo "\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\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"
4733
+ echo "\u2728 Done! File has been fixed."
4734
+ echo "\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\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"
4735
+ else
4736
+ echo "\u274C Fix cancelled"
4737
+ fi
4738
+
4739
+ echo ""
4740
+ read -p "Press Enter to close..."
4741
+ `.trim();
4742
+ const { writeFile: writeFile2, chmod, unlink } = await import("fs/promises");
4743
+ const { tmpdir } = await import("os");
4744
+ const { join: join3 } = await import("path");
4745
+ const scriptPath = join3(tmpdir(), `trie-fix-${Date.now()}.sh`);
4746
+ await writeFile2(scriptPath, fixScript, "utf-8");
4747
+ await chmod(scriptPath, 493);
4748
+ await spawnTerminal({
4749
+ command: `bash "${scriptPath}" && rm "${scriptPath}"`,
4750
+ cwd,
4751
+ title: `Fixing: ${file}`,
4752
+ keepOpen: true
4753
+ });
4754
+ }
4755
+
4756
+ // src/cli/dashboard/chat-tools.ts
4483
4757
  function textFromResult(result) {
4484
4758
  return result.content.map((c) => c.text).join("\n");
4485
4759
  }
@@ -4629,6 +4903,20 @@ var CHAT_TOOLS = [
4629
4903
  },
4630
4904
  required: ["decision", "context"]
4631
4905
  }
4906
+ },
4907
+ {
4908
+ name: "trie_fix_goal_violation",
4909
+ description: "Spawn Claude Code in a new terminal to fix a goal violation. Use when the user wants to auto-fix a goal violation detected by the watcher.",
4910
+ input_schema: {
4911
+ type: "object",
4912
+ properties: {
4913
+ file: { type: "string", description: "File path with the goal violation" },
4914
+ goal: { type: "string", description: "The goal that was violated" },
4915
+ violation: { type: "string", description: "Description of the violation" },
4916
+ suggestedFix: { type: "string", description: "Suggested fix for the violation (optional)" }
4917
+ },
4918
+ required: ["file", "goal", "violation"]
4919
+ }
4632
4920
  }
4633
4921
  ];
4634
4922
  async function executeTool(name, input) {
@@ -4778,6 +5066,35 @@ async function executeTool(name, input) {
4778
5066
  });
4779
5067
  return `Decision recorded [${hash}]: "${dec}"`;
4780
5068
  }
5069
+ case "trie_fix_goal_violation": {
5070
+ const file = String(input.file || "").trim();
5071
+ const goal = String(input.goal || "").trim();
5072
+ const violation = String(input.violation || "").trim();
5073
+ const suggestedFix = input.suggestedFix ? String(input.suggestedFix) : void 0;
5074
+ if (!file) return "File path is required.";
5075
+ if (!goal) return "Goal description is required.";
5076
+ if (!violation) return "Violation description is required.";
5077
+ try {
5078
+ await spawnClaudeCodeFix({
5079
+ file,
5080
+ goal,
5081
+ violation,
5082
+ suggestedFix,
5083
+ cwd: directory
5084
+ });
5085
+ return `\u2713 Spawned Claude Code in a new terminal to fix "${file}".
5086
+
5087
+ Claude Code will:
5088
+ 1. Review the file
5089
+ 2. Understand the goal: "${goal}"
5090
+ 3. Fix the violation: "${violation}"
5091
+ 4. Preserve all functionality
5092
+
5093
+ Check the new terminal window to see the fix in progress.`;
5094
+ } catch (error) {
5095
+ return `Failed to spawn Claude Code: ${error instanceof Error ? error.message : "unknown error"}`;
5096
+ }
5097
+ }
4781
5098
  default:
4782
5099
  return `Unknown tool: ${name}`;
4783
5100
  }
@@ -4785,8 +5102,36 @@ async function executeTool(name, input) {
4785
5102
 
4786
5103
  // src/cli/dashboard/views/ChatView.tsx
4787
5104
  import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
4788
- async function buildContext(workDir) {
5105
+ async function buildContext(workDir, dashboardState) {
4789
5106
  const parts = [];
5107
+ if (dashboardState?.agentInsights) {
5108
+ const recentNudges = dashboardState.agentInsights.filter((i) => i.type === "warning" && i.category === "quality" && !i.dismissed).slice(0, 5);
5109
+ if (recentNudges.length > 0) {
5110
+ parts.push("Recent goal violations (nudges):\n" + recentNudges.map((n) => {
5111
+ const fileMatch = n.message.match(/in ([^:]+):/);
5112
+ const goalMatch = n.message.match(/Goal "([^"]+)"/);
5113
+ const violationMatch = n.message.match(/: (.+?) \[/);
5114
+ return `- File: ${fileMatch?.[1] || "unknown"}
5115
+ Goal: ${goalMatch?.[1] || "unknown"}
5116
+ Violation: ${violationMatch?.[1] || n.message}
5117
+ Priority: ${n.priority}`;
5118
+ }).join("\n"));
5119
+ }
5120
+ }
5121
+ try {
5122
+ const guardianState = getGuardianState(workDir);
5123
+ await guardianState.load();
5124
+ const activeGoals = guardianState.getAllGoals().filter((g) => g.status === "active");
5125
+ if (activeGoals.length > 0) {
5126
+ parts.push("Active goals:\n" + activeGoals.map((g) => {
5127
+ const metadata = g.metadata || {};
5128
+ const caughtCount = metadata.caughtCount || 0;
5129
+ const lastCaught = metadata.lastCaught ? ` (last violation: ${metadata.lastCaughtFile || "unknown"})` : "";
5130
+ return `- "${g.description}" [${g.category || "general"}]${caughtCount > 0 ? ` - ${caughtCount} violation(s)${lastCaught}` : ""}`;
5131
+ }).join("\n"));
5132
+ }
5133
+ } catch {
5134
+ }
4790
5135
  try {
4791
5136
  const storage = new TieredStorage(workDir);
4792
5137
  try {
@@ -4851,6 +5196,19 @@ function chatHistoryToMessages(history) {
4851
5196
  }
4852
5197
  var SYSTEM_PROMPT = `You are Trie, a code guardian assistant embedded in a terminal TUI.
4853
5198
  You have tools to take actions on the user's codebase \u2014 use them when the user asks you to check files, record incidents, give feedback, query decisions, or save checkpoints.
5199
+
5200
+ **IMPORTANT: When the user asks to "fix" or "remove" something related to goal violations:**
5201
+ 1. Check the "Recent goal violations (nudges)" section in the project context
5202
+ 2. Extract: file path, goal description, and violation details
5203
+ 3. IMMEDIATELY use trie_fix_goal_violation to spawn Claude Code in a new terminal
5204
+ 4. Do NOT ask for clarification if the context has the violation details
5205
+ 5. Do NOT try to search for files - use the violation info from nudges
5206
+
5207
+ Examples:
5208
+ - User: "fix the emoji violation" \u2192 Look for emoji violations in nudges, call trie_fix_goal_violation
5209
+ - User: "remove emojis from this project" \u2192 Check nudges for emoji violations, call trie_fix_goal_violation
5210
+ - User: "can you fix Dashboard.tsx" \u2192 Check if Dashboard.tsx has violations in nudges, call trie_fix_goal_violation
5211
+
4854
5212
  Answer concisely. Reference specific files, decisions, and patterns when relevant.
4855
5213
  When you use a tool, briefly summarize what you did and what the result was.`;
4856
5214
  function ChatView() {
@@ -4866,7 +5224,7 @@ function ChatView() {
4866
5224
  dispatch({ type: "SET_CHAT_LOADING", loading: true });
4867
5225
  try {
4868
5226
  const workDir = getWorkingDirectory(void 0, true);
4869
- const contextBlock = await buildContext(workDir);
5227
+ const contextBlock = await buildContext(workDir, state);
4870
5228
  const fullSystem = `${SYSTEM_PROMPT}
4871
5229
 
4872
5230
  Project context:
@@ -4938,7 +5296,7 @@ ${contextBlock}`;
4938
5296
  dispatch({ type: "SET_CHAT_LOADING", loading: false });
4939
5297
  loadingRef.current = false;
4940
5298
  }
4941
- }, [dispatch, messages]);
5299
+ }, [dispatch, messages, state]);
4942
5300
  useInput8((input, key) => {
4943
5301
  if (loading) return;
4944
5302
  if (key.return && inputBuffer.trim().length > 0) {
@@ -5155,6 +5513,7 @@ function DashboardApp({ onReady }) {
5155
5513
  dispatchRef.current({ type: "STREAM_UPDATE", update: { type: "raw_log", data: { time, level, message }, timestamp: Date.now() } });
5156
5514
  },
5157
5515
  onNudge: (nudge) => {
5516
+ console.error("[Dashboard] onNudge called:", { message: nudge.message, severity: nudge.severity, file: nudge.file });
5158
5517
  const action = { type: "SHOW_NOTIFICATION", message: nudge.message, severity: nudge.severity };
5159
5518
  if (nudge.file !== void 0) action.file = nudge.file;
5160
5519
  if (nudge.autoHideMs !== void 0) action.autoHideMs = nudge.autoHideMs;
@@ -5171,6 +5530,7 @@ function DashboardApp({ onReady }) {
5171
5530
  relatedIssues: [],
5172
5531
  dismissed: false
5173
5532
  };
5533
+ console.error("[Dashboard] Adding insight:", { id: insight.id, type: insight.type, category: insight.category, priority: insight.priority });
5174
5534
  dispatchRef.current({ type: "ADD_INSIGHTS", insights: [insight] });
5175
5535
  }
5176
5536
  }
@@ -5358,4 +5718,4 @@ export {
5358
5718
  handleCheckpointTool,
5359
5719
  InteractiveDashboard
5360
5720
  };
5361
- //# sourceMappingURL=chunk-2764RZVV.js.map
5721
+ //# sourceMappingURL=chunk-OZGDXRLD.js.map