pinokiod 3.24.0 → 3.26.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.
@@ -0,0 +1,67 @@
1
+ const child_process = require('child_process')
2
+ module.exports = async (req, ondata, kernel) => {
3
+ /*
4
+ req := {
5
+ method: "exec",
6
+ params: {
7
+
8
+ // pinokio params
9
+ message: <message>,
10
+ path: <path>,
11
+
12
+ // node.js child_process.exec params
13
+
14
+ // Working directory
15
+ cwd: '/path/to/working/directory',
16
+
17
+ // Environment variables
18
+ env: { ...process.env, CUSTOM_VAR: 'value' },
19
+
20
+ // Encoding for stdout/stderr (default: 'utf8')
21
+ encoding: 'utf8', // or 'buffer', 'ascii', etc.
22
+
23
+ // Shell to execute the command
24
+ shell: '/bin/bash', // default varies by platform
25
+
26
+ // Timeout in milliseconds
27
+ timeout: 10000, // Kill process after 10 seconds
28
+
29
+ // Maximum buffer size for stdout/stderr
30
+ maxBuffer: 1024 * 1024, // 1MB (default: 1024 * 1024)
31
+
32
+ // Signal to send when killing due to timeout
33
+ killSignal: 'SIGTERM', // default: 'SIGTERM'
34
+
35
+ // User identity (Unix only)
36
+ uid: 1000,
37
+ gid: 1000,
38
+
39
+ // Windows-specific options
40
+ windowsHide: true, // Hide subprocess console window on Windows
41
+ windowsVerbatimArguments: false // Quote handling on Windows
42
+
43
+ }
44
+ }
45
+ */
46
+ if (req.params && req.params.message) {
47
+ // if cwd exists, use cwd
48
+ // if cwd doesn't exist, set pat
49
+ if (!req.params.cwd && req.params.path) {
50
+ req.params.cwd = req.params.path
51
+ }
52
+ req.params.env = Object.assign({}, kernel.envs, req.params.env)
53
+ console.log("env", JSON.stringify(req.params.env, null, 2))
54
+ ondata({ raw: `██ Exec: ${req.params.message}\r\n` })
55
+ let response = await new Promise((resolve, reject) => {
56
+ child_process.exec(req.params.message, req.params, (error, stdout, stderr) => {
57
+ resolve({
58
+ stdout,
59
+ error,
60
+ stderr
61
+ })
62
+ })
63
+ })
64
+ console.log({ response })
65
+ return response
66
+ }
67
+ }
@@ -1176,6 +1176,7 @@ class Api {
1176
1176
  // console.log("kernel.refresh after step")
1177
1177
  // this.kernel.refresh(true)
1178
1178
  } catch (e) {
1179
+ console.log("FUDKDFKSDFLJSDFHSDFLKHSDLFHSDFH", e)
1179
1180
  ondata({ raw: e.toString() })
1180
1181
  }
1181
1182
  }, concurrency)
