eminiar 0.7.0 → 0.8.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/.claude-plugin/plugin.json +1 -1
- package/dist/cli.js +471 -11
- package/dist/server.js +1 -0
- package/dist/ui/app.global.js +48 -48
- package/dist/ui/styles.css +4 -0
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eminiar",
|
|
3
3
|
"displayName": "Eminiar",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.0",
|
|
5
5
|
"description": "Local-first context, memory and knowledge graph for Claude Code: sandboxed execution, FTS5 + vector search, session continuity, code graph.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Ryan Dick"
|
package/dist/cli.js
CHANGED
|
@@ -35516,6 +35516,7 @@ __export(store_exports, {
|
|
|
35516
35516
|
isValidName: () => isValidName,
|
|
35517
35517
|
list: () => list,
|
|
35518
35518
|
memoriesDir: () => memoriesDir,
|
|
35519
|
+
memoriesRel: () => memoriesRel,
|
|
35519
35520
|
memoryLinks: () => memoryLinks,
|
|
35520
35521
|
normalizeRelated: () => normalizeRelated,
|
|
35521
35522
|
read: () => read,
|
|
@@ -43457,8 +43458,454 @@ var init_history_api = __esm({
|
|
|
43457
43458
|
}
|
|
43458
43459
|
});
|
|
43459
43460
|
|
|
43461
|
+
// src/history/lineage.ts
|
|
43462
|
+
function mergedBranchName(subject) {
|
|
43463
|
+
const pr = PR_MERGE.exec(subject);
|
|
43464
|
+
if (pr) return { name: pr[2], pr: Number(pr[1]) };
|
|
43465
|
+
const br = BRANCH_MERGE.exec(subject);
|
|
43466
|
+
if (br) return { name: br[1].replace(/^origin\//, "") };
|
|
43467
|
+
return void 0;
|
|
43468
|
+
}
|
|
43469
|
+
function firstParents(m, sha, stop, max) {
|
|
43470
|
+
const out = [];
|
|
43471
|
+
let cur = sha ? m.bySha.get(sha) : void 0;
|
|
43472
|
+
while (cur && !stop.has(cur.sha) && out.length < max) {
|
|
43473
|
+
out.push(cur);
|
|
43474
|
+
cur = cur.parents[0] ? m.bySha.get(cur.parents[0]) : void 0;
|
|
43475
|
+
}
|
|
43476
|
+
return out;
|
|
43477
|
+
}
|
|
43478
|
+
function branchLineage(m, opts = {}) {
|
|
43479
|
+
const max = opts.maxPerBranch ?? 500;
|
|
43480
|
+
const def = m.branches.find((b) => b.isDefault && !b.remote) ?? m.branches.find((b) => b.isDefault);
|
|
43481
|
+
const defaultName = def ? def.remote ? def.name.replace(/^[^/]+\//, "") : def.name : m.base ?? "main";
|
|
43482
|
+
const mainline = firstParents(m, def?.sha ?? m.head, /* @__PURE__ */ new Set(), 1e5);
|
|
43483
|
+
const onMain = new Set(mainline.map((c) => c.sha));
|
|
43484
|
+
const byName = /* @__PURE__ */ new Map();
|
|
43485
|
+
const entry = (name) => {
|
|
43486
|
+
let b = byName.get(name);
|
|
43487
|
+
if (!b) {
|
|
43488
|
+
b = {
|
|
43489
|
+
name,
|
|
43490
|
+
commits: [],
|
|
43491
|
+
tipAt: 0,
|
|
43492
|
+
isDefault: name === defaultName,
|
|
43493
|
+
live: false,
|
|
43494
|
+
merged: false,
|
|
43495
|
+
prs: [],
|
|
43496
|
+
merges: []
|
|
43497
|
+
};
|
|
43498
|
+
byName.set(name, b);
|
|
43499
|
+
}
|
|
43500
|
+
return b;
|
|
43501
|
+
};
|
|
43502
|
+
const own2 = /* @__PURE__ */ new Map();
|
|
43503
|
+
const add = (name, cs) => {
|
|
43504
|
+
const set2 = own2.get(name) ?? /* @__PURE__ */ new Set();
|
|
43505
|
+
for (const c of cs) if (!c.merge) set2.add(c.sha);
|
|
43506
|
+
own2.set(name, set2);
|
|
43507
|
+
const b = entry(name);
|
|
43508
|
+
for (const c of cs) b.tipAt = Math.max(b.tipAt, c.at);
|
|
43509
|
+
};
|
|
43510
|
+
add(defaultName, mainline);
|
|
43511
|
+
entry(defaultName).live = !!def;
|
|
43512
|
+
for (const c of mainline) {
|
|
43513
|
+
if (!c.merge || c.parents.length < 2) continue;
|
|
43514
|
+
const found = mergedBranchName(c.subject);
|
|
43515
|
+
const name = found?.name ?? (c.pr ? `PR #${c.pr}` : `merge ${c.short}`);
|
|
43516
|
+
if (name === defaultName) continue;
|
|
43517
|
+
add(name, firstParents(m, c.parents[1], onMain, max));
|
|
43518
|
+
const b = entry(name);
|
|
43519
|
+
b.merged = true;
|
|
43520
|
+
b.merges.push(c.sha);
|
|
43521
|
+
const pr = found?.pr ?? c.pr;
|
|
43522
|
+
if (pr && !b.prs.includes(pr)) b.prs.push(pr);
|
|
43523
|
+
}
|
|
43524
|
+
const locals = new Set(m.branches.filter((b) => !b.remote).map((b) => b.name));
|
|
43525
|
+
for (const ref of [...m.branches].sort((a, b) => Number(a.remote) - Number(b.remote))) {
|
|
43526
|
+
if (ref.isDefault) continue;
|
|
43527
|
+
const name = ref.remote ? ref.name.replace(/^[^/]+\//, "") : ref.name;
|
|
43528
|
+
if (ref.remote && (locals.has(name) || name === "HEAD" || !name)) continue;
|
|
43529
|
+
if (name === defaultName) continue;
|
|
43530
|
+
add(name, firstParents(m, ref.sha, onMain, max));
|
|
43531
|
+
const b = entry(name);
|
|
43532
|
+
b.live = true;
|
|
43533
|
+
b.merged ||= ref.merged;
|
|
43534
|
+
if (!b.tipAt) b.tipAt = ref.at;
|
|
43535
|
+
}
|
|
43536
|
+
for (const [name, set2] of own2) {
|
|
43537
|
+
entry(name).commits = [...set2].map((s) => m.bySha.get(s)).sort((a, b) => b.at - a.at).map((c) => c.sha);
|
|
43538
|
+
}
|
|
43539
|
+
const branches = [...byName.values()];
|
|
43540
|
+
const ownerOf = /* @__PURE__ */ new Map();
|
|
43541
|
+
for (const b of branches)
|
|
43542
|
+
for (const s of b.commits) ownerOf.set(s, [...ownerOf.get(s) ?? [], b.name]);
|
|
43543
|
+
return { defaultName, branches, ownerOf };
|
|
43544
|
+
}
|
|
43545
|
+
var PR_MERGE, BRANCH_MERGE;
|
|
43546
|
+
var init_lineage = __esm({
|
|
43547
|
+
"src/history/lineage.ts"() {
|
|
43548
|
+
"use strict";
|
|
43549
|
+
init_esm_shims();
|
|
43550
|
+
PR_MERGE = /^Merge pull request #(\d+) from [^/\s]+\/(\S+)/;
|
|
43551
|
+
BRANCH_MERGE = /^Merge (?:remote-tracking )?branch '([^']+)'/;
|
|
43552
|
+
}
|
|
43553
|
+
});
|
|
43554
|
+
|
|
43555
|
+
// src/ui/history-graph-api.ts
|
|
43556
|
+
import { existsSync as existsSync24 } from "fs";
|
|
43557
|
+
import { join as join28 } from "path";
|
|
43558
|
+
function parseList(raw) {
|
|
43559
|
+
if (!raw) return [];
|
|
43560
|
+
try {
|
|
43561
|
+
const v = JSON.parse(raw);
|
|
43562
|
+
return Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
|
|
43563
|
+
} catch {
|
|
43564
|
+
return [];
|
|
43565
|
+
}
|
|
43566
|
+
}
|
|
43567
|
+
function metaOf3(raw) {
|
|
43568
|
+
if (!raw) return {};
|
|
43569
|
+
try {
|
|
43570
|
+
return JSON.parse(raw);
|
|
43571
|
+
} catch {
|
|
43572
|
+
return {};
|
|
43573
|
+
}
|
|
43574
|
+
}
|
|
43575
|
+
function historyGraphKnowledgePayload(ctx, opts = {}) {
|
|
43576
|
+
const db = getStorage(ctx);
|
|
43577
|
+
const m = getHistory(ctx, db);
|
|
43578
|
+
if (!m) return NO_GIT2;
|
|
43579
|
+
reconcile(ctx, db);
|
|
43580
|
+
try {
|
|
43581
|
+
ensureDocsGraph(ctx, db);
|
|
43582
|
+
} catch {
|
|
43583
|
+
}
|
|
43584
|
+
return buildHistoryGraph(ctx, db, m, opts);
|
|
43585
|
+
}
|
|
43586
|
+
function buildHistoryGraph(ctx, db, m, opts = {}) {
|
|
43587
|
+
const nBranches = Math.max(1, Math.min(50, opts.branches ?? 8));
|
|
43588
|
+
const perBranch = Math.max(1, Math.min(200, opts.commitsPerBranch ?? 25));
|
|
43589
|
+
const perCommit = Math.max(1, Math.min(200, opts.filesPerCommit ?? 12));
|
|
43590
|
+
const limit = Math.max(20, Math.min(2e3, opts.limit ?? 400));
|
|
43591
|
+
const focus = opts.focus?.trim() || null;
|
|
43592
|
+
const { defaultName, branches, ownerOf } = branchLineage(m);
|
|
43593
|
+
const branchBy = new Map(branches.map((b) => [b.name, b]));
|
|
43594
|
+
const memDir = `${memoriesRel(ctx)}/`;
|
|
43595
|
+
const memoryOfPath = (p) => p.startsWith(memDir) && p.endsWith(".md") ? p.slice(memDir.length, -3) : void 0;
|
|
43596
|
+
const memRows = new Map(
|
|
43597
|
+
db.memoryList({ limit: 1e5 }).filter((r) => r.name).map((r) => [r.name, r])
|
|
43598
|
+
);
|
|
43599
|
+
const memFiles = /* @__PURE__ */ new Map();
|
|
43600
|
+
for (const [name, row] of memRows) {
|
|
43601
|
+
const paths2 = /* @__PURE__ */ new Set();
|
|
43602
|
+
for (const id of parseList(row.node_ids)) {
|
|
43603
|
+
const f = fileOf(id);
|
|
43604
|
+
if (f) paths2.add(f);
|
|
43605
|
+
}
|
|
43606
|
+
if (paths2.size) memFiles.set(name, [...paths2]);
|
|
43607
|
+
}
|
|
43608
|
+
const nonMerge = (cs) => cs.filter((c) => !c.merge);
|
|
43609
|
+
const touching = (paths2, cap) => {
|
|
43610
|
+
const out = /* @__PURE__ */ new Map();
|
|
43611
|
+
for (const p of paths2) for (const c of nonMerge(commitsForFile(m, p))) out.set(c.sha, c);
|
|
43612
|
+
return [...out.values()].sort((a, b) => b.at - a.at).slice(0, cap);
|
|
43613
|
+
};
|
|
43614
|
+
const commitSet = /* @__PURE__ */ new Map();
|
|
43615
|
+
const branchSet = /* @__PURE__ */ new Set();
|
|
43616
|
+
let onlyFiles = null;
|
|
43617
|
+
const addCommits = (cs) => {
|
|
43618
|
+
for (const c of cs) commitSet.set(c.sha, c);
|
|
43619
|
+
};
|
|
43620
|
+
let focusId = null;
|
|
43621
|
+
let followOwners = true;
|
|
43622
|
+
const kind = focus ? parseId(focus).kind : null;
|
|
43623
|
+
if (!focus) {
|
|
43624
|
+
followOwners = false;
|
|
43625
|
+
const feature = branches.filter((b) => !b.isDefault && b.commits.length).sort((a, b) => b.tipAt - a.tipAt).slice(0, nBranches);
|
|
43626
|
+
for (const b of feature) {
|
|
43627
|
+
branchSet.add(b.name);
|
|
43628
|
+
addCommits(b.commits.slice(0, perBranch).map((s) => m.bySha.get(s)));
|
|
43629
|
+
}
|
|
43630
|
+
const def = branchBy.get(defaultName);
|
|
43631
|
+
if (def) {
|
|
43632
|
+
branchSet.add(def.name);
|
|
43633
|
+
const oldest = Math.min(...feature.map((b) => b.tipAt), Date.now());
|
|
43634
|
+
addCommits(
|
|
43635
|
+
def.commits.map((s) => m.bySha.get(s)).filter((c, i) => i < perBranch && (feature.length < nBranches || c.at >= oldest))
|
|
43636
|
+
);
|
|
43637
|
+
}
|
|
43638
|
+
} else if (kind === "branch") {
|
|
43639
|
+
const name = focus.slice("branch:".length);
|
|
43640
|
+
const b = branchBy.get(name) ?? branches.find((x) => x.name.endsWith(`/${name}`));
|
|
43641
|
+
if (b) {
|
|
43642
|
+
focusId = branchId(b.name);
|
|
43643
|
+
branchSet.add(b.name);
|
|
43644
|
+
if (b.merged) branchSet.add(defaultName);
|
|
43645
|
+
addCommits(b.commits.slice(0, 150).map((s) => m.bySha.get(s)));
|
|
43646
|
+
}
|
|
43647
|
+
followOwners = false;
|
|
43648
|
+
} else if (kind === "commit") {
|
|
43649
|
+
const c = resolveCommit(m, focus.slice("commit:".length));
|
|
43650
|
+
if (c) {
|
|
43651
|
+
focusId = commitId(c.sha);
|
|
43652
|
+
addCommits([c]);
|
|
43653
|
+
addCommits([...c.origins, ...c.blamedBy].flatMap((s) => m.bySha.get(s) ?? []));
|
|
43654
|
+
}
|
|
43655
|
+
} else if (kind === "memory") {
|
|
43656
|
+
const name = focus.slice("memory:".length);
|
|
43657
|
+
focusId = memoryId(name);
|
|
43658
|
+
const paths2 = memFiles.get(name) ?? [];
|
|
43659
|
+
onlyFiles = new Set(paths2);
|
|
43660
|
+
const own2 = `${memDir}${name}.md`;
|
|
43661
|
+
addCommits([...touching(paths2, 60), ...touching([own2], 20)]);
|
|
43662
|
+
} else if (kind === "doc") {
|
|
43663
|
+
focusId = focus;
|
|
43664
|
+
const paths2 = db.graphEdgesFrom([focus], ["documents"]).map((e) => fileOf(e.dst)).filter((p) => !!p);
|
|
43665
|
+
onlyFiles = new Set(paths2);
|
|
43666
|
+
addCommits(touching(paths2, 60));
|
|
43667
|
+
} else {
|
|
43668
|
+
const path3 = fileOf(focus) ?? focus.replace(/^file:/, "");
|
|
43669
|
+
focusId = fileId(path3);
|
|
43670
|
+
onlyFiles = /* @__PURE__ */ new Set([path3]);
|
|
43671
|
+
addCommits(touching([path3], 60));
|
|
43672
|
+
}
|
|
43673
|
+
if (followOwners)
|
|
43674
|
+
for (const sha of commitSet.keys())
|
|
43675
|
+
for (const name of ownerOf.get(sha) ?? []) branchSet.add(name);
|
|
43676
|
+
const edges = /* @__PURE__ */ new Map();
|
|
43677
|
+
const addEdge = (src, dst, kind2, weight = 1) => {
|
|
43678
|
+
if (src === dst) return;
|
|
43679
|
+
const key = `${src}|${dst}|${kind2}`;
|
|
43680
|
+
if (!edges.has(key)) edges.set(key, { src, dst, kind: kind2, weight });
|
|
43681
|
+
};
|
|
43682
|
+
for (const name of branchSet) {
|
|
43683
|
+
const b = branchBy.get(name);
|
|
43684
|
+
if (!b) continue;
|
|
43685
|
+
for (const sha of b.commits)
|
|
43686
|
+
if (commitSet.has(sha)) addEdge(branchId(name), commitId(sha), "contains");
|
|
43687
|
+
if (b.merged && !b.isDefault && branchSet.has(defaultName))
|
|
43688
|
+
addEdge(branchId(name), branchId(defaultName), "merged_into");
|
|
43689
|
+
}
|
|
43690
|
+
const touchCount = /* @__PURE__ */ new Map();
|
|
43691
|
+
const commitFiles = /* @__PURE__ */ new Map();
|
|
43692
|
+
const recorded = /* @__PURE__ */ new Map();
|
|
43693
|
+
for (const c of commitSet.values()) {
|
|
43694
|
+
const mems = [];
|
|
43695
|
+
const paths2 = [];
|
|
43696
|
+
for (const f of [...c.files].sort((a, b) => b.added + b.deleted - (a.added + a.deleted))) {
|
|
43697
|
+
const mem = memoryOfPath(f.path);
|
|
43698
|
+
if (mem) {
|
|
43699
|
+
mems.push(mem);
|
|
43700
|
+
continue;
|
|
43701
|
+
}
|
|
43702
|
+
if (LOCKFILE.test(f.path)) continue;
|
|
43703
|
+
if (onlyFiles && !onlyFiles.has(f.path)) continue;
|
|
43704
|
+
paths2.push(f.path);
|
|
43705
|
+
}
|
|
43706
|
+
const kept2 = paths2.slice(0, perCommit);
|
|
43707
|
+
commitFiles.set(c.sha, kept2);
|
|
43708
|
+
for (const p of kept2) touchCount.set(p, (touchCount.get(p) ?? 0) + 1);
|
|
43709
|
+
if (mems.length) recorded.set(c.sha, mems);
|
|
43710
|
+
}
|
|
43711
|
+
for (const p of onlyFiles ?? []) if (!touchCount.has(p)) touchCount.set(p, 0);
|
|
43712
|
+
const fileBudget = Math.max(10, limit - branchSet.size - commitSet.size - 40);
|
|
43713
|
+
const files = new Set(
|
|
43714
|
+
[...touchCount.entries()].sort(
|
|
43715
|
+
(a, b) => Number(onlyFiles?.has(b[0]) ?? false) - Number(onlyFiles?.has(a[0]) ?? false) || b[1] - a[1] || (m.files.get(b[0])?.risk ?? 0) - (m.files.get(a[0])?.risk ?? 0) || a[0].localeCompare(b[0])
|
|
43716
|
+
).slice(0, fileBudget).map(([p]) => p)
|
|
43717
|
+
);
|
|
43718
|
+
for (const [sha, paths2] of commitFiles)
|
|
43719
|
+
for (const p of paths2) if (files.has(p)) addEdge(commitId(sha), fileId(p), "touches");
|
|
43720
|
+
const memories = /* @__PURE__ */ new Set();
|
|
43721
|
+
for (const [sha, mems] of recorded)
|
|
43722
|
+
for (const name of mems) {
|
|
43723
|
+
memories.add(name);
|
|
43724
|
+
addEdge(commitId(sha), memoryId(name), "records");
|
|
43725
|
+
}
|
|
43726
|
+
for (const [name, paths2] of memFiles)
|
|
43727
|
+
for (const p of paths2)
|
|
43728
|
+
if (files.has(p)) {
|
|
43729
|
+
memories.add(name);
|
|
43730
|
+
addEdge(memoryId(name), fileId(p), "mentions");
|
|
43731
|
+
}
|
|
43732
|
+
if (kind === "memory" && focus) memories.add(focus.slice("memory:".length));
|
|
43733
|
+
const docs = /* @__PURE__ */ new Set();
|
|
43734
|
+
if (files.size)
|
|
43735
|
+
for (const e of db.graphEdgesTo(
|
|
43736
|
+
[...files].map((p) => fileId(p)),
|
|
43737
|
+
["documents"]
|
|
43738
|
+
)) {
|
|
43739
|
+
docs.add(e.src);
|
|
43740
|
+
addEdge(e.src, e.dst, "documents");
|
|
43741
|
+
}
|
|
43742
|
+
if (kind === "doc" && focus) docs.add(focus);
|
|
43743
|
+
for (const l of m.links)
|
|
43744
|
+
if (commitSet.has(l.fix) && commitSet.has(l.origin))
|
|
43745
|
+
addEdge(commitId(l.fix), commitId(l.origin), "fixes", Math.min(3, 1 + l.lines / 20));
|
|
43746
|
+
const nodes = [];
|
|
43747
|
+
for (const name of branchSet) {
|
|
43748
|
+
const b = branchBy.get(name);
|
|
43749
|
+
if (!b) continue;
|
|
43750
|
+
const id = branchId(name);
|
|
43751
|
+
nodes.push({
|
|
43752
|
+
id,
|
|
43753
|
+
label: name,
|
|
43754
|
+
kind: "branch",
|
|
43755
|
+
group: "branch",
|
|
43756
|
+
path: null,
|
|
43757
|
+
line: null,
|
|
43758
|
+
root: id === focusId,
|
|
43759
|
+
at: b.tipAt,
|
|
43760
|
+
commits: b.commits.length,
|
|
43761
|
+
merged: b.merged,
|
|
43762
|
+
live: b.live,
|
|
43763
|
+
isDefault: b.isDefault,
|
|
43764
|
+
prs: b.prs.length ? b.prs : void 0
|
|
43765
|
+
});
|
|
43766
|
+
}
|
|
43767
|
+
for (const c of commitSet.values()) {
|
|
43768
|
+
const id = commitId(c.sha);
|
|
43769
|
+
nodes.push({
|
|
43770
|
+
id,
|
|
43771
|
+
label: c.subject,
|
|
43772
|
+
kind: "commit",
|
|
43773
|
+
group: "commit",
|
|
43774
|
+
path: null,
|
|
43775
|
+
line: null,
|
|
43776
|
+
root: id === focusId,
|
|
43777
|
+
sub: c.kind,
|
|
43778
|
+
bucket: c.bucket,
|
|
43779
|
+
at: c.at,
|
|
43780
|
+
author: c.author,
|
|
43781
|
+
short: c.short,
|
|
43782
|
+
risk: c.risk
|
|
43783
|
+
});
|
|
43784
|
+
}
|
|
43785
|
+
for (const p of files) {
|
|
43786
|
+
const id = fileId(p);
|
|
43787
|
+
const h = m.files.get(p);
|
|
43788
|
+
nodes.push({
|
|
43789
|
+
id,
|
|
43790
|
+
label: p,
|
|
43791
|
+
kind: "file",
|
|
43792
|
+
group: "file",
|
|
43793
|
+
path: p,
|
|
43794
|
+
line: null,
|
|
43795
|
+
root: id === focusId,
|
|
43796
|
+
missing: existsSync24(join28(ctx.root, p)) ? void 0 : true,
|
|
43797
|
+
risk: h?.risk,
|
|
43798
|
+
fixes: h?.fixes
|
|
43799
|
+
});
|
|
43800
|
+
}
|
|
43801
|
+
for (const name of memories) {
|
|
43802
|
+
const id = memoryId(name);
|
|
43803
|
+
const row = memRows.get(name);
|
|
43804
|
+
nodes.push({
|
|
43805
|
+
id,
|
|
43806
|
+
label: name,
|
|
43807
|
+
kind: "memory",
|
|
43808
|
+
group: "memory",
|
|
43809
|
+
path: row?.path ?? null,
|
|
43810
|
+
line: null,
|
|
43811
|
+
root: id === focusId,
|
|
43812
|
+
missing: row ? void 0 : true,
|
|
43813
|
+
sub: row?.kind,
|
|
43814
|
+
status: row?.status ?? (row?.kind === "decision" ? "accepted" : void 0),
|
|
43815
|
+
detail: name.includes("/") ? `${name.split("/")[0]}/` : void 0
|
|
43816
|
+
});
|
|
43817
|
+
}
|
|
43818
|
+
const docRows = new Map(db.graphGetNodes([...docs]).map((n) => [n.id, n]));
|
|
43819
|
+
for (const id of docs) {
|
|
43820
|
+
const row = docRows.get(id);
|
|
43821
|
+
const meta4 = metaOf3(row?.meta);
|
|
43822
|
+
const cat = typeof meta4.category === "string" ? meta4.category : void 0;
|
|
43823
|
+
nodes.push({
|
|
43824
|
+
id,
|
|
43825
|
+
label: row?.name ?? id.slice("doc:".length),
|
|
43826
|
+
kind: "doc",
|
|
43827
|
+
group: "doc",
|
|
43828
|
+
path: row?.path ?? null,
|
|
43829
|
+
line: null,
|
|
43830
|
+
root: id === focusId,
|
|
43831
|
+
missing: row ? void 0 : true,
|
|
43832
|
+
sub: cat,
|
|
43833
|
+
detail: cat ? categoryInfo(cat).label : void 0
|
|
43834
|
+
});
|
|
43835
|
+
}
|
|
43836
|
+
if (focusId && !nodes.some((n) => n.id === focusId)) {
|
|
43837
|
+
const p = parseId(focusId);
|
|
43838
|
+
nodes.push({
|
|
43839
|
+
id: focusId,
|
|
43840
|
+
label: p.rest,
|
|
43841
|
+
kind: p.kind,
|
|
43842
|
+
group: ["branch", "commit", "memory", "doc"].includes(p.kind) ? p.kind : "file",
|
|
43843
|
+
path: p.kind === "file" ? p.rest : null,
|
|
43844
|
+
line: null,
|
|
43845
|
+
root: true,
|
|
43846
|
+
missing: true
|
|
43847
|
+
});
|
|
43848
|
+
}
|
|
43849
|
+
for (const n of nodes) if (n.root) n.seed = true;
|
|
43850
|
+
const deg = /* @__PURE__ */ new Map();
|
|
43851
|
+
for (const e of edges.values()) {
|
|
43852
|
+
deg.set(e.src, (deg.get(e.src) ?? 0) + 1);
|
|
43853
|
+
deg.set(e.dst, (deg.get(e.dst) ?? 0) + 1);
|
|
43854
|
+
}
|
|
43855
|
+
const RANK = {
|
|
43856
|
+
branch: 1,
|
|
43857
|
+
commit: 2,
|
|
43858
|
+
memory: 3,
|
|
43859
|
+
doc: 3,
|
|
43860
|
+
file: 4
|
|
43861
|
+
};
|
|
43862
|
+
nodes.sort(
|
|
43863
|
+
(a, b) => (a.root ? 0 : RANK[a.group]) - (b.root ? 0 : RANK[b.group]) || (b.at ?? 0) - (a.at ?? 0) || (deg.get(b.id) ?? 0) - (deg.get(a.id) ?? 0) || a.id.localeCompare(b.id)
|
|
43864
|
+
);
|
|
43865
|
+
const total = nodes.length;
|
|
43866
|
+
const kept = nodes.slice(0, limit);
|
|
43867
|
+
const keep = new Set(kept.map((n) => n.id));
|
|
43868
|
+
const keptEdges = [...edges.values()].filter((e) => keep.has(e.src) && keep.has(e.dst));
|
|
43869
|
+
return {
|
|
43870
|
+
git: true,
|
|
43871
|
+
focus: focusId ?? focus,
|
|
43872
|
+
defaultBranch: defaultName,
|
|
43873
|
+
nodes: kept,
|
|
43874
|
+
edges: keptEdges,
|
|
43875
|
+
truncated: total > kept.length,
|
|
43876
|
+
total,
|
|
43877
|
+
/** Every branch with own commits, newest first, for the focus picker. */
|
|
43878
|
+
branches: branches.filter((b) => b.commits.length).sort((a, b) => Number(b.isDefault) - Number(a.isDefault) || b.tipAt - a.tipAt).map((b) => ({
|
|
43879
|
+
name: b.name,
|
|
43880
|
+
commits: b.commits.length,
|
|
43881
|
+
tipAt: b.tipAt,
|
|
43882
|
+
merged: b.merged,
|
|
43883
|
+
live: b.live,
|
|
43884
|
+
isDefault: b.isDefault
|
|
43885
|
+
}))
|
|
43886
|
+
};
|
|
43887
|
+
}
|
|
43888
|
+
var LOCKFILE, branchId, commitId, NO_GIT2;
|
|
43889
|
+
var init_history_graph_api = __esm({
|
|
43890
|
+
"src/ui/history-graph-api.ts"() {
|
|
43891
|
+
"use strict";
|
|
43892
|
+
init_esm_shims();
|
|
43893
|
+
init_category();
|
|
43894
|
+
init_graph();
|
|
43895
|
+
init_ids();
|
|
43896
|
+
init_lineage();
|
|
43897
|
+
init_model();
|
|
43898
|
+
init_store();
|
|
43899
|
+
init_storage();
|
|
43900
|
+
LOCKFILE = /(^|\/)(package-lock\.json|npm-shrinkwrap\.json|pnpm-lock\.yaml|yarn\.lock|bun\.lockb?|Cargo\.lock|go\.sum|poetry\.lock|uv\.lock|composer\.lock|Gemfile\.lock)$/;
|
|
43901
|
+
branchId = (name) => `branch:${name}`;
|
|
43902
|
+
commitId = (sha) => `commit:${sha}`;
|
|
43903
|
+
NO_GIT2 = { git: false, error: "not a git repository (or no commits yet)" };
|
|
43904
|
+
}
|
|
43905
|
+
});
|
|
43906
|
+
|
|
43460
43907
|
// src/ui/knowledge-api.ts
|
|
43461
|
-
function
|
|
43908
|
+
function metaOf4(row) {
|
|
43462
43909
|
if (!row?.meta) return {};
|
|
43463
43910
|
try {
|
|
43464
43911
|
return JSON.parse(row.meta);
|
|
@@ -43496,7 +43943,7 @@ function buildKnowledge(ctx, db, opts = {}) {
|
|
|
43496
43943
|
const hubsOf = (id) => {
|
|
43497
43944
|
const n = rows.get(id);
|
|
43498
43945
|
if (!n) return [];
|
|
43499
|
-
const m =
|
|
43946
|
+
const m = metaOf4(n);
|
|
43500
43947
|
const out = [];
|
|
43501
43948
|
if (n.kind === "memory") {
|
|
43502
43949
|
const row = memRows.get(n.name);
|
|
@@ -43626,7 +44073,7 @@ function buildKnowledge(ctx, db, opts = {}) {
|
|
|
43626
44073
|
}
|
|
43627
44074
|
const row = graphRows.get(id);
|
|
43628
44075
|
const base = vis(row, id, id === focus);
|
|
43629
|
-
const m =
|
|
44076
|
+
const m = metaOf4(row);
|
|
43630
44077
|
const node2 = {
|
|
43631
44078
|
...base,
|
|
43632
44079
|
kind: row ? row.kind : kindOfMissing(id),
|
|
@@ -43705,9 +44152,9 @@ __export(server_exports, {
|
|
|
43705
44152
|
uiDir: () => uiDir
|
|
43706
44153
|
});
|
|
43707
44154
|
import { spawn as spawn2 } from "child_process";
|
|
43708
|
-
import { existsSync as
|
|
44155
|
+
import { existsSync as existsSync25, readFileSync as readFileSync22, statSync as statSync11 } from "fs";
|
|
43709
44156
|
import { createServer } from "http";
|
|
43710
|
-
import { extname as extname3, join as
|
|
44157
|
+
import { extname as extname3, join as join29, normalize as normalize6 } from "path";
|
|
43711
44158
|
import { URL as URL2 } from "url";
|
|
43712
44159
|
function json2(res, status, body) {
|
|
43713
44160
|
res.writeHead(status, {
|
|
@@ -43729,7 +44176,7 @@ function strList(v) {
|
|
|
43729
44176
|
return void 0;
|
|
43730
44177
|
}
|
|
43731
44178
|
function uiDir() {
|
|
43732
|
-
return process.env.EMINIAR_UI_DIR ||
|
|
44179
|
+
return process.env.EMINIAR_UI_DIR || join29(pluginRoot(), "dist", "ui");
|
|
43733
44180
|
}
|
|
43734
44181
|
function originAllowed(req, port) {
|
|
43735
44182
|
const host = req.headers.host ?? "";
|
|
@@ -43753,14 +44200,14 @@ function originAllowed(req, port) {
|
|
|
43753
44200
|
function serveStatic(res, p) {
|
|
43754
44201
|
const dir = uiDir();
|
|
43755
44202
|
const rel = p === "/" ? "index.html" : p.replace(/^\/+/, "");
|
|
43756
|
-
const file3 = normalize6(
|
|
44203
|
+
const file3 = normalize6(join29(dir, rel));
|
|
43757
44204
|
if (!file3.startsWith(normalize6(dir))) return false;
|
|
43758
|
-
if (!
|
|
44205
|
+
if (!existsSync25(file3) || !statSync11(file3).isFile()) return false;
|
|
43759
44206
|
const type = MIME[extname3(file3).toLowerCase()] ?? "application/octet-stream";
|
|
43760
44207
|
if (rel === "index.html") {
|
|
43761
44208
|
const stamp = (name) => {
|
|
43762
44209
|
try {
|
|
43763
|
-
return `/${name}?v=${Math.floor(statSync11(
|
|
44210
|
+
return `/${name}?v=${Math.floor(statSync11(join29(dir, name)).mtimeMs)}`;
|
|
43764
44211
|
} catch {
|
|
43765
44212
|
return `/${name}`;
|
|
43766
44213
|
}
|
|
@@ -44090,6 +44537,18 @@ async function serve(opts) {
|
|
|
44090
44537
|
}
|
|
44091
44538
|
if (p === "/api/history/graph")
|
|
44092
44539
|
return json2(res, 200, historyGraphPayload(ctx(), num2("limit", 150)));
|
|
44540
|
+
if (p === "/api/history/knowledge")
|
|
44541
|
+
return json2(
|
|
44542
|
+
res,
|
|
44543
|
+
200,
|
|
44544
|
+
historyGraphKnowledgePayload(ctx(), {
|
|
44545
|
+
focus: str2("focus"),
|
|
44546
|
+
branches: num2("branches", 8),
|
|
44547
|
+
commitsPerBranch: num2("commits", 25),
|
|
44548
|
+
filesPerCommit: num2("files", 12),
|
|
44549
|
+
limit: num2("limit", 400)
|
|
44550
|
+
})
|
|
44551
|
+
);
|
|
44093
44552
|
if (p === "/api/history/risk")
|
|
44094
44553
|
return json2(res, 200, historyRiskPayload(ctx(), strList(q.get("paths"))));
|
|
44095
44554
|
if (p === "/api/history/symbol") {
|
|
@@ -44144,6 +44603,7 @@ var init_server = __esm({
|
|
|
44144
44603
|
init_api2();
|
|
44145
44604
|
init_graph_api();
|
|
44146
44605
|
init_history_api();
|
|
44606
|
+
init_history_graph_api();
|
|
44147
44607
|
init_knowledge_api();
|
|
44148
44608
|
MIME = {
|
|
44149
44609
|
".html": "text/html; charset=utf-8",
|
|
@@ -44167,7 +44627,7 @@ var statusline_exports = {};
|
|
|
44167
44627
|
__export(statusline_exports, {
|
|
44168
44628
|
renderStatusline: () => renderStatusline
|
|
44169
44629
|
});
|
|
44170
|
-
import { existsSync as
|
|
44630
|
+
import { existsSync as existsSync26, readFileSync as readFileSync23, writeFileSync as writeFileSync9 } from "fs";
|
|
44171
44631
|
function renderStatusline(raw) {
|
|
44172
44632
|
let input2 = {};
|
|
44173
44633
|
try {
|
|
@@ -44176,7 +44636,7 @@ function renderStatusline(raw) {
|
|
|
44176
44636
|
}
|
|
44177
44637
|
const cache3 = paths().statuslineCache;
|
|
44178
44638
|
try {
|
|
44179
|
-
if (
|
|
44639
|
+
if (existsSync26(cache3)) {
|
|
44180
44640
|
const c = JSON.parse(readFileSync23(cache3, "utf8"));
|
|
44181
44641
|
if (Date.now() - c.at < 5e3 && c.key === (input2.session_id ?? "")) return c.line;
|
|
44182
44642
|
}
|
package/dist/server.js
CHANGED
|
@@ -18023,6 +18023,7 @@ __export(store_exports, {
|
|
|
18023
18023
|
isValidName: () => isValidName,
|
|
18024
18024
|
list: () => list,
|
|
18025
18025
|
memoriesDir: () => memoriesDir,
|
|
18026
|
+
memoriesRel: () => memoriesRel,
|
|
18026
18027
|
memoryLinks: () => memoryLinks,
|
|
18027
18028
|
normalizeRelated: () => normalizeRelated,
|
|
18028
18029
|
read: () => read,
|