pinokiod 3.19.2 → 3.19.4

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.
@@ -1,5 +1,3 @@
1
- const path = require('path')
2
- const { spawn } = require("child_process");
3
1
  /*
4
2
  {
5
3
  method: "filepicker.open",
@@ -7,6 +5,7 @@ const { spawn } = require("child_process");
7
5
  title, := <dialog title>
8
6
  type, := folder | file (default)
9
7
  path, := <cwd to open from>
8
+ filetype, := <file types to accept> can be an array or string (example: `image/*.png,*.jpg` or `["image/*.png", "docs/*.pdf"]`)
10
9
  filetypes, := <file types to accept> (example: [["Images", "*.png *.jpg *.jpeg"]] )
11
10
  multiple, := True | False (allow multiple)
12
11
  save, := True | False ('save as' dialog, which lets the user select a file name)
@@ -26,6 +25,8 @@ returns: {
26
25
  }
27
26
 
28
27
  */
28
+ const path = require('path')
29
+ const Util = require("../../util")
29
30
  class Filepicker {
30
31
  async open(req, ondata, kernel) {
31
32
  if (req.params.cwd) {
@@ -35,27 +36,10 @@ class Filepicker {
35
36
  } else {
36
37
  req.params.cwd = req.cwd
37
38
  }
38
- let response = await new Promise((resolve, reject) => {
39
- let picker_path = kernel.path("bin/py/picker.py")
40
- const proc = spawn("python", [picker_path])
41
39
 
42
- let output = "";
43
- proc.stdout.on("data", (chunk) => output += chunk);
44
- proc.stderr.on("data", (err) => console.error("Python error:", err.toString()));
45
- proc.on("close", () => {
46
- try {
47
- const result = JSON.parse(output);
48
- if (result.error) return reject(result.error);
49
- resolve(result.paths); // Always an array
50
- } catch (e) {
51
- reject("Failed to parse Python output: " + output);
52
- }
53
- });
40
+ let res = await Util.filepicker(req, ondata, kernel)
41
+ return res
54
42
 
55
- proc.stdin.write(JSON.stringify(req.params));
56
- proc.stdin.end();
57
- });
58
- return { paths: response }
59
43
  }
60
44
  }
61
45
  module.exports = Filepicker
@@ -1321,7 +1321,6 @@ class Api {
1321
1321
  // look for pinokio.js
1322
1322
  let p = path.resolve(request.path, "pinokio.js")
1323
1323
  let exists = await this.exists(p)
1324
- console.log({ p, exists })
1325
1324
  if (exists) {
1326
1325
  await this.launch(request, p)
1327
1326
  } else {
@@ -1332,7 +1331,6 @@ class Api {
1332
1331
  })
1333
1332
  }
1334
1333
  } else {
1335
- console.log({ request })
1336
1334
  let { cwd, script } = await this.resolveScript(request.path)
1337
1335
 
1338
1336
  if (!script) {
@@ -0,0 +1,21 @@
1
+ /*
2
+ {
3
+ method: "push",
4
+ params: {
5
+ title: <string>,
6
+ subtitle: <string>,
7
+ message: <string>,
8
+ image: <image path>,
9
+ sound: true|false,
10
+ }
11
+ }
12
+ (*/
13
+ const util = require('../../util')
14
+ const path = require('path');
15
+ module.exports = async (req, ondata, kernel) => {
16
+ let params = req.params
17
+ if (params.image) {
18
+ params.image = path.resolve(req.cwd, params.image)
19
+ }
20
+ util.push(params)
21
+ }
@@ -0,0 +1,31 @@
1
+ const path = require('path')
2
+ class CLI {
3
+ async install(req, ondata) {
4
+ await this.kernel.exec({
5
+ message: "npm install -g pinokio-cli@latest",
6
+ }, ondata)
7
+ }
8
+ async installed(req, ondata) {
9
+ console.log("Check installed")
10
+ if (this.kernel.which('pinokio')) {
11
+ let res = await this.kernel.exec({
12
+ message: "pinokio version"
13
+ }, ondata)
14
+ if (/.*v0\.0\.4.*/.test(res.stdout)) {
15
+ console.log("Installed")
16
+ return true
17
+ } else {
18
+ console.log("Not Installed")
19
+ return false
20
+ }
21
+ } else {
22
+ return false
23
+ }
24
+ }
25
+ async uninstall(req, ondata) {
26
+ await this.kernel.exec({
27
+ message: "npm uninstall -g pinokio-cli",
28
+ }, ondata)
29
+ }
30
+ }
31
+ module.exports = CLI
package/kernel/bin/git.js CHANGED
@@ -45,6 +45,25 @@ class Git {
45
45
  gitconfig_path
46
46
  )
47
47
  }
48
+
49
+ await fs.promises.mkdir(this.kernel.path("scripts/git"), { recursive: true }).catch((e) => { })
50
+ let gitpush_path = path.resolve(this.kernel.homedir, "scripts/git/push.json")
51
+ await fs.promises.copyFile(
52
+ path.resolve(__dirname, "..", "scripts/git/push"),
53
+ gitpush_path
54
+ )
55
+
56
+ let gitcreate_path = path.resolve(this.kernel.homedir, "scripts/git/create.json")
57
+ await fs.promises.copyFile(
58
+ path.resolve(__dirname, "..", "scripts/git/create"),
59
+ gitcreate_path
60
+ )
61
+
62
+ let gitcommit_path = path.resolve(this.kernel.homedir, "scripts/git/commit.json")
63
+ await fs.promises.copyFile(
64
+ path.resolve(__dirname, "..", "scripts/git/commit"),
65
+ gitcommit_path
66
+ )
48
67
  }
