more-compute 0.1.3__py3-none-any.whl → 0.2.0__py3-none-any.whl

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 (55) hide show
  1. frontend/app/globals.css +322 -77
  2. frontend/app/layout.tsx +98 -82
  3. frontend/components/Cell.tsx +234 -95
  4. frontend/components/Notebook.tsx +430 -199
  5. frontend/components/{AddCellButton.tsx → cell/AddCellButton.tsx} +0 -2
  6. frontend/components/cell/MonacoCell.tsx +726 -0
  7. frontend/components/layout/ConnectionBanner.tsx +41 -0
  8. frontend/components/{Sidebar.tsx → layout/Sidebar.tsx} +16 -11
  9. frontend/components/modals/ConfirmModal.tsx +154 -0
  10. frontend/components/modals/SuccessModal.tsx +140 -0
  11. frontend/components/output/MarkdownRenderer.tsx +116 -0
  12. frontend/components/popups/ComputePopup.tsx +674 -365
  13. frontend/components/popups/MetricsPopup.tsx +11 -7
  14. frontend/components/popups/SettingsPopup.tsx +11 -13
  15. frontend/contexts/PodWebSocketContext.tsx +247 -0
  16. frontend/eslint.config.mjs +11 -0
  17. frontend/lib/monaco-themes.ts +160 -0
  18. frontend/lib/settings.ts +128 -26
  19. frontend/lib/themes.json +9973 -0
  20. frontend/lib/websocket-native.ts +19 -8
  21. frontend/lib/websocket.ts +59 -11
  22. frontend/next.config.ts +8 -0
  23. frontend/package-lock.json +1705 -3
  24. frontend/package.json +8 -1
  25. frontend/styling_README.md +18 -0
  26. kernel_run.py +161 -43
  27. more_compute-0.2.0.dist-info/METADATA +126 -0
  28. more_compute-0.2.0.dist-info/RECORD +100 -0
  29. morecompute/__version__.py +1 -0
  30. morecompute/execution/executor.py +31 -20
  31. morecompute/execution/worker.py +68 -7
  32. morecompute/models/__init__.py +31 -0
  33. morecompute/models/api_models.py +197 -0
  34. morecompute/notebook.py +50 -7
  35. morecompute/server.py +574 -94
  36. morecompute/services/data_manager.py +379 -0
  37. morecompute/services/lsp_service.py +335 -0
  38. morecompute/services/pod_manager.py +122 -20
  39. morecompute/services/pod_monitor.py +138 -0
  40. morecompute/services/prime_intellect.py +87 -63
  41. morecompute/utils/config_util.py +59 -0
  42. morecompute/utils/special_commands.py +11 -5
  43. morecompute/utils/zmq_util.py +51 -0
  44. frontend/components/MarkdownRenderer.tsx +0 -84
  45. frontend/components/popups/PythonPopup.tsx +0 -292
  46. more_compute-0.1.3.dist-info/METADATA +0 -173
  47. more_compute-0.1.3.dist-info/RECORD +0 -85
  48. /frontend/components/{CellButton.tsx → cell/CellButton.tsx} +0 -0
  49. /frontend/components/{ErrorModal.tsx → modals/ErrorModal.tsx} +0 -0
  50. /frontend/components/{CellOutput.tsx → output/CellOutput.tsx} +0 -0
  51. /frontend/components/{ErrorDisplay.tsx → output/ErrorDisplay.tsx} +0 -0
  52. {more_compute-0.1.3.dist-info → more_compute-0.2.0.dist-info}/WHEEL +0 -0
  53. {more_compute-0.1.3.dist-info → more_compute-0.2.0.dist-info}/entry_points.txt +0 -0
  54. {more_compute-0.1.3.dist-info → more_compute-0.2.0.dist-info}/licenses/LICENSE +0 -0
  55. {more_compute-0.1.3.dist-info → more_compute-0.2.0.dist-info}/top_level.txt +0 -0
