@ellery/terminal-mcp 0.2.1 → 0.2.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 +151 -5
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -61
- package/dist/client.js.map +1 -1
- package/dist/index.js +235 -13
- package/dist/index.js.map +1 -1
- package/dist/recording/index.d.ts +4 -0
- package/dist/recording/index.d.ts.map +1 -0
- package/dist/recording/index.js +3 -0
- package/dist/recording/index.js.map +1 -0
- package/dist/recording/manager.d.ts +62 -0
- package/dist/recording/manager.d.ts.map +1 -0
- package/dist/recording/manager.js +123 -0
- package/dist/recording/manager.js.map +1 -0
- package/dist/recording/recorder.d.ts +95 -0
- package/dist/recording/recorder.d.ts.map +1 -0
- package/dist/recording/recorder.js +296 -0
- package/dist/recording/recorder.js.map +1 -0
- package/dist/recording/types.d.ts +65 -0
- package/dist/recording/types.d.ts.map +1 -0
- package/dist/recording/types.js +2 -0
- package/dist/recording/types.js.map +1 -0
- package/dist/sandbox/config.d.ts +46 -0
- package/dist/sandbox/config.d.ts.map +1 -0
- package/dist/sandbox/config.js +144 -0
- package/dist/sandbox/config.js.map +1 -0
- package/dist/sandbox/controller.d.ts +72 -0
- package/dist/sandbox/controller.d.ts.map +1 -0
- package/dist/sandbox/controller.js +208 -0
- package/dist/sandbox/controller.js.map +1 -0
- package/dist/sandbox/index.d.ts +6 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +4 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/prompt.d.ts +10 -0
- package/dist/sandbox/prompt.d.ts.map +1 -0
- package/dist/sandbox/prompt.js +434 -0
- package/dist/sandbox/prompt.js.map +1 -0
- package/dist/terminal/index.d.ts +1 -0
- package/dist/terminal/index.d.ts.map +1 -1
- package/dist/terminal/manager.d.ts +58 -3
- package/dist/terminal/manager.d.ts.map +1 -1
- package/dist/terminal/manager.js +118 -3
- package/dist/terminal/manager.js.map +1 -1
- package/dist/terminal/session.d.ts +21 -1
- package/dist/terminal/session.d.ts.map +1 -1
- package/dist/terminal/session.js +44 -3
- package/dist/terminal/session.js.map +1 -1
- package/dist/tools/definitions.d.ts +18 -0
- package/dist/tools/definitions.d.ts.map +1 -0
- package/dist/tools/definitions.js +110 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +7 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/startRecording.d.ts +68 -0
- package/dist/tools/startRecording.d.ts.map +1 -0
- package/dist/tools/startRecording.js +111 -0
- package/dist/tools/startRecording.js.map +1 -0
- package/dist/tools/stopRecording.d.ts +31 -0
- package/dist/tools/stopRecording.d.ts.map +1 -0
- package/dist/tools/stopRecording.js +76 -0
- package/dist/tools/stopRecording.js.map +1 -0
- package/dist/transport/socket.d.ts.map +1 -1
- package/dist/transport/socket.js +10 -0
- package/dist/transport/socket.js.map +1 -1
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +17 -1
- package/dist/ui/index.js.map +1 -1
- package/dist/utils/platform.d.ts +6 -0
- package/dist/utils/platform.d.ts.map +1 -1
- package/dist/utils/platform.js +15 -0
- package/dist/utils/platform.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Recorder } from "./recorder.js";
|
|
2
|
+
import { RecordingMode, RecordingOptions, RecordingMetadata, StopReason } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* RecordingManager tracks and manages multiple recordings
|
|
5
|
+
*/
|
|
6
|
+
export declare class RecordingManager {
|
|
7
|
+
private recordings;
|
|
8
|
+
private defaultOptions;
|
|
9
|
+
constructor(options?: Partial<RecordingOptions>);
|
|
10
|
+
/**
|
|
11
|
+
* Create a new recording
|
|
12
|
+
* Returns the recorder instance
|
|
13
|
+
*/
|
|
14
|
+
createRecording(options?: Partial<RecordingOptions>): Recorder;
|
|
15
|
+
/**
|
|
16
|
+
* Get a recording by ID
|
|
17
|
+
*/
|
|
18
|
+
getRecording(id: string): Recorder | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Check if a recording exists
|
|
21
|
+
*/
|
|
22
|
+
hasRecording(id: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Get all active recordings
|
|
25
|
+
*/
|
|
26
|
+
getActiveRecordings(): Recorder[];
|
|
27
|
+
/**
|
|
28
|
+
* Get the count of active recordings
|
|
29
|
+
*/
|
|
30
|
+
getActiveCount(): number;
|
|
31
|
+
/**
|
|
32
|
+
* Record output to all active recordings
|
|
33
|
+
*/
|
|
34
|
+
recordOutputToAll(data: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* Record resize to all active recordings
|
|
37
|
+
*/
|
|
38
|
+
recordResizeToAll(cols: number, rows: number): void;
|
|
39
|
+
/**
|
|
40
|
+
* Finalize a specific recording
|
|
41
|
+
*/
|
|
42
|
+
finalizeRecording(id: string, exitCode: number | null, stopReason?: StopReason): Promise<RecordingMetadata | undefined>;
|
|
43
|
+
/**
|
|
44
|
+
* Finalize all active recordings
|
|
45
|
+
* Returns array of metadata for all finalized recordings
|
|
46
|
+
*/
|
|
47
|
+
finalizeAll(exitCode: number | null, stopReason?: StopReason): Promise<RecordingMetadata[]>;
|
|
48
|
+
/**
|
|
49
|
+
* Get default recording mode
|
|
50
|
+
*/
|
|
51
|
+
getDefaultMode(): RecordingMode;
|
|
52
|
+
/**
|
|
53
|
+
* Get default output directory
|
|
54
|
+
*/
|
|
55
|
+
getDefaultOutputDir(): string;
|
|
56
|
+
/**
|
|
57
|
+
* Check if auto-recording is enabled (mode !== 'off')
|
|
58
|
+
*/
|
|
59
|
+
isAutoRecordingEnabled(): boolean;
|
|
60
|
+
private generateId;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/recording/manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,aAAa,EAEb,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACX,MAAM,YAAY,CAAC;AAGpB;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,cAAc,CAAmB;gBAE7B,OAAO,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC;IAW/C;;;OAGG;IACH,eAAe,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,QAAQ;IAqB9D;;OAEG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAI9C;;OAEG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIjC;;OAEG;IACH,mBAAmB,IAAI,QAAQ,EAAE;IAIjC;;OAEG;IACH,cAAc,IAAI,MAAM;IAIxB;;OAEG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAMrC;;OAEG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAMnD;;OAEG;IACG,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;IAW7H;;;OAGG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,UAAU,GAAE,UAA2B,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAcjH;;OAEG;IACH,cAAc,IAAI,aAAa;IAI/B;;OAEG;IACH,mBAAmB,IAAI,MAAM;IAI7B;;OAEG;IACH,sBAAsB,IAAI,OAAO;IAIjC,OAAO,CAAC,UAAU;CAGnB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import * as crypto from "crypto";
|
|
2
|
+
import { Recorder } from "./recorder.js";
|
|
3
|
+
import { getDefaultRecordDir } from "../utils/platform.js";
|
|
4
|
+
/**
|
|
5
|
+
* RecordingManager tracks and manages multiple recordings
|
|
6
|
+
*/
|
|
7
|
+
export class RecordingManager {
|
|
8
|
+
recordings = new Map();
|
|
9
|
+
defaultOptions;
|
|
10
|
+
constructor(options) {
|
|
11
|
+
this.defaultOptions = {
|
|
12
|
+
mode: options?.mode ?? 'off',
|
|
13
|
+
format: options?.format ?? 'v2',
|
|
14
|
+
outputDir: options?.outputDir ?? getDefaultRecordDir(),
|
|
15
|
+
idleTimeLimit: options?.idleTimeLimit ?? 2,
|
|
16
|
+
maxDuration: options?.maxDuration ?? 3600, // 60 minutes default
|
|
17
|
+
inactivityTimeout: options?.inactivityTimeout ?? 600, // 10 minutes default
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Create a new recording
|
|
22
|
+
* Returns the recorder instance
|
|
23
|
+
*/
|
|
24
|
+
createRecording(options) {
|
|
25
|
+
const id = this.generateId();
|
|
26
|
+
const mergedOptions = {
|
|
27
|
+
...this.defaultOptions,
|
|
28
|
+
...options,
|
|
29
|
+
};
|
|
30
|
+
const recorder = new Recorder(id, mergedOptions.mode, mergedOptions.outputDir, mergedOptions.format, mergedOptions.idleTimeLimit, mergedOptions.maxDuration, mergedOptions.inactivityTimeout);
|
|
31
|
+
this.recordings.set(id, recorder);
|
|
32
|
+
return recorder;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get a recording by ID
|
|
36
|
+
*/
|
|
37
|
+
getRecording(id) {
|
|
38
|
+
return this.recordings.get(id);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Check if a recording exists
|
|
42
|
+
*/
|
|
43
|
+
hasRecording(id) {
|
|
44
|
+
return this.recordings.has(id);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get all active recordings
|
|
48
|
+
*/
|
|
49
|
+
getActiveRecordings() {
|
|
50
|
+
return Array.from(this.recordings.values()).filter(r => r.isActive());
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get the count of active recordings
|
|
54
|
+
*/
|
|
55
|
+
getActiveCount() {
|
|
56
|
+
return this.getActiveRecordings().length;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Record output to all active recordings
|
|
60
|
+
*/
|
|
61
|
+
recordOutputToAll(data) {
|
|
62
|
+
for (const recorder of this.getActiveRecordings()) {
|
|
63
|
+
recorder.recordOutput(data);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Record resize to all active recordings
|
|
68
|
+
*/
|
|
69
|
+
recordResizeToAll(cols, rows) {
|
|
70
|
+
for (const recorder of this.getActiveRecordings()) {
|
|
71
|
+
recorder.recordResize(cols, rows);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Finalize a specific recording
|
|
76
|
+
*/
|
|
77
|
+
async finalizeRecording(id, exitCode, stopReason) {
|
|
78
|
+
const recorder = this.recordings.get(id);
|
|
79
|
+
if (!recorder) {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
const metadata = await recorder.finalize(exitCode, stopReason);
|
|
83
|
+
this.recordings.delete(id);
|
|
84
|
+
return metadata;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Finalize all active recordings
|
|
88
|
+
* Returns array of metadata for all finalized recordings
|
|
89
|
+
*/
|
|
90
|
+
async finalizeAll(exitCode, stopReason = 'session_exit') {
|
|
91
|
+
const results = [];
|
|
92
|
+
for (const [id, recorder] of this.recordings) {
|
|
93
|
+
if (recorder.isActive()) {
|
|
94
|
+
const metadata = await recorder.finalize(exitCode, stopReason);
|
|
95
|
+
results.push(metadata);
|
|
96
|
+
}
|
|
97
|
+
this.recordings.delete(id);
|
|
98
|
+
}
|
|
99
|
+
return results;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get default recording mode
|
|
103
|
+
*/
|
|
104
|
+
getDefaultMode() {
|
|
105
|
+
return this.defaultOptions.mode;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get default output directory
|
|
109
|
+
*/
|
|
110
|
+
getDefaultOutputDir() {
|
|
111
|
+
return this.defaultOptions.outputDir;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Check if auto-recording is enabled (mode !== 'off')
|
|
115
|
+
*/
|
|
116
|
+
isAutoRecordingEnabled() {
|
|
117
|
+
return this.defaultOptions.mode !== 'off';
|
|
118
|
+
}
|
|
119
|
+
generateId() {
|
|
120
|
+
return crypto.randomBytes(8).toString('hex');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/recording/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { RecordingMode, RecordingFormat, RecordingMetadata, StopReason } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Recorder handles writing asciicast v2 format recordings
|
|
4
|
+
*
|
|
5
|
+
* Asciicast v2 format:
|
|
6
|
+
* - First line: JSON header with version, dimensions, timestamp
|
|
7
|
+
* - Subsequent lines: JSON arrays [time, type, data]
|
|
8
|
+
* - time: seconds since start (float)
|
|
9
|
+
* - type: "o" for output, "r" for resize
|
|
10
|
+
* - data: string content
|
|
11
|
+
*/
|
|
12
|
+
export declare class Recorder {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
private mode;
|
|
15
|
+
private format;
|
|
16
|
+
private outputDir;
|
|
17
|
+
private tempPath;
|
|
18
|
+
private finalPath;
|
|
19
|
+
private writeStream;
|
|
20
|
+
private startTime;
|
|
21
|
+
private bytesWritten;
|
|
22
|
+
private finalized;
|
|
23
|
+
private idleTimeLimit;
|
|
24
|
+
private lastEventTime;
|
|
25
|
+
private adjustedElapsed;
|
|
26
|
+
private maxDuration;
|
|
27
|
+
private inactivityTimeout;
|
|
28
|
+
private maxDurationTimer;
|
|
29
|
+
private inactivityTimer;
|
|
30
|
+
private stopReason;
|
|
31
|
+
private onAutoFinalize?;
|
|
32
|
+
constructor(id: string, mode: RecordingMode, outputDir: string, format?: RecordingFormat, idleTimeLimit?: number, maxDuration?: number, // 60 minutes default
|
|
33
|
+
inactivityTimeout?: number);
|
|
34
|
+
/**
|
|
35
|
+
* Start the recording
|
|
36
|
+
* Writes the asciicast header to the temp file
|
|
37
|
+
*/
|
|
38
|
+
start(width: number, height: number, env?: {
|
|
39
|
+
SHELL?: string;
|
|
40
|
+
TERM?: string;
|
|
41
|
+
}): void;
|
|
42
|
+
/**
|
|
43
|
+
* Record output data
|
|
44
|
+
*/
|
|
45
|
+
recordOutput(data: string): void;
|
|
46
|
+
/**
|
|
47
|
+
* Record terminal resize event
|
|
48
|
+
*/
|
|
49
|
+
recordResize(cols: number, rows: number): void;
|
|
50
|
+
/**
|
|
51
|
+
* Finalize the recording
|
|
52
|
+
* - For 'always' mode: move temp file to output dir
|
|
53
|
+
* - For 'on-failure' mode: move if exitCode !== 0, delete otherwise
|
|
54
|
+
*
|
|
55
|
+
* Returns metadata about the recording
|
|
56
|
+
*/
|
|
57
|
+
finalize(exitCode: number | null, stopReason?: StopReason): Promise<RecordingMetadata>;
|
|
58
|
+
/**
|
|
59
|
+
* Check if recording is active
|
|
60
|
+
*/
|
|
61
|
+
isActive(): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Get the temp file path (for debugging/testing)
|
|
64
|
+
*/
|
|
65
|
+
getTempPath(): string;
|
|
66
|
+
/**
|
|
67
|
+
* Get the final file path
|
|
68
|
+
*/
|
|
69
|
+
getFinalPath(): string;
|
|
70
|
+
private getElapsedSeconds;
|
|
71
|
+
private writeLine;
|
|
72
|
+
/**
|
|
73
|
+
* Clear all active timers
|
|
74
|
+
*/
|
|
75
|
+
private clearTimers;
|
|
76
|
+
/**
|
|
77
|
+
* Auto-finalize the recording due to timeout
|
|
78
|
+
* Called internally when max duration or inactivity timeout is reached
|
|
79
|
+
*/
|
|
80
|
+
private _autoFinalize;
|
|
81
|
+
/**
|
|
82
|
+
* Set callback for auto-finalize events (timeout triggered)
|
|
83
|
+
*/
|
|
84
|
+
setOnAutoFinalize(callback: (metadata: RecordingMetadata) => void): void;
|
|
85
|
+
/**
|
|
86
|
+
* Get timeout configuration and remaining time
|
|
87
|
+
*/
|
|
88
|
+
getTimeoutInfo(): {
|
|
89
|
+
maxDuration: number;
|
|
90
|
+
inactivityTimeout: number;
|
|
91
|
+
elapsedSeconds: number;
|
|
92
|
+
remainingMaxDuration: number;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=recorder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/recording/recorder.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EAGf,iBAAiB,EACjB,UAAU,EACX,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;GASG;AACH,qBAAa,QAAQ;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,IAAI,CAAgB;IAC5B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,eAAe,CAAa;IAGpC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,gBAAgB,CAA8C;IACtE,OAAO,CAAC,eAAe,CAA8C;IACrE,OAAO,CAAC,UAAU,CAA0B;IAG5C,OAAO,CAAC,cAAc,CAAC,CAAwC;gBAG7D,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,aAAa,EACnB,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,eAAsB,EAC9B,aAAa,GAAE,MAAU,EACzB,WAAW,GAAE,MAAa,EAAS,qBAAqB;IACxD,iBAAiB,GAAE,MAAY;IAiBjC;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IA0CnF;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAkBhC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAU9C;;;;;;OAMG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAiF5F;;OAEG;IACH,QAAQ,IAAI,OAAO;IAInB;;OAEG;IACH,WAAW,IAAI,MAAM;IAIrB;;OAEG;IACH,YAAY,IAAI,MAAM;IAItB,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,SAAS;IAQjB;;OAEG;IACH,OAAO,CAAC,WAAW;IAWnB;;;OAGG;YACW,aAAa;IAc3B;;OAEG;IACH,iBAAiB,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,iBAAiB,KAAK,IAAI,GAAG,IAAI;IAIxE;;OAEG;IACH,cAAc,IAAI;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,cAAc,EAAE,MAAM,CAAC;QACvB,oBAAoB,EAAE,MAAM,CAAC;KAC9B;CAWF"}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as os from "os";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
/**
|
|
5
|
+
* Recorder handles writing asciicast v2 format recordings
|
|
6
|
+
*
|
|
7
|
+
* Asciicast v2 format:
|
|
8
|
+
* - First line: JSON header with version, dimensions, timestamp
|
|
9
|
+
* - Subsequent lines: JSON arrays [time, type, data]
|
|
10
|
+
* - time: seconds since start (float)
|
|
11
|
+
* - type: "o" for output, "r" for resize
|
|
12
|
+
* - data: string content
|
|
13
|
+
*/
|
|
14
|
+
export class Recorder {
|
|
15
|
+
id;
|
|
16
|
+
mode;
|
|
17
|
+
format;
|
|
18
|
+
outputDir;
|
|
19
|
+
tempPath;
|
|
20
|
+
finalPath;
|
|
21
|
+
writeStream = null;
|
|
22
|
+
startTime = 0;
|
|
23
|
+
bytesWritten = 0;
|
|
24
|
+
finalized = false;
|
|
25
|
+
idleTimeLimit;
|
|
26
|
+
lastEventTime = 0;
|
|
27
|
+
adjustedElapsed = 0;
|
|
28
|
+
// Timeout settings
|
|
29
|
+
maxDuration;
|
|
30
|
+
inactivityTimeout;
|
|
31
|
+
maxDurationTimer = null;
|
|
32
|
+
inactivityTimer = null;
|
|
33
|
+
stopReason = 'explicit';
|
|
34
|
+
// Callback for auto-finalize events
|
|
35
|
+
onAutoFinalize;
|
|
36
|
+
constructor(id, mode, outputDir, format = 'v2', idleTimeLimit = 2, maxDuration = 3600, // 60 minutes default
|
|
37
|
+
inactivityTimeout = 600 // 10 minutes default
|
|
38
|
+
) {
|
|
39
|
+
this.id = id;
|
|
40
|
+
this.mode = mode;
|
|
41
|
+
this.format = format;
|
|
42
|
+
this.outputDir = outputDir;
|
|
43
|
+
this.idleTimeLimit = idleTimeLimit;
|
|
44
|
+
this.maxDuration = maxDuration;
|
|
45
|
+
this.inactivityTimeout = inactivityTimeout;
|
|
46
|
+
// Generate temp and final paths
|
|
47
|
+
const timestamp = Date.now();
|
|
48
|
+
const filename = `terminal-${timestamp}-${id}.cast`;
|
|
49
|
+
this.tempPath = path.join(os.tmpdir(), `terminal-mcp-recording-${id}.cast`);
|
|
50
|
+
this.finalPath = path.join(outputDir, filename);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Start the recording
|
|
54
|
+
* Writes the asciicast header to the temp file
|
|
55
|
+
*/
|
|
56
|
+
start(width, height, env) {
|
|
57
|
+
if (this.writeStream) {
|
|
58
|
+
throw new Error("Recording already started");
|
|
59
|
+
}
|
|
60
|
+
this.startTime = Date.now();
|
|
61
|
+
// Ensure output directory exists
|
|
62
|
+
fs.mkdirSync(this.outputDir, { recursive: true });
|
|
63
|
+
// Create write stream to temp file
|
|
64
|
+
this.writeStream = fs.createWriteStream(this.tempPath, { flags: 'w' });
|
|
65
|
+
// Write header
|
|
66
|
+
const header = {
|
|
67
|
+
version: 2,
|
|
68
|
+
width,
|
|
69
|
+
height,
|
|
70
|
+
timestamp: Math.floor(this.startTime / 1000),
|
|
71
|
+
};
|
|
72
|
+
if (env) {
|
|
73
|
+
header.env = env;
|
|
74
|
+
}
|
|
75
|
+
this.writeLine(JSON.stringify(header));
|
|
76
|
+
// Set up max duration timer
|
|
77
|
+
if (this.maxDuration > 0) {
|
|
78
|
+
this.maxDurationTimer = setTimeout(() => {
|
|
79
|
+
this._autoFinalize('max_duration');
|
|
80
|
+
}, this.maxDuration * 1000);
|
|
81
|
+
}
|
|
82
|
+
// Set up initial inactivity timer
|
|
83
|
+
if (this.inactivityTimeout > 0) {
|
|
84
|
+
this.inactivityTimer = setTimeout(() => {
|
|
85
|
+
this._autoFinalize('inactivity');
|
|
86
|
+
}, this.inactivityTimeout * 1000);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Record output data
|
|
91
|
+
*/
|
|
92
|
+
recordOutput(data) {
|
|
93
|
+
if (!this.writeStream || this.finalized) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
// Reset inactivity timer on each output event
|
|
97
|
+
if (this.inactivityTimeout > 0 && this.inactivityTimer) {
|
|
98
|
+
clearTimeout(this.inactivityTimer);
|
|
99
|
+
this.inactivityTimer = setTimeout(() => {
|
|
100
|
+
this._autoFinalize('inactivity');
|
|
101
|
+
}, this.inactivityTimeout * 1000);
|
|
102
|
+
}
|
|
103
|
+
const elapsed = this.getElapsedSeconds();
|
|
104
|
+
const event = [elapsed, 'o', data];
|
|
105
|
+
this.writeLine(JSON.stringify(event));
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Record terminal resize event
|
|
109
|
+
*/
|
|
110
|
+
recordResize(cols, rows) {
|
|
111
|
+
if (!this.writeStream || this.finalized) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const elapsed = this.getElapsedSeconds();
|
|
115
|
+
const event = [elapsed, 'r', `${cols}x${rows}`];
|
|
116
|
+
this.writeLine(JSON.stringify(event));
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Finalize the recording
|
|
120
|
+
* - For 'always' mode: move temp file to output dir
|
|
121
|
+
* - For 'on-failure' mode: move if exitCode !== 0, delete otherwise
|
|
122
|
+
*
|
|
123
|
+
* Returns metadata about the recording
|
|
124
|
+
*/
|
|
125
|
+
async finalize(exitCode, stopReason) {
|
|
126
|
+
if (this.finalized) {
|
|
127
|
+
throw new Error("Recording already finalized");
|
|
128
|
+
}
|
|
129
|
+
this.finalized = true;
|
|
130
|
+
const endTime = Date.now();
|
|
131
|
+
const durationMs = endTime - this.startTime;
|
|
132
|
+
// Clear any active timers
|
|
133
|
+
this.clearTimers();
|
|
134
|
+
// Use provided stopReason or the internally tracked one
|
|
135
|
+
const finalStopReason = stopReason ?? this.stopReason;
|
|
136
|
+
// Close the write stream
|
|
137
|
+
if (this.writeStream) {
|
|
138
|
+
await new Promise((resolve, reject) => {
|
|
139
|
+
this.writeStream.end((err) => {
|
|
140
|
+
if (err)
|
|
141
|
+
reject(err);
|
|
142
|
+
else
|
|
143
|
+
resolve();
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
let saved = false;
|
|
148
|
+
let finalPath = this.tempPath;
|
|
149
|
+
// Determine whether to save based on mode and exit code
|
|
150
|
+
const shouldSave = this.mode === 'always' ||
|
|
151
|
+
(this.mode === 'on-failure' && exitCode !== 0 && exitCode !== null);
|
|
152
|
+
if (shouldSave) {
|
|
153
|
+
// Move temp file to final location
|
|
154
|
+
try {
|
|
155
|
+
fs.renameSync(this.tempPath, this.finalPath);
|
|
156
|
+
finalPath = this.finalPath;
|
|
157
|
+
saved = true;
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
// If rename fails (cross-device), copy and delete
|
|
161
|
+
fs.copyFileSync(this.tempPath, this.finalPath);
|
|
162
|
+
fs.unlinkSync(this.tempPath);
|
|
163
|
+
finalPath = this.finalPath;
|
|
164
|
+
saved = true;
|
|
165
|
+
}
|
|
166
|
+
// Write metadata sidecar file
|
|
167
|
+
const metaPath = this.finalPath.replace(/\.cast$/, '.meta.json');
|
|
168
|
+
const meta = {
|
|
169
|
+
exitCode,
|
|
170
|
+
durationMs,
|
|
171
|
+
startTime: this.startTime,
|
|
172
|
+
endTime,
|
|
173
|
+
bytesWritten: this.bytesWritten,
|
|
174
|
+
stopReason: finalStopReason,
|
|
175
|
+
};
|
|
176
|
+
fs.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
// Delete temp file
|
|
180
|
+
try {
|
|
181
|
+
fs.unlinkSync(this.tempPath);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// Ignore if already deleted
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
id: this.id,
|
|
189
|
+
path: saved ? finalPath : '',
|
|
190
|
+
tempPath: this.tempPath,
|
|
191
|
+
startTime: this.startTime,
|
|
192
|
+
endTime,
|
|
193
|
+
durationMs,
|
|
194
|
+
bytesWritten: this.bytesWritten,
|
|
195
|
+
exitCode,
|
|
196
|
+
mode: this.mode,
|
|
197
|
+
saved,
|
|
198
|
+
stopReason: finalStopReason,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Check if recording is active
|
|
203
|
+
*/
|
|
204
|
+
isActive() {
|
|
205
|
+
return this.writeStream !== null && !this.finalized;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Get the temp file path (for debugging/testing)
|
|
209
|
+
*/
|
|
210
|
+
getTempPath() {
|
|
211
|
+
return this.tempPath;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Get the final file path
|
|
215
|
+
*/
|
|
216
|
+
getFinalPath() {
|
|
217
|
+
return this.finalPath;
|
|
218
|
+
}
|
|
219
|
+
getElapsedSeconds() {
|
|
220
|
+
const now = Date.now();
|
|
221
|
+
if (this.lastEventTime === 0) {
|
|
222
|
+
// First event - just record the time
|
|
223
|
+
this.lastEventTime = now;
|
|
224
|
+
this.adjustedElapsed = (now - this.startTime) / 1000;
|
|
225
|
+
return this.adjustedElapsed;
|
|
226
|
+
}
|
|
227
|
+
// Calculate actual idle time since last event
|
|
228
|
+
const idleTime = (now - this.lastEventTime) / 1000;
|
|
229
|
+
// Cap idle time if limit is set and exceeded
|
|
230
|
+
if (this.idleTimeLimit > 0 && idleTime > this.idleTimeLimit) {
|
|
231
|
+
// Only add the capped idle time to our adjusted elapsed
|
|
232
|
+
this.adjustedElapsed += this.idleTimeLimit;
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
// Add actual idle time
|
|
236
|
+
this.adjustedElapsed += idleTime;
|
|
237
|
+
}
|
|
238
|
+
this.lastEventTime = now;
|
|
239
|
+
return this.adjustedElapsed;
|
|
240
|
+
}
|
|
241
|
+
writeLine(line) {
|
|
242
|
+
if (this.writeStream) {
|
|
243
|
+
const data = line + '\n';
|
|
244
|
+
this.writeStream.write(data);
|
|
245
|
+
this.bytesWritten += Buffer.byteLength(data, 'utf8');
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Clear all active timers
|
|
250
|
+
*/
|
|
251
|
+
clearTimers() {
|
|
252
|
+
if (this.maxDurationTimer) {
|
|
253
|
+
clearTimeout(this.maxDurationTimer);
|
|
254
|
+
this.maxDurationTimer = null;
|
|
255
|
+
}
|
|
256
|
+
if (this.inactivityTimer) {
|
|
257
|
+
clearTimeout(this.inactivityTimer);
|
|
258
|
+
this.inactivityTimer = null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Auto-finalize the recording due to timeout
|
|
263
|
+
* Called internally when max duration or inactivity timeout is reached
|
|
264
|
+
*/
|
|
265
|
+
async _autoFinalize(reason) {
|
|
266
|
+
if (this.finalized) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
this.stopReason = reason;
|
|
270
|
+
const metadata = await this.finalize(null, reason);
|
|
271
|
+
// Notify callback if registered
|
|
272
|
+
if (this.onAutoFinalize) {
|
|
273
|
+
this.onAutoFinalize(metadata);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Set callback for auto-finalize events (timeout triggered)
|
|
278
|
+
*/
|
|
279
|
+
setOnAutoFinalize(callback) {
|
|
280
|
+
this.onAutoFinalize = callback;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Get timeout configuration and remaining time
|
|
284
|
+
*/
|
|
285
|
+
getTimeoutInfo() {
|
|
286
|
+
const elapsedSeconds = this.startTime > 0 ? (Date.now() - this.startTime) / 1000 : 0;
|
|
287
|
+
const remainingMaxDuration = this.maxDuration > 0 ? Math.max(0, this.maxDuration - elapsedSeconds) : -1;
|
|
288
|
+
return {
|
|
289
|
+
maxDuration: this.maxDuration,
|
|
290
|
+
inactivityTimeout: this.inactivityTimeout,
|
|
291
|
+
elapsedSeconds,
|
|
292
|
+
remainingMaxDuration,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
//# sourceMappingURL=recorder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recorder.js","sourceRoot":"","sources":["../../src/recording/recorder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recording mode determines when recordings are saved
|
|
3
|
+
* - 'always': Save all recordings
|
|
4
|
+
* - 'on-failure': Only save recordings when the session exits with non-zero code
|
|
5
|
+
* - 'off': Disable recording
|
|
6
|
+
*/
|
|
7
|
+
export type RecordingMode = 'always' | 'on-failure' | 'off';
|
|
8
|
+
/**
|
|
9
|
+
* Recording format (asciicast v2 is the only supported format)
|
|
10
|
+
*/
|
|
11
|
+
export type RecordingFormat = 'v2';
|
|
12
|
+
/**
|
|
13
|
+
* Options for creating a recording
|
|
14
|
+
*/
|
|
15
|
+
export interface RecordingOptions {
|
|
16
|
+
mode: RecordingMode;
|
|
17
|
+
format: RecordingFormat;
|
|
18
|
+
outputDir: string;
|
|
19
|
+
idleTimeLimit?: number;
|
|
20
|
+
maxDuration?: number;
|
|
21
|
+
inactivityTimeout?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Asciicast v2 header (first line of the .cast file)
|
|
25
|
+
*/
|
|
26
|
+
export interface AsciicastHeader {
|
|
27
|
+
version: 2;
|
|
28
|
+
width: number;
|
|
29
|
+
height: number;
|
|
30
|
+
timestamp: number;
|
|
31
|
+
env?: {
|
|
32
|
+
SHELL?: string;
|
|
33
|
+
TERM?: string;
|
|
34
|
+
};
|
|
35
|
+
title?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Asciicast event types:
|
|
39
|
+
* - 'o': output (data written to terminal)
|
|
40
|
+
* - 'r': resize (terminal dimensions changed)
|
|
41
|
+
*/
|
|
42
|
+
export type AsciicastOutputEvent = [number, 'o', string];
|
|
43
|
+
export type AsciicastResizeEvent = [number, 'r', string];
|
|
44
|
+
export type AsciicastEvent = AsciicastOutputEvent | AsciicastResizeEvent;
|
|
45
|
+
/**
|
|
46
|
+
* Reason why recording stopped
|
|
47
|
+
*/
|
|
48
|
+
export type StopReason = 'explicit' | 'session_exit' | 'max_duration' | 'inactivity';
|
|
49
|
+
/**
|
|
50
|
+
* Metadata returned after finalizing a recording
|
|
51
|
+
*/
|
|
52
|
+
export interface RecordingMetadata {
|
|
53
|
+
id: string;
|
|
54
|
+
path: string;
|
|
55
|
+
tempPath: string;
|
|
56
|
+
startTime: number;
|
|
57
|
+
endTime: number;
|
|
58
|
+
durationMs: number;
|
|
59
|
+
bytesWritten: number;
|
|
60
|
+
exitCode: number | null;
|
|
61
|
+
mode: RecordingMode;
|
|
62
|
+
saved: boolean;
|
|
63
|
+
stopReason?: StopReason;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/recording/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,YAAY,GAAG,KAAK,CAAC;AAE5D;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC;AAEnC;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,eAAe,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE;QACJ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;AACzD,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;AACzD,MAAM,MAAM,cAAc,GAAG,oBAAoB,GAAG,oBAAoB,CAAC;AAEzE;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,cAAc,GAAG,cAAc,GAAG,YAAY,CAAC;AAErF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB"}
|