49
68
  async installed() {
50
69
  let gitconfig_path = path.resolve(this.kernel.homedir, "gitconfig")
@@ -52,6 +71,21 @@ class Git {
52
71
  if (!exists) {
53
72
  return false;
54
73
  }
74
+ let gitpush_path = path.resolve(this.kernel.homedir, "scripts/git/push.json")
75
+ let exists2 = await this.kernel.api.exists(gitpush_path)
76
+ if (!exists2) {
77
+ return false;
78
+ }
79
+ let gitcreate_path = path.resolve(this.kernel.homedir, "scripts/git/create.json")
80
+ let exists3 = await this.kernel.api.exists(gitcreate_path)
81
+ if (!exists3) {
82
+ return false;
83
+ }
84
+ let gitcommit_path = path.resolve(this.kernel.homedir, "scripts/git/commit.json")
85
+ let exists4 = await this.kernel.api.exists(gitcommit_path)
86
+ if (!exists4) {
87
+ return false;
88
+ }
55
89
 
56
90
  if (this.kernel.platform === "darwin") {
57
91
  let gh_config_exists = await this.kernel.exists("config/gh")
@@ -4,13 +4,13 @@ const _ = require('lodash')
4
4
  const path = require('path')
5
5
  const { rimraf } = require('rimraf')
6
6
  const { DownloaderHelper } = require('node-downloader-helper');
7
- const { spawn } = require('child_process')
8
7
  const { ProxyAgent } = require('proxy-agent');
9
8
 
10
9
  //const Cmake = require("./cmake")
11
10
  const Python = require('./python')
12
11
  const Git = require('./git')
13
12
  const Node = require('./node')
13
+ const CLI = require('./cli')
14
14
  const Brew = require("./brew")
15
15
  const Conda = require("./conda")
16
16
  const Win = require("./win")
@@ -27,6 +27,7 @@ const fse = require('fs-extra')
27
27
  const semver = require('semver')
28
28
  //const { bootstrap } = require('global-agent')
29
29
  const Environment = require('../environment')
30
+ const Util = require("../util")
30
31
  //const imageToAscii = require("image-to-ascii");
31
32
 
32
33
  const Setup = require('./setup')
@@ -198,6 +199,7 @@ class Bin {
198
199
  return e
199
200
  }
200
201
  async init() {
202
+ this.requirements_cache = {}
201
203
  this.mods = []
202
204
  if (this.kernel.homedir) {
203
205
  const bin_folder = this.path()
@@ -658,32 +660,8 @@ class Bin {
658
660
  }
659
661
  }
660
662
  async filepicker(req, ondata) {
661
- /*
662
- req.params := {
663
- cwd: cwd
664
- }
665
- */
666
- let response = await new Promise((resolve, reject) => {
667
- let picker_path = this.kernel.path("bin/py/picker.py")
668
- const proc = spawn("python", [picker_path])
669
-
670
- let output = "";
671
- proc.stdout.on("data", (chunk) => output += chunk);
672
- proc.stderr.on("data", (err) => console.error("Python error:", err.toString()));
673
- proc.on("close", () => {
674
- try {
675
- const result = JSON.parse(output);
676
- if (result.error) return reject(result.error);
677
- resolve(result.paths); // Always an array
678
- } catch (e) {
679
- reject("Failed to parse Python output: " + output);
680
- }
681
- });
682
-
683
- proc.stdin.write(JSON.stringify(req.params));
684
- proc.stdin.end();
685
- });
686
- return { paths: response }
663
+ let res = await Util.filepicker(req, ondata, this.kernel)
664
+ return res
687
665
  }
688
666
  async install(req, ondata) {
689
667
  /*
@@ -703,6 +681,7 @@ class Bin {
703
681
  } else {
704
682
  this.client = null
705
683
  }
684
+ console.log("Client", this.client)
706
685
  let requirements = JSON.parse(req.params)
707
686
  for(let x=0; x<10; x++) {
708
687
  console.log(`## Install Attempt ${x}`)
@@ -1000,27 +979,40 @@ class Bin {
1000
979
  let install_required = true
1001
980
  if (!requirements_pending) {
1002
981
  install_required = false
982
+ console.log("requirements", requirements)
1003
983
  for(let i=0; i<requirements.length; i++) {
1004
984
  let r = requirements[i]
1005
- //let installed = await this.installed(r)
1006
- //requirements[i].installed = installed
1007
- //if (!installed) {
1008
- // install_required = true
1009
- //}
1010
- let relevant = this.relevant(r)
1011
- requirements[i].relevant = relevant
1012
- if (relevant) {
1013
- let dependencies
1014
- if (r.name === "conda") {
1015
- dependencies = config.bin.conda_requirements
1016
- requirements[i].dependencies = dependencies
1017
- }
1018
- let installed = await this.check_installed(r, dependencies)
1019
- requirements[i].installed = installed
1020
- if (!installed) {
1021
- install_required = true
985
+ let fingerprint = JSON.stringify(r)
986
+ let installed
987
+ if (this.requirements_cache[fingerprint]) {
988
+ console.log("USE CACHED", fingerprint)
989
+ installed = true
990
+ requirements[i].installed = true
991
+ } else {
992
+ //let installed = await this.installed(r)
993
+ //requirements[i].installed = installed
994
+ //if (!installed) {
995
+ // install_required = true
996
+ //}
997
+ let relevant = this.relevant(r)
998
+ requirements[i].relevant = relevant
999
+ if (relevant) {
1000
+ let dependencies
1001
+ if (r.name === "conda") {
1002
+ dependencies = config.bin.conda_requirements
1003
+ requirements[i].dependencies = dependencies
1004
+ }
1005
+ installed = await this.check_installed(r, dependencies)
1006
+ if (installed) {
1007
+ // cache if true
1008
+ this.requirements_cache[fingerprint] = true
1009
+ }
1010
+ requirements[i].installed = installed
1022
1011
  }
1023
1012
  }
1013
+ if (!installed) {
1014
+ install_required = true
1015
+ }
1024
1016
  }
1025
1017
  }
1026
1018
 
@@ -27,6 +27,7 @@ module.exports = {
27
27
  requirements = requirements.concat([
28
28
  { name: "git", },
29
29
  { name: "node", },
30
+ { name: "cli", },
30
31
  { name: "ffmpeg", },
31
32
  // { name: "caddy", }
32
33
  ])
@@ -68,6 +69,7 @@ module.exports = {
68
69
  requirements = requirements.concat([
69
70
  { name: "git", },
70
71
  { name: "node", },
72
+ { name: "cli", },
71
73
  { name: "py" },
72
74
  ])
73
75
  return {
@@ -118,6 +120,7 @@ module.exports = {
118
120
  requirements = requirements.concat([
119
121
  { name: "git", },
120
122
  { name: "node", },
123
+ { name: "cli", },
121
124
  { name: "uv", },
122
125
  ])
123
126
  let conda_requirements = [
@@ -310,9 +310,6 @@ const ENV = async (type, homedir) => {
310
310
  irrelevant_keys.push(e.key)
311
311
  }
312
312
  }
313
-
314
- console.log({ filtered_envs, irrelevant_keys })
315
-
316
313
  // let filtered_envs = envs.filter((e) => {
317
314
  // return e.type.includes(type)
318
315
  // })
package/kernel/git.js ADDED
@@ -0,0 +1,64 @@
1
+ const git = require('isomorphic-git')
2
+ const fs = require('fs')
3
+ const path = require('path')
4
+ const { glob, sync, hasMagic } = require('glob-gitignore')
5
+ const http = require('isomorphic-git/http/node')
6
+ const ini = require('ini')
7
+ class Git {
8
+ constructor(kernel) {
9
+ this.kernel = kernel
10
+ }
11
+ async repos (root) {
12
+ let _repos = await glob('**/.git/', {
13
+ cwd: root,
14
+ onlyDirectories: true,
15
+ dot: true,
16
+ ignore: ['**/node_modules/**', "**/venv/**"], // optional
17
+ });
18
+
19
+ let repos = []
20
+ for(let r of _repos) {
21
+ const gitPath = path.resolve(root, r)
22
+ const gitRelPath = path.relative(root, gitPath)
23
+ const gitParentPath = path.dirname(gitPath)
24
+ const gitParentRelPath = path.relative(this.kernel.path("api"), gitParentPath)
25
+ let dir = path.dirname(gitPath)
26
+ try {
27
+ let gitRemote = await git.getConfig({
28
+ fs,
29
+ http,
30
+ dir,
31
+ path: 'remote.origin.url'
32
+ })
33
+ repos.push({
34
+ gitPath,
35
+ gitRelPath,
36
+ gitParentPath,
37
+ gitParentRelPath,
38
+ dir,
39
+ url: gitRemote
40
+ })
41
+ } catch (e) {
42
+ repos.push({
43
+ gitPath,
44
+ gitRelPath,
45
+ gitParentPath,
46
+ gitParentRelPath,
47
+ dir,
48
+ })
49
+ }
50
+ }
51
+ return repos
52
+ }
53
+ async config (dir) {
54
+ try {
55
+ const gitConfigPath = path.resolve(dir, ".git/config")
56
+ const content = await fs.promises.readFile(gitConfigPath, 'utf-8');
57
+ const gitconfig = ini.parse(content);
58
+ return gitconfig
59
+ } catch (e) {
60
+ return null
61
+ }
62
+ }
63
+ }
64
+ module.exports = Git
package/kernel/index.js CHANGED
@@ -35,6 +35,7 @@ const Plugin = require('./plugin')
35
35
  const Router = require("./router")
36
36
  const Procs = require('./procs')
37
37
  const Peer = require('./peer')
38
+ const Git = require('./git')
38
39
  const Connect = require('./connect')
39
40
  const { DownloaderHelper } = require('node-downloader-helper');
40
41
  const { ProxyAgent } = require('proxy-agent');
@@ -658,6 +659,7 @@ class Kernel {
658
659
  this.kv = new KV(this)
659
660
  this.cloudflare = new Cloudflare()
660
661
  this.peer = new Peer()
662
+ this.git = new Git(this)
661
663
 
662
664
  this.homedir = home
663
665
 
@@ -200,19 +200,21 @@ class Router {
200
200
  this._mapping = {}
201
201
  this.localhost_home_router.handle()
202
202
  this.localhost_variable_router.handle(this.kernel.memory.local)
203
- for(let proc of this.kernel.processes.info) {
204
- this.localhost_port_router.handle(proc)
205
- }
206
- if (this.kernel.peer.active) {
207
- for(let host in this.kernel.peer.info) {
208
- let peer = this.kernel.peer.info[host]
209
- if (peer.host === this.kernel.peer.host) {
210
- this.peer_home_router.handle(peer)
211
- this.peer_variable_router.handle(peer)
212
- this.peer_port_router.handle(peer)
203
+ if (this.kernel.processes && this.kernel.processes.info) {
204
+ for(let proc of this.kernel.processes.info) {
205
+ this.localhost_port_router.handle(proc)
206
+ }
207
+ if (this.kernel.peer.active) {
208
+ for(let host in this.kernel.peer.info) {
209
+ let peer = this.kernel.peer.info[host]
210
+ if (peer.host === this.kernel.peer.host) {
211
+ this.peer_home_router.handle(peer)
212
+ this.peer_variable_router.handle(peer)
213
+ this.peer_port_router.handle(peer)
214
+ }
213
215
  }
216
+ await this.fill()
214
217
  }
215
- await this.fill()
216
218
  }
217
219
  this.mapping = this._mapping
218
220
  }
@@ -0,0 +1,21 @@
1
+ {
2
+ "run": [{
3
+ "method": "input",
4
+ "params": {
5
+ "form": [{
6
+ "key": "commit",
7
+ "title": "Commit message"
8
+ }]
9
+ }
10
+ }, {
11
+ "method": "shell.run",
12
+ "params": {
13
+ "chain": true,
14
+ "path": "{{args.cwd}}",
15
+ "message": [
16
+ "git add .",
17
+ "git commit -am {{input.commit}}"
18
+ ]
19
+ }
20
+ }]
21
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "run": [{
3
+ "method": "shell.run",
4
+ "params": {
5
+ "path": "{{args.cwd}}",
6
+ "input": true,
7
+ "message": [
8
+ "gh repo create"
9
+ ]
10
+ }
11
+ }]
12
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "run": [{
3
+ "method": "input",
4
+ "params": {
5
+ "form": [{
6
+ "key": "commit",
7
+ "title": "Commit message"
8
+ }]
9
+ }
10
+ }, {
11
+ "method": "shell.run",
12
+ "params": {
13
+ "chain": true,
14
+ "path": "{{args.cwd}}",
15
+ "message": [
16
+ "git add .",
17
+ "git commit -am {{input.commit}}",
18
+ "git push"
19
+ ]
20
+ }
21
+ }]
22
+ }
package/kernel/shell.js CHANGED
@@ -252,6 +252,7 @@ class Shell {
252
252
  this.ondata({ raw: `\r\n████\r\n██ Starting Shell ${this.id}\r\n` })
253
253
 
254
254
 
255
+ this.start_time = Date.now()
255
256
  this.params = params
256
257
 
257
258
  // 3. path => path can be http, relative, absolute
@@ -969,8 +970,22 @@ class Shell {
969
970
  this.done = false
970
971
  this.ptyProcess = pty.spawn(this.shell, this.args, config)
971
972
  this.ptyProcess.onData((data) => {
972
- // console.log("onData", { data })
973
+ if (!this.monitor) {
974
+ this.monitor = ""
975
+ }
976
+ this.monitor = this.monitor + data
977
+ this.monitor = this.monitor.slice(-300) // last 300
973
978
  if (!this.done) {
979
+
980
+ // "request cursor position" handling: https://github.com/microsoft/node-pty/issues/535
981
+ if (data.includes('\x1b[6n')) {
982
+ const row = this.vt.buffer.active.cursorY + 1;
983
+ const col = this.vt.buffer.active.cursorX + 1;
984
+ const response = `\x1b[${row};${col}R`;
985
+ this.ptyProcess.write(response);
986
+ data = data.replace(/\x1b\[6n/g, ''); // remove the code
987
+ }
988
+
974
989
  this.queue.push(data)
975
990
  }
976
991
  });
@@ -1151,6 +1166,7 @@ ${cleaned}
1151
1166
  raw: msg,
1152
1167
  cleaned,
1153
1168
  state: cleaned,
1169
+ buf,
1154
1170
  shell_id: this.id
1155
1171
  }
1156
1172
  this.state = cleaned
package/kernel/shells.js CHANGED
@@ -2,6 +2,7 @@ const os = require('os')
2
2
  const _ = require('lodash')
3
3
  const fs = require('fs')
4
4
  const set = require("./api/set")
5
+ const Util = require('./util')
5
6
  const {
6
7
  glob
7
8
  } = require('glob')
@@ -117,8 +118,16 @@ class Shells {
117
118
  message,
118
119
  on: [{
119
120
  event: <regex>,
120
- <done|kill|debug>: true
121
- }],
121
+ done: true|false,
122
+ kill: true|false,
123
+ debug: true|false,
124
+ notify: {
125
+ title,
126
+ sound,
127
+ message,
128
+ image
129
+ }
130
+ }]
122
131
  }
123
132
  }
124
133
  */
@@ -127,27 +136,43 @@ class Shells {
127
136
  // regexify
128
137
  //let matches = /^\/([^\/]+)\/([dgimsuy]*)$/.exec(handler.event)
129
138
  if (handler.event) {
130
- let matches = /^\/(.+)\/([dgimsuy]*)$/gs.exec(handler.event)
131
- if (!/g/.test(matches[2])) {
132
- matches[2] += "g" // if g option is not included, include it (need it for matchAll)
133
- }
134
- let re = new RegExp(matches[1], matches[2])
135
- if (stream.cleaned) {
136
- let line = stream.cleaned.replaceAll(/[\r\n]/g, "")
137
- //let rendered_event = [...stream.cleaned.matchAll(re)]
138
-
139
-
140
- let rendered_event = [...line.matchAll(re)]
141
- // 3. if the rendered expression is truthy, run the "run" script
142
- if (rendered_event.length > 0) {
143
- stream.matches = rendered_event
144
- if (handler.kill) {
145
- m = rendered_event[0]
146
- sh.kill()
139
+ if (handler.notify) {
140
+ // notify is a special case. check by line
141
+ let matches = /^\/(.+)\/([dgimsuy]*)$/gs.exec(handler.event)
142
+ if (!/g/.test(matches[2])) {
143
+ matches[2] += "g" // if g option is not included, include it (need it for matchAll)
144
+ }
145
+ let re = new RegExp(matches[1], matches[2])
146
+ let test = re.exec(sh.monitor)
147
+ if (test && test.length > 0) {
148
+ // reset monitor
149
+ sh.monitor = ""
150
+ let params = this.kernel.template.render(handler.notify, { event: test })
151
+ if (params.image) {
152
+ params.contentImage = path.resolve(req.cwd, params.image)
147
153
  }
148
- if (handler.done) {
149
- m = rendered_event[0]
150
- sh.continue()
154
+ Util.push(params)
155
+ }
156
+ } else {
157
+ let matches = /^\/(.+)\/([dgimsuy]*)$/gs.exec(handler.event)
158
+ if (!/g/.test(matches[2])) {
159
+ matches[2] += "g" // if g option is not included, include it (need it for matchAll)
160
+ }
161
+ let re = new RegExp(matches[1], matches[2])
162
+ if (stream.cleaned) {
163
+ let line = stream.cleaned.replaceAll(/[\r\n]/g, "")
164
+ let rendered_event = [...line.matchAll(re)]
165
+ // 3. if the rendered expression is truthy, run the "run" script
166
+ if (rendered_event.length > 0) {
167
+ stream.matches = rendered_event
168
+ if (handler.kill) {
169
+ m = rendered_event[0]
170
+ sh.kill()
171
+ }
172
+ if (handler.done) {
173
+ m = rendered_event[0]
174
+ sh.continue()
175
+ }
151
176
  }
152
177
  }
153
178
  }