parallel-codex-tui 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 (40) hide show
  1. package/.parallel-codex/config.example.toml +62 -0
  2. package/LICENSE +21 -0
  3. package/README.md +150 -0
  4. package/dist/bootstrap.js +25 -0
  5. package/dist/cli-args.js +26 -0
  6. package/dist/cli.js +48 -0
  7. package/dist/core/config.js +304 -0
  8. package/dist/core/file-store.js +56 -0
  9. package/dist/core/paths.js +17 -0
  10. package/dist/core/router.js +151 -0
  11. package/dist/core/session-index.js +180 -0
  12. package/dist/core/session-manager.js +264 -0
  13. package/dist/doctor.js +121 -0
  14. package/dist/domain/schemas.js +78 -0
  15. package/dist/orchestrator/collaboration-channel.js +103 -0
  16. package/dist/orchestrator/orchestrator.js +545 -0
  17. package/dist/orchestrator/prompts.js +124 -0
  18. package/dist/orchestrator/supervisor-summary.js +38 -0
  19. package/dist/tui/App.js +740 -0
  20. package/dist/tui/AppShell.js +129 -0
  21. package/dist/tui/InputBar.js +141 -0
  22. package/dist/tui/StatusBar.js +288 -0
  23. package/dist/tui/TerminalOutput.js +22 -0
  24. package/dist/tui/WorkerOutputView.js +4015 -0
  25. package/dist/tui/chat-input.js +37 -0
  26. package/dist/tui/display-width.js +132 -0
  27. package/dist/tui/keyboard.js +38 -0
  28. package/dist/tui/native-input.js +120 -0
  29. package/dist/tui/raw-input-decoder.js +18 -0
  30. package/dist/tui/scrolling.js +25 -0
  31. package/dist/tui/status-line.js +90 -0
  32. package/dist/tui/task-memory.js +26 -0
  33. package/dist/tui/terminal-screen.js +168 -0
  34. package/dist/version.js +1 -0
  35. package/dist/workers/mock-adapter.js +62 -0
  36. package/dist/workers/native-attach.js +189 -0
  37. package/dist/workers/process-adapter.js +265 -0
  38. package/dist/workers/registry.js +32 -0
  39. package/dist/workers/types.js +1 -0
  40. package/package.json +53 -0