@@ -1,20 +1,38 @@
1
- 'use client';
2
-
3
- import React, { useRef, useEffect, useState } from 'react';
4
- import { Cell as CellType } from '@/types/notebook';
5
- import CellOutput from './CellOutput';
6
- import AddCellButton from './AddCellButton';
7
- import MarkdownRenderer from './MarkdownRenderer';
8
- import CellButton from './CellButton';
9
- import { UpdateIcon, LinkBreak2Icon, PlayIcon, RowSpacingIcon } from '@radix-ui/react-icons';
10
- import { Check, X } from 'lucide-react';
11
- import { fixIndentation } from '@/lib/api';
1
+ /**
2
+ * LEGACY COMPONENT - NO LONGER USED
3
+ *
4
+ * This component has been replaced by MonacoCell.tsx which provides:
5
+ * - Modern Monaco Editor (VSCode engine)
6
+ * - LSP support for Python autocomplete and hover
7
+ * - Better performance and features
8
+ *
9
+ * Kept for reference only. Do not use in new code.
10
+ */
11
+
12
+ "use client";
13
+
14
+ import React, { useRef, useEffect, useState } from "react";
15
+ import { Cell as CellType } from "@/types/notebook";
16
+ import CellOutput from "./output/CellOutput";
17
+ import AddCellButton from "./cell/AddCellButton";
18
+ import MarkdownRenderer from "./output/MarkdownRenderer";
19
+ import CellButton from "./cell/CellButton";
20
+ import {
21
+ UpdateIcon,
22
+ LinkBreak2Icon,
23
+ PlayIcon,
24
+ ChevronUpIcon,
25
+ ChevronDownIcon,
26
+ } from "@radix-ui/react-icons";
27
+ import { Check, X } from "lucide-react";
28
+ import { fixIndentation } from "@/lib/api";
12
29
 
13
30
  declare const CodeMirror: any;
14
31
 
