pinokiod 5.1.5 → 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.
Files changed (54) hide show
  1. package/kernel/api/fs/download_worker.js +158 -0
  2. package/kernel/api/fs/index.js +95 -91
  3. package/kernel/api/index.js +3 -0
  4. package/kernel/bin/index.js +5 -2
  5. package/kernel/environment.js +19 -2
  6. package/kernel/git.js +972 -1
  7. package/kernel/index.js +65 -30
  8. package/kernel/peer.js +1 -2
  9. package/kernel/plugin.js +0 -8
  10. package/kernel/procs.js +92 -36
  11. package/kernel/prototype.js +45 -22
  12. package/kernel/shells.js +30 -6
  13. package/kernel/sysinfo.js +33 -13
  14. package/kernel/util.js +61 -24
  15. package/kernel/workspace_status.js +131 -7
  16. package/package.json +1 -1
  17. package/pipe/index.js +1 -1
  18. package/server/index.js +1173 -348
  19. package/server/public/create-launcher.js +157 -2
  20. package/server/public/install.js +135 -41
  21. package/server/public/style.css +32 -1
  22. package/server/public/tab-link-popover.js +45 -14
  23. package/server/public/terminal-settings.js +51 -35
  24. package/server/public/urldropdown.css +89 -3
  25. package/server/socket.js +12 -7
  26. package/server/views/agents.ejs +4 -3
  27. package/server/views/app.ejs +798 -30
  28. package/server/views/bootstrap.ejs +2 -1
  29. package/server/views/checkpoints.ejs +1014 -0
  30. package/server/views/checkpoints_registry_beta.ejs +260 -0
  31. package/server/views/columns.ejs +4 -4
  32. package/server/views/connect.ejs +1 -0
  33. package/server/views/d.ejs +74 -4
  34. package/server/views/download.ejs +28 -28
  35. package/server/views/editor.ejs +4 -5
  36. package/server/views/env_editor.ejs +1 -1
  37. package/server/views/file_explorer.ejs +1 -1
  38. package/server/views/index.ejs +3 -1
  39. package/server/views/init/index.ejs +2 -1
  40. package/server/views/install.ejs +2 -1
  41. package/server/views/net.ejs +9 -7
  42. package/server/views/network.ejs +15 -14
  43. package/server/views/pro.ejs +5 -2
  44. package/server/views/prototype/index.ejs +2 -1
  45. package/server/views/registry_link.ejs +76 -0
  46. package/server/views/rows.ejs +4 -4
  47. package/server/views/screenshots.ejs +1 -0
  48. package/server/views/settings.ejs +1 -0
  49. package/server/views/shell.ejs +4 -6
  50. package/server/views/terminal.ejs +528 -38
  51. package/server/views/tools.ejs +1 -0
  52. package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/1764297248545 +0 -45
  53. package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/events +0 -4
  54. package/undefined/logs/dev/plugin/cursor-agent.git/pinokio.js/latest +0 -45
package/kernel/util.js CHANGED
@@ -195,8 +195,6 @@ const filepicker = async(req, ondata, kernel) => {
195
195
  return [type, extensions]
196
196
  })
197
197
  }
