@triedotdev/mcp 1.0.115 → 1.0.117

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 (65) hide show
  1. package/dist/{autonomy-config-JXB7WCZ2.js → autonomy-config-QA6ATWLJ.js} +3 -3
  2. package/dist/{chunk-R4AAPFXC.js → chunk-45Y5TLQZ.js} +2 -2
  3. package/dist/{chunk-R4AAPFXC.js.map → chunk-45Y5TLQZ.js.map} +1 -1
  4. package/dist/{chunk-KRH642MT.js → chunk-4BGAVEO6.js} +2 -2
  5. package/dist/{chunk-NS2MSZMB.js → chunk-55CBWOEZ.js} +2 -2
  6. package/dist/{chunk-YR4BMGYO.js → chunk-7Q6I2CB4.js} +2 -2
  7. package/dist/{chunk-TKMV7JKN.js → chunk-DFHMB44X.js} +2 -2
  8. package/dist/{chunk-ZYKEILVK.js → chunk-EWVU7QUG.js} +464 -88
  9. package/dist/chunk-EWVU7QUG.js.map +1 -0
  10. package/dist/{chunk-D3EXBJE2.js → chunk-FNW7Z7ZS.js} +5 -5
  11. package/dist/{chunk-DZREHOGW.js → chunk-I7XKF5XD.js} +5 -5
  12. package/dist/{chunk-2SIFK7OW.js → chunk-IQBHPTV7.js} +4 -4
  13. package/dist/{chunk-AOFYU6T3.js → chunk-OMCEUJ5I.js} +12 -12
  14. package/dist/{chunk-MVNJPJBK.js → chunk-PPZYVTUO.js} +71 -5
  15. package/dist/{chunk-MVNJPJBK.js.map → chunk-PPZYVTUO.js.map} +1 -1
  16. package/dist/{chunk-55DOQNHJ.js → chunk-PRFHN2X6.js} +4 -4
  17. package/dist/{chunk-2GIAROBF.js → chunk-WHIQAGB7.js} +2 -2
  18. package/dist/{chunk-SWSK7ANT.js → chunk-WRGSH5RT.js} +2 -2
  19. package/dist/{chunk-6LXSA2OZ.js → chunk-Y52SNUW5.js} +3 -3
  20. package/dist/{chunk-I2GFI3AM.js → chunk-ZEXMMTIQ.js} +2 -2
  21. package/dist/cli/create-agent.js +1 -1
  22. package/dist/cli/main.js +66 -32
  23. package/dist/cli/main.js.map +1 -1
  24. package/dist/cli/yolo-daemon.js +14 -14
  25. package/dist/{client-7XZHCMD3.js → client-PMKE26IV.js} +3 -3
  26. package/dist/{goal-manager-LMS6ZJB7.js → goal-manager-JKTNFJQE.js} +7 -7
  27. package/dist/goal-validator-YSNN23D4.js +62 -0
  28. package/dist/goal-validator-YSNN23D4.js.map +1 -0
  29. package/dist/{graph-U5JWSAB5.js → graph-PAUZ5EMP.js} +3 -3
  30. package/dist/guardian-agent-UY2G56FT.js +25 -0
  31. package/dist/{hypothesis-KGC3P54C.js → hypothesis-RUCJ74X7.js} +7 -7
  32. package/dist/{incident-index-PNIVT47T.js → incident-index-ZCDSJ42L.js} +3 -3
  33. package/dist/index.js +215 -128
  34. package/dist/index.js.map +1 -1
  35. package/dist/{ledger-SR6OEBLO.js → ledger-JMPGJGLB.js} +3 -3
  36. package/package.json +1 -1
  37. package/dist/auto-fix-apply-PCAHWLXF.js +0 -10
  38. package/dist/chunk-DJ2YAGHK.js +0 -50
  39. package/dist/chunk-DJ2YAGHK.js.map +0 -1
  40. package/dist/chunk-ZYKEILVK.js.map +0 -1
  41. package/dist/goal-validator-T5HEYBC5.js +0 -186
  42. package/dist/goal-validator-T5HEYBC5.js.map +0 -1
  43. package/dist/guardian-agent-EXP7APLC.js +0 -25
  44. package/dist/ledger-SR6OEBLO.js.map +0 -1
  45. /package/dist/{auto-fix-apply-PCAHWLXF.js.map → autonomy-config-QA6ATWLJ.js.map} +0 -0
  46. /package/dist/{chunk-KRH642MT.js.map → chunk-4BGAVEO6.js.map} +0 -0
  47. /package/dist/{chunk-NS2MSZMB.js.map → chunk-55CBWOEZ.js.map} +0 -0
  48. /package/dist/{chunk-YR4BMGYO.js.map → chunk-7Q6I2CB4.js.map} +0 -0
  49. /package/dist/{chunk-TKMV7JKN.js.map → chunk-DFHMB44X.js.map} +0 -0
  50. /package/dist/{chunk-D3EXBJE2.js.map → chunk-FNW7Z7ZS.js.map} +0 -0
  51. /package/dist/{chunk-DZREHOGW.js.map → chunk-I7XKF5XD.js.map} +0 -0
  52. /package/dist/{chunk-2SIFK7OW.js.map → chunk-IQBHPTV7.js.map} +0 -0
  53. /package/dist/{chunk-AOFYU6T3.js.map → chunk-OMCEUJ5I.js.map} +0 -0
  54. /package/dist/{chunk-55DOQNHJ.js.map → chunk-PRFHN2X6.js.map} +0 -0
  55. /package/dist/{chunk-2GIAROBF.js.map → chunk-WHIQAGB7.js.map} +0 -0
  56. /package/dist/{chunk-SWSK7ANT.js.map → chunk-WRGSH5RT.js.map} +0 -0
  57. /package/dist/{chunk-6LXSA2OZ.js.map → chunk-Y52SNUW5.js.map} +0 -0
  58. /package/dist/{chunk-I2GFI3AM.js.map → chunk-ZEXMMTIQ.js.map} +0 -0
  59. /package/dist/{autonomy-config-JXB7WCZ2.js.map → client-PMKE26IV.js.map} +0 -0
  60. /package/dist/{client-7XZHCMD3.js.map → goal-manager-JKTNFJQE.js.map} +0 -0
  61. /package/dist/{goal-manager-LMS6ZJB7.js.map → graph-PAUZ5EMP.js.map} +0 -0
  62. /package/dist/{graph-U5JWSAB5.js.map → guardian-agent-UY2G56FT.js.map} +0 -0
  63. /package/dist/{guardian-agent-EXP7APLC.js.map → hypothesis-RUCJ74X7.js.map} +0 -0
  64. /package/dist/{hypothesis-KGC3P54C.js.map → incident-index-ZCDSJ42L.js.map} +0 -0
  65. /package/dist/{incident-index-PNIVT47T.js.map → ledger-JMPGJGLB.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getGuardian
3
- } from "./chunk-AOFYU6T3.js";
3
+ } from "./chunk-OMCEUJ5I.js";
4
4
  import {
5
5
  LearningEngine,
6
6
  exportToJson,
@@ -10,34 +10,34 @@ import {
10
10
  perceiveCurrentChanges,
11
11
  reasonAboutChangesHumanReadable,
12
12
  saveCheckpoint
13
- } from "./chunk-MVNJPJBK.js";
13
+ } from "./chunk-PPZYVTUO.js";
14
14
  import {
15
15
  TieredStorage,
16
16
  findCrossProjectPatterns,
17
17
  getStorage
18
- } from "./chunk-D3EXBJE2.js";
18
+ } from "./chunk-FNW7Z7ZS.js";
19
19
  import {
20
20
  getKeyFromKeychain,
21
21
  isAIAvailable,
22
22
  runAIWithTools,
23
23
  setAPIKey
24
- } from "./chunk-SWSK7ANT.js";
24
+ } from "./chunk-WRGSH5RT.js";
25
25
  import {
26
26
  getGuardianState
27
- } from "./chunk-KRH642MT.js";
27
+ } from "./chunk-4BGAVEO6.js";
28
28
  import {
29
29
  ContextGraph
30
- } from "./chunk-NS2MSZMB.js";
30
+ } from "./chunk-55CBWOEZ.js";
31
31
  import {
32
32
  IncidentIndex
33
- } from "./chunk-2GIAROBF.js";
33
+ } from "./chunk-WHIQAGB7.js";
34
34
  import {
35
35
  getOutputManager
36
36
  } from "./chunk-VRLMTOB6.js";
