@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,429 @@
1
+ import { FAINT, GRID, MUTED } from "../theme.js";
2
+ import { statusGlyph, statusSgr } from "./status.js";
3
+ import { humanAge, treeTitle } from "./sidebar.js";
4
+ import { fitText, truncate, } from "./style.js";
5
+ /** Selected markers get the whole name — the focused label must read fully. */
6
+ function shownName(ctx) {
7
+ return ctx.selected ? ctx.title : truncate(ctx.title, ctx.nameMax);
8
+ }
9
+ /**
10
+ * Emphasis for a name: unseen work shouts, seen work sits back, and a
11
+ * placeholder (an unnamed session showing its directory) never shouts at all.
12
+ */
13
+ function nameSgr(c) {
14
+ return c.fallback || c.t.seen ? MUTED : "1";
15
+ }
16
+ /** Draw a label, stopping cleanly at the right edge of the canvas. */
17
+ function label(canvas, c, x, y, text, sgr) {
18
+ const shown = fitText(text, x, c.vp.width);
19
+ if (shown)
20
+ canvas.text(x, y, shown, sgr, c.pickId);
21
+ }
22
+ /* ------------------------------- classic --------------------------------- */
23
+ const classic = {
24
+ id: "classic",
25
+ name: "classic",
26
+ blurb: "status dot + name, braille lineage threads",
27
+ footprint(t, pos, o) {
28
+ const label = o.selected
29
+ ? ` ▸ ${treeTitle(t).title} `
30
+ : ` ${truncate(treeTitle(t).title, o.nameMax)}`;
31
+ return { x: pos.x, y: pos.y, w: 1 + label.length, h: 1 };
32
+ },
33
+ drawTree(canvas, c) {
34
+ const sgr = statusSgr(c.t);
35
+ canvas.set(c.pos.x, c.pos.y, statusGlyph(c.t, c.spinnerFrame), c.selected ? `7;${sgr}` : sgr, c.pickId);
36
+ if (c.selected) {
37
+ label(canvas, c, c.pos.x + 1, c.pos.y, ` ▸ ${c.title} `, "1;7");
38
+ }
39
+ else if (c.roomy) {
40
+ label(canvas, c, c.pos.x + 1, c.pos.y, ` ${shownName(c)}`, nameSgr(c));
41
+ }
42
+ },
43
+ };
44
+ /**
45
+ * Needled, for a session with a process behind it.
46
+ *
47
+ * Even the smallest is a whole tree: a forest of one-cell triangles reads as
48
+ * punctuation, not as a wood. Size still varies — it is how the map shows you
49
+ * which conversations went long — but the silhouette is always a pine.
50
+ */
51
+ const PINE_XXL = {
52
+ trunk: 4,
53
+ rows: [" ▲ ", " ▟█▙ ", " ▟███▙ ", " ▟█████▙ ", "▟███████▙"],
54
+ tones: [" 0 ", " 012 ", " 01112 ", " 0111112 ", "011111112"],
55
+ };
56
+ const PINE_XL = {
57
+ trunk: 3,
58
+ rows: [" ▲ ", " ▟█▙ ", " ▟███▙ ", "▟█████▙"],
59
+ tones: [" 0 ", " 012 ", " 01112 ", "0111112"],
60
+ };
61
+ const PINE_L = {
62
+ trunk: 2,
63
+ rows: [" ▲ ", " ▟█▙ ", "▟███▙"],
64
+ tones: [" 0 ", " 012 ", "01112"],
65
+ };
66
+ const PINE_M = { trunk: 1, rows: [" ▲ ", "▟█▙"], tones: [" 0 ", "012"] };
67
+ /** Only for a forest with no room left at all. */
68
+ const PINE_S = { trunk: 0, rows: ["▲"], tones: ["1"] };
69
+ /** Bare: no process, no needles. Dormant work reads as winter wood. */
70
+ const BARE_XL = {
71
+ trunk: 2,
72
+ rows: ["╲ │ ╱", " ╲│╱ ", " │ "],
73
+ tones: ["0 1 0", " 010 ", " 2 "],
74
+ };
75
+ const BARE_L = {
76
+ trunk: 2,
77
+ rows: ["╲ │ ╱", " ╲│╱ "],
78
+ tones: ["0 1 0", " 010 "],
79
+ };
80
+ const BARE_M = { trunk: 1, rows: ["╲│╱", " │ "], tones: ["010", " 2 "] };
81
+ const BARE_S = { trunk: 0, rows: ["╵"], tones: ["1"] };
82
+ const PINES = [PINE_S, PINE_M, PINE_L, PINE_XL, PINE_XXL];
83
+ const BARES = [BARE_S, BARE_M, BARE_L, BARE_XL, BARE_XL];
84
+ /**
85
+ * Foliage comes in a few close greens, dealt out per tree: a real wood is
86
+ * many near-greens, not one, and the variation is what makes a hillside of
87
+ * pines read as alive instead of tiled. The pick is a hash of the tree id,
88
+ * so a tree keeps its color for life and never flickers between frames.
89
+ */
90
+ const FOLIAGE = [
91
+ ["38;5;114", "38;5;71", "38;5;29"], // fresh pine
92
+ ["38;5;150", "38;5;108", "38;5;65"], // dusty sage
93
+ ["38;5;113", "38;5;70", "38;5;28"], // sunlit lime
94
+ ];
95
+ /** Winter wood for dormant sessions: warm bark, dark heartwood. */
96
+ const BARK_TONES = ["38;5;180", "38;5;137", "38;5;95"];
97
+ /** A crashed session stands as burnt wood — ember red, unmistakable. */
98
+ const EMBER_TONES = ["38;5;203", "38;5;167", "38;5;124"];
99
+ function paletteOf(t) {
100
+ if (t.status === "crashed")
101
+ return EMBER_TONES;
102
+ if (t.status === "dormant")
103
+ return BARK_TONES;
104
+ let h = 2166136261;
105
+ for (let i = 0; i < t.treeId.length; i++) {
106
+ h ^= t.treeId.charCodeAt(i);
107
+ h = Math.imul(h, 16777619);
108
+ }
109
+ return FOLIAGE[(h >>> 0) % FOLIAGE.length];
110
+ }
111
+ /**
112
+ * How big a tree grew, and how big this forest can afford to draw it.
113
+ *
114
+ * Conversation length sets the size — it is the only structural signal the
115
+ * forest has at this zoom. Then the room between neighbors caps it: a packed
116
+ * forest keeps its trees small rather than growing them into each other, and
117
+ * zooming in lets them fill out again. The floor is a whole little pine; the
118
+ * bare single glyph is reserved for forests with no room at all. The
119
+ * five-row old-growth tier is earned twice over — a genuinely long session
120
+ * in a genuinely open forest.
121
+ */
122
+ function spriteFor(t, bare, spacing) {
123
+ const grown = t.nodeCount >= 100 ? 4 : t.nodeCount >= 35 ? 3 : t.nodeCount >= 12 ? 2 : 1;
124
+ const room = spacing >= 15 ? 4 : spacing >= 11 ? 3 : spacing >= 7 ? 2 : spacing >= 4 ? 1 : 0;
125
+ return (bare ? BARES : PINES)[Math.min(grown, room)];
126
+ }
127
+ /** Cell box a sprite fills, standing on (and excluding) its base row. */
128
+ function spriteRect(sprite, pos) {
129
+ const w = Math.max(...sprite.rows.map((r) => r.length));
130
+ return {
131
+ x: Math.round(pos.x) - sprite.trunk,
132
+ y: Math.round(pos.y) - sprite.rows.length,
133
+ w,
134
+ h: sprite.rows.length,
135
+ };
136
+ }
137
+ /**
138
+ * Paint a sprite so its trunk stands on `pos` and its foliage grows upward,
139
+ * each cell in its tone's color. Bold on selection: it reads as the whole
140
+ * tree catching the light.
141
+ */
142
+ function drawSprite(canvas, sprite, pos, palette, pickId, bold = false) {
143
+ const box = spriteRect(sprite, pos);
144
+ for (let r = 0; r < sprite.rows.length; r++) {
145
+ const row = sprite.rows[r];
146
+ const tones = sprite.tones[r];
147
+ for (let i = 0; i < row.length; i++) {
148
+ if (row[i] === " ")
149
+ continue;
150
+ const tone = palette[Number(tones[i])] ?? palette[1];
151
+ canvas.set(box.x + i, box.y + r, row[i], bold ? `1;${tone}` : tone, pickId);
152
+ }
153
+ }
154
+ }
155
+ const canopy = {
156
+ id: "canopy",
157
+ name: "canopy",
158
+ blurb: "a forester's plat — sunlit pines on graph paper, surveyed lineage",
159
+ underlay(canvas, ctx) {
160
+ // Graph paper, ruled to the forest: wider squares when trees are packed
161
+ // tightly, so the grid stays a backdrop instead of a texture.
162
+ //
163
+ // A middot rather than a braille dot. Braille would keep the paper in the
164
+ // sub-cell layer, out of the way of everything — but its dot sits in the
165
+ // cell's top-left corner and is small enough to vanish. A centered `·`
166
+ // reads as a ruled point. Nothing else in this look draws braille, and
167
+ // the underlay runs before edges and trees, so they still paint over it.
168
+ const step = ctx.spacing < 8 ? 8 : 6;
169
+ for (let y = 0; y < ctx.vp.height; y += step / 2) {
170
+ for (let x = 0; x < ctx.vp.width; x += step) {
171
+ canvas.set(x, Math.round(y), "·", GRID);
172
+ }
173
+ }
174
+ },
175
+ edge(canvas, a, b) {
176
+ // Lineage as survey lines: across at the parent's row, then down (or up)
177
+ // the child's column, ending under the child's trunk. Trees draw after
178
+ // edges, so a line runs to the wood and disappears behind it. Drawn a
179
+ // step brighter than the paper — parentage is information, the grid is
180
+ // decoration, and the two should not read as the same thing.
181
+ const ax = Math.round(a.x);
182
+ const ay = Math.round(a.y);
183
+ const bx = Math.round(b.x);
184
+ const by = Math.round(b.y);
185
+ // Half-open ranges, not step-until-equal: a run of zero length (parent and
186
+ // child sharing a row or column) must draw nothing, not loop forever.
187
+ for (let x = Math.min(ax, bx) + 1; x < Math.max(ax, bx); x++) {
188
+ canvas.set(x, ay, "─", FAINT);
189
+ }
190
+ if (ax !== bx && ay !== by) {
191
+ canvas.set(bx, ay, bx > ax ? (by > ay ? "╮" : "╯") : by > ay ? "╭" : "╰", FAINT);
192
+ }
193
+ for (let y = Math.min(ay, by) + 1; y < Math.max(ay, by); y++) {
194
+ canvas.set(bx, y, "│", FAINT);
195
+ }
196
+ },
197
+ // Foliage occupies real cells, so the whole tree is off limits to labels —
198
+ // at exactly the size this forest will draw it.
199
+ core: (t, pos, spacing) => {
200
+ const bare = t.status !== "running" && t.status !== "waiting";
201
+ const box = spriteRect(spriteFor(t, bare, spacing), pos);
202
+ return { x: box.x, y: box.y, w: box.w, h: box.h + 1 };
203
+ },
204
+ footprint(t, pos, o) {
205
+ const bare = t.status !== "running" && t.status !== "waiting";
206
+ // Claim the tree as drawn, plus room for the name beside its base.
207
+ const box = spriteRect(spriteFor(t, bare, o.spacing), pos);
208
+ const label = ` ${o.selected ? treeTitle(t).title : truncate(treeTitle(t).title, o.nameMax)} `;
209
+ const x = Math.min(box.x, Math.round(pos.x));
210
+ return {
211
+ x,
212
+ y: box.y,
213
+ w: Math.max(box.x + box.w - x, Math.round(pos.x) - x + 1 + label.length),
214
+ h: box.h + 1,
215
+ };
216
+ },
217
+ drawTree(canvas, c) {
218
+ const sgr = statusSgr(c.t);
219
+ const bare = c.t.status === "dormant" || c.t.status === "crashed";
220
+ const sprite = spriteFor(c.t, bare, c.spacing);
221
+ drawSprite(canvas, sprite, c.pos, paletteOf(c.t), c.pickId, c.selected);
222
+ // Work you have not looked at yet lights the crown, so attention reads
223
+ // from across the map without repainting the whole tree.
224
+ if (!c.t.seen) {
225
+ const box = spriteRect(sprite, c.pos);
226
+ canvas.set(Math.round(c.pos.x), box.y, sprite.rows[0].trim()[0] ?? "▲", `1;${sgr}`, c.pickId);
227
+ }
228
+ // The base carries the state itself, so "working" animates at the roots.
229
+ canvas.set(c.pos.x, c.pos.y, statusGlyph(c.t, c.spinnerFrame), c.selected ? `7;${sgr}` : sgr, c.pickId);
230
+ if (!c.speaks && !c.selected)
231
+ return; // a quiet tree in a packed forest
232
+ const text = ` ${shownName(c)} `;
233
+ // A crowded tree still deserves its name: try the base row, then the row
234
+ // above it, and only then stay anonymous.
235
+ let row = c.pos.y;
236
+ if (!c.roomy && !c.selected) {
237
+ if (c.labels.claim(c.pos.x + 1, c.pos.y, text.length, c.t.treeId))
238
+ row = c.pos.y;
239
+ else if (c.labels.claim(c.pos.x + 1, c.pos.y - 1, text.length, c.t.treeId))
240
+ row = c.pos.y - 1;
241
+ else
242
+ return;
243
+ }
244
+ label(canvas, c, c.pos.x + 1, row, text, c.selected ? "1;7" : nameSgr(c));
245
+ },
246
+ };
247
+ /* ----------------------------- constellation ------------------------------ */
248
+ /** Stars brighten with session size; the state glyph still wins for live work. */
249
+ function starGlyph(t, spinnerFrame) {
250
+ if (t.status === "running")
251
+ return statusGlyph(t, spinnerFrame);
252
+ if (t.status === "crashed")
253
+ return "✸";
254
+ if (t.status === "dormant")
255
+ return t.nodeCount >= 12 ? "✧" : "·";
256
+ return t.nodeCount >= 12 ? "✦" : "✧";
257
+ }
258
+ const constellation = {
259
+ id: "constellation",
260
+ name: "constellation",
261
+ blurb: "a star chart with curved lineage arcs",
262
+ footprint(t, pos, o) {
263
+ const label = ` ${o.selected ? treeTitle(t).title : truncate(treeTitle(t).title, o.nameMax)} `;
264
+ return { x: pos.x, y: pos.y, w: 1 + label.length, h: 1 };
265
+ },
266
+ edge(canvas, a, b) {
267
+ // A gentle arc instead of a straight thread: bow the line away from its
268
+ // own midpoint so sibling lineages fan out instead of overlapping.
269
+ const mx = (a.x + b.x) / 2;
270
+ const my = (a.y + b.y) / 2;
271
+ const dx = b.x - a.x;
272
+ const dy = b.y - a.y;
273
+ const len = Math.hypot(dx, dy * 2) || 1;
274
+ // Control point: the midpoint pushed along the perpendicular (cell aspect
275
+ // corrected, so the bow looks equally deep whatever the edge's angle).
276
+ const bow = 0.16;
277
+ const cx = mx - dy * 2 * bow;
278
+ const cy = my + dx * 0.5 * bow;
279
+ const steps = Math.max(8, Math.round(len));
280
+ let px = a.x;
281
+ let py = a.y;
282
+ for (let i = 1; i <= steps; i++) {
283
+ const s = i / steps;
284
+ const qx = (1 - s) * (1 - s) * a.x + 2 * (1 - s) * s * cx + s * s * b.x;
285
+ const qy = (1 - s) * (1 - s) * a.y + 2 * (1 - s) * s * cy + s * s * b.y;
286
+ // Dash the arc by segment, so a long lineage reads as a thread.
287
+ if (i % 4 !== 0)
288
+ canvas.line(px, py, qx, qy, FAINT);
289
+ px = qx;
290
+ py = qy;
291
+ }
292
+ },
293
+ drawTree(canvas, c) {
294
+ const sgr = statusSgr(c.t);
295
+ if (c.selected)
296
+ halo(canvas, c.pos);
297
+ canvas.set(c.pos.x, c.pos.y, starGlyph(c.t, c.spinnerFrame), c.selected ? `7;${sgr}` : c.t.seen ? sgr : `1;${sgr}`, c.pickId);
298
+ if (c.selected) {
299
+ label(canvas, c, c.pos.x + 1, c.pos.y, ` ${c.title} `, "1;7");
300
+ }
301
+ else if (c.roomy) {
302
+ label(canvas, c, c.pos.x + 1, c.pos.y, ` ${shownName(c)} `, nameSgr(c));
303
+ }
304
+ },
305
+ };
306
+ /** Braille ring around the focused star. */
307
+ function halo(canvas, pos) {
308
+ const rx = 2.2;
309
+ const ry = 1.1;
310
+ for (let i = 0; i < 72; i++) {
311
+ const a = (i / 72) * Math.PI * 2;
312
+ canvas.dot(Math.round((pos.x + rx * Math.cos(a)) * 2), Math.round((pos.y + ry * Math.sin(a)) * 4), FAINT);
313
+ }
314
+ }
315
+ /* --------------------------------- cards ---------------------------------- */
316
+ function chipText(c) {
317
+ return {
318
+ name: c.selected ? c.title : truncate(c.title, Math.min(16, c.nameMax)),
319
+ age: humanAge(c.t.mtime, c.now),
320
+ };
321
+ }
322
+ const cards = {
323
+ id: "cards",
324
+ name: "cards",
325
+ blurb: "dense chips: status bar, name, age",
326
+ footprint(t, pos, o) {
327
+ const { name, age } = chipText({
328
+ title: treeTitle(t).title,
329
+ selected: o.selected,
330
+ t,
331
+ now: o.now,
332
+ nameMax: o.nameMax,
333
+ });
334
+ // ▌ ◐ name 12m
335
+ return { x: pos.x, y: pos.y, w: 2 + 2 + name.length + 1 + age.length + 1, h: 1 };
336
+ },
337
+ drawTree(canvas, c) {
338
+ const sgr = statusSgr(c.t);
339
+ const { name, age } = chipText(c);
340
+ // A chip is only worth drawing whole: near the right edge, shrink the
341
+ // name, and when even that runs out fall back to the bare status glyph
342
+ // rather than a half-chip bleeding off the canvas.
343
+ const chrome = 3 + 1 + age.length + 1; // ▌ glyph space … space age space
344
+ const nameRoom = c.vp.width - Math.round(c.pos.x) - chrome;
345
+ const shown = truncate(name, Math.min(name.length, nameRoom));
346
+ if ((!c.roomy && !c.selected) || nameRoom < 4) {
347
+ canvas.set(c.pos.x, c.pos.y, statusGlyph(c.t, c.spinnerFrame), sgr, c.pickId);
348
+ return;
349
+ }
350
+ const inv = c.selected ? "7;" : "";
351
+ let x = c.pos.x;
352
+ // Status bar on the leading edge: a colored spine the eye can scan down.
353
+ canvas.set(x++, c.pos.y, "▌", `${inv}${sgr}`, c.pickId);
354
+ canvas.set(x++, c.pos.y, statusGlyph(c.t, c.spinnerFrame), `${inv}${sgr}`, c.pickId);
355
+ canvas.set(x++, c.pos.y, " ", c.selected ? "7" : null, c.pickId);
356
+ canvas.text(x, c.pos.y, shown, c.selected ? "1;7" : c.fallback ? MUTED : c.t.seen ? "0" : "1", c.pickId);
357
+ x += shown.length;
358
+ canvas.set(x++, c.pos.y, " ", c.selected ? "7" : null, c.pickId);
359
+ canvas.text(x, c.pos.y, age, c.selected ? "7" : MUTED, c.pickId);
360
+ x += age.length;
361
+ canvas.set(x, c.pos.y, " ", c.selected ? "7" : null, c.pickId);
362
+ },
363
+ };
364
+ /* -------------------------------- contour --------------------------------- */
365
+ const contour = {
366
+ id: "contour",
367
+ name: "contour",
368
+ blurb: "topographic — activity as elevation rings",
369
+ footprint(t, pos, o) {
370
+ const label = ` ${o.selected ? treeTitle(t).title : truncate(treeTitle(t).title, o.nameMax)} `;
371
+ return { x: pos.x, y: pos.y, w: 2 + label.length, h: 1 };
372
+ },
373
+ underlay(canvas, ctx) {
374
+ // Elevation = activity. A live agent (or work you haven't looked at yet)
375
+ // raises the ground around it into contours; everything settled is flat
376
+ // map. Rings stay in the faintest gray there is — contours belong *under*
377
+ // the labels, never around them.
378
+ //
379
+ // Ring size and count follow how much room the forest has: a crowded map
380
+ // gets one tight ring per live tree instead of two wide ones, so contours
381
+ // never turn into static.
382
+ const step = Math.max(0.7, Math.min(1.15, ctx.spacing / 6));
383
+ const maxRings = ctx.spacing >= 9 ? 2 : 1;
384
+ for (const { t, pos } of ctx.visible) {
385
+ const rings = Math.min(maxRings, !t.seen ? 2 : t.live ? 1 : 0);
386
+ for (let r = rings; r >= 1; r--) {
387
+ ring(canvas, pos, step * r, r === 1 && !t.seen ? statusSgr(t) : GRID);
388
+ }
389
+ }
390
+ },
391
+ drawTree(canvas, c) {
392
+ const sgr = statusSgr(c.t);
393
+ canvas.set(c.pos.x, c.pos.y, statusGlyph(c.t, c.spinnerFrame), c.selected ? `7;${sgr}` : sgr, c.pickId);
394
+ if (c.selected) {
395
+ label(canvas, c, c.pos.x + 1, c.pos.y, ` ${c.title} `, "1;7");
396
+ }
397
+ else if (c.roomy) {
398
+ label(canvas, c, c.pos.x + 1, c.pos.y, ` ${shownName(c)} `, nameSgr(c));
399
+ }
400
+ },
401
+ };
402
+ /** One contour ring, drawn in the braille layer so labels always win. */
403
+ function ring(canvas, pos, r, sgr) {
404
+ const steps = Math.max(28, Math.round(r * 34));
405
+ for (let i = 0; i < steps; i++) {
406
+ const a = (i / steps) * Math.PI * 2;
407
+ canvas.dot(Math.round((pos.x + r * 2 * Math.cos(a)) * 2), Math.round((pos.y + r * Math.sin(a)) * 4), sgr);
408
+ }
409
+ }
410
+ /* -------------------------------- registry -------------------------------- */
411
+ export const FOREST_STYLES = [
412
+ classic,
413
+ canopy,
414
+ constellation,
415
+ cards,
416
+ contour,
417
+ ];
418
+ // The plat is the forest's face: it is what the project is named for.
419
+ export const DEFAULT_STYLE_ID = "canopy";
420
+ export function forestStyle(id) {
421
+ return FOREST_STYLES.find((s) => s.id === id) ?? FOREST_STYLES[0];
422
+ }
423
+ /** Next style in the list, wrapping — the `v` key's cycle order. */
424
+ export function nextStyleId(id, dir = 1) {
425
+ const i = FOREST_STYLES.findIndex((s) => s.id === id);
426
+ const n = FOREST_STYLES.length;
427
+ return FOREST_STYLES[(((i < 0 ? 0 : i) + dir) % n + n) % n].id;
428
+ }
429
+ //# sourceMappingURL=styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../src/client/forest/styles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,181 @@
1
+ import { worldToCell } from "./camera.js";
2
+ import { treeTitle } from "./sidebar.js";
3
+ import { FAINT, MUTED } from "../theme.js";
4
+ import { forestStyle } from "./styles.js";
5
+ import { LabelPlacer } from "./style.js";
6
+ export { SPINNER_FRAMES, statusGlyph, statusSgr } from "./status.js";
7
+ /** Dash pattern for lineage threads, in braille dots (on, off). */
8
+ export const LINEAGE_DASH = [7, 4];
9
+ export function renderForest(canvas, input) {
10
+ const { trees, camera, vp, selectedId, spinnerFrame } = input;
11
+ const style = typeof input.style === "object" && input.style !== null
12
+ ? input.style
13
+ : forestStyle(input.style);
14
+ const now = input.now ?? Date.now();
15
+ const pickMap = new Map();
16
+ canvas.clear();
17
+ if (trees.length === 0) {
18
+ // Short lines (the canvas may be as narrow as ~45 cols beside the
19
+ // sidebar), block-aligned so the key column reads as a column.
20
+ const lines = [
21
+ "the forest is empty",
22
+ "",
23
+ "n plant a tree (runs pi here)",
24
+ "pi sessions started anywhere appear too",
25
+ ];
26
+ const blockW = Math.max(...lines.map((l) => l.length));
27
+ const x0 = Math.max(0, Math.floor((vp.width - blockW) / 2));
28
+ const y0 = Math.max(1, Math.floor(vp.height / 2) - 2);
29
+ for (let i = 0; i < lines.length; i++) {
30
+ canvas.text(x0, y0 + i, lines[i], i === 0 ? "1" : MUTED, -1);
31
+ }
32
+ return pickMap;
33
+ }
34
+ // Draw trees in attention priority so, when labels collide, the label that
35
+ // survives is the one the user most needs (selected > unseen > live > recent).
36
+ const prio = (t) => {
37
+ if (t.treeId === selectedId)
38
+ return 0;
39
+ if (!t.seen)
40
+ return 1;
41
+ if (t.live)
42
+ return 2;
43
+ return 3;
44
+ };
45
+ const ordered = [...trees].sort((a, b) => prio(a) - prio(b) || b.mtime - a.mtime);
46
+ let pickId = 0;
47
+ const visible = [];
48
+ for (const t of ordered) {
49
+ const pos = worldToCell(camera, vp, t.x, t.y);
50
+ if (pos.x < -30 || pos.y < -20 || pos.x > vp.width + 30 || pos.y > vp.height + 20)
51
+ continue;
52
+ const id = pickId++;
53
+ pickMap.set(id, t.treeId);
54
+ visible.push({ t, pos, pickId: id, selected: t.treeId === selectedId });
55
+ }
56
+ // Backdrop (grids, contour rings), then lineage edges: both live under
57
+ // every marker.
58
+ style.underlay?.(canvas, { vp, visible, now, spacing: medianSpacing(visible) });
59
+ const byPath = new Map();
60
+ for (const t of trees)
61
+ byPath.set(t.sessionPath, t);
62
+ for (const t of trees) {
63
+ if (!t.parentSessionPath)
64
+ continue;
65
+ const parent = byPath.get(t.parentSessionPath);
66
+ if (!parent)
67
+ continue;
68
+ const a = worldToCell(camera, vp, parent.x, parent.y);
69
+ const b = worldToCell(camera, vp, t.x, t.y);
70
+ if (offscreen(a, b, vp))
71
+ continue;
72
+ if (style.edge)
73
+ style.edge(canvas, a, b);
74
+ else
75
+ canvas.line(a.x, a.y, b.x, b.y, FAINT, LINEAGE_DASH);
76
+ }
77
+ const labels = new LabelPlacer();
78
+ // Names get shorter as the forest gets tighter, so more of them survive.
79
+ const spacing = medianSpacing(visible);
80
+ const nameMax = spacing < 10 ? 11 : 18;
81
+ const ctxFor = (e, roomy, speaks = true) => {
82
+ const { title, fallback } = treeTitle(e.t);
83
+ return { ...e, spinnerFrame, now, title, fallback, vp, roomy, speaks, nameMax, spacing, labels };
84
+ };
85
+ // One drawing path at every zoom: the sprite IS the tree — maturity by
86
+ // conversation size, life by color — and it simply fills out as spacing
87
+ // grows. (Mid-zoom once drew lane-graph minis here; they duplicated what
88
+ // the sprite already says, and structure lives in the conversation's
89
+ // metro map now.) Every tree's core cell is reserved before anything
90
+ // draws, so no marker or label can ever land on another tree's marker;
91
+ // then markers claim their full footprint in priority order.
92
+ for (const e of visible) {
93
+ labels.reserveRect(style.core?.(e.t, e.pos, spacing) ?? { x: e.pos.x, y: e.pos.y, w: 1, h: 1 }, e.t.treeId);
94
+ }
95
+ const sel = visible.find((e) => e.selected);
96
+ if (sel) {
97
+ labels.reserveRect(style.footprint(sel.t, sel.pos, { selected: true, now, nameMax, spacing }), sel.t.treeId);
98
+ }
99
+ const budget = labelBudget(visible);
100
+ for (const e of visible) {
101
+ if (e.selected)
102
+ continue;
103
+ const speaks = budget.has(e.t.treeId);
104
+ const rect = style.footprint(e.t, e.pos, { selected: false, now, nameMax, spacing });
105
+ const roomy = speaks && labels.claimRect(rect, e.t.treeId);
106
+ style.drawTree(canvas, ctxFor(e, roomy, speaks));
107
+ }
108
+ // The focused tree draws last, on top of everything: its label must
109
+ // always read cleanly — but it must never ERASE a neighbor: every other
110
+ // tree's core marker cells are painted back over the label's overflow.
111
+ if (sel) {
112
+ const cores = visible
113
+ .filter((e) => !e.selected)
114
+ .map((e) => canvas.snapshotRect(style.core?.(e.t, e.pos, spacing) ?? { x: e.pos.x, y: e.pos.y, w: 1, h: 1 }));
115
+ style.drawTree(canvas, ctxFor(sel, true));
116
+ for (const cells of cores)
117
+ canvas.restore(cells);
118
+ }
119
+ return pickMap;
120
+ }
121
+ /**
122
+ * Which trees get to speak their name.
123
+ *
124
+ * When trees are far apart every one of them can: the placer sorts out the
125
+ * occasional overlap. Packed together, first-come-first-served produces a
126
+ * wall of half-names where nothing stands out — so a crowded forest names
127
+ * only what you'd want to see from across the room (the live, the unseen, the
128
+ * crashed), topped up with the most recent so an all-quiet forest is never
129
+ * anonymous. Zooming in spreads the trees and hands everyone their name back.
130
+ */
131
+ function labelBudget(visible) {
132
+ const speaks = new Set();
133
+ if (medianSpacing(visible) >= 10) {
134
+ for (const e of visible)
135
+ speaks.add(e.t.treeId);
136
+ return speaks;
137
+ }
138
+ for (const e of visible) {
139
+ if (!e.t.seen || e.t.live || e.t.status === "crashed")
140
+ speaks.add(e.t.treeId);
141
+ }
142
+ const floor = Math.max(8, Math.round(visible.length * 0.25));
143
+ const byRecency = [...visible].sort((a, b) => b.t.mtime - a.t.mtime);
144
+ for (const e of byRecency) {
145
+ if (speaks.size >= floor)
146
+ break;
147
+ speaks.add(e.t.treeId);
148
+ }
149
+ return speaks;
150
+ }
151
+ /**
152
+ * Median nearest-neighbor distance, in cells. Cheap enough to brute-force at
153
+ * forest scale, and it tells a style how much room its decoration has.
154
+ */
155
+ function medianSpacing(visible) {
156
+ if (visible.length < 2)
157
+ return Infinity;
158
+ const dists = [];
159
+ for (let i = 0; i < visible.length; i++) {
160
+ let best = Infinity;
161
+ for (let j = 0; j < visible.length; j++) {
162
+ if (i === j)
163
+ continue;
164
+ const dx = visible[i].pos.x - visible[j].pos.x;
165
+ // Rows are twice as tall as columns are wide: compare in x-cell units.
166
+ const dy = (visible[i].pos.y - visible[j].pos.y) * 2;
167
+ best = Math.min(best, Math.hypot(dx, dy));
168
+ }
169
+ dists.push(best);
170
+ }
171
+ dists.sort((a, b) => a - b);
172
+ return dists[Math.floor(dists.length / 2)];
173
+ }
174
+ function offscreen(a, b, vp) {
175
+ const pad = 40;
176
+ return ((a.x < -pad && b.x < -pad) ||
177
+ (a.y < -pad && b.y < -pad) ||
178
+ (a.x > vp.width + pad && b.x > vp.width + pad) ||
179
+ (a.y > vp.height + pad && b.y > vp.height + pad));
180
+ }
181
+ //# sourceMappingURL=view.js.map