@edeng23/pines 0.1.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.
Files changed (98) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +37 -0
  3. package/dist/cli.js +83 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/client/ansi.js +37 -0
  6. package/dist/client/ansi.js.map +1 -0
  7. package/dist/client/app.js +1868 -0
  8. package/dist/client/app.js.map +1 -0
  9. package/dist/client/boot.js +221 -0
  10. package/dist/client/boot.js.map +1 -0
  11. package/dist/client/commands.js +133 -0
  12. package/dist/client/commands.js.map +1 -0
  13. package/dist/client/daemon-client.js +99 -0
  14. package/dist/client/daemon-client.js.map +1 -0
  15. package/dist/client/forest/camera.js +88 -0
  16. package/dist/client/forest/camera.js.map +1 -0
  17. package/dist/client/forest/canvas.js +175 -0
  18. package/dist/client/forest/canvas.js.map +1 -0
  19. package/dist/client/forest/sidebar.js +182 -0
  20. package/dist/client/forest/sidebar.js.map +1 -0
  21. package/dist/client/forest/status.js +39 -0
  22. package/dist/client/forest/status.js.map +1 -0
  23. package/dist/client/forest/style.js +70 -0
  24. package/dist/client/forest/style.js.map +1 -0
  25. package/dist/client/forest/styles.js +429 -0
  26. package/dist/client/forest/styles.js.map +1 -0
  27. package/dist/client/forest/view.js +181 -0
  28. package/dist/client/forest/view.js.map +1 -0
  29. package/dist/client/forest/wordmark.js +26 -0
  30. package/dist/client/forest/wordmark.js.map +1 -0
  31. package/dist/client/input.js +89 -0
  32. package/dist/client/input.js.map +1 -0
  33. package/dist/client/theme.js +27 -0
  34. package/dist/client/theme.js.map +1 -0
  35. package/dist/client/tree/asciitree.js +277 -0
  36. package/dist/client/tree/asciitree.js.map +1 -0
  37. package/dist/client/tree/convmap.js +260 -0
  38. package/dist/client/tree/convmap.js.map +1 -0
  39. package/dist/client/tree/lanegraph.js +260 -0
  40. package/dist/client/tree/lanegraph.js.map +1 -0
  41. package/dist/client/tree/merge.js +161 -0
  42. package/dist/client/tree/merge.js.map +1 -0
  43. package/dist/client/tree/sessionview.js +163 -0
  44. package/dist/client/tree/sessionview.js.map +1 -0
  45. package/dist/client/tree/view.js +238 -0
  46. package/dist/client/tree/view.js.map +1 -0
  47. package/dist/client/uistate.js +45 -0
  48. package/dist/client/uistate.js.map +1 -0
  49. package/dist/daemon/agents.js +102 -0
  50. package/dist/daemon/agents.js.map +1 -0
  51. package/dist/daemon/branch.js +149 -0
  52. package/dist/daemon/branch.js.map +1 -0
  53. package/dist/daemon/embed-worker.js +74 -0
  54. package/dist/daemon/embed-worker.js.map +1 -0
  55. package/dist/daemon/essence.js +194 -0
  56. package/dist/daemon/essence.js.map +1 -0
  57. package/dist/daemon/extbridge.js +138 -0
  58. package/dist/daemon/extbridge.js.map +1 -0
  59. package/dist/daemon/lifecycle.js +134 -0
  60. package/dist/daemon/lifecycle.js.map +1 -0
  61. package/dist/daemon/pty-compat.js +53 -0
  62. package/dist/daemon/pty-compat.js.map +1 -0
  63. package/dist/daemon/semantic.js +337 -0
  64. package/dist/daemon/semantic.js.map +1 -0
  65. package/dist/daemon/server.js +808 -0
  66. package/dist/daemon/server.js.map +1 -0
  67. package/dist/daemon/supervisor.js +311 -0
  68. package/dist/daemon/supervisor.js.map +1 -0
  69. package/dist/extension/pines-extension.js +191 -0
  70. package/dist/extension/pines-extension.js.map +1 -0
  71. package/dist/layout/lexical.js +104 -0
  72. package/dist/layout/lexical.js.map +1 -0
  73. package/dist/layout/pca.js +91 -0
  74. package/dist/layout/pca.js.map +1 -0
  75. package/dist/layout/relax.js +47 -0
  76. package/dist/layout/relax.js.map +1 -0
  77. package/dist/session/ingest.js +95 -0
  78. package/dist/session/ingest.js.map +1 -0
  79. package/dist/session/parser.js +254 -0
  80. package/dist/session/parser.js.map +1 -0
  81. package/dist/shared/config.js +30 -0
  82. package/dist/shared/config.js.map +1 -0
  83. package/dist/shared/paths.js +47 -0
  84. package/dist/shared/paths.js.map +1 -0
  85. package/dist/shared/protocol.js +9 -0
  86. package/dist/shared/protocol.js.map +1 -0
  87. package/dist/shared/types.js +3 -0
  88. package/dist/shared/types.js.map +1 -0
  89. package/dist/shared/wire.js +51 -0
  90. package/dist/shared/wire.js.map +1 -0
  91. package/dist/store/db.js +203 -0
  92. package/dist/store/db.js.map +1 -0
  93. package/dist/store/watcher.js +69 -0
  94. package/dist/store/watcher.js.map +1 -0
  95. package/package.json +80 -0
  96. package/scripts/fix-node-pty.mjs +34 -0
  97. package/src/extension/pines-extension.ts +192 -0
  98. package/src/store/schema.sql +60 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Cold-start forest layout: no embeddings needed, deterministic, instant.
