archymedes-cli 2.3.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/dist/{archymedes-aj30app4.mjs → archymedes-06fh0z84.mjs} +370 -159
- package/dist/{archymedes-d5wqcmdr.mjs → archymedes-0jxzsh4z.mjs} +97 -97
- package/dist/archymedes-130jt0wr.mjs +1231 -0
- package/dist/{archymedes-twbks7g3.mjs → archymedes-138genyy.mjs} +214 -5
- package/dist/{archymedes-h13ap0za.mjs → archymedes-1g1y6q74.mjs} +1 -1
- package/dist/{archymedes-dz59nvw7.mjs → archymedes-2kvjaajw.mjs} +21 -11
- package/dist/{archymedes-g8y3rt6t.mjs → archymedes-5vhvv8kr.mjs} +332 -9
- package/dist/{archymedes-4kx65anz.mjs → archymedes-a3ms7jvr.mjs} +43 -12
- package/dist/{archymedes-tsne2m7p.mjs → archymedes-bmtdqqwt.mjs} +2 -2
- package/dist/{archymedes-sf9t1hz9.mjs → archymedes-d3azqkay.mjs} +176 -77
- package/dist/archymedes-main.mjs +31312 -28352
- package/dist/archymedes-w4bjfye7.mjs +280 -0
- package/dist/{editor-screen-g08zzt70.mjs → editor-screen-e01mn7dd.mjs} +49 -14
- package/dist/{factory-7vtm2fed.mjs → factory-hyv8agr0.mjs} +326 -326
- package/dist/{file-screen-ma9yxq2b.mjs → file-screen-stcxznwy.mjs} +11 -9
- package/dist/{guide-screen-gd129txd.mjs → guide-screen-w5nb9sry.mjs} +10 -8
- package/dist/{index-qvgcwsvm.mjs → index-teq1cta4.mjs} +1 -1
- package/dist/{node-mdgzx68h.mjs → node-0fh63p8z.mjs} +7 -7
- package/dist/pager-screen-aamt6xv0.mjs +155 -0
- package/dist/projection-x6x6hm9t.mjs +248 -0
- package/dist/{sandbox-templates-9jcjws23.mjs → sandbox-templates-8sd1psez.mjs} +2 -2
- package/dist/workspace-screen-62k6hnq7.mjs +70 -0
- package/package.json +2 -2
- package/dist/archymedes-a10k8yrk.mjs +0 -464
- package/dist/workspace-screen-8cwk6jz9.mjs +0 -241
|
@@ -7,14 +7,17 @@ import {
|
|
|
7
7
|
STRIKE,
|
|
8
8
|
UNICODE_GLYPHS,
|
|
9
9
|
borderGlyphsFor,
|
|
10
|
+
codeStyle,
|
|
11
|
+
highlightSyntax,
|
|
12
|
+
newSyntaxState,
|
|
10
13
|
paint,
|
|
11
14
|
rainbowText,
|
|
12
15
|
rgbTo256,
|
|
13
16
|
roleCode,
|
|
14
17
|
visibleWidth
|
|
15
|
-
} from "./archymedes-
|
|
18
|
+
} from "./archymedes-130jt0wr.mjs";
|
|
16
19
|
|
|
17
|
-
// src/terminal/output.ts
|
|
20
|
+
// packages/archymedes-cli/src/terminal/output.ts
|
|
18
21
|
var terminalStream = {
|
|
19
22
|
write(text) {
|
|
20
23
|
process.stdout.write(text);
|
|
@@ -26,6 +29,90 @@ var terminalStream = {
|
|
|
26
29
|
return process.stdout.rows;
|
|
27
30
|
}
|
|
28
31
|
};
|
|
32
|
+
var DEFAULT_SCROLLBACK_LINES = 5000;
|
|
33
|
+
|
|
34
|
+
class LineLog {
|
|
35
|
+
limit;
|
|
36
|
+
committed = [];
|
|
37
|
+
partial = "";
|
|
38
|
+
droppedLines = 0;
|
|
39
|
+
constructor(limit = DEFAULT_SCROLLBACK_LINES) {
|
|
40
|
+
this.limit = limit;
|
|
41
|
+
}
|
|
42
|
+
write(text) {
|
|
43
|
+
if (text === "")
|
|
44
|
+
return;
|
|
45
|
+
const parts = (this.partial + text).split(`
|
|
46
|
+
`);
|
|
47
|
+
this.partial = parts.pop() ?? "";
|
|
48
|
+
for (const line of parts)
|
|
49
|
+
this.commit(line);
|
|
50
|
+
}
|
|
51
|
+
commit(line) {
|
|
52
|
+
this.committed.push(line);
|
|
53
|
+
if (this.committed.length > this.limit) {
|
|
54
|
+
this.committed.shift();
|
|
55
|
+
this.droppedLines += 1;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
flush() {
|
|
59
|
+
if (this.partial === "")
|
|
60
|
+
return;
|
|
61
|
+
this.commit(this.partial);
|
|
62
|
+
this.partial = "";
|
|
63
|
+
}
|
|
64
|
+
get lines() {
|
|
65
|
+
return this.committed;
|
|
66
|
+
}
|
|
67
|
+
get pending() {
|
|
68
|
+
return this.partial;
|
|
69
|
+
}
|
|
70
|
+
get size() {
|
|
71
|
+
return this.committed.length;
|
|
72
|
+
}
|
|
73
|
+
get dropped() {
|
|
74
|
+
return this.droppedLines;
|
|
75
|
+
}
|
|
76
|
+
tail(count) {
|
|
77
|
+
return count <= 0 ? [] : this.committed.slice(Math.max(0, this.committed.length - count));
|
|
78
|
+
}
|
|
79
|
+
clear() {
|
|
80
|
+
this.committed.length = 0;
|
|
81
|
+
this.partial = "";
|
|
82
|
+
this.droppedLines = 0;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
class TabSink {
|
|
87
|
+
downstream;
|
|
88
|
+
log;
|
|
89
|
+
live;
|
|
90
|
+
constructor(downstream = terminalStream, options = {}) {
|
|
91
|
+
this.downstream = downstream;
|
|
92
|
+
this.live = options.live ?? false;
|
|
93
|
+
this.log = new LineLog(options.limit);
|
|
94
|
+
}
|
|
95
|
+
get isLive() {
|
|
96
|
+
return this.live;
|
|
97
|
+
}
|
|
98
|
+
setLive(live) {
|
|
99
|
+
if (!live)
|
|
100
|
+
this.log.flush();
|
|
101
|
+
this.live = live;
|
|
102
|
+
}
|
|
103
|
+
write(text) {
|
|
104
|
+
this.log.write(text);
|
|
105
|
+
if (this.live)
|
|
106
|
+
this.downstream.write(text);
|
|
107
|
+
}
|
|
108
|
+
get columns() {
|
|
109
|
+
return this.downstream.columns;
|
|
110
|
+
}
|
|
111
|
+
get rows() {
|
|
112
|
+
return this.downstream.rows;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
29
116
|
class OutputRouter {
|
|
30
117
|
target;
|
|
31
118
|
constructor(target = terminalStream) {
|
|
@@ -52,7 +139,7 @@ function replayLines(log, count) {
|
|
|
52
139
|
return { lines, dropped: log.dropped, omitted: Math.max(0, log.size - lines.length) };
|
|
53
140
|
}
|
|
54
141
|
|
|
55
|
-
// src/render/markdown.ts
|
|
142
|
+
// packages/archymedes-cli/src/render/markdown.ts
|
|
56
143
|
var colour = (role, palette) => palette?.[role] || ANSI_PALETTE[role];
|
|
57
144
|
var INLINE_PATTERN = /(?<!\\)(`[^`\n]+`)|(?<!\\)(\*\*[^*\n]+\*\*)|(?<!\\)(__[^_\n]+__)|(?<!\\)(~~[^~\n]+~~)|(?<!\\)(\*[^*\n]+\*)|(?<!\\)(_[^_\n]+_)|(!?\[([^\]\n]+)\]\((https?:\/\/[^\s)\n]+)\))|(<(https?:\/\/[^>\s]+)>)/g;
|
|
58
145
|
var unescapeMarkdown = (text) => text.replace(/\\([\\`*_[\]{}()#+.!~>-])/g, "$1");
|
|
@@ -142,7 +229,7 @@ function wrapTokens(tokens, width, options) {
|
|
|
142
229
|
return lines;
|
|
143
230
|
}
|
|
144
231
|
function newMarkdownState() {
|
|
145
|
-
return { inFence: false, fenceLanguage: "" };
|
|
232
|
+
return { inFence: false, fenceLanguage: "", fenceLine: 0, fenceSyntax: newSyntaxState() };
|
|
146
233
|
}
|
|
147
234
|
var HEADING = /^(#{1,6})\s+(.*)$/;
|
|
148
235
|
var BULLET = /^(\s*)([-*+])\s+(.*)$/;
|
|
@@ -189,16 +276,24 @@ function renderMarkdownLine(line, state, options) {
|
|
|
189
276
|
if (state.inFence) {
|
|
190
277
|
state.inFence = false;
|
|
191
278
|
state.fenceLanguage = "";
|
|
279
|
+
state.fenceLine = 0;
|
|
280
|
+
state.fenceSyntax = newSyntaxState();
|
|
192
281
|
return [paint(` ${glyphs.boxBottomLeft}${glyphs.boxHorizontal.repeat(ruleWidth)}`, DIM, depth)];
|
|
193
282
|
}
|
|
194
283
|
state.inFence = true;
|
|
195
284
|
state.fenceLanguage = fence[1].trim();
|
|
285
|
+
state.fenceLine = 0;
|
|
286
|
+
state.fenceSyntax = newSyntaxState();
|
|
196
287
|
const label = state.fenceLanguage ? ` ${state.fenceLanguage} ` : "";
|
|
197
288
|
const drawn = 1 + visibleWidth(label);
|
|
198
|
-
return [paint(` ${glyphs.boxTopLeft}${glyphs.boxHorizontal}${label}${glyphs.boxHorizontal.repeat(Math.max(0, ruleWidth - drawn))
|
|
289
|
+
return [`${paint(` ${glyphs.boxTopLeft}${glyphs.boxHorizontal}`, DIM, depth)}${label ? paint(label, `${BOLD}${colour("primary", palette)}`, depth) : ""}${paint(glyphs.boxHorizontal.repeat(Math.max(0, ruleWidth - drawn)), DIM, depth)}`];
|
|
199
290
|
}
|
|
200
291
|
if (state.inFence) {
|
|
201
|
-
|
|
292
|
+
state.fenceLine += 1;
|
|
293
|
+
const style = codeStyle();
|
|
294
|
+
const number = style.lineNumbers ? `${paint(String(state.fenceLine).padStart(3), DIM, depth)} ` : "";
|
|
295
|
+
const code = style.colors === "vscode" ? highlightSyntax(line, { language: state.fenceLanguage, depth, palette, state: state.fenceSyntax }) : paint(line, colour("success", palette), depth);
|
|
296
|
+
return [`${paint(` ${glyphs.boxVertical} `, DIM, depth)}${number}${code}`];
|
|
202
297
|
}
|
|
203
298
|
const table = tableCells(line);
|
|
204
299
|
if (table) {
|
|
@@ -265,12 +360,107 @@ function renderMarkdown(text, options) {
|
|
|
265
360
|
`);
|
|
266
361
|
}
|
|
267
362
|
|
|
268
|
-
// src/render/tui.ts
|
|
363
|
+
// packages/archymedes-cli/src/render/tui.ts
|
|
269
364
|
function archymedesSpinnerFrame(index, glyphs = UNICODE_GLYPHS) {
|
|
270
365
|
const frames = glyphs.spinnerFrames;
|
|
271
366
|
const normalized = Number.isFinite(index) ? Math.max(0, Math.floor(index)) : 0;
|
|
272
367
|
return frames[normalized % frames.length];
|
|
273
368
|
}
|
|
369
|
+
|
|
370
|
+
class Spinner {
|
|
371
|
+
onTick;
|
|
372
|
+
intervalMs;
|
|
373
|
+
glyphs;
|
|
374
|
+
delayMs;
|
|
375
|
+
frame = 0;
|
|
376
|
+
timer;
|
|
377
|
+
delay;
|
|
378
|
+
constructor(onTick, intervalMs = 120, glyphs = UNICODE_GLYPHS, delayMs = 0) {
|
|
379
|
+
this.onTick = onTick;
|
|
380
|
+
this.intervalMs = intervalMs;
|
|
381
|
+
this.glyphs = glyphs;
|
|
382
|
+
this.delayMs = delayMs;
|
|
383
|
+
}
|
|
384
|
+
start() {
|
|
385
|
+
if (this.timer || this.delay)
|
|
386
|
+
return;
|
|
387
|
+
const begin = () => {
|
|
388
|
+
this.delay = undefined;
|
|
389
|
+
this.onTick();
|
|
390
|
+
this.timer = setInterval(() => {
|
|
391
|
+
this.frame = (this.frame + 1) % this.glyphs.spinnerFrames.length;
|
|
392
|
+
this.onTick();
|
|
393
|
+
}, this.intervalMs);
|
|
394
|
+
};
|
|
395
|
+
if (this.delayMs <= 0)
|
|
396
|
+
begin();
|
|
397
|
+
else
|
|
398
|
+
this.delay = setTimeout(begin, this.delayMs);
|
|
399
|
+
}
|
|
400
|
+
stop() {
|
|
401
|
+
if (this.delay) {
|
|
402
|
+
clearTimeout(this.delay);
|
|
403
|
+
this.delay = undefined;
|
|
404
|
+
}
|
|
405
|
+
if (!this.timer)
|
|
406
|
+
return;
|
|
407
|
+
clearInterval(this.timer);
|
|
408
|
+
this.timer = undefined;
|
|
409
|
+
}
|
|
410
|
+
get glyph() {
|
|
411
|
+
return archymedesSpinnerFrame(this.frame, this.glyphs);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
function formatCountdown(remainingMs) {
|
|
415
|
+
const totalSeconds = Math.max(0, Math.ceil(remainingMs / 1000));
|
|
416
|
+
if (totalSeconds < 60)
|
|
417
|
+
return `${totalSeconds}s`;
|
|
418
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
419
|
+
const seconds = totalSeconds % 60;
|
|
420
|
+
return `${minutes}m ${String(seconds).padStart(2, "0")}s`;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
class CountdownTimer {
|
|
424
|
+
onTick;
|
|
425
|
+
onDone;
|
|
426
|
+
intervalMs;
|
|
427
|
+
timer;
|
|
428
|
+
endsAt;
|
|
429
|
+
constructor(durationMs, onTick, onDone, intervalMs = 1000) {
|
|
430
|
+
this.onTick = onTick;
|
|
431
|
+
this.onDone = onDone;
|
|
432
|
+
this.intervalMs = intervalMs;
|
|
433
|
+
this.endsAt = Date.now() + Math.max(0, durationMs);
|
|
434
|
+
}
|
|
435
|
+
get remaining() {
|
|
436
|
+
return Math.max(0, this.endsAt - Date.now());
|
|
437
|
+
}
|
|
438
|
+
start() {
|
|
439
|
+
if (this.timer)
|
|
440
|
+
return;
|
|
441
|
+
if (this.remaining <= 0) {
|
|
442
|
+
this.onDone();
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
this.onTick(this.remaining);
|
|
446
|
+
this.timer = setInterval(() => {
|
|
447
|
+
const left = this.remaining;
|
|
448
|
+
if (left <= 0) {
|
|
449
|
+
this.stop();
|
|
450
|
+
this.onDone();
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
this.onTick(left);
|
|
454
|
+
}, this.intervalMs);
|
|
455
|
+
}
|
|
456
|
+
stop() {
|
|
457
|
+
if (!this.timer)
|
|
458
|
+
return;
|
|
459
|
+
clearInterval(this.timer);
|
|
460
|
+
this.timer = undefined;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
274
464
|
class Spring {
|
|
275
465
|
angularFrequency;
|
|
276
466
|
dampingRatio;
|
|
@@ -355,6 +545,21 @@ class SpringAnimator {
|
|
|
355
545
|
this.timer = undefined;
|
|
356
546
|
}
|
|
357
547
|
}
|
|
548
|
+
function formatHeaderSegments(segments, width, separator = " · ") {
|
|
549
|
+
const limit = Math.max(0, Math.floor(width));
|
|
550
|
+
if (limit === 0 || segments.length === 0)
|
|
551
|
+
return "";
|
|
552
|
+
let kept = [...segments];
|
|
553
|
+
while (kept.length > 0) {
|
|
554
|
+
const rendered = kept.map((segment) => segment.full).join(separator);
|
|
555
|
+
if (visibleWidth(rendered) <= limit)
|
|
556
|
+
return rendered;
|
|
557
|
+
kept = kept.slice(0, -1);
|
|
558
|
+
}
|
|
559
|
+
const first = segments[0];
|
|
560
|
+
const compact = first.compact ?? first.full;
|
|
561
|
+
return visibleWidth(compact) <= limit ? compact : "";
|
|
562
|
+
}
|
|
358
563
|
function formatElapsed(ms) {
|
|
359
564
|
const seconds = ms / 1000;
|
|
360
565
|
return seconds < 60 ? `${seconds.toFixed(1)}s` : `${Math.floor(seconds / 60)}m ${Math.round(seconds % 60)}s`;
|
|
@@ -525,6 +730,7 @@ function formatStatusLine(fields, width, depth, glyphs = UNICODE_GLYPHS, accent
|
|
|
525
730
|
fields.toolCalls > 0 ? `${fields.toolCalls} tool${fields.toolCalls === 1 ? "" : "s"}` : "",
|
|
526
731
|
fields.badge ?? "",
|
|
527
732
|
fields.steps && fields.steps.total > 0 ? stepProgress(fields.steps.done, fields.steps.total, { label: fields.steps.label ?? "steps", depth: "none" }) : "",
|
|
733
|
+
fields.allowance?.text ?? "",
|
|
528
734
|
fields.mode,
|
|
529
735
|
fields.balance ?? ""
|
|
530
736
|
].filter((segment) => segment !== "");
|
|
@@ -542,7 +748,9 @@ function formatStatusLine(fields, width, depth, glyphs = UNICODE_GLYPHS, accent
|
|
|
542
748
|
return width > 0 ? paint(glyphs.star, accent, depth) : "";
|
|
543
749
|
}
|
|
544
750
|
const gap = Math.max(1, width - visibleWidth(left) - right.length);
|
|
545
|
-
|
|
751
|
+
const warned = fields.allowance?.warning ? fields.allowance.text : undefined;
|
|
752
|
+
const paintedRight = warned && kept.includes(warned) ? [...kept, formatElapsed(fields.elapsedMs)].map((segment) => paint(segment, segment === warned ? roleCode("warning", undefined, depth) : DIM, depth)).join(paint(separator, DIM, depth)) : paint(right, DIM, depth);
|
|
753
|
+
return `${paintedLeft}${" ".repeat(gap)}${paintedRight}`;
|
|
546
754
|
}
|
|
547
755
|
kept = kept.slice(0, -1);
|
|
548
756
|
}
|
|
@@ -778,7 +986,12 @@ function joinHorizontal(left, right, options) {
|
|
|
778
986
|
}
|
|
779
987
|
var TONE_ROLE = { cyan: "primary", green: "success", yellow: "warning", red: "error" };
|
|
780
988
|
var MODE_ROLE = { plan: "warning", auto: "success", build: "primary", defender: "error" };
|
|
989
|
+
var PROMPT_PREFIX_COLUMNS = 4;
|
|
781
990
|
var PROMPT_CHROME_COLUMNS = 6;
|
|
991
|
+
function promptStatusRoom(mode, workspace, width, glyphs = UNICODE_GLYPHS) {
|
|
992
|
+
const compactTitle = `${glyphs.star} ${mode}`;
|
|
993
|
+
return Math.max(0, Math.max(12, width) - visibleWidth(compactTitle) - PROMPT_CHROME_COLUMNS - 3);
|
|
994
|
+
}
|
|
782
995
|
function renderPromptBox(options) {
|
|
783
996
|
const { mode, workspace, depth } = options;
|
|
784
997
|
const glyphs = options.glyphs ?? UNICODE_GLYPHS;
|
|
@@ -813,6 +1026,116 @@ function renderPromptBox(options) {
|
|
|
813
1026
|
const bottom = `${paint(border.bottomLeft, primary, depth)}${horizontal(width - 2)}${paint(border.bottomRight, primary, depth)}`;
|
|
814
1027
|
return { top, prefix, bottom };
|
|
815
1028
|
}
|
|
1029
|
+
function dropupPaintInPlace(lines) {
|
|
1030
|
+
if (lines.length === 0)
|
|
1031
|
+
return "";
|
|
1032
|
+
const parts = ["\x1B7\x1B[?25l", `\x1B[${lines.length + 1}A`];
|
|
1033
|
+
for (const line of lines)
|
|
1034
|
+
parts.push(`\r\x1B[2K${line}\x1B[1B`);
|
|
1035
|
+
parts.push("\x1B8\x1B[?25h");
|
|
1036
|
+
return parts.join("");
|
|
1037
|
+
}
|
|
1038
|
+
function dropupEraseBlock(currentRows) {
|
|
1039
|
+
return `\x1B[?25l\x1B[${currentRows + 1}A\r\x1B[0J`;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
class PromptBox {
|
|
1043
|
+
stream;
|
|
1044
|
+
options;
|
|
1045
|
+
drawn = false;
|
|
1046
|
+
borderCleared = false;
|
|
1047
|
+
suggestions = [];
|
|
1048
|
+
constructor(stream = terminalStream, options = { depth: "none" }) {
|
|
1049
|
+
this.stream = stream;
|
|
1050
|
+
this.options = options;
|
|
1051
|
+
}
|
|
1052
|
+
get isDrawn() {
|
|
1053
|
+
return this.drawn;
|
|
1054
|
+
}
|
|
1055
|
+
get width() {
|
|
1056
|
+
return Math.max(1, this.options.columns?.() ?? this.stream.columns ?? 80);
|
|
1057
|
+
}
|
|
1058
|
+
draw(mode, workspace, status) {
|
|
1059
|
+
const { prefix } = this.paintBlock(mode, workspace, status);
|
|
1060
|
+
this.drawn = true;
|
|
1061
|
+
this.borderCleared = false;
|
|
1062
|
+
return prefix;
|
|
1063
|
+
}
|
|
1064
|
+
paintBlock(mode, workspace, status) {
|
|
1065
|
+
const { top, prefix, bottom } = renderPromptBox({
|
|
1066
|
+
mode,
|
|
1067
|
+
workspace,
|
|
1068
|
+
depth: this.options.depth,
|
|
1069
|
+
palette: this.options.palette?.(),
|
|
1070
|
+
width: this.width,
|
|
1071
|
+
...status === undefined ? {} : { status },
|
|
1072
|
+
...this.options.glyphs === undefined ? {} : { glyphs: this.options.glyphs },
|
|
1073
|
+
...this.options.borderStyle === undefined ? {} : { borderStyle: this.options.borderStyle }
|
|
1074
|
+
});
|
|
1075
|
+
for (const line of this.suggestions)
|
|
1076
|
+
this.stream.write(`${line}
|
|
1077
|
+
`);
|
|
1078
|
+
this.stream.write(`${top}
|
|
1079
|
+
`);
|
|
1080
|
+
this.stream.write(`
|
|
1081
|
+
${bottom}`);
|
|
1082
|
+
this.stream.write("\x1B[1A\r");
|
|
1083
|
+
return { prefix };
|
|
1084
|
+
}
|
|
1085
|
+
get suggestionRows() {
|
|
1086
|
+
return this.suggestions.length;
|
|
1087
|
+
}
|
|
1088
|
+
setSuggestions(lines, bar) {
|
|
1089
|
+
if (!this.drawn)
|
|
1090
|
+
return { moved: false };
|
|
1091
|
+
const next = [...lines];
|
|
1092
|
+
if (next.length === this.suggestions.length) {
|
|
1093
|
+
if (next.every((line, index) => line === this.suggestions[index]))
|
|
1094
|
+
return { moved: false };
|
|
1095
|
+
this.suggestions = next;
|
|
1096
|
+
if (next.length > 0)
|
|
1097
|
+
this.stream.write(dropupPaintInPlace(next));
|
|
1098
|
+
return { moved: false };
|
|
1099
|
+
}
|
|
1100
|
+
this.stream.write(dropupEraseBlock(this.suggestions.length));
|
|
1101
|
+
this.suggestions = next;
|
|
1102
|
+
this.paintBlock(bar.mode, bar.workspace, bar.status);
|
|
1103
|
+
this.stream.write("\x1B[?25h");
|
|
1104
|
+
this.borderCleared = false;
|
|
1105
|
+
return { moved: true };
|
|
1106
|
+
}
|
|
1107
|
+
restoreBottomBorder(mode, workspace, status) {
|
|
1108
|
+
if (!this.drawn || this.borderCleared)
|
|
1109
|
+
return;
|
|
1110
|
+
const { bottom } = renderPromptBox({
|
|
1111
|
+
mode,
|
|
1112
|
+
workspace,
|
|
1113
|
+
depth: this.options.depth,
|
|
1114
|
+
palette: this.options.palette?.(),
|
|
1115
|
+
width: this.width,
|
|
1116
|
+
...status === undefined ? {} : { status },
|
|
1117
|
+
...this.options.glyphs === undefined ? {} : { glyphs: this.options.glyphs },
|
|
1118
|
+
...this.options.borderStyle === undefined ? {} : { borderStyle: this.options.borderStyle }
|
|
1119
|
+
});
|
|
1120
|
+
this.stream.write(`\x1B7\x1B[?25l\x1B[1B\r\x1B[2K${bottom}\x1B8\x1B[?25h`);
|
|
1121
|
+
}
|
|
1122
|
+
erase(submitted) {
|
|
1123
|
+
if (!this.drawn)
|
|
1124
|
+
return;
|
|
1125
|
+
const rows = Math.floor((PROMPT_PREFIX_COLUMNS + visibleWidth(submitted) - 1) / this.width) + 3 + this.suggestions.length;
|
|
1126
|
+
for (let index = 0;index < rows; index += 1)
|
|
1127
|
+
this.stream.write("\x1B[1A\x1B[2K");
|
|
1128
|
+
this.suggestions = [];
|
|
1129
|
+
this.drawn = false;
|
|
1130
|
+
}
|
|
1131
|
+
dropBorder(remainder) {
|
|
1132
|
+
if (!this.drawn || this.borderCleared || remainder === "")
|
|
1133
|
+
return;
|
|
1134
|
+
this.stream.write("\r\x1B[2K");
|
|
1135
|
+
this.stream.write(remainder);
|
|
1136
|
+
this.borderCleared = true;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
816
1139
|
function wrapPlain(text, width) {
|
|
817
1140
|
const lines = [];
|
|
818
1141
|
let current = "";
|
|
@@ -843,4 +1166,4 @@ function wrapPlain(text, width) {
|
|
|
843
1166
|
return lines.length === 0 ? [""] : lines;
|
|
844
1167
|
}
|
|
845
1168
|
|
|
846
|
-
export { terminalStream, OutputRouter, replayLines,
|
|
1169
|
+
export { terminalStream, TabSink, OutputRouter, replayLines, renderMarkdown, archymedesSpinnerFrame, Spinner, formatCountdown, CountdownTimer, SpringAnimator, formatHeaderSegments, sparkline, progressBar, table, scrollPercent, scrollIndicator, paginator, stepProgress, formatStatusLine, StatusBar, rowsOccupied, ReplaceableBlock, MarkdownStream, box, sliceToWidth, padToWidth, joinHorizontal, PROMPT_PREFIX_COLUMNS, promptStatusRoom, renderPromptBox, PromptBox, wrapPlain };
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SpringAnimator,
|
|
3
3
|
paginator
|
|
4
|
-
} from "./archymedes-
|
|
4
|
+
} from "./archymedes-5vhvv8kr.mjs";
|
|
5
5
|
import {
|
|
6
6
|
UNICODE_GLYPHS,
|
|
7
7
|
clipTo,
|
|
8
8
|
visibleWidth
|
|
9
|
-
} from "./archymedes-
|
|
9
|
+
} from "./archymedes-130jt0wr.mjs";
|
|
10
10
|
|
|
11
|
-
// src/ui/chooser.ts
|
|
11
|
+
// packages/archymedes-cli/src/ui/chooser.ts
|
|
12
12
|
var ALL_CHROME = { title: true, status: true, pagination: true, help: true };
|
|
13
13
|
function chromeOf(chrome) {
|
|
14
14
|
return { ...ALL_CHROME, ...chrome };
|
|
@@ -50,6 +50,7 @@ function advanceChooser(state, items, input, options = {}) {
|
|
|
50
50
|
const last = Math.max(0, visible.length - 1);
|
|
51
51
|
const page = options.page ?? 8;
|
|
52
52
|
const clamp = (index) => Math.max(0, Math.min(last, index));
|
|
53
|
+
state = { ...state, selected: clamp(state.selected) };
|
|
53
54
|
const keep = state.chrome === undefined ? {} : { chrome: state.chrome };
|
|
54
55
|
if (name === "escape" && options.filter && state.query !== "")
|
|
55
56
|
return { state: { selected: 0, query: "", ...keep } };
|
|
@@ -122,7 +123,7 @@ function renderChooser(state, items, options) {
|
|
|
122
123
|
const fadingOut = !active && index === options.transitionFrom;
|
|
123
124
|
const number = offset < 9 ? `${offset + 1}.` : " ";
|
|
124
125
|
const furniture = visibleWidth(` ${active ? ">" : " "} ${number} `) + 2;
|
|
125
|
-
if (width < furniture) {
|
|
126
|
+
if (width < furniture + 1) {
|
|
126
127
|
lines.push(active ? paint.green(clip(`${glyphs.prompt}${item.label}`, width)) : clip(item.label, width));
|
|
127
128
|
continue;
|
|
128
129
|
}
|
|
@@ -142,7 +143,8 @@ function renderChooser(state, items, options) {
|
|
|
142
143
|
}
|
|
143
144
|
const position = visible.length > height && chrome.pagination ? ` ${paginator(state.selected, visible.length)}` : "";
|
|
144
145
|
if (chrome.help) {
|
|
145
|
-
|
|
146
|
+
const legend = options.legend !== undefined && options.filter && state.query !== "" ? options.legend.replace(/Esc\b[^·]*$/, "Esc clear filter") : options.legend;
|
|
147
|
+
lines.push(paint.dim(clip(` ${legend ?? `${glyphs.arrowUp}${glyphs.arrowDown} move ${glyphs.middot} Enter choose ${glyphs.middot} ${options.filter ? `type to filter ${glyphs.middot} ` : ""}${options.filter ? "Esc clear/back" : "Esc back"}`}${position}`, width)));
|
|
146
148
|
} else if (position) {
|
|
147
149
|
lines.push(paint.dim(clip(position, width)));
|
|
148
150
|
}
|
|
@@ -158,7 +160,9 @@ async function runChooser(keys, items, paint, options) {
|
|
|
158
160
|
const height = Math.max(1, Math.min(options.height ?? 10, size?.height ?? Number.POSITIVE_INFINITY));
|
|
159
161
|
return { ...options, width: size?.width ?? options.width, height };
|
|
160
162
|
};
|
|
161
|
-
|
|
163
|
+
let list = items;
|
|
164
|
+
let pendingDelete;
|
|
165
|
+
paint(renderChooser(state, list, liveOptions()));
|
|
162
166
|
let glide;
|
|
163
167
|
const settleGlide = () => {
|
|
164
168
|
glide?.stop();
|
|
@@ -166,9 +170,36 @@ async function runChooser(keys, items, paint, options) {
|
|
|
166
170
|
};
|
|
167
171
|
try {
|
|
168
172
|
for await (const input of keys) {
|
|
173
|
+
if (pendingDelete && options.onDelete) {
|
|
174
|
+
const target = pendingDelete;
|
|
175
|
+
pendingDelete = undefined;
|
|
176
|
+
if (input.str === "y" || input.str === "Y") {
|
|
177
|
+
const outcome = await options.onDelete(target);
|
|
178
|
+
if (outcome.deleted) {
|
|
179
|
+
list = list.filter((item) => item !== target);
|
|
180
|
+
const remaining = filterItems(list, state.query).length;
|
|
181
|
+
state = { ...state, selected: Math.max(0, Math.min(state.selected, remaining - 1)), status: `deleted "${target.label}"` };
|
|
182
|
+
} else {
|
|
183
|
+
state = { ...state, status: outcome.reason };
|
|
184
|
+
}
|
|
185
|
+
} else {
|
|
186
|
+
state = { ...state, status: "kept" };
|
|
187
|
+
}
|
|
188
|
+
paint(renderChooser(state, list, liveOptions()));
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (options.onDelete && (input.key.name === "delete" || input.key.ctrl && input.key.name === "d")) {
|
|
192
|
+
const target = filterItems(list, state.query)[state.selected];
|
|
193
|
+
if (target && !target.pinned) {
|
|
194
|
+
pendingDelete = target;
|
|
195
|
+
state = { ...state, status: `Delete "${target.label}"? y/n` };
|
|
196
|
+
paint(renderChooser(state, list, liveOptions()));
|
|
197
|
+
}
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
169
200
|
const current = liveOptions();
|
|
170
201
|
const previousSelected = state.selected;
|
|
171
|
-
const step = advanceChooser(state,
|
|
202
|
+
const step = advanceChooser(state, list, input, {
|
|
172
203
|
filter: options.filter ?? false,
|
|
173
204
|
page: options.page ?? current.height ?? 8,
|
|
174
205
|
...current.height === undefined ? {} : { height: current.height }
|
|
@@ -178,24 +209,24 @@ async function runChooser(keys, items, paint, options) {
|
|
|
178
209
|
settleGlide();
|
|
179
210
|
if (step.done.index === undefined)
|
|
180
211
|
return;
|
|
181
|
-
return filterItems(
|
|
212
|
+
return filterItems(list, state.query)[step.done.index]?.value;
|
|
182
213
|
}
|
|
183
214
|
settleGlide();
|
|
184
215
|
const isSingleStep = (input.key.name === "up" || input.key.name === "down") && Math.abs(state.selected - previousSelected) === 1;
|
|
185
216
|
const motion = options.motion ?? (process.env.ARCHYMEDES_NO_MOTION !== "1" && process.env.NO_COLOR === undefined && process.env.TERM !== "dumb");
|
|
186
217
|
if (!motion || !isSingleStep || previousSelected === state.selected) {
|
|
187
|
-
paint(renderChooser(state,
|
|
218
|
+
paint(renderChooser(state, list, liveOptions()));
|
|
188
219
|
continue;
|
|
189
220
|
}
|
|
190
|
-
paint(renderChooser(state,
|
|
221
|
+
paint(renderChooser(state, list, { ...liveOptions(), transitionFrom: previousSelected, focusProgress: 0 }));
|
|
191
222
|
const animator = new SpringAnimator(0, (value) => {
|
|
192
223
|
if (value < 0.95) {
|
|
193
|
-
paint(renderChooser(state,
|
|
224
|
+
paint(renderChooser(state, list, { ...liveOptions(), transitionFrom: value < 0.5 ? previousSelected : undefined, focusProgress: value }));
|
|
194
225
|
return;
|
|
195
226
|
}
|
|
196
227
|
animator.stop();
|
|
197
228
|
glide = undefined;
|
|
198
|
-
paint(renderChooser(state,
|
|
229
|
+
paint(renderChooser(state, list, liveOptions()));
|
|
199
230
|
}, { intervalMs: 30 });
|
|
200
231
|
glide = animator;
|
|
201
232
|
animator.retarget(1);
|
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
paintAll,
|
|
8
8
|
roleCode,
|
|
9
9
|
visibleWidth
|
|
10
|
-
} from "./archymedes-
|
|
10
|
+
} from "./archymedes-130jt0wr.mjs";
|
|
11
11
|
|
|
12
|
-
// src/render/sections.ts
|
|
12
|
+
// packages/archymedes-cli/src/render/sections.ts
|
|
13
13
|
var TONE_ROLE = {
|
|
14
14
|
good: "success",
|
|
15
15
|
bad: "error",
|