nebula-notebook 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.md +222 -0
  2. package/bin/nebula-notebook.js +33 -0
  3. package/dist/assets/index-C1h_sArD.css +32 -0
  4. package/dist/assets/index-CDSTBon8.js +658 -0
  5. package/dist/favicon.svg +11 -0
  6. package/dist/index.html +73 -0
  7. package/node-server/dist/app.d.ts +5 -0
  8. package/node-server/dist/app.js +38 -0
  9. package/node-server/dist/auth/auth-middleware.d.ts +24 -0
  10. package/node-server/dist/auth/auth-middleware.js +276 -0
  11. package/node-server/dist/auth/auth-service.d.ts +84 -0
  12. package/node-server/dist/auth/auth-service.js +265 -0
  13. package/node-server/dist/auth/index.d.ts +3 -0
  14. package/node-server/dist/auth/index.js +8 -0
  15. package/node-server/dist/cluster/client-registration.d.ts +43 -0
  16. package/node-server/dist/cluster/client-registration.js +217 -0
  17. package/node-server/dist/cluster/cluster-secret.d.ts +11 -0
  18. package/node-server/dist/cluster/cluster-secret.js +90 -0
  19. package/node-server/dist/cluster/kernel-proxy.d.ts +100 -0
  20. package/node-server/dist/cluster/kernel-proxy.js +361 -0
  21. package/node-server/dist/cluster/server-registry.d.ts +109 -0
  22. package/node-server/dist/cluster/server-registry.js +217 -0
  23. package/node-server/dist/config/output-limits.d.ts +7 -0
  24. package/node-server/dist/config/output-limits.js +10 -0
  25. package/node-server/dist/discovery/discovery-service.d.ts +198 -0
  26. package/node-server/dist/discovery/discovery-service.js +811 -0
  27. package/node-server/dist/discovery/index.d.ts +5 -0
  28. package/node-server/dist/discovery/index.js +21 -0
  29. package/node-server/dist/discovery/types.d.ts +48 -0
  30. package/node-server/dist/discovery/types.js +24 -0
  31. package/node-server/dist/fs/fs-service.d.ts +218 -0
  32. package/node-server/dist/fs/fs-service.js +1422 -0
  33. package/node-server/dist/fs/index.d.ts +5 -0
  34. package/node-server/dist/fs/index.js +21 -0
  35. package/node-server/dist/fs/types.d.ts +132 -0
  36. package/node-server/dist/fs/types.js +5 -0
  37. package/node-server/dist/index.d.ts +13 -0
  38. package/node-server/dist/index.js +556 -0
  39. package/node-server/dist/kernel/default-kernel.d.ts +5 -0
  40. package/node-server/dist/kernel/default-kernel.js +138 -0
  41. package/node-server/dist/kernel/index.d.ts +7 -0
  42. package/node-server/dist/kernel/index.js +23 -0
  43. package/node-server/dist/kernel/kernel-service.d.ts +290 -0
  44. package/node-server/dist/kernel/kernel-service.js +1714 -0
  45. package/node-server/dist/kernel/kernelspec.d.ts +29 -0
  46. package/node-server/dist/kernel/kernelspec.js +210 -0
  47. package/node-server/dist/kernel/session-store.d.ts +87 -0
  48. package/node-server/dist/kernel/session-store.js +303 -0
  49. package/node-server/dist/kernel/types.d.ts +143 -0
  50. package/node-server/dist/kernel/types.js +17 -0
  51. package/node-server/dist/llm/index.d.ts +5 -0
  52. package/node-server/dist/llm/index.js +21 -0
  53. package/node-server/dist/llm/llm-service.d.ts +77 -0
  54. package/node-server/dist/llm/llm-service.js +454 -0
  55. package/node-server/dist/llm/types.d.ts +40 -0
  56. package/node-server/dist/llm/types.js +15 -0
  57. package/node-server/dist/notebook/cell-metadata.d.ts +27 -0
  58. package/node-server/dist/notebook/cell-metadata.js +76 -0
  59. package/node-server/dist/notebook/headless-handler.d.ts +127 -0
  60. package/node-server/dist/notebook/headless-handler.js +1530 -0
  61. package/node-server/dist/notebook/notebook-websocket.d.ts +12 -0
  62. package/node-server/dist/notebook/notebook-websocket.js +103 -0
  63. package/node-server/dist/notebook/operation-router.d.ts +115 -0
  64. package/node-server/dist/notebook/operation-router.js +641 -0
  65. package/node-server/dist/notebook/undoRedoManager.d.ts +194 -0
  66. package/node-server/dist/notebook/undoRedoManager.js +558 -0
  67. package/node-server/dist/output/display-data.d.ts +14 -0
  68. package/node-server/dist/output/display-data.js +134 -0
  69. package/node-server/dist/resources/resource-service.d.ts +69 -0
  70. package/node-server/dist/resources/resource-service.js +363 -0
  71. package/node-server/dist/routes/auth.d.ts +5 -0
  72. package/node-server/dist/routes/auth.js +61 -0
  73. package/node-server/dist/routes/cluster.d.ts +7 -0
  74. package/node-server/dist/routes/cluster.js +94 -0
  75. package/node-server/dist/routes/fs.d.ts +7 -0
  76. package/node-server/dist/routes/fs.js +392 -0
  77. package/node-server/dist/routes/kernel.d.ts +13 -0
  78. package/node-server/dist/routes/kernel.js +637 -0
  79. package/node-server/dist/routes/llm.d.ts +8 -0
  80. package/node-server/dist/routes/llm.js +105 -0
  81. package/node-server/dist/routes/notebook.d.ts +10 -0
  82. package/node-server/dist/routes/notebook.js +335 -0
  83. package/node-server/dist/routes/python.d.ts +8 -0
  84. package/node-server/dist/routes/python.js +187 -0
  85. package/node-server/dist/routes/resources.d.ts +7 -0
  86. package/node-server/dist/routes/resources.js +77 -0
  87. package/node-server/dist/scripts/show-auth-qr.d.ts +1 -0
  88. package/node-server/dist/scripts/show-auth-qr.js +81 -0
  89. package/node-server/dist/terminal/pty-manager.d.ts +100 -0
  90. package/node-server/dist/terminal/pty-manager.js +246 -0
  91. package/node-server/dist/terminal/server.d.ts +19 -0
  92. package/node-server/dist/terminal/server.js +254 -0
  93. package/node-server/dist/terminal/types.d.ts +50 -0
  94. package/node-server/dist/terminal/types.js +9 -0
  95. package/node-server/package.json +45 -0
  96. package/package.json +99 -0
  97. package/scripts/postinstall.cjs +26 -0
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ /**
3
+ * Resources API Routes
4
+ *
5
+ * Provides endpoints for system resource monitoring (RAM, GPU).
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.default = resourceRoutes;
9
+ const resource_service_1 = require("../resources/resource-service");
10
+ const server_registry_1 = require("../cluster/server-registry");
11
+ const resourceService = (0, resource_service_1.getResourceService)();
12
+ async function resourceRoutes(fastify) {
13
+ /**
14
+ * GET /
15
+ *
16
+ * Get server resources (RAM, GPU).
17
+ * If server_id is provided and not local, fetches from remote server.
18
+ * Returns cached data - never blocks.
19
+ */
20
+ fastify.get('/', async (request, reply) => {
21
+ try {
22
+ const serverId = request.query.server_id;
23
+ const localServerId = server_registry_1.serverRegistry.getLocalServerId();
24
+ // Check if we need to fetch from a remote server
25
+ if (serverId && serverId !== localServerId && serverId !== 'local') {
26
+ const server = server_registry_1.serverRegistry.getServer(serverId);
27
+ if (!server) {
28
+ return reply.code(404).send({ error: `Server not found: ${serverId}` });
29
+ }
30
+ if (server.status !== 'online') {
31
+ return reply.code(503).send({ error: `Server is offline: ${serverId}` });
32
+ }
33
+ // Fetch from remote server
34
+ const response = await fetch(`${server.url}/api/resources`, {
35
+ headers: process.env.NEBULA_CLUSTER_SECRET
36
+ ? { 'X-Nebula-Cluster-Secret': process.env.NEBULA_CLUSTER_SECRET }
37
+ : undefined,
38
+ });
39
+ if (!response.ok) {
40
+ const error = await response.json().catch(() => ({ error: 'Unknown error' }));
41
+ return reply.code(response.status).send({ error: error.error || 'Failed to fetch resources' });
42
+ }
43
+ const data = await response.json();
44
+ return reply.send(data);
45
+ }
46
+ // Return local resources
47
+ const resources = resourceService.getResources();
48
+ return reply.send({
49
+ ...resources,
50
+ isStale: resourceService.isStale(),
51
+ });
52
+ }
53
+ catch (err) {
54
+ const message = err instanceof Error ? err.message : 'Unknown error';
55
+ return reply.code(500).send({ error: message });
56
+ }
57
+ });
58
+ /**
59
+ * POST /refresh
60
+ *
61
+ * Force refresh resources (still has timeout protection).
62
+ * Use sparingly - normally cached data is sufficient.
63
+ */
64
+ fastify.post('/refresh', async (_request, reply) => {
65
+ try {
66
+ const resources = await resourceService.refreshResources();
67
+ return reply.send({
68
+ ...resources,
69
+ isStale: false,
70
+ });
71
+ }
72
+ catch (err) {
73
+ const message = err instanceof Error ? err.message : 'Unknown error';
74
+ return reply.code(500).send({ error: message });
75
+ }
76
+ });
77
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const fs_1 = __importDefault(require("fs"));
40
+ const os_1 = __importDefault(require("os"));
41
+ const path_1 = __importDefault(require("path"));
42
+ const otplib_1 = require("otplib");
43
+ const qrcode = __importStar(require("qrcode-terminal"));
44
+ const AUTH_CONFIG_FILE = path_1.default.join(os_1.default.homedir(), '.nebula', 'auth.json');
45
+ const ISSUER = 'NebulaNotebook';
46
+ const ACCOUNT_NAME = 'local';
47
+ function fail(message) {
48
+ console.error(message);
49
+ process.exit(1);
50
+ }
51
+ function readAuthConfig() {
52
+ if (!fs_1.default.existsSync(AUTH_CONFIG_FILE)) {
53
+ fail(`[Auth] Config not found: ${AUTH_CONFIG_FILE}\n[Auth] Start the Nebula server once to initialize 2FA.`);
54
+ }
55
+ try {
56
+ const raw = fs_1.default.readFileSync(AUTH_CONFIG_FILE, 'utf-8');
57
+ return JSON.parse(raw);
58
+ }
59
+ catch (error) {
60
+ const detail = error instanceof Error ? error.message : String(error);
61
+ fail(`[Auth] Failed to read ${AUTH_CONFIG_FILE}: ${detail}`);
62
+ }
63
+ }
64
+ function main() {
65
+ const config = readAuthConfig();
66
+ const secret = typeof config.totpSecret === 'string' ? config.totpSecret.trim() : '';
67
+ if (!secret) {
68
+ fail(`[Auth] Missing \"totpSecret\" in ${AUTH_CONFIG_FILE}`);
69
+ }
70
+ const otpAuthUrl = otplib_1.authenticator.keyuri(ACCOUNT_NAME, ISSUER, secret);
71
+ console.log('\n' + '='.repeat(60));
72
+ console.log(' NEBULA NOTEBOOK - 2FA QR');
73
+ console.log('='.repeat(60));
74
+ console.log('\nScan this QR code with your authenticator app:\n');
75
+ qrcode.generate(otpAuthUrl, { small: true });
76
+ console.log('\nOr enter this key manually: ' + secret);
77
+ console.log(`\nConfig: ${AUTH_CONFIG_FILE}`);
78
+ console.log(`[Auth] setupComplete=${config.setupComplete === true ? 'true' : 'false'}`);
79
+ console.log('='.repeat(60) + '\n');
80
+ }
81
+ main();
@@ -0,0 +1,100 @@
1
+ /**
2
+ * PTY Manager - Manages terminal sessions using node-pty
3
+ */
4
+ import * as pty from '@homebridge/node-pty-prebuilt-multiarch';
5
+ import { TerminalInfo } from './types';
6
+ interface TerminalSession {
7
+ id: string;
8
+ pty: pty.IPty;
9
+ cwd: string;
10
+ shell: string;
11
+ cols: number;
12
+ rows: number;
13
+ created: number;
14
+ lastActivity: number;
15
+ outputBuffer: string;
16
+ onData: ((data: string) => void) | null;
17
+ onExit: ((code: number) => void) | null;
18
+ }
19
+ export declare class PtyManager {
20
+ private sessions;
21
+ /**
22
+ * Get the default shell for the current platform
23
+ */
24
+ private getDefaultShell;
25
+ /**
26
+ * Normalize a terminal name to a valid ID
27
+ * - Lowercase
28
+ * - Only alphanumeric, hyphens, underscores
29
+ * - Max 32 chars
30
+ * - Falls back to 'default' if empty/invalid
31
+ */
32
+ normalizeTerminalName(name: string): string;
33
+ /**
34
+ * Create a new terminal session
35
+ */
36
+ create(options?: {
37
+ id?: string;
38
+ cwd?: string;
39
+ shell?: string;
40
+ cols?: number;
41
+ rows?: number;
42
+ }): TerminalInfo;
43
+ /**
44
+ * Get terminal info from session
45
+ */
46
+ private getInfo;
47
+ /**
48
+ * Get a terminal session by ID
49
+ */
50
+ get(id: string): TerminalSession | undefined;
51
+ /**
52
+ * Get terminal info by ID
53
+ */
54
+ getTerminalInfo(id: string): TerminalInfo | undefined;
55
+ /**
56
+ * List all active terminals
57
+ */
58
+ list(): TerminalInfo[];
59
+ /**
60
+ * Write data to a terminal
61
+ */
62
+ write(id: string, data: string): boolean;
63
+ /**
64
+ * Resize a terminal
65
+ */
66
+ resize(id: string, cols: number, rows: number): boolean;
67
+ /**
68
+ * Get or create a terminal by name
69
+ * If a terminal with the normalized name exists, return it
70
+ * Otherwise create a new one with that name
71
+ */
72
+ getOrCreate(name: string, options?: {
73
+ cwd?: string;
74
+ shell?: string;
75
+ cols?: number;
76
+ rows?: number;
77
+ }): TerminalInfo;
78
+ /**
79
+ * Kill a terminal session
80
+ */
81
+ kill(id: string): boolean;
82
+ /**
83
+ * Set data listener for a terminal (for WebSocket connection)
84
+ */
85
+ setOnData(id: string, callback: ((data: string) => void) | null): void;
86
+ /**
87
+ * Set exit listener for a terminal
88
+ */
89
+ setOnExit(id: string, callback: ((code: number) => void) | null): void;
90
+ /**
91
+ * Get buffered output for reconnection
92
+ */
93
+ getOutputBuffer(id: string): string;
94
+ /**
95
+ * Kill all terminal sessions (for cleanup)
96
+ */
97
+ killAll(): void;
98
+ }
99
+ export declare const ptyManager: PtyManager;
100
+ export {};
@@ -0,0 +1,246 @@
1
+ "use strict";
2
+ /**
3
+ * PTY Manager - Manages terminal sessions using node-pty
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.ptyManager = exports.PtyManager = void 0;
40
+ const pty = __importStar(require("@homebridge/node-pty-prebuilt-multiarch"));
41
+ const uuid_1 = require("uuid");
42
+ const types_1 = require("./types");
43
+ class PtyManager {
44
+ sessions = new Map();
45
+ /**
46
+ * Get the default shell for the current platform
47
+ */
48
+ getDefaultShell() {
49
+ if (process.platform === 'win32') {
50
+ return process.env.COMSPEC || 'cmd.exe';
51
+ }
52
+ return process.env.SHELL || '/bin/bash';
53
+ }
54
+ /**
55
+ * Normalize a terminal name to a valid ID
56
+ * - Lowercase
57
+ * - Only alphanumeric, hyphens, underscores
58
+ * - Max 32 chars
59
+ * - Falls back to 'default' if empty/invalid
60
+ */
61
+ normalizeTerminalName(name) {
62
+ const normalized = name
63
+ .toLowerCase()
64
+ .replace(/[^a-z0-9_-]/g, '-')
65
+ .replace(/-+/g, '-')
66
+ .replace(/^-|-$/g, '')
67
+ .slice(0, 32);
68
+ return normalized || 'default';
69
+ }
70
+ /**
71
+ * Create a new terminal session
72
+ */
73
+ create(options) {
74
+ const id = options?.id ? this.normalizeTerminalName(options.id) : (0, uuid_1.v4)();
75
+ const shell = options?.shell || this.getDefaultShell();
76
+ const cwd = options?.cwd || process.cwd();
77
+ const cols = options?.cols || 80;
78
+ const rows = options?.rows || 24;
79
+ // Spawn PTY process
80
+ const ptyProcess = pty.spawn(shell, [], {
81
+ name: 'xterm-256color',
82
+ cols,
83
+ rows,
84
+ cwd,
85
+ env: {
86
+ ...process.env,
87
+ TERM: 'xterm-256color',
88
+ COLORTERM: 'truecolor',
89
+ },
90
+ });
91
+ const session = {
92
+ id,
93
+ pty: ptyProcess,
94
+ cwd,
95
+ shell,
96
+ cols,
97
+ rows,
98
+ created: Date.now(),
99
+ lastActivity: Date.now(),
100
+ outputBuffer: '',
101
+ onData: null,
102
+ onExit: null,
103
+ };
104
+ // Handle PTY output
105
+ ptyProcess.onData((data) => {
106
+ session.lastActivity = Date.now();
107
+ // Append to output buffer for reconnection
108
+ session.outputBuffer += data;
109
+ // Trim buffer if too large
110
+ if (session.outputBuffer.length > types_1.OUTPUT_BUFFER_MAX_SIZE) {
111
+ session.outputBuffer = session.outputBuffer.slice(-types_1.OUTPUT_BUFFER_TRIM_SIZE);
112
+ }
113
+ // Forward to listener if connected
114
+ if (session.onData) {
115
+ session.onData(data);
116
+ }
117
+ });
118
+ // Handle PTY exit
119
+ ptyProcess.onExit(({ exitCode }) => {
120
+ if (session.onExit) {
121
+ session.onExit(exitCode);
122
+ }
123
+ this.sessions.delete(id);
124
+ });
125
+ this.sessions.set(id, session);
126
+ return this.getInfo(session);
127
+ }
128
+ /**
129
+ * Get terminal info from session
130
+ */
131
+ getInfo(session) {
132
+ return {
133
+ id: session.id,
134
+ pid: session.pty.pid,
135
+ cwd: session.cwd,
136
+ shell: session.shell,
137
+ cols: session.cols,
138
+ rows: session.rows,
139
+ created: session.created,
140
+ lastActivity: session.lastActivity,
141
+ };
142
+ }
143
+ /**
144
+ * Get a terminal session by ID
145
+ */
146
+ get(id) {
147
+ return this.sessions.get(id);
148
+ }
149
+ /**
150
+ * Get terminal info by ID
151
+ */
152
+ getTerminalInfo(id) {
153
+ const session = this.sessions.get(id);
154
+ return session ? this.getInfo(session) : undefined;
155
+ }
156
+ /**
157
+ * List all active terminals
158
+ */
159
+ list() {
160
+ return Array.from(this.sessions.values()).map((s) => this.getInfo(s));
161
+ }
162
+ /**
163
+ * Write data to a terminal
164
+ */
165
+ write(id, data) {
166
+ const session = this.sessions.get(id);
167
+ if (!session)
168
+ return false;
169
+ session.pty.write(data);
170
+ session.lastActivity = Date.now();
171
+ return true;
172
+ }
173
+ /**
174
+ * Resize a terminal
175
+ */
176
+ resize(id, cols, rows) {
177
+ const session = this.sessions.get(id);
178
+ if (!session)
179
+ return false;
180
+ session.pty.resize(cols, rows);
181
+ session.cols = cols;
182
+ session.rows = rows;
183
+ session.lastActivity = Date.now();
184
+ return true;
185
+ }
186
+ /**
187
+ * Get or create a terminal by name
188
+ * If a terminal with the normalized name exists, return it
189
+ * Otherwise create a new one with that name
190
+ */
191
+ getOrCreate(name, options) {
192
+ const normalizedId = this.normalizeTerminalName(name);
193
+ const existing = this.sessions.get(normalizedId);
194
+ if (existing) {
195
+ return this.getInfo(existing);
196
+ }
197
+ return this.create({ ...options, id: normalizedId });
198
+ }
199
+ /**
200
+ * Kill a terminal session
201
+ */
202
+ kill(id) {
203
+ const session = this.sessions.get(id);
204
+ if (!session)
205
+ return false;
206
+ session.pty.kill();
207
+ this.sessions.delete(id);
208
+ return true;
209
+ }
210
+ /**
211
+ * Set data listener for a terminal (for WebSocket connection)
212
+ */
213
+ setOnData(id, callback) {
214
+ const session = this.sessions.get(id);
215
+ if (session) {
216
+ session.onData = callback;
217
+ }
218
+ }
219
+ /**
220
+ * Set exit listener for a terminal
221
+ */
222
+ setOnExit(id, callback) {
223
+ const session = this.sessions.get(id);
224
+ if (session) {
225
+ session.onExit = callback;
226
+ }
227
+ }
228
+ /**
229
+ * Get buffered output for reconnection
230
+ */
231
+ getOutputBuffer(id) {
232
+ const session = this.sessions.get(id);
233
+ return session?.outputBuffer || '';
234
+ }
235
+ /**
236
+ * Kill all terminal sessions (for cleanup)
237
+ */
238
+ killAll() {
239
+ for (const [id] of this.sessions) {
240
+ this.kill(id);
241
+ }
242
+ }
243
+ }
244
+ exports.PtyManager = PtyManager;
245
+ // Singleton instance
246
+ exports.ptyManager = new PtyManager();
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Terminal Server - Routes and WebSocket setup for PTY management
3
+ */
4
+ import { FastifyInstance } from 'fastify';
5
+ import { WebSocketServer } from 'ws';
6
+ import { Server as HttpServer } from 'http';
7
+ /**
8
+ * Setup terminal REST routes as a Fastify plugin
9
+ */
10
+ export declare function setupTerminalRoutes(fastify: FastifyInstance): Promise<void>;
11
+ /**
12
+ * Setup terminal WebSocket server with noServer mode
13
+ * Returns the WSS so the upgrade can be handled externally
14
+ */
15
+ export declare function setupTerminalWebSocket(server: HttpServer): WebSocketServer;
16
+ /**
17
+ * Cleanup all terminals (call on shutdown)
18
+ */
19
+ export declare function cleanupTerminals(): void;