@triedotdev/mcp 1.0.118 → 1.0.119

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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getGuardian
3
- } from "./chunk-OMCEUJ5I.js";
3
+ } from "./chunk-5TQ7J7UI.js";
4
4
  import {
5
5
  LearningEngine,
6
6
  exportToJson,
@@ -901,16 +901,16 @@ var VIEW_SHORT = {
901
901
  };
902
902
  var TAB_VIEWS = ["overview", "memory", "goals", "hypotheses", "agent", "chat"];
903
903
  var CONTEXT_HINTS = {
904
- goals: "j/k nav \xB7 a add \xB7 enter complete \xB7 d delete \xB7 c clear achieved",
905
- hypotheses: "j/k nav \xB7 a add \xB7 v validate \xB7 x invalidate",
904
+ goals: "j/k nav \xB7 a add \xB7 s scan \xB7 enter complete \xB7 d delete \xB7 c clear achieved",
905
+ hypotheses: "j/k nav \xB7 a add \xB7 t test \xB7 v validate \xB7 x invalidate",
906
906
  agent: "j/k nav \xB7 enter expand \xB7 d dismiss",
907
907
  memory: "j/k nav \xB7 enter expand",
908
908
  chat: "type to ask \xB7 enter send \xB7 esc clear",
909
909
  rawlog: "n/p pages \xB7 b back"
910
910
  };
911
911
  var CONTEXT_HINTS_SHORT = {
912
- goals: "j/k a d c",
913
- hypotheses: "j/k a v x",
912
+ goals: "j/k a s d c",
913
+ hypotheses: "j/k a t v x",
914
914
  agent: "j/k enter d",
915
915
  memory: "j/k enter",
916
916
  chat: "enter esc",
@@ -1706,6 +1706,37 @@ function GoalsView() {
1706
1706
  } catch {
1707
1707
  }
1708
1708
  }, [dispatch, refreshGoals, goalsPanel.goals]);
