@triedotdev/mcp 1.0.163 → 1.0.164

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.
@@ -13,6 +13,9 @@ import {
13
13
  import {
14
14
  getOutputManager
15
15
  } from "./chunk-VR4VWXXU.js";
16
+ import {
17
+ getInsightStore
18
+ } from "./chunk-T63OHG4Q.js";
16
19
  import {
17
20
  LearningEngine,
18
21
  exportToJson,
@@ -697,10 +700,11 @@ function dashboardReducer(state, action) {
697
700
  const gotchas = action.storageGotchas ?? state.memoryTree.storageGotchas;
698
701
  const facts = action.storageFacts ?? state.memoryTree.storageFacts;
699
702
  const nudges = action.storageNudges ?? state.memoryTree.storageNudges;
703
+ const insights = action.storageInsights ?? state.memoryTree.storageInsights;
700
704
  const expanded = new Set(state.memoryTree.expandedNodes);
701
705
  if (blocks.length > 0) expanded.add("ledger-chain");
702
706
  if (gotchas.length > 0) expanded.add("gotchas");
703
- if (nudges.length > 0) expanded.add("patterns");
707
+ if (nudges.length > 0 || insights.length > 0) expanded.add("patterns");
704
708
  return {
705
709
  ...state,
706
710
  memoryTree: {
@@ -712,6 +716,7 @@ function dashboardReducer(state, action) {
712
716
  storageFacts: facts,
713
717
  storageGotchas: gotchas,
714
718
  storageNudges: nudges,
719
+ storageInsights: insights,
715
720
  ledgerBlocks: blocks,
716
721
  expandedNodes: expanded
717
722
  }
@@ -976,7 +981,7 @@ function createInitialState() {
976
981
  },
977
982
  goalsPanel: { goals: [], selectedIndex: 0, selectedAchievedIndex: 0, inputMode: "browse", inputBuffer: "", lastRefresh: 0, scanningGoalId: null, scanningProgress: "" },
978
983
  hypothesesPanel: { hypotheses: [], selectedIndex: 0, selectedCompletedIndex: 0, inputMode: "browse", inputBuffer: "", lastRefresh: 0, scanningHypothesisId: null, scanningProgress: "" },
979
- memoryTree: { loaded: false, snapshot: null, globalPatterns: [], storageGovernance: [], storageFacts: [], storageGotchas: [], storageNudges: [], ledgerBlocks: [], expandedNodes: /* @__PURE__ */ new Set(["decisions"]), expandedItemId: null, selectedNode: "decisions", scrollPosition: 0, lastRefresh: 0 },
984
+ memoryTree: { loaded: false, snapshot: null, globalPatterns: [], storageGovernance: [], storageFacts: [], storageGotchas: [], storageNudges: [], storageInsights: [], ledgerBlocks: [], expandedNodes: /* @__PURE__ */ new Set(["decisions"]), expandedItemId: null, selectedNode: "decisions", scrollPosition: 0, lastRefresh: 0 },
980
985
  agentBrain: { loaded: false, governance: [], patterns: [], ledgerHash: null, selectedIndex: 0, expandedIndex: null },
981
986
  chatState: { messages: [], inputBuffer: "", loading: false, progress: null, messageQueue: [], currentSessionId: null, currentSessionTitle: null },
982
987
  chatArchivePanel: { sessions: [], selectedIndex: 0, showArchived: false, loading: false, inputMode: "browse", inputBuffer: "" },
@@ -1977,8 +1982,8 @@ function AgentView() {
1977
1982
  if (!insight) return;
1978
1983
  try {
1979
1984
  const workDir = getWorkingDirectory(void 0, true);
1980
- const { getInsightStore } = await import("./insight-store-EC4PLSAW.js");
1981
- const store = getInsightStore(workDir);
1985
+ const { getInsightStore: getInsightStore2 } = await import("./insight-store-EC4PLSAW.js");
1986
+ const store = getInsightStore2(workDir);
1982
1987
  await store.dismissInsight(insight.id);
1983
1988
  const { getStorage: getStorage2 } = await import("./tiered-storage-FHHAJR4P.js");
1984
1989
  const storage = getStorage2(workDir);
@@ -2813,7 +2818,7 @@ function timeAgo2(iso) {
2813
2818
  function MemoryTreeView() {
2814
2819
  const { state, dispatch } = useDashboard();
2815
2820
  const { memoryTree } = state;
2816
- const { snapshot, globalPatterns, storageGovernance, storageFacts, storageGotchas, storageNudges, ledgerBlocks, expandedNodes, expandedItemId, selectedNode, loaded } = memoryTree;
2821
+ const { snapshot, globalPatterns, storageGovernance, storageFacts, storageGotchas, storageNudges, storageInsights, ledgerBlocks, expandedNodes, expandedItemId, selectedNode, loaded } = memoryTree;
2817
2822
  const { stdout } = useStdout8();
2818
2823
  const cols = stdout?.columns || 80;
2819
2824
  const narrow = cols < 60;
@@ -2823,6 +2828,7 @@ function MemoryTreeView() {
2823
2828
  const workDir = getWorkingDirectory(void 0, true);
2824
2829
  const graph = new ContextGraph(workDir);
2825
2830
  const storage = new TieredStorage(workDir);
2831
+ const insightStore = getInsightStore(workDir);
2826
2832
  const [snap, patterns, governance2, facts, gotchas, nudges, blocks] = await Promise.all([
2827
2833
  graph.getSnapshot(),
2828
2834
  findCrossProjectPatterns(2),
@@ -2832,7 +2838,9 @@ function MemoryTreeView() {
2832
2838
  storage.queryNudges({ limit: 20, resolved: false }).catch(() => []),
2833
2839
  getLedgerBlocks(workDir).catch(() => [])
2834
2840
  ]);
2835
- dispatch({ type: "SET_MEMORY_TREE", snapshot: snap, patterns, storageGovernance: governance2, storageFacts: facts, storageGotchas: gotchas, storageNudges: nudges, ledgerBlocks: blocks });
2841
+ await insightStore.load();
2842
+ const insights = insightStore.getActiveInsights(10);
2843
+ dispatch({ type: "SET_MEMORY_TREE", snapshot: snap, patterns, storageGovernance: governance2, storageFacts: facts, storageGotchas: gotchas, storageNudges: nudges, storageInsights: insights, ledgerBlocks: blocks });
2836
2844
  } catch (err) {
2837
2845
  dispatch({ type: "ADD_ACTIVITY", message: "Context graph load error" });
2838
2846
  }
@@ -2909,7 +2917,7 @@ function MemoryTreeView() {
2909
2917
  const order = { critical: 0, high: 1 };
2910
2918
  return (order[a.data.riskLevel] ?? 2) - (order[b.data.riskLevel] ?? 2);
2911
2919
  });
2912
- const totalEntries = productGovernance.length + learnedSignals.length + (storageFacts?.length ?? 0) + (storageNudges?.length ?? 0) + incidentNodes.length + patternNodes.length + globalPatterns.length + hotspots.length + ledgerBlocks.length;
2920
+ const totalEntries = productGovernance.length + learnedSignals.length + (storageFacts?.length ?? 0) + (storageNudges?.length ?? 0) + (storageInsights?.length ?? 0) + incidentNodes.length + patternNodes.length + globalPatterns.length + hotspots.length + ledgerBlocks.length;
2913
2921
  const expandedGovernance = expandedItemId?.startsWith("decision-") ? governance.find((g) => `decision-${g.id}` === expandedItemId) : null;
2914
2922
  const expandedIncident = expandedItemId?.startsWith("incident-") ? incidentNodes.find((n) => `incident-${n.id}` === expandedItemId) : null;
2915
2923
  const expandedGotcha = expandedItemId?.startsWith("gotcha-") ? storageGotchas.find((g) => `gotcha-${g.id}` === expandedItemId) ?? null : null;
@@ -3175,15 +3183,39 @@ function MemoryTreeView() {
3175
3183
  ] })
3176
3184
  ] }, g.id);
3177
3185
  }),
3178
- renderHeader("patterns", "Learned Signals", learnedSignals.length + (storageFacts?.length ?? 0) + (storageNudges?.length ?? 0) + patternNodes.length, learnedSignals.length === 0 && (storageFacts?.length ?? 0) === 0 && (storageNudges?.length ?? 0) === 0 && patternNodes.length === 0 ? "-- Trie learns as you work" : void 0),
3186
+ renderHeader("patterns", "Learned Signals", (storageInsights?.length ?? 0) + learnedSignals.length + (storageFacts?.length ?? 0) + (storageNudges?.length ?? 0) + patternNodes.length, (storageInsights?.length ?? 0) === 0 && learnedSignals.length === 0 && (storageFacts?.length ?? 0) === 0 && (storageNudges?.length ?? 0) === 0 && patternNodes.length === 0 ? "-- Trie learns as you work" : void 0),
3179
3187
  expandedNodes.has("patterns") && /* @__PURE__ */ jsxs10(Fragment6, { children: [
3180
- (storageNudges?.length ?? 0) > 0 && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
3188
+ (storageInsights?.length ?? 0) > 0 && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
3181
3189
  /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
3182
3190
  " ",
3183
3191
  " ",
3184
- "AI Detections"
3192
+ "Learnings"
3185
3193
  ] }),
3186
- storageNudges.slice(0, 5).map((n) => {
3194
+ storageInsights.slice(0, 5).map((insight) => {
3195
+ const descWidth = Math.max(30, contentWidth - 15);
3196
+ const desc = insight.message.length > descWidth ? insight.message.slice(0, descWidth - 3) + "..." : insight.message;
3197
+ const categoryLabel = insight.category === "security" ? "[sec]" : insight.category === "performance" ? "[perf]" : insight.category === "quality" ? "[qual]" : "[learn]";
3198
+ const confidenceColor = insight.priority >= 7 ? "green" : insight.priority >= 4 ? "yellow" : "white";
3199
+ return /* @__PURE__ */ jsxs10(Text10, { wrap: "truncate", children: [
3200
+ " ",
3201
+ /* @__PURE__ */ jsx11(Text10, { dimColor: true, children: categoryLabel }),
3202
+ " ",
3203
+ /* @__PURE__ */ jsx11(Text10, { children: desc }),
3204
+ narrow ? null : /* @__PURE__ */ jsxs10(Text10, { color: confidenceColor, dimColor: true, children: [
3205
+ " ",
3206
+ insight.priority,
3207
+ "/10"
3208
+ ] })
3209
+ ] }, insight.id);
3210
+ })
3211
+ ] }),
3212
+ (storageNudges?.length ?? 0) > 0 && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: (storageInsights?.length ?? 0) > 0 ? 1 : 0, children: [
3213
+ /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
3214
+ " ",
3215
+ " ",
3216
+ (storageInsights?.length ?? 0) > 0 ? "Raw Detections" : "AI Detections"
3217
+ ] }),
3218
+ storageNudges.slice(0, (storageInsights?.length ?? 0) > 0 ? 3 : 5).map((n) => {
3187
3219
  const descWidth = Math.max(30, contentWidth - 15);
3188
3220
  const desc = n.message.length > descWidth ? n.message.slice(0, descWidth - 3) + "..." : n.message;
3189
3221
  const severityColor = n.severity === "critical" ? "red" : n.severity === "high" ? "yellow" : "cyan";
@@ -3199,7 +3231,7 @@ function MemoryTreeView() {
3199
3231
  ] }, n.id);