37
37
  import {
38
38
  getTrieDirectory,
39
39
  getWorkingDirectory
40
- } from "./chunk-R4AAPFXC.js";
40
+ } from "./chunk-45Y5TLQZ.js";
41
41
  import {
42
42
  isInteractiveMode
43
43
  } from "./chunk-APMV77PU.js";
@@ -45,10 +45,14 @@ import {
45
45
  // src/tools/scan.ts
46
46
  var TrieScanTool = class {
47
47
  async execute(_input) {
48
- console.error("\u2139\uFE0F Trie scan has been refocused on decision ledger");
49
- console.error(" Use: trie tell - to report incidents");
50
- console.error(" Use: trie gotcha - to predict risks");
51
- console.error(" Use: trie learn - to learn from history");
48
+ if (!isInteractiveMode()) {
49
+ console.error("Trie scan has been refocused on decision ledger");
50
+ console.error(" trie tell - report incidents");
51
+ console.error(" trie gotcha - predict risks");
52
+ console.error(" trie learn - learn from history");
53
+ } else {
54
+ getOutputManager().log("info", "Scan refocused on decision ledger");
55
+ }
52
56
  return {
53
57
  content: [{
54
58
  type: "text",
@@ -217,6 +221,12 @@ var StreamingManager = class {
217
221
  reportWatchChange(file) {
218
222
  this.emit("watch_change", { file });
219
223
  }
224
+ /**
225
+ * Report a pending fix for user approval
226
+ */
227
+ reportPendingFix(fix) {
228
+ this.emit("pending_fix", fix);
229
+ }
220
230
  /**
221
231
  * Report memory operations (saving context, learning patterns)
222
232
  */
@@ -282,7 +292,7 @@ import React9 from "react";
282
292
 
283
293
  // src/cli/dashboard/App.tsx
284
294
  import { useState as useState2, useEffect as useEffect3, useCallback as useCallback6, useRef as useRef2 } from "react";
285
- import { Box as Box12, useInput as useInput8, useApp } from "ink";
295
+ import { Box as Box12, useInput as useInput9, useApp } from "ink";
286
296
 
287
297
  // src/cli/dashboard/state.tsx
288
298
  import React, { createContext, useContext, useReducer } from "react";
@@ -402,7 +412,8 @@ function handleStreamUpdate(state, update) {
402
412
  lastChange: entry.time,
403
413
  filesScannedSession: s.watch.filesScannedSession + 1
404
414
  };
405
- s = addActivity(s, `Change detected: ${update.data.file}`);
415
+ const shortFile = update.data.file.split("/").slice(-2).join("/");
416
+ s = addActivity(s, `Change: ${shortFile}`);
406
417
  break;
407
418
  }
408
419
  case "signal_extracted": {
@@ -430,6 +441,20 @@ function handleStreamUpdate(state, update) {
430
441
  message: update.data.message
431
442
  }, ...s.rawLog].slice(0, 500);
432
443
  break;
444
+ case "pending_fix":
445
+ s.pendingFixes = [{
446
+ id: update.data.id,
447
+ file: update.data.file,
448
+ description: update.data.description,
449
+ goalDescription: update.data.goalDescription,
450
+ confidence: update.data.confidence,
451
+ severity: update.data.severity,
452
+ suggestedFix: update.data.suggestedFix,
453
+ timestamp: update.timestamp,
454
+ status: "pending"
455
+ }, ...s.pendingFixes].slice(0, 20);
456
+ s = addActivity(s, `Goal violation: ${update.data.description} [${update.data.confidence}%]`);
457
+ break;
433
458
  }
434
459
  return s;
435
460
  }
@@ -687,6 +712,34 @@ function dashboardReducer(state, action) {
687
712
  if (!changed) return state;
688
713
  return { ...state, notificationHistory: history };
689
714
  }
715
+ case "ADD_PENDING_FIX":
716
+ return {
717
+ ...state,
718
+ pendingFixes: [action.fix, ...state.pendingFixes].slice(0, 20)
719
+ };
720
+ case "APPROVE_FIX":
721
+ return {
722
+ ...state,
723
+ pendingFixes: state.pendingFixes.map(
724
+ (f) => f.id === action.id ? { ...f, status: "applying" } : f
725
+ )
726
+ };
727
+ case "DISMISS_FIX":
728
+ return {
729
+ ...state,
730
+ pendingFixes: state.pendingFixes.map(
731
+ (f) => f.id === action.id ? { ...f, status: "dismissed" } : f
732
+ )
733
+ };
734
+ case "FIX_APPLIED":
735
+ return {
736
+ ...state,
737
+ pendingFixes: state.pendingFixes.map(
738
+ (f) => f.id === action.id ? { ...f, status: "applied" } : f
739
+ )
740
+ };
741
+ case "SELECT_FIX":
742
+ return { ...state, selectedFixIndex: action.index };
690
743
  default:
691
744
  return state;
692
745
  }
@@ -746,7 +799,9 @@ function createInitialState() {
746
799
  hypothesesPanel: { hypotheses: [], selectedIndex: 0, selectedCompletedIndex: 0, inputMode: "browse", inputBuffer: "", lastRefresh: 0 },
747
800
  memoryTree: { loaded: false, snapshot: null, globalPatterns: [], expandedNodes: /* @__PURE__ */ new Set(["decisions"]), selectedNode: "decisions", scrollPosition: 0, lastRefresh: 0 },
748
801
  agentBrain: { loaded: false, decisions: [], patterns: [], ledgerHash: null, selectedIndex: 0, expandedIndex: null },
749
- chatState: { messages: [], inputBuffer: "", loading: false }
802
+ chatState: { messages: [], inputBuffer: "", loading: false },
803
+ pendingFixes: [],
804
+ selectedFixIndex: 0
750
805
  };
751
806
  }
752
807
  var DashboardContext = createContext(null);
@@ -767,45 +822,50 @@ import { readFile as readFile2, writeFile, mkdir } from "fs/promises";
767
822
  import { join as join2 } from "path";
768
823
 
769
824
  // src/cli/dashboard/components/Header.tsx
770
- import { Box, Text } from "ink";
825
+ import { Box, Text, useStdout } from "ink";
771
826
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
772
827
  function Header() {
773
828
  const { state } = useDashboard();
774
829
  const { signalExtraction, watch, alerts } = state;
830
+ const { stdout } = useStdout();
831
+ const cols = stdout?.columns || 80;
832
+ const narrow = cols < 50;
775
833
  const totalExtracted = signalExtraction.decisionsExtracted + signalExtraction.factsExtracted + signalExtraction.blockersExtracted + signalExtraction.questionsExtracted;
776
834
  let status;
777
835
  if (watch.watching) {
778
836
  status = totalExtracted > 0 ? /* @__PURE__ */ jsxs(Text, { children: [
779
837
  /* @__PURE__ */ jsx2(Text, { color: "green", children: "\u25CF" }),
780
- " ",
781
- /* @__PURE__ */ jsx2(Text, { color: "green", children: "Learning" }),
782
- " ",
783
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
838
+ narrow ? "" : " ",
839
+ /* @__PURE__ */ jsx2(Text, { color: "green", children: narrow ? "" : "Learning" }),
840
+ !narrow && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
841
+ " ",
784
842
  totalExtracted,
785
843
  " signals"
786
844
  ] })
787
845
  ] }) : /* @__PURE__ */ jsxs(Text, { children: [
788
846
  /* @__PURE__ */ jsx2(Text, { color: "green", children: "\u25CF" }),
789
- " Watching"
847
+ !narrow && " Watching"
790
848
  ] });
791
849
  } else {
792
850
  status = /* @__PURE__ */ jsxs(Text, { children: [
793
851
  /* @__PURE__ */ jsx2(Text, { dimColor: true, children: "\u25CB" }),
794
- " ",
795
- /* @__PURE__ */ jsx2(Text, { dimColor: true, children: "Idle" })
852
+ !narrow && /* @__PURE__ */ jsx2(Text, { dimColor: true, children: " Idle" })
796
853
  ] });
797
854
  }
