pinokiod 7.2.18 → 7.3.1

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 (89) hide show
  1. package/Dockerfile +2 -0
  2. package/kernel/api/index.js +13 -179
  3. package/kernel/api/process/index.js +44 -99
  4. package/kernel/bin/conda-pins.js +53 -0
  5. package/kernel/bin/conda.js +35 -6
  6. package/kernel/bin/huggingface.js +1 -1
  7. package/kernel/bin/index.js +15 -2
  8. package/kernel/environment.js +11 -205
  9. package/kernel/git.js +13 -0
  10. package/kernel/index.js +1 -64
  11. package/kernel/plugin.js +58 -6
  12. package/kernel/prototype.js +0 -4
  13. package/kernel/shell.js +2 -23
  14. package/kernel/util.js +0 -60
  15. package/package.json +1 -1
  16. package/server/index.js +171 -229
  17. package/server/lib/content_validation.js +33 -47
  18. package/server/public/common.js +29 -103
  19. package/server/public/create-launcher.js +31 -4
  20. package/server/public/electron.css +6 -0
  21. package/server/public/style.css +0 -337
  22. package/server/public/task-launcher.css +3 -11
  23. package/server/public/task-launcher.js +32 -5
  24. package/server/public/universal-launcher.js +26 -3
  25. package/server/socket.js +11 -22
  26. package/server/views/app.ejs +30 -167
  27. package/server/views/d.ejs +35 -33
  28. package/server/views/editor.ejs +4 -25
  29. package/server/views/partials/main_sidebar.ejs +0 -1
  30. package/server/views/partials/menu.ejs +1 -1
  31. package/server/views/pre.ejs +1 -1
  32. package/server/views/shell.ejs +3 -11
  33. package/server/views/task_launch.ejs +10 -10
  34. package/server/views/terminal.ejs +5 -34
  35. package/spec/INSTRUCTION_SYNC.md +5 -5
  36. package/kernel/agent_instructions.js +0 -166
  37. package/kernel/api/shell_run_template.js +0 -273
  38. package/kernel/api/uri/index.js +0 -51
  39. package/kernel/plugin_sources.js +0 -289
  40. package/kernel/watch/context.js +0 -42
  41. package/kernel/watch/drivers/fs.js +0 -71
  42. package/kernel/watch/drivers/poll.js +0 -33
  43. package/kernel/watch/index.js +0 -185
  44. package/server/features/index.js +0 -13
  45. package/server/features/notes/index.js +0 -41
  46. package/server/features/notes/parser.js +0 -174
  47. package/server/features/notes/public/notes.css +0 -955
  48. package/server/features/notes/public/notes.js +0 -1149
  49. package/server/features/notes/registry_import.js +0 -412
  50. package/server/features/notes/routes.js +0 -156
  51. package/server/features/notes/service.js +0 -326
  52. package/server/features/notes/watcher.js +0 -74
  53. package/server/lib/workspace_catalog.js +0 -151
  54. package/server/lib/workspace_runtime.js +0 -390
  55. package/server/public/tasker.css +0 -336
  56. package/server/public/tasker.js +0 -407
  57. package/server/routes/workspaces.js +0 -44
  58. package/server/views/partials/workspace_row.ejs +0 -61
  59. package/server/views/tasker.ejs +0 -40
  60. package/server/views/workspaces.ejs +0 -813
  61. package/system/plugin/antigravity/antigravity.png +0 -0
  62. package/system/plugin/antigravity/pinokio.js +0 -35
  63. package/system/plugin/claude/claude.png +0 -0
  64. package/system/plugin/claude/pinokio.js +0 -61
  65. package/system/plugin/claude-auto/claude.png +0 -0
  66. package/system/plugin/claude-auto/pinokio.js +0 -72
  67. package/system/plugin/claude-desktop/icon.jpeg +0 -0
  68. package/system/plugin/claude-desktop/pinokio.js +0 -37
  69. package/system/plugin/codex/openai.webp +0 -0
  70. package/system/plugin/codex/pinokio.js +0 -56
  71. package/system/plugin/codex-auto/openai.webp +0 -0
  72. package/system/plugin/codex-auto/pinokio.js +0 -63
  73. package/system/plugin/codex-desktop/icon.png +0 -0
  74. package/system/plugin/codex-desktop/pinokio.js +0 -37
  75. package/system/plugin/crush/crush.png +0 -0
  76. package/system/plugin/crush/pinokio.js +0 -29
  77. package/system/plugin/cursor/cursor.jpeg +0 -0
  78. package/system/plugin/cursor/pinokio.js +0 -37
  79. package/system/plugin/gemini/gemini.jpeg +0 -0
  80. package/system/plugin/gemini/pinokio.js +0 -38
  81. package/system/plugin/gemini-auto/gemini.jpeg +0 -0
  82. package/system/plugin/gemini-auto/pinokio.js +0 -41
  83. package/system/plugin/qwen/pinokio.js +0 -48
  84. package/system/plugin/qwen/qwen.png +0 -0
  85. package/system/plugin/vscode/pinokio.js +0 -34
  86. package/system/plugin/vscode/vscode.png +0 -0
  87. package/system/plugin/windsurf/pinokio.js +0 -37
  88. package/system/plugin/windsurf/windsurf.png +0 -0
  89. package/test/plugin-sources.test.js +0 -45
