pinokiod 3.41.0 → 3.42.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 (82) hide show
  1. package/kernel/api/browser/index.js +3 -1
  2. package/kernel/api/cloudflare/index.js +3 -3
  3. package/kernel/api/index.js +187 -51
  4. package/kernel/api/loading/index.js +15 -0
  5. package/kernel/api/process/index.js +7 -0
  6. package/kernel/api/shell/index.js +0 -2
  7. package/kernel/bin/browserless.js +22 -0
  8. package/kernel/bin/caddy.js +36 -4
  9. package/kernel/bin/index.js +4 -1
  10. package/kernel/bin/setup.js +38 -5
  11. package/kernel/connect/backend.js +110 -0
  12. package/kernel/connect/config.js +171 -0
  13. package/kernel/connect/index.js +18 -7
  14. package/kernel/connect/providers/huggingface/index.js +98 -0
  15. package/kernel/connect/providers/x/index.js +0 -1
  16. package/kernel/environment.js +91 -19
  17. package/kernel/git.js +46 -3
  18. package/kernel/index.js +119 -39
  19. package/kernel/peer.js +40 -5
  20. package/kernel/plugin.js +3 -2
  21. package/kernel/procs.js +27 -20
  22. package/kernel/prototype.js +30 -16
  23. package/kernel/router/common.js +1 -1
  24. package/kernel/router/connector.js +1 -3
  25. package/kernel/router/index.js +38 -4
  26. package/kernel/router/localhost_home_router.js +5 -1
  27. package/kernel/router/localhost_port_router.js +27 -1
  28. package/kernel/router/localhost_static_router.js +93 -0
  29. package/kernel/router/localhost_variable_router.js +14 -9
  30. package/kernel/router/peer_peer_router.js +3 -0
  31. package/kernel/router/peer_static_router.js +43 -0
  32. package/kernel/router/peer_variable_router.js +15 -14
  33. package/kernel/router/processor.js +26 -1
  34. package/kernel/router/rewriter.js +59 -0
  35. package/kernel/scripts/git/commit +11 -1
  36. package/kernel/shell.js +8 -3
  37. package/kernel/util.js +65 -6
  38. package/package.json +2 -1
  39. package/server/index.js +1037 -964
  40. package/server/public/common.js +382 -1
  41. package/server/public/fscreator.js +0 -1
  42. package/server/public/loading.js +17 -0
  43. package/server/public/notifyinput.js +0 -1
  44. package/server/public/opener.js +4 -2
  45. package/server/public/style.css +310 -11
  46. package/server/socket.js +7 -1
  47. package/server/views/app.ejs +1747 -351
  48. package/server/views/columns.ejs +338 -0
  49. package/server/views/connect/huggingface.ejs +353 -0
  50. package/server/views/connect/index.ejs +410 -0
  51. package/server/views/connect/x.ejs +43 -9
  52. package/server/views/connect.ejs +709 -49
  53. package/server/views/container.ejs +357 -0
  54. package/server/views/d.ejs +251 -62
  55. package/server/views/download.ejs +54 -10
  56. package/server/views/editor.ejs +11 -0
  57. package/server/views/explore.ejs +40 -15
  58. package/server/views/file_explorer.ejs +25 -246
  59. package/server/views/form.ejs +44 -1
  60. package/server/views/frame.ejs +39 -1
  61. package/server/views/github.ejs +48 -11
  62. package/server/views/help.ejs +48 -7
  63. package/server/views/index.ejs +119 -58
  64. package/server/views/index2.ejs +3 -4
  65. package/server/views/init/index.ejs +651 -197
  66. package/server/views/install.ejs +1 -1
  67. package/server/views/mini.ejs +47 -18
  68. package/server/views/net.ejs +199 -67
  69. package/server/views/network.ejs +220 -94
  70. package/server/views/network2.ejs +3 -4
  71. package/server/views/old_network.ejs +3 -3
  72. package/server/views/prototype/index.ejs +48 -11
  73. package/server/views/review.ejs +1005 -0
  74. package/server/views/rows.ejs +341 -0
  75. package/server/views/screenshots.ejs +1020 -0
  76. package/server/views/settings.ejs +160 -23
  77. package/server/views/setup.ejs +49 -7
  78. package/server/views/setup_home.ejs +43 -10
  79. package/server/views/shell.ejs +7 -1
  80. package/server/views/start.ejs +14 -9
  81. package/server/views/terminal.ejs +13 -2
  82. package/server/views/tools.ejs +1015 -0