798
855
  return /* @__PURE__ */ jsxs(Box, { paddingX: 1, justifyContent: "space-between", children: [
799
- /* @__PURE__ */ jsx2(Text, { bold: true, children: "Trie" }),
800
- /* @__PURE__ */ jsxs(Box, { gap: 2, children: [
856
+ /* @__PURE__ */ jsx2(Text, { bold: true, color: "magenta", children: "Trie" }),
857
+ /* @__PURE__ */ jsxs(Box, { gap: narrow ? 1 : 2, children: [
801
858
  status,
802
- alerts.hasCritical && /* @__PURE__ */ jsx2(Text, { color: "red", bold: true, children: "\u25CF Alert" })
859
+ alerts.hasCritical && /* @__PURE__ */ jsxs(Text, { color: "red", bold: true, children: [
860
+ "\u25CF",
861
+ !narrow && " Alert"
862
+ ] })
803
863
  ] })
804
864
  ] });
805
865
  }
806
866
 
807
867
  // src/cli/dashboard/components/Footer.tsx
808
- import { Box as Box2, Text as Text2 } from "ink";
868
+ import { Box as Box2, Text as Text2, useStdout as useStdout2 } from "ink";
809
869
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
810
870
  var VIEW_LABELS = {
811
871
  overview: "Overview",
@@ -816,6 +876,15 @@ var VIEW_LABELS = {
816
876
  memory: "Ledger",
817
877
  chat: "Chat"
818
878
  };
879
+ var VIEW_SHORT = {
880
+ overview: "Ovr",
881
+ rawlog: "Log",
882
+ agent: "Ndg",
883
+ goals: "Gls",
884
+ hypotheses: "Hyp",
885
+ memory: "Ldg",
886
+ chat: "Cht"
887
+ };
819
888
  var TAB_VIEWS = ["overview", "memory", "goals", "hypotheses", "agent", "chat"];
820
889
  var CONTEXT_HINTS = {
821
890
  goals: "j/k nav \xB7 a add \xB7 enter complete \xB7 d delete",
@@ -825,14 +894,42 @@ var CONTEXT_HINTS = {
825
894
  chat: "type to ask \xB7 enter send \xB7 esc clear",
826
895
  rawlog: "n/p pages \xB7 b back"
827
896
  };
897
+ var CONTEXT_HINTS_SHORT = {
898
+ goals: "j/k a d",
899
+ hypotheses: "j/k a v x",
900
+ agent: "j/k enter d",
901
+ memory: "j/k enter",
902
+ chat: "enter esc",
903
+ rawlog: "n/p b"
904
+ };
828
905
  function Footer() {
829
906
  const { state } = useDashboard();
830
907
  const { view, goalsPanel, hypothesesPanel } = state;
831
- let hints = CONTEXT_HINTS[view] || "n/p pages \xB7 s settings";
832
- if (view === "goals" && goalsPanel.inputMode === "add") hints = "enter save \xB7 esc cancel";
833
- if (view === "hypotheses" && hypothesesPanel.inputMode === "add") hints = "enter save \xB7 esc cancel";
908
+ const { stdout } = useStdout2();
909
+ const cols = stdout?.columns || 80;
910
+ const narrow = cols < 60;
911
+ const veryNarrow = cols < 40;
912
+ const labels = narrow ? VIEW_SHORT : VIEW_LABELS;
913
+ let hints;
914
+ if (view === "goals" && goalsPanel.inputMode === "add") {
915
+ hints = narrow ? "enter esc" : "enter save \xB7 esc cancel";
916
+ } else if (view === "hypotheses" && hypothesesPanel.inputMode === "add") {
917
+ hints = narrow ? "enter esc" : "enter save \xB7 esc cancel";
918
+ } else {
919
+ const hintMap = narrow ? CONTEXT_HINTS_SHORT : CONTEXT_HINTS;
920
+ hints = hintMap[view] || (narrow ? "s n/p" : "n/p pages \xB7 s settings");
921
+ }
922
+ if (veryNarrow) {
923
+ 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)) }),
925
+ /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
926
+ hints,
927
+ " \xB7 q quit"
928
+ ] })
929
+ ] });
930
+ }
834
931
  return /* @__PURE__ */ jsxs2(Box2, { paddingX: 1, justifyContent: "space-between", children: [
835
- /* @__PURE__ */ jsx3(Box2, { gap: 1, children: TAB_VIEWS.map((v) => v === view ? /* @__PURE__ */ jsx3(Text2, { color: "green", bold: true, children: VIEW_LABELS[v] }, v) : /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: VIEW_LABELS[v] }, v)) }),
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)) }),
836
933
  /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
837
934
  hints,
838
935
  " \xB7 q quit"
@@ -841,21 +938,21 @@ function Footer() {
841
938
  }
842
939
 
843
940
  // src/cli/dashboard/components/Notification.tsx
844
- import { Box as Box3, Text as Text3 } from "ink";
941
+ import { Box as Box3, Text as Text3, useStdout as useStdout3 } from "ink";
845
942
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
846
943
  function Notification() {
847
944
  const { state } = useDashboard();
848
945
  const { notification } = state;
946
+ const { stdout } = useStdout3();
947
+ const cols = stdout?.columns || 80;
849
948
  if (!notification || !notification.active) return null;
850
949
  if (notification.autoHideAt && Date.now() > notification.autoHideAt) return null;
851
950
  const color = notification.severity === "critical" ? "red" : notification.severity === "warning" ? "yellow" : "blue";
951
+ const maxMsgLen = Math.max(20, cols - 8);
952
+ const msg = notification.message.length > maxMsgLen ? notification.message.slice(0, maxMsgLen - 1) + "..." : notification.message;
852
953
  return /* @__PURE__ */ jsxs3(Box3, { paddingX: 1, children: [
853
954
  /* @__PURE__ */ jsx4(Text3, { color, bold: true, children: "\u25CF " }),
854
- /* @__PURE__ */ jsx4(Text3, { children: notification.message }),
855
- notification.file && /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
856
- " ",
857
- notification.file
858
- ] })
955
+ /* @__PURE__ */ jsx4(Text3, { wrap: "truncate", children: msg })
859
956
  ] });
