@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.
Files changed (75) hide show
  1. package/README.md +151 -5
  2. package/dist/client.d.ts.map +1 -1
  3. package/dist/client.js +2 -61
  4. package/dist/client.js.map +1 -1
  5. package/dist/index.js +235 -13
  6. package/dist/index.js.map +1 -1
  7. package/dist/recording/index.d.ts +4 -0
  8. package/dist/recording/index.d.ts.map +1 -0
  9. package/dist/recording/index.js +3 -0
  10. package/dist/recording/index.js.map +1 -0
  11. package/dist/recording/manager.d.ts +62 -0
  12. package/dist/recording/manager.d.ts.map +1 -0
  13. package/dist/recording/manager.js +123 -0
  14. package/dist/recording/manager.js.map +1 -0
  15. package/dist/recording/recorder.d.ts +95 -0
  16. package/dist/recording/recorder.d.ts.map +1 -0
  17. package/dist/recording/recorder.js +296 -0
  18. package/dist/recording/recorder.js.map +1 -0
  19. package/dist/recording/types.d.ts +65 -0
  20. package/dist/recording/types.d.ts.map +1 -0
  21. package/dist/recording/types.js +2 -0
  22. package/dist/recording/types.js.map +1 -0
  23. package/dist/sandbox/config.d.ts +46 -0
  24. package/dist/sandbox/config.d.ts.map +1 -0
  25. package/dist/sandbox/config.js +144 -0
  26. package/dist/sandbox/config.js.map +1 -0
  27. package/dist/sandbox/controller.d.ts +72 -0
  28. package/dist/sandbox/controller.d.ts.map +1 -0
  29. package/dist/sandbox/controller.js +208 -0
  30. package/dist/sandbox/controller.js.map +1 -0
  31. package/dist/sandbox/index.d.ts +6 -0
  32. package/dist/sandbox/index.d.ts.map +1 -0
  33. package/dist/sandbox/index.js +4 -0
  34. package/dist/sandbox/index.js.map +1 -0
  35. package/dist/sandbox/prompt.d.ts +10 -0
  36. package/dist/sandbox/prompt.d.ts.map +1 -0
  37. package/dist/sandbox/prompt.js +434 -0
  38. package/dist/sandbox/prompt.js.map +1 -0
  39. package/dist/terminal/index.d.ts +1 -0
  40. package/dist/terminal/index.d.ts.map +1 -1
  41. package/dist/terminal/manager.d.ts +58 -3
  42. package/dist/terminal/manager.d.ts.map +1 -1
  43. package/dist/terminal/manager.js +118 -3
  44. package/dist/terminal/manager.js.map +1 -1
  45. package/dist/terminal/session.d.ts +21 -1
  46. package/dist/terminal/session.d.ts.map +1 -1
  47. package/dist/terminal/session.js +44 -3
  48. package/dist/terminal/session.js.map +1 -1
  49. package/dist/tools/definitions.d.ts +18 -0
  50. package/dist/tools/definitions.d.ts.map +1 -0
  51. package/dist/tools/definitions.js +110 -0
  52. package/dist/tools/definitions.js.map +1 -0
  53. package/dist/tools/index.d.ts.map +1 -1
  54. package/dist/tools/index.js +7 -1
  55. package/dist/tools/index.js.map +1 -1
  56. package/dist/tools/startRecording.d.ts +68 -0
  57. package/dist/tools/startRecording.d.ts.map +1 -0
  58. package/dist/tools/startRecording.js +111 -0
  59. package/dist/tools/startRecording.js.map +1 -0
  60. package/dist/tools/stopRecording.d.ts +31 -0
  61. package/dist/tools/stopRecording.d.ts.map +1 -0
  62. package/dist/tools/stopRecording.js +76 -0
  63. package/dist/tools/stopRecording.js.map +1 -0
  64. package/dist/transport/socket.d.ts.map +1 -1
  65. package/dist/transport/socket.js +10 -0
  66. package/dist/transport/socket.js.map +1 -1
  67. package/dist/ui/index.d.ts +1 -0
  68. package/dist/ui/index.d.ts.map +1 -1
  69. package/dist/ui/index.js +17 -1
  70. package/dist/ui/index.js.map +1 -1
  71. package/dist/utils/platform.d.ts +6 -0
  72. package/dist/utils/platform.d.ts.map +1 -1
  73. package/dist/utils/platform.js +15 -0
  74. package/dist/utils/platform.js.map +1 -1
  75. 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":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAQzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;GAEG;AACH,MAAM,OAAO,gBAAgB;IACnB,UAAU,GAA0B,IAAI,GAAG,EAAE,CAAC;IAC9C,cAAc,CAAmB;IAEzC,YAAY,OAAmC;QAC7C,IAAI,CAAC,cAAc,GAAG;YACpB,IAAI,EAAE,OAAO,EAAE,IAAI,IAAI,KAAK;YAC5B,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,IAAI;YAC/B,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,mBAAmB,EAAE;YACtD,aAAa,EAAE,OAAO,EAAE,aAAa,IAAI,CAAC;YAC1C,WAAW,EAAE,OAAO,EAAE,WAAW,IAAI,IAAI,EAAS,qBAAqB;YACvE,iBAAiB,EAAE,OAAO,EAAE,iBAAiB,IAAI,GAAG,EAAG,qBAAqB;SAC7E,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,eAAe,CAAC,OAAmC;QACjD,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAC7B,MAAM,aAAa,GAAqB;YACtC,GAAG,IAAI,CAAC,cAAc;YACtB,GAAG,OAAO;SACX,CAAC;QAEF,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAC3B,EAAE,EACF,aAAa,CAAC,IAAI,EAClB,aAAa,CAAC,SAAS,EACvB,aAAa,CAAC,MAAM,EACpB,aAAa,CAAC,aAAa,EAC3B,aAAa,CAAC,WAAW,EACzB,aAAa,CAAC,iBAAiB,CAChC,CAAC;QAEF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QAClC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,EAAU;QACrB,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,EAAU;QACrB,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,mBAAmB;QACjB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;IACxE,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,OAAO,IAAI,CAAC,mBAAmB,EAAE,CAAC,MAAM,CAAC;IAC3C,CAAC;IAED;;OAEG;IACH,iBAAiB,CAAC,IAAY;QAC5B,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAC;YAClD,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED;;OAEG;IACH,iBAAiB,CAAC,IAAY,EAAE,IAAY;QAC1C,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAC;YAClD,QAAQ,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CAAC,EAAU,EAAE,QAAuB,EAAE,UAAuB;QAClF,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAC/D,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC3B,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,WAAW,CAAC,QAAuB,EAAE,aAAyB,cAAc;QAChF,MAAM,OAAO,GAAwB,EAAE,CAAC;QAExC,KAAK,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC7C,IAAI,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC;gBACxB,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;gBAC/D,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACzB,CAAC;YACD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC7B,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,OAAO,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,mBAAmB;QACjB,OAAO,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,sBAAsB;QACpB,OAAO,IAAI,CAAC,cAAc,CAAC,IAAI,KAAK,KAAK,CAAC;IAC5C,CAAC;IAEO,UAAU;QAChB,OAAO,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC;CACF"}
@@ -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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map