pinokiod 7.3.9 → 7.3.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 (52) hide show
  1. package/kernel/bin/brew.js +12 -2
  2. package/kernel/bin/caddy.js +24 -20
  3. package/kernel/bin/huggingface.js +2 -2
  4. package/kernel/bin/setup.js +2 -3
  5. package/kernel/bin/uv.js +13 -6
  6. package/kernel/connect/index.js +5 -1
  7. package/kernel/connect/providers/huggingface/index.js +213 -75
  8. package/kernel/environment.js +16 -1
  9. package/kernel/router/localhost_home_router.js +7 -0
  10. package/kernel/shell.js +1 -5
  11. package/kernel/util.js +1 -0
  12. package/package.json +1 -1
  13. package/server/index.js +75 -33
  14. package/server/public/common.js +52 -88
  15. package/server/public/install.js +20 -2
  16. package/server/public/layout.js +1 -1
  17. package/server/public/nav.js +3 -1
  18. package/server/public/style.css +1455 -521
  19. package/server/public/tab-link-popover.css +162 -18
  20. package/server/public/tab-link-popover.js +230 -21
  21. package/server/public/task-launcher.css +182 -91
  22. package/server/public/terminal-settings.js +227 -50
  23. package/server/public/universal-launcher.css +42 -33
  24. package/server/public/urldropdown.css +284 -0
  25. package/server/views/app.ejs +1718 -352
  26. package/server/views/autolaunch.ejs +4 -5
  27. package/server/views/checkpoints.ejs +223 -50
  28. package/server/views/connect/huggingface.ejs +406 -325
  29. package/server/views/connect.ejs +0 -1
  30. package/server/views/github.ejs +277 -324
  31. package/server/views/index.ejs +65 -8
  32. package/server/views/install.ejs +134 -65
  33. package/server/views/logs.ejs +9 -8
  34. package/server/views/net.ejs +341 -64
  35. package/server/views/network.ejs +85 -63
  36. package/server/views/partials/main_sidebar.ejs +249 -24
  37. package/server/views/plugins.ejs +141 -3
  38. package/server/views/settings.ejs +103 -7
  39. package/server/views/setup.ejs +0 -5
  40. package/server/views/skills.ejs +0 -1
  41. package/server/views/task_list.ejs +0 -1
  42. package/server/views/terminal.ejs +285 -60
  43. package/server/views/terminals.ejs +346 -6
  44. package/server/views/tools.ejs +828 -1691
  45. package/test/caddy-install.test.js +53 -0
  46. package/test/connect-setup.test.js +16 -0
  47. package/test/github-connection.test.js +1 -1
  48. package/test/huggingface-bin.test.js +4 -4
  49. package/test/huggingface-connect.test.js +73 -0
  50. package/test/main-sidebar.test.js +31 -0
  51. package/test/shell-run-template.test.js +5 -1
  52. package/test/uv-bin.test.js +29 -0
@@ -0,0 +1,53 @@
1
+ const assert = require('node:assert/strict')
2
+ const test = require('node:test')
3
+
4
+ const Caddy = require('../kernel/bin/caddy')
5
+ const LocalhostHomeRouter = require('../kernel/router/localhost_home_router')
6
+
7
+ test('localhost router disables caddy automatic trust install', () => {
8
+ const router = {
9
+ kernel: {
10
+ peer: { host: 'pinokio.localhost' },
11
+ path: (...segments) => segments.join('/')
12
+ },
13
+ default_host: '127.0.0.1',
14
+ default_port: 42000,
15
+ default_match: 'pinokio.localhost',
16
+ add() {}
17
+ }
18
+
19
+ new LocalhostHomeRouter(router).handle()
20
+
21
+ assert.equal(
22
+ router.config.apps.pki.certificate_authorities.local.install_trust,
23
+ false
24
+ )
25
+ })
26
+
27
+ test('caddy admin wait returns false on timeout', async () => {
28
+ const caddy = new Caddy()
29
+ let checks = 0
30
+ caddy.running = async () => {
31
+ checks += 1
32
+ return false
33
+ }
34
+
35
+ const ready = await caddy.waitForAdmin(5, 1)
36
+
37
+ assert.equal(ready, false)
38
+ assert.ok(checks >= 1)
39
+ })
40
+
41
+ test('caddy admin wait returns true when admin responds', async () => {
42
+ const caddy = new Caddy()
43
+ let checks = 0
44
+ caddy.running = async () => {
45
+ checks += 1
46
+ return checks === 2
47
+ }
48
+
49
+ const ready = await caddy.waitForAdmin(100, 1)
50
+
51
+ assert.equal(ready, true)
52
+ assert.equal(checks, 2)
53
+ })
@@ -0,0 +1,16 @@
1
+ const assert = require('node:assert/strict')
2
+ const test = require('node:test')
3
+
4
+ const setup = require('../kernel/bin/setup')
5
+
6
+ test('connect setup requires auth tooling without requiring caddy', () => {
7
+ const preset = setup.connect({})
8
+ const requirementNames = preset.requirements.map((item) => item.name)
9
+
10
+ assert.equal(requirementNames.includes('huggingface'), true)
11
+ assert.equal(requirementNames.includes('git'), true)
12
+ assert.equal(requirementNames.includes('caddy'), false)
13
+ assert.equal(preset.conda_requirements.includes('huggingface'), true)
14
+ assert.equal(preset.conda_requirements.includes('git'), true)
15
+ assert.equal(preset.conda_requirements.includes('caddy'), false)
16
+ })
@@ -76,7 +76,7 @@ test('GitHub login uses success-only credential verification on Windows', () =>
76
76
  kernel: { platform: 'win32' }
77
77
  })
