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
frontend/package.json CHANGED
@@ -14,6 +14,7 @@
14
14
  "@codemirror/theme-one-dark": "^6.1.3",
15
15
  "@hugeicons/core-free-icons": "^1.1.0",
16
16
  "@hugeicons/react": "^1.1.1",
17
+ "@monaco-editor/react": "^4.7.0",
17
18
  "@radix-ui/react-icons": "^1.3.2",
18
19
  "@types/socket.io-client": "^1.4.36",
19
20
  "@uiw/react-codemirror": "^4.25.2",
@@ -21,11 +22,17 @@
21
22
  "codemirror": "^5.65.2",
22
23
  "framer-motion": "^12.23.22",
23
24
  "lucide-react": "^0.544.0",
25
+ "monaco-editor": "^0.54.0",
26
+ "monaco-languageclient": "^10.2.0",
24
27
  "next": "15.5.4",
25
28
  "react": "19.1.0",
26
29
  "react-dom": "19.1.0",
30
+ "react-window": "^2.2.1",
31
+ "react-window-infinite-loader": "^2.0.0",
27
32
  "socket.io-client": "^4.8.1",
28
- "sortablejs": "^1.15.3"
33
+ "sortablejs": "^1.15.3",
34
+ "vscode-languageclient": "^9.0.1",
35
+ "vscode-languageserver-protocol": "^3.17.5"
29
36
  },