@@ -0,0 +1,37 @@
1
+ export function applyChatInputChunk(currentValue, chunk) {
2
+ if (chunk === "\x03") {
3
+ return {
4
+ value: currentValue,
5
+ submit: null,
6
+ exit: true
7
+ };
8
+ }
9
+ let value = currentValue;
10
+ let submit = null;
11
+ const visible = chunk
12
+ .replaceAll("\x1b[200~", "")
13
+ .replaceAll("\x1b[201~", "")
14
+ .replace(/\x1b\[M[\s\S]{3}/g, "")
15
+ .replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "")
16
+ .replace(/\x1bO./g, "");
17
+ for (const char of visible) {
18
+ if (char === "\r" || char === "\n") {
19
+ submit = value;
20
+ value = "";
21
+ }
22
+ else if (char === "\x7f" || char === "\b") {
23
+ value = dropLastCodePoint(value);
24
+ }
25
+ else if (char >= " " && char !== "\x1b") {
26
+ value += char;
27
+ }
28
+ }
29
+ return {
30
+ value,
31
+ submit,
32
+ exit: false
33
+ };
34
+ }
35
+ function dropLastCodePoint(value) {
36
+ return [...value].slice(0, -1).join("");
37
+ }
@@ -0,0 +1,132 @@
1
+ export function displayWidth(value) {
2
+ let width = 0;
3
+ for (const char of Array.from(value)) {
4
+ width += charDisplayWidth(char);
5
+ }
6
+ return width;
7
+ }
8
+ export function compactEndByDisplayWidth(value, maxWidth) {
9
+ if (maxWidth <= 0) {
10
+ return "";
11
+ }
12
+ if (displayWidth(value) <= maxWidth) {
13
+ return value;
14
+ }
15
+ if (maxWidth <= 3) {
16
+ return takeStartByDisplayWidth(value, maxWidth);
17
+ }
18
+ return `${takeStartByDisplayWidth(value, maxWidth - 3)}...`;
19
+ }
20
+ export function compactTailByDisplayWidth(value, maxWidth) {
21
+ if (maxWidth <= 0) {
22
+ return "";
23
+ }
24
+ if (displayWidth(value) <= maxWidth) {
25
+ return value;
26
+ }
27
+ const prefix = maxWidth <= 3 ? "" : "...";
28
+ const tailWidth = Math.max(1, maxWidth - displayWidth(prefix));
29
+ return `${prefix}${takeEndByDisplayWidth(value, tailWidth)}`;
30
+ }
31
+ export function wrapByDisplayWidth(value, maxWidth) {
32
+ if (maxWidth <= 0) {
33
+ return [""];
34
+ }
35
+ if (!value) {
36
+ return [""];
37
+ }
38
+ if (displayWidth(value) <= maxWidth) {
39
+ return [value];
40
+ }
41
+ const chunks = [];
42
+ let rest = value;
43
+ while (displayWidth(rest) > maxWidth) {
44
+ const splitAtWidth = sliceEndIndexByDisplayWidth(rest, maxWidth);
45
+ const hardSlice = rest.slice(0, splitAtWidth);
46
+ const breakAt = Math.max(hardSlice.lastIndexOf(" "), hardSlice.lastIndexOf("/"));
47
+ const breakWidth = breakAt >= 0 ? displayWidth(hardSlice.slice(0, breakAt + 1)) : 0;
48
+ const splitAt = rest[splitAtWidth] === " "
49
+ ? splitAtWidth
50
+ : breakWidth > Math.floor(maxWidth * 0.3)
51
+ ? breakAt + 1
52
+ : splitAtWidth;
53
+ chunks.push(rest.slice(0, splitAt).trimEnd());
54
+ rest = rest.slice(splitAt).trimStart();
55
+ }
56
+ chunks.push(rest);
57
+ return chunks;
58
+ }
59
+ function takeStartByDisplayWidth(value, maxWidth) {
60
+ let result = "";
61
+ let width = 0;
62
+ for (const char of Array.from(value)) {
63
+ const charWidth = charDisplayWidth(char);
64
+ if (width + charWidth > maxWidth) {
65
+ break;
66
+ }
67
+ result += char;
68
+ width += charWidth;
69
+ }
70
+ return result;
71
+ }
72
+ function takeEndByDisplayWidth(value, maxWidth) {
73
+ let result = "";
74
+ let width = 0;
75
+ const chars = Array.from(value);
76
+ for (let index = chars.length - 1; index >= 0; index -= 1) {
77
+ const char = chars[index] ?? "";
78
+ const charWidth = charDisplayWidth(char);
79
+ if (width + charWidth > maxWidth) {
80
+ break;
81
+ }
82
+ result = `${char}${result}`;
83
+ width += charWidth;
84
+ }
85
+ return result;
86
+ }
87
+ function sliceEndIndexByDisplayWidth(text, maxWidth) {
88
+ let width = 0;
89
+ let endIndex = 0;
90
+ for (const char of Array.from(text)) {
91
+ const charWidth = charDisplayWidth(char);
92
+ if (width + charWidth > maxWidth && endIndex > 0) {
93
+ break;
94
+ }
95
+ endIndex += char.length;
96
+ width += charWidth;
97
+ if (width >= maxWidth) {
98
+ break;
99
+ }
100
+ }
101
+ return endIndex || text.length;
102
+ }
103
+ function charDisplayWidth(char) {
104
+ const codePoint = char.codePointAt(0) ?? 0;
105
+ if (codePoint === 0 || codePoint < 32 || (codePoint >= 0x7f && codePoint < 0xa0)) {
106
+ return 0;
107
+ }
108
+ if (isCombiningCodePoint(codePoint)) {
109
+ return 0;
110
+ }
111
+ return isWideCodePoint(codePoint) ? 2 : 1;
112
+ }
113
+ function isCombiningCodePoint(codePoint) {
114
+ return ((codePoint >= 0x0300 && codePoint <= 0x036f) ||
115
+ (codePoint >= 0x1ab0 && codePoint <= 0x1aff) ||
116
+ (codePoint >= 0x1dc0 && codePoint <= 0x1dff) ||
117
+ (codePoint >= 0x20d0 && codePoint <= 0x20ff) ||
118
+ (codePoint >= 0xfe20 && codePoint <= 0xfe2f));
119
+ }
120
+ function isWideCodePoint(codePoint) {
121
+ return (codePoint >= 0x1100 &&
122
+ (codePoint <= 0x115f ||
123
+ codePoint === 0x2329 ||
124
+ codePoint === 0x232a ||
125
+ (codePoint >= 0x2e80 && codePoint <= 0xa4cf && codePoint !== 0x303f) ||
126
+ (codePoint >= 0xac00 && codePoint <= 0xd7a3) ||
127
+ (codePoint >= 0xf900 && codePoint <= 0xfaff) ||
128
+ (codePoint >= 0xfe10 && codePoint <= 0xfe19) ||
129
+ (codePoint >= 0xfe30 && codePoint <= 0xfe6f) ||
130
+ (codePoint >= 0xff00 && codePoint <= 0xff60) ||
131
+ (codePoint >= 0xffe0 && codePoint <= 0xffe6)));
132
+ }
@@ -0,0 +1,38 @@
1
+ export function isLogsShortcut(input, key) {
2
+ return (key.ctrl === true && input.toLowerCase() === "w") || input === "\u0017";
3
+ }
4
+ export function isAttachShortcut(input, key) {
5
+ return (key.ctrl === true && input.toLowerCase() === "o") || input === "\u000f";
6
+ }
7
+ export function isExitShortcut(input, key) {
8
+ return (key.ctrl === true && input.toLowerCase() === "c") || input === "\u0003";
9
+ }
10
+ export function scrollDelta(input, key, pageSize) {
11
+ if (key.pageUp || (key.ctrl === true && input.toLowerCase() === "u")) {
12
+ return pageSize;
13
+ }
14
+ if (key.pageDown || (key.ctrl === true && input.toLowerCase() === "d")) {
15
+ return -pageSize;
16
+ }
17
+ return 0;
18
+ }
19
+ export function mouseScrollDelta(input, linesPerWheel = 3) {
20
+ let delta = 0;
21
+ for (const match of input.matchAll(/\x1b\[<(\d+);\d+;\d+[mM]/g)) {
22
+ delta += wheelButtonDelta(Number(match[1]), linesPerWheel);
23
+ }
24
+ for (const match of input.matchAll(/\x1b\[M([\s\S])[\s\S]{2}/g)) {
25
+ delta += wheelButtonDelta(match[1].charCodeAt(0) - 32, linesPerWheel);
26
+ }
27
+ return delta;
28
+ }
29
+ function wheelButtonDelta(button, linesPerWheel) {
30
+ const wheel = button & 0b11;
31
+ if (button >= 64 && wheel === 0) {
32
+ return linesPerWheel;
33
+ }
34
+ if (button >= 64 && wheel === 1) {
35
+ return -linesPerWheel;
36
+ }
37
+ return 0;
38
+ }
@@ -0,0 +1,120 @@
1
+ const NATIVE_ATTACH_DETACH = "\x1d";
2
+ export function applyNativeInputKey(currentDraft, input, key) {
3
+ if ((key.ctrl && input === "]") || input === NATIVE_ATTACH_DETACH) {
4
+ return {
5
+ draft: "",
6
+ outbound: null,
7
+ exit: true
8
+ };
9
+ }
10
+ if (key.escape) {
11
+ return {
12
+ draft: currentDraft,
13
+ outbound: "\x1b",
14
+ exit: false
15
+ };
16
+ }
17
+ if (key.return) {
18
+ return {
19
+ draft: "",
20
+ outbound: "\r",
21
+ exit: false
22
+ };
23
+ }
24
+ if (key.backspace || key.delete) {
25
+ return {
26
+ draft: dropLastCodePoint(currentDraft),
27
+ outbound: "\x7f",
28
+ exit: false
29
+ };
30
+ }
31
+ if (key.tab) {
32
+ return {
33
+ draft: `${currentDraft}\t`,
34
+ outbound: "\t",
35
+ exit: false
36
+ };
37
+ }
38
+ if (key.ctrl && input.length === 1) {
39
+ return {
40
+ draft: currentDraft,
41
+ outbound: controlLetter(input),
42
+ exit: false
43
+ };
44
+ }
45
+ const arrow = arrowSequence(key);
46
+ if (arrow) {
47
+ return {
48
+ draft: currentDraft,
49
+ outbound: arrow,
50
+ exit: false
51
+ };
52
+ }
53
+ return {
54
+ draft: `${currentDraft}${input}`,
55
+ outbound: input || null,
56
+ exit: false
57
+ };
58
+ }
59
+ export function applyNativeInputChunk(currentDraft, chunk, pageSize = 0) {
60
+ if (chunk === NATIVE_ATTACH_DETACH) {
61
+ return {
62
+ draft: "",
63
+ outbound: null,
64
+ exit: true,
65
+ scrollDelta: 0
66
+ };
67
+ }
68
+ return {
69
+ draft: visibleDraftAfterChunk(currentDraft, chunk),
70
+ outbound: chunk || null,
71
+ exit: false,
72
+ scrollDelta: 0
73
+ };
74
+ }
75
+ function controlLetter(input) {
76
+ const code = input.toLowerCase().charCodeAt(0);
77
+ if (code < 97 || code > 122) {
78
+ return null;
79
+ }
80
+ return String.fromCharCode(code - 96);
81
+ }
82
+ function visibleDraftAfterChunk(currentDraft, chunk) {
83
+ let draft = currentDraft;
84
+ const visible = chunk
85
+ .replaceAll("\x1b[200~", "")
86
+ .replaceAll("\x1b[201~", "")
87
+ .replace(/\x1b\[M[\s\S]{3}/g, "")
88
+ .replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "")
89
+ .replace(/\x1bO./g, "");
90
+ for (const char of visible) {
91
+ if (char === "\r" || char === "\n") {
92
+ draft = "";
93
+ }
94
+ else if (char === "\x7f" || char === "\b") {
95
+ draft = dropLastCodePoint(draft);
96
+ }
97
+ else if (char >= " " && char !== "\x1b") {
98
+ draft += char;
99
+ }
100
+ }
101
+ return draft;
102
+ }
103
+ function dropLastCodePoint(value) {
104
+ return [...value].slice(0, -1).join("");
105
+ }
106
+ function arrowSequence(key) {
107
+ if (key.upArrow) {
108
+ return "\x1b[A";
109
+ }
110
+ if (key.downArrow) {
111
+ return "\x1b[B";
112
+ }
113
+ if (key.rightArrow) {
114
+ return "\x1b[C";
115
+ }
116
+ if (key.leftArrow) {
117
+ return "\x1b[D";
118
+ }
119
+ return null;
120
+ }
@@ -0,0 +1,18 @@
1
+ import { StringDecoder } from "node:string_decoder";
2
+ export function createRawInputDecoder() {
3
+ const decoder = new StringDecoder("utf8");
4
+ return {
5
+ write(chunk) {
6
+ if (chunk == null) {
7
+ return "";
8
+ }
9
+ if (Buffer.isBuffer(chunk)) {
10
+ return decoder.write(chunk);
11
+ }
12
+ return chunk;
13
+ },
14
+ end() {
15
+ return decoder.end();
16
+ }
17
+ };
18
+ }
@@ -0,0 +1,25 @@
1
+ export function selectViewportLines(text, height, offsetFromBottom) {
2
+ const lines = splitLines(text);
3
+ const viewportHeight = Math.max(1, height);
4
+ const maxOffset = Math.max(0, lines.length - viewportHeight);
5
+ const clampedOffset = clamp(offsetFromBottom, 0, maxOffset);
6
+ const end = lines.length - clampedOffset;
7
+ const start = Math.max(0, end - viewportHeight);
8
+ return {
9
+ lines: lines.slice(start, end),
10
+ clampedOffset,
11
+ maxOffset
12
+ };
13
+ }
14
+ export function nextScrollOffset(current, delta, maxOffset) {
15
+ return clamp(current + delta, 0, Math.max(0, maxOffset));
16
+ }
17
+ function splitLines(text) {
18
+ if (!text) {
19
+ return [];
20
+ }
21
+ return text.replace(/\n$/, "").split("\n");
22
+ }
23
+ function clamp(value, min, max) {
24
+ return Math.min(max, Math.max(min, value));
25
+ }
@@ -0,0 +1,90 @@
1
+ export function formatStatusLine(state) {
2
+ if (!state) {
3
+ return "idle";
4
+ }
5
+ const parts = [compactTaskId(state.taskId)];
6
+ if (state.workers?.length) {
7
+ parts.push(formatWorkerSummary(state.workers));
8
+ return parts.join(" | ");
9
+ }
10
+ if (state.main) {
11
+ parts.push(`main ${compactStatus(state.main)}`);
12
+ }
13
+ if (state.judge) {
14
+ parts.push(`judge ${compactStatus(state.judge)}`);
15
+ }
16
+ if (state.actor) {
17
+ parts.push(`actor ${compactStatus(state.actor)}`);
18
+ }
19
+ if (state.critic) {
20
+ parts.push(`critic ${compactStatus(state.critic)}`);
21
+ }
22
+ return parts.join(" | ");
23
+ }
24
+ export function formatSelectedWorkerStatus(state, selectedIndex) {
25
+ const worker = state?.workers?.[selectedIndex];
26
+ if (!worker) {
27
+ return "";
28
+ }
29
+ return `${compactWorkerLabel(worker.label)} ${compactStatus(worker.status)}`;
30
+ }
31
+ export function formatWorkerRuntimeStatus(status) {
32
+ const native = status.native_session_id ? ` native:${compactNativeSessionId(status.native_session_id)}` : "";
33
+ const detail = `${status.state}/${status.phase}${native}: ${status.summary.trim() || "no summary"}`;
34
+ return detail.length > 96 ? `${detail.slice(0, 93)}...` : detail;
35
+ }
36
+ export function formatFooterHelp(mode = "chat") {
37
+ if (mode === "native") {
38
+ return "wheel/Pg · ^] detach";
39
+ }
40
+ if (mode === "worker") {
41
+ return "wheel/Pg · Tab worker · ^O attach · Esc chat";
42
+ }
43
+ return "^W logs · Tab worker · ^O attach";
44
+ }
45
+ function compactNativeSessionId(sessionId) {
46
+ return sessionId.length > 12 ? `${sessionId.slice(0, 8)}...` : sessionId;
47
+ }
48
+ function formatWorkerSummary(workers) {
49
+ const counts = new Map();
50
+ for (const worker of workers) {
51
+ const state = compactStatus(worker.status);
52
+ counts.set(state, (counts.get(state) ?? 0) + 1);
53
+ }
54
+ const priority = ["fail", "run", "wait", "done"];
55
+ const orderedStates = [
56
+ ...priority.filter((state) => counts.has(state)),
57
+ ...Array.from(counts.keys()).filter((state) => !priority.includes(state)).sort()
58
+ ];
59
+ const summary = orderedStates.map((state) => `${state} ${counts.get(state)}`).join(" ");
60
+ return `workers ${workers.length}${summary ? ` | ${summary}` : ""}`;
61
+ }
62
+ function compactStatus(status) {
63
+ const trimmed = status.trim();
64
+ if (!trimmed) {
65
+ return "idle";
66
+ }
67
+ const state = trimmed.split(/[/: ]/, 1)[0]?.trim().toLowerCase();
68
+ if (state === "running") {
69
+ return "run";
70
+ }
71
+ if (state === "failed" || state === "error") {
72
+ return "fail";
73
+ }
74
+ if (state === "waiting" || state === "queued") {
75
+ return "wait";
76
+ }
77
+ return state || "idle";
78
+ }
79
+ function compactTaskId(taskId) {
80
+ const withoutPrefix = taskId.startsWith("task-") ? taskId.slice("task-".length) : taskId;
81
+ const dated = withoutPrefix.match(/^\d{8}-(.+)$/);
82
+ return dated?.[1] ?? withoutPrefix;
83
+ }
84
+ function compactWorkerLabel(label) {
85
+ const match = label.match(/^\s*([^(]+?)\s*\(([^)]+)\)\s*$/);
86
+ if (match) {
87
+ return `${match[1].trim().toLowerCase()}/${match[2].trim().toLowerCase()}`;
88
+ }
89
+ return label.trim().toLowerCase().replace(/\s+/g, "/");
90
+ }
@@ -0,0 +1,26 @@
1
+ export function chooseSubmitTarget(state, route) {
2
+ if (state.activeTaskId && state.activeMode === "complex") {
3
+ if (route?.mode === "simple") {
4
+ return {
5
+ kind: "task-question",
6
+ taskId: state.activeTaskId
7
+ };
8
+ }
9
+ return {
10
+ kind: "task-turn",
11
+ taskId: state.activeTaskId
12
+ };
13
+ }
14
+ return {
15
+ kind: "new-request"
16
+ };
17
+ }
18
+ export function nextSubmitMemoryState(current, target, result) {
19
+ if (target.kind === "task-question") {
20
+ return current;
21
+ }
22
+ return {
23
+ activeMode: result.mode,
24
+ activeTaskId: result.mode === "complex" ? result.taskId : null
25
+ };
26
+ }
@@ -0,0 +1,168 @@
1
+ import * as xtermHeadless from "@xterm/headless";
2
+ const xtermRuntime = xtermHeadless;
3
+ const Terminal = resolveTerminalConstructor(xtermRuntime);
4
+ export class NativeTerminalScreen {
5
+ terminal;
6
+ constructor(options = {}) {
7
+ this.terminal = new Terminal({
8
+ allowProposedApi: true,
9
+ cols: options.cols ?? 120,
10
+ rows: options.rows ?? 24,
11
+ scrollback: options.scrollback ?? 1000
12
+ });
13
+ }
14
+ write(chunk) {
15
+ return new Promise((resolve) => {
16
+ this.terminal.write(chunk, resolve);
17
+ });
18
+ }
19
+ snapshot() {
20
+ return this.snapshotLines().join("\n");
21
+ }
22
+ snapshotLines() {
23
+ return this.styledSnapshotLines().map((line) => line.chunks.map((chunk) => chunk.text).join(""));
24
+ }
25
+ styledSnapshotLines(options = {}) {
26
+ const buffer = this.terminal.buffer.active;
27
+ const lines = [];
28
+ const cursorY = options.showCursor ? buffer.baseY + buffer.cursorY : null;
29
+ const cursorX = options.showCursor ? Math.min(buffer.cursorX, this.terminal.cols - 1) : null;
30
+ for (let row = 0; row < this.terminal.rows; row += 1) {
31
+ const absoluteY = buffer.viewportY + row;
32
+ const line = buffer.getLine(absoluteY);
33
+ lines.push(line
34
+ ? styledLineFromBufferLine(line, buffer.getNullCell(), absoluteY === cursorY ? cursorX : null)
35
+ : { chunks: [] });
36
+ }
37
+ return trimTrailingBlankTerminalLines(lines);
38
+ }
39
+ scrollLines(amount) {
40
+ this.terminal.scrollLines(amount);
41
+ }
42
+ scrollPages(pageCount) {
43
+ this.terminal.scrollPages(pageCount);
44
+ }
45
+ scrollToBottom() {
46
+ this.terminal.scrollToBottom();
47
+ }
48
+ scrollState() {
49
+ const buffer = this.terminal.buffer.active;
50
+ return {
51
+ offset: Math.max(0, buffer.baseY - buffer.viewportY),
52
+ maxOffset: Math.max(0, buffer.baseY)
53
+ };
54
+ }
55
+ }
56
+ function styledLineFromBufferLine(line, reusableCell, cursorColumn) {
57
+ const chunks = [];
58
+ let pendingStyle = null;
59
+ let pendingText = "";
60
+ const trimmedText = line.translateToString(true);
61
+ const cursorLimit = cursorColumn === null ? -1 : cursorColumn + 1;
62
+ let visibleTextLength = 0;
63
+ for (let column = 0; column < line.length && (visibleTextLength < trimmedText.length || column < cursorLimit); column += 1) {
64
+ const cell = line.getCell(column, reusableCell);
65
+ if (!cell || cell.getWidth() === 0) {
66
+ continue;
67
+ }
68
+ const text = cell.getChars() || " ";
69
+ visibleTextLength += text.length;
70
+ const style = styleFromCell(cell);
71
+ if (cursorColumn === column) {
72
+ style.cursor = true;
73
+ style.inverse = true;
74
+ }
75
+ if (pendingStyle && sameStyle(pendingStyle, style)) {
76
+ pendingText += text;
77
+ continue;
78
+ }
79
+ if (pendingStyle) {
80
+ chunks.push({ text: pendingText, style: pendingStyle });
81
+ }
82
+ pendingStyle = style;
83
+ pendingText = text;
84
+ }
85
+ if (pendingStyle) {
86
+ chunks.push({ text: pendingText, style: pendingStyle });
87
+ }
88
+ return { chunks };
89
+ }
90
+ function styleFromCell(cell) {
91
+ const style = {};
92
+ const color = colorFromCell(cell, "fg");
93
+ const backgroundColor = colorFromCell(cell, "bg");
94
+ if (color) {
95
+ style.color = color;
96
+ }
97
+ if (backgroundColor) {
98
+ style.backgroundColor = backgroundColor;
99
+ }
100
+ if (cell.isBold()) {
101
+ style.bold = true;
102
+ }
103
+ if (cell.isDim()) {
104
+ style.dimColor = true;
105
+ }
106
+ if (cell.isInverse()) {
107
+ style.inverse = true;
108
+ }
109
+ if (cell.isItalic()) {
110
+ style.italic = true;
111
+ }
112
+ if (cell.isStrikethrough()) {
113
+ style.strikethrough = true;
114
+ }
115
+ if (cell.isUnderline()) {
116
+ style.underline = true;
117
+ }
118
+ return style;
119
+ }
120
+ function colorFromCell(cell, kind) {
121
+ if (kind === "fg") {
122
+ if (cell.isFgRGB()) {
123
+ return rgbHex(cell.getFgColor());
124
+ }
125
+ if (cell.isFgPalette()) {
126
+ return `ansi256(${cell.getFgColor()})`;
127
+ }
128
+ return undefined;
129
+ }
130
+ if (cell.isBgRGB()) {
131
+ return rgbHex(cell.getBgColor());
132
+ }
133
+ if (cell.isBgPalette()) {
134
+ return `ansi256(${cell.getBgColor()})`;
135
+ }
136
+ return undefined;
137
+ }
138
+ function rgbHex(value) {
139
+ return `#${value.toString(16).padStart(6, "0")}`;
140
+ }
141
+ function sameStyle(left, right) {
142
+ return (left.backgroundColor === right.backgroundColor &&
143
+ left.bold === right.bold &&
144
+ left.color === right.color &&
145
+ left.cursor === right.cursor &&
146
+ left.dimColor === right.dimColor &&
147
+ left.inverse === right.inverse &&
148
+ left.italic === right.italic &&
149
+ left.strikethrough === right.strikethrough &&
150
+ left.underline === right.underline);
151
+ }
152
+ function trimTrailingBlankTerminalLines(lines) {
153
+ let end = lines.length;
154
+ while (end > 0 && terminalLineText(lines[end - 1]).trim() === "") {
155
+ end -= 1;
156
+ }
157
+ return lines.slice(0, end);
158
+ }
159
+ function terminalLineText(line) {
160
+ return line.chunks.map((chunk) => chunk.text).join("");
161
+ }
162
+ function resolveTerminalConstructor(runtime) {
163
+ const constructor = runtime.Terminal ?? runtime.default?.Terminal ?? runtime["module.exports"]?.Terminal;
164
+ if (!constructor) {
165
+ throw new Error("Unable to load @xterm/headless Terminal export.");
166
+ }
167
+ return constructor;
168
+ }
@@ -0,0 +1 @@
1
+ export const version = "0.1.0";