pinokiod 3.231.0 → 3.233.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,100 +3,107 @@ const fs = require('fs')
3
3
  const path = require('path')
4
4
  class Cuda {
5
5
  async install(req, ondata) {
6
- if (this.kernel.platform === "win32") {
7
- await this.kernel.bin.exec({
8
- message: [
9
- "conda clean -y --all",
10
- "conda install -y cudnn libzlib-wapi -c conda-forge",
11
- ]
12
- }, ondata)
13
- await this.kernel.bin.exec({
14
- message: [
15
- "conda clean -y --all",
16
- "conda install -y nvidia/label/cuda-12.8.1::cuda"
17
- ]
18
- }, ondata)
19
- const folder = this.kernel.bin.path("miniconda/etc/conda/activate.d")
20
- let deactivate_list = [
21
- "~cuda-nvcc_activate.bat",
22
- "vs2019_compiler_vars.bat",
23
- "vs2022_compiler_vars.bat",
24
- ]
25
- for(let item of deactivate_list) {
26
- const old_name = path.resolve(folder, item)
27
- const new_name = path.resolve(folder, item + ".disabled")
28
- console.log("rename", { old_name, new_name })
29
- await fs.promises.rename(old_name, new_name)
30
- }
31
- } else {
32
- await this.kernel.bin.exec({
33
- message: [
34
- "conda clean -y --all",
35
- "conda install -y cudnn -c conda-forge",
36
- ]
37
- }, ondata)
38
- await this.kernel.bin.exec({
39
- message: [
40
- "conda clean -y --all",
41
- "conda install -y nvidia/label/cuda-12.8.1::cuda"
6
+ if (this.kernel.gpu === "nvidia") {
7
+ if (this.kernel.platform === "win32") {
8
+ await this.kernel.bin.exec({
9
+ message: [
10
+ "conda clean -y --all",
11
+ "conda install -y cudnn libzlib-wapi -c conda-forge",
12
+ ]
13
+ }, ondata)
14
+ await this.kernel.bin.exec({
15
+ message: [
16
+ "conda clean -y --all",
17
+ "conda install -y nvidia/label/cuda-12.8.1::cuda"
18
+ ]
19
+ }, ondata)
20
+ const folder = this.kernel.bin.path("miniconda/etc/conda/activate.d")
21
+ let deactivate_list = [
22
+ "~cuda-nvcc_activate.bat",
23
+ "vs2019_compiler_vars.bat",
24
+ "vs2022_compiler_vars.bat",
42
25
  ]
43
- }, ondata)
44
- if (this.kernel.platform === "linux") {
26
+ for(let item of deactivate_list) {
27
+ const old_name = path.resolve(folder, item)
28
+ const new_name = path.resolve(folder, item + ".disabled")
29
+ console.log("rename", { old_name, new_name })
30
+ await fs.promises.rename(old_name, new_name)
31
+ }
32
+ } else {
45
33
  await this.kernel.bin.exec({
46
34
  message: [
47
- "conda install -y -c conda-forge nccl"
35
+ "conda clean -y --all",
36
+ "conda install -y cudnn -c conda-forge",
48
37
  ]
49
38
  }, ondata)
39
+ await this.kernel.bin.exec({
40
+ message: [
41
+ "conda clean -y --all",
42
+ "conda install -y nvidia/label/cuda-12.8.1::cuda"
43
+ ]
44
+ }, ondata)
45
+ if (this.kernel.platform === "linux") {
46
+ await this.kernel.bin.exec({
47
+ message: [
48
+ "conda install -y -c conda-forge nccl"
49
+ ]
50
+ }, ondata)
51
+ }
50
52
  }
51
53
  }
52
54
  }
53
55
  async installed() {
54
- if (this.kernel.platform === 'win32') {
55
- if (this.kernel.bin.installed.conda.has("cudnn") && this.kernel.bin.installed.conda.has("cuda") && this.kernel.bin.installed.conda.has("libzlib-wapi")) {
56
- let version = this.kernel.bin.installed.conda_versions.cuda
57
- if (version) {
58
- let coerced = semver.coerce(version)
59
- console.log("cuda version", coerced)
60
- if (semver.satisfies(coerced, ">=12.8.1")) {
61
- console.log("cuda satisfied")
62
- let deactivate_list = [
63
- "~cuda-nvcc_activate.bat",
64
- "vs2019_compiler_vars.bat",
65
- "vs2022_compiler_vars.bat",
66
- ]
67
- const folder = this.kernel.bin.path("miniconda/etc/conda/activate.d")
68
- let at_least_one_exists = false
69
- for(let item of deactivate_list) {
70
- let exists = await this.kernel.exists("bin/miniconda/etc/conda/activate.d/" + item)
71
- if (exists) {
72
- // break if at least one exists
73
- at_least_one_exists = true
74
- break
56
+ if (this.kernel.gpu === "nvidia") {
57
+ if (this.kernel.platform === 'win32') {
58
+ if (this.kernel.bin.installed.conda.has("cudnn") && this.kernel.bin.installed.conda.has("cuda") && this.kernel.bin.installed.conda.has("libzlib-wapi")) {
59
+ let version = this.kernel.bin.installed.conda_versions.cuda
60
+ if (version) {
61
+ let coerced = semver.coerce(version)
62
+ console.log("cuda version", coerced)
63
+ if (semver.satisfies(coerced, ">=12.8.1")) {
64
+ console.log("cuda satisfied")
65
+ let deactivate_list = [
66
+ "~cuda-nvcc_activate.bat",
67
+ "vs2019_compiler_vars.bat",
68
+ "vs2022_compiler_vars.bat",
69
+ ]
70
+ const folder = this.kernel.bin.path("miniconda/etc/conda/activate.d")
71
+ let at_least_one_exists = false
72
+ for(let item of deactivate_list) {
73
+ let exists = await this.kernel.exists("bin/miniconda/etc/conda/activate.d/" + item)
74
+ if (exists) {
75
+ // break if at least one exists
76
+ at_least_one_exists = true
77
+ break
78
+ }
79
+ }
80
+ console.log("nvcc_activate exists?", at_least_one_exists)
81
+ if (at_least_one_exists) {
82
+ return false
83
+ } else {
84
+ return true
75
85
  }
76
86
  }
77
- console.log("nvcc_activate exists?", at_least_one_exists)
78
- if (at_least_one_exists) {
79
- return false
80
- } else {
87
+ }
88
+ }
89
+ } else {
90
+ if (this.kernel.bin.installed.conda.has("cudnn") && this.kernel.bin.installed.conda.has("cuda")) {
91
+ let version = this.kernel.bin.installed.conda_versions.cuda
92
+ if (version) {
93
+ let coerced = semver.coerce(version)
94
+ console.log("cuda version", coerced)
95
+ if (semver.satisfies(coerced, ">=12.8.1")) {
96
+ console.log("satisfied")
81
97
  return true
82
98
  }
83
99
  }
84
100
  }
85
101
  }
102
+ return false
86
103
  } else {
87
- if (this.kernel.bin.installed.conda.has("cudnn") && this.kernel.bin.installed.conda.has("cuda")) {
88
- let version = this.kernel.bin.installed.conda_versions.cuda
89
- if (version) {
90
- let coerced = semver.coerce(version)
91
- console.log("cuda version", coerced)
92
- if (semver.satisfies(coerced, ">=12.8.1")) {
93
- console.log("satisfied")
94
- return true
95
- }
96
- }
97
- }
104
+ // just return true for all other gpus so they can be avoided
105
+ return true
98
106
  }
99
- return false
100
107
  }
101
108
  env() {
102
109
  return {
@@ -625,7 +625,7 @@ class Bin {
625
625
  }
626
626
  async install2(req, ondata) {
627
627
  let { requirements, install_required, requirements_pending, error } = await this.check({
628
- bin: this.preset("ai")
628
+ bin: this.preset("dev")
629
629
  })
630
630
  req.params = JSON.stringify(requirements)
631
631
  if (this.install_required) {
@@ -157,13 +157,17 @@ module.exports = {
157
157
  { name: "cli", },
158
158
  { name: "uv", },
159
159
  { name: "py", },
160
+ { name: "huggingface" },
161
+ { name: "ffmpeg", },
160
162
  { name: "browserless" },
161
163
  ])
162
164
  let conda_requirements = [
163
165
  zip_cmd,
164
166
  "uv",
165
167
  "node",
168
+ "huggingface",
166
169
  "git",
170
+ "ffmpeg",
167
171
  ]
168
172
  return {
169
173
  icon: "fa-solid fa-laptop-code",
@@ -188,6 +192,7 @@ module.exports = {
188
192
  { name: "uv", },
189
193
  { name: "caddy", },
190
194
  { name: "huggingface" },
195
+ { name: "ffmpeg", },
191
196
  { name: "py", },
192
197
  { name: "browserless" },
193
198
  ])
@@ -197,6 +202,7 @@ module.exports = {
197
202
  "node",
198
203
  "huggingface",
199
204
  "git",
205
+ "ffmpeg",
200
206
  "caddy",
201
207
  ]
202
208
  if (platform === "win32") {
package/kernel/index.js CHANGED
@@ -952,7 +952,7 @@ class Kernel {
952
952
  })
953
953
  this.shell.init().then(async () => {
954
954
  this.bin.check({
955
- bin: this.bin.preset("ai"),
955
+ bin: this.bin.preset("dev"),
956
956
  })
957
957
  if (this.envs) {
958
958
  this.template.update({
@@ -109,6 +109,19 @@ class Proto {
109
109
  let mod = await this.kernel.require(mod_path)
110
110
  let response = await mod(payload, ondata, this.kernel)
111
111
 
112
+ if (projectType === 'dns') {
113
+ try {
114
+ await this.kernel.dns({ path: payload.cwd })
115
+ } catch (dnsError) {
116
+ console.log('[proto] dns update failed', dnsError)
117
+ }
118
+ try {
119
+ await this.kernel.refresh(true)
120
+ } catch (refreshError) {
121
+ console.log('[proto] refresh failed after dns create', refreshError)
122
+ }
123
+ }
124
+
112
125
  // // copy readme
113
126
  // let readme_path = this.kernel.path("prototype/PINOKIO.md")
114
127
  // await fs.promises.cp(readme_path, path.resolve(cwd, name, "PINOKIO.md"))
@@ -38,6 +38,7 @@ class Router {
38
38
  this.local_network_mapping = {}
39
39
  this.custom_routers = {}
40
40
  this.rewrite_mapping = {}
41
+ this.stream_close_delay = '10m'
41
42
  }
42
43
  async init() {
43
44
  // if ~/pinokio/network doesn't exist, clone
@@ -258,6 +259,14 @@ class Router {
258
259
  }
259
260
  }
260
261
  this.mapping = this._mapping
262
+
263
+ // set self origins => used for detecting all IPs resembling pinokiod itself
264
+ const basePort = Number(this.kernel.server_port || this.default_port)
265
+ const mappedPort = this.port_mapping && basePort ? Number(this.port_mapping[String(basePort)]) : null
266
+ const lanHost = (this.kernel.peer && this.kernel.peer.host) ? String(this.kernel.peer.host).trim() : ''
267
+ const hosts = ['127.0.0.1', 'localhost', lanHost].filter(Boolean)
268
+ const ports = [basePort, mappedPort].filter((value) => Number.isFinite(value))
269
+ this.kernel.selfOrigins = hosts.flatMap((host) => ports.map((port) => `${host}:${port}`))
261
270
  }
262
271
 
263
272
  fallback() {
@@ -299,8 +308,40 @@ class Router {
299
308
  this.mapping = this._mapping
300
309
  }
301
310
 
311
+ ensureStreamCloseDelay(target) {
312
+ const delay = this.stream_close_delay
313
+ if (!delay || !target) {
314
+ return
315
+ }
316
+ const seen = new WeakSet()
317
+ const visit = (node) => {
318
+ if (!node || (typeof node === 'object' && seen.has(node))) {
319
+ return
320
+ }
321
+ if (typeof node === 'object') {
322
+ seen.add(node)
323
+ }
324
+ if (Array.isArray(node)) {
325
+ for (const item of node) {
326
+ visit(item)
327
+ }
328
+ return
329
+ }
330
+ if (typeof node === 'object') {
331
+ if (node.handler === 'reverse_proxy' && typeof node.stream_close_delay === 'undefined') {
332
+ node.stream_close_delay = delay
333
+ }
334
+ for (const key of Object.keys(node)) {
335
+ visit(node[key])
336
+ }
337
+ }
338
+ }
339
+ visit(target)
340
+ }
341
+
302
342
  // update caddy config
303
343
  async update() {
344
+ this.ensureStreamCloseDelay(this.config)
304
345
  if (JSON.stringify(this.config) === JSON.stringify(this.old_config)) {
305
346
  // console.log("######### config hasn't updated")
306
347
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "3.231.0",
3
+ "version": "3.233.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/server/index.js CHANGED
@@ -441,6 +441,7 @@ class Server {
441
441
  //browser_url = "/pinokio/browser/" + x.name
442
442
  browser_url = "/p/" + x.name
443
443
  }
444
+ let view_url = "/v/" + x.name
444
445
  let dev_url = browser_url + "/dev"
445
446
  let review_url = browser_url + "/review"
446
447
  let files_url = "/asset/api/" + x.name
@@ -469,6 +470,7 @@ class Server {
469
470
  url: browser_url,
470
471
  path: uri,
471
472
  dev_url,
473
+ view_url,
472
474
  review_url,
473
475
  files_url,
474
476
  }
@@ -703,16 +705,14 @@ class Server {
703
705
  // return current_urls
704
706
  }
705
707
 
706
- async chrome(req, res, type) {
708
+ async chrome(req, res, type, options) {
707
709
 
708
710
  let d = Date.now()
709
711
  let { requirements, install_required, requirements_pending, error } = await this.kernel.bin.check({
710
- //bin: this.kernel.bin.preset("dev"),
711
- bin: this.kernel.bin.preset("ai"),
712
+ bin: this.kernel.bin.preset("dev"),
712
713
  })
713
714
  if (!requirements_pending && install_required) {
714
- //res.redirect(`/setup/dev?callback=${req.originalUrl}`)
715
- res.redirect(`/setup/ai?callback=${req.originalUrl}`)
715
+ res.redirect(`/setup/dev?callback=${req.originalUrl}`)
716
716
  return
717
717
  }
718
718
 
@@ -850,7 +850,20 @@ class Server {
850
850
  dev_link = "/d/" + posix_path
851
851
  }
852
852
 
853
- let run_tab = "/p/" + name
853
+ let autoselect
854
+ let run_tab
855
+ if (type === "run") {
856
+ if (options && options.no_autoselect) {
857
+ run_tab = "/v/" + name
858
+ autoselect = false
859
+ } else {
860
+ run_tab = "/p/" + name
861
+ autoselect = true
862
+ }
863
+ } else {
864
+ run_tab = "/p/" + name
865
+ autoselect = false
866
+ }
854
867
  let dev_tab = "/p/" + name + "/dev"
855
868
  let review_tab = "/p/" + name + "/review"
856
869
  let files_tab = "/p/" + name + "/files"
@@ -889,6 +902,7 @@ class Server {
889
902
  port: this.port,
890
903
  // mem,
891
904
  type,
905
+ autoselect,
892
906
  platform,
893
907
  running:this.kernel.api.running,
894
908
  memory: this.kernel.memory,
@@ -1429,7 +1443,7 @@ class Server {
1429
1443
  })
1430
1444
  } else if (pathComponents.length === 0 && req.query.mode === "download") {
1431
1445
  let { requirements, install_required, requirements_pending, error } = await this.kernel.bin.check({
1432
- bin: this.kernel.bin.preset("ai"),
1446
+ bin: this.kernel.bin.preset("dev"),
1433
1447
  })
1434
1448
  let sanitizedPath = null
1435
1449
  if (typeof req.query.path === 'string') {
@@ -1677,12 +1691,29 @@ class Server {
1677
1691
  template = "editor"
1678
1692
  }
1679
1693
 
1694
+ let requires_bundle = null
1695
+ if (resolved && resolved.requires && !Array.isArray(resolved.requires)) {
1696
+ const bundle = resolved.requires.bundle
1697
+ if (typeof bundle === "string" && typeof Setup[bundle] === "function") {
1698
+ requires_bundle = bundle
1699
+ }
1700
+ }
1701
+
1702
+ const preset = requires_bundle ? this.kernel.bin.preset(requires_bundle) : this.kernel.bin.preset("dev")
1680
1703
  let { requirements, install_required, requirements_pending, error } = await this.kernel.bin.check({
1681
- //bin: this.kernel.bin.preset("ai"),
1682
- bin: this.kernel.bin.preset("dev"),
1704
+ bin: preset,
1683
1705
  script: resolved
1684
1706
  })
1685
1707
 
1708
+ if (requires_bundle) {
1709
+ console.log({ requires_bundle, requirements_pending, install_required, })
1710
+ }
1711
+
1712
+ if (requires_bundle && !requirements_pending && install_required) {
1713
+ res.redirect(`/setup/${requires_bundle}?callback=${req.originalUrl}`)
1714
+ return
1715
+ }
1716
+
1686
1717
  //let requirements = this.kernel.bin.requirements(resolved)
1687
1718
  //let requirements_pending = !this.kernel.bin.installed_initialized
1688
1719
  //let install_required = true
@@ -3019,7 +3050,8 @@ class Server {
3019
3050
  }
3020
3051
  } else {
3021
3052
  this.colors = {
3022
- color: "white",
3053
+ //color: "white",
3054
+ color: "#F4F4F4",
3023
3055
  // color: "#F5F4FA",
3024
3056
  symbolColor: "black",
3025
3057
  }
@@ -3368,7 +3400,7 @@ class Server {
3368
3400
  ]
3369
3401
  pushEntry({
3370
3402
  host: hostMeta,
3371
- name: `[Files] ${rewrite.name || key}`,
3403
+ name: `[Website] ${rewrite.name || key}`,
3372
3404
  ip: externalIp || null,
3373
3405
  httpUrl: externalIp,
3374
3406
  httpsUrls: Array.from(new Set(httpsSources))
@@ -3401,26 +3433,26 @@ class Server {
3401
3433
  })
3402
3434
  }
3403
3435
 
3404
- const installedApps = Array.isArray(hostInfo.installed) ? hostInfo.installed : []
3405
- for (const app of installedApps) {
3406
- if (!app) {
3407
- continue
3408
- }
3409
- const httpHref = Array.isArray(app.http_href) ? app.http_href[0] : app.http_href
3410
- const httpsCandidates = Array.from(new Set([
3411
- ...ensureArray(app.app_href),
3412
- ...ensureArray(app.https_href)
3413
- ]))
3414
- pushEntry({
3415
- host: hostMeta,
3416
- name: app.title || app.name || app.folder,
3417
- ip: httpHref ? httpHref.replace(/^https?:\/\//i, '') : null,
3418
- httpUrl: httpHref || null,
3419
- httpsUrls: httpsCandidates,
3420
- description: app.description,
3421
- icon: app.https_icon || app.http_icon || app.icon
3422
- })
3423
- }
3436
+ // const installedApps = Array.isArray(hostInfo.installed) ? hostInfo.installed : []
3437
+ // for (const app of installedApps) {
3438
+ // if (!app) {
3439
+ // continue
3440
+ // }
3441
+ // const httpHref = Array.isArray(app.http_href) ? app.http_href[0] : app.http_href
3442
+ // const httpsCandidates = Array.from(new Set([
3443
+ // ...ensureArray(app.app_href),
3444
+ // ...ensureArray(app.https_href)
3445
+ // ]))
3446
+ // pushEntry({
3447
+ // host: hostMeta,
3448
+ // name: app.title || app.name || app.folder,
3449
+ // ip: httpHref ? httpHref.replace(/^https?:\/\//i, '') : null,
3450
+ // httpUrl: httpHref || null,
3451
+ // httpsUrls: httpsCandidates,
3452
+ // description: app.description,
3453
+ // icon: app.https_icon || app.http_icon || app.icon
3454
+ // })
3455
+ // }
3424
3456
  }
3425
3457
  }
3426
3458
  async terminals(filepath) {
@@ -3728,6 +3760,7 @@ class Server {
3728
3760
 
3729
3761
 
3730
3762
  await this.kernel.init({ port: this.port})
3763
+ this.kernel.server_port = this.port
3731
3764
  this.kernel.peer.start(this.kernel)
3732
3765
 
3733
3766
 
@@ -5494,6 +5527,18 @@ class Server {
5494
5527
  requirements_pending,
5495
5528
  })
5496
5529
  }))
5530
+ this.app.get("/net/:name/diff", ex(async (req, res) => {
5531
+ try {
5532
+ let processes = this.kernel.peer.info[this.kernel.peer.host].router_info
5533
+ let last_proc = JSON.stringify(this.kernel.last_processes)
5534
+ let current_proc = JSON.stringify(processes)
5535
+ this.kernel.last_processes = processes
5536
+ res.json({ diff: last_proc !== current_proc })
5537
+ } catch (e) {
5538
+ console.log("ERROR", e)
5539
+ res.json({ diff: true })
5540
+ }
5541
+ }))
5497
5542
  this.app.get("/net/:name", ex(async (req, res) => {
5498
5543
  let protocol = req.get('X-Forwarded-Proto') || "http"
5499
5544
  let { requirements, install_required, requirements_pending, error } = await this.kernel.bin.check({
@@ -5547,6 +5592,7 @@ class Server {
5547
5592
  const peer_url = `http://${this.kernel.peer.host}:${DEFAULT_PORT}`
5548
5593
  let peer_qr = null
5549
5594
  try { peer_qr = await QRCode.toDataURL(peer_url) } catch (_) {}
5595
+ const allow_dns_creation = req.params.name === this.kernel.peer.name
5550
5596
  res.render("net", {
5551
5597
  static_routes,
5552
5598
  selected_name: req.params.name,
@@ -5567,6 +5613,8 @@ class Server {
5567
5613
  current_host: this.kernel.peer.host,
5568
5614
  peer_url,
5569
5615
  peer_qr,
5616
+ cwd: this.kernel.path("api"),
5617
+ allow_dns_creation,
5570
5618
  })
5571
5619
  }))
5572
5620
  this.app.get("/network", ex(async (req, res) => {
@@ -7103,7 +7151,13 @@ class Server {
7103
7151
  return hosts[0]
7104
7152
  }
7105
7153
 
7106
- const info = this.kernel.processes.info.map((item) => {
7154
+ const processes = Array.isArray(this.kernel.processes.info) ? this.kernel.processes.info : []
7155
+ const serverPid = Number(process.pid)
7156
+ const filteredProcesses = Number.isFinite(serverPid)
7157
+ ? processes.filter((item) => Number(item && item.pid) !== serverPid)
7158
+ : processes.slice()
7159
+
7160
+ let info = filteredProcesses.map((item) => {
7107
7161
  const httpUrl = item.ip ? `http://${item.ip}` : null
7108
7162
  let httpsHosts = []
7109
7163
  if (preferHttps) {
@@ -7149,6 +7203,12 @@ class Server {
7149
7203
 
7150
7204
  this.add_extra_urls(info)
7151
7205
 
7206
+ if (Array.isArray(this.kernel.selfOrigins) && this.kernel.selfOrigins.length > 0) {
7207
+ info = info.filter((entry) => {
7208
+ return !this.kernel.selfOrigins.includes(entry.ip)
7209
+ })
7210
+ }
7211
+
7152
7212
  const toArray = (value) => {
7153
7213
  if (!value) return []
7154
7214
  return Array.isArray(value) ? value.filter(Boolean) : [value].filter(Boolean)
@@ -7429,7 +7489,9 @@ class Server {
7429
7489
  this.app.get("/pinokio/browser/:name", ex(async (req, res) => {
7430
7490
  await this.chrome(req, res, "run")
7431
7491
  }))
7432
-
7492
+ this.app.get("/v/:name", ex(async (req, res) => {
7493
+ await this.chrome(req, res, "run", { no_autoselect: true })
7494
+ }))
7433
7495
 
7434
7496
  this.app.get("/p/:name/review", ex(async (req, res) => {
7435
7497
  let gitRemote = null