@triedotdev/mcp 1.0.94 → 1.0.99

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 (83) hide show
  1. package/README.md +145 -137
  2. package/dist/{chunk-JAAIHNOE.js → chunk-APMV77PU.js} +21 -6
  3. package/dist/chunk-APMV77PU.js.map +1 -0
  4. package/dist/{chunk-HLSBTOVE.js → chunk-B3MNN3XB.js} +13 -18
  5. package/dist/{chunk-HLSBTOVE.js.map → chunk-B3MNN3XB.js.map} +1 -1
  6. package/dist/{chunk-IIF5XDCJ.js → chunk-DIZFGLXE.js} +787 -4696
  7. package/dist/chunk-DIZFGLXE.js.map +1 -0
  8. package/dist/{chunk-JO6RVXS6.js → chunk-F4NJ4CBP.js} +2 -2
  9. package/dist/{chunk-AZRCKBGF.js → chunk-FNCCZ3XB.js} +1222 -75
  10. package/dist/chunk-FNCCZ3XB.js.map +1 -0
  11. package/dist/chunk-G76DYVGX.js +136 -0
  12. package/dist/chunk-G76DYVGX.js.map +1 -0
  13. package/dist/chunk-HSNE46VE.js +956 -0
  14. package/dist/chunk-HSNE46VE.js.map +1 -0
  15. package/dist/{chunk-STEFLYPR.js → chunk-IXO4G4D3.js} +2 -2
  16. package/dist/{chunk-OEYIOOYB.js → chunk-JDHR5BDR.js} +2 -3
  17. package/dist/chunk-NIASHOAB.js +1304 -0
  18. package/dist/chunk-NIASHOAB.js.map +1 -0
  19. package/dist/{chunk-CKM6A3G6.js → chunk-OVRG5RP3.js} +6 -7
  20. package/dist/chunk-OVRG5RP3.js.map +1 -0
  21. package/dist/{chunk-RYRVEO2B.js → chunk-R3I2GCZC.js} +3 -3
  22. package/dist/{chunk-WT3XQCG2.js → chunk-R4AAPFXC.js} +2 -2
  23. package/dist/cli/create-agent.js +931 -7
  24. package/dist/cli/create-agent.js.map +1 -1
  25. package/dist/cli/main.js +151 -383
  26. package/dist/cli/main.js.map +1 -1
  27. package/dist/cli/yolo-daemon.js +13 -20
  28. package/dist/cli/yolo-daemon.js.map +1 -1
  29. package/dist/{goal-manager-HOZ7R2QV.js → goal-manager-LAOT4QQX.js} +6 -6
  30. package/dist/guardian-agent-M352CBE5.js +19 -0
  31. package/dist/index.js +1025 -1550
  32. package/dist/index.js.map +1 -1
  33. package/dist/{issue-store-DXIOP6AK.js → issue-store-W2X33X2X.js} +4 -4
  34. package/dist/{progress-LHI66U7B.js → progress-PQVEM7BR.js} +2 -2
  35. package/dist/{vibe-code-signatures-C5A4BHXD.js → vibe-code-signatures-ELEWJFGZ.js} +3 -3
  36. package/dist/{vulnerability-signatures-SVIHJQO5.js → vulnerability-signatures-EIJQX2TS.js} +3 -3
  37. package/dist/workers/agent-worker.js +2 -11
  38. package/dist/workers/agent-worker.js.map +1 -1
  39. package/package.json +2 -2
  40. package/dist/agent-smith-MYQ35URL.js +0 -14
  41. package/dist/agent-smith-runner-4TBONXCP.js +0 -573
  42. package/dist/agent-smith-runner-4TBONXCP.js.map +0 -1
  43. package/dist/cache-manager-RMPRPD5T.js +0 -10
  44. package/dist/chunk-AZRCKBGF.js.map +0 -1
  45. package/dist/chunk-CKM6A3G6.js.map +0 -1
  46. package/dist/chunk-E2ZATINO.js +0 -10879
  47. package/dist/chunk-E2ZATINO.js.map +0 -1
  48. package/dist/chunk-FFWNZUG2.js +0 -266
  49. package/dist/chunk-FFWNZUG2.js.map +0 -1
  50. package/dist/chunk-FK6DQKDY.js +0 -175
  51. package/dist/chunk-FK6DQKDY.js.map +0 -1
  52. package/dist/chunk-IFGF33R5.js +0 -279
  53. package/dist/chunk-IFGF33R5.js.map +0 -1
  54. package/dist/chunk-IIF5XDCJ.js.map +0 -1
  55. package/dist/chunk-JAAIHNOE.js.map +0 -1
  56. package/dist/chunk-ODWDESYP.js +0 -141
  57. package/dist/chunk-ODWDESYP.js.map +0 -1
  58. package/dist/chunk-OWBWNXSC.js +0 -955
  59. package/dist/chunk-OWBWNXSC.js.map +0 -1
  60. package/dist/chunk-Q764X2WD.js +0 -2124
  61. package/dist/chunk-Q764X2WD.js.map +0 -1
  62. package/dist/chunk-RE6ZWXJC.js +0 -279
  63. package/dist/chunk-RE6ZWXJC.js.map +0 -1
  64. package/dist/chunk-RNJ6JKMA.js +0 -2270
  65. package/dist/chunk-RNJ6JKMA.js.map +0 -1
  66. package/dist/chunk-Y62VM3ER.js +0 -536
  67. package/dist/chunk-Y62VM3ER.js.map +0 -1
  68. package/dist/git-45LZUUYA.js +0 -29
  69. package/dist/guardian-agent-RB2UQP5V.js +0 -21
  70. package/dist/progress-LHI66U7B.js.map +0 -1
  71. package/dist/vibe-code-signatures-C5A4BHXD.js.map +0 -1
  72. package/dist/vulnerability-signatures-SVIHJQO5.js.map +0 -1
  73. /package/dist/{chunk-JO6RVXS6.js.map → chunk-F4NJ4CBP.js.map} +0 -0
  74. /package/dist/{chunk-STEFLYPR.js.map → chunk-IXO4G4D3.js.map} +0 -0
  75. /package/dist/{chunk-OEYIOOYB.js.map → chunk-JDHR5BDR.js.map} +0 -0
  76. /package/dist/{chunk-RYRVEO2B.js.map → chunk-R3I2GCZC.js.map} +0 -0
  77. /package/dist/{chunk-WT3XQCG2.js.map → chunk-R4AAPFXC.js.map} +0 -0
  78. /package/dist/{agent-smith-MYQ35URL.js.map → goal-manager-LAOT4QQX.js.map} +0 -0
  79. /package/dist/{cache-manager-RMPRPD5T.js.map → guardian-agent-M352CBE5.js.map} +0 -0
  80. /package/dist/{git-45LZUUYA.js.map → issue-store-W2X33X2X.js.map} +0 -0
  81. /package/dist/{goal-manager-HOZ7R2QV.js.map → progress-PQVEM7BR.js.map} +0 -0
  82. /package/dist/{guardian-agent-RB2UQP5V.js.map → vibe-code-signatures-ELEWJFGZ.js.map} +0 -0
  83. /package/dist/{issue-store-DXIOP6AK.js.map → vulnerability-signatures-EIJQX2TS.js.map} +0 -0
@@ -1,35 +1,32 @@
1
1
  import {
2
- Executor,
3
- Triager,
4
2
  detectStack,
5
- loadConfig
6
- } from "./chunk-Q764X2WD.js";
7
- import {
8
- getDiff,
9
- getRecentCommits,
10
- getStagedChanges,
11
- getUncommittedChanges,
12
- getWorkingTreeDiff
13
- } from "./chunk-FK6DQKDY.js";
3
+ runExecFile
4
+ } from "./chunk-HSNE46VE.js";
14
5
  import {
15
6
  ContextGraph
16
- } from "./chunk-Y62VM3ER.js";
7
+ } from "./chunk-NIASHOAB.js";
17
8
  import {
18
9
  scanForVulnerabilities
19
- } from "./chunk-JO6RVXS6.js";
20
- import {
21
- storeIssues
22
- } from "./chunk-OEYIOOYB.js";
10
+ } from "./chunk-F4NJ4CBP.js";
23
11
  import {
24
12
  scanForVibeCodeIssues
25
- } from "./chunk-STEFLYPR.js";
13
+ } from "./chunk-IXO4G4D3.js";
26
14
  import {
27
15
  Trie
28
16
  } from "./chunk-6NLHFIYA.js";
17
+ import {
18
+ storeIssues
19
+ } from "./chunk-JDHR5BDR.js";
29
20
  import {
30
21
  getTrieDirectory,
31
22
  getWorkingDirectory
32
- } from "./chunk-WT3XQCG2.js";
23
+ } from "./chunk-R4AAPFXC.js";
24
+ import {
25
+ isInteractiveMode
26
+ } from "./chunk-APMV77PU.js";
27
+ import {
28
+ __require
29
+ } from "./chunk-DGUM43GV.js";
33
30
 
34
31
  // src/cli/checkpoint.ts
35
32
  import { existsSync } from "fs";
@@ -202,10 +199,449 @@ async function handleCheckpointCommand(args) {
202
199
  }
203
200
  }
204
201
 
