pinokiod 3.8.0 → 3.8.5

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 (51) hide show
  1. package/kernel/api/fs/index.js +6 -4
  2. package/kernel/api/index.js +102 -31
  3. package/kernel/bin/cuda.js +7 -0
  4. package/kernel/bin/index.js +143 -4
  5. package/kernel/bin/node.js +9 -0
  6. package/kernel/index.js +32 -1
  7. package/kernel/info.js +1 -0
  8. package/kernel/prototype.js +47 -0
  9. package/kernel/shell.js +110 -54
  10. package/kernel/shells.js +16 -7
  11. package/kernel/store.js +58 -0
  12. package/kernel/util.js +106 -35
  13. package/package.json +1 -1
  14. package/script/index.js +12 -0
  15. package/server/index.js +466 -250
  16. package/server/public/SpaceMono-Bold.ttf +0 -0
  17. package/server/public/SpaceMono-BoldItalic.ttf +0 -0
  18. package/server/public/SpaceMono-Italic.ttf +0 -0
  19. package/server/public/SpaceMono-Regular.ttf +0 -0
  20. package/server/public/filepond-plugin-file-validate-type.min.js +9 -0
  21. package/server/public/filepond-plugin-image-crop.min.js +9 -0
  22. package/server/public/filepond-plugin-image-edit.min.css +8 -0
  23. package/server/public/filepond-plugin-image-edit.min.js +9 -0
  24. package/server/public/filepond-plugin-image-exif-orientation.min.js +9 -0
  25. package/server/public/filepond-plugin-image-preview.min.css +8 -0
  26. package/server/public/filepond-plugin-image-preview.min.js +9 -0
  27. package/server/public/filepond-plugin-image-resize.min.js +9 -0
  28. package/server/public/filepond-plugin-image-transform.min.js +9 -0
  29. package/server/public/filepond.min.css +8 -0
  30. package/server/public/filepond.min.js +9 -0
  31. package/server/public/fscreator.js +160 -0
  32. package/server/public/fseditor.js +189 -0
  33. package/server/public/github.png +0 -0
  34. package/server/public/opener.js +3 -1
  35. package/server/public/pinokio-black.png +0 -0
  36. package/server/public/pinokio-black2.png +0 -0
  37. package/server/public/style.css +131 -9
  38. package/server/socket.js +123 -37
  39. package/server/views/app.ejs +184 -11
  40. package/server/views/editor.ejs +12 -2
  41. package/server/views/explore.ejs +4 -3
  42. package/server/views/help.ejs +4 -2
  43. package/server/views/index.ejs +218 -80
  44. package/server/views/install.ejs +1 -1
  45. package/server/views/local_editor.ejs +282 -0
  46. package/server/views/minterm.ejs +687 -0
  47. package/server/views/partials/menu.ejs +7 -1
  48. package/server/views/prototypes.ejs +463 -0
  49. package/server/views/proxy.ejs +10 -4
  50. package/server/views/settings.ejs +4 -3
  51. package/server/views/terminal.ejs +99 -15
