@triedotdev/mcp 1.0.138 → 1.0.140

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +184 -38
  2. package/dist/{autonomy-config-TZ6HF4FA.js → autonomy-config-ZCOSTMPD.js} +2 -2
  3. package/dist/{chunk-X3F5QDER.js → chunk-4O2KRHK4.js} +934 -132
  4. package/dist/chunk-4O2KRHK4.js.map +1 -0
  5. package/dist/{chunk-J5EMP4XW.js → chunk-5KJ4UJOY.js} +9 -4
  6. package/dist/chunk-5KJ4UJOY.js.map +1 -0
  7. package/dist/chunk-62POBLFC.js +1925 -0
  8. package/dist/chunk-62POBLFC.js.map +1 -0
  9. package/dist/{chunk-GFFUDJMK.js → chunk-75ADWWUF.js} +13 -13
  10. package/dist/chunk-75ADWWUF.js.map +1 -0
  11. package/dist/{chunk-D3AS5LY7.js → chunk-7OJ6JIPL.js} +39 -604
  12. package/dist/chunk-7OJ6JIPL.js.map +1 -0
  13. package/dist/{chunk-3RRXWX3V.js → chunk-AF2APASP.js} +38 -4
  14. package/dist/{chunk-3RRXWX3V.js.map → chunk-AF2APASP.js.map} +1 -1
  15. package/dist/{chunk-QSWUPSLK.js → chunk-FH335WL5.js} +9 -1
  16. package/dist/chunk-FH335WL5.js.map +1 -0
  17. package/dist/{chunk-Y32FM3MR.js → chunk-FPEMP54L.js} +21 -15
  18. package/dist/chunk-FPEMP54L.js.map +1 -0
  19. package/dist/{chunk-EDDT4ZIH.js → chunk-GXF6JOCN.js} +21 -323
  20. package/dist/chunk-GXF6JOCN.js.map +1 -0
  21. package/dist/chunk-LD7ZEFNY.js +132 -0
  22. package/dist/chunk-LD7ZEFNY.js.map +1 -0
  23. package/dist/chunk-NKHO34UZ.js +467 -0
  24. package/dist/chunk-NKHO34UZ.js.map +1 -0
  25. package/dist/{chunk-YOKQ25IW.js → chunk-OQ4A3RDY.js} +14 -14
  26. package/dist/{chunk-6LLH3TBZ.js → chunk-UOSTOLU7.js} +12 -12
  27. package/dist/{chunk-67GSG2ST.js → chunk-XTTZAQWJ.js} +18 -15
  28. package/dist/chunk-XTTZAQWJ.js.map +1 -0
  29. package/dist/{chunk-FOCXXIXY.js → chunk-YEIJW6X6.js} +2 -2
  30. package/dist/chunk-YOJGSRZK.js +216 -0
  31. package/dist/chunk-YOJGSRZK.js.map +1 -0
  32. package/dist/cli/main.js +573 -59
  33. package/dist/cli/main.js.map +1 -1
  34. package/dist/cli/yolo-daemon.js +15 -13
  35. package/dist/cli/yolo-daemon.js.map +1 -1
  36. package/dist/{client-JTU5TRLB.js → client-INNE2GGZ.js} +2 -2
  37. package/dist/{codebase-index-FNJ4GCBE.js → codebase-index-5SEOESWM.js} +3 -3
  38. package/dist/fast-analyzer-AYLZB5TW.js +216 -0
  39. package/dist/fast-analyzer-AYLZB5TW.js.map +1 -0
  40. package/dist/github-ingester-J2ZFYXVE.js +11 -0
  41. package/dist/{goal-manager-6BJQ36AH.js → goal-manager-ZBWKWEML.js} +3 -3
  42. package/dist/{goal-validator-GISXYANK.js → goal-validator-HNXXUCPW.js} +3 -3
  43. package/dist/{graph-X2FMRQLG.js → graph-J4OGTYCO.js} +2 -2
  44. package/dist/{hypothesis-K3KQJOXJ.js → hypothesis-JCUMZKTG.js} +3 -3
  45. package/dist/index.js +1090 -108
  46. package/dist/index.js.map +1 -1
  47. package/dist/{issue-store-BO5OWLJW.js → issue-store-LZWZIGM7.js} +2 -2
  48. package/dist/linear-ingester-JRDQAIAA.js +11 -0
  49. package/dist/linear-ingester-JRDQAIAA.js.map +1 -0
  50. package/dist/{trie-agent-XMSGMD7E.js → trie-agent-M6PHM6UD.js} +10 -10
  51. package/dist/trie-agent-M6PHM6UD.js.map +1 -0
  52. package/package.json +15 -8
  53. package/dist/chunk-67GSG2ST.js.map +0 -1
  54. package/dist/chunk-D3AS5LY7.js.map +0 -1
  55. package/dist/chunk-EDDT4ZIH.js.map +0 -1
  56. package/dist/chunk-GFFUDJMK.js.map +0 -1
  57. package/dist/chunk-J5EMP4XW.js.map +0 -1
  58. package/dist/chunk-QSWUPSLK.js.map +0 -1
  59. package/dist/chunk-X3F5QDER.js.map +0 -1
  60. package/dist/chunk-Y32FM3MR.js.map +0 -1
  61. package/dist/chunk-Z2P4WST6.js +0 -883
  62. package/dist/chunk-Z2P4WST6.js.map +0 -1
  63. /package/dist/{autonomy-config-TZ6HF4FA.js.map → autonomy-config-ZCOSTMPD.js.map} +0 -0
  64. /package/dist/{chunk-YOKQ25IW.js.map → chunk-OQ4A3RDY.js.map} +0 -0
  65. /package/dist/{chunk-6LLH3TBZ.js.map → chunk-UOSTOLU7.js.map} +0 -0
  66. /package/dist/{chunk-FOCXXIXY.js.map → chunk-YEIJW6X6.js.map} +0 -0
  67. /package/dist/{client-JTU5TRLB.js.map → client-INNE2GGZ.js.map} +0 -0
  68. /package/dist/{codebase-index-FNJ4GCBE.js.map → codebase-index-5SEOESWM.js.map} +0 -0
  69. /package/dist/{goal-manager-6BJQ36AH.js.map → github-ingester-J2ZFYXVE.js.map} +0 -0
  70. /package/dist/{goal-validator-GISXYANK.js.map → goal-manager-ZBWKWEML.js.map} +0 -0
  71. /package/dist/{graph-X2FMRQLG.js.map → goal-validator-HNXXUCPW.js.map} +0 -0
  72. /package/dist/{hypothesis-K3KQJOXJ.js.map → graph-J4OGTYCO.js.map} +0 -0
  73. /package/dist/{issue-store-BO5OWLJW.js.map → hypothesis-JCUMZKTG.js.map} +0 -0
  74. /package/dist/{trie-agent-XMSGMD7E.js.map → issue-store-LZWZIGM7.js.map} +0 -0
