@duckmind/dm-darwin-x64 0.35.4 → 0.35.5

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 (43) hide show
  1. package/dm +0 -0
  2. package/extensions/.dm-extensions.json +1 -27
  3. package/package.json +1 -1
  4. package/extensions/dm-alps/LICENSE +0 -21
  5. package/extensions/dm-alps/README.md +0 -22
  6. package/extensions/dm-alps/index.ts +0 -172
  7. package/extensions/dm-alps/package.json +0 -49
  8. package/extensions/dm-alps/src/commands.ts +0 -208
  9. package/extensions/dm-alps/src/features/animations/debug.ts +0 -160
  10. package/extensions/dm-alps/src/features/animations/index.ts +0 -33
  11. package/extensions/dm-alps/src/features/animations/patch.ts +0 -112
  12. package/extensions/dm-alps/src/features/animations/preview.ts +0 -117
  13. package/extensions/dm-alps/src/features/animations/registry.ts +0 -593
  14. package/extensions/dm-alps/src/features/animations/runtime.ts +0 -574
  15. package/extensions/dm-alps/src/features/animations/settings.ts +0 -69
  16. package/extensions/dm-alps/src/features/bottom-input/cluster.ts +0 -2
  17. package/extensions/dm-alps/src/features/bottom-input/compositor.ts +0 -2
  18. package/extensions/dm-alps/src/features/bottom-input/editor.ts +0 -148
  19. package/extensions/dm-alps/src/features/bottom-input/frame.ts +0 -224
  20. package/extensions/dm-alps/src/features/bottom-input/icons.ts +0 -36
  21. package/extensions/dm-alps/src/features/bottom-input/index.ts +0 -8
  22. package/extensions/dm-alps/src/features/bottom-input/runtime.ts +0 -1197
  23. package/extensions/dm-alps/src/features/bottom-input/shortcuts.ts +0 -286
  24. package/extensions/dm-alps/src/features/bottom-input/status.ts +0 -663
  25. package/extensions/dm-alps/src/features/bottom-status/index.ts +0 -2
  26. package/extensions/dm-alps/src/features/chrome-frame/chrome.ts +0 -222
  27. package/extensions/dm-alps/src/features/chrome-frame/debug.ts +0 -212
  28. package/extensions/dm-alps/src/features/chrome-frame/image.ts +0 -11
  29. package/extensions/dm-alps/src/features/chrome-frame/index.ts +0 -4
  30. package/extensions/dm-alps/src/features/chrome-frame/osc.ts +0 -111
  31. package/extensions/dm-alps/src/features/chrome-frame/patch.ts +0 -769
  32. package/extensions/dm-alps/src/features/chrome-frame/preview.ts +0 -67
  33. package/extensions/dm-alps/src/features/chrome-frame/styles.ts +0 -105
  34. package/extensions/dm-alps/src/features/fixed-bottom-editor/cluster.ts +0 -161
  35. package/extensions/dm-alps/src/features/fixed-bottom-editor/compositor.ts +0 -1149
  36. package/extensions/dm-alps/src/features/fixed-bottom-editor/index.ts +0 -3
  37. package/extensions/dm-alps/src/features/fixed-bottom-editor/runtime.ts +0 -3
  38. package/extensions/dm-alps/src/settings-store.ts +0 -194
  39. package/extensions/dm-alps/src/settings-ui.ts +0 -653
  40. package/extensions/dm-alps/src/settings.ts +0 -102
  41. package/extensions/dm-alps/src/terminal-sanitizer.ts +0 -91
  42. package/extensions/dm-alps/themes/LICENSE.synthwave-84 +0 -21
  43. package/extensions/dm-alps/themes/alps.json +0 -93