78
78
 
79
- assert.match(message, /git credential-manager github login --web --force && cmd \/C "set GIT_TERMINAL_PROMPT=0&& set GCM_INTERACTIVE=never&& \(echo protocol=https& echo host=github\.com& echo\.\) \| git credential fill >NUL" && echo P\^INOKIO_GITHUB_LOGIN_DONE/)
79
+ assert.match(message, /git credential-manager github login --web --force && powershell\.exe -NoProfile -Command "\$env:GIT_TERMINAL_PROMPT='0'; \$env:GCM_INTERACTIVE='never'; @\('protocol=https','host=github\.com',''\) \| git credential fill > \$null; exit \$LASTEXITCODE" && echo P\^INOKIO_GITHUB_LOGIN_DONE/)
80
80
  assert.doesNotMatch(message, /PINOKIO_GITHUB_LOGIN_DONE/)
81
81
  })
82
82
 
@@ -16,10 +16,10 @@ function createHuggingface(version) {
16
16
  return huggingface
17
17
  }
18
18
 
19
- test('Huggingface.installed accepts exactly huggingface_hub 1.0.1', async () => {
20
- assert.equal(await createHuggingface('1.0.1').installed(), true)
21
- assert.equal(await createHuggingface('1.0.1-pyhd8ed1ab_0').installed(), true)
22
- assert.equal(await createHuggingface('1.0.2').installed(), false)
19
+ test('Huggingface.installed accepts exactly huggingface_hub 1.20.1', async () => {
20
+ assert.equal(await createHuggingface('1.20.1').installed(), true)
21
+ assert.equal(await createHuggingface('1.20.1-pyhcf101f3_0').installed(), true)
22
+ assert.equal(await createHuggingface('1.20.0').installed(), false)
23
23
  assert.equal(await createHuggingface('0.35.3').installed(), false)
24
24
  assert.equal(await createHuggingface(null).installed(), false)
25
25
  })
@@ -0,0 +1,73 @@
1
+ const assert = require('node:assert/strict')
2
+ const fs = require('node:fs/promises')
3
+ const os = require('node:os')
4
+ const path = require('node:path')
5
+ const test = require('node:test')
6
+
7
+ const HuggingfaceConnect = require('../kernel/connect/providers/huggingface')
8
+
9
+ function createKernel(root) {
10
+ return {
11
+ homedir: root,
12
+ platform: process.platform,
13
+ path: (...parts) => path.join(root, ...parts),
14
+ exists: async (...parts) => {
15
+ const target = parts.length === 1 && path.isAbsolute(parts[0]) ? parts[0] : path.join(root, ...parts)
16
+ try {
17
+ await fs.access(target)
18
+ return true
19
+ } catch (_) {
20
+ return false
21
+ }
22
+ }
23
+ }
24
+ }
25
+
26
+ test('Hugging Face connect parses managed hf JSON device login events', () => {
27
+ const provider = new HuggingfaceConnect(createKernel('/tmp/pinokio'), {})
28
+ const parsed = provider.parseDeviceLogin(
29
+ '{"event":"device_code","verification_uri":"https://hf.co/oauth/device","user_code":"ABCD-EFGH","verification_uri_complete":"https://hf.co/oauth/device","expires_in":300,"interval":5}\n'
30
+ )
31
+
32
+ assert.deepEqual(parsed, {
33
+ verification_uri_complete: 'https://hf.co/oauth/device',
34
+ user_code: 'ABCD-EFGH',
35
+ expires_in: 300,
36
+ interval: 5
37
+ })
38
+ })
39
+
40
+ test('Hugging Face connect parses managed hf agent login instructions', () => {
41
+ const provider = new HuggingfaceConnect(createKernel('/tmp/pinokio'), {})
42
+ const parsed = provider.parseDeviceLogin(
43
+ 'Ask the user to open https://hf.co/oauth/device in a browser and enter the code ABCD-EFGH. The code expires in 300 seconds. Waiting for authorization...'
44
+ )
45
+
46
+ assert.deepEqual(parsed, {
47
+ verification_uri_complete: 'https://hf.co/oauth/device',
48
+ user_code: 'ABCD-EFGH',
49
+ expires_in: 300
50
+ })
51
+ })
52
+
53
+ test('Hugging Face connect uses shared HF_TOKEN_PATH and ignores ambient HF_TOKEN', async () => {
54
+ const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-hf-connect-'))
55
+ await fs.writeFile(path.join(root, 'ENVIRONMENT'), 'HF_TOKEN_PATH=./custom/hf-token\n')
56
+ const oldToken = process.env.HF_TOKEN
57
+ process.env.HF_TOKEN = 'hf_should_not_win'
58
+ try {
59
+ const provider = new HuggingfaceConnect(createKernel(root), {})
60
+ const env = await provider.authEnv()
61
+
62
+ assert.equal(env.HF_TOKEN_PATH, path.join(root, 'custom', 'hf-token'))
63
+ assert.equal(env.HF_TOKEN, undefined)
64
+ assert.equal(env.HF_HUB_DISABLE_UPDATE_CHECK, '1')
65
+ } finally {
66
+ if (typeof oldToken === 'undefined') {
67
+ delete process.env.HF_TOKEN
68
+ } else {
69
+ process.env.HF_TOKEN = oldToken
70
+ }
71
+ await fs.rm(root, { recursive: true, force: true })
72
+ }
73
+ })
@@ -0,0 +1,31 @@
1
+ const assert = require('node:assert/strict')
2
+ const fs = require('node:fs/promises')
3
+ const path = require('node:path')
4
+ const test = require('node:test')
5
+
6
+ const sidebarFile = path.resolve(__dirname, '..', 'server', 'views', 'partials', 'main_sidebar.ejs')
7
+
8
+ test('main sidebar renders local network peers before phone access', async () => {
9
+ const source = await fs.readFile(sidebarFile, 'utf8')
10
+
11
+ const localNetworkIndex = source.indexOf('Local network')
12
+ const peerListIndex = source.indexOf('sidebarList.forEach')
13
+ const phoneIndex = source.indexOf('main-sidebar-phone-trigger')
14
+
15
+ assert.notEqual(localNetworkIndex, -1)
16
+ assert.notEqual(peerListIndex, -1)
17
+ assert.notEqual(phoneIndex, -1)
18
+ assert.ok(localNetworkIndex < peerListIndex)
19
+ assert.ok(peerListIndex < phoneIndex)
20
+ })
21
+
22
+ test('main sidebar gates phone QR behind local access setup', async () => {
23
+ const source = await fs.readFile(sidebarFile, 'utf8')
24
+
25
+ assert.match(source, /peer_access_router_installed/)
26
+ assert.match(source, /sidebarPhoneAccessNeedsSetup/)
27
+ assert.match(source, /Set up local access/)
28
+ assert.match(source, /\/setup\/network\?callback=/)
29
+ assert.match(source, /Scan with a device on the same local network/)
30
+ assert.match(source, /This link is not public and will not work outside this network/)
31
+ })
@@ -157,15 +157,19 @@ test('Shell.init_env disables Hugging Face hub update checks by default without
157
157
  env: {}
158
158
  })
159
159
  assert.equal(defaultShell.env.HF_HUB_DISABLE_UPDATE_CHECK, '1')
160
+ assert.equal(defaultShell.env.HF_TOKEN_PATH, path.join(root, 'cache', 'HF_AUTH', 'token'))
161
+ assert.equal(defaultShell.env.HF_TOKEN, undefined)
160
162
 
161
163
  const overrideShell = createShell(createKernel(root))
162
164
  await overrideShell.init_env({
163
165
  path: process.cwd(),
164
166
  env: {
165
- HF_HUB_DISABLE_UPDATE_CHECK: '0'
167
+ HF_HUB_DISABLE_UPDATE_CHECK: '0',
168
+ HF_TOKEN_PATH: path.join(root, 'custom', 'hf-token')
166
169
  }
167
170
  })
168
171
  assert.equal(overrideShell.env.HF_HUB_DISABLE_UPDATE_CHECK, '0')
172
+ assert.equal(overrideShell.env.HF_TOKEN_PATH, path.join(root, 'custom', 'hf-token'))
169
173
  })
