pinokiod 7.3.6 → 7.3.9

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 (39) hide show
  1. package/kernel/api/index.js +3 -2
  2. package/kernel/api/script/index.js +1 -0
  3. package/kernel/resource_usage/gpu.js +1 -1
  4. package/package.json +1 -1
  5. package/server/index.js +11 -2
  6. package/server/public/nav.js +1 -1
  7. package/server/public/style.css +298 -191
  8. package/server/public/task-launcher.css +16 -20
  9. package/server/public/terminal-settings.js +1 -19
  10. package/server/public/universal-launcher.css +0 -113
  11. package/server/public/universal-launcher.js +1 -1
  12. package/server/views/app.ejs +592 -298
  13. package/server/views/autolaunch.ejs +1 -1
  14. package/server/views/checkpoints.ejs +2 -6
  15. package/server/views/connect.ejs +1 -1
  16. package/server/views/explore.ejs +2 -1
  17. package/server/views/index.ejs +89 -60
  18. package/server/views/install.ejs +1 -0
  19. package/server/views/invalid_content.ejs +1 -1
  20. package/server/views/layout.ejs +7 -2
  21. package/server/views/logs.ejs +5 -27
  22. package/server/views/net.ejs +1 -1
  23. package/server/views/network.ejs +1 -1
  24. package/server/views/partials/fs_status.ejs +0 -8
  25. package/server/views/partials/main_sidebar.ejs +108 -44
  26. package/server/views/plugin_detail.ejs +1 -1
  27. package/server/views/plugins.ejs +1 -28
  28. package/server/views/screenshots.ejs +1 -1
  29. package/server/views/settings.ejs +2 -1
  30. package/server/views/setup.ejs +15 -1
  31. package/server/views/skills.ejs +1 -1
  32. package/server/views/task_builder.ejs +1 -1
  33. package/server/views/task_install.ejs +1 -1
  34. package/server/views/task_launch.ejs +1 -1
  35. package/server/views/task_list.ejs +1 -1
  36. package/server/views/terminal.ejs +0 -3
  37. package/server/views/tools.ejs +1 -1
  38. package/test/resource-usage-gpu.test.js +23 -0
  39. package/test/script-api.test.js +90 -0
@@ -16,7 +16,7 @@
16
16
  <% } %>
17
17
  <script src="/plugin-detail.js" defer></script>
18
18
  </head>
19
- <body class="<%= theme %> task-launcher-page task-page plugin-page plugin-detail-page" data-agent="<%= agent %>">
19
+ <body class="<%= theme %> main-sidebar-page task-launcher-page task-page plugin-page plugin-detail-page" data-agent="<%= agent %>">
20
20
  <% const currentPluginCwd = typeof pluginCwd === "string" ? pluginCwd : ""; %>
21
21
  <%- include('partials/app_navheader', { agent }) %>
22
22
  <main>
@@ -17,33 +17,6 @@
17
17
  <link href="/electron.css" rel="stylesheet"/>
18
18
  <% } %>
19
19
  <style>
20
- body.plugin-page main {
21
- display: flex;
22
- }
23
- body.plugin-page aside {
24
- width: 200px;
25
- display: block;
26
- flex-shrink: 0;
27
- }
28
- body.plugin-page aside .tab {
29
- display: flex;
30
- align-items: center;
31
- gap: 5px;
32
- color: inherit;
33
- text-decoration: none;
34
- padding: 10px;
35
- font-size: 12px;
36
- opacity: 0.5;
37
- border-left: 10px solid transparent;
38
- transition: color 0.2s ease, opacity 0.2s ease;
39
- }
40
- body.plugin-page aside .tab.selected {
41
- font-weight: 600;
42
- opacity: 1;
43
- }
44
- body.plugin-page aside .tab i {
45
- text-align: center;
46
- }
47
20
  body.plugin-page .plugin-container {
48
21
  box-sizing: border-box;
49
22
  }
@@ -747,7 +720,7 @@ body.plugin-page .plugin-card .disclosure-indicator {
747
720
  }
748
721
  </style>
749
722
  </head>
750
- <body class='<%=theme%> task-launcher-page task-page plugin-page' data-agent="<%=agent%>">
723
+ <body class='<%=theme%> main-sidebar-page task-launcher-page task-page plugin-page' data-agent="<%=agent%>">
751
724
  <%- include('partials/app_navheader', { agent }) %>