198
- console.log("Filetype", req.params.filetype)
199
- console.log("Filetypes", req.params.filetypes)
200
198
  let response = await new Promise((resolve, reject) => {
201
199
  let picker_path = kernel.path("bin/py/picker.py")
202
200
  let python
@@ -205,7 +203,6 @@ const filepicker = async(req, ondata, kernel) => {
205
203
  } else {
206
204
  python = kernel.path("bin/miniconda/bin/python")
207
205
  }
208
- console.log("run python", { python, picker_path })
209
206
  const proc = spawn(python, [picker_path])
210
207
 
211
208
  let output = "";
@@ -346,6 +343,10 @@ const parse_env = async (filename) => {
346
343
 
347
344
  return config
348
345
  } catch (e) {
346
+ if (e && e.code === "ENOENT") {
347
+ // Missing env files are expected on first run; treat as empty without warning
348
+ return {}
349
+ }
349
350
  console.warn(`[parse_env] failed to read/parse ${filename}: ${e.message}`)
350
351
  return {}
351
352
  }
@@ -395,16 +396,26 @@ const run = (cmd, cwd, kernel) => {
395
396
  // console.log("Util.run", { cmd, cwd })
396
397
  // child_process.exec(cmd, { cwd })
397
398
  if (kernel) {
398
- kernel.exec({
399
- message: cmd,
400
- path: cwd
401
- }, (e) => {
402
- process.stdout.write(e.raw)
403
- }).then(() => {
404
- console.log("DONE")
405
- })
399
+ try {
400
+ kernel.exec({
401
+ message: cmd,
402
+ path: cwd
403
+ }, (e) => {
404
+ process.stdout.write(e.raw)
405
+ }).then(() => {
406
+ console.log("DONE")
407
+ }).catch((err) => {
408
+ console.warn('[Util.run] kernel.exec failed:', err && err.message ? err.message : err)
409
+ })
410
+ } catch (err) {
411
+ console.warn('[Util.run] spawn failed:', err && err.message ? err.message : err)
412
+ }
406
413
  } else {
407
- child_process.exec(command)
414
+ try {
415
+ child_process.exec(cmd)
416
+ } catch (err) {
417
+ console.warn('[Util.run] exec failed:', err && err.message ? err.message : err)
418
+ }
408
419
  }
409
420
  }
410
421
  const openURL = (url) => {
@@ -417,7 +428,11 @@ const openURL = (url) => {
417
428
  } else {
418
429
  command = `xdg-open "${url}"`; // Linux
419
430
  }
420
- child_process.exec(command);
431
+ try {
432
+ child_process.exec(command);
433
+ } catch (err) {
434
+ console.warn('[Util.openURL] exec failed:', err && err.message ? err.message : err)
435
+ }
421
436
  }
422
437
  const openfs = (dirPath, options, kernel) => {
423
438
  let command = '';
@@ -443,7 +458,11 @@ const openfs = (dirPath, options, kernel) => {
443
458
  command = `xdg-open "${dirPath}"`;
444
459
  break;
445
460
  }
446
- child_process.exec(command)
461
+ try {
462
+ child_process.exec(command)
463
+ } catch (err) {
464
+ console.warn('[Util.openfs] exec(view) failed:', err && err.message ? err.message : err)
465
+ }
447
466
  } else if (mode === "open") {
448
467
  switch (platform) {
449
468
  case 'darwin':
@@ -456,20 +475,34 @@ const openfs = (dirPath, options, kernel) => {
456
475
  command = `xdg-open "${dirPath}"`;
457
476
  break;
458
477
  }
459
- child_process.exec(command)
478
+ try {
479
+ child_process.exec(command)
480
+ } catch (err) {
481
+ console.warn('[Util.openfs] exec(open) failed:', err && err.message ? err.message : err)
482
+ }
460
483
  } else {
461
484
  command = `${mode} "${dirPath}"`
462
485
  console.log("> command", command)
463
486
  if (kernel) {
464
- kernel.exec({
465
- message: command,
466
- }, (e) => {
467
- process.stdout.write(e.raw)
468
- }).then(() => {
469
- console.log("DONE")
470
- })
487
+ try {
488
+ kernel.exec({
489
+ message: command,
490
+ }, (e) => {
491
+ process.stdout.write(e.raw)
492
+ }).then(() => {
493
+ console.log("DONE")
494
+ }).catch((err) => {
495
+ console.warn('[Util.openfs] kernel.exec(custom) failed:', err && err.message ? err.message : err)
496
+ })
497
+ } catch (err) {
498
+ console.warn('[Util.openfs] spawn(custom) failed:', err && err.message ? err.message : err)
499
+ }
471
500
  } else {
472
- child_process.exec(command)
501
+ try {
502
+ child_process.exec(command)
503
+ } catch (err) {
504
+ console.warn('[Util.openfs] exec(custom) failed:', err && err.message ? err.message : err)
505
+ }
473
506
  }
474
507
  }
475
508
  } else {
@@ -502,7 +535,11 @@ const openfs = (dirPath, options, kernel) => {
502
535
  break;
503
536
  }
504
537
  }
505
- child_process.exec(command)
538
+ try {
539
+ child_process.exec(command)
540
+ } catch (err) {
541
+ console.warn('[Util.openfs] exec(default) failed:', err && err.message ? err.message : err)
542
+ }
506
543
  }
507
544
  }