package/Dockerfile CHANGED
@@ -37,6 +37,8 @@ RUN mkdir -p /app/.pinokio-seed \
37
37
  && rm -rf /app/.pinokio-seed/network/system/.git \
38
38
  && rm -rf /app/.pinokio-seed/plugin \
39
39
  && mkdir -p /app/.pinokio-seed/plugin \
40
+ && git clone --depth 1 https://github.com/pinokiocomputer/code /app/.pinokio-seed/plugin/code \
41
+ && rm -rf /app/.pinokio-seed/plugin/code/.git \
40
42
  && rm -rf /app/.pinokio-seed/prototype/system \
41
43
  && mkdir -p /app/.pinokio-seed/prototype \
42
44
  && git clone --depth 1 https://github.com/pinokiocomputer/proto /app/.pinokio-seed/prototype/system \
@@ -11,8 +11,6 @@ const fastq = require('fastq')
11
11
  const Loader = require("../loader")
12
12
  const Environment = require("../environment")
13
13
  const Util = require('../util')
14
- const ShellRunTemplate = require('./shell_run_template')
15
- const AgentInstructions = require("../agent_instructions")
16
14
 
17
15
  class Api {
18
16
  constructor(kernel) {
@@ -28,22 +26,8 @@ class Api {
28
26
  this.proxies = {}
29
27
  this.mods = {}
30
28
  this.child_procs = {}
31
- this.resolved_actions = {}
32
29
  this.lproxy = new Lproxy()
33
30
  }
34
- startData(rpc) {
35
- if (rpc && rpc.method === "process.wait" && rpc.params && typeof rpc.params === "object" && !Array.isArray(rpc.params)) {
36
- let data = rpc
37
- if (typeof data.title === "undefined" && typeof rpc.params.title !== "undefined") {
38
- data = { ...data, title: rpc.params.title }
39
- }
40
- if (typeof data.description === "undefined" && typeof rpc.params.description !== "undefined") {
41
- data = { ...data, description: rpc.params.description }
42
- }
43
- return data
44
- }
45
- return rpc
46
- }
47
31
  async launcher_path(name) {
48
32
  let root_path = this.kernel.path("api", name)
49
33
  let primary_path = path.resolve(root_path, "pinokio.js")
@@ -235,7 +219,7 @@ class Api {
235
219
  meta.ui = `/p/${api_name}`
236
220
  meta.browse = `/p/${api_name}/dev`
237
221
  } else {
238
- meta.icon = meta.icon ? `/asset/api/${api_name}/${relpath}/${meta.icon}` : "/pinokio-black.png"
222
+ meta.icon = meta.icon ? `/asset/api/${api_name}/${meta.icon}` : "/pinokio-black.png"
239
223
  meta.link = `/p/${api_name}/${relpath}/dev#n1`
240
224
  meta.web_path = `/api/${api_name}/${relpath}`
241
225
  meta.ui = `/p/${api_name}/${relpath}`
@@ -414,84 +398,6 @@ class Api {
414
398
  let result = await endpoint(rpc, ondata, this.kernel)
415
399
  return result
416
400
  }
417
- requestId(request) {
418
- return request ? (request.id || request.path) : null
419
- }
420
- clearResolvedAction(requestOrId) {
421
- const id = typeof requestOrId === "string" ? requestOrId : this.requestId(requestOrId)
422
- if (id) {
423
- delete this.resolved_actions[id]
424
- }
425
- }
426
- setRunning(request, done) {
427
- const id = this.requestId(request)
428
- if (!id) {
429
- return
430
- }
431
- this.running[id] = true
432
- this.done[id] = done
433
- }
434
- isActionCandidate(action) {
435
- return (Array.isArray(action) && action.length > 0) || typeof action === "function"
436
- }
437
- async actionContext({ request, script, scriptDir, actionKey, input, args }) {
438
- const cwd = request.cwd || scriptDir
439
- const id = this.requestId(request)
440
- const env = await Environment.get2(request.path, this.kernel)
441
- this.kernel.template.update({ envs: env, env })
442
- const port = await this.kernel.port()
443
- const name = path.relative(this.kernel.path("api"), scriptDir)
444
- return {
445
- kernel: this.kernel,
446
- info: this.kernel.info,
447
- script: this.kernel.script,
448
- action: actionKey,
449
- input,
450
- args,
451
- global: (this.kernel.memory.global[id] || {}),
452
- local: (this.kernel.memory.local[id] || {}),
453
- key: this.kernel.memory.key,
454
- uri: request.uri,
455
- cwd,
456
- dirname: scriptDir,
457
- exists: (...args) => {
458
- return fs.existsSync(path.resolve(cwd, ...args))
459
- },
460
- running: (...args) => {
461
- let fullpath = path.resolve(cwd, ...args)
462
- return this.running[fullpath]
463
- },
464
- name,
465
- self: script,
466
- port,
467
- env,
468
- envs: env,
469
- ...this.kernel.vars,
470
- }
471
- }
472
- async resolveActionSteps({ request, script, scriptDir, actionKey, input, args }) {
473
- const id = this.requestId(request)
474
- const cached = id ? this.resolved_actions[id] : null
475
- if (cached && cached.actionKey === actionKey && Array.isArray(cached.steps)) {
476
- return cached.steps
477
- }
478
-
479
- const action = script ? script[actionKey] : null
480
- let steps
481
- if (Array.isArray(action)) {
482
- steps = action
483
- } else if (typeof action === "function") {
484
- const context = await this.actionContext({ request, script, scriptDir, actionKey, input, args })
485
- steps = await action.call(script, this.kernel, this.kernel.info, context)
486
- } else {
487
- steps = null
488
- }
489
-
490
- if (id && Array.isArray(steps)) {
491
- this.resolved_actions[id] = { actionKey, steps }
492
- }
493
- return steps
494
- }
495
401
  async stop(req, ondata) {
496
402
  // 1. set the "stop" flag for the uri, so the next execution in the queue for the uri will NOT queue another task
497
403
  // 2. stream a message closing the socket
@@ -500,24 +406,16 @@ class Api {
500
406
  // /Users/x/pinokio/prototype/system/aicode/template/claude.json?cwd=/Users/x/pinokio/api/MMAudio.git
501
407
  // take the first part only since the rest is the cwd
502
408
  req.params.uri = req.params.id.split("?")[0]
503
- this.clearResolvedAction(req.params.id)
504
409
  }
505
410
 
506
411
  // 1. if the scropt has 'on.stop', run it when stopping
507
412
  let requestPath = this.filePath(req.params.uri)
508
- this.clearResolvedAction(requestPath)
509
413
  let { cwd, script } = await this.resolveScript(requestPath)
510
414
  if (script.on) {
511
415
  if (script.on.stop) {
512
416
  await this.process(script.on.stop)
513
417
  }
514
418
  }
515
- if (this.kernel.watch && typeof this.kernel.watch.stop === "function") {
516
- if (req.params.id) {
517
- await this.kernel.watch.stop(req.params.id)
518
- }
519
- await this.kernel.watch.stop(requestPath)
520
- }
521
419
  // reset modules
522
420
  let modpath = this.resolvePath(cwd, req.params.uri)
523
421
  if (this.child_procs[modpath]) {
@@ -992,7 +890,7 @@ class Api {
992
890
 
993
891
  let { cwd: scriptDir, script } = await this.resolveScript(request.path)
994
892
  const actionKey = request.action || 'run'
995
- const steps = await this.resolveActionSteps({ request, script, scriptDir, actionKey, input, args }) || []
893
+ const steps = (script && Array.isArray(script[actionKey])) ? script[actionKey] : []
996
894
  const totalSteps = steps.length
997
895
 
998
896
  let name = path.relative(this.kernel.path("api"), scriptDir)
@@ -1112,7 +1010,6 @@ class Api {
1112
1010
  }
1113
1011
  // replace {{{ }}} with {{ }}
1114
1012
  rpc = this.kernel.template.flatten(rpc)
1115
- rpc = ShellRunTemplate.renderEnvArgs(this.kernel, rpc, memory)
1116
1013
 
1117
1014
  // 6. rpc must have method names
1118
1015
  if (rpc.method) {
@@ -1281,7 +1178,7 @@ class Api {
1281
1178
  this.ondata({
1282
1179
  id: request.id || request.path,
1283
1180
  type: "start",
1284
- data: this.startData(rpc)
1181
+ data: rpc
1285
1182
  })
1286
1183
 
1287
1184
  // DEPRECATED APIS
@@ -1557,41 +1454,6 @@ class Api {
1557
1454
  }
1558
1455
  return false
1559
1456
  }
1560
- async startWatchersForRequest(request, script, scriptDir, input) {
1561
- if (!this.kernel.watch || typeof this.kernel.watch.startForScript !== "function") {
1562
- return
1563
- }
1564
- const id = request.id || request.path
1565
- if (!id) {
1566
- return
1567
- }
1568
- const cwd = request.cwd || scriptDir
1569
- await this.kernel.watch.startForScript({
1570
- id,
1571
- request,
1572
- script,
1573
- cwd,
1574
- dirname: scriptDir,
1575
- input,
1576
- args: input
1577
- })
1578
- }
1579
- async ensurePluginAgentInstructions(request) {
1580
- if (!request || !request.cwd || !request.path) {
1581
- return
1582
- }
1583
- if (!AgentInstructions.isPluginScriptPath(this.kernel, request.path)) {
1584
- return
1585
- }
1586
- try {
1587
- await AgentInstructions.ensureNoteInstructionsForCwd({
1588
- kernel: this.kernel,
1589
- cwd: request.cwd,
1590
- })
1591
- } catch (e) {
1592
- console.warn("[agent-instructions] failed to update note instructions:", e && e.message ? e.message : e)
1593
- }
1594
- }
1595
1457
  createQueue(queue_id, concurrency) {
1596
1458
  this.queues[queue_id] = fastq.promise(async ({ request, rawrpc, input, step, total, cwd, args }) => {
1597
1459
  try {
@@ -1809,12 +1671,18 @@ class Api {
1809
1671
  } else {
1810
1672
  const actionKey = request.action || 'run'
1811
1673
  request.action = actionKey
1812
- const action = script ? script[actionKey] : null
1674
+ const steps = script ? script[actionKey] : null
1813
1675
 
1814
- // 3. Check if the resolved endpoint has the requested action attribute and resolve it to steps.
1815
- if (this.isActionCandidate(action)) {
1676
+ // 3. Check if the resolved endpoint has the requested action attribute and it's an array
1677
+ if (Array.isArray(steps) && steps.length > 0) {
1816
1678
 
1817
- this.setRunning(request, done)
1679
+ if (request.id) {
1680
+ this.running[request.id] = true
1681
+ this.done[request.id] = done
1682
+ } else if (request.path) {
1683
+ this.running[request.path] = true
1684
+ this.done[request.path] = done
1685
+ }
1818
1686
 
1819
1687
  // set DNS
1820
1688
 
@@ -1827,40 +1695,6 @@ class Api {
1827
1695
  }
1828
1696
 
1829
1697
  const initialPayload = typeof request.input === "undefined" ? {} : request.input
1830
- let steps
1831
- try {
1832
- steps = await this.resolveActionSteps({
1833
- request,
1834
- script,
1835
- scriptDir: cwd,
1836
- actionKey,
1837
- input: initialPayload,
1838
- args: initialPayload
1839
- })
1840
- } catch (e) {
1841
- this.clearResolvedAction(request)
1842
- delete this.running[this.requestId(request)]
1843
- this.ondata({
1844
- id: request.id || request.path,
1845
- type: "error",
1846
- data: e.stack,
1847
- })
1848
- return
1849
- }
1850
-
1851
- if (!Array.isArray(steps) || steps.length === 0) {
1852
- this.clearResolvedAction(request)
1853
- delete this.running[this.requestId(request)]
1854
- this.ondata({
1855
- id: request.id || request.path,
1856
- type: "error",
1857
- data: `missing or invalid attribute: ${actionKey}`
1858
- })
1859
- return
1860
- }
1861
-
1862
- await this.ensurePluginAgentInstructions(request)
1863
- await this.startWatchersForRequest(request, script, cwd, initialPayload)
1864
1698
  this.queue(request, steps[0], initialPayload, 0, steps.length, cwd, initialPayload)
1865
1699
 
1866
1700
  } else {
@@ -34,16 +34,6 @@ class Process {
34
34
  constructor() {
35
35
  this.appApi = new AppAPI()
36
36
  }
37
- async waitIndefinitely(req, kernel) {
38
- await new Promise((resolve, reject) => {
39
- this.resolve = resolve
40
-
41
- // register the process with the root uri so it can be manually resolved (with this.resolve()) later
42
- if (kernel && kernel.procs && req && req.parent && req.parent.path) {
43
- kernel.procs[req.parent.path] = this
44
- }
45
- })
46
- }
47
37
  // async start(req, ondata, kernel) {
48
38
  // /*
49
39
  // req := {
@@ -169,8 +159,6 @@ class Process {
169
159
  /*
170
160
  params := {
171
161
  sec: <SECONDS>,
172
- title: (optional) Title to display in the footer while waiting,
173
- description: (optional) Description to display in the footer while waiting,
174
162
  message: (optional) Description to display while waiting,
175
163
  menu: (optional) menu to display in the modal while waiting,
176
164
  // ok: (optional) <ok button text> (if not specified, no ok button),
@@ -181,8 +169,6 @@ class Process {
181
169
 
182
170
  params := {
183
171
  min: <MINUTES>,
184
- title: (optional) Title to display in the footer while waiting,
185
- description: (optional) Description to display in the footer while waiting,
186
172
  message: (optional) Description to display while waiting,
187
173
  menu: (optional) menu to display in the modal while waiting,
188
174
  // ok: (optional) <ok button text> (if not specified, no ok button),
@@ -194,8 +180,6 @@ class Process {
194
180
  params := {
195
181
  url: <URL>,
196
182
  interval: (optional) how often to retry checking (in seconds)
197
- title: (optional) Title to display in the footer while waiting,
198
- description: (optional) Description to display in the footer while waiting,
199
183
  message: (optional) the message to display while retrying (default: no message)
200
184
  }
201
185
 
@@ -214,21 +198,9 @@ class Process {
214
198
 
215
199
  or
216
200
 
217
- params := {
218
- title: (optional) Title to display in the footer while waiting,
219
- description: (optional) Description to display in the footer while waiting,
220
- }
221
-
222
- This waits indefinitely until the script is stopped or the wait is manually
223
- resolved.
224
-
225
- or
226
-
227
201
 
228
202
  params := {
229
203
  on: <wait-on condition https://github.com/jeffbski/wait-on>,
230
- title: (optional) Title to display in the footer while waiting,
231
- description: (optional) Description to display in the footer while waiting,
232
204
  message: (optional) Description to display while waiting,
233
205
  menu: (optional) menu to display in the modal while waiting,
234
206
  // ok: (optional) <ok button text> (if not specified, no ok button),
@@ -240,84 +212,57 @@ class Process {
240
212
  if 'cancel' is pressed before the condition is met, stops the script
241
213
 
242
214
  */
243
- let ms
244
- const waitPath = req && req.parent && req.parent.path
245
- if (waitPath && kernel) {
246
- if (!kernel.activeProcessWaits) {
247
- kernel.activeProcessWaits = {}
215
+ let ms
216
+ if (req.params) {
217
+ if (req.params.app || req.params.id || req.params.name) {
218
+ await this.appApi.waitForAppPresence(req, ondata, kernel)
219
+ return
248
220
  }
249
- kernel.activeProcessWaits[waitPath] = {
250
- path: waitPath,
251
- params: req.params || {},
252
- title: req.params && req.params.title,
253
- description: req.params && req.params.description,
254
- message: req.params && req.params.message,
255
- started: Date.now()
256
- }
257
- }
258
- const showFooter = req.params && (req.params.title || req.params.description)
259
- if (showFooter && typeof ondata === "function") {
260
- ondata(req.params, "process.wait.start")
261
- }
262
- try {
263
- if (req.params) {
264
- if (req.params.app || req.params.id || req.params.name) {
265
- await this.appApi.waitForAppPresence(req, ondata, kernel)
266
- return
221
+ // Display modal
222
+ if (req.params.sec || req.params.min) {
223
+ // Wait
224
+ if (req.params.sec) {
225
+ ms = req.params.sec * 1000
226
+ } else if (req.params.min) {
227
+ ms = req.params.min * 60 * 1000
267
228
  }
268
- // Display modal
269
- if (req.params.sec || req.params.min) {
270
- // Wait
271
- if (req.params.sec) {
272
- ms = req.params.sec * 1000
273
- } else if (req.params.min) {
274
- ms = req.params.min * 60 * 1000
275
- }
276
- await new Promise((resolve, reject) => {
277
- this.resolve = resolve
229
+ await new Promise((resolve, reject) => {
230
+ this.resolve = resolve
278
231
 
279
- // register the process with the root uri so it can be manually resolved (with this.resolve()) later
280
- kernel.procs[req.parent.path] = this
232
+ // register the process with the root uri so it can be manually resolved (with this.resolve()) later
233
+ kernel.procs[req.parent.path] = this
281
234
 
282
- setTimeout(() => {
283
- this.resolve()
284
- }, ms)
235
+ setTimeout(() => {
236
+ this.resolve()
237
+ }, ms)
238
+ })
239
+ } else if (req.params.uri) {
240
+ let interval = req.params.interval ? req.params.interval * 1000 : 1000
241
+ ondata(req.params, "loading.start")
242
+ await waitForUrl(req.params.uri, req.params.message, interval, ondata)
243
+ ondata(req.params, "loading.end")
244
+ } else if (req.params.url) {
245
+ let interval = req.params.interval ? req.params.interval * 1000 : 1000
246
+ ondata(req.params, "loading.start")
247
+ await waitForUrl(req.params.url, req.params.message, interval, ondata)
248
+ ondata(req.params, "loading.end")
249
+ } else if (req.params.on) {
250
+ // Wait
251
+ if (req.params.message) {
252
+ ondata({
253
+ raw: `\r\nWaiting: ${JSON.stringify(req.params.on)}\r\n`
285
254
  })
286
- } else if (req.params.uri) {
287
- let interval = req.params.interval ? req.params.interval * 1000 : 1000
288
- ondata(req.params, "loading.start")
289
- await waitForUrl(req.params.uri, req.params.message, interval, ondata)
290
- ondata(req.params, "loading.end")
291
- } else if (req.params.url) {
292
- let interval = req.params.interval ? req.params.interval * 1000 : 1000
293
- ondata(req.params, "loading.start")
294
- await waitForUrl(req.params.url, req.params.message, interval, ondata)
295
- ondata(req.params, "loading.end")
296
- } else if (req.params.on) {
297
- // Wait
298
- if (req.params.message) {
299
- ondata({
300
- raw: `\r\nWaiting: ${JSON.stringify(req.params.on)}\r\n`
301
- })
302
- ondata(req.params, "wait")
303
- }
304
- console.log("Wait", req.params.on)
305
- await waitOn(req.params.on)
306
- console.log("Wait finished")
307
- ondata(req.params, "wait.end")
308
- } else {
309
- await this.waitIndefinitely(req, kernel)
255
+ ondata(req.params, "wait")
310
256
  }
311
- } else {
312
- await this.waitIndefinitely(req, kernel)
313
- }
314
- } finally {
315
- if (waitPath && kernel && kernel.activeProcessWaits) {
316
- delete kernel.activeProcessWaits[waitPath]
317
- }
318
- if (showFooter && typeof ondata === "function") {
319
- ondata(req.params, "process.wait.end")
257
+ console.log("Wait", req.params.on)
258
+ await waitOn(req.params.on)
259
+ console.log("Wait finished")
260
+ ondata(req.params, "wait.end")
320
261
  }
262
+ } else {
263
+ await new Promise((resolve, reject) => {
264
+ this.resolve = resolve
265
+ })
321
266
  }
322
267
  }
323
268
  }
@@ -0,0 +1,53 @@
1
+ const semver = require('semver')
2
+
3
+ const CONDA_PIN_VERSION = "25.5.1"
4
+ const DEFAULT_SQLITE_PIN_VERSION = "3.47.2"
5
+ const WINDOWS_SQLITE_PIN_VERSION = "3.53.2"
6
+ const WINDOWS_PYTHON_SSL_FIX_SPEC = "python=3.10.20=*_1_cpython"
7
+ const WINDOWS_PYTHON_SSL_FIX_VERSION = "3.10.20"
8
+
9
+ const sqlitePinVersion = (platform) => {
10
+ return platform === "win32" ? WINDOWS_SQLITE_PIN_VERSION : DEFAULT_SQLITE_PIN_VERSION
11
+ }
12
+
13
+ const sqliteInstallSpec = (platform) => {
14
+ return `sqlite=${sqlitePinVersion(platform)}`
15
+ }
16
+
17
+ const sqlitePinnedSpec = (platform) => {
18
+ return `sqlite ==${sqlitePinVersion(platform)}`
19
+ }
20
+
21
+ const isExpectedSqlitePinned = (platform, version) => {
22
+ return String(version) === sqlitePinVersion(platform)
23
+ }
24
+
25
+ const condaBuildNumber = (build) => {
26
+ const chunks = String(build || "").split("_").reverse()
27
+ const buildNumber = chunks.find((chunk) => /^\d+$/.test(chunk))
28
+ return buildNumber ? Number(buildNumber) : null
29
+ }
30
+
31
+ const isWindowsPythonSslFixed = (version, build) => {
32
+ const coerced = semver.coerce(version)
33
+ if (!coerced) {
34
+ return false
35
+ }
36
+ if (!semver.satisfies(coerced, ">=3.10.20 <3.11.0")) {
37
+ return false
38
+ }
39
+ if (semver.eq(coerced, WINDOWS_PYTHON_SSL_FIX_VERSION)) {
40
+ const buildNumber = condaBuildNumber(build)
41
+ return typeof buildNumber === "number" && buildNumber >= 1
42
+ }
43
+ return true
44
+ }
45
+
46
+ module.exports = {
47
+ CONDA_PIN_VERSION,
48
+ WINDOWS_PYTHON_SSL_FIX_SPEC,
49
+ isExpectedSqlitePinned,
50
+ isWindowsPythonSslFixed,
51
+ sqliteInstallSpec,
52
+ sqlitePinnedSpec,
53
+ }
@@ -4,6 +4,15 @@ const fetch = require('cross-fetch')
4
4
  const { glob } = require('glob')
5
5
  const semver = require('semver')
6
6
  const { buildCondaListFromMeta } = require('./conda-meta')
7
+ const {
8
+ CONDA_PIN_VERSION,
9
+ WINDOWS_PYTHON_SSL_FIX_SPEC,
10
+ isExpectedSqlitePinned,
11
+ isWindowsPythonSslFixed,
12
+ sqliteInstallSpec,
13
+ sqlitePinnedSpec,
14
+ } = require('./conda-pins')
15
+
7
16
  class Conda {
8
17
  description = "Pinokio uses Conda to install various useful programs in an isolated manner."
9
18
  urls = {
@@ -48,6 +57,12 @@ class Conda {
48
57
  win32: ["miniconda/etc/profile.d", "miniconda/bin", "miniconda/Scripts", "miniconda/condabin", "miniconda/lib", "miniconda/Library/bin", "miniconda/pkgs", "miniconda"],
49
58
  linux: ["miniconda/etc/profile.d", "miniconda/bin", "miniconda/condabin", "miniconda/lib", "miniconda/Library/bin", "miniconda/pkgs", "miniconda"]
50
59
  }
60
+ pinnedPackages() {
61
+ return [
62
+ `conda ==${CONDA_PIN_VERSION}`,
63
+ sqlitePinnedSpec(this.kernel.platform),
64
+ ].join("\n")
65
+ }
51
66
  env() {
52
67
  let base = {
53
68
  // CONDA_ROOT: this.kernel.bin.path("miniconda"),
@@ -129,7 +144,7 @@ report_errors: false`)
129
144
  let pinned_exists = await this.kernel.exists("bin/miniconda/conda-meta")
130
145
  if (pinned_exists) {
131
146
  //await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), `conda ==24.11.3`)
132
- await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), "conda ==25.5.1\nsqlite ==3.47.2")
147
+ await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), this.pinnedPackages())
133
148
  // await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), "")
134
149
  //sqlite ==3.47.2`)
135
150
  // await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), `conda=24.9.0`)
@@ -160,6 +175,7 @@ report_errors: false`)
160
175
  let conda_check = {}
161
176
  let conda = new Set()
162
177
  let conda_versions = {}
178
+ let conda_builds = {}
163
179
  let start = false
164
180
  for(let line of lines) {
165
181
  if (start) {
@@ -167,8 +183,10 @@ report_errors: false`)
167
183
  if (chunks.length > 2) {
168
184
  let name = chunks[0]
169
185
  let version = chunks[1]
186
+ let build = chunks[2]
170
187
  conda.add(name)
171
188
  conda_versions[name] = version
189
+ conda_builds[name] = build
172
190
  if (name === "conda") {
173
191
  conda_check.conda = true
174
192
  // //if (String(version) === "24.11.1") {
@@ -193,7 +211,7 @@ report_errors: false`)
193
211
  // Use sqlite to check if `conda update -y --all` went through successfully
194
212
  // sometimes it just fails silently so need to check
195
213
  if (name === "sqlite") {
196
- if (String(version) === "3.47.2") {
214
+ if (isExpectedSqlitePinned(this.kernel.platform, version)) {
197
215
  conda_check.sqlite = true
198
216
  }
199
217
  //let coerced = semver.coerce(version)
@@ -206,6 +224,9 @@ report_errors: false`)
206
224
  // console.log("semver NOT satisfied")
207
225
  //}
208
226
  }
227
+ if (name === "python") {
228
+ conda_check.python = this.kernel.platform !== "win32" || isWindowsPythonSslFixed(version, build)
229
+ }
209
230
  }
210
231
  } else {
211
232
  if (/.*name.*version.*build.*channel/i.test(line)) {
@@ -215,7 +236,8 @@ report_errors: false`)
215
236
  }
216
237
  this.kernel.bin.installed.conda = conda
217
238
  this.kernel.bin.installed.conda_versions = conda_versions
218
- return conda_check.conda && conda_check.mamba && conda_check.sqlite
239
+ this.kernel.bin.installed.conda_builds = conda_builds
240
+ return conda_check.conda && conda_check.mamba && conda_check.sqlite && (this.kernel.platform !== "win32" || conda_check.python)
219
241
  //return conda_check.conda && conda_check.mamba
220
242
  }
221
243
  async install(req, ondata) {
@@ -266,7 +288,7 @@ report_errors: false`)
266
288
  if (pinned_exists) {
267
289
  //await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), `conda=24.11.1`)
268
290
  //await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), `conda ==24.11.3`)
269
- await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), "conda ==25.5.1\nsqlite ==3.47.2")
291
+ await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), this.pinnedPackages())
270
292
  //await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), "sqlite ==3.47.2")
271
293
  //await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), "")
272
294
  //sqlite ==3.47.2`)
@@ -300,10 +322,18 @@ report_errors: false`)
300
322
  }).join(" ")
301
323
  console.log("Conda dependencies to install", { mods })
302
324
 
325
+ let condaPackages = [
326
+ `"${sqliteInstallSpec(this.kernel.platform)}"`,
327
+ `"conda-libmamba-solver>=25.4.0"`,
328
+ ]
329
+ if (this.kernel.platform === "win32") {
330
+ condaPackages.unshift(`"${WINDOWS_PYTHON_SSL_FIX_SPEC}"`)
331
+ }
332
+
303
333
  let cmds = [
304
334
  //"conda clean -y --index-cache",
305
335
  "conda clean -y --all",
306
- `conda install -y -c conda-forge "sqlite=3.47.2" "conda-libmamba-solver>=25.4.0" ${mods}`,
336
+ `conda install -y -c conda-forge ${condaPackages.join(" ")} ${mods}`.trim(),
307
337
 
308
338
  // `conda config --file ${this.kernel.path('condarc')} --set remote_connect_timeout_secs 20`,
309
339
  // `conda config --file ${this.kernel.path('condarc')} --set remote_read_timeout_secs 300`,
@@ -339,7 +369,6 @@ report_errors: false`)
339
369
  //if (this.kernel.platform === "win32" || this.kernel.platform === "darwin") {
340
370
  // cmds.push("conda install -y conda-libmamba-solver=24.7.0 conda=24.7.1 --freeze-installed")
341
371
  //}
342
-
343
372
  await this.kernel.bin.exec({
344
373
  message: cmds,
345
374
  env: {
@@ -18,7 +18,7 @@ class Huggingface {
18
18
  let version = this.kernel.bin.installed.conda_versions.huggingface_hub
19
19
  if (version) {
20
20
  let coerced = semver.coerce(version)
21
- if (coerced && semver.eq(coerced, "1.0.1")) {
21
+ if (semver.satisfies(coerced, ">=1.0.1")) {
22
22
  return true
23
23
  }
24
24
  }