pinokiod 7.5.0 → 7.5.2

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.
@@ -2,21 +2,21 @@ const fs = require('fs')
2
2
  const path = require('path')
3
3
  const { execFile } = require('child_process')
4
4
 
5
- async function buildCondaListFromMeta(condaRootPath, useCondaList) {
5
+ async function buildCondaListFromMeta(minicondaPath, useCondaList) {
6
6
  if (!useCondaList) {
7
- const metaOutput = await readFromMeta(condaRootPath)
7
+ const metaOutput = await readFromMeta(minicondaPath)
8
8
  if (metaOutput) {
9
9
  return { response: metaOutput, source: 'conda-meta' }
10
10
  }
11
11
  }
12
- return await runCondaList(condaRootPath)
12
+ return await runCondaList(minicondaPath)
13
13
  }
14
14
 
15
- async function readFromMeta(condaRootPath) {
16
- if (!condaRootPath) {
15
+ async function readFromMeta(minicondaPath) {
16
+ if (!minicondaPath) {
17
17
  return null
18
18
  }
19
- const metaDir = path.join(condaRootPath, 'conda-meta')
19
+ const metaDir = path.join(minicondaPath, 'conda-meta')
20
20
  let entries
21
21
  try {
22
22
  entries = await fs.promises.readdir(metaDir, { withFileTypes: true })
@@ -53,8 +53,8 @@ async function readFromMeta(condaRootPath) {
53
53
  return lines.join('\n')
54
54
  }
55
55
 
56
- async function runCondaList(condaRootPath) {
57
- const condaBinary = resolveCondaBinary(condaRootPath)
56
+ async function runCondaList(minicondaPath) {
57
+ const condaBinary = resolveCondaBinary(minicondaPath)
58
58
  if (!condaBinary) {
59
59
  return { response: '', source: 'conda-list' }
60
60
  }
@@ -69,18 +69,18 @@ async function runCondaList(condaRootPath) {
69
69
  })
70
70
  }
71
71
 
72
- function resolveCondaBinary(condaRootPath) {
72
+ function resolveCondaBinary(minicondaPath) {
73
73
  if (process.platform === 'win32') {
74
- if (condaRootPath) {
75
- const scriptPath = path.join(condaRootPath, 'Scripts', 'conda.exe')
74
+ if (minicondaPath) {
75
+ const scriptPath = path.join(minicondaPath, 'Scripts', 'conda.exe')
76
76
  if (fs.existsSync(scriptPath)) {
77
77
  return scriptPath
78
78
  }
79
79
  }
80
80
  return 'conda'
81
81
  }
82
- if (condaRootPath) {
83
- const binPath = path.join(condaRootPath, 'bin', 'conda')
82
+ if (minicondaPath) {
83
+ const binPath = path.join(minicondaPath, 'bin', 'conda')
84
84
  if (fs.existsSync(binPath)) {
85
85
  return binPath
86
86
  }
@@ -16,12 +16,7 @@ const {
16
16
  const MINIFORGE_RELEASE = "26.3.2-3"
17
17
  const MINIFORGE_BASE_URL = `https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_RELEASE}`
18
18
  const CONDA_ROOT_DIR = "miniforge"
19
- const CONDA_COMPAT_ROOT_DIR = "miniconda"
20
- const PINOKIO_CONDA_RUNTIME = {
21
- distribution: "miniforge",
22
- release: MINIFORGE_RELEASE,
23
- epoch: 1,
24
- }
19
+ const LEGACY_CONDA_ROOT_DIR = "miniconda"
25
20
 
26
21
  class Conda {
27
22
  description = "Pinokio uses Conda to install various useful programs in an isolated manner."
@@ -54,26 +49,8 @@ class Conda {
54
49
  sqlitePinnedSpec(this.kernel.platform),
55
50
  ].join("\n")
56
51
  }
57
- runtimeStampPath() {
58
- return this.kernel.bin.path(CONDA_ROOT_DIR, ".pinokio-runtime.json")
59
- }
60
- async hasCurrentRuntimeStamp() {
61
- try {
62
- const value = await fs.promises.readFile(this.runtimeStampPath(), "utf8")
63
- const runtime = JSON.parse(value)
64
- return !!(runtime &&
65
- runtime.distribution === PINOKIO_CONDA_RUNTIME.distribution &&
66
- runtime.release === PINOKIO_CONDA_RUNTIME.release &&
67
- runtime.epoch === PINOKIO_CONDA_RUNTIME.epoch)
68
- } catch (e) {
69
- return false
70
- }
71
- }
72
- async writeRuntimeStamp() {
73
- await fs.promises.writeFile(
74
- this.runtimeStampPath(),
75
- `${JSON.stringify(PINOKIO_CONDA_RUNTIME, null, 2)}\n`
76
- )
52
+ async hasCondaMeta() {
53
+ return await this.kernel.exists(`bin/${CONDA_ROOT_DIR}/conda-meta`)
77
54
  }
78
55
  env() {
79
56
  let base = {
@@ -100,6 +77,9 @@ class Conda {
100
77
  if (this.kernel.platform !== "win32") {
101
78
  return
102
79
  }
80
+ if (!(await this.hasCondaMeta())) {
81
+ return
82
+ }
103
83
  const activateDir = this.kernel.bin.path(`${CONDA_ROOT_DIR}/etc/conda/activate.d`)
104
84
  await fs.promises.mkdir(activateDir, { recursive: true }).catch(() => {})
105
85
  await fs.promises.writeFile(
@@ -141,12 +121,12 @@ remote_connect_timeout_secs: 20.0
141
121
  remote_read_timeout_secs: 300.0
142
122
  remote_max_retries: 6
143
123
  report_errors: false`)
144
- let pinned_exists = await this.kernel.exists(`bin/${CONDA_ROOT_DIR}/conda-meta`)
124
+ let pinned_exists = await this.hasCondaMeta()
145
125
  if (pinned_exists) {
146
126
  await fs.promises.writeFile(this.kernel.path(`bin/${CONDA_ROOT_DIR}/conda-meta/pinned`), this.pinnedPackages())
127
+ await this.ensureSslCertDirOverride()
128
+ await this.ensureCompatibilityAlias()
147
129
  }
148
- await this.ensureSslCertDirOverride()
149
- await this.ensureCompatibilityAlias()
150
130
  }
151
131
  }
152
132
  async check() {
@@ -228,10 +208,10 @@ report_errors: false`)
228
208
  const installer_url = this.urls[this.kernel.platform][this.kernel.arch]
229
209
  const installer = this.installer[this.kernel.platform]
230
210
  const install_path = this.kernel.bin.path(CONDA_ROOT_DIR)
231
- const compat_path = this.kernel.bin.path(CONDA_COMPAT_ROOT_DIR)
211
+ const legacy_path = this.kernel.bin.path(LEGACY_CONDA_ROOT_DIR)
232
212
  let install_path_exists = await this.kernel.exists(`bin/${CONDA_ROOT_DIR}`)
233
- let compat_path_exists = await this.kernel.exists(`bin/${CONDA_COMPAT_ROOT_DIR}`)
234
- if (install_path_exists || compat_path_exists) {
213
+ let legacy_path_exists = await this.kernel.exists(`bin/${LEGACY_CONDA_ROOT_DIR}`)
214
+ if (install_path_exists || legacy_path_exists) {
235
215
  console.log("Install path already exists. Will replace after installer download...", install_path)
236
216
  } else {
237
217
  console.log("Install path does not exist. Installing...")
@@ -240,10 +220,10 @@ report_errors: false`)
240
220
  ondata({ raw: `downloading installer: ${installer_url}...\r\n` })
241
221
  await this.kernel.bin.download(installer_url, installer, ondata)
242
222
 
243
- compat_path_exists = await this.kernel.exists(`bin/${CONDA_COMPAT_ROOT_DIR}`)
244
- if (compat_path_exists) {
245
- console.log("Removing compatibility install path...", compat_path)
246
- await this.removeInstallPath(compat_path)
223
+ legacy_path_exists = await this.kernel.exists(`bin/${LEGACY_CONDA_ROOT_DIR}`)
224
+ if (legacy_path_exists) {
225
+ console.log("Removing legacy install path...", legacy_path)
226
+ await this.removeInstallPath(legacy_path)
247
227
  }
248
228
  install_path_exists = await this.kernel.exists(`bin/${CONDA_ROOT_DIR}`)
249
229
  if (install_path_exists) {
@@ -309,7 +289,6 @@ report_errors: false`)
309
289
  )
310
290
  }
311
291
  await this.ensureSslCertDirOverride()
312
- await this.writeRuntimeStamp()
313
292
  await this.ensureCompatibilityAlias()
314
293
  ondata({ raw: `Install finished\r\n` })
315
294
  await this.kernel.bin.rm(installer, ondata)
@@ -346,9 +325,8 @@ report_errors: false`)
346
325
  }
347
326
  async ensureCompatibilityAlias() {
348
327
  const target = this.kernel.bin.path(CONDA_ROOT_DIR)
349
- const alias = this.kernel.bin.path(CONDA_COMPAT_ROOT_DIR)
350
- const targetExists = await fs.promises.access(target).then(() => true).catch(() => false)
351
- if (!targetExists) {
328
+ const alias = this.kernel.bin.path(LEGACY_CONDA_ROOT_DIR)
329
+ if (!(await this.hasCondaMeta())) {
352
330
  return
353
331
  }
354
332
  const aliasExists = await fs.promises.lstat(alias).then(() => true).catch(() => false)
@@ -378,10 +356,6 @@ report_errors: false`)
378
356
  for(let p of this.paths[this.kernel.platform]) {
379
357
  let e = await this.kernel.bin.exists(p)
380
358
  if (e && this.kernel.bin.correct_conda) {
381
- if (!(await this.hasCurrentRuntimeStamp())) {
382
- console.log("Pinokio Conda runtime changed; marking Conda invalid")
383
- return false
384
- }
385
359
  return true
386
360
  }
387
361
  }
@@ -389,7 +363,7 @@ report_errors: false`)
389
363
  }
390
364
 
391
365
  async uninstall(req, ondata) {
392
- await this.kernel.bin.rm(CONDA_COMPAT_ROOT_DIR, ondata)
366
+ await this.kernel.bin.rm(LEGACY_CONDA_ROOT_DIR, ondata)
393
367
  return this.kernel.bin.rm(CONDA_ROOT_DIR, ondata)
394
368
  }
395
369
 
@@ -1,6 +1,6 @@
1
1
  const RELEASE_VERSION = "8.1.2"
2
2
  const CONDA_SPEC = `ffmpeg=${RELEASE_VERSION}`
3
- const CONDA_CHANNEL_FLAGS = "--override-channels -c conda-forge"
3
+ const CONDA_CHANNEL_FLAGS = "-c conda-forge"
4
4
 
5
5
  class Ffmpeg {
6
6
  description = "Installs FFmpeg for audio and video processing."
@@ -14,6 +14,7 @@ module.exports = {
14
14
  "node",
15
15
  "huggingface",
16
16
  "git",
17
+ "ffmpeg",
17
18
  // "caddy"
18
19
  ]
19
20
  if (platform !== "win32") {
@@ -183,6 +184,7 @@ module.exports = {
183
184
  "node",
184
185
  "huggingface",
185
186
  "git",
187
+ "ffmpeg",
186
188
  ]
187
189
  if (platform !== "win32") {
188
190
  conda_requirements.push("tmux")
@@ -222,6 +224,7 @@ module.exports = {
222
224
  "huggingface",
223
225
  "git",
224
226
  "caddy",
227
+ "ffmpeg",
225
228
  ]
226
229
  if (platform === "win32") {
227
230
  requirements.push({ name: "registry" })
package/kernel/shell.js CHANGED
@@ -1245,8 +1245,6 @@ class Shell {
1245
1245
  this.env.PIP_REQUIRE_VIRTUALENV = "true"
1246
1246
  }
1247
1247
 
1248
- this.env.UV_PYTHON_PREFERENCE="only-managed"
1249
-
1250
1248
  // 2. venv
1251
1249
 
1252
1250
  /*
@@ -1322,7 +1320,7 @@ class Shell {
1322
1320
  if (use_uv) {
1323
1321
  // when python version is specified as venv.python => use uv
1324
1322
  venv_activation = [
1325
- `uv venv ${shellEnvPath}${python_version}`,
1323
+ `uv venv --managed-python ${shellEnvPath}${python_version}`,
1326
1324
  activate_command,
1327
1325
  // `uv pip install --upgrade pip setuptools wheel`,
1328
1326
  deactivate_path,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "7.5.0",
3
+ "version": "7.5.2",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/server/index.js CHANGED
@@ -6013,7 +6013,7 @@ class Server {
6013
6013
  this.kernel.store.set("version", this.version.pinokiod)
6014
6014
  console.log("[DONE] Updating to the new version")
6015
6015
  console.log("not up to date. update py.")
6016
- // remove ~/bin/py
6016
+ // remove ~/bin/miniconda/py
6017
6017
  let p = path.resolve(home, "bin/py")
6018
6018
  console.log(`[TRY] reset ${p}`)
6019
6019
  await fse.remove(p)
@@ -10034,6 +10034,7 @@ class Server {
10034
10034
  return
10035
10035
  }
10036
10036
  // check bin folder
10037
+ // let bin_path = this.kernel.path("bin/miniconda")
10037
10038
  // let bin_exists = await this.exists(bin_path)
10038
10039
  // if (!bin_exists) {
10039
10040
  // res.redirect("/setup")
@@ -46,17 +46,6 @@ async function createLegacyMiniconda(root) {
46
46
  return createCondaRoot(root, 'miniconda')
47
47
  }
48
48
 
49
- async function writeCurrentRuntimeStamp(root) {
50
- await fs.writeFile(
51
- path.join(root, 'bin', 'miniforge', '.pinokio-runtime.json'),
52
- `${JSON.stringify({
53
- distribution: 'miniforge',
54
- release: '26.3.2-3',
55
- epoch: 1,
56
- }, null, 2)}\n`
57
- )
58
- }
59
-
60
49
  function createConda(kernel) {
61
50
  const conda = new Conda()
62
51
  conda.kernel = kernel
@@ -81,6 +70,20 @@ test('Conda uses Miniforge assets and writes conda-forge-only config', async ()
81
70
  assert.doesNotMatch(condarc, /bin\/miniconda\/envs/)
82
71
  assert.doesNotMatch(condarc, /\bdefaults\b/)
83
72
  assert.doesNotMatch(condarc, /auto_accept_tos/)
73
+ assert.equal(await pathExists(path.join(root, 'bin', 'miniforge')), false)
74
+ })
75
+
76
+ test('Conda init writes activation hooks only after Miniforge exists', async () => {
77
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-init-hooks-'))
78
+ await fs.mkdir(path.join(root, 'bin', 'miniforge', 'conda-meta'), { recursive: true })
79
+ const conda = createConda(createKernel(root))
80
+
81
+ await conda.init()
82
+
83
+ assert.equal(
84
+ await pathExists(path.join(root, 'bin', 'miniforge', 'etc', 'conda', 'activate.d', 'zz_pinokio_unset_ssl_cert_dir-win.bat')),
85
+ true
86
+ )
84
87
  })
85
88
 
86
89
  test('Conda pins Python 3.10.20 consistently across platforms', async () => {
@@ -204,14 +207,6 @@ test('Conda installed stays false when metadata check already marked Conda inval
204
207
  assert.equal(await createConda(kernel).installed(), false)
205
208
  })
206
209
 
207
- test('Conda installed returns false for old Conda runtimes without the Miniforge stamp', async () => {
208
- const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-runtime-stale-'))
209
- await createMiniforge(root)
210
- const kernel = createKernel(root)
211
-
212
- assert.equal(await createConda(kernel).installed(), false)
213
- })
214
-
215
210
  test('Conda install keeps the old runtime when the replacement installer download fails', async () => {
216
211
  const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-download-fails-'))
217
212
  const miniconda = await createLegacyMiniconda(root)
@@ -2,6 +2,7 @@ const assert = require('node:assert/strict')
2
2
  const test = require('node:test')
3
3
 
4
4
  const Ffmpeg = require('../kernel/bin/ffmpeg')
5
+ const Setup = require('../kernel/bin/setup')
5
6
 
6
7
  function createKernel(platform = 'win32') {
7
8
  return {
@@ -34,7 +35,7 @@ test('FFmpeg bin installs pinned ffmpeg into base Conda on Windows', async () =>
34
35
  assert.equal(calls.length, 1)
35
36
  assert.deepEqual(calls[0].message, [
36
37
  'conda clean -y --all',
37
- 'conda install -y --override-channels -c conda-forge ffmpeg=8.1.2',
38
+ 'conda install -y -c conda-forge ffmpeg=8.1.2',
38
39
  ])
39
40
  assert.equal(calls[0].env, undefined)
40
41
  assert.equal(calls[0].message.some((command) => /ffmpeg-env|conda create|-p /.test(command)), false)
@@ -51,7 +52,7 @@ test('FFmpeg bin installs pinned ffmpeg into base Conda consistently across plat
51
52
 
52
53
  assert.deepEqual(calls[0].message, [
53
54
  'conda clean -y --all',
54
- 'conda install -y --override-channels -c conda-forge ffmpeg=8.1.2',
55
+ 'conda install -y -c conda-forge ffmpeg=8.1.2',
55
56
  ])
56
57
  })
57
58
 
@@ -70,3 +71,12 @@ test('FFmpeg installed check requires the base Conda package at the pinned versi
70
71
  kernel.bin.installed.conda_versions = {}
71
72
  assert.equal(await ffmpeg.installed(), false)
72
73
  })
74
+
75
+ test('setup presets bundle FFmpeg into Conda bootstrap and keep the module check', () => {
76
+ const kernel = { gpu: null }
77
+ for (const preset of ['ai', 'dev', 'advanced_dev']) {
78
+ const config = Setup[preset](kernel)
79
+ assert.equal(config.conda_requirements.includes('ffmpeg'), true)
80
+ assert.equal(config.requirements.some((requirement) => requirement.name === 'ffmpeg'), true)
81
+ }
82
+ })