pinokiod 3.9.0 → 3.9.3

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 (119) hide show
  1. package/:w +1247 -0
  2. package/kernel/api/filepicker/index.js +59 -0
  3. package/kernel/api/fs/index.js +6 -4
  4. package/kernel/api/index.js +123 -37
  5. package/kernel/api/input/index.js +2 -0
  6. package/kernel/api/web/index.js +6 -0
  7. package/kernel/bin/caddy.js +127 -0
  8. package/kernel/bin/cloudflared.js +1 -0
  9. package/kernel/bin/conda.js +10 -2
  10. package/kernel/bin/cuda.js +0 -16
  11. package/kernel/bin/ffmpeg.js +4 -6
  12. package/kernel/bin/git.js +55 -29
  13. package/kernel/bin/gxx.js +8 -6
  14. package/kernel/bin/huggingface.js +4 -5
  15. package/kernel/bin/index.js +347 -88
  16. package/kernel/bin/node.js +13 -6
  17. package/kernel/bin/py.js +1 -1
  18. package/kernel/bin/setup.js +146 -0
  19. package/kernel/bin/uv.js +4 -5
  20. package/kernel/bin/zip.js +7 -8
  21. package/kernel/connect/index.js +25 -0
  22. package/kernel/connect/providers/github/README.md +11 -0
  23. package/kernel/connect/providers/x/README.md +96 -0
  24. package/kernel/connect/providers/x/index.js +152 -0
  25. package/kernel/environment.js +50 -1
  26. package/kernel/index.js +152 -32
  27. package/kernel/info.js +4 -2
  28. package/kernel/kv.js +38 -0
  29. package/kernel/loader.js +13 -3
  30. package/kernel/peer.js +161 -0
  31. package/kernel/procs.js +116 -0
  32. package/kernel/prototype.js +62 -0
  33. package/kernel/router/common.js +42 -0
  34. package/kernel/router/connector.js +81 -0
  35. package/kernel/router/index.js +235 -0
  36. package/kernel/router/localhost_home_router.js +84 -0
  37. package/kernel/router/localhost_port_router.js +15 -0
  38. package/kernel/router/localhost_variable_router.js +37 -0
  39. package/kernel/router/peer_home_router.js +15 -0
  40. package/kernel/router/peer_peer_router.js +26 -0
  41. package/kernel/router/peer_port_router.js +45 -0
  42. package/kernel/router/peer_variable_router.js +46 -0
  43. package/kernel/router/processor.js +31 -0
  44. package/kernel/shell.js +141 -60
  45. package/kernel/shells.js +32 -17
  46. package/kernel/store.js +58 -0
  47. package/kernel/sysinfo.js +0 -1
  48. package/kernel/util.js +143 -36
  49. package/package.json +4 -1
  50. package/pipe/index.js +0 -2
  51. package/script/index.js +12 -0
  52. package/server/index.js +1473 -553
  53. package/server/public/Socket.js +5 -1
  54. package/server/public/SourceCodePro-Regular.ttf +0 -0
  55. package/server/public/SpaceMono-Bold.ttf +0 -0
  56. package/server/public/SpaceMono-BoldItalic.ttf +0 -0
  57. package/server/public/SpaceMono-Italic.ttf +0 -0
  58. package/server/public/SpaceMono-Regular.ttf +0 -0
  59. package/server/public/commander.js +40 -0
  60. package/server/public/common.js +60 -0
  61. package/server/public/dropzone-min.js +2 -0
  62. package/server/public/dropzone.css +1 -0
  63. package/server/public/filepond-plugin-file-validate-type.min.js +9 -0
  64. package/server/public/filepond-plugin-image-crop.min.js +9 -0
  65. package/server/public/filepond-plugin-image-edit.min.css +8 -0
  66. package/server/public/filepond-plugin-image-edit.min.js +9 -0
  67. package/server/public/filepond-plugin-image-exif-orientation.min.js +9 -0
  68. package/server/public/filepond-plugin-image-preview.min.css +8 -0
  69. package/server/public/filepond-plugin-image-preview.min.js +9 -0
  70. package/server/public/filepond-plugin-image-resize.min.js +9 -0
  71. package/server/public/filepond-plugin-image-transform.min.js +9 -0
  72. package/server/public/filepond.min.css +8 -0
  73. package/server/public/filepond.min.js +9 -0
  74. package/server/public/fscreator.js +174 -0
  75. package/server/public/fseditor.js +212 -0
  76. package/server/public/github.png +0 -0
  77. package/server/public/highlight-js.js +81 -0
  78. package/server/public/highlight.css +9 -0
  79. package/server/public/highlight.js +1244 -0
  80. package/server/public/install.js +17 -20
  81. package/server/public/modalinput.js +105 -9
  82. package/server/public/opener.js +3 -1
  83. package/server/public/pinokio-black.png +0 -0
  84. package/server/public/pinokio-black2.png +0 -0
  85. package/server/public/redoc.standalone.js +1832 -0
  86. package/server/public/style.css +215 -17
  87. package/server/public/swagger-ui-bundle.js +2 -0
  88. package/server/public/swagger-ui.css +3 -0
  89. package/server/public/x.js +63 -0
  90. package/server/socket.js +136 -39
  91. package/server/views/404.ejs +0 -1
  92. package/server/views/app.ejs +368 -98
  93. package/server/views/bootstrap.ejs +22 -19
  94. package/server/views/connect/x.ejs +324 -0
  95. package/server/views/connect.ejs +197 -0
  96. package/server/views/download.ejs +7 -1
  97. package/server/views/editor.ejs +68 -9
  98. package/server/views/explore.ejs +13 -10
  99. package/server/views/file_explorer.ejs +10 -37
  100. package/server/views/github.ejs +218 -0
  101. package/server/views/help.ejs +4 -3
  102. package/server/views/index.ejs +275 -121
  103. package/server/views/install.ejs +56 -29
  104. package/server/views/keys.ejs +276 -0
  105. package/server/views/network.ejs +889 -0
  106. package/server/views/partials/dynamic.ejs +9 -0
  107. package/server/views/partials/menu.ejs +7 -1
  108. package/server/views/prototype/index.ejs +311 -0
  109. package/server/views/prototype/show.ejs +383 -0
  110. package/server/views/redoc.ejs +18 -0
  111. package/server/views/required_env_editor.ejs +11 -2
  112. package/server/views/settings.ejs +38 -10
  113. package/server/views/setup.ejs +254 -0
  114. package/server/views/setup_home.ejs +192 -0
  115. package/server/views/shell.ejs +781 -0
  116. package/server/views/swaggerui.ejs +19 -0
  117. package/server/views/terminal.ejs +174 -42
  118. package/LICENSE +0 -7
  119. package/server/views/proxy.ejs +0 -405
