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.
- package/kernel/bin/brew.js +12 -2
- package/kernel/bin/caddy.js +24 -20
- package/kernel/bin/huggingface.js +2 -2
- package/kernel/bin/setup.js +2 -3
- package/kernel/bin/uv.js +13 -6
- package/kernel/connect/index.js +5 -1
- package/kernel/connect/providers/huggingface/index.js +213 -75
- package/kernel/environment.js +16 -1
- package/kernel/router/localhost_home_router.js +7 -0
- package/kernel/shell.js +1 -5
- package/kernel/util.js +1 -0
- package/package.json +1 -1
- package/server/index.js +75 -33
- package/server/public/common.js +52 -88
- package/server/public/install.js +20 -2
- package/server/public/layout.js +1 -1
- package/server/public/nav.js +3 -1
- package/server/public/style.css +1455 -521
- package/server/public/tab-link-popover.css +162 -18
- package/server/public/tab-link-popover.js +230 -21
- package/server/public/task-launcher.css +182 -91
- package/server/public/terminal-settings.js +227 -50
- package/server/public/universal-launcher.css +42 -33
- package/server/public/urldropdown.css +284 -0
- package/server/views/app.ejs +1718 -352
- package/server/views/autolaunch.ejs +4 -5
- package/server/views/checkpoints.ejs +223 -50
- package/server/views/connect/huggingface.ejs +406 -325
- package/server/views/connect.ejs +0 -1
- package/server/views/github.ejs +277 -324
- package/server/views/index.ejs +65 -8
- package/server/views/install.ejs +134 -65
- package/server/views/logs.ejs +9 -8
- package/server/views/net.ejs +341 -64
- package/server/views/network.ejs +85 -63
- package/server/views/partials/main_sidebar.ejs +249 -24
- package/server/views/plugins.ejs +141 -3
- package/server/views/settings.ejs +103 -7
- package/server/views/setup.ejs +0 -5
- package/server/views/skills.ejs +0 -1
- package/server/views/task_list.ejs +0 -1
- package/server/views/terminal.ejs +285 -60
- package/server/views/terminals.ejs +346 -6
- package/server/views/tools.ejs +828 -1691
- package/test/caddy-install.test.js +53 -0
- package/test/connect-setup.test.js +16 -0
- package/test/github-connection.test.js +1 -1
- package/test/huggingface-bin.test.js +4 -4
- package/test/huggingface-connect.test.js +73 -0
- package/test/main-sidebar.test.js +31 -0
- package/test/shell-run-template.test.js +5 -1
- 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 &&
|
|
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.
|
|
20
|
-
assert.equal(await createHuggingface('1.
|
|
21
|
-
assert.equal(await createHuggingface('1.
|
|
22
|
-
assert.equal(await createHuggingface('1.0
|
|
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
|
+
})
|