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,254 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Terminal Server - Routes and WebSocket setup for PTY management
|
|
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.setupTerminalRoutes = setupTerminalRoutes;
|
|
40
|
+
exports.setupTerminalWebSocket = setupTerminalWebSocket;
|
|
41
|
+
exports.cleanupTerminals = cleanupTerminals;
|
|
42
|
+
const ws_1 = require("ws");
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const pty_manager_1 = require("./pty-manager");
|
|
45
|
+
const fs_service_1 = require("../fs/fs-service");
|
|
46
|
+
// Get configured root directory for terminals
|
|
47
|
+
function getDefaultCwd() {
|
|
48
|
+
return fs_service_1.fsService.normalizePath('~');
|
|
49
|
+
}
|
|
50
|
+
// Nebula repo root on the server (parent of node-server). Surfaced so the UI
|
|
51
|
+
// can show a path-qualified MCP setup command — agents/users won't know where
|
|
52
|
+
// the repo lives, and `npm run setup-mcp` only works from inside it.
|
|
53
|
+
// Works from both src/ (tsx) and dist/ (build): each is 3 levels deep.
|
|
54
|
+
const NEBULA_REPO_ROOT = path.resolve(__dirname, '..', '..', '..');
|
|
55
|
+
// Track WebSocket connections by terminal ID
|
|
56
|
+
const wsConnections = new Map();
|
|
57
|
+
/**
|
|
58
|
+
* Setup terminal REST routes as a Fastify plugin
|
|
59
|
+
*/
|
|
60
|
+
async function setupTerminalRoutes(fastify) {
|
|
61
|
+
// Terminal health check (includes terminal count and repo root for the
|
|
62
|
+
// path-qualified MCP setup hint shown in the agent terminal UI)
|
|
63
|
+
fastify.get('/api/terminals/health', async (_request, reply) => {
|
|
64
|
+
return reply.send({ status: 'ok', terminals: pty_manager_1.ptyManager.list().length, repo_root: NEBULA_REPO_ROOT });
|
|
65
|
+
});
|
|
66
|
+
// List all terminals
|
|
67
|
+
fastify.get('/api/terminals', async (_request, reply) => {
|
|
68
|
+
return reply.send(pty_manager_1.ptyManager.list());
|
|
69
|
+
});
|
|
70
|
+
// Create a new terminal
|
|
71
|
+
fastify.post('/api/terminals', async (request, reply) => {
|
|
72
|
+
const options = request.body || {};
|
|
73
|
+
// Use configured root directory as default cwd
|
|
74
|
+
const finalOptions = { cwd: getDefaultCwd(), ...options };
|
|
75
|
+
try {
|
|
76
|
+
const terminal = pty_manager_1.ptyManager.create(finalOptions);
|
|
77
|
+
console.log(`[Terminal] Created terminal ${terminal.id} (PID: ${terminal.pid})`);
|
|
78
|
+
return reply.code(201).send(terminal);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.error('[Terminal] Failed to create terminal:', error);
|
|
82
|
+
return reply.code(500).send({
|
|
83
|
+
error: 'Failed to create terminal',
|
|
84
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
// Get or create a named terminal (for persistent terminals via URL)
|
|
89
|
+
fastify.post('/api/terminals/named/:name', async (request, reply) => {
|
|
90
|
+
const { name } = request.params;
|
|
91
|
+
const options = request.body || {};
|
|
92
|
+
// Use configured root directory as default cwd
|
|
93
|
+
const finalOptions = { cwd: getDefaultCwd(), ...options };
|
|
94
|
+
try {
|
|
95
|
+
const terminal = pty_manager_1.ptyManager.getOrCreate(name, finalOptions);
|
|
96
|
+
console.log(`[Terminal] Get/create named terminal '${name}' -> ${terminal.id}`);
|
|
97
|
+
return reply.send(terminal);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
console.error('[Terminal] Failed to get/create named terminal:', error);
|
|
101
|
+
return reply.code(500).send({
|
|
102
|
+
error: 'Failed to get/create terminal',
|
|
103
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
// Get terminal info
|
|
108
|
+
fastify.get('/api/terminals/:id', async (request, reply) => {
|
|
109
|
+
const terminal = pty_manager_1.ptyManager.getTerminalInfo(request.params.id);
|
|
110
|
+
if (!terminal) {
|
|
111
|
+
return reply.code(404).send({ error: 'Terminal not found' });
|
|
112
|
+
}
|
|
113
|
+
return reply.send(terminal);
|
|
114
|
+
});
|
|
115
|
+
// Delete/close a terminal
|
|
116
|
+
fastify.delete('/api/terminals/:id', async (request, reply) => {
|
|
117
|
+
const success = pty_manager_1.ptyManager.kill(request.params.id);
|
|
118
|
+
if (!success) {
|
|
119
|
+
return reply.code(404).send({ error: 'Terminal not found' });
|
|
120
|
+
}
|
|
121
|
+
console.log(`[Terminal] Closed terminal ${request.params.id}`);
|
|
122
|
+
return reply.send({ status: 'ok' });
|
|
123
|
+
});
|
|
124
|
+
// Resize terminal
|
|
125
|
+
fastify.post('/api/terminals/:id/resize', async (request, reply) => {
|
|
126
|
+
const { cols, rows } = request.body;
|
|
127
|
+
if (!cols || !rows) {
|
|
128
|
+
return reply.code(400).send({ error: 'cols and rows are required' });
|
|
129
|
+
}
|
|
130
|
+
const success = pty_manager_1.ptyManager.resize(request.params.id, cols, rows);
|
|
131
|
+
if (!success) {
|
|
132
|
+
return reply.code(404).send({ error: 'Terminal not found' });
|
|
133
|
+
}
|
|
134
|
+
return reply.send({ status: 'ok', cols, rows });
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Setup terminal WebSocket server with noServer mode
|
|
139
|
+
* Returns the WSS so the upgrade can be handled externally
|
|
140
|
+
*/
|
|
141
|
+
function setupTerminalWebSocket(server) {
|
|
142
|
+
// Use noServer mode to avoid conflicts with kernel WebSocket
|
|
143
|
+
const wss = new ws_1.WebSocketServer({
|
|
144
|
+
noServer: true,
|
|
145
|
+
perMessageDeflate: false, // Disable compression
|
|
146
|
+
});
|
|
147
|
+
// Handle upgrade requests for /ws path
|
|
148
|
+
server.on('upgrade', (request, socket, head) => {
|
|
149
|
+
const pathname = new URL(request.url || '', `http://${request.headers.host}`).pathname;
|
|
150
|
+
if (pathname === '/ws') {
|
|
151
|
+
// Authenticate WebSocket connection
|
|
152
|
+
const { authWebSocketMiddleware } = require('../auth');
|
|
153
|
+
if (!authWebSocketMiddleware(request)) {
|
|
154
|
+
socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
|
|
155
|
+
socket.destroy();
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
159
|
+
wss.emit('connection', ws, request);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
// Don't destroy socket for non-matching paths - let other handlers deal with it
|
|
163
|
+
});
|
|
164
|
+
wss.on('connection', (ws, req) => {
|
|
165
|
+
// Extract terminal ID from URL query
|
|
166
|
+
const url = new URL(req.url || '', `http://${req.headers.host}`);
|
|
167
|
+
const terminalId = url.searchParams.get('id');
|
|
168
|
+
if (!terminalId) {
|
|
169
|
+
ws.close(4000, 'Terminal ID required');
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const session = pty_manager_1.ptyManager.get(terminalId);
|
|
173
|
+
if (!session) {
|
|
174
|
+
ws.close(4004, 'Terminal not found');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
console.log(`[Terminal] WebSocket connected to terminal ${terminalId}`);
|
|
178
|
+
// Track this connection
|
|
179
|
+
if (!wsConnections.has(terminalId)) {
|
|
180
|
+
wsConnections.set(terminalId, new Set());
|
|
181
|
+
}
|
|
182
|
+
const connections = wsConnections.get(terminalId);
|
|
183
|
+
connections.add(ws);
|
|
184
|
+
// Send buffered output for reconnection
|
|
185
|
+
const buffer = pty_manager_1.ptyManager.getOutputBuffer(terminalId);
|
|
186
|
+
if (buffer) {
|
|
187
|
+
const replayMsg = { type: 'replay', data: buffer };
|
|
188
|
+
ws.send(JSON.stringify(replayMsg));
|
|
189
|
+
}
|
|
190
|
+
// Collaborative mode: broadcast output to ALL connected clients
|
|
191
|
+
const broadcastOutput = (data) => {
|
|
192
|
+
const msg = { type: 'output', data };
|
|
193
|
+
const msgStr = JSON.stringify(msg);
|
|
194
|
+
for (const conn of connections) {
|
|
195
|
+
if (conn.readyState === ws_1.WebSocket.OPEN) {
|
|
196
|
+
conn.send(msgStr);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
pty_manager_1.ptyManager.setOnData(terminalId, broadcastOutput);
|
|
201
|
+
// Set up exit listener - broadcast to all connections
|
|
202
|
+
pty_manager_1.ptyManager.setOnExit(terminalId, (code) => {
|
|
203
|
+
const msg = { type: 'exit', code };
|
|
204
|
+
const msgStr = JSON.stringify(msg);
|
|
205
|
+
for (const conn of connections) {
|
|
206
|
+
if (conn.readyState === ws_1.WebSocket.OPEN) {
|
|
207
|
+
conn.send(msgStr);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
// Handle incoming messages
|
|
212
|
+
ws.on('message', (rawData) => {
|
|
213
|
+
try {
|
|
214
|
+
const message = JSON.parse(rawData.toString());
|
|
215
|
+
switch (message.type) {
|
|
216
|
+
case 'input':
|
|
217
|
+
pty_manager_1.ptyManager.write(terminalId, message.data);
|
|
218
|
+
break;
|
|
219
|
+
case 'resize':
|
|
220
|
+
pty_manager_1.ptyManager.resize(terminalId, message.cols, message.rows);
|
|
221
|
+
break;
|
|
222
|
+
default:
|
|
223
|
+
console.warn(`[Terminal] Unknown message type:`, message);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
console.error('[Terminal] Failed to parse message:', error);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
// Handle disconnection
|
|
231
|
+
ws.on('close', () => {
|
|
232
|
+
console.log(`[Terminal] WebSocket disconnected from terminal ${terminalId}`);
|
|
233
|
+
const connections = wsConnections.get(terminalId);
|
|
234
|
+
if (connections) {
|
|
235
|
+
connections.delete(ws);
|
|
236
|
+
if (connections.size === 0) {
|
|
237
|
+
wsConnections.delete(terminalId);
|
|
238
|
+
// Clear the data listener when no connections
|
|
239
|
+
pty_manager_1.ptyManager.setOnData(terminalId, null);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
ws.on('error', (error) => {
|
|
244
|
+
console.error(`[Terminal] WebSocket error for terminal ${terminalId}:`, error);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
return wss;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Cleanup all terminals (call on shutdown)
|
|
251
|
+
*/
|
|
252
|
+
function cleanupTerminals() {
|
|
253
|
+
pty_manager_1.ptyManager.killAll();
|
|
254
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal Server Types
|
|
3
|
+
*/
|
|
4
|
+
export interface TerminalInfo {
|
|
5
|
+
id: string;
|
|
6
|
+
pid: number;
|
|
7
|
+
cwd: string;
|
|
8
|
+
shell: string;
|
|
9
|
+
cols: number;
|
|
10
|
+
rows: number;
|
|
11
|
+
created: number;
|
|
12
|
+
lastActivity: number;
|
|
13
|
+
}
|
|
14
|
+
export interface CreateTerminalRequest {
|
|
15
|
+
cwd?: string;
|
|
16
|
+
shell?: string;
|
|
17
|
+
cols?: number;
|
|
18
|
+
rows?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface ResizeTerminalRequest {
|
|
21
|
+
cols: number;
|
|
22
|
+
rows: number;
|
|
23
|
+
}
|
|
24
|
+
export type ClientMessage = {
|
|
25
|
+
type: 'input';
|
|
26
|
+
data: string;
|
|
27
|
+
} | {
|
|
28
|
+
type: 'resize';
|
|
29
|
+
cols: number;
|
|
30
|
+
rows: number;
|
|
31
|
+
};
|
|
32
|
+
export type ServerMessage = {
|
|
33
|
+
type: 'output';
|
|
34
|
+
data: string;
|
|
35
|
+
} | {
|
|
36
|
+
type: 'replay';
|
|
37
|
+
data: string;
|
|
38
|
+
} | {
|
|
39
|
+
type: 'exit';
|
|
40
|
+
code: number;
|
|
41
|
+
} | {
|
|
42
|
+
type: 'error';
|
|
43
|
+
message: string;
|
|
44
|
+
} | {
|
|
45
|
+
type: 'inactive';
|
|
46
|
+
} | {
|
|
47
|
+
type: 'active';
|
|
48
|
+
};
|
|
49
|
+
export declare const OUTPUT_BUFFER_MAX_SIZE = 100000;
|
|
50
|
+
export declare const OUTPUT_BUFFER_TRIM_SIZE = 50000;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Terminal Server Types
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.OUTPUT_BUFFER_TRIM_SIZE = exports.OUTPUT_BUFFER_MAX_SIZE = void 0;
|
|
7
|
+
// Output buffer settings
|
|
8
|
+
exports.OUTPUT_BUFFER_MAX_SIZE = 100000; // ~100KB of scrollback
|
|
9
|
+
exports.OUTPUT_BUFFER_TRIM_SIZE = 50000; // Trim to ~50KB when exceeded
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nebula-node-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Node.js server for Nebula Notebook (terminals, filesystem, kernels, LLM)",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc",
|
|
8
|
+
"start": "node dist/index.js",
|
|
9
|
+
"dev": "node --watch --import tsx src/index.ts",
|
|
10
|
+
"auth:qr": "tsx src/scripts/show-auth-qr.ts",
|
|
11
|
+
"test": "vitest",
|
|
12
|
+
"test:run": "vitest run"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@anthropic-ai/sdk": "^0.32.0",
|
|
16
|
+
"@fastify/cors": "^11.2.0",
|
|
17
|
+
"@fastify/multipart": "^9.4.0",
|
|
18
|
+
"@fastify/static": "^9.0.0",
|
|
19
|
+
"@fastify/websocket": "^11.2.0",
|
|
20
|
+
"@google/genai": "^0.7.0",
|
|
21
|
+
"@homebridge/node-pty-prebuilt-multiarch": "^0.14.0",
|
|
22
|
+
"better-sqlite3": "^11.0.0",
|
|
23
|
+
"fastify": "^5.8.2",
|
|
24
|
+
"jsonwebtoken": "^9.0.2",
|
|
25
|
+
"openai": "^4.77.0",
|
|
26
|
+
"otplib": "^12.0.1",
|
|
27
|
+
"qrcode-terminal": "^0.12.0",
|
|
28
|
+
"uuid": "^9.0.1",
|
|
29
|
+
"ws": "^8.16.0",
|
|
30
|
+
"zeromq": "^6.4.2"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/better-sqlite3": "^7.6.8",
|
|
34
|
+
"@types/jsonwebtoken": "^9.0.5",
|
|
35
|
+
"@types/node": "^20.10.0",
|
|
36
|
+
"@types/qrcode-terminal": "^0.12.2",
|
|
37
|
+
"@types/supertest": "^6.0.3",
|
|
38
|
+
"@types/uuid": "^9.0.7",
|
|
39
|
+
"@types/ws": "^8.5.10",
|
|
40
|
+
"supertest": "^7.2.2",
|
|
41
|
+
"tsx": "^4.7.0",
|
|
42
|
+
"typescript": "^5.3.0",
|
|
43
|
+
"vitest": "^4.0.16"
|
|
44
|
+
}
|
|
45
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nebula-notebook",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "AI-native notebook computing environment \u2014 real Jupyter kernels, real filesystem, built to be driven by agents (Claude Code / Codex) via MCP",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/jzthree/nebula-notebook.git"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"notebook",
|
|
13
|
+
"jupyter",
|
|
14
|
+
"ai",
|
|
15
|
+
"agent",
|
|
16
|
+
"mcp",
|
|
17
|
+
"claude",
|
|
18
|
+
"kernel"
|
|
19
|
+
],
|
|
20
|
+
"bin": {
|
|
21
|
+
"nebula-notebook": "bin/nebula-notebook.js"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"bin",
|
|
25
|
+
"dist",
|
|
26
|
+
"node-server/dist/**",
|
|
27
|
+
"node-server/package.json",
|
|
28
|
+
"scripts/postinstall.cjs"
|
|
29
|
+
],
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=20"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"dev": "concurrently --kill-others --kill-signal SIGTERM --raw \"cd node-server && PORT=${VITE_API_PORT:-8000} npm run dev\" \"VITE_API_PORT=${VITE_API_PORT:-8000} vite\"",
|
|
35
|
+
"start": "npm run dev",
|
|
36
|
+
"prod": "cd node-server && PORT=3000 npm run dev",
|
|
37
|
+
"auth:qr": "cd node-server && npm run auth:qr",
|
|
38
|
+
"build": "vite build",
|
|
39
|
+
"preview": "vite preview",
|
|
40
|
+
"node-server": "cd node-server && npm run dev",
|
|
41
|
+
"node-server:build": "cd node-server && npm run build",
|
|
42
|
+
"mcp": "npm --prefix packages/mcp run mcp",
|
|
43
|
+
"mcp:build": "npm --prefix packages/mcp run build",
|
|
44
|
+
"mcp:test": "npm --prefix packages/mcp test",
|
|
45
|
+
"setup-mcp": "npm --prefix packages/mcp run setup-mcp",
|
|
46
|
+
"setup": "node setup.cjs",
|
|
47
|
+
"postinstall": "node scripts/postinstall.cjs",
|
|
48
|
+
"prepublishOnly": "npm run build && npm run node-server:build",
|
|
49
|
+
"stop": "lsof -ti:3000,3001,8000 | xargs kill -9 2>/dev/null; echo 'Servers stopped'",
|
|
50
|
+
"test": "vitest",
|
|
51
|
+
"test:run": "vitest run"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@anthropic-ai/sdk": "^0.32.0",
|
|
55
|
+
"@fastify/cors": "^11.2.0",
|
|
56
|
+
"@fastify/multipart": "^9.4.0",
|
|
57
|
+
"@fastify/static": "^9.0.0",
|
|
58
|
+
"@fastify/websocket": "^11.2.0",
|
|
59
|
+
"@google/genai": "^0.7.0",
|
|
60
|
+
"@homebridge/node-pty-prebuilt-multiarch": "^0.14.0",
|
|
61
|
+
"better-sqlite3": "^11.0.0",
|
|
62
|
+
"fastify": "^5.8.2",
|
|
63
|
+
"jsonwebtoken": "^9.0.2",
|
|
64
|
+
"openai": "^4.77.0",
|
|
65
|
+
"otplib": "^12.0.1",
|
|
66
|
+
"qrcode-terminal": "^0.12.0",
|
|
67
|
+
"uuid": "^9.0.1",
|
|
68
|
+
"ws": "^8.16.0",
|
|
69
|
+
"zeromq": "^6.4.2"
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@codemirror/lang-markdown": "^6.5.0",
|
|
73
|
+
"@codemirror/lang-python": "^6.2.1",
|
|
74
|
+
"@playwright/test": "^1.57.0",
|
|
75
|
+
"@tailwindcss/vite": "^4.2.1",
|
|
76
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
77
|
+
"@testing-library/react": "^16.3.1",
|
|
78
|
+
"@types/diff-match-patch": "^1.0.36",
|
|
79
|
+
"@types/node": "^22.14.0",
|
|
80
|
+
"@types/react": "^19.2.7",
|
|
81
|
+
"@types/react-dom": "^19.2.3",
|
|
82
|
+
"@uiw/react-codemirror": "^4.25.4",
|
|
83
|
+
"@vitejs/plugin-react": "^5.0.0",
|
|
84
|
+
"@xterm/addon-fit": "^0.11.0",
|
|
85
|
+
"@xterm/addon-web-links": "^0.12.0",
|
|
86
|
+
"@xterm/xterm": "^6.0.0",
|
|
87
|
+
"ansi-to-html": "^0.7.2",
|
|
88
|
+
"concurrently": "^9.1.0",
|
|
89
|
+
"diff-match-patch": "^1.0.5",
|
|
90
|
+
"jsdom": "^27.3.0",
|
|
91
|
+
"lucide-react": "^0.561.0",
|
|
92
|
+
"react": "^19.2.3",
|
|
93
|
+
"react-dom": "^19.2.3",
|
|
94
|
+
"tailwindcss": "^4.2.1",
|
|
95
|
+
"typescript": "~5.8.2",
|
|
96
|
+
"vite": "^6.2.0",
|
|
97
|
+
"vitest": "^4.0.16"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repo-checkout convenience: install the node-server and packages/mcp
|
|
3
|
+
* subpackage dependencies after a root `npm install`.
|
|
4
|
+
*
|
|
5
|
+
* Skipped entirely when nebula-notebook is installed from npm as a
|
|
6
|
+
* dependency — the published package is self-contained (server runtime
|
|
7
|
+
* deps live in the root package.json; dist artifacts are prebuilt).
|
|
8
|
+
*/
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const { execSync } = require('child_process');
|
|
12
|
+
|
|
13
|
+
if (__dirname.split(path.sep).includes('node_modules')) {
|
|
14
|
+
process.exit(0);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const root = path.join(__dirname, '..');
|
|
18
|
+
for (const dir of ['node-server', path.join('packages', 'mcp')]) {
|
|
19
|
+
const pkg = path.join(root, dir, 'package.json');
|
|
20
|
+
if (!fs.existsSync(pkg)) continue;
|
|
21
|
+
try {
|
|
22
|
+
execSync('npm install', { cwd: path.join(root, dir), stdio: 'inherit' });
|
|
23
|
+
} catch {
|
|
24
|
+
console.warn(`⚠️ postinstall: npm install failed in ${dir}`);
|
|
25
|
+
}
|
|
26
|
+
}
|