@@ -0,0 +1,781 @@
1
+ <html>
2
+ <head>
3
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
4
+ <script src="/hotkeys.min.js"></script>
5
+ <script src="/ace/ace.js"></script>
6
+ <script src="/noty.js"></script>
7
+ <script src="/notyq.js"></script>
8
+ <script src="/xterm.js"></script>
9
+ <script src="/xterm-addon-fit.js"></script>
10
+ <script src="/xterm-addon-web-links.js"></script>
11
+ <script src="/xterm-theme.js"></script>
12
+ <script src="/xterm-addon-search.js"></script>
13
+ <script src="/xterm-addon-search-bar.js"></script>
14
+ <script src="/sweetalert2.js"></script>
15
+ <script src="/Socket.js"></script>
16
+ <script src="/common.js"></script>
17
+ <script src="/he.js"></script>
18
+ <script src="/opener.js"></script>
19
+ <!--
20
+ <script src="/nav.js"></script>
21
+ -->
22
+ <script src="/autoexpand.js"></script>
23
+ <script src="/modalinput.js"></script>
24
+ <script src="/simplemodal.js"></script>
25
+ <script src="/waitmodal.js"></script>
26
+ <script src="/notifyinput.js"></script>
27
+ <script src="/report.js"></script>
28
+ <script src="/mark.min.js"></script>
29
+ <link href="/xterm.min.css" rel="stylesheet" />
30
+ <link href="/css/fontawesome.min.css" rel="stylesheet">
31
+ <link href="/css/solid.min.css" rel="stylesheet">
32
+ <link href="/css/regular.min.css" rel="stylesheet">
33
+ <link href="/css/brands.min.css" rel="stylesheet">
34
+ <link href="/style.css" rel="stylesheet"/>
35
+ <link href="/noty.css" rel="stylesheet"/>
36
+ <!--
37
+ <link rel="preconnect" href="https://fonts.googleapis.com">
38
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
39
+ <link href="https://fonts.googleapis.com/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
40
+ <link rel="preconnect" href="https://fonts.googleapis.com">
41
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
42
+ <link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
43
+ -->
44
+
45
+
46
+ <% if (agent === "electron") { %>
47
+ <link href="/electron.css" rel="stylesheet"/>
48
+ <% } %>
49
+ <style>
50
+ .stopped-btn {
51
+ background: silver;
52
+ }
53
+ html {
54
+ scroll-behavior: smooth;
55
+ height: 100%;
56
+ overflow: hidden;
57
+ }
58
+ body {
59
+ height: 100%;
60
+ overflow: hidden;
61
+ display: flex;
62
+ flex-direction: column;
63
+ }
64
+ #table > table {
65
+ border-left: 2px solid black;
66
+ padding-left: 5px;
67
+ margin: 10px 0;
68
+ }
69
+ .highlight {
70
+ background: yellow;
71
+ width: 100px;
72
+ }
73
+ th {
74
+ background: rgba(0,0,0,0.1);
75
+ padding: 10px;
76
+ font-size: 12px;
77
+ }
78
+ td {
79
+ font-size: 12px;
80
+ padding: 10px;
81
+ }
82
+ td.val {
83
+ background: rgba(0,0,0,0.06);
84
+ }
85
+ td.key {
86
+ background: rgba(0,0,0,0.1);
87
+ }
88
+ .button {
89
+ cursor: pointer;
90
+ background: rgba(0,0,0,0.8);
91
+ color: white;
92
+ padding: 5px 10px;
93
+ border-radius: 4px;
94
+ }
95
+ header {
96
+ position: relative;
97
+ padding: 10px 0;
98
+ }
99
+ .button:hover {
100
+
101
+ }
102
+ .terminal {
103
+ box-sizing: border-box;
104
+ }
105
+ .xterm .xterm-viewport {
106
+ width: initial !important;
107
+ }
108
+ .navheader3 {
109
+ padding: 10px;
110
+ }
111
+ .navheader {
112
+ padding-bottom: 0;
113
+ }
114
+ /*
115
+ .navheader {
116
+ background: var(--dark-bg);
117
+ }
118
+ */
119
+ /*
120
+ .btn {
121
+ background: royalblue;
122
+ }
123
+ */
124
+ #del-bin {
125
+ color: royalblue;
126
+ cursor: pointer;
127
+ font-weight: bold;
128
+ padding: 0 5px;
129
+ text-decoration: underline;
130
+ }
131
+ body.frozen {
132
+ overflow: auto !important;
133
+ }
134
+ .terminal-container {
135
+ padding: 0;
136
+ }
137
+ </style>
138
+ <link href="/terminal.css" rel="stylesheet"/>
139
+ <script>
140
+ let shell_id
141
+ document.addEventListener("DOMContentLoaded", async () => {
142
+ const n = new N()
143
+ class RPC {
144
+ constructor() {
145
+ this.socket = new Socket()
146
+ this.buffer = []
147
+ }
148
+ write(text) {
149
+ if (text !== "\u0007") {
150
+ this.term.write(text)
151
+ }
152
+ this.dirty = true
153
+ }
154
+ finished() {
155
+ /*
156
+ n.Noty({
157
+ text: `[Success] All steps complete`,
158
+ })
159
+ */
160
+ document.querySelector(".play-btn").classList.remove("hidden")
161
+ document.querySelector(".stop-btn").classList.add("hidden")
162
+ document.querySelector(".starting-btn").classList.add("hidden")
163
+ }
164
+ stop() {
165
+ this.socket.run({
166
+ method: "kernel.bin.shell_kill",
167
+ params: {
168
+ id: shell_id
169
+ }
170
+ }, (stream) => {
171
+ })
172
+ }
173
+ save() {
174
+ return new Promise((resolve, reject) => {
175
+ let cwd = "~" + location.pathname
176
+
177
+ this.socket.close()
178
+ this.socket.run({
179
+ method: "fs.write",
180
+ params: {
181
+ path: cwd,
182
+ text: str,
183
+ // string: str
184
+ // json: instructions
185
+ }
186
+ }, (packet) => {
187
+ if (packet.type === "result" && packet.id === "fs.write") {
188
+ dirty = false
189
+ document.querySelector("#save").classList.add("disabled")
190
+ resolve()
191
+ }
192
+ })
193
+ })
194
+ }
195
+ start(mode) {
196
+ return new Promise(async (resolve, reject) => {
197
+ // await this.save()
198
+ await this.socket.close()
199
+
200
+ let query = Object.fromEntries(new URLSearchParams(location.search))
201
+ console.log(">>>>>>>> 1")
202
+
203
+ let firstPacketReceived = false
204
+ this.socket.run({
205
+ //method: "kernel.bin.shell_start",
206
+ method: "kernel.bin.exec",
207
+ <% if (message) { %>
208
+ message: "<%-message%>",
209
+ <% } %>
210
+ <% if (venv) { %>
211
+ venv: "<%=venv%>",
212
+ <% } %>
213
+ <% if (kill) { %>
214
+ on: [{
215
+ event: "<%=kill%>",
216
+ kill: true
217
+ }],
218
+ <% } %>
219
+ <% if (done) { %>
220
+ on: [{
221
+ event: "<%=done%>",
222
+ done: true
223
+ }],
224
+ <% } %>
225
+ <% if (input) { %>
226
+ input: true,
227
+ <% } %>
228
+ <% if (env) { %>
229
+ env: <%-JSON.stringify(env)%>,
230
+ <% } %>
231
+ <% if (conda) { %>
232
+ conda: <%-JSON.stringify(conda)%>,
233
+ <% } %>
234
+ id: "<%=id%>",
235
+ path: "<%=cwd%>",
236
+ client: {
237
+ cols: this.term.cols,
238
+ rows: this.term.rows,
239
+ }
240
+ }, async (packet) => {
241
+ if (!firstPacketReceived) {
242
+ refreshParent({
243
+ type: "start"
244
+ })
245
+ firstPacketReceived = true
246
+ }
247
+ console.log({ packet, type: packet.type })
248
+ if (packet.type === 'start') {
249
+ console.log("refreshParent", packet)
250
+ refreshParent(packet)
251
+ document.querySelector(".play-btn").classList.add("hidden")
252
+ document.querySelector(".starting-btn").classList.add("hidden")
253
+ document.querySelector(".stop-btn").classList.remove("hidden")
254
+ if (packet.data && packet.data.description) {
255
+ if ('current' in packet.data) {
256
+ document.querySelector("footer").innerHTML = `<b>
257
+ <i class="fa-solid fa-circle-notch fa-spin"></i>(${packet.data.current+1}/${packet.data.total}) ${packet.data.title ? packet.data.title : ''}
258
+ </b>
259
+ <div class='flexible content'>${packet.data.description}</div>`
260
+ // <div class='toggle-expand'>
261
+ // <i class="fa-solid fa-circle-chevron-up"></i>
262
+ // </div>`
263
+ } else {
264
+ document.querySelector("footer").innerHTML = `<b>
265
+ <i class="fa-solid fa-circle-notch fa-spin"></i> ${packet.data.title ? packet.data.title : ''}
266
+ </b>
267
+ <div class='flexible content'></div>`
268
+ // <div class='toggle-expand'>
269
+ // <i class="fa-solid fa-circle-chevron-up"></i>
270
+ // </div>`
271
+ }
272
+ } else if (packet.data && packet.data.method) {
273
+ document.querySelector("footer").innerHTML = `<b>
274
+ <i class="fa-solid fa-circle-notch fa-spin"></i> (${packet.data.current+1}/${packet.data.total}) ${packet.data.method}
275
+ </b>
276
+ <div class='flexible content'>${packet.data.params ? JSON.stringify(packet.data.params) : ''}</div>`
277
+ // <div class='toggle-expand'>
278
+ // <i class="fa-solid fa-circle-chevron-up"></i>
279
+ // </div>`
280
+ }
281
+ } else if (packet.type === "stream") {
282
+ console.log(">>>>>>>> 3")
283
+ // set the current shell id
284
+ if (packet.data.id) {
285
+ shell_id = packet.data.id
286
+ }
287
+ if (packet.data.raw) {
288
+ // console.log({ packet })
289
+ this.write(packet.data.raw)
290
+ } else if (packet.data.json) {
291
+ this.write(JSON.stringify(packet.data.json).replace(/\n/g, "\r\n"))
292
+ this.write("\r\n")
293
+ } else if (packet.data.json2) {
294
+ this.write(JSON.stringify(packet.data.json2, null, 2).replace(/\n/g, "\r\n"))
295
+ this.write("\r\n")
296
+ }
297
+ if (packet.data.type === "shell.kill") {
298
+ this.socket.close()
299
+ }
300
+ document.querySelector(".play-btn").classList.add("hidden")
301
+ document.querySelector(".starting-btn").classList.add("hidden")
302
+ document.querySelector(".stop-btn").classList.remove("hidden")
303
+ } else if (packet.type === 'disconnect') {
304
+ console.log("refreshParent", packet)
305
+ refreshParent(packet)
306
+ this.term.write("\r\nDisconnected...\r\n")
307
+ document.querySelector("footer").innerHTML = "<b>Ready</b>"
308
+ this.socket.close()
309
+ document.querySelector(".play-btn").classList.remove("hidden")
310
+ document.querySelector(".stop-btn").classList.add("hidden")
311
+ } else if (packet.type === 'connect') {
312
+ console.log("refreshParent", packet)
313
+ refreshParent(packet)
314
+ if (packet.data) {
315
+ if (packet.data.shell) {
316
+ shell_id = packet.data.shell
317
+ }
318
+ if (packet.data.state) {
319
+ this.write(packet.data.state)
320
+ }
321
+ }
322
+ document.querySelector(".play-btn").classList.add("hidden")
323
+ document.querySelector(".starting-btn").classList.add("hidden")
324
+ document.querySelector(".stop-btn").classList.remove("hidden")
325
+ } else if (packet.type === 'wait.end') {
326
+ try {
327
+ Swal.close()
328
+ } catch (e) {
329
+ }
330
+ this.socket.respond({
331
+ response: {},
332
+ // uri: "~" + location.pathname,
333
+ uri: packet.id
334
+ })
335
+ } else if (packet.type === 'wait') {
336
+ await WaitModal(packet.data)
337
+ } else if (packet.type === "modal") {
338
+ await SimpleModal(packet.data)
339
+ this.socket.respond({
340
+ response: {},
341
+ //uri: "~" + location.pathname,
342
+ uri: packet.id
343
+ })
344
+ } else if (packet.type === "input") {
345
+ let params = packet.data
346
+ let type = (params.type ? params.type : "modal")
347
+ let input
348
+ if (type === "modal") {
349
+ input = await ModalInput(packet.data)
350
+ } else if (type === "notify") {
351
+ input = await NotifyInput(packet.data, n)
352
+ }
353
+ if (input) {
354
+ this.socket.respond({
355
+ response: input,
356
+ uri: packet.id
357
+ // uri: "~" + location.pathname,
358
+ // uri: (packet.caller ? packet.caller : packet.id)
359
+ })
360
+ }
361
+ /*
362
+ params := {
363
+ title,
364
+ description,
365
+ form: [{
366
+ title,
367
+ description
368
+ }]
369
+ }
370
+ */
371
+ } else if (packet.type === "tab.open") {
372
+ refreshParent(packet)
373
+ } else if (packet.type === "browser.open") {
374
+ /*
375
+ {
376
+ "method": "browser.open",
377
+ "params": {
378
+ "uri",
379
+ "target": "_self (default)"|"_blank"|"_parent"|"_top",
380
+ "features"
381
+ }
382
+ }
383
+ */
384
+
385
+ ///// DEPRECATE browser.open : Pinokio IS the browser. Everything opens in Pinokio. May bring back when necessary
386
+ // refreshParent()
387
+ // let params = packet.data
388
+ // window.open(
389
+ // params.uri,
390
+ // (params.target || "_self"),
391
+ // params.features
392
+ // )
393
+ } else if (packet.type === "browser.close") {
394
+ let params = packet.data
395
+ if (params && params.target) {
396
+ let targetWindow = window.open('', params.target)
397
+ if (targetWindow) {
398
+ targetWindow.close();
399
+ }
400
+ } else {
401
+ window.close()
402
+ }
403
+ } else if (packet.type === "browser") {
404
+ /*
405
+ {
406
+ "method": "browser.close"
407
+ }
408
+ */
409
+ let { method, params } = packet.data
410
+ let resolved = window
411
+ let tokens = method.split(".")
412
+ for(let token of tokens) {
413
+ resolved = resolved[token]
414
+ }
415
+ let result = resolved(...params)
416
+ } else if (packet.type === "notify") {
417
+ /*
418
+ {
419
+ html: <notification html>,
420
+ href: <link location to open>,
421
+ target: <target for window.open()>,
422
+ features: <windowFeatures>, ("self" => opens in pinokio)
423
+ }
424
+ */
425
+ if (packet.data) {
426
+ let payload = {}
427
+ if (packet.data.html) {
428
+ payload.text = packet.data.html
429
+ }
430
+ if (packet.data.type) {
431
+ payload.type = packet.data.type
432
+ }
433
+ payload.silent = packet.data.silent
434
+ payload.callbacks = {
435
+ onClick: () => {
436
+ let params = packet.data
437
+ if (params.href || params.uri) {
438
+ window.open(
439
+ params.uri || params.href,
440
+ (params.target || "_self"),
441
+ params.features
442
+ )
443
+ } else if (params.action === "close") {
444
+ if (params && params.target) {
445
+ let targetWindow = window.open('', params.target)
446
+ if (targetWindow) {
447
+ targetWindow.close();
448
+ }
449
+ } else {
450
+ window.close()
451
+ }
452
+ }
453
+ }
454
+ }
455
+ n.Noty(payload)
456
+ }
457
+ } else if (packet.type === "result") {
458
+ // this.socket.close()
459
+ } else if (packet.type === "info") {
460
+ n.Noty({
461
+ text: `${packet.data}`,
462
+ })
463
+ } else if (packet.type === "error") {
464
+ // n.Noty({
465
+ // text: `${packet.data}`,
466
+ // type: "error"
467
+ // })
468
+
469
+ // this.socket.close()
470
+ // refreshParent(packet)
471
+
472
+
473
+
474
+ //document.querySelector("footer .content").innerHTML = document.querySelector("footer .content").innerHTML + `<pre class='error'>${packet.data}</pre>`
475
+ document.querySelector("footer .content").innerHTML = document.querySelector("footer .content").innerHTML + `<pre class='error'>ERROR</pre>`
476
+ // document.querySelector("footer .toggle-expand i").className = "fa-solid fa-circle-chevron-down"
477
+ // document.querySelector("footer").classList.add("expanded")
478
+ document.querySelector("footer i").className = "fa-solid fa-triangle-exclamation"
479
+
480
+ document.querySelector(".play-btn").classList.remove("hidden")
481
+ document.querySelector(".starting-btn").classList.add("hidden")
482
+ document.querySelector(".stop-btn").classList.add("hidden")
483
+
484
+ document.querySelector("#error-screen").classList.remove("hidden")
485
+ document.querySelector("#error-screen pre").textContent = packet.data
486
+ let instance = new Mark(document.querySelector("#error-screen pre"), {
487
+ separateWordSearch: false,
488
+ accuracy: "exactly"
489
+ })
490
+ /*
491
+ document.querySelector("#error-screen").addEventListener("click", (e) => {
492
+ document.querySelector("#error-screen").classList.add("hidden")
493
+ })
494
+ */
495
+ instance.mark(packet.event)
496
+ let element = document.querySelector("mark")
497
+ element.scrollIntoView({ behavior: "smooth", block: "center" });
498
+
499
+
500
+
501
+
502
+ } else if (packet.type === "event") {
503
+ if (packet.data === "stop") {
504
+ document.querySelector(".stop-btn").classList.add("hidden")
505
+ document.querySelector(".stopped-btn").classList.remove("hidden")
506
+ document.querySelector("footer").innerHTML = "<b>Ready</b>"
507
+ setTimeout(() => {
508
+
509
+ let params = new URLSearchParams(location.search)
510
+ let entries = [...params.entries()]
511
+ let options;
512
+ if (entries.length > 0) {
513
+ options = {}
514
+ for(const [key, value] of entries) {
515
+ options[key] = value;
516
+ }
517
+ }
518
+ if (options && options.html) {
519
+ n.Noty({
520
+ text: options.html,
521
+ timeout: 3000,
522
+ callbacks: {
523
+ onClose: () => {
524
+ let uri = options.uri || options.href
525
+ if (uri) {
526
+ let target = options.target || "_self"
527
+ let features = options.features
528
+ window.open(uri, target, features)
529
+ } else if (options.action === "close") {
530
+ window.close()
531
+ }
532
+ }
533
+ }
534
+ })
535
+ }
536
+ /*
537
+ n.Noty({
538
+ text: '[Notice] finished',
539
+ type: 'success'
540
+ })
541
+ */
542
+ document.querySelector(".play-btn").classList.remove("hidden")
543
+ document.querySelector(".starting-btn").classList.add("hidden")
544
+ document.querySelector(".stop-btn").classList.add("hidden")
545
+ }, 0)
546
+ //this.socket.close()
547
+ }
548
+ }
549
+
550
+ // Get the available space for the terminal
551
+ // let terminalContainer = document.querySelector("#terminal")
552
+ // const availableHeight = terminalContainer.clientHeight;
553
+ //
554
+ // // Calculate the number of columns and rows the terminal should have
555
+ // console.log(this.term)
556
+ // //const rows = Math.floor(availableHeight / this.term._core.viewport._charSizeService.height);
557
+ // const rows = Math.floor(this.term._core.viewport._lastRecordedViewportHeight / this.term._core.viewport._charSizeService.height);
558
+ //
559
+ //
560
+ // // Resize the terminal
561
+ // this.term.resize(this.term.cols, rows);
562
+ // this.term.scrollToLine(this.term.rows-1);
563
+ // this.fit.fit()
564
+ // let pageBottom = document.querySelector("#end")
565
+ // pageBottom.scrollIntoView()
566
+ }).then(() => {
567
+ refreshParent({
568
+ type: "disconnect"
569
+ })
570
+ document.querySelector(".stop-btn").classList.add("hidden")
571
+ document.querySelector(".stopped-btn").classList.remove("hidden")
572
+ <% if (kill_message) { %>
573
+ n.Noty({
574
+ text: "<%-kill_message%>",
575
+ // timeout: 3000,
576
+ <% if (callback) { %>
577
+ callbacks: {
578
+ onClose: () => {
579
+ location.href = "<%=callback%>"
580
+ }
581
+ }
582
+ <% } %>
583
+ })
584
+ <% } else { %>
585
+ <% if (callback) { %>
586
+ location.href = "<%=callback%>"
587
+ <% } %>
588
+ <% } %>
589
+ })
590
+ })
591
+ }
592
+ async run (mode) {
593
+ this.mode = (mode ? mode : "run")
594
+
595
+ // if (dirty) {
596
+ // await this.save()
597
+ // n.Noty({
598
+ // text: `script updated`,
599
+ // })
600
+ // }
601
+
602
+ <% if (theme === "dark") { %>
603
+ await this.createTerm(xtermTheme.FrontEndDelight)
604
+ <% } else { %>
605
+ await this.createTerm(xtermTheme.Tomorrow)
606
+ <% } %>
607
+ await this.start(mode)
608
+ }
609
+ async createTerm (_theme) {
610
+ console.log(xtermTheme)
611
+ if (!this.term) {
612
+ const theme = Object.assign({ }, _theme, {
613
+ selectionBackground: "red",
614
+ selectionForeground: "white"
615
+ })
616
+
617
+ let config = {
618
+ scrollback: 9999999,
619
+ //fontSize: 12,
620
+ fontSize: 14,
621
+ theme,
622
+ //theme: xtermTheme.FrontEndDelight
623
+ //theme: xtermTheme.Afterglow
624
+
625
+ //theme: xtermTheme.PencilLight
626
+
627
+ //theme: xtermTheme.Flatland
628
+ //theme: xtermTheme.OneHalfLight
629
+ //theme: xtermTheme.Piatto_Light
630
+ //theme: xtermTheme.Spring
631
+ //theme: xtermTheme.Terminal_Basic
632
+ //theme: xtermTheme.Tomorrow
633
+ }
634
+ let res = await fetch("/xterm_config").then((res) => {
635
+ return res.json()
636
+ })
637
+ if (res && res.config) {
638
+ config = res.config
639
+ }
640
+ const term = new Terminal(config)
641
+ term.open(document.querySelector("#terminal"))
642
+ term.attachCustomKeyEventHandler(event => {
643
+ console.log({ event })
644
+ if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
645
+ const selection = term.getSelection();
646
+ if (selection) {
647
+ navigator.clipboard.writeText(selection);
648
+ return false;
649
+ }
650
+ }
651
+ if ((event.ctrlKey || event.metaKey) && event.key === 'v') {
652
+ navigator.clipboard.readText().then((text) => {
653
+ this.socket.run({
654
+ key: "\x1b[200~" + text + "\x1b[201~",
655
+ id: shell_id
656
+ })
657
+ })
658
+ return false
659
+ }
660
+ return true;
661
+ });
662
+ //const rows = Math.floor(document.querySelector("#terminal").clientHeight / term._core.viewport._charSizeService.height);
663
+ //const cols = Math.floor(document.querySelector("#terminal").clientHeight / term._core.viewport._charSizeService.width);
664
+ //console.log(cols, term.cols)
665
+ // // Resize the terminal
666
+ ////term.resize(cols, rows-5);
667
+ //term.resize(cols, rows);
668
+
669
+ term.onKey(({ key }) => {
670
+ console.log({ key, shell_id })
671
+ if (this.socket) {
672
+ if (shell_id) {
673
+ this.socket.run({
674
+ key,
675
+ id: shell_id
676
+ })
677
+ }
678
+ }
679
+ });
680
+
681
+ const fitAddon = new FitAddon.FitAddon();
682
+ // const searchAddon = new SearchAddon.SearchAddon();
683
+ // const searchAddonBar = new SearchBarAddon.SearchBarAddon({searchAddon});
684
+ term.loadAddon(fitAddon);
685
+ <% if (agent === "electron") { %>
686
+ term.loadAddon(new WebLinksAddon.WebLinksAddon((event, uri) => {
687
+ window.open(uri, "_blank")
688
+ }))
689
+ <% } else { %>
690
+ term.loadAddon(new WebLinksAddon.WebLinksAddon());
691
+ <% } %>
692
+ // term.loadAddon(searchAddon)
693
+ // term.loadAddon(searchAddonBar);
694
+ // searchAddonBar.show();
695
+ fitAddon.fit();
696
+ this.term = term
697
+ this.fit = fitAddon
698
+
699
+ }
700
+ this.term.focus()
701
+ }
702
+ }
703
+ const rpc = new RPC()
704
+ document.querySelector(".stop-btn").addEventListener("click", async (e) => {
705
+ await rpc.stop()
706
+ // socket.run({
707
+ // id: location.pathname,
708
+ // method: "kernel.api.stop"
709
+ // }, (stream) => {
710
+ // console.log("#", stream)
711
+ // })
712
+
713
+
714
+ document.querySelector(".play-btn").classList.remove("hidden")
715
+ document.querySelector(".starting-btn").classList.add("hidden")
716
+ document.querySelector(".stop-btn").classList.add("hidden")
717
+ document.querySelector(".stopped-btn").classList.remove("hidden")
718
+ })
719
+ document.querySelector(".play-btn").addEventListener("click", async (e) => {
720
+ document.querySelector(".play-btn").classList.add("hidden")
721
+ document.querySelector(".starting-btn").classList.remove("hidden")
722
+ await rpc.run()
723
+ })
724
+ <% if (running) { %>
725
+ // if running, connect
726
+ rpc.run("listen")
727
+ // hide play button
728
+ document.querySelector(".play-btn").classList.add("hidden")
729
+ // show stop button
730
+ document.querySelector(".stop-btn").classList.remove("hidden")
731
+ <% } else { %>
732
+ // if not running, start
733
+ rpc.run()
734
+ // show starting button
735
+ document.querySelector(".starting-btn").classList.remove("hidden")
736
+ <% } %>
737
+
738
+ window.addEventListener('message', function(event) {
739
+ console.log("Message received from the parent: ", event.data); // Message received from parent
740
+ // "foreground" message adds a newline to the terminal
741
+ // Needed to fix the issue where the terminal won't write anything when in background
742
+ // so when coming back from background, need to refresh by just adding a newline.
743
+ if (event.data && event.data.action === "foreground") {
744
+ // if dirty, update
745
+ // if not dirty, don't update
746
+ const delimiter = "\r\n"
747
+ if (rpc.dirty) {
748
+ rpc.term.write(delimiter)
749
+ rpc.dirty = false
750
+ } else {
751
+ }
752
+ }
753
+ });
754
+ // rpc.run()
755
+ })
756
+
757
+ </script>
758
+ </head>
759
+ <body class='<%=theme%>'>
760
+ <header class='navheader grabbable'>
761
+ <div class='navheader3'>
762
+ <div class='hidden btn run play-btn'>
763
+ <span class='play'><i class="fa-solid fa-play"></i> Start</span>
764
+ </div>
765
+ <div class='hidden btn run starting-btn'>
766
+ <span class='starting'><i class="fa-solid fa-circle-notch fa-spin"></i> Starting...</span>
767
+ </div>
768
+ <div class='hidden btn run stop-btn'>
769
+ <span class='stop'><i class="fa-solid fa-stop"></i> Stop</span>
770
+ </div>
771
+ <div class='hidden btn stopped-btn'>
772
+ <span class='stopped'><i class="fa-solid fa-hand"></i> Stopped</span>
773
+ </div>
774
+ </div>
775
+ </header>
776
+ <div class='terminal-container'>
777
+ <div id='terminal'></div>
778
+ </div>
779
+ <footer><b>Ready</b></footer>
780
+ </body>
781
+ </html>