3200
3232
  })
3201
3233
  ] }),
3202
- learnedSignals.length > 0 && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: (storageNudges?.length ?? 0) > 0 ? 1 : 0, children: [
3234
+ learnedSignals.length > 0 && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: (storageInsights?.length ?? 0) > 0 || (storageNudges?.length ?? 0) > 0 ? 1 : 0, children: [
3203
3235
  /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
3204
3236
  " ",
3205
3237
  " ",
@@ -3220,7 +3252,7 @@ function MemoryTreeView() {
3220
3252
  ] }, g.id);
3221
3253
  })
3222
3254
  ] }),
3223
- (storageFacts?.length ?? 0) > 0 && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: (storageNudges?.length ?? 0) > 0 || learnedSignals.length > 0 ? 1 : 0, children: [
3255
+ (storageFacts?.length ?? 0) > 0 && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: (storageInsights?.length ?? 0) > 0 || (storageNudges?.length ?? 0) > 0 || learnedSignals.length > 0 ? 1 : 0, children: [
3224
3256
  /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
3225
3257
  " ",
3226
3258
  " ",
@@ -3241,8 +3273,8 @@ function MemoryTreeView() {
3241
3273
  ] }, f.id);
3242
3274
  })
3243
3275
  ] }),
3244
- patternNodes.length > 0 && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: (storageNudges?.length ?? 0) > 0 || learnedSignals.length > 0 || (storageFacts?.length ?? 0) > 0 ? 1 : 0, children: [
3245
- ((storageNudges?.length ?? 0) > 0 || learnedSignals.length > 0 || (storageFacts?.length ?? 0) > 0) && /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
3276
+ patternNodes.length > 0 && /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: (storageInsights?.length ?? 0) > 0 || (storageNudges?.length ?? 0) > 0 || learnedSignals.length > 0 || (storageFacts?.length ?? 0) > 0 ? 1 : 0, children: [
3277
+ ((storageInsights?.length ?? 0) > 0 || (storageNudges?.length ?? 0) > 0 || learnedSignals.length > 0 || (storageFacts?.length ?? 0) > 0) && /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
3246
3278
  " ",
3247
3279
  " ",
3248
3280
  "Patterns"
@@ -3253,7 +3285,7 @@ function MemoryTreeView() {
3253
3285
  const confColor = conf > 70 ? "green" : conf > 40 ? "yellow" : void 0;
3254
3286
  const descWidth = Math.max(30, contentWidth - 15);
3255
3287
  const desc = n.data.description.length > descWidth ? n.data.description.slice(0, descWidth - 3) + "..." : n.data.description;
3256
- const hasPreceding = (storageNudges?.length ?? 0) > 0 || learnedSignals.length > 0 || (storageFacts?.length ?? 0) > 0;
3288
+ const hasPreceding = (storageInsights?.length ?? 0) > 0 || (storageNudges?.length ?? 0) > 0 || learnedSignals.length > 0 || (storageFacts?.length ?? 0) > 0;
3257
3289
  return /* @__PURE__ */ jsxs10(Text10, { wrap: "truncate", children: [
3258
3290
  sel(nodeId) ? /* @__PURE__ */ jsx11(Text10, { bold: true, color: "green", children: "> " }) : hasPreceding ? " " : " ",
3259
3291
  !hasPreceding && " ",
@@ -3273,7 +3305,7 @@ function MemoryTreeView() {
3273
3305
  ] }, n.id);
3274
3306
  })
3275
3307
  ] }),
