pinokiod 3.270.0 → 3.272.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/kernel/ansi_stream_tracker.js +115 -0
  2. package/kernel/api/app/index.js +422 -0
  3. package/kernel/api/htmlmodal/index.js +94 -0
  4. package/kernel/app_launcher/index.js +115 -0
  5. package/kernel/app_launcher/platform/base.js +276 -0
  6. package/kernel/app_launcher/platform/linux.js +229 -0
  7. package/kernel/app_launcher/platform/macos.js +163 -0
  8. package/kernel/app_launcher/platform/unsupported.js +34 -0
  9. package/kernel/app_launcher/platform/windows.js +247 -0
  10. package/kernel/bin/conda-meta.js +93 -0
  11. package/kernel/bin/conda.js +2 -4
  12. package/kernel/bin/index.js +2 -4
  13. package/kernel/index.js +9 -2
  14. package/kernel/peer.js +186 -19
  15. package/kernel/shell.js +212 -1
  16. package/package.json +1 -1
  17. package/server/index.js +491 -6
  18. package/server/public/common.js +224 -741
  19. package/server/public/create-launcher.js +754 -0
  20. package/server/public/htmlmodal.js +292 -0
  21. package/server/public/logs.js +715 -0
  22. package/server/public/resizeSync.js +117 -0
  23. package/server/public/style.css +651 -6
  24. package/server/public/tab-idle-notifier.js +34 -59
  25. package/server/public/tab-link-popover.js +7 -10
  26. package/server/public/terminal-settings.js +723 -9
  27. package/server/public/terminal_input_utils.js +72 -0
  28. package/server/public/terminal_key_caption.js +187 -0
  29. package/server/public/urldropdown.css +120 -3
  30. package/server/public/xterm-inline-bridge.js +116 -0
  31. package/server/socket.js +29 -0
  32. package/server/views/agents.ejs +1 -2
  33. package/server/views/app.ejs +55 -28
  34. package/server/views/bookmarklet.ejs +1 -1
  35. package/server/views/bootstrap.ejs +1 -0
  36. package/server/views/connect.ejs +1 -2
  37. package/server/views/create.ejs +63 -0
  38. package/server/views/editor.ejs +36 -4
  39. package/server/views/index.ejs +1 -2
  40. package/server/views/index2.ejs +1 -2
  41. package/server/views/init/index.ejs +36 -28
  42. package/server/views/install.ejs +20 -22
  43. package/server/views/layout.ejs +2 -8
  44. package/server/views/logs.ejs +155 -0
  45. package/server/views/mini.ejs +0 -18
  46. package/server/views/net.ejs +2 -2
  47. package/server/views/network.ejs +1 -2
  48. package/server/views/network2.ejs +1 -2
  49. package/server/views/old_network.ejs +1 -2
  50. package/server/views/pro.ejs +26 -23
  51. package/server/views/prototype/index.ejs +30 -34
  52. package/server/views/screenshots.ejs +1 -2
  53. package/server/views/settings.ejs +1 -20
  54. package/server/views/shell.ejs +59 -66
  55. package/server/views/terminal.ejs +118 -73
  56. package/server/views/tools.ejs +1 -2
@@ -48,7 +48,7 @@
48
48
  notifyPreferences.set(key, Boolean(value));
49
49
  });
50
50
  } catch (error) {
51
- log('Failed to hydrate notification preferences', error);
51
+ console.log('Failed to hydrate notification preferences', error);
52
52
  }
53
53
  };
54
54
 
@@ -64,7 +64,7 @@
64
64
  localStorage.setItem(PREF_STORAGE_KEY, JSON.stringify(serialisable));
65
65
  }
66
66
  } catch (error) {
67
- log('Failed to persist notification preferences', error);
67
+ console.log('Failed to persist notification preferences', error);
68
68
  }
69
69
  };
70
70
 
@@ -119,7 +119,7 @@
119
119
  globalSoundPreference.choice = normaliseSoundChoice(parsed.choice);
120
120
  }
121
121
  } catch (error) {
122
- log('Failed to hydrate sound preference', error);
122
+ console.log('Failed to hydrate sound preference', error);
123
123
  globalSoundPreference = { choice: SOUND_DEFAULT_CHOICE };
124
124
  }