170
174
 
171
175
  test('Shell.init_env keeps Windows Hugging Face symlink defaults scoped to win32', async () => {
@@ -0,0 +1,29 @@
1
+ const assert = require('node:assert/strict')
2
+ const test = require('node:test')
3
+
4
+ const UV = require('../kernel/bin/uv')
5
+
6
+ function createUV(version) {
7
+ const uv = new UV()
8
+ uv.kernel = {
9
+ bin: {
10
+ installed: {
11
+ conda: new Set(version ? ['uv'] : []),
12
+ conda_versions: version ? { uv: version } : {},
13
+ },
14
+ },
15
+ }
16
+ return uv
17
+ }
18
+
19
+ test('UV bin pins uv to 0.11.23', () => {
20
+ assert.equal(createUV('0.11.23').cmd(), 'uv=0.11.23')
21
+ })
22
+
23
+ test('UV.installed accepts exactly uv 0.11.23', async () => {
24
+ assert.equal(await createUV('0.11.23').installed(), true)
25
+ assert.equal(await createUV('0.11.23-h1234567_0').installed(), true)
26
+ assert.equal(await createUV('0.11.22').installed(), false)
27
+ assert.equal(await createUV('0.12.0').installed(), false)
28
+ assert.equal(await createUV(null).installed(), false)
29
+ })