shellfie-cli 2.0.1 → 2.0.2
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 +1 -1
- package/dist/animator.d.ts +8 -0
- package/dist/animator.d.ts.map +1 -0
- package/dist/animator.js +210 -0
- package/dist/animator.js.map +1 -0
- package/dist/dvd-executor-v2.d.ts +76 -0
- package/dist/dvd-executor-v2.d.ts.map +1 -0
- package/dist/dvd-executor-v2.js +258 -0
- package/dist/dvd-executor-v2.js.map +1 -0
- package/dist/dvd-executor.d.ts +144 -0
- package/dist/dvd-executor.d.ts.map +1 -0
- package/dist/dvd-executor.js +669 -0
- package/dist/dvd-executor.js.map +1 -0
- package/dist/dvd-parser.d.ts +96 -0
- package/dist/dvd-parser.d.ts.map +1 -0
- package/dist/dvd-parser.js +279 -0
- package/dist/dvd-parser.js.map +1 -0
- package/dist/dvd.d.ts +31 -0
- package/dist/dvd.d.ts.map +1 -0
- package/dist/dvd.js +154 -0
- package/dist/dvd.js.map +1 -0
- package/dist/frame-animator.d.ts +21 -0
- package/dist/frame-animator.d.ts.map +1 -0
- package/dist/frame-animator.js +254 -0
- package/dist/frame-animator.js.map +1 -0
- package/dist/frame-capture.d.ts +16 -0
- package/dist/frame-capture.d.ts.map +1 -0
- package/dist/frame-capture.js +162 -0
- package/dist/frame-capture.js.map +1 -0
- package/dist/svg-animator-v2.d.ts +23 -0
- package/dist/svg-animator-v2.d.ts.map +1 -0
- package/dist/svg-animator-v2.js +134 -0
- package/dist/svg-animator-v2.js.map +1 -0
- package/dist/svg-animator.d.ts +23 -0
- package/dist/svg-animator.d.ts.map +1 -0
- package/dist/svg-animator.js +134 -0
- package/dist/svg-animator.js.map +1 -0
- package/dist/terminal-renderer.d.ts +34 -0
- package/dist/terminal-renderer.d.ts.map +1 -0
- package/dist/terminal-renderer.js +229 -0
- package/dist/terminal-renderer.js.map +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AnimationOptions } from './utils';
|
|
2
|
+
/**
|
|
3
|
+
* Injects animations into a static SVG to create a typing effect.
|
|
4
|
+
* Supports both SMIL and CSS animation methods.
|
|
5
|
+
* Splits tspans into individual characters for true character-by-character animation.
|
|
6
|
+
*/
|
|
7
|
+
export declare function injectAnimations(staticSvg: string, config: AnimationOptions): string;
|
|
8
|
+
//# sourceMappingURL=animator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animator.d.ts","sourceRoot":"","sources":["../src/animator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAQhD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAcpF"}
|
package/dist/animator.js
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.injectAnimations = injectAnimations;
|
|
4
|
+
/**
|
|
5
|
+
* Injects animations into a static SVG to create a typing effect.
|
|
6
|
+
* Supports both SMIL and CSS animation methods.
|
|
7
|
+
* Splits tspans into individual characters for true character-by-character animation.
|
|
8
|
+
*/
|
|
9
|
+
function injectAnimations(staticSvg, config) {
|
|
10
|
+
if (!config.enabled)
|
|
11
|
+
return staticSvg;
|
|
12
|
+
// First, split all tspans into character-level tspans
|
|
13
|
+
const characterSvg = splitTspansIntoCharacters(staticSvg);
|
|
14
|
+
const spans = parseSvgTextSpans(characterSvg);
|
|
15
|
+
if (spans.length === 0)
|
|
16
|
+
return staticSvg;
|
|
17
|
+
if (config.method === 'smil') {
|
|
18
|
+
return injectSmilAnimations(characterSvg, spans, config);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
return injectCssAnimations(characterSvg, spans, config);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Splits all tspans into character-level tspans for character-by-character animation.
|
|
26
|
+
*/
|
|
27
|
+
function splitTspansIntoCharacters(svg) {
|
|
28
|
+
const tspanRegex = /<tspan([^>]*)>(.*?)<\/tspan>/gs;
|
|
29
|
+
return svg.replace(tspanRegex, (match, attributes, content) => {
|
|
30
|
+
// Skip truly empty tspans (but NOT spaces - spaces are valid characters!)
|
|
31
|
+
if (!content || content.length === 0) {
|
|
32
|
+
return match;
|
|
33
|
+
}
|
|
34
|
+
// Extract x position from attributes
|
|
35
|
+
const xMatch = attributes.match(/x="([^"]*)"/);
|
|
36
|
+
const baseX = xMatch ? parseFloat(xMatch[1]) : 0;
|
|
37
|
+
// Extract font size from parent text element or use default
|
|
38
|
+
// We'll need to search backwards in the SVG for the font-size
|
|
39
|
+
const fontSizeMatch = svg.match(/font-size="(\d+)"/);
|
|
40
|
+
const fontSize = fontSizeMatch ? parseFloat(fontSizeMatch[1]) : 14;
|
|
41
|
+
// Calculate character width (monospace: ~0.6 * fontSize)
|
|
42
|
+
const charWidth = fontSize * 0.6;
|
|
43
|
+
// Extract text content
|
|
44
|
+
const text = content;
|
|
45
|
+
// Split into individual characters
|
|
46
|
+
const chars = [...text]; // Use spread to handle Unicode correctly
|
|
47
|
+
// Create a tspan for each character with progressive x positions
|
|
48
|
+
const charTspans = chars.map((char, index) => {
|
|
49
|
+
// Calculate x position for this character
|
|
50
|
+
const xPos = baseX + (index * charWidth);
|
|
51
|
+
// Remove x attribute from original attributes (handle both before and after other attrs)
|
|
52
|
+
let attrsWithoutX = attributes.replace(/\s*x="[^"]*"\s*/, ' ').trim();
|
|
53
|
+
// Escape special XML characters
|
|
54
|
+
const escapedChar = char
|
|
55
|
+
.replace(/&/g, '&')
|
|
56
|
+
.replace(/</g, '<')
|
|
57
|
+
.replace(/>/g, '>');
|
|
58
|
+
// CRITICAL: Set initial opacity to 0 so character is hidden until animation starts
|
|
59
|
+
// Always put x first, then other attributes, then opacity
|
|
60
|
+
const finalAttrs = attrsWithoutX ? ` x="${xPos.toFixed(1)}" ${attrsWithoutX} opacity="0"` : ` x="${xPos.toFixed(1)}" opacity="0"`;
|
|
61
|
+
return `<tspan${finalAttrs}>${escapedChar}</tspan>`;
|
|
62
|
+
}).join('');
|
|
63
|
+
return charTspans;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Parses SVG string to find all <tspan> elements.
|
|
68
|
+
*/
|
|
69
|
+
function parseSvgTextSpans(svg) {
|
|
70
|
+
const tspanRegex = /<tspan[^>]*>.*?<\/tspan>/gs;
|
|
71
|
+
const matches = [...svg.matchAll(tspanRegex)];
|
|
72
|
+
return matches.map((m) => ({
|
|
73
|
+
element: m[0],
|
|
74
|
+
startIndex: m.index,
|
|
75
|
+
endIndex: m.index + m[0].length,
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Injects SMIL <animate> elements into each tspan for progressive reveal.
|
|
80
|
+
*/
|
|
81
|
+
function injectSmilAnimations(svg, spans, config) {
|
|
82
|
+
let animatedSvg = svg;
|
|
83
|
+
let offset = 0;
|
|
84
|
+
// Calculate total animation duration for looping
|
|
85
|
+
const lastCharDelay = calculateDelay(spans.length - 1, config);
|
|
86
|
+
const fadeDuration = 0.1;
|
|
87
|
+
const totalDuration = lastCharDelay + fadeDuration;
|
|
88
|
+
spans.forEach((span, index) => {
|
|
89
|
+
const delay = calculateDelay(index, config);
|
|
90
|
+
const animatedSpan = addSmilAnimation(span.element, delay, fadeDuration, config.loop, totalDuration);
|
|
91
|
+
const diff = animatedSpan.length - span.element.length;
|
|
92
|
+
const start = span.startIndex + offset;
|
|
93
|
+
const end = span.endIndex + offset;
|
|
94
|
+
animatedSvg = animatedSvg.substring(0, start) + animatedSpan + animatedSvg.substring(end);
|
|
95
|
+
offset += diff;
|
|
96
|
+
});
|
|
97
|
+
return animatedSvg;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Adds SMIL animation to a tspan element.
|
|
101
|
+
*/
|
|
102
|
+
function addSmilAnimation(tspanElement, delay, duration, loop, totalDuration) {
|
|
103
|
+
// Check if tspan is self-closing or has content
|
|
104
|
+
const isSelfClosing = tspanElement.endsWith('/>');
|
|
105
|
+
if (isSelfClosing) {
|
|
106
|
+
// For self-closing tspans, convert to open/close format and add animation
|
|
107
|
+
const openTag = tspanElement.replace('/>', '>');
|
|
108
|
+
const animateTag = createSmilAnimateTag(delay, duration, loop, totalDuration);
|
|
109
|
+
return openTag + animateTag + '</tspan>';
|
|
110
|
+
}
|
|
111
|
+
// For regular tspans, insert animation before closing tag
|
|
112
|
+
const animateTag = createSmilAnimateTag(delay, duration, loop, totalDuration);
|
|
113
|
+
return tspanElement.replace('</tspan>', animateTag + '</tspan>');
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Creates a SMIL <animate> tag.
|
|
117
|
+
* For looping: creates a sequence that fades in, stays visible, then resets and repeats.
|
|
118
|
+
* For non-looping: fades in and stays visible with fill="freeze".
|
|
119
|
+
*/
|
|
120
|
+
function createSmilAnimateTag(delay, duration, loop, totalDuration) {
|
|
121
|
+
if (loop) {
|
|
122
|
+
// For looping: each character fades in at its delay time, stays visible, then all reset at once
|
|
123
|
+
// Use begin with delay to start each character's animation at the right time
|
|
124
|
+
// The animation itself is: fade in (0->1) over duration, then reset to 0 at end of total cycle
|
|
125
|
+
const pauseDuration = totalDuration + 0.5; // Add 0.5s pause between loops
|
|
126
|
+
return `<animate attributeName="opacity" values="0;1;1;0" keyTimes="0;${(duration / pauseDuration).toFixed(3)};${((pauseDuration - 0.01) / pauseDuration).toFixed(3)};1" begin="${delay.toFixed(3)}s" dur="${pauseDuration.toFixed(3)}s" repeatCount="indefinite"/>`;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
// For non-looping: use fill="freeze" to keep final state
|
|
130
|
+
return `<animate attributeName="opacity" from="0" to="1" begin="${delay.toFixed(3)}s" dur="${duration.toFixed(3)}s" fill="freeze"/>`;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Injects CSS animations by adding a stylesheet and classes to each tspan.
|
|
135
|
+
*/
|
|
136
|
+
function injectCssAnimations(svg, spans, config) {
|
|
137
|
+
const stylesheet = generateCssStylesheet(spans.length, config);
|
|
138
|
+
// Find the <defs> section or create one
|
|
139
|
+
let animatedSvg = svg;
|
|
140
|
+
const defsMatch = svg.match(/<defs>[\s\S]*?<\/defs>/);
|
|
141
|
+
if (defsMatch) {
|
|
142
|
+
// Insert stylesheet inside existing <defs>
|
|
143
|
+
animatedSvg = svg.replace('</defs>', ` <style>${stylesheet}</style>\n </defs>`);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// Create new <defs> section after opening <svg> tag
|
|
147
|
+
const svgOpenMatch = svg.match(/<svg[^>]*>/);
|
|
148
|
+
if (svgOpenMatch) {
|
|
149
|
+
const insertPos = svgOpenMatch.index + svgOpenMatch[0].length;
|
|
150
|
+
animatedSvg = svg.substring(0, insertPos) +
|
|
151
|
+
`\n <defs>\n <style>${stylesheet}</style>\n </defs>` +
|
|
152
|
+
svg.substring(insertPos);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Add classes to tspans
|
|
156
|
+
let offset = animatedSvg.length - svg.length; // Account for added stylesheet
|
|
157
|
+
spans.forEach((span, index) => {
|
|
158
|
+
const className = `anim-char-${index}`;
|
|
159
|
+
const modifiedSpan = addClassToTspan(span.element, className);
|
|
160
|
+
const diff = modifiedSpan.length - span.element.length;
|
|
161
|
+
const start = span.startIndex + offset;
|
|
162
|
+
const end = span.endIndex + offset;
|
|
163
|
+
animatedSvg = animatedSvg.substring(0, start) + modifiedSpan + animatedSvg.substring(end);
|
|
164
|
+
offset += diff;
|
|
165
|
+
});
|
|
166
|
+
return animatedSvg;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Generates CSS stylesheet for animations.
|
|
170
|
+
*/
|
|
171
|
+
function generateCssStylesheet(spanCount, config) {
|
|
172
|
+
const keyframes = `
|
|
173
|
+
@keyframes fadeIn {
|
|
174
|
+
from { opacity: 0; }
|
|
175
|
+
to { opacity: 1; }
|
|
176
|
+
}
|
|
177
|
+
`;
|
|
178
|
+
const classRules = Array.from({ length: spanCount }, (_, index) => {
|
|
179
|
+
const delay = calculateDelay(index, config);
|
|
180
|
+
const duration = 0.1;
|
|
181
|
+
const fillMode = 'forwards';
|
|
182
|
+
const iteration = config.loop ? 'infinite' : '1';
|
|
183
|
+
return `.anim-char-${index} { opacity: 0; animation: fadeIn ${duration}s ${delay}s ${fillMode}; animation-iteration-count: ${iteration}; }`;
|
|
184
|
+
}).join('\n ');
|
|
185
|
+
return keyframes + '\n ' + classRules;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Adds a class attribute to a tspan element.
|
|
189
|
+
*/
|
|
190
|
+
function addClassToTspan(tspanElement, className) {
|
|
191
|
+
// Check if tspan already has a class attribute
|
|
192
|
+
const classMatch = tspanElement.match(/class="([^"]*)"/);
|
|
193
|
+
if (classMatch) {
|
|
194
|
+
// Append to existing class
|
|
195
|
+
return tspanElement.replace(/class="([^"]*)"/, `class="$1 ${className}"`);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
// Add new class attribute before closing >
|
|
199
|
+
return tspanElement.replace(/<tspan([^>]*)>/, `<tspan$1 class="${className}">`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Calculates the delay for a given character index based on animation config.
|
|
204
|
+
*/
|
|
205
|
+
function calculateDelay(index, config) {
|
|
206
|
+
const baseDelay = (index * config.charDelay) / 1000; // Convert ms to seconds
|
|
207
|
+
const adjustedDelay = baseDelay / config.speed;
|
|
208
|
+
return config.initialDelay + adjustedDelay;
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=animator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animator.js","sourceRoot":"","sources":["../src/animator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DVD Command Executor V2
|
|
3
|
+
* Executes real commands with typing effect and cursor
|
|
4
|
+
*/
|
|
5
|
+
import type { DVDScript } from './dvd-parser';
|
|
6
|
+
import { type TerminalState } from './terminal-renderer';
|
|
7
|
+
export interface TerminalFrame {
|
|
8
|
+
timestamp: number;
|
|
9
|
+
svg: string;
|
|
10
|
+
state: TerminalState;
|
|
11
|
+
}
|
|
12
|
+
export interface SimulatorContext {
|
|
13
|
+
lines: string[];
|
|
14
|
+
currentLine: string;
|
|
15
|
+
cursorX: number;
|
|
16
|
+
cursorY: number;
|
|
17
|
+
frames: TerminalFrame[];
|
|
18
|
+
clipboard: string;
|
|
19
|
+
startTime: number;
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
fontSize: number;
|
|
23
|
+
title?: string;
|
|
24
|
+
template?: 'macos' | 'windows' | 'minimal';
|
|
25
|
+
}
|
|
26
|
+
export interface DVDExecutorOptions {
|
|
27
|
+
width?: number;
|
|
28
|
+
height?: number;
|
|
29
|
+
fontSize?: number;
|
|
30
|
+
title?: string;
|
|
31
|
+
template?: 'macos' | 'windows' | 'minimal';
|
|
32
|
+
onFrame?: (frame: TerminalFrame) => void;
|
|
33
|
+
onProgress?: (current: number, total: number) => void;
|
|
34
|
+
}
|
|
35
|
+
export declare class DVDExecutorV2 {
|
|
36
|
+
private context;
|
|
37
|
+
private options;
|
|
38
|
+
constructor(options?: DVDExecutorOptions);
|
|
39
|
+
/**
|
|
40
|
+
* Capture current terminal state as a frame
|
|
41
|
+
*/
|
|
42
|
+
private captureFrame;
|
|
43
|
+
/**
|
|
44
|
+
* Execute Type command - simulate typing character by character
|
|
45
|
+
*/
|
|
46
|
+
private executeType;
|
|
47
|
+
/**
|
|
48
|
+
* Execute Enter - run the command and capture output
|
|
49
|
+
*/
|
|
50
|
+
private executeEnter;
|
|
51
|
+
/**
|
|
52
|
+
* Execute arrow keys
|
|
53
|
+
*/
|
|
54
|
+
private executeArrow;
|
|
55
|
+
/**
|
|
56
|
+
* Execute Backspace
|
|
57
|
+
*/
|
|
58
|
+
private executeBackspace;
|
|
59
|
+
/**
|
|
60
|
+
* Execute a single command
|
|
61
|
+
*/
|
|
62
|
+
private executeCommand;
|
|
63
|
+
/**
|
|
64
|
+
* Execute complete DVD script
|
|
65
|
+
*/
|
|
66
|
+
execute(script: DVDScript): Promise<TerminalFrame[]>;
|
|
67
|
+
/**
|
|
68
|
+
* Get all captured frames
|
|
69
|
+
*/
|
|
70
|
+
getFrames(): TerminalFrame[];
|
|
71
|
+
/**
|
|
72
|
+
* Cleanup (no-op for simulation)
|
|
73
|
+
*/
|
|
74
|
+
cleanup(): Promise<void>;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=dvd-executor-v2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dvd-executor-v2.d.ts","sourceRoot":"","sources":["../src/dvd-executor-v2.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAc,SAAS,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAA0C,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIjG,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,aAAa,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;CAC5C;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;IAC3C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACzC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACvD;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,OAAO,CAAqB;gBAExB,OAAO,GAAE,kBAAuB;IAmB5C;;OAEG;IACH,OAAO,CAAC,YAAY;IA6BpB;;OAEG;YACW,WAAW;IAazB;;OAEG;YACW,YAAY;IA2D1B;;OAEG;YACW,YAAY;IA4B1B;;OAEG;YACW,gBAAgB;IAY9B;;OAEG;YACW,cAAc;IAsD5B;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IA6B1D;;OAEG;IACH,SAAS,IAAI,aAAa,EAAE;IAI5B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* DVD Command Executor V2
|
|
4
|
+
* Executes real commands with typing effect and cursor
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.DVDExecutorV2 = void 0;
|
|
8
|
+
const node_child_process_1 = require("node:child_process");
|
|
9
|
+
const node_util_1 = require("node:util");
|
|
10
|
+
const terminal_renderer_1 = require("./terminal-renderer");
|
|
11
|
+
const execAsync = (0, node_util_1.promisify)(node_child_process_1.exec);
|
|
12
|
+
class DVDExecutorV2 {
|
|
13
|
+
context;
|
|
14
|
+
options;
|
|
15
|
+
constructor(options = {}) {
|
|
16
|
+
this.options = options;
|
|
17
|
+
this.context = {
|
|
18
|
+
lines: [''],
|
|
19
|
+
currentLine: '',
|
|
20
|
+
cursorX: 0,
|
|
21
|
+
cursorY: 0,
|
|
22
|
+
frames: [],
|
|
23
|
+
clipboard: '',
|
|
24
|
+
startTime: Date.now(),
|
|
25
|
+
width: options.width || 800,
|
|
26
|
+
height: options.height || 600,
|
|
27
|
+
fontSize: options.fontSize || 14,
|
|
28
|
+
title: options.title,
|
|
29
|
+
template: options.template || 'macos',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Capture current terminal state as a frame
|
|
34
|
+
*/
|
|
35
|
+
captureFrame(showCursor = true) {
|
|
36
|
+
const buffer = [...this.context.lines];
|
|
37
|
+
buffer[this.context.cursorY] = this.context.currentLine;
|
|
38
|
+
const state = (0, terminal_renderer_1.createTerminalState)(buffer.join('\n'), this.context.cursorX, this.context.cursorY, this.context.width, this.context.height, this.context.fontSize, showCursor);
|
|
39
|
+
const svg = (0, terminal_renderer_1.renderTerminalSVG)(state, {
|
|
40
|
+
title: this.context.title,
|
|
41
|
+
template: this.context.template,
|
|
42
|
+
});
|
|
43
|
+
const frame = {
|
|
44
|
+
timestamp: Date.now() - this.context.startTime,
|
|
45
|
+
svg,
|
|
46
|
+
state,
|
|
47
|
+
};
|
|
48
|
+
this.context.frames.push(frame);
|
|
49
|
+
this.options.onFrame?.(frame);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Execute Type command - simulate typing character by character
|
|
53
|
+
*/
|
|
54
|
+
async executeType(text, speed) {
|
|
55
|
+
const delay = speed || 50;
|
|
56
|
+
for (const char of text) {
|
|
57
|
+
this.context.currentLine += char;
|
|
58
|
+
this.context.cursorX++;
|
|
59
|
+
// Capture frame showing the new character with cursor
|
|
60
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
61
|
+
this.captureFrame(true);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Execute Enter - run the command and capture output
|
|
66
|
+
*/
|
|
67
|
+
async executeEnter() {
|
|
68
|
+
const command = this.context.currentLine.trim();
|
|
69
|
+
// Finalize current line (the command that was typed)
|
|
70
|
+
this.context.lines[this.context.cursorY] = this.context.currentLine;
|
|
71
|
+
// Move to next line
|
|
72
|
+
this.context.cursorY++;
|
|
73
|
+
this.context.cursorX = 0;
|
|
74
|
+
this.context.currentLine = '';
|
|
75
|
+
if (!this.context.lines[this.context.cursorY]) {
|
|
76
|
+
this.context.lines[this.context.cursorY] = '';
|
|
77
|
+
}
|
|
78
|
+
// Capture frame showing command was submitted (cursor on new line)
|
|
79
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
80
|
+
this.captureFrame(true);
|
|
81
|
+
// Execute the command if it's not empty
|
|
82
|
+
if (command) {
|
|
83
|
+
try {
|
|
84
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
85
|
+
env: { ...process.env, FORCE_COLOR: '1', CLICOLOR_FORCE: '1' },
|
|
86
|
+
maxBuffer: 10 * 1024 * 1024, // 10MB buffer
|
|
87
|
+
});
|
|
88
|
+
const output = (stdout + stderr).trim();
|
|
89
|
+
if (output) {
|
|
90
|
+
// Split output into lines and add to terminal
|
|
91
|
+
const outputLines = output.split('\n');
|
|
92
|
+
for (const line of outputLines) {
|
|
93
|
+
this.context.lines[this.context.cursorY] = line;
|
|
94
|
+
this.context.cursorY++;
|
|
95
|
+
this.context.lines[this.context.cursorY] = '';
|
|
96
|
+
}
|
|
97
|
+
// Capture frame showing command output
|
|
98
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
99
|
+
this.captureFrame(true);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
// Command failed - show error output
|
|
104
|
+
const error = err;
|
|
105
|
+
const errorOutput = (error.stderr || error.stdout || 'Command failed').trim();
|
|
106
|
+
const errorLines = errorOutput.split('\n');
|
|
107
|
+
for (const line of errorLines) {
|
|
108
|
+
this.context.lines[this.context.cursorY] = line;
|
|
109
|
+
this.context.cursorY++;
|
|
110
|
+
this.context.lines[this.context.cursorY] = '';
|
|
111
|
+
}
|
|
112
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
113
|
+
this.captureFrame(true);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Execute arrow keys
|
|
119
|
+
*/
|
|
120
|
+
async executeArrow(direction) {
|
|
121
|
+
switch (direction) {
|
|
122
|
+
case 'Left':
|
|
123
|
+
if (this.context.cursorX > 0)
|
|
124
|
+
this.context.cursorX--;
|
|
125
|
+
break;
|
|
126
|
+
case 'Right':
|
|
127
|
+
if (this.context.cursorX < this.context.currentLine.length)
|
|
128
|
+
this.context.cursorX++;
|
|
129
|
+
break;
|
|
130
|
+
case 'Up':
|
|
131
|
+
if (this.context.cursorY > 0) {
|
|
132
|
+
this.context.cursorY--;
|
|
133
|
+
this.context.currentLine = this.context.lines[this.context.cursorY];
|
|
134
|
+
this.context.cursorX = Math.min(this.context.cursorX, this.context.currentLine.length);
|
|
135
|
+
}
|
|
136
|
+
break;
|
|
137
|
+
case 'Down':
|
|
138
|
+
if (this.context.cursorY < this.context.lines.length - 1) {
|
|
139
|
+
this.context.cursorY++;
|
|
140
|
+
this.context.currentLine = this.context.lines[this.context.cursorY];
|
|
141
|
+
this.context.cursorX = Math.min(this.context.cursorX, this.context.currentLine.length);
|
|
142
|
+
}
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
146
|
+
this.captureFrame(true);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Execute Backspace
|
|
150
|
+
*/
|
|
151
|
+
async executeBackspace() {
|
|
152
|
+
if (this.context.cursorX > 0) {
|
|
153
|
+
this.context.currentLine =
|
|
154
|
+
this.context.currentLine.slice(0, this.context.cursorX - 1) +
|
|
155
|
+
this.context.currentLine.slice(this.context.cursorX);
|
|
156
|
+
this.context.cursorX--;
|
|
157
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
158
|
+
this.captureFrame(true);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Execute a single command
|
|
163
|
+
*/
|
|
164
|
+
async executeCommand(command) {
|
|
165
|
+
switch (command.type) {
|
|
166
|
+
case 'Type':
|
|
167
|
+
await this.executeType(command.text, command.speed);
|
|
168
|
+
break;
|
|
169
|
+
case 'Key':
|
|
170
|
+
if (['Left', 'Right', 'Up', 'Down'].includes(command.key)) {
|
|
171
|
+
await this.executeArrow(command.key);
|
|
172
|
+
}
|
|
173
|
+
else if (command.key === 'Enter') {
|
|
174
|
+
await this.executeEnter();
|
|
175
|
+
}
|
|
176
|
+
else if (command.key === 'Backspace') {
|
|
177
|
+
await this.executeBackspace();
|
|
178
|
+
}
|
|
179
|
+
else if (command.key === 'Space') {
|
|
180
|
+
await this.executeType(' ');
|
|
181
|
+
}
|
|
182
|
+
else if (command.key === 'Tab') {
|
|
183
|
+
await this.executeType(' '); // 4 spaces
|
|
184
|
+
}
|
|
185
|
+
break;
|
|
186
|
+
case 'Sleep':
|
|
187
|
+
await new Promise((resolve) => setTimeout(resolve, command.duration));
|
|
188
|
+
this.captureFrame(true);
|
|
189
|
+
break;
|
|
190
|
+
case 'Screenshot':
|
|
191
|
+
this.captureFrame(true);
|
|
192
|
+
break;
|
|
193
|
+
case 'Copy':
|
|
194
|
+
this.context.clipboard = command.text;
|
|
195
|
+
break;
|
|
196
|
+
case 'Paste':
|
|
197
|
+
if (this.context.clipboard) {
|
|
198
|
+
await this.executeType(this.context.clipboard);
|
|
199
|
+
}
|
|
200
|
+
break;
|
|
201
|
+
case 'Hide':
|
|
202
|
+
case 'Show':
|
|
203
|
+
case 'Output':
|
|
204
|
+
case 'Require':
|
|
205
|
+
case 'Set':
|
|
206
|
+
case 'Source':
|
|
207
|
+
case 'Env':
|
|
208
|
+
case 'Comment':
|
|
209
|
+
case 'Shortcut':
|
|
210
|
+
case 'Wait':
|
|
211
|
+
// Not implemented in simulation mode
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Execute complete DVD script
|
|
217
|
+
*/
|
|
218
|
+
async execute(script) {
|
|
219
|
+
// Apply settings
|
|
220
|
+
for (const [key, value] of script.settings.entries()) {
|
|
221
|
+
if (key === 'Width')
|
|
222
|
+
this.context.width = parseInt(value, 10);
|
|
223
|
+
if (key === 'Height')
|
|
224
|
+
this.context.height = parseInt(value, 10);
|
|
225
|
+
if (key === 'FontSize')
|
|
226
|
+
this.context.fontSize = parseInt(value, 10);
|
|
227
|
+
if (key === 'Title')
|
|
228
|
+
this.context.title = value;
|
|
229
|
+
if (key === 'Template')
|
|
230
|
+
this.context.template = value;
|
|
231
|
+
}
|
|
232
|
+
// Capture initial frame
|
|
233
|
+
this.captureFrame(true);
|
|
234
|
+
// Execute commands
|
|
235
|
+
const actionCommands = script.commands.filter((cmd) => !['Output', 'Require', 'Set', 'Env'].includes(cmd.type));
|
|
236
|
+
for (let i = 0; i < actionCommands.length; i++) {
|
|
237
|
+
await this.executeCommand(actionCommands[i]);
|
|
238
|
+
this.options.onProgress?.(i + 1, actionCommands.length);
|
|
239
|
+
}
|
|
240
|
+
// Capture final frame without cursor
|
|
241
|
+
this.captureFrame(false);
|
|
242
|
+
return this.context.frames;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Get all captured frames
|
|
246
|
+
*/
|
|
247
|
+
getFrames() {
|
|
248
|
+
return this.context.frames;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Cleanup (no-op for simulation)
|
|
252
|
+
*/
|
|
253
|
+
async cleanup() {
|
|
254
|
+
// Nothing to clean up in simulation mode
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
exports.DVDExecutorV2 = DVDExecutorV2;
|
|
258
|
+
//# sourceMappingURL=dvd-executor-v2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dvd-executor-v2.js","sourceRoot":"","sources":["../src/dvd-executor-v2.ts"],"names":[],"mappings":"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"}
|