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
@@ -28,6 +28,7 @@ const semver = require('semver')
28
28
  const Environment = require('../environment')
29
29
  //const imageToAscii = require("image-to-ascii");
30
30
 
31
+ const Setup = require('./setup')
31
32
 
32
33
 
33
34
  //const Puppet = require("./puppeteer")
@@ -37,6 +38,18 @@ class Bin {
37
38
  this.arch = os.arch()
38
39
  this.platform = os.platform()
39
40
  }
41
+ async shell_kill(params, ondata) {
42
+ this.kernel.shell.kill(params.params)
43
+ }
44
+ async shell_start(params, ondata) {
45
+ params.path = params.path || this.path()
46
+ if (this.client) {
47
+ params.cols = this.client.cols
48
+ params.rows = this.client.rows
49
+ }
50
+ let response = await this.kernel.shell.start(params, null, ondata)
51
+ return response
52
+ }
40
53
  async exec(params, ondata) {
41
54
  params.path = params.path || this.path()
42
55
  if (this.client) {
@@ -55,10 +68,8 @@ class Bin {
55
68
  // })
56
69
  // }
57
70
  async download(url, dest, ondata) {
58
- console.log("DOWNLOAD process.env", process.env)
59
71
  const agent = new ProxyAgent();
60
72
  const userAgent = fakeUa()
61
- console.log("download userAgent", userAgent)
62
73
  const opts = {
63
74
  fileName: dest,
64
75
  override: true,
@@ -74,7 +85,6 @@ class Bin {
74
85
  opts.httpRequestOptions = { agent }
75
86
  opts.httpsRequestOptions = { agent }
76
87
  }
77
- console.log("opts", opts)
78
88
  const dl = new DownloaderHelper(url, this.path(), opts)
79
89
  ondata({ raw: `\r\nDownloading ${url} to ${this.path()}...\r\n` })
80
90
  let res = await new Promise((resolve, reject) => {
@@ -187,7 +197,6 @@ class Bin {
187
197
  return e
188
198
  }
189
199
  async init() {
190
- console.log("kernel.bin.init", this.kernel.homedir)
191
200
  if (this.kernel.homedir) {
192
201
  const bin_folder = this.path()
193
202
  await fs.promises.mkdir(bin_folder, { recursive: true }).catch((e) => { })
@@ -197,7 +206,6 @@ class Bin {
197
206
  }
198
207
  // await fs.promises.mkdir(playwright_folder, { recursive: true }).catch((e) => { })
199
208
  let system_env = await Environment.get(this.kernel.homedir)
200
- console.log("***********", { system_env })
201
209
 
202
210
  if (system_env.HTTP_PROXY) {
203
211
  process.env.HTTP_PROXY = system_env.HTTP_PROXY
@@ -266,6 +274,8 @@ class Bin {
266
274
  } catch (e) {
267
275
  console.log("RefreshInstalled Error", e)
268
276
  }
277
+
278
+ // initialize pipconfig
269
279
  let pipconfig_path = path.resolve(this.kernel.homedir, "pipconfig")
270
280
  let pipconfig_exists = await this.kernel.api.exists(pipconfig_path)
271
281
  // if not, create one
@@ -273,10 +283,6 @@ class Bin {
273
283
  const pipconfigStr = `[global]
274
284
  timeout = 1000`
275
285
  await fs.promises.writeFile(pipconfig_path, pipconfigStr)
276
- // await fs.promises.copyFile(
277
- // path.resolve(__dirname, "..", "pipconfig_template"),
278
- // pipconfig_path
279
- // )
280
286
  }
281
287
 
282
288
  // add gitconfig => support git lfs, long path, etc.
@@ -286,6 +292,13 @@ class Bin {
286
292
  path.resolve(__dirname, "..", "gitconfig_template"),
287
293
  gitconfig_path
288
294
  )
295
+
296
+ for(let mod of this.mods) {
297
+ if (mod.mod.start) {
298
+ await mod.mod.start()
299
+ }
300
+ }
301
+
289
302
  }
290
303
 
291
304
 
@@ -311,25 +324,27 @@ class Bin {
311
324
  } else {
312
325
  site_packages_path = path.resolve(this.kernel.homedir, "bin/miniconda/lib/python3.10/site-packages")
313
326
  }
314
- // check if any of 'uvicorn', 'importlib_metadata', 'fastapi' exists
315
- let module_paths = ["fastapi", "uvicorn", "importlib_metadata"].map((name) => {
316
- return path.resolve(site_packages_path, name)
317
- })
327
+ // // check if any of 'uvicorn', 'importlib_metadata', 'fastapi' exists
328
+ // let module_paths = ["fastapi", "uvicorn", "importlib_metadata"].map((name) => {
329
+ // return path.resolve(site_packages_path, name)
330
+ // })
331
+ // let to_reset_exists = false
332
+ // for(let module_path of module_paths) {
333
+ // let e = await this.kernel.exists(module_path)
334
+ // console.log("checking kernel exists", { module_path, e })
335
+ // if (e) {
336
+ // to_reset_exists = true
337
+ // break;
338
+ // }
339
+ // }
340
+ // console.log("> to_reset_exists", to_reset_exists)
341
+
318
342
  let to_reset_exists = false
319
- for(let module_path of module_paths) {
320
- let e = await this.kernel.exists(module_path)
321
- console.log({ e, module_path })
322
- if (e) {
323
- to_reset_exists = true
324
- break;
325
- }
326
- }
327
- console.log({ to_reset_exists })
343
+
328
344
  if (to_reset_exists) {
329
345
  this.correct_conda = false
330
346
  } else {
331
347
  res = await this.exec({ message: `conda list` }, (stream) => {
332
- // process.stdout.write(stream.raw)
333
348
  // console.log("conda list check", { stream })
334
349
  })
335
350
 
@@ -344,17 +359,12 @@ class Bin {
344
359
  conda_versions[name] = version
345
360
  if (name === "conda") {
346
361
  conda_check.conda = true
347
- // //if (String(version) === "24.11.1") {
348
- // if (String(version) === "24.11.3") {
349
- // conda_check.conda = true
350
- // }
351
362
  }
352
363
  if (name === "conda-libmamba-solver") {
353
364
  //if (String(version) === "24.7.0") {
354
365
  let channel = chunks[3]
355
366
  let coerced = semver.coerce(version)
356
367
  let mamba_requirement = ">=24.11.1"
357
- console.log({ name, channel, version })
358
368
  //if (semver.satisfies(coerced, mamba_requirement) && channel === "conda-forge") {
359
369
  if (semver.satisfies(coerced, mamba_requirement)) {
360
370
  conda_check.mamba = true
@@ -366,16 +376,6 @@ class Bin {
366
376
  if (String(version) === "3.47.2") {
367
377
  conda_check.sqlite = true
368
378
  }
369
- // let coerced = semver.coerce(version)
370
- // let sqlite_requirement = ">=3.47.2"
371
- // // console.log({ coerced, version, sqlite_requirement })
372
- // if (semver.satisfies(coerced, sqlite_requirement)) {
373
- // console.log("semver satisfied")
374
- //
375
- // conda_check.sqlite = true
376
- // } else {
377
- // console.log("semver NOT satisfied")
378
- // }
379
379
  }
380
380
  }
381
381
  } else {
@@ -385,7 +385,6 @@ class Bin {
385
385
  }
386
386
  }
387
387
 
388
- console.log({ conda_check })
389
388
  if (conda_check.conda && conda_check.mamba && conda_check.sqlite) {
390
389
  //if (conda_check.conda && conda_check.mamba) {
391
390
  this.correct_conda = true
@@ -396,23 +395,17 @@ class Bin {
396
395
  }
397
396
  async refreshInstalled() {
398
397
 
399
- console.log("refreshInstalled start")
400
-
401
-
402
398
  /// A. installed packages detection
403
399
 
404
400
  this.installed_initialized = false
405
401
 
406
402
  //this.installed = {}
407
403
 
408
- console.log("## check conda")
409
-
410
404
  // 1. conda
411
405
 
412
406
  // check conda location and see if it exists. only run if it exists
413
407
  let conda_path = path.resolve(this.kernel.homedir, "bin", "miniconda")
414
408
  let conda_exists = await this.exists(conda_path)
415
- console.log({ conda_path, conda_exists })
416
409
 
417
410
  let start
418
411
  let res
@@ -429,48 +422,17 @@ class Bin {
429
422
  }
430
423
  }
431
424
 
432
- // // 2. pip
433
- // let pip = new Set()
434
- // if (conda_exists) {
435
- // // conda comes with pip
436
- // console.log("## check pip")
437
- // start = false
438
- // res = await this.exec({ message: `pip list` }, (stream) => {
439
- //// console.log("pip list check", { stream })
440
- // })
441
- // console.log("PIP", res.response)
442
- // lines = res.response.split(/[\r\n]+/)
443
- // for(let line of lines) {
444
- // if (start) {
445
- // let chunks = line.split(/\s+/).filter(x => x)
446
- // if (chunks.length > 1) {
447
- // pip.add(chunks[0])
448
- // }
449
- // } else {
450
- // if (/-------.*/i.test(line)) {
451
- // start = true
452
- // }
453
- // }
454
- // }
455
- // }
456
- // this.installed.pip = pip
457
-
458
-
459
425
  if (this.platform === "darwin") {
460
426
  // 3. brew
461
- console.log("## check brew")
462
427
 
463
428
  let brew_path = path.resolve(this.kernel.homedir, "bin", "homebrew")
464
429
  let brew_exists = await this.exists(brew_path)
465
- console.log({ brew_path, brew_exists })
466
430
 
467
431
  let brew = []
468
432
  if (brew_exists) {
469
433
  start = false
470
434
  res = await this.exec({ message: `brew list -1`, conda: { skip: true } }, (stream) => {
471
- // console.log("brew list check", { stream })
472
435
  })
473
- console.log("BREW", res.response)
474
436
  lines = res.response.split(/[\r\n]+/).slice(0, -1) // ignore last line since it's the prompt
475
437
  let end = false
476
438
  for(let line of lines) {
@@ -494,7 +456,6 @@ class Bin {
494
456
 
495
457
 
496
458
  // check brew_installed
497
- console.log("checking brew installed")
498
459
  let e = await this.kernel.bin.exists("homebrew")
499
460
  let { stdout }= await this.exec({ message: "xcode-select -p", conda: { skip: true } }, (stream) => { })
500
461
  let e2 = /(.*Library.*Developer.*CommandLineTools.*|.*Xcode.*Developer.*)/gi.test(stdout)
@@ -512,7 +473,7 @@ class Bin {
512
473
  e4 = /xcode-select version ([0-9]+)/gi.exec(result.stdout)
513
474
  if (e4 && e4.length > 1) {
514
475
  let version = Number(e4[1])
515
- console.log("xcode-select version", version)
476
+ // console.log("xcode-select version", version)
516
477
  if (version >= 2349) {
517
478
  e4 = true
518
479
  } else {
@@ -569,7 +530,7 @@ class Bin {
569
530
  // await this.mod(name).rm({}, ondata)
570
531
  // await this.mod(name).install(options, ondata)
571
532
  //}
572
- async tryInstall(requirement, x, i, total, ondata) {
533
+ async tryInstall(id, requirement, x, i, total, ondata) {
573
534
  let current_platform = os.platform()
574
535
  let current_arch = os.arch()
575
536
  let current_gpu = this.kernel.gpu
@@ -629,7 +590,7 @@ class Bin {
629
590
  ondata({ html: `<b><i class="fas fa-circle-notch fa-spin"></i> ${progress} Installing ${name}</b>${message}` }, "notify2")
630
591
  console.log("## Before m.mod.install", requirement)
631
592
  requirement._attempt = x
632
- await m.mod.install(requirement, ondata, this.kernel)
593
+ await m.mod.install(requirement, ondata, this.kernel, id)
633
594
 
634
595
  // // 2 second delay to fix conda issue
635
596
  // await new Promise((resolve, reject) => {
@@ -646,6 +607,26 @@ class Bin {
646
607
  }
647
608
  // }
648
609
  }
610
+ async path_exists(req, ondata) {
611
+ let abspath = this.kernel.api.resolvePath(this.kernel.api.userdir, req.params.uri)
612
+ if (abspath) {
613
+ console.log({ abspath })
614
+ let exists = await new Promise(r=>fs.access(abspath, fs.constants.F_OK, e => r(!e)))
615
+ return exists
616
+ } else {
617
+ return false
618
+ }
619
+ }
620
+ async install2(req, ondata) {
621
+ let { requirements, install_required, requirements_pending, error } = await this.check({
622
+ bin: this.preset("ai")
623
+ })
624
+ req.params = JSON.stringify(requirements)
625
+ if (this.install_required) {
626
+ let res = await this.install(req, ondata)
627
+ return res
628
+ }
629
+ }
649
630
  async install(req, ondata) {
650
631
  /*
651
632
  req.params := {
@@ -664,9 +645,7 @@ class Bin {
664
645
  } else {
665
646
  this.client = null
666
647
  }
667
-
668
648
  let requirements = JSON.parse(req.params)
669
-
670
649
  for(let x=0; x<10; x++) {
671
650
  console.log(`## Install Attempt ${x}`)
672
651
  let i = 0;
@@ -680,7 +659,7 @@ class Bin {
680
659
  console.log("already installed. skip.")
681
660
  } else {
682
661
  console.log("not installed. install.")
683
- await this.tryInstall(requirement, x, i, requirements.length, ondata)
662
+ await this.tryInstall(req.id, requirement, x, i, requirements.length, ondata)
684
663
  }
685
664
  }
686
665
 
@@ -736,19 +715,45 @@ class Bin {
736
715
  // }
737
716
  // }
738
717
  //}
718
+ if (this.kernel.shell) {
719
+ this.kernel.shell.reset()
720
+ }
739
721
  await this.init()
740
722
  }
741
- async _installed(name, type) {
723
+ async check_installed(r, dependencies) {
724
+ if (Array.isArray(r.name)) {
725
+ for(let name of r.name) {
726
+ let installed = await this._installed(name, r.type, dependencies)
727
+ if (!installed) return false
728
+ }
729
+ return true
730
+ } else {
731
+ let installed = await this._installed(r.name, r.type, dependencies)
732
+ return installed
733
+ }
734
+ }
735
+ async _installed(name, type, dependencies) {
742
736
  if (type === "conda") {
743
- return this.kernel.bin.installed.conda.has(name)
737
+ let conda_installed = this.installed.conda.has(name)
738
+ console.log({ dependencies })
739
+ let dependencies_installed = true
740
+ for(let d of dependencies) {
741
+ console.log("checking dependency", d)
742
+ if(!this.installed.conda.has(d)) {
743
+ dependencies_installed = false
744
+ console.log("not installed", d)
745
+ break
746
+ }
747
+ }
748
+ return conda_installed && dependencies_installed
744
749
  } else if (type === "pip") {
745
- return this.kernel.bin.installed.pip && this.kernel.bin.installed.pip.has(name)
750
+ return this.installed.pip && this.installed.pip.has(name)
746
751
  } else if (type === "brew") {
747
- return this.kernel.bin.installed.brew.has(name)
752
+ return this.installed.brew.has(name)
748
753
  } else {
749
754
  // check kernel/bin/<module>.installed()
750
755
  let filepath = path.resolve(__dirname, "..", "kernel", "bin", name + ".js")
751
- let mod = this.kernel.bin.mod[name]
756
+ let mod = this.mod[name]
752
757
  let installed = false
753
758
  if (mod.installed) {
754
759
  installed = await mod.installed()
@@ -756,6 +761,260 @@ class Bin {
756
761
  return installed
757
762
  }
758
763
  }
764
+ preset(mode) {
765
+ return Setup[mode](this.kernel)
766
+ }
767
+ requirements(config) {
768
+ let requirements = config.bin.requirements
769
+ if (config.script && config.script.requires && config.script.requires.length > 0) {
770
+ /*********************************************************************
771
+
772
+ {
773
+ requires: [{
774
+ platform,
775
+ type,
776
+ name,
777
+ args
778
+ }, {
779
+ platform,
780
+ type,
781
+ name,
782
+ args
783
+ }],
784
+ run: [{
785
+ ...
786
+ }]
787
+ }
788
+
789
+ syntax :=
790
+
791
+ {
792
+ platform: <win32|darwin|linux>,
793
+ type: <conda|pip|brew|none>,
794
+ name: <package name>, (example: "ffmpeg", "git")
795
+ args: <install command flags> (example: "-c conda-forge")
796
+ }
797
+
798
+
799
+ 1. pinokio native install: no need for specifying platforms since they are included
800
+
801
+ {
802
+ name: "conda"
803
+ }
804
+
805
+
806
+ 2. non native install (conda, pip, brew)
807
+
808
+ 2.1. Same on all platforms
809
+
810
+ [{
811
+ type: "conda",
812
+ name: "ffmpeg",
813
+ args: "-c conda-forge"
814
+ }]
815
+
816
+ 2.2. Specify per platform
817
+
818
+
819
+ [
820
+ { name: "conda" },
821
+ { platform: "darwin", type: "brew", name: "llvm" },
822
+ { platform: "linux", tyoe: "conda", name: "llvm", args: "-c conda-forge llvm" },
823
+ { platform: "win32", tyoe: "conda", name: "llvm", args: "-c conda-forge llvm" }
824
+ ]
825
+
826
+ [
827
+ { name: "conda" },
828
+ { platform: ["darwin", "linux"], type: "brew", name: "llvm" },
829
+ { platform: "win32", tyoe: "conda", name: "llvm", args: "-c conda-forge llvm" }
830
+ ]
831
+
832
+
833
+
834
+ *********************************************************************/
835
+ let type_name_set = new Set()
836
+ for(let r of config.script.requires) {
837
+ // if no platform specified, or if the specified platform matches the current platform
838
+ if (!r.platform || platform === r.platform || Array.isArray(r.platform) && r.platform.includes(platform) ) {
839
+ if (Array.isArray(r.name)) {
840
+ // if array, just add it
841
+ requirements.push(r)
842
+ } else {
843
+ let type_name = `${r.type ? r.type : ''}/${r.name}`
844
+ if (!type_name_set.has(type_name)) {
845
+ type_name_set.add(type_name)
846
+ requirements.push(r)
847
+ }
848
+ }
849
+ }
850
+ }
851
+
852
+ }
853
+ return requirements
854
+ }
855
+ relevant(r) {
856
+ /*
857
+ single platform
858
+ [
859
+ { name: "conda" },
860
+ { platform: "darwin", type: "brew", name: "llvm" },
861
+ { platform: "linux", tyoe: "conda", name: "llvm", args: "-c conda-forge llvm" },
862
+ { platform: "win32", tyoe: "conda", name: "llvm", args: "-c conda-forge llvm" }
863
+ ]
864
+
865
+ multiple platforms
866
+ [
867
+ { name: "conda" },
868
+ { platform: ["darwin", "linux"], type: "brew", name: "llvm" },
869
+ { platform: "win32", tyoe: "conda", name: "llvm", args: "-c conda-forge llvm" }
870
+ ]
871
+
872
+
873
+ platform & arch
874
+ [
875
+ { name: "conda" },
876
+ { platform: "darwin", arch: ["arm64", "x64"], type: "brew", name: "llvm" },
877
+ ]
878
+ */
879
+
880
+ let platform = os.platform()
881
+ let arch = os.arch()
882
+ let gpu = this.kernel.gpu
883
+ let relevant = {
884
+ platform: false,
885
+ arch: false,
886
+ gpu: false,
887
+ }
888
+ if (r.platform) {
889
+ if (Array.isArray(r.platform)) {
890
+ // multiple items
891
+ if (r.platform.includes(platform)) {
892
+ relevant.platform = true
893
+ }
894
+ } else {
895
+ // one item
896
+ if (r.platform === platform) {
897
+ relevant.platform = true
898
+ }
899
+ }
900
+ } else {
901
+ // all platforms
902
+ relevant.platform = true
903
+ }
904
+ if (r.arch) {
905
+ if (Array.isArray(r.arch)) {
906
+ // multiple items
907
+ if (r.arch.includes(arch)) {
908
+ relevant.arch = true
909
+ }
910
+ } else {
911
+ // one item
912
+ if (r.arch === arch) {
913
+ relevant.arch = true
914
+ }
915
+ }
916
+ } else {
917
+ // all platforms
918
+ relevant.arch = true
919
+ }
920
+ if (r.gpu) {
921
+ if (Array.isArray(r.gpu)) {
922
+ // multiple items
923
+ if (r.gpu.includes(gpu)) {
924
+ relevant.gpu = true
925
+ }
926
+ } else {
927
+ // one item
928
+ if (r.gpu === gpu) {
929
+ relevant.gpu = true
930
+ }
931
+ }
932
+ } else {
933
+ // all platforms
934
+ relevant.gpu = true
935
+ }
936
+ return relevant.platform && relevant.arch && relevant.gpu
937
+ }
938
+ async check(config) {
939
+ let requirements = this.requirements(config)
940
+ let requirements_pending = !this.installed_initialized
941
+ let install_required = true
942
+ if (!requirements_pending) {
943
+ install_required = false
944
+ for(let i=0; i<requirements.length; i++) {
945
+ let r = requirements[i]
946
+ //let installed = await this.installed(r)
947
+ //requirements[i].installed = installed
948
+ //if (!installed) {
949
+ // install_required = true
950
+ //}
951
+ let relevant = this.relevant(r)
952
+ requirements[i].relevant = relevant
953
+ if (relevant) {
954
+ let dependencies
955
+ if (r.name === "conda") {
956
+ dependencies = config.bin.conda_requirements
957
+ console.log("check dependencies", dependencies)
958
+ requirements[i].dependencies = dependencies
959
+ }
960
+ let installed = await this.check_installed(r, dependencies)
961
+ requirements[i].installed = installed
962
+ if (!installed) {
963
+ install_required = true
964
+ }
965
+ }
966
+ }
967
+ }
968
+
969
+ let error = null
970
+ try {
971
+ this.compatible()
972
+ } catch (e) {
973
+ error = e.message
974
+ install_required = true
975
+ }
976
+
977
+ this.install_required = install_required
978
+ this.requirements_pending = requirements_pending
979
+
980
+ console.log("check_bin finished 2")
981
+
982
+ requirements = requirements.filter((r) => {
983
+ return r.relevant
984
+ })
985
+
986
+ return {
987
+ error,
988
+ requirements,
989
+ install_required,
990
+ requirements_pending
991
+ }
992
+
993
+ }
994
+ winBuildNumber() {
995
+ let osVersion = (/(\d+)\.(\d+)\.(\d+)/g).exec(os.release());
996
+ let buildNumber = 0;
997
+ if (osVersion && osVersion.length === 4) {
998
+ buildNumber = parseInt(osVersion[3]);
999
+ }
1000
+ return buildNumber;
1001
+ }
1002
+ compatible() {
1003
+ if (this.kernel.platform === "win32") {
1004
+ let buildNumber = this.winBuildNumber()
1005
+ if (buildNumber < 18309) {
1006
+ // must use conpty for node-pty, and conpty is only supported in win>=18309
1007
+ console.log("Windows buildNumber", buildNumber)
1008
+ throw new Error(`Pinokio supports Windows release 18309 and up (current system: ${buildNumber}`)
1009
+ }
1010
+
1011
+ // if (buildNumber > 25000) {
1012
+ // console.log("Windows buildNumber", buildNumber)
1013
+ // throw new Error(`Pinokio does not currently support Windows Canary (versions 25000 and up). The current system is ${buildNumber}`)
1014
+ //
1015
+ // }
1016
+ }
1017
+ }
759
1018
  async sh(params, ondata) {
760
1019
  let response = await this.kernel.shell.run(params, null, ondata)
761
1020
  return response
@@ -3,23 +3,30 @@ const fetch = require('cross-fetch')
3
3
  const { rimraf } = require('rimraf')
4
4
  const decompress = require('decompress');
5
5
  class Node {
6
+ cmd() {
7
+ return "nodejs pnpm"
8
+ }
6
9
  async install(req, ondata) {
7
10
  await this.kernel.bin.exec({
8
- //message: "conda install -y nodejs=22.12.0 -c conda-forge"
9
11
  message: [
10
12
  "conda clean -y --all",
11
13
  //"conda install -y nodejs=20.17.0 pnpm -c conda-forge"
12
- "conda install -y nodejs pnpm -c conda-forge"
14
+ `conda install -y -c conda-forge ${this.cmd()}`
13
15
  ]
14
- // conda: {
15
- // name: "base",
16
- // activate: "minimal"
17
- // }
18
16
  }, ondata)
19
17
  }
20
18
  async installed() {
21
19
  return this.kernel.bin.installed.conda.has("nodejs") && this.kernel.bin.installed.conda.has("pnpm")
22
20
  }
21
+ env() {
22
+ return {
23
+ PATH: [this.kernel.path("bin/npm"), this.kernel.path("bin/npm/bin")],
24
+ NPM_CONFIG_PREFIX: this.kernel.path("bin/npm"),
25
+ npm_config_prefix: this.kernel.path("bin/npm"),
26
+ PNPM_HOME: this.kernel.path("bin/npm"),
27
+ pnpm_home: this.kernel.path("bin/npm"),
28
+ }
29
+ }
23
30
  async uninstall(req, ondata) {
24
31
  await this.kernel.bin.exec({
25
32
  message: "conda remove nodejs pnpm",
package/kernel/bin/py.js CHANGED
@@ -8,7 +8,7 @@ class Py {
8
8
  path: this.kernel.path("bin")
9
9
  }, ondata)
10
10
  await this.kernel.exec({
11
- message: "pip install -r requirements.txt",
11
+ message: "uv pip install -r requirements.txt",
12
12
  venv: "env",
13
13
  path: this.kernel.bin.path("py")
14
14
  }, ondata)