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
package/server/index.js CHANGED
@@ -18,8 +18,6 @@ const semver = require('semver')
18
18
  const fse = require('fs-extra')
19
19
  const QRCode = require('qrcode')
20
20
 
21
- //const PINOKIO_HOMEPAGE = "http://localhost:3000"
22
-
23
21
  const git = require('isomorphic-git')
24
22
  const http = require('isomorphic-git/http/node')
25
23
  const marked = require('marked')
@@ -29,6 +27,8 @@ const multer = require('multer');
29
27
 
30
28
  const ejs = require('ejs');
31
29
 
30
+ const DEFAULT_PORT = 42000
31
+
32
32
  const ex = fn => (req, res, next) => {
33
33
  Promise.resolve(fn(req, res, next)).catch(next);
34
34
  };
@@ -42,11 +42,13 @@ const packagejson = require("../package.json")
42
42
  const Environment = require("../kernel/environment")
43
43
  const Cloudflare = require("../kernel/api/cloudflare")
44
44
  const Util = require("../kernel/util")
45
+
45
46
  class Server {
46
47
  constructor(config) {
47
48
  this.tabs = {}
48
49
  this.agent = config.agent
49
- this.port = config.port
50
+ this.port = DEFAULT_PORT
51
+ // this.port = config.port
50
52
  this.kernel = new Kernel(config.store)
51
53
  // this.tunnels = {}
52
54
  this.version = {
@@ -85,29 +87,45 @@ class Server {
85
87
  exists (s) {
86
88
  return new Promise(r=>fs.access(s, fs.constants.F_OK, e => r(!e)))
87
89
  }
88
- winBuildNumber() {
89
- let osVersion = (/(\d+)\.(\d+)\.(\d+)/g).exec(os.release());
90
- let buildNumber = 0;
91
- if (osVersion && osVersion.length === 4) {
92
- buildNumber = parseInt(osVersion[3]);
90
+ async updateMeta(formData, app_path) {
91
+ console.log("icon_dirty?", formData.icon_dirty)
92
+ if (formData.icon_dirty) {
93
+ // write icon file
94
+ let icon_path = this.kernel.path("api", formData.new_path, formData.icon_path)
95
+ console.log({ icon_path })
96
+ await fs.promises.writeFile(icon_path, formData.avatar)
93
97
  }
94
- return buildNumber;
95
- }
96
- compatible() {
97
- if (this.kernel.platform === "win32") {
98
- let buildNumber = this.winBuildNumber()
99
- if (buildNumber < 18309) {
100
- // must use conpty for node-pty, and conpty is only supported in win>=18309
101
- console.log("Windows buildNumber", buildNumber)
102
- throw new Error(`Pinokio supports Windows release 18309 and up (current system: ${buildNumber}`)
103
- }
104
98
 
105
- // if (buildNumber > 25000) {
106
- // console.log("Windows buildNumber", buildNumber)
107
- // throw new Error(`Pinokio does not currently support Windows Canary (versions 25000 and up). The current system is ${buildNumber}`)
108
- //
109
- // }
99
+ // write title/description to pinokio_meta.json
100
+ let dirty
101
+ let meta_path = this.kernel.path("api", app_path, "pinokio_meta.json")
102
+ let meta = (await this.kernel.loader.load(meta_path)).resolved
103
+ if (!meta) meta = {}
104
+ if (formData.title) {
105
+ meta.title = formData.title
106
+ dirty = true
110
107
  }
108
+ if (formData.description) {
109
+ meta.description = formData.description
110
+ dirty = true
111
+ }
112
+ if (dirty) {
113
+ await fs.promises.writeFile(meta_path, JSON.stringify(meta, null, 2))
114
+ }
115
+ }
116
+ async createMeta(formData) {
117
+ let icon_path = this.kernel.path("api", formData.path, "icon.png")
118
+ console.log({ icon_path })
119
+ await fs.promises.writeFile(icon_path, formData.avatar)
120
+
121
+ // write title/description to pinokio_meta.json
122
+ let meta_path = this.kernel.path("api", formData.path, "pinokio_meta.json")
123
+ let meta = {
124
+ title: formData.title,
125
+ description: formData.description,
126
+ icon: "icon.png"
127
+ }
128
+ await fs.promises.writeFile(meta_path, JSON.stringify(meta, null, 2))
111
129
  }
112
130
  getMemory(filepath) {
113
131
  let localMem = this.kernel.memory.local[filepath]
@@ -144,8 +162,10 @@ class Server {
144
162
  return items.map((x) => {
145
163
  let name
146
164
  let description
147
- let icon
165
+ let icon = "/pinokio-black.png"
148
166
  let uri
167
+ let iconpath
168
+ let apipath
149
169
  if (meta) {
150
170
  let m = meta[x.name]
151
171
  name = (m && m.title ? m.title : x.name)
@@ -153,7 +173,14 @@ class Server {
153
173
  if (m && m.icon) {
154
174
  icon = m.icon
155
175
  } else {
156
- icon = null
176
+ icon = "/pinokio-black.png"
177
+ //icon = null
178
+ }
179
+ if (m && m.iconpath) {
180
+ iconpath = m.iconpath
181
+ }
182
+ if (m && m.path) {
183
+ apipath = m.path
157
184
  }
158
185
  uri = x.name
159
186
  } else {
@@ -174,6 +201,8 @@ class Server {
174
201
  let browser_browse_url = browser_url + "/browse"
175
202
  return {
176
203
  icon,
204
+ iconpath,
205
+ path: apipath,
177
206
  running: x.running ? true : false,
178
207
  run: x.run,
179
208
  menu: x.menu,
@@ -226,7 +255,12 @@ class Server {
226
255
  let name = req.params.name
227
256
  let app_path = this.kernel.path("api", name, "pinokio.js")
228
257
  let rawpath = "/api/" + name
229
- let config = (await this.kernel.loader.load(app_path)).resolved
258
+ let config1 = (await this.kernel.loader.load(app_path)).resolved
259
+
260
+ let meta_path = this.kernel.path("api", name, "pinokio_meta.json")
261
+ let config2 = (await this.kernel.loader.load(meta_path)).resolved
262
+
263
+ let config = Object.assign({}, config1, config2)
230
264
 
231
265
  let error = null
232
266
  if (config && config.version) {
@@ -300,6 +334,17 @@ class Server {
300
334
  }
301
335
  let platform = os.platform()
302
336
 
337
+ if (config.icon) {
338
+ //config.iconpath = this.kernel.path("api", name, config.icon)
339
+ config.iconpath = config.icon
340
+ config.icon = `${rawpath}/${config.icon}?raw=true`
341
+ } else {
342
+ //config.iconpath = this.kernel.path("api", name, "pinokio_icon.png")
343
+ config.iconpath = "pinokio.png"
344
+ config.icon = "/pinokio-black.png"
345
+ }
346
+
347
+
303
348
 
304
349
  // get all memory variable stied to the current repository
305
350
  let api_path = this.kernel.path("api", name)
@@ -322,7 +367,6 @@ class Server {
322
367
 
323
368
  await this.init_env("api/" + name)
324
369
 
325
-
326
370
  let mode = "run"
327
371
  if (req.query && req.query.mode) {
328
372
  mode = req.query.mode
@@ -331,6 +375,17 @@ class Server {
331
375
 
332
376
  // profile + feed
333
377
  const repositoryPath = path.resolve(this.kernel.api.userdir, name)
378
+ console.log({ repositoryPath })
379
+
380
+ try {
381
+ await git.resolveRef({ fs, dir: repositoryPath, ref: 'HEAD' });
382
+ } catch (err) {
383
+ // repo doesn't exist. initialize.
384
+ console.log(`repo doesn't exist at ${repositoryPath}. initialize`)
385
+ await git.init({ fs, dir: repositoryPath });
386
+ }
387
+
388
+
334
389
  let gitRemote = await git.getConfig({ fs, http, dir: repositoryPath, path: 'remote.origin.url' })
335
390
  let profile
336
391
  let feed
@@ -500,84 +555,8 @@ class Server {
500
555
  display: ["form"]
501
556
  })
502
557
  } else if (pathComponents.length === 0 && req.query.mode === "download") {
503
-
504
- let requirements = [{
505
- name: "conda",
506
- }, {
507
- name: "git",
508
- }, {
509
- name: "zip",
510
- }, {
511
- name: "node",
512
- }, {
513
- name: "ffmpeg",
514
- // type: "conda",
515
- // name: "ffmpeg",
516
- // args: "-c conda-forge"
517
- }]
518
- let platform = os.platform()
519
- if (platform === "win32") {
520
- requirements.push({
521
- name: "registry"
522
- })
523
- requirements.push({
524
- name: "vs"
525
- })
526
- }
527
- if (platform === "darwin") {
528
- requirements.push({
529
- name: "brew"
530
- })
531
- }
532
- if (platform === "linux") {
533
- requirements.push({
534
- name: "gxx"
535
- })
536
- }
537
- if (this.kernel.gpu === "nvidia") {
538
- requirements.push({
539
- name: "cuda",
540
- })
541
- }
542
- requirements = requirements.concat([{
543
- name: "py"
544
- }, {
545
- name: "cloudflared"
546
- }, {
547
- name: "playwright"
548
- }, {
549
- name: "huggingface"
550
- }, {
551
- name: "uv"
552
- }])
553
-
554
- let requirements_pending = !this.kernel.bin.installed_initialized
555
-
556
-
557
- let install_required = true
558
- if (!requirements_pending) {
559
- install_required = false
560
- for(let i=0; i<requirements.length; i++) {
561
- let r = requirements[i]
562
- console.time(r.name)
563
- let installed = await this.installed(r)
564
- console.log({ r, installed })
565
- console.timeEnd(r.name)
566
- requirements[i].installed = installed
567
- if (!installed) {
568
- install_required = true
569
- }
570
- }
571
- }
572
-
573
- let error = null
574
- try {
575
- this.compatible()
576
- } catch (e) {
577
- error = e.message
578
- install_required = true
579
- }
580
-
558
+ let { requirements, install_required, requirements_pending, error } = await this.kernel.bin.check_bin()
559
+ console.log({ requirements, install_required, requirements_pending })
581
560
 
582
561
  res.render("download", {
583
562
  error,
@@ -959,7 +938,7 @@ class Server {
959
938
 
960
939
  let error = null
961
940
  try {
962
- this.compatible()
941
+ this.kernel.bin.compatible()
963
942
  } catch (e) {
964
943
  error = e.message
965
944
  install_required = true
@@ -1111,6 +1090,7 @@ class Server {
1111
1090
  // look for README.md
1112
1091
 
1113
1092
  let config
1093
+ console.log("f.files", f.files)
1114
1094
  for(let file of f.files) {
1115
1095
  if (file.name.toLowerCase() === "readme.md") {
1116
1096
  let p = path.resolve(filepath, file.name)
@@ -1163,6 +1143,24 @@ class Server {
1163
1143
  config.update = "/api/" + link
1164
1144
  }
1165
1145
  }
1146
+
1147
+ // override config
1148
+ if (file.name === "pinokio_meta.json") {
1149
+ let p = path.resolve(filepath, file.name)
1150
+ let c = (await this.kernel.loader.load(p)).resolved
1151
+ if (c.title) {
1152
+ if (!config) config = {}
1153
+ config.title = c.title
1154
+ }
1155
+ if (c.description) {
1156
+ if (!config) config = {}
1157
+ config.description = c.description
1158
+ }
1159
+ if (c.icon) {
1160
+ if (!config) config = {}
1161
+ config.icon = c.icon
1162
+ }
1163
+ }
1166
1164
  }
1167
1165
  if (!config) config = {}
1168
1166
 
@@ -1284,11 +1282,13 @@ class Server {
1284
1282
 
1285
1283
  // check if there is a running process with this folder name
1286
1284
  let runningApps = new Set()
1285
+ console.log("running", this.kernel.api.running)
1287
1286
  for(let key in this.kernel.api.running) {
1288
1287
  let p = this.kernel.path("api", items[i].name) + path.sep
1289
1288
  //let re = new RegExp(items[i].name)
1290
1289
  //if (re.test(key)) {
1291
1290
  //if (p === key) {
1291
+ console.log({ key, p})
1292
1292
  if (key.includes(p)) {
1293
1293
  items[i].running = true
1294
1294
  items[i].index = index
@@ -1299,7 +1299,7 @@ class Server {
1299
1299
  }
1300
1300
  index++;
1301
1301
  running.push(items[i])
1302
- break
1302
+ // break
1303
1303
  }
1304
1304
  }
1305
1305
  if (!items[i].running) {
@@ -1321,7 +1321,9 @@ class Server {
1321
1321
  //let name = (x.name.startsWith("0x") ? Buffer.from(x.name.slice(2), "hex").toString() : x.name)
1322
1322
  let name
1323
1323
  let description
1324
- let icon
1324
+ let icon = "/pinokio-black.png"
1325
+ let iconpath
1326
+ let apipath
1325
1327
  let uri
1326
1328
  if (meta) {
1327
1329
  let m = meta[x.name]
@@ -1330,7 +1332,14 @@ class Server {
1330
1332
  if (m && m.icon) {
1331
1333
  icon = m.icon
1332
1334
  } else {
1333
- icon = null
1335
+ //icon = null
1336
+ icon = "/pinokio-black.png"
1337
+ }
1338
+ if (m && m.iconpath) {
1339
+ iconpath = m.iconpath
1340
+ }
1341
+ if (m && m.path) {
1342
+ apipath = m.path
1334
1343
  }
1335
1344
  uri = x.name
1336
1345
  } else {
@@ -1344,6 +1353,8 @@ class Server {
1344
1353
  }
1345
1354
  return {
1346
1355
  icon,
1356
+ iconpath,
1357
+ path: apipath,
1347
1358
  menu: x.menu,
1348
1359
  run: x.run,
1349
1360
  shortcuts: x.shortcuts,
@@ -1359,6 +1370,8 @@ class Server {
1359
1370
  }
1360
1371
  })
1361
1372
 
1373
+ console.log("ITEMS", items)
1374
+
1362
1375
  // if (req.query && req.query.mode === "task") {
1363
1376
  // running = running.filter((x) => {
1364
1377
  // return x.run && Array.isArray(x.run)
@@ -1416,6 +1429,7 @@ class Server {
1416
1429
  if (meta) {
1417
1430
  items = running.concat(notRunning)
1418
1431
  res.render("index", {
1432
+ folders: null,
1419
1433
  launch_complete: this.kernel.launch_complete,
1420
1434
  home_url: `http://localhost:${this.port}`,
1421
1435
  proxy: home_proxy,
@@ -1552,6 +1566,9 @@ class Server {
1552
1566
  if (menuitem.fs) {
1553
1567
  // file explorer
1554
1568
  config.menu[i].href = path.resolve(this.kernel.homedir, "api", name, menuitem.href)
1569
+ } else if (menuitem.command) {
1570
+ // file explorer
1571
+ config.menu[i].href = path.resolve(this.kernel.homedir, "api", name, menuitem.href)
1555
1572
  } else {
1556
1573
  let absolute = path.resolve(__dirname, ...pathComponents, menuitem.href)
1557
1574
  let seed = path.resolve(__dirname)
@@ -1725,6 +1742,14 @@ class Server {
1725
1742
  //
1726
1743
  // console.log("MENU", JSON.stringify(config.menu, null, 2))
1727
1744
 
1745
+ // if (!config.icon) {
1746
+ // if (this.theme === "light") {
1747
+ // config.icon = "/pinokio-black.png"
1748
+ // } else {
1749
+ // config.icon = "/pinokio-white.png"
1750
+ // }
1751
+ // }
1752
+ // console.log("############## config", config)
1728
1753
 
1729
1754
  return config
1730
1755
  } else {
@@ -1929,79 +1954,78 @@ class Server {
1929
1954
  // 5. existing home is NOT set + new home is set => go through with the "home" setting procedure
1930
1955
  // 6. existing home is NOT set + new home is NOT set => don't touch anything => the homedir will be the default home
1931
1956
 
1932
- // 2. HOME
1933
- // 2.1. Check if the config includes NEW_HOME => if so,
1934
- // - move the HOME folder to NEW_HOME
1935
- // - set HOME=NEW_HOME
1936
- // - remove NEW_HOME
1937
- let existing_home = this.kernel.store.get("home")
1938
- let new_home = this.kernel.store.get("new_home")
1939
-
1940
- if (existing_home) {
1941
- let exists = await fse.pathExists(existing_home)
1942
- if (exists) {
1943
- if (new_home) {
1944
- let new_home_exists = await fse.pathExists(new_home)
1945
- if (new_home_exists) {
1946
- // - existing home is set
1947
- // - existing home exists
1948
- // - new home is set
1949
- // - new home exists already
1950
- // => delete store.new_home ==> will load at store.home
1951
- this.kernel.store.delete("new_home")
1952
- } else {
1953
- // - existing home is set
1954
- // - existing home exists
1955
- // - new home is set
1956
- // - new home does not exist
1957
- // => run mv()
1958
- // => update store.home
1959
- // => delete store.new_home
1960
- await this.mv(existing_home, new_home)
1961
- this.kernel.store.set("home", new_home)
1962
- this.kernel.store.delete("new_home")
1963
- }
1964
- } else {
1965
- // - existing home is set
1966
- // - existing home exists
1967
- // - new home is not set
1968
- // => This is most typical scenario => don't touch anything => the homedir will be the existing home
1969
- }
1970
- } else {
1971
- if (new_home) {
1972
- // - existing home is set
1973
- // - but the existing home path DOES NOT exist
1974
- // - new home is set
1975
- // => This is an invalid scenario => Just to avoid disaster, just delete store.home and delete store.new_home
1976
- // => the app will load at ~/pinokio
1977
- this.kernel.store.delete("home")
1978
- this.kernel.store.delete("new_home")
1979
- } else {
1980
- // - existing home is set
1981
- // - but the existing home path DOES NOT exist
1982
- // - new home is NOT set
1983
- // => This is an invalid scenario => just delete store.home
1984
- // => the app will load at ~/pinokio
1985
- this.kernel.store.delete("home")
1986
- }
1987
- }
1988
- } else {
1989
- if (new_home) {
1990
- // - existing home is NOT set
1991
- // - new home is set
1992
- // => update store.home
1993
- // => delete store.new_home
1994
- this.kernel.store.set("home", new_home)
1995
- this.kernel.store.delete("new_home")
1996
- } else {
1997
- // - existing home is NOT set
1998
- // - new home is NOT set
1999
- // => don't touch anything => will load at ~/pinokio
2000
- }
2001
- }
1957
+ // // 2. HOME
1958
+ // // 2.1. Check if the config includes NEW_HOME => if so,
1959
+ // // - move the HOME folder to NEW_HOME
1960
+ // // - set HOME=NEW_HOME
1961
+ // // - remove NEW_HOME
1962
+ // let existing_home = this.kernel.store.get("home")
1963
+ // let new_home = this.kernel.store.get("new_home")
1964
+ //
1965
+ // if (existing_home) {
1966
+ // let exists = await fse.pathExists(existing_home)
1967
+ // if (exists) {
1968
+ // if (new_home) {
1969
+ // let new_home_exists = await fse.pathExists(new_home)
1970
+ // if (new_home_exists) {
1971
+ // // - existing home is set
1972
+ // // - existing home exists
1973
+ // // - new home is set
1974
+ // // - new home exists already
1975
+ // // => delete store.new_home ==> will load at store.home
1976
+ // this.kernel.store.delete("new_home")
1977
+ // } else {
1978
+ // // - existing home is set
1979
+ // // - existing home exists
1980
+ // // - new home is set
1981
+ // // - new home does not exist
1982
+ // // => run mv()
1983
+ // // => update store.home
1984
+ // // => delete store.new_home
1985
+ // await this.mv(existing_home, new_home)
1986
+ // this.kernel.store.set("home", new_home)
1987
+ // this.kernel.store.delete("new_home")
1988
+ // }
1989
+ // } else {
1990
+ // // - existing home is set
1991
+ // // - existing home exists
1992
+ // // - new home is not set
1993
+ // // => This is most typical scenario => don't touch anything => the homedir will be the existing home
1994
+ // }
1995
+ // } else {
1996
+ // if (new_home) {
1997
+ // // - existing home is set
1998
+ // // - but the existing home path DOES NOT exist
1999
+ // // - new home is set
2000
+ // // => This is an invalid scenario => Just to avoid disaster, just delete store.home and delete store.new_home
2001
+ // // => the app will load at ~/pinokio
2002
+ // this.kernel.store.delete("home")
2003
+ // this.kernel.store.delete("new_home")
2004
+ // } else {
2005
+ // // - existing home is set
2006
+ // // - but the existing home path DOES NOT exist
2007
+ // // - new home is NOT set
2008
+ // // => This is an invalid scenario => just delete store.home
2009
+ // // => the app will load at ~/pinokio
2010
+ // this.kernel.store.delete("home")
2011
+ // }
2012
+ // }
2013
+ // } else {
2014
+ // if (new_home) {
2015
+ // // - existing home is NOT set
2016
+ // // - new home is set
2017
+ // // => update store.home
2018
+ // // => delete store.new_home
2019
+ // this.kernel.store.set("home", new_home)
2020
+ // this.kernel.store.delete("new_home")
2021
+ // } else {
2022
+ // // - existing home is NOT set
2023
+ // // - new home is NOT set
2024
+ // // => don't touch anything => will load at ~/pinokio
2025
+ // }
2026
+ // }
2002
2027
  }
2003
2028
  async setConfig(config) {
2004
- console.log("setConfig", config)
2005
2029
  let home = this.kernel.store.get("home")
2006
2030
  let theme = this.kernel.store.get("theme")
2007
2031
  // let drive = this.kernel.store.get("drive")
@@ -2024,13 +2048,14 @@ class Server {
2024
2048
  throw new Error("Invalid path: " + config.home)
2025
2049
  }
2026
2050
 
2027
- // check if the destination already exists => throw error
2028
- let exists = await fse.pathExists(config.home)
2029
- if (exists) {
2030
- throw new Error(`The path ${config.home} already exists. Please remove the folder and retry`)
2031
- }
2051
+ // // check if the destination already exists => throw error
2052
+ // let exists = await fse.pathExists(config.home)
2053
+ // if (exists) {
2054
+ // throw new Error(`The path ${config.home} already exists. Please remove the folder and retry`)
2055
+ // }
2032
2056
 
2033
- this.kernel.store.set("new_home", config.home)
2057
+ //this.kernel.store.set("new_home", config.home)
2058
+ this.kernel.store.set("home", config.home)
2034
2059
  }
2035
2060
 
2036
2061
  }
@@ -2071,7 +2096,16 @@ class Server {
2071
2096
  // if (config.HTTPS_PROXY) {
2072
2097
  // updated.HTTPS_PROXY = config.HTTPS_PROXY
2073
2098
  // }
2074
-
2099
+ if (this.kernel.homedir) {
2100
+ const updated = {
2101
+ HTTP_PROXY: config.HTTP_PROXY,
2102
+ HTTPS_PROXY: config.HTTPS_PROXY,
2103
+ NO_PROXY: config.NO_PROXY,
2104
+ }
2105
+ let fullpath = path.resolve(this.kernel.homedir, "ENVIRONMENT")
2106
+ console.log({ updated })
2107
+ await Util.update_env(fullpath, updated)
2108
+ }
2075
2109
 
2076
2110
  this.kernel.store.set("HTTP_PROXY", config.HTTP_PROXY)
2077
2111
  this.kernel.store.set("HTTPS_PROXY", config.HTTPS_PROXY)
@@ -2112,6 +2146,15 @@ class Server {
2112
2146
  }
2113
2147
  }
2114
2148
  }
2149
+ async running(port) {
2150
+ let p = port || DEFAULT_PORT
2151
+ const available = await Util.is_port_available(p)
2152
+ if (available) {
2153
+ return false
2154
+ } else {
2155
+ return true
2156
+ }
2157
+ }
2115
2158
  async start(options) {
2116
2159
  console.time("SERVER START")
2117
2160
  this.debug = false
@@ -2168,7 +2211,7 @@ class Server {
2168
2211
  // determine port if port is not passed in
2169
2212
 
2170
2213
  if (!this.port) {
2171
- this.port = 42000
2214
+ this.port = DEFAULT_PORT
2172
2215
  // let platform = os.platform()
2173
2216
  // if (platform === 'linux') {
2174
2217
  // // on linux you are not allowed to listen on ports below 1024
@@ -2213,17 +2256,23 @@ class Server {
2213
2256
  console.log(`[TRY] reset ${p}`)
2214
2257
  await fse.remove(p)
2215
2258
  console.log(`[DONE] reset ${p}`)
2259
+
2260
+ let p2 = path.resolve(home, "prototype")
2261
+ await fse.remove(p2)
2262
+
2216
2263
  console.log("[TRY] Updating to the new version")
2217
2264
  this.kernel.store.set("version", this.version.pinokiod)
2218
2265
  console.log("[DONE] Updating to the new version")
2266
+
2267
+
2219
2268
  }
2220
2269
  }
2221
-
2222
2270
  // initialize kernel
2223
2271
  console.time(">>>> 4 kernel.init")
2224
2272
  await this.kernel.init({ port: this.port})
2225
2273
  console.timeEnd(">>>> 4 kernel.init")
2226
2274
 
2275
+
2227
2276
  console.time(">>>> 5 kernel.initHome")
2228
2277
  console.log({ needInitHome })
2229
2278
  if (needInitHome) {
@@ -2331,6 +2380,7 @@ class Server {
2331
2380
 
2332
2381
  if (this.kernel.homedir) {
2333
2382
  this.app.use(express.static(this.kernel.path("web/public")))
2383
+ this.app.use('/prototype', express.static(this.kernel.path("prototype")))
2334
2384
  }
2335
2385
  this.app.use(express.static(path.resolve(__dirname, 'public')));
2336
2386
  this.app.use("/web", express.static(path.resolve(__dirname, "..", "..", "web")))
@@ -2354,6 +2404,7 @@ class Server {
2354
2404
  //let home = this.kernel.homedir
2355
2405
  //let home = this.kernel.store.get("home")
2356
2406
  this.app.get("/", ex(async (req, res) => {
2407
+ console.log("Shells", this.kernel.shell.shells.length)
2357
2408
  if (req.query.mode !== "settings" && !home) {
2358
2409
  res.redirect("/?mode=settings")
2359
2410
  return
@@ -2459,14 +2510,28 @@ class Server {
2459
2510
  for(let folder of folders) {
2460
2511
  let p = path.resolve(apipath, folder, "pinokio.js")
2461
2512
  let pinokio = (await this.kernel.loader.load(p)).resolved
2462
- if (pinokio) {
2463
- meta[folder] = {
2464
- title: pinokio.title,
2465
- description: pinokio.description,
2466
- icon: pinokio.icon ? `/api/${folder}/${pinokio.icon}?raw=true` : null
2467
- }
2468
- }
2513
+ let p2 = path.resolve(apipath, folder, "pinokio_meta.json")
2514
+ let pinokio2 = (await this.kernel.loader.load(p2)).resolved
2515
+
2516
+ meta[folder] = Object.assign({}, pinokio, pinokio2)
2517
+ meta[folder].iconpath = meta[folder].icon ? path.resolve(apipath, folder, meta[folder].icon) : null
2518
+ meta[folder].icon = meta[folder].icon ? `/api/${folder}/${meta[folder].icon}?raw=true` : null
2519
+ meta[folder].path = path.resolve(apipath, folder)
2520
+
2521
+ // if (pinokio) {
2522
+ // meta[folder] = {
2523
+ // title: pinokio.title,
2524
+ // description: pinokio.description,
2525
+ // icon: pinokio.icon ? `/api/${folder}/${pinokio.icon}?raw=true` : null
2526
+ // }
2527
+ // }
2528
+ // if (pinokio2) {
2529
+ // if (pinokio2.title) meta[folder].title = pinokio2.title
2530
+ // if (pinokio2.description) meta[folder].description = pinokio2.description
2531
+ // if (pinokio2.icon) meta[folder].icon = pinokio2.icon
2532
+ // }
2469
2533
  }
2534
+ console.log("META", { meta })
2470
2535
  await this.render(req, res, [], meta)
2471
2536
  // if (this.kernel.bin.all_installed) {
2472
2537
  // this.started = true
@@ -2503,9 +2568,18 @@ class Server {
2503
2568
  }))
2504
2569
 
2505
2570
  this.app.post("/openfs", ex(async (req, res) => {
2506
- Util.openfs(req.body.path, req.body.mode)
2571
+ //Util.openfs(req.body.path, req.body.mode)
2572
+ Util.openfs(req.body.path, req.body, this.kernel)
2507
2573
  res.json({ success: true })
2508
2574
  }))
2575
+ this.app.get("/terminal/:api/:id", ex(async (req, res) => {
2576
+ res.render("minterm", {
2577
+ theme: this.theme,
2578
+ agent: this.agent,
2579
+ cwd: this.kernel.path("api/" + req.params.api),
2580
+ id: req.params.id
2581
+ })
2582
+ }))
2509
2583
  this.app.get("/proxy", ex(async (req, res) => {
2510
2584
  let live_proxies = this.kernel.api.proxies["/proxy"]
2511
2585
  if (!live_proxies) live_proxies = []
@@ -2563,13 +2637,24 @@ class Server {
2563
2637
  for(let folder of folders) {
2564
2638
  let p = path.resolve(apipath, folder, "pinokio.js")
2565
2639
  let pinokio = (await this.kernel.loader.load(p)).resolved
2640
+ let p2 = path.resolve(apipath, folder, "pinokio_meta.json")
2641
+ let pinokio2 = (await this.kernel.loader.load(p2)).resolved
2642
+ let cc;
2566
2643
  if (pinokio) {
2567
- apps.push({
2644
+ cc = {
2568
2645
  name: pinokio.title,
2569
2646
  description: pinokio.description,
2570
2647
  link: `/pinokio/browser/${folder}/browse#n1`,
2571
2648
  icon: pinokio.icon ? `/api/${folder}/${pinokio.icon}?raw=true` : null
2572
- })
2649
+ }
2650
+ }
2651
+ if (pinokio2) {
2652
+ if (pinokio2.title) cc.title = pinokio2.title
2653
+ if (pinokio2.description) cc.description = pinokio2.description
2654
+ if (pinokio2.icon) cc.icon = pinokio2.icon
2655
+ }
2656
+ if (cc) {
2657
+ apps.push(cc)
2573
2658
  }
2574
2659
  }
2575
2660
  res.render("proxy", {
@@ -2587,6 +2672,35 @@ class Server {
2587
2672
  let str = await fs.promises.readFile(req.query.logpath, "utf8")
2588
2673
  res.send(str)
2589
2674
  }))
2675
+ this.app.post("/mkdir", ex(async (req, res) => {
2676
+ let folder = req.body.folder
2677
+ let folder_path = path.resolve(this.kernel.api.userdir, req.body.folder)
2678
+ try {
2679
+ await fs.promises.mkdir(folder_path)
2680
+ res.json({
2681
+ success: "/pinokio/browser/"+folder
2682
+ })
2683
+ } catch (e) {
2684
+ res.json({
2685
+ error: e.message
2686
+ })
2687
+ }
2688
+ }))
2689
+ this.app.post("/copy", ex(async (req, res) => {
2690
+ let src_path = path.resolve(this.kernel.api.userdir, req.body.src)
2691
+ let dest_path = path.resolve(this.kernel.api.userdir, req.body.dest)
2692
+ console.log({ src_path, dest_path })
2693
+ try {
2694
+ await fs.promises.cp(src_path, dest_path, { recursive: true })
2695
+ res.json({
2696
+ success: "/pinokio/browser/"+ req.body.dest + "/browse"
2697
+ })
2698
+ } catch (e) {
2699
+ res.json({
2700
+ error: e.message
2701
+ })
2702
+ }
2703
+ }))
2590
2704
  this.app.post("/proxy", ex(async (req, res) => {
2591
2705
  /*
2592
2706
  req.body := {
@@ -2675,6 +2789,36 @@ class Server {
2675
2789
  res.json({ error: "type must be 'local' or 'cloudflare'" })
2676
2790
  }
2677
2791
  }))
2792
+ this.app.get("/new", ex(async (req, res) => {
2793
+ console.log("items", this.kernel.proto.items)
2794
+ res.render("prototypes", {
2795
+ items: this.kernel.proto.items,
2796
+ logo: this.logo,
2797
+ theme: this.theme,
2798
+ agent: this.agent,
2799
+ kernel: this.kernel,
2800
+ })
2801
+ }))
2802
+ this.app.get("/prototypes/:type", ex(async (req, res) => {
2803
+ let script = this.kernel.proto.kv[req.params.type]
2804
+ res.render("local_editor", {
2805
+ type: req.params.type,
2806
+ script,
2807
+ theme: this.theme,
2808
+ agent: this.agent,
2809
+ items: (script.input || []),
2810
+ })
2811
+ }))
2812
+ this.app.post("/prototypes/:type", ex(async (req, res) => {
2813
+ let script = this.kernel.proto.kv[req.params.type]
2814
+ console.log({ script, body: req.body })
2815
+ try {
2816
+ const folder = await script.run(this.kernel, req.body)
2817
+ res.json({ success: folder })
2818
+ } catch (e) {
2819
+ res.json({ error: e.message })
2820
+ }
2821
+ }))
2678
2822
  this.app.post("/env", ex(async (req, res) => {
2679
2823
  let fullpath = path.resolve(this.kernel.homedir, req.body.filepath, "ENVIRONMENT")
2680
2824
  let updated = req.body.vals
@@ -2724,6 +2868,8 @@ class Server {
2724
2868
  }
2725
2869
  if (config.icon) {
2726
2870
  config.icon = `/${env_path}/${config.icon}?raw=true`
2871
+ } else {
2872
+ config.icon = "/pinokio-black.png"
2727
2873
  }
2728
2874
 
2729
2875
  let name
@@ -2784,6 +2930,8 @@ class Server {
2784
2930
  config.pre.forEach((item) => {
2785
2931
  if (item.icon) {
2786
2932
  item.icon = `/api/${req.params.name}/${item.icon}?raw=true`
2933
+ } else {
2934
+ item.icon = "/pinokio-black.png"
2787
2935
  }
2788
2936
  if (!item.href.startsWith("http")) {
2789
2937
  item.href = path.resolve(this.kernel.homedir, "api", req.params.name, item.href)
@@ -2939,7 +3087,13 @@ class Server {
2939
3087
  }))
2940
3088
  this.app.get("/api/*", ex(async (req, res) => {
2941
3089
  let pathComponents = req.params[0].split("/")
2942
- if (req.query && 'fs' in req.query) {
3090
+ if (req.query && 'command' in req.query) {
3091
+ let full_filepath = this.kernel.path("api", ...pathComponents)
3092
+ Util.openfs(full_filepath, { command: req.query.command })
3093
+ res.render("fs", {
3094
+ path: full_filepath
3095
+ })
3096
+ } else if (req.query && 'fs' in req.query) {
2943
3097
  // open in file system
2944
3098
  let full_filepath = this.kernel.path("api", ...pathComponents)
2945
3099
  if (req.query.fs) {
@@ -3262,6 +3416,115 @@ class Server {
3262
3416
  }
3263
3417
  res.redirect(webpath)
3264
3418
  }))
3419
+ this.app.get("/pinokio/folder/:id", ex(async (req, res) => {
3420
+ let folder = this.kernel.proto.kv[req.params.id]
3421
+ res.json(folder)
3422
+ }))
3423
+ this.app.post("/pinokio/create_folder", this.upload.any(), ex(async (req, res) => {
3424
+ try {
3425
+ /*
3426
+ {
3427
+ title,
3428
+ description,
3429
+ path,
3430
+ id
3431
+ }
3432
+ */
3433
+ let formData = req.body
3434
+ for(let key in req.files) {
3435
+ let file = req.files[key]
3436
+ formData[file.fieldname] = file.buffer
3437
+ }
3438
+ console.log({ formData })
3439
+ // 1. instantiate based on id
3440
+ let script = this.kernel.proto.kv[formData.id]
3441
+ await script.run(this.kernel, formData)
3442
+ // 2. create pinokio_meta.json
3443
+ await this.createMeta(formData)
3444
+ res.json({ success: true })
3445
+ } catch (e) {
3446
+ console.log("e", e)
3447
+ console.log("e.message", e.message)
3448
+ res.status(500).json({ error: e.message })
3449
+ }
3450
+ }))
3451
+ this.app.post("/pinokio/upload", this.upload.any(), ex(async (req, res) => {
3452
+ try {
3453
+
3454
+
3455
+ /*
3456
+ 1. edit
3457
+ 2. copy
3458
+ 3. copy + edit
3459
+ 4. move
3460
+ 5. move + edit
3461
+
3462
+ */
3463
+
3464
+ let formData = req.body
3465
+ for(let key in req.files) {
3466
+ let file = req.files[key]
3467
+ formData[file.fieldname] = file.buffer
3468
+ }
3469
+ console.log({ formData })
3470
+
3471
+ if (formData.edit) {
3472
+ if (formData.copy) {
3473
+ if (formData.old_path !== formData.new_path) {
3474
+
3475
+ // 1. copy first
3476
+ let old_path = this.kernel.path("api", formData.old_path)
3477
+ let new_path = this.kernel.path("api", formData.new_path)
3478
+ console.log({ old_path, new_path })
3479
+ await fs.promises.cp(old_path, new_path, { recursive: true })
3480
+
3481
+ // 2. edit meta in the new_path
3482
+ await this.updateMeta(formData, formData.new_path)
3483
+
3484
+ }
3485
+ } else if (formData.move) {
3486
+
3487
+ // 1. move first
3488
+ if (formData.old_path !== formData.new_path) {
3489
+ let old_path = this.kernel.path("api", formData.old_path)
3490
+ let new_path = this.kernel.path("api", formData.new_path)
3491
+ console.log({ old_path, new_path })
3492
+ await fs.promises.rename(old_path, new_path)
3493
+ }
3494
+
3495
+ // 2. edit meta in the new_path
3496
+ await this.updateMeta(formData, formData.new_path)
3497
+ } else {
3498
+ // 1. edit only
3499
+ if (formData.old_path === formData.new_path) {
3500
+ await this.updateMeta(formData, formData.new_path)
3501
+ }
3502
+ }
3503
+ } else {
3504
+ if (formData.copy) {
3505
+ // 1. copy only
3506
+ let old_path = this.kernel.path("api", formData.old_path)
3507
+ let new_path = this.kernel.path("api", formData.new_path)
3508
+ console.log({ old_path, new_path })
3509
+ await fs.promises.cp(old_path, new_path, { recursive: true })
3510
+ } else if (formData.move) {
3511
+ // 2. move only
3512
+ let old_path = this.kernel.path("api", formData.old_path)
3513
+ let new_path = this.kernel.path("api", formData.new_path)
3514
+ console.log({ old_path, new_path })
3515
+ await fs.promises.rename(old_path, new_path)
3516
+ } else {
3517
+ // nothing
3518
+ }
3519
+ }
3520
+ res.json({ success: true, reload: formData.new_path })
3521
+ } catch (e) {
3522
+ console.log("e", e)
3523
+ console.log("e.message", e.message)
3524
+ res.status(500).json({ error: e.message })
3525
+ }
3526
+
3527
+ }))
3265
3528
  /*
3266
3529
  SYNTAX
3267
3530
  fs.uri(<bin|api>, path)
@@ -3321,12 +3584,15 @@ class Server {
3321
3584
  object that's not (array, file, blob, uint8array, arraybuffer) => Object
3322
3585
  the rest => typeof(value)
3323
3586
  */
3587
+ console.log("req", req)
3324
3588
  let formData = req.body
3325
3589
  for(let key in req.files) {
3326
3590
  let file = req.files[key]
3327
3591
  formData[file.fieldname] = file.buffer
3328
3592
  }
3329
3593
 
3594
+ console.log({ formData })
3595
+
3330
3596
  const drive = formData.drive
3331
3597
  const home = formData.path
3332
3598
  const method = formData.method
@@ -3460,56 +3726,6 @@ class Server {
3460
3726
  console.log({ requirements_pending })
3461
3727
  res.json({ requirements_pending })
3462
3728
  }))
3463
- this.app.get("/feed/:name", ex(async (req, res) => {
3464
- try {
3465
- const repositoryPath = path.resolve(this.kernel.api.userdir, req.params.name)
3466
- let gitRemote = await git.getConfig({
3467
- fs,
3468
- http,
3469
- dir: repositoryPath,
3470
- path: 'remote.origin.url'
3471
- })
3472
- gitRemote = gitRemote.replace(/\.git$/i, '')
3473
-
3474
- let system_env = {}
3475
- if (this.kernel.homedir) {
3476
- system_env = await Environment.get(this.kernel.homedir)
3477
- }
3478
- const PINOKIO_HOMEPAGE = system_env.PINOKIO_HOMEPAGE || "https://pinokio.computer"
3479
-
3480
- let url = `${PINOKIO_HOMEPAGE}/i?uri=${gitRemote}&display=feed`
3481
- console.log({ url })
3482
- res.redirect(url)
3483
- } catch (e) {
3484
- console.log(e)
3485
- res.redirect(PINOKIO_HOMEPAGE)
3486
- }
3487
- }))
3488
- this.app.get("/profile/:name", ex(async (req, res) => {
3489
- try {
3490
- const repositoryPath = path.resolve(this.kernel.api.userdir, req.params.name)
3491
- let gitRemote = await git.getConfig({
3492
- fs,
3493
- http,
3494
- dir: repositoryPath,
3495
- path: 'remote.origin.url'
3496
- })
3497
- gitRemote = gitRemote.replace(/\.git$/i, '')
3498
-
3499
- let system_env = {}
3500
- if (this.kernel.homedir) {
3501
- system_env = await Environment.get(this.kernel.homedir)
3502
- }
3503
- const PINOKIO_HOMEPAGE = system_env.PINOKIO_HOMEPAGE || "https://pinokio.computer"
3504
-
3505
- let url = `${PINOKIO_HOMEPAGE}/i?uri=${gitRemote}&display=profile`
3506
- console.log({ url })
3507
- res.redirect(url)
3508
- } catch (e) {
3509
- console.log(e)
3510
- res.redirect(PINOKIO_HOMEPAGE)
3511
- }
3512
- }))
3513
3729
  this.app.get("/check", ex((req, res) => {
3514
3730
  res.json({ success: true })
3515
3731
  }))