@@ -1,3 +1,273 @@
1
+ function downloadBlob(blob, filename = 'screenshot.png') {
2
+ const url = URL.createObjectURL(blob);
3
+ const a = document.createElement('a');
4
+ a.href = url;
5
+ a.download = filename;
6
+ document.body.appendChild(a);
7
+ a.click();
8
+ document.body.removeChild(a);
9
+ URL.revokeObjectURL(url);
10
+ }
11
+ async function uploadBlob(blob, filename = 'screenshot.png') {
12
+ const fd = new FormData();
13
+ fd.append('file', blob, filename);
14
+
15
+ // Adjust URL as needed; include credentials if you use cookies/sessions
16
+ const res = await fetch('/screenshot', {
17
+ method: 'POST',
18
+ body: fd,
19
+ credentials: 'include'
20
+ });
21
+
22
+ if (!res.ok) {
23
+ const text = await res.text();
24
+ throw new Error(`Upload failed: ${res.status} ${text}`);
25
+ }
26
+ const json = await res.json();
27
+ return json
28
+
29
+ }
30
+ async function screenshot(opts = {}) {
31
+ const {
32
+ container = document.body,
33
+ mimeType = 'image/png',
34
+ autoDownload = false,
35
+ filename = 'screenshot.png'
36
+ } = opts;
37
+
38
+ // 1) Capture one frame (no modal visible yet)
39
+ const stream = await navigator.mediaDevices.getDisplayMedia({
40
+ video: { cursor: 'always' },
41
+ audio: false
42
+ });
43
+
44
+ const video = document.createElement('video');
45
+ video.srcObject = stream;
46
+ video.playsInline = true;
47
+ video.muted = true;
48
+ Object.assign(video.style, {
49
+ position: 'fixed', opacity: '0', pointerEvents: 'none', transform: 'translate(-99999px,-99999px)'
50
+ });
51
+ document.body.appendChild(video);
52
+
53
+ await new Promise(res => {
54
+ const ready = () => (video.readyState >= 2 ? res() : (video.onloadeddata = () => res()));
55
+ video.addEventListener('loadedmetadata', ready, { once: true });
56
+ video.addEventListener('loadeddata', ready, { once: true });
57
+ });
58
+ await video.play().catch(()=>{});
59
+
60
+ const vw = video.videoWidth || 1920;
61
+ const vh = video.videoHeight || 1080;
62
+ const snap = document.createElement('canvas');
63
+ snap.width = vw; snap.height = vh;
64
+ snap.getContext('2d').drawImage(video, 0, 0, vw, vh);
65
+
66
+ // Stop quickly; we only needed one frame
67
+ stream.getTracks().forEach(t => t.stop());
68
+ video.remove();
69
+
70
+ // 2) Crop UI over STILL image
71
+ const root = document.createElement('div');
72
+ root.style.cssText = `
73
+ position:fixed; inset:0; z-index:2147483647;
74
+ background:rgba(0,0,0,.65); display:grid; place-items:center;
75
+ font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;
76
+ `;
77
+ const frame = document.createElement('div');
78
+ frame.style.cssText = `
79
+ position:relative; background:#111; border-radius:12px; overflow:hidden;
80
+ box-shadow:0 10px 40px rgba(0,0,0,.5);
81
+ width:min(90vw,1200px);
82
+ display:grid; grid-template-rows:1fr auto;
83
+ `;
84
+ const stage = document.createElement('div');
85
+ stage.style.cssText = `position:relative;background:#000;`;
86
+
87
+ const img = new Image();
88
+ img.src = snap.toDataURL('image/png');
89
+ img.style.cssText = `max-width:100%;max-height:100%;display:block;margin:auto;user-select:none;`;
90
+
91
+ const overlay = document.createElement('canvas');
92
+ overlay.style.cssText = `position:absolute;inset:0;cursor:crosshair;touch-action:none;`;
93
+
94
+ const toolbar = document.createElement('div');
95
+ toolbar.style.cssText = `
96
+ display:flex;gap:8px;padding:10px;background:#0b0b0b;border-top:1px solid #222;
97
+ align-items:center;justify-content:space-between;color:#ddd;font-size:14px;
98
+ `;
99
+ const hint = document.createElement('div');
100
+ hint.textContent = 'Drag to select an area. Click “Save” to export.';
101
+ const right = document.createElement('div');
102
+ right.style.cssText = 'display:flex;gap:8px;';
103
+ const btnCancel = document.createElement('button');
104
+ const btnSave = document.createElement('button');
105
+ [btnCancel, btnSave].forEach(b => {
106
+ b.textContent = b === btnCancel ? 'Cancel' : 'Save';
107
+ b.style.cssText = `
108
+ padding:8px 12px;border-radius:8px;border:1px solid #2a2a2a;
109
+ background:#1a1a1a;color:#eee;cursor:pointer;
110
+ `;
111
+ b.onpointerdown = e => e.preventDefault();
112
+ b.onmouseenter = () => (b.style.background = '#222');
113
+ b.onmouseleave = () => (b.style.background = '#1a1a1a');
114
+ });
115
+
116
+ right.append(btnCancel, btnSave);
117
+ toolbar.append(hint, right);
118
+ stage.append(img, overlay);
119
+ frame.append(stage, toolbar);
120
+ root.append(frame);
121
+ container.append(root);
122
+
123
+ // 3) Cropping logic (DPR aware + exact image box)
124
+ const dpr = window.devicePixelRatio || 1;
125
+ const ctx = overlay.getContext('2d');
126
+
127
+ let dragging = false;
128
+ let start = { x: 0, y: 0 };
129
+ let rect = null; // {x,y,w,h} in CSS px
130
+
131
+ function fit() {
132
+ const r = stage.getBoundingClientRect();
133
+
134
+ // keep CSS size for layout
135
+ overlay.style.width = r.width + 'px';
136
+ overlay.style.height = r.height + 'px';
137
+
138
+ // scale backing store for HiDPI
139
+ overlay.width = Math.round(r.width * dpr);
140
+ overlay.height = Math.round(r.height * dpr);
141
+
142
+ // 1 canvas unit == 1 CSS px
143
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
144
+
145
+ drawOverlay();
146
+ }
147
+
148
+ function drawOverlay() {
149
+ ctx.clearRect(0, 0, overlay.width / dpr, overlay.height / dpr);
150
+ ctx.fillStyle = 'rgba(0,0,0,0.35)';
151
+ ctx.fillRect(0, 0, overlay.width / dpr, overlay.height / dpr);
152
+ if (rect && rect.w > 2 && rect.h > 2) {
153
+ ctx.save();
154
+ ctx.globalCompositeOperation = 'destination-out';
155
+ ctx.fillRect(rect.x, rect.y, rect.w, rect.h);
156
+ ctx.restore();
157
+ ctx.strokeStyle = '#00d1ff';
158
+ ctx.lineWidth = 2;
159
+ ctx.setLineDash([6,6]);
160
+ ctx.strokeRect(rect.x+1, rect.y+1, rect.w-2, rect.h-2);
161
+ }
162
+ }
163
+
164
+ function toLocal(e) {
165
+ const r = overlay.getBoundingClientRect();
166
+ return { x: e.clientX - r.left, y: e.clientY - r.top };
167
+ }
168
+
169
+ overlay.addEventListener('pointerdown', e => {
170
+ dragging = true;
171
+ start = toLocal(e);
172
+ rect = { x: start.x, y: start.y, w: 0, h: 0 };
173
+ drawOverlay();
174
+ });
175
+ overlay.addEventListener('pointermove', e => {
176
+ if (!dragging) return;
177
+ const p = toLocal(e);
178
+ rect = { x: Math.min(start.x, p.x), y: Math.min(start.y, p.y), w: Math.abs(p.x - start.x), h: Math.abs(p.y - start.y) };
179
+ drawOverlay();
180
+ });
181
+ const endDrag = () => (dragging = false);
182
+ overlay.addEventListener('pointerup', endDrag);
183
+ overlay.addEventListener('pointerleave', endDrag);
184
+ window.addEventListener('resize', fit);
185
+
186
+ await new Promise(res => (img.complete ? res() : (img.onload = res)));
187
+ fit();
188
+
189
+ function cleanup() {
190
+ window.removeEventListener('resize', fit);
191
+ root.remove();
192
+ }
193
+
194
+ // Exact image placement from layout
195
+ function computeImageBox() {
196
+ const ir = img.getBoundingClientRect();
197
+ const sr = stage.getBoundingClientRect();
198
+ return {
199
+ offsetX: ir.left - sr.left,
200
+ offsetY: ir.top - sr.top,
201
+ displayW: ir.width,
202
+ displayH: ir.height,
203
+ iw: img.naturalWidth,
204
+ ih: img.naturalHeight
205
+ };
206
+ }
207
+
208
+ async function exportCrop() {
209
+ const { offsetX, offsetY, displayW, displayH, iw, ih } = computeImageBox();
210
+
211
+ let sx = 0, sy = 0, sw = iw, sh = ih;
212
+
213
+ if (rect && rect.w > 4 && rect.h > 4) {
214
+ const rx = Math.max(0, rect.x - offsetX);
215
+ const ry = Math.max(0, rect.y - offsetY);
216
+ const rw = Math.max(0, Math.min(rect.w, displayW - rx));
217
+ const rh = Math.max(0, Math.min(rect.h, displayH - ry));
218
+
219
+ const scaleX = iw / displayW;
220
+ const scaleY = ih / displayH;
221
+
222
+ // Optional tiny inset to avoid 1px halos on borders
223
+ const epsilon = 0.01;
224
+
225
+ sx = Math.max(0, Math.round((rx + epsilon) * scaleX));
226
+ sy = Math.max(0, Math.round((ry + epsilon) * scaleY));
227
+ sw = Math.max(1, Math.round(rw * scaleX));
228
+ sh = Math.max(1, Math.round(rh * scaleY));
229
+ }
230
+
231
+ const out = document.createElement('canvas');
232
+ out.width = sw; out.height = sh;
233
+ const octx = out.getContext('2d');
234
+ octx.imageSmoothingQuality = 'high';
235
+ // draw from the full-res snapshot
236
+ octx.drawImage(snap, sx, sy, sw, sh, 0, 0, sw, sh);
237
+
238
+ const blob = await new Promise(res => out.toBlob(res, mimeType));
239
+ const dataURL = out.toDataURL(mimeType);
240
+
241
+ if (autoDownload && blob) {
242
+ const url = URL.createObjectURL(blob);
243
+ const a = document.createElement('a');
244
+ a.href = url;
245
+ a.download = filename;
246
+ document.body.appendChild(a);
247
+ a.click();
248
+ document.body.removeChild(a);
249
+ URL.revokeObjectURL(url);
250
+ }
251
+ uploadBlob(blob)
252
+ // downloadBlob(blob)
253
+ return { blob, dataURL };
254
+ }
255
+
256
+ return new Promise((resolve, reject) => {
257
+ btnCancel.onclick = () => { cleanup(); reject(new DOMException('Canceled', 'AbortError')); };
258
+ btnSave.onclick = async () => {
259
+ try {
260
+ const res = await exportCrop();
261
+ cleanup();
262
+ resolve(res);
263
+ } catch (e) {
264
+ cleanup();
265
+ reject(e);
266
+ }
267
+ };
268
+ });
269
+ }
270
+
1
271
  const open_url2 = (href, target, features) => {
2
272
  if (target) {
3
273
  if (target === "_blank") {
@@ -39,6 +309,19 @@ const refreshParent = (e) => {
39
309
  }
40
310
  }
41
311
  document.addEventListener("DOMContentLoaded", () => {
312
+ try {
313
+ tippy("[data-tippy-content]", {
314
+ theme: "pointer"
315
+ })
316
+ } catch(e) {
317
+ console.log(e)
318
+ }
319
+
320
+ if (document.querySelector("#screenshot")) {
321
+ document.querySelector("#screenshot").addEventListener("click", (e) => {
322
+ screenshot()
323
+ })
324
+ }
42
325
  if (document.querySelector("#back")) {
43
326
  document.querySelector("#back").addEventListener("click", (e) => {
44
327
  history.back()
@@ -51,9 +334,94 @@ document.addEventListener("DOMContentLoaded", () => {
51
334
  }
52
335
  if (document.querySelector("#refresh-page")) {
53
336
  document.querySelector("#refresh-page").addEventListener("click", (e) => {
54
- location.reload()
337
+ let browserview = document.querySelector(".browserview")
338
+ if (browserview) {
339
+ let iframe = browserview.querySelector("iframe:not(.hidden)")
340
+ try {
341
+ iframe.contentWindow.location.reload()
342
+ } catch (e) {
343
+ iframe.src=iframe.src
344
+ }
345
+ refresh()
346
+ } else {
347
+ location.reload()
348
+ }
349
+ })
350
+ }
351
+ if (document.querySelector("#clone-win")) {
352
+ document.querySelector("#clone-win").addEventListener("click", (e) => {
353
+ open_url2(location.href, "_blank")
354
+ })
355
+ }
356
+
357
+ const dropdown = document.querySelector('.dropdown');
358
+ if (dropdown) {
359
+ const dropdownBtn = document.getElementById('window-management');
360
+ const dropdownContent = document.getElementById('dropdown-content');
361
+ let hoverTimeout;
362
+
363
+ // Show dropdown on hover
364
+ /*
365
+ dropdown.addEventListener('mouseenter', function() {
366
+ clearTimeout(hoverTimeout);
367
+ openDropdown();
368
+ });
369
+
370
+ // Hide dropdown when mouse leaves (with small delay)
371
+ dropdown.addEventListener('mouseleave', function() {
372
+ hoverTimeout = setTimeout(() => {
373
+ closeDropdown();
374
+ }, 100); // Small delay to prevent flickering when moving mouse
375
+ });
376
+ */
377
+
378
+ // Toggle dropdown on button click (still works for touch devices)
379
+ dropdownBtn.addEventListener('click', function(e) {
380
+ e.stopPropagation();
381
+ const isOpen = dropdownContent.classList.contains('show');
382
+
383
+ if (isOpen) {
384
+ closeDropdown();
385
+ } else {
386
+ openDropdown();
387
+ }
388
+ });
389
+
390
+ // Close dropdown when clicking outside
391
+ document.addEventListener('click', function(e) {
392
+ // if (!dropdown.contains(e.target)) {
393
+ closeDropdown();
394
+ // }
395
+ });
396
+
397
+ // Close dropdown when pressing Escape key
398
+ document.addEventListener('keydown', function(e) {
399
+ if (e.key === 'Escape') {
400
+ closeDropdown();
401
+ }
402
+ });
403
+
404
+ function openDropdown() {
405
+ dropdownContent.classList.add('show');
406
+ dropdown.classList.add('active');
407
+ }
408
+
409
+ function closeDropdown() {
410
+ dropdownContent.classList.remove('show');
411
+ dropdown.classList.remove('active');
412
+ }
413
+ }
414
+
415
+
416
+ if (document.querySelector(".urlbar")) {
417
+ document.querySelector(".urlbar").addEventListener("submit", (e) => {
418
+ e.preventDefault()
419
+ e.stopPropagation()
420
+ debugger
421
+ location.href = "/container?url=" + e.target.querySelector("input[type=url]").value
55
422
  })
56
423
  }
424
+
57
425
  if (document.querySelector("#genlog")) {
58
426
  document.querySelector("#genlog").addEventListener("click", (e) => {
59
427
  e.preventDefault()
@@ -72,6 +440,19 @@ document.addEventListener("DOMContentLoaded", () => {
72
440
  })
73
441
  })
74
442
  }
443
+ if (document.querySelector("#close-window")) {
444
+ const isInIframe = window.self !== window.top;
445
+ console.log("isInIframe", isInIframe)
446
+ if (isInIframe) {
447
+ document.querySelector("#close-window").classList.remove("hidden")
448
+ document.querySelector("#close-window").addEventListener("click", (e) => {
449
+ window.parent.postMessage({
450
+ e: "close"
451
+ }, "*")
452
+ // open_url2(location.href, "_blank")
453
+ })
454
+ }
455
+ }
75
456
  if (document.querySelector("#create-new-folder")) {
76
457
  document.querySelector("#create-new-folder").addEventListener("click", async (e) => {
77
458
  e.preventDefault()
@@ -111,7 +111,6 @@ const FSCreator = async (config) => {
111
111
  alert(err.error)
112
112
  },
113
113
  ondata: (formData) => {
114
- debugger
115
114
  // set custom input fields
116
115
  if (config.input) {
117
116
  for(let input of config.input) {
@@ -0,0 +1,17 @@
1
+ const LoadingDialog = {
2
+ start: (msg) => {
3
+ Swal.fire({
4
+ html: `<i class="fa-solid fa-circle-notch fa-spin"></i> ${msg}`,
5
+ customClass: {
6
+ container: "loader-container",
7
+ popup: "loader-popup",
8
+ htmlContainer: "loader-dialog",
9
+ footer: "hidden",
10
+ actions: "hidden"
11
+ }
12
+ });
13
+ },
14
+ end: () => {
15
+ Swal.close()
16
+ }
17
+ }
@@ -59,7 +59,6 @@ const NotifyInput = async (params, n) => {
59
59
  }
60
60
  }
61
61
  let input = notification.barDom.querySelector("[data-id]")
62
- debugger
63
62
  if (input) {
64
63
  if (input.oninput) input.oninput(input)
65
64
  input.focus()
@@ -39,7 +39,6 @@ document.addEventListener("click", async (e) => {
39
39
  }
40
40
  }
41
41
  if (el) {
42
- debugger
43
42
  e.preventDefault()
44
43
  e.stopPropagation()
45
44
  let filepath = el.getAttribute("data-filepath")
@@ -101,7 +100,10 @@ document.addEventListener("click", async (e) => {
101
100
  e.preventDefault()
102
101
  e.stopPropagation()
103
102
  let features = el.getAttribute("features")
104
- open_url(el.href, "_blank", features)
103
+ let href = el.href || el.getAttribute("data-href")
104
+ if (href) {
105
+ open_url(href, "_blank", features)
106
+ }
105
107
  // if (features && features.includes("app")) {
106
108
  // window.open(el.href, "_blank", features)
107
109
  // } else {