@triedotdev/mcp 1.0.113 → 1.0.115
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.
- package/dist/auto-fix-apply-PCAHWLXF.js +10 -0
- package/dist/autonomy-config-JXB7WCZ2.js +30 -0
- package/dist/chunk-2GIAROBF.js +173 -0
- package/dist/chunk-2GIAROBF.js.map +1 -0
- package/dist/{chunk-33WL3D7A.js → chunk-2SIFK7OW.js} +7 -419
- package/dist/chunk-2SIFK7OW.js.map +1 -0
- package/dist/chunk-43X6JBEM.js +36 -0
- package/dist/chunk-43X6JBEM.js.map +1 -0
- package/dist/chunk-55DOQNHJ.js +772 -0
- package/dist/chunk-55DOQNHJ.js.map +1 -0
- package/dist/chunk-6LXSA2OZ.js +425 -0
- package/dist/chunk-6LXSA2OZ.js.map +1 -0
- package/dist/{chunk-SDS3UVFY.js → chunk-AOFYU6T3.js} +113 -559
- package/dist/chunk-AOFYU6T3.js.map +1 -0
- package/dist/{chunk-6QR6QZIX.js → chunk-D3EXBJE2.js} +25 -658
- package/dist/chunk-D3EXBJE2.js.map +1 -0
- package/dist/chunk-DJ2YAGHK.js +50 -0
- package/dist/chunk-DJ2YAGHK.js.map +1 -0
- package/dist/chunk-DZREHOGW.js +706 -0
- package/dist/chunk-DZREHOGW.js.map +1 -0
- package/dist/chunk-I2GFI3AM.js +340 -0
- package/dist/chunk-I2GFI3AM.js.map +1 -0
- package/dist/chunk-KRH642MT.js +947 -0
- package/dist/chunk-KRH642MT.js.map +1 -0
- package/dist/{chunk-QYOACM2C.js → chunk-MVNJPJBK.js} +22 -252
- package/dist/chunk-MVNJPJBK.js.map +1 -0
- package/dist/chunk-NS2MSZMB.js +394 -0
- package/dist/chunk-NS2MSZMB.js.map +1 -0
- package/dist/chunk-SWSK7ANT.js +340 -0
- package/dist/chunk-SWSK7ANT.js.map +1 -0
- package/dist/chunk-VRLMTOB6.js +566 -0
- package/dist/chunk-VRLMTOB6.js.map +1 -0
- package/dist/chunk-YR4BMGYO.js +130 -0
- package/dist/chunk-YR4BMGYO.js.map +1 -0
- package/dist/chunk-ZV2K6M7T.js +74 -0
- package/dist/chunk-ZV2K6M7T.js.map +1 -0
- package/dist/{chunk-2764KZZQ.js → chunk-ZYKEILVK.js} +451 -1069
- package/dist/chunk-ZYKEILVK.js.map +1 -0
- package/dist/cli/main.js +107 -375
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/yolo-daemon.js +18 -8
- package/dist/cli/yolo-daemon.js.map +1 -1
- package/dist/client-7XZHCMD3.js +28 -0
- package/dist/client-7XZHCMD3.js.map +1 -0
- package/dist/{goal-manager-AP4LTE6U.js → goal-manager-LMS6ZJB7.js} +7 -3
- package/dist/goal-manager-LMS6ZJB7.js.map +1 -0
- package/dist/goal-validator-T5HEYBC5.js +186 -0
- package/dist/goal-validator-T5HEYBC5.js.map +1 -0
- package/dist/graph-U5JWSAB5.js +10 -0
- package/dist/graph-U5JWSAB5.js.map +1 -0
- package/dist/guardian-agent-EXP7APLC.js +25 -0
- package/dist/guardian-agent-EXP7APLC.js.map +1 -0
- package/dist/hypothesis-KGC3P54C.js +19 -0
- package/dist/hypothesis-KGC3P54C.js.map +1 -0
- package/dist/incident-index-PNIVT47T.js +11 -0
- package/dist/incident-index-PNIVT47T.js.map +1 -0
- package/dist/index.js +369 -43
- package/dist/index.js.map +1 -1
- package/dist/ledger-SR6OEBLO.js +15 -0
- package/dist/ledger-SR6OEBLO.js.map +1 -0
- package/dist/output-manager-BOTMXSND.js +13 -0
- package/dist/output-manager-BOTMXSND.js.map +1 -0
- package/dist/pattern-discovery-F7LU5K6E.js +8 -0
- package/dist/pattern-discovery-F7LU5K6E.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-2764KZZQ.js.map +0 -1
- package/dist/chunk-33WL3D7A.js.map +0 -1
- package/dist/chunk-6JPPYG7F.js +0 -1813
- package/dist/chunk-6JPPYG7F.js.map +0 -1
- package/dist/chunk-6QR6QZIX.js.map +0 -1
- package/dist/chunk-QYOACM2C.js.map +0 -1
- package/dist/chunk-SDS3UVFY.js.map +0 -1
- package/dist/guardian-agent-XEYNG7RH.js +0 -18
- /package/dist/{goal-manager-AP4LTE6U.js.map → auto-fix-apply-PCAHWLXF.js.map} +0 -0
- /package/dist/{guardian-agent-XEYNG7RH.js.map → autonomy-config-JXB7WCZ2.js.map} +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
clearConfigCache,
|
|
3
|
+
createIssueHash,
|
|
4
|
+
getAutonomyConfig,
|
|
5
|
+
getEscalationLevel,
|
|
6
|
+
groupFixesByFile,
|
|
7
|
+
loadAutonomyConfig,
|
|
8
|
+
recordBypass,
|
|
9
|
+
saveAutonomyConfig,
|
|
10
|
+
shouldAutoFix,
|
|
11
|
+
shouldBlockPush,
|
|
12
|
+
trackIssueOccurrence
|
|
13
|
+
} from "./chunk-I2GFI3AM.js";
|
|
14
|
+
import "./chunk-R4AAPFXC.js";
|
|
15
|
+
import "./chunk-APMV77PU.js";
|
|
16
|
+
import "./chunk-DGUM43GV.js";
|
|
17
|
+
export {
|
|
18
|
+
clearConfigCache,
|
|
19
|
+
createIssueHash,
|
|
20
|
+
getAutonomyConfig,
|
|
21
|
+
getEscalationLevel,
|
|
22
|
+
groupFixesByFile,
|
|
23
|
+
loadAutonomyConfig,
|
|
24
|
+
recordBypass,
|
|
25
|
+
saveAutonomyConfig,
|
|
26
|
+
shouldAutoFix,
|
|
27
|
+
shouldBlockPush,
|
|
28
|
+
trackIssueOccurrence
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=autonomy-config-JXB7WCZ2.js.map
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Trie
|
|
3
|
+
} from "./chunk-6NLHFIYA.js";
|
|
4
|
+
import {
|
|
5
|
+
getTrieDirectory
|
|
6
|
+
} from "./chunk-R4AAPFXC.js";
|
|
7
|
+
|
|
8
|
+
// src/context/incident-index.ts
|
|
9
|
+
import path2 from "path";
|
|
10
|
+
|
|
11
|
+
// src/context/file-trie.ts
|
|
12
|
+
import fs from "fs";
|
|
13
|
+
import path from "path";
|
|
14
|
+
import { performance } from "perf_hooks";
|
|
15
|
+
function normalizePath(filePath) {
|
|
16
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
17
|
+
return normalized.startsWith("./") ? normalized.slice(2) : normalized;
|
|
18
|
+
}
|
|
19
|
+
var FilePathTrie = class {
|
|
20
|
+
trie = new Trie();
|
|
21
|
+
persistPath;
|
|
22
|
+
constructor(persistPath) {
|
|
23
|
+
if (persistPath) this.persistPath = persistPath;
|
|
24
|
+
if (persistPath && fs.existsSync(persistPath)) {
|
|
25
|
+
try {
|
|
26
|
+
const raw = fs.readFileSync(persistPath, "utf-8");
|
|
27
|
+
if (raw.trim().length > 0) {
|
|
28
|
+
const json = JSON.parse(raw);
|
|
29
|
+
this.trie = Trie.fromJSON(json);
|
|
30
|
+
}
|
|
31
|
+
} catch {
|
|
32
|
+
this.trie = new Trie();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
addIncident(filePath, incident) {
|
|
37
|
+
const key = normalizePath(filePath);
|
|
38
|
+
const existing = this.trie.search(key);
|
|
39
|
+
const incidents = existing.found && Array.isArray(existing.value) ? existing.value : [];
|
|
40
|
+
incidents.push(incident);
|
|
41
|
+
this.trie.insert(key, incidents);
|
|
42
|
+
this.persist();
|
|
43
|
+
}
|
|
44
|
+
getIncidents(filePath) {
|
|
45
|
+
const key = normalizePath(filePath);
|
|
46
|
+
const result = this.trie.search(key);
|
|
47
|
+
return result.found && Array.isArray(result.value) ? result.value : [];
|
|
48
|
+
}
|
|
49
|
+
getDirectoryIncidents(prefix) {
|
|
50
|
+
const normalizedPrefix = normalizePath(prefix);
|
|
51
|
+
const matches = this.trie.getWithPrefix(normalizedPrefix);
|
|
52
|
+
return matches.flatMap((m) => Array.isArray(m.value) ? m.value : []).filter(Boolean);
|
|
53
|
+
}
|
|
54
|
+
getHotZones(threshold) {
|
|
55
|
+
const matches = this.trie.getWithPrefix("");
|
|
56
|
+
const zones = [];
|
|
57
|
+
for (const match of matches) {
|
|
58
|
+
const incidents = Array.isArray(match.value) ? match.value : [];
|
|
59
|
+
if (incidents.length >= threshold) {
|
|
60
|
+
zones.push({
|
|
61
|
+
path: match.pattern,
|
|
62
|
+
incidentCount: incidents.length,
|
|
63
|
+
confidence: this.calculateConfidence(incidents.length)
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return zones.sort((a, b) => b.incidentCount - a.incidentCount);
|
|
68
|
+
}
|
|
69
|
+
suggestPaths(partial, limit = 5) {
|
|
70
|
+
const normalized = normalizePath(partial);
|
|
71
|
+
const results = this.trie.getWithPrefix(normalized);
|
|
72
|
+
return results.map((r) => ({
|
|
73
|
+
path: r.pattern,
|
|
74
|
+
incidentCount: Array.isArray(r.value) ? r.value.length : 0
|
|
75
|
+
})).sort((a, b) => b.incidentCount - a.incidentCount).slice(0, limit);
|
|
76
|
+
}
|
|
77
|
+
timeLookup(path3) {
|
|
78
|
+
const start = performance.now();
|
|
79
|
+
this.getIncidents(path3);
|
|
80
|
+
return performance.now() - start;
|
|
81
|
+
}
|
|
82
|
+
toJSON() {
|
|
83
|
+
return this.trie.toJSON();
|
|
84
|
+
}
|
|
85
|
+
calculateConfidence(count) {
|
|
86
|
+
const capped = Math.min(count, 10);
|
|
87
|
+
return Math.round(capped / 10 * 100) / 100;
|
|
88
|
+
}
|
|
89
|
+
persist() {
|
|
90
|
+
if (!this.persistPath) return;
|
|
91
|
+
try {
|
|
92
|
+
const dir = path.dirname(this.persistPath);
|
|
93
|
+
if (!fs.existsSync(dir)) {
|
|
94
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
95
|
+
}
|
|
96
|
+
fs.writeFileSync(this.persistPath, JSON.stringify(this.trie.toJSON()), "utf-8");
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// src/context/incident-index.ts
|
|
103
|
+
var IncidentIndex = class _IncidentIndex {
|
|
104
|
+
graph;
|
|
105
|
+
trie;
|
|
106
|
+
projectRoot;
|
|
107
|
+
constructor(graph, projectRoot, options) {
|
|
108
|
+
this.graph = graph;
|
|
109
|
+
this.projectRoot = projectRoot;
|
|
110
|
+
this.trie = new FilePathTrie(
|
|
111
|
+
options?.persistPath ?? path2.join(getTrieDirectory(projectRoot), "incident-trie.json")
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
static async build(graph, projectRoot, options) {
|
|
115
|
+
const index = new _IncidentIndex(graph, projectRoot, options);
|
|
116
|
+
await index.rebuild();
|
|
117
|
+
return index;
|
|
118
|
+
}
|
|
119
|
+
async rebuild() {
|
|
120
|
+
const nodes = await this.graph.listNodes();
|
|
121
|
+
const incidents = nodes.filter((n) => n.type === "incident");
|
|
122
|
+
for (const incident of incidents) {
|
|
123
|
+
const files = await this.getFilesForIncident(incident.id);
|
|
124
|
+
this.addIncidentToTrie(incident, files);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
addIncidentToTrie(incident, files) {
|
|
128
|
+
const meta = {
|
|
129
|
+
id: incident.id,
|
|
130
|
+
file: "",
|
|
131
|
+
description: incident.data.description,
|
|
132
|
+
severity: incident.data.severity,
|
|
133
|
+
timestamp: incident.data.timestamp
|
|
134
|
+
};
|
|
135
|
+
for (const file of files) {
|
|
136
|
+
const normalized = this.normalizePath(file);
|
|
137
|
+
this.trie.addIncident(normalized, { ...meta, file: normalized });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
getFileTrie() {
|
|
141
|
+
return this.trie;
|
|
142
|
+
}
|
|
143
|
+
async getFilesForIncident(incidentId) {
|
|
144
|
+
const files = /* @__PURE__ */ new Set();
|
|
145
|
+
const edges = await this.graph.getEdges(incidentId, "both");
|
|
146
|
+
for (const edge of edges) {
|
|
147
|
+
if (edge.type === "causedBy" || edge.type === "leadTo") {
|
|
148
|
+
const changeId = edge.type === "causedBy" ? edge.to_id : edge.from_id;
|
|
149
|
+
const change = await this.graph.getNode("change", changeId);
|
|
150
|
+
if (change?.data && "files" in change.data && Array.isArray(change.data.files)) {
|
|
151
|
+
change.data.files.forEach((f) => files.add(f));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (edge.type === "affects") {
|
|
155
|
+
const fileNode = await this.graph.getNode("file", edge.to_id) || await this.graph.getNode("file", edge.from_id);
|
|
156
|
+
if (fileNode && typeof fileNode.data?.path === "string") {
|
|
157
|
+
files.add(fileNode.data.path);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return Array.from(files);
|
|
162
|
+
}
|
|
163
|
+
normalizePath(filePath) {
|
|
164
|
+
const absolute = path2.isAbsolute(filePath) ? filePath : path2.join(this.projectRoot, filePath);
|
|
165
|
+
const relative = path2.relative(this.projectRoot, absolute);
|
|
166
|
+
return relative.replace(/\\/g, "/");
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
export {
|
|
171
|
+
IncidentIndex
|
|
172
|
+
};
|
|
173
|
+
//# sourceMappingURL=chunk-2GIAROBF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context/incident-index.ts","../src/context/file-trie.ts"],"sourcesContent":["import path from 'node:path';\n\nimport type { IncidentNode } from './nodes.js';\nimport type { ContextGraph } from './graph.js';\nimport { FilePathTrie, type IncidentMetadata } from './file-trie.js';\nimport { getTrieDirectory } from '../utils/workspace.js';\n\nexport interface IncidentIndexOptions {\n persistPath?: string;\n}\n\nexport class IncidentIndex {\n private readonly graph: ContextGraph;\n private readonly trie: FilePathTrie;\n private readonly projectRoot: string;\n\n constructor(graph: ContextGraph, projectRoot: string, options?: IncidentIndexOptions) {\n this.graph = graph;\n this.projectRoot = projectRoot;\n this.trie = new FilePathTrie(\n options?.persistPath ?? path.join(getTrieDirectory(projectRoot), 'incident-trie.json')\n );\n }\n\n static async build(graph: ContextGraph, projectRoot: string, options?: IncidentIndexOptions): Promise<IncidentIndex> {\n const index = new IncidentIndex(graph, projectRoot, options);\n await index.rebuild();\n return index;\n }\n\n async rebuild(): Promise<void> {\n const nodes = await this.graph.listNodes();\n const incidents = nodes.filter((n) => n.type === 'incident') as IncidentNode[];\n\n for (const incident of incidents) {\n const files = await this.getFilesForIncident(incident.id);\n this.addIncidentToTrie(incident, files);\n }\n }\n\n addIncidentToTrie(incident: IncidentNode, files: string[]): void {\n const meta: IncidentMetadata = {\n id: incident.id,\n file: '',\n description: incident.data.description,\n severity: incident.data.severity,\n timestamp: incident.data.timestamp,\n };\n\n for (const file of files) {\n const normalized = this.normalizePath(file);\n this.trie.addIncident(normalized, { ...meta, file: normalized });\n }\n }\n\n getFileTrie(): FilePathTrie {\n return this.trie;\n }\n\n private async getFilesForIncident(incidentId: string): Promise<string[]> {\n const files = new Set<string>();\n const edges = await this.graph.getEdges(incidentId, 'both');\n\n // Traverse connected changes to pull file lists\n for (const edge of edges) {\n if (edge.type === 'causedBy' || edge.type === 'leadTo') {\n // Identify the change node id regardless of direction\n const changeId = edge.type === 'causedBy' ? edge.to_id : edge.from_id;\n const change = await this.graph.getNode('change', changeId);\n if (change?.data && 'files' in change.data && Array.isArray(change.data.files)) {\n (change.data.files as string[]).forEach((f: string) => files.add(f));\n }\n }\n\n // If there are direct file links, capture them as well\n if (edge.type === 'affects') {\n const fileNode =\n (await this.graph.getNode('file', edge.to_id)) ||\n (await this.graph.getNode('file', edge.from_id));\n if (fileNode && typeof (fileNode as any).data?.path === 'string') {\n files.add((fileNode as any).data.path);\n }\n }\n }\n\n return Array.from(files);\n }\n\n private normalizePath(filePath: string): string {\n const absolute = path.isAbsolute(filePath) ? filePath : path.join(this.projectRoot, filePath);\n const relative = path.relative(this.projectRoot, absolute);\n return relative.replace(/\\\\/g, '/');\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { performance } from 'node:perf_hooks';\n\nimport { Trie } from '../trie/trie.js';\n\nexport interface IncidentMetadata {\n id: string;\n file: string;\n description: string;\n severity: 'minor' | 'major' | 'critical' | string;\n timestamp: string;\n}\n\nexport interface HotZone {\n path: string;\n incidentCount: number;\n confidence: number;\n}\n\nfunction normalizePath(filePath: string): string {\n const normalized = filePath.replace(/\\\\/g, '/');\n return normalized.startsWith('./') ? normalized.slice(2) : normalized;\n}\n\nexport class FilePathTrie {\n private trie: Trie<IncidentMetadata[]> = new Trie();\n private persistPath?: string;\n\n constructor(persistPath?: string) {\n if (persistPath) this.persistPath = persistPath;\n if (persistPath && fs.existsSync(persistPath)) {\n try {\n const raw = fs.readFileSync(persistPath, 'utf-8');\n if (raw.trim().length > 0) {\n const json = JSON.parse(raw);\n this.trie = Trie.fromJSON<IncidentMetadata[]>(json);\n }\n } catch {\n this.trie = new Trie();\n }\n }\n }\n\n addIncident(filePath: string, incident: IncidentMetadata): void {\n const key = normalizePath(filePath);\n const existing = this.trie.search(key);\n const incidents = existing.found && Array.isArray(existing.value) ? existing.value : [];\n incidents.push(incident);\n this.trie.insert(key, incidents);\n this.persist();\n }\n\n getIncidents(filePath: string): IncidentMetadata[] {\n const key = normalizePath(filePath);\n const result = this.trie.search(key);\n return result.found && Array.isArray(result.value) ? result.value : [];\n }\n\n getDirectoryIncidents(prefix: string): IncidentMetadata[] {\n const normalizedPrefix = normalizePath(prefix);\n const matches = this.trie.getWithPrefix(normalizedPrefix);\n return matches.flatMap((m) => (Array.isArray(m.value) ? m.value : [])).filter(Boolean);\n }\n\n getHotZones(threshold: number): HotZone[] {\n const matches = this.trie.getWithPrefix('');\n const zones: HotZone[] = [];\n\n for (const match of matches) {\n const incidents = Array.isArray(match.value) ? match.value : [];\n if (incidents.length >= threshold) {\n zones.push({\n path: match.pattern,\n incidentCount: incidents.length,\n confidence: this.calculateConfidence(incidents.length),\n });\n }\n }\n\n return zones.sort((a, b) => b.incidentCount - a.incidentCount);\n }\n\n suggestPaths(partial: string, limit = 5): Array<{ path: string; incidentCount: number }> {\n const normalized = normalizePath(partial);\n const results = this.trie.getWithPrefix(normalized);\n return results\n .map((r) => ({\n path: r.pattern,\n incidentCount: Array.isArray(r.value) ? r.value.length : 0,\n }))\n .sort((a, b) => b.incidentCount - a.incidentCount)\n .slice(0, limit);\n }\n\n timeLookup(path: string): number {\n const start = performance.now();\n this.getIncidents(path);\n return performance.now() - start;\n }\n\n toJSON(): object {\n return this.trie.toJSON();\n }\n\n private calculateConfidence(count: number): number {\n const capped = Math.min(count, 10);\n return Math.round((capped / 10) * 100) / 100; // 0-1 scale\n }\n\n private persist(): void {\n if (!this.persistPath) return;\n try {\n const dir = path.dirname(this.persistPath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(this.persistPath, JSON.stringify(this.trie.toJSON()), 'utf-8');\n } catch {\n // Persistence is best-effort; ignore failures\n }\n }\n}\n"],"mappings":"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","names":["path","path","path"]}
|
|
@@ -1,424 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
getInsightStore
|
|
3
|
+
} from "./chunk-6LXSA2OZ.js";
|
|
4
|
+
import {
|
|
5
5
|
getMemoryStats,
|
|
6
|
-
safeParseAndValidate,
|
|
7
6
|
searchIssues
|
|
8
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-55DOQNHJ.js";
|
|
9
8
|
import {
|
|
10
|
-
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
|
|
13
|
-
// src/guardian/insight-store.ts
|
|
14
|
-
import { mkdir, readFile } from "fs/promises";
|
|
15
|
-
import { existsSync } from "fs";
|
|
16
|
-
import { join } from "path";
|
|
17
|
-
import { z } from "zod";
|
|
18
|
-
var InsightDetailsSchema = z.object({
|
|
19
|
-
affectedFiles: z.array(z.string()).optional(),
|
|
20
|
-
issueBreakdown: z.record(z.string(), z.number()).optional(),
|
|
21
|
-
examples: z.array(z.string()).optional(),
|
|
22
|
-
trend: z.enum(["improving", "stable", "worsening"]).optional(),
|
|
23
|
-
comparison: z.string().optional(),
|
|
24
|
-
resolvedCount: z.number().optional(),
|
|
25
|
-
resolvedIssues: z.array(z.object({
|
|
26
|
-
file: z.string(),
|
|
27
|
-
line: z.number().optional(),
|
|
28
|
-
issue: z.string(),
|
|
29
|
-
agent: z.string(),
|
|
30
|
-
resolvedAt: z.string().optional()
|
|
31
|
-
})).optional(),
|
|
32
|
-
summary: z.string().optional()
|
|
33
|
-
});
|
|
34
|
-
var GuardianInsightSchema = z.object({
|
|
35
|
-
id: z.string(),
|
|
36
|
-
type: z.enum(["observation", "warning", "suggestion", "celebration", "question"]),
|
|
37
|
-
message: z.string(),
|
|
38
|
-
context: z.string().optional(),
|
|
39
|
-
suggestedAction: z.string().optional(),
|
|
40
|
-
actionCommand: z.string().optional(),
|
|
41
|
-
relatedIssues: z.array(z.string()),
|
|
42
|
-
priority: z.number().min(1).max(10),
|
|
43
|
-
timestamp: z.number(),
|
|
44
|
-
dismissed: z.boolean(),
|
|
45
|
-
category: z.enum(["security", "quality", "performance", "pattern", "progress", "general"]),
|
|
46
|
-
details: InsightDetailsSchema.optional()
|
|
47
|
-
});
|
|
48
|
-
var InsightStoreDataSchema = z.object({
|
|
49
|
-
version: z.literal(1),
|
|
50
|
-
insights: z.array(GuardianInsightSchema),
|
|
51
|
-
cooldowns: z.record(z.string(), z.number()),
|
|
52
|
-
// insightKey -> timestamp
|
|
53
|
-
dismissedIds: z.array(z.string()),
|
|
54
|
-
// Track dismissed insight IDs permanently
|
|
55
|
-
lastUpdated: z.string()
|
|
56
|
-
});
|
|
57
|
-
var InsightStore = class _InsightStore {
|
|
58
|
-
projectPath;
|
|
59
|
-
data;
|
|
60
|
-
loaded = false;
|
|
61
|
-
dirty = false;
|
|
62
|
-
// Default cooldown periods (in ms)
|
|
63
|
-
static COOLDOWNS = {
|
|
64
|
-
"pre-push-warning": 6e4,
|
|
65
|
-
// 1 min between pre-push warnings
|
|
66
|
-
"security-warning": 3e4,
|
|
67
|
-
// 30s between security warnings
|
|
68
|
-
"new-issues": 3e4,
|
|
69
|
-
// 30s between new issue observations
|
|
70
|
-
"celebration": 6e4,
|
|
71
|
-
// 1 min between celebrations
|
|
72
|
-
"pattern-suggestion": 12e4,
|
|
73
|
-
// 2 min between pattern suggestions
|
|
74
|
-
"accessibility-visual-qa": 3e5,
|
|
75
|
-
// 5 min between visual QA suggestions
|
|
76
|
-
"goal-suggestion": 3e5,
|
|
77
|
-
// 5 min between goal suggestions
|
|
78
|
-
"risk-prediction": 18e4,
|
|
79
|
-
// 3 min between risk predictions
|
|
80
|
-
"hypothesis-update": 6e5,
|
|
81
|
-
// 10 min between hypothesis updates
|
|
82
|
-
"auto-escalation": 3e5
|
|
83
|
-
// 5 min between auto-escalations
|
|
84
|
-
};
|
|
85
|
-
constructor(projectPath) {
|
|
86
|
-
this.projectPath = projectPath;
|
|
87
|
-
this.data = this.createEmptyData();
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Get the storage file path
|
|
91
|
-
*/
|
|
92
|
-
getStorePath() {
|
|
93
|
-
return join(getTrieDirectory(this.projectPath), "memory", "guardian-insights.json");
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Create empty data structure
|
|
97
|
-
*/
|
|
98
|
-
createEmptyData() {
|
|
99
|
-
return {
|
|
100
|
-
version: 1,
|
|
101
|
-
insights: [],
|
|
102
|
-
cooldowns: {},
|
|
103
|
-
dismissedIds: [],
|
|
104
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Load insights from disk
|
|
109
|
-
*
|
|
110
|
-
* If the file is corrupted, attempts recovery from backup.
|
|
111
|
-
* Returns empty data if no valid file/backup exists.
|
|
112
|
-
*/
|
|
113
|
-
async load() {
|
|
114
|
-
if (this.loaded) {
|
|
115
|
-
return this.data;
|
|
116
|
-
}
|
|
117
|
-
const storePath = this.getStorePath();
|
|
118
|
-
try {
|
|
119
|
-
if (existsSync(storePath)) {
|
|
120
|
-
const content = await readFile(storePath, "utf-8");
|
|
121
|
-
const result = safeParseAndValidate(content, InsightStoreDataSchema);
|
|
122
|
-
if (result.success) {
|
|
123
|
-
this.data = result.data;
|
|
124
|
-
this.loaded = true;
|
|
125
|
-
this.deduplicateInsights();
|
|
126
|
-
return this.data;
|
|
127
|
-
}
|
|
128
|
-
console.error(` Insight store corrupted: ${result.error}`);
|
|
129
|
-
const backupManager = new BackupManager(storePath);
|
|
130
|
-
if (await backupManager.recoverFromBackup()) {
|
|
131
|
-
console.error(" Recovered from backup");
|
|
132
|
-
const recovered = await readFile(storePath, "utf-8");
|
|
133
|
-
const recoveredResult = safeParseAndValidate(recovered, InsightStoreDataSchema);
|
|
134
|
-
if (recoveredResult.success) {
|
|
135
|
-
this.data = recoveredResult.data;
|
|
136
|
-
this.loaded = true;
|
|
137
|
-
this.deduplicateInsights();
|
|
138
|
-
return this.data;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
console.error(" No valid backup found, starting fresh");
|
|
142
|
-
}
|
|
143
|
-
} catch (error) {
|
|
144
|
-
console.error(` Could not load insight store: ${error}`);
|
|
145
|
-
}
|
|
146
|
-
this.data = this.createEmptyData();
|
|
147
|
-
this.loaded = true;
|
|
148
|
-
return this.data;
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Deduplicate existing insights on load
|
|
152
|
-
* Keeps the most recent instance of each unique insight
|
|
153
|
-
*/
|
|
154
|
-
deduplicateInsights() {
|
|
155
|
-
const seen = /* @__PURE__ */ new Map();
|
|
156
|
-
const toRemove = [];
|
|
157
|
-
for (let i = 0; i < this.data.insights.length; i++) {
|
|
158
|
-
const insight = this.data.insights[i];
|
|
159
|
-
if (!insight) continue;
|
|
160
|
-
const contentKey = this.getContentKey(insight);
|
|
161
|
-
if (seen.has(contentKey)) {
|
|
162
|
-
toRemove.push(i);
|
|
163
|
-
} else {
|
|
164
|
-
seen.set(contentKey, i);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
if (toRemove.length > 0) {
|
|
168
|
-
for (let i = toRemove.length - 1; i >= 0; i--) {
|
|
169
|
-
const idx = toRemove[i];
|
|
170
|
-
if (idx !== void 0) {
|
|
171
|
-
this.data.insights.splice(idx, 1);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
this.dirty = true;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Save insights to disk
|
|
179
|
-
*
|
|
180
|
-
* Creates backup before writing, uses atomic write.
|
|
181
|
-
*/
|
|
182
|
-
async save() {
|
|
183
|
-
if (!this.dirty && this.loaded) {
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
const storePath = this.getStorePath();
|
|
187
|
-
const memoryDir = join(getTrieDirectory(this.projectPath), "memory");
|
|
188
|
-
await mkdir(memoryDir, { recursive: true });
|
|
189
|
-
const backupManager = new BackupManager(storePath);
|
|
190
|
-
await backupManager.createBackup();
|
|
191
|
-
this.data.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
192
|
-
await atomicWriteJSON(storePath, this.data);
|
|
193
|
-
this.dirty = false;
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Generate a content-based key for deduplication
|
|
197
|
-
* Insights with the same content key are considered duplicates
|
|
198
|
-
*/
|
|
199
|
-
getContentKey(insight) {
|
|
200
|
-
const normalizedMessage = insight.message.replace(/\d+/g, "N").toLowerCase().trim();
|
|
201
|
-
return `${insight.type}:${insight.category}:${normalizedMessage}`;
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Add an insight to the store
|
|
205
|
-
*
|
|
206
|
-
* Checks for duplicates using both insight ID and content similarity.
|
|
207
|
-
* If a similar insight already exists (same type, category, and normalized message),
|
|
208
|
-
* updates its timestamp instead of creating a duplicate.
|
|
209
|
-
* Respects cooldowns to prevent insight spam.
|
|
210
|
-
*/
|
|
211
|
-
async addInsight(insight) {
|
|
212
|
-
await this.load();
|
|
213
|
-
if (this.data.insights.some((i) => i.id === insight.id)) {
|
|
214
|
-
return false;
|
|
215
|
-
}
|
|
216
|
-
if (this.data.dismissedIds.includes(insight.id)) {
|
|
217
|
-
return false;
|
|
218
|
-
}
|
|
219
|
-
const contentKey = this.getContentKey(insight);
|
|
220
|
-
const existingIndex = this.data.insights.findIndex(
|
|
221
|
-
(i) => !i.dismissed && this.getContentKey(i) === contentKey
|
|
222
|
-
);
|
|
223
|
-
if (existingIndex >= 0) {
|
|
224
|
-
const existing = this.data.insights[existingIndex];
|
|
225
|
-
if (existing) {
|
|
226
|
-
existing.timestamp = insight.timestamp;
|
|
227
|
-
existing.message = insight.message;
|
|
228
|
-
existing.details = insight.details;
|
|
229
|
-
existing.relatedIssues = insight.relatedIssues;
|
|
230
|
-
existing.suggestedAction = insight.suggestedAction;
|
|
231
|
-
this.data.insights.splice(existingIndex, 1);
|
|
232
|
-
this.data.insights.unshift(existing);
|
|
233
|
-
this.dirty = true;
|
|
234
|
-
await this.save();
|
|
235
|
-
}
|
|
236
|
-
return false;
|
|
237
|
-
}
|
|
238
|
-
this.data.insights.unshift(insight);
|
|
239
|
-
if (this.data.insights.length > 100) {
|
|
240
|
-
this.data.insights = this.data.insights.slice(0, 100);
|
|
241
|
-
}
|
|
242
|
-
this.dirty = true;
|
|
243
|
-
await this.save();
|
|
244
|
-
return true;
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* Check if a cooldown has expired for an insight type
|
|
248
|
-
*/
|
|
249
|
-
canCreateInsight(insightKey) {
|
|
250
|
-
const lastTime = this.data.cooldowns[insightKey];
|
|
251
|
-
const cooldown = _InsightStore.COOLDOWNS[insightKey] || 3e4;
|
|
252
|
-
if (!lastTime) return true;
|
|
253
|
-
return Date.now() - lastTime > cooldown;
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Mark that an insight type was created (set cooldown)
|
|
257
|
-
*/
|
|
258
|
-
async markInsightCreated(insightKey) {
|
|
259
|
-
await this.load();
|
|
260
|
-
this.data.cooldowns[insightKey] = Date.now();
|
|
261
|
-
this.dirty = true;
|
|
262
|
-
await this.save();
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Get active (non-dismissed) insights
|
|
266
|
-
*
|
|
267
|
-
* Returns insights sorted by priority (highest first),
|
|
268
|
-
* limited to the specified count.
|
|
269
|
-
*/
|
|
270
|
-
getActiveInsights(limit = 5) {
|
|
271
|
-
return this.data.insights.filter((i) => !i.dismissed).sort((a, b) => b.priority - a.priority).slice(0, limit);
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* Get all insights (including dismissed)
|
|
275
|
-
*/
|
|
276
|
-
getAllInsights() {
|
|
277
|
-
return [...this.data.insights];
|
|
278
|
-
}
|
|
279
|
-
/**
|
|
280
|
-
* Dismiss an insight by ID
|
|
281
|
-
*/
|
|
282
|
-
async dismissInsight(insightId) {
|
|
283
|
-
await this.load();
|
|
284
|
-
const insight = this.data.insights.find((i) => i.id === insightId);
|
|
285
|
-
if (!insight) {
|
|
286
|
-
return false;
|
|
287
|
-
}
|
|
288
|
-
insight.dismissed = true;
|
|
289
|
-
if (!this.data.dismissedIds.includes(insightId)) {
|
|
290
|
-
this.data.dismissedIds.push(insightId);
|
|
291
|
-
if (this.data.dismissedIds.length > 500) {
|
|
292
|
-
this.data.dismissedIds = this.data.dismissedIds.slice(-500);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
this.dirty = true;
|
|
296
|
-
await this.save();
|
|
297
|
-
return true;
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* Remove an insight entirely
|
|
301
|
-
*/
|
|
302
|
-
async removeInsight(insightId) {
|
|
303
|
-
await this.load();
|
|
304
|
-
const index = this.data.insights.findIndex((i) => i.id === insightId);
|
|
305
|
-
if (index === -1) {
|
|
306
|
-
return false;
|
|
307
|
-
}
|
|
308
|
-
this.data.insights.splice(index, 1);
|
|
309
|
-
this.dirty = true;
|
|
310
|
-
await this.save();
|
|
311
|
-
return true;
|
|
312
|
-
}
|
|
313
|
-
/**
|
|
314
|
-
* Clear all cooldowns
|
|
315
|
-
*/
|
|
316
|
-
async clearCooldowns() {
|
|
317
|
-
await this.load();
|
|
318
|
-
this.data.cooldowns = {};
|
|
319
|
-
this.dirty = true;
|
|
320
|
-
await this.save();
|
|
321
|
-
}
|
|
322
|
-
/**
|
|
323
|
-
* Get insight by ID
|
|
324
|
-
*/
|
|
325
|
-
getInsight(insightId) {
|
|
326
|
-
return this.data.insights.find((i) => i.id === insightId);
|
|
327
|
-
}
|
|
328
|
-
/**
|
|
329
|
-
* Update an existing insight
|
|
330
|
-
*/
|
|
331
|
-
async updateInsight(insightId, updates) {
|
|
332
|
-
await this.load();
|
|
333
|
-
const insight = this.data.insights.find((i) => i.id === insightId);
|
|
334
|
-
if (!insight) {
|
|
335
|
-
return false;
|
|
336
|
-
}
|
|
337
|
-
Object.assign(insight, updates);
|
|
338
|
-
this.dirty = true;
|
|
339
|
-
await this.save();
|
|
340
|
-
return true;
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* Get insights by category
|
|
344
|
-
*/
|
|
345
|
-
getInsightsByCategory(category) {
|
|
346
|
-
return this.data.insights.filter((i) => i.category === category && !i.dismissed);
|
|
347
|
-
}
|
|
348
|
-
/**
|
|
349
|
-
* Get insights by type
|
|
350
|
-
*/
|
|
351
|
-
getInsightsByType(type) {
|
|
352
|
-
return this.data.insights.filter((i) => i.type === type && !i.dismissed);
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* Get insights from the last N hours
|
|
356
|
-
*/
|
|
357
|
-
getRecentInsights(hours = 24) {
|
|
358
|
-
const cutoff = Date.now() - hours * 60 * 60 * 1e3;
|
|
359
|
-
return this.data.insights.filter((i) => i.timestamp >= cutoff);
|
|
360
|
-
}
|
|
361
|
-
/**
|
|
362
|
-
* Get statistics about insights
|
|
363
|
-
*/
|
|
364
|
-
getStats() {
|
|
365
|
-
const stats = {
|
|
366
|
-
total: this.data.insights.length,
|
|
367
|
-
active: 0,
|
|
368
|
-
dismissed: 0,
|
|
369
|
-
byCategory: {},
|
|
370
|
-
byType: {}
|
|
371
|
-
};
|
|
372
|
-
for (const insight of this.data.insights) {
|
|
373
|
-
if (insight.dismissed) {
|
|
374
|
-
stats.dismissed++;
|
|
375
|
-
} else {
|
|
376
|
-
stats.active++;
|
|
377
|
-
}
|
|
378
|
-
stats.byCategory[insight.category] = (stats.byCategory[insight.category] || 0) + 1;
|
|
379
|
-
stats.byType[insight.type] = (stats.byType[insight.type] || 0) + 1;
|
|
380
|
-
}
|
|
381
|
-
return stats;
|
|
382
|
-
}
|
|
383
|
-
/**
|
|
384
|
-
* Prune old insights (older than N days)
|
|
385
|
-
*/
|
|
386
|
-
async pruneOldInsights(daysToKeep = 30) {
|
|
387
|
-
await this.load();
|
|
388
|
-
const cutoff = Date.now() - daysToKeep * 24 * 60 * 60 * 1e3;
|
|
389
|
-
const originalCount = this.data.insights.length;
|
|
390
|
-
this.data.insights = this.data.insights.filter((i) => i.timestamp >= cutoff);
|
|
391
|
-
const pruned = originalCount - this.data.insights.length;
|
|
392
|
-
if (pruned > 0) {
|
|
393
|
-
this.dirty = true;
|
|
394
|
-
await this.save();
|
|
395
|
-
}
|
|
396
|
-
return pruned;
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* Check if the store has been loaded
|
|
400
|
-
*/
|
|
401
|
-
isLoaded() {
|
|
402
|
-
return this.loaded;
|
|
403
|
-
}
|
|
404
|
-
/**
|
|
405
|
-
* Force reload from disk
|
|
406
|
-
*/
|
|
407
|
-
async reload() {
|
|
408
|
-
this.loaded = false;
|
|
409
|
-
this.dirty = false;
|
|
410
|
-
return this.load();
|
|
411
|
-
}
|
|
412
|
-
};
|
|
413
|
-
var insightStores = /* @__PURE__ */ new Map();
|
|
414
|
-
function getInsightStore(projectPath) {
|
|
415
|
-
let store = insightStores.get(projectPath);
|
|
416
|
-
if (!store) {
|
|
417
|
-
store = new InsightStore(projectPath);
|
|
418
|
-
insightStores.set(projectPath, store);
|
|
419
|
-
}
|
|
420
|
-
return store;
|
|
421
|
-
}
|
|
9
|
+
getGuardianState
|
|
10
|
+
} from "./chunk-KRH642MT.js";
|
|
422
11
|
|
|
423
12
|
// src/guardian/goal-manager.ts
|
|
424
13
|
import { basename } from "path";
|
|
@@ -1032,11 +621,10 @@ function clearGoalManagers() {
|
|
|
1032
621
|
}
|
|
1033
622
|
|
|
1034
623
|
export {
|
|
1035
|
-
getInsightStore,
|
|
1036
624
|
GoalManager,
|
|
1037
625
|
calculateAdaptiveScanFrequency,
|
|
1038
626
|
adaptScanFrequency,
|
|
1039
627
|
getGoalManager,
|
|
1040
628
|
clearGoalManagers
|
|
1041
629
|
};
|
|
1042
|
-
//# sourceMappingURL=chunk-
|
|
630
|
+
//# sourceMappingURL=chunk-2SIFK7OW.js.map
|