more-compute 0.2.6__py3-none-any.whl → 0.3.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.
@@ -84,8 +84,8 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
84
84
  top: "50%",
85
85
  left: "50%",
86
86
  transform: "translate(-50%, -50%)",
87
- backgroundColor: "white",
88
- border: "1px solid #d1d5db",
87
+ backgroundColor: "var(--mc-cell-background)",
88
+ border: "1px solid var(--mc-border)",
89
89
  borderRadius: "8px",
90
90
  padding: "16px",
91
91
  width: "320px",
@@ -110,7 +110,7 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
110
110
  fontSize: "14px",
111
111
  fontWeight: 600,
112
112
  margin: 0,
113
- color: "#111827",
113
+ color: "var(--mc-text-color)",
114
114
  }}
115
115
  >
116
116
  Filter
@@ -119,7 +119,7 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
119
119
  onClick={handleClearAll}
120
120
  style={{
121
121
  fontSize: "11px",
122
- color: "#3b82f6",
122
+ color: "var(--mc-primary)",
123
123
  background: "none",
124
124
  border: "none",
125
125
  cursor: "pointer",
@@ -142,9 +142,9 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
142
142
  width: "100%",
143
143
  padding: "8px 10px",
144
144
  borderRadius: "6px",
145
- border: "1px solid #d1d5db",
146
- backgroundColor: "white",
147
- color: "#111827",
145
+ border: "1px solid var(--mc-border)",
146
+ backgroundColor: "var(--mc-input-background)",
147
+ color: "var(--mc-text-color)",
148
148
  fontSize: "12px",
149
149
  marginBottom: "12px",
150
150
  cursor: "pointer",
@@ -166,9 +166,9 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
166
166
  width: "100%",
167
167
  padding: "8px 10px",
168
168
  borderRadius: "6px",
169
- border: "1px solid #d1d5db",
170
- backgroundColor: "white",
171
- color: "#111827",
169
+ border: "1px solid var(--mc-border)",
170
+ backgroundColor: "var(--mc-input-background)",
171
+ color: "var(--mc-text-color)",
172
172
  fontSize: "12px",
173
173
  marginBottom: "12px",
174
174
  boxSizing: "border-box",
@@ -182,7 +182,7 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
182
182
  overflowY: "auto",
183
183
  marginBottom: "16px",
184
184
  maxHeight: "240px",
185
- border: "1px solid #e5e7eb",
185
+ border: "1px solid var(--mc-border)",
186
186
  borderRadius: "6px",
187
187
  padding: "4px",
188
188
  }}
@@ -200,12 +200,12 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
200
200
  padding: "8px 6px",
201
201
  cursor: "pointer",
202
202
  fontSize: "12px",
203
- color: "#374151",
203
+ color: "var(--mc-text-color)",
204
204
  borderRadius: "4px",
205
205
  transition: "background-color 0.15s",
206
206
  }}
207
207
  onMouseEnter={(e) =>
208
- (e.currentTarget.style.backgroundColor = "#f3f4f6")
208
+ (e.currentTarget.style.backgroundColor = "var(--mc-secondary)")
209
209
  }
210
210
  onMouseLeave={(e) =>
211
211
  (e.currentTarget.style.backgroundColor = "transparent")
@@ -249,12 +249,12 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
249
249
  padding: "8px 6px",
250
250
  cursor: "pointer",
251
251
  fontSize: "12px",
252
- color: "#374151",
252
+ color: "var(--mc-text-color)",
253
253
  borderRadius: "4px",
254
254
  transition: "background-color 0.15s",
255
255
  }}
256
256
  onMouseEnter={(e) =>
257
- (e.currentTarget.style.backgroundColor = "#f3f4f6")
257
+ (e.currentTarget.style.backgroundColor = "var(--mc-secondary)")
258
258
  }
259
259
  onMouseLeave={(e) =>
260
260
  (e.currentTarget.style.backgroundColor = "transparent")
@@ -303,12 +303,12 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
303
303
  padding: "8px 6px",
304
304
  cursor: "pointer",
305
305
  fontSize: "12px",
306
- color: "#374151",
306
+ color: "var(--mc-text-color)",
307
307
  borderRadius: "4px",
308
308
  transition: "background-color 0.15s",
309
309
  }}
