pinokiod 3.271.0 → 3.273.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.
- package/kernel/ansi_stream_tracker.js +115 -0
- package/kernel/api/app/index.js +422 -0
- package/kernel/api/htmlmodal/index.js +94 -0
- package/kernel/app_launcher/index.js +115 -0
- package/kernel/app_launcher/platform/base.js +276 -0
- package/kernel/app_launcher/platform/linux.js +229 -0
- package/kernel/app_launcher/platform/macos.js +163 -0
- package/kernel/app_launcher/platform/unsupported.js +34 -0
- package/kernel/app_launcher/platform/windows.js +247 -0
- package/kernel/bin/conda-meta.js +93 -0
- package/kernel/bin/conda.js +2 -4
- package/kernel/bin/index.js +2 -4
- package/kernel/index.js +7 -0
- package/kernel/shell.js +212 -1
- package/package.json +1 -1
- package/server/index.js +491 -6
- package/server/public/common.js +224 -741
- package/server/public/create-launcher.js +754 -0
- package/server/public/htmlmodal.js +292 -0
- package/server/public/logs.js +715 -0
- package/server/public/resizeSync.js +117 -0
- package/server/public/style.css +653 -8
- package/server/public/tab-idle-notifier.js +34 -59
- package/server/public/tab-link-popover.js +7 -10
- package/server/public/terminal-settings.js +723 -9
- package/server/public/terminal_input_utils.js +72 -0
- package/server/public/terminal_key_caption.js +187 -0
- package/server/public/urldropdown.css +120 -3
- package/server/public/xterm-inline-bridge.js +116 -0
- package/server/socket.js +29 -0
- package/server/views/agents.ejs +1 -2
- package/server/views/app.ejs +55 -28
- package/server/views/bookmarklet.ejs +1 -1
- package/server/views/bootstrap.ejs +1 -0
- package/server/views/connect.ejs +1 -2
- package/server/views/create.ejs +63 -0
- package/server/views/editor.ejs +36 -4
- package/server/views/index.ejs +1 -2
- package/server/views/index2.ejs +1 -2
- package/server/views/init/index.ejs +36 -28
- package/server/views/install.ejs +20 -22
- package/server/views/layout.ejs +2 -8
- package/server/views/logs.ejs +155 -0
- package/server/views/mini.ejs +0 -18
- package/server/views/net.ejs +2 -2
- package/server/views/network.ejs +1 -2
- package/server/views/network2.ejs +1 -2
- package/server/views/old_network.ejs +1 -2
- package/server/views/pro.ejs +26 -23
- package/server/views/prototype/index.ejs +30 -34
- package/server/views/screenshots.ejs +1 -2
- package/server/views/settings.ejs +1 -20
- package/server/views/shell.ejs +59 -66
- package/server/views/terminal.ejs +118 -73
- package/server/views/tools.ejs +1 -2
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
(function (global) {
|
|
2
|
+
function processTerminalInputData(data, handlers) {
|
|
3
|
+
if (!data || typeof data !== 'string' || !handlers) {
|
|
4
|
+
return
|
|
5
|
+
}
|
|
6
|
+
const capture = typeof handlers.capture === 'function' ? handlers.capture : function () {}
|
|
7
|
+
const handleBackspace = typeof handlers.backspace === 'function' ? handlers.backspace : function () {}
|
|
8
|
+
const resetBuffer = typeof handlers.reset === 'function' ? handlers.reset : function () {}
|
|
9
|
+
|
|
10
|
+
let printable = ''
|
|
11
|
+
let lastWasCR = false
|
|
12
|
+
const flush = () => {
|
|
13
|
+
if (printable) {
|
|
14
|
+
capture(printable)
|
|
15
|
+
printable = ''
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
for (let i = 0; i < data.length; i++) {
|
|
20
|
+
const ch = data[i]
|
|
21
|
+
if (ch === '\u0008' || ch === '\u007f') { // backspace / DEL
|
|
22
|
+
flush()
|
|
23
|
+
handleBackspace()
|
|
24
|
+
lastWasCR = false
|
|
25
|
+
continue
|
|
26
|
+
}
|
|
27
|
+
if (ch === '\r') {
|
|
28
|
+
flush()
|
|
29
|
+
capture('\n')
|
|
30
|
+
lastWasCR = true
|
|
31
|
+
continue
|
|
32
|
+
}
|
|
33
|
+
if (ch === '\n') {
|
|
34
|
+
if (lastWasCR) {
|
|
35
|
+
lastWasCR = false
|
|
36
|
+
continue
|
|
37
|
+
}
|
|
38
|
+
flush()
|
|
39
|
+
capture('\n')
|
|
40
|
+
lastWasCR = false
|
|
41
|
+
continue
|
|
42
|
+
}
|
|
43
|
+
if (ch === '\t') {
|
|
44
|
+
flush()
|
|
45
|
+
capture('\t')
|
|
46
|
+
lastWasCR = false
|
|
47
|
+
continue
|
|
48
|
+
}
|
|
49
|
+
if (ch === '\u001b') { // ESC
|
|
50
|
+
flush()
|
|
51
|
+
if (data.length === 1) {
|
|
52
|
+
resetBuffer()
|
|
53
|
+
}
|
|
54
|
+
lastWasCR = false
|
|
55
|
+
continue
|
|
56
|
+
}
|
|
57
|
+
if (ch === '\u0015' || ch === '\u0017' || ch === '\u000b' || ch === '\u0003') {
|
|
58
|
+
flush()
|
|
59
|
+
resetBuffer()
|
|
60
|
+
lastWasCR = false
|
|
61
|
+
continue
|
|
62
|
+
}
|
|
63
|
+
if (ch >= ' ') {
|
|
64
|
+
printable += ch
|
|
65
|
+
}
|
|
66
|
+
lastWasCR = false
|
|
67
|
+
}
|
|
68
|
+
flush()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
global.processTerminalInputData = processTerminalInputData
|
|
72
|
+
})(typeof window !== 'undefined' ? window : this)
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
(function (global) {
|
|
2
|
+
const DEFAULT_LIMIT = 512
|
|
3
|
+
const NAVIGATION_KEYS = new Set([
|
|
4
|
+
'ArrowUp',
|
|
5
|
+
'ArrowDown',
|
|
6
|
+
'ArrowLeft',
|
|
7
|
+
'ArrowRight',
|
|
8
|
+
'Home',
|
|
9
|
+
'End',
|
|
10
|
+
'PageUp',
|
|
11
|
+
'PageDown',
|
|
12
|
+
'Insert'
|
|
13
|
+
])
|
|
14
|
+
|
|
15
|
+
class TabCaptionHelper {
|
|
16
|
+
constructor(term, options = {}) {
|
|
17
|
+
this.term = term
|
|
18
|
+
this.tracker = options.tracker || null
|
|
19
|
+
this.limit = Number.isFinite(options.maxBuffer) && options.maxBuffer > 0 ? options.maxBuffer : DEFAULT_LIMIT
|
|
20
|
+
this.buffer = ''
|
|
21
|
+
this.pendingLine = null
|
|
22
|
+
this.keyListener = null
|
|
23
|
+
this.restoreSubmit = null
|
|
24
|
+
this.install()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
install() {
|
|
28
|
+
this.attachKeyListener()
|
|
29
|
+
this.patchTracker()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
attachKeyListener() {
|
|
33
|
+
if (!this.term || typeof this.term.onKey !== 'function') {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
const disposable = this.term.onKey((event) => {
|
|
37
|
+
this.handleKeyEvent(event)
|
|
38
|
+
})
|
|
39
|
+
if (disposable && typeof disposable.dispose === 'function') {
|
|
40
|
+
this.keyListener = () => {
|
|
41
|
+
disposable.dispose()
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
patchTracker() {
|
|
47
|
+
if (!this.tracker || typeof this.tracker.submit !== 'function') {
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
const originalSubmit = this.tracker.submit
|
|
51
|
+
const helper = this
|
|
52
|
+
this.tracker.submit = function helperSubmit(line, meta) {
|
|
53
|
+
const override = helper.consumePendingLine()
|
|
54
|
+
if (typeof override === 'string') {
|
|
55
|
+
return originalSubmit.call(this, override, meta)
|
|
56
|
+
}
|
|
57
|
+
return originalSubmit.call(this, line, meta)
|
|
58
|
+
}
|
|
59
|
+
this.restoreSubmit = () => {
|
|
60
|
+
this.tracker.submit = originalSubmit
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
consumePendingLine() {
|
|
65
|
+
if (this.pendingLine !== null) {
|
|
66
|
+
const next = this.pendingLine
|
|
67
|
+
this.pendingLine = null
|
|
68
|
+
return next
|
|
69
|
+
}
|
|
70
|
+
return null
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
handleKeyEvent(event) {
|
|
74
|
+
if (!event || !event.domEvent) {
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
const domEvent = event.domEvent
|
|
78
|
+
const key = domEvent.key
|
|
79
|
+
if (!key) {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
if (domEvent.isComposing) {
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
if (key === 'Enter') {
|
|
86
|
+
this.commitBuffer()
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
if (key === 'Backspace') {
|
|
90
|
+
this.applyBackspace()
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
if (key === 'Escape') {
|
|
94
|
+
this.resetBuffer()
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
if (domEvent.ctrlKey || domEvent.metaKey) {
|
|
98
|
+
this.handleModifierCombo(key)
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
if (NAVIGATION_KEYS.has(key) || key === 'Tab') {
|
|
102
|
+
this.resetBuffer()
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
if (this.isPrintable(domEvent)) {
|
|
106
|
+
this.appendCharacter(domEvent.key)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
handleModifierCombo(key) {
|
|
111
|
+
const lower = typeof key === 'string' ? key.toLowerCase() : ''
|
|
112
|
+
if (!lower) {
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
if (lower === 'c' || lower === 'd' || lower === 'l') {
|
|
116
|
+
this.resetBuffer()
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
if (lower === 'u' || lower === 'w' || lower === 'k') {
|
|
120
|
+
this.resetBuffer()
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
isPrintable(domEvent) {
|
|
125
|
+
if (!domEvent || typeof domEvent.key !== 'string') {
|
|
126
|
+
return false
|
|
127
|
+
}
|
|
128
|
+
if (domEvent.ctrlKey || domEvent.metaKey) {
|
|
129
|
+
return false
|
|
130
|
+
}
|
|
131
|
+
if (domEvent.altKey && domEvent.key.length !== 1) {
|
|
132
|
+
return false
|
|
133
|
+
}
|
|
134
|
+
return domEvent.key.length === 1
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
appendCharacter(char) {
|
|
138
|
+
if (typeof char !== 'string' || char.length === 0) {
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
if (this.buffer.length >= this.limit) {
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
this.buffer += char
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
applyBackspace() {
|
|
148
|
+
if (!this.buffer) {
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
this.buffer = this.buffer.slice(0, -1)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
commitBuffer() {
|
|
155
|
+
this.pendingLine = this.buffer
|
|
156
|
+
this.buffer = ''
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
resetBuffer() {
|
|
160
|
+
this.buffer = ''
|
|
161
|
+
this.pendingLine = null
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
dispose() {
|
|
165
|
+
if (this.keyListener) {
|
|
166
|
+
this.keyListener()
|
|
167
|
+
this.keyListener = null
|
|
168
|
+
}
|
|
169
|
+
if (this.restoreSubmit) {
|
|
170
|
+
this.restoreSubmit()
|
|
171
|
+
this.restoreSubmit = null
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function attach(term, options) {
|
|
177
|
+
if (!term) {
|
|
178
|
+
return null
|
|
179
|
+
}
|
|
180
|
+
return new TabCaptionHelper(term, options || {})
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
global.PinokioTabCaptionHelper = {
|
|
184
|
+
attach,
|
|
185
|
+
Helper: TabCaptionHelper
|
|
186
|
+
}
|
|
187
|
+
})(typeof window !== 'undefined' ? window : this)
|
|
@@ -184,7 +184,8 @@ body.dark .url-dropdown-empty-description {
|
|
|
184
184
|
-webkit-backdrop-filter: blur(14px);
|
|
185
185
|
backdrop-filter: blur(14px);
|
|
186
186
|
}
|
|
187
|
-
.create-launcher-modal
|
|
187
|
+
.create-launcher-modal,
|
|
188
|
+
.create-launcher-page-card {
|
|
188
189
|
background: rgba(255, 255, 255, 0.86);
|
|
189
190
|
border: 1px solid rgba(15, 23, 42, 0.08);
|
|
190
191
|
border-radius: 20px;
|
|
@@ -202,7 +203,8 @@ body.dark .url-dropdown-empty-description {
|
|
|
202
203
|
backdrop-filter: blur(28px);
|
|
203
204
|
position: relative;
|
|
204
205
|
}
|
|
205
|
-
body.dark .create-launcher-modal
|
|
206
|
+
body.dark .create-launcher-modal,
|
|
207
|
+
body.dark .create-launcher-page-card {
|
|
206
208
|
background: rgba(17, 24, 39, 0.82);
|
|
207
209
|
border: 1px solid rgba(148, 163, 184, 0.22);
|
|
208
210
|
color: rgba(226, 232, 240, 0.96);
|
|
@@ -267,7 +269,8 @@ body.dark .create-launcher-modal-close:hover {
|
|
|
267
269
|
flex-direction: column;
|
|
268
270
|
gap: 6px;
|
|
269
271
|
}
|
|
270
|
-
.create-launcher-modal h3
|
|
272
|
+
.create-launcher-modal h3,
|
|
273
|
+
.create-launcher-page-card h3 {
|
|
271
274
|
margin: 0;
|
|
272
275
|
font-size: 24px;
|
|
273
276
|
font-weight: 600;
|
|
@@ -616,6 +619,9 @@ body.dark .create-launcher-modal-button.confirm {
|
|
|
616
619
|
margin-top: 6px;
|
|
617
620
|
font-size: 13px;
|
|
618
621
|
}
|
|
622
|
+
.create-launcher-modal-links .create-launcher-modal-bookmarklet {
|
|
623
|
+
margin-left: 8px;
|
|
624
|
+
}
|
|
619
625
|
.create-launcher-modal-advanced {
|
|
620
626
|
display: inline-flex;
|
|
621
627
|
align-items: center;
|
|
@@ -648,6 +654,27 @@ body.dark .create-launcher-modal-advanced.secondary {
|
|
|
648
654
|
body.dark .create-launcher-modal-advanced.secondary:hover {
|
|
649
655
|
color: rgba(226, 232, 240, 0.98);
|
|
650
656
|
}
|
|
657
|
+
.create-launcher-modal-bookmarklet {
|
|
658
|
+
font-size: 13px;
|
|
659
|
+
font-weight: 600;
|
|
660
|
+
text-transform: uppercase;
|
|
661
|
+
letter-spacing: 0.08em;
|
|
662
|
+
color: rgba(127, 91, 243, 0.95);
|
|
663
|
+
text-decoration: underline;
|
|
664
|
+
transition: color 0.2s ease;
|
|
665
|
+
}
|
|
666
|
+
.create-launcher-modal-bookmarklet:hover,
|
|
667
|
+
.create-launcher-modal-bookmarklet:focus-visible {
|
|
668
|
+
color: rgba(84, 63, 196, 1);
|
|
669
|
+
text-decoration: underline;
|
|
670
|
+
}
|
|
671
|
+
body.dark .create-launcher-modal-bookmarklet {
|
|
672
|
+
color: rgba(183, 161, 255, 0.95);
|
|
673
|
+
}
|
|
674
|
+
body.dark .create-launcher-modal-bookmarklet:hover,
|
|
675
|
+
body.dark .create-launcher-modal-bookmarklet:focus-visible {
|
|
676
|
+
color: rgba(225, 213, 255, 0.98);
|
|
677
|
+
}
|
|
651
678
|
@media (max-width: 640px) {
|
|
652
679
|
.modal-overlay {
|
|
653
680
|
padding: 16px;
|
|
@@ -686,6 +713,96 @@ body.dark .create-launcher-modal-advanced.secondary:hover {
|
|
|
686
713
|
width: 100%;
|
|
687
714
|
}
|
|
688
715
|
}
|
|
716
|
+
.create-page {
|
|
717
|
+
max-width: 960px;
|
|
718
|
+
margin: 0 auto;
|
|
719
|
+
padding: 30px 20px 80px;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
.create-page-hero {
|
|
723
|
+
border: 1px solid rgba(0, 0, 0, 0.05);
|
|
724
|
+
border-radius: 24px;
|
|
725
|
+
padding: 32px;
|
|
726
|
+
background: rgba(0, 0, 0, 0.01);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
body.dark .create-page-hero {
|
|
730
|
+
background: rgba(255, 255, 255, 0.02);
|
|
731
|
+
border-color: rgba(255, 255, 255, 0.05);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
.create-page-hero .eyebrow {
|
|
735
|
+
text-transform: uppercase;
|
|
736
|
+
letter-spacing: 0.08em;
|
|
737
|
+
font-size: 12px;
|
|
738
|
+
margin: 0 0 8px;
|
|
739
|
+
color: rgba(0, 0, 0, 0.6);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
body.dark .create-page-hero .eyebrow {
|
|
743
|
+
color: rgba(255, 255, 255, 0.6);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
.create-page-hero h1 {
|
|
747
|
+
margin: 0 0 12px;
|
|
748
|
+
font-size: 32px;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
.create-page-hero .subtitle {
|
|
752
|
+
margin: 0;
|
|
753
|
+
font-size: 16px;
|
|
754
|
+
color: rgba(0, 0, 0, 0.7);
|
|
755
|
+
max-width: 640px;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
body.dark .create-page-hero .subtitle {
|
|
759
|
+
color: rgba(255, 255, 255, 0.7);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
.create-page-root {
|
|
763
|
+
margin-top: 28px;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
.create-launcher-page-card {
|
|
767
|
+
width: min(720px, 100%);
|
|
768
|
+
margin: 0 auto;
|
|
769
|
+
max-height: none;
|
|
770
|
+
overflow: visible;
|
|
771
|
+
padding: 32px;
|
|
772
|
+
border-radius: 26px;
|
|
773
|
+
background: #fff;
|
|
774
|
+
border: 1px solid rgba(15, 23, 42, 0.06);
|
|
775
|
+
box-shadow: 0 20px 65px rgba(15, 15, 15, 0.08);
|
|
776
|
+
-webkit-backdrop-filter: none;
|
|
777
|
+
backdrop-filter: none;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
body.dark .create-launcher-page-card {
|
|
781
|
+
background: rgba(17, 24, 39, 0.92);
|
|
782
|
+
border-color: rgba(148, 163, 184, 0.15);
|
|
783
|
+
box-shadow: 0 22px 55px rgba(0, 0, 0, 0.55);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.create-launcher-page-card .create-launcher-modal-links {
|
|
787
|
+
justify-content: space-between;
|
|
788
|
+
flex-wrap: wrap;
|
|
789
|
+
gap: 12px;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
.create-launcher-page-card .create-launcher-modal-button.cancel {
|
|
793
|
+
display: none;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
@media (max-width: 720px) {
|
|
797
|
+
.create-page {
|
|
798
|
+
padding: 20px 12px 60px;
|
|
799
|
+
}
|
|
800
|
+
.create-launcher-page-card {
|
|
801
|
+
padding: 24px;
|
|
802
|
+
border-radius: 18px;
|
|
803
|
+
width: 100%;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
689
806
|
.capture-modal-overlay {
|
|
690
807
|
background: rgba(15, 23, 42, 0.45);
|
|
691
808
|
-webkit-backdrop-filter: blur(16px);
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
if (typeof window === 'undefined' || window.PinokioInlineBridgeInitialized) {
|
|
3
|
+
return;
|
|
4
|
+
}
|
|
5
|
+
const isStandaloneMobile = () => {
|
|
6
|
+
try {
|
|
7
|
+
if (window.top !== window.self) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
} catch (_) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
const ua = (navigator.userAgent || '').toLowerCase();
|
|
14
|
+
return /iphone|ipad|ipod|android|mobile/.test(ua);
|
|
15
|
+
};
|
|
16
|
+
if (!isStandaloneMobile()) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
window.PinokioInlineBridgeInitialized = true;
|
|
20
|
+
|
|
21
|
+
const ensureFrameName = () => {
|
|
22
|
+
if (typeof window.name === 'string' && window.name.trim()) {
|
|
23
|
+
return window.name;
|
|
24
|
+
}
|
|
25
|
+
const generated = `inline-${Date.now()}`;
|
|
26
|
+
window.name = generated;
|
|
27
|
+
return generated;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const createFrameLink = (frameName) => {
|
|
31
|
+
const existing = document.querySelector('.frame-link.pinokio-inline');
|
|
32
|
+
if (existing) {
|
|
33
|
+
return existing;
|
|
34
|
+
}
|
|
35
|
+
const link = document.createElement('div');
|
|
36
|
+
link.className = 'frame-link pinokio-inline';
|
|
37
|
+
link.setAttribute('target', frameName);
|
|
38
|
+
link.dataset.canNotify = 'true';
|
|
39
|
+
link.style.display = 'none';
|
|
40
|
+
link.innerHTML = `
|
|
41
|
+
<div class="tab">
|
|
42
|
+
<div class="tab-main">
|
|
43
|
+
<div class="tab-details">
|
|
44
|
+
<div class="tab-updated">
|
|
45
|
+
<span class="indicator">
|
|
46
|
+
<span class="dot"></span>
|
|
47
|
+
<span class="label"></span>
|
|
48
|
+
</span>
|
|
49
|
+
</div>
|
|
50
|
+
<div class="tab-preview"></div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
`;
|
|
55
|
+
document.body.appendChild(link);
|
|
56
|
+
return link;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const init = () => {
|
|
60
|
+
const frameName = ensureFrameName();
|
|
61
|
+
const link = createFrameLink(frameName);
|
|
62
|
+
if (!link) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
window.PinokioInlineIdle = true;
|
|
66
|
+
const indicator = link.querySelector('.tab-updated');
|
|
67
|
+
const label = indicator ? indicator.querySelector('.label') : null;
|
|
68
|
+
const preview = link.querySelector('.tab-preview');
|
|
69
|
+
const updateIndicator = (text, hasContent) => {
|
|
70
|
+
if (preview) {
|
|
71
|
+
preview.textContent = hasContent ? text : '';
|
|
72
|
+
}
|
|
73
|
+
const now = Date.now();
|
|
74
|
+
indicator.dataset.timestamp = String(now);
|
|
75
|
+
indicator.classList.add('is-live');
|
|
76
|
+
if (label) {
|
|
77
|
+
label.textContent = 'live';
|
|
78
|
+
}
|
|
79
|
+
clearTimeout(updateIndicator._timer);
|
|
80
|
+
updateIndicator._timer = setTimeout(() => {
|
|
81
|
+
indicator.classList.remove('is-live');
|
|
82
|
+
indicator.dataset.timestamp = String(Date.now());
|
|
83
|
+
if (label) {
|
|
84
|
+
label.textContent = 'idle';
|
|
85
|
+
}
|
|
86
|
+
}, 1200);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const handleMessage = (event) => {
|
|
90
|
+
if (!event || typeof event.data !== 'object' || event.data === null) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const data = event.data;
|
|
94
|
+
if (data.type === 'terminal-input') {
|
|
95
|
+
const hasContent = typeof data.hasContent === 'boolean'
|
|
96
|
+
? data.hasContent
|
|
97
|
+
: Boolean(data.line && data.line.length > 0);
|
|
98
|
+
updateIndicator(data.line || '', hasContent);
|
|
99
|
+
} else if (data.type === 'stream') {
|
|
100
|
+
updateIndicator('', true);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
window.addEventListener('message', handleMessage, true);
|
|
105
|
+
const script = document.createElement('script');
|
|
106
|
+
script.src = '/tab-idle-notifier.js';
|
|
107
|
+
script.async = false;
|
|
108
|
+
document.head.appendChild(script);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
if (document.readyState === 'loading') {
|
|
112
|
+
document.addEventListener('DOMContentLoaded', init, { once: true });
|
|
113
|
+
} else {
|
|
114
|
+
init();
|
|
115
|
+
}
|
|
116
|
+
})();
|
package/server/socket.js
CHANGED
|
@@ -12,6 +12,7 @@ class Socket {
|
|
|
12
12
|
this.sessions = {}
|
|
13
13
|
this.connected = {}
|
|
14
14
|
this.active_shell = {}
|
|
15
|
+
this.shell_to_path = {}
|
|
15
16
|
this.parent = parent
|
|
16
17
|
this.server = parent.server
|
|
17
18
|
// this.kernel = parent.kernel
|
|
@@ -217,18 +218,45 @@ class Socket {
|
|
|
217
218
|
}
|
|
218
219
|
}
|
|
219
220
|
} else if (req.emit) {
|
|
221
|
+
if (req.id) {
|
|
222
|
+
const shell = this.parent.kernel.shell.get(req.id)
|
|
223
|
+
if (shell) {
|
|
224
|
+
shell.setUserActive(true)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
220
227
|
this.parent.kernel.shell.emit(req)
|
|
221
228
|
} else if (req.key && req.id) {
|
|
229
|
+
const shell = this.parent.kernel.shell.get(req.id)
|
|
230
|
+
if (shell) {
|
|
231
|
+
shell.setUserActive(true)
|
|
232
|
+
}
|
|
222
233
|
this.parent.kernel.shell.emit({
|
|
223
234
|
id: req.id,
|
|
224
235
|
emit: req.key,
|
|
225
236
|
paste: req.paste
|
|
226
237
|
})
|
|
227
238
|
} else if (req.resize && req.id) {
|
|
239
|
+
const targetId = this.shell_to_path[req.id] || req.id
|
|
228
240
|
this.parent.kernel.shell.resize({
|
|
229
241
|
id: req.id,
|
|
230
242
|
resize: req.resize
|
|
231
243
|
})
|
|
244
|
+
const subscribers = this.subscriptions.get(targetId)
|
|
245
|
+
if (subscribers && subscribers.size > 0) {
|
|
246
|
+
const payload = JSON.stringify({
|
|
247
|
+
type: 'resize',
|
|
248
|
+
data: {
|
|
249
|
+
id: req.id,
|
|
250
|
+
cols: req.resize.cols,
|
|
251
|
+
rows: req.resize.rows
|
|
252
|
+
}
|
|
253
|
+
})
|
|
254
|
+
subscribers.forEach((subscriber) => {
|
|
255
|
+
if (subscriber !== ws && subscriber.readyState === WebSocket.OPEN) {
|
|
256
|
+
subscriber.send(payload)
|
|
257
|
+
}
|
|
258
|
+
})
|
|
259
|
+
}
|
|
232
260
|
}
|
|
233
261
|
}
|
|
234
262
|
|
|
@@ -333,6 +361,7 @@ class Socket {
|
|
|
333
361
|
|
|
334
362
|
if (e.data && e.data.shell_id) {
|
|
335
363
|
this.active_shell[id] = e.data.shell_id
|
|
364
|
+
this.shell_to_path[e.data.shell_id] = id
|
|
336
365
|
}
|
|
337
366
|
|
|
338
367
|
// send to caller session
|
package/server/views/agents.ejs
CHANGED
|
@@ -513,8 +513,7 @@ body.dark .plugin-option:hover {
|
|
|
513
513
|
<% } %>
|
|
514
514
|
<a href="/connect" class='tab'><i class="fa-solid fa-plug"></i><div class='caption'>Login</div></a>
|
|
515
515
|
<a class='tab' href="<%=portal%>" target="_blank"><i class="fa-solid fa-question"></i><div class='caption'>Help</div></a>
|
|
516
|
-
<a class='tab' id='genlog'><i class="fa-solid fa-laptop-code"></i><div class='caption'>Logs</div></a>
|
|
517
|
-
<a id='downloadlogs' download class='hidden btn2' href="/pinokio/logs.zip"><i class="fa-solid fa-download"></i><div class='caption'>Download logs</div></a>
|
|
516
|
+
<a class='tab' id='genlog' href="/logs"><i class="fa-solid fa-laptop-code"></i><div class='caption'>Logs</div></a>
|
|
518
517
|
<a class='tab' href="/screenshots"><i class="fa-solid fa-camera"></i><div class='caption'>Screenshots</div></a>
|
|
519
518
|
<a class='tab' href="/tools"><i class="fa-solid fa-toolbox"></i><div class='caption'>Installed Tools</div></a>
|
|
520
519
|
<a class='tab selected' href="/agents"><i class="fa-solid fa-robot"></i><div class='caption'>Agents</div></a>
|