860
957
  }
861
958
 
@@ -1035,11 +1132,13 @@ function ConfigDialog({ onClose }) {
1035
1132
  const workDir = getWorkingDirectory(void 0, true);
1036
1133
  const trieDir = getTrieDirectory(workDir);
1037
1134
  const filesToDelete = [
1038
- join(trieDir, "context-graph.json"),
1135
+ join(trieDir, "context.db"),
1136
+ join(trieDir, "context.json"),
1039
1137
  join(trieDir, "incident-trie.json"),
1040
1138
  join(trieDir, "memory", "ledger.json"),
1041
1139
  join(trieDir, "memory", "issue-store.db"),
1042
- join(trieDir, "memory", "insights.json")
1140
+ join(trieDir, "memory", "insights.json"),
1141
+ join(trieDir, "memory", "issues.json")
1043
1142
  ];
1044
1143
  for (const file of filesToDelete) {
1045
1144
  if (existsSync(file)) {
@@ -1105,18 +1204,41 @@ function ConfigDialog({ onClose }) {
1105
1204
  }
1106
1205
 
1107
1206
  // src/cli/dashboard/views/OverviewView.tsx
1108
- import { Box as Box5, Text as Text5 } from "ink";
1109
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1207
+ import { Box as Box5, Text as Text5, useInput as useInput2, useStdout as useStdout4 } from "ink";
1208
+ import { Fragment, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1209
+ function truncate(str, max) {
1210
+ return str.length > max ? str.slice(0, max - 1) + "..." : str;
1211
+ }
1110
1212
  function OverviewView() {
1111
- const { state } = useDashboard();
1112
- const { progress, signalExtraction, watch, issues, activityLog, activityPage } = state;
1213
+ const { state, dispatch } = useDashboard();
1214
+ const { progress, signalExtraction, watch, issues, activityLog, activityPage, pendingFixes, selectedFixIndex } = state;
1113
1215
  const { totalIssues } = progress;
1216
+ const { stdout } = useStdout4();
1217
+ const cols = stdout?.columns || 80;
1218
+ const narrow = cols < 60;
1219
+ const contentWidth = Math.max(20, cols - 4);
1114
1220
  const endTime = state.scanComplete && state.scanEndTime ? state.scanEndTime : Date.now();
1115
1221
  const elapsed = ((endTime - state.scanStartTime) / 1e3).toFixed(1);
1116
1222
  const criticalIssues = issues.filter((i) => i.severity === "critical").slice(0, 3);
1117
- const activityRows = 8;
1223
+ const activeFixes = pendingFixes.filter((f) => f.status === "pending" || f.status === "applying");
1224
+ const activityRows = activeFixes.length > 0 ? 5 : 8;
1118
1225
  const startIdx = activityPage * activityRows;
1119
1226
  const pageActivities = activityLog.slice(startIdx, startIdx + activityRows);
1227
+ useInput2((input, key) => {
1228
+ if (state.view !== "overview" || activeFixes.length === 0) return;
1229
+ if (key.upArrow && activeFixes.length > 0) {
1230
+ dispatch({ type: "SELECT_FIX", index: Math.max(0, selectedFixIndex - 1) });
1231
+ }
1232
+ if (key.downArrow && activeFixes.length > 0) {
1233
+ dispatch({ type: "SELECT_FIX", index: Math.min(activeFixes.length - 1, selectedFixIndex + 1) });
1234
+ }
1235
+ if (input === "f" && activeFixes[selectedFixIndex]) {
1236
+ dispatch({ type: "APPROVE_FIX", id: activeFixes[selectedFixIndex].id });
1237
+ }
1238
+ if (input === "x" && activeFixes[selectedFixIndex]) {
1239
+ dispatch({ type: "DISMISS_FIX", id: activeFixes[selectedFixIndex].id });
1240
+ }
1241
+ });
1120
1242
  return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", paddingX: 1, children: [
1121
1243
  /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
1122
1244
  "Scanned ",
@@ -1125,26 +1247,27 @@ function OverviewView() {
1125
1247
  elapsed,
1126
1248
  "s"
1127
1249
  ] }),
1128
- watch.watching && signalExtraction.enabled && /* @__PURE__ */ jsxs5(Text5, { children: [
1250
+ watch.watching && signalExtraction.enabled && /* @__PURE__ */ jsxs5(Text5, { wrap: "truncate", children: [
1129
1251
  /* @__PURE__ */ jsx6(Text5, { color: "green", children: "\u25CF" }),
1130
1252
  " Signal extraction",
1131
- (signalExtraction.decisionsExtracted > 0 || signalExtraction.factsExtracted > 0 || signalExtraction.blockersExtracted > 0) && /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
1253
+ !narrow && (signalExtraction.decisionsExtracted > 0 || signalExtraction.factsExtracted > 0 || signalExtraction.blockersExtracted > 0) && /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
1132
1254
  " ",
1133
1255
  signalExtraction.decisionsExtracted,
1134
- " decisions \xB7 ",
1256
+ "d \xB7 ",
1135
1257
  signalExtraction.factsExtracted,
1136
- " facts \xB7 ",
1258
+ "f \xB7 ",
1137
1259
  signalExtraction.blockersExtracted,
1138
- " blockers"
1260
+ "b"
1139
1261
  ] })
1140
1262
  ] }),
1141
1263
  criticalIssues.length > 0 && criticalIssues.map((issue, i) => {
1142
1264
  const filename = issue.file.split("/").pop() || issue.file;
1143
1265
  const lineNum = issue.line ? `:${issue.line}` : "";
1144
- return /* @__PURE__ */ jsxs5(Text5, { children: [
1266
+ const issueLen = Math.max(15, contentWidth - filename.length - 6);
1267
+ return /* @__PURE__ */ jsxs5(Text5, { wrap: "truncate", children: [
1145
1268
  /* @__PURE__ */ jsx6(Text5, { color: "red", children: "\u25CF" }),
1146
1269
  " ",
1147
- /* @__PURE__ */ jsx6(Text5, { color: "red", children: issue.issue.slice(0, 55) }),
1270
+ /* @__PURE__ */ jsx6(Text5, { color: "red", children: truncate(issue.issue, issueLen) }),
1148
1271
  /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
1149
1272
  " ",
1150
1273
  filename,
@@ -1152,25 +1275,62 @@ function OverviewView() {
1152
1275
  ] })
1153
1276
  ] }, i);
1154
1277
  }),
1155
- totalIssues === 0 && criticalIssues.length === 0 && /* @__PURE__ */ jsxs5(Text5, { children: [
1278
+ totalIssues === 0 && criticalIssues.length === 0 && activeFixes.length === 0 && /* @__PURE__ */ jsxs5(Text5, { children: [
1156
1279
  /* @__PURE__ */ jsx6(Text5, { color: "green", children: "\u25CF" }),
1157
1280
  " No issues"
1158
1281
  ] }),
1159
- /* @__PURE__ */ jsx6(Text5, { children: " " }),
1160
- /* @__PURE__ */ jsx6(Text5, { bold: true, children: "Activity" }),
1161
- pageActivities.map((entry, i) => /* @__PURE__ */ jsxs5(Text5, { children: [
1162
- " ",
1163
- /* @__PURE__ */ jsx6(Text5, { dimColor: true, children: entry.time }),
1164
- " ",
1165
- entry.message
1166
- ] }, i)),
1167
- pageActivities.length === 0 && /* @__PURE__ */ jsx6(Text5, { dimColor: true, children: " No activity yet" })
1282
+ activeFixes.length > 0 && /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
1283
+ /* @__PURE__ */ jsx6(Text5, { bold: true, children: "Goal Violations" }),
1284
+ activeFixes.map((fix, i) => {
1285
+ const isSelected = i === selectedFixIndex;
1286
+ const confidenceColor = fix.confidence >= 90 ? "green" : fix.confidence >= 70 ? "yellow" : "red";
1287
+ const shortFile = fix.file.split("/").pop() || fix.file;
1288
+ const descLen = Math.max(15, contentWidth - shortFile.length - 10);
1289
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
1290
+ /* @__PURE__ */ jsxs5(Text5, { wrap: "truncate", children: [
1291
+ isSelected ? /* @__PURE__ */ jsx6(Text5, { bold: true, color: "yellow", children: "> " }) : " ",
1292
+ /* @__PURE__ */ jsx6(Text5, { color: "yellow", children: "\u25CF" }),
1293
+ " ",
1294
+ /* @__PURE__ */ jsx6(Text5, { children: truncate(fix.description, descLen) }),
1295
+ /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
1296
+ " ",
1297
+ shortFile
1298
+ ] })
1299
+ ] }),
1300
+ /* @__PURE__ */ jsxs5(Text5, { wrap: "truncate", children: [
1301
+ " ",
1302
+ /* @__PURE__ */ jsxs5(Text5, { color: confidenceColor, bold: true, children: [
1303
+ fix.confidence,
1304
+ "%"
1305
+ ] }),
1306
+ narrow ? fix.status === "applying" && /* @__PURE__ */ jsx6(Text5, { color: "cyan", children: " applying..." }) : /* @__PURE__ */ jsxs5(Fragment, { children: [
1307
+ /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
1308
+ " confidence fix: ",
1309
+ truncate(fix.suggestedFix, contentWidth - 25)
1310
+ ] }),
1311
+ fix.status === "applying" && /* @__PURE__ */ jsx6(Text5, { color: "cyan", children: " applying..." })
1312
+ ] })
1313
+ ] })
1314
+ ] }, fix.id);
1315
+ }),
1316
+ /* @__PURE__ */ jsx6(Text5, { dimColor: true, children: " f fix \xB7 x dismiss" })
1317
+ ] }),
1318
+ /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 1, children: [
1319
+ /* @__PURE__ */ jsx6(Text5, { bold: true, children: "Activity" }),
1320
+ pageActivities.map((entry, i) => /* @__PURE__ */ jsxs5(Text5, { wrap: "truncate", children: [
1321
+ " ",
1322
+ /* @__PURE__ */ jsx6(Text5, { dimColor: true, children: entry.time }),
1323
+ " ",
1324
+ truncate(entry.message, contentWidth - 14)
1325
+ ] }, i)),
1326
+ pageActivities.length === 0 && /* @__PURE__ */ jsx6(Text5, { dimColor: true, children: " No activity yet" })
1327
+ ] })
1168
1328
  ] });