@@ -0,0 +1,132 @@
1
+ import {
2
+ loadConfig
3
+ } from "./chunk-NKHO34UZ.js";
4
+
5
+ // src/ingest/linear-ingester.ts
6
+ import path from "path";
7
+ var LinearIngester = class {
8
+ graph;
9
+ constructor(_projectPath, graph) {
10
+ this.graph = graph;
11
+ }
12
+ async syncTickets() {
13
+ const apiKey = await this.getApiKey();
14
+ if (!apiKey) {
15
+ console.warn('Linear API key not found. Run "trie linear auth <key>" to enable ticket sync.');
16
+ return;
17
+ }
18
+ const tickets = await this.fetchActiveTickets(apiKey);
19
+ for (const ticket of tickets) {
20
+ await this.ingestTicket(ticket);
21
+ }
22
+ }
23
+ async getApiKey() {
24
+ const config = await loadConfig();
25
+ return config.apiKeys?.linear ?? process.env.LINEAR_API_KEY ?? null;
26
+ }
27
+ async fetchActiveTickets(apiKey) {
28
+ const query = `
29
+ query {
30
+ issues(filter: { state: { type: { in: ["started", "unstarted"] } } }) {
31
+ nodes {
32
+ id
33
+ identifier
34
+ title
35
+ description
36
+ priority
37
+ url
38
+ status {
39
+ name
40
+ }
41
+ assignee {
42
+ name
43
+ }
44
+ labels {
45
+ nodes {
46
+ name
47
+ }
48
+ }
49
+ createdAt
50
+ updatedAt
51
+ }
52
+ }
53
+ }
54
+ `;
55
+ const response = await fetch("https://api.linear.app/graphql", {
56
+ method: "POST",
57
+ headers: {
58
+ "Content-Type": "application/json",
59
+ "Authorization": apiKey
60
+ },
61
+ body: JSON.stringify({ query })
62
+ });
63
+ if (!response.ok) {
64
+ throw new Error(`Linear API error: ${response.statusText}`);
65
+ }
66
+ const data = await response.json();
67
+ return data.data.issues.nodes;
68
+ }
69
+ async ingestTicket(ticket) {
70
+ const labels = ticket.labels.nodes.map((l) => l.name);
71
+ const intentVibe = this.extractIntentVibes(ticket.title, ticket.description, labels);
72
+ const linkedFiles = this.extractLinkedFiles(ticket.description);
73
+ const data = {
74
+ ticketId: ticket.identifier,
75
+ title: ticket.title,
76
+ description: ticket.description || "",
77
+ priority: this.mapPriority(ticket.priority),
78
+ labels,
79
+ intentVibe,
80
+ linkedFiles,
81
+ status: ticket.status.name,
82
+ assignee: ticket.assignee?.name || null,
83
+ url: ticket.url || `https://linear.app/issue/${ticket.identifier}`,
84
+ createdAt: ticket.createdAt,
85
+ updatedAt: ticket.updatedAt
86
+ };
87
+ await this.graph.addNode("linear-ticket", data);
88
+ for (const file of linkedFiles) {
89
+ const resolvedPath = path.resolve(this.graph.projectRoot, file);
90
+ const fileNode = await this.graph.getNode("file", resolvedPath);
91
+ if (fileNode) {
92
+ await this.graph.addEdge(`linear:${ticket.identifier}`, fileNode.id, "relatedTo");
93
+ }
94
+ }
95
+ }
96
+ extractIntentVibes(title, description, labels) {
97
+ const vibes = /* @__PURE__ */ new Set();
98
+ const text = (title + " " + (description || "") + " " + labels.join(" ")).toLowerCase();
99
+ if (text.includes("performance") || text.includes("slow") || text.includes("optimize")) vibes.add("performance");
100
+ if (text.includes("security") || text.includes("auth") || text.includes("vulnerability")) vibes.add("security");
101
+ if (text.includes("refactor") || text.includes("cleanup") || text.includes("debt")) vibes.add("refactor");
102
+ if (text.includes("feature") || text.includes("new")) vibes.add("feature");
103
+ if (text.includes("bug") || text.includes("fix") || text.includes("broken")) vibes.add("bug");
104
+ if (text.includes("breaking") || text.includes("major change")) vibes.add("breaking-change");
105
+ return Array.from(vibes);
106
+ }
107
+ extractLinkedFiles(description) {
108
+ if (!description) return [];
109
+ const matches = description.match(/[\w./_-]+\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs)/gi);
110
+ if (!matches) return [];
111
+ return Array.from(new Set(matches.map((m) => m.replace(/^\.\/+/, ""))));
112
+ }
113
+ mapPriority(priority) {
114
+ switch (priority) {
115
+ case 1:
116
+ return "urgent";
117
+ case 2:
118
+ return "high";
119
+ case 3:
120
+ return "medium";
121
+ case 4:
122
+ return "low";
123
+ default:
124
+ return "none";
125
+ }
126
+ }
127
+ };
128
+
129
+ export {
130
+ LinearIngester
131
+ };
132
+ //# sourceMappingURL=chunk-LD7ZEFNY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ingest/linear-ingester.ts"],"sourcesContent":["import path from 'node:path';\nimport { loadConfig } from '../config/loader.js';\nimport { ContextGraph } from '../context/graph.js';\nimport type { LinearTicketNodeData } from '../context/nodes.js';\n\nexport interface LinearTicket {\n id: string;\n identifier: string;\n title: string;\n description: string;\n priority: number;\n url: string;\n status: { name: string };\n assignee?: { name: string };\n labels: { nodes: { name: string }[] };\n createdAt: string;\n updatedAt: string;\n}\n\nexport class LinearIngester {\n private readonly graph: ContextGraph;\n\n constructor(_projectPath: string, graph: ContextGraph) {\n this.graph = graph;\n }\n\n async syncTickets(): Promise<void> {\n const apiKey = await this.getApiKey();\n if (!apiKey) {\n console.warn('Linear API key not found. Run \"trie linear auth <key>\" to enable ticket sync.');\n return;\n }\n\n const tickets = await this.fetchActiveTickets(apiKey);\n for (const ticket of tickets) {\n await this.ingestTicket(ticket);\n }\n }\n\n private async getApiKey(): Promise<string | null> {\n const config = await loadConfig();\n return config.apiKeys?.linear ?? process.env.LINEAR_API_KEY ?? null;\n }\n\n private async fetchActiveTickets(apiKey: string): Promise<LinearTicket[]> {\n const query = `\n query {\n issues(filter: { state: { type: { in: [\"started\", \"unstarted\"] } } }) {\n nodes {\n id\n identifier\n title\n description\n priority\n url\n status {\n name\n }\n assignee {\n name\n }\n labels {\n nodes {\n name\n }\n }\n createdAt\n updatedAt\n }\n }\n }\n `;\n\n const response = await fetch('https://api.linear.app/graphql', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': apiKey,\n },\n body: JSON.stringify({ query }),\n });\n\n if (!response.ok) {\n throw new Error(`Linear API error: ${response.statusText}`);\n }\n\n const data = (await response.json()) as any;\n return data.data.issues.nodes as LinearTicket[];\n }\n\n private async ingestTicket(ticket: LinearTicket): Promise<void> {\n const labels = ticket.labels.nodes.map(l => l.name);\n const intentVibe = this.extractIntentVibes(ticket.title, ticket.description, labels);\n \n // Attempt to find linked files in description or via labels (heuristic)\n const linkedFiles = this.extractLinkedFiles(ticket.description);\n\n const data: LinearTicketNodeData = {\n ticketId: ticket.identifier,\n title: ticket.title,\n description: ticket.description || '',\n priority: this.mapPriority(ticket.priority),\n labels,\n intentVibe,\n linkedFiles,\n status: ticket.status.name,\n assignee: ticket.assignee?.name || null,\n url: ticket.url || `https://linear.app/issue/${ticket.identifier}`,\n createdAt: ticket.createdAt,\n updatedAt: ticket.updatedAt,\n };\n\n await this.graph.addNode('linear-ticket', data);\n\n // Link to files if found (file node IDs are normalized absolute paths)\n for (const file of linkedFiles) {\n const resolvedPath = path.resolve(this.graph.projectRoot, file);\n const fileNode = await this.graph.getNode('file', resolvedPath);\n if (fileNode) {\n await this.graph.addEdge(`linear:${ticket.identifier}`, fileNode.id, 'relatedTo');\n }\n }\n }\n\n private extractIntentVibes(title: string, description: string, labels: string[]): string[] {\n const vibes = new Set<string>();\n const text = (title + ' ' + (description || '') + ' ' + labels.join(' ')).toLowerCase();\n\n if (text.includes('performance') || text.includes('slow') || text.includes('optimize')) vibes.add('performance');\n if (text.includes('security') || text.includes('auth') || text.includes('vulnerability')) vibes.add('security');\n if (text.includes('refactor') || text.includes('cleanup') || text.includes('debt')) vibes.add('refactor');\n if (text.includes('feature') || text.includes('new')) vibes.add('feature');\n if (text.includes('bug') || text.includes('fix') || text.includes('broken')) vibes.add('bug');\n if (text.includes('breaking') || text.includes('major change')) vibes.add('breaking-change');\n\n return Array.from(vibes);\n }\n\n private extractLinkedFiles(description: string): string[] {\n if (!description) return [];\n const matches = description.match(/[\\w./_-]+\\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs)/gi);\n if (!matches) return [];\n return Array.from(new Set(matches.map(m => m.replace(/^\\.\\/+/, ''))));\n }\n\n private mapPriority(priority: number): string {\n switch (priority) {\n case 1: return 'urgent';\n case 2: return 'high';\n case 3: return 'medium';\n case 4: return 'low';\n default: return 'none';\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,467 @@
1
+ import {
2
+ getTrieDirectory,
3
+ getWorkingDirectory
4
+ } from "./chunk-SH7H3WRU.js";
5
+ import {
6
+ isInteractiveMode
7
+ } from "./chunk-APMV77PU.js";
8
+
9
+ // src/config/loader.ts
10
+ import { readFile, writeFile, mkdir } from "fs/promises";
11
+ import { existsSync as existsSync2 } from "fs";
12
+ import { join as join2, dirname } from "path";
13
+
14
+ // src/config/validation.ts
15
+ import { z } from "zod";
16
+ import { existsSync, readFileSync, mkdirSync } from "fs";
17
+ import { resolve, join } from "path";
18
+ var API_KEY_PATTERNS = {
19
+ anthropic: /^sk-ant-api\d{2}-[\w-]{95}$/,
20
+ openai: /^sk-[\w]{48}$/,
21
+ github: /^ghp_[\w]{36}$/,
22
+ vercel: /^[\w]{24}$/,
23
+ linear: /^lin_api_[\w]{40,60}$/
24
+ };
25
+ var ApiKeysSchema = z.object({
26
+ anthropic: z.string().regex(API_KEY_PATTERNS.anthropic, "Invalid Anthropic API key format").optional(),
27
+ openai: z.string().regex(API_KEY_PATTERNS.openai, "Invalid OpenAI API key format").optional(),
28
+ // Lenient: accept GitHub classic (ghp_*), fine-grained (github_pat_*), or any string 10+ chars
29
+ github: z.string().min(10).optional(),
30
+ vercel: z.string().regex(API_KEY_PATTERNS.vercel, "Invalid Vercel token format").optional(),
31
+ linear: z.string().optional(),
32
+ cursor: z.string().optional()
33
+ });
34
+ var AgentConfigSchema = z.object({
35
+ enabled: z.array(z.string()).optional().default([]),
36
+ disabled: z.array(z.string()).optional().default([]),
37
+ parallel: z.boolean().optional().default(true),
38
+ maxConcurrency: z.number().int().min(1).max(20).optional().default(4),
39
+ timeout: z.number().int().min(1e3).max(3e5).optional().default(12e4),
40
+ // 2 minutes
41
+ cache: z.boolean().optional().default(true)
42
+ });
43
+ var ComplianceSchema = z.object({
44
+ standards: z.array(z.enum(["SOC2", "GDPR", "HIPAA", "CCPA", "PCI-DSS"])).optional().default(["SOC2"]),
45
+ enforceCompliance: z.boolean().optional().default(false),
46
+ reportFormat: z.enum(["json", "sarif", "csv", "html"]).optional().default("json")
47
+ });
48
+ var OutputSchema = z.object({
49
+ format: z.enum(["console", "json", "sarif", "junit"]).optional().default("console"),
50
+ level: z.enum(["critical", "serious", "moderate", "low", "all"]).optional().default("all"),
51
+ interactive: z.boolean().optional().default(false),
52
+ streaming: z.boolean().optional().default(true),
53
+ colors: z.boolean().optional().default(true)
54
+ });
55
+ var PathsSchema = z.object({
56
+ include: z.array(z.string()).optional().default([]),
57
+ exclude: z.array(z.string()).optional().default(["node_modules", "dist", "build", ".git"]),
58
+ configDir: z.string().optional().default(".trie"),
59
+ outputDir: z.string().optional().default("trie-reports")
60
+ });
61
+ var IntegrationsSchema = z.object({
62
+ github: z.object({
63
+ enabled: z.boolean().optional().default(false),
64
+ token: z.string().optional(),
65
+ webhook: z.string().url().optional()
66
+ }).optional(),
67
+ slack: z.object({
68
+ enabled: z.boolean().optional().default(false),
69
+ webhook: z.string().url().optional(),
70
+ channel: z.string().optional()
71
+ }).optional(),
72
+ jira: z.object({
73
+ enabled: z.boolean().optional().default(false),
74
+ url: z.string().url().optional(),
75
+ token: z.string().optional(),
76
+ project: z.string().optional()
77
+ }).optional()
78
+ });
79
+ var UserSchema = z.object({
80
+ name: z.string().min(1).optional(),
81
+ email: z.string().email().optional(),
82
+ role: z.enum([
83
+ "developer",
84
+ "designer",
85
+ "qa",
86
+ "devops",
87
+ "security",
88
+ "architect",
89
+ "manager",
90
+ "contributor"
91
+ ]).optional().default("developer"),
92
+ github: z.string().optional(),
93
+ // GitHub username
94
+ url: z.string().url().optional()
95
+ // Personal/portfolio URL
96
+ });
97
+ var TrieConfigSchema = z.object({
98
+ version: z.string().optional().default("1.0.0"),
99
+ apiKeys: ApiKeysSchema.optional(),
100
+ agents: AgentConfigSchema.optional(),
101
+ compliance: ComplianceSchema.optional(),
102
+ output: OutputSchema.optional(),
103
+ paths: PathsSchema.optional(),
104
+ integrations: IntegrationsSchema.optional(),
105
+ user: UserSchema.optional()
106
+ // User identity for attribution
107
+ });
108
+ var ConfigValidator = class {
109
+ /**
110
+ * Validate configuration object
111
+ */
112
+ validateConfig(config) {
113
+ try {
114
+ const validated = TrieConfigSchema.parse(config);
115
+ const businessErrors = this.validateBusinessLogic(validated);
116
+ if (businessErrors.length > 0) {
117
+ return { success: false, errors: businessErrors };
118
+ }
119
+ return { success: true, data: validated };
120
+ } catch (error) {
121
+ if (error instanceof z.ZodError) {
122
+ const errors = error.errors.map(
123
+ (err) => `${err.path.join(".")}: ${err.message}`
124
+ );
125
+ return { success: false, errors };
126
+ }
127
+ return {
128
+ success: false,
129
+ errors: [`Configuration validation failed: ${error instanceof Error ? error.message : "Unknown error"}`]
130
+ };
131
+ }
132
+ }
133
+ /**
134
+ * Validate environment variables for API keys
135
+ */
136
+ validateEnvironment() {
137
+ const warnings = [];
138
+ const errors = [];
139
+ const exposedPatterns = [
140
+ "NEXT_PUBLIC_ANTHROPIC",
141
+ "REACT_APP_ANTHROPIC",
142
+ "VITE_ANTHROPIC",
143
+ "PUBLIC_ANTHROPIC"
144
+ ];
145
+ for (const pattern of exposedPatterns) {
146
+ const envVars = Object.keys(process.env).filter((key) => key.includes(pattern));
147
+ for (const envVar of envVars) {
148
+ errors.push(`[!] Security risk: API key in client-side environment variable: ${envVar}`);
149
+ }
150
+ }
151
+ let anthropicKey = process.env.ANTHROPIC_API_KEY;
152
+ if (!anthropicKey) {
153
+ try {
154
+ const configPath = join(getTrieDirectory(getWorkingDirectory(void 0, true)), "config.json");
155
+ if (existsSync(configPath)) {
156
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
157
+ anthropicKey = config.apiKeys?.anthropic;
158
+ }
159
+ } catch {
160
+ }
161
+ }
162
+ if (anthropicKey && !API_KEY_PATTERNS.anthropic.test(anthropicKey)) {
163
+ errors.push("ANTHROPIC_API_KEY does not match expected format");
164
+ }
165
+ if (!anthropicKey) {
166
+ warnings.push("ANTHROPIC_API_KEY not set - AI features will be disabled. Set in environment, .trie/config.json, or .env file");
167
+ }
168
+ if (!process.env.GITHUB_TOKEN && process.env.CI) {
169
+ warnings.push("GITHUB_TOKEN not set - GitHub integration disabled");
170
+ }
171
+ return {
172
+ valid: errors.length === 0,
173
+ warnings,
174
+ errors
175
+ };
176
+ }
177
+ /**
178
+ * Validate file paths in configuration
179
+ */
180
+ validatePaths(paths) {
181
+ const errors = [];
182
+ if (paths?.include) {
183
+ for (const path of paths.include) {
184
+ const resolvedPath = resolve(path);
185
+ if (!existsSync(resolvedPath)) {
186
+ errors.push(`Include path does not exist: ${path}`);
187
+ }
188
+ }
189
+ }
190
+ if (paths?.configDir) {
191
+ const configPath = resolve(paths.configDir);
192
+ if (!existsSync(configPath)) {
193
+ try {
194
+ mkdirSync(configPath, { recursive: true });
195
+ } catch {
196
+ errors.push(`Cannot create config directory: ${paths.configDir}`);
197
+ }
198
+ }
199
+ }
200
+ return {
201
+ valid: errors.length === 0,
202
+ errors
203
+ };
204
+ }
205
+ /**
206
+ * Validate integration configurations
207
+ */
208
+ validateIntegrations(integrations) {
209
+ const errors = [];
210
+ if (integrations?.github?.enabled) {
211
+ if (!integrations.github.token) {
212
+ errors.push("GitHub integration enabled but no token provided");
213
+ }
214
+ }
215
+ if (integrations?.slack?.enabled) {
216
+ if (!integrations.slack.webhook) {
217
+ errors.push("Slack integration enabled but no webhook URL provided");
218
+ }
219
+ }
220
+ if (integrations?.jira?.enabled) {
221
+ if (!integrations.jira.url || !integrations.jira.token || !integrations.jira.project) {
222
+ errors.push("JIRA integration enabled but missing required fields (url, token, project)");
223
+ }
224
+ }
225
+ return {
226
+ valid: errors.length === 0,
227
+ errors
228
+ };
229
+ }
230
+ /**
231
+ * Business logic validation
232
+ */
233
+ validateBusinessLogic(config) {
234
+ const errors = [];
235
+ if (config.agents?.enabled && config.agents?.disabled) {
236
+ const overlap = config.agents.enabled.filter(
237
+ (agent) => config.agents?.disabled?.includes(agent)
238
+ );
239
+ if (overlap.length > 0) {
240
+ errors.push(`Agents cannot be both enabled and disabled: ${overlap.join(", ")}`);
241
+ }
242
+ }
243
+ if (config.agents?.maxConcurrency && config.agents.maxConcurrency > 10) {
244
+ errors.push("maxConcurrency should not exceed 10 for optimal performance");
245
+ }
246
+ if (config.compliance?.standards) {
247
+ const invalidStandards = config.compliance.standards.filter(
248
+ (standard) => !["SOC2", "GDPR", "HIPAA", "CCPA", "PCI-DSS"].includes(standard)
249
+ );
250
+ if (invalidStandards.length > 0) {
251
+ errors.push(`Invalid compliance standards: ${invalidStandards.join(", ")}`);
252
+ }
253
+ }
254
+ if (config.paths) {
255
+ const pathValidation = this.validatePaths(config.paths);
256
+ errors.push(...pathValidation.errors);
257
+ }
258
+ if (config.integrations) {
259
+ const integrationValidation = this.validateIntegrations(config.integrations);
260
+ errors.push(...integrationValidation.errors);
261
+ }
262
+ return errors;
263
+ }
264
+ /**
265
+ * Generate configuration template
266
+ */
267
+ generateTemplate() {
268
+ return {
269
+ version: "1.0.0",
270
+ agents: {
271
+ enabled: ["security", "bugs", "types"],
272
+ disabled: [],
273
+ parallel: true,
274
+ maxConcurrency: 4,
275
+ timeout: 12e4,
276
+ cache: true
277
+ },
278
+ compliance: {
279
+ standards: ["SOC2"],
280
+ enforceCompliance: false,
281
+ reportFormat: "json"
282
+ },
283
+ output: {
284
+ format: "console",
285
+ level: "all",
286
+ interactive: false,
287
+ streaming: true,
288
+ colors: true
289
+ },
290
+ paths: {
291
+ include: [],
292
+ exclude: ["node_modules", "dist", "build", ".git"],
293
+ configDir: ".trie",
294
+ outputDir: "trie-reports"
295
+ }
296
+ };
297
+ }
298
+ /**
299
+ * Validate and provide suggestions for improvement
300
+ */
301
+ analyze(config) {
302
+ const suggestions = [];
303
+ const securityIssues = [];
304
+ const optimizations = [];
305
+ let score = 100;
306
+ let hasApiKey = Boolean(config.apiKeys?.anthropic || process.env.ANTHROPIC_API_KEY);
307
+ if (!hasApiKey) {
308
+ try {
309
+ const workDir = getWorkingDirectory(void 0, true);
310
+ const envFiles = [".env", ".env.local", ".env.production"];
311
+ for (const envFile of envFiles) {
312
+ const envPath = join(workDir, envFile);
313
+ if (existsSync(envPath)) {
314
+ const envContent = readFileSync(envPath, "utf-8");
315
+ if (envContent.includes("ANTHROPIC_API_KEY=")) {
316
+ hasApiKey = true;
317
+ break;
318
+ }
319
+ }
320
+ }
321
+ } catch {
322
+ }
323
+ }
324
+ if (!hasApiKey) {
325
+ suggestions.push("Add ANTHROPIC_API_KEY to enable AI-powered analysis for better issue detection. Set in environment, .trie/config.json, or .env file");
326
+ score -= 10;
327
+ }
328
+ if (config.agents?.parallel === false) {
329
+ optimizations.push("Enable parallel agent execution for 3-5x faster scans");
330
+ score -= 15;
331
+ }
332
+ if (config.agents?.cache === false) {
333
+ optimizations.push("Enable result caching to speed up repeated scans");
334
+ score -= 10;
335
+ }
336
+ if (!config.compliance?.standards || config.compliance.standards.length === 0) {
337
+ suggestions.push("Configure compliance standards (SOC2, GDPR, etc.) for regulatory requirements");
338
+ score -= 5;
339
+ }
340
+ const hasIntegrations = config.integrations && (config.integrations.github?.enabled || config.integrations.slack?.enabled || config.integrations.jira?.enabled);
341
+ if (!hasIntegrations) {
342
+ suggestions.push("Consider enabling GitHub/Slack/JIRA integrations for better team collaboration");
343
+ score -= 5;
344
+ }
345
+ if (config.apiKeys) {
346
+ securityIssues.push("API keys in config file - consider using environment variables instead");
347
+ score -= 20;
348
+ }
349
+ return {
350
+ score: Math.max(0, score),
351
+ suggestions,
352
+ securityIssues,
353
+ optimizations
354
+ };
355
+ }
356
+ };
357
+ var DEFAULT_CONFIG = {
358
+ version: "1.0.0",
359
+ agents: {
360
+ enabled: [],
361
+ disabled: [],
362
+ parallel: true,
363
+ maxConcurrency: 4,
364
+ timeout: 12e4,
365
+ cache: true
366
+ },
367
+ compliance: {
368
+ standards: ["SOC2"],
369
+ enforceCompliance: false,
370
+ reportFormat: "json"
371
+ },
372
+ output: {
373
+ format: "console",
374
+ level: "all",
375
+ interactive: false,
376
+ streaming: true,
377
+ colors: true
378
+ },
379
+ paths: {
380
+ include: [],
381
+ exclude: ["node_modules", "dist", "build", ".git", ".next", ".nuxt", "coverage"],
382
+ configDir: ".trie",
383
+ outputDir: "trie-reports"
384
+ }
385
+ };
386
+
387
+ // src/config/loader.ts
388
+ async function loadConfig() {
389
+ const validator = new ConfigValidator();
390
+ const configPath = join2(getTrieDirectory(getWorkingDirectory(void 0, true)), "config.json");
391
+ try {
392
+ if (!existsSync2(configPath)) {
393
+ return DEFAULT_CONFIG;
394
+ }
395
+ const configFile = await readFile(configPath, "utf-8");
396
+ const userConfig = JSON.parse(configFile);
397
+ const merged = mergeConfig(DEFAULT_CONFIG, userConfig);
398
+ const result = validator.validateConfig(merged);
399
+ if (!result.success) {
400
+ if (!isInteractiveMode()) {
401
+ console.error("Configuration validation failed:");
402
+ for (const error of result.errors) {
403
+ console.error(` - ${error}`);
404
+ }
405
+ }
406
+ return DEFAULT_CONFIG;
407
+ }
408
+ if (!isInteractiveMode()) {
409
+ const envValidation = validator.validateEnvironment();
410
+ for (const warning of envValidation.warnings) {
411
+ console.warn(warning);
412
+ }
413
+ for (const error of envValidation.errors) {
414
+ console.error(error);
415
+ }
416
+ }
417
+ return result.data;
418
+ } catch (error) {
419
+ if (!isInteractiveMode()) {
420
+ console.error("Failed to load config, using defaults:", error);
421
+ }
422
+ return DEFAULT_CONFIG;
423
+ }
424
+ }
425
+ async function saveConfig(config) {
426
+ const configPath = join2(getTrieDirectory(getWorkingDirectory(void 0, true)), "config.json");
427
+ const dir = dirname(configPath);
428
+ if (!existsSync2(dir)) {
429
+ await mkdir(dir, { recursive: true });
430
+ }
431
+ let existing = {};
432
+ if (existsSync2(configPath)) {
433
+ try {
434
+ const content = await readFile(configPath, "utf-8");
435
+ existing = JSON.parse(content);
436
+ } catch {
437
+ }
438
+ }
439
+ const toWrite = {
440
+ ...existing,
441
+ ...config,
442
+ // Preserve autonomy block (used by Cursor key, etc.) - TrieConfig doesn't include it
443
+ autonomy: existing.autonomy ?? void 0
444
+ };
445
+ await writeFile(configPath, JSON.stringify(toWrite, null, 2), "utf-8");
446
+ }
447
+ function mergeConfig(defaults, user) {
448
+ if (typeof user !== "object" || user === null || Array.isArray(user)) {
449
+ return { ...defaults };
450
+ }
451
+ const result = { ...defaults };
452
+ for (const [key, value] of Object.entries(user)) {
453
+ const defaultValue = defaults[key];
454
+ if (typeof value === "object" && value !== null && !Array.isArray(value) && typeof defaultValue === "object" && defaultValue !== null) {
455
+ result[key] = mergeConfig(defaultValue, value);
456
+ } else {
457
+ result[key] = value;
458
+ }
459
+ }
460
+ return result;
461
+ }
462
+
463
+ export {
464
+ loadConfig,
465
+ saveConfig
466
+ };
467
+ //# sourceMappingURL=chunk-NKHO34UZ.js.map