30
37
  "devDependencies": {
31
38
  "@eslint/eslintrc": "^3",
@@ -0,0 +1,18 @@
1
+ (for settings.json)
2
+
3
+ Possible Themes:
4
+
5
+ light
6
+ dark
7
+ tokyo-night
8
+ tokyo-night-storm
9
+ tokyo-night-light
10
+ night-owl
11
+ night-owl-light
12
+ synthwave-84
13
+ one-dark-pro
14
+
15
+ Example settings.json:
16
+ {
17
+ "theme": "dark"
18
+ }
kernel_run.py CHANGED
@@ -8,9 +8,11 @@ import time
8
8
  import signal
9
9
  import threading
10
10
  import webbrowser
11
+ import platform
11
12
  from pathlib import Path
12
13
 
13
14
  from morecompute.notebook import Notebook
15
+ from morecompute.__version__ import __version__
14
16
 
15
17
  DEFAULT_NOTEBOOK_NAME = "notebook.ipynb"
16
18
 
@@ -21,6 +23,7 @@ class NotebookLauncher:
21
23
  self.root_dir = Path(__file__).parent
22
24
  self.debug = debug
23
25
  self.notebook_path = notebook_path
26
+ self.is_windows = platform.system() == "Windows"
24
27
  root_dir = notebook_path.parent if notebook_path.parent != Path('') else Path.cwd()
25
28
  os.environ["MORECOMPUTE_ROOT"] = str(root_dir.resolve())
26
29
  os.environ["MORECOMPUTE_NOTEBOOK_PATH"] = str(self.notebook_path)
@@ -77,48 +80,107 @@ class NotebookLauncher:
77
80
  sys.exit(1)
78
81
 
79
82
  def _ensure_port_available(self, port: int) -> None:
83
+ """Cross-platform port availability check and cleanup"""
80
84
  import socket
85
+
81
86
  with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
82
87
  s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
83
88
  try:
84
89
  s.bind(("127.0.0.1", port))
85
- return # free
90
+ return # Port is free
86
91
  except OSError:
87
- pass # in use
88
- # Port is in use - show processes and ask to kill
89
- print(f"\nPort {port} appears to be in use.")
92
+ pass # Port is in use
93
+
94
+ print(f"\nPort {port} is currently in use.")
90
95
  pids = []
96
+
91
97
  try:
92
- out = subprocess.check_output(["lsof", "-nP", f"-iTCP:{port}", "-sTCP:LISTEN"]).decode("utf-8", errors="ignore")
93
- print(out)
94
- for line in out.splitlines()[1:]:
95
- parts = line.split()
96
- if len(parts) > 1 and parts[1].isdigit():
97
- pids.append(int(parts[1]))
98
- except Exception:
99
- print("Could not list processes with lsof. You may need to free the port manually.")
100
- resp = input(f"Kill processes on port {port} and continue? [y/N]: ").strip().lower()
98
+ if self.is_windows:
99
+ # Windows: Use netstat
100
+ out = subprocess.check_output(
101
+ ["netstat", "-ano"],
102
+ text=True,
103
+ encoding='utf-8',
104
+ errors='replace'
105
+ )
106
+ for line in out.splitlines():
107
+ if f":{port}" in line and "LISTENING" in line:
108
+ parts = line.split()
109
+ if parts and parts[-1].isdigit():
110
+ pid = int(parts[-1])
111
+ if pid not in pids:
112
+ pids.append(pid)
113
+ # Get process name
114
+ try:
115
+ proc_out = subprocess.check_output(
116
+ ["tasklist", "/FI", f"PID eq {pid}", "/FO", "CSV", "/NH"],
117
+ text=True,
118
+ encoding='utf-8',
119
+ errors='replace'
120
+ )
121
+ proc_name = proc_out.split(',')[0].strip('"')
122
+ print(f" PID {pid}: {proc_name}")
123
+ except Exception:
124
+ print(f" PID {pid}")
125
+ else:
126
+ # Unix: Use lsof
127
+ out = subprocess.check_output(
128
+ ["lsof", "-nP", f"-iTCP:{port}", "-sTCP:LISTEN"],
129
+ text=True,
130
+ encoding='utf-8',
131
+ errors='replace'
132
+ )
133
+ print(out)
134
+ for line in out.splitlines()[1:]:
135
+ parts = line.split()
136
+ if len(parts) > 1 and parts[1].isdigit():
137
+ pids.append(int(parts[1]))
138
+ except Exception as e:
139
+ print(f"Could not list processes: {e}")
140
+
141
+ if not pids:
142
+ print(f"Could not find process using port {port}.")
143
+ print("Please free the port manually or set MORECOMPUTE_PORT to a different port.")
144
+ sys.exit(1)
145
+
146
+ resp = input(f"Kill process(es) on port {port} and continue? [y/N]: ").strip().lower()
101
147
  if resp != "y":
102
148
  print("Aborting. Set MORECOMPUTE_PORT to a different port to override.")
103
149
  sys.exit(1)
104
- # Attempt to kill
150
+
151
+ # Kill processes
105
152
  for pid in pids:
106
153
  try:
107
- os.kill(pid, 9)
154
+ if self.is_windows:
155
+ subprocess.run(
156
+ ["taskkill", "/F", "/PID", str(pid)],
157
+ stdout=subprocess.DEVNULL,
158
+ stderr=subprocess.DEVNULL,
159
+ encoding='utf-8',
160
+ errors='replace'
161
+ )
162
+ else:
163
+ os.kill(pid, signal.SIGKILL)
164
+ except Exception as e:
165
+ print(f"Failed to kill PID {pid}: {e}")
166
+
167
+ # Fallback: kill known patterns (Unix only)
168
+ if not self.is_windows:
169
+ try:
170
+ subprocess.run(["pkill", "-f", "uvicorn .*morecompute.server:app"],
171
+ stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
108
172
  except Exception:
109
173
  pass
110
- # Fallback: kill known patterns
111
- try:
112
- subprocess.run(["pkill", "-f", "uvicorn .*morecompute.server:app"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
113
- except Exception:
114
- pass
115
- try:
116
- subprocess.run(["pkill", "-f", "morecompute.execution.worker"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
117
- except Exception:
118
- pass
119
- # Brief pause to let the OS release the port
120
- time.sleep(0.5)
121
- # Poll until it binds
174
+ try:
175
+ subprocess.run(["pkill", "-f", "morecompute.execution.worker"],
176
+ stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
177
+ except Exception:
178
+ pass
179
+
180
+ # Windows needs more time to release ports
181
+ time.sleep(1.0 if self.is_windows else 0.5)
182
+
183
+ # Poll until port is available
122
184
  start = time.time()
123
185
  while time.time() - start < 5.0:
124
186
  with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s2:
@@ -128,6 +190,7 @@ class NotebookLauncher:
128
190
  return
129
191
  except OSError:
130
192
  time.sleep(0.25)
193
+
131
194
  print(f"Port {port} still busy. Please free it or set MORECOMPUTE_PORT to another port.")
132
195
  sys.exit(1)
133
196
 
@@ -136,25 +199,51 @@ class NotebookLauncher:
136
199
  try:
137
200
  frontend_dir = self.root_dir / "frontend"
138
201
 
202
+ # Use Windows-specific npm command
203
+ npm_cmd = "npm.cmd" if self.is_windows else "npm"
204
+
205
+ # Verify npm exists
206
+ try:
207
+ subprocess.run(
208
+ [npm_cmd, "--version"],
209
+ check=True,
210
+ stdout=subprocess.DEVNULL,
211
+ stderr=subprocess.DEVNULL,
212
+ shell=self.is_windows,
213
+ encoding='utf-8',
214
+ errors='replace'
215
+ )
216
+ except (subprocess.CalledProcessError, FileNotFoundError):
217
+ print("\nError: npm not found. Please install Node.js from https://nodejs.org/")
218
+ print("After installation, restart your terminal and try again.")
219
+ self.cleanup()
220
+ sys.exit(1)
221
+
139
222
  # Check if node_modules exists
140
223
  if not (frontend_dir / "node_modules").exists():
141
224
  print("Installing dependencies...")
142
225
  subprocess.run(
143
- ["npm", "install"],
226
+ [npm_cmd, "install"],
144
227
  cwd=frontend_dir,
145
228
  check=True,
146
229
  stdout=subprocess.DEVNULL,
147
- stderr=subprocess.DEVNULL
230
+ stderr=subprocess.DEVNULL,
231
+ shell=self.is_windows,
232
+ encoding='utf-8',
233
+ errors='replace'
148
234
  )
149
235
 
150
236
  fe_stdout = None if self.debug else subprocess.DEVNULL
151
237
  fe_stderr = None if self.debug else subprocess.DEVNULL
152
238
 
153
239
  self.frontend_process = subprocess.Popen(
154
- ["npm", "run", "dev"],
240
+ [npm_cmd, "run", "dev"],
155
241
  cwd=frontend_dir,
156
242
  stdout=fe_stdout,
157
- stderr=fe_stderr
243
+ stderr=fe_stderr,
244
+ shell=self.is_windows, # CRITICAL for Windows
245
+ encoding='utf-8',
246
+ errors='replace'
158
247
  )
159
248
 
160
249
  # Wait a bit then open browser
@@ -169,18 +258,40 @@ class NotebookLauncher:
169
258
  def cleanup(self):
170
259
  """Clean up processes on exit"""
171
260
  if self.frontend_process:
172
- self.frontend_process.terminate()
173
261
  try:
174
- self.frontend_process.wait(timeout=5)
175
- except subprocess.TimeoutExpired:
176
- self.frontend_process.kill()
262
+ if self.is_windows:
263
+ # Windows: Use taskkill for more reliable cleanup
264
+ subprocess.run(
265
+ ["taskkill", "/F", "/T", "/PID", str(self.frontend_process.pid)],
266
+ stdout=subprocess.DEVNULL,
267
+ stderr=subprocess.DEVNULL
268
+ )
269
+ else:
270
+ self.frontend_process.terminate()
271
+ try:
272
+ self.frontend_process.wait(timeout=5)
273
+ except subprocess.TimeoutExpired:
274
+ self.frontend_process.kill()
275
+ except Exception:
276
+ pass
177
277
 
178
278
  if self.backend_process:
179
- self.backend_process.terminate()
180
279
  try:
181
- self.backend_process.wait(timeout=5)
182
- except subprocess.TimeoutExpired:
183
- self.backend_process.kill()
280
+ if self.is_windows:
281
+ # Windows: Use taskkill for more reliable cleanup
282
+ subprocess.run(
283
+ ["taskkill", "/F", "/T", "/PID", str(self.backend_process.pid)],
284
+ stdout=subprocess.DEVNULL,
285
+ stderr=subprocess.DEVNULL
286
+ )
287
+ else:
288
+ self.backend_process.terminate()
289
+ try:
290
+ self.backend_process.wait(timeout=5)
291
+ except subprocess.TimeoutExpired:
292
+ self.backend_process.kill()
293
+ except Exception:
294
+ pass
184
295
 
185
296
  def run(self):
186
297
  """Main run method"""
@@ -189,12 +300,19 @@ class NotebookLauncher:
189
300
 
190
301
  # Set up signal handlers
191
302
  def signal_handler(signum, frame):
192
- print("\n\n Thanks for using MoreCompute!\n")
303
+ # Shutdown immediately on Ctrl+C
304
+ print("\nREMINDER: Any running GPU pods will continue to incur costs until you terminate them in the Compute popup.")
305
+ print("\n Thanks for using MoreCompute!\n")
193
306
  self.cleanup()
194
307
  sys.exit(0)
195
308
 
196
- signal.signal(signal.SIGINT, signal_handler)
197
- signal.signal(signal.SIGTERM, signal_handler)
309
+ # Windows signal handling is different
310
+ if not self.is_windows:
311
+ signal.signal(signal.SIGINT, signal_handler)
312
+ signal.signal(signal.SIGTERM, signal_handler)
313
+ else:
314
+ # Windows only supports SIGINT and SIGBREAK
315
+ signal.signal(signal.SIGINT, signal_handler)
198
316
 
199
317
  # Start services
200
318
  self.start_backend()
@@ -226,7 +344,7 @@ def build_parser() -> argparse.ArgumentParser:
226
344
  "--version",
227
345
  "-v",
228
346
  action="version",
229
- version="%(prog)s 0.1.2",
347
+ version=f"%(prog)s {__version__}",
230
348
  )
231
349
  parser.add_argument(
232
350
  "notebook_path",
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.4
2
+ Name: more-compute
3
+ Version: 0.2.0
4
+ Summary: An interactive notebook environment for local and GPU computing
5
+ Home-page: https://github.com/DannyMang/MORECOMPUTE
6
+ Author: MoreCompute Team
7
+ Author-email: MoreCompute Team <hello@morecompute.dev>
8
+ License: MIT
9
+ Project-URL: Homepage, https://github.com/DannyMang/MORECOMPUTE
10
+ Project-URL: Repository, https://github.com/DannyMang/MORECOMPUTE
11
+ Project-URL: Issues, https://github.com/DannyMang/MORECOMPUTE/issues
12
+ Keywords: jupyter,notebook,gpu,computing,interactive
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Requires-Python: >=3.8
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: fastapi>=0.104.0
27
+ Requires-Dist: uvicorn[standard]>=0.24.0
28
+ Requires-Dist: python-multipart>=0.0.5
29
+ Requires-Dist: nbformat>=5.0.0
30
+ Requires-Dist: click>=8.0.0
31
+ Requires-Dist: pyzmq>=25.0.0
32
+ Requires-Dist: psutil>=5.9.0
33
+ Requires-Dist: httpx>=0.24.0
34
+ Requires-Dist: cachetools>=5.3.0
35
+ Requires-Dist: matplotlib>=3.5.0
36
+ Dynamic: author
37
+ Dynamic: home-page
38
+ Dynamic: license-file
39
+ Dynamic: requires-python
40
+
41
+ # more-compute
42
+
43
+ [![PyPI version](https://badge.fury.io/py/more-compute.svg)](https://pypi.org/project/more-compute/)
44
+ [![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
45
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
46
+
47
+ Interactive notebook environment for local Python development. Works with standard `.ipynb` files,
48
+ similar to Jupyter Lab but more awesome.
49
+
50
+ ## Installation
51
+
52
+ **Prerequisites:** [Node.js](https://nodejs.org/) 16+ required for web interface.
53
+
54
+ ### Using uv (Recommended)
55
+
56
+ ```bash
57
+ # macOS/Linux
58
+ curl -LsSf https://astral.sh/uv/install.sh | sh
59
+ uv tool install more-compute
60
+
61
+ # Windows
62
+ powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
63
+ uv tool install more-compute
64
+ ```
65
+
66
+ ### Using pip
67
+
68
+ ```bash
69
+ pip install more-compute
70
+
71
+ # Add to PATH if needed:
72
+ # macOS/Linux: echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
73
+ # Windows: See troubleshooting below
74
+ ```
75
+
76
+ ## Usage
77
+
78
+ ```bash
79
+ more-compute notebook.ipynb # Open existing notebook
80
+ more-compute # Create and open new notebook
81
+ more-compute --debug # Show logs
82
+ ```
83
+
84
+ Opens automatically at http://localhost:8000
85
+
86
+ ## Troubleshooting
87
+
88
+ **Command not found:**
89
+ ```bash
90
+ uv tool update-shell # Fixes PATH automatically
91
+ ```
92
+
93
+ **Manual PATH fix (macOS/Linux):**
94
+ ```bash
95
+ echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
96
+ source ~/.bashrc
97
+ ```
98
+
99
+ **Manual PATH fix (Windows):**
100
+ ```powershell
101
+ $pythonScripts = python -c "import site; print(site.USER_BASE)"
102
+ $userPath = [Environment]::GetEnvironmentVariable("Path", "User")
103
+ [Environment]::SetEnvironmentVariable("Path", "$userPath;$pythonScripts\Scripts", "User")
104
+ # Restart PowerShell
105
+ ```
106
+
107
+ **Port in use:**
108
+ ```bash
109
+ export MORECOMPUTE_PORT=8080 # macOS/Linux
110
+ $env:MORECOMPUTE_PORT = "8080" # Windows
111
+ ```
112
+
113
+ ## Development
114
+
115
+ ```bash
116
+ git clone https://github.com/DannyMang/MORECOMPUTE.git
117
+ cd MORECOMPUTE
118
+ uv venv && source .venv/bin/activate
119
+ uv pip install -e .
120
+ cd frontend && npm install && cd ..
121
+ python kernel_run.py notebook.ipynb
122
+ ```
123
+
124
+ ## License
125
+
126
+ MIT - see [LICENSE](LICENSE)
@@ -0,0 +1,100 @@
1
+ kernel_run.py,sha256=otblv5fH9VyucgBsh_LwcgAWLNun0E9ioGIZvzWuP84,14656
2
+ frontend/.DS_Store,sha256=uQeHnkKyuTF1AVax3NPqtN0uCH6XNXAxL9Nkb6Q9cGw,8196
3
+ frontend/.gitignore,sha256=IH4mX_SQH5rZ-W2M4IUw4E-fxgCBVHKmbQpEYJbWVM0,480
4
+ frontend/README.md,sha256=YLVf9995r3JZD5UkII5GZCvDK9wXXNrUE0loHA4vlY8,1450
5
+ frontend/__init__.py,sha256=L5SAOdfDfKqlgEVCvYQQRDZBTlCxutZKSpJp4018IG4,100
6
+ frontend/eslint.config.mjs,sha256=LBCCw4SomtiVMmlTSpYRXfkRs6Xs04R1YFfoyorYyT8,879
7
+ frontend/next-env.d.ts,sha256=ha5a7nXwEZZ88tJcvDQvYtaTFOnZJff0qjRW_Cz_zKY,262
8
+ frontend/next.config.mjs,sha256=n0o6cIIVIoOtI6JlvAK-HUFd2lg1pQPfUwlFS4O6TK0,346
9
+ frontend/next.config.ts,sha256=OL_rEfTIZxsB_B5R9JX2AxYXgC0Fc_XiDoRlOGEDEpk,368
10
+ frontend/package-lock.json,sha256=uv1cRVRHKZCzk5ceHJN8bOhJzv4a3XjeIbyTF2oYCho,306688
11
+ frontend/package.json,sha256=P7Hrwl1vUCUjhi44Eg3oqc4-4l-V0Ea6__S2Mx_Qp7A,1367
12
+ frontend/postcss.config.mjs,sha256=FB7yTKJ6mdCJYiEP3yAhLTQ1_c-iG0bNiLRNIvdR364,81
13
+ frontend/styling_README.md,sha256=RAQ4q-axGqugym8L22KpxB2ReBbEtg67YCEHLvTVvAw,196
14
+ frontend/tailwind.config.ts,sha256=eP9nVaAuyYo46vGQfCyWbo25_pr2hW830fs1Itcix9Q,620
15
+ frontend/tsconfig.json,sha256=7SvBlRBYmuXAlAteRQTGwEE7ooWuNaPUrZ219dOo61E,598
16
+ frontend/app/favicon.ico,sha256=K4rS0zRVqPc2_DqOv48L3qiEitTA20iigzvQ-c13WTI,25931
17
+ frontend/app/globals.css,sha256=imFZBoEmnHEOpo7Jegj8F71iPwSwNQivtH0ylpCKyWE,35682
18
+ frontend/app/layout.tsx,sha256=R1vUDTImQzUJIW51rdvBUIsvejSbjfLrwgbLSjrmcMM,6035
19
+ frontend/app/page.tsx,sha256=p-DgDv8xDnwcRfDJY4rtfSQ2VdYwbnP3G-otWqDR1l0,256
20
+ frontend/components/Cell.tsx,sha256=JeXn5Z_jzezYOtrgl291b6HBKJdfhQ88dTTDZjFoWmk,12237
21
+ frontend/components/Notebook.tsx,sha256=tJt45gyNch3ifWjnKUDoyvik7snrgRqt55gQgiYEnlc,21528
22
+ frontend/components/cell/AddCellButton.tsx,sha256=ZC2Vck0JIRDxGYhYv3LPYAdKDo13U6008WG_-XoPlIM,1012
23
+ frontend/components/cell/CellButton.tsx,sha256=BjfazBKzlybA5Syx6tXGTJa1U_jwL8C_IeQKbcHlkyk,1364
24
+ frontend/components/cell/MonacoCell.tsx,sha256=11jSlfGcUpxvbRDJr1GGocNtzZIarioDdgg7WLuZs9U,24334
25
+ frontend/components/layout/ConnectionBanner.tsx,sha256=-m77wKCFpeRJ_AQwnM38jLwCY5vfpqE846xeXmT3p8A,870
26
+ frontend/components/layout/Sidebar.tsx,sha256=kxgO2mXX11xI6rX478cUqqQ3xB40jlby21y27GTJSLU,1551
27
+ frontend/components/modals/ConfirmModal.tsx,sha256=3WgXy_wmR8FHZPwzMevfZHFXa0blR4v_SbKG3d5McT4,3652
28
+ frontend/components/modals/ErrorModal.tsx,sha256=kkGHQvgyMYlScKwni04-V_Dq6a0-lg0WodglLARR-uA,3536
29
+ frontend/components/modals/SuccessModal.tsx,sha256=7NVg0MFPVvsBGDOHPVyZTNx4kmZLHgxdhZKKtTD9FTU,3385
30
+ frontend/components/output/CellOutput.tsx,sha256=D1ZIvOmQvFn_4Y1ahGM5rp0Yr5_Zp_loNJaEUA-GCrA,2073
31
+ frontend/components/output/ErrorDisplay.tsx,sha256=d6I2WVyDLPsonyDuqsrrN8sc_KHg0VTAW86DfcqfqL0,5978
32
+ frontend/components/output/MarkdownRenderer.tsx,sha256=RtZ5yNRxDXIh_NkNsNiy30wMGIW7V1gfhsjecgMdc80,3341
33
+ frontend/components/popups/ComputePopup.tsx,sha256=B7AwwjpJ9_nNI5qSN53jdR2tAulB5yl7spjMXjH4yDM,44021
34
+ frontend/components/popups/FilterPopup.tsx,sha256=4kx9txg8cWeC6XHlh0pu0-BAfZkLTDYEU93fMdzn86M,13818
35
+ frontend/components/popups/FolderPopup.tsx,sha256=V2tDAbztvNIUyPWtFiwjeIoCmFGQyDosQgST_JsAzLo,5215
36
+ frontend/components/popups/MetricsPopup.tsx,sha256=V4Srat-RRr7B046Ezg5w99_E_t9j0P3Ch5DO9rF7Nx0,5028
37
+ frontend/components/popups/PackagesPopup.tsx,sha256=K_9kGlQ-y-njugOLrahbv0KHRh_mXIlzuMg0giRsTb8,3606
38
+ frontend/components/popups/SettingsPopup.tsx,sha256=etwDuB4HHfadzN7CZf9omZ0uNl_4vhwJ92C5p3rleuY,2395
39
+ frontend/contexts/PodWebSocketContext.tsx,sha256=QyEg1Msyum7h3T6F3j6pn4Ds5sXFT_9WYu5_0YZ2IUI,8256
40
+ frontend/lib/api.ts,sha256=0N4PCSC5pfbq7GvR_6aOdPZ3JGujzi1Rz4V51g8sHP8,10852
41
+ frontend/lib/monaco-themes.ts,sha256=jh_pZAmSMKjY_belbMbZX2WpFBN7baRxvJp9shUDYgk,5396
42
+ frontend/lib/settings.ts,sha256=ZAdwLErjPITkIc87D3DTcHYhhUP3fBI-LpDYsH9eVE4,5842
43
+ frontend/lib/themes.json,sha256=mk6IGy6o_DCOerBH3QmfXozTHEiy-alsTLTTIaba7No,292018
44
+ frontend/lib/websocket-native.ts,sha256=6QUSLSONnCImPp9hpFo_XdXME5X7DOptW1mrtG7E99A,5962
45
+ frontend/lib/websocket.ts,sha256=V2Y7sktt2dm1G-ZILggcqIWccsh-xoAG9dLHpNVqIqs,4500
46
+ frontend/public/file.svg,sha256=K2eBLDJcGZoCU2zb7qDFk6cvcH0yO3LuPgjbqwZ1O9Q,391
47
+ frontend/public/globe.svg,sha256=thS5vxg5JZV2YayFFJj-HYAp_UOmL7_thvniYkpX588,1035
48
+ frontend/public/next.svg,sha256=VZld-tbstJRaHoVt3KA8XhaqW_E_0htN9qdK55NXvPw,1375
49
+ frontend/public/vercel.svg,sha256=8IEzey_uY1tFW2MnVAaj5_OdagFOJa2Q2rWmfmKhKsQ,128
50
+ frontend/public/window.svg,sha256=ZEdoxKrrR2e84pM0TusMEl-4BKlNgBRAQkByIC2F46E,385
51
+ frontend/public/assets/icons/add.svg,sha256=_R2g6_rQSd9uQ52d_yxLY8kFGvAgJBAOvWUN00aoSkY,511
52
+ frontend/public/assets/icons/check.svg,sha256=MdLhklRIgz5dZqWuUQe0CdBzfA5W63X6RbvOT3C9YTE,261
53
+ frontend/public/assets/icons/copy.svg,sha256=Bd_NXZR-inj4X0WGhkpojErq6F6UXwpdp3DL6rm57r0,355
54
+ frontend/public/assets/icons/folder.svg,sha256=uzpAVxIsuGivdrte56WJOfqCWc1TNN9ldPhrHKEA674,400
55
+ frontend/public/assets/icons/metric.svg,sha256=biafr0qAHRV_8CnMEWrh3Wk3ZMAgbfaL0I1N7Uqfp_U,440
56
+ frontend/public/assets/icons/packages.svg,sha256=70XqerYscy3b-YkLpuNSBalECfmlfRVjgN5Pq4Uvd-I,460
57
+ frontend/public/assets/icons/play.svg,sha256=ca5409xQtDl8rOHp0Dv6t6WWra7QvTupbcGj-OubjL8,326
58
+ frontend/public/assets/icons/python.svg,sha256=uuyGYqFGHCyswya1TScnyy8c4HugLQD1uCbQNRBPZJ8,9605
59
+ frontend/public/assets/icons/setting.svg,sha256=oUwRxiQjyK33aAv4AK1r8FYwIM8RnuwKTTaMU9v_l-U,610
60
+ frontend/public/assets/icons/stop.svg,sha256=98xoeoVwCEFq142v5IYE1GxcD4o3_UGa0pCOu3wzbqw,285
61
+ frontend/public/assets/icons/trash.svg,sha256=ikf6zdvwlLWmmGISVPzrtDlQNMPJ3VskgoCfQCEbCck,398
62
+ frontend/public/assets/icons/up-down.svg,sha256=ocaOoU8RZDKuyrlcPJjESz24GGvas16rytFbC7DXzGg,339
63
+ frontend/public/assets/icons/x.svg,sha256=TPiVYZTK-vRlaG-nLrARcnPIWCJ1xA9sqhr-9Y4Kquk,270
64
+ frontend/public/fonts/Fira.ttf,sha256=dbSM4W7Drd9n_EkfXq8P31KuxbjZ1wtuFiZ8aFebvTw,242896
65
+ frontend/public/fonts/Tiempos.woff2,sha256=h83bJKvAK301wXCMIvK7ZG5j0H2K3tzAfgo0yk4z8OE,13604
66
+ frontend/public/fonts/VeraMono.ttf,sha256=2kKB3H2xej385kpiztkodcWJU0AFXsi6JKORTrl7NJ0,49224
67
+ frontend/types/notebook.ts,sha256=v23RaZe6H3lU5tq6sqnJDPxC2mu0NZFDCJfiN0mgvSs,1359
68
+ more_compute-0.2.0.dist-info/licenses/LICENSE,sha256=0Ot-XIetYt06iay6IhtpJkruD-cLZtjyv7_aIEE-oSc,1073
69
+ morecompute/__init__.py,sha256=pcMVq8Q7qb42AOn7tqgoZJOi3epDDBnEriiv2WVKnXY,87
70
+ morecompute/__version__.py,sha256=Zn1KFblwuFHiDRdRAiRnDBRkbPttWh44jKa5zG2ov0E,22
71
+ morecompute/cli.py,sha256=kVvzvPBqF8xO6UuhU_-TBn99nKwJ405R2mAS6zU0KBc,734
72
+ morecompute/notebook.py,sha256=KEcv0eOEh9N7bPVGoRuKJb47G9MmpQ5zz1B6Dm58w18,4651
73
+ morecompute/process_worker.py,sha256=KsE3r-XpkYGuyO4w3t54VKkD51LfNHAZc3TYattMtrg,7185
74
+ morecompute/server.py,sha256=W_EfX4NiSYZgK3ZZFP-LPO78_Sjzuyo3eiKprnAxsfI,40144
75
+ morecompute/execution/__init__.py,sha256=jPmBmq8BZWbUEY9XFSpqt5FkgX04uNS10WnUlr7Rnms,134
76
+ morecompute/execution/__main__.py,sha256=pAWB_1bn99u8Gb-tVMSMI-NYvbYbDiwbn40L0a0djeA,202
77
+ morecompute/execution/executor.py,sha256=v8OKWuHykuLvhnvsRydFECcgqRqfCFM__FAHb22ARcg,20128
78
+ morecompute/execution/worker.py,sha256=9z1-3ruT5DbsqRJWw54J8VFVOnm_X1Vwcp6GCV5JP4o,12465
79
+ morecompute/models/__init__.py,sha256=VLJ5GWi2uTNiZBdvl-ipSbmA6EL8FZHZ5oq-rJmm9z0,640
80
+ morecompute/models/api_models.py,sha256=-ydvi9SeTfdoY9oVPNQS4by-kQGSknx6BHhGD8E2tpo,4553
81
+ morecompute/services/data_manager.py,sha256=c4GKucetMM-VPNbHyzce6bZRvFfmz8kTd5RppLjoLVc,14329
82
+ morecompute/services/lsp_service.py,sha256=Le8ARImcg2P6oueF_14L8rStHOOseHruRTd_wfDVw7s,12237
83
+ morecompute/services/pod_manager.py,sha256=rg6mQJOieElDaO-KGBmg7wO6APkBThLpWmDi472Mvbw,21068
84
+ morecompute/services/pod_monitor.py,sha256=Y5aiNoVsvkGiHddNbfR1laAKn8G0eY0_nJyTM4VVkyg,4711
85
+ morecompute/services/prime_intellect.py,sha256=b705rHv3RPRsgWedRlHwoP_S-TxxZtMSyZhnaiZpMgk,10273
86
+ morecompute/static/styles.css,sha256=el_NtrUMbAUNSiMVBn1xlG70m3iPv7dyaIbWQMexhsY,19277
87
+ morecompute/utils/__init__.py,sha256=VIxCL3S1pnjEs4cjKGZqZB68_P8FegdeMIqBjJhI5jQ,419
88
+ morecompute/utils/cache_util.py,sha256=lVlXudHvtyvSo_kCSxORJrI85Jod8FrQLbI2f_JOIbA,661
89
+ morecompute/utils/config_util.py,sha256=fGTQll7Zh05ZHrW8LuQNTJGziGnIfvKIU3azbrY-I-s,1793
90
+ morecompute/utils/error_utils.py,sha256=e50WLFdD6ngIC30xAgrzdTYtD8tPOIFkKAAh_sPbK0I,11667
91
+ morecompute/utils/notebook_util.py,sha256=3hH94dtXvhizRVTU9a2b38m_51Y4igoXpkjAXUqpVBQ,1353
92
+ morecompute/utils/python_environment_util.py,sha256=l8WWWPwKbypknw8GwL22NXCji5i1FOy1vWG47J6og4g,7441
93
+ morecompute/utils/special_commands.py,sha256=JTc9II2EitmivwTTdnydEefShasiTa-7w8tNyYVIenw,19104
94
+ morecompute/utils/system_environment_util.py,sha256=32mQRubo0i4X61o-825T7m-eUSidcEp07qkInP1sWZA,4774
95
+ morecompute/utils/zmq_util.py,sha256=tx7-iS04UN69OFtBzkxcEnRhT7xtI9EzRnrZ_nsH_O0,1889
96
+ more_compute-0.2.0.dist-info/METADATA,sha256=ieZK-lZJs3LfJfflN59QmczXIRNEMp5GrgdkGKE0U70,3593
97
+ more_compute-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
98
+ more_compute-0.2.0.dist-info/entry_points.txt,sha256=xp7z9eRPNRM4oxkZZVlyXkhkSjN1AjoYI_B7qpDJ1bI,49
99
+ more_compute-0.2.0.dist-info/top_level.txt,sha256=Tamm6ADzjwaQa1z27O7Izcyhyt9f0gVjMv1_tC810aI,32
100
+ more_compute-0.2.0.dist-info/RECORD,,
@@ -0,0 +1 @@
1
+ __version__ = "0.2.0"
@@ -26,6 +26,7 @@ class NextZmqExecutor:
26
26
  ctx: object # zmq.Context - untyped due to zmq type limitations
27
27
  req: object # zmq.Socket - untyped due to zmq type limitations
28
28
  sub: object # zmq.Socket - untyped due to zmq type limitations
29
+ is_remote: bool # Flag to track if connected to remote worker
29
30
 
30
31
  def __init__(self, error_utils: "ErrorUtils", cmd_addr: str | None = None, pub_addr: str | None = None, interrupt_timeout: float = 0.5) -> None:
31
32
  self.error_utils = error_utils
@@ -37,6 +38,7 @@ class NextZmqExecutor:
37
38
  self.worker_proc = None
38
39
  self.interrupted_cell = None
39
40
  self.special_handler = None
41
+ self.is_remote = False # Start with local worker
40
42
  self._ensure_special_handler()
41
43
  self.ctx = zmq.Context.instance() # type: ignore[reportUnknownMemberType]
42
44
  self.req = self.ctx.socket(zmq.REQ) # type: ignore[reportUnknownMemberType, reportAttributeAccessIssue]
@@ -51,6 +53,11 @@ class NextZmqExecutor:
51
53
  self.special_handler = AsyncSpecialCommandHandler({"__name__": "__main__"})
52
54
 
53
55
  def _ensure_worker(self) -> None:
56
+ """Ensure a worker is available. If connected to remote pod, skip local worker spawn."""
57
+ # If we're connected to a remote worker, don't try to spawn local worker
58
+ if self.is_remote:
59
+ return
60
+
54
61
  # Use a temporary REQ socket for probing to avoid locking self.req's state
55
62
  tmp = self.ctx.socket(zmq.REQ) # type: ignore[reportUnknownMemberType, reportAttributeAccessIssue]
56
63
  tmp.setsockopt(zmq.LINGER, 0) # type: ignore[reportAttributeAccessIssue]
@@ -107,32 +114,36 @@ class NextZmqExecutor:
107
114
  raise RuntimeError('Failed to start/connect ZMQ worker')
108
115
 
109
116
  async def execute_cell(self, cell_index: int, source_code: str, websocket: WebSocket | None = None) -> dict[str, object]:
110
- import sys
111
117
  self._ensure_special_handler()
112
118
  handler = self.special_handler
113
119
  normalized_source = source_code
114
120
  if handler is not None:
115
121
  normalized_source = handler._coerce_source_to_text(source_code) # type: ignore[reportPrivateUsage]
116
122
  if handler.is_special_command(normalized_source):
117
- execution_count = getattr(self, 'execution_count', 0) + 1
118
- self.execution_count = execution_count
119
- start_time = time.time()
120
- result: dict[str, object] = {
121
- 'outputs': [],
122
- 'error': None,
123
- 'status': 'ok',
124
- 'execution_count': execution_count,
125
- 'execution_time': None,
126
- }
127
- if websocket:
128
- await websocket.send_json({'type': 'execution_start', 'data': {'cell_index': cell_index, 'execution_count': execution_count}})
129
- result = await handler.execute_special_command(
130
- normalized_source, result, start_time, execution_count, websocket, cell_index
131
- )
132
- result['execution_time'] = f"{(time.time()-start_time)*1000:.1f}ms"
133
- if websocket:
134
- await websocket.send_json({'type': 'execution_complete', 'data': {'cell_index': cell_index, 'result': result}})
135
- return result
123
+ # If connected to remote pod, send special commands to remote worker
124
+ # Otherwise they execute locally which gives wrong results
125
+ if not self.is_remote:
126
+ # Execute special command locally
127
+ execution_count = getattr(self, 'execution_count', 0) + 1
128
+ self.execution_count = execution_count
129
+ start_time = time.time()
130
+ result: dict[str, object] = {
131
+ 'outputs': [],
132
+ 'error': None,
133
+ 'status': 'ok',
134
+ 'execution_count': execution_count,
135
+ 'execution_time': None,
136
+ }
137
+ if websocket:
138
+ await websocket.send_json({'type': 'execution_start', 'data': {'cell_index': cell_index, 'execution_count': execution_count}})
139
+ result = await handler.execute_special_command(
140
+ normalized_source, result, start_time, execution_count, websocket, cell_index
141
+ )
142
+ result['execution_time'] = f"{(time.time()-start_time)*1000:.1f}ms"
143
+ if websocket:
144
+ await websocket.send_json({'type': 'execution_complete', 'data': {'cell_index': cell_index, 'result': result}})
145
+ return result
146
+ # For remote execution, fall through to send via ZMQ
136
147
 
137
148
  execution_count = getattr(self, 'execution_count', 0) + 1
138
149
  self.execution_count = execution_count