205
- // src/utils/autonomy-config.ts
202
+ // src/config/loader.ts
206
203
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
207
- import { existsSync as existsSync2 } from "fs";
208
- import { join as join2 } from "path";
204
+ import { existsSync as existsSync3 } from "fs";
205
+ import { join as join3, dirname } from "path";
206
+
207
+ // src/config/validation.ts
208
+ import { z } from "zod";
209
+ import { existsSync as existsSync2, readFileSync } from "fs";
210
+ import { resolve, join as join2 } from "path";
211
+ var API_KEY_PATTERNS = {
212
+ anthropic: /^sk-ant-api\d{2}-[\w-]{95}$/,
213
+ openai: /^sk-[\w]{48}$/,
214
+ github: /^ghp_[\w]{36}$/,
215
+ vercel: /^[\w]{24}$/,
216
+ linear: /^lin_api_[\w]{40,60}$/
217
+ };
218
+ var ApiKeysSchema = z.object({
219
+ anthropic: z.string().regex(API_KEY_PATTERNS.anthropic, "Invalid Anthropic API key format").optional(),
220
+ openai: z.string().regex(API_KEY_PATTERNS.openai, "Invalid OpenAI API key format").optional(),
221
+ github: z.string().regex(API_KEY_PATTERNS.github, "Invalid GitHub token format").optional(),
222
+ vercel: z.string().regex(API_KEY_PATTERNS.vercel, "Invalid Vercel token format").optional(),
223
+ linear: z.string().optional()
224
+ // Linear keys can vary, so we'll be flexible but allow storage
225
+ });
226
+ var AgentConfigSchema = z.object({
227
+ enabled: z.array(z.string()).optional().default([]),
228
+ disabled: z.array(z.string()).optional().default([]),
229
+ parallel: z.boolean().optional().default(true),
230
+ maxConcurrency: z.number().int().min(1).max(20).optional().default(4),
231
+ timeout: z.number().int().min(1e3).max(3e5).optional().default(12e4),
232
+ // 2 minutes
233
+ cache: z.boolean().optional().default(true)
234
+ });
235
+ var ComplianceSchema = z.object({
236
+ standards: z.array(z.enum(["SOC2", "GDPR", "HIPAA", "CCPA", "PCI-DSS"])).optional().default(["SOC2"]),
237
+ enforceCompliance: z.boolean().optional().default(false),
238
+ reportFormat: z.enum(["json", "sarif", "csv", "html"]).optional().default("json")
239
+ });
240
+ var OutputSchema = z.object({
241
+ format: z.enum(["console", "json", "sarif", "junit"]).optional().default("console"),
242
+ level: z.enum(["critical", "serious", "moderate", "low", "all"]).optional().default("all"),
243
+ interactive: z.boolean().optional().default(false),
244
+ streaming: z.boolean().optional().default(true),
245
+ colors: z.boolean().optional().default(true)
246
+ });
247
+ var PathsSchema = z.object({
248
+ include: z.array(z.string()).optional().default([]),
249
+ exclude: z.array(z.string()).optional().default(["node_modules", "dist", "build", ".git"]),
250
+ configDir: z.string().optional().default(".trie"),
251
+ outputDir: z.string().optional().default("trie-reports")
252
+ });
253
+ var IntegrationsSchema = z.object({
254
+ github: z.object({
255
+ enabled: z.boolean().optional().default(false),
256
+ token: z.string().optional(),
257
+ webhook: z.string().url().optional()
258
+ }).optional(),
259
+ slack: z.object({
260
+ enabled: z.boolean().optional().default(false),
261
+ webhook: z.string().url().optional(),
262
+ channel: z.string().optional()
263
+ }).optional(),
264
+ jira: z.object({
265
+ enabled: z.boolean().optional().default(false),
266
+ url: z.string().url().optional(),
267
+ token: z.string().optional(),
268
+ project: z.string().optional()
269
+ }).optional()
270
+ });
271
+ var UserSchema = z.object({
272
+ name: z.string().min(1).optional(),
273
+ email: z.string().email().optional(),
274
+ role: z.enum([
275
+ "developer",
276
+ "designer",
277
+ "qa",
278
+ "devops",
279
+ "security",
280
+ "architect",
281
+ "manager",
282
+ "contributor"
283
+ ]).optional().default("developer"),
284
+ github: z.string().optional(),
285
+ // GitHub username
286
+ url: z.string().url().optional()
287
+ // Personal/portfolio URL
288
+ });
289
+ var TrieConfigSchema = z.object({
290
+ version: z.string().optional().default("1.0.0"),
291
+ apiKeys: ApiKeysSchema.optional(),
292
+ agents: AgentConfigSchema.optional(),
293
+ compliance: ComplianceSchema.optional(),
294
+ output: OutputSchema.optional(),
295
+ paths: PathsSchema.optional(),
296
+ integrations: IntegrationsSchema.optional(),
297
+ user: UserSchema.optional()
298
+ // User identity for attribution
299
+ });
300
+ var ConfigValidator = class {
301
+ /**
302
+ * Validate configuration object
303
+ */
304
+ validateConfig(config) {
305
+ try {
306
+ const validated = TrieConfigSchema.parse(config);
307
+ const businessErrors = this.validateBusinessLogic(validated);
308
+ if (businessErrors.length > 0) {
309
+ return { success: false, errors: businessErrors };
310
+ }
311
+ return { success: true, data: validated };
312
+ } catch (error) {
313
+ if (error instanceof z.ZodError) {
314
+ const errors = error.errors.map(
315
+ (err) => `${err.path.join(".")}: ${err.message}`
316
+ );
317
+ return { success: false, errors };
318
+ }
319
+ return {
320
+ success: false,
321
+ errors: [`Configuration validation failed: ${error instanceof Error ? error.message : "Unknown error"}`]
322
+ };
323
+ }
324
+ }
325
+ /**
326
+ * Validate environment variables for API keys
327
+ */
328
+ validateEnvironment() {
329
+ const warnings = [];
330
+ const errors = [];
331
+ const exposedPatterns = [
332
+ "NEXT_PUBLIC_ANTHROPIC",
333
+ "REACT_APP_ANTHROPIC",
334
+ "VITE_ANTHROPIC",
335
+ "PUBLIC_ANTHROPIC"
336
+ ];
337
+ for (const pattern of exposedPatterns) {
338
+ const envVars = Object.keys(process.env).filter((key) => key.includes(pattern));
339
+ for (const envVar of envVars) {
340
+ errors.push(`[!] Security risk: API key in client-side environment variable: ${envVar}`);
341
+ }
342
+ }
343
+ let anthropicKey = process.env.ANTHROPIC_API_KEY;
344
+ if (!anthropicKey) {
345
+ try {
346
+ const configPath = join2(getTrieDirectory(getWorkingDirectory(void 0, true)), "config.json");
347
+ if (existsSync2(configPath)) {
348
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
349
+ anthropicKey = config.apiKeys?.anthropic;
350
+ }
351
+ } catch {
352
+ }
353
+ }
354
+ if (anthropicKey && !API_KEY_PATTERNS.anthropic.test(anthropicKey)) {
355
+ errors.push("ANTHROPIC_API_KEY does not match expected format");
356
+ }
357
+ if (!anthropicKey) {
358
+ warnings.push("ANTHROPIC_API_KEY not set - AI features will be disabled. Set in environment, .trie/config.json, or .env file");
359
+ }
360
+ if (!process.env.GITHUB_TOKEN && process.env.CI) {
361
+ warnings.push("GITHUB_TOKEN not set - GitHub integration disabled");
362
+ }
363
+ return {
364
+ valid: errors.length === 0,
365
+ warnings,
366
+ errors
367
+ };
368
+ }
369
+ /**
370
+ * Validate file paths in configuration
371
+ */
372
+ validatePaths(paths) {
373
+ const errors = [];
374
+ if (paths?.include) {
375
+ for (const path8 of paths.include) {
376
+ const resolvedPath = resolve(path8);
377
+ if (!existsSync2(resolvedPath)) {
378
+ errors.push(`Include path does not exist: ${path8}`);
379
+ }
380
+ }
381
+ }
382
+ if (paths?.configDir) {
383
+ const configPath = resolve(paths.configDir);
384
+ if (!existsSync2(configPath)) {
385
+ try {
386
+ __require("fs").mkdirSync(configPath, { recursive: true });
387
+ } catch {
388
+ errors.push(`Cannot create config directory: ${paths.configDir}`);
389
+ }
390
+ }
391
+ }
392
+ return {
393
+ valid: errors.length === 0,
394
+ errors
395
+ };
396
+ }
397
+ /**
398
+ * Validate integration configurations
399
+ */
400
+ validateIntegrations(integrations) {
401
+ const errors = [];
402
+ if (integrations?.github?.enabled) {
403
+ if (!integrations.github.token) {
404
+ errors.push("GitHub integration enabled but no token provided");
405
+ }
406
+ }
407
+ if (integrations?.slack?.enabled) {
408
+ if (!integrations.slack.webhook) {
409
+ errors.push("Slack integration enabled but no webhook URL provided");
410
+ }
411
+ }
412
+ if (integrations?.jira?.enabled) {
413
+ if (!integrations.jira.url || !integrations.jira.token || !integrations.jira.project) {
414
+ errors.push("JIRA integration enabled but missing required fields (url, token, project)");
415
+ }
416
+ }
417
+ return {
418
+ valid: errors.length === 0,
419
+ errors
420
+ };
421
+ }
422
+ /**
423
+ * Business logic validation
424
+ */
425
+ validateBusinessLogic(config) {
426
+ const errors = [];
427
+ if (config.agents?.enabled && config.agents?.disabled) {
428
+ const overlap = config.agents.enabled.filter(
429
+ (agent) => config.agents?.disabled?.includes(agent)
430
+ );
431
+ if (overlap.length > 0) {
432
+ errors.push(`Agents cannot be both enabled and disabled: ${overlap.join(", ")}`);
433
+ }
434
+ }
435
+ if (config.agents?.maxConcurrency && config.agents.maxConcurrency > 10) {
436
+ errors.push("maxConcurrency should not exceed 10 for optimal performance");
437
+ }
438
+ if (config.compliance?.standards) {
439
+ const invalidStandards = config.compliance.standards.filter(
440
+ (standard) => !["SOC2", "GDPR", "HIPAA", "CCPA", "PCI-DSS"].includes(standard)
441
+ );
442
+ if (invalidStandards.length > 0) {
443
+ errors.push(`Invalid compliance standards: ${invalidStandards.join(", ")}`);
444
+ }
445
+ }
446
+ if (config.paths) {
447
+ const pathValidation = this.validatePaths(config.paths);
448
+ errors.push(...pathValidation.errors);
449
+ }
450
+ if (config.integrations) {
451
+ const integrationValidation = this.validateIntegrations(config.integrations);
452
+ errors.push(...integrationValidation.errors);
453
+ }
454
+ return errors;
455
+ }
456
+ /**
457
+ * Generate configuration template
458
+ */
459
+ generateTemplate() {
460
+ return {
461
+ version: "1.0.0",
462
+ agents: {
463
+ enabled: ["security", "bugs", "types"],
464
+ disabled: [],
465
+ parallel: true,
466
+ maxConcurrency: 4,
467
+ timeout: 12e4,
468
+ cache: true
469
+ },
470
+ compliance: {
471
+ standards: ["SOC2"],
472
+ enforceCompliance: false,
473
+ reportFormat: "json"
474
+ },
475
+ output: {
476
+ format: "console",
477
+ level: "all",
478
+ interactive: false,
479
+ streaming: true,
480
+ colors: true
481
+ },
482
+ paths: {
483
+ include: [],
484
+ exclude: ["node_modules", "dist", "build", ".git"],
485
+ configDir: ".trie",
486
+ outputDir: "trie-reports"
487
+ }
488
+ };
489
+ }
490
+ /**
491
+ * Validate and provide suggestions for improvement
492
+ */
493
+ analyze(config) {
494
+ const suggestions = [];
495
+ const securityIssues = [];
496
+ const optimizations = [];
497
+ let score = 100;
498
+ let hasApiKey = Boolean(config.apiKeys?.anthropic || process.env.ANTHROPIC_API_KEY);
499
+ if (!hasApiKey) {
500
+ try {
501
+ const workDir = getWorkingDirectory(void 0, true);
502
+ const envFiles = [".env", ".env.local", ".env.production"];
503
+ for (const envFile of envFiles) {
504
+ const envPath = join2(workDir, envFile);
505
+ if (existsSync2(envPath)) {
506
+ const envContent = readFileSync(envPath, "utf-8");
507
+ if (envContent.includes("ANTHROPIC_API_KEY=")) {
508
+ hasApiKey = true;
509
+ break;
510
+ }
511
+ }
512
+ }
513
+ } catch {
514
+ }
515
+ }
516
+ if (!hasApiKey) {
517
+ suggestions.push("Add ANTHROPIC_API_KEY to enable AI-powered analysis for better issue detection. Set in environment, .trie/config.json, or .env file");
518
+ score -= 10;
519
+ }
520
+ if (config.agents?.parallel === false) {
521
+ optimizations.push("Enable parallel agent execution for 3-5x faster scans");
522
+ score -= 15;
523
+ }
524
+ if (config.agents?.cache === false) {
525
+ optimizations.push("Enable result caching to speed up repeated scans");
526
+ score -= 10;
527
+ }
528
+ if (!config.compliance?.standards || config.compliance.standards.length === 0) {
529
+ suggestions.push("Configure compliance standards (SOC2, GDPR, etc.) for regulatory requirements");
530
+ score -= 5;
531
+ }
532
+ const hasIntegrations = config.integrations && (config.integrations.github?.enabled || config.integrations.slack?.enabled || config.integrations.jira?.enabled);
533
+ if (!hasIntegrations) {
534
+ suggestions.push("Consider enabling GitHub/Slack/JIRA integrations for better team collaboration");
535
+ score -= 5;
536
+ }
537
+ if (config.apiKeys) {
538
+ securityIssues.push("API keys in config file - consider using environment variables instead");
539
+ score -= 20;
540
+ }
541
+ return {
542
+ score: Math.max(0, score),
543
+ suggestions,
544
+ securityIssues,
545
+ optimizations
546
+ };
547
+ }
548
+ };
549
+ var DEFAULT_CONFIG = {
550
+ version: "1.0.0",
551
+ agents: {
552
+ enabled: [],
553
+ disabled: [],
554
+ parallel: true,
555
+ maxConcurrency: 4,
556
+ timeout: 12e4,
557
+ cache: true
558
+ },
559
+ compliance: {
560
+ standards: ["SOC2"],
561
+ enforceCompliance: false,
562
+ reportFormat: "json"
563
+ },
564
+ output: {
565
+ format: "console",
566
+ level: "all",
567
+ interactive: false,
568
+ streaming: true,
569
+ colors: true
570
+ },
571
+ paths: {
572
+ include: [],
573
+ exclude: ["node_modules", "dist", "build", ".git", ".next", ".nuxt", "coverage"],
574
+ configDir: ".trie",
575
+ outputDir: "trie-reports"
576
+ }
577
+ };
578
+
579
+ // src/config/loader.ts
580
+ async function loadConfig() {
581
+ const validator = new ConfigValidator();
582
+ const configPath = join3(getTrieDirectory(getWorkingDirectory(void 0, true)), "config.json");
583
+ try {
584
+ if (!existsSync3(configPath)) {
585
+ return DEFAULT_CONFIG;
586
+ }
587
+ const configFile = await readFile2(configPath, "utf-8");
588
+ const userConfig = JSON.parse(configFile);
589
+ const merged = mergeConfig(DEFAULT_CONFIG, userConfig);
590
+ const result = validator.validateConfig(merged);
591
+ if (!result.success) {
592
+ if (!isInteractiveMode()) {
593
+ console.error("Configuration validation failed:");
594
+ for (const error of result.errors) {
595
+ console.error(` - ${error}`);
596
+ }
597
+ }
598
+ return DEFAULT_CONFIG;
599
+ }
600
+ if (!isInteractiveMode()) {
601
+ const envValidation = validator.validateEnvironment();
602
+ for (const warning of envValidation.warnings) {
603
+ console.warn(warning);
604
+ }
605
+ for (const error of envValidation.errors) {
606
+ console.error(error);
607
+ }
608
+ }
609
+ return result.data;
610
+ } catch (error) {
611
+ if (!isInteractiveMode()) {
612
+ console.error("Failed to load config, using defaults:", error);
613
+ }
614
+ return DEFAULT_CONFIG;
615
+ }
616
+ }
617
+ async function saveConfig(config) {
618
+ const configPath = join3(getTrieDirectory(getWorkingDirectory(void 0, true)), "config.json");
619
+ const dir = dirname(configPath);
620
+ if (!existsSync3(dir)) {
621
+ await mkdir2(dir, { recursive: true });
622
+ }
623
+ await writeFile2(configPath, JSON.stringify(config, null, 2), "utf-8");
624
+ }
625
+ function mergeConfig(defaults, user) {
626
+ if (typeof user !== "object" || user === null || Array.isArray(user)) {
627
+ return { ...defaults };
628
+ }
629
+ const result = { ...defaults };
630
+ for (const [key, value] of Object.entries(user)) {
631
+ const defaultValue = defaults[key];
632
+ if (typeof value === "object" && value !== null && !Array.isArray(value) && typeof defaultValue === "object" && defaultValue !== null) {
633
+ result[key] = mergeConfig(defaultValue, value);
634
+ } else {
635
+ result[key] = value;
636
+ }
637
+ }
638
+ return result;
639
+ }
640
+
641
+ // src/utils/autonomy-config.ts
642
+ import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
643
+ import { existsSync as existsSync4 } from "fs";
644
+ import { join as join4 } from "path";
209
645
 
