@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.
- package/LICENSE +202 -0
- package/README.md +37 -0
- package/dist/cli.js +83 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/ansi.js +37 -0
- package/dist/client/ansi.js.map +1 -0
- package/dist/client/app.js +1868 -0
- package/dist/client/app.js.map +1 -0
- package/dist/client/boot.js +221 -0
- package/dist/client/boot.js.map +1 -0
- package/dist/client/commands.js +133 -0
- package/dist/client/commands.js.map +1 -0
- package/dist/client/daemon-client.js +99 -0
- package/dist/client/daemon-client.js.map +1 -0
- package/dist/client/forest/camera.js +88 -0
- package/dist/client/forest/camera.js.map +1 -0
- package/dist/client/forest/canvas.js +175 -0
- package/dist/client/forest/canvas.js.map +1 -0
- package/dist/client/forest/sidebar.js +182 -0
- package/dist/client/forest/sidebar.js.map +1 -0
- package/dist/client/forest/status.js +39 -0
- package/dist/client/forest/status.js.map +1 -0
- package/dist/client/forest/style.js +70 -0
- package/dist/client/forest/style.js.map +1 -0
- package/dist/client/forest/styles.js +429 -0
- package/dist/client/forest/styles.js.map +1 -0
- package/dist/client/forest/view.js +181 -0
- package/dist/client/forest/view.js.map +1 -0
- package/dist/client/forest/wordmark.js +26 -0
- package/dist/client/forest/wordmark.js.map +1 -0
- package/dist/client/input.js +89 -0
- package/dist/client/input.js.map +1 -0
- package/dist/client/theme.js +27 -0
- package/dist/client/theme.js.map +1 -0
- package/dist/client/tree/asciitree.js +277 -0
- package/dist/client/tree/asciitree.js.map +1 -0
- package/dist/client/tree/convmap.js +260 -0
- package/dist/client/tree/convmap.js.map +1 -0
- package/dist/client/tree/lanegraph.js +260 -0
- package/dist/client/tree/lanegraph.js.map +1 -0
- package/dist/client/tree/merge.js +161 -0
- package/dist/client/tree/merge.js.map +1 -0
- package/dist/client/tree/sessionview.js +163 -0
- package/dist/client/tree/sessionview.js.map +1 -0
- package/dist/client/tree/view.js +238 -0
- package/dist/client/tree/view.js.map +1 -0
- package/dist/client/uistate.js +45 -0
- package/dist/client/uistate.js.map +1 -0
- package/dist/daemon/agents.js +102 -0
- package/dist/daemon/agents.js.map +1 -0
- package/dist/daemon/branch.js +149 -0
- package/dist/daemon/branch.js.map +1 -0
- package/dist/daemon/embed-worker.js +74 -0
- package/dist/daemon/embed-worker.js.map +1 -0
- package/dist/daemon/essence.js +194 -0
- package/dist/daemon/essence.js.map +1 -0
- package/dist/daemon/extbridge.js +138 -0
- package/dist/daemon/extbridge.js.map +1 -0
- package/dist/daemon/lifecycle.js +134 -0
- package/dist/daemon/lifecycle.js.map +1 -0
- package/dist/daemon/pty-compat.js +53 -0
- package/dist/daemon/pty-compat.js.map +1 -0
- package/dist/daemon/semantic.js +337 -0
- package/dist/daemon/semantic.js.map +1 -0
- package/dist/daemon/server.js +808 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/supervisor.js +311 -0
- package/dist/daemon/supervisor.js.map +1 -0
- package/dist/extension/pines-extension.js +191 -0
- package/dist/extension/pines-extension.js.map +1 -0
- package/dist/layout/lexical.js +104 -0
- package/dist/layout/lexical.js.map +1 -0
- package/dist/layout/pca.js +91 -0
- package/dist/layout/pca.js.map +1 -0
- package/dist/layout/relax.js +47 -0
- package/dist/layout/relax.js.map +1 -0
- package/dist/session/ingest.js +95 -0
- package/dist/session/ingest.js.map +1 -0
- package/dist/session/parser.js +254 -0
- package/dist/session/parser.js.map +1 -0
- package/dist/shared/config.js +30 -0
- package/dist/shared/config.js.map +1 -0
- package/dist/shared/paths.js +47 -0
- package/dist/shared/paths.js.map +1 -0
- package/dist/shared/protocol.js +9 -0
- package/dist/shared/protocol.js.map +1 -0
- package/dist/shared/types.js +3 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/shared/wire.js +51 -0
- package/dist/shared/wire.js.map +1 -0
- package/dist/store/db.js +203 -0
- package/dist/store/db.js.map +1 -0
- package/dist/store/watcher.js +69 -0
- package/dist/store/watcher.js.map +1 -0
- package/package.json +80 -0
- package/scripts/fix-node-pty.mjs +34 -0
- package/src/extension/pines-extension.ts +192 -0
- package/src/store/schema.sql +60 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-client.js","sourceRoot":"","sources":["../../src/client/daemon-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export const Y_ASPECT = 0.5;
|
|
2
|
+
export function worldToCell(cam, vp, wx, wy) {
|
|
3
|
+
return {
|
|
4
|
+
x: (wx - cam.cx) * cam.zoom + vp.width / 2,
|
|
5
|
+
y: (wy - cam.cy) * cam.zoom * Y_ASPECT + vp.height / 2,
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export function cellToWorld(cam, vp, x, y) {
|
|
9
|
+
return {
|
|
10
|
+
wx: (x - vp.width / 2) / cam.zoom + cam.cx,
|
|
11
|
+
wy: (y - vp.height / 2) / (cam.zoom * Y_ASPECT) + cam.cy,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/** Zoom about a fixed screen point (mouse wheel behavior). */
|
|
15
|
+
export function zoomAt(cam, vp, x, y, factor) {
|
|
16
|
+
const { wx, wy } = cellToWorld(cam, vp, x, y);
|
|
17
|
+
const zoom = clampZoom(cam.zoom * factor);
|
|
18
|
+
// Keep (wx,wy) under the cursor after the zoom change.
|
|
19
|
+
return {
|
|
20
|
+
zoom,
|
|
21
|
+
cx: wx - (x - vp.width / 2) / zoom,
|
|
22
|
+
cy: wy - (y - vp.height / 2) / (zoom * Y_ASPECT),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export const MIN_ZOOM = 0.4;
|
|
26
|
+
export const MAX_ZOOM = 24;
|
|
27
|
+
export function clampZoom(z) {
|
|
28
|
+
return Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, z));
|
|
29
|
+
}
|
|
30
|
+
/** Semantic zoom bands. */
|
|
31
|
+
export function zoomBand(zoom) {
|
|
32
|
+
return zoom < 3 ? "z0" : "z1";
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Past this, a focused tree "opens" into the full tree view. Kept just shy of
|
|
36
|
+
* MAX_ZOOM so there's plenty of z1 headroom to study the minis up close —
|
|
37
|
+
* the flip into the tree view should feel like pushing through the end stop,
|
|
38
|
+
* not an ambush halfway through the zoom range.
|
|
39
|
+
*/
|
|
40
|
+
export const OPEN_TREE_ZOOM = 22;
|
|
41
|
+
/**
|
|
42
|
+
* Scroll-into-view-if-needed: return a camera from which (wx,wy) is visible
|
|
43
|
+
* with `margin` cells of breathing room. If it already is, the camera comes
|
|
44
|
+
* back unchanged (same reference) — selection moves, the view stays put. If
|
|
45
|
+
* not, pan the minimum distance that lands the point just inside the margin,
|
|
46
|
+
* rather than recentering; the user keeps their bearings.
|
|
47
|
+
*/
|
|
48
|
+
export function ensureVisible(cam, vp, wx, wy, margin = { x: 10, y: 4 }) {
|
|
49
|
+
const p = worldToCell(cam, vp, wx, wy);
|
|
50
|
+
let dx = 0;
|
|
51
|
+
let dy = 0;
|
|
52
|
+
if (p.x < margin.x)
|
|
53
|
+
dx = p.x - margin.x;
|
|
54
|
+
else if (p.x > vp.width - margin.x)
|
|
55
|
+
dx = p.x - (vp.width - margin.x);
|
|
56
|
+
if (p.y < margin.y)
|
|
57
|
+
dy = p.y - margin.y;
|
|
58
|
+
else if (p.y > vp.height - margin.y)
|
|
59
|
+
dy = p.y - (vp.height - margin.y);
|
|
60
|
+
if (dx === 0 && dy === 0)
|
|
61
|
+
return cam;
|
|
62
|
+
return {
|
|
63
|
+
...cam,
|
|
64
|
+
cx: cam.cx + dx / cam.zoom,
|
|
65
|
+
cy: cam.cy + dy / (cam.zoom * Y_ASPECT),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** Fit camera to a set of world points with padding. */
|
|
69
|
+
export function fitCamera(points, vp) {
|
|
70
|
+
if (points.length === 0)
|
|
71
|
+
return { cx: 0, cy: 0, zoom: 2 };
|
|
72
|
+
let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
|
|
73
|
+
for (const p of points) {
|
|
74
|
+
minX = Math.min(minX, p.x);
|
|
75
|
+
maxX = Math.max(maxX, p.x);
|
|
76
|
+
minY = Math.min(minY, p.y);
|
|
77
|
+
maxY = Math.max(maxY, p.y);
|
|
78
|
+
}
|
|
79
|
+
const cx = (minX + maxX) / 2;
|
|
80
|
+
const cy = (minY + maxY) / 2;
|
|
81
|
+
const spanX = Math.max(maxX - minX, 1e-6);
|
|
82
|
+
const spanY = Math.max(maxY - minY, 1e-6);
|
|
83
|
+
// Padding: 20% margin, and leave room for name labels (~12 cells).
|
|
84
|
+
const zx = (vp.width - 24) / (spanX * 1.4);
|
|
85
|
+
const zy = (vp.height - 4) / (spanY * 1.4 * Y_ASPECT);
|
|
86
|
+
return { cx, cy, zoom: clampZoom(Math.min(zx, zy)) };
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=camera.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"camera.js","sourceRoot":"","sources":["../../../src/client/forest/camera.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cell canvas: a styled character grid with a Braille sub-cell layer for
|
|
3
|
+
* smooth edges and a pick-buffer for O(1) mouse hit-testing.
|
|
4
|
+
*
|
|
5
|
+
* Braille resolution is 2×4 dots per cell; lines are Bresenham-rasterized
|
|
6
|
+
* into dot masks and composed into cells that hold no glyph.
|
|
7
|
+
*/
|
|
8
|
+
const BRAILLE_MASK = [
|
|
9
|
+
[0x01, 0x08],
|
|
10
|
+
[0x02, 0x10],
|
|
11
|
+
[0x04, 0x20],
|
|
12
|
+
[0x40, 0x80],
|
|
13
|
+
];
|
|
14
|
+
export const NO_PICK = -1;
|
|
15
|
+
export class Canvas {
|
|
16
|
+
w;
|
|
17
|
+
h;
|
|
18
|
+
ch;
|
|
19
|
+
sgr;
|
|
20
|
+
pick;
|
|
21
|
+
dots;
|
|
22
|
+
dotSgr;
|
|
23
|
+
/** Cells explicitly written (even with a space) occlude the Braille layer. */
|
|
24
|
+
occupied;
|
|
25
|
+
constructor(w, h) {
|
|
26
|
+
this.w = w;
|
|
27
|
+
this.h = h;
|
|
28
|
+
this.ch = new Array(w * h).fill(" ");
|
|
29
|
+
this.sgr = new Array(w * h).fill(null);
|
|
30
|
+
this.pick = new Int32Array(w * h).fill(NO_PICK);
|
|
31
|
+
this.dots = new Uint8Array(w * h);
|
|
32
|
+
this.dotSgr = new Array(w * h).fill(null);
|
|
33
|
+
this.occupied = new Uint8Array(w * h);
|
|
34
|
+
}
|
|
35
|
+
clear() {
|
|
36
|
+
this.ch.fill(" ");
|
|
37
|
+
this.sgr.fill(null);
|
|
38
|
+
this.pick.fill(NO_PICK);
|
|
39
|
+
this.dots.fill(0);
|
|
40
|
+
this.dotSgr.fill(null);
|
|
41
|
+
this.occupied.fill(0);
|
|
42
|
+
}
|
|
43
|
+
inBounds(x, y) {
|
|
44
|
+
return x >= 0 && y >= 0 && x < this.w && y < this.h;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Snapshot a rect's occupied cells so they can be painted back verbatim
|
|
48
|
+
* after something draws over them (a selected tree's label must never
|
|
49
|
+
* erase a neighbor's marker).
|
|
50
|
+
*/
|
|
51
|
+
snapshotRect(r) {
|
|
52
|
+
const out = [];
|
|
53
|
+
for (let dy = 0; dy < r.h; dy++) {
|
|
54
|
+
for (let dx = 0; dx < r.w; dx++) {
|
|
55
|
+
const x = Math.round(r.x) + dx;
|
|
56
|
+
const y = Math.round(r.y) + dy;
|
|
57
|
+
if (!this.inBounds(x, y))
|
|
58
|
+
continue;
|
|
59
|
+
const i = y * this.w + x;
|
|
60
|
+
if (!this.occupied[i])
|
|
61
|
+
continue;
|
|
62
|
+
out.push({ x, y, ch: this.ch[i], sgr: this.sgr[i], pick: this.pick[i] });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
restore(cells) {
|
|
68
|
+
for (const c of cells)
|
|
69
|
+
this.set(c.x, c.y, c.ch, c.sgr, c.pick);
|
|
70
|
+
}
|
|
71
|
+
set(x, y, ch, sgr, pickId = NO_PICK) {
|
|
72
|
+
x = Math.round(x);
|
|
73
|
+
y = Math.round(y);
|
|
74
|
+
if (!this.inBounds(x, y))
|
|
75
|
+
return;
|
|
76
|
+
const i = y * this.w + x;
|
|
77
|
+
this.ch[i] = ch;
|
|
78
|
+
this.sgr[i] = sgr;
|
|
79
|
+
this.occupied[i] = 1;
|
|
80
|
+
if (pickId !== NO_PICK)
|
|
81
|
+
this.pick[i] = pickId;
|
|
82
|
+
}
|
|
83
|
+
text(x, y, str, sgr, pickId = NO_PICK) {
|
|
84
|
+
x = Math.round(x);
|
|
85
|
+
y = Math.round(y);
|
|
86
|
+
for (let i = 0; i < str.length; i++) {
|
|
87
|
+
this.set(x + i, y, str[i], sgr, pickId);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** Plot one Braille dot at sub-cell resolution (2× width, 4× height). */
|
|
91
|
+
dot(px, py, sgr) {
|
|
92
|
+
const cx = Math.floor(px / 2);
|
|
93
|
+
const cy = Math.floor(py / 4);
|
|
94
|
+
if (!this.inBounds(cx, cy))
|
|
95
|
+
return;
|
|
96
|
+
const dx = ((px % 2) + 2) % 2;
|
|
97
|
+
const dy = ((py % 4) + 4) % 4;
|
|
98
|
+
const i = cy * this.w + cx;
|
|
99
|
+
this.dots[i] = (this.dots[i] | BRAILLE_MASK[dy][dx]) & 0xff;
|
|
100
|
+
if (sgr)
|
|
101
|
+
this.dotSgr[i] = sgr;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Rasterize a line between cell-space endpoints into the Braille layer.
|
|
105
|
+
*
|
|
106
|
+
* `dash` is [on, off] in dots: a long lineage edge drawn solid reads as a
|
|
107
|
+
* structural rule across the map, while a dashed one reads as a thread
|
|
108
|
+
* between two trees, which is what it is.
|
|
109
|
+
*/
|
|
110
|
+
line(x0, y0, x1, y1, sgr, dash) {
|
|
111
|
+
// Convert cell coords to dot coords.
|
|
112
|
+
let px0 = Math.round(x0 * 2);
|
|
113
|
+
let py0 = Math.round(y0 * 4);
|
|
114
|
+
const px1 = Math.round(x1 * 2);
|
|
115
|
+
const py1 = Math.round(y1 * 4);
|
|
116
|
+
const dx = Math.abs(px1 - px0);
|
|
117
|
+
const dy = -Math.abs(py1 - py0);
|
|
118
|
+
const sx = px0 < px1 ? 1 : -1;
|
|
119
|
+
const sy = py0 < py1 ? 1 : -1;
|
|
120
|
+
let err = dx + dy;
|
|
121
|
+
let guard = 0;
|
|
122
|
+
let step = 0;
|
|
123
|
+
const period = dash ? dash[0] + dash[1] : 0;
|
|
124
|
+
const maxSteps = (this.w * 2 + this.h * 4) * 2;
|
|
125
|
+
for (;;) {
|
|
126
|
+
if (!dash || step % period < dash[0])
|
|
127
|
+
this.dot(px0, py0, sgr);
|
|
128
|
+
step++;
|
|
129
|
+
if (px0 === px1 && py0 === py1)
|
|
130
|
+
break;
|
|
131
|
+
if (++guard > maxSteps)
|
|
132
|
+
break;
|
|
133
|
+
const e2 = 2 * err;
|
|
134
|
+
if (e2 >= dy) {
|
|
135
|
+
err += dy;
|
|
136
|
+
px0 += sx;
|
|
137
|
+
}
|
|
138
|
+
if (e2 <= dx) {
|
|
139
|
+
err += dx;
|
|
140
|
+
py0 += sy;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
pickAt(x, y) {
|
|
145
|
+
if (!this.inBounds(x, y))
|
|
146
|
+
return NO_PICK;
|
|
147
|
+
return this.pick[y * this.w + x];
|
|
148
|
+
}
|
|
149
|
+
/** Compose to per-row ANSI strings (Braille fills glyph-free cells). */
|
|
150
|
+
render() {
|
|
151
|
+
const rows = [];
|
|
152
|
+
for (let y = 0; y < this.h; y++) {
|
|
153
|
+
let row = "";
|
|
154
|
+
let curSgr;
|
|
155
|
+
for (let x = 0; x < this.w; x++) {
|
|
156
|
+
const i = y * this.w + x;
|
|
157
|
+
let ch = this.ch[i];
|
|
158
|
+
let sgr = this.sgr[i];
|
|
159
|
+
if (ch === " " && !this.occupied[i] && this.dots[i] !== 0) {
|
|
160
|
+
ch = String.fromCharCode(0x2800 + this.dots[i]);
|
|
161
|
+
sgr = this.dotSgr[i];
|
|
162
|
+
}
|
|
163
|
+
if (sgr !== curSgr) {
|
|
164
|
+
row += sgr === null ? "\x1b[0m" : `\x1b[0m\x1b[${sgr}m`;
|
|
165
|
+
curSgr = sgr;
|
|
166
|
+
}
|
|
167
|
+
row += ch;
|
|
168
|
+
}
|
|
169
|
+
row += "\x1b[0m";
|
|
170
|
+
rows.push(row);
|
|
171
|
+
}
|
|
172
|
+
return rows;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=canvas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canvas.js","sourceRoot":"","sources":["../../../src/client/forest/canvas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agents-style sidebar: a linear, state-grouped list of every tree — the
|
|
3
|
+
* triage inbox beside the spatial forest. Modeled on Claude Code's agents
|
|
4
|
+
* view: groups by state first (needs input → working → recent), recency
|
|
5
|
+
* within each group, one row per tree with status glyph, name, and age.
|
|
6
|
+
*
|
|
7
|
+
* Pure rendering: callers own selection, scrolling, and sizing.
|
|
8
|
+
*/
|
|
9
|
+
import { basename } from "node:path";
|
|
10
|
+
import { clipAnsi, visibleLength } from "../ansi.js";
|
|
11
|
+
import { statusGlyph, statusSgr } from "./status.js";
|
|
12
|
+
import { MASCOT, WORDMARK, WORDMARK_SGR } from "./wordmark.js";
|
|
13
|
+
import { MUTED } from "../theme.js";
|
|
14
|
+
/**
|
|
15
|
+
* Display title for a tree: its name (session name or derived first prompt);
|
|
16
|
+
* before any prompt exists, the directory basename as a placeholder; the raw
|
|
17
|
+
* id only as a last resort. `fallback` tells callers to render it lighter.
|
|
18
|
+
*/
|
|
19
|
+
export function treeTitle(t) {
|
|
20
|
+
if (t.name)
|
|
21
|
+
return { title: t.name, fallback: false };
|
|
22
|
+
if (t.cwd)
|
|
23
|
+
return { title: basename(t.cwd), fallback: true };
|
|
24
|
+
return { title: t.treeId, fallback: true };
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Group and order the forest for the list: trees needing attention first
|
|
28
|
+
* (waiting-unseen and crashed-unseen), then live working trees, then
|
|
29
|
+
* everything else — each group ordered by last interaction, newest first.
|
|
30
|
+
* Archived trees (only present when the caller chooses to show them) sit in
|
|
31
|
+
* their own group at the bottom regardless of status.
|
|
32
|
+
*/
|
|
33
|
+
export function sidebarRows(trees) {
|
|
34
|
+
const needsInput = [];
|
|
35
|
+
const working = [];
|
|
36
|
+
const recent = [];
|
|
37
|
+
const archived = [];
|
|
38
|
+
for (const t of trees) {
|
|
39
|
+
if (t.archived)
|
|
40
|
+
archived.push(t);
|
|
41
|
+
else if ((t.status === "waiting" || t.status === "crashed") && !t.seen)
|
|
42
|
+
needsInput.push(t);
|
|
43
|
+
else if (t.status === "running")
|
|
44
|
+
working.push(t);
|
|
45
|
+
else
|
|
46
|
+
recent.push(t);
|
|
47
|
+
}
|
|
48
|
+
const byRecency = (a, b) => b.mtime - a.mtime;
|
|
49
|
+
needsInput.sort(byRecency);
|
|
50
|
+
working.sort(byRecency);
|
|
51
|
+
recent.sort(byRecency);
|
|
52
|
+
archived.sort(byRecency);
|
|
53
|
+
const rows = [];
|
|
54
|
+
const push = (label, group) => {
|
|
55
|
+
if (group.length === 0)
|
|
56
|
+
return;
|
|
57
|
+
rows.push({ kind: "header", label });
|
|
58
|
+
for (const t of group)
|
|
59
|
+
rows.push({ kind: "tree", treeId: t.treeId });
|
|
60
|
+
};
|
|
61
|
+
push("needs input", needsInput);
|
|
62
|
+
push("working", working);
|
|
63
|
+
push("recent", recent);
|
|
64
|
+
push("archived", archived);
|
|
65
|
+
return rows;
|
|
66
|
+
}
|
|
67
|
+
/** Tree ids in list order (selection stepping). */
|
|
68
|
+
export function sidebarOrder(rows) {
|
|
69
|
+
return rows.filter((r) => r.kind === "tree").map((r) => r.treeId);
|
|
70
|
+
}
|
|
71
|
+
/** Compact age like Claude Agents: 45s, 12m, 3h, 5d. */
|
|
72
|
+
export function humanAge(mtime, now) {
|
|
73
|
+
const s = Math.max(0, Math.floor((now - mtime) / 1000));
|
|
74
|
+
if (s < 60)
|
|
75
|
+
return `${s}s`;
|
|
76
|
+
const m = Math.floor(s / 60);
|
|
77
|
+
if (m < 60)
|
|
78
|
+
return `${m}m`;
|
|
79
|
+
const h = Math.floor(m / 60);
|
|
80
|
+
if (h < 48)
|
|
81
|
+
return `${h}h`;
|
|
82
|
+
return `${Math.floor(h / 24)}d`;
|
|
83
|
+
}
|
|
84
|
+
/** Rows the mascot header consumes (0 when it doesn't fit or isn't wanted). */
|
|
85
|
+
export function sidebarHeaderH(input) {
|
|
86
|
+
return input.brand && input.height >= 16 && input.width >= 30 ? 6 : 0;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Render the sidebar as `height` lines of exactly `width` visible columns.
|
|
90
|
+
* Returns the lines plus a per-line map to tree ids (mouse hit-testing).
|
|
91
|
+
*/
|
|
92
|
+
export function renderSidebar(input) {
|
|
93
|
+
const { trees, rows, selectedId, width, height, scroll, spinnerFrame, now } = input;
|
|
94
|
+
const lines = [];
|
|
95
|
+
const lineToTree = [];
|
|
96
|
+
const pad = (s) => {
|
|
97
|
+
const clipped = clipAnsi(s, width);
|
|
98
|
+
return clipped + " ".repeat(Math.max(0, width - visibleLength(clipped)));
|
|
99
|
+
};
|
|
100
|
+
// Mascot header: the pine and the canopy-gradient wordmark, with live
|
|
101
|
+
// counts — the same at-a-glance block Claude Agents keeps in its top-left.
|
|
102
|
+
const headerH = sidebarHeaderH(input);
|
|
103
|
+
if (headerH > 0 && input.brand) {
|
|
104
|
+
const b = input.brand;
|
|
105
|
+
let unseen = 0;
|
|
106
|
+
let running = 0;
|
|
107
|
+
for (const t of trees.values()) {
|
|
108
|
+
if (t.status === "waiting" && !t.seen)
|
|
109
|
+
unseen++;
|
|
110
|
+
if (t.status === "running")
|
|
111
|
+
running++;
|
|
112
|
+
}
|
|
113
|
+
const counts = [
|
|
114
|
+
unseen > 0 ? `\x1b[1;38;5;44m●${unseen}\x1b[0m` : "",
|
|
115
|
+
running > 0 ? `\x1b[33m◐${running}\x1b[0m` : "",
|
|
116
|
+
`\x1b[${MUTED}m${trees.size} tree${trees.size === 1 ? "" : "s"}\x1b[0m`,
|
|
117
|
+
]
|
|
118
|
+
.filter(Boolean)
|
|
119
|
+
.join(`\x1b[${MUTED}m · \x1b[0m`);
|
|
120
|
+
const G = (s, c) => `\x1b[${c}m${s}\x1b[0m`;
|
|
121
|
+
const mast = (i) => G(MASCOT[i][0], MASCOT[i][1]);
|
|
122
|
+
const mark = (i) => G(WORDMARK[i], WORDMARK_SGR[i]);
|
|
123
|
+
lines.push(pad(` ${mast(0)} ${mark(0)}`), pad(` ${mast(1)} ${mark(1)}`), pad(` ${mast(2)} ${mark(2)}`), pad(` ${mast(3)} \x1b[${MUTED}mv${b.version} · pi ${b.pi}\x1b[0m`), pad(` ${counts}`), pad(""));
|
|
124
|
+
for (let i = 0; i < headerH; i++)
|
|
125
|
+
lineToTree.push(null);
|
|
126
|
+
}
|
|
127
|
+
const listH = height - headerH;
|
|
128
|
+
if (rows.length === 0) {
|
|
129
|
+
lines.push(pad(""), pad(` \x1b[${MUTED}m(no trees yet)\x1b[0m`));
|
|
130
|
+
lineToTree.push(null, null);
|
|
131
|
+
}
|
|
132
|
+
for (let i = scroll; i < Math.min(rows.length, scroll + listH); i++) {
|
|
133
|
+
const row = rows[i];
|
|
134
|
+
if (row.kind === "header") {
|
|
135
|
+
lines.push(pad(` \x1b[${MUTED}m${row.label}\x1b[0m`));
|
|
136
|
+
lineToTree.push(null);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const t = trees.get(row.treeId);
|
|
140
|
+
if (!t) {
|
|
141
|
+
lines.push(pad(""));
|
|
142
|
+
lineToTree.push(null);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const selected = t.treeId === selectedId;
|
|
146
|
+
const glyph = statusGlyph(t, spinnerFrame);
|
|
147
|
+
const sgr = statusSgr(t);
|
|
148
|
+
const age = humanAge(t.mtime, now);
|
|
149
|
+
const { title, fallback } = treeTitle(t);
|
|
150
|
+
// ` ✻ title…… dir 12m ` — title flexes; the directory is a light label
|
|
151
|
+
// (Claude Agents keeps cwd as metadata, never the name).
|
|
152
|
+
const dirChip = width >= 32 && t.name && t.cwd ? basename(t.cwd).slice(0, 10) : "";
|
|
153
|
+
const chipW = dirChip ? dirChip.length + 1 : 0;
|
|
154
|
+
const nameW = Math.max(4, width - 4 - age.length - 2 - chipW);
|
|
155
|
+
const shownName = title.length > nameW ? title.slice(0, nameW - 1) + "…" : title.padEnd(nameW);
|
|
156
|
+
const nameSgr = selected ? "7" : fallback ? MUTED : t.seen ? "0" : "1";
|
|
157
|
+
const chip = dirChip ? `\x1b[${MUTED}m${dirChip}\x1b[0m ` : "";
|
|
158
|
+
lines.push(pad(` \x1b[${sgr}m${glyph}\x1b[0m \x1b[${nameSgr}m${shownName}\x1b[0m ${chip}\x1b[${MUTED}m${age}\x1b[0m `));
|
|
159
|
+
lineToTree.push(t.treeId);
|
|
160
|
+
}
|
|
161
|
+
while (lines.length < height) {
|
|
162
|
+
lines.push(pad(""));
|
|
163
|
+
lineToTree.push(null);
|
|
164
|
+
}
|
|
165
|
+
return { lines, lineToTree };
|
|
166
|
+
}
|
|
167
|
+
/** Clamp scroll so the selected row stays visible. */
|
|
168
|
+
export function sidebarScrollTo(rows, selectedId, scroll, height) {
|
|
169
|
+
if (!selectedId)
|
|
170
|
+
return Math.max(0, Math.min(scroll, rows.length - height));
|
|
171
|
+
const idx = rows.findIndex((r) => r.treeId === selectedId);
|
|
172
|
+
if (idx < 0)
|
|
173
|
+
return scroll;
|
|
174
|
+
// Keep the group header above the selection visible when it's adjacent.
|
|
175
|
+
const top = idx > 0 && rows[idx - 1].kind === "header" ? idx - 1 : idx;
|
|
176
|
+
if (top < scroll)
|
|
177
|
+
return top;
|
|
178
|
+
if (idx >= scroll + height)
|
|
179
|
+
return idx - height + 1;
|
|
180
|
+
return scroll;
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=sidebar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar.js","sourceRoot":"","sources":["../../../src/client/forest/sidebar.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,CAAc;IACtC,IAAI,CAAC,CAAC,IAAI;QAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IACtD,IAAI,CAAC,CAAC,GAAG;QAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC7D,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAC7C,CAAC;AAQD;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,KAAoB;IAC9C,MAAM,UAAU,GAAkB,EAAE,CAAC;IACrC,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAkB,EAAE,CAAC;IACnC,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC,QAAQ;YAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;aAC5B,IAAI,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;YAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;aACtF,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;;YAC5C,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IACD,MAAM,SAAS,GAAG,CAAC,CAAc,EAAE,CAAc,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;IACxE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC3B,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACxB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAEzB,MAAM,IAAI,GAAiB,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,KAAoB,EAAE,EAAE;QACnD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC/B,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QACrC,KAAK,MAAM,CAAC,IAAI,KAAK;YAAE,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC,CAAC;IACF,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IAChC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACzB,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACvB,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC3B,OAAO,IAAI,CAAC;AACd,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,YAAY,CAAC,IAAkB;IAC7C,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAO,CAAC,CAAC;AACrE,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,QAAQ,CAAC,KAAa,EAAE,GAAW;IACjD,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IACxD,IAAI,CAAC,GAAG,EAAE;QAAE,OAAO,GAAG,CAAC,GAAG,CAAC;IAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG,EAAE;QAAE,OAAO,GAAG,CAAC,GAAG,CAAC;IAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG,EAAE;QAAE,OAAO,GAAG,CAAC,GAAG,CAAC;IAC3B,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC;AAClC,CAAC;AAeD,+EAA+E;AAC/E,MAAM,UAAU,cAAc,CAAC,KAI9B;IACC,OAAO,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,IAAI,EAAE,IAAI,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAyB;IAIrD,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;IACpF,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,UAAU,GAAsB,EAAE,CAAC;IAEzC,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACnC,OAAO,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3E,CAAC,CAAC;IAEF,sEAAsE;IACtE,2EAA2E;IAC3E,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;QACtB,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YAC/B,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,IAAI;gBAAE,MAAM,EAAE,CAAC;YAChD,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS;gBAAE,OAAO,EAAE,CAAC;QACxC,CAAC;QACD,MAAM,MAAM,GAAG;YACb,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,mBAAmB,MAAM,SAAS,CAAC,CAAC,CAAC,EAAE;YACpD,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,OAAO,SAAS,CAAC,CAAC,CAAC,EAAE;YAC/C,QAAQ,KAAK,IAAI,KAAK,CAAC,IAAI,QAAQ,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,SAAS;SACxE;aACE,MAAM,CAAC,OAAO,CAAC;aACf,IAAI,CAAC,QAAQ,KAAK,aAAa,CAAC,CAAC;QACpC,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC;QAC5D,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5D,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAE,EAAE,YAAY,CAAC,CAAC,CAAE,CAAC,CAAC;QAC9D,KAAK,CAAC,IAAI,CACR,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAC/B,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAC9B,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAC7B,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,KAAK,KAAK,CAAC,CAAC,OAAO,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,EACpE,GAAG,CAAC,IAAI,MAAM,EAAE,CAAC,EACjB,GAAG,CAAC,EAAE,CAAC,CACR,CAAC;QACF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE;YAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;IAE/B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,SAAS,KAAK,wBAAwB,CAAC,CAAC,CAAC;QACjE,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,KAAK,IAAI,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACpE,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACrB,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,KAAK,IAAI,GAAG,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC;YACtD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtB,SAAS;QACX,CAAC;QACD,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,MAAO,CAAC,CAAC;QACjC,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YACpB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtB,SAAS;QACX,CAAC;QACD,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC;QACzC,MAAM,KAAK,GAAG,WAAW,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACnC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QACzC,uEAAuE;QACvE,yDAAyD;QACzD,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACnF,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;QAC9D,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC/F,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QACvE,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,QAAQ,KAAK,IAAI,OAAO,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,KAAK,CAAC,IAAI,CACR,GAAG,CACD,SAAS,GAAG,IAAI,KAAK,gBAAgB,OAAO,IAAI,SAAS,WAAW,IAAI,QAAQ,KAAK,IAAI,GAAG,UAAU,CACvG,CACF,CAAC;QACF,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,KAAK,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACpB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;AAC/B,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,eAAe,CAC7B,IAAkB,EAClB,UAAyB,EACzB,MAAc,EACd,MAAc;IAEd,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;IAC5E,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC;IAC3D,IAAI,GAAG,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IAC3B,wEAAwE;IACxE,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,CAAE,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACxE,IAAI,GAAG,GAAG,MAAM;QAAE,OAAO,GAAG,CAAC;IAC7B,IAAI,GAAG,IAAI,MAAM,GAAG,MAAM;QAAE,OAAO,GAAG,GAAG,MAAM,GAAG,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status vocabulary shared by every forest style, the sidebar, and the status
|
|
3
|
+
* bar: one glyph and one color per lifecycle state.
|
|
4
|
+
*
|
|
5
|
+
* Styles may dress a tree up however they like, but they all reach for these
|
|
6
|
+
* two functions for the state itself — a tree's color and animation mean the
|
|
7
|
+
* same thing in every option.
|
|
8
|
+
*/
|
|
9
|
+
import { MUTED } from "../theme.js";
|
|
10
|
+
export const SPINNER_FRAMES = ["◐", "◓", "◑", "◒"];
|
|
11
|
+
export function statusSgr(t) {
|
|
12
|
+
switch (t.status) {
|
|
13
|
+
case "running":
|
|
14
|
+
return "33"; // yellow
|
|
15
|
+
case "waiting":
|
|
16
|
+
return t.seen ? "32" : "38;5;44"; // green ○ once acknowledged, teal ● before
|
|
17
|
+
case "crashed":
|
|
18
|
+
return "31";
|
|
19
|
+
case "completed":
|
|
20
|
+
return "32"; // green, undimmed — dim colors sink below visibility on dark themes
|
|
21
|
+
default:
|
|
22
|
+
return MUTED; // dormant
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function statusGlyph(t, spinnerFrame) {
|
|
26
|
+
switch (t.status) {
|
|
27
|
+
case "running":
|
|
28
|
+
return SPINNER_FRAMES[spinnerFrame % SPINNER_FRAMES.length];
|
|
29
|
+
case "waiting":
|
|
30
|
+
return t.seen ? "○" : "●";
|
|
31
|
+
case "crashed":
|
|
32
|
+
return "●";
|
|
33
|
+
case "completed":
|
|
34
|
+
return "✓"; // distinguishes from waiting ○ now both are full green
|
|
35
|
+
default:
|
|
36
|
+
return "·";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/client/forest/status.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAEnD,MAAM,UAAU,SAAS,CAAC,CAAoC;IAC5D,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC;QACjB,KAAK,SAAS;YACZ,OAAO,IAAI,CAAC,CAAC,SAAS;QACxB,KAAK,SAAS;YACZ,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,2CAA2C;QAC/E,KAAK,SAAS;YACZ,OAAO,IAAI,CAAC;QACd,KAAK,WAAW;YACd,OAAO,IAAI,CAAC,CAAC,oEAAoE;QACnF;YACE,OAAO,KAAK,CAAC,CAAC,UAAU;IAC5B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,CAAoC,EAAE,YAAoB;IACpF,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC;QACjB,KAAK,SAAS;YACZ,OAAO,cAAc,CAAC,YAAY,GAAG,cAAc,CAAC,MAAM,CAAE,CAAC;QAC/D,KAAK,SAAS;YACZ,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QAC5B,KAAK,SAAS;YACZ,OAAO,GAAG,CAAC;QACb,KAAK,WAAW;YACd,OAAO,GAAG,CAAC,CAAC,uDAAuD;QACrE;YACE,OAAO,GAAG,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Row-interval registry that de-clutters overlapping text: higher-priority
|
|
3
|
+
* markers (drawn first) claim their span; later claims that intersect an
|
|
4
|
+
* occupied span are rejected so names never overwrite each other.
|
|
5
|
+
*
|
|
6
|
+
* Spans carry the tree that owns them, so a marker can claim a rectangle that
|
|
7
|
+
* includes its own already-reserved core cell.
|
|
8
|
+
*/
|
|
9
|
+
export class LabelPlacer {
|
|
10
|
+
rows = new Map();
|
|
11
|
+
/** Mark cells occupied without competing (glyphs, minis). */
|
|
12
|
+
reserve(x, y, width, owner = null) {
|
|
13
|
+
const row = Math.round(y);
|
|
14
|
+
const spans = this.rows.get(row) ?? [];
|
|
15
|
+
spans.push({ a: Math.round(x), b: Math.round(x) + width - 1, owner });
|
|
16
|
+
this.rows.set(row, spans);
|
|
17
|
+
}
|
|
18
|
+
/** Try to claim a span; false = something already there, skip drawing. */
|
|
19
|
+
claim(x, y, width, owner = null) {
|
|
20
|
+
if (!this.free(x, y, width, owner))
|
|
21
|
+
return false;
|
|
22
|
+
this.reserve(x, y, width, owner);
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
reserveRect(r, owner = null) {
|
|
26
|
+
for (let i = 0; i < r.h; i++)
|
|
27
|
+
this.reserve(r.x, r.y + i, r.w, owner);
|
|
28
|
+
}
|
|
29
|
+
/** All-or-nothing claim across every row of a rectangle. */
|
|
30
|
+
claimRect(r, owner = null) {
|
|
31
|
+
for (let i = 0; i < r.h; i++) {
|
|
32
|
+
if (!this.free(r.x, r.y + i, r.w, owner))
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
this.reserveRect(r, owner);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
free(x, y, width, owner) {
|
|
39
|
+
const spans = this.rows.get(Math.round(y));
|
|
40
|
+
if (!spans)
|
|
41
|
+
return true;
|
|
42
|
+
const x0 = Math.round(x);
|
|
43
|
+
const x1 = x0 + width - 1;
|
|
44
|
+
for (const s of spans) {
|
|
45
|
+
if (s.owner !== null && s.owner === owner)
|
|
46
|
+
continue; // one's own reservation
|
|
47
|
+
if (x0 <= s.b && x1 >= s.a)
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function truncate(s, n) {
|
|
54
|
+
return s.length <= n ? s : s.slice(0, n - 1) + "…";
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Clip a label to what is left of the row. Terminal canvases drop
|
|
58
|
+
* out-of-bounds writes silently, which cuts a name mid-word at the right
|
|
59
|
+
* edge — on a narrow pane with prompt-derived names that is the common case,
|
|
60
|
+
* not an edge case. An ellipsis says "there is more" instead.
|
|
61
|
+
*/
|
|
62
|
+
export function fitText(s, x, vpWidth) {
|
|
63
|
+
const room = vpWidth - Math.round(x);
|
|
64
|
+
if (room <= 0)
|
|
65
|
+
return "";
|
|
66
|
+
if (s.length <= room)
|
|
67
|
+
return s;
|
|
68
|
+
return room === 1 ? "…" : truncate(s, room);
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=style.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style.js","sourceRoot":"","sources":["../../../src/client/forest/style.ts"],"names":[],"mappings":"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"}
|