archymedes-cli 2.2.0 → 2.5.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/README.md +17 -7
- package/dist/{archymedes-76z6n643.mjs → archymedes-06fh0z84.mjs} +233 -12
- package/dist/archymedes-130jt0wr.mjs +1231 -0
- package/dist/{archymedes-pg3pvh9r.mjs → archymedes-138genyy.mjs} +214 -5
- package/dist/{archymedes-sc3mwttb.mjs → archymedes-2kvjaajw.mjs} +66 -25
- package/dist/archymedes-5vhvv8kr.mjs +1169 -0
- package/dist/{archymedes-wjaqydyg.mjs → archymedes-a3ms7jvr.mjs} +45 -29
- package/dist/{archymedes-cdgejs3p.mjs → archymedes-bmtdqqwt.mjs} +17 -44
- package/dist/{archymedes-npcrm9a0.mjs → archymedes-d3azqkay.mjs} +537 -9
- package/dist/archymedes-main.mjs +31452 -25912
- package/dist/archymedes-w4bjfye7.mjs +280 -0
- package/dist/{editor-screen-1b3z96tn.mjs → editor-screen-e01mn7dd.mjs} +62 -26
- package/dist/{factory-96yy6mxr.mjs → factory-hyv8agr0.mjs} +1 -1
- package/dist/{file-screen-m7q1xcer.mjs → file-screen-stcxznwy.mjs} +10 -8
- package/dist/guide-screen-w5nb9sry.mjs +273 -0
- package/dist/pager-screen-aamt6xv0.mjs +155 -0
- package/dist/projection-x6x6hm9t.mjs +248 -0
- package/dist/workspace-screen-62k6hnq7.mjs +70 -0
- package/package.json +1 -1
- package/dist/archymedes-5zn4zp84.mjs +0 -646
- package/dist/archymedes-r54qthg5.mjs +0 -495
- package/dist/guide-screen-aj9n9v80.mjs +0 -569
- package/dist/workspace-screen-w88mcw4w.mjs +0 -241
|
@@ -1,495 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ASCII_GLYPHS,
|
|
3
|
-
UNICODE_GLYPHS,
|
|
4
|
-
borderGlyphsFor,
|
|
5
|
-
newMarkdownState,
|
|
6
|
-
rainbowText,
|
|
7
|
-
renderMarkdownLine,
|
|
8
|
-
rgbTo256,
|
|
9
|
-
visibleWidth
|
|
10
|
-
} from "./archymedes-5zn4zp84.mjs";
|
|
11
|
-
|
|
12
|
-
// packages/archymedes-cli/src/output.ts
|
|
13
|
-
var terminalStream = {
|
|
14
|
-
write(text) {
|
|
15
|
-
process.stdout.write(text);
|
|
16
|
-
},
|
|
17
|
-
get columns() {
|
|
18
|
-
return process.stdout.columns;
|
|
19
|
-
},
|
|
20
|
-
get rows() {
|
|
21
|
-
return process.stdout.rows;
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
// packages/archymedes-cli/src/tui.ts
|
|
26
|
-
var RESET = "\x1B[0m";
|
|
27
|
-
var DIM = "\x1B[2m";
|
|
28
|
-
var CYAN = "\x1B[36m";
|
|
29
|
-
var GREEN = "\x1B[32m";
|
|
30
|
-
var YELLOW = "\x1B[33m";
|
|
31
|
-
var RED = "\x1B[31m";
|
|
32
|
-
function paint(text, code, depth) {
|
|
33
|
-
return depth === "none" ? text : `${code}${text}${RESET}`;
|
|
34
|
-
}
|
|
35
|
-
function archymedesSpinnerFrame(index, glyphs = UNICODE_GLYPHS) {
|
|
36
|
-
const frames = glyphs.spinnerFrames;
|
|
37
|
-
const normalized = Number.isFinite(index) ? Math.max(0, Math.floor(index)) : 0;
|
|
38
|
-
return frames[normalized % frames.length];
|
|
39
|
-
}
|
|
40
|
-
class Spring {
|
|
41
|
-
angularFrequency;
|
|
42
|
-
dampingRatio;
|
|
43
|
-
constructor(angularFrequency, dampingRatio) {
|
|
44
|
-
this.angularFrequency = angularFrequency;
|
|
45
|
-
this.dampingRatio = dampingRatio;
|
|
46
|
-
}
|
|
47
|
-
update(position, velocity, target, dt) {
|
|
48
|
-
const omega = this.angularFrequency;
|
|
49
|
-
const zeta = this.dampingRatio;
|
|
50
|
-
const f = 1 + 2 * dt * zeta * omega;
|
|
51
|
-
const oo = omega * omega;
|
|
52
|
-
const hoo = dt * oo;
|
|
53
|
-
const hhoo = dt * hoo;
|
|
54
|
-
const detInv = 1 / (f + hhoo);
|
|
55
|
-
const detX = f * position + dt * velocity + hhoo * target;
|
|
56
|
-
const detV = velocity + hoo * (target - position);
|
|
57
|
-
return [detX * detInv, detV * detInv];
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
class SpringAnimator {
|
|
62
|
-
onTick;
|
|
63
|
-
spring;
|
|
64
|
-
position;
|
|
65
|
-
velocity = 0;
|
|
66
|
-
target;
|
|
67
|
-
timer;
|
|
68
|
-
intervalMs;
|
|
69
|
-
epsilon;
|
|
70
|
-
constructor(initial, onTick, options = {}) {
|
|
71
|
-
this.onTick = onTick;
|
|
72
|
-
this.position = initial;
|
|
73
|
-
this.target = initial;
|
|
74
|
-
this.spring = new Spring(options.angularFrequency ?? 18, options.dampingRatio ?? 0.86);
|
|
75
|
-
this.intervalMs = options.intervalMs ?? 40;
|
|
76
|
-
this.epsilon = options.epsilon ?? 0.01;
|
|
77
|
-
}
|
|
78
|
-
get value() {
|
|
79
|
-
return this.position;
|
|
80
|
-
}
|
|
81
|
-
get settled() {
|
|
82
|
-
return !this.timer;
|
|
83
|
-
}
|
|
84
|
-
retarget(target) {
|
|
85
|
-
this.target = target;
|
|
86
|
-
if (Math.abs(this.target - this.position) < this.epsilon && Math.abs(this.velocity) < this.epsilon) {
|
|
87
|
-
this.position = target;
|
|
88
|
-
this.onTick(target);
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
this.ensureRunning();
|
|
92
|
-
}
|
|
93
|
-
snapTo(target) {
|
|
94
|
-
this.stop();
|
|
95
|
-
this.position = target;
|
|
96
|
-
this.velocity = 0;
|
|
97
|
-
this.target = target;
|
|
98
|
-
this.onTick(target);
|
|
99
|
-
}
|
|
100
|
-
ensureRunning() {
|
|
101
|
-
if (this.timer)
|
|
102
|
-
return;
|
|
103
|
-
this.timer = setInterval(() => {
|
|
104
|
-
const dt = this.intervalMs / 1000;
|
|
105
|
-
const [pos, vel] = this.spring.update(this.position, this.velocity, this.target, dt);
|
|
106
|
-
this.position = pos;
|
|
107
|
-
this.velocity = vel;
|
|
108
|
-
if (Math.abs(this.target - pos) < this.epsilon && Math.abs(vel) < this.epsilon) {
|
|
109
|
-
this.position = this.target;
|
|
110
|
-
this.stop();
|
|
111
|
-
this.onTick(this.target);
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
this.onTick(pos);
|
|
115
|
-
}, this.intervalMs);
|
|
116
|
-
}
|
|
117
|
-
stop() {
|
|
118
|
-
if (!this.timer)
|
|
119
|
-
return;
|
|
120
|
-
clearInterval(this.timer);
|
|
121
|
-
this.timer = undefined;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
function formatElapsed(ms) {
|
|
125
|
-
const seconds = ms / 1000;
|
|
126
|
-
return seconds < 60 ? `${seconds.toFixed(1)}s` : `${Math.floor(seconds / 60)}m ${Math.round(seconds % 60)}s`;
|
|
127
|
-
}
|
|
128
|
-
function formatTokens(tokens) {
|
|
129
|
-
if (tokens < 1000)
|
|
130
|
-
return `${tokens} tokens`;
|
|
131
|
-
return `${(tokens / 1000).toFixed(1)}k tokens`;
|
|
132
|
-
}
|
|
133
|
-
function sparkline(values, glyphs = UNICODE_GLYPHS) {
|
|
134
|
-
const levels = glyphs.sparkLevels;
|
|
135
|
-
if (values.length === 0)
|
|
136
|
-
return "";
|
|
137
|
-
const max = Math.max(...values);
|
|
138
|
-
if (max <= 0)
|
|
139
|
-
return levels[0].repeat(values.length);
|
|
140
|
-
return values.map((value) => levels[Math.min(levels.length - 1, Math.floor(Math.max(0, value) / max * (levels.length - 1)))]).join("");
|
|
141
|
-
}
|
|
142
|
-
var PARTIAL_BLOCKS = ["", "▏", "▎", "▍", "▌", "▋", "▊", "▉"];
|
|
143
|
-
var FULL_BLOCK = "█";
|
|
144
|
-
var TRACK_BLOCK = "░";
|
|
145
|
-
var DEFAULT_GRADIENT_FROM = { r: 124, g: 197, b: 255 };
|
|
146
|
-
var DEFAULT_GRADIENT_TO = { r: 255, g: 207, b: 107 };
|
|
147
|
-
function lerp(from, to, t) {
|
|
148
|
-
return { r: from.r + (to.r - from.r) * t, g: from.g + (to.g - from.g) * t, b: from.b + (to.b - from.b) * t };
|
|
149
|
-
}
|
|
150
|
-
function paintRgb(text, rgb, depth) {
|
|
151
|
-
if (depth === "none")
|
|
152
|
-
return text;
|
|
153
|
-
const r = Math.round(rgb.r);
|
|
154
|
-
const g = Math.round(rgb.g);
|
|
155
|
-
const b = Math.round(rgb.b);
|
|
156
|
-
const code = depth === "truecolor" ? `\x1B[38;2;${r};${g};${b}m` : `\x1B[38;5;${rgbTo256({ r, g, b })}m`;
|
|
157
|
-
return `${code}${text}\x1B[0m`;
|
|
158
|
-
}
|
|
159
|
-
function progressBar(fraction, width, options) {
|
|
160
|
-
const clamped = Math.max(0, Math.min(1, Number.isFinite(fraction) ? fraction : 0));
|
|
161
|
-
const cells = Math.max(1, Math.floor(width));
|
|
162
|
-
const from = options.from ?? DEFAULT_GRADIENT_FROM;
|
|
163
|
-
const to = options.to ?? DEFAULT_GRADIENT_TO;
|
|
164
|
-
const ascii = options.glyphs === ASCII_GLYPHS;
|
|
165
|
-
const eighths = ascii ? cells : cells * 8;
|
|
166
|
-
const filledEighths = Math.round(clamped * eighths);
|
|
167
|
-
let bar = "";
|
|
168
|
-
for (let index = 0;index < cells; index += 1) {
|
|
169
|
-
const t = cells <= 1 ? 0 : index / (cells - 1);
|
|
170
|
-
const rgb = lerp(from, to, t);
|
|
171
|
-
if (ascii) {
|
|
172
|
-
bar += index < filledEighths ? paintRgb("#", rgb, options.depth) : "-";
|
|
173
|
-
continue;
|
|
174
|
-
}
|
|
175
|
-
const cellStart = index * 8;
|
|
176
|
-
if (filledEighths >= cellStart + 8)
|
|
177
|
-
bar += paintRgb(FULL_BLOCK, rgb, options.depth);
|
|
178
|
-
else if (filledEighths > cellStart)
|
|
179
|
-
bar += paintRgb(PARTIAL_BLOCKS[filledEighths - cellStart], rgb, options.depth);
|
|
180
|
-
else
|
|
181
|
-
bar += options.depth === "none" ? TRACK_BLOCK : `\x1B[2m${TRACK_BLOCK}\x1B[0m`;
|
|
182
|
-
}
|
|
183
|
-
return bar;
|
|
184
|
-
}
|
|
185
|
-
function table(columns, rows, options) {
|
|
186
|
-
const glyphs = options.glyphs ?? UNICODE_GLYPHS;
|
|
187
|
-
const border = borderGlyphsFor(options.borderStyle ?? "round", glyphs);
|
|
188
|
-
const terminalWidth = Math.max(1, options.width ?? process.stdout.columns ?? 80);
|
|
189
|
-
const count = columns.length;
|
|
190
|
-
const widths = columns.map((header, index) => Math.max(visibleWidth(header), ...rows.map((row2) => visibleWidth(row2[index] ?? ""))));
|
|
191
|
-
const budget = terminalWidth - (count + 1) - count * 2;
|
|
192
|
-
while (widths.reduce((sum, width) => sum + width, 0) > Math.max(count, budget)) {
|
|
193
|
-
const widest = widths.indexOf(Math.max(...widths));
|
|
194
|
-
if (widths[widest] <= 3)
|
|
195
|
-
break;
|
|
196
|
-
widths[widest] -= 1;
|
|
197
|
-
}
|
|
198
|
-
const cell = (text, width) => {
|
|
199
|
-
const clipped = visibleWidth(text) > width ? `${sliceToWidth(text, Math.max(0, width - visibleWidth(glyphs.ellipsis)))}${glyphs.ellipsis}` : text;
|
|
200
|
-
return `${clipped}${" ".repeat(Math.max(0, width - visibleWidth(clipped)))}`;
|
|
201
|
-
};
|
|
202
|
-
const rule = (left, mid, right) => `${left}${widths.map((width) => border.horizontal.repeat(width + 2)).join(mid)}${right}`;
|
|
203
|
-
const row = (cells) => `${border.vertical} ${widths.map((width, index) => cell(cells[index] ?? "", width)).join(` ${border.vertical} `)} ${border.vertical}`;
|
|
204
|
-
return [
|
|
205
|
-
rule(border.topLeft, border.horizontal, border.topRight),
|
|
206
|
-
row(columns.map((header) => paint(header, DIM, options.depth))),
|
|
207
|
-
rule(border.teeLeft, border.cross, border.teeRight),
|
|
208
|
-
...rows.map((line) => row(line)),
|
|
209
|
-
rule(border.bottomLeft, border.horizontal, border.bottomRight)
|
|
210
|
-
].join(`
|
|
211
|
-
`);
|
|
212
|
-
}
|
|
213
|
-
function scrollPercent(offsetFromTop, contentLines, viewportHeight) {
|
|
214
|
-
const maxOffset = Math.max(0, contentLines - viewportHeight);
|
|
215
|
-
if (maxOffset === 0)
|
|
216
|
-
return 1;
|
|
217
|
-
return Math.max(0, Math.min(1, offsetFromTop / maxOffset));
|
|
218
|
-
}
|
|
219
|
-
function scrollIndicator(fraction) {
|
|
220
|
-
if (fraction >= 1)
|
|
221
|
-
return "Bot";
|
|
222
|
-
if (fraction <= 0)
|
|
223
|
-
return "Top";
|
|
224
|
-
return `${Math.round(fraction * 100)}%`;
|
|
225
|
-
}
|
|
226
|
-
function paginator(current, total, options = {}) {
|
|
227
|
-
const count = Math.max(1, Math.floor(total));
|
|
228
|
-
const index = Math.max(0, Math.min(Math.floor(current), count - 1));
|
|
229
|
-
if (options.style === "dots") {
|
|
230
|
-
const glyphs = options.glyphs ?? UNICODE_GLYPHS;
|
|
231
|
-
return Array.from({ length: count }, (_, position) => position === index ? glyphs.bullet : glyphs.middot).join(" ");
|
|
232
|
-
}
|
|
233
|
-
return `${index + 1}/${count}`;
|
|
234
|
-
}
|
|
235
|
-
var VERBS = ["Thinking", "Reasoning", "Tracing", "Considering"];
|
|
236
|
-
function thinkingVerb(elapsedMs) {
|
|
237
|
-
return VERBS[Math.floor(Math.max(0, elapsedMs) / 6000) % VERBS.length];
|
|
238
|
-
}
|
|
239
|
-
function activityLabel(phase, operation, elapsedMs) {
|
|
240
|
-
if (phase === "thinking")
|
|
241
|
-
return thinkingVerb(elapsedMs);
|
|
242
|
-
switch (operation) {
|
|
243
|
-
case "read_file":
|
|
244
|
-
return "Reading file";
|
|
245
|
-
case "list_files":
|
|
246
|
-
case "glob_files":
|
|
247
|
-
case "grep_files":
|
|
248
|
-
return "Searching workspace";
|
|
249
|
-
case "write_file":
|
|
250
|
-
case "edit_file":
|
|
251
|
-
return "Editing workspace";
|
|
252
|
-
case "run_command":
|
|
253
|
-
return "Running command";
|
|
254
|
-
case "web_search":
|
|
255
|
-
return "Searching the web";
|
|
256
|
-
case "deep_research":
|
|
257
|
-
return "Researching in depth";
|
|
258
|
-
case "todo_write":
|
|
259
|
-
return "Updating plan";
|
|
260
|
-
default:
|
|
261
|
-
return "Running operation";
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
function stepProgress(done, total, options) {
|
|
265
|
-
const safeTotal = Math.max(0, Math.floor(Number.isFinite(total) ? total : 0));
|
|
266
|
-
const safeDone = Math.max(0, Math.min(safeTotal, Math.floor(Number.isFinite(done) ? done : 0)));
|
|
267
|
-
const counted = `${safeDone}/${safeTotal}`;
|
|
268
|
-
const label = options.label ? `${options.label} ` : "";
|
|
269
|
-
if (safeTotal === 0)
|
|
270
|
-
return `${label}${counted}`;
|
|
271
|
-
const width = Math.floor(options.width ?? 0);
|
|
272
|
-
if (width <= 0)
|
|
273
|
-
return `${label}${counted}`;
|
|
274
|
-
const bar = progressBar(safeDone / safeTotal, width, {
|
|
275
|
-
depth: options.depth,
|
|
276
|
-
glyphs: options.glyphs ?? UNICODE_GLYPHS,
|
|
277
|
-
...options.from ? { from: options.from } : {},
|
|
278
|
-
...options.to ? { to: options.to } : {}
|
|
279
|
-
});
|
|
280
|
-
return `${label}${counted} ${bar}`;
|
|
281
|
-
}
|
|
282
|
-
function formatStatusLine(fields, width, depth, glyphs = UNICODE_GLYPHS, accent = CYAN) {
|
|
283
|
-
const label = activityLabel(fields.phase ?? "thinking", fields.operation, fields.elapsedMs);
|
|
284
|
-
const ellipsis = glyphs.ellipsis;
|
|
285
|
-
const separator = ` ${glyphs.middot} `;
|
|
286
|
-
const left = `${fields.spinnerGlyph} ${label}${ellipsis}`;
|
|
287
|
-
const paintedLeft = `${paint(fields.spinnerGlyph, accent, depth)} ${paint(`${label}${ellipsis}`, DIM, depth)}`;
|
|
288
|
-
const optional = [
|
|
289
|
-
fields.cost,
|
|
290
|
-
fields.tokens > 0 ? formatTokens(fields.tokens) : "",
|
|
291
|
-
fields.toolCalls > 0 ? `${fields.toolCalls} tool${fields.toolCalls === 1 ? "" : "s"}` : "",
|
|
292
|
-
fields.badge ?? "",
|
|
293
|
-
fields.steps && fields.steps.total > 0 ? stepProgress(fields.steps.done, fields.steps.total, { label: fields.steps.label ?? "steps", depth: "none" }) : "",
|
|
294
|
-
fields.mode,
|
|
295
|
-
fields.balance ?? ""
|
|
296
|
-
].filter((segment) => segment !== "");
|
|
297
|
-
let kept = [...optional].reverse();
|
|
298
|
-
for (;; ) {
|
|
299
|
-
const right = [...kept, formatElapsed(fields.elapsedMs)].join(`${separator}`);
|
|
300
|
-
const total = visibleWidth(left) + 1 + right.length;
|
|
301
|
-
if (total <= width || kept.length === 0) {
|
|
302
|
-
if (total > width) {
|
|
303
|
-
if (visibleWidth(left) <= width)
|
|
304
|
-
return paintedLeft;
|
|
305
|
-
const compact = `${fields.spinnerGlyph} ${ellipsis}`;
|
|
306
|
-
if (visibleWidth(compact) <= width)
|
|
307
|
-
return `${paint(fields.spinnerGlyph, accent, depth)} ${paint(ellipsis, DIM, depth)}`;
|
|
308
|
-
return width > 0 ? paint(glyphs.star, accent, depth) : "";
|
|
309
|
-
}
|
|
310
|
-
const gap = Math.max(1, width - visibleWidth(left) - right.length);
|
|
311
|
-
return `${paintedLeft}${" ".repeat(gap)}${paint(right, DIM, depth)}`;
|
|
312
|
-
}
|
|
313
|
-
kept = kept.slice(0, -1);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
function rowsOccupied(text, columns) {
|
|
317
|
-
const width = visibleWidth(text);
|
|
318
|
-
if (width === 0)
|
|
319
|
-
return 1;
|
|
320
|
-
return Math.ceil(width / Math.max(1, columns));
|
|
321
|
-
}
|
|
322
|
-
class MarkdownStream {
|
|
323
|
-
stream;
|
|
324
|
-
depth;
|
|
325
|
-
columns;
|
|
326
|
-
live;
|
|
327
|
-
glyphs;
|
|
328
|
-
pending = "";
|
|
329
|
-
atLineStart = true;
|
|
330
|
-
state = newMarkdownState();
|
|
331
|
-
constructor(stream = terminalStream, depth = "none", columns = () => process.stdout.columns ?? 80, live = true, glyphs = UNICODE_GLYPHS) {
|
|
332
|
-
this.stream = stream;
|
|
333
|
-
this.depth = depth;
|
|
334
|
-
this.columns = columns;
|
|
335
|
-
this.live = live;
|
|
336
|
-
this.glyphs = glyphs;
|
|
337
|
-
}
|
|
338
|
-
get active() {
|
|
339
|
-
return this.live ? this.pending !== "" : !this.atLineStart;
|
|
340
|
-
}
|
|
341
|
-
push(text) {
|
|
342
|
-
if (!this.live) {
|
|
343
|
-
if (text === "")
|
|
344
|
-
return;
|
|
345
|
-
this.stream.write(text);
|
|
346
|
-
this.atLineStart = text.endsWith(`
|
|
347
|
-
`);
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
const parts = text.split(`
|
|
351
|
-
`);
|
|
352
|
-
for (let index = 0;index < parts.length; index += 1) {
|
|
353
|
-
if (index > 0)
|
|
354
|
-
this.finalizeLine();
|
|
355
|
-
if (parts[index] !== "") {
|
|
356
|
-
this.pending += parts[index];
|
|
357
|
-
this.stream.write(parts[index]);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
end() {
|
|
362
|
-
if (!this.live) {
|
|
363
|
-
if (!this.atLineStart) {
|
|
364
|
-
this.stream.write(`
|
|
365
|
-
`);
|
|
366
|
-
this.atLineStart = true;
|
|
367
|
-
}
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
if (this.pending !== "")
|
|
371
|
-
this.finalizeLine();
|
|
372
|
-
if (this.state.inFence) {
|
|
373
|
-
const rendered = renderMarkdownLine("```", this.state, { width: this.columns(), depth: this.depth, glyphs: this.glyphs });
|
|
374
|
-
this.stream.write(`${rendered.join(`
|
|
375
|
-
`)}
|
|
376
|
-
`);
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
reset() {
|
|
380
|
-
this.pending = "";
|
|
381
|
-
this.atLineStart = true;
|
|
382
|
-
this.state = newMarkdownState();
|
|
383
|
-
}
|
|
384
|
-
finalizeLine() {
|
|
385
|
-
this.erasePending();
|
|
386
|
-
const rendered = renderMarkdownLine(this.pending, this.state, { width: this.columns(), depth: this.depth, glyphs: this.glyphs });
|
|
387
|
-
this.stream.write(`${rendered.join(`
|
|
388
|
-
`)}
|
|
389
|
-
`);
|
|
390
|
-
this.pending = "";
|
|
391
|
-
}
|
|
392
|
-
erasePending() {
|
|
393
|
-
if (this.pending === "")
|
|
394
|
-
return;
|
|
395
|
-
const rows = rowsOccupied(this.pending, this.columns());
|
|
396
|
-
this.stream.write("\r\x1B[2K");
|
|
397
|
-
for (let index = 1;index < rows; index += 1)
|
|
398
|
-
this.stream.write("\x1B[1A\x1B[2K");
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
function box(lines, options) {
|
|
402
|
-
const terminalWidth = options.width ?? process.stdout.columns ?? 80;
|
|
403
|
-
const glyphs = options.glyphs ?? UNICODE_GLYPHS;
|
|
404
|
-
const border = borderGlyphsFor(options.borderStyle ?? "round", glyphs);
|
|
405
|
-
const titleWidth = options.title ? visibleWidth(options.title) : 0;
|
|
406
|
-
const titlePaint = TONE_CODES[options.titleColor ?? "cyan"];
|
|
407
|
-
const rainbowBorder = options.borderColor === "rainbow";
|
|
408
|
-
const edge = (text, phase = 0) => {
|
|
409
|
-
if (options.borderColor === undefined)
|
|
410
|
-
return text;
|
|
411
|
-
return rainbowBorder ? rainbowText(text, options.depth, phase) : paint(text, TONE_CODES[options.borderColor], options.depth);
|
|
412
|
-
};
|
|
413
|
-
const contentWidth = Math.min(Math.max(titleWidth, ...lines.map((line) => visibleWidth(line)), 1), Math.max(1, terminalWidth - 4));
|
|
414
|
-
const horizontal = border.horizontal.repeat(contentWidth + 2);
|
|
415
|
-
const top = options.title ? `${edge(`${border.topLeft}${border.horizontal}`, 0)} ${paint(options.title, titlePaint, options.depth)} ${edge(`${border.horizontal.repeat(Math.max(0, contentWidth - titleWidth - 1))}${border.topRight}`, 0.08)}` : edge(`${border.topLeft}${horizontal}${border.topRight}`, 0);
|
|
416
|
-
const bottomPhase = (lines.length + 1) * 0.1;
|
|
417
|
-
const bottom = edge(`${border.bottomLeft}${horizontal}${border.bottomRight}`, bottomPhase);
|
|
418
|
-
const body = lines.map((line, index) => {
|
|
419
|
-
const clipped = visibleWidth(line) > contentWidth ? `${sliceToWidth(line, contentWidth - visibleWidth(glyphs.ellipsis))}${glyphs.ellipsis}` : line;
|
|
420
|
-
const rowPhase = (index + 1) * 0.1;
|
|
421
|
-
return `${edge(border.vertical, rowPhase)} ${clipped}${" ".repeat(Math.max(0, contentWidth - visibleWidth(clipped)))} ${edge(border.vertical, rowPhase)}`;
|
|
422
|
-
});
|
|
423
|
-
return [top, ...body, bottom].join(`
|
|
424
|
-
`);
|
|
425
|
-
}
|
|
426
|
-
function sliceToWidth(text, width) {
|
|
427
|
-
let taken = "";
|
|
428
|
-
let used = 0;
|
|
429
|
-
for (const token of text.match(/\x1b\[[0-9;]*m|[\s\S]/gu) ?? []) {
|
|
430
|
-
if (token.startsWith("\x1B")) {
|
|
431
|
-
taken += token;
|
|
432
|
-
continue;
|
|
433
|
-
}
|
|
434
|
-
const next = visibleWidth(token);
|
|
435
|
-
if (used + next > width)
|
|
436
|
-
break;
|
|
437
|
-
taken += token;
|
|
438
|
-
used += next;
|
|
439
|
-
}
|
|
440
|
-
return taken;
|
|
441
|
-
}
|
|
442
|
-
function padToWidth(text, width, align = "left") {
|
|
443
|
-
const size = visibleWidth(text);
|
|
444
|
-
if (size >= width)
|
|
445
|
-
return sliceToWidth(text, width);
|
|
446
|
-
const slack = width - size;
|
|
447
|
-
if (align === "right")
|
|
448
|
-
return " ".repeat(slack) + text;
|
|
449
|
-
if (align === "center")
|
|
450
|
-
return " ".repeat(Math.floor(slack / 2)) + text + " ".repeat(Math.ceil(slack / 2));
|
|
451
|
-
return text + " ".repeat(slack);
|
|
452
|
-
}
|
|
453
|
-
function joinHorizontal(left, right, options) {
|
|
454
|
-
const separator = options.separator ?? " ";
|
|
455
|
-
return `${padToWidth(left, options.leftWidth, options.leftAlign)}${separator}${padToWidth(right, options.rightWidth, options.rightAlign)}`;
|
|
456
|
-
}
|
|
457
|
-
var TONE_CODES = { cyan: CYAN, green: GREEN, yellow: YELLOW, red: RED };
|
|
458
|
-
var MODE_COLORS = { plan: YELLOW, auto: GREEN, build: CYAN, defender: RED };
|
|
459
|
-
var PROMPT_CHROME_COLUMNS = 6;
|
|
460
|
-
function renderPromptBox(options) {
|
|
461
|
-
const { mode, workspace, depth } = options;
|
|
462
|
-
const glyphs = options.glyphs ?? UNICODE_GLYPHS;
|
|
463
|
-
const border = borderGlyphsFor(options.palette?.borderStyle ?? options.borderStyle ?? "round", glyphs);
|
|
464
|
-
const width = Math.max(12, options.width);
|
|
465
|
-
const primary = options.palette?.primary ?? CYAN;
|
|
466
|
-
const modeColor = options.palette ? { plan: options.palette.warning, auto: options.palette.success, build: primary, defender: options.palette.error }[mode] ?? primary : MODE_COLORS[mode] ?? CYAN;
|
|
467
|
-
const horizontal = (count) => paint(border.horizontal.repeat(Math.max(0, count)), primary, depth);
|
|
468
|
-
const CHROME = PROMPT_CHROME_COLUMNS;
|
|
469
|
-
const status = options.status ?? "";
|
|
470
|
-
const separator = ` ${glyphs.middot} `;
|
|
471
|
-
const full = `${paint(glyphs.star, primary, depth)} ${paint("archymedes", primary, depth)}${separator}${paint(mode, modeColor, depth)}`;
|
|
472
|
-
const compact = `${paint(glyphs.star, primary, depth)} ${paint(mode, modeColor, depth)}`;
|
|
473
|
-
const statusRoom = status === "" ? 0 : visibleWidth(status) + 2;
|
|
474
|
-
const showStatus = status !== "" && width - CHROME - 1 - statusRoom - visibleWidth(compact) >= 0;
|
|
475
|
-
const room = width - CHROME - 1 - (showStatus ? statusRoom : 0);
|
|
476
|
-
const workspaceRoom = room - visibleWidth(full) - visibleWidth(separator);
|
|
477
|
-
let title;
|
|
478
|
-
if (workspaceRoom >= 4) {
|
|
479
|
-
const shown = visibleWidth(workspace) <= workspaceRoom ? workspace : `${sliceToWidth(workspace, Math.max(0, workspaceRoom - visibleWidth(glyphs.ellipsis)))}${glyphs.ellipsis}`;
|
|
480
|
-
title = `${full}${separator}${paint(shown, DIM, depth)}`;
|
|
481
|
-
} else if (visibleWidth(full) <= room)
|
|
482
|
-
title = full;
|
|
483
|
-
else if (visibleWidth(compact) <= room)
|
|
484
|
-
title = compact;
|
|
485
|
-
else
|
|
486
|
-
title = paint(glyphs.star, primary, depth);
|
|
487
|
-
const tail = showStatus ? ` ${status} ` : "";
|
|
488
|
-
const filler = Math.max(1, width - visibleWidth(title) - visibleWidth(tail) - CHROME);
|
|
489
|
-
const top = `${paint(`${border.topLeft}${border.horizontal}`, primary, depth)} ${title} ${horizontal(filler)}${tail}${horizontal(1)}${paint(border.topRight, primary, depth)}`;
|
|
490
|
-
const prefix = `${paint(border.vertical, primary, depth)} ${paint(glyphs.caret, modeColor, depth)} `;
|
|
491
|
-
const bottom = `${paint(border.bottomLeft, primary, depth)}${horizontal(width - 2)}${paint(border.bottomRight, primary, depth)}`;
|
|
492
|
-
return { top, prefix, bottom };
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
export { terminalStream, archymedesSpinnerFrame, SpringAnimator, sparkline, progressBar, table, scrollPercent, scrollIndicator, paginator, stepProgress, formatStatusLine, rowsOccupied, box, sliceToWidth, padToWidth, joinHorizontal, renderPromptBox };
|