125
125
  };
@@ -133,7 +133,7 @@
133
133
  }
134
134
  localStorage.setItem(SOUND_PREF_STORAGE_KEY, JSON.stringify({ choice }));
135
135
  } catch (error) {
136
- log('Failed to persist sound preference', error);
136
+ console.log('Failed to persist sound preference', error);
137
137
  }
138
138
  };
139
139
 
@@ -213,7 +213,7 @@
213
213
  return soundOptionsCache.map((option) => ({ ...option }));
214
214
  })
215
215
  .catch((error) => {
216
- log('Failed to load notification sound list', error);
216
+ console.log('Failed to load notification sound list', error);
217
217
  return baseSoundOptions().map((option) => ({ ...option }));
218
218
  })
219
219
  .finally(() => {
@@ -258,7 +258,7 @@
258
258
  result.catch(() => {});
259
259
  }
260
260
  } catch (error) {
261
- log('Failed to play sound preview', error);
261
+ console.log('Failed to play sound preview', error);
262
262
  }
263
263
  };
264
264
 
@@ -650,25 +650,6 @@
650
650
  persistPreferences();
651
651
  };
652
652
 
653
- const DEBUG_STORAGE_KEY = 'pinokio:idle-debug';
654
- const readDebugFlag = () => {
655
- try {
656
- return localStorage.getItem(DEBUG_STORAGE_KEY) === '1';
657
- } catch (_) {
658
- return false;
659
- }
660
- };
661
-
662
- let DEBUG = readDebugFlag();
663
- const log = (...args) => {
664
- if (DEBUG) {
665
- console.debug('[PinokioIdleNotifier]', ...args);
666
- }
667
- };
668
-
669
- const updateDebugFlag = () => {
670
- DEBUG = readDebugFlag();
671
- };
672
653
 
673
654
  const aggregateDebounce = (fn, delay = 100) => {
674
655
  let timer = null;
@@ -717,7 +698,7 @@
717
698
  notifyEnabled: getPreference(frameName),
718
699
  };
719
700
  tabStates.set(frameName, state);
720
- log('Created state for frame', frameName);
701
+ console.log('Created state for frame', frameName);
721
702
  } else if (typeof state.notifyEnabled === 'undefined') {
722
703
  state.notifyEnabled = getPreference(frameName);
723
704
  }
@@ -1038,7 +1019,7 @@ const syncToggleAppearance = (toggle, enabled) => {
1038
1019
  current.notifyEnabled = next;
1039
1020
  setPreference(frameName, next);
1040
1021
  syncToggleAppearance(toggle, next);
1041
- log('Notification preference changed', { frameName, enabled: next });
1022
+ console.log('Notification preference changed', { frameName, enabled: next });
1042
1023
  };
1043
1024
 
1044
1025
  toggle._pinokioToggleActivate = activate;
@@ -1136,7 +1117,6 @@ const ensureTabAccessories = aggregateDebounce(() => {
1136
1117
  }
1137
1118
  indicatorObserver.observe(node, { attributes: true, attributeFilter: ['class', 'data-timestamp'] });
1138
1119
  observedIndicators.add(node);
1139
- log('Observing indicator', node);
1140
1120
  });
1141
1121
  ensureTabAccessories();
1142
1122
  });
