musememory 3.0.2 → 3.2.0
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/.agents/artifacts/2026-10-26-dashboard-rehaul-rashin-research-and-wave-23-tickets.md +234 -0
- package/.agents/artifacts/2026-10-26-wave-29-code-review-audit.md +52 -0
- package/.agents/artifacts/2026-10-26-wave-29-gauntlet-acceptance-packet.md +48 -0
- package/.agents/artifacts/2026-10-26-wave-29-muse-security-audit.md +71 -0
- package/.agents/artifacts/2026-10-26-wave-29-sovereign-lifeos-migration-plan.md +88 -0
- package/.agents/artifacts/HANDOFF.md +124 -15
- package/.agents/artifacts/WORKTREE-LEASE.md +86 -0
- package/.agents/context/current.md +91 -6
- package/.agents/context/index.md +1 -1
- package/.agents/context/roadmap.md +10 -1
- package/.agents/context/ticket-plan.md +99 -6
- package/.agents/skills/muse-health/SKILL.md +29 -0
- package/.agents/standards/README.md +1 -0
- package/.agents/standards/dox-hierarchy.md +2 -1
- package/.agents/standards/git-workflow.md +14 -1
- package/.agents/standards/landing-gate.md +253 -0
- package/.agents/standards/memory-context.md +5 -6
- package/.agents/standards/security-vibeguard.md +1 -1
- package/.agents/standards/workflows.md +8 -2
- package/README.md +220 -91
- package/claims.json +4 -4
- package/dist/index.js +1669 -194
- package/docs/agent-reference.md +36 -0
- package/docs/cli-reference.md +4 -1
- package/package.json +9 -2
package/dist/index.js
CHANGED
|
@@ -4480,7 +4480,7 @@ function searchMemoriesFts(db, query, filters) {
|
|
|
4480
4480
|
sql += ` ORDER BY rank ASC`;
|
|
4481
4481
|
const targetLimit = filters?.limit;
|
|
4482
4482
|
if (targetLimit) {
|
|
4483
|
-
const shouldOverfetch = filters?.overfetch !== false && !filters?.
|
|
4483
|
+
const shouldOverfetch = filters?.overfetch !== false && !filters?.status && (!filters?.includeSuperseded || !filters?.includeConflicted);
|
|
4484
4484
|
const fetchLimit = shouldOverfetch ? Math.min(500, Math.max(targetLimit * 2, targetLimit + 10)) : targetLimit;
|
|
4485
4485
|
sql += ` LIMIT ?`;
|
|
4486
4486
|
params.push(fetchLimit);
|
|
@@ -4495,6 +4495,10 @@ function searchMemoriesFts(db, query, filters) {
|
|
|
4495
4495
|
hidden_count++;
|
|
4496
4496
|
continue;
|
|
4497
4497
|
}
|
|
4498
|
+
if (!filters?.includeConflicted && !filters?.status && entry.status === "conflicted") {
|
|
4499
|
+
hidden_count++;
|
|
4500
|
+
continue;
|
|
4501
|
+
}
|
|
4498
4502
|
activeHits.push({ entry, rank: r.rank });
|
|
4499
4503
|
}
|
|
4500
4504
|
const finalHits = targetLimit ? activeHits.slice(0, targetLimit) : activeHits;
|
|
@@ -4601,6 +4605,29 @@ function findConflictBetween(db, memoryA, memoryB) {
|
|
|
4601
4605
|
return null;
|
|
4602
4606
|
return rowToConflictRecord(row);
|
|
4603
4607
|
}
|
|
4608
|
+
function listConflictsFromDb(db, options) {
|
|
4609
|
+
let sql = `SELECT * FROM conflicts`;
|
|
4610
|
+
const conditions = [];
|
|
4611
|
+
const params = [];
|
|
4612
|
+
if (options?.status) {
|
|
4613
|
+
conditions.push(`status = ?`);
|
|
4614
|
+
params.push(options.status);
|
|
4615
|
+
}
|
|
4616
|
+
if (options?.memoryId) {
|
|
4617
|
+
conditions.push(`(memory_a_id = ? OR memory_b_id = ?)`);
|
|
4618
|
+
params.push(options.memoryId, options.memoryId);
|
|
4619
|
+
}
|
|
4620
|
+
if (conditions.length > 0) {
|
|
4621
|
+
sql += ` WHERE ` + conditions.join(" AND ");
|
|
4622
|
+
}
|
|
4623
|
+
sql += ` ORDER BY detected_at DESC`;
|
|
4624
|
+
if (options?.limit && options.limit > 0) {
|
|
4625
|
+
sql += ` LIMIT ?`;
|
|
4626
|
+
params.push(options.limit);
|
|
4627
|
+
}
|
|
4628
|
+
const rows = db.query(sql).all(params);
|
|
4629
|
+
return rows.map(rowToConflictRecord);
|
|
4630
|
+
}
|
|
4604
4631
|
function insertFactProvenance(db, record) {
|
|
4605
4632
|
try {
|
|
4606
4633
|
const scope = record.scope ?? "global";
|
|
@@ -7559,6 +7586,10 @@ function queryContext(store, query = "", options = {}) {
|
|
|
7559
7586
|
hidden_count++;
|
|
7560
7587
|
return false;
|
|
7561
7588
|
}
|
|
7589
|
+
if (!options.includeConflicted && options.status !== "conflicted" && e.status === "conflicted") {
|
|
7590
|
+
hidden_count++;
|
|
7591
|
+
return false;
|
|
7592
|
+
}
|
|
7562
7593
|
if (!options.includeArchived && options.status !== "archived" && e.status === "archived") {
|
|
7563
7594
|
hidden_count++;
|
|
7564
7595
|
return false;
|
|
@@ -7840,7 +7871,7 @@ function searchTemporal(store, query, atTime, options = {}) {
|
|
|
7840
7871
|
};
|
|
7841
7872
|
}
|
|
7842
7873
|
function formatPromptContext(store, memoryDir, query = "", options = {}) {
|
|
7843
|
-
const cacheKey = store.cache ? `ctx:${query}:${options.project || ""}:${options.depth || "L2"}:${options.limit ?? 5}:${options.tokenBudget ?? ""}:${options.type || ""}:${options.status || ""}:${options.verified ? "1" : "0"}:${options.minVeracity ?? ""}:${options.as_of || ""}:${options.includeSuperseded ? "1" : "0"}:${options.includeArchived ? "1" : "0"}:${options.includeUntrusted ? "1" : "0"}:${options.types?.join(",") || ""}:${options.tags?.join(",") || ""}` : undefined;
|
|
7874
|
+
const cacheKey = store.cache ? `ctx:${query}:${options.project || ""}:${options.depth || "L2"}:${options.limit ?? 5}:${options.tokenBudget ?? ""}:${options.type || ""}:${options.status || ""}:${options.verified ? "1" : "0"}:${options.minVeracity ?? ""}:${options.as_of || ""}:${options.includeSuperseded ? "1" : "0"}:${options.includeConflicted ? "1" : "0"}:${options.includeArchived ? "1" : "0"}:${options.includeUntrusted ? "1" : "0"}:${options.types?.join(",") || ""}:${options.tags?.join(",") || ""}` : undefined;
|
|
7844
7875
|
if (cacheKey && store.cache) {
|
|
7845
7876
|
const cached = store.cache.getContext(cacheKey);
|
|
7846
7877
|
if (cached) {
|
|
@@ -10305,6 +10336,166 @@ var init_embedders = __esm(() => {
|
|
|
10305
10336
|
init_schema();
|
|
10306
10337
|
});
|
|
10307
10338
|
|
|
10339
|
+
// src/quality/scope.ts
|
|
10340
|
+
function canonicalizeScope(scope) {
|
|
10341
|
+
if (!scope)
|
|
10342
|
+
return "";
|
|
10343
|
+
const norm = scope.toLowerCase().trim().replace(/[-_]+/g, " ").replace(/\s+/g, " ");
|
|
10344
|
+
if (SCOPE_ALIASES[norm])
|
|
10345
|
+
return SCOPE_ALIASES[norm];
|
|
10346
|
+
const tokens = norm.split(" ").filter(Boolean);
|
|
10347
|
+
if (tokens.length > 1) {
|
|
10348
|
+
const mapped = tokens.map((token) => SCOPE_ALIASES[token]);
|
|
10349
|
+
if (mapped.every((value) => value && value === mapped[0]))
|
|
10350
|
+
return mapped[0];
|
|
10351
|
+
}
|
|
10352
|
+
return norm;
|
|
10353
|
+
}
|
|
10354
|
+
function extractTrailingScope(text, fromIndex) {
|
|
10355
|
+
const rest = text.slice(fromIndex);
|
|
10356
|
+
const defaultMatch = rest.match(/^[\s,;:()\-]*(?:by\s+default)\b/i);
|
|
10357
|
+
if (defaultMatch)
|
|
10358
|
+
return canonicalizeScope("default");
|
|
10359
|
+
const prepMatch = rest.match(/^[\s,;:()\-]*(?:only\s+)?(instead\s+of|within|throughout|during|while|when|before|after|under|across|between|in|on|at|for|per)\b/i);
|
|
10360
|
+
if (!prepMatch)
|
|
10361
|
+
return;
|
|
10362
|
+
const afterPrep = rest.slice(prepMatch[0].length);
|
|
10363
|
+
const tokens = afterPrep.split(/[^A-Za-z0-9_\-\/]+/).filter(Boolean);
|
|
10364
|
+
if (tokens.length === 0)
|
|
10365
|
+
return;
|
|
10366
|
+
const phrase = [];
|
|
10367
|
+
for (const token of tokens) {
|
|
10368
|
+
if (phrase.length >= SCOPE_MAX_TOKENS)
|
|
10369
|
+
break;
|
|
10370
|
+
const lower = token.toLowerCase();
|
|
10371
|
+
if (phrase.length > 0 && SCOPE_BOUNDARY_TOKENS.has(lower))
|
|
10372
|
+
break;
|
|
10373
|
+
phrase.push(token);
|
|
10374
|
+
}
|
|
10375
|
+
if (phrase.length === 0)
|
|
10376
|
+
return;
|
|
10377
|
+
return canonicalizeScope(phrase.join(" "));
|
|
10378
|
+
}
|
|
10379
|
+
function extractLeadingScope(clause) {
|
|
10380
|
+
const re = /\b(?:only\s+)?(instead\s+of|within|during|while|when|before|after|under|across|between|in|on|at|for|per)\s+([^,;.]{1,40}),/gi;
|
|
10381
|
+
let last;
|
|
10382
|
+
let match;
|
|
10383
|
+
while ((match = re.exec(clause)) !== null) {
|
|
10384
|
+
const tokens = match[2].split(/[^A-Za-z0-9_\-/]+/).filter(Boolean);
|
|
10385
|
+
if (tokens.length === 0)
|
|
10386
|
+
continue;
|
|
10387
|
+
const phrase = [];
|
|
10388
|
+
for (const token of tokens) {
|
|
10389
|
+
if (phrase.length >= SCOPE_MAX_TOKENS)
|
|
10390
|
+
break;
|
|
10391
|
+
if (phrase.length > 0 && SCOPE_BOUNDARY_TOKENS.has(token.toLowerCase()))
|
|
10392
|
+
break;
|
|
10393
|
+
phrase.push(token);
|
|
10394
|
+
}
|
|
10395
|
+
if (phrase.length === 0)
|
|
10396
|
+
continue;
|
|
10397
|
+
last = canonicalizeScope(phrase.join(" "));
|
|
10398
|
+
}
|
|
10399
|
+
return last;
|
|
10400
|
+
}
|
|
10401
|
+
function isStrongScope(scope) {
|
|
10402
|
+
if (!scope)
|
|
10403
|
+
return false;
|
|
10404
|
+
const norm = canonicalizeScope(scope);
|
|
10405
|
+
if (STRONG_SCOPES.has(norm))
|
|
10406
|
+
return true;
|
|
10407
|
+
return /^(tier|level|stage|phase|version|v)\s*\d+$/.test(norm);
|
|
10408
|
+
}
|
|
10409
|
+
function scopesAreCompatible(scopeA, scopeB) {
|
|
10410
|
+
const a = scopeA ? canonicalizeScope(scopeA) : "";
|
|
10411
|
+
const b = scopeB ? canonicalizeScope(scopeB) : "";
|
|
10412
|
+
if (!a && !b)
|
|
10413
|
+
return true;
|
|
10414
|
+
if (!a || !b)
|
|
10415
|
+
return false;
|
|
10416
|
+
return a === b;
|
|
10417
|
+
}
|
|
10418
|
+
var SCOPE_ALIASES, SCOPE_BOUNDARY_TOKENS, SCOPE_MAX_TOKENS = 3, STRONG_SCOPES;
|
|
10419
|
+
var init_scope = __esm(() => {
|
|
10420
|
+
SCOPE_ALIASES = {
|
|
10421
|
+
prod: "production",
|
|
10422
|
+
production: "production",
|
|
10423
|
+
dev: "development",
|
|
10424
|
+
development: "development",
|
|
10425
|
+
test: "testing",
|
|
10426
|
+
testing: "testing",
|
|
10427
|
+
qa: "testing",
|
|
10428
|
+
staging: "staging",
|
|
10429
|
+
stage: "staging",
|
|
10430
|
+
analytics: "analytics",
|
|
10431
|
+
warehouse: "analytics",
|
|
10432
|
+
olap: "analytics",
|
|
10433
|
+
macos: "desktop",
|
|
10434
|
+
desktop: "desktop",
|
|
10435
|
+
mobile: "mobile",
|
|
10436
|
+
ios: "mobile",
|
|
10437
|
+
android: "mobile",
|
|
10438
|
+
frontend: "frontend",
|
|
10439
|
+
backend: "backend",
|
|
10440
|
+
localhost: "local",
|
|
10441
|
+
local: "local",
|
|
10442
|
+
ci: "ci",
|
|
10443
|
+
cd: "ci",
|
|
10444
|
+
container: "container",
|
|
10445
|
+
docker: "container",
|
|
10446
|
+
browser: "browser",
|
|
10447
|
+
server: "server",
|
|
10448
|
+
client: "client"
|
|
10449
|
+
};
|
|
10450
|
+
SCOPE_BOUNDARY_TOKENS = new Set([
|
|
10451
|
+
"and",
|
|
10452
|
+
"but",
|
|
10453
|
+
"or",
|
|
10454
|
+
"so",
|
|
10455
|
+
"because",
|
|
10456
|
+
"since",
|
|
10457
|
+
"unless",
|
|
10458
|
+
"which",
|
|
10459
|
+
"that",
|
|
10460
|
+
"who",
|
|
10461
|
+
"is",
|
|
10462
|
+
"are",
|
|
10463
|
+
"was",
|
|
10464
|
+
"were",
|
|
10465
|
+
"be",
|
|
10466
|
+
"been",
|
|
10467
|
+
"to",
|
|
10468
|
+
"as",
|
|
10469
|
+
"if",
|
|
10470
|
+
"then",
|
|
10471
|
+
"otherwise",
|
|
10472
|
+
"however",
|
|
10473
|
+
"meanwhile",
|
|
10474
|
+
"also",
|
|
10475
|
+
"both",
|
|
10476
|
+
"either",
|
|
10477
|
+
"neither"
|
|
10478
|
+
]);
|
|
10479
|
+
STRONG_SCOPES = new Set([
|
|
10480
|
+
"production",
|
|
10481
|
+
"development",
|
|
10482
|
+
"testing",
|
|
10483
|
+
"staging",
|
|
10484
|
+
"analytics",
|
|
10485
|
+
"desktop",
|
|
10486
|
+
"mobile",
|
|
10487
|
+
"frontend",
|
|
10488
|
+
"backend",
|
|
10489
|
+
"local",
|
|
10490
|
+
"ci",
|
|
10491
|
+
"container",
|
|
10492
|
+
"browser",
|
|
10493
|
+
"server",
|
|
10494
|
+
"client",
|
|
10495
|
+
"default"
|
|
10496
|
+
]);
|
|
10497
|
+
});
|
|
10498
|
+
|
|
10308
10499
|
// src/quality/invalidation.ts
|
|
10309
10500
|
function normalizeTerm(term) {
|
|
10310
10501
|
if (!term)
|
|
@@ -10315,10 +10506,6 @@ function canonicalizeRelation(rel) {
|
|
|
10315
10506
|
const norm = normalizeTerm(rel);
|
|
10316
10507
|
return RELATION_ALIASES[norm] || norm;
|
|
10317
10508
|
}
|
|
10318
|
-
function canonicalizeScope(scope) {
|
|
10319
|
-
const norm = normalizeTerm(scope);
|
|
10320
|
-
return SCOPE_ALIASES[norm] || norm;
|
|
10321
|
-
}
|
|
10322
10509
|
function extractFactTriples(entry) {
|
|
10323
10510
|
if (entry.triples && Array.isArray(entry.triples) && entry.triples.length > 0) {
|
|
10324
10511
|
return entry.triples.map((t) => ({
|
|
@@ -10331,32 +10518,32 @@ function extractFactTriples(entry) {
|
|
|
10331
10518
|
const triples = [];
|
|
10332
10519
|
const text = `${entry.title} ${entry.content}`;
|
|
10333
10520
|
const lowerText = text.toLowerCase();
|
|
10334
|
-
let
|
|
10521
|
+
let tagScope;
|
|
10335
10522
|
if (entry.tags) {
|
|
10336
10523
|
for (const tag of entry.tags) {
|
|
10337
10524
|
if (tag.startsWith("scope:")) {
|
|
10338
|
-
|
|
10525
|
+
tagScope = canonicalizeScope(tag.replace("scope:", ""));
|
|
10339
10526
|
break;
|
|
10340
10527
|
}
|
|
10341
10528
|
}
|
|
10342
10529
|
}
|
|
10343
|
-
|
|
10344
|
-
|
|
10345
|
-
|
|
10346
|
-
|
|
10347
|
-
|
|
10348
|
-
|
|
10349
|
-
|
|
10350
|
-
|
|
10351
|
-
|
|
10352
|
-
|
|
10353
|
-
|
|
10354
|
-
|
|
10355
|
-
|
|
10356
|
-
|
|
10357
|
-
|
|
10358
|
-
|
|
10359
|
-
|
|
10530
|
+
let fixedScope;
|
|
10531
|
+
if (/\b(in\s+production|for\s+production|prod\s+server|production\s+database|production\s+environment)\b/i.test(text)) {
|
|
10532
|
+
fixedScope = "production";
|
|
10533
|
+
} else if (/\b(in\s+development|for\s+development|dev\s+server|development\s+environment|local\s+dev)\b/i.test(text)) {
|
|
10534
|
+
fixedScope = "development";
|
|
10535
|
+
} else if (/\b(for\s+analytics|analytics\s+warehouse|analytics\s+database|in\s+olap)\b/i.test(text)) {
|
|
10536
|
+
fixedScope = "analytics";
|
|
10537
|
+
} else if (/\b(on\s+macos|macos\s+desktop|for\s+desktop)\b/i.test(text)) {
|
|
10538
|
+
fixedScope = "desktop";
|
|
10539
|
+
} else if (/\b(on\s+mobile|mobile\s+ios|on\s+ios|on\s+android|mobile\s+app)\b/i.test(text)) {
|
|
10540
|
+
fixedScope = "mobile";
|
|
10541
|
+
} else if (/\b(in\s+staging|staging\s+environment)\b/i.test(text)) {
|
|
10542
|
+
fixedScope = "staging";
|
|
10543
|
+
} else if (/\b(in\s+testing|for\s+test|test\s+environment)\b/i.test(text)) {
|
|
10544
|
+
fixedScope = "testing";
|
|
10545
|
+
}
|
|
10546
|
+
const scopeFor = (claimEndIndex) => tagScope ?? fixedScope ?? extractTrailingScope(text, claimEndIndex);
|
|
10360
10547
|
const dbMatch = text.match(/\b(primary\s+database|database|warehouse|persistence|db)\b.*?uses?\s+([A-Za-z0-9_]+)/i) || text.match(/\buses?\s+(postgresql|postgres|mysql|sqlite|mongodb)\b/i);
|
|
10361
10548
|
if (dbMatch) {
|
|
10362
10549
|
const target = dbMatch[2] ? dbMatch[2].toLowerCase() : dbMatch[1].toLowerCase();
|
|
@@ -10364,7 +10551,7 @@ function extractFactTriples(entry) {
|
|
|
10364
10551
|
entity: "database",
|
|
10365
10552
|
relation: "database",
|
|
10366
10553
|
target: target.startsWith("postgres") ? "postgresql" : target,
|
|
10367
|
-
scope:
|
|
10554
|
+
scope: scopeFor((dbMatch.index ?? 0) + dbMatch[0].length)
|
|
10368
10555
|
});
|
|
10369
10556
|
}
|
|
10370
10557
|
const portMatch = text.match(/\b(binds?\s+to\s+port|runs?\s+on\s+port|port\s+binding|port)\s+([0-9]{2,5})\b/i);
|
|
@@ -10373,7 +10560,7 @@ function extractFactTriples(entry) {
|
|
|
10373
10560
|
entity: "gateway",
|
|
10374
10561
|
relation: "port",
|
|
10375
10562
|
target: portMatch[2],
|
|
10376
|
-
scope:
|
|
10563
|
+
scope: scopeFor((portMatch.index ?? 0) + portMatch[0].length)
|
|
10377
10564
|
});
|
|
10378
10565
|
}
|
|
10379
10566
|
const themeMatch = text.match(/\b(theme|mode)\b.*?\b(dark|light)\b/i) || text.match(/\bprefers?\s+(dark|light)\s+(mode|theme)?\b/i);
|
|
@@ -10383,7 +10570,7 @@ function extractFactTriples(entry) {
|
|
|
10383
10570
|
entity: "user_theme",
|
|
10384
10571
|
relation: "theme",
|
|
10385
10572
|
target,
|
|
10386
|
-
scope:
|
|
10573
|
+
scope: scopeFor((themeMatch.index ?? 0) + themeMatch[0].length)
|
|
10387
10574
|
});
|
|
10388
10575
|
}
|
|
10389
10576
|
const runtimeMatch = text.match(/\b(runtime|engine)\b.*?\b(bun|node|deno)\b/i) || text.match(/\b(bun|node|deno)\s+runtime\b/i);
|
|
@@ -10393,7 +10580,7 @@ function extractFactTriples(entry) {
|
|
|
10393
10580
|
entity: "runtime",
|
|
10394
10581
|
relation: "runtime",
|
|
10395
10582
|
target,
|
|
10396
|
-
scope:
|
|
10583
|
+
scope: scopeFor((runtimeMatch.index ?? 0) + runtimeMatch[0].length)
|
|
10397
10584
|
});
|
|
10398
10585
|
}
|
|
10399
10586
|
const statusMatch = text.match(/\b([A-Za-z0-9_-]+)\s+(service|feature|caching|compression|plugin)\s*(?:is\s+)?(enabled|disabled|allowed|denied|forbidden|active|inactive)\b/i);
|
|
@@ -10402,7 +10589,7 @@ function extractFactTriples(entry) {
|
|
|
10402
10589
|
entity: normalizeTerm(statusMatch[1]),
|
|
10403
10590
|
relation: "status",
|
|
10404
10591
|
target: normalizeTerm(statusMatch[3]),
|
|
10405
|
-
scope:
|
|
10592
|
+
scope: scopeFor((statusMatch.index ?? 0) + statusMatch[0].length)
|
|
10406
10593
|
});
|
|
10407
10594
|
}
|
|
10408
10595
|
return triples;
|
|
@@ -10463,52 +10650,10 @@ function evaluateScopedAlignment(tripleA, tripleB) {
|
|
|
10463
10650
|
reason: `Target values '${tripleA.target}' and '${tripleB.target}' are consistent`
|
|
10464
10651
|
};
|
|
10465
10652
|
}
|
|
10466
|
-
|
|
10467
|
-
const existingTriples = extractFactTriples(existing);
|
|
10468
|
-
const candidateTriples = extractFactTriples(candidate);
|
|
10469
|
-
if (existingTriples.length > 0 && candidateTriples.length > 0) {
|
|
10470
|
-
let hadScopeOrEntityMismatch = false;
|
|
10471
|
-
let mismatchReason = "";
|
|
10472
|
-
for (const eTriple of existingTriples) {
|
|
10473
|
-
for (const cTriple of candidateTriples) {
|
|
10474
|
-
const alignment = evaluateScopedAlignment(eTriple, cTriple);
|
|
10475
|
-
if (alignment.aligned && alignment.conflicting) {
|
|
10476
|
-
return {
|
|
10477
|
-
shouldInvalidate: true,
|
|
10478
|
-
aligned: true,
|
|
10479
|
-
conflicting: true,
|
|
10480
|
-
confidence: 0.95,
|
|
10481
|
-
reason: alignment.reason,
|
|
10482
|
-
matchingTriples: {
|
|
10483
|
-
existingTriple: eTriple,
|
|
10484
|
-
candidateTriple: cTriple
|
|
10485
|
-
}
|
|
10486
|
-
};
|
|
10487
|
-
} else if (!alignment.aligned) {
|
|
10488
|
-
hadScopeOrEntityMismatch = true;
|
|
10489
|
-
mismatchReason = alignment.reason || "Entity or scope mismatch";
|
|
10490
|
-
}
|
|
10491
|
-
}
|
|
10492
|
-
}
|
|
10493
|
-
if (hadScopeOrEntityMismatch) {
|
|
10494
|
-
return {
|
|
10495
|
-
shouldInvalidate: false,
|
|
10496
|
-
aligned: false,
|
|
10497
|
-
conflicting: false,
|
|
10498
|
-
confidence: 0,
|
|
10499
|
-
reason: mismatchReason
|
|
10500
|
-
};
|
|
10501
|
-
}
|
|
10502
|
-
}
|
|
10503
|
-
return {
|
|
10504
|
-
shouldInvalidate: false,
|
|
10505
|
-
aligned: false,
|
|
10506
|
-
conflicting: false,
|
|
10507
|
-
confidence: 0
|
|
10508
|
-
};
|
|
10509
|
-
}
|
|
10510
|
-
var RELATION_ALIASES, SCOPE_ALIASES, CONFLICTING_TARGET_PAIRS;
|
|
10653
|
+
var RELATION_ALIASES, CONFLICTING_TARGET_PAIRS;
|
|
10511
10654
|
var init_invalidation = __esm(() => {
|
|
10655
|
+
init_scope();
|
|
10656
|
+
init_scope();
|
|
10512
10657
|
RELATION_ALIASES = {
|
|
10513
10658
|
db: "database",
|
|
10514
10659
|
database: "database",
|
|
@@ -10531,25 +10676,6 @@ var init_invalidation = __esm(() => {
|
|
|
10531
10676
|
runtime: "runtime",
|
|
10532
10677
|
runtime_engine: "runtime"
|
|
10533
10678
|
};
|
|
10534
|
-
SCOPE_ALIASES = {
|
|
10535
|
-
prod: "production",
|
|
10536
|
-
production: "production",
|
|
10537
|
-
dev: "development",
|
|
10538
|
-
development: "development",
|
|
10539
|
-
test: "testing",
|
|
10540
|
-
testing: "testing",
|
|
10541
|
-
staging: "staging",
|
|
10542
|
-
analytics: "analytics",
|
|
10543
|
-
warehouse: "analytics",
|
|
10544
|
-
olap: "analytics",
|
|
10545
|
-
macos: "desktop",
|
|
10546
|
-
desktop: "desktop",
|
|
10547
|
-
mobile: "mobile",
|
|
10548
|
-
ios: "mobile",
|
|
10549
|
-
android: "mobile",
|
|
10550
|
-
frontend: "frontend",
|
|
10551
|
-
backend: "backend"
|
|
10552
|
-
};
|
|
10553
10679
|
CONFLICTING_TARGET_PAIRS = [
|
|
10554
10680
|
[/\b(enable|enabled|true|allow|allowed|active)\b/i, /\b(disable|disabled|false|deny|denied|inactive|forbidden)\b/i],
|
|
10555
10681
|
[/\b(postgres|postgresql)\b/i, /\b(mysql|sqlite|mongodb)\b/i],
|
|
@@ -10561,10 +10687,570 @@ var init_invalidation = __esm(() => {
|
|
|
10561
10687
|
];
|
|
10562
10688
|
});
|
|
10563
10689
|
|
|
10690
|
+
// src/quality/polarity.ts
|
|
10691
|
+
function tokenize2(text) {
|
|
10692
|
+
return text.split(/[^A-Za-z0-9_\-/]+/).filter(Boolean);
|
|
10693
|
+
}
|
|
10694
|
+
function lastClauseBoundary(text) {
|
|
10695
|
+
let index = -1;
|
|
10696
|
+
for (const boundary of CLAUSE_BOUNDARIES) {
|
|
10697
|
+
const found = text.lastIndexOf(boundary);
|
|
10698
|
+
if (found > index)
|
|
10699
|
+
index = found;
|
|
10700
|
+
}
|
|
10701
|
+
return index;
|
|
10702
|
+
}
|
|
10703
|
+
function trimTrailing(tokens, vocab) {
|
|
10704
|
+
const out = [...tokens];
|
|
10705
|
+
while (out.length && vocab.has(out[out.length - 1].toLowerCase()))
|
|
10706
|
+
out.pop();
|
|
10707
|
+
return out;
|
|
10708
|
+
}
|
|
10709
|
+
function subjectBefore(text, claimIndex, maxTokens = 4) {
|
|
10710
|
+
const before = text.slice(0, claimIndex);
|
|
10711
|
+
const clause = before.slice(lastClauseBoundary(before) + 1);
|
|
10712
|
+
let tokens = tokenize2(clause);
|
|
10713
|
+
tokens = trimTrailing(tokens, AUXILIARY_TOKENS);
|
|
10714
|
+
tokens = trimTrailing(tokens, TRAILING_VERB_TOKENS);
|
|
10715
|
+
tokens = trimTrailing(tokens, TRAILING_PREPOSITION_TOKENS);
|
|
10716
|
+
tokens = tokens.slice(-maxTokens);
|
|
10717
|
+
tokens = tokens.filter((token) => !TECHNOLOGY_TOKENS.has(token.toLowerCase()));
|
|
10718
|
+
while (tokens.length && LEADING_TRIM_TOKENS.has(tokens[0].toLowerCase()))
|
|
10719
|
+
tokens.shift();
|
|
10720
|
+
tokens = trimTrailing(tokens, TRAILING_PREPOSITION_TOKENS);
|
|
10721
|
+
return tokens.join(" ").toLowerCase();
|
|
10722
|
+
}
|
|
10723
|
+
function objectAfter(text, fromIndex) {
|
|
10724
|
+
const rest = text.slice(fromIndex);
|
|
10725
|
+
const tokens = [];
|
|
10726
|
+
let consumed = fromIndex;
|
|
10727
|
+
const re = /[\s:,\-]*([A-Za-z0-9_\-/]+)/g;
|
|
10728
|
+
let match;
|
|
10729
|
+
while ((match = re.exec(rest)) !== null) {
|
|
10730
|
+
const word = match[1];
|
|
10731
|
+
const lower = word.toLowerCase();
|
|
10732
|
+
if (tokens.length >= 4)
|
|
10733
|
+
break;
|
|
10734
|
+
if (tokens.length > 0 && (TRAILING_PREPOSITION_TOKENS.has(lower) || AUXILIARY_TOKENS.has(lower)))
|
|
10735
|
+
break;
|
|
10736
|
+
if (tokens.length === 0 && DETERMINER_TOKENS.has(lower)) {
|
|
10737
|
+
consumed = fromIndex + match.index + match[0].length;
|
|
10738
|
+
continue;
|
|
10739
|
+
}
|
|
10740
|
+
tokens.push(word);
|
|
10741
|
+
consumed = fromIndex + match.index + match[0].length;
|
|
10742
|
+
}
|
|
10743
|
+
if (tokens.length === 0)
|
|
10744
|
+
return null;
|
|
10745
|
+
return { phrase: tokens.join(" ").toLowerCase(), endIndex: consumed };
|
|
10746
|
+
}
|
|
10747
|
+
function isMigrationContext(before) {
|
|
10748
|
+
const tail = before.slice(-48).toLowerCase();
|
|
10749
|
+
return /\b(from|migrat\w*|switch\w*|move[ds]?|chang\w*|replac\w*|instead\s+of|convert\w*|port\w*)\b[^.]{0,30}$/.test(tail);
|
|
10750
|
+
}
|
|
10751
|
+
function resolveScope(text, claimEnd, claimStart, options) {
|
|
10752
|
+
const strongOnly = options?.strongOnly === true;
|
|
10753
|
+
const trailing = extractTrailingScope(text, claimEnd);
|
|
10754
|
+
if (trailing && (!strongOnly || isStrongScope(trailing)))
|
|
10755
|
+
return trailing;
|
|
10756
|
+
const before = text.slice(0, claimStart);
|
|
10757
|
+
const clause = before.slice(lastClauseBoundary(before) + 1);
|
|
10758
|
+
const leading = extractLeadingScope(clause);
|
|
10759
|
+
if (leading && (!strongOnly || isStrongScope(leading)))
|
|
10760
|
+
return leading;
|
|
10761
|
+
return;
|
|
10762
|
+
}
|
|
10763
|
+
function statusClaims(text) {
|
|
10764
|
+
const claims = [];
|
|
10765
|
+
const adjectiveRe = new RegExp(`\\b(${STATUS_ADJECTIVES.join("|")})\\b`, "gi");
|
|
10766
|
+
let match;
|
|
10767
|
+
while ((match = adjectiveRe.exec(text)) !== null) {
|
|
10768
|
+
const term = match[1].toLowerCase();
|
|
10769
|
+
const entity = subjectBefore(text, match.index);
|
|
10770
|
+
if (!entity)
|
|
10771
|
+
continue;
|
|
10772
|
+
const scope = resolveScope(text, match.index + match[0].length, match.index);
|
|
10773
|
+
claims.push({
|
|
10774
|
+
entity,
|
|
10775
|
+
relation: "status",
|
|
10776
|
+
target: term,
|
|
10777
|
+
scope,
|
|
10778
|
+
evidence: match[0]
|
|
10779
|
+
});
|
|
10780
|
+
}
|
|
10781
|
+
const booleanRe = /\b(is|are|was|were|=|:)\s+(true|false)\b/gi;
|
|
10782
|
+
while ((match = booleanRe.exec(text)) !== null) {
|
|
10783
|
+
const term = match[2].toLowerCase();
|
|
10784
|
+
const entity = subjectBefore(text, match.index);
|
|
10785
|
+
if (!entity)
|
|
10786
|
+
continue;
|
|
10787
|
+
const scope = resolveScope(text, match.index + match[0].length, match.index);
|
|
10788
|
+
claims.push({
|
|
10789
|
+
entity,
|
|
10790
|
+
relation: "status",
|
|
10791
|
+
target: term,
|
|
10792
|
+
scope,
|
|
10793
|
+
evidence: match[0]
|
|
10794
|
+
});
|
|
10795
|
+
}
|
|
10796
|
+
const verbRe = /\b(enables?|disables?|allows?|denies?)\b/gi;
|
|
10797
|
+
while ((match = verbRe.exec(text)) !== null) {
|
|
10798
|
+
const verb = match[1].toLowerCase();
|
|
10799
|
+
const target = VERB_STATUS[verb];
|
|
10800
|
+
if (!target)
|
|
10801
|
+
continue;
|
|
10802
|
+
const object = objectAfter(text, match.index + match[0].length);
|
|
10803
|
+
if (!object)
|
|
10804
|
+
continue;
|
|
10805
|
+
const scope = resolveScope(text, object.endIndex, match.index);
|
|
10806
|
+
claims.push({
|
|
10807
|
+
entity: object.phrase,
|
|
10808
|
+
relation: "status",
|
|
10809
|
+
target,
|
|
10810
|
+
scope,
|
|
10811
|
+
evidence: `${match[0]} ${object.phrase}`
|
|
10812
|
+
});
|
|
10813
|
+
}
|
|
10814
|
+
return claims;
|
|
10815
|
+
}
|
|
10816
|
+
function databaseClaims(text) {
|
|
10817
|
+
const claims = [];
|
|
10818
|
+
const re = /\b(postgres(?:ql)?|mysql|sqlite|mongodb)\b/gi;
|
|
10819
|
+
let match;
|
|
10820
|
+
while ((match = re.exec(text)) !== null) {
|
|
10821
|
+
const token = match[1].toLowerCase();
|
|
10822
|
+
const before = text.slice(0, match.index);
|
|
10823
|
+
const after = text.slice(match.index + match[0].length);
|
|
10824
|
+
if (isMigrationContext(before))
|
|
10825
|
+
continue;
|
|
10826
|
+
const anchored = DB_ANCHOR_BEFORE.test(before) || DB_ANCHOR_AFTER.test(after);
|
|
10827
|
+
if (!anchored)
|
|
10828
|
+
continue;
|
|
10829
|
+
const scope = resolveScope(text, match.index + match[0].length, match.index, { strongOnly: true });
|
|
10830
|
+
claims.push({
|
|
10831
|
+
entity: subjectBefore(text, match.index, 3) || "database",
|
|
10832
|
+
relation: "database",
|
|
10833
|
+
target: DB_TARGETS[token] ?? token,
|
|
10834
|
+
scope,
|
|
10835
|
+
evidence: match[0]
|
|
10836
|
+
});
|
|
10837
|
+
}
|
|
10838
|
+
return claims;
|
|
10839
|
+
}
|
|
10840
|
+
function portClaims(text) {
|
|
10841
|
+
const claims = [];
|
|
10842
|
+
const re = /\bport\s+(\d{2,5})\b/gi;
|
|
10843
|
+
let match;
|
|
10844
|
+
while ((match = re.exec(text)) !== null) {
|
|
10845
|
+
const entity = subjectBefore(text, match.index, 3);
|
|
10846
|
+
if (!entity)
|
|
10847
|
+
continue;
|
|
10848
|
+
const scope = resolveScope(text, match.index + match[0].length, match.index, { strongOnly: true });
|
|
10849
|
+
claims.push({
|
|
10850
|
+
entity,
|
|
10851
|
+
relation: "port",
|
|
10852
|
+
target: match[1],
|
|
10853
|
+
scope,
|
|
10854
|
+
evidence: match[0]
|
|
10855
|
+
});
|
|
10856
|
+
}
|
|
10857
|
+
return claims;
|
|
10858
|
+
}
|
|
10859
|
+
function protocolClaims(text) {
|
|
10860
|
+
const claims = [];
|
|
10861
|
+
const re = /\b(rest\s+api|graphql|grpc|rest)\b/gi;
|
|
10862
|
+
let match;
|
|
10863
|
+
while ((match = re.exec(text)) !== null) {
|
|
10864
|
+
const token = match[1].toLowerCase();
|
|
10865
|
+
if (isMigrationContext(text.slice(0, match.index)))
|
|
10866
|
+
continue;
|
|
10867
|
+
const before = text.slice(0, match.index);
|
|
10868
|
+
const clause = text.slice(lastClauseBoundary(before) + 1);
|
|
10869
|
+
const clauseWithoutMatch = `${clause}${text.slice(match.index + match[0].length).split(/[.;\n]/)[0]}`;
|
|
10870
|
+
if (!PROTOCOL_ANCHOR.test(clauseWithoutMatch))
|
|
10871
|
+
continue;
|
|
10872
|
+
const entity = subjectBefore(text, match.index, 3);
|
|
10873
|
+
if (!entity)
|
|
10874
|
+
continue;
|
|
10875
|
+
const target = token.startsWith("rest") ? "rest" : token;
|
|
10876
|
+
const scope = resolveScope(text, match.index + match[0].length, match.index, { strongOnly: true });
|
|
10877
|
+
claims.push({
|
|
10878
|
+
entity,
|
|
10879
|
+
relation: "protocol",
|
|
10880
|
+
target,
|
|
10881
|
+
scope,
|
|
10882
|
+
evidence: match[0]
|
|
10883
|
+
});
|
|
10884
|
+
}
|
|
10885
|
+
return claims;
|
|
10886
|
+
}
|
|
10887
|
+
function runtimeClaims(text) {
|
|
10888
|
+
const claims = [];
|
|
10889
|
+
const re = /\b(bun|node|deno)\s+runtime\b/gi;
|
|
10890
|
+
let match;
|
|
10891
|
+
while ((match = re.exec(text)) !== null) {
|
|
10892
|
+
if (isMigrationContext(text.slice(0, match.index)))
|
|
10893
|
+
continue;
|
|
10894
|
+
const entity = subjectBefore(text, match.index, 3);
|
|
10895
|
+
if (!entity)
|
|
10896
|
+
continue;
|
|
10897
|
+
const scope = resolveScope(text, match.index + match[0].length, match.index, { strongOnly: true });
|
|
10898
|
+
claims.push({
|
|
10899
|
+
entity,
|
|
10900
|
+
relation: "runtime",
|
|
10901
|
+
target: match[1].toLowerCase(),
|
|
10902
|
+
scope,
|
|
10903
|
+
evidence: match[0]
|
|
10904
|
+
});
|
|
10905
|
+
}
|
|
10906
|
+
return claims;
|
|
10907
|
+
}
|
|
10908
|
+
function themeClaims(text) {
|
|
10909
|
+
const claims = [];
|
|
10910
|
+
const re = /\b(dark|light)\s+(?:mode|theme)\b/gi;
|
|
10911
|
+
let match;
|
|
10912
|
+
while ((match = re.exec(text)) !== null) {
|
|
10913
|
+
const entity = subjectBefore(text, match.index, 3);
|
|
10914
|
+
if (!entity)
|
|
10915
|
+
continue;
|
|
10916
|
+
const scope = resolveScope(text, match.index + match[0].length, match.index, { strongOnly: true });
|
|
10917
|
+
claims.push({
|
|
10918
|
+
entity,
|
|
10919
|
+
relation: "theme",
|
|
10920
|
+
target: match[1].toLowerCase(),
|
|
10921
|
+
scope,
|
|
10922
|
+
evidence: match[0]
|
|
10923
|
+
});
|
|
10924
|
+
}
|
|
10925
|
+
return claims;
|
|
10926
|
+
}
|
|
10927
|
+
function policyClaims(text) {
|
|
10928
|
+
const claims = [];
|
|
10929
|
+
const re = /\b(always|never)\b/gi;
|
|
10930
|
+
let match;
|
|
10931
|
+
while ((match = re.exec(text)) !== null) {
|
|
10932
|
+
const object = objectAfter(text, match.index + match[0].length);
|
|
10933
|
+
if (!object)
|
|
10934
|
+
continue;
|
|
10935
|
+
claims.push({
|
|
10936
|
+
entity: object.phrase,
|
|
10937
|
+
relation: "policy",
|
|
10938
|
+
target: match[1].toLowerCase(),
|
|
10939
|
+
scope: undefined,
|
|
10940
|
+
evidence: `${match[0]} ${object.phrase}`
|
|
10941
|
+
});
|
|
10942
|
+
}
|
|
10943
|
+
return claims;
|
|
10944
|
+
}
|
|
10945
|
+
function dedupeClaims(claims) {
|
|
10946
|
+
const scopedKeys = new Set;
|
|
10947
|
+
for (const claim of claims) {
|
|
10948
|
+
if (claim.scope)
|
|
10949
|
+
scopedKeys.add(`${claim.entity}|${claim.relation}|${claim.target}`);
|
|
10950
|
+
}
|
|
10951
|
+
const seen = new Set;
|
|
10952
|
+
const unique = [];
|
|
10953
|
+
for (const claim of claims) {
|
|
10954
|
+
const key = `${claim.entity}|${claim.relation}|${claim.target}|${claim.scope ?? ""}`;
|
|
10955
|
+
if (seen.has(key))
|
|
10956
|
+
continue;
|
|
10957
|
+
if (!claim.scope && scopedKeys.has(`${claim.entity}|${claim.relation}|${claim.target}`))
|
|
10958
|
+
continue;
|
|
10959
|
+
seen.add(key);
|
|
10960
|
+
unique.push(claim);
|
|
10961
|
+
}
|
|
10962
|
+
return unique;
|
|
10963
|
+
}
|
|
10964
|
+
function extractPolarityClaims(text) {
|
|
10965
|
+
if (!text)
|
|
10966
|
+
return [];
|
|
10967
|
+
const claims = [
|
|
10968
|
+
...statusClaims(text),
|
|
10969
|
+
...databaseClaims(text),
|
|
10970
|
+
...portClaims(text),
|
|
10971
|
+
...protocolClaims(text),
|
|
10972
|
+
...runtimeClaims(text),
|
|
10973
|
+
...themeClaims(text),
|
|
10974
|
+
...policyClaims(text)
|
|
10975
|
+
];
|
|
10976
|
+
return dedupeClaims(claims);
|
|
10977
|
+
}
|
|
10978
|
+
function comparePolarityClaims(a, b) {
|
|
10979
|
+
if (a.relation !== b.relation)
|
|
10980
|
+
return { conflicting: false };
|
|
10981
|
+
if (!a.entity || !b.entity)
|
|
10982
|
+
return { conflicting: false };
|
|
10983
|
+
const entityMatches = a.entity === b.entity || a.entity.includes(b.entity) || b.entity.includes(a.entity);
|
|
10984
|
+
if (!entityMatches) {
|
|
10985
|
+
return {
|
|
10986
|
+
conflicting: false,
|
|
10987
|
+
reason: `Subject mismatch: '${a.entity}' vs '${b.entity}' are different subjects`
|
|
10988
|
+
};
|
|
10989
|
+
}
|
|
10990
|
+
if (!scopesAreCompatible(a.scope, b.scope)) {
|
|
10991
|
+
return {
|
|
10992
|
+
conflicting: false,
|
|
10993
|
+
reason: `Distinct scopes: '${a.scope ?? "unscoped"}' vs '${b.scope ?? "unscoped"}' represent distinct contextual truths, not a contradiction`
|
|
10994
|
+
};
|
|
10995
|
+
}
|
|
10996
|
+
if (areTargetsContradictory(a.target, b.target)) {
|
|
10997
|
+
const label = RELATION_LABELS[a.relation] ?? "Contradictory claims";
|
|
10998
|
+
return {
|
|
10999
|
+
conflicting: true,
|
|
11000
|
+
reason: `${label}: contradictory ${a.relation} values '${a.target}' vs '${b.target}' for subject '${a.entity}'${a.scope ? ` in scope '${a.scope}'` : ""}`
|
|
11001
|
+
};
|
|
11002
|
+
}
|
|
11003
|
+
return { conflicting: false };
|
|
11004
|
+
}
|
|
11005
|
+
var DETERMINER_TOKENS, AUXILIARY_TOKENS, TRAILING_PREPOSITION_TOKENS, LEADING_TRIM_TOKENS, TRAILING_VERB_TOKENS, CLAUSE_BOUNDARIES, TECHNOLOGY_TOKENS, STATUS_ADJECTIVES, VERB_STATUS, DB_TARGETS, DB_ANCHOR_BEFORE, DB_ANCHOR_AFTER, PROTOCOL_ANCHOR, RELATION_LABELS;
|
|
11006
|
+
var init_polarity = __esm(() => {
|
|
11007
|
+
init_invalidation();
|
|
11008
|
+
init_scope();
|
|
11009
|
+
DETERMINER_TOKENS = new Set([
|
|
11010
|
+
"the",
|
|
11011
|
+
"a",
|
|
11012
|
+
"an",
|
|
11013
|
+
"this",
|
|
11014
|
+
"that",
|
|
11015
|
+
"these",
|
|
11016
|
+
"those",
|
|
11017
|
+
"our",
|
|
11018
|
+
"its",
|
|
11019
|
+
"their",
|
|
11020
|
+
"my",
|
|
11021
|
+
"your",
|
|
11022
|
+
"some",
|
|
11023
|
+
"any",
|
|
11024
|
+
"each",
|
|
11025
|
+
"every",
|
|
11026
|
+
"all",
|
|
11027
|
+
"both",
|
|
11028
|
+
"one",
|
|
11029
|
+
"other",
|
|
11030
|
+
"no",
|
|
11031
|
+
"most",
|
|
11032
|
+
"such"
|
|
11033
|
+
]);
|
|
11034
|
+
AUXILIARY_TOKENS = new Set([
|
|
11035
|
+
"is",
|
|
11036
|
+
"are",
|
|
11037
|
+
"was",
|
|
11038
|
+
"were",
|
|
11039
|
+
"be",
|
|
11040
|
+
"been",
|
|
11041
|
+
"being",
|
|
11042
|
+
"am",
|
|
11043
|
+
"remains",
|
|
11044
|
+
"remain",
|
|
11045
|
+
"remained",
|
|
11046
|
+
"stays",
|
|
11047
|
+
"stay",
|
|
11048
|
+
"stayed",
|
|
11049
|
+
"get",
|
|
11050
|
+
"gets",
|
|
11051
|
+
"got",
|
|
11052
|
+
"getting",
|
|
11053
|
+
"should",
|
|
11054
|
+
"must",
|
|
11055
|
+
"needs",
|
|
11056
|
+
"need",
|
|
11057
|
+
"to",
|
|
11058
|
+
"has",
|
|
11059
|
+
"have",
|
|
11060
|
+
"had",
|
|
11061
|
+
"will",
|
|
11062
|
+
"would",
|
|
11063
|
+
"can",
|
|
11064
|
+
"could",
|
|
11065
|
+
"may",
|
|
11066
|
+
"might",
|
|
11067
|
+
"do",
|
|
11068
|
+
"does",
|
|
11069
|
+
"did",
|
|
11070
|
+
"not",
|
|
11071
|
+
"also",
|
|
11072
|
+
"then",
|
|
11073
|
+
"than",
|
|
11074
|
+
"so",
|
|
11075
|
+
"if",
|
|
11076
|
+
"when",
|
|
11077
|
+
"while",
|
|
11078
|
+
"because",
|
|
11079
|
+
"since",
|
|
11080
|
+
"unless",
|
|
11081
|
+
"which",
|
|
11082
|
+
"that",
|
|
11083
|
+
"where",
|
|
11084
|
+
"how",
|
|
11085
|
+
"what",
|
|
11086
|
+
"why",
|
|
11087
|
+
"and",
|
|
11088
|
+
"or",
|
|
11089
|
+
"but",
|
|
11090
|
+
"there",
|
|
11091
|
+
"it",
|
|
11092
|
+
"its",
|
|
11093
|
+
"we",
|
|
11094
|
+
"you",
|
|
11095
|
+
"they"
|
|
11096
|
+
]);
|
|
11097
|
+
TRAILING_PREPOSITION_TOKENS = new Set([
|
|
11098
|
+
"for",
|
|
11099
|
+
"in",
|
|
11100
|
+
"on",
|
|
11101
|
+
"at",
|
|
11102
|
+
"of",
|
|
11103
|
+
"with",
|
|
11104
|
+
"to",
|
|
11105
|
+
"from",
|
|
11106
|
+
"by",
|
|
11107
|
+
"during",
|
|
11108
|
+
"when",
|
|
11109
|
+
"while",
|
|
11110
|
+
"under",
|
|
11111
|
+
"within",
|
|
11112
|
+
"across",
|
|
11113
|
+
"per",
|
|
11114
|
+
"about",
|
|
11115
|
+
"into",
|
|
11116
|
+
"onto",
|
|
11117
|
+
"via",
|
|
11118
|
+
"using",
|
|
11119
|
+
"after",
|
|
11120
|
+
"before",
|
|
11121
|
+
"since",
|
|
11122
|
+
"until",
|
|
11123
|
+
"against",
|
|
11124
|
+
"between",
|
|
11125
|
+
"among",
|
|
11126
|
+
"like",
|
|
11127
|
+
"as",
|
|
11128
|
+
"than",
|
|
11129
|
+
"and",
|
|
11130
|
+
"or",
|
|
11131
|
+
"but",
|
|
11132
|
+
"so",
|
|
11133
|
+
"because",
|
|
11134
|
+
"over",
|
|
11135
|
+
"under"
|
|
11136
|
+
]);
|
|
11137
|
+
LEADING_TRIM_TOKENS = new Set([
|
|
11138
|
+
...DETERMINER_TOKENS,
|
|
11139
|
+
"for",
|
|
11140
|
+
"about",
|
|
11141
|
+
"regarding",
|
|
11142
|
+
"concerning",
|
|
11143
|
+
"with",
|
|
11144
|
+
"using",
|
|
11145
|
+
"via",
|
|
11146
|
+
"when",
|
|
11147
|
+
"while",
|
|
11148
|
+
"because",
|
|
11149
|
+
"since",
|
|
11150
|
+
"if"
|
|
11151
|
+
]);
|
|
11152
|
+
TRAILING_VERB_TOKENS = new Set([
|
|
11153
|
+
"bind",
|
|
11154
|
+
"binds",
|
|
11155
|
+
"binding",
|
|
11156
|
+
"run",
|
|
11157
|
+
"runs",
|
|
11158
|
+
"running",
|
|
11159
|
+
"listen",
|
|
11160
|
+
"listens",
|
|
11161
|
+
"listening",
|
|
11162
|
+
"serve",
|
|
11163
|
+
"serves",
|
|
11164
|
+
"serving",
|
|
11165
|
+
"use",
|
|
11166
|
+
"uses",
|
|
11167
|
+
"using",
|
|
11168
|
+
"connect",
|
|
11169
|
+
"connects",
|
|
11170
|
+
"connecting",
|
|
11171
|
+
"expose",
|
|
11172
|
+
"exposes",
|
|
11173
|
+
"exposing",
|
|
11174
|
+
"prefers",
|
|
11175
|
+
"prefer",
|
|
11176
|
+
"prefers",
|
|
11177
|
+
"target",
|
|
11178
|
+
"targets",
|
|
11179
|
+
"targeting",
|
|
11180
|
+
"serve",
|
|
11181
|
+
"serves",
|
|
11182
|
+
"provide",
|
|
11183
|
+
"provides",
|
|
11184
|
+
"providing",
|
|
11185
|
+
"keep",
|
|
11186
|
+
"keeps",
|
|
11187
|
+
"keeping",
|
|
11188
|
+
"always",
|
|
11189
|
+
"never"
|
|
11190
|
+
]);
|
|
11191
|
+
CLAUSE_BOUNDARIES = [".", ";", `
|
|
11192
|
+
`, "!", "?", "|"];
|
|
11193
|
+
TECHNOLOGY_TOKENS = new Set([
|
|
11194
|
+
"postgres",
|
|
11195
|
+
"postgresql",
|
|
11196
|
+
"mysql",
|
|
11197
|
+
"sqlite",
|
|
11198
|
+
"mongodb",
|
|
11199
|
+
"bun",
|
|
11200
|
+
"node",
|
|
11201
|
+
"deno",
|
|
11202
|
+
"rest",
|
|
11203
|
+
"graphql",
|
|
11204
|
+
"grpc",
|
|
11205
|
+
"dark",
|
|
11206
|
+
"light"
|
|
11207
|
+
]);
|
|
11208
|
+
STATUS_ADJECTIVES = [
|
|
11209
|
+
"enabled",
|
|
11210
|
+
"disabled",
|
|
11211
|
+
"active",
|
|
11212
|
+
"inactive",
|
|
11213
|
+
"allowed",
|
|
11214
|
+
"denied",
|
|
11215
|
+
"forbidden"
|
|
11216
|
+
];
|
|
11217
|
+
VERB_STATUS = {
|
|
11218
|
+
enable: "enabled",
|
|
11219
|
+
enables: "enabled",
|
|
11220
|
+
disable: "disabled",
|
|
11221
|
+
disables: "disabled",
|
|
11222
|
+
allow: "allowed",
|
|
11223
|
+
allows: "allowed",
|
|
11224
|
+
deny: "denied",
|
|
11225
|
+
denies: "denied"
|
|
11226
|
+
};
|
|
11227
|
+
DB_TARGETS = {
|
|
11228
|
+
postgres: "postgresql",
|
|
11229
|
+
postgresql: "postgresql",
|
|
11230
|
+
mysql: "mysql",
|
|
11231
|
+
sqlite: "sqlite",
|
|
11232
|
+
mongodb: "mongodb"
|
|
11233
|
+
};
|
|
11234
|
+
DB_ANCHOR_BEFORE = /\b(?:uses?|using|use\s+of|primary\s+database|database|db|engine|store|persistence|persisted\s+(?:in|to)|backed\s+by|runs?\s+on)\b[^A-Za-z0-9]{0,30}$/i;
|
|
11235
|
+
DB_ANCHOR_AFTER = /^\s*(?:is|as)\s+(?:the\s+)?(?:primary\s+)?(?:database|store|engine|db)\b/i;
|
|
11236
|
+
PROTOCOL_ANCHOR = /\b(api|protocol|service|endpoint|interface|route|client|server)\b/i;
|
|
11237
|
+
RELATION_LABELS = {
|
|
11238
|
+
status: "Opposing configuration polarity",
|
|
11239
|
+
database: "Conflicting primary database choice",
|
|
11240
|
+
port: "Conflicting port binding",
|
|
11241
|
+
protocol: "Conflicting communication protocol",
|
|
11242
|
+
runtime: "Conflicting runtime engine",
|
|
11243
|
+
theme: "Conflicting theme selection",
|
|
11244
|
+
policy: "Contradictory universal policy"
|
|
11245
|
+
};
|
|
11246
|
+
});
|
|
11247
|
+
|
|
10564
11248
|
// src/quality/contradiction.ts
|
|
10565
11249
|
import { randomUUID } from "node:crypto";
|
|
10566
|
-
function detectConflict(store, candidate) {
|
|
10567
|
-
const
|
|
11250
|
+
function detectConflict(store, candidate, options) {
|
|
11251
|
+
const dryRun = options?.dryRun === true;
|
|
11252
|
+
const candidateText = `${candidate.title || ""} ${candidate.content || ""}`;
|
|
11253
|
+
const candidateClaims = extractPolarityClaims(candidateText);
|
|
10568
11254
|
const entries = list(store, candidate.project ? { project: candidate.project } : undefined);
|
|
10569
11255
|
for (const entry of entries) {
|
|
10570
11256
|
if (candidate.id && entry.id === candidate.id)
|
|
@@ -10572,55 +11258,93 @@ function detectConflict(store, candidate) {
|
|
|
10572
11258
|
if (entry.status !== "active" && entry.status !== "confirmed" && entry.status !== "conflicted") {
|
|
10573
11259
|
continue;
|
|
10574
11260
|
}
|
|
10575
|
-
const
|
|
10576
|
-
|
|
10577
|
-
|
|
10578
|
-
|
|
10579
|
-
|
|
10580
|
-
|
|
10581
|
-
|
|
10582
|
-
|
|
11261
|
+
const existingTriples = entry.triples && entry.triples.length > 0 ? extractFactTriples(entry) : [];
|
|
11262
|
+
const candidateTriples = candidate.triples && candidate.triples.length > 0 ? extractFactTriples(candidate) : [];
|
|
11263
|
+
if (existingTriples.length > 0 && candidateTriples.length > 0) {
|
|
11264
|
+
for (const existingTriple of existingTriples) {
|
|
11265
|
+
for (const candidateTriple of candidateTriples) {
|
|
11266
|
+
const alignment = evaluateScopedAlignment(existingTriple, candidateTriple);
|
|
11267
|
+
if (alignment.aligned && alignment.conflicting) {
|
|
11268
|
+
return {
|
|
11269
|
+
conflicted: true,
|
|
11270
|
+
conflictingEntry: entry,
|
|
11271
|
+
confidence: 0.95,
|
|
11272
|
+
reason: alignment.reason,
|
|
11273
|
+
dryRun
|
|
11274
|
+
};
|
|
11275
|
+
}
|
|
10583
11276
|
}
|
|
10584
11277
|
}
|
|
10585
|
-
const combinedReason = pairReason ? `${pairReason}: ${scopedCheck.reason}` : scopedCheck.reason || `Scoped contradiction detected with "${entry.title}" (${entry.id})`;
|
|
10586
|
-
return {
|
|
10587
|
-
conflicted: true,
|
|
10588
|
-
conflictingEntry: entry,
|
|
10589
|
-
confidence: scopedCheck.confidence,
|
|
10590
|
-
reason: combinedReason
|
|
10591
|
-
};
|
|
10592
|
-
}
|
|
10593
|
-
if (scopedCheck.reason && !scopedCheck.aligned && !scopedCheck.shouldInvalidate) {
|
|
10594
|
-
continue;
|
|
10595
11278
|
}
|
|
10596
|
-
const entryText = `${entry.title} ${entry.content}
|
|
10597
|
-
const
|
|
10598
|
-
|
|
10599
|
-
for (const
|
|
10600
|
-
const
|
|
10601
|
-
|
|
10602
|
-
const aInEntry = patternA.test(entryText);
|
|
10603
|
-
const bInEntry = patternB.test(entryText);
|
|
10604
|
-
if (aInCand && bInEntry || bInCand && aInEntry) {
|
|
11279
|
+
const entryText = `${entry.title || ""} ${entry.content || ""}`;
|
|
11280
|
+
const entryClaims = extractPolarityClaims(entryText);
|
|
11281
|
+
for (const candidateClaim of candidateClaims) {
|
|
11282
|
+
for (const entryClaim of entryClaims) {
|
|
11283
|
+
const comparison = comparePolarityClaims(candidateClaim, entryClaim);
|
|
11284
|
+
if (comparison.conflicting) {
|
|
10605
11285
|
return {
|
|
10606
11286
|
conflicted: true,
|
|
10607
11287
|
conflictingEntry: entry,
|
|
10608
11288
|
confidence: 0.85,
|
|
10609
|
-
reason:
|
|
11289
|
+
reason: comparison.reason,
|
|
11290
|
+
dryRun
|
|
10610
11291
|
};
|
|
10611
11292
|
}
|
|
10612
11293
|
}
|
|
10613
|
-
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
|
|
10617
|
-
|
|
10618
|
-
|
|
10619
|
-
|
|
11294
|
+
}
|
|
11295
|
+
const candidateLower = candidateText.toLowerCase();
|
|
11296
|
+
const entryLower = entryText.toLowerCase();
|
|
11297
|
+
const topicSimilarity = computeJaccardSimilarity(candidate.title || "", entry.title || "");
|
|
11298
|
+
if (topicSimilarity > 0.6 && (candidateLower.includes("do not") && !entryLower.includes("do not") || !candidateLower.includes("do not") && entryLower.includes("do not"))) {
|
|
11299
|
+
return {
|
|
11300
|
+
conflicted: true,
|
|
11301
|
+
conflictingEntry: entry,
|
|
11302
|
+
confidence: 0.8,
|
|
11303
|
+
reason: `Direct negation detected on topic "${entry.title}" (${entry.id})`,
|
|
11304
|
+
dryRun
|
|
11305
|
+
};
|
|
11306
|
+
}
|
|
11307
|
+
}
|
|
11308
|
+
return { conflicted: false, confidence: 0, dryRun };
|
|
11309
|
+
}
|
|
11310
|
+
function scanPotentialConflicts(store, options) {
|
|
11311
|
+
const entries = list(store, options?.project ? { project: options.project } : undefined).filter((entry) => entry.status === "active" || entry.status === "confirmed");
|
|
11312
|
+
const claimsById = new Map;
|
|
11313
|
+
for (const entry of entries) {
|
|
11314
|
+
claimsById.set(entry.id, extractPolarityClaims(`${entry.title || ""} ${entry.content || ""}`));
|
|
11315
|
+
}
|
|
11316
|
+
const found = [];
|
|
11317
|
+
for (let i = 0;i < entries.length; i++) {
|
|
11318
|
+
for (let j = i + 1;j < entries.length; j++) {
|
|
11319
|
+
const a = entries[i];
|
|
11320
|
+
const b = entries[j];
|
|
11321
|
+
const aClaims = claimsById.get(a.id) ?? [];
|
|
11322
|
+
const bClaims = claimsById.get(b.id) ?? [];
|
|
11323
|
+
let conflict = null;
|
|
11324
|
+
for (const aClaim of aClaims) {
|
|
11325
|
+
for (const bClaim of bClaims) {
|
|
11326
|
+
const comparison = comparePolarityClaims(aClaim, bClaim);
|
|
11327
|
+
if (comparison.conflicting) {
|
|
11328
|
+
conflict = comparison;
|
|
11329
|
+
break;
|
|
11330
|
+
}
|
|
11331
|
+
}
|
|
11332
|
+
if (conflict)
|
|
11333
|
+
break;
|
|
11334
|
+
}
|
|
11335
|
+
if (conflict) {
|
|
11336
|
+
found.push({
|
|
11337
|
+
entry_a_id: a.id,
|
|
11338
|
+
entry_a_title: a.title,
|
|
11339
|
+
entry_b_id: b.id,
|
|
11340
|
+
entry_b_title: b.title,
|
|
11341
|
+
confidence: 0.85,
|
|
11342
|
+
reason: conflict.reason
|
|
11343
|
+
});
|
|
10620
11344
|
}
|
|
10621
11345
|
}
|
|
10622
11346
|
}
|
|
10623
|
-
return
|
|
11347
|
+
return options?.limit !== undefined ? found.slice(0, options.limit) : found;
|
|
10624
11348
|
}
|
|
10625
11349
|
function flagConflict(store, existingId, newId, reason, options) {
|
|
10626
11350
|
const existing = get(store, existingId);
|
|
@@ -10780,22 +11504,18 @@ function resolveConflict(store, options) {
|
|
|
10780
11504
|
message
|
|
10781
11505
|
};
|
|
10782
11506
|
}
|
|
10783
|
-
|
|
11507
|
+
function listConflicts(store, options) {
|
|
11508
|
+
if (!store.db)
|
|
11509
|
+
return [];
|
|
11510
|
+
return listConflictsFromDb(store.db, options);
|
|
11511
|
+
}
|
|
10784
11512
|
var init_contradiction = __esm(() => {
|
|
10785
11513
|
init_store();
|
|
10786
11514
|
init_audit();
|
|
10787
11515
|
init_dedup();
|
|
10788
11516
|
init_sqlite();
|
|
10789
11517
|
init_invalidation();
|
|
10790
|
-
|
|
10791
|
-
[/\b(enable|enabled|true)\b/i, /\b(disable|disabled|false)\b/i, "Opposing configuration polarity"],
|
|
10792
|
-
[/\b(allow|allowed)\b/i, /\b(deny|denied|disallow|disallowed|forbidden)\b/i, "Opposing permission rule"],
|
|
10793
|
-
[/\b(uses?\s+postgresql|postgres)\b/i, /\b(uses?\s+mysql|uses?\s+sqlite|uses?\s+mongodb)\b/i, "Conflicting primary database choice"],
|
|
10794
|
-
[/\b(port\s+3000)\b/i, /\b(port\s+8080|port\s+5000|port\s+4000)\b/i, "Conflicting port binding"],
|
|
10795
|
-
[/\b(rest\s+api)\b/i, /\b(graphql\s+only|grpc\s+only)\b/i, "Conflicting communication protocol"],
|
|
10796
|
-
[/\b(bun\s+runtime)\b/i, /\b(node\s+runtime\s+only|deno\s+only)\b/i, "Conflicting runtime engine"],
|
|
10797
|
-
[/\b(always)\b/i, /\b(never)\b/i, "Contradictory universal policy"]
|
|
10798
|
-
];
|
|
11518
|
+
init_polarity();
|
|
10799
11519
|
});
|
|
10800
11520
|
|
|
10801
11521
|
// src/quality/retention.ts
|
|
@@ -13142,6 +13862,9 @@ async function rankAndRetrieveMemories(store, query, options = {}) {
|
|
|
13142
13862
|
if (!options.includeSuperseded) {
|
|
13143
13863
|
entries = entries.filter((e) => e.status !== "superseded" && e.status !== "rejected");
|
|
13144
13864
|
}
|
|
13865
|
+
if (!options.includeConflicted) {
|
|
13866
|
+
entries = entries.filter((e) => e.status !== "conflicted");
|
|
13867
|
+
}
|
|
13145
13868
|
if (options.sessionId && options.suppressReinjection !== false) {
|
|
13146
13869
|
const filtered = defaultReinjectionTracker.filterSuppressed(options.sessionId, entries, {
|
|
13147
13870
|
turn: options.sessionTurn,
|
|
@@ -13441,6 +14164,8 @@ function passesRowFilter(entry, o, now) {
|
|
|
13441
14164
|
return false;
|
|
13442
14165
|
if (!o.includeSuperseded && (entry.status === "superseded" || entry.status === "rejected"))
|
|
13443
14166
|
return false;
|
|
14167
|
+
if (!o.includeConflicted && entry.status === "conflicted")
|
|
14168
|
+
return false;
|
|
13444
14169
|
if (!o.includeArchived && entry.status === "archived")
|
|
13445
14170
|
return false;
|
|
13446
14171
|
if (!o.includeExpired && isExpired(entry, now))
|
|
@@ -13926,6 +14651,10 @@ function list(store, filters) {
|
|
|
13926
14651
|
}
|
|
13927
14652
|
return entries;
|
|
13928
14653
|
}
|
|
14654
|
+
function listForProject(store, project) {
|
|
14655
|
+
const trimmed = project?.trim();
|
|
14656
|
+
return trimmed ? list(store, { project: trimmed }) : list(store);
|
|
14657
|
+
}
|
|
13929
14658
|
function countMemories(store) {
|
|
13930
14659
|
if (store.circuit?.isDegraded() && store.cache) {
|
|
13931
14660
|
return store.cache.size();
|
|
@@ -14318,14 +15047,30 @@ function propose(store, opts) {
|
|
|
14318
15047
|
}
|
|
14319
15048
|
}
|
|
14320
15049
|
if (opts.checkConflict) {
|
|
15050
|
+
const conflictDryRun = opts.conflictDryRun === true;
|
|
14321
15051
|
const conflict = detectConflict(store, {
|
|
14322
15052
|
title: entry.title,
|
|
14323
15053
|
content: entry.content,
|
|
14324
15054
|
project: entry.project,
|
|
14325
15055
|
type: entry.type,
|
|
14326
15056
|
id: entry.id
|
|
14327
|
-
});
|
|
15057
|
+
}, { dryRun: conflictDryRun });
|
|
14328
15058
|
if (conflict.conflicted && conflict.conflictingEntry) {
|
|
15059
|
+
if (conflictDryRun) {
|
|
15060
|
+
if (store.memoryDir) {
|
|
15061
|
+
recordAuditEvent(store.memoryDir, {
|
|
15062
|
+
operation: "conflict_detected_dry_run",
|
|
15063
|
+
entry_id: entry.id,
|
|
15064
|
+
project: entry.project,
|
|
15065
|
+
details: {
|
|
15066
|
+
would_conflict_with: conflict.conflictingEntry.id,
|
|
15067
|
+
reason: conflict.reason || "Contradiction detected",
|
|
15068
|
+
confidence: conflict.confidence
|
|
15069
|
+
}
|
|
15070
|
+
});
|
|
15071
|
+
}
|
|
15072
|
+
return entry;
|
|
15073
|
+
}
|
|
14329
15074
|
const flagged = flagConflict(store, conflict.conflictingEntry.id, entry.id, conflict.reason || "Contradiction detected");
|
|
14330
15075
|
return flagged.incoming;
|
|
14331
15076
|
}
|
|
@@ -18686,7 +19431,7 @@ async function getLatestNpmVersion(packageName = "musememory") {
|
|
|
18686
19431
|
try {
|
|
18687
19432
|
const res = await fetch(`https://registry.npmjs.org/${packageName}/latest`, {
|
|
18688
19433
|
headers: { Accept: "application/json" },
|
|
18689
|
-
signal: AbortSignal.timeout(
|
|
19434
|
+
signal: AbortSignal.timeout(2000)
|
|
18690
19435
|
});
|
|
18691
19436
|
if (res.ok) {
|
|
18692
19437
|
const data = await res.json();
|
|
@@ -18698,6 +19443,7 @@ async function getLatestNpmVersion(packageName = "musememory") {
|
|
|
18698
19443
|
try {
|
|
18699
19444
|
const out = execFileSync("npm", ["show", packageName, "version"], {
|
|
18700
19445
|
encoding: "utf8",
|
|
19446
|
+
timeout: 1500,
|
|
18701
19447
|
stdio: ["ignore", "pipe", "ignore"]
|
|
18702
19448
|
}).trim();
|
|
18703
19449
|
if (out && !out.includes("error"))
|
|
@@ -26181,7 +26927,6 @@ function getStandardAgentTranscriptDirs(home = homedir5()) {
|
|
|
26181
26927
|
join36(home, ".local", "share", "opencode", "transcripts"),
|
|
26182
26928
|
join36(home, ".claude", "transcripts"),
|
|
26183
26929
|
join36(home, ".claude", "projects"),
|
|
26184
|
-
join36(home, ".config", "LIFEOS", "runtime", "transcripts"),
|
|
26185
26930
|
join36(home, ".hermes", "sessions"),
|
|
26186
26931
|
join36(home, ".hermes", "transcripts"),
|
|
26187
26932
|
join36(home, ".config", "goose", "sessions"),
|
|
@@ -27312,7 +28057,7 @@ var init_pack = __esm(() => {
|
|
|
27312
28057
|
// src/retrieval/tree-index.ts
|
|
27313
28058
|
import { existsSync as existsSync43, readFileSync as readFileSync37, writeFileSync as writeFileSync26, mkdirSync as mkdirSync25, rmSync } from "node:fs";
|
|
27314
28059
|
import { join as join40 } from "node:path";
|
|
27315
|
-
function
|
|
28060
|
+
function tokenize3(text) {
|
|
27316
28061
|
if (!text || typeof text !== "string")
|
|
27317
28062
|
return [];
|
|
27318
28063
|
return text.toLowerCase().match(/[a-z0-9]+/g) ?? [];
|
|
@@ -27546,10 +28291,10 @@ function selectPartitions(index, options) {
|
|
|
27546
28291
|
return result;
|
|
27547
28292
|
}
|
|
27548
28293
|
function scoreNode(node, query) {
|
|
27549
|
-
const queryTokens = new Set(
|
|
28294
|
+
const queryTokens = new Set(tokenize3(query));
|
|
27550
28295
|
if (queryTokens.size === 0)
|
|
27551
28296
|
return 0;
|
|
27552
|
-
const haystack =
|
|
28297
|
+
const haystack = tokenize3(`${node.title} ${node.summary} ${(node.metadata?.tags ?? []).join(" ")}`);
|
|
27553
28298
|
const hay = new Set(haystack);
|
|
27554
28299
|
let overlap = 0;
|
|
27555
28300
|
for (const t of queryTokens)
|
|
@@ -28019,6 +28764,7 @@ class RetrievalEngine {
|
|
|
28019
28764
|
limit: options.limit !== undefined ? clampLimit(options.limit, 10, 200, 1) : 10,
|
|
28020
28765
|
project: options.project,
|
|
28021
28766
|
includeSuperseded: options.includeSuperseded,
|
|
28767
|
+
includeConflicted: options.includeConflicted,
|
|
28022
28768
|
includeArchived: options.includeArchived,
|
|
28023
28769
|
includeExpired: options.includeExpired,
|
|
28024
28770
|
now: options.now
|
|
@@ -29032,8 +29778,8 @@ function attachAnchorToMemory(store, memoryId, anchor, actor = "agent", options
|
|
|
29032
29778
|
}
|
|
29033
29779
|
return entry;
|
|
29034
29780
|
}
|
|
29035
|
-
function auditMemoryAnchors(store, workspaceRoot) {
|
|
29036
|
-
const entries =
|
|
29781
|
+
function auditMemoryAnchors(store, workspaceRoot, options) {
|
|
29782
|
+
const entries = listForProject(store, options?.project);
|
|
29037
29783
|
const details = [];
|
|
29038
29784
|
let validCount = 0;
|
|
29039
29785
|
let driftedCount = 0;
|
|
@@ -29181,8 +29927,8 @@ function extractExportedSymbols(filePath) {
|
|
|
29181
29927
|
}
|
|
29182
29928
|
return symbols;
|
|
29183
29929
|
}
|
|
29184
|
-
function detectDocumentationCodeDrift(store, workspaceRoot) {
|
|
29185
|
-
const allEntries =
|
|
29930
|
+
function detectDocumentationCodeDrift(store, workspaceRoot, options) {
|
|
29931
|
+
const allEntries = listForProject(store, options?.project);
|
|
29186
29932
|
const items = [];
|
|
29187
29933
|
let documentedCount = 0;
|
|
29188
29934
|
let implementedCount = 0;
|
|
@@ -29314,7 +30060,7 @@ function scanFiles(dir, maxFiles = 50) {
|
|
|
29314
30060
|
walk(dir);
|
|
29315
30061
|
return files;
|
|
29316
30062
|
}
|
|
29317
|
-
function analyzeTechnicalDebt(store, workspaceRoot) {
|
|
30063
|
+
function analyzeTechnicalDebt(store, workspaceRoot, options) {
|
|
29318
30064
|
const items = [];
|
|
29319
30065
|
const hotspotMap = new Map;
|
|
29320
30066
|
const sourceFiles = scanFiles(workspaceRoot, 40);
|
|
@@ -29358,7 +30104,7 @@ function analyzeTechnicalDebt(store, workspaceRoot) {
|
|
|
29358
30104
|
}
|
|
29359
30105
|
}
|
|
29360
30106
|
}
|
|
29361
|
-
const allEntries =
|
|
30107
|
+
const allEntries = listForProject(store, options?.project);
|
|
29362
30108
|
for (const entry of allEntries) {
|
|
29363
30109
|
if (entry.status === "archived" || entry.status === "superseded")
|
|
29364
30110
|
continue;
|
|
@@ -29426,8 +30172,8 @@ function classifyBug(entry) {
|
|
|
29426
30172
|
}
|
|
29427
30173
|
return "general_bug";
|
|
29428
30174
|
}
|
|
29429
|
-
function clusterRecurringBugsAndFriction(store) {
|
|
29430
|
-
const entries =
|
|
30175
|
+
function clusterRecurringBugsAndFriction(store, options) {
|
|
30176
|
+
const entries = listForProject(store, options?.project);
|
|
29431
30177
|
const bugEntries = entries.filter((e) => e.status !== "archived" && (e.type === "fix" || e.type === "negative" || e.negative != null || e.tags?.includes("bug") || e.tags?.includes("fix") || e.tags?.includes("failure") || e.tags?.includes("error")));
|
|
29432
30178
|
const clusterMap = new Map;
|
|
29433
30179
|
for (const entry of bugEntries) {
|
|
@@ -29533,9 +30279,10 @@ function scoreToStatus(score) {
|
|
|
29533
30279
|
return "WARN";
|
|
29534
30280
|
return "FAIL";
|
|
29535
30281
|
}
|
|
29536
|
-
function evaluateProjectHealth(store, workspaceRoot) {
|
|
30282
|
+
function evaluateProjectHealth(store, workspaceRoot, options) {
|
|
29537
30283
|
const now = new Date().toISOString();
|
|
29538
|
-
const
|
|
30284
|
+
const projectFilter = options?.project?.trim() || undefined;
|
|
30285
|
+
const entries = listForProject(store, projectFilter);
|
|
29539
30286
|
const checklist = [];
|
|
29540
30287
|
let activeCount = 0;
|
|
29541
30288
|
let confirmedCount = 0;
|
|
@@ -29578,7 +30325,7 @@ function evaluateProjectHealth(store, workspaceRoot) {
|
|
|
29578
30325
|
},
|
|
29579
30326
|
remediation_items: integrityRemediations
|
|
29580
30327
|
};
|
|
29581
|
-
const anchorAudit = auditMemoryAnchors(store, workspaceRoot);
|
|
30328
|
+
const anchorAudit = auditMemoryAnchors(store, workspaceRoot, { project: projectFilter });
|
|
29582
30329
|
const anchorScore = Math.round(anchorAudit.integrity_score * 100);
|
|
29583
30330
|
const anchorRemediations = [];
|
|
29584
30331
|
if (anchorAudit.drifted_anchors > 0) {
|
|
@@ -29601,7 +30348,7 @@ function evaluateProjectHealth(store, workspaceRoot) {
|
|
|
29601
30348
|
},
|
|
29602
30349
|
remediation_items: anchorRemediations
|
|
29603
30350
|
};
|
|
29604
|
-
const driftAudit = detectDocumentationCodeDrift(store, workspaceRoot);
|
|
30351
|
+
const driftAudit = detectDocumentationCodeDrift(store, workspaceRoot, { project: projectFilter });
|
|
29605
30352
|
const driftScore = Math.round(driftAudit.alignment_score * 100);
|
|
29606
30353
|
const driftRemediations = [];
|
|
29607
30354
|
if (driftAudit.missing_count > 0) {
|
|
@@ -29655,8 +30402,8 @@ function evaluateProjectHealth(store, workspaceRoot) {
|
|
|
29655
30402
|
},
|
|
29656
30403
|
remediation_items: negativeRemediations
|
|
29657
30404
|
};
|
|
29658
|
-
const debtReport = analyzeTechnicalDebt(store, workspaceRoot);
|
|
29659
|
-
const bugClusters = clusterRecurringBugsAndFriction(store);
|
|
30405
|
+
const debtReport = analyzeTechnicalDebt(store, workspaceRoot, { project: projectFilter });
|
|
30406
|
+
const bugClusters = clusterRecurringBugsAndFriction(store, { project: projectFilter });
|
|
29660
30407
|
const topFragility = bugClusters.length > 0 ? bugClusters[0].fragility_score : 0;
|
|
29661
30408
|
const debtPenalty = debtReport.debt_score + Math.round(topFragility * 20);
|
|
29662
30409
|
const debtScore = Math.max(0, Math.min(100, 100 - debtPenalty));
|
|
@@ -29682,7 +30429,16 @@ function evaluateProjectHealth(store, workspaceRoot) {
|
|
|
29682
30429
|
checklist.push(...docCodeAlignmentPillar.remediation_items);
|
|
29683
30430
|
checklist.push(...negativeAntiPatternsPillar.remediation_items);
|
|
29684
30431
|
checklist.push(...techDebtPillar.remediation_items);
|
|
29685
|
-
const
|
|
30432
|
+
const projectsCovered = [
|
|
30433
|
+
...new Set(entries.map((e) => e.project).filter((p) => Boolean(p)))
|
|
30434
|
+
].sort();
|
|
30435
|
+
const projectName = projectFilter ?? (projectsCovered.length === 1 ? projectsCovered[0] : "all");
|
|
30436
|
+
const scope = {
|
|
30437
|
+
filter: projectFilter ?? null,
|
|
30438
|
+
projects: projectsCovered,
|
|
30439
|
+
entry_count: entries.length,
|
|
30440
|
+
code_scope: "workspace"
|
|
30441
|
+
};
|
|
29686
30442
|
let summary = `Project health evaluated with overall Grade ${overallGrade} (${overallScore}/100) — Status: ${gateStatus}.`;
|
|
29687
30443
|
if (gateStatus === "PASS") {
|
|
29688
30444
|
summary += " All 5 pillars meet production hardening criteria.";
|
|
@@ -29691,8 +30447,10 @@ function evaluateProjectHealth(store, workspaceRoot) {
|
|
|
29691
30447
|
} else {
|
|
29692
30448
|
summary += " Critical architectural violations or unverified contradictions must be resolved before sign-off.";
|
|
29693
30449
|
}
|
|
30450
|
+
summary += ` Scope: ${projectFilter ? `project "${projectFilter}"` : "entire store"} (${entries.length} memories across ${projectsCovered.length} project${projectsCovered.length === 1 ? "" : "s"}); code-side metrics cover the workspace.`;
|
|
29694
30451
|
return {
|
|
29695
30452
|
project: projectName,
|
|
30453
|
+
scope,
|
|
29696
30454
|
timestamp: now,
|
|
29697
30455
|
overall_score: overallScore,
|
|
29698
30456
|
overall_grade: overallGrade,
|
|
@@ -29919,10 +30677,35 @@ var init_reconcile = __esm(() => {
|
|
|
29919
30677
|
init_resolver();
|
|
29920
30678
|
});
|
|
29921
30679
|
|
|
30680
|
+
// src/health/resolve.ts
|
|
30681
|
+
function listProjectNames(store) {
|
|
30682
|
+
return [
|
|
30683
|
+
...new Set(list(store).map((e) => e.project).filter((p) => Boolean(p)))
|
|
30684
|
+
].sort();
|
|
30685
|
+
}
|
|
30686
|
+
function resolveProjectName(store, requested) {
|
|
30687
|
+
const name = requested?.trim();
|
|
30688
|
+
if (!name)
|
|
30689
|
+
return;
|
|
30690
|
+
const projects = listProjectNames(store);
|
|
30691
|
+
if (projects.includes(name))
|
|
30692
|
+
return name;
|
|
30693
|
+
const matches = projects.filter((p) => p.toLowerCase() === name.toLowerCase());
|
|
30694
|
+
return matches.length === 1 ? matches[0] : undefined;
|
|
30695
|
+
}
|
|
30696
|
+
function formatAvailable(store) {
|
|
30697
|
+
const available = listProjectNames(store);
|
|
30698
|
+
return available.length > 0 ? available.join(", ") : "none";
|
|
30699
|
+
}
|
|
30700
|
+
var init_resolve = __esm(() => {
|
|
30701
|
+
init_store();
|
|
30702
|
+
});
|
|
30703
|
+
|
|
29922
30704
|
// src/health/index.ts
|
|
29923
30705
|
var init_health = __esm(() => {
|
|
29924
30706
|
init_gate();
|
|
29925
30707
|
init_reconcile();
|
|
30708
|
+
init_resolve();
|
|
29926
30709
|
});
|
|
29927
30710
|
// src/adrs/engine.ts
|
|
29928
30711
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
@@ -31290,7 +32073,18 @@ function startUiServer(opts) {
|
|
|
31290
32073
|
const workspaceRoot = opts.store.layout?.root || getStorageLayout(opts.memoryDir).root;
|
|
31291
32074
|
if (pathname === "/api/health" && req.method === "GET") {
|
|
31292
32075
|
try {
|
|
31293
|
-
const
|
|
32076
|
+
const requestedProject = url.searchParams.get("project")?.trim() || undefined;
|
|
32077
|
+
const canonicalProject = resolveProjectName(opts.store, requestedProject);
|
|
32078
|
+
if (requestedProject && canonicalProject === undefined) {
|
|
32079
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
32080
|
+
res.end(JSON.stringify({
|
|
32081
|
+
error: `no memories for project "${requestedProject}" — available: ${formatAvailable(opts.store)}`
|
|
32082
|
+
}));
|
|
32083
|
+
return;
|
|
32084
|
+
}
|
|
32085
|
+
const report = evaluateProjectHealth(opts.store, workspaceRoot, {
|
|
32086
|
+
project: canonicalProject
|
|
32087
|
+
});
|
|
31294
32088
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
31295
32089
|
res.end(JSON.stringify(report));
|
|
31296
32090
|
} catch (err) {
|
|
@@ -31312,7 +32106,18 @@ function startUiServer(opts) {
|
|
|
31312
32106
|
}
|
|
31313
32107
|
if (pathname === "/api/drift" && req.method === "GET") {
|
|
31314
32108
|
try {
|
|
31315
|
-
const
|
|
32109
|
+
const requestedProject = url.searchParams.get("project")?.trim() || undefined;
|
|
32110
|
+
const canonicalProject = resolveProjectName(opts.store, requestedProject);
|
|
32111
|
+
if (requestedProject && canonicalProject === undefined) {
|
|
32112
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
32113
|
+
res.end(JSON.stringify({
|
|
32114
|
+
error: `no memories for project "${requestedProject}" — available: ${formatAvailable(opts.store)}`
|
|
32115
|
+
}));
|
|
32116
|
+
return;
|
|
32117
|
+
}
|
|
32118
|
+
const drift = detectDocumentationCodeDrift(opts.store, workspaceRoot, {
|
|
32119
|
+
project: canonicalProject
|
|
32120
|
+
});
|
|
31316
32121
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
31317
32122
|
res.end(JSON.stringify(drift));
|
|
31318
32123
|
} catch (err) {
|
|
@@ -31340,7 +32145,18 @@ function startUiServer(opts) {
|
|
|
31340
32145
|
}
|
|
31341
32146
|
if (pathname === "/api/cognition/clusters" && req.method === "GET") {
|
|
31342
32147
|
try {
|
|
31343
|
-
const
|
|
32148
|
+
const requestedProject = url.searchParams.get("project")?.trim() || undefined;
|
|
32149
|
+
const canonicalProject = resolveProjectName(opts.store, requestedProject);
|
|
32150
|
+
if (requestedProject && canonicalProject === undefined) {
|
|
32151
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
32152
|
+
res.end(JSON.stringify({
|
|
32153
|
+
error: `no memories for project "${requestedProject}" — available: ${formatAvailable(opts.store)}`
|
|
32154
|
+
}));
|
|
32155
|
+
return;
|
|
32156
|
+
}
|
|
32157
|
+
const clusters = clusterRecurringBugsAndFriction(opts.store, {
|
|
32158
|
+
project: canonicalProject
|
|
32159
|
+
});
|
|
31344
32160
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
31345
32161
|
res.end(JSON.stringify({ total_clusters: clusters.length, clusters }));
|
|
31346
32162
|
} catch (err) {
|
|
@@ -31351,7 +32167,18 @@ function startUiServer(opts) {
|
|
|
31351
32167
|
}
|
|
31352
32168
|
if (pathname === "/api/cognition/debt" && req.method === "GET") {
|
|
31353
32169
|
try {
|
|
31354
|
-
const
|
|
32170
|
+
const requestedProject = url.searchParams.get("project")?.trim() || undefined;
|
|
32171
|
+
const canonicalProject = resolveProjectName(opts.store, requestedProject);
|
|
32172
|
+
if (requestedProject && canonicalProject === undefined) {
|
|
32173
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
32174
|
+
res.end(JSON.stringify({
|
|
32175
|
+
error: `no memories for project "${requestedProject}" — available: ${formatAvailable(opts.store)}`
|
|
32176
|
+
}));
|
|
32177
|
+
return;
|
|
32178
|
+
}
|
|
32179
|
+
const debt = analyzeTechnicalDebt(opts.store, workspaceRoot, {
|
|
32180
|
+
project: canonicalProject
|
|
32181
|
+
});
|
|
31355
32182
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
31356
32183
|
res.end(JSON.stringify(debt));
|
|
31357
32184
|
} catch (err) {
|
|
@@ -31589,6 +32416,10 @@ var MAX_BODY_SIZE, EMBEDDED_HTML = `<!DOCTYPE html>
|
|
|
31589
32416
|
|
|
31590
32417
|
/* Stats & Quick Actions */
|
|
31591
32418
|
.header-actions { display: flex; align-items: center; gap: 12px; }
|
|
32419
|
+
.scope-filter { display: flex; align-items: center; gap: 8px; }
|
|
32420
|
+
.scope-filter-label { font-size: 10px; font-weight: 700; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.05em; white-space: nowrap; }
|
|
32421
|
+
.scope-filter-input { width: 140px; background: #090d14; border: 1px solid var(--panel-border); border-radius: var(--radius-md); padding: 6px 10px; color: #fff; font-size: 12px; outline: none; transition: var(--transition); }
|
|
32422
|
+
.scope-filter-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); }
|
|
31592
32423
|
.status-badge { font-size: 12px; font-weight: 600; background: rgba(16,185,129,0.12); color: var(--green); padding: 5px 12px; border-radius: var(--radius-full); border: 1px solid rgba(16,185,129,0.25); display: flex; align-items: center; gap: 6px; }
|
|
31593
32424
|
.status-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--green); box-shadow: 0 0 8px var(--green); }
|
|
31594
32425
|
.btn-icon { background: rgba(255,255,255,0.04); border: 1px solid var(--panel-border); color: var(--text-muted); padding: 6px 12px; border-radius: var(--radius-md); font-size: 12px; font-weight: 600; cursor: pointer; transition: var(--transition); display: inline-flex; align-items: center; gap: 6px; }
|
|
@@ -31795,6 +32626,10 @@ var MAX_BODY_SIZE, EMBEDDED_HTML = `<!DOCTYPE html>
|
|
|
31795
32626
|
</div>
|
|
31796
32627
|
|
|
31797
32628
|
<div class="header-actions">
|
|
32629
|
+
<div class="scope-filter">
|
|
32630
|
+
<label class="scope-filter-label" for="projectFilter">Project Scope</label>
|
|
32631
|
+
<input type="text" id="projectFilter" class="scope-filter-input" placeholder="all projects" autocomplete="off" spellcheck="false" title="Leave empty to audit the whole memory store, or enter a project name to scope the health gate, drift, bug cluster and technical debt audits." />
|
|
32632
|
+
</div>
|
|
31798
32633
|
<button class="btn-icon btn-refresh" id="refreshBtn" onclick="refreshMemories()" title="Refresh and sync active constraints, handoff state, and prior memories">
|
|
31799
32634
|
<span class="refresh-icon" id="refreshIcon">\uD83D\uDD04</span>
|
|
31800
32635
|
<span id="refreshLabel">Refresh</span>
|
|
@@ -31977,6 +32812,10 @@ var MAX_BODY_SIZE, EMBEDDED_HTML = `<!DOCTYPE html>
|
|
|
31977
32812
|
<span class="gate-badge gate-pass" id="healthGate">[PASS]</span>
|
|
31978
32813
|
</div>
|
|
31979
32814
|
<div style="font-size:13px; color:var(--text-muted); margin-top:3px;" id="healthSummary">Comprehensive project cognitive health evaluation.</div>
|
|
32815
|
+
<div style="font-size:11px; color:var(--text-dim); margin-top:6px; display:flex; gap:14px; flex-wrap:wrap;">
|
|
32816
|
+
<span id="healthScopeProject">Project: --</span>
|
|
32817
|
+
<span id="healthScope">Scope: --</span>
|
|
32818
|
+
</div>
|
|
31980
32819
|
</div>
|
|
31981
32820
|
</div>
|
|
31982
32821
|
<div style="text-align:right;">
|
|
@@ -32213,6 +33052,36 @@ var MAX_BODY_SIZE, EMBEDDED_HTML = `<!DOCTYPE html>
|
|
|
32213
33052
|
let searchQuery = '';
|
|
32214
33053
|
let currentTab = 'graph';
|
|
32215
33054
|
|
|
33055
|
+
// T-321: optional project scope for the studio's audit surfaces.
|
|
33056
|
+
// An empty value means the whole store; a value scopes the health gate,
|
|
33057
|
+
// drift, bug cluster and technical debt audits to that memory project.
|
|
33058
|
+
// The initial value comes from the URL query string so a scoped link
|
|
33059
|
+
// stays shareable and reloadable.
|
|
33060
|
+
let projectScope = (new URLSearchParams(window.location.search).get('project') || '').trim();
|
|
33061
|
+
|
|
33062
|
+
function projectScopeQuery() {
|
|
33063
|
+
return projectScope ? '?project=' + encodeURIComponent(projectScope) : '';
|
|
33064
|
+
}
|
|
33065
|
+
|
|
33066
|
+
function syncProjectScopeUrl() {
|
|
33067
|
+
try {
|
|
33068
|
+
const url = new URL(window.location.href);
|
|
33069
|
+
if (projectScope) url.searchParams.set('project', projectScope);
|
|
33070
|
+
else url.searchParams.delete('project');
|
|
33071
|
+
window.history.replaceState({}, '', url.toString());
|
|
33072
|
+
} catch (err) {
|
|
33073
|
+
console.error('Failed to sync project scope in URL:', err);
|
|
33074
|
+
}
|
|
33075
|
+
}
|
|
33076
|
+
|
|
33077
|
+
function applyProjectScope(value) {
|
|
33078
|
+
projectScope = (value || '').trim();
|
|
33079
|
+
syncProjectScopeUrl();
|
|
33080
|
+
fetchHealth();
|
|
33081
|
+
if (currentTab === 'adrs') fetchDrift();
|
|
33082
|
+
if (currentTab === 'cognition') fetchCognition();
|
|
33083
|
+
}
|
|
33084
|
+
|
|
32216
33085
|
// ---- Graph state (3D force-directed) ----
|
|
32217
33086
|
const TYPE_COLORS = {
|
|
32218
33087
|
fix: '#10b981',
|
|
@@ -32879,7 +33748,7 @@ var MAX_BODY_SIZE, EMBEDDED_HTML = `<!DOCTYPE html>
|
|
|
32879
33748
|
// R15 Studio Loaders
|
|
32880
33749
|
async function fetchHealth() {
|
|
32881
33750
|
try {
|
|
32882
|
-
const res = await fetch('/api/health');
|
|
33751
|
+
const res = await fetch('/api/health' + projectScopeQuery());
|
|
32883
33752
|
const data = await res.json();
|
|
32884
33753
|
renderHealth(data);
|
|
32885
33754
|
} catch (err) {
|
|
@@ -32887,12 +33756,25 @@ var MAX_BODY_SIZE, EMBEDDED_HTML = `<!DOCTYPE html>
|
|
|
32887
33756
|
}
|
|
32888
33757
|
}
|
|
32889
33758
|
|
|
33759
|
+
// T-321: mirrors the CLI scope wording — "N memories across M project(s)".
|
|
33760
|
+
function formatHealthScope(scope) {
|
|
33761
|
+
if (!scope) return 'Scope: --';
|
|
33762
|
+
const count = scope.entry_count || 0;
|
|
33763
|
+
const projectCount = (scope.projects || []).length;
|
|
33764
|
+
const memories = count === 1 ? 'memory' : 'memories';
|
|
33765
|
+
const projects = projectCount === 1 ? 'project' : 'projects';
|
|
33766
|
+
const label = scope.filter ? 'project "' + scope.filter + '"' : 'entire store';
|
|
33767
|
+
return 'Scope: ' + label + ' (' + count + ' ' + memories + ' across ' + projectCount + ' ' + projects + '); code-side metrics cover the ' + (scope.code_scope || 'workspace') + '.';
|
|
33768
|
+
}
|
|
33769
|
+
|
|
32890
33770
|
function renderHealth(data) {
|
|
32891
33771
|
if (!data) return;
|
|
32892
33772
|
const gradeEl = document.getElementById('healthGrade');
|
|
32893
33773
|
const scoreEl = document.getElementById('healthScore');
|
|
32894
33774
|
const gateEl = document.getElementById('healthGate');
|
|
32895
33775
|
const summaryEl = document.getElementById('healthSummary');
|
|
33776
|
+
const scopeEl = document.getElementById('healthScope');
|
|
33777
|
+
const scopeProjectEl = document.getElementById('healthScopeProject');
|
|
32896
33778
|
const grade = data.overall_grade || data.grade || '--';
|
|
32897
33779
|
const score = data.overall_score !== undefined ? data.overall_score : (data.score || 0);
|
|
32898
33780
|
if (gradeEl) {
|
|
@@ -32905,6 +33787,8 @@ var MAX_BODY_SIZE, EMBEDDED_HTML = `<!DOCTYPE html>
|
|
|
32905
33787
|
gateEl.className = 'gate-badge gate-' + (data.gate_status || 'WARN').toLowerCase();
|
|
32906
33788
|
}
|
|
32907
33789
|
if (summaryEl) summaryEl.textContent = data.summary || '';
|
|
33790
|
+
if (scopeEl) scopeEl.textContent = formatHealthScope(data.scope);
|
|
33791
|
+
if (scopeProjectEl) scopeProjectEl.textContent = 'Project: ' + (data.project || '--');
|
|
32908
33792
|
|
|
32909
33793
|
if (data.pillars) {
|
|
32910
33794
|
const p1 = data.pillars.store_integrity || data.pillars.memory_integrity;
|
|
@@ -33007,7 +33891,7 @@ var MAX_BODY_SIZE, EMBEDDED_HTML = `<!DOCTYPE html>
|
|
|
33007
33891
|
|
|
33008
33892
|
async function fetchDrift() {
|
|
33009
33893
|
try {
|
|
33010
|
-
const res = await fetch('/api/drift');
|
|
33894
|
+
const res = await fetch('/api/drift' + projectScopeQuery());
|
|
33011
33895
|
const drift = await res.json();
|
|
33012
33896
|
const tbody = document.getElementById('driftTableBody');
|
|
33013
33897
|
if (tbody) {
|
|
@@ -33065,8 +33949,8 @@ var MAX_BODY_SIZE, EMBEDDED_HTML = `<!DOCTYPE html>
|
|
|
33065
33949
|
async function fetchCognition() {
|
|
33066
33950
|
try {
|
|
33067
33951
|
const [clustRes, debtRes] = await Promise.all([
|
|
33068
|
-
fetch('/api/cognition/clusters'),
|
|
33069
|
-
fetch('/api/cognition/debt')
|
|
33952
|
+
fetch('/api/cognition/clusters' + projectScopeQuery()),
|
|
33953
|
+
fetch('/api/cognition/debt' + projectScopeQuery())
|
|
33070
33954
|
]);
|
|
33071
33955
|
const clustersData = await clustRes.json();
|
|
33072
33956
|
const debtData = await debtRes.json();
|
|
@@ -33303,6 +34187,16 @@ var MAX_BODY_SIZE, EMBEDDED_HTML = `<!DOCTYPE html>
|
|
|
33303
34187
|
setupCanvasInteractions();
|
|
33304
34188
|
setupTimeline();
|
|
33305
34189
|
|
|
34190
|
+
// T-321: project scope control. Seeded from the URL so a scoped link is
|
|
34191
|
+
// reloadable; an empty value means the whole store.
|
|
34192
|
+
const projectFilterInput = document.getElementById('projectFilter');
|
|
34193
|
+
if (projectFilterInput) {
|
|
34194
|
+
projectFilterInput.value = projectScope;
|
|
34195
|
+
projectFilterInput.addEventListener('change', () => {
|
|
34196
|
+
applyProjectScope(projectFilterInput.value);
|
|
34197
|
+
});
|
|
34198
|
+
}
|
|
34199
|
+
|
|
33306
34200
|
let searchDebounceTimer = null;
|
|
33307
34201
|
document.getElementById('searchInput').addEventListener('input', (e) => {
|
|
33308
34202
|
searchQuery = e.target.value;
|
|
@@ -43347,7 +44241,7 @@ var package_default;
|
|
|
43347
44241
|
var init_package = __esm(() => {
|
|
43348
44242
|
package_default = {
|
|
43349
44243
|
name: "musememory",
|
|
43350
|
-
version: "3.0
|
|
44244
|
+
version: "3.2.0",
|
|
43351
44245
|
description: "Autonomous, self-organizing cognitive memory system for AI agents and agency networks",
|
|
43352
44246
|
main: "dist/index.js",
|
|
43353
44247
|
type: "module",
|
|
@@ -43368,13 +44262,17 @@ var init_package = __esm(() => {
|
|
|
43368
44262
|
"build:gif": "bun run --cwd apps/website scripts/build-readme-gif.ts",
|
|
43369
44263
|
"claims:generate": "bun scripts/generate-claims.ts && bun scripts/generate-cli-reference.ts",
|
|
43370
44264
|
"claims:check": "bun scripts/generate-claims.ts --check",
|
|
44265
|
+
"check:landed": "bun run scripts/check-landed.ts",
|
|
44266
|
+
"check:landed:pr": "bun run scripts/check-landed.ts --pr",
|
|
43371
44267
|
"docs:check": "bun scripts/check-doc-links.ts",
|
|
43372
44268
|
test: "bun test",
|
|
43373
44269
|
typecheck: "tsc --noEmit",
|
|
43374
44270
|
validate: "bun run dist/index.js validate --dry-run",
|
|
43375
44271
|
start: "bun run dist/index.js mcp",
|
|
43376
44272
|
prepublishOnly: "bun run build && bun test",
|
|
43377
|
-
"site:qa": "bun run --cwd apps/website scripts/qa-gate.ts"
|
|
44273
|
+
"site:qa": "bun run --cwd apps/website scripts/qa-gate.ts",
|
|
44274
|
+
"showreel:hash": "bun scripts/showreel-hash.ts",
|
|
44275
|
+
"showreel:hash:write": "bun scripts/showreel-hash.ts --write"
|
|
43378
44276
|
},
|
|
43379
44277
|
bin: {
|
|
43380
44278
|
memory: "dist/index.js",
|
|
@@ -43410,6 +44308,9 @@ var init_package = __esm(() => {
|
|
|
43410
44308
|
url: "git+ssh://git@github.com/harshsinghmp/musememory.git"
|
|
43411
44309
|
},
|
|
43412
44310
|
license: "MIT",
|
|
44311
|
+
publishConfig: {
|
|
44312
|
+
access: "public"
|
|
44313
|
+
},
|
|
43413
44314
|
dependencies: {
|
|
43414
44315
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
43415
44316
|
ajv: "^8.17.1",
|
|
@@ -44968,7 +45869,7 @@ var init_constitution = __esm(() => {
|
|
|
44968
45869
|
trim_exempt: true,
|
|
44969
45870
|
category: "runtime",
|
|
44970
45871
|
severity: "critical",
|
|
44971
|
-
source: "
|
|
45872
|
+
source: "Agency Architecture R1"
|
|
44972
45873
|
},
|
|
44973
45874
|
{
|
|
44974
45875
|
id: "R2-zero-secret-exposure",
|
|
@@ -44977,7 +45878,7 @@ var init_constitution = __esm(() => {
|
|
|
44977
45878
|
trim_exempt: true,
|
|
44978
45879
|
category: "security",
|
|
44979
45880
|
severity: "critical",
|
|
44980
|
-
source: "
|
|
45881
|
+
source: "Vibeguard Security Protocol"
|
|
44981
45882
|
},
|
|
44982
45883
|
{
|
|
44983
45884
|
id: "R3-evidence-before-claims",
|
|
@@ -45002,12 +45903,12 @@ var init_constitution = __esm(() => {
|
|
|
45002
45903
|
|
|
45003
45904
|
// src/orchestrator/freshness.ts
|
|
45004
45905
|
import { readFileSync as readFileSync49, statSync as statSync21 } from "node:fs";
|
|
45005
|
-
import { resolve as
|
|
45906
|
+
import { resolve as resolve8 } from "node:path";
|
|
45006
45907
|
function cacheKey2(fullPath, symbol, mtimeMs) {
|
|
45007
45908
|
return `${fullPath}::${symbol ?? "*"}::${mtimeMs}`;
|
|
45008
45909
|
}
|
|
45009
45910
|
function checkAnchorLive(workspaceRoot, anchor) {
|
|
45010
|
-
const fullPath =
|
|
45911
|
+
const fullPath = resolve8(workspaceRoot, anchor.file_path);
|
|
45011
45912
|
let mtimeMs = 0;
|
|
45012
45913
|
try {
|
|
45013
45914
|
mtimeMs = statSync21(fullPath).mtimeMs;
|
|
@@ -45553,7 +46454,8 @@ async function resolveMuseContext(store, workspaceRoot, input) {
|
|
|
45553
46454
|
} catch {}
|
|
45554
46455
|
}
|
|
45555
46456
|
const allEntries = list(store);
|
|
45556
|
-
const
|
|
46457
|
+
const conflictedIds = new Set(allEntries.filter((e) => e.status === "conflicted").map((e) => e.id));
|
|
46458
|
+
const constraintEntries = allEntries.filter((e) => (e.type === "constraint" || e.temporal_mode === "timeless") && e.status !== "archived" && e.status !== "superseded" && e.status !== "rejected" && !(e.status === "conflicted" && !input.include_conflicted));
|
|
45557
46459
|
for (const ce of constraintEntries) {
|
|
45558
46460
|
if (activeConstraints.length >= 5)
|
|
45559
46461
|
break;
|
|
@@ -45579,6 +46481,8 @@ ${c.content}`);
|
|
|
45579
46481
|
continue;
|
|
45580
46482
|
if (e.status === "archived" || e.status === "superseded")
|
|
45581
46483
|
continue;
|
|
46484
|
+
if (e.status === "conflicted" && !input.include_conflicted)
|
|
46485
|
+
continue;
|
|
45582
46486
|
for (const anc of e.anchors) {
|
|
45583
46487
|
let fileMatch = false;
|
|
45584
46488
|
let symbolMatch = false;
|
|
@@ -45608,6 +46512,7 @@ ${c.content}`);
|
|
|
45608
46512
|
suppressReinjection: false,
|
|
45609
46513
|
suppressSelfEcho: false,
|
|
45610
46514
|
suppressSeenChunks: false,
|
|
46515
|
+
includeConflicted: input.include_conflicted === true,
|
|
45611
46516
|
recordSeenChunks: false,
|
|
45612
46517
|
echoHorizonMs: input.echo_horizon_ms,
|
|
45613
46518
|
agent: input.agent,
|
|
@@ -45619,6 +46524,13 @@ ${c.content}`);
|
|
|
45619
46524
|
active_file: input.active_file,
|
|
45620
46525
|
symbol: input.symbol
|
|
45621
46526
|
});
|
|
46527
|
+
if (!input.include_conflicted && conflictedIds.size > 0) {
|
|
46528
|
+
routeLookup.matched_routes = routeLookup.matched_routes.map((rt) => ({
|
|
46529
|
+
...rt,
|
|
46530
|
+
entry_ids: rt.entry_ids.filter((id) => !conflictedIds.has(id))
|
|
46531
|
+
}));
|
|
46532
|
+
routeLookup.prioritized_entry_ids = routeLookup.prioritized_entry_ids.filter((id) => !conflictedIds.has(id));
|
|
46533
|
+
}
|
|
45622
46534
|
const candidatePool = trivialGate.isTrivial ? [] : [...entriesWithMatchingAnchors];
|
|
45623
46535
|
if (!trivialGate.isTrivial) {
|
|
45624
46536
|
for (const pid of routeLookup.prioritized_entry_ids) {
|
|
@@ -45635,6 +46547,18 @@ ${c.content}`);
|
|
|
45635
46547
|
}
|
|
45636
46548
|
}
|
|
45637
46549
|
}
|
|
46550
|
+
const withheldConflicted = [];
|
|
46551
|
+
if (!input.include_conflicted && conflictedIds.size > 0) {
|
|
46552
|
+
for (let i = candidatePool.length - 1;i >= 0; i--) {
|
|
46553
|
+
if (conflictedIds.has(candidatePool[i].id)) {
|
|
46554
|
+
const removed = candidatePool.splice(i, 1)[0];
|
|
46555
|
+
withheldConflicted.push({
|
|
46556
|
+
id: removed.id,
|
|
46557
|
+
reason: "conflicted_status - resolve in memory conflicts; opt-in via include_conflicted: true"
|
|
46558
|
+
});
|
|
46559
|
+
}
|
|
46560
|
+
}
|
|
46561
|
+
}
|
|
45638
46562
|
const withheldUntrusted = [];
|
|
45639
46563
|
let filteredCandidates = candidatePool;
|
|
45640
46564
|
if (!input.include_untrusted) {
|
|
@@ -45801,6 +46725,9 @@ ${c.content}`);
|
|
|
45801
46725
|
if (withheldUntrusted.length > 0) {
|
|
45802
46726
|
suggestedNextSteps.push(`${withheldUntrusted.length} untrusted memor${withheldUntrusted.length === 1 ? "y" : "ies"} withheld — pass include_untrusted: true to include them`);
|
|
45803
46727
|
}
|
|
46728
|
+
if (withheldConflicted.length > 0) {
|
|
46729
|
+
suggestedNextSteps.push(`${withheldConflicted.length} conflicted memor${withheldConflicted.length === 1 ? "y" : "ies"} withheld — resolve them via memory conflicts or pass include_conflicted: true`);
|
|
46730
|
+
}
|
|
45804
46731
|
if (digestRefusalReason) {
|
|
45805
46732
|
suggestedNextSteps.push(`Refused incomplete or corrupted CURRENT.md digest: ${digestRefusalReason} — re-generate with memory handoff or repair CURRENT.md`);
|
|
45806
46733
|
}
|
|
@@ -46536,6 +47463,7 @@ You are equipped with Muse Memory, an autonomous persistent cognitive memory sys
|
|
|
46536
47463
|
limit: { type: "number" },
|
|
46537
47464
|
token_budget: { type: "number", description: "Maximum token budget to consume" },
|
|
46538
47465
|
include_superseded: { type: "boolean" },
|
|
47466
|
+
include_conflicted: { type: "boolean", description: "Include memories flagged conflicted by the contradiction engine (excluded by default — known potential falsehoods)" },
|
|
46539
47467
|
hybrid: { type: "boolean", description: "Use the offline vector+BM25 index (requires 'memory reindex'); falls back to live scoring when absent" },
|
|
46540
47468
|
type: { type: "string" },
|
|
46541
47469
|
status: { type: "string" },
|
|
@@ -46656,6 +47584,7 @@ You are equipped with Muse Memory, an autonomous persistent cognitive memory sys
|
|
|
46656
47584
|
limit: { type: "number" },
|
|
46657
47585
|
token_budget: { type: "number", description: "Maximum token budget to consume" },
|
|
46658
47586
|
include_superseded: { type: "boolean" },
|
|
47587
|
+
include_conflicted: { type: "boolean", description: "Include memories flagged conflicted by the contradiction engine (excluded by default — known potential falsehoods)" },
|
|
46659
47588
|
type: { type: "string" },
|
|
46660
47589
|
status: { type: "string" },
|
|
46661
47590
|
verified: { type: "boolean" },
|
|
@@ -47754,7 +48683,8 @@ You are equipped with Muse Memory, an autonomous persistent cognitive memory sys
|
|
|
47754
48683
|
inputSchema: {
|
|
47755
48684
|
type: "object",
|
|
47756
48685
|
properties: {
|
|
47757
|
-
dir: { type: "string", description: "Optional project workspace directory path" }
|
|
48686
|
+
dir: { type: "string", description: "Optional project workspace directory path" },
|
|
48687
|
+
project: { type: "string", description: "Optional memory project scope filter" }
|
|
47758
48688
|
}
|
|
47759
48689
|
}
|
|
47760
48690
|
},
|
|
@@ -47890,7 +48820,8 @@ You are equipped with Muse Memory, an autonomous persistent cognitive memory sys
|
|
|
47890
48820
|
inputSchema: {
|
|
47891
48821
|
type: "object",
|
|
47892
48822
|
properties: {
|
|
47893
|
-
dir: { type: "string", description: "Optional project workspace directory path" }
|
|
48823
|
+
dir: { type: "string", description: "Optional project workspace directory path" },
|
|
48824
|
+
project: { type: "string", description: "Optional memory project scope filter" }
|
|
47894
48825
|
}
|
|
47895
48826
|
}
|
|
47896
48827
|
},
|
|
@@ -47914,7 +48845,8 @@ You are equipped with Muse Memory, an autonomous persistent cognitive memory sys
|
|
|
47914
48845
|
inputSchema: {
|
|
47915
48846
|
type: "object",
|
|
47916
48847
|
properties: {
|
|
47917
|
-
dir: { type: "string", description: "Optional workspace directory" }
|
|
48848
|
+
dir: { type: "string", description: "Optional workspace directory" },
|
|
48849
|
+
project: { type: "string", description: "Optional memory project scope filter" }
|
|
47918
48850
|
}
|
|
47919
48851
|
}
|
|
47920
48852
|
},
|
|
@@ -47924,7 +48856,8 @@ You are equipped with Muse Memory, an autonomous persistent cognitive memory sys
|
|
|
47924
48856
|
inputSchema: {
|
|
47925
48857
|
type: "object",
|
|
47926
48858
|
properties: {
|
|
47927
|
-
dir: { type: "string", description: "Optional workspace directory" }
|
|
48859
|
+
dir: { type: "string", description: "Optional workspace directory" },
|
|
48860
|
+
project: { type: "string", description: "Optional memory project scope filter" }
|
|
47928
48861
|
}
|
|
47929
48862
|
}
|
|
47930
48863
|
},
|
|
@@ -47934,7 +48867,8 @@ You are equipped with Muse Memory, an autonomous persistent cognitive memory sys
|
|
|
47934
48867
|
inputSchema: {
|
|
47935
48868
|
type: "object",
|
|
47936
48869
|
properties: {
|
|
47937
|
-
dir: { type: "string", description: "Optional workspace directory path" }
|
|
48870
|
+
dir: { type: "string", description: "Optional workspace directory path" },
|
|
48871
|
+
project: { type: "string", description: "Optional memory project scope filter" }
|
|
47938
48872
|
}
|
|
47939
48873
|
}
|
|
47940
48874
|
},
|
|
@@ -48241,6 +49175,7 @@ You are equipped with Muse Memory, an autonomous persistent cognitive memory sys
|
|
|
48241
49175
|
limit: clampLimit(a.limit, 10, 100, 1),
|
|
48242
49176
|
tokenBudget: typeof a.token_budget === "number" ? a.token_budget : undefined,
|
|
48243
49177
|
includeSuperseded: a.include_superseded === true,
|
|
49178
|
+
includeConflicted: a.include_conflicted === true,
|
|
48244
49179
|
type: a.type ? String(a.type) : undefined,
|
|
48245
49180
|
status: a.status ? String(a.status) : undefined,
|
|
48246
49181
|
verified: a.verified === true,
|
|
@@ -49144,7 +50079,14 @@ Path: ${item.path}`,
|
|
|
49144
50079
|
});
|
|
49145
50080
|
}
|
|
49146
50081
|
case "memory_anchor_audit": {
|
|
49147
|
-
const
|
|
50082
|
+
const requestedProject = a.project ? String(a.project).trim() || undefined : undefined;
|
|
50083
|
+
const canonicalProject = resolveProjectName(activeStore, requestedProject);
|
|
50084
|
+
if (requestedProject && canonicalProject === undefined) {
|
|
50085
|
+
return toolError(`no memories for project "${requestedProject}" — available: ${formatAvailable(activeStore)}`);
|
|
50086
|
+
}
|
|
50087
|
+
const report = auditMemoryAnchors(activeStore, activeRoot, {
|
|
50088
|
+
project: canonicalProject
|
|
50089
|
+
});
|
|
49148
50090
|
return toolResult(report);
|
|
49149
50091
|
}
|
|
49150
50092
|
case "muse_context": {
|
|
@@ -49226,7 +50168,14 @@ Path: ${item.path}`,
|
|
|
49226
50168
|
});
|
|
49227
50169
|
}
|
|
49228
50170
|
case "memory_drift_audit": {
|
|
49229
|
-
const
|
|
50171
|
+
const requestedProject = a.project ? String(a.project).trim() || undefined : undefined;
|
|
50172
|
+
const canonicalProject = resolveProjectName(activeStore, requestedProject);
|
|
50173
|
+
if (requestedProject && canonicalProject === undefined) {
|
|
50174
|
+
return toolError(`no memories for project "${requestedProject}" — available: ${formatAvailable(activeStore)}`);
|
|
50175
|
+
}
|
|
50176
|
+
const report = detectDocumentationCodeDrift(activeStore, activeRoot, {
|
|
50177
|
+
project: canonicalProject
|
|
50178
|
+
});
|
|
49230
50179
|
return toolResult(report);
|
|
49231
50180
|
}
|
|
49232
50181
|
case "muse_why": {
|
|
@@ -49238,18 +50187,39 @@ Path: ${item.path}`,
|
|
|
49238
50187
|
return toolResult(explanation);
|
|
49239
50188
|
}
|
|
49240
50189
|
case "muse_bug_clusters": {
|
|
49241
|
-
const
|
|
50190
|
+
const requestedProject = a.project ? String(a.project).trim() || undefined : undefined;
|
|
50191
|
+
const canonicalProject = resolveProjectName(activeStore, requestedProject);
|
|
50192
|
+
if (requestedProject && canonicalProject === undefined) {
|
|
50193
|
+
return toolError(`no memories for project "${requestedProject}" — available: ${formatAvailable(activeStore)}`);
|
|
50194
|
+
}
|
|
50195
|
+
const clusters = clusterRecurringBugsAndFriction(activeStore, {
|
|
50196
|
+
project: canonicalProject
|
|
50197
|
+
});
|
|
49242
50198
|
return toolResult({
|
|
49243
50199
|
total_clusters: clusters.length,
|
|
49244
50200
|
clusters
|
|
49245
50201
|
});
|
|
49246
50202
|
}
|
|
49247
50203
|
case "muse_tech_debt": {
|
|
49248
|
-
const
|
|
50204
|
+
const requestedProject = a.project ? String(a.project).trim() || undefined : undefined;
|
|
50205
|
+
const canonicalProject = resolveProjectName(activeStore, requestedProject);
|
|
50206
|
+
if (requestedProject && canonicalProject === undefined) {
|
|
50207
|
+
return toolError(`no memories for project "${requestedProject}" — available: ${formatAvailable(activeStore)}`);
|
|
50208
|
+
}
|
|
50209
|
+
const report = analyzeTechnicalDebt(activeStore, activeRoot, {
|
|
50210
|
+
project: canonicalProject
|
|
50211
|
+
});
|
|
49249
50212
|
return toolResult(report);
|
|
49250
50213
|
}
|
|
49251
50214
|
case "muse_health": {
|
|
49252
|
-
const
|
|
50215
|
+
const requestedProject = a.project ? String(a.project).trim() || undefined : undefined;
|
|
50216
|
+
const canonicalProject = resolveProjectName(activeStore, requestedProject);
|
|
50217
|
+
if (requestedProject && canonicalProject === undefined) {
|
|
50218
|
+
return toolError(`no memories for project "${requestedProject}" — available: ${formatAvailable(activeStore)}`);
|
|
50219
|
+
}
|
|
50220
|
+
const report = evaluateProjectHealth(activeStore, activeRoot, {
|
|
50221
|
+
project: canonicalProject
|
|
50222
|
+
});
|
|
49253
50223
|
return toolResult(report);
|
|
49254
50224
|
}
|
|
49255
50225
|
case "muse_sync_broadcast": {
|
|
@@ -50641,6 +51611,7 @@ async function handleSearchCommand({ positional, flags }) {
|
|
|
50641
51611
|
tokenBudget,
|
|
50642
51612
|
project: flags["project"],
|
|
50643
51613
|
includeSuperseded: flags["include-superseded"] === "true",
|
|
51614
|
+
includeConflicted: flags["include-conflicted"] === "true",
|
|
50644
51615
|
type: flags["type"],
|
|
50645
51616
|
status: flags["status"],
|
|
50646
51617
|
verified: flags["verified"] === "true"
|
|
@@ -52544,7 +53515,17 @@ async function handleHealthCommand(parsed) {
|
|
|
52544
53515
|
return 1;
|
|
52545
53516
|
}
|
|
52546
53517
|
const { root, store } = ctx;
|
|
52547
|
-
const
|
|
53518
|
+
const requestedProject = parsed.flags["project"]?.trim() || undefined;
|
|
53519
|
+
const canonicalProject = resolveProjectName(store, requestedProject);
|
|
53520
|
+
if (requestedProject && canonicalProject === undefined) {
|
|
53521
|
+
console.error(`Error: no memories for project "${requestedProject}" — available: ${formatAvailable(store)}`);
|
|
53522
|
+
return 1;
|
|
53523
|
+
}
|
|
53524
|
+
const project = canonicalProject;
|
|
53525
|
+
if (canonicalProject && canonicalProject !== requestedProject) {
|
|
53526
|
+
console.error(`Note: project filter matched canonical "${canonicalProject}" (requested "${requestedProject}").`);
|
|
53527
|
+
}
|
|
53528
|
+
const report = evaluateProjectHealth(store, root, { project });
|
|
52548
53529
|
if (parsed.flags.json) {
|
|
52549
53530
|
console.log(JSON.stringify(report, null, 2));
|
|
52550
53531
|
return report.gate_status === "FAIL" ? 1 : 0;
|
|
@@ -52556,6 +53537,7 @@ async function handleHealthCommand(parsed) {
|
|
|
52556
53537
|
${bold}\uD83C\uDFE5 MUSE MEMORY 5-PILLAR PROJECT HEALTH GATE${reset}`);
|
|
52557
53538
|
console.log(`${"=".repeat(50)}`);
|
|
52558
53539
|
console.log(`Project: ${bold}${report.project}${reset}`);
|
|
53540
|
+
console.log(`Scope: ${report.scope.entry_count} ` + `${report.scope.entry_count === 1 ? "memory" : "memories"} across ` + `${report.scope.projects.length} project${report.scope.projects.length === 1 ? "" : "s"}` + (report.scope.filter ? ` (filtered to "${report.scope.filter}")` : ""));
|
|
52559
53541
|
console.log(`Overall Grade: ${bold}${report.overall_grade}${reset} (${report.overall_score}/100)`);
|
|
52560
53542
|
console.log(`Gate Status: ${statusColor}${bold}${report.gate_status}${reset}
|
|
52561
53543
|
`);
|
|
@@ -52704,9 +53686,98 @@ var init_health2 = __esm(() => {
|
|
|
52704
53686
|
init_shared();
|
|
52705
53687
|
});
|
|
52706
53688
|
|
|
53689
|
+
// src/cli/conflicts.ts
|
|
53690
|
+
async function handleConflictsCommand(parsed) {
|
|
53691
|
+
const ctx = requireRoot(parsed.flags);
|
|
53692
|
+
if (!ctx) {
|
|
53693
|
+
console.error("Error: Could not resolve project root or initialize .memory directory.");
|
|
53694
|
+
return 1;
|
|
53695
|
+
}
|
|
53696
|
+
const { store } = ctx;
|
|
53697
|
+
const isTrue = (val) => val === true || val === "true" || val === "";
|
|
53698
|
+
const dryRun = isTrue(parsed.flags["dry-run"]) || isTrue(parsed.flags["n"]);
|
|
53699
|
+
const project = parsed.flags["project"];
|
|
53700
|
+
await Promise.resolve().then(() => init_contradiction());
|
|
53701
|
+
const recorded = listConflicts(store, { status: "open" });
|
|
53702
|
+
const resolved = listConflicts(store, { status: "resolved" });
|
|
53703
|
+
if (dryRun) {
|
|
53704
|
+
const potential = scanPotentialConflicts(store, { project });
|
|
53705
|
+
if (parsed.flags.json) {
|
|
53706
|
+
console.log(JSON.stringify({
|
|
53707
|
+
mode: "dry-run",
|
|
53708
|
+
project: project ?? null,
|
|
53709
|
+
recorded_open: recorded.length,
|
|
53710
|
+
recorded_resolved: resolved.length,
|
|
53711
|
+
potential_conflicts: potential
|
|
53712
|
+
}, null, 2));
|
|
53713
|
+
return 0;
|
|
53714
|
+
}
|
|
53715
|
+
const bold = "\x1B[1m";
|
|
53716
|
+
const reset = "\x1B[0m";
|
|
53717
|
+
const yellow = "\x1B[33m";
|
|
53718
|
+
const red = "\x1B[31m";
|
|
53719
|
+
console.log(`
|
|
53720
|
+
${bold}\uD83D\uDD0D CONTRADICTION ENGINE — DRY RUN${reset}`);
|
|
53721
|
+
console.log(`${"=".repeat(56)}`);
|
|
53722
|
+
console.log(`Project: ${bold}${project ?? "all"}${reset}`);
|
|
53723
|
+
console.log(`Recorded (open): ${recorded.length}`);
|
|
53724
|
+
console.log(`Recorded (resolved):${resolved.length}`);
|
|
53725
|
+
console.log(`Potential pairs: ${potential.length}
|
|
53726
|
+
`);
|
|
53727
|
+
if (potential.length === 0) {
|
|
53728
|
+
console.log(` ✅ No memory pairs would be flagged as contradictory.
|
|
53729
|
+
`);
|
|
53730
|
+
return 0;
|
|
53731
|
+
}
|
|
53732
|
+
console.log(`${yellow}Would be flagged (nothing was changed):${reset}`);
|
|
53733
|
+
for (const pair of potential) {
|
|
53734
|
+
console.log(` ${red}✗${reset} ${pair.entry_a_title}`);
|
|
53735
|
+
console.log(` ${pair.entry_a_id}`);
|
|
53736
|
+
console.log(` ${red}✗${reset} ${pair.entry_b_title}`);
|
|
53737
|
+
console.log(` ${pair.entry_b_id}`);
|
|
53738
|
+
console.log(` reason: ${pair.reason ?? "unknown"}`);
|
|
53739
|
+
console.log("");
|
|
53740
|
+
}
|
|
53741
|
+
console.log(`${bold}Note${reset}: flagging a pair moves BOTH memories to 'conflicted' (25 health points each)
|
|
53742
|
+
and removes both from every future sync broadcast. Resolve with 'memory_resolve_conflict'.
|
|
53743
|
+
`);
|
|
53744
|
+
return 0;
|
|
53745
|
+
}
|
|
53746
|
+
if (parsed.flags.json) {
|
|
53747
|
+
console.log(JSON.stringify({ mode: "recorded", open: recorded, resolved: resolved.length }, null, 2));
|
|
53748
|
+
return 0;
|
|
53749
|
+
}
|
|
53750
|
+
const bold = "\x1B[1m";
|
|
53751
|
+
const reset = "\x1B[0m";
|
|
53752
|
+
console.log(`
|
|
53753
|
+
${bold}⚖️ CONFLICTS${reset}`);
|
|
53754
|
+
console.log(`${"=".repeat(56)}`);
|
|
53755
|
+
console.log(`Open: ${recorded.length}`);
|
|
53756
|
+
console.log(`Resolved: ${resolved.length}
|
|
53757
|
+
`);
|
|
53758
|
+
if (recorded.length === 0) {
|
|
53759
|
+
console.log(` ✅ No open conflicts.
|
|
53760
|
+
`);
|
|
53761
|
+
return 0;
|
|
53762
|
+
}
|
|
53763
|
+
for (const conflict of recorded) {
|
|
53764
|
+
console.log(`${bold}${conflict.memory_a_id}${reset} ↔ ${bold}${conflict.memory_b_id}${reset}`);
|
|
53765
|
+
console.log(` type: ${conflict.conflict_type} confidence: ${conflict.confidence}`);
|
|
53766
|
+
console.log(` reason: ${conflict.reason ?? "unknown"}`);
|
|
53767
|
+
console.log(` detected: ${conflict.detected_at}`);
|
|
53768
|
+
console.log("");
|
|
53769
|
+
}
|
|
53770
|
+
console.log(`${bold}Tip${reset}: run 'memory conflicts --dry-run' to preview what would be flagged.
|
|
53771
|
+
`);
|
|
53772
|
+
return 0;
|
|
53773
|
+
}
|
|
53774
|
+
var init_conflicts = __esm(() => {
|
|
53775
|
+
init_shared();
|
|
53776
|
+
});
|
|
53777
|
+
|
|
52707
53778
|
// src/cli/sync.ts
|
|
52708
53779
|
import { writeFileSync as writeFileSync39, readFileSync as readFileSync59 } from "node:fs";
|
|
52709
|
-
import { resolve as
|
|
53780
|
+
import { resolve as resolve9 } from "node:path";
|
|
52710
53781
|
async function handleSyncCommand(parsed) {
|
|
52711
53782
|
const ctx = requireRoot(parsed.flags);
|
|
52712
53783
|
if (!ctx) {
|
|
@@ -52721,7 +53792,7 @@ async function handleSyncCommand(parsed) {
|
|
|
52721
53792
|
project: parsed.flags.project
|
|
52722
53793
|
});
|
|
52723
53794
|
if (parsed.flags.out) {
|
|
52724
|
-
const outPath =
|
|
53795
|
+
const outPath = resolve9(process.cwd(), parsed.flags.out);
|
|
52725
53796
|
writeFileSync39(outPath, JSON.stringify(packet, null, 2), "utf-8");
|
|
52726
53797
|
console.log(`\x1B[32m✓ Broadcast packet saved to '${outPath}' (${packet.payload.memories.length} memories)\x1B[0m`);
|
|
52727
53798
|
} else {
|
|
@@ -52730,7 +53801,7 @@ async function handleSyncCommand(parsed) {
|
|
|
52730
53801
|
return 0;
|
|
52731
53802
|
}
|
|
52732
53803
|
if (parsed.flags.ingest) {
|
|
52733
|
-
const inPath =
|
|
53804
|
+
const inPath = resolve9(process.cwd(), parsed.flags.ingest);
|
|
52734
53805
|
try {
|
|
52735
53806
|
const raw = readFileSync59(inPath, "utf-8");
|
|
52736
53807
|
const packet = JSON.parse(raw);
|
|
@@ -52755,7 +53826,8 @@ async function handleSyncCommand(parsed) {
|
|
|
52755
53826
|
}
|
|
52756
53827
|
}
|
|
52757
53828
|
if (parsed.flags.pool || !parsed.flags.status && !parsed.flags.broadcast && !parsed.flags.ingest) {
|
|
52758
|
-
const
|
|
53829
|
+
const rawPool = parsed.flags.pool;
|
|
53830
|
+
const poolDir = typeof rawPool === "string" && rawPool !== "true" && rawPool.trim() !== "" ? resolve9(process.cwd(), rawPool) : undefined;
|
|
52759
53831
|
const report = syncWithSharedPool(store, root, poolDir, agentId);
|
|
52760
53832
|
if (parsed.flags.json) {
|
|
52761
53833
|
console.log(JSON.stringify(report, null, 2));
|
|
@@ -53112,6 +54184,394 @@ var init_versioning = __esm(() => {
|
|
|
53112
54184
|
init_retention();
|
|
53113
54185
|
});
|
|
53114
54186
|
|
|
54187
|
+
// src/cli/secrets.ts
|
|
54188
|
+
import { existsSync as existsSync69, readdirSync as readdirSync23, readFileSync as readFileSync61, statSync as statSync22 } from "node:fs";
|
|
54189
|
+
import { join as join64, relative as relative10, extname as extname2 } from "node:path";
|
|
54190
|
+
function isBinaryBuffer(buffer) {
|
|
54191
|
+
const checkLength = Math.min(buffer.length, 1024);
|
|
54192
|
+
for (let i = 0;i < checkLength; i++) {
|
|
54193
|
+
if (buffer[i] === 0)
|
|
54194
|
+
return true;
|
|
54195
|
+
}
|
|
54196
|
+
return false;
|
|
54197
|
+
}
|
|
54198
|
+
function walkScanFiles(dir, baseDir = dir, customIgnores = []) {
|
|
54199
|
+
const results = [];
|
|
54200
|
+
if (!existsSync69(dir))
|
|
54201
|
+
return results;
|
|
54202
|
+
const entries = readdirSync23(dir, { withFileTypes: true });
|
|
54203
|
+
for (const entry of entries) {
|
|
54204
|
+
const fullPath = join64(dir, entry.name);
|
|
54205
|
+
const relPath = relative10(baseDir, fullPath);
|
|
54206
|
+
if (entry.isDirectory()) {
|
|
54207
|
+
if (DEFAULT_IGNORED_DIRS.has(entry.name) || customIgnores.some((pattern) => relPath.includes(pattern))) {
|
|
54208
|
+
continue;
|
|
54209
|
+
}
|
|
54210
|
+
results.push(...walkScanFiles(fullPath, baseDir, customIgnores));
|
|
54211
|
+
} else if (entry.isFile()) {
|
|
54212
|
+
const ext = extname2(entry.name).toLowerCase();
|
|
54213
|
+
if (BINARY_EXTENSIONS.has(ext))
|
|
54214
|
+
continue;
|
|
54215
|
+
if (customIgnores.some((pattern) => relPath.includes(pattern)))
|
|
54216
|
+
continue;
|
|
54217
|
+
results.push(fullPath);
|
|
54218
|
+
}
|
|
54219
|
+
}
|
|
54220
|
+
return results;
|
|
54221
|
+
}
|
|
54222
|
+
async function executeSecretScan(options) {
|
|
54223
|
+
const startTime = Date.now();
|
|
54224
|
+
const targetDir = options.targetDir;
|
|
54225
|
+
const customIgnores = options.ignorePatterns || [];
|
|
54226
|
+
if (!existsSync69(targetDir)) {
|
|
54227
|
+
return {
|
|
54228
|
+
targetDir,
|
|
54229
|
+
scannedFiles: 0,
|
|
54230
|
+
findings: [],
|
|
54231
|
+
clean: false,
|
|
54232
|
+
durationMs: Date.now() - startTime
|
|
54233
|
+
};
|
|
54234
|
+
}
|
|
54235
|
+
let files = [];
|
|
54236
|
+
try {
|
|
54237
|
+
const stat = statSync22(targetDir);
|
|
54238
|
+
if (stat.isFile()) {
|
|
54239
|
+
files = [targetDir];
|
|
54240
|
+
} else {
|
|
54241
|
+
files = walkScanFiles(targetDir, targetDir, customIgnores);
|
|
54242
|
+
}
|
|
54243
|
+
} catch {
|
|
54244
|
+
files = [];
|
|
54245
|
+
}
|
|
54246
|
+
const findings = [];
|
|
54247
|
+
for (const file of files) {
|
|
54248
|
+
try {
|
|
54249
|
+
const stats = statSync22(file);
|
|
54250
|
+
if (stats.size > 5 * 1024 * 1024)
|
|
54251
|
+
continue;
|
|
54252
|
+
const buffer = readFileSync61(file);
|
|
54253
|
+
if (isBinaryBuffer(buffer))
|
|
54254
|
+
continue;
|
|
54255
|
+
const content = buffer.toString("utf8");
|
|
54256
|
+
const lines = content.split(/\r?\n/);
|
|
54257
|
+
for (let i = 0;i < lines.length; i++) {
|
|
54258
|
+
const line = lines[i];
|
|
54259
|
+
if (!line.trim())
|
|
54260
|
+
continue;
|
|
54261
|
+
for (const rule of SECRET_RULES) {
|
|
54262
|
+
if (rule.pattern.test(line)) {
|
|
54263
|
+
findings.push({
|
|
54264
|
+
file: relative10(targetDir, file) || file,
|
|
54265
|
+
line: i + 1,
|
|
54266
|
+
rule: rule.name,
|
|
54267
|
+
redactedSnippet: redactSecrets(line.trim())
|
|
54268
|
+
});
|
|
54269
|
+
break;
|
|
54270
|
+
}
|
|
54271
|
+
}
|
|
54272
|
+
}
|
|
54273
|
+
} catch {}
|
|
54274
|
+
}
|
|
54275
|
+
const durationMs = Date.now() - startTime;
|
|
54276
|
+
return {
|
|
54277
|
+
targetDir,
|
|
54278
|
+
scannedFiles: files.length,
|
|
54279
|
+
findings,
|
|
54280
|
+
clean: findings.length === 0,
|
|
54281
|
+
durationMs
|
|
54282
|
+
};
|
|
54283
|
+
}
|
|
54284
|
+
async function handleScanSecretsCommand(args) {
|
|
54285
|
+
const targetDir = args.positional?.[0] || args.args?.[0] || ".";
|
|
54286
|
+
const verbose = Boolean(args.flags.verbose || args.flags.v);
|
|
54287
|
+
const jsonMode = Boolean(args.flags.json);
|
|
54288
|
+
const silent = Boolean(args.flags.silent);
|
|
54289
|
+
const failOnSecrets = args.flags["fail-on-secrets"] !== "false";
|
|
54290
|
+
const customIgnores = args.flags.ignore ? String(args.flags.ignore).split(",").map((s) => s.trim()) : [];
|
|
54291
|
+
if (!existsSync69(targetDir)) {
|
|
54292
|
+
if (!silent) {
|
|
54293
|
+
console.error(`
|
|
54294
|
+
❌ Error: Target path does not exist: ${targetDir}`);
|
|
54295
|
+
}
|
|
54296
|
+
return 1;
|
|
54297
|
+
}
|
|
54298
|
+
const result = await executeSecretScan({
|
|
54299
|
+
targetDir,
|
|
54300
|
+
verbose,
|
|
54301
|
+
json: jsonMode,
|
|
54302
|
+
silent,
|
|
54303
|
+
ignorePatterns: customIgnores,
|
|
54304
|
+
failOnSecrets
|
|
54305
|
+
});
|
|
54306
|
+
if (jsonMode) {
|
|
54307
|
+
console.log(JSON.stringify(result, null, 2));
|
|
54308
|
+
return result.clean ? 0 : 1;
|
|
54309
|
+
}
|
|
54310
|
+
if (silent) {
|
|
54311
|
+
return result.clean ? 0 : 1;
|
|
54312
|
+
}
|
|
54313
|
+
console.log(`
|
|
54314
|
+
\uD83D\uDEE1️ Native Vibeguard Secret Scanner`);
|
|
54315
|
+
console.log(`─────────────────────────────────────────────────────────────`);
|
|
54316
|
+
console.log(`Target Directory : ${targetDir}`);
|
|
54317
|
+
console.log(`Scanned Files : ${result.scannedFiles}`);
|
|
54318
|
+
console.log(`Duration : ${result.durationMs}ms`);
|
|
54319
|
+
if (result.clean) {
|
|
54320
|
+
console.log(`
|
|
54321
|
+
✅ Zero credentials leaked. All files verified clean.`);
|
|
54322
|
+
return 0;
|
|
54323
|
+
}
|
|
54324
|
+
console.log(`
|
|
54325
|
+
\uD83D\uDEA8 Potential Credential Leaks Detected: ${result.findings.length}
|
|
54326
|
+
`);
|
|
54327
|
+
for (const finding of result.findings) {
|
|
54328
|
+
console.log(` \uD83D\uDCCD ${finding.file}:${finding.line}`);
|
|
54329
|
+
console.log(` Rule : ${finding.rule}`);
|
|
54330
|
+
console.log(` Preview : ${finding.redactedSnippet}`);
|
|
54331
|
+
console.log(``);
|
|
54332
|
+
}
|
|
54333
|
+
console.log(`❌ Audit failed. Remove or redact exposed secrets before committing.`);
|
|
54334
|
+
return failOnSecrets ? 1 : 0;
|
|
54335
|
+
}
|
|
54336
|
+
var DEFAULT_IGNORED_DIRS, BINARY_EXTENSIONS;
|
|
54337
|
+
var init_secrets2 = __esm(() => {
|
|
54338
|
+
init_secrets();
|
|
54339
|
+
DEFAULT_IGNORED_DIRS = new Set([
|
|
54340
|
+
".git",
|
|
54341
|
+
"node_modules",
|
|
54342
|
+
"dist",
|
|
54343
|
+
"build",
|
|
54344
|
+
".next",
|
|
54345
|
+
".astro",
|
|
54346
|
+
"coverage",
|
|
54347
|
+
".turbo",
|
|
54348
|
+
".cache",
|
|
54349
|
+
".agents/archive",
|
|
54350
|
+
"snapshots"
|
|
54351
|
+
]);
|
|
54352
|
+
BINARY_EXTENSIONS = new Set([
|
|
54353
|
+
".png",
|
|
54354
|
+
".jpg",
|
|
54355
|
+
".jpeg",
|
|
54356
|
+
".gif",
|
|
54357
|
+
".webp",
|
|
54358
|
+
".ico",
|
|
54359
|
+
".woff",
|
|
54360
|
+
".woff2",
|
|
54361
|
+
".ttf",
|
|
54362
|
+
".eot",
|
|
54363
|
+
".otf",
|
|
54364
|
+
".mp4",
|
|
54365
|
+
".webm",
|
|
54366
|
+
".mp3",
|
|
54367
|
+
".wav",
|
|
54368
|
+
".zip",
|
|
54369
|
+
".tar",
|
|
54370
|
+
".gz",
|
|
54371
|
+
".tgz",
|
|
54372
|
+
".7z",
|
|
54373
|
+
".rar",
|
|
54374
|
+
".sqlite",
|
|
54375
|
+
".db",
|
|
54376
|
+
".bin",
|
|
54377
|
+
".exe",
|
|
54378
|
+
".dll",
|
|
54379
|
+
".so",
|
|
54380
|
+
".dylib",
|
|
54381
|
+
".wasm",
|
|
54382
|
+
".lock",
|
|
54383
|
+
".lockb",
|
|
54384
|
+
".pdf"
|
|
54385
|
+
]);
|
|
54386
|
+
});
|
|
54387
|
+
|
|
54388
|
+
// src/vault/system.ts
|
|
54389
|
+
import { existsSync as existsSync70, mkdirSync as mkdirSync36, writeFileSync as writeFileSync41 } from "node:fs";
|
|
54390
|
+
import { join as join65 } from "node:path";
|
|
54391
|
+
import os from "node:os";
|
|
54392
|
+
import { Socket } from "node:net";
|
|
54393
|
+
import { spawnSync } from "node:child_process";
|
|
54394
|
+
function probePort(port) {
|
|
54395
|
+
return new Promise((resolve) => {
|
|
54396
|
+
const socket = new Socket;
|
|
54397
|
+
socket.setTimeout(100);
|
|
54398
|
+
socket.once("connect", () => {
|
|
54399
|
+
socket.destroy();
|
|
54400
|
+
resolve(true);
|
|
54401
|
+
});
|
|
54402
|
+
socket.once("timeout", () => {
|
|
54403
|
+
socket.destroy();
|
|
54404
|
+
resolve(false);
|
|
54405
|
+
});
|
|
54406
|
+
socket.once("error", () => {
|
|
54407
|
+
socket.destroy();
|
|
54408
|
+
resolve(false);
|
|
54409
|
+
});
|
|
54410
|
+
socket.connect(port, "127.0.0.1");
|
|
54411
|
+
});
|
|
54412
|
+
}
|
|
54413
|
+
function runBinarySafe(binary, args) {
|
|
54414
|
+
try {
|
|
54415
|
+
const res = spawnSync(binary, args, { stdio: ["ignore", "pipe", "ignore"], timeout: 1500 });
|
|
54416
|
+
if (res.status === 0 && res.stdout) {
|
|
54417
|
+
return res.stdout.toString("utf8").trim();
|
|
54418
|
+
}
|
|
54419
|
+
} catch {
|
|
54420
|
+
return;
|
|
54421
|
+
}
|
|
54422
|
+
return;
|
|
54423
|
+
}
|
|
54424
|
+
async function collectSystemTerrain() {
|
|
54425
|
+
const cpus = os.cpus() || [];
|
|
54426
|
+
const firstCpu = cpus[0] || { model: "Unknown", speed: 0 };
|
|
54427
|
+
const host = {
|
|
54428
|
+
platform: os.platform(),
|
|
54429
|
+
arch: os.arch(),
|
|
54430
|
+
hostname: os.hostname(),
|
|
54431
|
+
release: os.release(),
|
|
54432
|
+
cpus: {
|
|
54433
|
+
model: firstCpu.model,
|
|
54434
|
+
speed: firstCpu.speed,
|
|
54435
|
+
count: cpus.length
|
|
54436
|
+
},
|
|
54437
|
+
totalMemoryGb: Math.round(os.totalmem() / 1024 / 1024 / 1024 * 100) / 100,
|
|
54438
|
+
freeMemoryGb: Math.round(os.freemem() / 1024 / 1024 / 1024 * 100) / 100,
|
|
54439
|
+
uptimeHours: Math.round(os.uptime() / 3600 * 10) / 10
|
|
54440
|
+
};
|
|
54441
|
+
const toolchains = {
|
|
54442
|
+
bunVersion: process.versions.bun || runBinarySafe("bun", ["--version"]),
|
|
54443
|
+
nodeVersion: process.versions.node || runBinarySafe("node", ["--version"]),
|
|
54444
|
+
gitVersion: runBinarySafe("git", ["--version"])?.replace(/^git version\s*/, ""),
|
|
54445
|
+
cargoVersion: runBinarySafe("cargo", ["--version"])?.replace(/^cargo\s*/, ""),
|
|
54446
|
+
pythonVersion: runBinarySafe("python3", ["--version"])?.replace(/^Python\s*/, ""),
|
|
54447
|
+
dockerAvailable: Boolean(runBinarySafe("docker", ["--version"]))
|
|
54448
|
+
};
|
|
54449
|
+
const knownServices = [
|
|
54450
|
+
{ port: 2222, name: "Muse Memory Studio" },
|
|
54451
|
+
{ port: 31337, name: "Pulse Dashboard" },
|
|
54452
|
+
{ port: 3600, name: "Ryoku Rashin Hub" },
|
|
54453
|
+
{ port: 7878, name: "Muse Daemon SSE" },
|
|
54454
|
+
{ port: 11434, name: "Ollama Local LLM" },
|
|
54455
|
+
{ port: 8000, name: "Local AI Endpoint" }
|
|
54456
|
+
];
|
|
54457
|
+
const probedPorts = await Promise.all(knownServices.map(async (svc) => {
|
|
54458
|
+
const listening = await probePort(svc.port);
|
|
54459
|
+
return { port: svc.port, service: svc.name, listening };
|
|
54460
|
+
}));
|
|
54461
|
+
let installedAgents = [];
|
|
54462
|
+
try {
|
|
54463
|
+
const detected = detectAgents();
|
|
54464
|
+
installedAgents = detected.filter((a) => a.installed).map((a) => a.name);
|
|
54465
|
+
} catch {
|
|
54466
|
+
installedAgents = ["antigravity", "opencode", "claude-code"];
|
|
54467
|
+
}
|
|
54468
|
+
return {
|
|
54469
|
+
timestamp: new Date().toISOString(),
|
|
54470
|
+
host,
|
|
54471
|
+
toolchains,
|
|
54472
|
+
agentEcosystem: {
|
|
54473
|
+
activePorts: probedPorts.filter((p) => p.listening),
|
|
54474
|
+
detectedAgents: installedAgents
|
|
54475
|
+
}
|
|
54476
|
+
};
|
|
54477
|
+
}
|
|
54478
|
+
function formatSystemTerrainMarkdown(terrain) {
|
|
54479
|
+
const { host, toolchains, agentEcosystem } = terrain;
|
|
54480
|
+
const lines = [
|
|
54481
|
+
`# Machine & System Terrain`,
|
|
54482
|
+
`> Deterministic hardware, runtime toolchains, and agent ecosystem map.`,
|
|
54483
|
+
`> Collected at: \`${terrain.timestamp}\``,
|
|
54484
|
+
``,
|
|
54485
|
+
`## \uD83D\uDDA5️ Host & Hardware`,
|
|
54486
|
+
`| Property | Value |`,
|
|
54487
|
+
`| --- | --- |`,
|
|
54488
|
+
`| **OS / Platform** | \`${host.platform}\` (${host.release}) |`,
|
|
54489
|
+
`| **Architecture** | \`${host.arch}\` |`,
|
|
54490
|
+
`| **Hostname** | \`${host.hostname}\` |`,
|
|
54491
|
+
`| **CPU Model** | ${host.cpus.model} |`,
|
|
54492
|
+
`| **CPU Cores** | ${host.cpus.count} cores @ ${host.cpus.speed} MHz |`,
|
|
54493
|
+
`| **Memory (RAM)** | ${host.freeMemoryGb} GB free / ${host.totalMemoryGb} GB total |`,
|
|
54494
|
+
`| **Host Uptime** | ${host.uptimeHours} hours |`,
|
|
54495
|
+
``,
|
|
54496
|
+
`## \uD83D\uDEE0️ Toolchains & Runtimes`,
|
|
54497
|
+
`| Runtime / Tool | Version / Status |`,
|
|
54498
|
+
`| --- | --- |`,
|
|
54499
|
+
`| **Bun Runtime** | \`${toolchains.bunVersion || "Not Found"}\` |`,
|
|
54500
|
+
`| **Node.js** | \`${toolchains.nodeVersion || "Not Found"}\` |`,
|
|
54501
|
+
`| **Git CLI** | \`${toolchains.gitVersion || "Not Found"}\` |`,
|
|
54502
|
+
`| **Cargo (Rust)** | \`${toolchains.cargoVersion || "Not Found"}\` |`,
|
|
54503
|
+
`| **Python 3** | \`${toolchains.pythonVersion || "Not Found"}\` |`,
|
|
54504
|
+
`| **Docker Engine** | \`${toolchains.dockerAvailable ? "Available" : "Unavailable"}\` |`,
|
|
54505
|
+
``,
|
|
54506
|
+
`## \uD83E\uDD16 Agent Ecosystem`,
|
|
54507
|
+
`### Installed Coding Agents (${agentEcosystem.detectedAgents.length})`,
|
|
54508
|
+
agentEcosystem.detectedAgents.length > 0 ? agentEcosystem.detectedAgents.map((a) => `- \`${a}\``).join(`
|
|
54509
|
+
`) : `_No recognized agent platforms installed._`,
|
|
54510
|
+
``,
|
|
54511
|
+
`### Active Local Agent Ports`
|
|
54512
|
+
];
|
|
54513
|
+
if (agentEcosystem.activePorts.length > 0) {
|
|
54514
|
+
lines.push(`| Port | Service | Status |`);
|
|
54515
|
+
lines.push(`| --- | --- | --- |`);
|
|
54516
|
+
for (const p of agentEcosystem.activePorts) {
|
|
54517
|
+
lines.push(`| \`:${p.port}\` | ${p.service} | \uD83D\uDFE2 Active |`);
|
|
54518
|
+
}
|
|
54519
|
+
} else {
|
|
54520
|
+
lines.push(`_No common agent daemons actively listening._`);
|
|
54521
|
+
}
|
|
54522
|
+
lines.push(``);
|
|
54523
|
+
lines.push(`---`);
|
|
54524
|
+
lines.push(`*Generated by Muse Vault System Collector.*`);
|
|
54525
|
+
return lines.join(`
|
|
54526
|
+
`);
|
|
54527
|
+
}
|
|
54528
|
+
async function writeSystemTerrainMap(targetVaultDir) {
|
|
54529
|
+
if (!existsSync70(targetVaultDir)) {
|
|
54530
|
+
mkdirSync36(targetVaultDir, { recursive: true });
|
|
54531
|
+
}
|
|
54532
|
+
const terrain = await collectSystemTerrain();
|
|
54533
|
+
const md = formatSystemTerrainMarkdown(terrain);
|
|
54534
|
+
const targetFile = join65(targetVaultDir, "system.md");
|
|
54535
|
+
writeFileSync41(targetFile, md, "utf8");
|
|
54536
|
+
return targetFile;
|
|
54537
|
+
}
|
|
54538
|
+
async function handleTerrainCommand(args) {
|
|
54539
|
+
const silent = Boolean(args.flags.silent);
|
|
54540
|
+
const outFile = args.flags.out;
|
|
54541
|
+
const projectRootInfo = findOrCreateProjectRoot(process.cwd());
|
|
54542
|
+
const defaultVaultDir = join65(projectRootInfo.memoryDir, "vault");
|
|
54543
|
+
const terrain = await collectSystemTerrain();
|
|
54544
|
+
const markdown = formatSystemTerrainMarkdown(terrain);
|
|
54545
|
+
if (outFile) {
|
|
54546
|
+
writeFileSync41(outFile, markdown, "utf8");
|
|
54547
|
+
if (!silent) {
|
|
54548
|
+
console.log(`
|
|
54549
|
+
\uD83D\uDDFA️ Machine terrain written to: ${outFile}`);
|
|
54550
|
+
}
|
|
54551
|
+
return 0;
|
|
54552
|
+
}
|
|
54553
|
+
try {
|
|
54554
|
+
const savedPath = await writeSystemTerrainMap(defaultVaultDir);
|
|
54555
|
+
if (!silent) {
|
|
54556
|
+
console.log(`
|
|
54557
|
+
\uD83D\uDDFA️ Machine terrain compiled to: ${savedPath}
|
|
54558
|
+
`);
|
|
54559
|
+
console.log(markdown);
|
|
54560
|
+
}
|
|
54561
|
+
return 0;
|
|
54562
|
+
} catch (err) {
|
|
54563
|
+
if (!silent) {
|
|
54564
|
+
console.error(`
|
|
54565
|
+
❌ Failed to write terrain map: ${err.message}`);
|
|
54566
|
+
}
|
|
54567
|
+
return 1;
|
|
54568
|
+
}
|
|
54569
|
+
}
|
|
54570
|
+
var init_system = __esm(() => {
|
|
54571
|
+
init_detect2();
|
|
54572
|
+
init_root();
|
|
54573
|
+
});
|
|
54574
|
+
|
|
53115
54575
|
// src/cli.ts
|
|
53116
54576
|
async function main(argv) {
|
|
53117
54577
|
if (argv.length === 0 || argv[0] === "--help" || argv[0] === "-h" || argv[0] === "help") {
|
|
@@ -53276,10 +54736,19 @@ async function main(argv) {
|
|
|
53276
54736
|
return handleLoopCommand(parsed);
|
|
53277
54737
|
case "health":
|
|
53278
54738
|
return handleHealthCommand(parsed);
|
|
54739
|
+
case "conflicts":
|
|
54740
|
+
return handleConflictsCommand(parsed);
|
|
53279
54741
|
case "reconcile":
|
|
53280
54742
|
return handleReconcileCommand(parsed);
|
|
53281
54743
|
case "benchmark":
|
|
53282
54744
|
return handleBenchmarkCommand(parsed);
|
|
54745
|
+
case "scan-secrets":
|
|
54746
|
+
case "secrets-scan":
|
|
54747
|
+
case "vibe-scan":
|
|
54748
|
+
return handleScanSecretsCommand(parsed);
|
|
54749
|
+
case "terrain":
|
|
54750
|
+
case "machine-terrain":
|
|
54751
|
+
return handleTerrainCommand(parsed);
|
|
53283
54752
|
case "code-impact":
|
|
53284
54753
|
case "impact":
|
|
53285
54754
|
return handleCodeImpactCommand(parsed);
|
|
@@ -53385,9 +54854,12 @@ Ecosystem, Migration & Connectivity:
|
|
|
53385
54854
|
daemon [--port N] Real-time agency hub (SSE event stream + publish API, default port 7878)
|
|
53386
54855
|
sync [status|broadcast|ingest|pool] Cross-agent knowledge sync & P2P gossip mesh
|
|
53387
54856
|
mesh [query|check|link|unlink|propagate] Multi-repo & monorepo cross-project mesh
|
|
53388
|
-
health
|
|
54857
|
+
health [--project P] Run unified 5-pillar architectural health evaluation; --project scopes it to one memory project
|
|
54858
|
+
conflicts [--dry-run] Inspect recorded contradictions; --dry-run previews what would be flagged
|
|
53389
54859
|
reconcile [--prune] [--stale] Reconcile orphaned & drifted code anchors across memories
|
|
53390
54860
|
benchmark [--iterations N] Run microsecond speed, quality & token economy benchmark suite
|
|
54861
|
+
scan-secrets [dir] [--json] Native Vibeguard secret scanner (zero external dependencies)
|
|
54862
|
+
terrain [--out file.md] Collect machine hardware, toolchain & agent ecosystem map
|
|
53391
54863
|
code-impact <file> [--symbol] Synthesize code callers, ADRs, negative warnings & risk score
|
|
53392
54864
|
pr-context [--base B] [--out] Generate memory-verified PR description from git diff
|
|
53393
54865
|
mcp Run stdio MCP server for agent platforms
|
|
@@ -53412,9 +54884,12 @@ var init_cli = __esm(() => {
|
|
|
53412
54884
|
init_lifecycle();
|
|
53413
54885
|
init_evolution();
|
|
53414
54886
|
init_health2();
|
|
54887
|
+
init_conflicts();
|
|
53415
54888
|
init_sync2();
|
|
53416
54889
|
init_mesh2();
|
|
53417
54890
|
init_versioning();
|
|
54891
|
+
init_secrets2();
|
|
54892
|
+
init_system();
|
|
53418
54893
|
});
|
|
53419
54894
|
|
|
53420
54895
|
// bin/memory.ts
|