752
725
  <main class='plugin-main'>
753
726
  <div class='task-container plugin-container'>
@@ -861,7 +861,7 @@ document.addEventListener('DOMContentLoaded', function() {
861
861
  </script>
862
862
  <script src="/report.js"></script>
863
863
  </head>
864
- <body class='<%=theme%> task-launcher-page task-page screenshots-page' data-agent="<%=agent%>">
864
+ <body class='<%=theme%> main-sidebar-page task-launcher-page task-page screenshots-page' data-agent="<%=agent%>">
865
865
  <!--
866
866
  <nav>
867
867
  <a class='logo' href="/home">dal</a>
@@ -902,7 +902,7 @@ document.addEventListener('DOMContentLoaded', function() {
902
902
  </script>
903
903
  <script src="/report.js"></script>
904
904
  </head>
905
- <body class='<%=theme%> task-launcher-page task-page settings-page <%= hasHome ? "has-home" : "needs-home-setup" %>' data-agent="<%=agent%>">
905
+ <body class='<%=theme%> main-sidebar-page task-launcher-page task-page settings-page <%= hasHome ? "has-home" : "needs-home-setup" %>' data-agent="<%=agent%>">
906
906
  <!--
907
907
  <nav>
908
908
  <a class='logo' href="/home">dal</a>
@@ -1163,6 +1163,7 @@ document.addEventListener('DOMContentLoaded', function() {
1163
1163
  </div>
1164
1164
  </section>
1165
1165
  </div>
1166
+ <%- include('partials/main_sidebar', { selected: 'settings' }) %>
1166
1167
  </main>
1167
1168
  <script>
1168
1169
  document.addEventListener("DOMContentLoaded", async () => {
@@ -28,8 +28,21 @@
28
28
  const readyDescription = install_required
29
29
  ? "Install or refresh what Pinokio needs before reopening this destination."
30
30
  : "Everything Pinokio needs is already available. Continue to reopen this destination.";
31
+ const setupSidebarSelected = (() => {
32
+ if (setupMode === "network" || targetPath.indexOf("/network") === 0) return "network";
33
+ if (setupMode === "connect" || targetPath.indexOf("/connect") === 0 || targetPath.indexOf("/github") === 0) return "connect";
34
+ if (targetPath.indexOf("/tools") === 0) return "tools";
35
+ if (targetPath.indexOf("/plugins") === 0) return "plugins";
36
+ if (targetPath.indexOf("/tasks") === 0) return "tasks";
37
+ if (targetPath.indexOf("/skills") === 0) return "skills";
38
+ if (targetPath.indexOf("/logs") === 0) return "logs";
39
+ if (targetPath.indexOf("/autolaunch") === 0) return "autolaunch";
40
+ if (targetPath.indexOf("/home?mode=settings") === 0) return "settings";
41
+ if (targetPath.indexOf("/home") === 0) return "home";
42
+ return "";
43
+ })();
31
44
  %>
32
- <body class="<%= theme %> task-launcher-page task-page setup-page" data-agent="<%= agent %>">
45
+ <body class="<%= theme %> main-sidebar-page task-launcher-page task-page setup-page" data-agent="<%= agent %>">
33
46
  <%- include('partials/app_navheader', { agent }) %>
34
47
  <main>
35
48
  <div class="task-container">
@@ -188,6 +201,7 @@
188
201
  </div>
189
202
  </section>
190
203
  </div>
204
+ <%- include('partials/main_sidebar', { selected: setupSidebarSelected }) %>
191
205
  </main>
192
206
 
193
207
  <script>
@@ -322,7 +322,7 @@
322
322
  };
323
323
  const targetClass = (status) => status === "conflict" ? "conflict" : "";
324
324
  %>
325
- <body class="<%= theme %> task-launcher-page task-page skills-page" data-agent="<%= agent %>">
325
+ <body class="<%= theme %> main-sidebar-page task-launcher-page task-page skills-page" data-agent="<%= agent %>">
326
326
  <%- include('partials/app_navheader', { agent }) %>
327
327
  <main>
328
328
  <div class="task-container">
@@ -18,7 +18,7 @@
18
18
  <%
19
19
  const displayTarget = defaults.target || 'workspaces'
20
20
  %>
21
- <body class="<%= theme %> task-launcher-page task-page task-builder-page" data-agent="<%= agent %>">
21
+ <body class="<%= theme %> main-sidebar-page task-launcher-page task-page task-builder-page" data-agent="<%= agent %>">
22
22
  <%- include('partials/app_navheader', { agent }) %>
23
23
  <main>
24
24
  <div class="task-container">
@@ -15,7 +15,7 @@
15
15
  <% } %>
16
16
  <script src="/task-launcher.js" defer></script>
17
17
  </head>
18
- <body class="<%= theme %> task-launcher-page task-page task-install-page" data-agent="<%= agent %>">
18
+ <body class="<%= theme %> main-sidebar-page task-launcher-page task-page task-install-page" data-agent="<%= agent %>">
19
19
  <%- include('partials/app_navheader', { agent }) %>
20
20
  <main>
21
21
  <div class="task-container">
@@ -32,7 +32,7 @@
32
32
  ? task.config.description
33
33
  : ''
34
34
  %>
35
- <body class="<%= theme %> task-launcher-page task-page task-detail-page" data-agent="<%= agent %>">
35
+ <body class="<%= theme %> main-sidebar-page task-launcher-page task-page task-detail-page" data-agent="<%= agent %>">
36
36
  <%- include('partials/app_navheader', { agent }) %>
37
37
  <main>
38
38
  <div class="task-container">
@@ -20,7 +20,7 @@
20
20
  return value
21
21
  }
22
22
  %>
23
- <body class="<%= theme %> task-launcher-page task-page task-library-page" data-agent="<%= agent %>">
23
+ <body class="<%= theme %> main-sidebar-page task-launcher-page task-page task-library-page" data-agent="<%= agent %>">
24
24
  <%- include('partials/app_navheader', { agent }) %>
25
25
  <main>
26
26
  <div class="task-container">
@@ -2985,9 +2985,6 @@ const reloadMemory = async () => {
2985
2985
  <span class='starting hidden'><i class="fa-solid fa-circle-notch fa-spin"></i> Starting...</span>
2986
2986
  <span class='stop hidden'><i class="fa-solid fa-stop"></i> Stop</span>
2987
2987
  </div>
2988
- <% if (locals.filepath) { %>
2989
- <button class='btn' id='open-fs' data-filepath="<%=filepath%>" data-command="view"><i class="fa-solid fa-folder-open"></i> File Explorer</button>
2990
- <% } %>
2991
2988
  <% if (locals.protection_app_id) { %>
2992
2989
  <button
2993
2990
  type='button'
@@ -1361,7 +1361,7 @@ document.addEventListener('DOMContentLoaded', function() {
1361
1361
  </script>
1362
1362
  <script src="/report.js"></script>
1363
1363
  </head>
1364
- <body class='<%=theme%> task-launcher-page task-page tools-page' data-agent="<%=agent%>">
1364
+ <body class='<%=theme%> main-sidebar-page task-launcher-page task-page tools-page' data-agent="<%=agent%>">
1365
1365
  <!--
1366
1366
  <nav>
1367
1367
  <a class='logo' href="/home">dal</a>
@@ -7,6 +7,7 @@ const test = require("node:test")
7
7
  const {
8
8
  GpuSampler,
9
9
  NvmlGpuMemoryClient,
10
+ WindowsPdhGpuMemoryClient,
10
11
  collectLinuxDrmFdinfoProcesses,
11
12
  decodeWindowsMultiSz,
12
13
  extractPidFromWindowsGpuInstance,
@@ -36,6 +37,28 @@ test("decodeWindowsMultiSz decodes double-null UTF-16 string lists", () => {
36
37
  assert.deepEqual(decodeWindowsMultiSz(buffer, text.length), ["one", "two"])
37
38
  })
38
39
 
40
+ test("Windows PDH binds formatted counter value with exported symbol name", () => {
41
+ const signatures = []
42
+ const fakeKoffi = {
43
+ struct: (name, fields) => ({ name, fields }),
44
+ load: (library) => {
45
+ assert.equal(library, "pdh.dll")
46
+ return {
47
+ func: (signature) => {
48
+ signatures.push(signature)
49
+ return () => 0
50
+ }
51
+ }
52
+ }
53
+ }
54
+
55
+ const client = new WindowsPdhGpuMemoryClient({ koffi: fakeKoffi })
56
+ client.init()
57
+
58
+ assert(signatures.some((signature) => signature.includes("PdhGetFormattedCounterValue(")))
59
+ assert(!signatures.some((signature) => signature.includes("PdhGetFormattedCounterValueW(")))
60
+ })
61
+
39
62
  test("parseLinuxDrmFdinfo counts dedicated DRM memory regions only", () => {
40
63
  const amdgpu = parseLinuxDrmFdinfo([
41
64
  "drm-driver:\tamdgpu",
@@ -1,7 +1,10 @@
1
1
  const assert = require('node:assert/strict')
2
+ const fs = require('node:fs')
3
+ const os = require('node:os')
2
4
  const path = require('node:path')
3
5
  const test = require('node:test')
4
6
 
7
+ const Api = require('../kernel/api')
5
8
  const Script = require('../kernel/api/script')
6
9
 
7
10
  test('script.restart stops explicit target and schedules start with explicit params', async () => {
@@ -95,3 +98,90 @@ test('script.restart self restart preserves session id and parent args', async (
95
98
  params: { prompt: 'again' }
96
99
  })
97
100
  })
101
+
102
+ test('script.run refreshes git mapping before resolving remote dependency uri', async () => {
103
+ const script = new Script()
104
+ const calls = []
105
+ let initialized = false
106
+ const remoteUri = 'https://github.com/example/dependency.pinokio.git/start.js'
107
+ const resolvedPath = '/pinokio/api/github_com_example_dependency_pinokio_git/start.js'
108
+ const kernel = {
109
+ path: (...parts) => path.join('/pinokio', ...parts),
110
+ bin: {
111
+ sh: async () => {
112
+ throw new Error('should not clone when init maps existing dependency')
113
+ }
114
+ },
115
+ api: {
116
+ userdir: '/pinokio/api',
117
+ running: {},
118
+ init: async () => {
119
+ calls.push('init')
120
+ initialized = true
121
+ },
122
+ filePath: (uri) => {
123
+ calls.push('filePath')
124
+ assert.equal(initialized, true)
125
+ assert.equal(uri, remoteUri)
126
+ return resolvedPath
127
+ },
128
+ resolveGitURI: (uri) => {
129
+ calls.push('resolveGitURI')
130
+ assert.equal(initialized, true)
131
+ assert.equal(uri, remoteUri)
132
+ return resolvedPath
133
+ },
134
+ getGitURI: () => 'https://github.com/example/dependency.pinokio.git',
135
+ process: (request, done) => {
136
+ calls.push('process')
137
+ assert.equal(request.uri, remoteUri)
138
+ done({ input: { ok: true } })
139
+ }
140
+ }
141
+ }
142
+
143
+ const result = await script.run({
144
+ params: {
145
+ uri: remoteUri,
146
+ params: { prompt: 'go' }
147
+ }
148
+ }, () => {}, kernel)
149
+
150
+ assert.deepEqual(result, { ok: true })
151
+ assert.deepEqual(calls, ['init', 'filePath', 'resolveGitURI', 'init', 'process'])
152
+ })
153
+
154
+ test('api.linkGit keeps previous git mapping until refresh completes', async () => {
155
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'pinokio-linkgit-'))
156
+ const userdir = path.join(root, 'api')
157
+ const repo = path.join(userdir, 'demo')
158
+ fs.mkdirSync(path.join(repo, '.git'), { recursive: true })
159
+ fs.writeFileSync(path.join(repo, '.git', 'config'), [
160
+ '[remote "origin"]',
161
+ '\turl = https://github.com/example/demo.git',
162
+ '\tfetch = +refs/heads/*:refs/remotes/origin/*',
163
+ ''
164
+ ].join('\n'))
165
+
166
+ try {
167
+ const api = new Api({
168
+ homedir: root,
169
+ path: (...parts) => path.join(root, ...parts)
170
+ })
171
+ api.userdir = userdir
172
+ api.gitPath = {
173
+ 'https://github.com/example/old.git': path.join(userdir, 'old')
174
+ }
175
+
176
+ const refresh = api.linkGit()
177
+ assert.deepEqual(api.gitPath, {
178
+ 'https://github.com/example/old.git': path.join(userdir, 'old')
179
+ })
180
+ await refresh
181
+ assert.deepEqual(api.gitPath, {
182
+ 'https://github.com/example/demo.git': repo
183
+ })
184
+ } finally {
185
+ fs.rmSync(root, { recursive: true, force: true })
186
+ }
187
+ })