@@ -0,0 +1,189 @@
1
+ const FSEditor = async ({title, description, old_path, icon, iconpath, redirect, copy, move, edit }) => {
2
+ console.log({ icon, iconpath })
3
+ const compare = async (file1, file2) => {
4
+ if (file1.size !== file2.size) return false;
5
+ console.log({ file1, file2 })
6
+ const buffer1 = await file1.arrayBuffer();
7
+ const buffer2 = await file2.arrayBuffer();
8
+ const view1 = new Uint8Array(buffer1);
9
+ const view2 = new Uint8Array(buffer2);
10
+ for (let i = 0; i < view1.length; i++) {
11
+ if (view1[i] !== view2[i]) return false;
12
+ }
13
+ return true;
14
+ }
15
+ let dirty
16
+ let mode
17
+ let new_path
18
+ let initial_file
19
+ let title_label
20
+ let file_type
21
+ let folderpath_html = ""
22
+ if (copy) {
23
+ mode = "copy"
24
+ title_label = "Copy to"
25
+ } else if (move) {
26
+ mode = "move"
27
+ title_label = "Move to"
28
+ } else {
29
+ mode = "edit"
30
+ title_label = "Edit"
31
+ }
32
+ if (copy || move) {
33
+ folderpath_html = `<div class='folder-row'>
34
+ <label for='new-folder-description'>Folder Path</label>
35
+ <div class='field-row'>
36
+ <label>/api/</label>
37
+ <input id="new-folder-path" class="swal2-input" placeholder="Folder Path" value="${old_path}" />
38
+ </div>
39
+ </div>`
40
+ }
41
+ let result = await Swal.fire({
42
+ title: title_label,
43
+ html: `<div class='filepond-wrapper'>
44
+ <div class='avatar-field'>
45
+ <input id='new-folder-image' type="file" class="filepond" name="avatar" accept="image/png, image/jpeg, image/gif" />
46
+ </div>
47
+ <div class='folder-rows'>
48
+ ${folderpath_html}
49
+ <div class='folder-row'>
50
+ <label for='new-folder-title'>Title</label>
51
+ <input id="new-folder-title" class="swal2-input" placeholder="Folder Name" value="${title}" />
52
+ </div>
53
+ <div class='folder-row'>
54
+ <label for='new-folder-description'>Description</label>
55
+ <textarea id="new-folder-description" class="swal2-input" placeholder="Folder Description">${description}</textarea>
56
+ </div>
57
+ </div>
58
+ </div>`,
59
+ allowOutsideClick: true,
60
+ focusConfirm: false,
61
+ // showCancelButton: true,
62
+ confirmButtonText: 'Save',
63
+ didOpen: () => {
64
+ const textarea = document.querySelector("#new-folder-description")
65
+ textarea.style.height = 'auto';
66
+ textarea.style.height = textarea.scrollHeight + 'px';
67
+ textarea.addEventListener('input', () => {
68
+ textarea.style.height = textarea.scrollHeight + 'px';
69
+ });
70
+ FilePond.registerPlugin(
71
+ FilePondPluginFileValidateType,
72
+ FilePondPluginImageExifOrientation,
73
+ FilePondPluginImagePreview,
74
+ FilePondPluginImageCrop,
75
+ FilePondPluginImageResize,
76
+ FilePondPluginImageTransform,
77
+ FilePondPluginImageEdit
78
+ );
79
+ pond = FilePond.create(
80
+ document.querySelector('#new-folder-image'),
81
+ {
82
+ allowReplace: true,
83
+ allowRevert: true,
84
+ allowRemove: true,
85
+
86
+ allowImageCrop: true,
87
+ allowImageEdit: true,
88
+ allowImageTransform: true,
89
+
90
+
91
+ labelIdle: `Drag & Drop your picture or <span class="filepond--label-action">Browse</span>`,
92
+ imagePreviewHeight: 170,
93
+ imageCropAspectRatio: '1:1',
94
+ imageResizeTargetWidth: 200,
95
+ imageResizeTargetHeight: 200,
96
+ stylePanelLayout: 'compact circle',
97
+ instantUpload: false,
98
+ server: {
99
+ process: {
100
+ url: '/pinokio/upload', // optional if same as above
101
+ ondata: (formData) => {
102
+ console.log("upload", { dirty })
103
+ if (dirty) {
104
+ formData.append("icon_dirty", true)
105
+ }
106
+ formData.append("icon_path", iconpath)
107
+ let title = Swal.getPopup().querySelector('#new-folder-title').value
108
+ let description = Swal.getPopup().querySelector('#new-folder-description').value
109
+ let folder_path_el = Swal.getPopup().querySelector('#new-folder-path')
110
+ formData.append("title", title)
111
+ formData.append("description", description)
112
+ formData.append("old_path", old_path)
113
+ let path
114
+ if (folder_path_el) {
115
+ path = folder_path_el.value
116
+ formData.append("new_path", path)
117
+ } else {
118
+ path = old_path
119
+ formData.append("new_path", old_path)
120
+ }
121
+ if (mode === "copy") {
122
+ formData.append("copy", true)
123
+ } else if (mode === "move") {
124
+ formData.append("move", true)
125
+ }
126
+ if (edit) {
127
+ formData.append("edit", true)
128
+ }
129
+ new_path = path
130
+ return formData;
131
+ }
132
+ }
133
+ },
134
+ onaddfile(error, file) {
135
+ console.log({ file, initial_file })
136
+ if (initial_file) {
137
+ compare(initial_file.file, file.file).then((same) => {
138
+ if (same) {
139
+ // don't do anything
140
+ } else {
141
+ dirty = true
142
+ // make sure the image mime type is transformed into the same type as the existing image
143
+ pond.setOptions({
144
+ imageTransformOutputMimeType: initial_file.fileType
145
+ })
146
+ }
147
+ initial_file = file
148
+ })
149
+ } else {
150
+ initial_file = file
151
+ }
152
+ },
153
+ onprocessfile(error, file) {
154
+ console.log("onprocessfile")
155
+ debugger
156
+ if (error) {
157
+ alert(error.body)
158
+ } else {
159
+ Swal.close()
160
+ if (new_path) {
161
+ location.href = redirect(new_path)
162
+ } else {
163
+ location.href = location.href
164
+ }
165
+ }
166
+ },
167
+ files: [
168
+ {
169
+ type: 'local',
170
+ source: icon,
171
+ }
172
+ ]
173
+ }
174
+ );
175
+ },
176
+ preConfirm: () => {
177
+ if (mode === "copy") {
178
+ let new_path = Swal.getPopup().querySelector('#new-folder-path').value
179
+ if (new_path === old_path) {
180
+ alert("Please specify a new folder name to copy to")
181
+ return false
182
+ }
183
+ }
184
+ pond.processFile()
185
+ return false
186
+ }
187
+ })
188
+
189
+ }
Binary file
@@ -9,13 +9,15 @@ document.addEventListener("click", async (e) => {
9
9
  }
10
10
  if (el) {
11
11
  let filepath = el.getAttribute("data-filepath")
12
+ let command = el.getAttribute("data-command")
12
13
  await fetch("/openfs", {
13
14
  method: "post",
14
15
  headers: {
15
16
  "Content-Type": "application/json"
16
17
  },
17
18
  body: JSON.stringify({
18
- path: filepath
19
+ path: filepath,
20
+ command
19
21
  })
20
22
  }).then((res) => {
21
23
  return res.json()
Binary file
Binary file
@@ -1,3 +1,9 @@
1
+ @font-face {
2
+ font-family: 'SpaceMono';
3
+ src: url('/SpaceMono-Regular.ttf') format('truetype');
4
+ font-weight: normal;
5
+ font-style: normal;
6
+ }
1
7
  :root {
2
8
  --content-width: 900px;
3
9
 
@@ -53,6 +59,16 @@
53
59
  */
54
60
  --dark-btn-color: whitesmoke;
55
61
  }
62
+ .drawer {
63
+ max-height: 100000px;
64
+ overflow: hidden;
65
+ height: auto;
66
+ transition: max-height 3s ease-in-out;
67
+ }
68
+ .drawer.vertical-collapsed {
69
+ max-height: 0;
70
+ }
71
+
56
72
  .type-tabs {
57
73
  display: flex;
58
74
  padding: 20px 20px 0;
@@ -87,7 +103,13 @@ body.dark .type-tabs {
87
103
  height: 20px;
88
104
  margin-right: 5px;
89
105
  }
106
+ .navheader2 {
107
+ padding: 15px 10px;
108
+ background: white;
109
+ }
90
110
  .navheader {
111
+ backdrop-filter: blur(16px);
112
+
91
113
  padding: 15px 10px;
92
114
  }
93
115
  body.columns footer {
@@ -190,8 +212,10 @@ footer {
190
212
  overflow: auto;
191
213
  */
192
214
  box-sizing: border-box;
215
+ /*
193
216
  color: var(--dark-color);
194
217
  background: var(--dark-bg);
218
+ */
195
219
  /*
196
220
  border-top: 1px solid rgba(255,255,255,0.05);
197
221
  */
@@ -207,7 +231,9 @@ footer b i {
207
231
  }
208
232
  footer b {
209
233
  flex-shrink: 0;
234
+ /*
210
235
  color: var(--dark-btn-color);
236
+ */
211
237
  margin-right: 10px;
212
238
  font-weight: normal;
213
239
  font-size: 11px;
@@ -551,6 +577,7 @@ body.columns main #editor {
551
577
  height: 100% !important;
552
578
  }
553
579
  #terminal {
580
+
554
581
  height: 100%;
555
582
  /*
556
583
  overflow: auto;
@@ -595,9 +622,12 @@ body.columns .containers {
595
622
  height: 100%;
596
623
  }
597
624
  .terminal-container {
625
+ background: white;
598
626
  flex-grow: 1;
599
627
  position: relative;
628
+ /*
600
629
  background: var(--dark-bg);
630
+ */
601
631
  overflow: auto;
602
632
  }
603
633
  .terminal-container #terminal-resize {
@@ -675,10 +705,16 @@ body.columns .containers {
675
705
  margin: 0 auto;
676
706
  }
677
707
  */
708
+ .xterm-rows {
709
+ font-family: "Space Mono", monospace !important;
710
+ font-weight: 400 !important;
711
+ font-style: normal !important;
712
+
713
+ }
678
714
  .xterm {
679
- padding: 10px 20px !important;
680
- /*
681
715
  padding: 0 20px !important;
716
+ /*
717
+ padding: 10px 20px !important;
682
718
  */
683
719
  cursor: pointer;
684
720
  overflow: auto;
@@ -691,15 +727,17 @@ body.columns .containers {
691
727
  .panels > div {
692
728
  width: 50%;
693
729
  }
730
+ /*
694
731
  body.dark header {
695
732
  background: var(--dark-nav-bg);
696
733
  }
734
+ */
697
735
  header {
698
- background: var(--dark-nav-bg);
699
736
  /*
737
+ background: var(--dark-nav-bg);
700
738
  background: var(--light-nav-bg);
701
- */
702
739
  background: white;
740
+ */
703
741
  position: sticky;
704
742
  padding: 10px;
705
743
  top: 0;
@@ -1005,13 +1043,19 @@ body.dark .line i {
1005
1043
  text-align: center;
1006
1044
  }
1007
1045
  .line img {
1008
- /*
1009
- width: 60px;
1010
- height: 60px;
1046
+ width: 50px;
1047
+ height: 50px;
1048
+ /*
1049
+ padding: 10px;
1011
1050
  */
1051
+ padding: 4px;
1052
+ /*
1012
1053
  width: 40px;
1013
1054
  height: 40px;
1055
+ */
1056
+ /*
1014
1057
  border-radius: 10px;
1058
+ */
1015
1059
  }
1016
1060
  body.dark .line .btn {
1017
1061
  color: var(--dark-btn-color);
@@ -1172,7 +1216,7 @@ body.dark .swal2-popup {
1172
1216
  color: var(--dark-btn-color);
1173
1217
  }
1174
1218
  .swal2-popup {
1175
- border-radius: 20px !important;
1219
+ border-radius: 0px !important;
1176
1220
  box-sizing: border-box;
1177
1221
  }
1178
1222
  .swal2-html-container a {
@@ -1331,6 +1375,9 @@ body.dark .swal2-styled.swal2-confirm{
1331
1375
  font-weight: bold;
1332
1376
  border: none;
1333
1377
  }
1378
+ .swal2-input:focus, .swal2-file:focus, .swal2-textarea:focus {
1379
+ box-shadow: none !important;
1380
+ }
1334
1381
  .swal2-input {
1335
1382
  margin: 0 !important;
1336
1383
  width: 100% !important;
@@ -1484,6 +1531,16 @@ b {
1484
1531
  .opener.btn {
1485
1532
  background: royalblue;
1486
1533
  }
1534
+ .field-row {
1535
+ display: flex;
1536
+ align-items: center;
1537
+ }
1538
+ .folder-row .field-row label {
1539
+ font-size: 14px;
1540
+ flex-shrink: 0;
1541
+ padding: 0 5px 0 0;
1542
+ display: block;
1543
+ }
1487
1544
  body.dark #new-window {
1488
1545
  color: var(--dark-btn-color);
1489
1546
  }
@@ -1591,15 +1648,27 @@ nav.error-message {
1591
1648
  color: rgba(0,0,0,0.7);
1592
1649
  font-weight: bold;
1593
1650
  }
1651
+ /*
1594
1652
  .not-running-apps, .running-apps {
1595
1653
  background: rgba(0,0,100,0.04);
1596
1654
  }
1597
1655
  body.dark .not-running-apps, body.dark .running-apps {
1598
1656
  background: rgba(255,255,255,0.03);
1599
1657
  }
1658
+ */
1659
+ /*
1660
+ .running-apps .line .title {
1661
+ color: #82bc09;
1662
+ }
1663
+ */
1600
1664
  .running-apps .line img {
1601
- border: 4px solid #8fd400;
1665
+ background: #82bc09;
1666
+ /*
1667
+ border: 3px solid #8fd400;
1668
+ */
1669
+ /*
1602
1670
  border-radius: 5px;
1671
+ */
1603
1672
  }
1604
1673
  /*
1605
1674
  .running-apps .line.align-top h3 .col .title {
@@ -1701,6 +1770,16 @@ footer.status {
1701
1770
  text-transform: uppercase;
1702
1771
  }
1703
1772
 
1773
+ #fsmenu {
1774
+ /*
1775
+ background: rgba(0,0,100,0.04);
1776
+ */
1777
+ display: flex;
1778
+ padding: 10px;
1779
+ /*
1780
+ padding: 20px 20px 0;
1781
+ */
1782
+ }
1704
1783
  mark{
1705
1784
  background: firebrick;
1706
1785
  color: white;
@@ -1714,3 +1793,46 @@ mark{
1714
1793
  color: royalblue !important;
1715
1794
  cursor: pointer;
1716
1795
  }
1796
+
1797
+ .filepond--image-preview-wrapper {
1798
+ border-radius: 0 !important;
1799
+ }
1800
+
1801
+ .filepond-wrapper {
1802
+ /*
1803
+ position: relative;
1804
+ display: inline-block;
1805
+ */
1806
+ display: flex;
1807
+ }
1808
+ .filepond-wrapper .folder-rows {
1809
+ flex-grow: 1;
1810
+ }
1811
+ .filepond-wrapper .avatar-field {
1812
+ width: 150px;
1813
+ margin-right: 15px;
1814
+ margin-top: 10px;
1815
+ }
1816
+ .folder-row {
1817
+ text-align: left;
1818
+ padding-bottom: 10px;
1819
+ }
1820
+ .folder-row label {
1821
+ padding: 5px 0;
1822
+ display: block;
1823
+ font-size: 14px;
1824
+ }
1825
+ .folderpath {
1826
+ opacity: 0.5;
1827
+ }
1828
+ .swal2-modal .filepond--root button {
1829
+ cursor: pointer;
1830
+ background: black !important;
1831
+ color: white !important;
1832
+ border: 2px solid !important;
1833
+ /*
1834
+ background: unset !important;
1835
+ */
1836
+ padding: unset !important;
1837
+ font-size: unset !important;
1838
+ }
package/server/socket.js CHANGED
@@ -1,8 +1,10 @@
1
1
  const WebSocket = require('ws');
2
+ const Util = require("../kernel/util")
2
3
  class Socket {
3
4
  constructor(parent) {
4
5
  this.buffer = {}
5
6
  this.connected = {}
7
+ this.active_shell = {}
6
8
  this.parent = parent
7
9
  this.server = parent.server
8
10
  // this.kernel = parent.kernel
@@ -17,6 +19,7 @@ class Socket {
17
19
  });
18
20
  ws.on('message', async (message) => {
19
21
  const req = JSON.parse(message);
22
+ console.log({ req })
20
23
  if (req.response) {
21
24
  this.parent.kernel.api.respond(req)
22
25
  } else {
@@ -25,49 +28,109 @@ class Socket {
25
28
  // look for repos that match
26
29
 
27
30
  if (req.uri) {
28
- /******************************************************************
29
- *
30
- * req.uri is ALWAYS either of the two:
31
- * 1. ~/...
32
- * 2. https://github.com/...
33
- *
34
- * Need to turn it into absolute file path before subscribing
35
- *
36
- ******************************************************************/
37
-
38
- // req.uri is always http or absolute path
39
- let id = this.parent.kernel.api.filePath(req.uri)
40
-
41
- if (req.status) {
42
- ws.send(JSON.stringify({
43
- data: this.parent.kernel.api.running[id] ? true : false
44
- }))
45
- } else if (req.stop) {
46
- this.parent.kernel.api.stop({ params: req })
31
+ console.log("## 1")
32
+ if (req.mode === "open") {
33
+ console.log("## 2")
34
+ // get the default script and respond
35
+ let id = this.parent.kernel.api.filePath(req.uri)
36
+ try {
37
+ console.log("## 3")
38
+ let default_url = await this.parent.kernel.api.get_default(id)
39
+ console.log({ id, default_url })
40
+ ws.send(JSON.stringify({
41
+ data: {
42
+ uri: default_url
43
+ }
44
+ }))
45
+ } catch (e) {
46
+ console.log(e)
47
+ }
47
48
  } else {
48
- this.subscribe(ws, id)
49
-
50
- if (req.mode !== "listen") {
51
- // Run only if currently not running
52
- if (!this.parent.kernel.api.running[id]) {
53
-
54
- // clear the log first
55
-
56
- await this.parent.kernel.clearLog(id)
57
-
58
-
59
- this.parent.kernel.api.process(req)
49
+ console.log("## 4")
50
+ console.log("REQ.URI", req.uri)
51
+ if (req.uri.startsWith("http")) {
52
+ console.log("## 5")
53
+ // open
54
+ Util.openfs(req.uri, { mode: "open" })
55
+ } else {
56
+ console.log("## 6")
57
+ console.log("sdfsfsfsdfsd>>>>>>>>>>>>>>>>>>>>>>>>>>>")
58
+ /******************************************************************
59
+ *
60
+ * req.uri is ALWAYS either of the two:
61
+ * 1. ~/...
62
+ * 2. https://github.com/...
63
+ *
64
+ * Need to turn it into absolute file path before subscribing
65
+ *
66
+ ******************************************************************/
67
+
68
+ // req.uri is always http or absolute path
69
+ let id = this.parent.kernel.api.filePath(req.uri)
70
+
71
+ if (req.status) {
72
+ console.log("## 7")
73
+ ws.send(JSON.stringify({
74
+ data: this.parent.kernel.api.running[id] ? true : false
75
+ }))
76
+ } else if (req.stop) {
77
+ console.log("## 8")
78
+ console.log(">>>>>>>>>>>>>>>>>>>>>")
79
+ this.parent.kernel.api.stop({ params: req })
80
+ } else {
81
+ console.log("## 9")
82
+ let buf = this.buffer[id]
83
+ let sh = this.active_shell[id]
84
+ this.subscribe(ws, id, buf, sh)
85
+ if (req.mode !== "listen") {
86
+ console.log("## 10")
87
+ // Run only if currently not running
88
+ if (!this.parent.kernel.api.running[id]) {
89
+ console.log("## 11")
90
+
91
+ // clear the log first
92
+
93
+ await this.parent.kernel.clearLog(id)
94
+
95
+
96
+ this.parent.kernel.api.process(req)
97
+ }
98
+ }
60
99
  }
61
100
  }
62
- }
63
101
 
102
+ }
64
103
  } else if (req.method) {
65
- this.subscribe(ws, req.method)
66
- if (req.mode !== "listen") {
67
- this.parent.kernel.api.process(req)
104
+ if (req.id) {
105
+ console.log("req.id", req.id)
106
+ let buf = this.buffer[req.id]
107
+ let sh = this.active_shell[req.id]
108
+ console.log({ buf, sh })
109
+ this.subscribe(ws, req.id, buf, sh)
110
+ console.log("Process 2")
111
+ if (!sh) {
112
+ //if (req.mode !== "listen") {
113
+ console.log("Process 3")
114
+ this.parent.kernel.api.process(req)
115
+ console.log("Process 4")
116
+ }
117
+ } else {
118
+ console.log("Process 1")
119
+ this.subscribe(ws, req.method)
120
+ console.log("Process 2")
121
+ if (req.mode !== "listen") {
122
+ console.log("Process 3")
123
+ this.parent.kernel.api.process(req)
124
+ console.log("Process 4")
125
+ }
68
126
  }
69
127
  } else if (req.emit) {
70
128
  this.parent.kernel.shell.emit(req)
129
+ } else if (req.key && req.id) {
130
+ this.parent.kernel.shell.emit({
131
+ id: req.id,
132
+ emit: req.key
133
+ })
71
134
  }
72
135
  }
73
136
 
@@ -78,11 +141,16 @@ class Socket {
78
141
  headers.push('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');
79
142
  });
80
143
  }
81
- subscribe(ws, id) {
144
+ subscribe(ws, id, buf, sh) {
82
145
 
83
146
  if (this.parent.kernel.api.running[id]) {
84
147
  ws.send(JSON.stringify({
85
- type: "connect"
148
+ type: "connect",
149
+ data: {
150
+ id,
151
+ state: buf,
152
+ shell: sh
153
+ }
86
154
  }))
87
155
  }
88
156
 
@@ -120,6 +188,15 @@ class Socket {
120
188
  });
121
189
  }
122
190
 
191
+ if (!this.buffer[id]) {
192
+ this.buffer[id] = ""
193
+ }
194
+ if (e.data && e.data.raw) this.buffer[id] += e.data.raw
195
+
196
+ if (e.data && e.data.shell_id) {
197
+ this.active_shell[id] = e.data.shell_id
198
+ }
199
+
123
200
  // send to caller session
124
201
  if (e.caller) {
125
202
  let caller
@@ -148,6 +225,15 @@ class Socket {
148
225
  }
149
226
  });
150
227
  }
228
+
229
+ if (!this.buffer[caller]) {
230
+ this.buffer[caller] = ""
231
+ }
232
+ if (e.data.raw) this.buffer[caller] += e.data.raw
233
+
234
+ if (e.data && e.data.shell_id) {
235
+ this.active_shell[caller] = e.data.shell_id
236
+ }
151
237
  }
152
238
  }
153
239
  }