3276
- patternNodes.length === 0 && learnedSignals.length === 0 && (storageFacts?.length ?? 0) === 0 && (storageNudges?.length ?? 0) === 0 && /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
3308
+ patternNodes.length === 0 && learnedSignals.length === 0 && (storageFacts?.length ?? 0) === 0 && (storageNudges?.length ?? 0) === 0 && (storageInsights?.length ?? 0) === 0 && /* @__PURE__ */ jsxs10(Text10, { dimColor: true, children: [
3277
3309
  " ",
3278
3310
  " ",
3279
3311
  "No signals learned yet. Trie will extract insights as you work."
@@ -9983,7 +10015,248 @@ var InteractiveDashboard = class {
9983
10015
  import { watch, existsSync as existsSync6, readFileSync as readFileSync2 } from "fs";
9984
10016
  import { stat, readFile as readFile5 } from "fs/promises";
9985
10017
  import { join as join4, extname as extname3, basename } from "path";
10018
+ import { createHash as createHash3 } from "crypto";
10019
+
10020
+ // src/agent/signal-summarizer.ts
10021
+ import Anthropic2 from "@anthropic-ai/sdk";
9986
10022
  import { createHash as createHash2 } from "crypto";
10023
+ var SIGNAL_THRESHOLD = 5;
10024
+ var SUMMARIZE_PROMPT = `You are an AI that learns patterns about a codebase from repeated issues.
10025
+
10026
+ Given a batch of similar code quality issues, extract a LEARNING about the codebase's tendencies. Don't summarize or count issues - identify what this pattern reveals about the codebase or team habits.
10027
+
10028
+ Good learnings (what we want):
10029
+ - "Type safety tends to be weak in this codebase"
10030
+ - "Error handling is often skipped in async code"
10031
+ - "The dashboard module has inconsistent patterns"
10032
+ - "State management doesn't follow a clear convention"
10033
+
10034
+ Bad learnings (avoid these):
10035
+ - "5 type safety issues detected" (just counting)
10036
+ - "Consider adding null checks" (action without insight)
10037
+ - "Issues found in src/dashboard" (no actual learning)
10038
+
10039
+ Respond with JSON:
10040
+ {
10041
+ "learning": "One sentence stating what Trie learned about this codebase (a tendency, habit, or pattern)",
10042
+ "evidence": "Brief explanation of what patterns led to this conclusion",
10043
+ "suggestedAction": "What could improve this tendency",
10044
+ "category": "quality" | "security" | "performance" | "pattern",
10045
+ "confidence": 1-10 (how confident is this learning based on evidence)
10046
+ }`;
10047
+ var SignalSummarizer = class {
10048
+ client = null;
10049
+ projectPath;
10050
+ processedBatches = /* @__PURE__ */ new Set();
10051
+ constructor(projectPath) {
10052
+ this.projectPath = projectPath;
10053
+ const apiKey = process.env.ANTHROPIC_API_KEY;
10054
+ if (apiKey) {
10055
+ this.client = new Anthropic2({ apiKey });
10056
+ }
10057
+ }
10058
+ /**
10059
+ * Check if we have enough nudges to generate a signal
10060
+ */
10061
+ async checkAndSummarize() {
10062
+ const storage = getStorage(this.projectPath);
10063
+ await storage.initialize();
10064
+ const nudges = await storage.queryNudges({ resolved: false, limit: 100 });
10065
+ if (nudges.length < SIGNAL_THRESHOLD) {
10066
+ return null;
10067
+ }
10068
+ const batches = this.groupNudges(nudges);
10069
+ for (const batch of batches) {
10070
+ if (batch.nudges.length >= SIGNAL_THRESHOLD && !this.processedBatches.has(batch.key)) {
10071
+ const insight = await this.summarizeBatch(batch);
10072
+ if (insight) {
10073
+ this.processedBatches.add(batch.key);
10074
+ return insight;
10075
+ }
10076
+ }
10077
+ }
10078
+ return null;
10079
+ }
10080
+ /**
10081
+ * Group nudges by similarity (same goal, same category, similar files)
10082
+ */
10083
+ groupNudges(nudges) {
10084
+ const groups = /* @__PURE__ */ new Map();
10085
+ for (const nudge of nudges) {
10086
+ const goalMatch = nudge.message.match(/Goal "([^"]+)" violated/);
10087
+ const goalPattern = goalMatch?.[1];
10088
+ const key = goalPattern ? `goal:${goalPattern}` : `category:${nudge.category || "general"}`;
10089
+ if (!groups.has(key)) {
10090
+ groups.set(key, {
10091
+ key,
10092
+ nudges: [],
10093
+ category: nudge.category || "quality",
10094
+ goalPattern,
10095
+ files: []
10096
+ });
10097
+ }
10098
+ const batch = groups.get(key);
10099
+ batch.nudges.push(nudge);
10100
+ if (nudge.file && !batch.files.includes(nudge.file)) {
10101
+ batch.files.push(nudge.file);
10102
+ }
10103
+ }
10104
+ return Array.from(groups.values());
10105
+ }
10106
+ /**
10107
+ * Use AI to summarize a batch of nudges into an insight
10108
+ */
10109
+ async summarizeBatch(batch) {
10110
+ if (!this.client) {
10111
+ return this.createFallbackInsight(batch);
10112
+ }
10113
+ try {
10114
+ const nudgeDescriptions = batch.nudges.slice(0, 10).map((n) => `- ${n.message}${n.file ? ` (${n.file})` : ""}`).join("\n");
10115
+ const response = await this.client.messages.create({
10116
+ model: "claude-3-haiku-20240307",
10117
+ max_tokens: 512,
10118
+ temperature: 0.3,
10119
+ messages: [{
10120
+ role: "user",
10121
+ content: `${SUMMARIZE_PROMPT}
10122
+
10123
+ Batch of ${batch.nudges.length} similar issues:
10124
+ ${nudgeDescriptions}
10125
+
10126
+ Files affected: ${batch.files.slice(0, 5).join(", ")}${batch.files.length > 5 ? ` (+${batch.files.length - 5} more)` : ""}`
10127
+ }]
10128
+ });
10129
+ const text = response.content[0]?.type === "text" ? response.content[0].text : "";
10130
+ const parsed = this.parseResponse(text);
10131
+ if (!parsed) {
10132
+ return this.createFallbackInsight(batch);
10133
+ }
10134
+ const insight = {
10135
+ id: `signal-${createHash2("sha256").update(batch.key + Date.now()).digest("hex").slice(0, 12)}`,
10136
+ type: "observation",
10137
+ message: parsed.learning,
10138
+ context: parsed.evidence,
10139
+ suggestedAction: parsed.suggestedAction,
10140
+ relatedIssues: batch.nudges.map((n) => n.id),
10141
+ priority: parsed.confidence,
10142
+ timestamp: Date.now(),
10143
+ dismissed: false,
10144
+ category: parsed.category,
10145
+ details: {
10146
+ affectedFiles: batch.files,
10147
+ issueBreakdown: { [batch.category]: batch.nudges.length },
10148
+ summary: parsed.learning
10149
+ }
10150
+ };
10151
+ const insightStore = getInsightStore(this.projectPath);
10152
+ await insightStore.load();
10153
+ await insightStore.addInsight(insight);
10154
+ const storage = getStorage(this.projectPath);
10155
+ for (const nudge of batch.nudges) {
10156
+ await storage.resolveNudge(nudge.id, "auto-fixed");
10157
+ }
10158
+ return insight;
10159
+ } catch (error) {
10160
+ console.error("[SignalSummarizer] AI summarization failed:", error);
10161
+ return this.createFallbackInsight(batch);
10162
+ }
10163
+ }
10164
+ /**
10165
+ * Parse AI response
10166
+ */
10167
+ parseResponse(text) {
10168
+ try {
10169
+ const jsonMatch = text.match(/\{[\s\S]*\}/);
10170
+ if (!jsonMatch) return null;
10171
+ const parsed = JSON.parse(jsonMatch[0]);
10172
+ return {
10173
+ learning: parsed.learning || "Pattern detected",
10174
+ evidence: parsed.evidence,
10175
+ suggestedAction: parsed.suggestedAction || "Review affected files",
10176
+ category: parsed.category || "quality",
10177
+ confidence: Math.min(10, Math.max(1, parsed.confidence || 5))
10178
+ };
10179
+ } catch {
10180
+ return null;
10181
+ }
10182
+ }
10183
+ /**
10184
+ * Create a fallback insight without AI
10185
+ */
10186
+ createFallbackInsight(batch) {
10187
+ let message;
10188
+ let suggestedAction;
10189
+ if (batch.goalPattern) {
10190
+ const pattern = batch.goalPattern.toLowerCase();
10191
+ if (pattern.includes("type") || pattern.includes("safety")) {
10192
+ message = `Type safety tends to be weak in this codebase`;
10193
+ } else if (pattern.includes("error") || pattern.includes("handling")) {
10194
+ message = `Error handling is often incomplete`;
10195
+ } else if (pattern.includes("test")) {
10196
+ message = `Test coverage appears insufficient`;
10197
+ } else if (pattern.includes("security") || pattern.includes("auth")) {
10198
+ message = `Security practices need attention`;
10199
+ } else {
10200
+ message = `"${batch.goalPattern}" compliance tends to be inconsistent`;
10201
+ }
10202
+ suggestedAction = `Establish stricter conventions for ${pattern}`;
10203
+ } else {
10204
+ if (batch.category === "security") {
10205
+ message = `Security practices need strengthening`;
10206
+ } else if (batch.category === "performance") {
10207
+ message = `Performance optimizations are often overlooked`;
10208
+ } else {
10209
+ message = `Code quality patterns are inconsistent`;
10210
+ }
10211
+ suggestedAction = `Review ${batch.category} conventions across the codebase`;
10212
+ }
10213
+ return {
10214
+ id: `signal-${createHash2("sha256").update(batch.key + Date.now()).digest("hex").slice(0, 12)}`,
10215
+ type: "observation",
10216
+ message,
10217
+ suggestedAction,
10218
+ relatedIssues: batch.nudges.map((n) => n.id),
10219
+ priority: 5,
10220
+ timestamp: Date.now(),
10221
+ dismissed: false,
10222
+ category: batch.category || "quality",
10223
+ details: {
10224
+ affectedFiles: batch.files,
10225
+ issueBreakdown: { [batch.category]: batch.nudges.length }
10226
+ }
10227
+ };
10228
+ }
10229
+ /**
10230
+ * Force summarization of all current nudge batches
10231
+ */
10232
+ async summarizeAll() {
10233
+ const storage = getStorage(this.projectPath);
10234
+ await storage.initialize();
10235
+ const nudges = await storage.queryNudges({ resolved: false, limit: 100 });
10236
+ const batches = this.groupNudges(nudges);
10237
+ const insights = [];
10238
+ for (const batch of batches) {
10239
+ if (batch.nudges.length >= SIGNAL_THRESHOLD) {
10240
+ const insight = await this.summarizeBatch(batch);
10241
+ if (insight) {
10242
+ insights.push(insight);
10243
+ }
10244
+ }
10245
+ }
10246
+ return insights;
10247
+ }
10248
+ };
10249
+ var summarizers = /* @__PURE__ */ new Map();
10250
+ function getSignalSummarizer(projectPath) {
10251
+ let summarizer = summarizers.get(projectPath);
10252
+ if (!summarizer) {
10253
+ summarizer = new SignalSummarizer(projectPath);
10254
+ summarizers.set(projectPath, summarizer);
10255
+ }
10256
+ return summarizer;
10257
+ }
10258
+
10259
+ // src/tools/watch.ts
9987
10260
  var WATCH_EXTENSIONS = /* @__PURE__ */ new Set([
9988
10261
  ".ts",
9989
10262
  ".tsx",
@@ -11353,7 +11626,7 @@ ${recentNudges || "(none)"}
11353
11626
  */
11354
11627
  async persistNudge(params) {
11355
11628
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
11356
- const nudgeId = createHash2("sha256").update(`${params.message}|${params.file || ""}|${timestamp}`).digest("hex").slice(0, 16);
11629
+ const nudgeId = createHash3("sha256").update(`${params.message}|${params.file || ""}|${timestamp}`).digest("hex").slice(0, 16);
11357
11630
  const nudge = {
11358
11631
  id: nudgeId,
11359
11632
  message: params.message,
@@ -11380,10 +11653,46 @@ ${recentNudges || "(none)"}
11380
11653
  const storage = getStorage(this.watchedDirectory);
11381
11654
  await storage.storeNudge(nudge);
11382
11655
  console.debug(`[Watch] \u2713 Persisted nudge to storage: ${nudge.message.slice(0, 60)}...`);
11656
+ void this.checkSignalThreshold();
11383
11657
  } catch (error) {
11384
11658
  console.error("[Watch] Failed to persist nudge to storage:", error);
11385
11659
  }
11386
11660
  }
11661
+ /**
11662
+ * Check if we have enough nudges (5+) to generate an AI-summarized signal.
11663
+ * Runs periodically after nudge persistence to batch similar issues into insights.
11664
+ */
11665
+ async checkSignalThreshold() {
11666
+ try {
11667
+ const summarizer = getSignalSummarizer(this.watchedDirectory);
11668
+ const insight = await summarizer.checkAndSummarize();
11669
+ if (insight) {
11670
+ getOutputManager().nudge(
11671
+ `Trie learned: ${insight.message}`,
11672
+ "info",
11673
+ void 0,
11674
+ 15e3
11675
+ );
11676
+ if (!isInteractiveMode()) {
11677
+ console.error(` [+] Learning: ${insight.message}`);
11678
+ if (insight.suggestedAction) {
11679
+ console.error(` Suggestion: ${insight.suggestedAction}`);
11680
+ }
11681
+ }
11682
+ if (this.streamingManager) {
11683
+ this.streamingManager.reportSignalExtraction({
11684
+ governance: 1,
11685
+ // Insights are a form of governance
11686
+ facts: 0,
11687
+ blockers: 0,
11688
+ questions: 0
11689
+ });
11690
+ }
11691
+ }
11692
+ } catch (error) {
11693
+ console.debug("[Watch] Signal threshold check failed:", error);
11694
+ }
11695
+ }
11387
11696
  getNudges() {
11388
11697
  return {
11389
11698
  content: [
@@ -11441,4 +11750,4 @@ export {
11441
11750
  InteractiveDashboard,
11442
11751
  TrieWatchTool
11443
11752
  };
11444
- //# sourceMappingURL=chunk-XSKLOBD2.js.map
11753
+ //# sourceMappingURL=chunk-D6E4Q4I6.js.map