310
310
  onMouseEnter={(e) =>
311
- (e.currentTarget.style.backgroundColor = "#f3f4f6")
311
+ (e.currentTarget.style.backgroundColor = "var(--mc-secondary)")
312
312
  }
313
313
  onMouseLeave={(e) =>
314
314
  (e.currentTarget.style.backgroundColor = "transparent")
@@ -352,12 +352,12 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
352
352
  padding: "8px 6px",
353
353
  cursor: "pointer",
354
354
  fontSize: "12px",
355
- color: "#374151",
355
+ color: "var(--mc-text-color)",
356
356
  borderRadius: "4px",
357
357
  transition: "background-color 0.15s",
358
358
  }}
359
359
  onMouseEnter={(e) =>
360
- (e.currentTarget.style.backgroundColor = "#f3f4f6")
360
+ (e.currentTarget.style.backgroundColor = "var(--mc-secondary)")
361
361
  }
362
362
  onMouseLeave={(e) =>
363
363
  (e.currentTarget.style.backgroundColor = "transparent")
@@ -390,9 +390,9 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
390
390
  padding: "8px 16px",
391
391
  fontSize: "12px",
392
392
  borderRadius: "6px",
393
- border: "1px solid #d1d5db",
394
- backgroundColor: "white",
395
- color: "#374151",
393
+ border: "1px solid var(--mc-border)",
394
+ backgroundColor: "var(--mc-secondary)",
395
+ color: "var(--mc-text-color)",
396
396
  cursor: "pointer",
397
397
  fontWeight: 500,
398
398
  }}
@@ -410,8 +410,8 @@ const FilterPopup: React.FC<FilterPopupProps> = ({
410
410
  fontSize: "12px",
411
411
  borderRadius: "6px",
412
412
  border: "none",
413
- backgroundColor: "#3b82f6",
414
- color: "white",
413
+ backgroundColor: "var(--mc-primary)",
414
+ color: "var(--mc-button-foreground)",
415
415
  cursor: "pointer",
416
416
  fontWeight: 500,
417
417
  }}
