@triedotdev/mcp 1.0.113 → 1.0.114
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auto-fix-apply-PCAHWLXF.js +10 -0
- package/dist/autonomy-config-O4H3Z7YV.js +30 -0
- package/dist/chunk-2GIAROBF.js +173 -0
- package/dist/chunk-2GIAROBF.js.map +1 -0
- package/dist/{chunk-33WL3D7A.js → chunk-2SIFK7OW.js} +7 -419
- package/dist/chunk-2SIFK7OW.js.map +1 -0
- package/dist/chunk-43X6JBEM.js +36 -0
- package/dist/chunk-43X6JBEM.js.map +1 -0
- package/dist/{chunk-2764KZZQ.js → chunk-4SBZXIMG.js} +133 -595
- package/dist/chunk-4SBZXIMG.js.map +1 -0
- package/dist/chunk-55DOQNHJ.js +772 -0
- package/dist/chunk-55DOQNHJ.js.map +1 -0
- package/dist/chunk-6LXSA2OZ.js +425 -0
- package/dist/chunk-6LXSA2OZ.js.map +1 -0
- package/dist/{chunk-SDS3UVFY.js → chunk-AOFYU6T3.js} +113 -559
- package/dist/chunk-AOFYU6T3.js.map +1 -0
- package/dist/{chunk-6QR6QZIX.js → chunk-D3EXBJE2.js} +25 -658
- package/dist/chunk-D3EXBJE2.js.map +1 -0
- package/dist/chunk-DJ2YAGHK.js +50 -0
- package/dist/chunk-DJ2YAGHK.js.map +1 -0
- package/dist/chunk-DRDEEF6G.js +328 -0
- package/dist/chunk-DRDEEF6G.js.map +1 -0
- package/dist/chunk-DZREHOGW.js +706 -0
- package/dist/chunk-DZREHOGW.js.map +1 -0
- package/dist/chunk-KRH642MT.js +947 -0
- package/dist/chunk-KRH642MT.js.map +1 -0
- package/dist/{chunk-QYOACM2C.js → chunk-MVNJPJBK.js} +22 -252
- package/dist/chunk-MVNJPJBK.js.map +1 -0
- package/dist/chunk-NS2MSZMB.js +394 -0
- package/dist/chunk-NS2MSZMB.js.map +1 -0
- package/dist/chunk-SWSK7ANT.js +340 -0
- package/dist/chunk-SWSK7ANT.js.map +1 -0
- package/dist/chunk-VRLMTOB6.js +566 -0
- package/dist/chunk-VRLMTOB6.js.map +1 -0
- package/dist/chunk-YR4BMGYO.js +130 -0
- package/dist/chunk-YR4BMGYO.js.map +1 -0
- package/dist/chunk-ZV2K6M7T.js +74 -0
- package/dist/chunk-ZV2K6M7T.js.map +1 -0
- package/dist/cli/main.js +107 -375
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/yolo-daemon.js +18 -8
- package/dist/cli/yolo-daemon.js.map +1 -1
- package/dist/client-7XZHCMD3.js +28 -0
- package/dist/client-7XZHCMD3.js.map +1 -0
- package/dist/{goal-manager-AP4LTE6U.js → goal-manager-LMS6ZJB7.js} +7 -3
- package/dist/goal-manager-LMS6ZJB7.js.map +1 -0
- package/dist/goal-validator-7UPLOVAZ.js +184 -0
- package/dist/goal-validator-7UPLOVAZ.js.map +1 -0
- package/dist/graph-U5JWSAB5.js +10 -0
- package/dist/graph-U5JWSAB5.js.map +1 -0
- package/dist/guardian-agent-EXP7APLC.js +25 -0
- package/dist/guardian-agent-EXP7APLC.js.map +1 -0
- package/dist/hypothesis-KGC3P54C.js +19 -0
- package/dist/hypothesis-KGC3P54C.js.map +1 -0
- package/dist/incident-index-PNIVT47T.js +11 -0
- package/dist/incident-index-PNIVT47T.js.map +1 -0
- package/dist/index.js +285 -16
- package/dist/index.js.map +1 -1
- package/dist/ledger-SR6OEBLO.js +15 -0
- package/dist/ledger-SR6OEBLO.js.map +1 -0
- package/dist/output-manager-BOTMXSND.js +13 -0
- package/dist/output-manager-BOTMXSND.js.map +1 -0
- package/dist/pattern-discovery-F7LU5K6E.js +8 -0
- package/dist/pattern-discovery-F7LU5K6E.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-2764KZZQ.js.map +0 -1
- package/dist/chunk-33WL3D7A.js.map +0 -1
- package/dist/chunk-6JPPYG7F.js +0 -1813
- package/dist/chunk-6JPPYG7F.js.map +0 -1
- package/dist/chunk-6QR6QZIX.js.map +0 -1
- package/dist/chunk-QYOACM2C.js.map +0 -1
- package/dist/chunk-SDS3UVFY.js.map +0 -1
- package/dist/guardian-agent-XEYNG7RH.js +0 -18
- /package/dist/{goal-manager-AP4LTE6U.js.map → auto-fix-apply-PCAHWLXF.js.map} +0 -0
- /package/dist/{guardian-agent-XEYNG7RH.js.map → autonomy-config-O4H3Z7YV.js.map} +0 -0
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "./chunk-
|
|
2
|
+
tryGetClient
|
|
3
|
+
} from "./chunk-SWSK7ANT.js";
|
|
4
4
|
import {
|
|
5
|
-
BackupManager,
|
|
6
|
-
GlobalPatternsIndexSchema,
|
|
7
|
-
atomicWriteJSON,
|
|
8
|
-
safeParseAndValidate,
|
|
9
5
|
searchIssues
|
|
10
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-55DOQNHJ.js";
|
|
11
7
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
BackupManager,
|
|
9
|
+
GlobalPatternsIndexSchema,
|
|
10
|
+
safeParseAndValidate
|
|
11
|
+
} from "./chunk-KRH642MT.js";
|
|
15
12
|
import {
|
|
16
13
|
scanForVulnerabilities
|
|
17
14
|
} from "./chunk-F4NJ4CBP.js";
|
|
15
|
+
import {
|
|
16
|
+
scanForVibeCodeIssues
|
|
17
|
+
} from "./chunk-IXO4G4D3.js";
|
|
18
|
+
import {
|
|
19
|
+
atomicWriteJSON
|
|
20
|
+
} from "./chunk-43X6JBEM.js";
|
|
21
|
+
import {
|
|
22
|
+
getTrieDirectory
|
|
23
|
+
} from "./chunk-R4AAPFXC.js";
|
|
18
24
|
|
|
19
25
|
// src/memory/global-memory.ts
|
|
20
26
|
import { mkdir, writeFile, readFile, readdir } from "fs/promises";
|
|
@@ -266,256 +272,9 @@ function sanitizeName(name) {
|
|
|
266
272
|
return name.replace(/[^a-zA-Z0-9-_]/g, "-").toLowerCase();
|
|
267
273
|
}
|
|
268
274
|
|
|
269
|
-
// src/ai/client.ts
|
|
270
|
-
import Anthropic from "@anthropic-ai/sdk";
|
|
271
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync as existsSync2 } from "fs";
|
|
272
|
-
import { execSync } from "child_process";
|
|
273
|
-
import { join as join2 } from "path";
|
|
274
|
-
var clientInstance = null;
|
|
275
|
-
var apiKeyChecked = false;
|
|
276
|
-
var apiKeyAvailable = false;
|
|
277
|
-
function isAIAvailable() {
|
|
278
|
-
if (!apiKeyChecked) {
|
|
279
|
-
checkAPIKey();
|
|
280
|
-
}
|
|
281
|
-
return apiKeyAvailable;
|
|
282
|
-
}
|
|
283
|
-
function getKeyFromKeychain() {
|
|
284
|
-
if (process.platform !== "darwin") return null;
|
|
285
|
-
try {
|
|
286
|
-
const result = execSync(
|
|
287
|
-
'security find-generic-password -a "trie" -s "anthropic-api-key" -w 2>/dev/null',
|
|
288
|
-
{ encoding: "utf-8" }
|
|
289
|
-
).trim();
|
|
290
|
-
return result.length > 10 ? result : null;
|
|
291
|
-
} catch {
|
|
292
|
-
return null;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
function saveKeyToKeychain(key) {
|
|
296
|
-
if (process.platform !== "darwin") return false;
|
|
297
|
-
try {
|
|
298
|
-
try {
|
|
299
|
-
execSync('security delete-generic-password -a "trie" -s "anthropic-api-key" 2>/dev/null');
|
|
300
|
-
} catch {
|
|
301
|
-
}
|
|
302
|
-
execSync(`security add-generic-password -a "trie" -s "anthropic-api-key" -w "${key.replace(/"/g, '\\"')}"`);
|
|
303
|
-
return true;
|
|
304
|
-
} catch {
|
|
305
|
-
return false;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
function setAPIKey(key) {
|
|
309
|
-
process.env.ANTHROPIC_API_KEY = key;
|
|
310
|
-
clientInstance = null;
|
|
311
|
-
apiKeyChecked = true;
|
|
312
|
-
apiKeyAvailable = true;
|
|
313
|
-
if (saveKeyToKeychain(key)) {
|
|
314
|
-
return { saved: true, method: "keychain" };
|
|
315
|
-
}
|
|
316
|
-
try {
|
|
317
|
-
const workDir = getWorkingDirectory(void 0, true);
|
|
318
|
-
const trieDir = getTrieDirectory(workDir);
|
|
319
|
-
const configPath = join2(trieDir, "config.json");
|
|
320
|
-
let config = {};
|
|
321
|
-
if (existsSync2(configPath)) {
|
|
322
|
-
config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
323
|
-
}
|
|
324
|
-
if (!config.apiKeys || typeof config.apiKeys !== "object") config.apiKeys = {};
|
|
325
|
-
config.apiKeys.anthropic = key;
|
|
326
|
-
mkdirSync(trieDir, { recursive: true });
|
|
327
|
-
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
328
|
-
} catch {
|
|
329
|
-
}
|
|
330
|
-
return { saved: true, method: "config" };
|
|
331
|
-
}
|
|
332
|
-
function checkAPIKey() {
|
|
333
|
-
apiKeyChecked = true;
|
|
334
|
-
const envApiKey = process.env.ANTHROPIC_API_KEY;
|
|
335
|
-
if (envApiKey && envApiKey.length > 10) {
|
|
336
|
-
apiKeyAvailable = true;
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
const keychainKey = getKeyFromKeychain();
|
|
340
|
-
if (keychainKey) {
|
|
341
|
-
process.env.ANTHROPIC_API_KEY = keychainKey;
|
|
342
|
-
apiKeyAvailable = true;
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
try {
|
|
346
|
-
const workDir = getWorkingDirectory(void 0, true);
|
|
347
|
-
const configPath = join2(getTrieDirectory(workDir), "config.json");
|
|
348
|
-
if (existsSync2(configPath)) {
|
|
349
|
-
const configContent = readFileSync(configPath, "utf-8");
|
|
350
|
-
const config = JSON.parse(configContent);
|
|
351
|
-
if (config.apiKeys?.anthropic && config.apiKeys.anthropic.length > 10) {
|
|
352
|
-
process.env.ANTHROPIC_API_KEY = config.apiKeys.anthropic;
|
|
353
|
-
apiKeyAvailable = true;
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
} catch {
|
|
358
|
-
}
|
|
359
|
-
try {
|
|
360
|
-
const workDir = getWorkingDirectory(void 0, true);
|
|
361
|
-
const envFiles = [".env", ".env.local", ".env.production"];
|
|
362
|
-
for (const envFile of envFiles) {
|
|
363
|
-
const envPath = join2(workDir, envFile);
|
|
364
|
-
if (existsSync2(envPath)) {
|
|
365
|
-
const envContent = readFileSync(envPath, "utf-8");
|
|
366
|
-
const lines = envContent.split("\n");
|
|
367
|
-
for (const line of lines) {
|
|
368
|
-
const match = line.match(/^\s*ANTHROPIC_API_KEY\s*=\s*(.+)$/);
|
|
369
|
-
if (match && match[1]) {
|
|
370
|
-
const key = match[1].trim().replace(/^["']|["']$/g, "");
|
|
371
|
-
if (key.length > 10) {
|
|
372
|
-
process.env.ANTHROPIC_API_KEY = key;
|
|
373
|
-
apiKeyAvailable = true;
|
|
374
|
-
return;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
} catch {
|
|
381
|
-
}
|
|
382
|
-
apiKeyAvailable = false;
|
|
383
|
-
}
|
|
384
|
-
function tryGetClient() {
|
|
385
|
-
if (!isAIAvailable()) {
|
|
386
|
-
return null;
|
|
387
|
-
}
|
|
388
|
-
if (!clientInstance) {
|
|
389
|
-
clientInstance = new Anthropic();
|
|
390
|
-
}
|
|
391
|
-
return clientInstance;
|
|
392
|
-
}
|
|
393
|
-
async function runAIAnalysis(request) {
|
|
394
|
-
const client = tryGetClient();
|
|
395
|
-
if (!client) {
|
|
396
|
-
return {
|
|
397
|
-
success: false,
|
|
398
|
-
content: "",
|
|
399
|
-
error: "AI not available - ANTHROPIC_API_KEY not set"
|
|
400
|
-
};
|
|
401
|
-
}
|
|
402
|
-
try {
|
|
403
|
-
const response = await client.messages.create({
|
|
404
|
-
model: "claude-sonnet-4-20250514",
|
|
405
|
-
max_tokens: request.maxTokens || 4096,
|
|
406
|
-
temperature: request.temperature ?? 0.3,
|
|
407
|
-
system: request.systemPrompt,
|
|
408
|
-
messages: [
|
|
409
|
-
{
|
|
410
|
-
role: "user",
|
|
411
|
-
content: request.userPrompt
|
|
412
|
-
}
|
|
413
|
-
]
|
|
414
|
-
});
|
|
415
|
-
const textContent = response.content.filter((block) => block.type === "text").map((block) => block.text).join("\n");
|
|
416
|
-
return {
|
|
417
|
-
success: true,
|
|
418
|
-
content: textContent,
|
|
419
|
-
tokensUsed: {
|
|
420
|
-
input: response.usage.input_tokens,
|
|
421
|
-
output: response.usage.output_tokens
|
|
422
|
-
}
|
|
423
|
-
};
|
|
424
|
-
} catch (error) {
|
|
425
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
426
|
-
if (errorMessage.includes("authentication") || errorMessage.includes("API key")) {
|
|
427
|
-
return {
|
|
428
|
-
success: false,
|
|
429
|
-
content: "",
|
|
430
|
-
error: "Invalid API key. Check your ANTHROPIC_API_KEY."
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
if (errorMessage.includes("rate limit")) {
|
|
434
|
-
return {
|
|
435
|
-
success: false,
|
|
436
|
-
content: "",
|
|
437
|
-
error: "Rate limited. Try again in a moment."
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
return {
|
|
441
|
-
success: false,
|
|
442
|
-
content: "",
|
|
443
|
-
error: `AI analysis failed: ${errorMessage}`
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
async function runAIWithTools(request) {
|
|
448
|
-
const client = tryGetClient();
|
|
449
|
-
if (!client) {
|
|
450
|
-
return { success: false, content: "", error: "AI not available - ANTHROPIC_API_KEY not set" };
|
|
451
|
-
}
|
|
452
|
-
const maxRounds = request.maxToolRounds ?? 5;
|
|
453
|
-
const messages = [...request.messages];
|
|
454
|
-
const allToolCalls = [];
|
|
455
|
-
try {
|
|
456
|
-
for (let round = 0; round < maxRounds; round++) {
|
|
457
|
-
const response = await client.messages.create({
|
|
458
|
-
model: "claude-sonnet-4-20250514",
|
|
459
|
-
max_tokens: request.maxTokens || 4096,
|
|
460
|
-
temperature: 0.3,
|
|
461
|
-
system: request.systemPrompt,
|
|
462
|
-
messages,
|
|
463
|
-
tools: request.tools
|
|
464
|
-
});
|
|
465
|
-
const toolUseBlocks = response.content.filter(
|
|
466
|
-
(b) => b.type === "tool_use"
|
|
467
|
-
);
|
|
468
|
-
const textBlocks = response.content.filter(
|
|
469
|
-
(b) => b.type === "text"
|
|
470
|
-
);
|
|
471
|
-
if (toolUseBlocks.length === 0) {
|
|
472
|
-
const result2 = {
|
|
473
|
-
success: true,
|
|
474
|
-
content: textBlocks.map((b) => b.text).join("\n")
|
|
475
|
-
};
|
|
476
|
-
if (allToolCalls.length > 0) result2.toolCalls = allToolCalls;
|
|
477
|
-
return result2;
|
|
478
|
-
}
|
|
479
|
-
messages.push({ role: "assistant", content: response.content });
|
|
480
|
-
const toolResults = [];
|
|
481
|
-
for (const block of toolUseBlocks) {
|
|
482
|
-
const input = block.input ?? {};
|
|
483
|
-
allToolCalls.push({ name: block.name, input });
|
|
484
|
-
let resultText;
|
|
485
|
-
let isError = false;
|
|
486
|
-
try {
|
|
487
|
-
resultText = await request.executeTool(block.name, input);
|
|
488
|
-
} catch (err) {
|
|
489
|
-
resultText = `Tool error: ${err instanceof Error ? err.message : String(err)}`;
|
|
490
|
-
isError = true;
|
|
491
|
-
}
|
|
492
|
-
toolResults.push({
|
|
493
|
-
type: "tool_result",
|
|
494
|
-
tool_use_id: block.id,
|
|
495
|
-
content: resultText,
|
|
496
|
-
is_error: isError
|
|
497
|
-
});
|
|
498
|
-
}
|
|
499
|
-
messages.push({ role: "user", content: toolResults });
|
|
500
|
-
if (response.stop_reason === "end_turn") {
|
|
501
|
-
const text = textBlocks.map((b) => b.text).join("\n");
|
|
502
|
-
const result2 = { success: true, content: text || "Done." };
|
|
503
|
-
if (allToolCalls.length > 0) result2.toolCalls = allToolCalls;
|
|
504
|
-
return result2;
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
const result = { success: true, content: "Reached maximum tool rounds." };
|
|
508
|
-
if (allToolCalls.length > 0) result.toolCalls = allToolCalls;
|
|
509
|
-
return result;
|
|
510
|
-
} catch (error) {
|
|
511
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
512
|
-
return { success: false, content: "", error: `AI tool-use failed: ${errorMessage}` };
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
|
|
516
275
|
// src/storage/tiered-storage.ts
|
|
517
276
|
import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
518
|
-
import { join as
|
|
277
|
+
import { join as join2 } from "path";
|
|
519
278
|
import { createHash as createHash2 } from "crypto";
|
|
520
279
|
import Database from "better-sqlite3";
|
|
521
280
|
var TieredStorage = class {
|
|
@@ -530,10 +289,10 @@ var TieredStorage = class {
|
|
|
530
289
|
*/
|
|
531
290
|
async initialize() {
|
|
532
291
|
const trieDir = getTrieDirectory(this.workDir);
|
|
533
|
-
await mkdir2(
|
|
534
|
-
await mkdir2(
|
|
535
|
-
await mkdir2(
|
|
536
|
-
const dbPath =
|
|
292
|
+
await mkdir2(join2(trieDir, "hot"), { recursive: true });
|
|
293
|
+
await mkdir2(join2(trieDir, "warm"), { recursive: true });
|
|
294
|
+
await mkdir2(join2(trieDir, "cold"), { recursive: true });
|
|
295
|
+
const dbPath = join2(trieDir, "warm", "decisions.db");
|
|
537
296
|
this.warmDb = new Database(dbPath);
|
|
538
297
|
this.warmDb.exec(`
|
|
539
298
|
CREATE TABLE IF NOT EXISTS decisions (
|
|
@@ -815,8 +574,8 @@ var TieredStorage = class {
|
|
|
815
574
|
const cutoffDate = /* @__PURE__ */ new Date();
|
|
816
575
|
cutoffDate.setDate(cutoffDate.getDate() - olderThanDays);
|
|
817
576
|
const cutoff = cutoffDate.toISOString();
|
|
818
|
-
const coldDir =
|
|
819
|
-
const archivePath =
|
|
577
|
+
const coldDir = join2(getTrieDirectory(this.workDir), "cold");
|
|
578
|
+
const archivePath = join2(coldDir, `archive-${Date.now()}.json`);
|
|
820
579
|
const decisions = this.warmDb.prepare("SELECT * FROM decisions WHERE timestamp < ? AND accessCount < 3").all(cutoff);
|
|
821
580
|
const facts = this.warmDb.prepare("SELECT * FROM facts WHERE timestamp < ? AND accessCount < 3").all(cutoff);
|
|
822
581
|
const blockers = this.warmDb.prepare("SELECT * FROM blockers WHERE timestamp < ? AND resolvedAt IS NOT NULL").all(cutoff);
|
|
@@ -1031,392 +790,6 @@ var GotchaPredictor = class {
|
|
|
1031
790
|
}
|
|
1032
791
|
};
|
|
1033
792
|
|
|
1034
|
-
// src/context/graph.ts
|
|
1035
|
-
import crypto from "crypto";
|
|
1036
|
-
import path3 from "path";
|
|
1037
|
-
|
|
1038
|
-
// src/context/store.ts
|
|
1039
|
-
import Database2 from "better-sqlite3";
|
|
1040
|
-
import fs2 from "fs";
|
|
1041
|
-
import path2 from "path";
|
|
1042
|
-
var ContextStore = class {
|
|
1043
|
-
db;
|
|
1044
|
-
dbFilePath;
|
|
1045
|
-
constructor(projectPath, dbFilePath) {
|
|
1046
|
-
this.dbFilePath = dbFilePath ?? path2.join(getTrieDirectory(projectPath), "context.db");
|
|
1047
|
-
this.ensureDirectory();
|
|
1048
|
-
this.db = new Database2(this.dbFilePath);
|
|
1049
|
-
this.configure();
|
|
1050
|
-
this.prepareSchema();
|
|
1051
|
-
}
|
|
1052
|
-
get databasePath() {
|
|
1053
|
-
return this.dbFilePath;
|
|
1054
|
-
}
|
|
1055
|
-
addNode(node) {
|
|
1056
|
-
const stmt = this.db.prepare(
|
|
1057
|
-
`INSERT INTO nodes (id, type, data, created_at, updated_at)
|
|
1058
|
-
VALUES (@id, @type, @data, @created_at, @updated_at)`
|
|
1059
|
-
);
|
|
1060
|
-
stmt.run({
|
|
1061
|
-
id: node.id,
|
|
1062
|
-
type: node.type,
|
|
1063
|
-
data: JSON.stringify(node.data),
|
|
1064
|
-
created_at: node.created_at,
|
|
1065
|
-
updated_at: node.updated_at
|
|
1066
|
-
});
|
|
1067
|
-
return node;
|
|
1068
|
-
}
|
|
1069
|
-
upsertNode(node) {
|
|
1070
|
-
const stmt = this.db.prepare(
|
|
1071
|
-
`INSERT INTO nodes (id, type, data, created_at, updated_at)
|
|
1072
|
-
VALUES (@id, @type, @data, @created_at, @updated_at)
|
|
1073
|
-
ON CONFLICT(id) DO UPDATE SET
|
|
1074
|
-
type=excluded.type,
|
|
1075
|
-
data=excluded.data,
|
|
1076
|
-
updated_at=excluded.updated_at`
|
|
1077
|
-
);
|
|
1078
|
-
stmt.run({
|
|
1079
|
-
id: node.id,
|
|
1080
|
-
type: node.type,
|
|
1081
|
-
data: JSON.stringify(node.data),
|
|
1082
|
-
created_at: node.created_at,
|
|
1083
|
-
updated_at: node.updated_at
|
|
1084
|
-
});
|
|
1085
|
-
return node;
|
|
1086
|
-
}
|
|
1087
|
-
getNode(id) {
|
|
1088
|
-
const row = this.db.prepare("SELECT * FROM nodes WHERE id = ?").get(id);
|
|
1089
|
-
return row ? this.mapNodeRow(row) : null;
|
|
1090
|
-
}
|
|
1091
|
-
getNodeByType(type, id) {
|
|
1092
|
-
const row = this.db.prepare("SELECT * FROM nodes WHERE id = ? AND type = ?").get(id, type);
|
|
1093
|
-
return row ? this.mapNodeRow(row) : null;
|
|
1094
|
-
}
|
|
1095
|
-
updateNode(id, updates, updatedAt) {
|
|
1096
|
-
const existing = this.getNode(id);
|
|
1097
|
-
if (!existing) {
|
|
1098
|
-
return null;
|
|
1099
|
-
}
|
|
1100
|
-
const merged = {
|
|
1101
|
-
...existing,
|
|
1102
|
-
data: { ...existing.data, ...updates },
|
|
1103
|
-
updated_at: updatedAt
|
|
1104
|
-
};
|
|
1105
|
-
this.db.prepare(
|
|
1106
|
-
`UPDATE nodes SET data = @data, updated_at = @updated_at
|
|
1107
|
-
WHERE id = @id`
|
|
1108
|
-
).run({
|
|
1109
|
-
id,
|
|
1110
|
-
data: JSON.stringify(merged.data),
|
|
1111
|
-
updated_at: merged.updated_at
|
|
1112
|
-
});
|
|
1113
|
-
return merged;
|
|
1114
|
-
}
|
|
1115
|
-
deleteNode(id) {
|
|
1116
|
-
const deleteEdges = this.db.prepare("DELETE FROM edges WHERE from_id = ? OR to_id = ?");
|
|
1117
|
-
const deleteNodeStmt = this.db.prepare("DELETE FROM nodes WHERE id = ?");
|
|
1118
|
-
const transaction = this.db.transaction((nodeId) => {
|
|
1119
|
-
deleteEdges.run(nodeId, nodeId);
|
|
1120
|
-
deleteNodeStmt.run(nodeId);
|
|
1121
|
-
});
|
|
1122
|
-
transaction(id);
|
|
1123
|
-
}
|
|
1124
|
-
listNodes() {
|
|
1125
|
-
const rows = this.db.prepare("SELECT * FROM nodes").all();
|
|
1126
|
-
return rows.map((row) => this.mapNodeRow(row));
|
|
1127
|
-
}
|
|
1128
|
-
findNodesByType(type) {
|
|
1129
|
-
const rows = this.db.prepare("SELECT * FROM nodes WHERE type = ?").all(type);
|
|
1130
|
-
return rows.map((row) => this.mapNodeRow(row));
|
|
1131
|
-
}
|
|
1132
|
-
addEdge(edge) {
|
|
1133
|
-
const stmt = this.db.prepare(
|
|
1134
|
-
`INSERT INTO edges (id, from_id, to_id, type, weight, metadata, created_at)
|
|
1135
|
-
VALUES (@id, @from_id, @to_id, @type, @weight, @metadata, @created_at)`
|
|
1136
|
-
);
|
|
1137
|
-
stmt.run({
|
|
1138
|
-
id: edge.id,
|
|
1139
|
-
from_id: edge.from_id,
|
|
1140
|
-
to_id: edge.to_id,
|
|
1141
|
-
type: edge.type,
|
|
1142
|
-
weight: edge.weight,
|
|
1143
|
-
metadata: JSON.stringify(edge.metadata ?? {}),
|
|
1144
|
-
created_at: edge.created_at
|
|
1145
|
-
});
|
|
1146
|
-
return edge;
|
|
1147
|
-
}
|
|
1148
|
-
upsertEdge(edge) {
|
|
1149
|
-
const stmt = this.db.prepare(
|
|
1150
|
-
`INSERT INTO edges (id, from_id, to_id, type, weight, metadata, created_at)
|
|
1151
|
-
VALUES (@id, @from_id, @to_id, @type, @weight, @metadata, @created_at)
|
|
1152
|
-
ON CONFLICT(id) DO UPDATE SET
|
|
1153
|
-
from_id=excluded.from_id,
|
|
1154
|
-
to_id=excluded.to_id,
|
|
1155
|
-
type=excluded.type,
|
|
1156
|
-
weight=excluded.weight,
|
|
1157
|
-
metadata=excluded.metadata`
|
|
1158
|
-
);
|
|
1159
|
-
stmt.run({
|
|
1160
|
-
id: edge.id,
|
|
1161
|
-
from_id: edge.from_id,
|
|
1162
|
-
to_id: edge.to_id,
|
|
1163
|
-
type: edge.type,
|
|
1164
|
-
weight: edge.weight,
|
|
1165
|
-
metadata: JSON.stringify(edge.metadata ?? {}),
|
|
1166
|
-
created_at: edge.created_at
|
|
1167
|
-
});
|
|
1168
|
-
return edge;
|
|
1169
|
-
}
|
|
1170
|
-
getEdge(id) {
|
|
1171
|
-
const row = this.db.prepare("SELECT * FROM edges WHERE id = ?").get(id);
|
|
1172
|
-
return row ? this.mapEdgeRow(row) : null;
|
|
1173
|
-
}
|
|
1174
|
-
getEdges(nodeId, direction = "both") {
|
|
1175
|
-
let rows;
|
|
1176
|
-
if (direction === "in") {
|
|
1177
|
-
rows = this.db.prepare("SELECT * FROM edges WHERE to_id = ?").all(nodeId);
|
|
1178
|
-
} else if (direction === "out") {
|
|
1179
|
-
rows = this.db.prepare("SELECT * FROM edges WHERE from_id = ?").all(nodeId);
|
|
1180
|
-
} else {
|
|
1181
|
-
rows = this.db.prepare("SELECT * FROM edges WHERE from_id = ? OR to_id = ?").all(nodeId, nodeId);
|
|
1182
|
-
}
|
|
1183
|
-
return rows.map((row) => this.mapEdgeRow(row));
|
|
1184
|
-
}
|
|
1185
|
-
listEdges() {
|
|
1186
|
-
const rows = this.db.prepare("SELECT * FROM edges").all();
|
|
1187
|
-
return rows.map((row) => this.mapEdgeRow(row));
|
|
1188
|
-
}
|
|
1189
|
-
deleteEdge(id) {
|
|
1190
|
-
this.db.prepare("DELETE FROM edges WHERE id = ?").run(id);
|
|
1191
|
-
}
|
|
1192
|
-
close() {
|
|
1193
|
-
this.db.close();
|
|
1194
|
-
}
|
|
1195
|
-
ensureDirectory() {
|
|
1196
|
-
fs2.mkdirSync(path2.dirname(this.dbFilePath), { recursive: true });
|
|
1197
|
-
}
|
|
1198
|
-
configure() {
|
|
1199
|
-
this.db.pragma("journal_mode = WAL");
|
|
1200
|
-
this.db.pragma("busy_timeout = 5000");
|
|
1201
|
-
this.db.pragma("synchronous = NORMAL");
|
|
1202
|
-
}
|
|
1203
|
-
prepareSchema() {
|
|
1204
|
-
this.db.exec(`
|
|
1205
|
-
CREATE TABLE IF NOT EXISTS nodes (
|
|
1206
|
-
id TEXT PRIMARY KEY,
|
|
1207
|
-
type TEXT NOT NULL,
|
|
1208
|
-
data TEXT NOT NULL,
|
|
1209
|
-
created_at TEXT NOT NULL,
|
|
1210
|
-
updated_at TEXT NOT NULL
|
|
1211
|
-
);
|
|
1212
|
-
|
|
1213
|
-
CREATE TABLE IF NOT EXISTS edges (
|
|
1214
|
-
id TEXT PRIMARY KEY,
|
|
1215
|
-
from_id TEXT NOT NULL,
|
|
1216
|
-
to_id TEXT NOT NULL,
|
|
1217
|
-
type TEXT NOT NULL,
|
|
1218
|
-
weight REAL NOT NULL DEFAULT 1,
|
|
1219
|
-
metadata TEXT DEFAULT '{}',
|
|
1220
|
-
created_at TEXT NOT NULL
|
|
1221
|
-
);
|
|
1222
|
-
|
|
1223
|
-
CREATE INDEX IF NOT EXISTS idx_nodes_type ON nodes(type);
|
|
1224
|
-
CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(from_id);
|
|
1225
|
-
CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(to_id);
|
|
1226
|
-
CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(type);
|
|
1227
|
-
`);
|
|
1228
|
-
}
|
|
1229
|
-
mapNodeRow(row) {
|
|
1230
|
-
return {
|
|
1231
|
-
id: row.id,
|
|
1232
|
-
type: row.type,
|
|
1233
|
-
data: JSON.parse(row.data),
|
|
1234
|
-
created_at: row.created_at,
|
|
1235
|
-
updated_at: row.updated_at
|
|
1236
|
-
};
|
|
1237
|
-
}
|
|
1238
|
-
mapEdgeRow(row) {
|
|
1239
|
-
return {
|
|
1240
|
-
id: row.id,
|
|
1241
|
-
from_id: row.from_id,
|
|
1242
|
-
to_id: row.to_id,
|
|
1243
|
-
type: row.type,
|
|
1244
|
-
weight: row.weight,
|
|
1245
|
-
created_at: row.created_at,
|
|
1246
|
-
metadata: row.metadata ? JSON.parse(row.metadata) : {}
|
|
1247
|
-
};
|
|
1248
|
-
}
|
|
1249
|
-
};
|
|
1250
|
-
|
|
1251
|
-
// src/context/graph.ts
|
|
1252
|
-
var ContextGraph = class {
|
|
1253
|
-
store;
|
|
1254
|
-
projectPath;
|
|
1255
|
-
constructor(projectPath, dbPath, store) {
|
|
1256
|
-
this.projectPath = projectPath;
|
|
1257
|
-
this.store = store ?? new ContextStore(projectPath, dbPath);
|
|
1258
|
-
}
|
|
1259
|
-
get projectRoot() {
|
|
1260
|
-
return this.projectPath;
|
|
1261
|
-
}
|
|
1262
|
-
async addNode(type, data) {
|
|
1263
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1264
|
-
const id = this.generateNodeId(type, data);
|
|
1265
|
-
const node = {
|
|
1266
|
-
id,
|
|
1267
|
-
type,
|
|
1268
|
-
data,
|
|
1269
|
-
created_at: now,
|
|
1270
|
-
updated_at: now
|
|
1271
|
-
};
|
|
1272
|
-
this.store.addNode(node);
|
|
1273
|
-
return node;
|
|
1274
|
-
}
|
|
1275
|
-
async getNode(type, id) {
|
|
1276
|
-
return this.store.getNodeByType(type, id);
|
|
1277
|
-
}
|
|
1278
|
-
async updateNode(type, id, updates) {
|
|
1279
|
-
const updated = this.store.updateNode(id, updates, (/* @__PURE__ */ new Date()).toISOString());
|
|
1280
|
-
if (updated && updated.type !== type) {
|
|
1281
|
-
throw new Error(`Type mismatch for node ${id}: expected ${type} but found ${updated.type}`);
|
|
1282
|
-
}
|
|
1283
|
-
}
|
|
1284
|
-
async deleteNode(_type, id) {
|
|
1285
|
-
this.store.deleteNode(id);
|
|
1286
|
-
}
|
|
1287
|
-
async addEdge(fromId, toId, type, metadata = {}, weight = 1) {
|
|
1288
|
-
const edge = {
|
|
1289
|
-
id: crypto.randomUUID(),
|
|
1290
|
-
from_id: fromId,
|
|
1291
|
-
to_id: toId,
|
|
1292
|
-
type,
|
|
1293
|
-
weight,
|
|
1294
|
-
metadata,
|
|
1295
|
-
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1296
|
-
};
|
|
1297
|
-
this.store.addEdge(edge);
|
|
1298
|
-
return edge;
|
|
1299
|
-
}
|
|
1300
|
-
async getEdges(nodeId, direction = "both") {
|
|
1301
|
-
return this.store.getEdges(nodeId, direction);
|
|
1302
|
-
}
|
|
1303
|
-
async getIncidentsForFile(filePath) {
|
|
1304
|
-
const fileNode = this.findFileNode(filePath);
|
|
1305
|
-
if (!fileNode) return [];
|
|
1306
|
-
const incidents = /* @__PURE__ */ new Map();
|
|
1307
|
-
const affectEdges = this.store.getEdges(fileNode.id, "in").filter((edge) => edge.type === "affects");
|
|
1308
|
-
for (const edge of affectEdges) {
|
|
1309
|
-
const changeId = edge.from_id;
|
|
1310
|
-
const leadEdges = this.store.getEdges(changeId, "out").filter((e) => e.type === "leadTo");
|
|
1311
|
-
const causedByEdges = this.store.getEdges(changeId, "in").filter((e) => e.type === "causedBy");
|
|
1312
|
-
for (const le of leadEdges) {
|
|
1313
|
-
const incident = this.store.getNodeByType("incident", le.to_id);
|
|
1314
|
-
if (incident) incidents.set(incident.id, incident);
|
|
1315
|
-
}
|
|
1316
|
-
for (const ce of causedByEdges) {
|
|
1317
|
-
const incident = this.store.getNodeByType("incident", ce.from_id);
|
|
1318
|
-
if (incident) incidents.set(incident.id, incident);
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
return Array.from(incidents.values());
|
|
1322
|
-
}
|
|
1323
|
-
async getPatternsForFile(filePath) {
|
|
1324
|
-
const normalized = this.normalizePath(filePath);
|
|
1325
|
-
const nodes = this.store.findNodesByType("pattern");
|
|
1326
|
-
return nodes.filter(
|
|
1327
|
-
(node) => node.data.appliesTo.some((pattern) => normalized.includes(pattern) || filePath.includes(pattern))
|
|
1328
|
-
);
|
|
1329
|
-
}
|
|
1330
|
-
async getRecentChanges(limit) {
|
|
1331
|
-
const nodes = this.store.findNodesByType("change");
|
|
1332
|
-
return nodes.sort((a, b) => new Date(b.data.timestamp).getTime() - new Date(a.data.timestamp).getTime()).slice(0, limit);
|
|
1333
|
-
}
|
|
1334
|
-
async calculateFileRisk(filePath) {
|
|
1335
|
-
const fileNode = this.findFileNode(filePath);
|
|
1336
|
-
if (!fileNode) return "low";
|
|
1337
|
-
const incidentScore = Math.min(fileNode.data.incidentCount * 2, 6);
|
|
1338
|
-
const changeScore = Math.min(fileNode.data.changeCount, 4);
|
|
1339
|
-
const baseScore = this.riskLevelToScore(fileNode.data.riskLevel);
|
|
1340
|
-
const total = baseScore + incidentScore + changeScore;
|
|
1341
|
-
if (total >= 10) return "critical";
|
|
1342
|
-
if (total >= 7) return "high";
|
|
1343
|
-
if (total >= 4) return "medium";
|
|
1344
|
-
return "low";
|
|
1345
|
-
}
|
|
1346
|
-
async listNodes() {
|
|
1347
|
-
return this.store.listNodes();
|
|
1348
|
-
}
|
|
1349
|
-
async listEdges() {
|
|
1350
|
-
return this.store.listEdges();
|
|
1351
|
-
}
|
|
1352
|
-
async deleteEdge(id) {
|
|
1353
|
-
this.store.deleteEdge(id);
|
|
1354
|
-
}
|
|
1355
|
-
async getSnapshot() {
|
|
1356
|
-
return {
|
|
1357
|
-
nodes: this.store.listNodes(),
|
|
1358
|
-
edges: this.store.listEdges(),
|
|
1359
|
-
exported_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1360
|
-
};
|
|
1361
|
-
}
|
|
1362
|
-
async applySnapshot(snapshot) {
|
|
1363
|
-
for (const node of snapshot.nodes) {
|
|
1364
|
-
const existing = this.store.getNode(node.id);
|
|
1365
|
-
if (!existing || this.isNewer(node.updated_at, existing.updated_at)) {
|
|
1366
|
-
this.store.upsertNode(node);
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
for (const edge of snapshot.edges) {
|
|
1370
|
-
const existing = this.store.getEdge(edge.id);
|
|
1371
|
-
if (!existing) {
|
|
1372
|
-
this.store.upsertEdge(edge);
|
|
1373
|
-
}
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
generateNodeId(type, data) {
|
|
1377
|
-
if (type === "file") {
|
|
1378
|
-
const fileData = data;
|
|
1379
|
-
return this.normalizePath(fileData.path);
|
|
1380
|
-
}
|
|
1381
|
-
if (type === "change") {
|
|
1382
|
-
const changeData = data;
|
|
1383
|
-
if (changeData.commitHash) {
|
|
1384
|
-
return changeData.commitHash;
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
|
-
if (type === "linear-ticket") {
|
|
1388
|
-
const ticketData = data;
|
|
1389
|
-
return `linear:${ticketData.ticketId}`;
|
|
1390
|
-
}
|
|
1391
|
-
return crypto.randomUUID();
|
|
1392
|
-
}
|
|
1393
|
-
findFileNode(filePath) {
|
|
1394
|
-
const normalized = this.normalizePath(filePath);
|
|
1395
|
-
const nodes = this.store.findNodesByType("file");
|
|
1396
|
-
return nodes.find(
|
|
1397
|
-
(node) => node.id === normalized || this.normalizePath(node.data.path) === normalized || node.data.path === filePath
|
|
1398
|
-
) ?? null;
|
|
1399
|
-
}
|
|
1400
|
-
normalizePath(filePath) {
|
|
1401
|
-
return path3.resolve(this.projectPath, filePath);
|
|
1402
|
-
}
|
|
1403
|
-
riskLevelToScore(level) {
|
|
1404
|
-
switch (level) {
|
|
1405
|
-
case "critical":
|
|
1406
|
-
return 6;
|
|
1407
|
-
case "high":
|
|
1408
|
-
return 4;
|
|
1409
|
-
case "medium":
|
|
1410
|
-
return 2;
|
|
1411
|
-
default:
|
|
1412
|
-
return 0;
|
|
1413
|
-
}
|
|
1414
|
-
}
|
|
1415
|
-
isNewer(incoming, existing) {
|
|
1416
|
-
return new Date(incoming).getTime() >= new Date(existing).getTime();
|
|
1417
|
-
}
|
|
1418
|
-
};
|
|
1419
|
-
|
|
1420
793
|
export {
|
|
1421
794
|
recordToGlobalMemory,
|
|
1422
795
|
findCrossProjectPatterns,
|
|
@@ -1424,14 +797,8 @@ export {
|
|
|
1424
797
|
getGlobalMemoryStats,
|
|
1425
798
|
updateGlobalMemoryMd,
|
|
1426
799
|
searchGlobalPatterns,
|
|
1427
|
-
isAIAvailable,
|
|
1428
|
-
getKeyFromKeychain,
|
|
1429
|
-
setAPIKey,
|
|
1430
|
-
runAIAnalysis,
|
|
1431
|
-
runAIWithTools,
|
|
1432
800
|
TieredStorage,
|
|
1433
801
|
getStorage,
|
|
1434
|
-
GotchaPredictor
|
|
1435
|
-
ContextGraph
|
|
802
|
+
GotchaPredictor
|
|
1436
803
|
};
|
|
1437
|
-
//# sourceMappingURL=chunk-
|
|
804
|
+
//# sourceMappingURL=chunk-D3EXBJE2.js.map
|