pinokiod 5.1.10 → 5.1.11
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.
- package/kernel/api/fs/download_worker.js +158 -0
- package/kernel/api/fs/index.js +95 -91
- package/kernel/api/index.js +3 -0
- package/kernel/bin/index.js +5 -2
- package/kernel/environment.js +19 -2
- package/kernel/git.js +972 -1
- package/kernel/index.js +65 -30
- package/kernel/peer.js +1 -2
- package/kernel/plugin.js +0 -8
- package/kernel/procs.js +92 -36
- package/kernel/prototype.js +45 -22
- package/kernel/shells.js +30 -6
- package/kernel/sysinfo.js +33 -13
- package/kernel/util.js +61 -24
- package/kernel/workspace_status.js +131 -7
- package/package.json +1 -1
- package/pipe/index.js +1 -1
- package/server/index.js +1169 -350
- package/server/public/create-launcher.js +157 -2
- package/server/public/install.js +135 -41
- package/server/public/style.css +32 -1
- package/server/public/tab-link-popover.js +45 -14
- package/server/public/terminal-settings.js +51 -35
- package/server/public/urldropdown.css +89 -3
- package/server/socket.js +12 -7
- package/server/views/agents.ejs +4 -3
- package/server/views/app.ejs +798 -30
- package/server/views/bootstrap.ejs +2 -1
- package/server/views/checkpoints.ejs +1014 -0
- package/server/views/checkpoints_registry_beta.ejs +260 -0
- package/server/views/columns.ejs +4 -4
- package/server/views/connect.ejs +1 -0
- package/server/views/d.ejs +74 -4
- package/server/views/download.ejs +28 -28
- package/server/views/editor.ejs +4 -5
- package/server/views/env_editor.ejs +1 -1
- package/server/views/file_explorer.ejs +1 -1
- package/server/views/index.ejs +3 -1
- package/server/views/init/index.ejs +2 -1
- package/server/views/install.ejs +2 -1
- package/server/views/net.ejs +9 -7
- package/server/views/network.ejs +15 -14
- package/server/views/pro.ejs +5 -2
- package/server/views/prototype/index.ejs +2 -1
- package/server/views/registry_link.ejs +76 -0
- package/server/views/rows.ejs +4 -4
- package/server/views/screenshots.ejs +1 -0
- package/server/views/settings.ejs +1 -0
- package/server/views/shell.ejs +4 -6
- package/server/views/terminal.ejs +528 -38
- package/server/views/tools.ejs +1 -0
- package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/1764297248545 +0 -45
- package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/1764335557118 +0 -45
- package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/1764335834126 +0 -45
- package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/events +0 -12
- package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/latest +0 -45
|
@@ -185,6 +185,213 @@ body.frozen {
|
|
|
185
185
|
flex-direction: column !important;
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
|
+
.ai-consent-overlay {
|
|
189
|
+
position: fixed;
|
|
190
|
+
inset: 0;
|
|
191
|
+
display: none;
|
|
192
|
+
place-items: center;
|
|
193
|
+
z-index: 2147483000;
|
|
194
|
+
padding: 16px;
|
|
195
|
+
background: rgba(15, 17, 23, 0.52);
|
|
196
|
+
backdrop-filter: blur(10px);
|
|
197
|
+
pointer-events: auto;
|
|
198
|
+
}
|
|
199
|
+
.ai-consent-overlay.is-visible {
|
|
200
|
+
display: grid;
|
|
201
|
+
}
|
|
202
|
+
.ai-consent-modal {
|
|
203
|
+
width: min(520px, 100%);
|
|
204
|
+
background: #fdfdfd;
|
|
205
|
+
color: #0f1117;
|
|
206
|
+
border-radius: 16px;
|
|
207
|
+
border: 1px solid #e8eaf0;
|
|
208
|
+
box-shadow: 0 24px 60px rgba(0, 0, 0, 0.18);
|
|
209
|
+
padding: 22px 22px 18px;
|
|
210
|
+
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", sans-serif;
|
|
211
|
+
animation: ai-pop 160ms ease-out;
|
|
212
|
+
pointer-events: auto;
|
|
213
|
+
}
|
|
214
|
+
.ai-consent-overlay * {
|
|
215
|
+
pointer-events: auto;
|
|
216
|
+
}
|
|
217
|
+
body.dark .ai-consent-modal {
|
|
218
|
+
background: #0f1117;
|
|
219
|
+
color: #eef1f8;
|
|
220
|
+
border-color: rgba(255, 255, 255, 0.1);
|
|
221
|
+
box-shadow: 0 28px 70px rgba(0, 0, 0, 0.5);
|
|
222
|
+
}
|
|
223
|
+
.ai-consent-icon {
|
|
224
|
+
font-size: 28px;
|
|
225
|
+
margin-bottom: 10px;
|
|
226
|
+
}
|
|
227
|
+
.ai-consent-header {
|
|
228
|
+
display: flex;
|
|
229
|
+
align-items: flex-start;
|
|
230
|
+
gap: 12px;
|
|
231
|
+
margin-bottom: 6px;
|
|
232
|
+
}
|
|
233
|
+
.ai-consent-header .ai-consent-text {
|
|
234
|
+
flex: 1;
|
|
235
|
+
}
|
|
236
|
+
.ai-consent-title {
|
|
237
|
+
margin: 0 0 10px;
|
|
238
|
+
font-size: 18px;
|
|
239
|
+
font-weight: 700;
|
|
240
|
+
}
|
|
241
|
+
.ai-consent-list {
|
|
242
|
+
margin: 0 0 14px;
|
|
243
|
+
padding-left: 18px;
|
|
244
|
+
color: #2c3143;
|
|
245
|
+
line-height: 1.5;
|
|
246
|
+
}
|
|
247
|
+
.ai-consent-desc {
|
|
248
|
+
margin: 6px 0 12px;
|
|
249
|
+
font-size: 14px;
|
|
250
|
+
color: #2f3241;
|
|
251
|
+
}
|
|
252
|
+
body.dark .ai-consent-desc {
|
|
253
|
+
color: #cdd5e7;
|
|
254
|
+
}
|
|
255
|
+
.ai-consent-list li {
|
|
256
|
+
margin-bottom: 6px;
|
|
257
|
+
font-size: 14px;
|
|
258
|
+
}
|
|
259
|
+
body.dark .ai-consent-list {
|
|
260
|
+
color: #cdd5e7;
|
|
261
|
+
}
|
|
262
|
+
.ai-consent-remember {
|
|
263
|
+
display: flex;
|
|
264
|
+
align-items: center;
|
|
265
|
+
gap: 8px;
|
|
266
|
+
font-size: 14px;
|
|
267
|
+
color: #232635;
|
|
268
|
+
margin-bottom: 14px;
|
|
269
|
+
}
|
|
270
|
+
body.dark .ai-consent-remember {
|
|
271
|
+
color: #d8def0;
|
|
272
|
+
}
|
|
273
|
+
.ai-consent-actions {
|
|
274
|
+
display: flex;
|
|
275
|
+
justify-content: flex-end;
|
|
276
|
+
gap: 10px;
|
|
277
|
+
}
|
|
278
|
+
.ai-btn-primary,
|
|
279
|
+
.ai-btn-secondary {
|
|
280
|
+
font: 600 14px -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", sans-serif;
|
|
281
|
+
padding: 9px 14px;
|
|
282
|
+
border-radius: 10px;
|
|
283
|
+
border: 1px solid transparent;
|
|
284
|
+
cursor: pointer;
|
|
285
|
+
transition: transform 120ms ease, box-shadow 120ms ease, background 120ms ease;
|
|
286
|
+
}
|
|
287
|
+
.ai-btn-primary {
|
|
288
|
+
background: linear-gradient(135deg, #2b7bff, #5e5df0);
|
|
289
|
+
color: #fff;
|
|
290
|
+
box-shadow: 0 10px 24px rgba(46, 111, 255, 0.25);
|
|
291
|
+
}
|
|
292
|
+
.ai-btn-primary:hover {
|
|
293
|
+
transform: translateY(-1px);
|
|
294
|
+
box-shadow: 0 12px 28px rgba(46, 111, 255, 0.3);
|
|
295
|
+
}
|
|
296
|
+
.ai-btn-secondary {
|
|
297
|
+
background: #f5f7fb;
|
|
298
|
+
color: #0f1117;
|
|
299
|
+
border-color: #d8dbe5;
|
|
300
|
+
}
|
|
301
|
+
.ai-btn-secondary:hover {
|
|
302
|
+
transform: translateY(-1px);
|
|
303
|
+
box-shadow: 0 10px 22px rgba(0, 0, 0, 0.06);
|
|
304
|
+
}
|
|
305
|
+
body.dark .ai-btn-secondary {
|
|
306
|
+
background: rgba(255, 255, 255, 0.08);
|
|
307
|
+
color: #eef1f8;
|
|
308
|
+
border-color: rgba(255, 255, 255, 0.12);
|
|
309
|
+
}
|
|
310
|
+
.ai-consent-manage {
|
|
311
|
+
margin-top: 10px;
|
|
312
|
+
background: none;
|
|
313
|
+
border: none;
|
|
314
|
+
color: #3c6df0;
|
|
315
|
+
font: 600 13px -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", sans-serif;
|
|
316
|
+
cursor: pointer;
|
|
317
|
+
padding: 0;
|
|
318
|
+
}
|
|
319
|
+
body.dark .ai-consent-manage {
|
|
320
|
+
color: #9bb4ff;
|
|
321
|
+
}
|
|
322
|
+
.ai-manage-sheet {
|
|
323
|
+
position: fixed;
|
|
324
|
+
inset: auto 12px 12px auto;
|
|
325
|
+
width: min(360px, 92vw);
|
|
326
|
+
background: #ffffff;
|
|
327
|
+
color: #0f1117;
|
|
328
|
+
border-radius: 14px;
|
|
329
|
+
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.18);
|
|
330
|
+
border: 1px solid #e6e8ee;
|
|
331
|
+
padding: 14px 16px 12px;
|
|
332
|
+
z-index: 2147483001;
|
|
333
|
+
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", sans-serif;
|
|
334
|
+
}
|
|
335
|
+
body.dark .ai-manage-sheet {
|
|
336
|
+
background: #0f1117;
|
|
337
|
+
color: #eef1f8;
|
|
338
|
+
border-color: rgba(255, 255, 255, 0.08);
|
|
339
|
+
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.45);
|
|
340
|
+
}
|
|
341
|
+
.ai-manage-header {
|
|
342
|
+
display: flex;
|
|
343
|
+
justify-content: space-between;
|
|
344
|
+
align-items: center;
|
|
345
|
+
margin-bottom: 10px;
|
|
346
|
+
}
|
|
347
|
+
.ai-manage-header h3 {
|
|
348
|
+
margin: 0;
|
|
349
|
+
font-size: 15px;
|
|
350
|
+
font-weight: 700;
|
|
351
|
+
}
|
|
352
|
+
#ai-manage-close {
|
|
353
|
+
border: none;
|
|
354
|
+
background: none;
|
|
355
|
+
font-size: 20px;
|
|
356
|
+
cursor: pointer;
|
|
357
|
+
color: inherit;
|
|
358
|
+
}
|
|
359
|
+
.ai-manage-list {
|
|
360
|
+
max-height: 240px;
|
|
361
|
+
overflow: auto;
|
|
362
|
+
}
|
|
363
|
+
.ai-manage-item {
|
|
364
|
+
display: flex;
|
|
365
|
+
justify-content: space-between;
|
|
366
|
+
align-items: center;
|
|
367
|
+
padding: 10px 0;
|
|
368
|
+
border-bottom: 1px solid #f0f2f7;
|
|
369
|
+
font-size: 14px;
|
|
370
|
+
}
|
|
371
|
+
body.dark .ai-manage-item {
|
|
372
|
+
border-color: rgba(255, 255, 255, 0.08);
|
|
373
|
+
}
|
|
374
|
+
.ai-manage-item button {
|
|
375
|
+
background: none;
|
|
376
|
+
border: none;
|
|
377
|
+
color: #e14b4b;
|
|
378
|
+
cursor: pointer;
|
|
379
|
+
font-weight: 600;
|
|
380
|
+
}
|
|
381
|
+
.ai-manage-empty {
|
|
382
|
+
padding: 8px 0 4px;
|
|
383
|
+
font-size: 13px;
|
|
384
|
+
opacity: 0.7;
|
|
385
|
+
}
|
|
386
|
+
.ai-manage-footer {
|
|
387
|
+
margin-top: 8px;
|
|
388
|
+
display: flex;
|
|
389
|
+
justify-content: flex-end;
|
|
390
|
+
}
|
|
391
|
+
@keyframes ai-pop {
|
|
392
|
+
from { transform: translateY(8px) scale(0.98); opacity: 0; }
|
|
393
|
+
to { transform: none; opacity: 1; }
|
|
394
|
+
}
|
|
188
395
|
</style>
|
|
189
396
|
<link href="/terminal.css" rel="stylesheet"/>
|
|
190
397
|
<script>
|
|
@@ -278,6 +485,294 @@ const sanitizePreviewLine = (value) => {
|
|
|
278
485
|
: fallbackPreviewSanitizer
|
|
279
486
|
return sanitizer(value || "")
|
|
280
487
|
}
|
|
488
|
+
const formatConsentPath = (value) => {
|
|
489
|
+
if (!value) return "this app folder"
|
|
490
|
+
const normalized = value.replace(/\\/g, "/")
|
|
491
|
+
const marker = "/pinokio/api/"
|
|
492
|
+
const lower = normalized.toLowerCase()
|
|
493
|
+
const idx = lower.lastIndexOf(marker)
|
|
494
|
+
if (idx >= 0) {
|
|
495
|
+
const suffix = normalized.slice(idx + marker.length).replace(/^\/+/, "")
|
|
496
|
+
return `~/pinokio/api/${suffix}`
|
|
497
|
+
}
|
|
498
|
+
if (normalized.startsWith("~")) return normalized
|
|
499
|
+
return normalized
|
|
500
|
+
}
|
|
501
|
+
const getSafeLocalStorage = () => {
|
|
502
|
+
try {
|
|
503
|
+
const store = window.localStorage
|
|
504
|
+
const key = "__aiConsentTest__"
|
|
505
|
+
store.setItem(key, "1")
|
|
506
|
+
store.removeItem(key)
|
|
507
|
+
return store
|
|
508
|
+
} catch (_) {
|
|
509
|
+
return null
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
const createRunControls = () => {
|
|
513
|
+
const container = document.querySelector(".run")
|
|
514
|
+
const play = container ? container.querySelector(".play") : null
|
|
515
|
+
const starting = container ? container.querySelector(".starting") : null
|
|
516
|
+
const stop = container ? container.querySelector(".stop") : null
|
|
517
|
+
const set = (state) => {
|
|
518
|
+
if (!play || !starting || !stop) return
|
|
519
|
+
play.classList.toggle("hidden", state !== "idle")
|
|
520
|
+
starting.classList.toggle("hidden", state !== "starting")
|
|
521
|
+
stop.classList.toggle("hidden", state !== "running")
|
|
522
|
+
}
|
|
523
|
+
return { set }
|
|
524
|
+
}
|
|
525
|
+
const createAiConsentManager = (context = {}) => {
|
|
526
|
+
const storage = getSafeLocalStorage()
|
|
527
|
+
const storageSupported = !!storage
|
|
528
|
+
const PREFIX = "pinokio:ai-consent:"
|
|
529
|
+
const extractCwdFromUri = (uri) => {
|
|
530
|
+
if (!uri || typeof uri !== "string") return ""
|
|
531
|
+
try {
|
|
532
|
+
const url = new URL(uri, window.location.origin)
|
|
533
|
+
const cwd = url.searchParams.get("cwd")
|
|
534
|
+
return cwd || ""
|
|
535
|
+
} catch (_) {
|
|
536
|
+
return ""
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
const normalizeSource = (value) => {
|
|
540
|
+
if (!value || typeof value !== "string") return ""
|
|
541
|
+
return value.trim().replace(/\\/g, "/").replace(/\/+$/, "")
|
|
542
|
+
}
|
|
543
|
+
const source = normalizeSource(context.folder || extractCwdFromUri(context.uri || ""))
|
|
544
|
+
const label = formatConsentPath(source)
|
|
545
|
+
const storageKey = source ? `${PREFIX}${encodeURIComponent(source)}` : null
|
|
546
|
+
const state = { overlay: null, manage: null }
|
|
547
|
+
const guessProviderLabel = () => {
|
|
548
|
+
const raw = (context.uri || "") + " " + (context.folder || "")
|
|
549
|
+
const lower = raw.toLowerCase()
|
|
550
|
+
const pattern = /\/plugin\/([^/]+)\/([^/]+)\/pinokio\.js/
|
|
551
|
+
const match = lower.match(pattern)
|
|
552
|
+
const candidate = match && match[2] ? match[2] : (match && match[1] ? match[1] : "")
|
|
553
|
+
if (!candidate) return ""
|
|
554
|
+
const clean = candidate.replace(/[-_]+/g, " ").trim()
|
|
555
|
+
if (!clean) return ""
|
|
556
|
+
return clean.split(/\s+/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ")
|
|
557
|
+
}
|
|
558
|
+
const providerLabel = guessProviderLabel()
|
|
559
|
+
|
|
560
|
+
const listConsents = () => {
|
|
561
|
+
if (!storageSupported) return []
|
|
562
|
+
const items = []
|
|
563
|
+
for (let i = 0; i < storage.length; i++) {
|
|
564
|
+
const key = storage.key(i)
|
|
565
|
+
if (key && key.startsWith(PREFIX)) {
|
|
566
|
+
const decoded = decodeURIComponent(key.slice(PREFIX.length))
|
|
567
|
+
items.push({
|
|
568
|
+
key,
|
|
569
|
+
path: decoded,
|
|
570
|
+
label: formatConsentPath(decoded),
|
|
571
|
+
})
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
return items.sort((a, b) => a.label.localeCompare(b.label))
|
|
575
|
+
}
|
|
576
|
+
const remember = () => {
|
|
577
|
+
if (!storageSupported || !storageKey) return
|
|
578
|
+
storage.setItem(storageKey, source || "1")
|
|
579
|
+
}
|
|
580
|
+
const revoke = (key) => {
|
|
581
|
+
if (!storageSupported || !key) return
|
|
582
|
+
storage.removeItem(key)
|
|
583
|
+
}
|
|
584
|
+
const isRemembered = () => {
|
|
585
|
+
if (!storageSupported || !storageKey) return false
|
|
586
|
+
return storage.getItem(storageKey) !== null
|
|
587
|
+
}
|
|
588
|
+
const renderManageList = () => {
|
|
589
|
+
if (!state.manage) return
|
|
590
|
+
const listEl = state.manage.querySelector(".ai-manage-list")
|
|
591
|
+
if (!listEl) return
|
|
592
|
+
if (!storageSupported) {
|
|
593
|
+
listEl.innerHTML = `<div class="ai-manage-empty">Browser storage is unavailable, so permissions cannot be saved.</div>`
|
|
594
|
+
return
|
|
595
|
+
}
|
|
596
|
+
const entries = listConsents()
|
|
597
|
+
if (entries.length === 0) {
|
|
598
|
+
listEl.innerHTML = `<div class="ai-manage-empty">No saved permissions.</div>`
|
|
599
|
+
return
|
|
600
|
+
}
|
|
601
|
+
listEl.innerHTML = entries.map((entry) => {
|
|
602
|
+
return `
|
|
603
|
+
<div class="ai-manage-item">
|
|
604
|
+
<div class="ai-manage-path">${entry.label}</div>
|
|
605
|
+
<button type="button" data-ai-revoke="${entry.key}">Revoke</button>
|
|
606
|
+
</div>
|
|
607
|
+
`
|
|
608
|
+
}).join("")
|
|
609
|
+
listEl.querySelectorAll("[data-ai-revoke]").forEach((btn) => {
|
|
610
|
+
btn.addEventListener("click", () => {
|
|
611
|
+
const targetKey = btn.getAttribute("data-ai-revoke")
|
|
612
|
+
revoke(targetKey)
|
|
613
|
+
renderManageList()
|
|
614
|
+
})
|
|
615
|
+
})
|
|
616
|
+
}
|
|
617
|
+
const ensureManageSheet = () => {
|
|
618
|
+
if (state.manage) return state.manage
|
|
619
|
+
const sheet = document.createElement("div")
|
|
620
|
+
sheet.className = "ai-manage-sheet"
|
|
621
|
+
sheet.hidden = true
|
|
622
|
+
sheet.innerHTML = `
|
|
623
|
+
<div class="ai-manage-header">
|
|
624
|
+
<h3>AI permissions</h3>
|
|
625
|
+
<button type="button" id="ai-manage-close">×</button>
|
|
626
|
+
</div>
|
|
627
|
+
<div class="ai-manage-list"></div>
|
|
628
|
+
<div class="ai-manage-footer">
|
|
629
|
+
<button class="ai-btn-secondary" id="ai-manage-clear">Clear all</button>
|
|
630
|
+
</div>
|
|
631
|
+
`
|
|
632
|
+
document.body.appendChild(sheet)
|
|
633
|
+
sheet.querySelector("#ai-manage-close")?.addEventListener("click", () => {
|
|
634
|
+
sheet.hidden = true
|
|
635
|
+
})
|
|
636
|
+
sheet.querySelector("#ai-manage-clear")?.addEventListener("click", () => {
|
|
637
|
+
if (storageSupported) {
|
|
638
|
+
listConsents().forEach((entry) => revoke(entry.key))
|
|
639
|
+
}
|
|
640
|
+
renderManageList()
|
|
641
|
+
})
|
|
642
|
+
state.manage = sheet
|
|
643
|
+
return sheet
|
|
644
|
+
}
|
|
645
|
+
const openManage = () => {
|
|
646
|
+
const sheet = ensureManageSheet()
|
|
647
|
+
renderManageList()
|
|
648
|
+
sheet.hidden = false
|
|
649
|
+
}
|
|
650
|
+
const ensureOverlay = () => {
|
|
651
|
+
if (state.overlay) return state.overlay
|
|
652
|
+
const overlay = document.createElement("div")
|
|
653
|
+
overlay.className = "ai-consent-overlay"
|
|
654
|
+
overlay.style.display = "none"
|
|
655
|
+
overlay.style.pointerEvents = "auto"
|
|
656
|
+
overlay.innerHTML = `
|
|
657
|
+
<div class="ai-consent-modal" role="dialog" aria-modal="true" aria-labelledby="ai-consent-title">
|
|
658
|
+
<div class="ai-consent-header">
|
|
659
|
+
<div class="ai-consent-icon" aria-hidden="true"><i class="fa-solid fa-shield-halved"></i></div>
|
|
660
|
+
<div class="ai-consent-text">
|
|
661
|
+
<h2 class="ai-consent-title" id="ai-consent-title"></h2>
|
|
662
|
+
<p class="ai-consent-desc"></p>
|
|
663
|
+
</div>
|
|
664
|
+
</div>
|
|
665
|
+
<ul class="ai-consent-list">
|
|
666
|
+
<li><strong>Will access:</strong> <span class="ai-consent-scope"></span></li>
|
|
667
|
+
<li><strong>Won't access:</strong> other folders</li>
|
|
668
|
+
</ul>
|
|
669
|
+
<label class="ai-consent-remember">
|
|
670
|
+
<input type="checkbox" id="ai-consent-remember">
|
|
671
|
+
<span class="ai-consent-remember-label"></span>
|
|
672
|
+
</label>
|
|
673
|
+
<div class="ai-consent-actions">
|
|
674
|
+
<button class="ai-btn-secondary" type="button" data-ai-consent-cancel>Cancel</button>
|
|
675
|
+
<button class="ai-btn-primary" type="button" data-ai-consent-next>Next</button>
|
|
676
|
+
</div>
|
|
677
|
+
<button class="ai-consent-manage" type="button" data-ai-consent-manage>Manage permissions</button>
|
|
678
|
+
</div>
|
|
679
|
+
`
|
|
680
|
+
document.body.appendChild(overlay)
|
|
681
|
+
state.overlay = overlay
|
|
682
|
+
return overlay
|
|
683
|
+
}
|
|
684
|
+
const prompt = () => new Promise((resolve) => {
|
|
685
|
+
if (!source) {
|
|
686
|
+
resolve({ allow: true, remember: false })
|
|
687
|
+
return
|
|
688
|
+
}
|
|
689
|
+
const overlay = ensureOverlay()
|
|
690
|
+
const title = overlay.querySelector(".ai-consent-title")
|
|
691
|
+
const desc = overlay.querySelector(".ai-consent-desc")
|
|
692
|
+
const scope = overlay.querySelector(".ai-consent-scope")
|
|
693
|
+
const rememberLabel = overlay.querySelector(".ai-consent-remember-label")
|
|
694
|
+
const rememberBox = overlay.querySelector("#ai-consent-remember")
|
|
695
|
+
const nextBtn = overlay.querySelector("[data-ai-consent-next]")
|
|
696
|
+
const cancelBtn = overlay.querySelector("[data-ai-consent-cancel]")
|
|
697
|
+
const manageBtn = overlay.querySelector("[data-ai-consent-manage]")
|
|
698
|
+
|
|
699
|
+
if (title) title.textContent = "Remote Network Access"
|
|
700
|
+
if (desc) {
|
|
701
|
+
const target = providerLabel || "a remote API"
|
|
702
|
+
desc.textContent = `This script may send files inside ${label} to ${target}.`
|
|
703
|
+
}
|
|
704
|
+
if (scope) scope.textContent = label
|
|
705
|
+
if (rememberLabel) rememberLabel.textContent = `Always allow for ${label}`
|
|
706
|
+
if (rememberBox) {
|
|
707
|
+
rememberBox.checked = storageSupported
|
|
708
|
+
rememberBox.disabled = !storageSupported
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
const close = () => {
|
|
712
|
+
overlay.classList.remove("is-visible")
|
|
713
|
+
setTimeout(() => {
|
|
714
|
+
overlay.style.display = "none"
|
|
715
|
+
}, 150)
|
|
716
|
+
}
|
|
717
|
+
const cleanup = () => {
|
|
718
|
+
nextBtn?.removeEventListener("click", onNext)
|
|
719
|
+
cancelBtn?.removeEventListener("click", onCancel)
|
|
720
|
+
manageBtn?.removeEventListener("click", onManage)
|
|
721
|
+
overlay.removeEventListener("click", onBackdrop)
|
|
722
|
+
}
|
|
723
|
+
const onNext = () => {
|
|
724
|
+
cleanup()
|
|
725
|
+
close()
|
|
726
|
+
const rememberChoice = rememberBox ? rememberBox.checked : false
|
|
727
|
+
resolve({ allow: true, remember: storageSupported && rememberChoice })
|
|
728
|
+
}
|
|
729
|
+
const onCancel = () => {
|
|
730
|
+
cleanup()
|
|
731
|
+
close()
|
|
732
|
+
resolve({ allow: false, remember: false })
|
|
733
|
+
}
|
|
734
|
+
const onManage = (event) => {
|
|
735
|
+
event.preventDefault()
|
|
736
|
+
openManage()
|
|
737
|
+
}
|
|
738
|
+
const onBackdrop = (event) => {
|
|
739
|
+
if (event.target === overlay) {
|
|
740
|
+
onCancel()
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
overlay.style.display = "grid"
|
|
745
|
+
requestAnimationFrame(() => overlay.classList.add("is-visible"))
|
|
746
|
+
|
|
747
|
+
nextBtn?.addEventListener("click", onNext)
|
|
748
|
+
cancelBtn?.addEventListener("click", onCancel)
|
|
749
|
+
manageBtn?.addEventListener("click", onManage)
|
|
750
|
+
overlay.addEventListener("click", onBackdrop)
|
|
751
|
+
if (nextBtn && typeof nextBtn.focus === "function") {
|
|
752
|
+
nextBtn.focus()
|
|
753
|
+
}
|
|
754
|
+
})
|
|
755
|
+
const ensureAllowed = async () => {
|
|
756
|
+
if (!source) return true
|
|
757
|
+
if (isRemembered()) {
|
|
758
|
+
return true
|
|
759
|
+
}
|
|
760
|
+
const result = await prompt()
|
|
761
|
+
if (!result || !result.allow) {
|
|
762
|
+
return false
|
|
763
|
+
}
|
|
764
|
+
if (result.remember) {
|
|
765
|
+
remember()
|
|
766
|
+
}
|
|
767
|
+
return true
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
return {
|
|
771
|
+
ensureAllowed,
|
|
772
|
+
showChipIfRemembered: () => {},
|
|
773
|
+
openManage,
|
|
774
|
+
}
|
|
775
|
+
}
|
|
281
776
|
document.addEventListener("DOMContentLoaded", async () => {
|
|
282
777
|
<% if (error) { %>
|
|
283
778
|
document.querySelector(".requirements .content").innerHTML = '<div class="loading"><i class="fa-solid fa-circle-exclamation"></i> <%=error%></div>'
|
|
@@ -305,6 +800,12 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
305
800
|
const scriptUri = <% if (script_path) { %><%- JSON.stringify(script_path) %><% } else { %>null<% } %>
|
|
306
801
|
const scriptCwd = <% if (cwd) { %><%- JSON.stringify(cwd) %><% } else { %>null<% } %>
|
|
307
802
|
const scriptAction = <% if (typeof action !== 'undefined') { %><%- JSON.stringify(action) %><% } else { %>null<% } %>
|
|
803
|
+
const consentManager = createAiConsentManager({
|
|
804
|
+
folder: scriptCwd,
|
|
805
|
+
uri: scriptUri || ("~" + location.pathname)
|
|
806
|
+
})
|
|
807
|
+
const runControls = createRunControls()
|
|
808
|
+
consentManager.showChipIfRemembered()
|
|
308
809
|
class RPC {
|
|
309
810
|
constructor() {
|
|
310
811
|
this.socket = new Socket()
|
|
@@ -392,9 +893,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
392
893
|
text: `[Success] All steps complete`,
|
|
393
894
|
})
|
|
394
895
|
*/
|
|
395
|
-
|
|
396
|
-
document.querySelector(".run .stop").classList.add("hidden")
|
|
397
|
-
document.querySelector(".run .starting").classList.add("hidden")
|
|
896
|
+
runControls.set("idle")
|
|
398
897
|
}
|
|
399
898
|
stop() {
|
|
400
899
|
const params = {
|
|
@@ -436,10 +935,9 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
436
935
|
})
|
|
437
936
|
})
|
|
438
937
|
}
|
|
439
|
-
start(mode) {
|
|
440
|
-
return new Promise(async (resolve, reject) => {
|
|
938
|
+
async start(mode) {
|
|
441
939
|
// await this.save()
|
|
442
|
-
|
|
940
|
+
this.socket.close()
|
|
443
941
|
|
|
444
942
|
const searchParams = new URLSearchParams(location.search)
|
|
445
943
|
const query = Object.fromEntries(searchParams)
|
|
@@ -474,9 +972,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
474
972
|
if (packet.type === 'start') {
|
|
475
973
|
refreshParent(packet)
|
|
476
974
|
reloadMemory()
|
|
477
|
-
|
|
478
|
-
document.querySelector(".run .starting").classList.add("hidden")
|
|
479
|
-
document.querySelector(".run .stop").classList.remove("hidden")
|
|
975
|
+
runControls.set("running")
|
|
480
976
|
if (packet.data && packet.data.description) {
|
|
481
977
|
if ('current' in packet.data) {
|
|
482
978
|
document.querySelector("#status-window").innerHTML = `<b>
|
|
@@ -527,17 +1023,14 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
527
1023
|
document.querySelector("#progress-window").classList.add("hidden")
|
|
528
1024
|
document.querySelector("#progress-bar").style.width = "0%"
|
|
529
1025
|
}
|
|
530
|
-
|
|
531
|
-
document.querySelector(".run .starting").classList.add("hidden")
|
|
532
|
-
document.querySelector(".run .stop").classList.remove("hidden")
|
|
1026
|
+
runControls.set("running")
|
|
533
1027
|
} else if (packet.type === 'disconnect') {
|
|
534
1028
|
refreshParent(packet)
|
|
535
1029
|
reloadMemory()
|
|
536
1030
|
this.term.write("\r\nDisconnected...\r\n")
|
|
537
1031
|
document.querySelector("#status-window").innerHTML = "<b>Ready</b>"
|
|
538
1032
|
this.socket.close()
|
|
539
|
-
|
|
540
|
-
document.querySelector(".run .stop").classList.add("hidden")
|
|
1033
|
+
runControls.set("idle")
|
|
541
1034
|
this.resizeSync.reset()
|
|
542
1035
|
|
|
543
1036
|
<% if (kill_message) { %>
|
|
@@ -629,9 +1122,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
629
1122
|
})
|
|
630
1123
|
}
|
|
631
1124
|
*/
|
|
632
|
-
|
|
633
|
-
document.querySelector(".run .starting").classList.add("hidden")
|
|
634
|
-
document.querySelector(".run .stop").classList.remove("hidden")
|
|
1125
|
+
runControls.set("running")
|
|
635
1126
|
} else if (packet.type === 'resize') {
|
|
636
1127
|
this.resizeSync.handleResizePacket(packet)
|
|
637
1128
|
// } else if (packet.type === "key.set") {
|
|
@@ -869,9 +1360,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
869
1360
|
text: `${packet.data}`,
|
|
870
1361
|
})
|
|
871
1362
|
} else if (packet.type === "error") {
|
|
872
|
-
|
|
873
|
-
document.querySelector(".run .starting").classList.add("hidden")
|
|
874
|
-
document.querySelector(".run .stop").classList.add("hidden")
|
|
1363
|
+
runControls.set("idle")
|
|
875
1364
|
|
|
876
1365
|
|
|
877
1366
|
document.querySelector("#error-screen").classList.remove("hidden")
|
|
@@ -942,9 +1431,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
942
1431
|
type: 'success'
|
|
943
1432
|
})
|
|
944
1433
|
*/
|
|
945
|
-
|
|
946
|
-
document.querySelector(".run .starting").classList.add("hidden")
|
|
947
|
-
document.querySelector(".run .stop").classList.add("hidden")
|
|
1434
|
+
runControls.set("idle")
|
|
948
1435
|
}, 0)
|
|
949
1436
|
//this.socket.close()
|
|
950
1437
|
}
|
|
@@ -967,10 +1454,20 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
967
1454
|
// let pageBottom = document.querySelector("#end")
|
|
968
1455
|
// pageBottom.scrollIntoView()
|
|
969
1456
|
})
|
|
970
|
-
})
|
|
971
1457
|
}
|
|
972
1458
|
async run (mode) {
|
|
973
1459
|
this.mode = (mode ? mode : "run")
|
|
1460
|
+
const allowed = await consentManager.ensureAllowed()
|
|
1461
|
+
if (!allowed) {
|
|
1462
|
+
runControls.set("idle")
|
|
1463
|
+
n.Noty({
|
|
1464
|
+
text: "Run canceled; AI agents remain blocked for this folder.",
|
|
1465
|
+
type: "warning",
|
|
1466
|
+
timeout: 4000
|
|
1467
|
+
})
|
|
1468
|
+
return false
|
|
1469
|
+
}
|
|
1470
|
+
runControls.set("starting")
|
|
974
1471
|
|
|
975
1472
|
// if (dirty) {
|
|
976
1473
|
// await this.save()
|
|
@@ -985,6 +1482,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
985
1482
|
await this.createTerm(xtermTheme.Tomorrow)
|
|
986
1483
|
<% } %>
|
|
987
1484
|
await this.start(mode)
|
|
1485
|
+
return true
|
|
988
1486
|
}
|
|
989
1487
|
async uploadFiles(files, overlay) {
|
|
990
1488
|
const localFiles = Array.isArray(files) ? files : []
|
|
@@ -1294,8 +1792,8 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1294
1792
|
<% } %>
|
|
1295
1793
|
let config = {
|
|
1296
1794
|
scrollback: 9999999,
|
|
1297
|
-
fontSize:
|
|
1298
|
-
|
|
1795
|
+
fontSize: 14,
|
|
1796
|
+
fontFamily: 'monospace',
|
|
1299
1797
|
theme,
|
|
1300
1798
|
//theme: xtermTheme.FrontEndDelight
|
|
1301
1799
|
//theme: xtermTheme.Afterglow
|
|
@@ -1769,15 +2267,11 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1769
2267
|
// }, (stream) => {
|
|
1770
2268
|
// console.log("#", stream)
|
|
1771
2269
|
// })
|
|
1772
|
-
|
|
1773
|
-
document.querySelector(".run .starting").classList.add("hidden")
|
|
1774
|
-
document.querySelector(".run .stop").classList.add("hidden")
|
|
2270
|
+
runControls.set("idle")
|
|
1775
2271
|
})
|
|
1776
2272
|
}
|
|
1777
2273
|
if (document.querySelector(".play")) {
|
|
1778
2274
|
document.querySelector(".play").addEventListener("click", async (e) => {
|
|
1779
|
-
document.querySelector(".run .play").classList.add("hidden")
|
|
1780
|
-
document.querySelector(".run .starting").classList.remove("hidden")
|
|
1781
2275
|
await rpc.run()
|
|
1782
2276
|
})
|
|
1783
2277
|
}
|
|
@@ -1785,17 +2279,13 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1785
2279
|
|
|
1786
2280
|
<% if (stop) { %>
|
|
1787
2281
|
await rpc.stop()
|
|
1788
|
-
|
|
1789
|
-
document.querySelector(".run .starting").classList.add("hidden")
|
|
1790
|
-
document.querySelector(".run .stop").classList.add("hidden")
|
|
2282
|
+
runControls.set("idle")
|
|
1791
2283
|
<% } else { %>
|
|
1792
2284
|
<% if (run) { %>
|
|
1793
2285
|
// run (query params run=true)
|
|
1794
|
-
|
|
1795
|
-
document.querySelector(".run .starting").classList.remove("hidden")
|
|
1796
|
-
rpc.run()
|
|
2286
|
+
await rpc.run()
|
|
1797
2287
|
<% } else { %>
|
|
1798
|
-
rpc.run("listen")
|
|
2288
|
+
await rpc.run("listen")
|
|
1799
2289
|
<% } %>
|
|
1800
2290
|
<% } %>
|
|
1801
2291
|
<% } %>
|
package/server/views/tools.ejs
CHANGED
|
@@ -1280,6 +1280,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
1280
1280
|
<a href="/connect" class='tab'><i class="fa-solid fa-plug"></i><div class='caption'>Login</div></a>
|
|
1281
1281
|
<a class='tab' href="<%=portal%>" target="_blank"><i class="fa-solid fa-question"></i><div class='caption'>Help</div></a>
|
|
1282
1282
|
<a class='tab' id='genlog' href="/logs"><i class="fa-solid fa-laptop-code"></i><div class='caption'>Logs</div></a>
|
|
1283
|
+
<a class='tab' href="/checkpoints"><i class="fa-solid fa-clock-rotate-left"></i><div class='caption'>Checkpoints</div></a>
|
|
1283
1284
|
<a class='tab' href="/screenshots"><i class="fa-solid fa-camera"></i><div class='caption'>Screenshots</div></a>
|
|
1284
1285
|
<a class='tab selected' href="/tools"><i class="fa-solid fa-toolbox"></i><div class='caption'>Installed Tools</div></a>
|
|
1285
1286
|
<a class='tab' href="/agents"><i class="fa-solid fa-robot"></i><div class='caption'>Agents</div></a>
|