pinokiod 5.1.10 → 5.1.11
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.
- package/kernel/api/fs/download_worker.js +158 -0
- package/kernel/api/fs/index.js +95 -91
- package/kernel/api/index.js +3 -0
- package/kernel/bin/index.js +5 -2
- package/kernel/environment.js +19 -2
- package/kernel/git.js +972 -1
- package/kernel/index.js +65 -30
- package/kernel/peer.js +1 -2
- package/kernel/plugin.js +0 -8
- package/kernel/procs.js +92 -36
- package/kernel/prototype.js +45 -22
- package/kernel/shells.js +30 -6
- package/kernel/sysinfo.js +33 -13
- package/kernel/util.js +61 -24
- package/kernel/workspace_status.js +131 -7
- package/package.json +1 -1
- package/pipe/index.js +1 -1
- package/server/index.js +1169 -350
- package/server/public/create-launcher.js +157 -2
- package/server/public/install.js +135 -41
- package/server/public/style.css +32 -1
- package/server/public/tab-link-popover.js +45 -14
- package/server/public/terminal-settings.js +51 -35
- package/server/public/urldropdown.css +89 -3
- package/server/socket.js +12 -7
- package/server/views/agents.ejs +4 -3
- package/server/views/app.ejs +798 -30
- package/server/views/bootstrap.ejs +2 -1
- package/server/views/checkpoints.ejs +1014 -0
- package/server/views/checkpoints_registry_beta.ejs +260 -0
- package/server/views/columns.ejs +4 -4
- package/server/views/connect.ejs +1 -0
- package/server/views/d.ejs +74 -4
- package/server/views/download.ejs +28 -28
- package/server/views/editor.ejs +4 -5
- package/server/views/env_editor.ejs +1 -1
- package/server/views/file_explorer.ejs +1 -1
- package/server/views/index.ejs +3 -1
- package/server/views/init/index.ejs +2 -1
- package/server/views/install.ejs +2 -1
- package/server/views/net.ejs +9 -7
- package/server/views/network.ejs +15 -14
- package/server/views/pro.ejs +5 -2
- package/server/views/prototype/index.ejs +2 -1
- package/server/views/registry_link.ejs +76 -0
- package/server/views/rows.ejs +4 -4
- package/server/views/screenshots.ejs +1 -0
- package/server/views/settings.ejs +1 -0
- package/server/views/shell.ejs +4 -6
- package/server/views/terminal.ejs +528 -38
- package/server/views/tools.ejs +1 -0
- package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/1764297248545 +0 -45
- package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/1764335557118 +0 -45
- package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/1764335834126 +0 -45
- package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/events +0 -12
- package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/latest +0 -45
package/kernel/index.js
CHANGED
|
@@ -89,6 +89,11 @@ class Kernel {
|
|
|
89
89
|
this.pinokio_configs = {}
|
|
90
90
|
this.shellpath = shellPath.sync()
|
|
91
91
|
this.favicon = new Favicon()
|
|
92
|
+
this.vram = 0
|
|
93
|
+
this.ram = 0
|
|
94
|
+
this.sysReady = new Promise((resolve) => {
|
|
95
|
+
this._resolveSysReady = resolve
|
|
96
|
+
})
|
|
92
97
|
|
|
93
98
|
|
|
94
99
|
}
|
|
@@ -999,9 +1004,16 @@ class Kernel {
|
|
|
999
1004
|
|
|
1000
1005
|
}
|
|
1001
1006
|
|
|
1007
|
+
// Load git checkpoints as soon as homedir is ready so features depending on it
|
|
1008
|
+
// (like the Backups page) can see prior state immediately.
|
|
1009
|
+
console.time("git.loadCheckpoints")
|
|
1010
|
+
await this.git.loadCheckpoints()
|
|
1011
|
+
console.timeEnd("git.loadCheckpoints")
|
|
1012
|
+
|
|
1002
1013
|
// let contents = await fs.promises.readdir(this.homedir)
|
|
1003
1014
|
//await this.bin.init()
|
|
1004
1015
|
let ts = Date.now()
|
|
1016
|
+
// Initialize core tools
|
|
1005
1017
|
this.bin.init().then(() => {
|
|
1006
1018
|
if (this.homedir) {
|
|
1007
1019
|
this.git.init().then(() => {
|
|
@@ -1053,6 +1065,10 @@ class Kernel {
|
|
|
1053
1065
|
this.sysinfo = info
|
|
1054
1066
|
|
|
1055
1067
|
await this.getInfo(true)
|
|
1068
|
+
if (this._resolveSysReady) {
|
|
1069
|
+
this._resolveSysReady()
|
|
1070
|
+
this._resolveSysReady = null
|
|
1071
|
+
}
|
|
1056
1072
|
|
|
1057
1073
|
await fs.promises.mkdir(this.path("logs"), { recursive: true }).catch((e) => { })
|
|
1058
1074
|
await fs.promises.writeFile(this.path("logs/system.json"), JSON.stringify(this.i, null, 2))
|
|
@@ -1064,39 +1080,49 @@ class Kernel {
|
|
|
1064
1080
|
// get env
|
|
1065
1081
|
if (!this.launch_complete) {
|
|
1066
1082
|
let interval = setInterval(async () => {
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
let
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1083
|
+
try {
|
|
1084
|
+
if (this.i) {
|
|
1085
|
+
for (let api of this.i.api) {
|
|
1086
|
+
let env_path = path.resolve(this.api.userdir, api.path)
|
|
1087
|
+
let e = await Environment.get(env_path, this)
|
|
1088
|
+
if (e.PINOKIO_SCRIPT_AUTOLAUNCH && e.PINOKIO_SCRIPT_AUTOLAUNCH.trim().length > 0) {
|
|
1089
|
+
let autolaunch_path = path.resolve(env_path, e.PINOKIO_SCRIPT_AUTOLAUNCH)
|
|
1090
|
+
let exists = await this.exists(autolaunch_path)
|
|
1091
|
+
if (exists) {
|
|
1092
|
+
this.api.process({
|
|
1093
|
+
uri: autolaunch_path,
|
|
1094
|
+
input: {}
|
|
1078
1095
|
// client: req.client,
|
|
1079
1096
|
// caller: req.parent.path,
|
|
1080
|
-
|
|
1081
|
-
|
|
1097
|
+
}, (r) => {
|
|
1098
|
+
console.log({ autolaunch_path, r })
|
|
1082
1099
|
// resolve(r.input)
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1100
|
+
}).catch((err) => {
|
|
1101
|
+
console.warn('[Kernel.init] autolaunch process failed:', err && err.message ? err.message : err)
|
|
1102
|
+
})
|
|
1103
|
+
} else {
|
|
1104
|
+
console.log("SCRIPT DOES NOT EXIST. Ignoring.", autolaunch_path)
|
|
1105
|
+
}
|
|
1086
1106
|
}
|
|
1087
1107
|
}
|
|
1108
|
+
clearInterval(interval)
|
|
1109
|
+
setTimeout(() => {
|
|
1110
|
+
this.launch_complete = true
|
|
1111
|
+
console.log("SETTING launch complete", this.launch_complete)
|
|
1112
|
+
}, 2000)
|
|
1088
1113
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
this.launch_complete = true
|
|
1092
|
-
console.log("SETTING launch complete", this.launch_complete)
|
|
1093
|
-
}, 2000)
|
|
1114
|
+
} catch (err) {
|
|
1115
|
+
console.warn('[Kernel.init] autolaunch loop failed:', err && err.message ? err.message : err)
|
|
1094
1116
|
}
|
|
1095
1117
|
}, 1000)
|
|
1096
1118
|
}
|
|
1097
1119
|
}
|
|
1120
|
+
}).catch((err) => {
|
|
1121
|
+
console.warn("Shell init error:", err && err.message ? err.message : err)
|
|
1098
1122
|
})
|
|
1099
1123
|
}
|
|
1124
|
+
}).catch((err) => {
|
|
1125
|
+
console.warn("Bin init error:", err && err.message ? err.message : err)
|
|
1100
1126
|
})
|
|
1101
1127
|
let ts2 = Date.now()
|
|
1102
1128
|
await this.api.init()
|
|
@@ -1109,6 +1135,8 @@ class Kernel {
|
|
|
1109
1135
|
system,
|
|
1110
1136
|
platform: this.platform,
|
|
1111
1137
|
arch: this.arch,
|
|
1138
|
+
vram: this.vram,
|
|
1139
|
+
ram: this.ram,
|
|
1112
1140
|
proxy: (port) => {
|
|
1113
1141
|
return this.api.get_proxy_url("/proxy", port)
|
|
1114
1142
|
},
|
|
@@ -1118,19 +1146,24 @@ class Kernel {
|
|
|
1118
1146
|
// }, 3000)
|
|
1119
1147
|
|
|
1120
1148
|
// refresh every 5 second
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
this.refresh_interval = setInterval(() => {
|
|
1149
|
+
const scheduleRefresh = () => {
|
|
1150
|
+
if (this.refresh_interval) {
|
|
1151
|
+
clearTimeout(this.refresh_interval)
|
|
1152
|
+
}
|
|
1153
|
+
this.refresh_interval = setTimeout(async () => {
|
|
1127
1154
|
if (this.server_running) {
|
|
1128
|
-
|
|
1155
|
+
try {
|
|
1156
|
+
await this.refresh(true)
|
|
1157
|
+
} catch (err) {
|
|
1158
|
+
console.warn('[Kernel.refresh] background refresh failed:', err && err.message ? err.message : err)
|
|
1159
|
+
}
|
|
1129
1160
|
} else {
|
|
1130
1161
|
console.log("server not running yet. retry network refresh in 5 secs")
|
|
1131
1162
|
}
|
|
1163
|
+
scheduleRefresh()
|
|
1132
1164
|
}, 5000)
|
|
1133
|
-
|
|
1165
|
+
}
|
|
1166
|
+
scheduleRefresh()
|
|
1134
1167
|
|
|
1135
1168
|
}
|
|
1136
1169
|
|
|
@@ -1148,13 +1181,15 @@ class Kernel {
|
|
|
1148
1181
|
async update_sysinfo() {
|
|
1149
1182
|
try {
|
|
1150
1183
|
if (this.sys) {
|
|
1151
|
-
await this.sys.refresh()
|
|
1184
|
+
// await this.sys.refresh()
|
|
1152
1185
|
let info = this.sys.info
|
|
1153
1186
|
this.template.update(info)
|
|
1154
1187
|
this.sysinfo = info
|
|
1155
1188
|
this.gpu = info.gpu
|
|
1156
1189
|
this.gpu_model = info.gpu_model
|
|
1157
1190
|
this.gpus = info.gpus
|
|
1191
|
+
this.vram = typeof info.vram === "number" ? info.vram : 0
|
|
1192
|
+
this.ram = typeof info.ram === "number" ? info.ram : 0
|
|
1158
1193
|
}
|
|
1159
1194
|
} catch (e) {
|
|
1160
1195
|
console.log("sysinfo error", e)
|
package/kernel/peer.js
CHANGED
|
@@ -74,7 +74,7 @@ class PeerDiscovery {
|
|
|
74
74
|
return fallback
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
const peer_active = resolveFlag('PINOKIO_NETWORK_ACTIVE',
|
|
77
|
+
const peer_active = resolveFlag('PINOKIO_NETWORK_ACTIVE', false)
|
|
78
78
|
const https_active = resolveFlag('PINOKIO_HTTPS_ACTIVE', false)
|
|
79
79
|
// console.log("kernel.refresh", { active, notify_peers })
|
|
80
80
|
|
|
@@ -101,7 +101,6 @@ class PeerDiscovery {
|
|
|
101
101
|
async start(kernel) {
|
|
102
102
|
await this.check(kernel)
|
|
103
103
|
|
|
104
|
-
//if (this.active) {
|
|
105
104
|
if (this.peer_active) {
|
|
106
105
|
// Listen for incoming pings
|
|
107
106
|
this.socket = dgram.createSocket('udp4');
|
package/kernel/plugin.js
CHANGED
|
@@ -64,14 +64,6 @@ class Plugin {
|
|
|
64
64
|
return
|
|
65
65
|
}
|
|
66
66
|
} else {
|
|
67
|
-
if (this.kernel.bin.installed && this.kernel.bin.installed.conda && this.kernel.bin.installed.conda.has("git")) {
|
|
68
|
-
await this.kernel.exec({
|
|
69
|
-
message: "git pull",
|
|
70
|
-
path: this.kernel.path("plugin/code")
|
|
71
|
-
}, (e) => {
|
|
72
|
-
process.stdout.write(e.raw)
|
|
73
|
-
})
|
|
74
|
-
}
|
|
75
67
|
await this.setConfig()
|
|
76
68
|
}
|
|
77
69
|
}
|
package/kernel/procs.js
CHANGED
|
@@ -163,12 +163,29 @@ class Procs {
|
|
|
163
163
|
}
|
|
164
164
|
getPortPidList(cb) {
|
|
165
165
|
const cmd = isWin ? 'netstat -ano -p tcp' : 'lsof -nP -iTCP -sTCP:LISTEN';
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
166
|
+
try {
|
|
167
|
+
exec(cmd, { maxBuffer: 10 * 1024 * 1024 }, async (err, stdout) => {
|
|
168
|
+
if (err) {
|
|
169
|
+
console.warn('[Procs] getPortPidList failed:', err && err.message ? err.message : err)
|
|
170
|
+
cb([])
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
try {
|
|
174
|
+
this.get_pids(stdout || '').then((pids) => {
|
|
175
|
+
cb(pids)
|
|
176
|
+
}).catch((e) => {
|
|
177
|
+
console.warn('[Procs] get_pids failed:', e && e.message ? e.message : e)
|
|
178
|
+
cb([])
|
|
179
|
+
})
|
|
180
|
+
} catch (e) {
|
|
181
|
+
console.warn('[Procs] get_pids threw:', e && e.message ? e.message : e)
|
|
182
|
+
cb([])
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
} catch (e) {
|
|
186
|
+
console.warn('[Procs] spawn getPortPidList failed:', e && e.message ? e.message : e)
|
|
187
|
+
cb([])
|
|
188
|
+
}
|
|
172
189
|
}
|
|
173
190
|
get_name(stdout) {
|
|
174
191
|
const lines = stdout.trim().split('\n');
|
|
@@ -206,42 +223,81 @@ class Procs {
|
|
|
206
223
|
return
|
|
207
224
|
}
|
|
208
225
|
const cmd = isWin ? 'tasklist /fo csv /nh' : 'ps -Ao pid,comm';
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
226
|
+
try {
|
|
227
|
+
exec(cmd, { maxBuffer: 10 * 1024 * 1024 }, async (err, stdout) => {
|
|
228
|
+
if (err) {
|
|
229
|
+
console.warn('[Procs] getPidToNameMap failed:', err && err.message ? err.message : err)
|
|
230
|
+
cb(this.port_map || {})
|
|
231
|
+
return
|
|
232
|
+
}
|
|
233
|
+
let map
|
|
234
|
+
try {
|
|
235
|
+
map = this.get_name(stdout || '')
|
|
236
|
+
} catch (e) {
|
|
237
|
+
console.warn('[Procs] get_name threw:', e && e.message ? e.message : e)
|
|
238
|
+
cb(this.port_map || {})
|
|
239
|
+
return
|
|
240
|
+
}
|
|
241
|
+
if (!this.port_map) {
|
|
242
|
+
this.port_map = {}
|
|
243
|
+
}
|
|
244
|
+
for(let key in map) {
|
|
245
|
+
this.port_map[key] = map[key]
|
|
246
|
+
}
|
|
247
|
+
cb(this.port_map)
|
|
248
|
+
});
|
|
249
|
+
} catch (e) {
|
|
250
|
+
console.warn('[Procs] spawn getPidToNameMap failed:', e && e.message ? e.message : e)
|
|
251
|
+
cb(this.port_map || {})
|
|
252
|
+
}
|
|
219
253
|
}
|
|
220
254
|
async refresh() {
|
|
255
|
+
if (this.kernel && typeof this.kernel.binCheckDepth === 'number' && this.kernel.binCheckDepth > 0) {
|
|
256
|
+
return
|
|
257
|
+
}
|
|
221
258
|
let map = {}
|
|
222
259
|
this.refreshing = true
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
if (["caddy", "caddy.exe"].includes(name)) {
|
|
231
|
-
this.caddy_pid = pid
|
|
232
|
-
return null
|
|
233
|
-
} else {
|
|
234
|
-
map["" + pid] = fullname
|
|
235
|
-
return { port, pid , name, fullname, ip }
|
|
260
|
+
try {
|
|
261
|
+
let list = await new Promise((resolve, reject) => {
|
|
262
|
+
try {
|
|
263
|
+
this.getPortPidList((portPidList) => {
|
|
264
|
+
if (!Array.isArray(portPidList) || portPidList.length === 0) {
|
|
265
|
+
resolve([])
|
|
266
|
+
return
|
|
236
267
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
268
|
+
this.getPidToNameMap(portPidList, (pidToName) => {
|
|
269
|
+
try {
|
|
270
|
+
let list = portPidList.map(({ port, pid, ip }) => {
|
|
271
|
+
const fullname = pidToName[pid] || 'Unknown';
|
|
272
|
+
const name = fullname.split(path.sep).pop()
|
|
273
|
+
if (["caddy", "caddy.exe"].includes(name)) {
|
|
274
|
+
this.caddy_pid = pid
|
|
275
|
+
return null
|
|
276
|
+
} else {
|
|
277
|
+
map["" + pid] = fullname
|
|
278
|
+
return { port, pid , name, fullname, ip }
|
|
279
|
+
}
|
|
280
|
+
}).filter((x) => { return x })
|
|
281
|
+
resolve(list)
|
|
282
|
+
} catch (e) {
|
|
283
|
+
console.warn('[Procs] refresh mapping failed:', e && e.message ? e.message : e)
|
|
284
|
+
resolve([])
|
|
285
|
+
}
|
|
286
|
+
})
|
|
287
|
+
})
|
|
288
|
+
} catch (e) {
|
|
289
|
+
reject(e)
|
|
290
|
+
}
|
|
240
291
|
})
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
292
|
+
this.info = list
|
|
293
|
+
this.map = map
|
|
294
|
+
} catch (e) {
|
|
295
|
+
console.warn('[Procs] refresh failed:', e && e.message ? e.message : e)
|
|
296
|
+
this.info = []
|
|
297
|
+
this.map = {}
|
|
298
|
+
} finally {
|
|
299
|
+
this.refreshing = false
|
|
300
|
+
}
|
|
245
301
|
}
|
|
246
302
|
}
|
|
247
303
|
module.exports = Procs
|
package/kernel/prototype.js
CHANGED
|
@@ -14,14 +14,7 @@ class Proto {
|
|
|
14
14
|
|
|
15
15
|
// if ~/pinokio/prototype doesn't exist, clone
|
|
16
16
|
let exists = await this.kernel.exists("prototype/system")
|
|
17
|
-
if (exists) {
|
|
18
|
-
await this.kernel.exec({
|
|
19
|
-
message: "git pull",
|
|
20
|
-
path: this.kernel.path("prototype/system")
|
|
21
|
-
}, (e) => {
|
|
22
|
-
process.stdout.write(e.raw)
|
|
23
|
-
})
|
|
24
|
-
} else {
|
|
17
|
+
if (!exists) {
|
|
25
18
|
console.log("prototype doesn't exist. cloning...")
|
|
26
19
|
await fs.promises.mkdir(this.kernel.path("prototype"), { recursive: true }).catch((e) => { })
|
|
27
20
|
await this.kernel.exec({
|
|
@@ -31,20 +24,26 @@ class Proto {
|
|
|
31
24
|
process.stdout.write(e.raw)
|
|
32
25
|
})
|
|
33
26
|
}
|
|
34
|
-
await this.kernel.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
27
|
+
let pinokio_exists = await this.kernel.exists("prototype/PINOKIO.md")
|
|
28
|
+
if (!pinokio_exists) {
|
|
29
|
+
await this.kernel.download({
|
|
30
|
+
uri: "https://raw.githubusercontent.com/pinokiocomputer/home/refs/heads/main/docs/README.md",
|
|
31
|
+
path: this.kernel.path("prototype"),
|
|
32
|
+
filename: "PINOKIO.md"
|
|
33
|
+
}, (e) => {
|
|
34
|
+
process.stdout.write(e.raw)
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
let pterm_exists = await this.kernel.exists("prototype/PTERM.md")
|
|
38
|
+
if (!pterm_exists) {
|
|
39
|
+
await this.kernel.download({
|
|
40
|
+
uri: "https://raw.githubusercontent.com/pinokiocomputer/pterm/refs/heads/main/README.md",
|
|
41
|
+
path: this.kernel.path("prototype"),
|
|
42
|
+
filename: "PTERM.md"
|
|
43
|
+
}, (e) => {
|
|
44
|
+
process.stdout.write(e.raw)
|
|
45
|
+
})
|
|
46
|
+
}
|
|
48
47
|
}
|
|
49
48
|
}
|
|
50
49
|
async ai() {
|
|
@@ -74,6 +73,7 @@ class Proto {
|
|
|
74
73
|
await fs.promises.rm(this.kernel.path("prototype"), { recursive: true })
|
|
75
74
|
}
|
|
76
75
|
async create(req, ondata) {
|
|
76
|
+
let uploadTmpDir = null;
|
|
77
77
|
try {
|
|
78
78
|
if (req.client) {
|
|
79
79
|
this.kernel.client = req.client
|
|
@@ -88,6 +88,23 @@ class Proto {
|
|
|
88
88
|
payload.cwd = path.resolve(cwd, name)
|
|
89
89
|
payload.input = req.params
|
|
90
90
|
|
|
91
|
+
const uploadToken = req.params && req.params.uploadToken ? String(req.params.uploadToken).trim() : ''
|
|
92
|
+
if (uploadToken) {
|
|
93
|
+
uploadTmpDir = this.kernel.path("tmp", "create", uploadToken)
|
|
94
|
+
const exists = await this.kernel.exists(uploadTmpDir)
|
|
95
|
+
if (!exists) {
|
|
96
|
+
throw new Error("Upload token not found or expired")
|
|
97
|
+
}
|
|
98
|
+
await fs.promises.mkdir(payload.cwd, { recursive: true })
|
|
99
|
+
const entries = await fs.promises.readdir(uploadTmpDir, { withFileTypes: true })
|
|
100
|
+
for (const entry of entries) {
|
|
101
|
+
if (!entry.isFile()) continue
|
|
102
|
+
const src = path.resolve(uploadTmpDir, entry.name)
|
|
103
|
+
const dest = path.resolve(payload.cwd, entry.name)
|
|
104
|
+
await fs.promises.copyFile(src, dest)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
91
108
|
|
|
92
109
|
// 1. move mkdir into each launcher
|
|
93
110
|
// 2. run logic
|
|
@@ -138,6 +155,12 @@ class Proto {
|
|
|
138
155
|
} catch (e) {
|
|
139
156
|
console.log("ERROR", e)
|
|
140
157
|
return { error: e.stack }
|
|
158
|
+
} finally {
|
|
159
|
+
if (uploadTmpDir) {
|
|
160
|
+
try {
|
|
161
|
+
await fs.promises.rm(uploadTmpDir, { recursive: true, force: true })
|
|
162
|
+
} catch (_) {}
|
|
163
|
+
}
|
|
141
164
|
}
|
|
142
165
|
}
|
|
143
166
|
async readme(proto) {
|
package/kernel/shells.js
CHANGED
|
@@ -158,9 +158,29 @@ class Shells {
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
let exec_path = (params.path ? params.path : ".") // use the current path if not specified
|
|
161
|
-
let cwd = (options && options.cwd ? options.cwd : this.kernel.homedir) // if cwd exists, use it. Otherwise the cwd is pinokio home folder (~/pinokio)
|
|
161
|
+
let cwd = (options && options.cwd ? options.cwd : this.kernel.homedir) // if cwd exists, use it. Otherwise the cwd is pinokio home folder (~/pinokio)
|
|
162
162
|
params.path = this.kernel.api.resolvePath(cwd, exec_path)
|
|
163
163
|
|
|
164
|
+
// If this shell runs under ~/pinokio/api/<workspace>, remember the workspace
|
|
165
|
+
// and the current set of known git repo roots so we can detect new repos
|
|
166
|
+
// created by this step and pin them to recorded commits.
|
|
167
|
+
let workspaceName
|
|
168
|
+
let workspaceRoot
|
|
169
|
+
let beforeDirs
|
|
170
|
+
if (params.path && this.kernel && this.kernel.path) {
|
|
171
|
+
const apiRoot = this.kernel.path("api")
|
|
172
|
+
const rel = path.relative(apiRoot, params.path)
|
|
173
|
+
if (rel && !rel.startsWith("..") && !path.isAbsolute(rel)) {
|
|
174
|
+
const segments = rel.split(path.sep).filter(Boolean)
|
|
175
|
+
if (segments.length > 0) {
|
|
176
|
+
workspaceName = segments[0]
|
|
177
|
+
workspaceRoot = this.kernel.path("api", workspaceName)
|
|
178
|
+
beforeDirs = new Set(this.kernel.git.dirs)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const parentMeta = params.$parent || null
|
|
183
|
+
|
|
164
184
|
const plannedShell = params.shell || (this.kernel.platform === 'win32' ? 'cmd.exe' : 'bash')
|
|
165
185
|
await this.ensureBracketedPasteSupport(plannedShell)
|
|
166
186
|
let sh = new Shell(this.kernel)
|
|
@@ -275,6 +295,15 @@ class Shells {
|
|
|
275
295
|
sh.kill()
|
|
276
296
|
}
|
|
277
297
|
})
|
|
298
|
+
// If this shell ran under a workspace, rescan git repos for that workspace.
|
|
299
|
+
// Snapshots are now always user-initiated via the backups UI; here we only
|
|
300
|
+
// pin new repos to specific commits when this run was started from a
|
|
301
|
+
// snapshot restore.
|
|
302
|
+
if (workspaceRoot && beforeDirs) {
|
|
303
|
+
try {
|
|
304
|
+
await this.kernel.git.restoreNewReposForActiveSnapshot(workspaceName, workspaceRoot, beforeDirs)
|
|
305
|
+
} catch (_) {}
|
|
306
|
+
}
|
|
278
307
|
/*
|
|
279
308
|
{
|
|
280
309
|
method: "shell.run",
|
|
@@ -450,11 +479,6 @@ class Shells {
|
|
|
450
479
|
}
|
|
451
480
|
return true
|
|
452
481
|
} else {
|
|
453
|
-
const preview = typeof params.emit === 'string' ? params.emit.slice(0, 64) : ''
|
|
454
|
-
console.warn('[shell.emit] missing session for id', params.id, {
|
|
455
|
-
paste: !!params.paste,
|
|
456
|
-
preview
|
|
457
|
-
})
|
|
458
482
|
return false
|
|
459
483
|
}
|
|
460
484
|
}
|
package/kernel/sysinfo.js
CHANGED
|
@@ -10,7 +10,8 @@ class Sysinfo {
|
|
|
10
10
|
// await this.refresh()
|
|
11
11
|
}
|
|
12
12
|
async static() {
|
|
13
|
-
await Promise.all([this.gpus(), this.system(), this.cpu(), this.os(), this.audio(), this.env()])
|
|
13
|
+
//await Promise.all([this.gpus(), this.system(), this.cpu(), this.os(), this.audio(), this.env()])
|
|
14
|
+
await Promise.all([this.gpus(), this.system(), this.cpu(), this.os(), this.audio(), this.env(), this.memory()])
|
|
14
15
|
// await this.gpus()
|
|
15
16
|
// await this.system()
|
|
16
17
|
// await this.cpu()
|
|
@@ -25,7 +26,8 @@ class Sysinfo {
|
|
|
25
26
|
// await this.time()
|
|
26
27
|
|
|
27
28
|
|
|
28
|
-
await Promise.all([this.memory(), this.battery(), this.proc(), this.bluetooth()])
|
|
29
|
+
//await Promise.all([this.memory(), this.battery(), this.proc(), this.bluetooth()])
|
|
30
|
+
// await Promise.all([this.memory(), this.proc()])
|
|
29
31
|
// await this.memory()
|
|
30
32
|
// await this.battery()
|
|
31
33
|
// await this.proc()
|
|
@@ -37,12 +39,13 @@ class Sysinfo {
|
|
|
37
39
|
}
|
|
38
40
|
async gpus() {
|
|
39
41
|
let g = await system.graphics()
|
|
42
|
+
let controllers = Array.isArray(g && g.controllers) ? g.controllers : []
|
|
40
43
|
let gpus
|
|
41
|
-
if (
|
|
42
|
-
gpus =
|
|
44
|
+
if (controllers.length > 0) {
|
|
45
|
+
gpus = controllers.map((x) => {
|
|
43
46
|
return {
|
|
44
|
-
name: x.vendor.toLowerCase(),
|
|
45
|
-
model: x.model.toLowerCase()
|
|
47
|
+
name: (x.vendor || "").toLowerCase(),
|
|
48
|
+
model: (x.model || "").toLowerCase()
|
|
46
49
|
}
|
|
47
50
|
})
|
|
48
51
|
} else {
|
|
@@ -71,11 +74,25 @@ class Sysinfo {
|
|
|
71
74
|
gpu = "none"
|
|
72
75
|
}
|
|
73
76
|
|
|
77
|
+
let primaryController
|
|
78
|
+
if (is_nvidia) {
|
|
79
|
+
primaryController = controllers.find(x => /nvidia/i.test(x.vendor || ""))
|
|
80
|
+
} else if (is_amd) {
|
|
81
|
+
primaryController = controllers.find(x => /(amd|advanced micro devices)/i.test(x.vendor || ""))
|
|
82
|
+
} else if (is_apple) {
|
|
83
|
+
primaryController = controllers.find(x => /apple/i.test(x.vendor || ""))
|
|
84
|
+
} else if (controllers.length > 0) {
|
|
85
|
+
primaryController = controllers[0]
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let vramMB = primaryController && primaryController.vram ? primaryController.vram : 0
|
|
89
|
+
let vramGB = vramMB > 0 ? Math.round(vramMB / 1024) : 0
|
|
90
|
+
|
|
74
91
|
this.info.graphics = g
|
|
75
92
|
this.info.gpus = gpus
|
|
76
93
|
this.info.gpu = gpu
|
|
77
94
|
this.info.gpu_model = gpu_model
|
|
78
|
-
|
|
95
|
+
this.info.vram = vramGB
|
|
79
96
|
}
|
|
80
97
|
// async time() {
|
|
81
98
|
// this.info.time = await system.time()
|
|
@@ -88,10 +105,13 @@ class Sysinfo {
|
|
|
88
105
|
}
|
|
89
106
|
async memory() {
|
|
90
107
|
this.info.mem = await system.mem()
|
|
108
|
+
let totalBytes = this.info.mem && this.info.mem.total ? this.info.mem.total : 0
|
|
109
|
+
let totalGB = totalBytes > 0 ? Math.round(totalBytes / (1024 * 1024 * 1024)) : 0
|
|
110
|
+
this.info.ram = totalGB
|
|
91
111
|
}
|
|
92
|
-
async battery() {
|
|
93
|
-
this.info.battery = await system.battery()
|
|
94
|
-
}
|
|
112
|
+
// async battery() {
|
|
113
|
+
// this.info.battery = await system.battery()
|
|
114
|
+
// }
|
|
95
115
|
async os() {
|
|
96
116
|
this.info.osInfo = await system.osInfo()
|
|
97
117
|
this.info.shell = await system.shell()
|
|
@@ -113,9 +133,9 @@ class Sysinfo {
|
|
|
113
133
|
this.info.gateway = await system.networkGatewayDefault()
|
|
114
134
|
this.info.interface = await system.networkInterfaces("default")
|
|
115
135
|
}
|
|
116
|
-
async bluetooth() {
|
|
117
|
-
this.info.bluetooth = await system.bluetoothDevices()
|
|
118
|
-
}
|
|
136
|
+
// async bluetooth() {
|
|
137
|
+
// this.info.bluetooth = await system.bluetoothDevices()
|
|
138
|
+
// }
|
|
119
139
|
exists(_path) {
|
|
120
140
|
return new Promise(r=>fs.access(_path, fs.constants.F_OK, e => r(!e)))
|
|
121
141
|
}
|