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,138 @@
1
+ "use strict";
2
+ /**
3
+ * Default kernel resolution based on the Python executable in the server env.
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.getDefaultKernelName = getDefaultKernelName;
40
+ exports.invalidateDefaultKernelName = invalidateDefaultKernelName;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const child_process_1 = require("child_process");
44
+ const util_1 = require("util");
45
+ const kernelspec_1 = require("./kernelspec");
46
+ const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
47
+ let defaultKernelPromise = null;
48
+ let defaultKernelValue = undefined;
49
+ const DEFAULT_PYTHON_COMMANDS = [
50
+ process.env.PYTHON,
51
+ 'python3',
52
+ 'python',
53
+ ].filter(Boolean);
54
+ async function resolveRealPath(filePath) {
55
+ try {
56
+ return await fs.promises.realpath(filePath);
57
+ }
58
+ catch {
59
+ return filePath;
60
+ }
61
+ }
62
+ async function findExecutableOnPath(command, envPath) {
63
+ if (!envPath)
64
+ return null;
65
+ const pathEntries = envPath.split(path.delimiter).filter(Boolean);
66
+ for (const entry of pathEntries) {
67
+ const candidate = path.join(entry, command);
68
+ try {
69
+ await fs.promises.access(candidate, fs.constants.X_OK);
70
+ return candidate;
71
+ }
72
+ catch {
73
+ // Keep searching
74
+ }
75
+ }
76
+ return null;
77
+ }
78
+ async function resolveKernelPython(spec) {
79
+ const argv0 = spec.argv?.[0];
80
+ if (!argv0)
81
+ return null;
82
+ if (path.isAbsolute(argv0))
83
+ return argv0;
84
+ const envPath = spec.env?.PATH || process.env.PATH;
85
+ return await findExecutableOnPath(argv0, envPath);
86
+ }
87
+ async function detectPythonExecutable() {
88
+ for (const cmd of DEFAULT_PYTHON_COMMANDS) {
89
+ try {
90
+ const { stdout } = await execFileAsync(cmd, ['-c', 'import sys; print(sys.executable)'], { env: process.env, timeout: 5000, maxBuffer: 1024 * 1024 });
91
+ const trimmed = stdout.trim();
92
+ if (trimmed)
93
+ return trimmed;
94
+ }
95
+ catch {
96
+ // Try next candidate
97
+ }
98
+ }
99
+ return null;
100
+ }
101
+ async function getDefaultKernelName() {
102
+ if (defaultKernelValue !== undefined) {
103
+ return defaultKernelValue;
104
+ }
105
+ if (!defaultKernelPromise) {
106
+ defaultKernelPromise = (async () => {
107
+ const pythonExe = await detectPythonExecutable();
108
+ if (!pythonExe)
109
+ return null;
110
+ const pythonReal = await resolveRealPath(pythonExe);
111
+ const specs = (0, kernelspec_1.discoverKernelSpecs)();
112
+ for (const spec of specs) {
113
+ const resolved = await resolveKernelPython(spec);
114
+ if (!resolved)
115
+ continue;
116
+ const resolvedReal = await resolveRealPath(resolved);
117
+ if (resolvedReal === pythonReal) {
118
+ return spec.name;
119
+ }
120
+ }
121
+ return null;
122
+ })()
123
+ .then((name) => {
124
+ defaultKernelValue = name;
125
+ return name;
126
+ })
127
+ .catch((err) => {
128
+ console.warn('[DefaultKernel] Failed to detect default kernel:', err);
129
+ defaultKernelValue = null;
130
+ return null;
131
+ });
132
+ }
133
+ return defaultKernelPromise;
134
+ }
135
+ function invalidateDefaultKernelName() {
136
+ defaultKernelValue = undefined;
137
+ defaultKernelPromise = null;
138
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Kernel Service Module
3
+ */
4
+ export * from './types';
5
+ export * from './kernelspec';
6
+ export * from './session-store';
7
+ export * from './kernel-service';
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ /**
3
+ * Kernel Service Module
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
17
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ __exportStar(require("./types"), exports);
21
+ __exportStar(require("./kernelspec"), exports);
22
+ __exportStar(require("./session-store"), exports);
23
+ __exportStar(require("./kernel-service"), exports);
@@ -0,0 +1,290 @@
1
+ /**
2
+ * Kernel Service
3
+ *
4
+ * Manages Jupyter kernel sessions - spawning, execution, and lifecycle.
5
+ * Uses ZeroMQ for kernel communication following the Jupyter messaging protocol.
6
+ */
7
+ import { KernelOutput, ExecutionResult, ExecutionQueueInfo, StartKernelOptions, SessionInfo, KernelServiceConfig } from './types';
8
+ import { SessionStore } from './session-store';
9
+ import { KernelSpec } from './kernelspec';
10
+ export declare class KernelService {
11
+ private sessions;
12
+ private fileToSession;
13
+ private kernelProcesses;
14
+ private processLifecycleHandlers;
15
+ private zmqSockets;
16
+ private sessionStore;
17
+ private config;
18
+ private kernelSpecsCache;
19
+ private ready;
20
+ private zmq;
21
+ private executionQueues;
22
+ private executionQueueSizes;
23
+ private shellRequestQueues;
24
+ private reattachInProgress;
25
+ private serverId;
26
+ private serverInstanceId;
27
+ private legacyCleanupWarned;
28
+ private cellOutputBuffers;
29
+ private cellOutputTracking;
30
+ private executingCellIds;
31
+ constructor(config?: KernelServiceConfig, sessionStore?: SessionStore);
32
+ setServerIdentity(serverId: string, serverInstanceId?: string): void;
33
+ /**
34
+ * Check if a PID is still alive.
35
+ */
36
+ private isPidAlive;
37
+ private attachProcessLifecycle;
38
+ private detachProcessLifecycle;
39
+ /**
40
+ * Load a Jupyter connection file.
41
+ */
42
+ private loadConnectionFile;
43
+ /**
44
+ * Initialize the service (lazy load ZeroMQ and discover kernels)
45
+ */
46
+ initialize(): Promise<void>;
47
+ /**
48
+ * Attempt to reattach to orphaned kernel sessions from a previous server run.
49
+ */
50
+ reattachOrphanedSessions(): Promise<{
51
+ attempted: number;
52
+ reattached: number;
53
+ failed: number;
54
+ skipped: number;
55
+ }>;
56
+ /**
57
+ * Check if service is ready
58
+ */
59
+ get isReady(): boolean;
60
+ /**
61
+ * Get available kernelspecs
62
+ */
63
+ getAvailableKernels(): KernelSpec[];
64
+ /**
65
+ * Re-run kernelspec discovery and refresh the in-memory cache.
66
+ *
67
+ * `getAvailableKernels()` caches once at startup and never expires, so a kernel
68
+ * registered while the server is running would otherwise stay invisible until a
69
+ * restart. Call this after registering/installing a kernel.
70
+ */
71
+ refreshKernelSpecs(): KernelSpec[];
72
+ /**
73
+ * Normalize file path for consistent lookup
74
+ */
75
+ private normalizePath;
76
+ /**
77
+ * Normalize notebook path for external callers (e.g., routes).
78
+ */
79
+ normalizeNotebookPath(filePath: string): string;
80
+ /**
81
+ * Save kernel preference for a notebook file.
82
+ */
83
+ saveNotebookKernelPreference(filePath: string, kernelName: string, serverId?: string | null): void;
84
+ /**
85
+ * Get kernel preference for a notebook file.
86
+ */
87
+ getNotebookKernelPreference(filePath: string): {
88
+ kernelName: string;
89
+ serverId: string | null;
90
+ updatedAt: number;
91
+ } | null;
92
+ /**
93
+ * Generate a connection file for the kernel
94
+ */
95
+ private allocateEphemeralPort;
96
+ private generateConnectionFile;
97
+ /**
98
+ * Start a new kernel session
99
+ */
100
+ startKernel(options?: StartKernelOptions): Promise<string>;
101
+ /**
102
+ * Wait for kernel to be ready by connecting to ZeroMQ channels.
103
+ *
104
+ * Returns the detected kernel execution state:
105
+ * - 'idle': kernel responded to kernel_info_request (ready for work)
106
+ * - 'busy': kernel PID is alive but shell channel is blocked (mid-execution)
107
+ *
108
+ * @param timeoutSeconds Optional override for startup timeout (default: use config)
109
+ * @param pid Optional kernel PID — used to distinguish "busy" from "dead" on timeout
110
+ */
111
+ private waitForReady;
112
+ /**
113
+ * Monitor a busy reattached kernel on iopub. When its current execution
114
+ * finishes (status: idle on iopub), verify shell connectivity and update
115
+ * the in-memory session status.
116
+ */
117
+ private monitorBusyKernel;
118
+ /**
119
+ * Send kernel_info_request and wait for reply to verify kernel is ready
120
+ * Throws if no reply received within timeout
121
+ */
122
+ private sendKernelInfoRequest;
123
+ /**
124
+ * Create a Jupyter protocol message
125
+ */
126
+ private createJupyterMessage;
127
+ /**
128
+ * Get or create kernel for a file (one notebook = one kernel).
129
+ * Returns whether a new session was created.
130
+ */
131
+ getOrCreateKernel(filePath: string, kernelName?: string): Promise<{
132
+ sessionId: string;
133
+ created: boolean;
134
+ }>;
135
+ /**
136
+ * Get existing kernel session ID for a notebook file (if any).
137
+ * Returns null if no live session is associated with the file.
138
+ */
139
+ getSessionIdForFile(filePath: string): string | null;
140
+ /**
141
+ * Check if a kernel session exists.
142
+ */
143
+ hasSession(sessionId: string): boolean;
144
+ /**
145
+ * Get the notebook file path associated with a session (if any).
146
+ * Used for output persistence when no UI is connected.
147
+ */
148
+ getSessionFilePath(sessionId: string): string | null;
149
+ /**
150
+ * Get the kernel name associated with a session (if any).
151
+ */
152
+ getSessionKernelName(sessionId: string): string | null;
153
+ /**
154
+ * Execute code in a kernel session
155
+ */
156
+ executeCode(sessionId: string, code: string, onOutput: (output: KernelOutput, cellId?: string | null) => Promise<void>, onQueueInfo?: (info: ExecutionQueueInfo) => void, cellId?: string | null): Promise<ExecutionResult>;
157
+ private enqueueExecution;
158
+ /**
159
+ * Queue shell socket requests to prevent concurrent receive operations
160
+ */
161
+ private enqueueShellRequest;
162
+ private reserveExecutionSlot;
163
+ private releaseExecutionSlot;
164
+ private formatExecutionError;
165
+ private executeCodeInternal;
166
+ /**
167
+ * Request code completion from the kernel
168
+ * Uses a separate queue for shell socket operations to avoid "socket busy" errors
169
+ */
170
+ complete(sessionId: string, code: string, cursorPos: number): Promise<{
171
+ status: string;
172
+ matches: string[];
173
+ cursor_start: number;
174
+ cursor_end: number;
175
+ }>;
176
+ /**
177
+ * Internal completion implementation (runs within shell queue)
178
+ */
179
+ private completeInternal;
180
+ /**
181
+ * Parse a Jupyter protocol message
182
+ */
183
+ private parseJupyterMessage;
184
+ /**
185
+ * Format display data for output
186
+ */
187
+ private formatDisplayData;
188
+ /**
189
+ * Strip ANSI escape codes from text
190
+ */
191
+ private stripAnsi;
192
+ private getOutputStats;
193
+ private ensureCellBuffers;
194
+ private ensureCellTracking;
195
+ /**
196
+ * Buffer an output for a cell. Returns the outputs actually stored (0 if truncated, 1 normally).
197
+ */
198
+ bufferOutput(sessionId: string, output: KernelOutput, cellId?: string | null): KernelOutput[];
199
+ /**
200
+ * Clear outputs for a specific cell (called on re-execute).
201
+ */
202
+ clearCellOutputs(sessionId: string, cellId: string): void;
203
+ /**
204
+ * Get all cell outputs for a session, grouped by cellId.
205
+ */
206
+ getAllCellOutputs(sessionId: string): Map<string, KernelOutput[]>;
207
+ getExecutingCellId(sessionId: string): string | null;
208
+ /**
209
+ * Stop a kernel session
210
+ */
211
+ stopKernel(sessionId: string): Promise<boolean>;
212
+ /**
213
+ * Check command line for a PID (best-effort).
214
+ */
215
+ private getPidCommand;
216
+ /**
217
+ * Get process start time (best-effort), used to prevent PID reuse mistakes.
218
+ */
219
+ private getProcessStartTime;
220
+ /**
221
+ * Best-effort check to ensure the PID is a kernel process we started.
222
+ */
223
+ private isExpectedKernelProcess;
224
+ /**
225
+ * Attempt to terminate a PID gracefully, then force kill.
226
+ */
227
+ private terminatePid;
228
+ private cleanupPersistedSessionArtifacts;
229
+ /**
230
+ * Cleanup kernel resources
231
+ */
232
+ private cleanupKernelResources;
233
+ /**
234
+ * Cleanup only in-memory tracking for a session (keeps connection file and session store).
235
+ */
236
+ private cleanupInMemorySession;
237
+ /**
238
+ * Interrupt kernel execution
239
+ */
240
+ interruptKernel(sessionId: string): Promise<boolean>;
241
+ /**
242
+ * Restart a kernel (in-place, preserving session ID like Python)
243
+ */
244
+ restartKernel(sessionId: string): Promise<boolean>;
245
+ /**
246
+ * Get session status
247
+ */
248
+ getSessionStatusFast(sessionId: string): SessionInfo | null;
249
+ getSessionStatus(sessionId: string): Promise<SessionInfo | null>;
250
+ /**
251
+ * Get all sessions
252
+ */
253
+ getAllSessions(): Promise<SessionInfo[]>;
254
+ /**
255
+ * Get dead sessions (orphaned or terminated) that can be cleaned up
256
+ */
257
+ getDeadSessions(): {
258
+ sessionId: string;
259
+ kernelName: string;
260
+ filePath: string | null;
261
+ status: string;
262
+ lastHeartbeat: number;
263
+ }[];
264
+ /**
265
+ * Cleanup dead sessions by deleting them from the database
266
+ */
267
+ cleanupDeadSessions(sessionIds?: string[]): Promise<number>;
268
+ /**
269
+ * Cleanup all sessions
270
+ */
271
+ cleanup(): Promise<void>;
272
+ /**
273
+ * Shutdown kernel service.
274
+ * If preserveKernels is true, keep kernel processes running and close the session store.
275
+ */
276
+ shutdown(options?: {
277
+ preserveKernels?: boolean;
278
+ }): Promise<void>;
279
+ /**
280
+ * Helper: sleep for ms milliseconds
281
+ */
282
+ private sleep;
283
+ /**
284
+ * Get memory usage (RSS) for multiple processes in MB
285
+ * Returns a map of pid -> memoryMb
286
+ * Cross-platform: uses /proc on Linux, ps on macOS
287
+ */
288
+ private getProcessMemoryMap;
289
+ }
290
+ export declare const kernelService: KernelService;