1709
+ const checkGoalNow = useCallback2(async (goalId) => {
1710
+ try {
1711
+ const workDir = getWorkingDirectory(void 0, true);
1712
+ const goal = goalsPanel.goals.find((g) => g.id === goalId);
1713
+ if (!goal) return;
1714
+ dispatch({ type: "ADD_ACTIVITY", message: `Checking goal: ${goal.description.slice(0, 30)}...` });
1715
+ dispatch({ type: "SHOW_NOTIFICATION", message: `Scanning files for goal violations...`, severity: "info", autoHideMs: 3e3 });
1716
+ const { checkFilesForGoalViolations } = await import("./goal-validator-P67RNO2U.js");
1717
+ const violations = await checkFilesForGoalViolations([goal], workDir);
1718
+ if (violations.length === 0) {
1719
+ dispatch({ type: "SHOW_NOTIFICATION", message: `\u2713 No violations found for: ${goal.description.slice(0, 40)}`, severity: "info", autoHideMs: 5e3 });
1720
+ dispatch({ type: "ADD_ACTIVITY", message: `No violations found` });
1721
+ } else {
1722
+ dispatch({ type: "SHOW_NOTIFICATION", message: `Found ${violations.length} violation(s) for: ${goal.description.slice(0, 30)}`, severity: "warning", autoHideMs: 5e3 });
1723
+ dispatch({ type: "ADD_ACTIVITY", message: `Found ${violations.length} violation(s)` });
1724
+ for (const violation of violations) {
1725
+ dispatch({ type: "ADD_INSIGHTS", insights: [{
1726
+ message: violation.message,
1727
+ severity: violation.severity,
1728
+ timestamp: Date.now(),
1729
+ category: "goal",
1730
+ dismissed: false,
1731
+ priority: "high",
1732
+ file: violation.file
1733
+ }] });
1734
+ }
1735
+ }
1736
+ } catch (error) {
1737
+ dispatch({ type: "ADD_ACTIVITY", message: `Check failed: ${error instanceof Error ? error.message : "unknown"}` });
1738
+ }
1739
+ }, [dispatch, goalsPanel.goals]);
1709
1740
  useInput4((_input, key) => {
1710
1741
  if (goalsPanel.inputMode === "add") {
1711
1742
  if (key.escape) {
@@ -1723,7 +1754,10 @@ function GoalsView() {
1723
1754
  if (_input === "a") dispatch({ type: "SET_GOALS_INPUT_MODE", mode: "add" });
1724
1755
  else if (key.upArrow || _input === "k") dispatch({ type: "SELECT_GOAL", index: Math.max(0, goalsPanel.selectedIndex - 1) });
1725
1756
  else if (key.downArrow || _input === "j") dispatch({ type: "SELECT_GOAL", index: Math.min(activeGoals.length - 1, goalsPanel.selectedIndex + 1) });
1726
- else if (key.return) {
1757
+ else if (_input === "s") {
1758
+ const selected = activeGoals[goalsPanel.selectedIndex];
1759
+ if (selected) void checkGoalNow(selected.id);
1760
+ } else if (key.return) {
1727
1761
  const selected = activeGoals[goalsPanel.selectedIndex];
1728
1762
  if (selected) void completeGoal(selected.id);
1729
1763
  } else if (_input === "d") {
@@ -1869,6 +1903,29 @@ function HypothesesView() {
1869
1903
  } catch {
1870
1904
  }
1871
1905
  }, [dispatch, refreshHypotheses]);
1906
+ const checkHypothesisNow = useCallback3(async (hypoId) => {
1907
+ try {
1908
+ const workDir = getWorkingDirectory(void 0, true);
1909
+ const hypo = hypothesesPanel.hypotheses.find((h) => h.id === hypoId);
1910
+ if (!hypo) return;
1911
+ dispatch({ type: "ADD_ACTIVITY", message: `Testing hypothesis: ${hypo.statement.slice(0, 30)}...` });
1912
+ dispatch({ type: "SHOW_NOTIFICATION", message: `Gathering evidence for hypothesis...`, severity: "info", autoHideMs: 3e3 });
1913
+ const { gatherEvidenceForHypothesis } = await import("./hypothesis-PEVD2IJR.js");
1914
+ const evidence = await gatherEvidenceForHypothesis(hypoId, workDir);
1915
+ if (evidence.length === 0) {
1916
+ dispatch({ type: "SHOW_NOTIFICATION", message: `No evidence found for: ${hypo.statement.slice(0, 40)}`, severity: "info", autoHideMs: 5e3 });
1917
+ dispatch({ type: "ADD_ACTIVITY", message: `No evidence found` });
1918
+ } else {
1919
+ const supporting = evidence.filter((e) => e.supports).length;
1920
+ const against = evidence.length - supporting;
1921
+ dispatch({ type: "SHOW_NOTIFICATION", message: `Found ${evidence.length} evidence (${supporting} for, ${against} against)`, severity: "info", autoHideMs: 5e3 });
1922
+ dispatch({ type: "ADD_ACTIVITY", message: `Found ${evidence.length} evidence items` });
1923
+ await refreshHypotheses();
1924
+ }
1925
+ } catch (error) {
1926
+ dispatch({ type: "ADD_ACTIVITY", message: `Check failed: ${error instanceof Error ? error.message : "unknown"}` });
1927
+ }
1928
+ }, [dispatch, hypothesesPanel.hypotheses, refreshHypotheses]);
1872
1929
  useInput5((_input, key) => {
1873
1930
  if (hypothesesPanel.inputMode === "add") {
1874
1931
  if (key.escape) {
@@ -1886,7 +1943,10 @@ function HypothesesView() {
1886
1943
  if (_input === "a") dispatch({ type: "SET_HYPOTHESES_INPUT_MODE", mode: "add" });
1887
1944
  else if (key.upArrow || _input === "k") dispatch({ type: "SELECT_HYPOTHESIS", index: Math.max(0, hypothesesPanel.selectedIndex - 1) });
1888
1945
  else if (key.downArrow || _input === "j") dispatch({ type: "SELECT_HYPOTHESIS", index: Math.min(testing.length - 1, hypothesesPanel.selectedIndex + 1) });
1889
- else if (_input === "v") {
1946
+ else if (_input === "t") {
1947
+ const selected = testing[hypothesesPanel.selectedIndex];
1948
+ if (selected) void checkHypothesisNow(selected.id);
1949
+ } else if (_input === "v") {
1890
1950
  const selected = testing[hypothesesPanel.selectedIndex];
1891
1951
  if (selected) void updateHypothesis(selected.id, "validate");
1892
1952
  } else if (_input === "x") {
@@ -4563,197 +4623,6 @@ ${checkpoint.files.length > 0 ? `**Files:** ${checkpoint.files.join(", ")}` : ""
4563
4623
 
4564
4624
  // src/cli/dashboard/chat-tools.ts
4565
4625
  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
4757
4626
  function textFromResult(result) {
4758
4627
  return result.content.map((c) => c.text).join("\n");
4759
4628
  }
@@ -4905,8 +4774,8 @@ var CHAT_TOOLS = [
4905
4774
  }
4906
4775
  },
4907
4776
  {
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.",
4777
+ name: "trie_propose_fix",
4778
+ description: "Propose a fix for a goal violation. This will ask the user for confirmation before spawning Claude Code. Use when the user wants to fix a goal violation.",
4910
4779
  input_schema: {
4911
4780
  type: "object",
4912
4781
  properties: {
@@ -4917,6 +4786,28 @@ var CHAT_TOOLS = [
4917
4786
  },
4918
4787
  required: ["file", "goal", "violation"]
4919
4788
  }
4789
+ },
4790
+ {
4791
+ name: "trie_search_files",
4792
+ description: "Search source code files for text patterns, emojis, or code patterns. Use when the user asks about code content that might not be in recent nudges.",
4793
+ input_schema: {
4794
+ type: "object",
4795
+ properties: {
4796
+ pattern: {
4797
+ type: "string",
4798
+ description: 'Text or regex pattern to search for. For emojis, use patterns like "[\u{1F300}-\u{1F9FF}]" or specific emoji characters.'
4799
+ },
4800
+ filePattern: {
4801
+ type: "string",
4802
+ description: 'Glob pattern for files to search (e.g., "*.tsx", "*.ts", "src/**/*.js"). Omit to search all files.'
4803
+ },
4804
+ contextLines: {
4805
+ type: "number",
4806
+ description: "Number of context lines to show around matches (default 2)"
4807
+ }
4808
+ },
4809
+ required: ["pattern"]
4810
+ }
4920
4811
  }
4921
4812
  ];
4922
4813
  async function executeTool(name, input) {
@@ -5066,7 +4957,7 @@ async function executeTool(name, input) {
5066
4957
  });
5067
4958
  return `Decision recorded [${hash}]: "${dec}"`;
5068
4959
  }
5069
- case "trie_fix_goal_violation": {
4960
+ case "trie_propose_fix": {
5070
4961
  const file = String(input.file || "").trim();
5071
4962
  const goal = String(input.goal || "").trim();
5072
4963
  const violation = String(input.violation || "").trim();
@@ -5074,25 +4965,84 @@ async function executeTool(name, input) {
5074
4965
  if (!file) return "File path is required.";
5075
4966
  if (!goal) return "Goal description is required.";
5076
4967
  if (!violation) return "Violation description is required.";
4968
+ const fixProposal = {
4969
+ file,
4970
+ goal,
4971
+ violation,
4972
+ suggestedFix,
4973
+ directory
4974
+ };
4975
+ return `I found a violation to fix:
4976
+
4977
+ \u{1F4C1} File: ${file}
4978
+ \u{1F3AF} Goal: ${goal}
4979
+ \u26A0\uFE0F Violation: ${violation}
4980
+ ${suggestedFix ? `\u{1F4A1} Suggested fix: ${suggestedFix}
4981
+ ` : ""}
4982
+ Would you like me to spawn Claude Code to fix this?
4983
+
4984
+ Type "yes" to proceed, or "no" to cancel.
4985
+
4986
+ [PENDING_FIX:${JSON.stringify(fixProposal)}]`;
4987
+ }
4988
+ case "trie_search_files": {
4989
+ const pattern = String(input.pattern || "").trim();
4990
+ const filePattern = input.filePattern ? String(input.filePattern).trim() : void 0;
4991
+ const contextLines = typeof input.contextLines === "number" ? input.contextLines : 2;
4992
+ if (!pattern) return "Search pattern is required.";
4993
+ const { execSync } = await import("child_process");
5077
4994
  try {
5078
- await spawnClaudeCodeFix({
5079
- file,
5080
- goal,
5081
- violation,
5082
- suggestedFix,
5083
- cwd: directory
4995
+ const rgArgs = [
4996
+ "rg",
4997
+ "--context",
4998
+ String(contextLines),
4999
+ "--heading",
5000
+ "--line-number",
5001
+ "--color=never",
5002
+ "--max-count",
5003
+ "50"
5004
+ // Limit matches per file
5005
+ ];
5006
+ if (filePattern) {
5007
+ rgArgs.push("--glob", filePattern);
5008
+ }
5009
+ rgArgs.push(
5010
+ "--glob",
5011
+ "!node_modules/**",
5012
+ "--glob",
5013
+ "!.git/**",
5014
+ "--glob",
5015
+ "!dist/**",
5016
+ "--glob",
5017
+ "!build/**",
5018
+ "--glob",
5019
+ "!coverage/**"
5020
+ );
5021
+ rgArgs.push(pattern, directory);
5022
+ const result = execSync(rgArgs.join(" "), {
5023
+ encoding: "utf-8",
5024
+ maxBuffer: 10 * 1024 * 1024
5025
+ // 10MB
5084
5026
  });
5085
- return `\u2713 Spawned Claude Code in a new terminal to fix "${file}".
5027
+ if (!result.trim()) {
5028
+ return `No matches found for pattern: ${pattern}`;
5029
+ }
5030
+ const maxLength = 5e3;
5031
+ const truncated = result.length > maxLength ? result.slice(0, maxLength) + `
5086
5032
 
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
5033
+ ... (truncated, ${result.length - maxLength} more characters)` : result;
5034
+ const matchCount = (result.match(/^\d+:/gm) || []).length;
5035
+ return `Found ${matchCount} match(es) for "${pattern}":
5092
5036
 
5093
- Check the new terminal window to see the fix in progress.`;
5037
+ ${truncated}`;
5094
5038
  } catch (error) {
5095
- return `Failed to spawn Claude Code: ${error instanceof Error ? error.message : "unknown error"}`;
5039
+ if (error.status === 1) {
5040
+ return `No matches found for pattern: ${pattern}`;
5041
+ }
5042
+ if (error.status === 2) {
5043
+ return `Error: ripgrep not found. Please install ripgrep (brew install ripgrep)`;
5044
+ }
5045
+ return `Search failed: ${error.message}`;
5096
5046
  }
5097
5047
  }
5098
5048
  default:
@@ -5195,22 +5145,33 @@ function chatHistoryToMessages(history) {
5195
5145
  }));
5196
5146
  }
5197
5147
  var SYSTEM_PROMPT = `You are Trie, a code guardian assistant embedded in a terminal TUI.
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
5148
 
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
5149
+ **What you CAN do:**
5150
+ - Check recent goal violations (nudges) in the provided project context
5151
+ - Search source code files using trie_search_files (uses ripgrep)
5152
+ - Record incidents, decisions, and feedback about the codebase
5153
+ - Query stored decisions, blockers, facts, and questions from the decision ledger
5154
+ - Create and manage goals and hypotheses
5155
+ - Propose fixes for goal violations (requires user confirmation before spawning Claude Code)
5156
+ - Save work checkpoints
5157
+
5158
+ **When user asks about code content:**
5159
+ 1. First check the "Recent goal violations (nudges)" section in project context
5160
+ 2. If not found in nudges, use trie_search_files to search source code directly
5161
+ 3. For emojis specifically, search for common emoji patterns or unicode ranges
5162
+
5163
+ **When user asks to fix violations:**
5164
+ 1. Look in "Recent goal violations (nudges)" section of project context
5202
5165
  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
5166
+ 3. Use trie_propose_fix to propose the fix - this will ASK THE USER for confirmation
5167
+ 4. Do NOT assume the user wants to proceed - always get confirmation first
5206
5168
 
5207
5169
  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
5170
+ - User: "do we have emojis?" \u2192 Check nudges first. If none, use trie_search_files to search for emoji patterns.
5171
+ - User: "fix the emoji violation" \u2192 Find emoji violation in nudges, call trie_propose_fix (will ask user to confirm)
5172
+ - User: "search for TODO comments" \u2192 Use trie_search_files with pattern "TODO|FIXME"
5211
5173
 
5212
- Answer concisely. Reference specific files, decisions, and patterns when relevant.
5213
- When you use a tool, briefly summarize what you did and what the result was.`;
5174
+ Answer concisely. Reference specific files, decisions, and patterns when relevant.`;
5214
5175
  function ChatView() {
5215
5176
  const { state, dispatch } = useDashboard();
5216
5177
  const { chatState } = state;
@@ -5224,6 +5185,50 @@ function ChatView() {
5224
5185
  dispatch({ type: "SET_CHAT_LOADING", loading: true });
5225
5186
  try {
5226
5187
  const workDir = getWorkingDirectory(void 0, true);
5188
+ const lastMessage = messages[messages.length - 1];
5189
+ if (lastMessage?.role === "assistant" && lastMessage.pendingFix) {
5190
+ const response = question.trim().toLowerCase();
5191
+ if (response === "yes" || response === "y") {
5192
+ const { spawnClaudeCodeFix } = await import("./terminal-spawn-2GU5KLPS.js");
5193
+ try {
5194
+ await spawnClaudeCodeFix(lastMessage.pendingFix);
5195
+ dispatch({
5196
+ type: "ADD_CHAT_MESSAGE",
5197
+ role: "assistant",
5198
+ content: `\u2713 Spawned Claude Code in a new terminal to fix "${lastMessage.pendingFix.file}".
5199
+
5200
+ Claude Code will:
5201
+ 1. Review the file
5202
+ 2. Understand the goal: "${lastMessage.pendingFix.goal}"
5203
+ 3. Fix the violation: "${lastMessage.pendingFix.violation}"
5204
+ 4. Preserve all functionality
5205
+
5206
+ Check the new terminal window to see the fix in progress.`
5207
+ });
5208
+ dispatch({ type: "SET_CHAT_LOADING", loading: false });
5209
+ loadingRef.current = false;
5210
+ return;
5211
+ } catch (error) {
5212
+ dispatch({
5213
+ type: "ADD_CHAT_MESSAGE",
5214
+ role: "assistant",
5215
+ content: `Failed to spawn Claude Code: ${error instanceof Error ? error.message : "unknown error"}`
5216
+ });
5217
+ dispatch({ type: "SET_CHAT_LOADING", loading: false });
5218
+ loadingRef.current = false;
5219
+ return;
5220
+ }
5221
+ } else if (response === "no" || response === "n") {
5222
+ dispatch({
5223
+ type: "ADD_CHAT_MESSAGE",
5224
+ role: "assistant",
5225
+ content: "Fix cancelled. Let me know if you need anything else!"
5226
+ });
5227
+ dispatch({ type: "SET_CHAT_LOADING", loading: false });
5228
+ loadingRef.current = false;
5229
+ return;
5230
+ }
5231
+ }
5227
5232
  const contextBlock = await buildContext(workDir, state);
5228
5233
  const fullSystem = `${SYSTEM_PROMPT}
5229
5234
 
@@ -5247,6 +5252,15 @@ ${contextBlock}`;
5247
5252
  role: "assistant",
5248
5253
  content: result.content
5249
5254
  };
5255
+ const pendingFixMatch = result.content.match(/\[PENDING_FIX:(.+?)\]/);
5256
+ if (pendingFixMatch) {
5257
+ try {
5258
+ const fixData = JSON.parse(pendingFixMatch[1]);
5259
+ action.pendingFix = fixData;
5260
+ action.content = result.content.replace(/\[PENDING_FIX:.+?\]/, "").trim();
5261
+ } catch {
5262
+ }
5263
+ }
5250
5264
  if (result.toolCalls && result.toolCalls.length > 0) {
5251
5265
  action.toolCalls = result.toolCalls;
5252
5266
  const toolNames = new Set(result.toolCalls.map((tc) => tc.name));
@@ -5315,33 +5329,34 @@ ${contextBlock}`;
5315
5329
  /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: " AI is not available. Press s to open settings and add your Anthropic API key." })
5316
5330
  ] });
5317
5331
  }
5318
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingX: 1, children: [
5332
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingX: 1, flexGrow: 1, children: [
5319
5333
  /* @__PURE__ */ jsx12(Text11, { bold: true, children: "Chat" }),
5320
- messages.length === 0 && !loading && /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: " Ask about your codebase, decisions, patterns, or risks." }),
5321
- messages.map((msg, idx) => /* @__PURE__ */ jsx12(Box11, { flexDirection: "column", marginTop: idx === 0 ? 1 : 0, marginBottom: 1, children: msg.role === "user" ? /* @__PURE__ */ jsxs11(Text11, { children: [
5322
- " ",
5323
- /* @__PURE__ */ jsx12(Text11, { bold: true, color: "green", children: "You:" }),
5324
- " ",
5325
- msg.content
5326
- ] }) : /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
5327
- msg.toolCalls && msg.toolCalls.length > 0 && msg.toolCalls.map((tc, ti) => /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
5334
+ /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", flexGrow: 1, overflow: "hidden", marginTop: 1, children: [
5335
+ messages.length === 0 && !loading && /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: " Ask about your codebase, decisions, patterns, or risks." }),
5336
+ messages.map((msg, idx) => /* @__PURE__ */ jsx12(Box11, { flexDirection: "column", marginTop: idx === 0 ? 0 : 1, marginBottom: 1, children: msg.role === "user" ? /* @__PURE__ */ jsxs11(Text11, { children: [
5328
5337
  " ",
5329
- /* @__PURE__ */ jsxs11(Text11, { color: "yellow", children: [
5330
- "[",
5331
- tc.name,
5332
- "]"
5333
- ] }),
5338
+ /* @__PURE__ */ jsx12(Text11, { bold: true, color: "green", children: "You:" }),
5334
5339
  " ",
5335
- formatToolInput(tc.input)
5336
- ] }, ti)),
5337
- msg.content.split("\n").map((line, li) => /* @__PURE__ */ jsxs11(Text11, { children: [
5338
- li === 0 ? " Trie: " : " ",
5339
- line
5340
- ] }, li))
5341
- ] }) }, idx)),
5342
- loading && /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: " Thinking..." }),
5343
- /* @__PURE__ */ jsx12(Box11, { flexGrow: 1 }),
5344
- /* @__PURE__ */ jsx12(Box11, { borderStyle: "single", borderColor: "green", paddingX: 1, children: /* @__PURE__ */ jsxs11(Text11, { children: [
5340
+ msg.content
5341
+ ] }) : /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
5342
+ msg.toolCalls && msg.toolCalls.length > 0 && msg.toolCalls.map((tc, ti) => /* @__PURE__ */ jsxs11(Text11, { dimColor: true, children: [
5343
+ " ",
5344
+ /* @__PURE__ */ jsxs11(Text11, { color: "yellow", children: [
5345
+ "[",
5346
+ tc.name,
5347
+ "]"
5348
+ ] }),
5349
+ " ",
5350
+ formatToolInput(tc.input)
5351
+ ] }, ti)),
5352
+ msg.content.split("\n").map((line, li) => /* @__PURE__ */ jsxs11(Text11, { children: [
5353
+ li === 0 ? " Trie: " : " ",
5354
+ line
5355
+ ] }, li))
5356
+ ] }) }, idx)),
5357
+ loading && /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: " Thinking..." })
5358
+ ] }),
5359
+ /* @__PURE__ */ jsx12(Box11, { borderStyle: "single", borderColor: "green", paddingX: 1, flexShrink: 0, children: /* @__PURE__ */ jsxs11(Text11, { children: [
5345
5360
  inputBuffer || /* @__PURE__ */ jsx12(Text11, { dimColor: true, children: "Ask a question..." }),
5346
5361
  /* @__PURE__ */ jsx12(Text11, { bold: true, color: "green", children: "|" })
5347
5362
  ] }) })
@@ -5397,7 +5412,7 @@ ${content}
5397
5412
  fixedContent = fixedContent.replace(/^```\w*\n?/, "").replace(/\n?```$/, "");
5398
5413
  }
5399
5414
  await writeFile(fullPath, fixedContent, "utf-8");
5400
- const { recordGoalViolationFixed, getActiveGoals } = await import("./goal-validator-YSNN23D4.js");
5415
+ const { recordGoalViolationFixed, getActiveGoals } = await import("./goal-validator-P67RNO2U.js");
5401
5416
  const goals = await getActiveGoals(projectPath);
5402
5417
  const matchedGoal = goals.find((g) => g.description === fix.goalDescription);
5403
5418
  if (matchedGoal) {
@@ -5718,4 +5733,4 @@ export {
5718
5733
  handleCheckpointTool,
5719
5734
  InteractiveDashboard
5720
5735
  };
5721
- //# sourceMappingURL=chunk-OZGDXRLD.js.map
5736
+ //# sourceMappingURL=chunk-GSYMJLZY.js.map