@@ -113,7 +113,7 @@ class Caddy {
113
113
  //let response = await this.kernel.api.wait(id)
114
114
  console.log("ondata", ondata.toString())
115
115
  setTimeout(() => {
116
- ondata({ html: `<b><i class="fa-solid fa-keyboard"></i> Enter the system password to generate a certificate</b>` }, "notify3")
116
+ ondata({ html: `<b><i class="fa-solid fa-keyboard"></i> Enter the system password to generate an HTTPS certificate</b>` }, "notify3")
117
117
  }, 2000)
118
118
  await this.kernel.exec({
119
119
  input: true,
package/kernel/index.js CHANGED
@@ -293,16 +293,11 @@ class Kernel {
293
293
  async refresh(notify_peers) {
294
294
  const ts = Date.now()
295
295
  let network_active = await this.network_active()
296
- // console.log({ network_active })
297
296
  if (!network_active) {
298
297
  return
299
298
  }
300
299
  let network_running = await this.network_running()
301
- // console.log({ network_running })
302
- // console.log({ refreshing: this.processes.refreshing })
303
300
  if (network_running) {
304
-
305
-
306
301
  let ts = Date.now()
307
302
  if (this.processes.refreshing) {
308
303
  // process list refreshing. try again later
@@ -680,7 +675,7 @@ class Kernel {
680
675
  this.processes = new Procs(this)
681
676
  this.kv = new KV(this)
682
677
  this.cloudflare = new Cloudflare()
683
- this.peer = new Peer()
678
+ this.peer = new Peer(this)
684
679
  this.git = new Git(this)
685
680
 
686
681
  this.homedir = home
package/kernel/peer.js CHANGED
@@ -3,7 +3,8 @@ const axios = require('axios');
3
3
  const os = require('os')
4
4
  const Environment = require("./environment")
5
5
  class PeerDiscovery {
6
- constructor(port = 41234, message = 'ping', interval = 1000) {
6
+ constructor(kernel, port = 41234, message = 'ping', interval = 1000) {
7
+ this.kernel = kernel
7
8
  this.port = port;
8
9
  this.message = Buffer.from(message);
9
10
  this.interval = interval;
@@ -100,10 +101,14 @@ class PeerDiscovery {
100
101
  }
101
102
  async _refresh(host) {
102
103
  try {
103
- let res = await axios.get(`http://${host}:${this.default_port}/pinokio/peer`, {
104
- timeout: 2000
105
- })
106
- return res.data
104
+ if (host === this.host) {
105
+ return this.current_host()
106
+ } else {
107
+ let res = await axios.get(`http://${host}:${this.default_port}/pinokio/peer`, {
108
+ timeout: 2000
109
+ })
110
+ return res.data
111
+ }
107
112
  } catch (e) {
108
113
  console.log("_refresh error", { host , e })
109
114
  return null
@@ -128,6 +133,19 @@ class PeerDiscovery {
128
133
  return res
129
134
  }
130
135
  }
136
+ current_host() {
137
+ return {
138
+ home: this.kernel.homedir,
139
+ arch: this.kernel.arch,
140
+ platform: this.kernel.platform,
141
+ name: this.kernel.peer.name,
142
+ host: this.kernel.peer.host,
143
+ port_mapping: this.kernel.router.port_mapping,
144
+ proc: this.kernel.processes.info,
145
+ router: this.kernel.router.published(),
146
+ memory: this.kernel.memory
147
+ }
148
+ }
131
149
  // refresh peer info
132
150
  async refresh(peers) {
133
151
  // if (this.active) {
package/kernel/plugin.js CHANGED
@@ -5,33 +5,13 @@ class Plugin {
5
5
  constructor(kernel) {
6
6
  this.kernel = kernel
7
7
  }
8
- async init() {
9
- let exists = await this.kernel.exists("plugin")
10
- if (!exists) {
11
- await fs.promises.mkdir(this.kernel.path("plugin"), { recursive: true }).catch((e) => {})
12
- if (this.kernel.bin.installed && this.kernel.bin.installed.conda && this.kernel.bin.installed.conda.has("git")) {
13
- await this.kernel.exec({
14
- //message: "git clone https://github.com/peanutcocktail/plugin",
15
- //message: "git clone https://github.com/pinokiocomputer/plugin",
16
- message: "git clone https://github.com/pinokiocomputer/code",
17
- path: this.kernel.path("plugin")
18
- }, (e) => {
19
- process.stdout.write(e.raw)
20
- })
21
- }
22
- }
8
+ async setConfig() {
23
9
  let plugin_dir = path.resolve(this.kernel.homedir, "plugin")
24
- // this.config = await this.kernel.require(pinokiojs)
25
10
  this.cache = {}
26
11
 
27
12
  let plugin_paths = await glob('**/pinokio.js', { cwd: plugin_dir })
28
- console.log({ plugin_paths })
29
13
 
30
14
  let plugins = []
31
- // let info = new Info(this.kernel)
32
- // info.cwd = () => {
33
- // return plugin_dir
34
- // }
35
15
  for(let plugin_path of plugin_paths) {
36
16
  let config = await this.kernel.require(path.resolve(plugin_dir, plugin_path))
37
17
  let cwd = plugin_path.split("/").slice(0, -1).join("/")
@@ -48,26 +28,29 @@ class Plugin {
48
28
  return plugin
49
29
  })
50
30
  }
51
- console.log("THIS.config", JSON.stringify(this.config, null, 2))
52
-
53
- // if (this.kernel.bin.installed && this.kernel.bin.installed.conda && this.kernel.bin.installed.conda.has("git")) {
54
- // // if ~/pinokio/prototype doesn't exist, clone
55
- // let exists = await this.kernel.exists("plugin")
56
- // if (!exists) {
57
- // await this.kernel.exec({
58
- // //message: "git clone https://github.com/peanutcocktail/plugin",
59
- // //message: "git clone https://github.com/pinokiocomputer/plugin",
60
- // message: "git clone https://github.com/pinokiocomputer/code",
61
- // path: this.kernel.homedir
62
- // }, (e) => {
63
- // process.stdout.write(e.raw)
64
- // })
65
- // }
66
- // let plugin_dir = path.resolve(this.kernel.homedir, "plugin")
67
- // let pinokiojs = path.resolve(plugin_dir, "pinokio.js")
68
- // this.config = await this.kernel.require(pinokiojs)
69
- // this.cache = {}
70
- // }
31
+ }
32
+ async init() {
33
+ let exists = await this.kernel.exists("plugin")
34
+ if (!exists) {
35
+ await fs.promises.mkdir(this.kernel.path("plugin"), { recursive: true }).catch((e) => {})
36
+ }
37
+ let code_exists = await this.kernel.exists("plugin/code")
38
+ if (!code_exists) {
39
+ if (this.kernel.bin.installed && this.kernel.bin.installed.conda && this.kernel.bin.installed.conda.has("git")) {
40
+ await this.kernel.exec({
41
+ //message: "git clone https://github.com/peanutcocktail/plugin",
42
+ //message: "git clone https://github.com/pinokiocomputer/plugin",
43
+ message: "git clone https://github.com/pinokiocomputer/code",
44
+ path: this.kernel.path("plugin")
45
+ }, (e) => {
46
+ process.stdout.write(e.raw)
47
+ })
48
+ await this.setConfig()
49
+ return
50
+ }
51
+ } else {
52
+ await this.setConfig()
53
+ }
71
54
  }
72
55
  async update() {
73
56
  if (this.kernel.bin.installed && this.kernel.bin.installed.conda && this.kernel.bin.installed.conda.has("git")) {
@@ -2,6 +2,7 @@ const fs = require('fs')
2
2
  const path = require('path')
3
3
  const { glob, sync, hasMagic } = require('glob-gitignore')
4
4
  const marked = require('marked')
5
+ const matter = require('gray-matter');
5
6
  class Proto {
6
7
  constructor(kernel) {
7
8
  this.kernel = kernel
@@ -49,10 +50,34 @@ class Proto {
49
50
  }
50
51
  console.log("Proto init done")
51
52
  }
53
+ async ai() {
54
+ let ai_path = this.kernel.path("prototype/system/ai/new/static")
55
+ let mds = await fs.promises.readdir(ai_path)
56
+ mds = mds.filter((md) => {
57
+ return md.endsWith(".md")
58
+ })
59
+ const results = []
60
+ for(let md of mds) {
61
+ let mdpath = path.resolve(ai_path, md)
62
+ let mdstr = await fs.promises.readFile(mdpath, "utf8")
63
+ const { data, content } = matter(mdstr)
64
+ // const html = marked.parse(content)
65
+ let { title, description, ...meta } = data
66
+ results.push({
67
+ title,
68
+ description,
69
+ meta,
70
+ data,
71
+ content
72
+ })
73
+ }
74
+ return results
75
+ }
52
76
  async reset() {
53
77
  await fs.promises.rm(this.kernel.path("prototype"), { recursive: true })
54
78
  }
55
79
  async create(req, ondata) {
80
+ console.log("REQ", req)
56
81
  try {
57
82
  let projectType = req.params.projectType
58
83
  let startType = req.params.cliType || req.params.startType
@@ -216,6 +216,19 @@ class Router {
216
216
  await this.fill()
217
217
  }
218
218
  }
219
+ this.config.apps.http.servers.main.routes.push({
220
+ "handle": [
221
+ {
222
+ "handler": "static_response",
223
+ "status_code": 302,
224
+ "headers": {
225
+ "Location": [
226
+ `https://${this.default_match}/launch?url={http.request.scheme}://{http.request.host}{http.request.uri}`
227
+ ]
228
+ }
229
+ }
230
+ ]
231
+ })
219
232
  this.mapping = this._mapping
220
233
  }
221
234
 
@@ -6,6 +6,17 @@ class LocalhostHomeRouter {
6
6
  this.router.add({ host: this.router.kernel.peer.host, dial: this.router.default_host + ":" + this.router.default_port, match: this.router.default_match })
7
7
  this.router.config = {
8
8
  "apps": {
9
+ "tls": {
10
+ "automation": {
11
+ "policies": [
12
+ {
13
+ "issuers": [{ "module": "internal" }],
14
+ "on_demand": true
15
+ }
16
+ ]
17
+ }
18
+ },
19
+
9
20
  "http": {
10
21
  "servers": {
11
22
  "main": {
package/kernel/shell.js CHANGED
@@ -209,7 +209,6 @@ class Shell {
209
209
  }
210
210
  }
211
211
  async start(params, ondata) {
212
- console.log("SHELL START", params)
213
212
  this.ondata = ondata
214
213
 
215
214
  /*
@@ -1056,10 +1055,8 @@ class Shell {
1056
1055
  for(let notif of notifications) {
1057
1056
  if (notif.type !== "bell") {
1058
1057
  Util.push({
1059
- // title: notif.type,
1060
- // subtitle: notif.title,
1061
1058
  image: path.resolve(__dirname, "../server/public/pinokio-black.png"),
1062
- message: notif.title,//`🔔 [${notif.type}] ${notif.title}: ${notif.message}\n`,
1059
+ message: notif.title,
1063
1060
  sound: true,
1064
1061
  timeout: 30,
1065
1062
  })
@@ -1135,8 +1132,10 @@ class Shell {
1135
1132
  this.ptyProcess = undefined
1136
1133
  // automatically remove the shell from this.kernel.shells
1137
1134
  this.kernel.shell.rm(this.id)
1138
- this.ondata({ raw: `\r\n\r\n██ Terminated Shell ${this.id}\r\n████\r\n` })
1139
- this.ondata({ raw: "", type: "shell.kill" })
1135
+ if (!this.mute) {
1136
+ this.ondata({ raw: `\r\n\r\n██ Terminated Shell ${this.id}\r\n████\r\n` })
1137
+ this.ondata({ raw: "", type: "shell.kill" })
1138
+ }
1140
1139
  cb()
1141
1140
  } else {
1142
1141
  kill(this.ptyProcess.pid, "SIGKILL", true)
@@ -1144,13 +1143,17 @@ class Shell {
1144
1143
  this.ptyProcess = undefined
1145
1144
  // automatically remove the shell from this.kernel.shells
1146
1145
  this.kernel.shell.rm(this.id)
1147
- this.ondata({ raw: `\r\n\r\n██ Terminated Shell ${this.id}\r\n████\r\n` })
1148
- this.ondata({ raw: "", type: "shell.kill" })
1146
+ if (!this.mute) {
1147
+ this.ondata({ raw: `\r\n\r\n██ Terminated Shell ${this.id}\r\n████\r\n` })
1148
+ this.ondata({ raw: "", type: "shell.kill" })
1149
+ }
1149
1150
  }
1150
1151
  } else {
1151
1152
  this.kernel.shell.rm(this.id)
1152
- this.ondata({ raw: `\r\n\r\n██ Terminated Shell ${this.id}\r\n████\r\n` })
1153
- this.ondata({ raw: "", type: "shell.kill" })
1153
+ if (!this.mute) {
1154
+ this.ondata({ raw: `\r\n\r\n██ Terminated Shell ${this.id}\r\n████\r\n` })
1155
+ this.ondata({ raw: "", type: "shell.kill" })
1156
+ }
1154
1157
  }
1155
1158
 
1156
1159
 
package/kernel/shells.js CHANGED
@@ -142,59 +142,66 @@ class Shells {
142
142
  }
143
143
  }
144
144
  */
145
- if (params.on && Array.isArray(params.on)) {
146
- for(let i=0; i<params.on.length; i++) {
147
- let handler = params.on[i]
148
- // regexify
149
- //let matches = /^\/([^\/]+)\/([dgimsuy]*)$/.exec(handler.event)
150
- if (handler.event) {
151
- if (handler.notify) {
152
- // notify is a special case. check by line
153
- let matches = /^\/(.+)\/([dgimsuy]*)$/gs.exec(handler.event)
154
- if (!/g/.test(matches[2])) {
155
- matches[2] += "g" // if g option is not included, include it (need it for matchAll)
156
- }
157
- let re = new RegExp(matches[1], matches[2])
158
- let test = re.exec(sh.monitor)
159
- if (test && test.length > 0) {
160
- // reset monitor
161
- sh.monitor = ""
162
- let params = this.kernel.template.render(handler.notify, { event: test })
163
- if (params.image) {
164
- params.contentImage = path.resolve(req.cwd, params.image)
145
+ try {
146
+ if (params.on && Array.isArray(params.on)) {
147
+ for(let i=0; i<params.on.length; i++) {
148
+ let handler = params.on[i]
149
+ // regexify
150
+ //let matches = /^\/([^\/]+)\/([dgimsuy]*)$/.exec(handler.event)
151
+ if (handler.event) {
152
+ if (handler.notify) {
153
+ // notify is a special case. check by line
154
+ let matches = /^\/(.+)\/([dgimsuy]*)$/gs.exec(handler.event)
155
+ if (!/g/.test(matches[2])) {
156
+ matches[2] += "g" // if g option is not included, include it (need it for matchAll)
165
157
  }
166
- Util.push(params)
167
- }
168
- } else {
169
- let matches = /^\/(.+)\/([dgimsuy]*)$/gs.exec(handler.event)
170
- if (!/g/.test(matches[2])) {
171
- matches[2] += "g" // if g option is not included, include it (need it for matchAll)
172
- }
173
- let re = new RegExp(matches[1], matches[2])
174
- if (stream.cleaned) {
175
- let line = stream.cleaned.replaceAll(/[\r\n]/g, "")
176
- let rendered_event = [...line.matchAll(re)]
177
- // 3. if the rendered expression is truthy, run the "run" script
178
- if (rendered_event.length > 0) {
179
- stream.matches = rendered_event
180
- if (handler.kill) {
181
- m = rendered_event[0]
182
- matched_index = i
183
- sh.kill()
158
+ let re = new RegExp(matches[1], matches[2])
159
+ let test = re.exec(sh.monitor)
160
+ if (test && test.length > 0) {
161
+ // reset monitor
162
+ sh.monitor = ""
163
+ let params = this.kernel.template.render(handler.notify, { event: test })
164
+ if (params.image) {
165
+ params.contentImage = path.resolve(req.cwd, params.image)
184
166
  }
185
- if (handler.done) {
186
- m = rendered_event[0]
187
- matched_index = i
188
- sh.continue()
167
+ Util.push(params)
168
+ }
169
+ } else {
170
+ let matches = /^\/(.+)\/([dgimsuy]*)$/gs.exec(handler.event)
171
+ if (!/g/.test(matches[2])) {
172
+ matches[2] += "g" // if g option is not included, include it (need it for matchAll)
173
+ }
174
+ let re = new RegExp(matches[1], matches[2])
175
+ if (stream.cleaned) {
176
+ let line = stream.cleaned.replaceAll(/[\r\n]/g, "")
177
+ let rendered_event = [...line.matchAll(re)]
178
+ // 3. if the rendered expression is truthy, run the "run" script
179
+ if (rendered_event.length > 0) {
180
+ stream.matches = rendered_event
181
+ if (handler.kill) {
182
+ m = rendered_event[0]
183
+ matched_index = i
184
+ sh.kill()
185
+ }
186
+ if (handler.done) {
187
+ m = rendered_event[0]
188
+ matched_index = i
189
+ sh.continue()
190
+ }
189
191
  }
190
192
  }
191
193
  }
192
194
  }
193
195
  }
194
196
  }
195
- }
196
- if (ondata) {
197
- ondata(stream)
197
+ if (ondata) {
198
+ ondata(stream)
199
+ }
200
+ } catch (e) {
201
+ console.log("Capture error", e)
202
+ ondata({ raw: e.stack })
203
+ sh.mute = true
204
+ sh.kill()
198
205
  }
199
206
  })
200
207
  /*
@@ -490,8 +497,6 @@ class Shells {
490
497
 
491
498
  if (request.id) {
492
499
 
493
- console.log("this.shells", this.shells.map((x) => { return x.id }))
494
-
495
500
  let shells = []
496
501
  for(let i=0; i<this.shells.length; i++) {
497
502
  shells.push(this.shells[i])
package/kernel/util.js CHANGED
@@ -224,7 +224,6 @@ const openURL = (url) => {
224
224
  } else {
225
225
  command = `xdg-open "${url}"`; // Linux
226
226
  }
227
- console.log("openURL", { url, command })
228
227
  child_process.exec(command);
229
228
  }
230
229
  const openfs = (dirPath, options, kernel) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "3.24.0",
3
+ "version": "3.26.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -36,6 +36,7 @@
36
36
  "glob": "^10.3.3",
37
37
  "glob-gitignore": "^1.0.14",
38
38
  "go-get-folder-size": "^0.5.5",
39
+ "gray-matter": "^4.0.3",
39
40
  "http-proxy": "^1.18.1",
40
41
  "http-proxy-middleware": "^3.0.0",
41
42
  "http-terminator": "^3.2.0",