more-compute 0.1.4__py3-none-any.whl → 0.2.1__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 +159 -42
  27. more_compute-0.2.1.dist-info/METADATA +126 -0
  28. more_compute-0.2.1.dist-info/RECORD +100 -0
  29. morecompute/__version__.py +1 -1
  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.4.dist-info/METADATA +0 -173
  47. more_compute-0.1.4.dist-info/RECORD +0 -86
  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.4.dist-info → more_compute-0.2.1.dist-info}/WHEEL +0 -0
  53. {more_compute-0.1.4.dist-info → more_compute-0.2.1.dist-info}/entry_points.txt +0 -0
  54. {more_compute-0.1.4.dist-info → more_compute-0.2.1.dist-info}/licenses/LICENSE +0 -0
  55. {more_compute-0.1.4.dist-info → more_compute-0.2.1.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,6 +8,7 @@ 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
@@ -22,6 +23,7 @@ class NotebookLauncher:
22
23
  self.root_dir = Path(__file__).parent
23
24
  self.debug = debug
24
25
  self.notebook_path = notebook_path
26
+ self.is_windows = platform.system() == "Windows"
25
27
  root_dir = notebook_path.parent if notebook_path.parent != Path('') else Path.cwd()
26
28
  os.environ["MORECOMPUTE_ROOT"] = str(root_dir.resolve())
27
29
  os.environ["MORECOMPUTE_NOTEBOOK_PATH"] = str(self.notebook_path)
@@ -78,48 +80,107 @@ class NotebookLauncher:
78
80
  sys.exit(1)
79
81
 
80
82
  def _ensure_port_available(self, port: int) -> None:
83
+ """Cross-platform port availability check and cleanup"""
81
84
  import socket
85
+
82
86
  with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
83
87
  s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
84
88
  try:
85
89
  s.bind(("127.0.0.1", port))
86
- return # free
90
+ return # Port is free
87
91
  except OSError:
88
- pass # in use
89
- # Port is in use - show processes and ask to kill
90
- 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.")
91
95
  pids = []
96
+
92
97
  try:
93
- out = subprocess.check_output(["lsof", "-nP", f"-iTCP:{port}", "-sTCP:LISTEN"]).decode("utf-8", errors="ignore")
94
- print(out)
95
- for line in out.splitlines()[1:]:
96
- parts = line.split()
97
- if len(parts) > 1 and parts[1].isdigit():
98
- pids.append(int(parts[1]))
99
- except Exception:
100
- print("Could not list processes with lsof. You may need to free the port manually.")
101
- 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()
102
147
  if resp != "y":
103
148
  print("Aborting. Set MORECOMPUTE_PORT to a different port to override.")
104
149
  sys.exit(1)
105
- # Attempt to kill
150
+
151
+ # Kill processes
106
152
  for pid in pids:
107
153
  try:
108
- 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)
109
172
  except Exception:
110
173
  pass
111
- # Fallback: kill known patterns
112
- try:
113
- subprocess.run(["pkill", "-f", "uvicorn .*morecompute.server:app"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
114
- except Exception:
115
- pass
116
- try:
117
- subprocess.run(["pkill", "-f", "morecompute.execution.worker"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
118
- except Exception:
119
- pass
120
- # Brief pause to let the OS release the port
121
- time.sleep(0.5)
122
- # 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
123
184
  start = time.time()
124
185
  while time.time() - start < 5.0:
125
186
  with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s2:
@@ -129,6 +190,7 @@ class NotebookLauncher:
129
190
  return
130
191
  except OSError:
131
192
  time.sleep(0.25)
193
+
132
194
  print(f"Port {port} still busy. Please free it or set MORECOMPUTE_PORT to another port.")
133
195
  sys.exit(1)
134
196
 
@@ -137,25 +199,51 @@ class NotebookLauncher:
137
199
  try:
138
200
  frontend_dir = self.root_dir / "frontend"
139
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
+
140
222
  # Check if node_modules exists
141
223
  if not (frontend_dir / "node_modules").exists():
142
224
  print("Installing dependencies...")
143
225
  subprocess.run(
144
- ["npm", "install"],
226
+ [npm_cmd, "install"],
145
227
  cwd=frontend_dir,
146
228
  check=True,
147
229
  stdout=subprocess.DEVNULL,
148
- stderr=subprocess.DEVNULL
230
+ stderr=subprocess.DEVNULL,
231
+ shell=self.is_windows,
232
+ encoding='utf-8',
233
+ errors='replace'
149
234
  )
150
235
 
151
236
  fe_stdout = None if self.debug else subprocess.DEVNULL
152
237
  fe_stderr = None if self.debug else subprocess.DEVNULL
153
238
 
154
239
  self.frontend_process = subprocess.Popen(
155
- ["npm", "run", "dev"],
240
+ [npm_cmd, "run", "dev"],
156
241
  cwd=frontend_dir,
157
242
  stdout=fe_stdout,
158
- stderr=fe_stderr
243
+ stderr=fe_stderr,
244
+ shell=self.is_windows, # CRITICAL for Windows
245
+ encoding='utf-8',
246
+ errors='replace'
159
247
  )
160
248
 
161
249
  # Wait a bit then open browser
@@ -170,18 +258,40 @@ class NotebookLauncher:
170
258
  def cleanup(self):
171
259
  """Clean up processes on exit"""
172
260
  if self.frontend_process:
173
- self.frontend_process.terminate()
174
261
  try:
175
- self.frontend_process.wait(timeout=5)
176
- except subprocess.TimeoutExpired:
177
- 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
178
277
 
179
278
  if self.backend_process:
180
- self.backend_process.terminate()
181
279
  try:
182
- self.backend_process.wait(timeout=5)
183
- except subprocess.TimeoutExpired:
184
- 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
185
295
 
186
296
  def run(self):
187
297
  """Main run method"""
@@ -190,12 +300,19 @@ class NotebookLauncher:
190
300
 
191
301
  # Set up signal handlers
192
302
  def signal_handler(signum, frame):
193
- 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")
194
306
  self.cleanup()
195
307
  sys.exit(0)
196
308
 
197
- signal.signal(signal.SIGINT, signal_handler)
198
- 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)
199
316
 
200
317
  # Start services
201
318
  self.start_backend()
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.4
2
+ Name: more-compute
3
+ Version: 0.2.1
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.1.dist-info/licenses/LICENSE,sha256=0Ot-XIetYt06iay6IhtpJkruD-cLZtjyv7_aIEE-oSc,1073
69
+ morecompute/__init__.py,sha256=pcMVq8Q7qb42AOn7tqgoZJOi3epDDBnEriiv2WVKnXY,87
70
+ morecompute/__version__.py,sha256=HfjVOrpTnmZ-xVFCYSVmX50EXaBQeJteUHG-PD6iQs8,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.1.dist-info/METADATA,sha256=zbjJ25jtbsr9fTTe33coPyMpTKTlLPa9gqpfIQJ6nXw,3593
97
+ more_compute-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
98
+ more_compute-0.2.1.dist-info/entry_points.txt,sha256=xp7z9eRPNRM4oxkZZVlyXkhkSjN1AjoYI_B7qpDJ1bI,49
99
+ more_compute-0.2.1.dist-info/top_level.txt,sha256=Tamm6ADzjwaQa1z27O7Izcyhyt9f0gVjMv1_tC810aI,32
100
+ more_compute-0.2.1.dist-info/RECORD,,
@@ -1 +1 @@
1
- __version__ = "0.1.4"
1
+ __version__ = "0.2.1"
@@ -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