@@ -1,222 +0,0 @@
1
-
2
- import { truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@mariozechner/pi-tui";
3
- import { sanitizeTerminalText } from "../../terminal-sanitizer.ts";
4
- import { isImageEscapeLine } from "./image.ts";
5
- import { collectBoundaryOscMarkersFromBlankEdges, extractBoundaryOscMarkers, restoreBoundaryOscMarkers } from "./osc.ts";
6
- import { DEFAULT_CONFIG, getChromeLabel, getChromeStyle, type ChromeConfig, type ChromeKind, type ChromeStatus, type ThemeLike } from "./styles.ts";
7
-
8
- export type RenderBoxOptions = {
9
- toolName?: string;
10
- status?: ChromeStatus;
11
- config?: ChromeConfig;
12
- elapsedText?: string;
13
- };
14
-
15
- const MIN_FULL_BOX_WIDTH = 8;
16
- const COMPACT_THINKING_BORDER_TOKEN = "borderAccent";
17
-
18
- export function padToWidth(line: string, width: number): string {
19
- const current = visibleWidth(line);
20
- if (current >= width) return line;
21
- return line + " ".repeat(width - current);
22
- }
23
-
24
- function safeWidth(width: number): number {
25
- if (!Number.isFinite(width)) return 0;
26
- return Math.max(0, Math.floor(width));
27
- }
28
-
29
- function styleText(theme: ThemeLike, token: string, text: string): string {
30
- return theme.fg(token, text);
31
- }
32
-
33
- function applyLineBackground(_theme: ThemeLike, _bgToken: string, line: string, width: number): string {
34
- return padToWidth(line, width);
35
- }
36
-
37
- function simpleLines(lines: readonly string[], width: number): string[] {
38
- const max = safeWidth(width);
39
- if (max <= 0) return [];
40
- const raw = lines.length > 0 ? lines : [""];
41
- return raw
42
- .flatMap((line) => sanitizeTerminalText(line, { preserveSgr: true }).split("\n"))
43
- .map((line) => truncateToWidth(line, max, "", false));
44
- }
45
-
46
- function buildTopBorder(label: string, width: number, theme: ThemeLike, borderToken: string, labelToken: string): string {
47
- const left = "╭─ ";
48
- const separator = " ";
49
- const right = "╮";
50
- const labelBudget = Math.max(0, width - visibleWidth(left + separator + right));
51
- const visibleLabel = truncateToWidth(label, labelBudget, "", false);
52
- const leftBorder = styleText(theme, borderToken, left);
53
- const styledLabel = styleText(theme, labelToken, visibleLabel);
54
- const dashCount = Math.max(0, width - visibleWidth(left + visibleLabel + separator + right));
55
- const rightBorder = styleText(theme, borderToken, separator + "─".repeat(dashCount) + right);
56
- return leftBorder + styledLabel + rightBorder;
57
- }
58
-
59
- function buildCompactThinkingTopBorder(label: string, width: number, theme: ThemeLike, borderToken: string, labelToken: string): string {
60
- return buildTopBorder(label, width, theme, borderToken, labelToken);
61
- }
62
-
63
- function buildCompactThinkingBottomBorder(width: number, theme: ThemeLike, borderToken: string): string {
64
- return styleText(theme, borderToken, "╰" + "─".repeat(Math.max(0, width - 2)) + "╯");
65
- }
66
-
67
- function stripAnsiForContent(line: string): string {
68
- return stripControlMarkers(line).trim();
69
- }
70
-
71
- function firstCompactThinkingLine(lines: readonly string[]): string {
72
- for (const raw of lines) {
73
- for (const part of String(raw).split("\n")) {
74
- const text = stripAnsiForContent(part);
75
- if (text) return text;
76
- }
77
- }
78
- return "Thinking complete";
79
- }
80
-
81
- export function renderCompactThinkingBox(contentLines: readonly string[], width: number, theme: ThemeLike, config: ChromeConfig = DEFAULT_CONFIG): string[] {
82
- const boxWidth = safeWidth(width);
83
- if (boxWidth < MIN_FULL_BOX_WIDTH) return simpleLines(contentLines, boxWidth);
84
- const label = "THINK";
85
- const style = getChromeStyle("thinking", {}, config);
86
- const borderToken = COMPACT_THINKING_BORDER_TOKEN;
87
- const innerWidth = Math.max(0, boxWidth - 4);
88
- const content = truncateToWidth(firstCompactThinkingLine(contentLines), innerWidth, "", false);
89
- const padded = padToWidth(content, innerWidth);
90
- return [
91
- buildCompactThinkingTopBorder(label, boxWidth, theme, borderToken, style.label),
92
- styleText(theme, borderToken, "│") + " " + styleText(theme, borderToken, padded) + " " + styleText(theme, borderToken, "│"),
93
- buildCompactThinkingBottomBorder(boxWidth, theme, borderToken),
94
- ];
95
- }
96
-
97
- function buildBottomBorder(width: number, theme: ThemeLike, borderToken: string, elapsedText?: string): string {
98
- const text = elapsedText?.trim();
99
- if (!text) {
100
- return styleText(theme, borderToken, "╰" + "─".repeat(Math.max(0, width - 2)) + "╯");
101
- }
102
-
103
- const textBudget = Math.max(0, width - visibleWidth("╰ ╯"));
104
- const visibleText = truncateToWidth(text, textBudget, "", false);
105
- if (!visibleText) {
106
- return styleText(theme, borderToken, "╰" + "─".repeat(Math.max(0, width - 2)) + "╯");
107
- }
108
- const suffix = ` ${visibleText} `;
109
- const dashCount = Math.max(0, width - visibleWidth(`╰${suffix}╯`));
110
- return styleText(theme, borderToken, "╰" + "─".repeat(dashCount) + suffix + "╯");
111
- }
112
-
113
- function wrapContentLine(line: string, innerWidth: number, hasImage: boolean): string[] {
114
- if (hasImage) return [line];
115
- const wrapped = wrapTextWithAnsi(line, Math.max(1, innerWidth));
116
- return wrapped.length > 0 ? wrapped : [""];
117
- }
118
-
119
- function renderContentLine(line: string, width: number, theme: ThemeLike, borderToken: string, textToken: string): string {
120
- const innerWidth = Math.max(0, width - 4);
121
- const clipped = truncateToWidth(line, innerWidth, "", false);
122
- const padded = padToWidth(clipped, innerWidth);
123
- return styleText(theme, borderToken, "│") + " " + styleText(theme, textToken, padded) + " " + styleText(theme, borderToken, "│");
124
- }
125
-
126
- function stripControlMarkers(line: string): string {
127
- return sanitizeTerminalText(line, { allowNewline: false, allowTab: false, preserveSgr: false });
128
- }
129
-
130
- function sanitizeContentLines(lines: readonly string[]): string[] {
131
- const raw = lines.length > 0 ? lines : [""];
132
- return raw.map((line) => isImageEscapeLine(line) ? String(line) : sanitizeTerminalText(line, { preserveSgr: true }));
133
- }
134
-
135
- function isBlankAfterControlMarkers(line: string): boolean {
136
- const text = String(line);
137
- if (!text.includes("\x1b")) return text.trim().length === 0;
138
- return stripControlMarkers(text).trim().length === 0;
139
- }
140
-
141
- function shouldTrimBoundaryBlankLines(kind: ChromeKind): boolean {
142
- return kind === "assistant"
143
- || kind === "thinking"
144
- || kind === "bash"
145
- || kind === "tool"
146
- || kind === "toolPending"
147
- || kind === "toolSuccess"
148
- || kind === "toolError"
149
- || kind === "custom"
150
- || kind === "skill"
151
- || kind === "compaction"
152
- || kind === "branch";
153
- }
154
-
155
- function trimBoundaryBlankContentLines(kind: ChromeKind, lines: readonly string[]): string[] {
156
- const normalized = [...lines];
157
- if (!shouldTrimBoundaryBlankLines(kind)) return normalized;
158
- while (normalized.length > 0 && !isImageEscapeLine(normalized[0] ?? "") && isBlankAfterControlMarkers(normalized[0] ?? "")) {
159
- normalized.shift();
160
- }
161
- while (normalized.length > 0 && !isImageEscapeLine(normalized.at(-1) ?? "") && isBlankAfterControlMarkers(normalized.at(-1) ?? "")) {
162
- normalized.pop();
163
- }
164
- return normalized;
165
- }
166
-
167
- export function isEmptyMessageChrome(kind: ChromeKind, contentLines: readonly string[]): boolean {
168
- if (kind === "tool" || kind === "toolPending" || kind === "toolSuccess" || kind === "toolError" || kind === "bash" || kind === "working") {
169
- return false;
170
- }
171
- if (contentLines.length === 0) return true;
172
- return contentLines.every(isBlankAfterControlMarkers);
173
- }
174
-
175
- export function renderNeonBox(kind: ChromeKind, contentLines: readonly string[], width: number, theme: ThemeLike, options: RenderBoxOptions = {}): string[] {
176
- if (isEmptyMessageChrome(kind, contentLines)) return [];
177
- const boxWidth = safeWidth(width);
178
- if (boxWidth < MIN_FULL_BOX_WIDTH) {
179
- return simpleLines(contentLines, boxWidth);
180
- }
181
-
182
- const markers = collectBoundaryOscMarkersFromBlankEdges(
183
- extractBoundaryOscMarkers(contentLines.map(String)),
184
- isBlankAfterControlMarkers,
185
- isImageEscapeLine,
186
- );
187
- const rawLines = sanitizeContentLines(trimBoundaryBlankContentLines(kind, markers.lines));
188
- if (isEmptyMessageChrome(kind, rawLines)) return [];
189
- const status = options.status;
190
- const style = getChromeStyle(kind, { toolName: options.toolName, status }, options.config ?? DEFAULT_CONFIG);
191
- const label = getChromeLabel(kind, { toolName: options.toolName, status });
192
- const innerWidth = Math.max(1, boxWidth - 4);
193
-
194
- const lines: string[] = [];
195
- const pushTextLine = (line: string) => {
196
- lines.push(applyLineBackground(theme, style.bg, line, boxWidth));
197
- };
198
- const pushContentLine = (line: string) => {
199
- lines.push(line);
200
- };
201
- pushTextLine(buildTopBorder(label, boxWidth, theme, style.border, style.label));
202
- for (const raw of rawLines) {
203
- const split = String(raw).split("\n");
204
- for (const part of split) {
205
- const partHasImage = isImageEscapeLine(part);
206
- const wrapped = wrapContentLine(part, innerWidth, partHasImage);
207
- for (const wrappedLine of wrapped) {
208
- if (partHasImage) {
209
- pushContentLine(wrappedLine);
210
- } else {
211
- pushContentLine(applyLineBackground(theme, style.bg, renderContentLine(wrappedLine, boxWidth, theme, style.border, style.text), boxWidth));
212
- }
213
- }
214
- }
215
- }
216
- if (lines.length === 1) {
217
- pushContentLine(applyLineBackground(theme, style.bg, renderContentLine("", boxWidth, theme, style.border, style.text), boxWidth));
218
- }
219
- pushTextLine(buildBottomBorder(boxWidth, theme, style.border, options.elapsedText));
220
-
221
- return restoreBoundaryOscMarkers(lines, markers, { startIndex: 0, endIndex: lines.length - 1 });
222
- }
@@ -1,212 +0,0 @@
1
-
2
- import { appendFileSync, mkdirSync } from "node:fs";
3
- import { dirname, isAbsolute } from "node:path";
4
- import { visibleWidth } from "@mariozechner/pi-tui";
5
- import { isImageEscapeLine } from "./image.ts";
6
- import type { ChromeKind } from "./styles.ts";
7
-
8
- export type ChromeFrameDebugBranch =
9
- | "normal"
10
- | "fallback"
11
- | "narrowFallback"
12
- | "imageFallback"
13
- | "compactThinking"
14
- | "cacheHit"
15
- | "empty"
16
- | "errorFallback";
17
-
18
- export type ChromeFrameDebugOptions = {
19
- targetId: string;
20
- targetKind: ChromeKind;
21
- inputWidth: number;
22
- resolvedFrameWidth: number;
23
- innerWidth?: number | null;
24
- originalLineCount?: number | null;
25
- displayedLineCount?: number | null;
26
- boxedLineCount?: number | null;
27
- branch: ChromeFrameDebugBranch;
28
- cacheKeySummary?: string | null;
29
- hasImageLine?: boolean;
30
- usesCompactThinking?: boolean;
31
- error?: string;
32
- lines: readonly string[];
33
- };
34
-
35
- type ControlSummary = {
36
- osc133: number;
37
- osc: number;
38
- csi: number;
39
- sgr: number;
40
- dcs: number;
41
- apc: number;
42
- pm: number;
43
- };
44
-
45
- const PREVIEW_LIMIT = 24;
46
- const TAIL_CODEPOINT_LIMIT = 10;
47
- const OSC133_PATTERN = /\x1b\]133;[A-Z](?:\x07|\x1b\\)/g;
48
- const OSC_PATTERN = /\x1b\][\s\S]*?(?:\x07|\x1b\\)/g;
49
- const CSI_PATTERN = /\x1b\[[0-?]*[ -/]*[@-~]/g;
50
- const SGR_PATTERN = /\x1b\[[0-9;:]*m/g;
51
- const DCS_PATTERN = /\x1bP[\s\S]*?(?:\x07|\x1b\\)/g;
52
- const APC_PATTERN = /\x1b_[\s\S]*?(?:\x07|\x1b\\)/g;
53
- const PM_PATTERN = /\x1b\^[\s\S]*?(?:\x07|\x1b\\)/g;
54
- const C0_PATTERN = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
55
- let sequence = 0;
56
-
57
- export function isChromeFrameDebugEnabled(): boolean {
58
- const logPath = process.env.ALPS_DM_FRAME_DEBUG_LOG?.trim();
59
- return Boolean(logPath && isAbsolute(logPath));
60
- }
61
-
62
- function countMatches(input: string, pattern: RegExp): number {
63
- pattern.lastIndex = 0;
64
- let count = 0;
65
- while (pattern.exec(input)) count += 1;
66
- return count;
67
- }
68
-
69
- function summarizeControls(input: string): ControlSummary {
70
- return {
71
- osc133: countMatches(input, OSC133_PATTERN),
72
- osc: countMatches(input, OSC_PATTERN),
73
- csi: countMatches(input, CSI_PATTERN),
74
- sgr: countMatches(input, SGR_PATTERN),
75
- dcs: countMatches(input, DCS_PATTERN),
76
- apc: countMatches(input, APC_PATTERN),
77
- pm: countMatches(input, PM_PATTERN),
78
- };
79
- }
80
-
81
- function stripInvisibleControls(input: string): string {
82
- return input
83
- .replace(DCS_PATTERN, "")
84
- .replace(APC_PATTERN, "")
85
- .replace(PM_PATTERN, "")
86
- .replace(OSC_PATTERN, "")
87
- .replace(CSI_PATTERN, "")
88
- .replace(C0_PATTERN, "");
89
- }
90
-
91
- function previewClass(char: string): string {
92
- if (/\s/u.test(char)) return "S";
93
- if (/^[╭╮╰╯│─]$/u.test(char)) return "B";
94
- if (/^[A-Z]$/u.test(char)) return "U";
95
- if (/^[a-z]$/u.test(char)) return "L";
96
- if (/^[0-9]$/u.test(char)) return "D";
97
- if (/^[\p{P}\p{S}]$/u.test(char)) return "P";
98
- if (visibleWidth(char) > 1) return "W";
99
- return "O";
100
- }
101
-
102
- function maskedPreviewStart(input: string, limit = PREVIEW_LIMIT): string {
103
- return [...input].slice(0, limit).map(previewClass).join("");
104
- }
105
-
106
- function maskedPreviewEnd(input: string, limit = PREVIEW_LIMIT): string {
107
- const chars = [...input];
108
- return chars.slice(Math.max(0, chars.length - limit)).map(previewClass).join("");
109
- }
110
-
111
- function tailCodepoints(input: string): string[] {
112
- const controls: string[] = [];
113
- const chars = [...input].reverse();
114
- for (const char of chars) {
115
- const code = char.codePointAt(0)!;
116
- if (code === 0x1b || code === 0x07 || code === 0x0a || code === 0x0d || code === 0x09 || code < 0x20 || code === 0x7f) {
117
- controls.push(`U+${code.toString(16).toUpperCase().padStart(4, "0")}`);
118
- if (controls.length >= TAIL_CODEPOINT_LIMIT) break;
119
- }
120
- }
121
- return controls.reverse();
122
- }
123
-
124
- function safeVisibleWidth(input: string): number {
125
- try {
126
- return visibleWidth(stripInvisibleControls(input));
127
- } catch {
128
- return 0;
129
- }
130
- }
131
-
132
- function lineRole(index: number, total: number, branch: ChromeFrameDebugBranch, usesCompactThinking: boolean | undefined): string {
133
- if (branch === "normal" || branch === "cacheHit") {
134
- if (usesCompactThinking) {
135
- if (index === 0) return "compactTop";
136
- if (index === total - 1) return "compactBottom";
137
- return "compactContent";
138
- }
139
- if (index === 0) return "top";
140
- if (index === total - 1) return "bottom";
141
- return "content";
142
- }
143
- if (branch === "compactThinking") {
144
- if (index === 0) return "compactTop";
145
- if (index === total - 1) return "compactBottom";
146
- return "compactContent";
147
- }
148
- if (branch === "fallback" || branch === "narrowFallback" || branch === "imageFallback" || branch === "errorFallback") return "fallback";
149
- return "unknown";
150
- }
151
-
152
- function summarizeLine(line: string, index: number, total: number, branch: ChromeFrameDebugBranch, usesCompactThinking: boolean | undefined) {
153
- const raw = String(line);
154
- const isImageLine = isImageEscapeLine(raw);
155
- const printable = isImageLine ? "" : stripInvisibleControls(raw);
156
- const controlSummary = summarizeControls(raw);
157
- return {
158
- index,
159
- role: lineRole(index, total, branch, usesCompactThinking),
160
- visibleWidth: safeVisibleWidth(raw),
161
- startsWithOsc133: /^\x1b\]133;[A-Z](?:\x07|\x1b\\)/.test(raw),
162
- containsOsc133: controlSummary.osc133 > 0,
163
- containsOsc: controlSummary.osc > 0,
164
- containsCsi: controlSummary.csi > 0,
165
- blank: printable.trim().length === 0,
166
- prefixPreview: isImageLine ? "" : maskedPreviewStart(printable),
167
- suffixPreview: isImageLine ? "" : maskedPreviewEnd(printable),
168
- tailCodepoints: isImageLine ? [] : tailCodepoints(raw),
169
- rawLength: raw.length,
170
- controlSummary,
171
- isImageLine,
172
- };
173
- }
174
-
175
- export function summarizeChromeFrameCacheKey(value: string | undefined): string | null {
176
- if (!value) return null;
177
- let hash = 5381;
178
- for (let index = 0; index < value.length; index += 1) {
179
- hash = ((hash << 5) + hash) ^ value.charCodeAt(index);
180
- }
181
- return `len:${value.length}:hash:${(hash >>> 0).toString(16)}`;
182
- }
183
-
184
- export function writeChromeFrameDebugLog(options: ChromeFrameDebugOptions): void {
185
- const logPath = process.env.ALPS_DM_FRAME_DEBUG_LOG?.trim();
186
- if (!logPath || !isAbsolute(logPath)) return;
187
- try {
188
- const lines = options.lines.map(String);
189
- const entry = {
190
- event: "chrome-frame-render",
191
- seq: ++sequence,
192
- timestamp: new Date().toISOString(),
193
- targetId: options.targetId || "unknown",
194
- targetKind: options.targetKind,
195
- inputWidth: options.inputWidth,
196
- resolvedFrameWidth: options.resolvedFrameWidth,
197
- innerWidth: options.innerWidth ?? null,
198
- originalLineCount: options.originalLineCount ?? null,
199
- displayedLineCount: options.displayedLineCount ?? null,
200
- boxedLineCount: options.boxedLineCount ?? lines.length,
201
- branch: options.branch,
202
- cacheKeySummary: options.cacheKeySummary ?? null,
203
- hasImageLine: Boolean(options.hasImageLine),
204
- usesCompactThinking: Boolean(options.usesCompactThinking),
205
- error: options.error,
206
- lines: lines.map((line, index) => summarizeLine(line, index, lines.length, options.branch, options.usesCompactThinking)),
207
- };
208
- mkdirSync(dirname(logPath), { recursive: true });
209
- appendFileSync(logPath, `${JSON.stringify(entry)}\n`, "utf8");
210
- } catch {
211
- }
212
- }
@@ -1,11 +0,0 @@
1
-
2
- const KITTY_IMAGE_PREFIX = "\x1b_G";
3
- const ITERM_IMAGE_PREFIX = "\x1b]1337;File=";
4
-
5
- export function isImageEscapeLine(line: string): boolean {
6
- return line.includes(KITTY_IMAGE_PREFIX) || line.includes(ITERM_IMAGE_PREFIX);
7
- }
8
-
9
- export function containsImageLine(lines: readonly string[]): boolean {
10
- return lines.some(isImageEscapeLine);
11
- }
@@ -1,4 +0,0 @@
1
-
2
- export { createPreviewComponent } from "./preview.ts";
3
- export { disablePatch, enablePatch, getGlobalPatchState, getRuntimeTheme } from "./patch.ts";
4
- export type { PatchState } from "./patch.ts";
@@ -1,111 +0,0 @@
1
-
2
- export type OscExtraction = {
3
- lines: string[];
4
- startMarkers: string[];
5
- endMarkers: string[];
6
- };
7
-
8
- export type OscRestoreOptions = {
9
- startIndex?: number;
10
- endIndex?: number;
11
- };
12
-
13
- const OSC133_PATTERN = /^\x1b\]133;([ABC])\x07/;
14
- const OSC133_ANYWHERE_PATTERN = /\x1b\]133;([ABC])\x07/g;
15
- const OSC133_ALL_CODES = new Set(["A", "B", "C"]);
16
- const OSC133_START_CODES = new Set(["A"]);
17
- const OSC133_END_CODES = new Set(["B", "C"]);
18
-
19
- function extractLeadingOsc133Codes(input: string, allowedCodes: ReadonlySet<string>): { markers: string[]; rest: string } {
20
- const markers: string[] = [];
21
- let rest = input;
22
- while (true) {
23
- const match = OSC133_PATTERN.exec(rest);
24
- if (!match || !allowedCodes.has(match[1] ?? "")) break;
25
- markers.push(match[0]);
26
- rest = rest.slice(match[0].length);
27
- }
28
- return { markers, rest };
29
- }
30
-
31
- export function extractLeadingOsc133(input: string): { markers: string[]; rest: string } {
32
- return extractLeadingOsc133Codes(input, OSC133_ALL_CODES);
33
- }
34
-
35
- export function extractBoundaryOscMarkers(lines: readonly string[]): OscExtraction {
36
- try {
37
- const clean = [...lines];
38
- const startMarkers: string[] = [];
39
- const endMarkers: string[] = [];
40
- if (clean.length > 0) {
41
- const tailIndex = clean.length - 1;
42
- const ending = extractLeadingOsc133Codes(clean[tailIndex] ?? "", OSC133_END_CODES);
43
- endMarkers.push(...ending.markers);
44
- clean[tailIndex] = ending.rest;
45
- const leading = extractLeadingOsc133Codes(clean[0] ?? "", OSC133_START_CODES);
46
- startMarkers.push(...leading.markers);
47
- clean[0] = leading.rest;
48
- }
49
- return { lines: clean, startMarkers, endMarkers };
50
- } catch {
51
- return { lines: [...lines], startMarkers: [], endMarkers: [] };
52
- }
53
- }
54
-
55
- function stripOsc133Markers(input: string, target: string[], allowedCodes: ReadonlySet<string>): string {
56
- return input.replace(OSC133_ANYWHERE_PATTERN, (marker: string, code: string) => {
57
- if (allowedCodes.has(code)) {
58
- target.push(marker);
59
- return "";
60
- }
61
- return marker;
62
- });
63
- }
64
-
65
- export function collectBoundaryOscMarkersFromBlankEdges(extraction: OscExtraction, isBlankBoundaryLine: (line: string) => boolean, isProtectedLine: (line: string) => boolean): OscExtraction {
66
- try {
67
- const clean = [...extraction.lines];
68
- const startMarkers = [...extraction.startMarkers];
69
- const endMarkers = [...extraction.endMarkers];
70
- for (let index = 0; index < clean.length; index += 1) {
71
- const line = clean[index] ?? "";
72
- if (isProtectedLine(line)) break;
73
- const stripped = stripOsc133Markers(line, startMarkers, OSC133_START_CODES);
74
- clean[index] = stripped;
75
- if (!isBlankBoundaryLine(stripped)) break;
76
- }
77
- for (let index = clean.length - 1; index >= 0; index -= 1) {
78
- const line = clean[index] ?? "";
79
- if (isProtectedLine(line)) break;
80
- const lineEndMarkers: string[] = [];
81
- const stripped = stripOsc133Markers(line, lineEndMarkers, OSC133_END_CODES);
82
- if (lineEndMarkers.length > 0) endMarkers.unshift(...lineEndMarkers);
83
- clean[index] = stripped;
84
- if (!isBlankBoundaryLine(stripped)) break;
85
- }
86
- return { lines: clean, startMarkers, endMarkers };
87
- } catch {
88
- return extraction;
89
- }
90
- }
91
-
92
- export const stripBoundaryOscMarkers = extractBoundaryOscMarkers;
93
-
94
- function clampLineIndex(index: number | undefined, fallback: number, length: number): number {
95
- if (!Number.isFinite(index)) return fallback;
96
- return Math.min(Math.max(0, Math.floor(index as number)), Math.max(0, length - 1));
97
- }
98
-
99
- export function restoreBoundaryOscMarkers(lines: readonly string[], markers: OscExtraction, options: OscRestoreOptions = {}): string[] {
100
- if (lines.length === 0) return [];
101
- const restored = [...lines];
102
- if (markers.startMarkers.length > 0) {
103
- const startIndex = clampLineIndex(options.startIndex, 0, restored.length);
104
- restored[startIndex] = markers.startMarkers.join("") + restored[startIndex];
105
- }
106
- if (markers.endMarkers.length > 0) {
107
- const endIndex = clampLineIndex(options.endIndex, restored.length - 1, restored.length);
108
- restored[endIndex] = markers.endMarkers.join("") + restored[endIndex];
109
- }
110
- return restored;
111
- }