508
545
  const parse_env_detail = async (filename) => {
@@ -1,4 +1,7 @@
1
1
  const ParcelWatcher = require('@parcel/watcher')
2
+ const fs = require('fs')
3
+ const path = require('path')
4
+ const ignore = require('ignore')
2
5
 
3
6
  class WorkspaceStatusManager {
4
7
  constructor(options = {}) {
@@ -6,6 +9,8 @@ class WorkspaceStatusManager {
6
9
  this.fallbackIntervalMs = typeof options.fallbackIntervalMs === 'number' ? options.fallbackIntervalMs : 60000
7
10
  this.cache = new Map()
8
11
  this.watchers = new Map()
12
+ this.onEvent = typeof options.onEvent === 'function' ? options.onEvent : null
13
+ this.gitIgnoreEngines = new Map()
9
14
  this.defaultIgnores = options.ignores && Array.isArray(options.ignores) ? options.ignores : [
10
15
  '**/.git/**',
11
16
  '**/node_modules/**',
@@ -26,6 +31,76 @@ class WorkspaceStatusManager {
26
31
  ]
27
32
  }
28
33
 
34
+ async ensureGitIgnoreEngine(workspaceName, workspaceRoot) {
35
+ if (!workspaceRoot) {
36
+ return
37
+ }
38
+ if (this.gitIgnoreEngines.has(workspaceName)) {
39
+ return
40
+ }
41
+ const ig = ignore()
42
+ const gitignoreFiles = []
43
+
44
+ const walk = async (dir) => {
45
+ let entries
46
+ try {
47
+ entries = await fs.promises.readdir(dir, { withFileTypes: true })
48
+ } catch (error) {
49
+ return
50
+ }
51
+ for (const entry of entries) {
52
+ if (entry.isDirectory()) {
53
+ if (entry.name === '.git' || entry.name === 'node_modules' || entry.name === 'venv' || entry.name === '.venv') {
54
+ continue
55
+ }
56
+ await walk(path.join(dir, entry.name))
57
+ } else if (entry.isFile() && entry.name === '.gitignore') {
58
+ gitignoreFiles.push(path.join(dir, entry.name))
59
+ }
60
+ }
61
+ }
62
+
63
+ try {
64
+ await walk(workspaceRoot)
65
+ } catch (error) {
66
+ console.warn('workspace gitignore scan failed', workspaceName, error && error.message ? error.message : error)
67
+ }
68
+
69
+ for (const gitignorePath of gitignoreFiles) {
70
+ let content
71
+ try {
72
+ content = await fs.promises.readFile(gitignorePath, 'utf8')
73
+ } catch (_) {
74
+ continue
75
+ }
76
+ const relDir = path.relative(workspaceRoot, path.dirname(gitignorePath))
77
+ const prefix = relDir && relDir !== '.' ? relDir.split(path.sep).join('/') + '/' : ''
78
+ const lines = content.split(/\r?\n/)
79
+ for (let line of lines) {
80
+ if (!line) continue
81
+ line = line.trim()
82
+ if (!line || line.startsWith('#')) continue
83
+ let negated = false
84
+ if (line.startsWith('!')) {
85
+ negated = true
86
+ line = line.slice(1)
87
+ }
88
+ if (!line) continue
89
+ line = line.replace(/^\/+/, '')
90
+ if (!line) continue
91
+ const pattern = prefix + line
92
+ if (!pattern) continue
93
+ if (negated) {
94
+ ig.add('!' + pattern)
95
+ } else {
96
+ ig.add(pattern)
97
+ }
98
+ }
99
+ }
100
+
101
+ this.gitIgnoreEngines.set(workspaceName, ig)
102
+ }
103
+
29
104
  markDirty(workspaceName) {
30
105
  let entry = this.cache.get(workspaceName)
31
106
  if (!entry) {
@@ -44,6 +119,7 @@ class WorkspaceStatusManager {
44
119
  return
45
120
  }
46
121
  try {
122
+ await this.ensureGitIgnoreEngine(workspaceName, workspaceRoot)
47
123
  const subscription = await ParcelWatcher.subscribe(
48
124
  workspaceRoot,
49
125
  (error, events) => {
@@ -51,9 +127,35 @@ class WorkspaceStatusManager {
51
127
  console.warn('workspace watcher error', workspaceName, error)
52
128
  return
53
129
  }
54
- if (events && events.length > 0) {
55
- console.log("Events", events)
56
- this.markDirty(workspaceName)
130
+ if (!events || events.length === 0) {
131
+ return
132
+ }
133
+ let relevantEvents = events
134
+ const engine = this.gitIgnoreEngines.get(workspaceName)
135
+ if (engine && workspaceRoot) {
136
+ const root = workspaceRoot
137
+ relevantEvents = events.filter((evt) => {
138
+ if (!evt || !evt.path) {
139
+ return true
140
+ }
141
+ let rel = path.relative(root, evt.path)
142
+ if (!rel || rel.startsWith('..') || path.isAbsolute(rel)) {
143
+ return true
144
+ }
145
+ const normalized = rel.split(path.sep).join('/')
146
+ return !engine.ignores(normalized)
147
+ })
148
+ }
149
+ if (relevantEvents.length === 0) {
150
+ return
151
+ }
152
+ this.markDirty(workspaceName)
153
+ if (this.onEvent) {
154
+ try {
155
+ this.onEvent(workspaceName, relevantEvents)
156
+ } catch (err) {
157
+ console.warn('workspace watcher callback error', workspaceName, err && err.message ? err.message : err)
158
+ }
57
159
  }
58
160
  },
59
161
  { ignore: this.defaultIgnores }
@@ -81,15 +183,37 @@ class WorkspaceStatusManager {
81
183
  entry.dirty = true
82
184
  }
83
185
 
186
+ if (this.enableWatchers && workspaceRoot) {
187
+ await this.ensureWatcher(workspaceName, workspaceRoot)
188
+ }
189
+
84
190
  if (!entry.dirty && entry.data) {
85
191
  return entry.data
86
192
  }
87
- if (entry.inflight) {
88
- return entry.inflight
193
+
194
+ if (entry.dirty && entry.data) {
195
+ if (!entry.inflight) {
196
+ entry.inflight = (async () => {
197
+ try {
198
+ const data = await computeStatusFn()
199
+ entry.data = data
200
+ entry.dirty = false
201
+ entry.updatedAt = Date.now()
202
+ } catch (error) {
203
+ console.warn('workspace status background compute failed', workspaceName, error && error.message ? error.message : error)
204
+ } finally {
205
+ entry.inflight = null
206
+ }
207
+ })()
208
+ }
209
+ return entry.data
89
210
  }
90
211
 
91
- if (this.enableWatchers && workspaceRoot) {
92
- await this.ensureWatcher(workspaceName, workspaceRoot)
212
+ if (entry.inflight) {
213
+ if (entry.data) {
214
+ return entry.data
215
+ }
216
+ return entry.inflight
93
217
  }
94
218
 
95
219
  entry.inflight = (async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "5.1.5",
3
+ "version": "5.1.11",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/pipe/index.js CHANGED
@@ -77,7 +77,7 @@ class Pipe {
77
77
  }
78
78
  })
79
79
  req.session.authenticated = true;
80
- res.redirect('/');
80
+ res.redirect('/home');
81
81
  } else {
82
82
  res.status(401).render("login", { error: "Invalid passcode", ...config })
83
83
  }