1169
1329
  }
1170
1330
 
1171
1331
  // src/cli/dashboard/views/AgentView.tsx
1172
1332
  import { useEffect, useCallback } from "react";
1173
- import { Box as Box6, Text as Text6, useInput as useInput2 } from "ink";
1333
+ import { Box as Box6, Text as Text6, useInput as useInput3, useStdout as useStdout5 } from "ink";
1174
1334
 
1175
1335
  // src/cli/dashboard/theme.ts
1176
1336
  import pc from "picocolors";
@@ -1221,6 +1381,9 @@ function timeAgo(iso) {
1221
1381
  function AgentView() {
1222
1382
  const { state, dispatch } = useDashboard();
1223
1383
  const { agentInsights, agentBrain, selectedInsight, expandedInsight } = state;
1384
+ const { stdout } = useStdout5();
1385
+ const cols = stdout?.columns || 80;
1386
+ const msgLen = Math.max(20, cols - 25);
1224
1387
  const visibleInsights = getVisibleInsights(state);
1225
1388
  const alerts = visibleInsights.filter((i) => i.type === "warning");
1226
1389
  const { decisions, patterns, loaded } = agentBrain;
@@ -1244,7 +1407,7 @@ function AgentView() {
1244
1407
  void loadBrain();
1245
1408
  }
1246
1409
  }, [loaded, loadBrain]);
