musememory 2.2.0 β 2.2.1
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/context/current.md +7 -2
- package/README.md +23 -49
- package/dist/index.js +173 -94
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# π Current Shipped State & Active Invariants
|
|
2
2
|
|
|
3
|
-
> **Version**: `v2.1
|
|
4
|
-
> **Status**: Production Release (
|
|
3
|
+
> **Version**: `v2.2.1`
|
|
4
|
+
> **Status**: Production Release (Hardened v2.2 with Linus-Style Code Review Bug Fixes)
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -34,6 +34,11 @@
|
|
|
34
34
|
25. **Cross-Agent Knowledge Sync & P2P Gossip Protocol (R14)**: Portable sealed `SyncPacket` with SHA-256 integrity, vector clock causal ordering, bidirectional shared pool drop-directory gossip exchange, deduplication, Vibeguard secret scrubbing, and semantic contradiction tagging with mutual `conflict_ids`.
|
|
35
35
|
26. **Full Web Observability Studio & Interactive Visual Dashboard (R15)**: Integrated web studio served over local HTTP (`memory studio`), featuring a 5-pillar health scorecard, overall letter grade, prioritized remediation action checklist, ADR registry with code-to-doc drift inspector, autonomous "Why" reasoner, bug friction clusters heatmap, debt hotspots, and live P2P mesh topology visualizer.
|
|
36
36
|
27. **Multi-Repo & Monorepo Cross-Project Mesh (R16)**: Automatic workspace detection across pnpm, npm, bun, lerna, and multi-repo sibling groups; cross-project memory querying with origin package provenance; cross-package contract and entrypoint export auditing; explicit mesh linking (`mesh_links.json`); and shared invariant propagation across the entire mesh.
|
|
37
|
+
28. **Unified Code & Memory Impact Analysis**: Pre-flight blast radius analysis evaluating AST callers, test suites, governing ADRs, negative warnings, and risk levels (`memory code-impact` / `muse_code_impact`).
|
|
38
|
+
29. **PR & Change Context Generator**: Automatically turns git diffs into rich, memory-grounded GitHub PR descriptions linking touched anchors and active constraints (`memory pr-context` / `muse_pr_context`).
|
|
39
|
+
30. **Interactive Code Anchor Reconciler**: Audits and repairs code anchors across memories, pruning dead references and updating structural hashes (`memory reconcile` / `muse_reconcile_anchors`).
|
|
40
|
+
31. **Latency & Quality Telemetry Suite**: Benchmarks microsecond hot caches, FTS5 BM25 search, knapsack token packing, and ROI in a clean ASCII scoreboard (`memory benchmark`).
|
|
41
|
+
32. **Linus-Style Architectural Hardening (v2.2.1)**: Elimination of shell command injection via `execFileSync`, concurrency-safe `PRAGMA busy_timeout = 5000` on SQLite WAL mode, O(N) stat storm elimination in `list(store)`, structured warnings on YAML dual-write failures, and tightened word-boundary/code-anchor ADR matching.
|
|
37
42
|
|
|
38
43
|
---
|
|
39
44
|
|
package/README.md
CHANGED
|
@@ -24,60 +24,34 @@
|
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
27
|
-
## π What's New
|
|
28
|
-
|
|
29
|
-
###
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
-
|
|
48
|
-
|
|
49
|
-
- Zero-daemon shared filesystem gossip pool (`.memory/sync_pool/`) allowing autonomous subagent teams (frontend, backend, test) to exchange insights asynchronously.
|
|
50
|
-
- Ingestion deduplication, inline Vibeguard secret scrubbing, and semantic contradiction tagging with mutual `conflict_ids`.
|
|
51
|
-
- CLI `memory sync` command suite & 4 MCP tools (`muse_sync_broadcast`, `muse_sync_ingest`, `muse_sync_status`, `muse_sync_pool`).
|
|
52
|
-
- **π Full Web Observability Studio (`memory studio`) (R15)**:
|
|
53
|
-
- Embedded zero-dependency visual web dashboard (`memory studio` or `memory ui`) with interactive control plane.
|
|
54
|
-
- Live 5-pillar health scorecard (AβF letter grade, PASS/WARN/FAIL gate status, and prioritized remediation checklist).
|
|
55
|
-
- Interactive ADR registry and bidirectional documentation $\longleftrightarrow$ code drift inspector.
|
|
56
|
-
- Historical "Why" reasoner query interface, recurring bug friction heatmap, and debt scanner.
|
|
57
|
-
- Real-time P2P gossip mesh status and interactive broadcast/shared pool sync controls.
|
|
58
|
-
- **πΈοΈ Multi-Repo & Monorepo Cross-Project Mesh (R16)**:
|
|
59
|
-
- Passive automatic monorepo discovery across `pnpm`, `npm`, `bun`, `lerna`, and multi-repo sibling directories.
|
|
60
|
-
- Cross-project memory query resolver (`resolveMeshMemories`) with origin package provenance tags (`[mesh:@scope/package]`).
|
|
61
|
-
- Shared invariant and working constraint propagation (`propagateConstraintToMesh`) broadcasting critical security rules across all packages.
|
|
62
|
-
- Cross-package dependency contract and entrypoint export auditor (`auditMeshContracts`) validating cross-package imports and cross-repo code anchors.
|
|
63
|
-
- CLI `memory mesh` suite & 4 MCP tools (`muse_mesh_status`, `muse_mesh_query`, `muse_mesh_audit`, `muse_mesh_link`).
|
|
64
|
-
|
|
65
|
-
### π§ v2.0.0 Major Cognitive Overhaul:
|
|
66
|
-
- **π₯ Unified 5-Pillar Project Health Gate (`memory health` / `muse_health`)**: Single-call architectural audit across Store Integrity, Code Anchors, Doc-Code Alignment, Negative Sentry, and Technical Debt.
|
|
67
|
-
- **π€ Autonomous Engineering Cognition & "Why" Reasoner (`muse_why`)**: Reconstructs historical code evolution through past bug workarounds, accepted trade-offs, and timeless rules before refactoring.
|
|
68
|
-
- **ποΈ First-Class Architecture Decision Records (`memory adr` / `memory_adr_record`)**: Living, queryable ADR entities with options considered, consequences, native code anchors, and supersession lineage.
|
|
69
|
-
- **π Bidirectional Documentation $\longleftrightarrow$ Code Drift Engine (`memory_drift_audit`)**: Continuously verifies alignment across 6 states (`DOCUMENTED`, `IMPLEMENTED`, `PARTIAL`, `CONFLICTING`, `STALE`, `MISSING`).
|
|
70
|
-
- **π― Flagship Unified Context Orchestrator (`muse_context`)**: Single-call fused context injection with knapsack token budget packing.
|
|
71
|
-
- **βοΈ Task-Focused MCP Profiles**: Dynamic role-based tool filtering (`core`, `coding`, `debugging`, `review`, `architecture`, `maintenance`).
|
|
72
|
-
- **β Native Structural Code Anchors (`src/anchors/`)**: Line-independent structural SHA-256 hashing insensitive to spacing/comments.
|
|
73
|
-
- **πͺ Scoped Promotion & Extended Archival Lifecycle (`src/promotion/`)**: 3-tier promotion ladder (`local` $\rightarrow$ `project` $\rightarrow$ `global`), 5Γ repeated success policy, universal generalization, and `active` $\rightarrow$ `cold` $\rightarrow$ `dormant` $\rightarrow$ `archived` lifecycle with query rehydration.
|
|
74
|
-
- **β‘ Hot Query Cache & SQLite WAL Optimization**: Microsecond memory lookups and high-throughput concurrent I/O.
|
|
27
|
+
## π What's New
|
|
28
|
+
|
|
29
|
+
### v2.2.0
|
|
30
|
+
- **Unified Code & Memory Impact Analysis**: Pre-flight blast radius analysis evaluating AST callers, test suites, governing ADRs, negative warnings, and risk levels (`memory code-impact` / `muse_code_impact`).
|
|
31
|
+
- **PR & Change Context Generator**: Automatically turns git diffs into rich, memory-grounded GitHub PR descriptions linking touched anchors and active constraints (`memory pr-context` / `muse_pr_context`).
|
|
32
|
+
- **Interactive Code Anchor Reconciler**: Audits and repairs code anchors across memories, pruning dead references and updating structural hashes (`memory reconcile` / `muse_reconcile_anchors`).
|
|
33
|
+
- **Latency & Quality Telemetry Suite**: Benchmarks microsecond hot caches, FTS5 BM25 search, knapsack token packing, and ROI in a clean ASCII scoreboard (`memory benchmark`).
|
|
34
|
+
- **Expanded Agent Skills**: Shipped turnkey skills for `muse-health`, `muse-drift`, `muse-why`, `muse-sync`, and `muse-mesh`.
|
|
35
|
+
|
|
36
|
+
### v2.1.0
|
|
37
|
+
- **Cross-Agent Knowledge Sync & P2P Gossip Protocol**: Sealed portable `SyncPacket` engine with SHA-256 integrity and zero-daemon shared filesystem gossip pool (`memory sync` / `muse_sync_*`).
|
|
38
|
+
- **Web Observability Studio**: Embedded visual dashboard (`memory studio` / `memory ui`) with interactive 5-pillar health, ADR registry, code drift inspector, and sync controls.
|
|
39
|
+
- **Monorepo & Multi-Repo Mesh**: Automatic workspace discovery (pnpm, npm, bun, lerna) with cross-project memory queries and shared constraint propagation (`memory mesh` / `muse_mesh_*`).
|
|
40
|
+
|
|
41
|
+
### v2.0.0
|
|
42
|
+
- **5-Pillar Project Health Gate**: Architectural health gate evaluating store integrity, code anchors, doc-code alignment, negative sentry, and technical debt (`memory health` / `muse_health`).
|
|
43
|
+
- **Cognitive "Why" Reasoner**: Reconstructs historical code evolution, bug workarounds, and trade-offs before refactoring (`muse_why`).
|
|
44
|
+
- **Living Architecture Decision Records (ADRs)**: Queryable ADRs with options, consequences, native code anchors, and supersession lineage (`memory adr` / `memory_adr_record`).
|
|
45
|
+
- **Doc β· Code Drift Engine**: Continuously audits documentation against AST code implementations across 6 drift states (`memory drift` / `memory_drift_audit`).
|
|
46
|
+
- **Unified Context Orchestrator & MCP Profiles**: Single-call fused context injection with knapsack token packing (`muse_context`) and task-specific tool profiles.
|
|
47
|
+
- **Native Structural Code Anchors**: Line-independent structural SHA-256 hashing for files, symbols, and routes.
|
|
48
|
+
- **Scoped Promotion & Archival Lifecycle**: 3-tier promotion ladder (`local` β `project` β `global`) and cold/dormant/archived storage tiers.
|
|
75
49
|
|
|
76
50
|
---
|
|
77
51
|
|
|
78
52
|
## π Table of Contents
|
|
79
53
|
|
|
80
|
-
- [π What's New
|
|
54
|
+
- [π What's New](#-whats-new)
|
|
81
55
|
- [π‘ What is Muse Memory? (TL;DR)](#-what-is-muse-memory-tldr)
|
|
82
56
|
- [β¨ Key Feature Highlights](#-key-feature-highlights)
|
|
83
57
|
- [β‘ Quick Start & Installation](#-quick-start--installation)
|
package/dist/index.js
CHANGED
|
@@ -5720,6 +5720,8 @@ function openDatabase(dbPath) {
|
|
|
5720
5720
|
rawDb = new Database(dbPath, { create: true });
|
|
5721
5721
|
rawDb.run("PRAGMA journal_mode = WAL;");
|
|
5722
5722
|
rawDb.run("PRAGMA synchronous = NORMAL;");
|
|
5723
|
+
rawDb.run("PRAGMA busy_timeout = 5000;");
|
|
5724
|
+
rawDb.run("PRAGMA foreign_keys = ON;");
|
|
5723
5725
|
rawDb.run("PRAGMA cache_size = -64000;");
|
|
5724
5726
|
rawDb.run("PRAGMA mmap_size = 268435456;");
|
|
5725
5727
|
rawDb.run("PRAGMA temp_store = MEMORY;");
|
|
@@ -5758,6 +5760,8 @@ function openDatabase(dbPath) {
|
|
|
5758
5760
|
rawDb = new DatabaseSync(dbPath);
|
|
5759
5761
|
rawDb.exec("PRAGMA journal_mode = WAL;");
|
|
5760
5762
|
rawDb.exec("PRAGMA synchronous = NORMAL;");
|
|
5763
|
+
rawDb.exec("PRAGMA busy_timeout = 5000;");
|
|
5764
|
+
rawDb.exec("PRAGMA foreign_keys = ON;");
|
|
5761
5765
|
rawDb.exec("PRAGMA cache_size = -64000;");
|
|
5762
5766
|
rawDb.exec("PRAGMA mmap_size = 268435456;");
|
|
5763
5767
|
rawDb.exec("PRAGMA temp_store = MEMORY;");
|
|
@@ -6709,19 +6713,52 @@ function list(store, filters) {
|
|
|
6709
6713
|
if (cached)
|
|
6710
6714
|
return cached;
|
|
6711
6715
|
}
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6720
|
-
|
|
6716
|
+
let entries = [];
|
|
6717
|
+
if (store.db) {
|
|
6718
|
+
entries = listMemories(store.db, filters);
|
|
6719
|
+
if (existsSync10(store.dir)) {
|
|
6720
|
+
const dbIds = new Set(entries.map((e) => e.id));
|
|
6721
|
+
const diskFiles = readdirSync2(store.dir);
|
|
6722
|
+
for (const f of diskFiles) {
|
|
6723
|
+
if (f.endsWith(".yaml")) {
|
|
6724
|
+
const diskId = f.slice(0, -5);
|
|
6725
|
+
if (!dbIds.has(diskId)) {
|
|
6726
|
+
const externalEntry = get(store, diskId);
|
|
6727
|
+
if (externalEntry) {
|
|
6728
|
+
try {
|
|
6729
|
+
insertOrReplaceMemory(store.db, externalEntry);
|
|
6730
|
+
} catch {}
|
|
6731
|
+
let matches = true;
|
|
6732
|
+
if (filters?.project && externalEntry.project !== filters.project)
|
|
6733
|
+
matches = false;
|
|
6734
|
+
if (filters?.type && externalEntry.type !== filters.type)
|
|
6735
|
+
matches = false;
|
|
6736
|
+
if (filters?.status && externalEntry.status !== filters.status)
|
|
6737
|
+
matches = false;
|
|
6738
|
+
if (matches)
|
|
6739
|
+
entries.push(externalEntry);
|
|
6740
|
+
}
|
|
6741
|
+
}
|
|
6742
|
+
}
|
|
6743
|
+
}
|
|
6744
|
+
}
|
|
6745
|
+
} else {
|
|
6746
|
+
const ids = listIds(store);
|
|
6747
|
+
entries = ids.map((id) => get(store, id)).filter((e) => e !== null);
|
|
6748
|
+
if (filters?.project)
|
|
6749
|
+
entries = entries.filter((e) => e.project === filters.project);
|
|
6750
|
+
if (filters?.type)
|
|
6751
|
+
entries = entries.filter((e) => e.type === filters.type);
|
|
6752
|
+
if (filters?.status)
|
|
6753
|
+
entries = entries.filter((e) => e.status === filters.status);
|
|
6754
|
+
}
|
|
6721
6755
|
if (store.cache) {
|
|
6722
|
-
store.cache.setQuery(cacheKey,
|
|
6756
|
+
store.cache.setQuery(cacheKey, entries, undefined, dirMtime);
|
|
6757
|
+
for (const e of entries) {
|
|
6758
|
+
store.cache.setEntry(e);
|
|
6759
|
+
}
|
|
6723
6760
|
}
|
|
6724
|
-
return
|
|
6761
|
+
return entries;
|
|
6725
6762
|
}
|
|
6726
6763
|
function extractEntryText(entry) {
|
|
6727
6764
|
const parts = [
|
|
@@ -6756,7 +6793,9 @@ function save(store, entry, options = {}) {
|
|
|
6756
6793
|
try {
|
|
6757
6794
|
mtimeMs = statSync(file).mtimeMs;
|
|
6758
6795
|
} catch {}
|
|
6759
|
-
} catch {
|
|
6796
|
+
} catch (err) {
|
|
6797
|
+
console.warn(`[WARN] Dual-write YAML failed for memory '${entry.id}':`, err instanceof Error ? err.message : String(err));
|
|
6798
|
+
}
|
|
6760
6799
|
if (store.cache) {
|
|
6761
6800
|
store.cache.setEntry(entry, undefined, mtimeMs);
|
|
6762
6801
|
}
|
|
@@ -20574,77 +20613,97 @@ async function reconcileCodeAnchors(store, options = {}) {
|
|
|
20574
20613
|
let repairedEntriesCount = 0;
|
|
20575
20614
|
let staleEntriesCount = 0;
|
|
20576
20615
|
const details = [];
|
|
20577
|
-
|
|
20578
|
-
|
|
20579
|
-
|
|
20580
|
-
|
|
20581
|
-
|
|
20582
|
-
|
|
20583
|
-
|
|
20584
|
-
const
|
|
20585
|
-
|
|
20586
|
-
|
|
20587
|
-
|
|
20588
|
-
const
|
|
20589
|
-
|
|
20590
|
-
|
|
20591
|
-
|
|
20592
|
-
|
|
20593
|
-
|
|
20594
|
-
|
|
20595
|
-
|
|
20596
|
-
|
|
20597
|
-
|
|
20598
|
-
|
|
20616
|
+
const inTx = !dryRun && !!store.db;
|
|
20617
|
+
if (inTx) {
|
|
20618
|
+
try {
|
|
20619
|
+
store.db.exec("BEGIN TRANSACTION;");
|
|
20620
|
+
} catch {}
|
|
20621
|
+
}
|
|
20622
|
+
try {
|
|
20623
|
+
for (const entry of entries) {
|
|
20624
|
+
if (!entry.anchors || entry.anchors.length === 0)
|
|
20625
|
+
continue;
|
|
20626
|
+
totalAuditedEntries++;
|
|
20627
|
+
const survivingAnchors = [];
|
|
20628
|
+
const entryOrphaned = [];
|
|
20629
|
+
const entryDrifted = [];
|
|
20630
|
+
const actionsTaken = [];
|
|
20631
|
+
let entryModified = false;
|
|
20632
|
+
for (const anchor of entry.anchors) {
|
|
20633
|
+
totalAnchors++;
|
|
20634
|
+
const verification = verifyCodeAnchor(root, anchor);
|
|
20635
|
+
if (verification.status === "valid") {
|
|
20636
|
+
validCount++;
|
|
20637
|
+
survivingAnchors.push(anchor);
|
|
20638
|
+
} else if (verification.status === "drifted") {
|
|
20639
|
+
driftedCount++;
|
|
20640
|
+
entryDrifted.push(`${anchor.file_path}${anchor.symbol_name ? `::${anchor.symbol_name}` : ""}`);
|
|
20641
|
+
if (updateHashes && verification.current_hash) {
|
|
20642
|
+
if (!dryRun) {
|
|
20643
|
+
anchor.structural_hash = verification.current_hash;
|
|
20644
|
+
anchor.verified_at = new Date().toISOString();
|
|
20645
|
+
}
|
|
20646
|
+
entryModified = true;
|
|
20647
|
+
actionsTaken.push(`Updated structural hash for drifted anchor '${anchor.id}'`);
|
|
20599
20648
|
}
|
|
20600
|
-
entryModified = true;
|
|
20601
|
-
actionsTaken.push(`Updated structural hash for drifted anchor '${anchor.id}'`);
|
|
20602
|
-
}
|
|
20603
|
-
survivingAnchors.push(anchor);
|
|
20604
|
-
} else {
|
|
20605
|
-
orphanedCount++;
|
|
20606
|
-
entryOrphaned.push(`${anchor.file_path}${anchor.symbol_name ? `::${anchor.symbol_name}` : ""}`);
|
|
20607
|
-
if (prune) {
|
|
20608
|
-
entryModified = true;
|
|
20609
|
-
prunedAnchorsCount++;
|
|
20610
|
-
actionsTaken.push(`Pruned orphaned anchor '${anchor.id}' (${verification.drift_details || "code deleted"})`);
|
|
20611
|
-
} else {
|
|
20612
20649
|
survivingAnchors.push(anchor);
|
|
20650
|
+
} else {
|
|
20651
|
+
orphanedCount++;
|
|
20652
|
+
entryOrphaned.push(`${anchor.file_path}${anchor.symbol_name ? `::${anchor.symbol_name}` : ""}`);
|
|
20653
|
+
if (prune) {
|
|
20654
|
+
entryModified = true;
|
|
20655
|
+
prunedAnchorsCount++;
|
|
20656
|
+
actionsTaken.push(`Pruned orphaned anchor '${anchor.id}' (${verification.drift_details || "code deleted"})`);
|
|
20657
|
+
} else {
|
|
20658
|
+
survivingAnchors.push(anchor);
|
|
20659
|
+
}
|
|
20613
20660
|
}
|
|
20614
20661
|
}
|
|
20615
|
-
|
|
20616
|
-
|
|
20617
|
-
|
|
20618
|
-
|
|
20619
|
-
actionsTaken.push(`Marked memory '${entry.id}' as stale (all code anchors orphaned)`);
|
|
20620
|
-
}
|
|
20621
|
-
if (!dryRun) {
|
|
20622
|
-
entry.anchors = survivingAnchors.length > 0 ? survivingAnchors : undefined;
|
|
20623
|
-
if ((!entry.anchors || entry.anchors.length === 0) && markStale2 && entry.status === "confirmed") {
|
|
20624
|
-
entry.status = "stale";
|
|
20625
|
-
entry.stale_reason = "All associated code anchors were orphaned and pruned";
|
|
20662
|
+
if (prune && entryModified) {
|
|
20663
|
+
if ((!survivingAnchors || survivingAnchors.length === 0) && markStale2 && entry.status === "confirmed") {
|
|
20664
|
+
staleEntriesCount++;
|
|
20665
|
+
actionsTaken.push(`Marked memory '${entry.id}' as stale (all code anchors orphaned)`);
|
|
20626
20666
|
}
|
|
20627
|
-
|
|
20628
|
-
|
|
20667
|
+
if (!dryRun) {
|
|
20668
|
+
entry.anchors = survivingAnchors.length > 0 ? survivingAnchors : undefined;
|
|
20669
|
+
if ((!entry.anchors || entry.anchors.length === 0) && markStale2 && entry.status === "confirmed") {
|
|
20670
|
+
entry.status = "stale";
|
|
20671
|
+
entry.stale_reason = "All associated code anchors were orphaned and pruned";
|
|
20672
|
+
}
|
|
20673
|
+
entry.updated_at = new Date().toISOString();
|
|
20674
|
+
save(store, entry);
|
|
20675
|
+
}
|
|
20676
|
+
repairedEntriesCount++;
|
|
20677
|
+
} else if (updateHashes && entryModified) {
|
|
20678
|
+
if (!dryRun) {
|
|
20679
|
+
entry.anchors = survivingAnchors.length > 0 ? survivingAnchors : undefined;
|
|
20680
|
+
entry.updated_at = new Date().toISOString();
|
|
20681
|
+
save(store, entry);
|
|
20682
|
+
}
|
|
20683
|
+
repairedEntriesCount++;
|
|
20629
20684
|
}
|
|
20630
|
-
|
|
20631
|
-
|
|
20632
|
-
|
|
20633
|
-
|
|
20634
|
-
|
|
20635
|
-
|
|
20685
|
+
if (entryOrphaned.length > 0 || entryDrifted.length > 0 || actionsTaken.length > 0) {
|
|
20686
|
+
details.push({
|
|
20687
|
+
entryId: entry.id,
|
|
20688
|
+
title: entry.title,
|
|
20689
|
+
actionsTaken,
|
|
20690
|
+
orphanedAnchors: entryOrphaned,
|
|
20691
|
+
driftedAnchors: entryDrifted
|
|
20692
|
+
});
|
|
20636
20693
|
}
|
|
20637
|
-
repairedEntriesCount++;
|
|
20638
20694
|
}
|
|
20639
|
-
if (
|
|
20640
|
-
|
|
20641
|
-
|
|
20642
|
-
|
|
20643
|
-
actionsTaken,
|
|
20644
|
-
orphanedAnchors: entryOrphaned,
|
|
20645
|
-
driftedAnchors: entryDrifted
|
|
20646
|
-
});
|
|
20695
|
+
if (inTx) {
|
|
20696
|
+
try {
|
|
20697
|
+
store.db.exec("COMMIT;");
|
|
20698
|
+
} catch {}
|
|
20647
20699
|
}
|
|
20700
|
+
} catch (err) {
|
|
20701
|
+
if (inTx) {
|
|
20702
|
+
try {
|
|
20703
|
+
store.db.exec("ROLLBACK;");
|
|
20704
|
+
} catch {}
|
|
20705
|
+
}
|
|
20706
|
+
throw err;
|
|
20648
20707
|
}
|
|
20649
20708
|
if (!dryRun && store.memoryDir && (prunedAnchorsCount > 0 || staleEntriesCount > 0)) {
|
|
20650
20709
|
recordAuditEvent(store.memoryDir, {
|
|
@@ -33838,11 +33897,19 @@ async function analyzeMemoryCodeImpact(store, options) {
|
|
|
33838
33897
|
}));
|
|
33839
33898
|
const allAdrs = listAdrs(store);
|
|
33840
33899
|
const matchedAdrs = [];
|
|
33900
|
+
const normTarget = targetFile.toLowerCase().replace(/^[./\\]+/, "");
|
|
33841
33901
|
const fileBase = basename2(targetFile).toLowerCase();
|
|
33902
|
+
const symbolRegex = targetSymbol && targetSymbol.length > 2 ? new RegExp(`\\b${targetSymbol.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&")}\\b`, "i") : null;
|
|
33903
|
+
const pathRegex = fileBase.length > 3 && fileBase !== "index.ts" && fileBase !== "index.js" ? new RegExp(`\\b${fileBase.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&")}\\b`, "i") : null;
|
|
33842
33904
|
for (const adr of allAdrs) {
|
|
33843
|
-
const text = `${adr.title} ${adr.content}
|
|
33844
|
-
const hasAnchor = adr.anchors?.some((a) =>
|
|
33845
|
-
|
|
33905
|
+
const text = `${adr.title} ${adr.content}`;
|
|
33906
|
+
const hasAnchor = adr.anchors?.some((a) => {
|
|
33907
|
+
const aPath = a.file_path.toLowerCase().replace(/^[./\\]+/, "");
|
|
33908
|
+
return aPath === normTarget || aPath.endsWith("/" + fileBase) || targetSymbol && a.symbol_name?.toLowerCase() === targetSymbol.toLowerCase();
|
|
33909
|
+
});
|
|
33910
|
+
const matchesSymbol = symbolRegex ? symbolRegex.test(text) : false;
|
|
33911
|
+
const matchesPath = pathRegex ? pathRegex.test(text) : false;
|
|
33912
|
+
if (hasAnchor || matchesSymbol || matchesPath) {
|
|
33846
33913
|
matchedAdrs.push({
|
|
33847
33914
|
id: adr.id,
|
|
33848
33915
|
title: adr.title,
|
|
@@ -34295,28 +34362,38 @@ var init_harvester2 = __esm(() => {
|
|
|
34295
34362
|
});
|
|
34296
34363
|
|
|
34297
34364
|
// src/compaction/pr-context.ts
|
|
34298
|
-
import {
|
|
34365
|
+
import { execFileSync } from "node:child_process";
|
|
34299
34366
|
import { existsSync as existsSync46, readFileSync as readFileSync38 } from "node:fs";
|
|
34300
34367
|
import { join as join43, basename as basename3 } from "node:path";
|
|
34301
34368
|
async function generatePrContext(store, options = {}) {
|
|
34302
34369
|
const root = options.workspaceRoot || store.dir || process.cwd();
|
|
34303
|
-
const
|
|
34370
|
+
const rawBase = options.baseBranch || "main";
|
|
34371
|
+
const safeBase = /^[a-zA-Z0-9._\/-]+$/.test(rawBase) ? rawBase : "main";
|
|
34304
34372
|
let changedFiles = [];
|
|
34305
34373
|
try {
|
|
34306
|
-
const
|
|
34307
|
-
|
|
34374
|
+
const stdout = execFileSync("git", ["diff", "--name-only", `${safeBase}...HEAD`], {
|
|
34375
|
+
cwd: root,
|
|
34376
|
+
encoding: "utf8",
|
|
34377
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
34378
|
+
});
|
|
34308
34379
|
changedFiles = stdout.split(`
|
|
34309
34380
|
`).map((f) => f.trim()).filter(Boolean);
|
|
34310
34381
|
} catch {
|
|
34311
34382
|
try {
|
|
34312
|
-
const
|
|
34313
|
-
|
|
34383
|
+
const stdout = execFileSync("git", ["diff", "--name-only", "HEAD~1"], {
|
|
34384
|
+
cwd: root,
|
|
34385
|
+
encoding: "utf8",
|
|
34386
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
34387
|
+
});
|
|
34314
34388
|
changedFiles = stdout.split(`
|
|
34315
34389
|
`).map((f) => f.trim()).filter(Boolean);
|
|
34316
34390
|
} catch {
|
|
34317
34391
|
try {
|
|
34318
|
-
const
|
|
34319
|
-
|
|
34392
|
+
const stdout = execFileSync("git", ["status", "--porcelain"], {
|
|
34393
|
+
cwd: root,
|
|
34394
|
+
encoding: "utf8",
|
|
34395
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
34396
|
+
});
|
|
34320
34397
|
changedFiles = stdout.split(`
|
|
34321
34398
|
`).map((l) => l.slice(3).trim()).filter(Boolean);
|
|
34322
34399
|
} catch {
|
|
@@ -34472,7 +34549,7 @@ async function generatePrContext(store, options = {}) {
|
|
|
34472
34549
|
return {
|
|
34473
34550
|
title: prTitle,
|
|
34474
34551
|
bodyMarkdown: md,
|
|
34475
|
-
baseBranch:
|
|
34552
|
+
baseBranch: safeBase,
|
|
34476
34553
|
changedFiles,
|
|
34477
34554
|
anchorsTouched: totalAnchorsTouched,
|
|
34478
34555
|
adrsInvolved,
|
|
@@ -35349,7 +35426,7 @@ __export(exports_drift, {
|
|
|
35349
35426
|
scanCodeDrift: () => scanCodeDrift,
|
|
35350
35427
|
scanCodeDriftFromDiff: () => scanCodeDriftFromDiff
|
|
35351
35428
|
});
|
|
35352
|
-
import { execSync as
|
|
35429
|
+
import { execSync as execSync3 } from "node:child_process";
|
|
35353
35430
|
import { existsSync as existsSync52 } from "node:fs";
|
|
35354
35431
|
import { join as join49, isAbsolute as isAbsolute2 } from "node:path";
|
|
35355
35432
|
function scanCodeDriftFromDiff(entries, changedFiles, workspaceRoot) {
|
|
@@ -35390,7 +35467,7 @@ function scanCodeDriftFromDiff(entries, changedFiles, workspaceRoot) {
|
|
|
35390
35467
|
function getGitChangedFiles(workspaceRoot) {
|
|
35391
35468
|
const root = workspaceRoot || process.cwd();
|
|
35392
35469
|
try {
|
|
35393
|
-
const stdout =
|
|
35470
|
+
const stdout = execSync3("git status --porcelain", {
|
|
35394
35471
|
cwd: root,
|
|
35395
35472
|
encoding: "utf8",
|
|
35396
35473
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -35407,7 +35484,7 @@ function getGitChangedFiles(workspaceRoot) {
|
|
|
35407
35484
|
files.push(filePath);
|
|
35408
35485
|
}
|
|
35409
35486
|
try {
|
|
35410
|
-
const diffOut =
|
|
35487
|
+
const diffOut = execSync3("git diff --name-only HEAD", {
|
|
35411
35488
|
cwd: root,
|
|
35412
35489
|
encoding: "utf8",
|
|
35413
35490
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -40249,8 +40326,9 @@ async function runMemoryBenchmark(store, options = {}) {
|
|
|
40249
40326
|
const iterations = options.iterations || 30;
|
|
40250
40327
|
const testQuery = options.query || "authentication architecture security";
|
|
40251
40328
|
const tokenBudget = options.tokenBudget || 1500;
|
|
40252
|
-
const allEntries = list(store);
|
|
40253
40329
|
const coldStartT0 = performance.now();
|
|
40330
|
+
const coldStore = openStore(store.memoryDir || store.dir);
|
|
40331
|
+
const allEntries = list(coldStore);
|
|
40254
40332
|
const entriesCount = allEntries.length;
|
|
40255
40333
|
const cold_startup_ms = Math.round((performance.now() - coldStartT0) * 100) / 100;
|
|
40256
40334
|
const hotSamplesUs = [];
|
|
@@ -40473,10 +40551,11 @@ async function handleReconcileCommand(parsed) {
|
|
|
40473
40551
|
return 1;
|
|
40474
40552
|
}
|
|
40475
40553
|
const { root, store } = ctx;
|
|
40476
|
-
const
|
|
40477
|
-
const
|
|
40478
|
-
const
|
|
40479
|
-
const
|
|
40554
|
+
const isTrue = (val) => val === true || val === "true" || val === "";
|
|
40555
|
+
const prune = isTrue(parsed.flags["prune"]) || isTrue(parsed.flags["p"]);
|
|
40556
|
+
const markStale2 = isTrue(parsed.flags["mark-stale"]) || isTrue(parsed.flags["stale"]);
|
|
40557
|
+
const updateHashes = isTrue(parsed.flags["update-hashes"]);
|
|
40558
|
+
const dryRun = isTrue(parsed.flags["dry-run"]) || !prune && !markStale2 && !updateHashes;
|
|
40480
40559
|
const { reconcileCodeAnchors: reconcileCodeAnchors2, formatReconcileReport: formatReconcileReport2 } = await Promise.resolve().then(() => (init_health(), exports_health));
|
|
40481
40560
|
const report = await reconcileCodeAnchors2(store, {
|
|
40482
40561
|
prune,
|