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.
- package/README.md +222 -0
- package/bin/nebula-notebook.js +33 -0
- package/dist/assets/index-C1h_sArD.css +32 -0
- package/dist/assets/index-CDSTBon8.js +658 -0
- package/dist/favicon.svg +11 -0
- package/dist/index.html +73 -0
- package/node-server/dist/app.d.ts +5 -0
- package/node-server/dist/app.js +38 -0
- package/node-server/dist/auth/auth-middleware.d.ts +24 -0
- package/node-server/dist/auth/auth-middleware.js +276 -0
- package/node-server/dist/auth/auth-service.d.ts +84 -0
- package/node-server/dist/auth/auth-service.js +265 -0
- package/node-server/dist/auth/index.d.ts +3 -0
- package/node-server/dist/auth/index.js +8 -0
- package/node-server/dist/cluster/client-registration.d.ts +43 -0
- package/node-server/dist/cluster/client-registration.js +217 -0
- package/node-server/dist/cluster/cluster-secret.d.ts +11 -0
- package/node-server/dist/cluster/cluster-secret.js +90 -0
- package/node-server/dist/cluster/kernel-proxy.d.ts +100 -0
- package/node-server/dist/cluster/kernel-proxy.js +361 -0
- package/node-server/dist/cluster/server-registry.d.ts +109 -0
- package/node-server/dist/cluster/server-registry.js +217 -0
- package/node-server/dist/config/output-limits.d.ts +7 -0
- package/node-server/dist/config/output-limits.js +10 -0
- package/node-server/dist/discovery/discovery-service.d.ts +198 -0
- package/node-server/dist/discovery/discovery-service.js +811 -0
- package/node-server/dist/discovery/index.d.ts +5 -0
- package/node-server/dist/discovery/index.js +21 -0
- package/node-server/dist/discovery/types.d.ts +48 -0
- package/node-server/dist/discovery/types.js +24 -0
- package/node-server/dist/fs/fs-service.d.ts +218 -0
- package/node-server/dist/fs/fs-service.js +1422 -0
- package/node-server/dist/fs/index.d.ts +5 -0
- package/node-server/dist/fs/index.js +21 -0
- package/node-server/dist/fs/types.d.ts +132 -0
- package/node-server/dist/fs/types.js +5 -0
- package/node-server/dist/index.d.ts +13 -0
- package/node-server/dist/index.js +556 -0
- package/node-server/dist/kernel/default-kernel.d.ts +5 -0
- package/node-server/dist/kernel/default-kernel.js +138 -0
- package/node-server/dist/kernel/index.d.ts +7 -0
- package/node-server/dist/kernel/index.js +23 -0
- package/node-server/dist/kernel/kernel-service.d.ts +290 -0
- package/node-server/dist/kernel/kernel-service.js +1714 -0
- package/node-server/dist/kernel/kernelspec.d.ts +29 -0
- package/node-server/dist/kernel/kernelspec.js +210 -0
- package/node-server/dist/kernel/session-store.d.ts +87 -0
- package/node-server/dist/kernel/session-store.js +303 -0
- package/node-server/dist/kernel/types.d.ts +143 -0
- package/node-server/dist/kernel/types.js +17 -0
- package/node-server/dist/llm/index.d.ts +5 -0
- package/node-server/dist/llm/index.js +21 -0
- package/node-server/dist/llm/llm-service.d.ts +77 -0
- package/node-server/dist/llm/llm-service.js +454 -0
- package/node-server/dist/llm/types.d.ts +40 -0
- package/node-server/dist/llm/types.js +15 -0
- package/node-server/dist/notebook/cell-metadata.d.ts +27 -0
- package/node-server/dist/notebook/cell-metadata.js +76 -0
- package/node-server/dist/notebook/headless-handler.d.ts +127 -0
- package/node-server/dist/notebook/headless-handler.js +1530 -0
- package/node-server/dist/notebook/notebook-websocket.d.ts +12 -0
- package/node-server/dist/notebook/notebook-websocket.js +103 -0
- package/node-server/dist/notebook/operation-router.d.ts +115 -0
- package/node-server/dist/notebook/operation-router.js +641 -0
- package/node-server/dist/notebook/undoRedoManager.d.ts +194 -0
- package/node-server/dist/notebook/undoRedoManager.js +558 -0
- package/node-server/dist/output/display-data.d.ts +14 -0
- package/node-server/dist/output/display-data.js +134 -0
- package/node-server/dist/resources/resource-service.d.ts +69 -0
- package/node-server/dist/resources/resource-service.js +363 -0
- package/node-server/dist/routes/auth.d.ts +5 -0
- package/node-server/dist/routes/auth.js +61 -0
- package/node-server/dist/routes/cluster.d.ts +7 -0
- package/node-server/dist/routes/cluster.js +94 -0
- package/node-server/dist/routes/fs.d.ts +7 -0
- package/node-server/dist/routes/fs.js +392 -0
- package/node-server/dist/routes/kernel.d.ts +13 -0
- package/node-server/dist/routes/kernel.js +637 -0
- package/node-server/dist/routes/llm.d.ts +8 -0
- package/node-server/dist/routes/llm.js +105 -0
- package/node-server/dist/routes/notebook.d.ts +10 -0
- package/node-server/dist/routes/notebook.js +335 -0
- package/node-server/dist/routes/python.d.ts +8 -0
- package/node-server/dist/routes/python.js +187 -0
- package/node-server/dist/routes/resources.d.ts +7 -0
- package/node-server/dist/routes/resources.js +77 -0
- package/node-server/dist/scripts/show-auth-qr.d.ts +1 -0
- package/node-server/dist/scripts/show-auth-qr.js +81 -0
- package/node-server/dist/terminal/pty-manager.d.ts +100 -0
- package/node-server/dist/terminal/pty-manager.js +246 -0
- package/node-server/dist/terminal/server.d.ts +19 -0
- package/node-server/dist/terminal/server.js +254 -0
- package/node-server/dist/terminal/types.d.ts +50 -0
- package/node-server/dist/terminal/types.js +9 -0
- package/node-server/package.json +45 -0
- package/package.json +99 -0
- package/scripts/postinstall.cjs +26 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notebook Operations WebSocket
|
|
3
|
+
*
|
|
4
|
+
* Handles real-time communication between UI and backend for notebook operations.
|
|
5
|
+
* Path: /api/notebook/{notebook_path}/ws
|
|
6
|
+
*/
|
|
7
|
+
import { WebSocketServer } from 'ws';
|
|
8
|
+
import { Server as HttpServer } from 'http';
|
|
9
|
+
/**
|
|
10
|
+
* Setup notebook operations WebSocket handler
|
|
11
|
+
*/
|
|
12
|
+
export declare function setupNotebookWebSocket(server: HttpServer): WebSocketServer;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Notebook Operations WebSocket
|
|
4
|
+
*
|
|
5
|
+
* Handles real-time communication between UI and backend for notebook operations.
|
|
6
|
+
* Path: /api/notebook/{notebook_path}/ws
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.setupNotebookWebSocket = setupNotebookWebSocket;
|
|
10
|
+
const ws_1 = require("ws");
|
|
11
|
+
const url_1 = require("url");
|
|
12
|
+
const operation_router_1 = require("./operation-router");
|
|
13
|
+
/**
|
|
14
|
+
* Setup notebook operations WebSocket handler
|
|
15
|
+
*/
|
|
16
|
+
function setupNotebookWebSocket(server) {
|
|
17
|
+
const wss = new ws_1.WebSocketServer({
|
|
18
|
+
noServer: true,
|
|
19
|
+
perMessageDeflate: false,
|
|
20
|
+
});
|
|
21
|
+
// Handle upgrade requests for /api/notebook/{path}/ws
|
|
22
|
+
server.on('upgrade', (request, socket, head) => {
|
|
23
|
+
const parsedUrl = (0, url_1.parse)(request.url || '', true);
|
|
24
|
+
const pathname = parsedUrl.pathname || '';
|
|
25
|
+
// Match /api/notebook/{encoded_path}/ws
|
|
26
|
+
const match = pathname.match(/^\/api\/notebook\/(.+)\/ws$/);
|
|
27
|
+
if (match) {
|
|
28
|
+
// Authenticate WebSocket connection
|
|
29
|
+
const { authWebSocketMiddleware } = require('../auth');
|
|
30
|
+
if (!authWebSocketMiddleware(request)) {
|
|
31
|
+
socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
|
|
32
|
+
socket.destroy();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
36
|
+
wss.emit('connection', ws, request);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// Don't destroy socket for non-matching paths
|
|
40
|
+
});
|
|
41
|
+
wss.on('connection', async (ws, req) => {
|
|
42
|
+
const parsedUrl = (0, url_1.parse)(req.url || '', true);
|
|
43
|
+
const pathname = parsedUrl.pathname || '';
|
|
44
|
+
const match = pathname.match(/^\/api\/notebook\/(.+)\/ws$/);
|
|
45
|
+
if (!match) {
|
|
46
|
+
ws.close(1008, 'Invalid path');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
// Decode the notebook path
|
|
50
|
+
const encodedPath = match[1];
|
|
51
|
+
const notebookPath = decodeURIComponent(encodedPath);
|
|
52
|
+
console.log(`[Notebook WS] Connected for notebook: ${notebookPath}`);
|
|
53
|
+
// Register UI connection
|
|
54
|
+
await operation_router_1.operationRouter.registerUI(ws, notebookPath);
|
|
55
|
+
const heartbeatInterval = setInterval(() => {
|
|
56
|
+
if (ws.readyState === ws_1.WebSocket.OPEN) {
|
|
57
|
+
try {
|
|
58
|
+
ws.ping();
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Ignore ping failures; close/error handlers will clean up.
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}, 15000);
|
|
65
|
+
ws.on('error', (err) => {
|
|
66
|
+
console.error(`[Notebook WS] WebSocket error for ${notebookPath}:`, err);
|
|
67
|
+
});
|
|
68
|
+
ws.on('pong', () => {
|
|
69
|
+
operation_router_1.operationRouter.markUIActivity(ws, notebookPath);
|
|
70
|
+
});
|
|
71
|
+
ws.on('message', async (data) => {
|
|
72
|
+
operation_router_1.operationRouter.markUIActivity(ws, notebookPath);
|
|
73
|
+
try {
|
|
74
|
+
const message = JSON.parse(data.toString());
|
|
75
|
+
if (message.type === 'operationResult') {
|
|
76
|
+
// UI is responding to an operation request
|
|
77
|
+
operation_router_1.operationRouter.handleUIResponse(notebookPath, message);
|
|
78
|
+
}
|
|
79
|
+
else if (message.type === 'notebookData') {
|
|
80
|
+
// UI is responding to a readNotebook request
|
|
81
|
+
// Pass message directly like Python does - it contains { requestId, result: { success, data } }
|
|
82
|
+
operation_router_1.operationRouter.handleUIResponse(notebookPath, message);
|
|
83
|
+
}
|
|
84
|
+
else if (message.type === 'ping') {
|
|
85
|
+
// Respond to keep-alive ping with pong
|
|
86
|
+
ws.send(JSON.stringify({ type: 'pong' }));
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
console.warn(`[Notebook WS] Unknown message type:`, message.type);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
console.error('[Notebook WS] Error parsing message:', err);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
ws.on('close', () => {
|
|
97
|
+
clearInterval(heartbeatInterval);
|
|
98
|
+
console.log(`[Notebook WS] Disconnected for notebook: ${notebookPath}`);
|
|
99
|
+
operation_router_1.operationRouter.unregisterUI(ws, notebookPath);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
return wss;
|
|
103
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notebook Operation Router
|
|
3
|
+
*
|
|
4
|
+
* Routes notebook operations to either:
|
|
5
|
+
* 1. Connected UI via WebSocket (real-time collaboration)
|
|
6
|
+
* 2. Headless notebook manager (file-based when no UI)
|
|
7
|
+
*
|
|
8
|
+
* From the agent's (MCP) perspective, operations look identical regardless of mode.
|
|
9
|
+
*/
|
|
10
|
+
import { WebSocket } from 'ws';
|
|
11
|
+
import { HeadlessOperationHandler } from './headless-handler';
|
|
12
|
+
interface KernelChangedPayload {
|
|
13
|
+
kernelName: string;
|
|
14
|
+
serverId?: string | null;
|
|
15
|
+
}
|
|
16
|
+
type Backend = 'ui' | 'headless';
|
|
17
|
+
interface OperationResult {
|
|
18
|
+
success: boolean;
|
|
19
|
+
error?: string;
|
|
20
|
+
backend?: Backend;
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
interface AgentLock {
|
|
24
|
+
agentId: string;
|
|
25
|
+
clientName?: string;
|
|
26
|
+
clientVersion?: string;
|
|
27
|
+
expiresAt: number;
|
|
28
|
+
notebookPath: string;
|
|
29
|
+
lockedAt: number;
|
|
30
|
+
}
|
|
31
|
+
export declare class OperationRouter {
|
|
32
|
+
private uiConnections;
|
|
33
|
+
private headlessHandler;
|
|
34
|
+
private operationTimeout;
|
|
35
|
+
private agentLocks;
|
|
36
|
+
setHeadlessHandler(handler: HeadlessOperationHandler): void;
|
|
37
|
+
/**
|
|
38
|
+
* Register a UI connection for a notebook path.
|
|
39
|
+
*/
|
|
40
|
+
registerUI(websocket: WebSocket, notebookPath: string): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Unregister a UI connection.
|
|
43
|
+
*/
|
|
44
|
+
unregisterUI(websocket: WebSocket, notebookPath: string): void;
|
|
45
|
+
notifyKernelChanged(notebookPath: string, payload: KernelChangedPayload): void;
|
|
46
|
+
/**
|
|
47
|
+
* Check if a UI is connected for the notebook.
|
|
48
|
+
*/
|
|
49
|
+
hasUI(notebookPath: string): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Record UI WebSocket activity so stale connections stop intercepting operations.
|
|
52
|
+
*/
|
|
53
|
+
markUIActivity(websocket: WebSocket, notebookPath: string): void;
|
|
54
|
+
/**
|
|
55
|
+
* Start an agent session with locking.
|
|
56
|
+
* Returns success if lock acquired, error if already locked by another agent.
|
|
57
|
+
*/
|
|
58
|
+
startAgentSession(notebookPath: string, agentId: string, metadata?: {
|
|
59
|
+
clientName?: string;
|
|
60
|
+
clientVersion?: string;
|
|
61
|
+
}): {
|
|
62
|
+
success: boolean;
|
|
63
|
+
error?: string;
|
|
64
|
+
lock?: AgentLock;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* End an agent session and release the lock.
|
|
68
|
+
* Only the lock holder can release the lock.
|
|
69
|
+
*/
|
|
70
|
+
endAgentSession(notebookPath: string, agentId: string): {
|
|
71
|
+
success: boolean;
|
|
72
|
+
error?: string;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Check if a notebook is in an agent session.
|
|
76
|
+
*/
|
|
77
|
+
isAgentSession(notebookPath: string): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Get the agent ID holding the lock, if any.
|
|
80
|
+
*/
|
|
81
|
+
getAgentLock(notebookPath: string): AgentLock | null;
|
|
82
|
+
/**
|
|
83
|
+
* Refresh lock timeout for an agent operation.
|
|
84
|
+
*/
|
|
85
|
+
refreshAgentLock(notebookPath: string, agentId: string): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Clean up expired locks.
|
|
88
|
+
*/
|
|
89
|
+
private cleanupExpiredLocks;
|
|
90
|
+
/**
|
|
91
|
+
* Get the first available UI connection (for operations that can use any UI).
|
|
92
|
+
*/
|
|
93
|
+
private getAnyUIConnection;
|
|
94
|
+
private isUIConnectionResponsive;
|
|
95
|
+
private getResponsiveUIConnection;
|
|
96
|
+
/**
|
|
97
|
+
* Apply a notebook operation.
|
|
98
|
+
*/
|
|
99
|
+
applyOperation(operation: Record<string, unknown>): Promise<OperationResult>;
|
|
100
|
+
private forwardToUI;
|
|
101
|
+
/**
|
|
102
|
+
* Handle operation response from UI.
|
|
103
|
+
*/
|
|
104
|
+
handleUIResponse(notebookPath: string, response: Record<string, unknown>): void;
|
|
105
|
+
private applyHeadless;
|
|
106
|
+
/**
|
|
107
|
+
* Read notebook state.
|
|
108
|
+
*/
|
|
109
|
+
readNotebook(notebookPath: string, includeOutputs?: boolean, maxLines?: number, maxChars?: number, maxLinesError?: number, maxCharsError?: number): Promise<OperationResult>;
|
|
110
|
+
private readFromUI;
|
|
111
|
+
private readFromFile;
|
|
112
|
+
private applyOutputTruncation;
|
|
113
|
+
}
|
|
114
|
+
export declare const operationRouter: OperationRouter;
|
|
115
|
+
export {};
|