15
32
  interface CellProps {
16
33
  cell: CellType;
17
34
  index: number;
35
+ totalCells: number;
18
36
  isActive: boolean;
19
37
  isExecuting: boolean;
20
38
  onExecute: (index: number) => void;
@@ -22,12 +40,15 @@ interface CellProps {
22
40
  onDelete: (index: number) => void;
23
41
  onUpdate: (index: number, source: string) => void;
24
42
  onSetActive: (index: number) => void;
25
- onAddCell: (type: 'code' | 'markdown', index: number) => void;
43
+ onAddCell: (type: "code" | "markdown", index: number) => void;
44
+ onMoveUp: (index: number) => void;
45
+ onMoveDown: (index: number) => void;
26
46
  }
27
47
 
28
48
  export const Cell: React.FC<CellProps> = ({
29
49
  cell,
30
50
  index,
51
+ totalCells,
31
52
  isActive,
32
53
  isExecuting,
33
54
  onExecute,
@@ -36,38 +57,107 @@ export const Cell: React.FC<CellProps> = ({
36
57
  onUpdate,
37
58
  onSetActive,
38
59
  onAddCell,
60
+ onMoveUp,
61
+ onMoveDown,
39
62
  }) => {
63
+ // ============================================================================
64
+ // REFS
65
+ // ============================================================================
40
66
  const editorRef = useRef<HTMLTextAreaElement>(null);
41
- const codeMirrorInstance = useRef<any>(null);
42
- // Keep a ref to the latest index to avoid stale closures in event handlers
67
+ const codeMirrorInstance = useRef<{
68
+ setValue: (value: string) => void;
69
+ toTextArea: () => void;
70
+ getValue: () => string;
71
+ } | null>(null);
72
+ const wasEditingMarkdown = useRef(false);
43
73
  const indexRef = useRef<number>(index);
44
- useEffect(() => { indexRef.current = index; }, [index]);
74
+ const intervalRef = useRef<NodeJS.Timeout | null>(null);
45
75
 
46
- // Execution timer (shows while running and persists final duration afterwards)
47
- const intervalRef = useRef<any>(null);
48
- const [elapsedLabel, setElapsedLabel] = useState<string | null>(cell.execution_time ?? null);
76
+ // ============================================================================
77
+ // STATE
78
+ // ============================================================================
79
+ const [isEditing, setIsEditing] = useState(
80
+ () => cell.cell_type === "code" || !cell.source?.trim()
81
+ );
82
+ const [elapsedLabel, setElapsedLabel] = useState<string | null>(
83
+ cell.execution_time ?? null
84
+ );
49
85
 
86
+ // ============================================================================
87
+ // UTILITIES
88
+ // ============================================================================
50
89
  const formatMs = (ms: number): string => {
51
90
  if (ms < 1000) return `${ms.toFixed(0)}ms`;
52
91
  if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;
53
92
  const totalSeconds = Math.floor(ms / 1000);
54
93
  const minutes = Math.floor(totalSeconds / 60);
55
94
  const seconds = totalSeconds % 60;
56
- return `${minutes}:${seconds.toString().padStart(2, '0')}s`;
95
+ return `${minutes}:${seconds.toString().padStart(2, "0")}s`;
57
96
  };
58
97
 
59
98
  const parseExecTime = (s?: string | null): number | null => {
60
99
  if (!s) return null;
61
- // Accept "123.4ms" or "1.2s"
62
- if (s.endsWith('ms')) return parseFloat(s.replace('ms', ''));
63
- if (s.endsWith('s')) return parseFloat(s.replace('s', '')) * 1000;
100
+ if (s.endsWith("ms")) return parseFloat(s.replace("ms", ""));
101
+ if (s.endsWith("s")) return parseFloat(s.replace("s", "")) * 1000;
64
102
  return null;
65
103
  };
66
104
 
105
+ // ============================================================================
106
+ // COMPUTED VALUES
107
+ // ============================================================================
108
+ const isMarkdownWithContent =
109
+ cell.cell_type === "markdown" && !isEditing && cell.source?.trim();
110
+
111
+ // ============================================================================
112
+ // HANDLERS
113
+ // ============================================================================
114
+ const handleExecute = () => {
115
+ if (cell.cell_type === "markdown") {
116
+ onExecute(indexRef.current);
117
+ setIsEditing(false);
118
+ } else {
119
+ if (isExecuting) {
120
+ onInterrupt(indexRef.current);
121
+ } else {
122
+ onExecute(indexRef.current);
123
+ }
124
+ }
125
+ };
126
+
127
+ const handleCellClick = () => {
128
+ onSetActive(indexRef.current);
129
+ if (cell.cell_type === "markdown") {
130
+ setIsEditing(true);
131
+ }
132
+ };
133
+
134
+ const handleFixIndentation = async () => {
135
+ try {
136
+ const fixedCode = await fixIndentation(cell.source);
137
+ onUpdate(indexRef.current, fixedCode);
138
+
139
+ if (codeMirrorInstance.current) {
140
+ codeMirrorInstance.current.setValue(fixedCode);
141
+ }
142
+ } catch (err) {
143
+ console.error("Failed to fix indentation:", err);
144
+ }
145
+ };
146
+
147
+ // ============================================================================
148
+ // EFFECTS
149
+ // ============================================================================
150
+
151
+ // Keep indexRef in sync
152
+ useEffect(() => {
153
+ indexRef.current = index;
154
+ }, [index]);
155
+
156
+ // Execution timer
67
157
  useEffect(() => {
68
158
  if (isExecuting) {
69
159
  const start = Date.now();
70
- setElapsedLabel('0ms');
160
+ setElapsedLabel("0ms");
71
161
  if (intervalRef.current) clearInterval(intervalRef.current);
72
162
  intervalRef.current = setInterval(() => {
73
163
  setElapsedLabel(formatMs(Date.now() - start));
@@ -77,10 +167,10 @@ export const Cell: React.FC<CellProps> = ({
77
167
  clearInterval(intervalRef.current);
78
168
  intervalRef.current = null;
79
169
  }
80
- // Persist final time from cell.execution_time if available
81
170
  const ms = parseExecTime(cell.execution_time as any);
82
171
  if (ms != null) setElapsedLabel(formatMs(ms));
83
172
  }
173
+
84
174
  return () => {
85
175
  if (intervalRef.current) {
86
176
  clearInterval(intervalRef.current);
@@ -88,30 +178,64 @@ export const Cell: React.FC<CellProps> = ({
88
178
  }
89
179
  };
90
180
  }, [isExecuting, cell.execution_time]);
91
- const [isEditing, setIsEditing] = useState(() => cell.cell_type === 'code' || !cell.source?.trim());
92
181
 
93
- // Determine if this is a markdown cell with content in display mode
94
- const isMarkdownWithContent = cell.cell_type === 'markdown' && !isEditing && cell.source?.trim();
182
+ // Track when user is editing markdown (for auto-save on click away)
183
+ useEffect(() => {
184
+ if (isActive && cell.cell_type === "markdown" && isEditing) {
185
+ wasEditingMarkdown.current = true;
186
+ }
187
+ }, [isActive, cell.cell_type]);
95
188
 
189
+ // Auto-save markdown when user clicks away
190
+ useEffect(() => {
191
+ if (
192
+ !isActive &&
193
+ wasEditingMarkdown.current &&
194
+ cell.cell_type === "markdown"
195
+ ) {
196
+ if (cell.source?.trim()) {
197
+ onExecute(indexRef.current);
198
+ setIsEditing(false);
199
+ }
200
+ wasEditingMarkdown.current = false;
201
+ }
202
+ }, [isActive, cell.cell_type]);
203
+
204
+ // CodeMirror editor initialization and cleanup
96
205
  useEffect(() => {
97
206
  if (isEditing) {
98
- if (!codeMirrorInstance.current && editorRef.current && typeof CodeMirror !== 'undefined') {
207
+ if (
208
+ !codeMirrorInstance.current &&
209
+ editorRef.current &&
210
+ typeof CodeMirror !== "undefined"
211
+ ) {
99
212
  const editor = CodeMirror.fromTextArea(editorRef.current, {
100
- mode: cell.cell_type === 'code' ? 'python' : 'text/plain',
101
- lineNumbers: cell.cell_type === 'code',
102
- theme: 'default',
213
+ mode: cell.cell_type === "code" ? "python" : "text/plain",
214
+ lineNumbers: cell.cell_type === "code",
215
+ theme: "default",
103
216
  lineWrapping: true,
104
- placeholder: cell.cell_type === 'code' ? 'Enter code...' : 'Enter markdown...',
217
+ placeholder:
218
+ cell.cell_type === "code" ? "Enter code..." : "Enter markdown...",
105
219
  });
106
220
  codeMirrorInstance.current = editor;
107
221
 
108
- editor.on('change', (instance: any) => onUpdate(indexRef.current, instance.getValue()));
109
- editor.on('focus', () => onSetActive(indexRef.current));
110
- editor.on('blur', () => {
111
- if (cell.cell_type === 'markdown') setIsEditing(false);
222
+ editor.on("change", (instance: any) =>
223
+ onUpdate(indexRef.current, instance.getValue())
224
+ );
225
+ editor.on("focus", () => onSetActive(indexRef.current));
226
+ editor.on("blur", () => {
227
+ if (cell.cell_type === "markdown") {
228
+ if (cell.source?.trim()) {
229
+ // Auto-save on blur
230
+ onExecute(indexRef.current);
231
+ setIsEditing(false);
232
+ }
233
+ // If empty, stay in editing mode but mark as no longer editing
234
+ wasEditingMarkdown.current = false;
235
+ }
112
236
  });
113
- editor.on('keydown', (instance: any, event: KeyboardEvent) => {
114
- if (event.shiftKey && event.key === 'Enter') {
237
+ editor.on("keydown", (instance: any, event: KeyboardEvent) => {
238
+ if (event.shiftKey && event.key === "Enter") {
115
239
  event.preventDefault();
116
240
  handleExecute();
117
241
  }
@@ -129,42 +253,12 @@ export const Cell: React.FC<CellProps> = ({
129
253
  }
130
254
  }, [isEditing, cell.source]);
131
255
 
132
- const handleExecute = () => {
133
- if (cell.cell_type === 'markdown') {
134
- onExecute(indexRef.current); // Call onExecute for save logic
135
- setIsEditing(false);
136
- } else {
137
- if (isExecuting) {
138
- onInterrupt(indexRef.current);
139
- } else {
140
- onExecute(indexRef.current);
141
- }
142
- }
143
- };
144
-
145
- const handleCellClick = () => {
146
- onSetActive(indexRef.current);
147
- if (cell.cell_type === 'markdown') {
148
- setIsEditing(true);
149
- }
150
- };
151
-
152
- const handleFixIndentation = async () => {
153
- try {
154
- const fixedCode = await fixIndentation(cell.source);
155
- onUpdate(indexRef.current, fixedCode);
156
-
157
- // Update CodeMirror if it's initialized
158
- if (codeMirrorInstance.current) {
159
- codeMirrorInstance.current.setValue(fixedCode);
160
- }
161
- } catch (err) {
162
- console.error('Failed to fix indentation:', err);
163
- }
164
- };
165
-
256
+ // ============================================================================
257
+ // RENDER
258
+ // ============================================================================
166
259
  return (
167
260
  <div className="cell-wrapper">
261
+ {/* Status Indicator */}
168
262
  {!isMarkdownWithContent && (
169
263
  <div className="cell-status-indicator">
170
264
  <span className="status-indicator">
@@ -176,68 +270,113 @@ export const Cell: React.FC<CellProps> = ({
176
270
  ) : cell.execution_count != null ? (
177
271
  <Check size={14} color="#16a34a" />
178
272
  ) : (
179
- <span style={{ width: '14px', height: '14px', display: 'inline-block' }}></span>
273
+ <span
274
+ style={{
275
+ width: "14px",
276
+ height: "14px",
277
+ display: "inline-block",
278
+ }}
279
+ ></span>
180
280
  )}
181
281
  <span className="status-bracket">]</span>
182
282
  </span>
183
283
  {elapsedLabel && (
184
- <span className="status-timer" title="Execution time">{elapsedLabel}</span>
284
+ <span className="status-timer" title="Execution time">
285
+ {elapsedLabel}
286
+ </span>
185
287
  )}
186
288
  </div>
187
289
  )}
290
+
291
+ {/* Add Cell Above Button */}
188
292
  <div className="add-cell-line add-line-above">
189
293
  <AddCellButton onAddCell={(type) => onAddCell(type, indexRef.current)} />
190
294
  </div>
191
295
 
296
+ {/* Main Cell Container */}
192
297
  <div
193
- className={`cell ${isActive ? 'active' : ''} ${isExecuting ? 'executing' : ''} ${isMarkdownWithContent ? 'markdown-display-mode' : ''}`}
298
+ className={`cell ${isActive ? "active" : ""} ${isExecuting ? "executing" : ""} ${isMarkdownWithContent ? "markdown-display-mode" : ""}`}
194
299
  data-cell-index={index}
195
300
  >
196
- {/* Only show hover controls for non-markdown-display cells */}
301
+ {/* Hover Controls */}
197
302
  {!isMarkdownWithContent && (
198
303
  <div className="cell-hover-controls">
199
304
  <div className="cell-actions-right">
200
305
  <CellButton
201
- icon={
202
- <PlayIcon className="w-6 h-6" />
203
- }
204
- onClick={(e) => { e.stopPropagation(); handleExecute(); }}
306
+ icon={<PlayIcon className="w-6 h-6" />}
307
+ onClick={(e) => {
308
+ e.stopPropagation();
309
+ handleExecute();
310
+ }}
205
311
  title={isExecuting ? "Stop execution" : "Run cell"}
206
312
  isLoading={isExecuting}
207
313
  />
208
314
  <CellButton
209
- icon={
210
- <RowSpacingIcon className="w-6 h-6" />
211
- }
212
- title="Drag to reorder"
315
+ icon={<ChevronUpIcon className="w-6 h-6" />}
316
+ onClick={(e) => {
317
+ e.stopPropagation();
318
+ onMoveUp(indexRef.current);
319
+ }}
320
+ title="Move cell up"
321
+ disabled={index === 0}
322
+ />
323
+ <CellButton
324
+ icon={<ChevronDownIcon className="w-6 h-6" />}
325
+ onClick={(e) => {
326
+ e.stopPropagation();
327
+ onMoveDown(indexRef.current);
328
+ }}
329
+ title="Move cell down"
330
+ disabled={index === totalCells - 1}
213
331
  />
214
332
  <CellButton
215
- icon={
216
- <LinkBreak2Icon className="w-5 h-5" />
217
- }
218
- onClick={(e) => { e.stopPropagation(); onDelete(indexRef.current); }}
333
+ icon={<LinkBreak2Icon className="w-5 h-5" />}
334
+ onClick={(e) => {
335
+ e.stopPropagation();
336
+ onDelete(indexRef.current);
337
+ }}
219
338
  title="Delete cell"
220
339
  />
221
340
  </div>
222
341
  </div>
223
342
  )}
224
343
 
225
- <div className={`cell-content ${isMarkdownWithContent ? 'cursor-pointer' : ''}`} onClick={handleCellClick}>
344
+ {/* Cell Content */}
345
+ <div
346
+ className={`cell-content ${isMarkdownWithContent ? "cursor-pointer" : ""}`}
347
+ onClick={handleCellClick}
348
+ >
226
349
  <div className="cell-input">
227
- {isEditing || cell.cell_type === 'code' ? (
228
- <div className={`cell-editor-container ${cell.cell_type === 'markdown' ? 'markdown-editor-container' : 'code-editor-container'}`}>
229
- <textarea ref={editorRef} defaultValue={cell.source} className={`cell-editor ${cell.cell_type === 'markdown' ? 'markdown-editor' : 'code-editor'}`} />
350
+ {isEditing || cell.cell_type === "code" ? (
351
+ <div
352
+ className={`cell-editor-container ${cell.cell_type === "markdown" ? "markdown-editor-container" : "code-editor-container"}`}
353
+ >
354
+ <textarea
355
+ ref={editorRef}
356
+ defaultValue={cell.source}
357
+ className={`cell-editor ${cell.cell_type === "markdown" ? "markdown-editor" : "code-editor"}`}
358
+ />
230
359
  </div>
231
360
  ) : (
232
- <MarkdownRenderer source={cell.source} onClick={() => setIsEditing(true)} />
361
+ <MarkdownRenderer
362
+ source={cell.source}
363
+ onClick={() => setIsEditing(true)}
364
+ />
233
365
  )}
234
366
  </div>
235
- <CellOutput outputs={cell.outputs} error={cell.error} onFixIndentation={handleFixIndentation} />
367
+ <CellOutput
368
+ outputs={cell.outputs}
369
+ error={cell.error}
370
+ onFixIndentation={handleFixIndentation}
371
+ />
236
372
  </div>
237
373
  </div>
238
374
 
375
+ {/* Add Cell Below Button */}
239
376
  <div className="add-cell-line add-line-below">
240
- <AddCellButton onAddCell={(type) => onAddCell(type, indexRef.current + 1)} />
377
+ <AddCellButton
378
+ onAddCell={(type) => onAddCell(type, indexRef.current + 1)}
379
+ />
241
380
  </div>
242
381
  </div>
243
382
  );