@triedotdev/mcp 1.0.44 → 1.0.45

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.
@@ -0,0 +1,1598 @@
1
+ import {
2
+ getWorkingDirectory
3
+ } from "./chunk-IMFD4SJC.js";
4
+
5
+ // src/utils/project-info.ts
6
+ import { readFile, writeFile, mkdir } from "fs/promises";
7
+ import { existsSync } from "fs";
8
+ import { join } from "path";
9
+ var PROJECT_MD_PATH = ".trie/PROJECT.md";
10
+ function getProjectTemplate() {
11
+ return `# Project Information
12
+
13
+ > This file stores important project context for AI assistants.
14
+ > Edit freely - this file is yours, not auto-generated.
15
+ > Available via MCP resource: \`trie://project\`
16
+
17
+ ---
18
+
19
+ ## Project Overview
20
+
21
+ <!-- Describe your project's purpose and goals -->
22
+
23
+ [Add project description here]
24
+
25
+ ---
26
+
27
+ ## Technology Stack
28
+
29
+ <!-- List frameworks, languages, databases, cloud services, etc. -->
30
+
31
+ - **Language:**
32
+ - **Framework:**
33
+ - **Database:**
34
+ - **Hosting:**
35
+
36
+ ---
37
+
38
+ ## Architecture
39
+
40
+ <!-- Key patterns, architectural decisions, and system design -->
41
+
42
+ [Describe your architecture here]
43
+
44
+ ---
45
+
46
+ ## Coding Conventions
47
+
48
+ <!-- Style guidelines, naming conventions, patterns to follow -->
49
+
50
+ -
51
+ -
52
+ -
53
+
54
+ ---
55
+
56
+ ## Environment
57
+
58
+ <!-- URLs, API endpoints, deployment info -->
59
+
60
+ | Environment | URL | Notes |
61
+ |-------------|-----|-------|
62
+ | Development | | |
63
+ | Staging | | |
64
+ | Production | | |
65
+
66
+ ---
67
+
68
+ ## Team
69
+
70
+ <!-- Ownership, contacts, responsibilities -->
71
+
72
+ - **Owner:**
73
+ - **Team:**
74
+
75
+ ---
76
+
77
+ ## Compliance
78
+
79
+ <!-- HIPAA, SOC2, GDPR, PCI-DSS requirements if applicable -->
80
+
81
+ - [ ] GDPR
82
+ - [ ] SOC2
83
+ - [ ] HIPAA
84
+ - [ ] PCI-DSS
85
+
86
+ ---
87
+
88
+ ## AI Instructions
89
+
90
+ <!-- Special instructions for AI assistants working on this project -->
91
+
92
+ When working on this project, AI assistants should:
93
+
94
+ 1.
95
+ 2.
96
+ 3.
97
+
98
+ ---
99
+
100
+ *This file is read by Trie agents and exposed via \`trie://project\` MCP resource.*
101
+ *Edit this file to provide context to Claude Code, Cursor, GitHub Actions, and other AI tools.*
102
+ `;
103
+ }
104
+ function projectInfoExists(workDir) {
105
+ const dir = workDir || getWorkingDirectory(void 0, true);
106
+ const projectPath = join(dir, PROJECT_MD_PATH);
107
+ return existsSync(projectPath);
108
+ }
109
+ async function loadProjectInfo(workDir) {
110
+ const dir = workDir || getWorkingDirectory(void 0, true);
111
+ const projectPath = join(dir, PROJECT_MD_PATH);
112
+ try {
113
+ if (!existsSync(projectPath)) {
114
+ return null;
115
+ }
116
+ return await readFile(projectPath, "utf-8");
117
+ } catch {
118
+ return null;
119
+ }
120
+ }
121
+ async function saveProjectInfo(content, workDir) {
122
+ const dir = workDir || getWorkingDirectory(void 0, true);
123
+ const trieDir = join(dir, ".trie");
124
+ const projectPath = join(dir, PROJECT_MD_PATH);
125
+ await mkdir(trieDir, { recursive: true });
126
+ await writeFile(projectPath, content, "utf-8");
127
+ }
128
+ async function initProjectInfo(workDir) {
129
+ const dir = workDir || getWorkingDirectory(void 0, true);
130
+ const projectPath = join(dir, PROJECT_MD_PATH);
131
+ if (existsSync(projectPath)) {
132
+ return { created: false, path: projectPath };
133
+ }
134
+ await saveProjectInfo(getProjectTemplate(), dir);
135
+ return { created: true, path: projectPath };
136
+ }
137
+ async function getProjectSection(sectionName, workDir) {
138
+ const content = await loadProjectInfo(workDir);
139
+ if (!content) return null;
140
+ const sectionRegex = new RegExp(
141
+ `## ${escapeRegex(sectionName)}\\s*\\n([\\s\\S]*?)(?=\\n## |\\n---\\s*$|$)`,
142
+ "i"
143
+ );
144
+ const match = content.match(sectionRegex);
145
+ if (match) {
146
+ return match[1].trim();
147
+ }
148
+ return null;
149
+ }
150
+ async function updateProjectSection(sectionName, newContent, workDir) {
151
+ let content = await loadProjectInfo(workDir);
152
+ if (!content) {
153
+ await initProjectInfo(workDir);
154
+ content = await loadProjectInfo(workDir);
155
+ if (!content) return false;
156
+ }
157
+ const sectionRegex = new RegExp(
158
+ `(## ${escapeRegex(sectionName)}\\s*\\n)([\\s\\S]*?)((?=\\n## )|(?=\\n---\\s*$)|$)`,
159
+ "i"
160
+ );
161
+ if (content.match(sectionRegex)) {
162
+ const updatedContent = content.replace(sectionRegex, `$1
163
+ ${newContent}
164
+
165
+ $3`);
166
+ await saveProjectInfo(updatedContent, workDir);
167
+ return true;
168
+ }
169
+ return false;
170
+ }
171
+ async function appendToSection(sectionName, contentToAdd, workDir) {
172
+ const currentContent = await getProjectSection(sectionName, workDir);
173
+ if (currentContent === null) return false;
174
+ const newContent = currentContent + "\n" + contentToAdd;
175
+ return updateProjectSection(sectionName, newContent, workDir);
176
+ }
177
+ async function getProjectSections(workDir) {
178
+ const content = await loadProjectInfo(workDir);
179
+ if (!content) return [];
180
+ const sectionRegex = /^## (.+)$/gm;
181
+ const sections = [];
182
+ let match;
183
+ while ((match = sectionRegex.exec(content)) !== null) {
184
+ sections.push(match[1].trim());
185
+ }
186
+ return sections;
187
+ }
188
+ async function getProjectInfoStructured(workDir) {
189
+ const dir = workDir || getWorkingDirectory(void 0, true);
190
+ const projectPath = join(dir, PROJECT_MD_PATH);
191
+ const content = await loadProjectInfo(dir);
192
+ if (!content) {
193
+ return {
194
+ exists: false,
195
+ path: projectPath,
196
+ sections: {},
197
+ raw: null
198
+ };
199
+ }
200
+ const sectionNames = await getProjectSections(dir);
201
+ const sections = {};
202
+ for (const name of sectionNames) {
203
+ const sectionContent = await getProjectSection(name, dir);
204
+ if (sectionContent) {
205
+ sections[name] = sectionContent;
206
+ }
207
+ }
208
+ return {
209
+ exists: true,
210
+ path: projectPath,
211
+ sections,
212
+ raw: content
213
+ };
214
+ }
215
+ function escapeRegex(str) {
216
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
217
+ }
218
+
219
+ // src/skills/installer.ts
220
+ import { mkdir as mkdir2, rm, writeFile as writeFile2, readdir, readFile as readFile3, access, cp } from "fs/promises";
221
+ import { join as join3 } from "path";
222
+ import { exec } from "child_process";
223
+ import { promisify } from "util";
224
+
225
+ // src/skills/parser.ts
226
+ import { readFile as readFile2 } from "fs/promises";
227
+ import { join as join2 } from "path";
228
+ async function parseSkillMd(skillPath) {
229
+ const skillMdPath = join2(skillPath, "SKILL.md");
230
+ const rawContent = await readFile2(skillMdPath, "utf-8");
231
+ const frontmatterMatch = rawContent.match(/^---\n([\s\S]*?)\n---/);
232
+ if (!frontmatterMatch || !frontmatterMatch[1]) {
233
+ throw new Error("Invalid SKILL.md: missing YAML frontmatter");
234
+ }
235
+ const frontmatter = parseYamlFrontmatter(frontmatterMatch[1]);
236
+ if (!frontmatter.name || !frontmatter.description) {
237
+ throw new Error("Invalid SKILL.md: missing required name or description in frontmatter");
238
+ }
239
+ const content = rawContent.slice(frontmatterMatch[0].length).trim();
240
+ return {
241
+ frontmatter,
242
+ content,
243
+ rawContent
244
+ };
245
+ }
246
+ function parseYamlFrontmatter(yaml) {
247
+ const result = {};
248
+ const lines = yaml.split("\n");
249
+ for (const line of lines) {
250
+ const trimmed = line.trim();
251
+ if (!trimmed || trimmed.startsWith("#")) continue;
252
+ const colonIndex = trimmed.indexOf(":");
253
+ if (colonIndex === -1) continue;
254
+ const key = trimmed.slice(0, colonIndex).trim();
255
+ let value = trimmed.slice(colonIndex + 1).trim();
256
+ if (value === "") continue;
257
+ if (typeof value === "string") {
258
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
259
+ value = value.slice(1, -1);
260
+ }
261
+ if (typeof value === "string" && value.startsWith("[") && value.endsWith("]")) {
262
+ value = value.slice(1, -1).split(",").map((s) => s.trim().replace(/^["']|["']$/g, ""));
263
+ }
264
+ }
265
+ result[key] = value;
266
+ }
267
+ return result;
268
+ }
269
+
270
+ // src/skills/installer.ts
271
+ var execAsync = promisify(exec);
272
+ async function installSkill(source, skillName) {
273
+ const parts = source.split("/");
274
+ if (parts.length < 2) {
275
+ return { success: false, name: "unknown", error: "Invalid source format. Use owner/repo or owner/repo/skill-name" };
276
+ }
277
+ const owner = parts[0];
278
+ const repo = parts[1];
279
+ const specifiedSkill = skillName || parts[2];
280
+ const skillsDir = join3(getWorkingDirectory(void 0, true), ".trie", "skills");
281
+ const tempDir = join3(skillsDir, `.temp-${Date.now()}`);
282
+ try {
283
+ await mkdir2(skillsDir, { recursive: true });
284
+ const repoUrl = `https://github.com/${owner}/${repo}.git`;
285
+ await execAsync(`git clone --depth 1 "${repoUrl}" "${tempDir}"`, { timeout: 6e4 });
286
+ const sourcePath = await findSkillPath(tempDir, specifiedSkill);
287
+ if (!sourcePath) {
288
+ throw new Error(`SKILL.md not found in repository. Searched in: root, skills/, ${specifiedSkill || "subdirectories"}`);
289
+ }
290
+ const parsed = await parseSkillMd(sourcePath);
291
+ const name = parsed.frontmatter.name;
292
+ const targetPath = join3(skillsDir, name);
293
+ await rm(targetPath, { recursive: true, force: true });
294
+ await cp(sourcePath, targetPath, { recursive: true });
295
+ await writeFile2(join3(targetPath, ".installed.json"), JSON.stringify({
296
+ installedFrom: source,
297
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
298
+ repository: `${owner}/${repo}`
299
+ }, null, 2));
300
+ return { success: true, name, path: targetPath };
301
+ } catch (error) {
302
+ const message = error instanceof Error ? error.message : String(error);
303
+ return { success: false, name: skillName || "unknown", error: message };
304
+ } finally {
305
+ await rm(tempDir, { recursive: true, force: true }).catch(() => {
306
+ });
307
+ }
308
+ }
309
+ async function findSkillPath(repoPath, skillName) {
310
+ const searchPaths = [];
311
+ if (skillName) {
312
+ searchPaths.push(
313
+ join3(repoPath, "skills", skillName),
314
+ join3(repoPath, skillName)
315
+ );
316
+ }
317
+ searchPaths.push(
318
+ repoPath,
319
+ join3(repoPath, "skill")
320
+ );
321
+ if (!skillName) {
322
+ try {
323
+ const skillsSubdir = join3(repoPath, "skills");
324
+ await access(skillsSubdir);
325
+ const entries = await readdir(skillsSubdir, { withFileTypes: true });
326
+ for (const entry of entries) {
327
+ if (entry.isDirectory() && !entry.name.startsWith(".")) {
328
+ searchPaths.push(join3(skillsSubdir, entry.name));
329
+ }
330
+ }
331
+ } catch {
332
+ }
333
+ }
334
+ for (const searchPath of searchPaths) {
335
+ try {
336
+ await parseSkillMd(searchPath);
337
+ return searchPath;
338
+ } catch {
339
+ }
340
+ }
341
+ return null;
342
+ }
343
+ async function listInstalledSkills() {
344
+ const skillsDir = join3(getWorkingDirectory(void 0, true), ".trie", "skills");
345
+ const skills = [];
346
+ try {
347
+ const entries = await readdir(skillsDir, { withFileTypes: true });
348
+ for (const entry of entries) {
349
+ if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
350
+ const skillPath = join3(skillsDir, entry.name);
351
+ try {
352
+ const parsed = await parseSkillMd(skillPath);
353
+ const metaPath = join3(skillPath, ".installed.json");
354
+ let meta = { installedFrom: "unknown", installedAt: (/* @__PURE__ */ new Date()).toISOString() };
355
+ try {
356
+ meta = JSON.parse(await readFile3(metaPath, "utf-8"));
357
+ } catch {
358
+ }
359
+ skills.push({
360
+ name: parsed.frontmatter.name,
361
+ description: parsed.frontmatter.description,
362
+ path: skillPath,
363
+ installedFrom: meta.installedFrom,
364
+ installedAt: meta.installedAt
365
+ });
366
+ } catch {
367
+ }
368
+ }
369
+ } catch {
370
+ }
371
+ return skills;
372
+ }
373
+ async function removeSkill(skillName) {
374
+ const skillsDir = join3(getWorkingDirectory(void 0, true), ".trie", "skills");
375
+ const skillPath = join3(skillsDir, skillName);
376
+ try {
377
+ await rm(skillPath, { recursive: true });
378
+ return true;
379
+ } catch {
380
+ return false;
381
+ }
382
+ }
383
+
384
+ // src/memory/issue-store.ts
385
+ import { mkdir as mkdir4, writeFile as writeFile4, readFile as readFile5, readdir as readdir2 } from "fs/promises";
386
+ import { existsSync as existsSync3 } from "fs";
387
+ import { join as join5 } from "path";
388
+
389
+ // src/memory/bm25.ts
390
+ var BM25Index = class _BM25Index {
391
+ documents = /* @__PURE__ */ new Map();
392
+ termFrequencies = /* @__PURE__ */ new Map();
393
+ documentFrequencies = /* @__PURE__ */ new Map();
394
+ documentLengths = /* @__PURE__ */ new Map();
395
+ avgDocLength = 0;
396
+ k1 = 1.5;
397
+ b = 0.75;
398
+ /**
399
+ * Add a document to the index
400
+ */
401
+ addDocument(doc) {
402
+ const tokens = this.tokenize(doc.text);
403
+ this.documents.set(doc.id, doc);
404
+ this.documentLengths.set(doc.id, tokens.length);
405
+ const termFreq = /* @__PURE__ */ new Map();
406
+ const seenTerms = /* @__PURE__ */ new Set();
407
+ for (const token of tokens) {
408
+ termFreq.set(token, (termFreq.get(token) || 0) + 1);
409
+ if (!seenTerms.has(token)) {
410
+ seenTerms.add(token);
411
+ this.documentFrequencies.set(token, (this.documentFrequencies.get(token) || 0) + 1);
412
+ }
413
+ }
414
+ this.termFrequencies.set(doc.id, termFreq);
415
+ this.updateAvgDocLength();
416
+ }
417
+ /**
418
+ * Add multiple documents
419
+ */
420
+ addDocuments(docs) {
421
+ for (const doc of docs) {
422
+ this.addDocument(doc);
423
+ }
424
+ }
425
+ /**
426
+ * Search the index
427
+ */
428
+ search(query, limit = 10) {
429
+ const queryTokens = this.tokenize(query);
430
+ const scores = /* @__PURE__ */ new Map();
431
+ const N = this.documents.size;
432
+ for (const [docId] of this.documents) {
433
+ let score = 0;
434
+ const docLength = this.documentLengths.get(docId) || 0;
435
+ const termFreqs = this.termFrequencies.get(docId);
436
+ if (!termFreqs) continue;
437
+ for (const term of queryTokens) {
438
+ const tf = termFreqs.get(term) || 0;
439
+ if (tf === 0) continue;
440
+ const df = this.documentFrequencies.get(term) || 0;
441
+ const idf = Math.log((N - df + 0.5) / (df + 0.5) + 1);
442
+ const numerator = tf * (this.k1 + 1);
443
+ const denominator = tf + this.k1 * (1 - this.b + this.b * (docLength / this.avgDocLength));
444
+ score += idf * (numerator / denominator);
445
+ }
446
+ if (score > 0) {
447
+ scores.set(docId, score);
448
+ }
449
+ }
450
+ return Array.from(scores.entries()).sort((a, b) => b[1] - a[1]).slice(0, limit).map(([id, score]) => ({
451
+ id,
452
+ score,
453
+ metadata: this.documents.get(id)?.metadata
454
+ }));
455
+ }
456
+ /**
457
+ * Get document count
458
+ */
459
+ get size() {
460
+ return this.documents.size;
461
+ }
462
+ /**
463
+ * Clear the index
464
+ */
465
+ clear() {
466
+ this.documents.clear();
467
+ this.termFrequencies.clear();
468
+ this.documentFrequencies.clear();
469
+ this.documentLengths.clear();
470
+ this.avgDocLength = 0;
471
+ }
472
+ /**
473
+ * Serialize the index to JSON
474
+ */
475
+ serialize() {
476
+ return JSON.stringify({
477
+ documents: Array.from(this.documents.entries()),
478
+ termFrequencies: Array.from(this.termFrequencies.entries()).map(([k, v]) => [k, Array.from(v.entries())]),
479
+ documentFrequencies: Array.from(this.documentFrequencies.entries()),
480
+ documentLengths: Array.from(this.documentLengths.entries()),
481
+ avgDocLength: this.avgDocLength
482
+ });
483
+ }
484
+ /**
485
+ * Load from serialized JSON
486
+ */
487
+ static deserialize(json) {
488
+ const data = JSON.parse(json);
489
+ const index = new _BM25Index();
490
+ index.documents = new Map(data.documents);
491
+ index.termFrequencies = new Map(data.termFrequencies.map(([k, v]) => [k, new Map(v)]));
492
+ index.documentFrequencies = new Map(data.documentFrequencies);
493
+ index.documentLengths = new Map(data.documentLengths);
494
+ index.avgDocLength = data.avgDocLength;
495
+ return index;
496
+ }
497
+ tokenize(text) {
498
+ return text.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((token) => token.length > 2 && !this.isStopWord(token));
499
+ }
500
+ isStopWord(word) {
501
+ const stopWords = /* @__PURE__ */ new Set([
502
+ "the",
503
+ "be",
504
+ "to",
505
+ "of",
506
+ "and",
507
+ "a",
508
+ "in",
509
+ "that",
510
+ "have",
511
+ "i",
512
+ "it",
513
+ "for",
514
+ "not",
515
+ "on",
516
+ "with",
517
+ "he",
518
+ "as",
519
+ "you",
520
+ "do",
521
+ "at",
522
+ "this",
523
+ "but",
524
+ "his",
525
+ "by",
526
+ "from",
527
+ "they",
528
+ "we",
529
+ "say",
530
+ "her",
531
+ "she",
532
+ "or",
533
+ "an",
534
+ "will",
535
+ "my",
536
+ "one",
537
+ "all",
538
+ "would",
539
+ "there",
540
+ "their",
541
+ "what",
542
+ "so",
543
+ "up",
544
+ "out",
545
+ "if",
546
+ "about",
547
+ "who",
548
+ "get",
549
+ "which",
550
+ "go",
551
+ "me",
552
+ "when",
553
+ "make",
554
+ "can",
555
+ "like",
556
+ "time",
557
+ "no",
558
+ "just",
559
+ "him",
560
+ "know",
561
+ "take",
562
+ "into",
563
+ "year",
564
+ "your",
565
+ "some",
566
+ "could",
567
+ "them",
568
+ "see",
569
+ "other",
570
+ "than",
571
+ "then",
572
+ "now",
573
+ "look",
574
+ "only",
575
+ "come",
576
+ "its",
577
+ "over",
578
+ "also",
579
+ "back",
580
+ "after",
581
+ "use",
582
+ "two",
583
+ "how",
584
+ "our",
585
+ "first",
586
+ "way",
587
+ "even",
588
+ "new",
589
+ "want",
590
+ "because",
591
+ "any",
592
+ "these",
593
+ "give",
594
+ "day",
595
+ "most",
596
+ "us",
597
+ "should",
598
+ "been",
599
+ "has",
600
+ "was",
601
+ "are"
602
+ ]);
603
+ return stopWords.has(word);
604
+ }
605
+ updateAvgDocLength() {
606
+ if (this.documentLengths.size === 0) {
607
+ this.avgDocLength = 0;
608
+ return;
609
+ }
610
+ const total = Array.from(this.documentLengths.values()).reduce((a, b) => a + b, 0);
611
+ this.avgDocLength = total / this.documentLengths.size;
612
+ }
613
+ };
614
+
615
+ // src/memory/compactor.ts
616
+ import { mkdir as mkdir3, writeFile as writeFile3, readFile as readFile4 } from "fs/promises";
617
+ import { existsSync as existsSync2 } from "fs";
618
+ import { join as join4 } from "path";
619
+ async function compactOldIssues(issues, options = {}) {
620
+ const keepDays = options.keepDays ?? 30;
621
+ const minIssues = options.minIssuesToCompact ?? 100;
622
+ const cutoffDate = /* @__PURE__ */ new Date();
623
+ cutoffDate.setDate(cutoffDate.getDate() - keepDays);
624
+ const oldIssues = issues.filter((i) => new Date(i.timestamp) < cutoffDate);
625
+ const recentIssues = issues.filter((i) => new Date(i.timestamp) >= cutoffDate);
626
+ if (oldIssues.length < minIssues) {
627
+ return { summary: null, remaining: issues };
628
+ }
629
+ const summary = buildSummary(oldIssues);
630
+ return { summary, remaining: recentIssues };
631
+ }
632
+ function buildSummary(issues) {
633
+ const sorted = issues.sort(
634
+ (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
635
+ );
636
+ const bySeverity = {};
637
+ const byAgent = {};
638
+ const patternMap = /* @__PURE__ */ new Map();
639
+ const fileCount = /* @__PURE__ */ new Map();
640
+ for (const issue of issues) {
641
+ bySeverity[issue.severity] = (bySeverity[issue.severity] || 0) + 1;
642
+ byAgent[issue.agent] = (byAgent[issue.agent] || 0) + 1;
643
+ const patternKey = normalizePattern(issue.issue);
644
+ const existing = patternMap.get(patternKey);
645
+ if (existing) {
646
+ existing.count++;
647
+ } else {
648
+ patternMap.set(patternKey, { count: 1, issue });
649
+ }
650
+ const fileName = issue.file.split("/").pop() || issue.file;
651
+ fileCount.set(fileName, (fileCount.get(fileName) || 0) + 1);
652
+ }
653
+ const topPatterns = Array.from(patternMap.entries()).sort((a, b) => b[1].count - a[1].count).slice(0, 10).map(([pattern, data]) => ({
654
+ pattern: pattern.slice(0, 100),
655
+ count: data.count,
656
+ severity: data.issue.severity,
657
+ agent: data.issue.agent,
658
+ exampleFix: data.issue.fix.slice(0, 200)
659
+ }));
660
+ const hotFiles = Array.from(fileCount.entries()).sort((a, b) => b[1] - a[1]).slice(0, 10).map(([file, count]) => ({ file, count }));
661
+ return {
662
+ period: `${sorted[0]?.timestamp.split("T")[0]} to ${sorted[sorted.length - 1]?.timestamp.split("T")[0]}`,
663
+ startDate: sorted[0]?.timestamp || "",
664
+ endDate: sorted[sorted.length - 1]?.timestamp || "",
665
+ totalIssues: issues.length,
666
+ resolvedCount: issues.filter((i) => i.resolved).length,
667
+ bySeverity,
668
+ byAgent,
669
+ topPatterns,
670
+ hotFiles,
671
+ compactedAt: (/* @__PURE__ */ new Date()).toISOString()
672
+ };
673
+ }
674
+ function normalizePattern(text) {
675
+ return text.toLowerCase().replace(/`[^`]+`/g, "CODE").replace(/\b\d+\b/g, "N").replace(/["']/g, "").replace(/\s+/g, " ").trim().slice(0, 150);
676
+ }
677
+ async function saveCompactedSummary(summary, projectDir) {
678
+ const memoryDir = join4(projectDir, ".trie", "memory");
679
+ await mkdir3(memoryDir, { recursive: true });
680
+ const summaryPath = join4(memoryDir, "compacted-summaries.json");
681
+ let summaries = [];
682
+ try {
683
+ if (existsSync2(summaryPath)) {
684
+ summaries = JSON.parse(await readFile4(summaryPath, "utf-8"));
685
+ }
686
+ } catch {
687
+ summaries = [];
688
+ }
689
+ summaries.push(summary);
690
+ if (summaries.length > 12) {
691
+ summaries = summaries.slice(-12);
692
+ }
693
+ await writeFile3(summaryPath, JSON.stringify(summaries, null, 2));
694
+ }
695
+ async function loadCompactedSummaries(projectDir) {
696
+ const summaryPath = join4(projectDir, ".trie", "memory", "compacted-summaries.json");
697
+ try {
698
+ if (existsSync2(summaryPath)) {
699
+ return JSON.parse(await readFile4(summaryPath, "utf-8"));
700
+ }
701
+ } catch {
702
+ }
703
+ return [];
704
+ }
705
+ async function getHistoricalInsights(projectDir) {
706
+ const summaries = await loadCompactedSummaries(projectDir);
707
+ if (summaries.length === 0) {
708
+ return {
709
+ totalHistoricalIssues: 0,
710
+ recurringPatterns: [],
711
+ improvementTrend: "unknown"
712
+ };
713
+ }
714
+ const totalHistoricalIssues = summaries.reduce((sum, s) => sum + s.totalIssues, 0);
715
+ const patternCounts = /* @__PURE__ */ new Map();
716
+ for (const summary of summaries) {
717
+ for (const pattern of summary.topPatterns) {
718
+ const key = pattern.pattern;
719
+ const existing = patternCounts.get(key);
720
+ if (existing) {
721
+ existing.count += pattern.count;
722
+ existing.appearances++;
723
+ } else {
724
+ patternCounts.set(key, { ...pattern, appearances: 1 });
725
+ }
726
+ }
727
+ }
728
+ const recurringPatterns = Array.from(patternCounts.values()).filter((p) => p.appearances >= 2).sort((a, b) => b.count - a.count).slice(0, 5);
729
+ let improvementTrend = "unknown";
730
+ if (summaries.length >= 2) {
731
+ const recent = summaries.slice(-2);
732
+ const olderCount = recent[0]?.totalIssues || 0;
733
+ const newerCount = recent[1]?.totalIssues || 0;
734
+ if (newerCount < olderCount * 0.8) {
735
+ improvementTrend = "improving";
736
+ } else if (newerCount > olderCount * 1.2) {
737
+ improvementTrend = "declining";
738
+ } else {
739
+ improvementTrend = "stable";
740
+ }
741
+ }
742
+ return {
743
+ totalHistoricalIssues,
744
+ recurringPatterns,
745
+ improvementTrend
746
+ };
747
+ }
748
+
749
+ // src/memory/issue-store.ts
750
+ async function storeIssues(issues, project, workDir) {
751
+ const projectDir = workDir || getWorkingDirectory(void 0, true);
752
+ const memoryDir = join5(projectDir, ".trie", "memory");
753
+ await mkdir4(memoryDir, { recursive: true });
754
+ const stored = [];
755
+ const now = (/* @__PURE__ */ new Date()).toISOString();
756
+ for (const issue of issues) {
757
+ const hash = hashIssue(issue);
758
+ stored.push({
759
+ id: issue.id,
760
+ hash,
761
+ severity: issue.severity,
762
+ issue: issue.issue,
763
+ fix: issue.fix,
764
+ file: issue.file,
765
+ line: issue.line,
766
+ agent: issue.agent,
767
+ category: issue.category,
768
+ timestamp: now,
769
+ project,
770
+ resolved: false
771
+ });
772
+ }
773
+ await appendToDailyLog(stored, projectDir);
774
+ await updateIssueIndex(stored, projectDir);
775
+ return stored.length;
776
+ }
777
+ async function searchIssues(query, options = {}) {
778
+ const projectDir = options.workDir || getWorkingDirectory(void 0, true);
779
+ const limit = options.limit || 10;
780
+ const allIssues = await loadIssueIndex(projectDir);
781
+ if (allIssues.length === 0) {
782
+ return [];
783
+ }
784
+ const filteredIssues = allIssues.filter((issue) => {
785
+ if (options.project && issue.project !== options.project) return false;
786
+ if (options.severity && !options.severity.includes(issue.severity)) return false;
787
+ if (options.agent && issue.agent !== options.agent) return false;
788
+ if (!options.includeResolved && issue.resolved) return false;
789
+ return true;
790
+ });
791
+ if (filteredIssues.length === 0) {
792
+ return [];
793
+ }
794
+ const bm25 = new BM25Index();
795
+ const issueMap = /* @__PURE__ */ new Map();
796
+ for (const issue of filteredIssues) {
797
+ const searchText = `${issue.issue} ${issue.fix} ${issue.file} ${issue.agent} ${issue.category || ""} ${issue.severity}`;
798
+ bm25.addDocument({
799
+ id: issue.id,
800
+ text: searchText
801
+ });
802
+ issueMap.set(issue.id, issue);
803
+ }
804
+ const bm25Results = bm25.search(query, limit);
805
+ return bm25Results.map((result) => ({
806
+ issue: issueMap.get(result.id),
807
+ score: result.score,
808
+ matchType: "bm25"
809
+ }));
810
+ }
811
+ async function findSimilarIssues(issue, options = {}) {
812
+ const query = `${issue.issue} ${issue.fix} ${issue.agent}`;
813
+ const results = await searchIssues(query, {
814
+ workDir: options.workDir,
815
+ limit: (options.limit || 5) + 5,
816
+ // Get extra to account for filtering
817
+ includeResolved: true
818
+ });
819
+ let filtered = results.filter((r) => r.issue.id !== issue.id);
820
+ if (options.excludeSameFile) {
821
+ filtered = filtered.filter((r) => r.issue.file !== issue.file);
822
+ }
823
+ return filtered.slice(0, options.limit || 5);
824
+ }
825
+ async function markIssueResolved(issueId, workDir) {
826
+ const projectDir = workDir || getWorkingDirectory(void 0, true);
827
+ const index = await loadIssueIndex(projectDir);
828
+ const issue = index.find((i) => i.id === issueId);
829
+ if (!issue) return false;
830
+ issue.resolved = true;
831
+ issue.resolvedAt = (/* @__PURE__ */ new Date()).toISOString();
832
+ await saveIssueIndex(index, projectDir);
833
+ return true;
834
+ }
835
+ async function getMemoryStats(workDir) {
836
+ const projectDir = workDir || getWorkingDirectory(void 0, true);
837
+ const index = await loadIssueIndex(projectDir);
838
+ const historical = await getHistoricalInsights(projectDir);
839
+ const stats = {
840
+ totalIssues: index.length,
841
+ issuesByAgent: {},
842
+ issuesBySeverity: {},
843
+ resolvedCount: 0,
844
+ historicalIssues: historical.totalHistoricalIssues,
845
+ improvementTrend: historical.improvementTrend
846
+ };
847
+ for (const issue of index) {
848
+ stats.issuesByAgent[issue.agent] = (stats.issuesByAgent[issue.agent] || 0) + 1;
849
+ stats.issuesBySeverity[issue.severity] = (stats.issuesBySeverity[issue.severity] || 0) + 1;
850
+ if (issue.resolved) stats.resolvedCount++;
851
+ }
852
+ if (index.length > 0) {
853
+ const sorted = [...index].sort(
854
+ (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
855
+ );
856
+ stats.oldestIssue = sorted[0]?.timestamp;
857
+ stats.newestIssue = sorted[sorted.length - 1]?.timestamp;
858
+ }
859
+ return stats;
860
+ }
861
+ async function getRecentIssues(options = {}) {
862
+ const projectDir = options.workDir || getWorkingDirectory(void 0, true);
863
+ const index = await loadIssueIndex(projectDir);
864
+ const limit = options.limit || 20;
865
+ const daysBack = options.daysBack || 7;
866
+ const cutoff = /* @__PURE__ */ new Date();
867
+ cutoff.setDate(cutoff.getDate() - daysBack);
868
+ return index.filter((i) => new Date(i.timestamp) >= cutoff).sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()).slice(0, limit);
869
+ }
870
+ async function getDailyLogs(workDir) {
871
+ const projectDir = workDir || getWorkingDirectory(void 0, true);
872
+ const memoryDir = join5(projectDir, ".trie", "memory");
873
+ try {
874
+ if (!existsSync3(memoryDir)) return [];
875
+ const files = await readdir2(memoryDir);
876
+ return files.filter((f) => /^\d{4}-\d{2}-\d{2}\.md$/.test(f)).sort().reverse();
877
+ } catch {
878
+ return [];
879
+ }
880
+ }
881
+ async function appendToDailyLog(issues, projectDir) {
882
+ const memoryDir = join5(projectDir, ".trie", "memory");
883
+ const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
884
+ const logPath = join5(memoryDir, `${today}.md`);
885
+ let content = "";
886
+ try {
887
+ if (existsSync3(logPath)) {
888
+ content = await readFile5(logPath, "utf-8");
889
+ } else {
890
+ content = `# Issue Log: ${today}
891
+
892
+ `;
893
+ }
894
+ } catch {
895
+ content = `# Issue Log: ${today}
896
+
897
+ `;
898
+ }
899
+ const time = (/* @__PURE__ */ new Date()).toTimeString().split(" ")[0];
900
+ const newEntries = issues.map(
901
+ (i) => `## [${time}] ${i.severity.toUpperCase()}: ${i.issue.slice(0, 80)}${i.issue.length > 80 ? "..." : ""}
902
+ - **File:** \`${i.file}\`${i.line ? `:${i.line}` : ""}
903
+ - **Agent:** ${i.agent}
904
+ - **Fix:** ${i.fix.slice(0, 200)}${i.fix.length > 200 ? "..." : ""}
905
+ `
906
+ ).join("\n");
907
+ content += newEntries + "\n";
908
+ await writeFile4(logPath, content);
909
+ }
910
+ async function loadIssueIndex(projectDir) {
911
+ const indexPath = join5(projectDir, ".trie", "memory", "issues.json");
912
+ try {
913
+ if (existsSync3(indexPath)) {
914
+ const content = await readFile5(indexPath, "utf-8");
915
+ return JSON.parse(content);
916
+ }
917
+ } catch {
918
+ }
919
+ return [];
920
+ }
921
+ async function updateIssueIndex(newIssues, projectDir) {
922
+ const memoryDir = join5(projectDir, ".trie", "memory");
923
+ const indexPath = join5(memoryDir, "issues.json");
924
+ await mkdir4(memoryDir, { recursive: true });
925
+ let existing = await loadIssueIndex(projectDir);
926
+ const hashSet = new Set(existing.map((i) => i.hash));
927
+ const toAdd = newIssues.filter((i) => !hashSet.has(i.hash));
928
+ existing = [...existing, ...toAdd];
929
+ if (existing.length > 500) {
930
+ const { summary, remaining } = await compactOldIssues(existing, {
931
+ keepDays: 30,
932
+ minIssuesToCompact: 100
933
+ });
934
+ if (summary) {
935
+ await saveCompactedSummary(summary, projectDir);
936
+ existing = remaining;
937
+ }
938
+ }
939
+ if (existing.length > 1e3) {
940
+ existing = existing.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()).slice(0, 1e3);
941
+ }
942
+ await saveIssueIndex(existing, projectDir);
943
+ }
944
+ async function saveIssueIndex(issues, projectDir) {
945
+ const indexPath = join5(projectDir, ".trie", "memory", "issues.json");
946
+ await writeFile4(indexPath, JSON.stringify(issues, null, 2));
947
+ }
948
+ function hashIssue(issue) {
949
+ const content = `${issue.issue}|${issue.file}|${issue.severity}|${issue.agent}`;
950
+ let hash = 0;
951
+ for (let i = 0; i < content.length; i++) {
952
+ const char = content.charCodeAt(i);
953
+ hash = (hash << 5) - hash + char;
954
+ hash = hash & hash;
955
+ }
956
+ return Math.abs(hash).toString(36);
957
+ }
958
+
959
+ // src/memory/global-memory.ts
960
+ import { mkdir as mkdir5, writeFile as writeFile5, readFile as readFile6, readdir as readdir3 } from "fs/promises";
961
+ import { existsSync as existsSync4 } from "fs";
962
+ import { join as join6 } from "path";
963
+ import { homedir } from "os";
964
+ var GLOBAL_TRIE_DIR = join6(homedir(), ".trie");
965
+ var GLOBAL_MEMORY_DIR = join6(GLOBAL_TRIE_DIR, "memory");
966
+ async function recordToGlobalMemory(issues, projectName, projectPath, healthScore = 0) {
967
+ await mkdir5(GLOBAL_MEMORY_DIR, { recursive: true });
968
+ await mkdir5(join6(GLOBAL_MEMORY_DIR, "projects"), { recursive: true });
969
+ const patterns = await loadGlobalPatterns();
970
+ const now = (/* @__PURE__ */ new Date()).toISOString();
971
+ for (const issue of issues) {
972
+ const patternId = extractPatternId(issue);
973
+ const existing = patterns.find((p) => p.id === patternId);
974
+ if (existing) {
975
+ existing.occurrences++;
976
+ existing.lastSeen = now;
977
+ if (!existing.projects.includes(projectName)) {
978
+ existing.projects.push(projectName);
979
+ }
980
+ } else {
981
+ patterns.push({
982
+ id: patternId,
983
+ pattern: issue.issue.slice(0, 200),
984
+ description: issue.fix.slice(0, 200),
985
+ severity: issue.severity,
986
+ agent: issue.agent,
987
+ occurrences: 1,
988
+ projects: [projectName],
989
+ firstSeen: now,
990
+ lastSeen: now
991
+ });
992
+ }
993
+ }
994
+ await saveGlobalPatterns(patterns);
995
+ const summaryPath = join6(GLOBAL_MEMORY_DIR, "projects", `${sanitizeName(projectName)}.json`);
996
+ const summary = {
997
+ name: projectName,
998
+ path: projectPath,
999
+ lastScan: now,
1000
+ healthScore,
1001
+ totalIssues: issues.length,
1002
+ patterns: [...new Set(issues.map((i) => extractPatternId(i)))]
1003
+ };
1004
+ await writeFile5(summaryPath, JSON.stringify(summary, null, 2));
1005
+ }
1006
+ async function findCrossProjectPatterns(minOccurrences = 2) {
1007
+ const patterns = await loadGlobalPatterns();
1008
+ return patterns.filter((p) => p.projects.length >= minOccurrences).sort((a, b) => b.occurrences - a.occurrences);
1009
+ }
1010
+ async function listTrackedProjects() {
1011
+ const projectsDir = join6(GLOBAL_MEMORY_DIR, "projects");
1012
+ try {
1013
+ if (!existsSync4(projectsDir)) return [];
1014
+ const files = await readdir3(projectsDir);
1015
+ const summaries = [];
1016
+ for (const file of files) {
1017
+ if (!file.endsWith(".json")) continue;
1018
+ try {
1019
+ const content = await readFile6(join6(projectsDir, file), "utf-8");
1020
+ summaries.push(JSON.parse(content));
1021
+ } catch {
1022
+ }
1023
+ }
1024
+ return summaries.sort(
1025
+ (a, b) => new Date(b.lastScan).getTime() - new Date(a.lastScan).getTime()
1026
+ );
1027
+ } catch {
1028
+ return [];
1029
+ }
1030
+ }
1031
+ async function getGlobalMemoryStats() {
1032
+ const patterns = await loadGlobalPatterns();
1033
+ const projects = await listTrackedProjects();
1034
+ const patternsByAgent = {};
1035
+ for (const pattern of patterns) {
1036
+ patternsByAgent[pattern.agent] = (patternsByAgent[pattern.agent] || 0) + 1;
1037
+ }
1038
+ return {
1039
+ totalPatterns: patterns.length,
1040
+ crossProjectPatterns: patterns.filter((p) => p.projects.length >= 2).length,
1041
+ trackedProjects: projects.length,
1042
+ totalOccurrences: patterns.reduce((sum, p) => sum + p.occurrences, 0),
1043
+ fixedPatterns: patterns.filter((p) => p.fixApplied).length,
1044
+ patternsByAgent
1045
+ };
1046
+ }
1047
+ async function updateGlobalMemoryMd() {
1048
+ const patterns = await loadGlobalPatterns();
1049
+ const crossProject = patterns.filter((p) => p.projects.length >= 2);
1050
+ const projects = await listTrackedProjects();
1051
+ const lines = [
1052
+ "# Global Trie Memory",
1053
+ "",
1054
+ "> Auto-generated file tracking patterns across all your projects.",
1055
+ `> Last updated: ${(/* @__PURE__ */ new Date()).toISOString()}`,
1056
+ "",
1057
+ "## Summary",
1058
+ "",
1059
+ `- **Projects tracked:** ${projects.length}`,
1060
+ `- **Total patterns:** ${patterns.length}`,
1061
+ `- **Cross-project patterns:** ${crossProject.length}`,
1062
+ "",
1063
+ "## Cross-Project Patterns",
1064
+ "",
1065
+ "These issues appear in multiple projects:",
1066
+ ""
1067
+ ];
1068
+ for (const p of crossProject.slice(0, 20)) {
1069
+ lines.push(
1070
+ `### ${p.pattern.slice(0, 60)}${p.pattern.length > 60 ? "..." : ""}`,
1071
+ "",
1072
+ `- **Severity:** ${p.severity}`,
1073
+ `- **Agent:** ${p.agent}`,
1074
+ `- **Occurrences:** ${p.occurrences} across ${p.projects.length} projects`,
1075
+ `- **Projects:** ${p.projects.slice(0, 5).join(", ")}${p.projects.length > 5 ? "..." : ""}`
1076
+ );
1077
+ if (p.fixApplied) {
1078
+ lines.push(`- **Fixed in:** ${p.fixApplied.project} on ${p.fixApplied.timestamp.split("T")[0]}`);
1079
+ } else {
1080
+ lines.push("- **Status:** Not fixed");
1081
+ }
1082
+ lines.push("");
1083
+ }
1084
+ lines.push(
1085
+ "## Tracked Projects",
1086
+ "",
1087
+ "| Project | Last Scan | Health | Issues |",
1088
+ "|---------|-----------|--------|--------|"
1089
+ );
1090
+ for (const p of projects.slice(0, 20)) {
1091
+ lines.push(`| ${p.name} | ${p.lastScan.split("T")[0]} | ${p.healthScore}% | ${p.totalIssues} |`);
1092
+ }
1093
+ lines.push("", "---", "", "*This file is auto-generated by Trie. Do not edit manually.*");
1094
+ await mkdir5(GLOBAL_MEMORY_DIR, { recursive: true });
1095
+ await writeFile5(join6(GLOBAL_MEMORY_DIR, "GLOBAL_MEMORY.md"), lines.join("\n"));
1096
+ }
1097
+ async function searchGlobalPatterns(query, options = {}) {
1098
+ const patterns = await loadGlobalPatterns();
1099
+ const limit = options.limit || 10;
1100
+ const queryTerms = query.toLowerCase().split(/\s+/).filter((t) => t.length > 2);
1101
+ const scored = patterns.filter((p) => {
1102
+ if (options.severity && !options.severity.includes(p.severity)) return false;
1103
+ if (options.agent && p.agent !== options.agent) return false;
1104
+ return true;
1105
+ }).map((p) => {
1106
+ const text = `${p.pattern} ${p.description} ${p.agent}`.toLowerCase();
1107
+ let score = 0;
1108
+ for (const term of queryTerms) {
1109
+ if (text.includes(term)) score++;
1110
+ }
1111
+ return { pattern: p, score };
1112
+ }).filter((s) => s.score > 0).sort((a, b) => b.score - a.score).slice(0, limit);
1113
+ return scored.map((s) => s.pattern);
1114
+ }
1115
+ async function loadGlobalPatterns() {
1116
+ const patternsPath = join6(GLOBAL_MEMORY_DIR, "global-patterns.json");
1117
+ try {
1118
+ if (existsSync4(patternsPath)) {
1119
+ const content = await readFile6(patternsPath, "utf-8");
1120
+ return JSON.parse(content);
1121
+ }
1122
+ } catch {
1123
+ }
1124
+ return [];
1125
+ }
1126
+ async function saveGlobalPatterns(patterns) {
1127
+ await mkdir5(GLOBAL_MEMORY_DIR, { recursive: true });
1128
+ const patternsPath = join6(GLOBAL_MEMORY_DIR, "global-patterns.json");
1129
+ const pruned = patterns.sort((a, b) => new Date(b.lastSeen).getTime() - new Date(a.lastSeen).getTime()).slice(0, 500);
1130
+ await writeFile5(patternsPath, JSON.stringify(pruned, null, 2));
1131
+ }
1132
+ function extractPatternId(issue) {
1133
+ const normalized = issue.issue.toLowerCase().replace(/`[^`]+`/g, "CODE").replace(/\b\d+\b/g, "N").replace(/['"]/g, "").slice(0, 100);
1134
+ let hash = 0;
1135
+ for (let i = 0; i < normalized.length; i++) {
1136
+ const char = normalized.charCodeAt(i);
1137
+ hash = (hash << 5) - hash + char;
1138
+ hash = hash & hash;
1139
+ }
1140
+ return `${issue.agent}-${issue.severity}-${Math.abs(hash).toString(36)}`;
1141
+ }
1142
+ function sanitizeName(name) {
1143
+ return name.replace(/[^a-zA-Z0-9-_]/g, "-").toLowerCase();
1144
+ }
1145
+
1146
+ // src/utils/context-state.ts
1147
+ import { readFile as readFile7, writeFile as writeFile6, mkdir as mkdir6 } from "fs/promises";
1148
+ import { existsSync as existsSync5 } from "fs";
1149
+ import { join as join7, basename } from "path";
1150
+ var AGENTS_MD_PATH = ".trie/AGENTS.md";
1151
+ var STATE_JSON_PATH = ".trie/state.json";
1152
+ async function loadContextState() {
1153
+ const workDir = getWorkingDirectory(void 0, true);
1154
+ const statePath = join7(workDir, STATE_JSON_PATH);
1155
+ const defaults = getDefaultState();
1156
+ try {
1157
+ if (existsSync5(statePath)) {
1158
+ const content = await readFile7(statePath, "utf-8");
1159
+ const loaded = JSON.parse(content);
1160
+ return {
1161
+ ...defaults,
1162
+ ...loaded,
1163
+ skills: loaded.skills || defaults.skills
1164
+ };
1165
+ }
1166
+ } catch {
1167
+ }
1168
+ return defaults;
1169
+ }
1170
+ async function saveContextState(state) {
1171
+ const workDir = getWorkingDirectory(void 0, true);
1172
+ const trieDir = join7(workDir, ".trie");
1173
+ const statePath = join7(workDir, STATE_JSON_PATH);
1174
+ await mkdir6(trieDir, { recursive: true });
1175
+ await writeFile6(statePath, JSON.stringify(state, null, 2));
1176
+ }
1177
+ async function updateContextAfterScan(results, filesScanned, contextSignals, duration) {
1178
+ const state = await loadContextState();
1179
+ const workDir = getWorkingDirectory(void 0, true);
1180
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1181
+ const allIssues = results.flatMap((r) => r.issues);
1182
+ const issueCounts = {
1183
+ critical: allIssues.filter((i) => i.severity === "critical").length,
1184
+ serious: allIssues.filter((i) => i.severity === "serious").length,
1185
+ moderate: allIssues.filter((i) => i.severity === "moderate").length,
1186
+ low: allIssues.filter((i) => i.severity === "low").length,
1187
+ total: allIssues.length
1188
+ };
1189
+ const fileIssueMap = /* @__PURE__ */ new Map();
1190
+ for (const issue of allIssues) {
1191
+ const count = fileIssueMap.get(issue.file) || 0;
1192
+ fileIssueMap.set(issue.file, count + 1);
1193
+ }
1194
+ const hotFiles = Array.from(fileIssueMap.entries()).sort((a, b) => b[1] - a[1]).slice(0, 10).map(([file, issueCount]) => ({ file, issueCount }));
1195
+ const scanSummary = {
1196
+ timestamp: now,
1197
+ agents: results.map((r) => r.agent),
1198
+ filesScanned,
1199
+ issues: issueCounts,
1200
+ duration,
1201
+ hotFiles
1202
+ };
1203
+ for (const result of results) {
1204
+ state.agentStatus[result.agent] = {
1205
+ lastRun: now,
1206
+ issuesFound: result.issues.length
1207
+ };
1208
+ }
1209
+ const criticalPenalty = issueCounts.critical * 25;
1210
+ const seriousPenalty = issueCounts.serious * 10;
1211
+ const moderatePenalty = issueCounts.moderate * 3;
1212
+ const lowPenalty = issueCounts.low * 1;
1213
+ const totalPenalty = Math.min(100, criticalPenalty + seriousPenalty + moderatePenalty + lowPenalty);
1214
+ state.healthScore = Math.max(0, 100 - totalPenalty);
1215
+ state.activePriorities = generatePriorities(issueCounts, contextSignals);
1216
+ state.contextSignals = { ...state.contextSignals, ...contextSignals };
1217
+ state.scanHistory = [scanSummary, ...state.scanHistory.slice(0, 19)];
1218
+ state.lastScan = scanSummary;
1219
+ await saveContextState(state);
1220
+ await updateAgentsMd(state);
1221
+ if (allIssues.length > 0) {
1222
+ const projectName = basename(workDir);
1223
+ try {
1224
+ await storeIssues(allIssues, projectName, workDir);
1225
+ await recordToGlobalMemory(allIssues, projectName, workDir, state.healthScore);
1226
+ await updateGlobalMemoryMd();
1227
+ } catch {
1228
+ }
1229
+ }
1230
+ }
1231
+ async function updateAgentsMd(state) {
1232
+ const workDir = getWorkingDirectory(void 0, true);
1233
+ const mdPath = join7(workDir, AGENTS_MD_PATH);
1234
+ let content;
1235
+ try {
1236
+ content = await readFile7(mdPath, "utf-8");
1237
+ } catch {
1238
+ content = getAgentsMdTemplate();
1239
+ }
1240
+ content = updateSection(content, "Project State", generateProjectStateTable(state));
1241
+ content = updateSection(content, "Active Priorities", generatePrioritiesList(state));
1242
+ content = updateSection(content, "Agent Status", generateAgentStatusTable(state));
1243
+ content = updateSection(content, "Recent Scan History", generateScanHistoryTable(state));
1244
+ content = updateSection(content, "Context Signals Detected", generateContextSignals(state));
1245
+ content = updateSection(content, "Risk Assessment", generateRiskAssessment(state));
1246
+ content = updateSection(content, "Hot Files", generateHotFilesSection(state));
1247
+ content = content.replace(
1248
+ /Last updated:.*$/m,
1249
+ `Last updated: ${(/* @__PURE__ */ new Date()).toISOString()}`
1250
+ );
1251
+ await writeFile6(mdPath, content);
1252
+ }
1253
+ function updateSection(content, sectionName, newContent) {
1254
+ const sectionRegex = new RegExp(
1255
+ `(### ${sectionName}[\\s\\S]*?)(?=###|---|
1256
+ ## |$)`,
1257
+ "g"
1258
+ );
1259
+ const replacement = `### ${sectionName}
1260
+ ${newContent}
1261
+
1262
+ `;
1263
+ if (content.match(sectionRegex)) {
1264
+ return content.replace(sectionRegex, replacement);
1265
+ }
1266
+ return content;
1267
+ }
1268
+ function generateProjectStateTable(state) {
1269
+ const lastScan = state.lastScan;
1270
+ const lastScanDate = lastScan ? new Date(lastScan.timestamp).toLocaleString() : "Never";
1271
+ const criticalCount = lastScan?.issues.critical ?? 0;
1272
+ const totalTasks = lastScan?.issues.total ?? 0;
1273
+ return `| Metric | Value | Updated |
1274
+ |--------|-------|---------|
1275
+ | Last Scan | ${lastScanDate} | ${lastScan ? "Auto" : "-"} |
1276
+ | Critical Issues | ${criticalCount} | ${lastScan ? "Auto" : "-"} |
1277
+ | Open Tasks | ${totalTasks} | ${lastScan ? "Auto" : "-"} |
1278
+ | Health Score | ${state.healthScore}% | ${lastScan ? "Auto" : "-"} |`;
1279
+ }
1280
+ function generatePrioritiesList(state) {
1281
+ if (state.activePriorities.length === 0) {
1282
+ return "_No active priorities. Run a scan to identify issues._";
1283
+ }
1284
+ return state.activePriorities.map((p, i) => `${i + 1}. ${p}`).join("\n");
1285
+ }
1286
+ function generatePriorities(issues, contextSignals) {
1287
+ const priorities = [];
1288
+ if (issues.critical > 0) {
1289
+ priorities.push(`\u{1F6A8} Fix ${issues.critical} critical security issue${issues.critical > 1 ? "s" : ""} immediately`);
1290
+ }
1291
+ if (issues.serious > 0) {
1292
+ priorities.push(`\u26A0\uFE0F Address ${issues.serious} serious issue${issues.serious > 1 ? "s" : ""} before deployment`);
1293
+ }
1294
+ if (contextSignals.touchesAuth && issues.critical === 0) {
1295
+ priorities.push("\u2705 Auth code reviewed - continue monitoring");
1296
+ }
1297
+ if (contextSignals.touchesPayments) {
1298
+ priorities.push("\u{1F4B3} Payment code detected - ensure PCI compliance");
1299
+ }
1300
+ if (contextSignals.touchesUserData) {
1301
+ priorities.push("\u{1F510} User data handling detected - verify privacy compliance");
1302
+ }
1303
+ if (issues.moderate > 5) {
1304
+ priorities.push(`\u{1F4CB} Schedule time to address ${issues.moderate} moderate issues`);
1305
+ }
1306
+ if (priorities.length === 0) {
1307
+ priorities.push("\u2728 No critical issues - focus on feature development");
1308
+ }
1309
+ return priorities.slice(0, 5);
1310
+ }
1311
+ function generateAgentStatusTable(state) {
1312
+ const builtInAgents = [
1313
+ "security",
1314
+ "privacy",
1315
+ "legal",
1316
+ "accessibility",
1317
+ "bugs",
1318
+ "design",
1319
+ "architecture",
1320
+ "performance",
1321
+ "devops",
1322
+ "soc2",
1323
+ "e2e",
1324
+ "typecheck",
1325
+ "visual-qa",
1326
+ "data-flow"
1327
+ ];
1328
+ let table = `| Agent | Status | Last Run | Issues Found |
1329
+ |-------|--------|----------|--------------|`;
1330
+ for (const agent of builtInAgents) {
1331
+ const status = state.agentStatus[agent];
1332
+ const lastRun = status?.lastRun ? new Date(status.lastRun).toLocaleDateString() : "Never";
1333
+ const issues = status?.issuesFound ?? "-";
1334
+ const statusEmoji = status ? "\u2705" : "\u23F8\uFE0F";
1335
+ table += `
1336
+ | ${agent} | ${statusEmoji} Ready | ${lastRun} | ${issues} |`;
1337
+ }
1338
+ return table;
1339
+ }
1340
+ function generateScanHistoryTable(state) {
1341
+ if (state.scanHistory.length === 0) {
1342
+ return `| Date | Agents | Files | Issues | Duration |
1343
+ |------|--------|-------|--------|----------|
1344
+ | - | - | - | - | - |`;
1345
+ }
1346
+ let table = `| Date | Agents | Files | Issues | Duration |
1347
+ |------|--------|-------|--------|----------|`;
1348
+ for (const scan of state.scanHistory.slice(0, 10)) {
1349
+ const date = new Date(scan.timestamp).toLocaleDateString();
1350
+ const agents = scan.agents.slice(0, 3).join(", ") + (scan.agents.length > 3 ? "..." : "");
1351
+ const duration = `${(scan.duration / 1e3).toFixed(1)}s`;
1352
+ table += `
1353
+ | ${date} | ${agents} | ${scan.filesScanned} | ${scan.issues.total} | ${duration} |`;
1354
+ }
1355
+ return table;
1356
+ }
1357
+ function generateContextSignals(state) {
1358
+ const signals = [
1359
+ "touchesAuth",
1360
+ "touchesPayments",
1361
+ "touchesUserData",
1362
+ "touchesAPI",
1363
+ "touchesDatabase",
1364
+ "touchesCrypto"
1365
+ ];
1366
+ return signals.map((s) => {
1367
+ const value = state.contextSignals[s];
1368
+ const emoji = value === true ? "\u2705" : value === false ? "\u274C" : "\u2753";
1369
+ return `- \`${s}\`: ${emoji} ${value === void 0 ? "Unknown" : value ? "Yes" : "No"}`;
1370
+ }).join("\n");
1371
+ }
1372
+ function generateRiskAssessment(state) {
1373
+ const score = state.healthScore;
1374
+ let riskLevel;
1375
+ let confidence;
1376
+ if (state.lastScan === null) {
1377
+ return `- Overall Risk: Unknown
1378
+ - Confidence: 0%`;
1379
+ }
1380
+ if (score >= 90) {
1381
+ riskLevel = "\u{1F7E2} Low";
1382
+ confidence = 95;
1383
+ } else if (score >= 70) {
1384
+ riskLevel = "\u{1F7E1} Medium";
1385
+ confidence = 85;
1386
+ } else if (score >= 50) {
1387
+ riskLevel = "\u{1F7E0} High";
1388
+ confidence = 80;
1389
+ } else {
1390
+ riskLevel = "\u{1F534} Critical";
1391
+ confidence = 90;
1392
+ }
1393
+ return `- Overall Risk: ${riskLevel}
1394
+ - Health Score: ${score}%
1395
+ - Confidence: ${confidence}%`;
1396
+ }
1397
+ function generateHotFilesSection(state) {
1398
+ if (!state.lastScan || state.lastScan.hotFiles.length === 0) {
1399
+ return "_Run a scan to identify hot files._";
1400
+ }
1401
+ return state.lastScan.hotFiles.map((f) => `- \`${f.file}\` - ${f.issueCount} issue${f.issueCount > 1 ? "s" : ""}`).join("\n");
1402
+ }
1403
+ function getDefaultState() {
1404
+ return {
1405
+ lastScan: null,
1406
+ healthScore: 0,
1407
+ activePriorities: [
1408
+ "Initial setup required - run first scan with `trie scan`",
1409
+ "Configure agents in `.trie/config.json`",
1410
+ "Set up CI/CD integration"
1411
+ ],
1412
+ contextSignals: {},
1413
+ agentStatus: {},
1414
+ scanHistory: [],
1415
+ customAgents: [],
1416
+ skills: {},
1417
+ environment: detectEnvironment()
1418
+ };
1419
+ }
1420
+ function detectEnvironment() {
1421
+ if (process.env.GITHUB_ACTIONS) return "github-actions";
1422
+ if (process.env.GITLAB_CI) return "gitlab-ci";
1423
+ if (process.env.CI) return "ci";
1424
+ const parent = process.env._ || "";
1425
+ if (parent.includes("cursor")) return "cursor";
1426
+ if (parent.includes("claude")) return "claude-code";
1427
+ return "cli";
1428
+ }
1429
+ async function recordSkillInstalled(params) {
1430
+ const state = await loadContextState();
1431
+ state.skills[params.name] = {
1432
+ source: params.source,
1433
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
1434
+ timesApplied: 0,
1435
+ appliedBy: []
1436
+ };
1437
+ await saveContextState(state);
1438
+ }
1439
+ async function recordSkillUsage(params) {
1440
+ const state = await loadContextState();
1441
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1442
+ for (const skillName of params.skillNames) {
1443
+ const skillRecord = state.skills[skillName];
1444
+ if (skillRecord) {
1445
+ skillRecord.timesApplied++;
1446
+ skillRecord.lastApplied = now;
1447
+ if (!skillRecord.appliedBy.includes(params.agentName)) {
1448
+ skillRecord.appliedBy.push(params.agentName);
1449
+ }
1450
+ }
1451
+ }
1452
+ const agentStatus = state.agentStatus[params.agentName];
1453
+ if (agentStatus) {
1454
+ agentStatus.skillsApplied = params.skillNames;
1455
+ }
1456
+ await saveContextState(state);
1457
+ }
1458
+ function getAgentsMdTemplate() {
1459
+ return `# Trie Agent Context
1460
+
1461
+ > **Auto-generated file** - Updated automatically when agents run.
1462
+ > Last updated: Never (initial state)
1463
+
1464
+ This file provides prioritized context for all AI coding assistants working with this codebase.
1465
+ Agents should read this file first and update it after completing scans.
1466
+
1467
+ ---
1468
+
1469
+ ## Quick Context (Read First)
1470
+
1471
+ ### Project State
1472
+ | Metric | Value | Updated |
1473
+ |--------|-------|---------|
1474
+ | Last Scan | Never | - |
1475
+ | Critical Issues | 0 | - |
1476
+ | Open Tasks | 0 | - |
1477
+ | Health Score | Unknown | - |
1478
+
1479
+ ### Active Priorities
1480
+ 1. Initial setup required - run first scan with \`trie scan\`
1481
+ 2. Configure agents in \`.trie/config.json\`
1482
+ 3. Set up CI/CD integration
1483
+
1484
+ ### Hot Files
1485
+ _Run a scan to identify hot files._
1486
+
1487
+ ---
1488
+
1489
+ ## Agent Status
1490
+
1491
+ ### Agent Status
1492
+ | Agent | Status | Last Run | Issues Found |
1493
+ |-------|--------|----------|--------------|
1494
+ | security | Ready | Never | - |
1495
+ | privacy | Ready | Never | - |
1496
+ | bugs | Ready | Never | - |
1497
+
1498
+ ### Recent Scan History
1499
+ | Date | Agents | Files | Issues | Duration |
1500
+ |------|--------|-------|--------|----------|
1501
+ | - | - | - | - | - |
1502
+
1503
+ ---
1504
+
1505
+ ## Context Analysis
1506
+
1507
+ ### Context Signals Detected
1508
+ - \`touchesAuth\`: Unknown
1509
+ - \`touchesPayments\`: Unknown
1510
+ - \`touchesUserData\`: Unknown
1511
+ - \`touchesAPI\`: Unknown
1512
+ - \`touchesDatabase\`: Unknown
1513
+ - \`touchesCrypto\`: Unknown
1514
+
1515
+ ### Risk Assessment
1516
+ - Overall Risk: Unknown
1517
+ - Confidence: 0%
1518
+
1519
+ ---
1520
+
1521
+ *This file is maintained by Trie agents. Manual edits will be preserved in non-auto sections.*
1522
+ `;
1523
+ }
1524
+ async function getContextForAI() {
1525
+ const state = await loadContextState();
1526
+ const workDir = getWorkingDirectory(void 0, true);
1527
+ const lines = [];
1528
+ if (projectInfoExists(workDir)) {
1529
+ const projectInfo = await loadProjectInfo(workDir);
1530
+ if (projectInfo) {
1531
+ lines.push(projectInfo);
1532
+ lines.push("");
1533
+ lines.push("---");
1534
+ lines.push("");
1535
+ }
1536
+ }
1537
+ lines.push(
1538
+ "## Trie Scan Context",
1539
+ "",
1540
+ `**Health Score:** ${state.healthScore}%`,
1541
+ `**Last Scan:** ${state.lastScan ? new Date(state.lastScan.timestamp).toLocaleString() : "Never"}`,
1542
+ "",
1543
+ "**Active Priorities:**",
1544
+ ...state.activePriorities.map((p) => `- ${p}`),
1545
+ ""
1546
+ );
1547
+ if (state.lastScan) {
1548
+ lines.push(
1549
+ "**Recent Issues:**",
1550
+ `- Critical: ${state.lastScan.issues.critical}`,
1551
+ `- Serious: ${state.lastScan.issues.serious}`,
1552
+ `- Moderate: ${state.lastScan.issues.moderate}`,
1553
+ `- Low: ${state.lastScan.issues.low}`,
1554
+ ""
1555
+ );
1556
+ if (state.lastScan.hotFiles.length > 0) {
1557
+ lines.push(
1558
+ "**Hot Files (most issues):**",
1559
+ ...state.lastScan.hotFiles.slice(0, 5).map((f) => `- ${f.file}: ${f.issueCount} issues`),
1560
+ ""
1561
+ );
1562
+ }
1563
+ }
1564
+ return lines.join("\n");
1565
+ }
1566
+
1567
+ export {
1568
+ parseSkillMd,
1569
+ installSkill,
1570
+ listInstalledSkills,
1571
+ removeSkill,
1572
+ projectInfoExists,
1573
+ loadProjectInfo,
1574
+ initProjectInfo,
1575
+ getProjectSection,
1576
+ updateProjectSection,
1577
+ appendToSection,
1578
+ getProjectSections,
1579
+ getProjectInfoStructured,
1580
+ getHistoricalInsights,
1581
+ searchIssues,
1582
+ findSimilarIssues,
1583
+ markIssueResolved,
1584
+ getMemoryStats,
1585
+ getRecentIssues,
1586
+ getDailyLogs,
1587
+ findCrossProjectPatterns,
1588
+ listTrackedProjects,
1589
+ getGlobalMemoryStats,
1590
+ updateGlobalMemoryMd,
1591
+ searchGlobalPatterns,
1592
+ loadContextState,
1593
+ updateContextAfterScan,
1594
+ recordSkillInstalled,
1595
+ recordSkillUsage,
1596
+ getContextForAI
1597
+ };
1598
+ //# sourceMappingURL=chunk-PZDQIFKO.js.map