210
646
  // src/types/autonomy.ts
211
647
  var DEFAULT_AUTONOMY_CONFIG = {
@@ -252,12 +688,12 @@ var DEFAULT_AUTONOMY_CONFIG = {
252
688
  // src/utils/autonomy-config.ts
253
689
  import { createHash } from "crypto";
254
690
  async function loadAutonomyConfig(projectPath) {
255
- const configPath = join2(getTrieDirectory(projectPath), "config.json");
691
+ const configPath = join4(getTrieDirectory(projectPath), "config.json");
256
692
  try {
257
- if (!existsSync2(configPath)) {
693
+ if (!existsSync4(configPath)) {
258
694
  return { ...DEFAULT_AUTONOMY_CONFIG };
259
695
  }
260
- const content = await readFile2(configPath, "utf-8");
696
+ const content = await readFile3(configPath, "utf-8");
261
697
  const config = JSON.parse(content);
262
698
  return mergeWithDefaults(config.autonomy || {});
263
699
  } catch (error) {
@@ -295,11 +731,11 @@ async function getOccurrences(projectPath) {
295
731
  if (occurrenceCache.has(projectPath)) {
296
732
  return occurrenceCache.get(projectPath);
297
733
  }
298
- const occurrencesPath = join2(getTrieDirectory(projectPath), "memory", "occurrences.json");
734
+ const occurrencesPath = join4(getTrieDirectory(projectPath), "memory", "occurrences.json");
299
735
  const occurrences = /* @__PURE__ */ new Map();
300
736
  try {
301
- if (existsSync2(occurrencesPath)) {
302
- const content = await readFile2(occurrencesPath, "utf-8");
737
+ if (existsSync4(occurrencesPath)) {
738
+ const content = await readFile3(occurrencesPath, "utf-8");
303
739
  const data = JSON.parse(content);
304
740
  for (const [hash, occ] of Object.entries(data)) {
305
741
  occurrences.set(hash, occ);
@@ -313,17 +749,17 @@ async function getOccurrences(projectPath) {
313
749
  async function saveOccurrences(projectPath) {
314
750
  const occurrences = occurrenceCache.get(projectPath);
315
751
  if (!occurrences) return;
316
- const occurrencesPath = join2(getTrieDirectory(projectPath), "memory", "occurrences.json");
317
- const memoryDir = join2(getTrieDirectory(projectPath), "memory");
752
+ const occurrencesPath = join4(getTrieDirectory(projectPath), "memory", "occurrences.json");
753
+ const memoryDir = join4(getTrieDirectory(projectPath), "memory");
318
754
  try {
319
- if (!existsSync2(memoryDir)) {
320
- await mkdir2(memoryDir, { recursive: true });
755
+ if (!existsSync4(memoryDir)) {
756
+ await mkdir3(memoryDir, { recursive: true });
321
757
  }
322
758
  const data = {};
323
759
  for (const [hash, occ] of occurrences.entries()) {
324
760
  data[hash] = occ;
325
761
  }
326
- await writeFile2(occurrencesPath, JSON.stringify(data, null, 2));
762
+ await writeFile3(occurrencesPath, JSON.stringify(data, null, 2));
327
763
  } catch (error) {
328
764
  console.error("Failed to save occurrences:", error);
329
765
  }
@@ -470,8 +906,93 @@ async function getAutonomyConfig(projectPath) {
470
906
  return config;
471
907
  }
472
908
 
473
- // src/agent/perceive.ts
909
+ // src/agent/git.ts
910
+ import { existsSync as existsSync5 } from "fs";
474
911
  import path from "path";
912
+ async function execGit(args, cwd) {
913
+ try {
914
+ const { stdout } = await runExecFile(
915
+ "git",
916
+ ["-C", cwd, ...args],
917
+ { actor: "internal:git", triggeredBy: "manual", targetPath: cwd },
918
+ { maxBuffer: 10 * 1024 * 1024, captureOutput: false }
919
+ );
920
+ return stdout.trim();
921
+ } catch (error) {
922
+ const stderr = error?.stderr?.toString();
923
+ if (stderr?.includes("not a git repository") || stderr?.includes("does not have any commits")) {
924
+ return null;
925
+ }
926
+ throw error;
927
+ }
928
+ }
929
+ async function ensureRepo(projectPath) {
930
+ const result = await execGit(["rev-parse", "--is-inside-work-tree"], projectPath);
931
+ return result === "true";
932
+ }
933
+ function parseNameStatus(output) {
934
+ return output.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => {
935
+ const parts = line.split(" ");
936
+ const status = parts[0] ?? "";
937
+ const filePath = parts[1] ?? "";
938
+ const oldPath = parts[2];
939
+ const change = { status, path: filePath };
940
+ if (oldPath) change.oldPath = oldPath;
941
+ return change;
942
+ }).filter((entry) => entry.path.length > 0);
943
+ }
944
+ async function getRecentCommits(projectPath, limit) {
945
+ const isRepo = await ensureRepo(projectPath);
946
+ if (!isRepo) return [];
947
+ const output = await execGit(
948
+ ["log", `-n`, String(limit), "--pretty=format:%H%x09%an%x09%ad%x09%s", "--date=iso"],
949
+ projectPath
950
+ );
951
+ if (!output) return [];
952
+ return output.split("\n").map((line) => {
953
+ const [hash, author, date, message] = line.split(" ");
954
+ return { hash, author, date, message };
955
+ });
956
+ }
957
+ async function getStagedChanges(projectPath) {
958
+ const isRepo = await ensureRepo(projectPath);
959
+ if (!isRepo) return [];
960
+ const output = await execGit(["diff", "--cached", "--name-status"], projectPath);
961
+ if (!output) return [];
962
+ return parseNameStatus(output);
963
+ }
964
+ async function getUncommittedChanges(projectPath) {
965
+ const isRepo = await ensureRepo(projectPath);
966
+ if (!isRepo) return [];
967
+ const changes = [];
968
+ const unstaged = await execGit(["diff", "--name-status"], projectPath);
969
+ if (unstaged) {
970
+ changes.push(...parseNameStatus(unstaged));
971
+ }
972
+ const untracked = await execGit(["ls-files", "--others", "--exclude-standard"], projectPath);
973
+ if (untracked) {
974
+ changes.push(
975
+ ...untracked.split("\n").map((p) => p.trim()).filter(Boolean).map((p) => ({ status: "??", path: p }))
976
+ );
977
+ }
978
+ return changes;
979
+ }
980
+ async function getDiff(projectPath, commitHash) {
981
+ const isRepo = await ensureRepo(projectPath);
982
+ if (!isRepo) return "";
983
+ const diff = await execGit(["show", commitHash, "--unified=3", "--no-color"], projectPath);
984
+ return diff ?? "";
985
+ }
986
+ async function getWorkingTreeDiff(projectPath, stagedOnly = false) {
987
+ const isRepo = await ensureRepo(projectPath);
988
+ if (!isRepo) return "";
989
+ const args = stagedOnly ? ["diff", "--cached", "--unified=3", "--no-color"] : ["diff", "--unified=3", "--no-color"];
990
+ const diff = await execGit(args, projectPath);
991
+ return diff ?? "";
992
+ }
993
+
994
+ // src/agent/perceive.ts
995
+ import path2 from "path";
475
996
 
476
997
  // src/agent/diff-analyzer.ts
477
998
  var RISKY_PATTERNS = [/auth/i, /token/i, /password/i, /secret/i, /validate/i, /sanitize/i];
@@ -575,7 +1096,7 @@ async function upsertWorkingChange(graph, files, projectPath) {
575
1096
  return change.id;
576
1097
  }
577
1098
  async function ensureFileNode(graph, filePath, projectPath) {
578
- const normalized = path.resolve(projectPath, filePath);
1099
+ const normalized = path2.resolve(projectPath, filePath);
579
1100
  const existing = await graph.getNode("file", normalized);
580
1101
  const now = (/* @__PURE__ */ new Date()).toISOString();
581
1102
  if (existing) {
@@ -588,7 +1109,7 @@ async function ensureFileNode(graph, filePath, projectPath) {
588
1109
  }
589
1110
  const data = {
590
1111
  path: filePath,
591
- extension: path.extname(filePath),
1112
+ extension: path2.extname(filePath),
592
1113
  purpose: "",
593
1114
  riskLevel: "medium",
594
1115
  whyRisky: null,
@@ -601,7 +1122,7 @@ async function ensureFileNode(graph, filePath, projectPath) {
601
1122
  }
602
1123
 
603
1124
  // src/agent/risk-scorer.ts
604
- import path2 from "path";
1125
+ import path3 from "path";
605
1126
  var BASE_RISK = {
606
1127
  low: 10,
607
1128
  medium: 35,
@@ -611,8 +1132,7 @@ var BASE_RISK = {
611
1132
  var SENSITIVE_PATHS = [
612
1133
  { pattern: /auth|login|token|session/i, weight: 20, reason: "touches authentication" },
613
1134
  { pattern: /payment|billing|stripe|paypal|checkout/i, weight: 25, reason: "touches payments" },
614
- { pattern: /secret|credential|env|config\/security/i, weight: 15, reason: "touches secrets/security config" },
615
- { pattern: /gdpr|privacy|pii|phi/i, weight: 15, reason: "touches sensitive data" }
1135
+ { pattern: /secret|credential|env|config\/security/i, weight: 15, reason: "touches secrets/security config" }
616
1136
  ];
617
1137
  function levelFromScore(score) {
618
1138
  if (score >= 90) return "critical";
@@ -622,7 +1142,7 @@ function levelFromScore(score) {
622
1142
  }
623
1143
  async function scoreFile(graph, filePath, matchedPatterns = []) {
624
1144
  const reasons = [];
625
- const normalized = path2.resolve(graph.projectRoot, filePath);
1145
+ const normalized = path3.resolve(graph.projectRoot, filePath);
626
1146
  const node = await graph.getNode("file", normalized);
627
1147
  const incidents = await graph.getIncidentsForFile(filePath);
628
1148
  let score = 10;
@@ -724,6 +1244,629 @@ async function matchPatternsForFiles(graph, files) {
724
1244
  return { matches, byFile };
725
1245
  }
726
1246
 
1247
+ // src/orchestrator/triager.ts
1248
+ var Triager = class {
1249
+ constructor(_config) {
1250
+ }
1251
+ /**
1252
+ * Triage a change to select appropriate agents
1253
+ * Note: Skills/agents have been removed - Trie is now purely a decision ledger
1254
+ */
1255
+ async triage(_context, _forceAgents) {
1256
+ return [];
1257
+ }
1258
+ /**
1259
+ * Get all available agent names (deprecated - returns empty array)
1260
+ */
1261
+ getAvailableAgents() {
1262
+ return [];
1263
+ }
1264
+ };
1265
+
1266
+ // src/utils/parallel-executor.ts
1267
+ import { Worker } from "worker_threads";
1268
+ import { cpus } from "os";
1269
+ import { existsSync as existsSync6 } from "fs";
1270
+ import { fileURLToPath } from "url";
1271
+ var ParallelExecutor = class {
1272
+ maxWorkers;
1273
+ cache;
1274
+ streaming;
1275
+ activeWorkers = /* @__PURE__ */ new Set();
1276
+ cacheEnabled = true;
1277
+ useWorkerThreads = false;
1278
+ workerAvailable = null;
1279
+ warnedWorkerFallback = false;
1280
+ constructor(cacheManager, maxWorkers = Math.max(2, Math.min(cpus().length - 1, 8)), options) {
1281
+ this.maxWorkers = maxWorkers;
1282
+ this.cache = cacheManager;
1283
+ this.cacheEnabled = options?.cacheEnabled ?? true;
1284
+ this.useWorkerThreads = options?.useWorkerThreads ?? false;
1285
+ }
1286
+ /**
1287
+ * Set streaming manager for real-time updates
1288
+ */
1289
+ setStreaming(streaming) {
1290
+ this.streaming = streaming;
1291
+ }
1292
+ /**
1293
+ * Execute agents in parallel with intelligent scheduling
1294
+ */
1295
+ async executeAgents(agents, files, context) {
1296
+ if (agents.length === 0) {
1297
+ return /* @__PURE__ */ new Map();
1298
+ }
1299
+ if (this.streaming && this.streaming.getProgress().totalFiles === 0) {
1300
+ this.streaming.startScan(files.length);
1301
+ }
1302
+ const cacheResults = /* @__PURE__ */ new Map();
1303
+ const uncachedTasks = [];
1304
+ for (const agent of agents) {
1305
+ const cached = await this.checkAgentCache(agent, files);
1306
+ if (cached) {
1307
+ cacheResults.set(agent.name, cached);
1308
+ this.streaming?.completeAgent(agent.name, cached.issues);
1309
+ } else {
1310
+ uncachedTasks.push({
1311
+ agent,
1312
+ files,
1313
+ context,
1314
+ priority: agent.priority?.tier || 2,
1315
+ timeoutMs: context?.config?.timeoutMs || 12e4
1316
+ });
1317
+ }
1318
+ }
1319
+ uncachedTasks.sort((a, b) => a.priority - b.priority);
1320
+ const parallelResults = await this.executeTasksParallel(uncachedTasks);
1321
+ await this.cacheResults(parallelResults);
1322
+ const allResults = /* @__PURE__ */ new Map();
1323
+ for (const [agent, result] of cacheResults) {
1324
+ allResults.set(agent, result);
1325
+ }
1326
+ for (const result of parallelResults) {
1327
+ allResults.set(result.agent, result.result);
1328
+ }
1329
+ const allIssues = Array.from(allResults.values()).flatMap((r) => r.issues);
1330
+ this.streaming?.completeScan(allIssues);
1331
+ return allResults;
1332
+ }
1333
+ /**
1334
+ * Check if agent has cached results for given files
1335
+ */
1336
+ async checkAgentCache(agent, files) {
1337
+ if (!this.cacheEnabled || !this.cache) {
1338
+ return null;
1339
+ }
1340
+ const cachedIssues = await this.cache.getCachedBatch(files, agent.name);
1341
+ if (cachedIssues.size === files.length) {
1342
+ const allIssues = Array.from(cachedIssues.values()).flat();
1343
+ return {
1344
+ agent: agent.name,
1345
+ issues: allIssues,
1346
+ executionTime: 0,
1347
+ // Cached
1348
+ success: true,
1349
+ metadata: {
1350
+ filesAnalyzed: files.length,
1351
+ linesAnalyzed: 0
1352
+ }
1353
+ };
1354
+ }
1355
+ return null;
1356
+ }
1357
+ /**
1358
+ * Execute tasks in parallel batches
1359
+ */
1360
+ async executeTasksParallel(tasks) {
1361
+ if (tasks.length === 0) {
1362
+ return [];
1363
+ }
1364
+ const results = [];
1365
+ const batches = this.createBatches(tasks, this.maxWorkers);
1366
+ for (const batch of batches) {
1367
+ const batchResults = await Promise.all(
1368
+ batch.map((task) => this.executeTask(task))
1369
+ );
1370
+ results.push(...batchResults);
1371
+ }
1372
+ return results;
1373
+ }
1374
+ /**
1375
+ * Create batches for parallel execution
1376
+ */
1377
+ createBatches(tasks, batchSize) {
1378
+ const batches = [];
1379
+ for (let i = 0; i < tasks.length; i += batchSize) {
1380
+ batches.push(tasks.slice(i, i + batchSize));
1381
+ }
1382
+ return batches;
1383
+ }
1384
+ /**
1385
+ * Execute a single task
1386
+ */
1387
+ async executeTask(task) {
1388
+ const startTime = Date.now();
1389
+ this.streaming?.startAgent(task.agent.name);
1390
+ try {
1391
+ const result = this.canUseWorkers() ? await this.executeTaskInWorker(task) : await task.agent.scan(task.files, task.context);
1392
+ const executionTime = Date.now() - startTime;
1393
+ this.streaming?.completeAgent(task.agent.name, result.issues);
1394
+ return {
1395
+ agent: task.agent.name,
1396
+ result,
1397
+ fromCache: false,
1398
+ executionTime
1399
+ };
1400
+ } catch (error) {
1401
+ const executionTime = Date.now() - startTime;
1402
+ const errorMessage = error instanceof Error ? error.message : String(error);
1403
+ this.streaming?.reportError(new Error(errorMessage), `Agent: ${task.agent.name}`);
1404
+ return {
1405
+ agent: task.agent.name,
1406
+ result: {
1407
+ agent: task.agent.name,
1408
+ issues: [],
1409
+ executionTime,
1410
+ success: false,
1411
+ error: errorMessage
1412
+ },
1413
+ fromCache: false,
1414
+ executionTime
1415
+ };
1416
+ }
1417
+ }
1418
+ canUseWorkers() {
1419
+ if (!this.useWorkerThreads) {
1420
+ return false;
1421
+ }
1422
+ if (this.workerAvailable !== null) {
1423
+ return this.workerAvailable;
1424
+ }
1425
+ const workerUrl = this.getWorkerUrl();
1426
+ this.workerAvailable = existsSync6(fileURLToPath(workerUrl));
1427
+ if (!this.workerAvailable && !this.warnedWorkerFallback && !isInteractiveMode()) {
1428
+ console.error("Worker threads unavailable; falling back to in-process agents.");
1429
+ this.warnedWorkerFallback = true;
1430
+ }
1431
+ return this.workerAvailable;
1432
+ }
1433
+ getWorkerUrl() {
1434
+ const distDir = new URL(".", import.meta.url);
1435
+ return new URL("workers/agent-worker.js", distDir);
1436
+ }
1437
+ async executeTaskInWorker(task) {
1438
+ const workerUrl = this.getWorkerUrl();
1439
+ return new Promise((resolve2, reject) => {
1440
+ const worker = new Worker(workerUrl, {
1441
+ workerData: {
1442
+ agentName: task.agent.name,
1443
+ files: task.files,
1444
+ context: task.context
1445
+ }
1446
+ });
1447
+ this.activeWorkers.add(worker);
1448
+ const timeout = setTimeout(() => {
1449
+ worker.terminate().catch(() => void 0);
1450
+ reject(new Error(`Agent ${task.agent.name} timed out after ${task.timeoutMs}ms`));
1451
+ }, task.timeoutMs);
1452
+ worker.on("message", (message) => {
1453
+ if (message?.type === "result") {
1454
+ clearTimeout(timeout);
1455
+ resolve2(message.result);
1456
+ } else if (message?.type === "error") {
1457
+ clearTimeout(timeout);
1458
+ reject(new Error(message.error));
1459
+ }
1460
+ });
1461
+ worker.on("error", (error) => {
1462
+ clearTimeout(timeout);
1463
+ reject(error);
1464
+ });
1465
+ worker.on("exit", (code) => {
1466
+ this.activeWorkers.delete(worker);
1467
+ if (code !== 0) {
1468
+ clearTimeout(timeout);
1469
+ reject(new Error(`Worker stopped with exit code ${code}`));
1470
+ }
1471
+ });
1472
+ });
1473
+ }
1474
+ /**
1475
+ * Cache results for future use
1476
+ */
1477
+ async cacheResults(results) {
1478
+ if (!this.cacheEnabled || !this.cache) {
1479
+ return;
1480
+ }
1481
+ const cachePromises = results.filter((r) => r.result.success && !r.fromCache).map((r) => {
1482
+ const issuesByFile = this.groupIssuesByFile(r.result.issues);
1483
+ const perFilePromises = Object.entries(issuesByFile).map(
1484
+ ([file, issues]) => this.cache.setCached(file, r.agent, issues, r.executionTime)
1485
+ );
1486
+ return Promise.all(perFilePromises);
1487
+ });
1488
+ await Promise.allSettled(cachePromises);
1489
+ }
1490
+ /**
1491
+ * Cleanup resources
1492
+ */
1493
+ async cleanup() {
1494
+ const terminationPromises = Array.from(this.activeWorkers).map(
1495
+ (worker) => worker.terminate()
1496
+ );
1497
+ await Promise.allSettled(terminationPromises);
1498
+ this.activeWorkers.clear();
1499
+ }
1500
+ groupIssuesByFile(issues) {
1501
+ const grouped = {};
1502
+ for (const issue of issues) {
1503
+ if (!grouped[issue.file]) {
1504
+ grouped[issue.file] = [];
1505
+ }
1506
+ grouped[issue.file].push(issue);
1507
+ }
1508
+ return grouped;
1509
+ }
1510
+ };
1511
+ function calculateOptimalConcurrency() {
1512
+ const numCPUs = cpus().length;
1513
+ const availableMemoryGB = process.memoryUsage().rss / 1024 / 1024 / 1024;
1514
+ let optimal = Math.max(2, Math.min(numCPUs - 1, 8));
1515
+ if (availableMemoryGB < 2) {
1516
+ optimal = Math.max(2, Math.floor(optimal / 2));
1517
+ }
1518
+ if (numCPUs > 8) {
1519
+ optimal = Math.min(optimal + 2, 12);
1520
+ }
1521
+ return optimal;
1522
+ }
1523
+
1524
+ // src/utils/cache-manager.ts
1525
+ import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4, stat } from "fs/promises";
1526
+ import { join as join5 } from "path";
1527
+ import { createHash as createHash2 } from "crypto";
1528
+ var CacheManager = class {
1529
+ cacheDir;
1530
+ indexPath;
1531
+ VERSION = "1.0.0";
1532
+ MAX_AGE_MS = 24 * 60 * 60 * 1e3;
1533
+ // 24 hours
1534
+ MAX_ENTRIES = 1e3;
1535
+ constructor(baseDir) {
1536
+ this.cacheDir = join5(getTrieDirectory(baseDir), "cache");
1537
+ this.indexPath = join5(this.cacheDir, "index.json");
1538
+ }
1539
+ /**
1540
+ * Generate cache key for a file and agent combination
1541
+ */
1542
+ generateCacheKey(filePath, agent, fileHash) {
1543
+ const key = `${filePath}:${agent}:${fileHash}`;
1544
+ return createHash2("sha256").update(key).digest("hex").slice(0, 16);
1545
+ }
1546
+ /**
1547
+ * Get file hash for cache validation
1548
+ */
1549
+ async getFileHash(filePath) {
1550
+ try {
1551
+ const content = await readFile4(filePath, "utf-8");
1552
+ const stats = await stat(filePath);
1553
+ const hash = createHash2("sha256").update(content).digest("hex").slice(0, 16);
1554
+ return {
1555
+ hash,
1556
+ size: stats.size,
1557
+ mtime: stats.mtime.getTime()
1558
+ };
1559
+ } catch {
1560
+ return { hash: "", size: 0, mtime: 0 };
1561
+ }
1562
+ }
1563
+ /**
1564
+ * Load cache index
1565
+ */
1566
+ async loadIndex() {
1567
+ try {
1568
+ const content = await readFile4(this.indexPath, "utf-8");
1569
+ return JSON.parse(content);
1570
+ } catch {
1571
+ return {
1572
+ version: this.VERSION,
1573
+ created: Date.now(),
1574
+ entries: {}
1575
+ };
1576
+ }
1577
+ }
1578
+ /**
1579
+ * Save cache index
1580
+ */
1581
+ async saveIndex(index) {
1582
+ try {
1583
+ await mkdir4(this.cacheDir, { recursive: true });
1584
+ await writeFile4(this.indexPath, JSON.stringify(index, null, 2));
1585
+ } catch (error) {
1586
+ if (!isInteractiveMode()) {
1587
+ console.warn("Failed to save cache index:", error);
1588
+ }
1589
+ }
1590
+ }
1591
+ /**
1592
+ * Clean up expired entries
1593
+ */
1594
+ cleanupExpired(index) {
1595
+ const now = Date.now();
1596
+ const validEntries = {};
1597
+ for (const [key, entry] of Object.entries(index.entries)) {
1598
+ if (now - entry.timestamp < this.MAX_AGE_MS) {
1599
+ validEntries[key] = entry;
1600
+ }
1601
+ }
1602
+ const entries = Object.entries(validEntries);
1603
+ if (entries.length > this.MAX_ENTRIES) {
1604
+ entries.sort((a, b) => b[1].timestamp - a[1].timestamp);
1605
+ const limited = entries.slice(0, this.MAX_ENTRIES);
1606
+ return {
1607
+ ...index,
1608
+ entries: Object.fromEntries(limited)
1609
+ };
1610
+ }
1611
+ return {
1612
+ ...index,
1613
+ entries: validEntries
1614
+ };
1615
+ }
1616
+ /**
1617
+ * Get cached result for a file and agent
1618
+ *
1619
+ * Cache automatically invalidates when files change:
1620
+ * - Cache key includes file hash: hash(filePath:agent:fileHash)
1621
+ * - When file changes, hash changes, so cache key changes
1622
+ * - Old cache entry won't be found (different key)
1623
+ * - File is automatically rescanned
1624
+ *
1625
+ * This means cache auto-updates when Claude fixes code - no manual invalidation needed!
1626
+ */
1627
+ async getCached(filePath, agent) {
1628
+ try {
1629
+ const { hash, size: _size, mtime: _mtime } = await this.getFileHash(filePath);
1630
+ if (!hash) return null;
1631
+ const index = await this.loadIndex();
1632
+ const cacheKey = this.generateCacheKey(filePath, agent, hash);
1633
+ const entry = index.entries[cacheKey];
1634
+ if (!entry) return null;
1635
+ const isValid = entry.fileHash === hash && entry.version === this.VERSION && Date.now() - entry.timestamp < this.MAX_AGE_MS;
1636
+ if (!isValid) {
1637
+ delete index.entries[cacheKey];
1638
+ await this.saveIndex(index);
1639
+ return null;
1640
+ }
1641
+ return entry.issues;
1642
+ } catch {
1643
+ return null;
1644
+ }
1645
+ }
1646
+ /**
1647
+ * Cache result for a file and agent
1648
+ */
1649
+ async setCached(filePath, agent, issues, executionTime) {
1650
+ try {
1651
+ const { hash, size } = await this.getFileHash(filePath);
1652
+ if (!hash) return;
1653
+ const index = await this.loadIndex();
1654
+ const cacheKey = this.generateCacheKey(filePath, agent, hash);
1655
+ index.entries[cacheKey] = {
1656
+ version: this.VERSION,
1657
+ timestamp: Date.now(),
1658
+ fileHash: hash,
1659
+ fileSize: size,
1660
+ agent,
1661
+ issues,
1662
+ executionTime
1663
+ };
1664
+ const cleanedIndex = this.cleanupExpired(index);
1665
+ await this.saveIndex(cleanedIndex);
1666
+ } catch (error) {
1667
+ if (!isInteractiveMode()) {
1668
+ console.warn("Failed to cache result:", error);
1669
+ }
1670
+ }
1671
+ }
1672
+ /**
1673
+ * Check if multiple files have cached results
1674
+ */
1675
+ async getCachedBatch(files, agent) {
1676
+ const results = /* @__PURE__ */ new Map();
1677
+ await Promise.all(
1678
+ files.map(async (file) => {
1679
+ const cached = await this.getCached(file, agent);
1680
+ if (cached) {
1681
+ results.set(file, cached);
1682
+ }
1683
+ })
1684
+ );
1685
+ return results;
1686
+ }
1687
+ /**
1688
+ * Get cache statistics
1689
+ */
1690
+ async getStats() {
1691
+ try {
1692
+ const index = await this.loadIndex();
1693
+ const entries = Object.values(index.entries);
1694
+ const totalSizeKB = entries.reduce((acc, entry) => acc + entry.fileSize, 0) / 1024;
1695
+ const timestamps = entries.map((e) => e.timestamp);
1696
+ const agents = [...new Set(entries.map((e) => e.agent))];
1697
+ return {
1698
+ totalEntries: entries.length,
1699
+ totalSizeKB: Math.round(totalSizeKB),
1700
+ oldestEntry: timestamps.length > 0 ? Math.min(...timestamps) : null,
1701
+ newestEntry: timestamps.length > 0 ? Math.max(...timestamps) : null,
1702
+ agents
1703
+ };
1704
+ } catch {
1705
+ return {
1706
+ totalEntries: 0,
1707
+ totalSizeKB: 0,
1708
+ oldestEntry: null,
1709
+ newestEntry: null,
1710
+ agents: []
1711
+ };
1712
+ }
1713
+ }
1714
+ /**
1715
+ * Clean up stale cache entries by verifying file hashes
1716
+ * This removes entries where files have changed or no longer exist
1717
+ * Called periodically to keep cache clean
1718
+ *
1719
+ * Note: Since cache keys are hashed, we can't easily reverse-engineer file paths.
1720
+ * However, when getCached() is called, it naturally invalidates stale entries
1721
+ * by checking if the current file hash matches the cached hash. This method
1722
+ * proactively cleans up entries for known changed files.
1723
+ */
1724
+ async cleanupStaleEntries(filePaths) {
1725
+ try {
1726
+ const index = await this.loadIndex();
1727
+ let removedCount = 0;
1728
+ const keysToRemove = [];
1729
+ if (filePaths && filePaths.length > 0) {
1730
+ const agents = /* @__PURE__ */ new Set();
1731
+ for (const entry of Object.values(index.entries)) {
1732
+ agents.add(entry.agent);
1733
+ }
1734
+ for (const filePath of filePaths) {
1735
+ try {
1736
+ const { hash: currentHash } = await this.getFileHash(filePath);
1737
+ if (!currentHash) {
1738
+ continue;
1739
+ }
1740
+ for (const agent of agents) {
1741
+ for (const [key, entry] of Object.entries(index.entries)) {
1742
+ if (entry.agent !== agent) continue;
1743
+ if (entry.fileHash !== currentHash) {
1744
+ const oldKey = this.generateCacheKey(filePath, agent, entry.fileHash);
1745
+ if (oldKey === key) {
1746
+ keysToRemove.push(key);
1747
+ removedCount++;
1748
+ }
1749
+ }
1750
+ }
1751
+ }
1752
+ } catch {
1753
+ continue;
1754
+ }
1755
+ }
1756
+ }
1757
+ const uniqueKeys = [...new Set(keysToRemove)];
1758
+ for (const key of uniqueKeys) {
1759
+ delete index.entries[key];
1760
+ }
1761
+ if (removedCount > 0) {
1762
+ await this.saveIndex(index);
1763
+ }
1764
+ return removedCount;
1765
+ } catch (error) {
1766
+ if (!isInteractiveMode()) {
1767
+ console.warn("Failed to cleanup stale cache entries:", error);
1768
+ }
1769
+ return 0;
1770
+ }
1771
+ }
1772
+ /**
1773
+ * Clear all cache
1774
+ */
1775
+ async clear() {
1776
+ try {
1777
+ const emptyIndex = {
1778
+ version: this.VERSION,
1779
+ created: Date.now(),
1780
+ entries: {}
1781
+ };
1782
+ await this.saveIndex(emptyIndex);
1783
+ } catch (error) {
1784
+ if (!isInteractiveMode()) {
1785
+ console.warn("Failed to clear cache:", error);
1786
+ }
1787
+ }
1788
+ }
1789
+ };
1790
+
1791
+ // src/orchestrator/executor.ts
1792
+ var Executor = class {
1793
+ async executeAgents(agents, files, context, options) {
1794
+ const parallel = options?.parallel ?? true;
1795
+ const cacheEnabled = options?.cacheEnabled ?? true;
1796
+ const maxConcurrency = options?.maxConcurrency ?? calculateOptimalConcurrency();
1797
+ const useWorkerThreads = options?.useWorkerThreads ?? false;
1798
+ if (!isInteractiveMode()) {
1799
+ console.error(`Executing ${agents.length} scouts ${parallel ? "in parallel" : "sequentially"}...`);
1800
+ }
1801
+ if (parallel) {
1802
+ const cacheManager = cacheEnabled ? new CacheManager(context.workingDir) : null;
1803
+ const executor = new ParallelExecutor(cacheManager, maxConcurrency, {
1804
+ cacheEnabled,
1805
+ useWorkerThreads
1806
+ });
1807
+ if (options?.streaming) {
1808
+ executor.setStreaming(options.streaming);
1809
+ }
1810
+ const results = await executor.executeAgents(agents, files, {
1811
+ ...context,
1812
+ config: { timeoutMs: options?.timeoutMs ?? 12e4 }
1813
+ });
1814
+ return agents.map((agent) => results.get(agent.name)).filter(Boolean);
1815
+ }
1816
+ const promises = agents.map(
1817
+ (agent) => this.executeAgentWithTimeout(agent, files, context, options?.timeoutMs ?? 3e4)
1818
+ );
1819
+ try {
1820
+ const results = await Promise.allSettled(promises);
1821
+ return results.map((result, index) => {
1822
+ if (result.status === "fulfilled") {
1823
+ if (!isInteractiveMode()) {
1824
+ console.error(`${agents[index].name} completed in ${result.value.executionTime}ms`);
1825
+ }
1826
+ return result.value;
1827
+ } else {
1828
+ if (!isInteractiveMode()) {
1829
+ console.error(`${agents[index].name} failed:`, result.reason);
1830
+ }
1831
+ return {
1832
+ agent: agents[index].name,
1833
+ issues: [],
1834
+ executionTime: 0,
1835
+ success: false,
1836
+ error: result.reason instanceof Error ? result.reason.message : String(result.reason)
1837
+ };
1838
+ }
1839
+ });
1840
+ } catch (error) {
1841
+ if (!isInteractiveMode()) {
1842
+ console.error("Executor error:", error);
1843
+ }
1844
+ return agents.map((agent) => ({
1845
+ agent: agent.name,
1846
+ issues: [],
1847
+ executionTime: 0,
1848
+ success: false,
1849
+ error: "Execution failed"
1850
+ }));
1851
+ }
1852
+ }
1853
+ async executeAgentWithTimeout(agent, files, context, timeoutMs = 3e4) {
1854
+ return new Promise(async (resolve2, reject) => {
1855
+ const timeout = setTimeout(() => {
1856
+ reject(new Error(`Agent ${agent.name} timed out after ${timeoutMs}ms`));
1857
+ }, timeoutMs);
1858
+ try {
1859
+ const result = await agent.scan(files, context);
1860
+ clearTimeout(timeout);
1861
+ resolve2(result);
1862
+ } catch (error) {
1863
+ clearTimeout(timeout);
1864
+ reject(error);
1865
+ }
1866
+ });
1867
+ }
1868
+ };
1869
+
727
1870
  // src/agent/reason.ts
728
1871
  function buildDefaultCodeContext() {
729
1872
  return {
@@ -801,7 +1944,7 @@ async function reasonAboutChanges(projectPath, files, options = {}) {
801
1944
  if (options.runAgents) {
802
1945
  const codeContext = options.codeContext ?? buildDefaultCodeContext();
803
1946
  const triager = new Triager();
804
- const agents = await triager.selectAgents(codeContext, riskLevel);
1947
+ const agents = await triager.triage(codeContext);
805
1948
  if (agents.length > 0) {
806
1949
  const executor = new Executor();
807
1950
  const scanContext = {
@@ -827,9 +1970,9 @@ async function reasonAboutChangesHumanReadable(projectPath, files, options = {})
827
1970
  }
828
1971
 
829
1972
  // src/bootstrap/files.ts
830
- import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3 } from "fs/promises";
831
- import { existsSync as existsSync3 } from "fs";
832
- import { join as join3 } from "path";
1973
+ import { readFile as readFile5, writeFile as writeFile5, unlink, mkdir as mkdir5 } from "fs/promises";
1974
+ import { existsSync as existsSync7 } from "fs";
1975
+ import { join as join6 } from "path";
833
1976
  var BOOTSTRAP_FILES = [
834
1977
  { name: "PROJECT.md", type: "user", description: "Project overview and conventions" },
835
1978
  { name: "RULES.md", type: "user", description: "Coding standards agents enforce" },
@@ -844,15 +1987,15 @@ async function loadBootstrapContext(workDir) {
844
1987
  const contentParts = [];
845
1988
  let needsBootstrap2 = false;
846
1989
  for (const file of BOOTSTRAP_FILES) {
847
- const filePath = join3(trieDir, file.name);
848
- const exists = existsSync3(filePath);
1990
+ const filePath = join6(trieDir, file.name);
1991
+ const exists = existsSync7(filePath);
849
1992
  if (file.name === "BOOTSTRAP.md" && exists) {
850
1993
  needsBootstrap2 = true;
851
1994
  }
852
1995
  let content;
853
1996
  if (exists) {
854
1997
  try {
855
- content = await readFile3(filePath, "utf-8");
1998
+ content = await readFile5(filePath, "utf-8");
856
1999
  if (content.trim() && file.type !== "one-time") {
857
2000
  contentParts.push(`<!-- ${file.name} -->
858
2001
  ${content}`);
@@ -878,13 +2021,13 @@ ${content}`);
878
2021
  async function initializeBootstrapFiles(options = {}) {
879
2022
  const projectDir = options.workDir || getWorkingDirectory(void 0, true);
880
2023
  const trieDir = getTrieDirectory(projectDir);
881
- await mkdir3(trieDir, { recursive: true });
2024
+ await mkdir5(trieDir, { recursive: true });
882
2025
  const created = [];
883
2026
  const skipped = [];
884
2027
  const stack = await detectStack(projectDir);
885
2028
  for (const file of BOOTSTRAP_FILES) {
886
- const filePath = join3(trieDir, file.name);
887
- const exists = existsSync3(filePath);
2029
+ const filePath = join6(trieDir, file.name);
2030
+ const exists = existsSync7(filePath);
888
2031
  if (exists && !options.force) {
889
2032
  skipped.push(file.name);
890
2033
  continue;
@@ -899,7 +2042,7 @@ async function initializeBootstrapFiles(options = {}) {
899
2042
  }
900
2043
  const template = getFileTemplate(file.name, stack);
901
2044
  if (template) {
902
- await writeFile3(filePath, template);
2045
+ await writeFile5(filePath, template);
903
2046
  created.push(file.name);
904
2047
  }
905
2048
  }
@@ -907,7 +2050,7 @@ async function initializeBootstrapFiles(options = {}) {
907
2050
  }
908
2051
  async function completeBootstrap(workDir) {
909
2052
  const projectDir = workDir || getWorkingDirectory(void 0, true);
910
- const bootstrapPath = join3(getTrieDirectory(projectDir), "BOOTSTRAP.md");
2053
+ const bootstrapPath = join6(getTrieDirectory(projectDir), "BOOTSTRAP.md");
911
2054
  try {
912
2055
  await unlink(bootstrapPath);
913
2056
  return true;
@@ -917,15 +2060,15 @@ async function completeBootstrap(workDir) {
917
2060
  }
918
2061
  function needsBootstrap(workDir) {
919
2062
  const projectDir = workDir || getWorkingDirectory(void 0, true);
920
- const bootstrapPath = join3(getTrieDirectory(projectDir), "BOOTSTRAP.md");
921
- return existsSync3(bootstrapPath);
2063
+ const bootstrapPath = join6(getTrieDirectory(projectDir), "BOOTSTRAP.md");
2064
+ return existsSync7(bootstrapPath);
922
2065
  }
923
2066
  async function loadRules(workDir) {
924
2067
  const projectDir = workDir || getWorkingDirectory(void 0, true);
925
- const rulesPath = join3(getTrieDirectory(projectDir), "RULES.md");
2068
+ const rulesPath = join6(getTrieDirectory(projectDir), "RULES.md");
926
2069
  try {
927
- if (existsSync3(rulesPath)) {
928
- return await readFile3(rulesPath, "utf-8");
2070
+ if (existsSync7(rulesPath)) {
2071
+ return await readFile5(rulesPath, "utf-8");
929
2072
  }
930
2073
  } catch {
931
2074
  }
@@ -933,10 +2076,10 @@ async function loadRules(workDir) {
933
2076
  }
934
2077
  async function loadTeamInfo(workDir) {
935
2078
  const projectDir = workDir || getWorkingDirectory(void 0, true);
936
- const teamPath = join3(getTrieDirectory(projectDir), "TEAM.md");
2079
+ const teamPath = join6(getTrieDirectory(projectDir), "TEAM.md");
937
2080
  try {
938
- if (existsSync3(teamPath)) {
939
- return await readFile3(teamPath, "utf-8");
2081
+ if (existsSync7(teamPath)) {
2082
+ return await readFile5(teamPath, "utf-8");
940
2083
  }
941
2084
  } catch {
942
2085
  }
@@ -1060,7 +2203,7 @@ function getBootstrapTemplate(stack) {
1060
2203
  if (stack.auth) lines.push(`- **Auth:** ${stack.auth}`);
1061
2204
  lines.push("", "## Recommended Actions", "", "### 1. Skills to Install", "Based on your stack, consider installing:", "```bash");
1062
2205
  lines.push(skillCommands || "# No specific skills detected - browse https://skills.sh");
1063
- lines.push("```", "", "### 2. Agents to Enable", `Your stack suggests these agents: ${agentList || "security, privacy, bugs"}`, "");
2206
+ lines.push("```", "", "### 2. Agents to Enable", `Your stack suggests these agents: ${agentList || "security, bugs"}`, "");
1064
2207
  lines.push("### 3. Configure Rules", "Add your coding standards to `.trie/RULES.md`.", "");
1065
2208
  lines.push("### 4. Run First Scan", "```bash", "trie scan", "```", "");
1066
2209
  lines.push("---", "", "**Delete this file after completing setup.** Run:", "```bash", "rm .trie/BOOTSTRAP.md", "```");
@@ -1091,28 +2234,28 @@ function formatFriendlyError(error) {
1091
2234
 
1092
2235
  // src/context/sync.ts
1093
2236
  import fs from "fs/promises";
1094
- import path3 from "path";
2237
+ import path4 from "path";
1095
2238
  var DEFAULT_JSON_NAME = "context.json";
1096
2239
  async function exportToJson(graph, targetPath) {
1097
2240
  const snapshot = await graph.getSnapshot();
1098
2241
  const json = JSON.stringify(snapshot, null, 2);
1099
- const outputPath = targetPath ?? path3.join(getTrieDirectory(graph.projectRoot), DEFAULT_JSON_NAME);
1100
- await fs.mkdir(path3.dirname(outputPath), { recursive: true });
2242
+ const outputPath = targetPath ?? path4.join(getTrieDirectory(graph.projectRoot), DEFAULT_JSON_NAME);
2243
+ await fs.mkdir(path4.dirname(outputPath), { recursive: true });
1101
2244
  await fs.writeFile(outputPath, json, "utf8");
1102
2245
  return json;
1103
2246
  }
1104
2247
  async function importFromJson(graph, json, sourcePath) {
1105
- const payload = json.trim().length > 0 ? json : await fs.readFile(sourcePath ?? path3.join(getTrieDirectory(graph.projectRoot), DEFAULT_JSON_NAME), "utf8");
2248
+ const payload = json.trim().length > 0 ? json : await fs.readFile(sourcePath ?? path4.join(getTrieDirectory(graph.projectRoot), DEFAULT_JSON_NAME), "utf8");
1106
2249
  const snapshot = JSON.parse(payload);
1107
2250
  await graph.applySnapshot(snapshot);
1108
2251
  }
1109
2252
 
1110
2253
  // src/context/incident-index.ts
1111
- import path5 from "path";
2254
+ import path6 from "path";
1112
2255
 
1113
2256
  // src/context/file-trie.ts
1114
2257
  import fs2 from "fs";
1115
- import path4 from "path";
2258
+ import path5 from "path";
1116
2259
  import { performance } from "perf_hooks";
1117
2260
  function normalizePath(filePath) {
1118
2261
  const normalized = filePath.replace(/\\/g, "/");
@@ -1176,9 +2319,9 @@ var FilePathTrie = class {
1176
2319
  incidentCount: Array.isArray(r.value) ? r.value.length : 0
1177
2320
  })).sort((a, b) => b.incidentCount - a.incidentCount).slice(0, limit);
1178
2321
  }
1179
- timeLookup(path7) {
2322
+ timeLookup(path8) {
1180
2323
  const start = performance.now();
1181
- this.getIncidents(path7);
2324
+ this.getIncidents(path8);
1182
2325
  return performance.now() - start;
1183
2326
  }
1184
2327
  toJSON() {
@@ -1191,7 +2334,7 @@ var FilePathTrie = class {
1191
2334
  persist() {
1192
2335
  if (!this.persistPath) return;
1193
2336
  try {
1194
- const dir = path4.dirname(this.persistPath);
2337
+ const dir = path5.dirname(this.persistPath);
1195
2338
  if (!fs2.existsSync(dir)) {
1196
2339
  fs2.mkdirSync(dir, { recursive: true });
1197
2340
  }
@@ -1210,7 +2353,7 @@ var IncidentIndex = class _IncidentIndex {
1210
2353
  this.graph = graph;
1211
2354
  this.projectRoot = projectRoot;
1212
2355
  this.trie = new FilePathTrie(
1213
- options?.persistPath ?? path5.join(getTrieDirectory(projectRoot), "incident-trie.json")
2356
+ options?.persistPath ?? path6.join(getTrieDirectory(projectRoot), "incident-trie.json")
1214
2357
  );
1215
2358
  }
1216
2359
  static async build(graph, projectRoot, options) {
@@ -1263,8 +2406,8 @@ var IncidentIndex = class _IncidentIndex {
1263
2406
  return Array.from(files);
1264
2407
  }
1265
2408
  normalizePath(filePath) {
1266
- const absolute = path5.isAbsolute(filePath) ? filePath : path5.join(this.projectRoot, filePath);
1267
- const relative = path5.relative(this.projectRoot, absolute);
2409
+ const absolute = path6.isAbsolute(filePath) ? filePath : path6.join(this.projectRoot, filePath);
2410
+ const relative = path6.relative(this.projectRoot, absolute);
1268
2411
  return relative.replace(/\\/g, "/");
1269
2412
  }
1270
2413
  };
@@ -1404,7 +2547,7 @@ var LearningSystem = class {
1404
2547
  };
1405
2548
 
1406
2549
  // src/guardian/learning-engine.ts
1407
- import path6 from "path";
2550
+ import path7 from "path";
1408
2551
  var LearningEngine = class {
1409
2552
  projectPath;
1410
2553
  graph;
@@ -1453,7 +2596,7 @@ var LearningEngine = class {
1453
2596
  }
1454
2597
  }
1455
2598
  if (issuesToStore.length > 0) {
1456
- const result = await storeIssues(issuesToStore, path6.basename(this.projectPath), this.projectPath);
2599
+ const result = await storeIssues(issuesToStore, path7.basename(this.projectPath), this.projectPath);
1457
2600
  return result.stored;
1458
2601
  }
1459
2602
  return 0;
@@ -1666,11 +2809,15 @@ var LinearIngester = class {
1666
2809
  };
1667
2810
 
1668
2811
  export {
2812
+ loadConfig,
2813
+ saveConfig,
1669
2814
  trackIssueOccurrence,
1670
2815
  recordBypass,
1671
2816
  shouldAutoFix,
1672
2817
  shouldBlockPush,
1673
2818
  getAutonomyConfig,
2819
+ getStagedChanges,
2820
+ getUncommittedChanges,
1674
2821
  perceiveCurrentChanges,
1675
2822
  reasonAboutChangesHumanReadable,
1676
2823
  loadBootstrapContext,
@@ -1690,4 +2837,4 @@ export {
1690
2837
  LearningEngine,
1691
2838
  LinearIngester
1692
2839
  };
1693
- //# sourceMappingURL=chunk-AZRCKBGF.js.map
2840
+ //# sourceMappingURL=chunk-FNCCZ3XB.js.map