3
+ *
4
+ * Trees cluster by cwd (shared project → shared neighborhood); cluster
5
+ * anchors sit on a phyllotaxis spiral (evenly spread, no grid artifacts),
6
+ * and trees within a cluster ring around the anchor by recency.
7
+ *
8
+ * Only unpositioned trees (x=0, y=0) are placed — semantic layout (M5) and
9
+ * user relayouts overwrite positions later; existing trees never move here.
10
+ */
11
+ const GOLDEN_ANGLE = Math.PI * (3 - Math.sqrt(5));
12
+ const CLUSTER_SPACING = 14;
13
+ const RING_SPACING = 3.2;
14
+ function hashString(s) {
15
+ let h = 2166136261;
16
+ for (let i = 0; i < s.length; i++) {
17
+ h ^= s.charCodeAt(i);
18
+ h = Math.imul(h, 16777619);
19
+ }
20
+ return h >>> 0;
21
+ }
22
+ /**
23
+ * Sanity bound for persisted world coordinates. Real layouts live within
24
+ * ~±100; anything beyond this is corruption (e.g. the pre-fix relax()
25
+ * divide-by-zero wrote positions around ±1.5e9 into people's databases) and
26
+ * should be re-placed rather than trusted — one such tree makes zoom-to-fit
27
+ * frame a viewport a billion units wide.
28
+ */
29
+ export const MAX_SANE_COORD = 10_000;
30
+ export function isSanePosition(x, y) {
31
+ return (Number.isFinite(x) && Number.isFinite(y) && Math.abs(x) <= MAX_SANE_COORD && Math.abs(y) <= MAX_SANE_COORD);
32
+ }
33
+ export function assignLexicalPositions(trees) {
34
+ const unplaced = trees.filter((t) => t.x === 0 && t.y === 0);
35
+ if (unplaced.length === 0)
36
+ return [];
37
+ // Cluster key: cwd (or a bucket for unknown).
38
+ const clusters = new Map();
39
+ for (const t of unplaced) {
40
+ const key = t.cwd ?? "~unknown";
41
+ let arr = clusters.get(key);
42
+ if (!arr)
43
+ clusters.set(key, (arr = []));
44
+ arr.push(t);
45
+ }
46
+ // Anchor per cluster on a deterministic phyllotaxis spiral, ordered by key
47
+ // hash so anchors are stable regardless of discovery order. Anchors of
48
+ // clusters that already have placed trees reuse their centroid.
49
+ const placedByCwd = new Map();
50
+ for (const t of trees) {
51
+ if (t.x === 0 && t.y === 0)
52
+ continue;
53
+ const key = t.cwd ?? "~unknown";
54
+ const c = placedByCwd.get(key) ?? { x: 0, y: 0, n: 0 };
55
+ c.x += t.x;
56
+ c.y += t.y;
57
+ c.n++;
58
+ placedByCwd.set(key, c);
59
+ }
60
+ const keys = [...clusters.keys()].sort((a, b) => hashString(a) - hashString(b));
61
+ const changed = [];
62
+ keys.forEach((key) => {
63
+ const members = clusters.get(key);
64
+ let ax;
65
+ let ay;
66
+ const placed = placedByCwd.get(key);
67
+ if (placed && placed.n > 0) {
68
+ ax = placed.x / placed.n;
69
+ ay = placed.y / placed.n;
70
+ }
71
+ else {
72
+ // Spiral slot derived purely from the key hash: stable regardless of
73
+ // discovery order, and a wide slot range keeps distinct clusters from
74
+ // landing on the same anchor (exact collisions are still safe — the
75
+ // overlap relaxation separates them).
76
+ const idx = 1 + (hashString(key) % 97);
77
+ const r = CLUSTER_SPACING * Math.sqrt(1 + (idx % 12));
78
+ const theta = idx * GOLDEN_ANGLE;
79
+ ax = r * Math.cos(theta);
80
+ ay = r * Math.sin(theta);
81
+ }
82
+ // Members ring around the anchor by recency (newest closest).
83
+ members.sort((a, b) => b.mtime - a.mtime);
84
+ members.forEach((t, mi) => {
85
+ if (mi === 0 && !placed) {
86
+ t.x = ax;
87
+ t.y = ay;
88
+ }
89
+ else {
90
+ const ringIdx = placed ? mi + placed.n : mi;
91
+ const r = RING_SPACING * Math.sqrt(ringIdx + 1);
92
+ const theta = ringIdx * GOLDEN_ANGLE + hashString(t.treeId) % 7;
93
+ t.x = ax + r * Math.cos(theta);
94
+ t.y = ay + r * Math.sin(theta);
95
+ }
96
+ // (0,0) is the "unpositioned" sentinel — nudge exact zeros off it.
97
+ if (t.x === 0 && t.y === 0)
98
+ t.x = 0.001;
99
+ changed.push(t);
100
+ });
101
+ });
102
+ return changed;
103
+ }
104
+ //# sourceMappingURL=lexical.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lexical.js","sourceRoot":"","sources":["../../src/layout/lexical.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * PCA projection: 384-d embeddings → 2-d forest coordinates.
3
+ *
4
+ * Deterministic power iteration for the top-2 principal components. The basis
5
+ * (mean + two components) is cached; new trees project through the cached
6
+ * basis so existing trees never move when a tree is added.
7
+ */
8
+ function dot(a, b) {
9
+ let s = 0;
10
+ for (let i = 0; i < a.length; i++)
11
+ s += a[i] * b[i];
12
+ return s;
13
+ }
14
+ function norm(a) {
15
+ return Math.sqrt(dot(a, a));
16
+ }
17
+ /** Deterministic unit start vector (no Math.random — reproducible layouts). */
18
+ function seedVector(d, seed) {
19
+ const v = new Array(d);
20
+ let state = seed >>> 0 || 1;
21
+ for (let i = 0; i < d; i++) {
22
+ // xorshift32
23
+ state ^= state << 13;
24
+ state ^= state >>> 17;
25
+ state ^= state << 5;
26
+ state >>>= 0;
27
+ v[i] = state / 0xffffffff - 0.5;
28
+ }
29
+ const n = norm(v);
30
+ for (let i = 0; i < d; i++)
31
+ v[i] /= n;
32
+ return v;
33
+ }
34
+ /**
35
+ * Power-iterate the covariance of `vectors` (n×d, centered internally) for the
36
+ * top component orthogonal to `deflate` (if given).
37
+ */
38
+ function topComponent(centered, d, deflate, seed) {
39
+ let v = seedVector(d, seed);
40
+ for (let iter = 0; iter < 60; iter++) {
41
+ // w = Cov · v computed as Σ x (x·v) without materializing the d×d matrix.
42
+ const w = new Array(d).fill(0);
43
+ for (const x of centered) {
44
+ const p = dot(x, v);
45
+ for (let i = 0; i < d; i++)
46
+ w[i] += x[i] * p;
47
+ }
48
+ if (deflate) {
49
+ const p = dot(w, deflate);
50
+ for (let i = 0; i < d; i++)
51
+ w[i] -= deflate[i] * p;
52
+ }
53
+ const n = norm(w);
54
+ if (n < 1e-12)
55
+ break;
56
+ for (let i = 0; i < d; i++)
57
+ w[i] /= n;
58
+ v = w;
59
+ }
60
+ return v;
61
+ }
62
+ export function fitPca(vectors, targetSpan = 30) {
63
+ const n = vectors.length;
64
+ const d = vectors[0]?.length ?? 0;
65
+ const mean = new Array(d).fill(0);
66
+ for (const v of vectors)
67
+ for (let i = 0; i < d; i++)
68
+ mean[i] += v[i] / n;
69
+ const centered = vectors.map((v) => {
70
+ const c = new Array(d);
71
+ for (let i = 0; i < d; i++)
72
+ c[i] = v[i] - mean[i];
73
+ return c;
74
+ });
75
+ const c1 = topComponent(centered, d, null, 42);
76
+ const c2 = topComponent(centered, d, c1, 1337);
77
+ // Scale so the projected point cloud spans roughly `targetSpan` world units.
78
+ let maxAbs = 1e-9;
79
+ for (const x of centered) {
80
+ maxAbs = Math.max(maxAbs, Math.abs(dot(x, c1)), Math.abs(dot(x, c2)));
81
+ }
82
+ return { mean, c1, c2, scale: targetSpan / (2 * maxAbs) };
83
+ }
84
+ export function projectPca(basis, v) {
85
+ const d = basis.mean.length;
86
+ const c = new Array(d);
87
+ for (let i = 0; i < d; i++)
88
+ c[i] = v[i] - basis.mean[i];
89
+ return { x: dot(c, basis.c1) * basis.scale, y: dot(c, basis.c2) * basis.scale };
90
+ }
91
+ //# sourceMappingURL=pca.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pca.js","sourceRoot":"","sources":["../../src/layout/pca.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Overlap removal: repulsion-only local relaxation.
3
+ *
4
+ * Movable points are pushed apart until no pair sits closer than `minDist`;
5
+ * pinned points never move (existing trees stay put when new ones arrive).
6
+ */
7
+ export function relax(points, minDist = 2.4, iterations = 30) {
8
+ for (let iter = 0; iter < iterations; iter++) {
9
+ let moved = false;
10
+ for (let i = 0; i < points.length; i++) {
11
+ const p = points[i];
12
+ if (p.pinned)
13
+ continue;
14
+ let pushX = 0;
15
+ let pushY = 0;
16
+ for (let j = 0; j < points.length; j++) {
17
+ if (i === j)
18
+ continue;
19
+ const q = points[j];
20
+ let dx = p.x - q.x;
21
+ let dy = p.y - q.y;
22
+ const dist = Math.hypot(dx, dy);
23
+ if (dist >= minDist)
24
+ continue;
25
+ if (dist < 1e-9) {
26
+ // Coincident: push a half-separation in a deterministic direction.
27
+ // (dx/dy are unit-length here — do NOT divide by the zero distance.)
28
+ const angle = (i * 2.399963) % (Math.PI * 2);
29
+ pushX += Math.cos(angle) * minDist * 0.5;
30
+ pushY += Math.sin(angle) * minDist * 0.5;
31
+ continue;
32
+ }
33
+ const overlap = (minDist - dist) / dist;
34
+ pushX += dx * overlap * 0.5;
35
+ pushY += dy * overlap * 0.5;
36
+ }
37
+ if (pushX !== 0 || pushY !== 0) {
38
+ p.x += pushX;
39
+ p.y += pushY;
40
+ moved = true;
41
+ }
42
+ }
43
+ if (!moved)
44
+ break;
45
+ }
46
+ }
47
+ //# sourceMappingURL=relax.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relax.js","sourceRoot":"","sources":["../../src/layout/relax.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,MAAM,UAAU,KAAK,CAAC,MAAoB,EAAE,OAAO,GAAG,GAAG,EAAE,UAAU,GAAG,EAAE;IACxE,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,UAAU,EAAE,IAAI,EAAE,EAAE,CAAC;QAC7C,IAAI,KAAK,GAAG,KAAK,CAAC;QAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;YACrB,IAAI,CAAC,CAAC,MAAM;gBAAE,SAAS;YACvB,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACvC,IAAI,CAAC,KAAK,CAAC;oBAAE,SAAS;gBACtB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;gBACrB,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBACnB,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBACnB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;gBAChC,IAAI,IAAI,IAAI,OAAO;oBAAE,SAAS;gBAC9B,IAAI,IAAI,GAAG,IAAI,EAAE,CAAC;oBAChB,mEAAmE;oBACnE,qEAAqE;oBACrE,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;oBAC7C,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,OAAO,GAAG,GAAG,CAAC;oBACzC,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,OAAO,GAAG,GAAG,CAAC;oBACzC,SAAS;gBACX,CAAC;gBACD,MAAM,OAAO,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;gBACxC,KAAK,IAAI,EAAE,GAAG,OAAO,GAAG,GAAG,CAAC;gBAC5B,KAAK,IAAI,EAAE,GAAG,OAAO,GAAG,GAAG,CAAC;YAC9B,CAAC;YACD,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBAC/B,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;gBACb,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;gBACb,KAAK,GAAG,IAAI,CAAC;YACf,CAAC;QACH,CAAC;QACD,IAAI,CAAC,KAAK;YAAE,MAAM;IACpB,CAAC;AACH,CAAC"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Incremental ingest: session JSONL → trees row + FTS index.
3
+ *
4
+ * JSONL is append-only, so we index only entries that appeared after the
5
+ * stored ingest_offset. A file that shrank (e.g. replaced by a fork flow)
6
+ * triggers a full re-ingest for that tree.
7
+ */
8
+ import { randomUUID } from "node:crypto";
9
+ import { readFileSync, statSync } from "node:fs";
10
+ import { deleteFtsForTree, insertFts, treeBySessionPath, upsertTree, } from "../store/db.js";
11
+ import { parseSessionContent, parseSessionFile } from "./parser.js";
12
+ function ftsRowsFrom(parsed, treeId, sinceByte) {
13
+ // We re-derive which entries are "new" by parsing only the appended slice in
14
+ // the caller; here parsed is already just that slice (or the whole file).
15
+ void sinceByte;
16
+ const rows = [];
17
+ for (const e of parsed.entries) {
18
+ if (e.type === "message" && e.role === "user" && e.text) {
19
+ rows.push({ text: e.text, treeId, entryId: e.id, kind: "user_msg" });
20
+ }
21
+ else if ((e.type === "compaction" || e.type === "branch_summary") && e.text) {
22
+ rows.push({ text: e.text, treeId, entryId: e.id, kind: "summary" });
23
+ }
24
+ }
25
+ for (const [entryId, label] of parsed.labels) {
26
+ rows.push({ text: label, treeId, entryId, kind: "label" });
27
+ }
28
+ return rows;
29
+ }
30
+ /**
31
+ * Ingest one session file. Returns the treeId (existing or newly assigned)
32
+ * and the full parse of the file. `preferredTreeId` is used only when the
33
+ * session has no row yet (lets the daemon keep a spawn-time provisional id).
34
+ */
35
+ export async function ingestSessionFile(db, sessionPath, opts) {
36
+ const st = statSync(sessionPath);
37
+ const existing = treeBySessionPath(db, sessionPath);
38
+ const full = await parseSessionFile(sessionPath);
39
+ let treeId;
40
+ let isNew = false;
41
+ let newRows;
42
+ if (!existing) {
43
+ treeId = opts?.preferredTreeId ?? `t_${randomUUID().slice(0, 8)}`;
44
+ isNew = true;
45
+ newRows = ftsRowsFrom(full, treeId, 0);
46
+ if (full.name)
47
+ newRows.push({ text: full.name, treeId, entryId: null, kind: "name" });
48
+ }
49
+ else {
50
+ treeId = existing.tree_id;
51
+ if (st.size < existing.ingest_offset) {
52
+ // File shrank: full re-index.
53
+ deleteFtsForTree(db, treeId);
54
+ newRows = ftsRowsFrom(full, treeId, 0);
55
+ if (full.name)
56
+ newRows.push({ text: full.name, treeId, entryId: null, kind: "name" });
57
+ }
58
+ else if (full.completeBytes > existing.ingest_offset) {
59
+ // Parse only the appended slice for FTS deltas (labels in the slice are
60
+ // additive; full.labels remains authoritative for display).
61
+ const slice = readFileSync(sessionPath).subarray(existing.ingest_offset).toString("utf8");
62
+ const appended = await parseSessionContent(slice);
63
+ newRows = ftsRowsFrom(appended, treeId, existing.ingest_offset);
64
+ const knownName = existing.name ?? null;
65
+ if (full.name && full.name !== knownName) {
66
+ newRows.push({ text: full.name, treeId, entryId: null, kind: "name" });
67
+ }
68
+ }
69
+ else {
70
+ newRows = [];
71
+ }
72
+ }
73
+ upsertTree(db, {
74
+ tree_id: treeId,
75
+ session_path: sessionPath,
76
+ session_id: full.header.sessionId,
77
+ name: full.name,
78
+ cwd: full.header.cwd,
79
+ parent_session_path: full.header.parentSession,
80
+ leaf_id: full.leafId,
81
+ node_count: full.entries.length,
82
+ mtime: Math.floor(st.mtimeMs),
83
+ ingest_offset: full.completeBytes,
84
+ });
85
+ if (isNew) {
86
+ // Lineage row (ordinal 0) — graft (v2) adds more ordinals.
87
+ if (full.header.parentSession) {
88
+ db.prepare("INSERT OR IGNORE INTO graft_parents (tree_id, parent_session_path, parent_entry_id, ordinal) VALUES (?, ?, NULL, 0)").run(treeId, full.header.parentSession);
89
+ }
90
+ }
91
+ if (newRows.length > 0)
92
+ insertFts(db, newRows);
93
+ return { treeId, parsed: full, isNew };
94
+ }
95
+ //# sourceMappingURL=ingest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest.js","sourceRoot":"","sources":["../../src/session/ingest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Session JSONL → tree. This is the isolation layer around pi's session format:
3
+ * all @earendil-works imports for *reading* sessions live here (R3), and the
4
+ * parser tolerates a torn trailing line (a live pi may be mid-append, R8).
5
+ */
6
+ import { readFileSync, statSync } from "node:fs";
7
+ let piModule;
8
+ function pi() {
9
+ piModule ??= import("@earendil-works/pi-coding-agent");
10
+ return piModule;
11
+ }
12
+ /**
13
+ * Extract display text from a pi message-ish object. Content is a string or
14
+ * an array of blocks — text, thinking {thinking}, toolCall {name}, image.
15
+ * An assistant turn that only thinks and calls tools has no text block, so
16
+ * fall through: text, else the tool calls, else the thinking, else images.
17
+ */
18
+ function textOf(obj) {
19
+ if (typeof obj === "string")
20
+ return obj;
21
+ if (!Array.isArray(obj))
22
+ return "";
23
+ const texts = [];
24
+ const calls = [];
25
+ const thinking = [];
26
+ let images = 0;
27
+ for (const part of obj) {
28
+ if (typeof part !== "object" || part === null)
29
+ continue;
30
+ const p = part;
31
+ if (typeof p.text === "string" && p.text.trim())
32
+ texts.push(p.text);
33
+ else if (p.type === "toolCall")
34
+ calls.push(`${String(p.name ?? "tool")}(…)`);
35
+ else if (typeof p.thinking === "string" && p.thinking.trim())
36
+ thinking.push(p.thinking);
37
+ else if (p.type === "image")
38
+ images += 1;
39
+ }
40
+ if (texts.length > 0)
41
+ return texts.join(" ");
42
+ if (calls.length > 0)
43
+ return calls.join(", ");
44
+ if (thinking.length > 0)
45
+ return thinking.join(" ");
46
+ if (images > 0)
47
+ return images === 1 ? "[image]" : `[${images} images]`;
48
+ return "";
49
+ }
50
+ function entryText(raw) {
51
+ const type = raw.type;
52
+ if (type === "message") {
53
+ const msg = raw.message;
54
+ const role = msg?.role ?? null;
55
+ return { role, text: textOf(msg?.content).trim() };
56
+ }
57
+ if (type === "compaction" || type === "branch_summary") {
58
+ return { role: null, text: String(raw.summary ?? "").trim() };
59
+ }
60
+ if (type === "custom_message") {
61
+ return { role: "custom", text: textOf(raw.content).trim() };
62
+ }
63
+ if (type === "session_info") {
64
+ return { role: null, text: String(raw.name ?? "").trim() };
65
+ }
66
+ // Settings bookkeeping that pi records as tree entries. Normally spliced
67
+ // out of the lane graph; readable when surfaced (e.g. labeled).
68
+ if (type === "model_change") {
69
+ return { role: null, text: `model → ${String(raw.modelId ?? "?")}` };
70
+ }
71
+ if (type === "thinking_level_change") {
72
+ return { role: null, text: `thinking → ${String(raw.thinkingLevel ?? "?")}` };
73
+ }
74
+ if (type === "active_tools_change") {
75
+ return { role: null, text: "active tools changed" };
76
+ }
77
+ return { role: null, text: "" };
78
+ }
79
+ /**
80
+ * Parse raw JSONL content. Lines are split on LF only; an incomplete trailing
81
+ * line is ignored and excluded from `completeBytes`.
82
+ */
83
+ export async function parseSessionContent(content) {
84
+ const { migrateSessionEntries } = await pi();
85
+ const header = { sessionId: null, cwd: null, parentSession: null };
86
+ let headerRaw;
87
+ const rawEntries = [];
88
+ let completeBytes = 0;
89
+ let cursor = 0;
90
+ while (cursor < content.length) {
91
+ const nl = content.indexOf("\n", cursor);
92
+ if (nl < 0)
93
+ break; // torn tail — a writer is mid-append
94
+ const line = content.slice(cursor, nl);
95
+ const lineEnd = nl + 1;
96
+ cursor = lineEnd;
97
+ const trimmed = line.endsWith("\r") ? line.slice(0, -1) : line;
98
+ if (trimmed.length === 0) {
99
+ completeBytes = Buffer.byteLength(content.slice(0, lineEnd), "utf8");
100
+ continue;
101
+ }
102
+ let obj;
103
+ try {
104
+ obj = JSON.parse(trimmed);
105
+ }
106
+ catch {
107
+ // A malformed complete line should not appear in an append-only file;
108
+ // stop advancing the cursor so a future re-read can retry.
109
+ break;
110
+ }
111
+ completeBytes = Buffer.byteLength(content.slice(0, lineEnd), "utf8");
112
+ if (obj.type === "session") {
113
+ headerRaw = obj;
114
+ header.sessionId = obj.id ?? null;
115
+ header.cwd = obj.cwd ?? null;
116
+ header.parentSession = obj.parentSession ?? null;
117
+ }
118
+ else {
119
+ rawEntries.push(obj);
120
+ }
121
+ }
122
+ // Let pi migrate v1/v2 shapes in place. The header MUST be in the array —
123
+ // version detection reads it (headerless input would be "migrated" as v1,
124
+ // rewriting every id). Unknown future entry types (e.g. the newer "leaf"
125
+ // pointer) pass through untouched.
126
+ try {
127
+ const fileEntries = headerRaw ? [headerRaw, ...rawEntries] : rawEntries;
128
+ migrateSessionEntries(fileEntries);
129
+ }
130
+ catch {
131
+ // Migration is best-effort; raw v3 files don't need it.
132
+ }
133
+ const entries = [];
134
+ const order = [];
135
+ const labels = new Map();
136
+ let name = null;
137
+ let leafFromLeafEntry;
138
+ let firstUserText = null;
139
+ const summaries = [];
140
+ for (const raw of rawEntries) {
141
+ const type = raw.type;
142
+ if (type === "leaf") {
143
+ // Newer agent-core persists the active leaf pointer as an entry.
144
+ leafFromLeafEntry = raw.targetId ?? null;
145
+ continue;
146
+ }
147
+ if (type === "label") {
148
+ const target = raw.targetId;
149
+ const label = raw.label;
150
+ if (label)
151
+ labels.set(target, label);
152
+ else
153
+ labels.delete(target);
154
+ continue;
155
+ }
156
+ if (type === "session_info") {
157
+ name = raw.name ?? name;
158
+ continue;
159
+ }
160
+ const id = raw.id;
161
+ if (!id)
162
+ continue;
163
+ const { role, text } = entryText(raw);
164
+ if (type === "compaction" || type === "branch_summary") {
165
+ if (text)
166
+ summaries.push(text);
167
+ }
168
+ if (role === "user" && firstUserText === null && text)
169
+ firstUserText = text;
170
+ entries.push({
171
+ id,
172
+ parentId: raw.parentId ?? null,
173
+ type,
174
+ timestamp: raw.timestamp ?? "",
175
+ role,
176
+ text,
177
+ raw,
178
+ });
179
+ order.push(id);
180
+ }
181
+ // Leaf: an explicit leaf entry wins; otherwise the last appended tree entry
182
+ // (pi reconstructs the leaf the same way on load).
183
+ const leafId = leafFromLeafEntry !== undefined ? leafFromLeafEntry : (order[order.length - 1] ?? null);
184
+ return { header, entries, order, name, labels, leafId, completeBytes, firstUserText, summaries };
185
+ }
186
+ const cache = new Map();
187
+ const CACHE_MAX = 64;
188
+ export async function parseSessionFile(path) {
189
+ const st = statSync(path);
190
+ const hit = cache.get(path);
191
+ if (hit && hit.mtimeMs === st.mtimeMs && hit.size === st.size)
192
+ return hit.parsed;
193
+ const parsed = await parseSessionContent(readFileSync(path, "utf8"));
194
+ cache.set(path, { mtimeMs: st.mtimeMs, size: st.size, parsed });
195
+ if (cache.size > CACHE_MAX) {
196
+ const oldest = cache.keys().next().value;
197
+ if (oldest !== undefined)
198
+ cache.delete(oldest);
199
+ }
200
+ return parsed;
201
+ }
202
+ /** Which entry types appear as nodes in tree views. */
203
+ function nodeKind(e) {
204
+ if (e.type === "message") {
205
+ if (e.role === "user")
206
+ return "user";
207
+ if (e.role === "assistant")
208
+ return "assistant";
209
+ if (e.role === "toolResult")
210
+ return "tool";
211
+ return "other";
212
+ }
213
+ if (e.type === "compaction")
214
+ return "compaction";
215
+ if (e.type === "branch_summary")
216
+ return "branch_summary";
217
+ if (e.type === "custom" || e.type === "custom_message")
218
+ return "custom";
219
+ // Settings changes are plumbing, not conversation: give them the same
220
+ // spliceable kind as pines' own markers so trees don't open with a stack
221
+ // of unreadable bookkeeping rows.
222
+ if (e.type === "model_change" ||
223
+ e.type === "thinking_level_change" ||
224
+ e.type === "active_tools_change") {
225
+ return "custom";
226
+ }
227
+ return "other";
228
+ }
229
+ const EXCERPT_LEN = 80;
230
+ export function toTreeDetail(treeId, parsed) {
231
+ const nodes = {};
232
+ const rootIds = [];
233
+ for (const e of parsed.entries) {
234
+ nodes[e.id] = {
235
+ id: e.id,
236
+ parentId: e.parentId,
237
+ kind: nodeKind(e),
238
+ excerpt: e.text.replace(/\s+/g, " ").slice(0, EXCERPT_LEN),
239
+ label: parsed.labels.get(e.id) ?? null,
240
+ timestamp: e.timestamp,
241
+ children: [],
242
+ };
243
+ }
244
+ for (const e of parsed.entries) {
245
+ if (e.parentId && nodes[e.parentId]) {
246
+ nodes[e.parentId].children.push(e.id);
247
+ }
248
+ else {
249
+ rootIds.push(e.id);
250
+ }
251
+ }
252
+ return { treeId, rootIds, nodes, leafId: parsed.leafId };
253
+ }
254
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/session/parser.ts"],"names":[],"mappings":"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"}