@@ -11,17 +11,39 @@ import {
11
11
 
12
12
  const POLL_MS = 3000;
13
13
 
14
- const MetricsPopup: React.FC<{ onClose?: () => void }> = ({ onClose }) => {
14
+ interface MetricsPopupProps {
15
+ onClose?: () => void;
16
+ sharedHistory?: MetricsSnapshot[]; // Passed from parent when in persistent mode
17
+ }
18
+
19
+ const MetricsPopup: React.FC<MetricsPopupProps> = ({ onClose, sharedHistory }) => {
15
20
  const [metrics, setMetrics] = useState<MetricsSnapshot | null>(null);
16
- const [history, setHistory] = useState<MetricsSnapshot[]>([]);
21
+ const [localHistory, setLocalHistory] = useState<MetricsSnapshot[]>([]);
17
22
  const intervalRef = useRef<number | null>(null);
18
23
 
24
+ // Use shared history if provided (persistent mode), otherwise use local history (on-demand mode)
25
+ const history = sharedHistory ?? localHistory;
26
+ const isPersistentMode = sharedHistory !== undefined;
27
+
28
+ // Update current metrics from shared history
19
29
  useEffect(() => {
30
+ if (isPersistentMode && sharedHistory && sharedHistory.length > 0) {
31
+ setMetrics(sharedHistory[sharedHistory.length - 1]);
32
+ }
33
+ }, [isPersistentMode, sharedHistory]);
34
+
35
+ // On-demand mode: poll metrics when popup is open
36
+ useEffect(() => {
37
+ if (isPersistentMode) {
38
+ // Don't poll in persistent mode - use shared history
39
+ return;
40
+ }
41
+
20
42
  const load = async () => {
21
43
  try {
22
44
  const snap = await fetchMetrics();
23
45
  setMetrics(snap);
24
- setHistory((prev) => {
46
+ setLocalHistory((prev) => {
25
47
  const arr = [...prev, snap];
26
48
  return arr.slice(-100);
27
49
  });
@@ -32,7 +54,7 @@ const MetricsPopup: React.FC<{ onClose?: () => void }> = ({ onClose }) => {
32
54
  return () => {
33
55
  if (intervalRef.current) window.clearInterval(intervalRef.current);
34
56
  };
35
- }, []);
57
+ }, [isPersistentMode]);
36
58
 
37
59
  const hasGPU = metrics?.gpu && metrics.gpu.length > 0;
38
60
 
@@ -137,7 +159,7 @@ const BigValue: React.FC<{ value: string; subtitle?: string }> = ({
137
159
  );
138
160
 
139
161
  const MiniChart: React.FC<{ data: number[] }> = ({ data }) => {
140
- const width = 220;
162
+ const width = 100;
141
163
  const height = 48;
142
164
  const max = Math.max(100, ...data);
143
165
  const points = data
@@ -148,8 +170,21 @@ const MiniChart: React.FC<{ data: number[] }> = ({ data }) => {
148
170
  })
149
171
  .join(" ");
150
172
  return (
151
- <svg width={width} height={height} className="mini-chart">
152
- <polyline points={points} fill="none" stroke="var(--mc-primary)" strokeWidth="2" />
173
+ <svg
174
+ width="100%"
175
+ height={height}
176
+ viewBox={`0 0 ${width} ${height}`}
177
+ preserveAspectRatio="none"
178
+ className="mini-chart"
179
+ style={{ display: 'block' }}
180
+ >
181
+ <polyline
182
+ points={points}
183
+ fill="none"
184
+ stroke="var(--mc-primary)"
185
+ strokeWidth="2"
186
+ vectorEffect="non-scaling-stroke"
187
+ />
153
188
  </svg>
154
189
  );
155
190
  };
@@ -19,7 +19,8 @@ const PackagesPopup: React.FC<PackagesPopupProps> = ({ onClose }) => {
19
19
  const [query, setQuery] = useState('');
20
20
 
21
21
  useEffect(() => {
22
- loadPackages();
22
+ // Always force refresh on initial load to ensure fresh data
23
+ loadPackages(true);
23
24
  const handler = () => loadPackages(true); // Force refresh when packages updated
24
25
  if (typeof window !== 'undefined') {
25
26
  window.addEventListener('mc:packages-updated', handler as EventListener);
frontend/lib/api.ts CHANGED
@@ -51,8 +51,12 @@ export interface PackagesResponse {
51
51
  }
52
52
 
53
53
  export async function fetchInstalledPackages(forceRefresh: boolean = false): Promise<PackageInfo[]> {
54
- const url = forceRefresh ? `/api/packages?force_refresh=true` : `/api/packages`;
55
- const response = await fetch(url);
54
+ // Add timestamp to prevent browser caching
55
+ const timestamp = forceRefresh ? `&t=${Date.now()}` : '';
56
+ const url = forceRefresh ? `/api/packages?force_refresh=true${timestamp}` : `/api/packages`;
57
+ const response = await fetch(url, {
58
+ cache: forceRefresh ? 'no-store' : 'default'
59
+ });
56
60
  if (!response.ok) {
57
61
  throw new Error(`Failed to load packages: ${response.status}`);
58
62
  }
frontend/lib/settings.ts CHANGED
@@ -106,12 +106,16 @@ export const THEMES: Record<string, ThemeDefinition> = (() => {
106
106
  return themes;
107
107
  })();
108
108
 
109
+ export type MetricsCollectionMode = 'persistent' | 'on-demand';
110
+
109
111
  export type NotebookSettings = {
110
112
  theme: keyof typeof THEMES;
113
+ metricsCollectionMode: MetricsCollectionMode;
111
114
  };
112
115
 
113
116
  export const DEFAULT_SETTINGS: NotebookSettings = {
114
117
  theme: 'light',
118
+ metricsCollectionMode: 'on-demand', // Only collect metrics when popup is open to save memory
115
119
  };
116
120
 
117
121
  const STORAGE_KEY = 'morecompute-settings';
@@ -127,6 +131,9 @@ export function loadSettings(): NotebookSettings {
127
131
  // Return only valid settings fields (remove old auto_save, font_size, font_family, etc.)
128
132
  const cleanSettings: NotebookSettings = {
129
133
  theme,
134
+ metricsCollectionMode: parsed.metricsCollectionMode === 'on-demand' || parsed.metricsCollectionMode === 'persistent'
135
+ ? parsed.metricsCollectionMode
136
+ : DEFAULT_SETTINGS.metricsCollectionMode,
130
137
  };
131
138
 
132
139
  // Save cleaned settings back to localStorage
@@ -62,6 +62,9 @@ export class WebSocketService {
62
62
  case 'execution_start':
63
63
  this.emit('execution_start', messageData);
64
64
  break;
65
+ case 'heartbeat':
66
+ this.emit('heartbeat', messageData);
67
+ break;
65
68
  case 'stream_output':
66
69
  this.emit('stream_output', messageData);
67
70
  break;
@@ -2,9 +2,22 @@
2
2
 
3
3
  Available themes: `light`, `dark`, `tokyo-night`, `tokyo-night-storm`, `tokyo-night-light`, `night-owl`, `night-owl-light`, `synthwave-84`, `one-dark-pro`
4
4
 
5
- Example:
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
+ Available metricsCollectionMode: `on-demand` (only collect when popup open), `persistent` (collect continuously in background, uses more memory (obviously)
16
+
17
+ Example settings.json:
6
18
  ```json
7
19
  {
8
- "theme": "dark"
20
+ "theme": "dark",
21
+ "metricsCollectionMode": "on-demand"
9
22
  }
10
23
  ```
kernel_run.py CHANGED
@@ -24,6 +24,7 @@ class NotebookLauncher:
24
24
  self.debug = debug
25
25
  self.notebook_path = notebook_path
26
26
  self.is_windows = platform.system() == "Windows"
27
+ self.cleaning_up = False # Flag to prevent multiple cleanup calls
27
28
  root_dir = notebook_path.parent if notebook_path.parent != Path('') else Path.cwd()
28
29
  os.environ["MORECOMPUTE_ROOT"] = str(root_dir.resolve())
29
30
  os.environ["MORECOMPUTE_NOTEBOOK_PATH"] = str(self.notebook_path)
@@ -262,8 +263,14 @@ class NotebookLauncher:
262
263
  self.cleanup()
263
264
  sys.exit(1)
264
265
 
265
- def cleanup(self):
266
+ def cleanup(self, force=False):
266
267
  """Clean up processes on exit"""
268
+ if self.cleaning_up:
269
+ return # Already cleaning up, don't run again
270
+ self.cleaning_up = True
271
+
272
+ timeout = 0.5 if force else 2 # Shorter timeout on force exit
273
+
267
274
  if self.frontend_process:
268
275
  try:
269
276
  if self.is_windows:
@@ -274,11 +281,14 @@ class NotebookLauncher:
274
281
  stderr=subprocess.DEVNULL
275
282
  )
276
283
  else:
277
- self.frontend_process.terminate()
278
- try:
279
- self.frontend_process.wait(timeout=5)
280
- except subprocess.TimeoutExpired:
281
- self.frontend_process.kill()
284
+ if force:
285
+ self.frontend_process.kill() # Force kill immediately
286
+ else:
287
+ self.frontend_process.terminate()
288
+ try:
289
+ self.frontend_process.wait(timeout=timeout)
290
+ except subprocess.TimeoutExpired:
291
+ self.frontend_process.kill()
282
292
  except Exception:
283
293
  pass
284
294
 
@@ -292,11 +302,14 @@ class NotebookLauncher:
292
302
  stderr=subprocess.DEVNULL
293
303
  )
294
304
  else:
295
- self.backend_process.terminate()
296
- try:
297
- self.backend_process.wait(timeout=5)
298
- except subprocess.TimeoutExpired:
299
- self.backend_process.kill()
305
+ if force:
306
+ self.backend_process.kill() # Force kill immediately
307
+ else:
308
+ self.backend_process.terminate()
309
+ try:
310
+ self.backend_process.wait(timeout=timeout)
311
+ except subprocess.TimeoutExpired:
312
+ self.backend_process.kill()
300
313
  except Exception:
301
314
  pass
302
315
 
@@ -316,8 +329,8 @@ class NotebookLauncher:
316
329
  print("[CTRL-C AGAIN TO EXIT]")
317
330
  else:
318
331
  print("\n Thanks for using MoreCompute!\n")
319
- self.cleanup()
320
- sys.exit(0)
332
+ self.cleanup(force=True) # Force immediate cleanup
333
+ os._exit(0) # Hard exit without raising SystemExit
321
334
 
322
335
  # Windows signal handling is different
323
336
  if not self.is_windows:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: more-compute
3
- Version: 0.2.6
3
+ Version: 0.3.1
4
4
  Summary: An interactive notebook environment for local and GPU computing
5
5
  Home-page: https://github.com/DannyMang/MORECOMPUTE
6
6
  Author: MoreCompute Team
@@ -1,4 +1,4 @@
1
- kernel_run.py,sha256=XAgUmZO9EVPXMlQe8RO8w4s_NveB9U7J6S-CyF12D0o,15847
1
+ kernel_run.py,sha256=sQchzBOWgynXOKkSMp8T8BAkljw5CqDFrHX2Y0U6yto,16526
2
2
  frontend/.DS_Store,sha256=uQeHnkKyuTF1AVax3NPqtN0uCH6XNXAxL9Nkb6Q9cGw,8196
3
3
  frontend/.gitignore,sha256=IH4mX_SQH5rZ-W2M4IUw4E-fxgCBVHKmbQpEYJbWVM0,480
4
4
  frontend/README.md,sha256=YLVf9995r3JZD5UkII5GZCvDK9wXXNrUE0loHA4vlY8,1450
@@ -10,38 +10,37 @@ frontend/next.config.ts,sha256=OL_rEfTIZxsB_B5R9JX2AxYXgC0Fc_XiDoRlOGEDEpk,368
10
10
  frontend/package-lock.json,sha256=pGL_J72WHNTz7iLx2MOwHwnDGfbKzN-r_qnnbzfGbEU,334369
11
11
  frontend/package.json,sha256=nUVMqlXGT5m431ArOzzs_geSfmq0AKfqUB40zIAeZ5s,1395
12
12
  frontend/postcss.config.mjs,sha256=jEBxSXR5tLs0bQ67U7G961Vb62WVEqqg1piNDYPd7tU,105
13
- frontend/styling_README.md,sha256=H7eCyVMCNk_3tsKvJQHISFSL7ra6M6V58Vfsbt28wBY,220
13
+ frontend/styling_README.md,sha256=jvoXKUzJv0rEIU40gz23Z6Xugy4To8P0N9szg_hKrqw,561
14
14
  frontend/tailwind.config.ts,sha256=eP9nVaAuyYo46vGQfCyWbo25_pr2hW830fs1Itcix9Q,620
15
15
  frontend/tsconfig.json,sha256=7SvBlRBYmuXAlAteRQTGwEE7ooWuNaPUrZ219dOo61E,598
16
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
17
+ frontend/app/globals.css,sha256=zx2VGZhPHqrFSwCsW667gJ80BkEwL8E7J_IJNoMuYGQ,33738
18
+ frontend/app/layout.tsx,sha256=VMkhvePu0hV0w-huEmTocTr7lZ6DF_7eidrhzCCMwzc,7604
19
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
20
+ frontend/components/Notebook.tsx,sha256=JImlThoX4F363yShOqdYDjIIO3i1uqfCLRkDlzurinQ,21851
22
21
  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
22
+ frontend/components/cell/CellButton.tsx,sha256=j3lRStluVtRXjZOhi9isS3XKsRmM0WTn5SaFDM6GuYg,1386
23
+ frontend/components/cell/MonacoCell.tsx,sha256=YunwOlyeRsFqx-sHowhctqMV0RmhcQ1glSl5LO0s7NY,23914
25
24
  frontend/components/layout/ConnectionBanner.tsx,sha256=-m77wKCFpeRJ_AQwnM38jLwCY5vfpqE846xeXmT3p8A,870
26
25
  frontend/components/layout/Sidebar.tsx,sha256=kxgO2mXX11xI6rX478cUqqQ3xB40jlby21y27GTJSLU,1551
27
26
  frontend/components/modals/ConfirmModal.tsx,sha256=3WgXy_wmR8FHZPwzMevfZHFXa0blR4v_SbKG3d5McT4,3652
28
27
  frontend/components/modals/ErrorModal.tsx,sha256=kkGHQvgyMYlScKwni04-V_Dq6a0-lg0WodglLARR-uA,3536
29
28
  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
29
+ frontend/components/output/CellOutput.tsx,sha256=KLRzwEchvBoeoai8TbabKEwO4tHmog3EKeTJAXtmveI,3665
30
+ frontend/components/output/ErrorDisplay.tsx,sha256=kYfip5zikcFIuN7WW47RVjoqwDujC1q_yMbgHrHl0E0,4996
32
31
  frontend/components/output/MarkdownRenderer.tsx,sha256=RtZ5yNRxDXIh_NkNsNiy30wMGIW7V1gfhsjecgMdc80,3341
33
32
  frontend/components/popups/ComputePopup.tsx,sha256=B7AwwjpJ9_nNI5qSN53jdR2tAulB5yl7spjMXjH4yDM,44021
34
- frontend/components/popups/FilterPopup.tsx,sha256=4kx9txg8cWeC6XHlh0pu0-BAfZkLTDYEU93fMdzn86M,13818
33
+ frontend/components/popups/FilterPopup.tsx,sha256=KRIzRvVxEF47ELWIAvrqv7BZQYmEo_zOX8Nbpz0zEik,14133
35
34
  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
35
+ frontend/components/popups/MetricsPopup.tsx,sha256=ublYbOQ-pSU_w48F10uFjDYctysEwmri9lrji5YHIC4,6034
36
+ frontend/components/popups/PackagesPopup.tsx,sha256=faeXL7hGFIEUBU6PUrTIr9P5Lw-81GGKWK1ldnIEDcc,3675
38
37
  frontend/components/popups/SettingsPopup.tsx,sha256=rGwYxjkADnyTtpP0MjVpFPBsGoT1eENN2z7nWjLuzFE,2773
39
38
  frontend/contexts/PodWebSocketContext.tsx,sha256=QyEg1Msyum7h3T6F3j6pn4Ds5sXFT_9WYu5_0YZ2IUI,8256
40
- frontend/lib/api.ts,sha256=0N4PCSC5pfbq7GvR_6aOdPZ3JGujzi1Rz4V51g8sHP8,10852
39
+ frontend/lib/api.ts,sha256=L6Js3K7RcPCLfVVUz-bKX5hLAVFKCfUSHAKSHk2keAk,11026
41
40
  frontend/lib/monaco-themes.ts,sha256=jh_pZAmSMKjY_belbMbZX2WpFBN7baRxvJp9shUDYgk,5396
42
- frontend/lib/settings.ts,sha256=ZAdwLErjPITkIc87D3DTcHYhhUP3fBI-LpDYsH9eVE4,5842
41
+ frontend/lib/settings.ts,sha256=klHVyB2n-wTc8YrjKCIf2BEmrR-JLVHrRYIXkDxv9-A,6263
43
42
  frontend/lib/themes.json,sha256=mk6IGy6o_DCOerBH3QmfXozTHEiy-alsTLTTIaba7No,292018
44
- frontend/lib/websocket-native.ts,sha256=6QUSLSONnCImPp9hpFo_XdXME5X7DOptW1mrtG7E99A,5962
43
+ frontend/lib/websocket-native.ts,sha256=KcokVZAl08iWRAcBOfyt3uej352esOa_-YwLk7M5iSU,6046
45
44
  frontend/lib/websocket.ts,sha256=V2Y7sktt2dm1G-ZILggcqIWccsh-xoAG9dLHpNVqIqs,4500
46
45
  frontend/public/file.svg,sha256=K2eBLDJcGZoCU2zb7qDFk6cvcH0yO3LuPgjbqwZ1O9Q,391
47
46
  frontend/public/globe.svg,sha256=thS5vxg5JZV2YayFFJj-HYAp_UOmL7_thvniYkpX588,1035
@@ -65,17 +64,17 @@ frontend/public/fonts/Fira.ttf,sha256=dbSM4W7Drd9n_EkfXq8P31KuxbjZ1wtuFiZ8aFebvT
65
64
  frontend/public/fonts/Tiempos.woff2,sha256=h83bJKvAK301wXCMIvK7ZG5j0H2K3tzAfgo0yk4z8OE,13604
66
65
  frontend/public/fonts/VeraMono.ttf,sha256=2kKB3H2xej385kpiztkodcWJU0AFXsi6JKORTrl7NJ0,49224
67
66
  frontend/types/notebook.ts,sha256=v23RaZe6H3lU5tq6sqnJDPxC2mu0NZFDCJfiN0mgvSs,1359
68
- more_compute-0.2.6.dist-info/licenses/LICENSE,sha256=0Ot-XIetYt06iay6IhtpJkruD-cLZtjyv7_aIEE-oSc,1073
67
+ more_compute-0.3.1.dist-info/licenses/LICENSE,sha256=0Ot-XIetYt06iay6IhtpJkruD-cLZtjyv7_aIEE-oSc,1073
69
68
  morecompute/__init__.py,sha256=pcMVq8Q7qb42AOn7tqgoZJOi3epDDBnEriiv2WVKnXY,87
70
- morecompute/__version__.py,sha256=Oz5HbwHMyE87nmwV80AZzpkJPf-wBg7eDuJr_BXZkhU,22
69
+ morecompute/__version__.py,sha256=r4xAFihOf72W9TD-lpMi6ntWSTKTP2SlzKP1ytkjRbI,22
71
70
  morecompute/cli.py,sha256=kVvzvPBqF8xO6UuhU_-TBn99nKwJ405R2mAS6zU0KBc,734
72
71
  morecompute/notebook.py,sha256=KEcv0eOEh9N7bPVGoRuKJb47G9MmpQ5zz1B6Dm58w18,4651
73
72
  morecompute/process_worker.py,sha256=KsE3r-XpkYGuyO4w3t54VKkD51LfNHAZc3TYattMtrg,7185
74
- morecompute/server.py,sha256=W_EfX4NiSYZgK3ZZFP-LPO78_Sjzuyo3eiKprnAxsfI,40144
73
+ morecompute/server.py,sha256=mdN80iBUixq4KUQfu53aoVsNZ6DM9RaBXc-lwt4bxFk,40285
75
74
  morecompute/execution/__init__.py,sha256=jPmBmq8BZWbUEY9XFSpqt5FkgX04uNS10WnUlr7Rnms,134
76
75
  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
76
+ morecompute/execution/executor.py,sha256=BesGdx10HSGj8PyPrekdQZzc0tXoqidznEaFITOq8JM,20554
77
+ morecompute/execution/worker.py,sha256=4yZc_Z4A_nhCv_Lv8MaseSe7KYdXPYK5yDeQeDZoVwM,16004
79
78
  morecompute/models/__init__.py,sha256=VLJ5GWi2uTNiZBdvl-ipSbmA6EL8FZHZ5oq-rJmm9z0,640
80
79
  morecompute/models/api_models.py,sha256=-ydvi9SeTfdoY9oVPNQS4by-kQGSknx6BHhGD8E2tpo,4553
81
80
  morecompute/services/data_manager.py,sha256=c4GKucetMM-VPNbHyzce6bZRvFfmz8kTd5RppLjoLVc,14329
@@ -86,15 +85,18 @@ morecompute/services/prime_intellect.py,sha256=b705rHv3RPRsgWedRlHwoP_S-TxxZtMSy
86
85
  morecompute/static/styles.css,sha256=el_NtrUMbAUNSiMVBn1xlG70m3iPv7dyaIbWQMexhsY,19277
87
86
  morecompute/utils/__init__.py,sha256=VIxCL3S1pnjEs4cjKGZqZB68_P8FegdeMIqBjJhI5jQ,419
88
87
  morecompute/utils/cache_util.py,sha256=lVlXudHvtyvSo_kCSxORJrI85Jod8FrQLbI2f_JOIbA,661
88
+ morecompute/utils/cell_magics.py,sha256=XUxy6lIsrx-9r0mWn0smI1gvT3-kv0rhN5km9cs3D48,27278
89
89
  morecompute/utils/config_util.py,sha256=fGTQll7Zh05ZHrW8LuQNTJGziGnIfvKIU3azbrY-I-s,1793
90
90
  morecompute/utils/error_utils.py,sha256=e50WLFdD6ngIC30xAgrzdTYtD8tPOIFkKAAh_sPbK0I,11667
91
+ morecompute/utils/line_magics.py,sha256=kTutYBPAWoURY_pk8HXQ38IP712M2rBBfUg3oN8VrP0,33740
91
92
  morecompute/utils/notebook_util.py,sha256=3hH94dtXvhizRVTU9a2b38m_51Y4igoXpkjAXUqpVBQ,1353
92
93
  morecompute/utils/python_environment_util.py,sha256=l8WWWPwKbypknw8GwL22NXCji5i1FOy1vWG47J6og4g,7441
93
- morecompute/utils/special_commands.py,sha256=JTc9II2EitmivwTTdnydEefShasiTa-7w8tNyYVIenw,19104
94
+ morecompute/utils/shell_utils.py,sha256=fGFLhQLZU-lmMGALbbS-fKPkhQtmMhZ1FkgQ3TeoFhA,1917
95
+ morecompute/utils/special_commands.py,sha256=IyF9MTINMNNo3P_f56Q6yS_P2HNjA9vohYVxEV7KYnc,17331
94
96
  morecompute/utils/system_environment_util.py,sha256=32mQRubo0i4X61o-825T7m-eUSidcEp07qkInP1sWZA,4774
95
97
  morecompute/utils/zmq_util.py,sha256=tx7-iS04UN69OFtBzkxcEnRhT7xtI9EzRnrZ_nsH_O0,1889
96
- more_compute-0.2.6.dist-info/METADATA,sha256=WwIvC8bdlk8MTsPcfHiiyoVOShlimReIQuEaPwYep0Q,3631
97
- more_compute-0.2.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
98
- more_compute-0.2.6.dist-info/entry_points.txt,sha256=xp7z9eRPNRM4oxkZZVlyXkhkSjN1AjoYI_B7qpDJ1bI,49
99
- more_compute-0.2.6.dist-info/top_level.txt,sha256=Tamm6ADzjwaQa1z27O7Izcyhyt9f0gVjMv1_tC810aI,32
100
- more_compute-0.2.6.dist-info/RECORD,,
98
+ more_compute-0.3.1.dist-info/METADATA,sha256=sJSEnJl02gb23g01UgOx8LXmdb9RUtuweZ7Z-Ak43eA,3631
99
+ more_compute-0.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
100
+ more_compute-0.3.1.dist-info/entry_points.txt,sha256=xp7z9eRPNRM4oxkZZVlyXkhkSjN1AjoYI_B7qpDJ1bI,49
101
+ more_compute-0.3.1.dist-info/top_level.txt,sha256=Tamm6ADzjwaQa1z27O7Izcyhyt9f0gVjMv1_tC810aI,32
102
+ more_compute-0.3.1.dist-info/RECORD,,
@@ -1 +1 @@
1
- __version__ = "0.2.6"
1
+ __version__ = "0.3.1"
@@ -120,10 +120,17 @@ class NextZmqExecutor:
120
120
  if handler is not None:
121
121
  normalized_source = handler._coerce_source_to_text(source_code) # type: ignore[reportPrivateUsage]
122
122
  if handler.is_special_command(normalized_source):
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
123
+ # Check if this is a PURE special command (starts with !, %%, or %)
124
+ # vs a MIXED command (contains shell commands but also has Python code)
125
+ stripped = normalized_source.strip()
126
+ is_pure_special = (stripped.startswith('!') or
127
+ stripped.startswith('%%') or
128
+ stripped.startswith('%'))
129
+
130
+ # Only execute PURE special commands locally
131
+ # Mixed commands must go to worker for proper streaming
132
+ if not self.is_remote and is_pure_special:
133
+ # Execute pure special command locally
127
134
  execution_count = getattr(self, 'execution_count', 0) + 1
128
135
  self.execution_count = execution_count
129
136
  start_time = time.time()
@@ -143,7 +150,7 @@ class NextZmqExecutor:
143
150
  if websocket:
144
151
  await websocket.send_json({'type': 'execution_complete', 'data': {'cell_index': cell_index, 'result': result}})
145
152
  return result
146
- # For remote execution, fall through to send via ZMQ
153
+ # For remote execution OR mixed commands, fall through to send via ZMQ
147
154
 
148
155
  execution_count = getattr(self, 'execution_count', 0) + 1
149
156
  self.execution_count = execution_count