1247
- useInput2((input, key) => {
1410
+ useInput3((input, key) => {
1248
1411
  if (key.upArrow || input === "k") dispatch({ type: "NAVIGATE_UP" });
1249
1412
  else if (key.downArrow || input === "j") dispatch({ type: "NAVIGATE_DOWN" });
1250
1413
  else if (key.return) dispatch({ type: "TOGGLE_INSIGHT", index: selectedInsight });
@@ -1282,10 +1445,10 @@ function AgentView() {
1282
1445
  const isSelected = idx === selectedInsight;
1283
1446
  const isExpanded = idx === expandedInsight;
1284
1447
  const ago = formatTimeAgo(insight.timestamp);
1285
- const msg = insight.message.slice(0, 60) + (insight.message.length > 60 ? "..." : "");
1448
+ const msg = insight.message.slice(0, msgLen) + (insight.message.length > msgLen ? "..." : "");
1286
1449
  const riskColor = insight.priority >= 8 ? "red" : insight.priority >= 5 ? "yellow" : void 0;
1287
1450
  return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
1288
- /* @__PURE__ */ jsxs6(Text6, { children: [
1451
+ /* @__PURE__ */ jsxs6(Text6, { wrap: "truncate", children: [
1289
1452
  isSelected ? /* @__PURE__ */ jsx7(Text6, { bold: true, color: "green", children: "> " }) : " ",
1290
1453
  riskColor ? /* @__PURE__ */ jsx7(Text6, { color: riskColor, children: "\u25CF" }) : /* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "\u25CB" }),
1291
1454
  " ",
@@ -1316,8 +1479,8 @@ function AgentView() {
1316
1479
  " ",
1317
1480
  active ? /* @__PURE__ */ jsx7(Text6, { color: "green", children: "\u25CF" }) : /* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "\u25CB" }),
1318
1481
  " ",
1319
- dec.decision.slice(0, 50),
1320
- dec.decision.length > 50 ? "..." : "",
1482
+ dec.decision.slice(0, msgLen),
1483
+ dec.decision.length > msgLen ? "..." : "",
1321
1484
  /* @__PURE__ */ jsxs6(Text6, { dimColor: true, children: [
1322
1485
  " ",
1323
1486
  ago
@@ -1334,8 +1497,8 @@ function AgentView() {
1334
1497
  " ",
1335
1498
  pat.isAntiPattern ? /* @__PURE__ */ jsx7(Text6, { color: "red", children: "\u25CF" }) : /* @__PURE__ */ jsx7(Text6, { dimColor: true, children: "\u25CB" }),
1336
1499
  " ",
1337
- pat.description.slice(0, 48),
1338
- pat.description.length > 48 ? "..." : "",
1500
+ pat.description.slice(0, msgLen),
1501
+ pat.description.length > msgLen ? "..." : "",
1339
1502
  " ",
1340
1503
  confColor ? /* @__PURE__ */ jsxs6(Text6, { color: confColor, children: [
1341
1504
  conf,
@@ -1367,8 +1530,8 @@ function AgentView() {
1367
1530
 
1368
1531
  // src/cli/dashboard/views/GoalsView.tsx
1369
1532
  import { useCallback as useCallback2 } from "react";
1370
- import { Box as Box7, Text as Text7, useInput as useInput3 } from "ink";
1371
- import { Fragment, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1533
+ import { Box as Box7, Text as Text7, useInput as useInput4 } from "ink";
1534
+ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1372
1535
  function calculateGoalProgress(goal) {
1373
1536
  if (goal.target <= 0) return 0;
1374
1537
  const startValue = goal.startValue ?? goal.currentValue;
@@ -1464,7 +1627,7 @@ function GoalsView() {
1464
1627
  } catch {
1465
1628
  }
1466
1629
  }, [dispatch, refreshGoals]);
1467
- useInput3((_input, key) => {
1630
+ useInput4((_input, key) => {
1468
1631
  if (goalsPanel.inputMode === "add") {
1469
1632
  if (key.escape) {
1470
1633
  dispatch({ type: "SET_GOALS_INPUT_MODE", mode: "browse" });
@@ -1503,7 +1666,7 @@ function GoalsView() {
1503
1666
  /* @__PURE__ */ jsx8(Text7, { bold: true, color: "green", children: "|" })
1504
1667
  ] }) }),
1505
1668
  /* @__PURE__ */ jsx8(Text7, { dimColor: true, children: " enter save \xB7 esc cancel" })
1506
- ] }) : /* @__PURE__ */ jsx8(Fragment, { children: goalsPanel.goals.length === 0 ? /* @__PURE__ */ jsx8(Text7, { dimColor: true, children: " No goals yet. Press a to add one." }) : /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1669
+ ] }) : /* @__PURE__ */ jsx8(Fragment2, { children: goalsPanel.goals.length === 0 ? /* @__PURE__ */ jsx8(Text7, { dimColor: true, children: " No goals yet. Press a to add one." }) : /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
1507
1670
  activeGoals.map((goal, idx) => {
1508
1671
  const isSelected = goalsPanel.selectedIndex === idx;
1509
1672
  const progress = calculateGoalProgress(goal);
@@ -1555,8 +1718,8 @@ function GoalsView() {
1555
1718
 
1556
1719
  // src/cli/dashboard/views/HypothesesView.tsx
1557
1720
  import { useCallback as useCallback3 } from "react";
1558
- import { Box as Box8, Text as Text8, useInput as useInput4 } from "ink";
1559
- import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1721
+ import { Box as Box8, Text as Text8, useInput as useInput5 } from "ink";
1722
+ import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1560
1723
  function HypothesesView() {
1561
1724
  const { state, dispatch } = useDashboard();
1562
1725
  const { hypothesesPanel } = state;
@@ -1625,7 +1788,7 @@ function HypothesesView() {
1625
1788
  } catch {
1626
1789
  }
1627
1790
  }, [dispatch, refreshHypotheses]);
1628
- useInput4((_input, key) => {
1791
+ useInput5((_input, key) => {
1629
1792
  if (hypothesesPanel.inputMode === "add") {
1630
1793
  if (key.escape) {
1631
1794
  dispatch({ type: "SET_HYPOTHESES_INPUT_MODE", mode: "browse" });
@@ -1667,7 +1830,7 @@ function HypothesesView() {
1667
1830
  /* @__PURE__ */ jsx9(Text8, { bold: true, color: "green", children: "|" })
1668
1831
  ] }) }),
1669
1832
  /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: " enter save \xB7 esc cancel" })
1670
- ] }) : /* @__PURE__ */ jsx9(Fragment2, { children: hypothesesPanel.hypotheses.length === 0 ? /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: " No hypotheses yet. Press a to add one." }) : /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
1833
+ ] }) : /* @__PURE__ */ jsx9(Fragment3, { children: hypothesesPanel.hypotheses.length === 0 ? /* @__PURE__ */ jsx9(Text8, { dimColor: true, children: " No hypotheses yet. Press a to add one." }) : /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
1671
1834
  testing.map((hypo, idx) => {
1672
1835
  const isSelected = hypothesesPanel.selectedIndex === idx;
1673
1836
  const conf = Math.round(hypo.confidence * 100);
@@ -1719,8 +1882,8 @@ function HypothesesView() {
1719
1882
 
1720
1883
  // src/cli/dashboard/views/MemoryTreeView.tsx
1721
1884
  import { useEffect as useEffect2, useCallback as useCallback4 } from "react";
1722
- import { Box as Box9, Text as Text9, useInput as useInput5 } from "ink";
1723
- import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1885
+ import { Box as Box9, Text as Text9, useInput as useInput6 } from "ink";
1886
+ import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1724
1887
  function timeAgo2(iso) {
1725
1888
  const ms = Date.now() - new Date(iso).getTime();
1726
1889
  const mins = Math.floor(ms / 6e4);
@@ -1751,7 +1914,7 @@ function MemoryTreeView() {
1751
1914
  void loadData();
1752
1915
  }
1753
1916
  }, [loaded, loadData]);
1754
- useInput5((_input, key) => {
1917
+ useInput6((_input, key) => {
1755
1918
  if (key.upArrow || _input === "k") dispatch({ type: "NAVIGATE_UP" });
1756
1919
  else if (key.downArrow || _input === "j") dispatch({ type: "NAVIGATE_DOWN" });
1757
1920
  else if (key.return) dispatch({ type: "TOGGLE_MEMORY_NODE", nodeId: selectedNode });
@@ -1888,7 +2051,7 @@ function MemoryTreeView() {
1888
2051
  ] })
1889
2052
  ] }, pattern.id);
1890
2053
  }),
1891
- hotspots.length > 0 && /* @__PURE__ */ jsxs9(Fragment3, { children: [
2054
+ hotspots.length > 0 && /* @__PURE__ */ jsxs9(Fragment4, { children: [
1892
2055
  renderHeader("hotspots", "Risk Hotspots", hotspots.length),
1893
2056
  expandedNodes.has("hotspots") && hotspots.slice(0, 10).map((n) => {
1894
2057
  const nodeId = `file-${n.id}`;
@@ -1914,14 +2077,14 @@ function MemoryTreeView() {
1914
2077
  }
1915
2078
 
1916
2079
  // src/cli/dashboard/views/RawLogView.tsx
1917
- import { Box as Box10, Text as Text10, useInput as useInput6 } from "ink";
2080
+ import { Box as Box10, Text as Text10, useInput as useInput7 } from "ink";
1918
2081
  import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1919
2082
  function RawLogView() {
1920
2083
  const { state, dispatch } = useDashboard();
1921
2084
  const { rawLog, rawLogPage } = state;
1922
2085
  const pageSize = Math.max(10, (process.stdout.rows || 40) - 10);
1923
2086
  const totalPages = Math.max(1, Math.ceil(rawLog.length / pageSize));
1924
- useInput6((input, _key) => {
2087
+ useInput7((input, _key) => {
1925
2088
  if (input === "n") dispatch({ type: "SET_RAW_LOG_PAGE", page: Math.min(totalPages - 1, rawLogPage + 1) });
1926
2089
  else if (input === "p") dispatch({ type: "SET_RAW_LOG_PAGE", page: Math.max(0, rawLogPage - 1) });
1927
2090
  });
@@ -1955,7 +2118,7 @@ function RawLogView() {
1955
2118
 
1956
2119
  // src/cli/dashboard/views/ChatView.tsx
1957
2120
  import { useCallback as useCallback5, useRef } from "react";
1958
- import { Box as Box11, Text as Text11, useInput as useInput7 } from "ink";
2121
+ import { Box as Box11, Text as Text11, useInput as useInput8 } from "ink";
1959
2122
 
1960
2123
  // src/tools/tell.ts
1961
2124
  import path from "path";
@@ -4319,6 +4482,98 @@ ${checkpoint.files.length > 0 ? `**Files:** ${checkpoint.files.join(", ")}` : ""
4319
4482
 
4320
4483
  // src/cli/dashboard/chat-tools.ts
4321
4484
  import { createHash } from "crypto";
4485
+
4486
+ // src/utils/terminal-spawn.ts
4487
+ import { exec } from "child_process";
4488
+ import { promisify } from "util";
4489
+ import { platform } from "os";
4490
+ var execAsync = promisify(exec);
4491
+ async function spawnTerminal(options) {
4492
+ const { command, cwd, title, keepOpen = true } = options;
4493
+ const os = platform();
4494
+ if (os === "darwin") {
4495
+ await spawnMacOSTerminal(command, cwd, title, keepOpen);
4496
+ } else if (os === "linux") {
4497
+ await spawnLinuxTerminal(command, cwd, title, keepOpen);
4498
+ } else {
4499
+ throw new Error(`Terminal spawning not supported on ${os}`);
4500
+ }
4501
+ }
4502
+ async function spawnMacOSTerminal(command, cwd, title, keepOpen) {
4503
+ const escapedCommand = command.replace(/'/g, `'"'"'`);
4504
+ const escapedCwd = cwd?.replace(/'/g, `'"'"'`) || process.cwd();
4505
+ const escapedTitle = title?.replace(/'/g, `'"'"'`) || "Trie Agent";
4506
+ const fullCommand = cwd ? `cd '${escapedCwd}' && ${command}` : command;
4507
+ const escapedFullCommand = fullCommand.replace(/'/g, `'"'"'`);
4508
+ const script = `
4509
+ tell application "Terminal"
4510
+ activate
4511
+ set newTab to do script "${escapedFullCommand}"
4512
+ set custom title of newTab to "${escapedTitle}"
4513
+ end tell
4514
+ `.trim();
4515
+ try {
4516
+ await execAsync(`osascript -e '${script.replace(/'/g, `'"'"'`)}'`);
4517
+ } catch (error) {
4518
+ console.error("Terminal.app spawn failed, trying fallback...");
4519
+ const shellCmd = keepOpen ? `${fullCommand}; exec bash` : fullCommand;
4520
+ await execAsync(`open -a Terminal "${escapedCwd}" --args -e "${shellCmd}"`);
4521
+ }
4522
+ }
4523
+ async function spawnLinuxTerminal(command, cwd, title, keepOpen) {
4524
+ const workDir = cwd || process.cwd();
4525
+ const termTitle = title || "Trie Agent";
4526
+ const shellCmd = keepOpen ? `${command}; exec bash` : command;
4527
+ const terminals = [
4528
+ // GNOME Terminal
4529
+ {
4530
+ command: "gnome-terminal",
4531
+ args: `--working-directory="${workDir}" --title="${termTitle}" -- bash -c "${shellCmd}"`
4532
+ },
4533
+ // Konsole (KDE)
4534
+ {
4535
+ command: "konsole",
4536
+ args: `--workdir "${workDir}" --title "${termTitle}" -e bash -c "${shellCmd}"`
4537
+ },
4538
+ // xterm (fallback)
4539
+ {
4540
+ command: "xterm",
4541
+ args: `-T "${termTitle}" -e "cd '${workDir}' && ${shellCmd}"`
4542
+ }
4543
+ ];
4544
+ for (const term of terminals) {
4545
+ try {
4546
+ await execAsync(`which ${term.command}`);
4547
+ await execAsync(`${term.command} ${term.args} &`);
4548
+ return;
4549
+ } catch {
4550
+ continue;
4551
+ }
4552
+ }
4553
+ throw new Error("No supported terminal emulator found (tried: gnome-terminal, konsole, xterm)");
4554
+ }
4555
+ async function spawnClaudeCodeFix(options) {
4556
+ const { file, goal, violation, suggestedFix, cwd } = options;
4557
+ const prompt = `Fix this goal violation:
4558
+
4559
+ Goal: ${goal}
4560
+ File: ${file}
4561
+ Violation: ${violation}
4562
+ ${suggestedFix ? `Suggested fix: ${suggestedFix}` : ""}
4563
+
4564
+ Please review the file and fix the violation while preserving functionality.`;
4565
+ const escapedPrompt = prompt.replace(/"/g, '\\"').replace(/\n/g, "\\n");
4566
+ const escapedFile = file.replace(/"/g, '\\"');
4567
+ const command = `echo "${escapedPrompt}" | claude --file="${escapedFile}"`;
4568
+ await spawnTerminal({
4569
+ command,
4570
+ cwd,
4571
+ title: `Fixing: ${file}`,
4572
+ keepOpen: true
4573
+ });
4574
+ }
4575
+
4576
+ // src/cli/dashboard/chat-tools.ts
4322
4577
  function textFromResult(result) {
4323
4578
  return result.content.map((c) => c.text).join("\n");
4324
4579
  }
@@ -4468,6 +4723,20 @@ var CHAT_TOOLS = [
4468
4723
  },
4469
4724
  required: ["decision", "context"]
4470
4725
  }
4726
+ },
4727
+ {
4728
+ name: "trie_fix_goal_violation",
4729
+ 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.",
4730
+ input_schema: {
4731
+ type: "object",
4732
+ properties: {
4733
+ file: { type: "string", description: "File path with the goal violation" },
4734
+ goal: { type: "string", description: "The goal that was violated" },
4735
+ violation: { type: "string", description: "Description of the violation" },
4736
+ suggestedFix: { type: "string", description: "Suggested fix for the violation (optional)" }
4737
+ },
4738
+ required: ["file", "goal", "violation"]
4739
+ }
4471
4740
  }
4472
4741
  ];
4473
4742
  async function executeTool(name, input) {
@@ -4617,6 +4886,35 @@ async function executeTool(name, input) {
4617
4886
  });
4618
4887
  return `Decision recorded [${hash}]: "${dec}"`;
4619
4888
  }
4889
+ case "trie_fix_goal_violation": {
4890
+ const file = String(input.file || "").trim();
4891
+ const goal = String(input.goal || "").trim();
4892
+ const violation = String(input.violation || "").trim();
4893
+ const suggestedFix = input.suggestedFix ? String(input.suggestedFix) : void 0;
4894
+ if (!file) return "File path is required.";
4895
+ if (!goal) return "Goal description is required.";
4896
+ if (!violation) return "Violation description is required.";
4897
+ try {
4898
+ await spawnClaudeCodeFix({
4899
+ file,
4900
+ goal,
4901
+ violation,
4902
+ suggestedFix,
4903
+ cwd: directory
4904
+ });
4905
+ return `\u2713 Spawned Claude Code in a new terminal to fix "${file}".
4906
+
4907
+ Claude Code will:
4908
+ 1. Review the file
4909
+ 2. Understand the goal: "${goal}"
4910
+ 3. Fix the violation: "${violation}"
4911
+ 4. Preserve all functionality
4912
+
4913
+ Check the new terminal window to see the fix in progress.`;
4914
+ } catch (error) {
4915
+ return `Failed to spawn Claude Code: ${error instanceof Error ? error.message : "unknown error"}`;
4916
+ }
4917
+ }
4620
4918
  default:
4621
4919
  return `Unknown tool: ${name}`;
4622
4920
  }
@@ -4626,6 +4924,20 @@ async function executeTool(name, input) {
4626
4924
  import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
4627
4925
  async function buildContext(workDir) {
4628
4926
  const parts = [];
4927
+ try {
4928
+ const guardianState = getGuardianState(workDir);
4929
+ await guardianState.load();
4930
+ const activeGoals = guardianState.getAllGoals().filter((g) => g.status === "active");
4931
+ if (activeGoals.length > 0) {
4932
+ parts.push("Active goals:\n" + activeGoals.map((g) => {
4933
+ const metadata = g.metadata || {};
4934
+ const caughtCount = metadata.caughtCount || 0;
4935
+ const lastCaught = metadata.lastCaught ? ` (last violation: ${metadata.lastCaughtFile || "unknown"})` : "";
4936
+ return `- "${g.description}" [${g.category || "general"}]${caughtCount > 0 ? ` - ${caughtCount} violation(s)${lastCaught}` : ""}`;
4937
+ }).join("\n"));
4938
+ }
4939
+ } catch {
4940
+ }
4629
4941
  try {
4630
4942
  const storage = new TieredStorage(workDir);
4631
4943
  try {
@@ -4690,6 +5002,12 @@ function chatHistoryToMessages(history) {
4690
5002
  }
4691
5003
  var SYSTEM_PROMPT = `You are Trie, a code guardian assistant embedded in a terminal TUI.
4692
5004
  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.
5005
+
5006
+ When the user mentions a goal violation or asks you to fix something detected by the watcher:
5007
+ 1. Extract the file path, goal description, and violation details from context
5008
+ 2. Use trie_fix_goal_violation to spawn Claude Code in a new terminal
5009
+ 3. Claude Code will automatically fix the violation
5010
+
4693
5011
  Answer concisely. Reference specific files, decisions, and patterns when relevant.
4694
5012
  When you use a tool, briefly summarize what you did and what the result was.`;
4695
5013
  function ChatView() {
@@ -4778,7 +5096,7 @@ ${contextBlock}`;
4778
5096
  loadingRef.current = false;
4779
5097
  }
4780
5098
  }, [dispatch, messages]);
4781
- useInput7((input, key) => {
5099
+ useInput8((input, key) => {
4782
5100
  if (loading) return;
4783
5101
  if (key.return && inputBuffer.trim().length > 0) {
4784
5102
  void sendMessage(inputBuffer.trim());
@@ -4841,6 +5159,56 @@ function formatToolInput(input) {
4841
5159
  // src/cli/dashboard/App.tsx
4842
5160
  import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
4843
5161
  var MAIN_VIEWS = ["overview", "memory", "goals", "hypotheses", "agent", "chat"];
5162
+ async function applyGoalFix(fix, dispatch) {
5163
+ try {
5164
+ const { runAIAnalysis, isAIAvailable: isAIAvailable2 } = await import("./client-PMKE26IV.js");
5165
+ if (!isAIAvailable2()) {
5166
+ dispatch({ type: "DISMISS_FIX", id: fix.id });
5167
+ getOutputManager().nudge("AI not available for fix", "warning");
5168
+ return;
5169
+ }
5170
+ const projectPath = getWorkingDirectory(void 0, true);
5171
+ const fullPath = join2(projectPath, fix.file);
5172
+ const content = await readFile2(fullPath, "utf-8");
5173
+ const result = await runAIAnalysis({
5174
+ systemPrompt: `You are a precise code fixer. The user has a quality goal: "${fix.goalDescription}".
5175
+ A violation was detected: "${fix.description}"
5176
+ Suggested fix: "${fix.suggestedFix}"
5177
+
5178
+ Return the COMPLETE fixed file content. Make the minimal change needed to resolve the violation.
5179
+ Do NOT add comments explaining the fix. Do NOT change anything else.
5180
+ Output ONLY the file content, no markdown fences, no explanation.`,
5181
+ userPrompt: `Fix this file:
5182
+
5183
+ \`\`\`
5184
+ ${content}
5185
+ \`\`\``,
5186
+ maxTokens: 4096,
5187
+ temperature: 0
5188
+ });
5189
+ if (!result.success || !result.content.trim()) {
5190
+ dispatch({ type: "DISMISS_FIX", id: fix.id });
5191
+ getOutputManager().nudge("Fix generation failed", "warning");
5192
+ return;
5193
+ }
5194
+ let fixedContent = result.content.trim();
5195
+ if (fixedContent.startsWith("```")) {
5196
+ fixedContent = fixedContent.replace(/^```\w*\n?/, "").replace(/\n?```$/, "");
5197
+ }
5198
+ await writeFile(fullPath, fixedContent, "utf-8");
5199
+ const { recordGoalViolationFixed, getActiveGoals } = await import("./goal-validator-YSNN23D4.js");
5200
+ const goals = await getActiveGoals(projectPath);
5201
+ const matchedGoal = goals.find((g) => g.description === fix.goalDescription);
5202
+ if (matchedGoal) {
5203
+ await recordGoalViolationFixed(matchedGoal, fix.file, projectPath);
5204
+ }
5205
+ dispatch({ type: "FIX_APPLIED", id: fix.id });
5206
+ getOutputManager().nudge(`Fixed: ${fix.description} in ${fix.file.split("/").pop()}`, "info", fix.file, 8e3);
5207
+ } catch (error) {
5208
+ dispatch({ type: "DISMISS_FIX", id: fix.id });
5209
+ getOutputManager().nudge(`Fix failed: ${error}`, "warning");
5210
+ }
5211
+ }
4844
5212
  function DashboardApp({ onReady }) {
4845
5213
  const { state, dispatch } = useDashboard();
4846
5214
  const { exit } = useApp();
@@ -4864,7 +5232,7 @@ function DashboardApp({ onReady }) {
4864
5232
  const workDir = getWorkingDirectory(void 0, true);
4865
5233
  await mkdir(getTrieDirectory(workDir), { recursive: true });
4866
5234
  await writeFile(configPath, JSON.stringify(stateRef.current.agentConfig, null, 2), "utf-8");
4867
- const { saveAutonomyConfig, loadAutonomyConfig } = await import("./autonomy-config-JXB7WCZ2.js");
5235
+ const { saveAutonomyConfig, loadAutonomyConfig } = await import("./autonomy-config-QA6ATWLJ.js");
4868
5236
  const autonomy = await loadAutonomyConfig(workDir);
4869
5237
  autonomy.aiWatcher = stateRef.current.agentConfig.aiWatcher;
4870
5238
  await saveAutonomyConfig(workDir, autonomy);
@@ -4990,7 +5358,15 @@ function DashboardApp({ onReady }) {
4990
5358
  }, 5e3);
4991
5359
  return () => clearInterval(interval);
4992
5360
  }, []);
4993
- useInput8((input, key) => {
5361
+ const applyingFixIds = useRef2(/* @__PURE__ */ new Set());
5362
+ useEffect3(() => {
5363
+ const toApply = state.pendingFixes.filter((f) => f.status === "applying" && !applyingFixIds.current.has(f.id));
5364
+ for (const fix of toApply) {
5365
+ applyingFixIds.current.add(fix.id);
5366
+ void applyGoalFix(fix, dispatchRef.current);
5367
+ }
5368
+ }, [state.pendingFixes]);
5369
+ useInput9((input, key) => {
4994
5370
  if (showConfig) return;
4995
5371
  if (state.view === "goals" && state.goalsPanel.inputMode === "add") return;
4996
5372
  if (state.view === "hypotheses" && state.hypothesesPanel.inputMode === "add") return;
@@ -5139,4 +5515,4 @@ export {
5139
5515
  handleCheckpointTool,
5140
5516
  InteractiveDashboard
5141
5517
  };
5142
- //# sourceMappingURL=chunk-ZYKEILVK.js.map
5518
+ //# sourceMappingURL=chunk-EWVU7QUG.js.map