@@ -1157,8 +1137,25 @@ const ensureTabAccessories = aggregateDebounce(() => {
1157
1137
  return null;
1158
1138
  };
1159
1139
 
1140
+ const playInlineSound = () => {
1141
+ const audioEl = window.__pinokioCustomNotificationAudio || window.__pinokioChimeAudio;
1142
+ if (!audioEl) {
1143
+ return;
1144
+ }
1145
+ try {
1146
+ audioEl.currentTime = 0;
1147
+ const playPromise = audioEl.play();
1148
+ if (playPromise && typeof playPromise.catch === 'function') {
1149
+ playPromise.catch((err) => console.log('inline audio blocked', err));
1150
+ }
1151
+ } catch (err) {
1152
+ console.log('inline audio play failed', err);
1153
+ }
1154
+ };
1155
+
1160
1156
  const sendNotification = (link, state) => {
1161
1157
  if (!link || !state) {
1158
+ console.log('sendNotification skipped – link/state missing');
1162
1159
  return;
1163
1160
  }
1164
1161
  const tab = link.querySelector('.tab');
@@ -1182,8 +1179,13 @@ const ensureTabAccessories = aggregateDebounce(() => {
1182
1179
  payload.image = image;
1183
1180
  }
1184
1181
 
1182
+ const isInlineMode = () => Boolean(window.PinokioInlineIdle);
1183
+ if (isInlineMode()) {
1184
+ playInlineSound();
1185
+ return;
1186
+ }
1187
+
1185
1188
  try {
1186
- log('Sending notification payload', payload);
1187
1189
  fetch(PUSH_ENDPOINT, {
1188
1190
  method: 'POST',
1189
1191
  headers: {
@@ -1235,7 +1237,6 @@ const ensureTabAccessories = aggregateDebounce(() => {
1235
1237
  const isLive = indicator.classList.contains(LIVE_CLASS);
1236
1238
  state.isLive = isLive;
1237
1239
  updateActivityTimestamp(indicator, state);
1238
- log('Indicator change', { frameName, isLive, awaitingLive: state.awaitingLive, awaitingIdle: state.awaitingIdle });
1239
1240
 
1240
1241
  if (isLive) {
1241
1242
  state.lastLiveTimestamp = Date.now();
@@ -1263,13 +1264,12 @@ const ensureTabAccessories = aggregateDebounce(() => {
1263
1264
  }
1264
1265
 
1265
1266
  if (runtimeMs !== null && runtimeMs < MIN_COMMAND_DURATION_MS) {
1266
- log('Skipping idle notification (command completed quickly)', { frameName, runtimeMs });
1267
+ console.log('[idle notifier] skipping quick command', { frameName, runtimeMs });
1267
1268
  } else if (!state.notifyEnabled) {
1268
- log('Notifications disabled for frame', frameName);
1269
+ console.log('[idle notifier] notifications disabled for frame', frameName);
1269
1270
  } else if (shouldNotify(link)) {
1270
1271
  sendNotification(link, state);
1271
1272
  state.notified = true;
1272
- log('Idle notification dispatched', { frameName, runtimeMs });
1273
1273
  }
1274
1274
  }
1275
1275
 
@@ -1299,7 +1299,6 @@ const ensureTabAccessories = aggregateDebounce(() => {
1299
1299
  if (node.matches(TAB_UPDATED_SELECTOR)) {
1300
1300
  indicatorObserver.observe(node, { attributes: true, attributeFilter: ['class', 'data-timestamp'] });
1301
1301
  observedIndicators.add(node);
1302
- log('Observed newly added indicator', node);
1303
1302
  shouldRescan = true;
1304
1303
  } else if (node.classList && node.classList.contains('frame-link')) {
1305
1304
  shouldRescan = true;
@@ -1342,13 +1341,11 @@ const ensureTabAccessories = aggregateDebounce(() => {
1342
1341
  state.commandStartTimestamp = Date.now();
1343
1342
  state.lastActivityTimestamp = 0;
1344
1343
  state.lastLiveTimestamp = 0;
1345
- log('Terminal input captured', { frameName, line: data.line, state: { ...state } });
1346
1344
 
1347
1345
  const indicator = findIndicatorForFrame(frameName);
1348
1346
  if (indicator && indicator.classList.contains(LIVE_CLASS)) {
1349
1347
  state.awaitingLive = false;
1350
1348
  state.awaitingIdle = true;
1351
- log('Indicator already live when input arrived', frameName);
1352
1349
  }
1353
1350
  };
1354
1351
 
@@ -1362,7 +1359,6 @@ const ensureTabAccessories = aggregateDebounce(() => {
1362
1359
  };
1363
1360
 
1364
1361
  const initialise = () => {
1365
- log('Initialising idle notifier');
1366
1362
  ensureIndicatorObservers();
1367
1363
  ensureTabAccessories();
1368
1364
  treeObserver.observe(document.body, { childList: true, subtree: true });
@@ -1373,23 +1369,18 @@ const ensureTabAccessories = aggregateDebounce(() => {
1373
1369
  window.addEventListener('resize', handleViewportChange);
1374
1370
  window.addEventListener('scroll', handleViewportChange, true);
1375
1371
  window.addEventListener('storage', (event) => {
1376
- if (event.key === DEBUG_STORAGE_KEY) {
1377
- updateDebugFlag();
1378
- log('Debug flag updated via storage event');
1379
- } else if (event.key === PREF_STORAGE_KEY) {
1372
+ if (event.key === PREF_STORAGE_KEY) {
1380
1373
  notifyPreferences.clear();
1381
1374
  hydratePreferences();
1382
1375
  tabStates.forEach((state, frame) => {
1383
1376
  state.notifyEnabled = getPreference(frame);
1384
1377
  });
1385
1378
  ensureTabAccessories();
1386
- log('Notification preferences refreshed from storage event');
1387
1379
  } else if (event.key === SOUND_PREF_STORAGE_KEY) {
1388
1380
  hydrateSoundPreference();
1389
1381
  if (openMenuContext) {
1390
1382
  renderSoundMenu(openMenuContext);
1391
1383
  }
1392
- log('Sound preference refreshed from storage event');
1393
1384
  }
1394
1385
  });
1395
1386
  };
@@ -1400,25 +1391,9 @@ const ensureTabAccessories = aggregateDebounce(() => {
1400
1391
  initialise();
1401
1392
  }
1402
1393
  window.PinokioIdleNotifier = {
1403
- enableDebug() {
1404
- try {
1405
- localStorage.setItem(DEBUG_STORAGE_KEY, '1');
1406
- } catch (_) {}
1407
- updateDebugFlag();
1408
- log('Debug enabled');
1409
- },
1410
- disableDebug() {
1411
- try {
1412
- localStorage.removeItem(DEBUG_STORAGE_KEY);
1413
- } catch (_) {}
1414
- updateDebugFlag();
1415
- log('Debug disabled');
1416
- },
1417
- refreshDebug: updateDebugFlag,
1418
1394
  forceScan() {
1419
1395
  ensureIndicatorObservers();
1420
1396
  ensureTabAccessories();
1421
- log('Force scan triggered');
1422
1397
  }
1423
1398
  };
1424
1399
  })();
@@ -1243,16 +1243,10 @@
1243
1243
  const popoverWidth = popover.offsetWidth
1244
1244
  let popoverHeight = popover.offsetHeight
1245
1245
  const viewportPadding = 12
1246
- const availableHeight = Math.max(80, window.innerHeight - viewportPadding * 2)
1247
-
1248
- if (popoverHeight > availableHeight) {
1249
- popover.style.maxHeight = `${Math.round(availableHeight)}px`
1250
- popover.style.overflowY = "auto"
1251
- popoverHeight = Math.min(availableHeight, popover.offsetHeight)
1252
- }
1246
+ const dropOffset = 8
1253
1247
 
1254
1248
  let left = rect.left
1255
- let top = rect.bottom + 8
1249
+ const top = Math.max(viewportPadding, rect.bottom + dropOffset)
1256
1250
 
1257
1251
  if (left + popoverWidth > window.innerWidth - viewportPadding) {
1258
1252
  left = window.innerWidth - popoverWidth - viewportPadding
@@ -1261,8 +1255,11 @@
1261
1255
  left = viewportPadding
1262
1256
  }
1263
1257
 
1264
- if (top + popoverHeight > window.innerHeight - viewportPadding) {
1265
- top = Math.max(viewportPadding, rect.top - popoverHeight - 8)
1258
+ const availableBelow = Math.max(0, window.innerHeight - viewportPadding - top)
1259
+ if (availableBelow > 0 && popoverHeight > availableBelow) {
1260
+ popover.style.maxHeight = `${Math.round(availableBelow)}px`
1261
+ popover.style.overflowY = "auto"
1262
+ popoverHeight = Math.min(availableBelow, popover.offsetHeight)
1266
1263
  }
1267
1264
 
1268
1265
  popover.style.left = `${Math.round(left)}px`