@triedotdev/mcp 1.0.41 → 1.0.42

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,814 @@
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/utils/context-state.ts
385
+ import { readFile as readFile4, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
386
+ import { existsSync as existsSync2 } from "fs";
387
+ import { join as join4 } from "path";
388
+ var AGENTS_MD_PATH = ".trie/AGENTS.md";
389
+ var STATE_JSON_PATH = ".trie/state.json";
390
+ async function loadContextState() {
391
+ const workDir = getWorkingDirectory(void 0, true);
392
+ const statePath = join4(workDir, STATE_JSON_PATH);
393
+ const defaults = getDefaultState();
394
+ try {
395
+ if (existsSync2(statePath)) {
396
+ const content = await readFile4(statePath, "utf-8");
397
+ const loaded = JSON.parse(content);
398
+ return {
399
+ ...defaults,
400
+ ...loaded,
401
+ skills: loaded.skills || defaults.skills
402
+ };
403
+ }
404
+ } catch {
405
+ }
406
+ return defaults;
407
+ }
408
+ async function saveContextState(state) {
409
+ const workDir = getWorkingDirectory(void 0, true);
410
+ const trieDir = join4(workDir, ".trie");
411
+ const statePath = join4(workDir, STATE_JSON_PATH);
412
+ await mkdir3(trieDir, { recursive: true });
413
+ await writeFile3(statePath, JSON.stringify(state, null, 2));
414
+ }
415
+ async function updateContextAfterScan(results, filesScanned, contextSignals, duration) {
416
+ const state = await loadContextState();
417
+ const now = (/* @__PURE__ */ new Date()).toISOString();
418
+ const allIssues = results.flatMap((r) => r.issues);
419
+ const issueCounts = {
420
+ critical: allIssues.filter((i) => i.severity === "critical").length,
421
+ serious: allIssues.filter((i) => i.severity === "serious").length,
422
+ moderate: allIssues.filter((i) => i.severity === "moderate").length,
423
+ low: allIssues.filter((i) => i.severity === "low").length,
424
+ total: allIssues.length
425
+ };
426
+ const fileIssueMap = /* @__PURE__ */ new Map();
427
+ for (const issue of allIssues) {
428
+ const count = fileIssueMap.get(issue.file) || 0;
429
+ fileIssueMap.set(issue.file, count + 1);
430
+ }
431
+ const hotFiles = Array.from(fileIssueMap.entries()).sort((a, b) => b[1] - a[1]).slice(0, 10).map(([file, issueCount]) => ({ file, issueCount }));
432
+ const scanSummary = {
433
+ timestamp: now,
434
+ agents: results.map((r) => r.agent),
435
+ filesScanned,
436
+ issues: issueCounts,
437
+ duration,
438
+ hotFiles
439
+ };
440
+ for (const result of results) {
441
+ state.agentStatus[result.agent] = {
442
+ lastRun: now,
443
+ issuesFound: result.issues.length
444
+ };
445
+ }
446
+ const criticalPenalty = issueCounts.critical * 25;
447
+ const seriousPenalty = issueCounts.serious * 10;
448
+ const moderatePenalty = issueCounts.moderate * 3;
449
+ const lowPenalty = issueCounts.low * 1;
450
+ const totalPenalty = Math.min(100, criticalPenalty + seriousPenalty + moderatePenalty + lowPenalty);
451
+ state.healthScore = Math.max(0, 100 - totalPenalty);
452
+ state.activePriorities = generatePriorities(issueCounts, contextSignals);
453
+ state.contextSignals = { ...state.contextSignals, ...contextSignals };
454
+ state.scanHistory = [scanSummary, ...state.scanHistory.slice(0, 19)];
455
+ state.lastScan = scanSummary;
456
+ await saveContextState(state);
457
+ await updateAgentsMd(state);
458
+ }
459
+ async function updateAgentsMd(state) {
460
+ const workDir = getWorkingDirectory(void 0, true);
461
+ const mdPath = join4(workDir, AGENTS_MD_PATH);
462
+ let content;
463
+ try {
464
+ content = await readFile4(mdPath, "utf-8");
465
+ } catch {
466
+ content = getAgentsMdTemplate();
467
+ }
468
+ content = updateSection(content, "Project State", generateProjectStateTable(state));
469
+ content = updateSection(content, "Active Priorities", generatePrioritiesList(state));
470
+ content = updateSection(content, "Agent Status", generateAgentStatusTable(state));
471
+ content = updateSection(content, "Recent Scan History", generateScanHistoryTable(state));
472
+ content = updateSection(content, "Context Signals Detected", generateContextSignals(state));
473
+ content = updateSection(content, "Risk Assessment", generateRiskAssessment(state));
474
+ content = updateSection(content, "Hot Files", generateHotFilesSection(state));
475
+ content = content.replace(
476
+ /Last updated:.*$/m,
477
+ `Last updated: ${(/* @__PURE__ */ new Date()).toISOString()}`
478
+ );
479
+ await writeFile3(mdPath, content);
480
+ }
481
+ function updateSection(content, sectionName, newContent) {
482
+ const sectionRegex = new RegExp(
483
+ `(### ${sectionName}[\\s\\S]*?)(?=###|---|
484
+ ## |$)`,
485
+ "g"
486
+ );
487
+ const replacement = `### ${sectionName}
488
+ ${newContent}
489
+
490
+ `;
491
+ if (content.match(sectionRegex)) {
492
+ return content.replace(sectionRegex, replacement);
493
+ }
494
+ return content;
495
+ }
496
+ function generateProjectStateTable(state) {
497
+ const lastScan = state.lastScan;
498
+ const lastScanDate = lastScan ? new Date(lastScan.timestamp).toLocaleString() : "Never";
499
+ const criticalCount = lastScan?.issues.critical ?? 0;
500
+ const totalTasks = lastScan?.issues.total ?? 0;
501
+ return `| Metric | Value | Updated |
502
+ |--------|-------|---------|
503
+ | Last Scan | ${lastScanDate} | ${lastScan ? "Auto" : "-"} |
504
+ | Critical Issues | ${criticalCount} | ${lastScan ? "Auto" : "-"} |
505
+ | Open Tasks | ${totalTasks} | ${lastScan ? "Auto" : "-"} |
506
+ | Health Score | ${state.healthScore}% | ${lastScan ? "Auto" : "-"} |`;
507
+ }
508
+ function generatePrioritiesList(state) {
509
+ if (state.activePriorities.length === 0) {
510
+ return "_No active priorities. Run a scan to identify issues._";
511
+ }
512
+ return state.activePriorities.map((p, i) => `${i + 1}. ${p}`).join("\n");
513
+ }
514
+ function generatePriorities(issues, contextSignals) {
515
+ const priorities = [];
516
+ if (issues.critical > 0) {
517
+ priorities.push(`\u{1F6A8} Fix ${issues.critical} critical security issue${issues.critical > 1 ? "s" : ""} immediately`);
518
+ }
519
+ if (issues.serious > 0) {
520
+ priorities.push(`\u26A0\uFE0F Address ${issues.serious} serious issue${issues.serious > 1 ? "s" : ""} before deployment`);
521
+ }
522
+ if (contextSignals.touchesAuth && issues.critical === 0) {
523
+ priorities.push("\u2705 Auth code reviewed - continue monitoring");
524
+ }
525
+ if (contextSignals.touchesPayments) {
526
+ priorities.push("\u{1F4B3} Payment code detected - ensure PCI compliance");
527
+ }
528
+ if (contextSignals.touchesUserData) {
529
+ priorities.push("\u{1F510} User data handling detected - verify privacy compliance");
530
+ }
531
+ if (issues.moderate > 5) {
532
+ priorities.push(`\u{1F4CB} Schedule time to address ${issues.moderate} moderate issues`);
533
+ }
534
+ if (priorities.length === 0) {
535
+ priorities.push("\u2728 No critical issues - focus on feature development");
536
+ }
537
+ return priorities.slice(0, 5);
538
+ }
539
+ function generateAgentStatusTable(state) {
540
+ const builtInAgents = [
541
+ "security",
542
+ "privacy",
543
+ "legal",
544
+ "accessibility",
545
+ "bugs",
546
+ "design",
547
+ "architecture",
548
+ "performance",
549
+ "devops",
550
+ "soc2",
551
+ "e2e",
552
+ "typecheck",
553
+ "visual-qa",
554
+ "data-flow"
555
+ ];
556
+ let table = `| Agent | Status | Last Run | Issues Found |
557
+ |-------|--------|----------|--------------|`;
558
+ for (const agent of builtInAgents) {
559
+ const status = state.agentStatus[agent];
560
+ const lastRun = status?.lastRun ? new Date(status.lastRun).toLocaleDateString() : "Never";
561
+ const issues = status?.issuesFound ?? "-";
562
+ const statusEmoji = status ? "\u2705" : "\u23F8\uFE0F";
563
+ table += `
564
+ | ${agent} | ${statusEmoji} Ready | ${lastRun} | ${issues} |`;
565
+ }
566
+ return table;
567
+ }
568
+ function generateScanHistoryTable(state) {
569
+ if (state.scanHistory.length === 0) {
570
+ return `| Date | Agents | Files | Issues | Duration |
571
+ |------|--------|-------|--------|----------|
572
+ | - | - | - | - | - |`;
573
+ }
574
+ let table = `| Date | Agents | Files | Issues | Duration |
575
+ |------|--------|-------|--------|----------|`;
576
+ for (const scan of state.scanHistory.slice(0, 10)) {
577
+ const date = new Date(scan.timestamp).toLocaleDateString();
578
+ const agents = scan.agents.slice(0, 3).join(", ") + (scan.agents.length > 3 ? "..." : "");
579
+ const duration = `${(scan.duration / 1e3).toFixed(1)}s`;
580
+ table += `
581
+ | ${date} | ${agents} | ${scan.filesScanned} | ${scan.issues.total} | ${duration} |`;
582
+ }
583
+ return table;
584
+ }
585
+ function generateContextSignals(state) {
586
+ const signals = [
587
+ "touchesAuth",
588
+ "touchesPayments",
589
+ "touchesUserData",
590
+ "touchesAPI",
591
+ "touchesDatabase",
592
+ "touchesCrypto"
593
+ ];
594
+ return signals.map((s) => {
595
+ const value = state.contextSignals[s];
596
+ const emoji = value === true ? "\u2705" : value === false ? "\u274C" : "\u2753";
597
+ return `- \`${s}\`: ${emoji} ${value === void 0 ? "Unknown" : value ? "Yes" : "No"}`;
598
+ }).join("\n");
599
+ }
600
+ function generateRiskAssessment(state) {
601
+ const score = state.healthScore;
602
+ let riskLevel;
603
+ let confidence;
604
+ if (state.lastScan === null) {
605
+ return `- Overall Risk: Unknown
606
+ - Confidence: 0%`;
607
+ }
608
+ if (score >= 90) {
609
+ riskLevel = "\u{1F7E2} Low";
610
+ confidence = 95;
611
+ } else if (score >= 70) {
612
+ riskLevel = "\u{1F7E1} Medium";
613
+ confidence = 85;
614
+ } else if (score >= 50) {
615
+ riskLevel = "\u{1F7E0} High";
616
+ confidence = 80;
617
+ } else {
618
+ riskLevel = "\u{1F534} Critical";
619
+ confidence = 90;
620
+ }
621
+ return `- Overall Risk: ${riskLevel}
622
+ - Health Score: ${score}%
623
+ - Confidence: ${confidence}%`;
624
+ }
625
+ function generateHotFilesSection(state) {
626
+ if (!state.lastScan || state.lastScan.hotFiles.length === 0) {
627
+ return "_Run a scan to identify hot files._";
628
+ }
629
+ return state.lastScan.hotFiles.map((f) => `- \`${f.file}\` - ${f.issueCount} issue${f.issueCount > 1 ? "s" : ""}`).join("\n");
630
+ }
631
+ function getDefaultState() {
632
+ return {
633
+ lastScan: null,
634
+ healthScore: 0,
635
+ activePriorities: [
636
+ "Initial setup required - run first scan with `trie scan`",
637
+ "Configure agents in `.trie/config.json`",
638
+ "Set up CI/CD integration"
639
+ ],
640
+ contextSignals: {},
641
+ agentStatus: {},
642
+ scanHistory: [],
643
+ customAgents: [],
644
+ skills: {},
645
+ environment: detectEnvironment()
646
+ };
647
+ }
648
+ function detectEnvironment() {
649
+ if (process.env.GITHUB_ACTIONS) return "github-actions";
650
+ if (process.env.GITLAB_CI) return "gitlab-ci";
651
+ if (process.env.CI) return "ci";
652
+ const parent = process.env._ || "";
653
+ if (parent.includes("cursor")) return "cursor";
654
+ if (parent.includes("claude")) return "claude-code";
655
+ return "cli";
656
+ }
657
+ async function recordSkillInstalled(params) {
658
+ const state = await loadContextState();
659
+ state.skills[params.name] = {
660
+ source: params.source,
661
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
662
+ timesApplied: 0,
663
+ appliedBy: []
664
+ };
665
+ await saveContextState(state);
666
+ }
667
+ async function recordSkillUsage(params) {
668
+ const state = await loadContextState();
669
+ const now = (/* @__PURE__ */ new Date()).toISOString();
670
+ for (const skillName of params.skillNames) {
671
+ const skillRecord = state.skills[skillName];
672
+ if (skillRecord) {
673
+ skillRecord.timesApplied++;
674
+ skillRecord.lastApplied = now;
675
+ if (!skillRecord.appliedBy.includes(params.agentName)) {
676
+ skillRecord.appliedBy.push(params.agentName);
677
+ }
678
+ }
679
+ }
680
+ const agentStatus = state.agentStatus[params.agentName];
681
+ if (agentStatus) {
682
+ agentStatus.skillsApplied = params.skillNames;
683
+ }
684
+ await saveContextState(state);
685
+ }
686
+ function getAgentsMdTemplate() {
687
+ return `# Trie Agent Context
688
+
689
+ > **Auto-generated file** - Updated automatically when agents run.
690
+ > Last updated: Never (initial state)
691
+
692
+ This file provides prioritized context for all AI coding assistants working with this codebase.
693
+ Agents should read this file first and update it after completing scans.
694
+
695
+ ---
696
+
697
+ ## Quick Context (Read First)
698
+
699
+ ### Project State
700
+ | Metric | Value | Updated |
701
+ |--------|-------|---------|
702
+ | Last Scan | Never | - |
703
+ | Critical Issues | 0 | - |
704
+ | Open Tasks | 0 | - |
705
+ | Health Score | Unknown | - |
706
+
707
+ ### Active Priorities
708
+ 1. Initial setup required - run first scan with \`trie scan\`
709
+ 2. Configure agents in \`.trie/config.json\`
710
+ 3. Set up CI/CD integration
711
+
712
+ ### Hot Files
713
+ _Run a scan to identify hot files._
714
+
715
+ ---
716
+
717
+ ## Agent Status
718
+
719
+ ### Agent Status
720
+ | Agent | Status | Last Run | Issues Found |
721
+ |-------|--------|----------|--------------|
722
+ | security | Ready | Never | - |
723
+ | privacy | Ready | Never | - |
724
+ | bugs | Ready | Never | - |
725
+
726
+ ### Recent Scan History
727
+ | Date | Agents | Files | Issues | Duration |
728
+ |------|--------|-------|--------|----------|
729
+ | - | - | - | - | - |
730
+
731
+ ---
732
+
733
+ ## Context Analysis
734
+
735
+ ### Context Signals Detected
736
+ - \`touchesAuth\`: Unknown
737
+ - \`touchesPayments\`: Unknown
738
+ - \`touchesUserData\`: Unknown
739
+ - \`touchesAPI\`: Unknown
740
+ - \`touchesDatabase\`: Unknown
741
+ - \`touchesCrypto\`: Unknown
742
+
743
+ ### Risk Assessment
744
+ - Overall Risk: Unknown
745
+ - Confidence: 0%
746
+
747
+ ---
748
+
749
+ *This file is maintained by Trie agents. Manual edits will be preserved in non-auto sections.*
750
+ `;
751
+ }
752
+ async function getContextForAI() {
753
+ const state = await loadContextState();
754
+ const workDir = getWorkingDirectory(void 0, true);
755
+ const lines = [];
756
+ if (projectInfoExists(workDir)) {
757
+ const projectInfo = await loadProjectInfo(workDir);
758
+ if (projectInfo) {
759
+ lines.push(projectInfo);
760
+ lines.push("");
761
+ lines.push("---");
762
+ lines.push("");
763
+ }
764
+ }
765
+ lines.push(
766
+ "## Trie Scan Context",
767
+ "",
768
+ `**Health Score:** ${state.healthScore}%`,
769
+ `**Last Scan:** ${state.lastScan ? new Date(state.lastScan.timestamp).toLocaleString() : "Never"}`,
770
+ "",
771
+ "**Active Priorities:**",
772
+ ...state.activePriorities.map((p) => `- ${p}`),
773
+ ""
774
+ );
775
+ if (state.lastScan) {
776
+ lines.push(
777
+ "**Recent Issues:**",
778
+ `- Critical: ${state.lastScan.issues.critical}`,
779
+ `- Serious: ${state.lastScan.issues.serious}`,
780
+ `- Moderate: ${state.lastScan.issues.moderate}`,
781
+ `- Low: ${state.lastScan.issues.low}`,
782
+ ""
783
+ );
784
+ if (state.lastScan.hotFiles.length > 0) {
785
+ lines.push(
786
+ "**Hot Files (most issues):**",
787
+ ...state.lastScan.hotFiles.slice(0, 5).map((f) => `- ${f.file}: ${f.issueCount} issues`),
788
+ ""
789
+ );
790
+ }
791
+ }
792
+ return lines.join("\n");
793
+ }
794
+
795
+ export {
796
+ parseSkillMd,
797
+ installSkill,
798
+ listInstalledSkills,
799
+ removeSkill,
800
+ projectInfoExists,
801
+ loadProjectInfo,
802
+ initProjectInfo,
803
+ getProjectSection,
804
+ updateProjectSection,
805
+ appendToSection,
806
+ getProjectSections,
807
+ getProjectInfoStructured,
808
+ loadContextState,
809
+ updateContextAfterScan,
810
+ recordSkillInstalled,
811
+ recordSkillUsage,
812
+ getContextForAI
813
+ };
814
+ //# sourceMappingURL=chunk-52SSNKXS.js.map