pinokiod 7.2.17 → 7.3.0

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 (78) hide show
  1. package/Dockerfile +2 -0
  2. package/kernel/api/index.js +1 -42
  3. package/kernel/api/process/index.js +44 -99
  4. package/kernel/bin/conda-python.js +30 -0
  5. package/kernel/bin/conda.js +22 -3
  6. package/kernel/bin/index.js +11 -1
  7. package/kernel/environment.js +2 -182
  8. package/kernel/git.js +13 -0
  9. package/kernel/index.js +1 -64
  10. package/kernel/plugin.js +58 -6
  11. package/kernel/shell.js +2 -21
  12. package/kernel/util.js +0 -60
  13. package/package.json +1 -1
  14. package/server/index.js +149 -176
  15. package/server/lib/content_validation.js +25 -28
  16. package/server/public/common.js +29 -103
  17. package/server/public/create-launcher.js +31 -4
  18. package/server/public/electron.css +6 -0
  19. package/server/public/style.css +0 -337
  20. package/server/public/task-launcher.js +32 -5
  21. package/server/public/universal-launcher.js +26 -3
  22. package/server/socket.js +11 -22
  23. package/server/views/app.ejs +30 -167
  24. package/server/views/d.ejs +33 -0
  25. package/server/views/editor.ejs +4 -25
  26. package/server/views/partials/main_sidebar.ejs +0 -1
  27. package/server/views/shell.ejs +3 -11
  28. package/server/views/terminal.ejs +3 -23
  29. package/server/views/terminals.ejs +0 -1
  30. package/spec/INSTRUCTION_SYNC.md +5 -5
  31. package/kernel/api/shell_run_template.js +0 -273
  32. package/kernel/api/uri/index.js +0 -51
  33. package/kernel/plugin_sources.js +0 -236
  34. package/kernel/watch/context.js +0 -42
  35. package/kernel/watch/drivers/fs.js +0 -71
  36. package/kernel/watch/drivers/poll.js +0 -33
  37. package/kernel/watch/index.js +0 -158
  38. package/server/features/drafts/index.js +0 -41
  39. package/server/features/drafts/parser.js +0 -169
  40. package/server/features/drafts/public/drafts.js +0 -1504
  41. package/server/features/drafts/registry_import.js +0 -412
  42. package/server/features/drafts/routes.js +0 -68
  43. package/server/features/drafts/service.js +0 -261
  44. package/server/features/drafts/watcher.js +0 -76
  45. package/server/features/index.js +0 -13
  46. package/server/lib/workspace_catalog.js +0 -151
  47. package/server/lib/workspace_runtime.js +0 -390
  48. package/server/routes/workspaces.js +0 -44
  49. package/server/views/partials/workspace_row.ejs +0 -61
  50. package/server/views/workspaces.ejs +0 -812
  51. package/system/plugin/antigravity/antigravity.png +0 -0
  52. package/system/plugin/antigravity/pinokio.js +0 -37
  53. package/system/plugin/claude/claude.png +0 -0
  54. package/system/plugin/claude/pinokio.js +0 -63
  55. package/system/plugin/claude-auto/claude.png +0 -0
  56. package/system/plugin/claude-auto/pinokio.js +0 -74
  57. package/system/plugin/claude-desktop/icon.jpeg +0 -0
  58. package/system/plugin/claude-desktop/pinokio.js +0 -39
  59. package/system/plugin/codex/openai.webp +0 -0
  60. package/system/plugin/codex/pinokio.js +0 -58
  61. package/system/plugin/codex-auto/openai.webp +0 -0
  62. package/system/plugin/codex-auto/pinokio.js +0 -65
  63. package/system/plugin/codex-desktop/icon.png +0 -0
  64. package/system/plugin/codex-desktop/pinokio.js +0 -39
  65. package/system/plugin/crush/crush.png +0 -0
  66. package/system/plugin/crush/pinokio.js +0 -31
  67. package/system/plugin/cursor/cursor.jpeg +0 -0
  68. package/system/plugin/cursor/pinokio.js +0 -39
  69. package/system/plugin/gemini/gemini.jpeg +0 -0
  70. package/system/plugin/gemini/pinokio.js +0 -40
  71. package/system/plugin/gemini-auto/gemini.jpeg +0 -0
  72. package/system/plugin/gemini-auto/pinokio.js +0 -43
  73. package/system/plugin/qwen/pinokio.js +0 -50
  74. package/system/plugin/qwen/qwen.png +0 -0
  75. package/system/plugin/vscode/pinokio.js +0 -36
  76. package/system/plugin/vscode/vscode.png +0 -0
  77. package/system/plugin/windsurf/pinokio.js +0 -39
  78. package/system/plugin/windsurf/windsurf.png +0 -0
@@ -1,390 +0,0 @@
1
- const path = require("path");
2
-
3
- function createWorkspaceRuntimeService({ kernel }) {
4
- if (!kernel) {
5
- throw new Error("kernel is required");
6
- }
7
-
8
- const normalizePathKey = (value) => {
9
- if (typeof value !== "string" || !value.trim()) {
10
- return "";
11
- }
12
- const resolved = path.resolve(value.trim());
13
- return process.platform === "win32" ? resolved.toLowerCase() : resolved;
14
- };
15
-
16
- const decodeMaybe = (value) => {
17
- const raw = typeof value === "string" ? value.trim() : "";
18
- if (!raw) {
19
- return "";
20
- }
21
- try {
22
- return decodeURIComponent(raw).trim();
23
- } catch (_) {
24
- return raw;
25
- }
26
- };
27
-
28
- const resolveCandidatePath = (value) => {
29
- const decoded = decodeMaybe(value);
30
- if (!decoded || decoded.includes("\0")) {
31
- return "";
32
- }
33
- if (decoded.startsWith("~/")) {
34
- return path.resolve(kernel.homedir, decoded.slice(2));
35
- }
36
- if (path.isAbsolute(decoded)) {
37
- return path.resolve(decoded);
38
- }
39
- return "";
40
- };
41
-
42
- const knownRoots = () => {
43
- const roots = [];
44
- const addRoot = (type, label) => {
45
- if (!kernel || typeof kernel.path !== "function") {
46
- return;
47
- }
48
- const rootPath = kernel.path(type);
49
- if (typeof rootPath === "string" && rootPath.trim()) {
50
- roots.push({
51
- type,
52
- label,
53
- path: path.resolve(rootPath)
54
- });
55
- }
56
- };
57
- addRoot("workspaces", "Workspace");
58
- addRoot("api", "App");
59
- addRoot("plugin", "Plugin");
60
- return roots;
61
- };
62
-
63
- const isPathWithin = (candidate, root) => {
64
- if (!candidate || !root) {
65
- return false;
66
- }
67
- const relative = path.relative(root, candidate);
68
- return Boolean(relative && !relative.startsWith("..") && !path.isAbsolute(relative));
69
- };
70
-
71
- const resolveWorkspaceForPath = (candidatePath) => {
72
- const candidate = resolveCandidatePath(candidatePath);
73
- if (!candidate) {
74
- return null;
75
- }
76
- for (const root of knownRoots()) {
77
- if (!isPathWithin(candidate, root.path)) {
78
- continue;
79
- }
80
- const relative = path.relative(root.path, candidate);
81
- const segments = relative.split(path.sep).filter(Boolean);
82
- const name = segments[0] || "";
83
- if (!name) {
84
- continue;
85
- }
86
- const cwd = path.resolve(root.path, name);
87
- return {
88
- key: normalizePathKey(cwd),
89
- cwd,
90
- name,
91
- root: root.type,
92
- rootLabel: root.label
93
- };
94
- }
95
- return null;
96
- };
97
-
98
- const parseParamsFromText = (value) => {
99
- const raw = typeof value === "string" ? value : "";
100
- const index = raw.indexOf("?");
101
- if (index < 0) {
102
- return null;
103
- }
104
- try {
105
- return new URLSearchParams(raw.slice(index + 1).replace(/&amp;/g, "&"));
106
- } catch (_) {
107
- return null;
108
- }
109
- };
110
-
111
- const firstWorkspaceFromCandidates = (candidates) => {
112
- for (const candidate of candidates) {
113
- const workspace = resolveWorkspaceForPath(candidate);
114
- if (workspace) {
115
- return workspace;
116
- }
117
- }
118
- return null;
119
- };
120
-
121
- const getShellCandidates = (shell) => {
122
- const candidates = [];
123
- if (!shell || typeof shell !== "object") {
124
- return candidates;
125
- }
126
- const push = (value) => {
127
- if (typeof value === "string" && value.trim()) {
128
- candidates.push(value);
129
- }
130
- };
131
- push(shell.path);
132
- push(shell.group);
133
- if (shell.params && typeof shell.params === "object") {
134
- push(shell.params.cwd);
135
- push(shell.params.path);
136
- if (shell.params.$parent && typeof shell.params.$parent === "object") {
137
- push(shell.params.$parent.cwd);
138
- push(shell.params.$parent.path);
139
- }
140
- }
141
- for (const text of [shell.id, shell.group]) {
142
- const params = parseParamsFromText(text);
143
- if (!params) {
144
- continue;
145
- }
146
- push(params.get("cwd"));
147
- push(params.get("path"));
148
- }
149
- return candidates;
150
- };
151
-
152
- const getScriptCandidates = (id) => {
153
- const candidates = [];
154
- const raw = typeof id === "string" ? id : "";
155
- if (!raw) {
156
- return candidates;
157
- }
158
- const params = parseParamsFromText(raw);
159
- if (params) {
160
- candidates.push(params.get("cwd"));
161
- candidates.push(params.get("path"));
162
- }
163
- const pathPart = raw.split("?")[0];
164
- candidates.push(pathPart);
165
- return candidates;
166
- };
167
-
168
- const parseTerminalIdFromText = (value) => {
169
- const params = parseParamsFromText(value);
170
- if (!params) {
171
- return "";
172
- }
173
- const terminalId = params.get("terminal_id");
174
- return typeof terminalId === "string" ? terminalId.trim() : "";
175
- };
176
-
177
- const buildShellUrl = (shell) => {
178
- const raw = shell && typeof shell.id === "string" ? shell.id.trim() : "";
179
- if (!raw) {
180
- return "";
181
- }
182
- const index = raw.indexOf("?");
183
- const base = index >= 0 ? raw.slice(0, index) : raw;
184
- const query = index >= 0 ? raw.slice(index + 1) : "";
185
- const params = new URLSearchParams(query);
186
- if (!params.has("path") && shell && typeof shell.path === "string" && shell.path.trim()) {
187
- params.set("path", shell.path.trim());
188
- }
189
- if (!params.has("terminal_id") && shell && typeof shell.terminal_id === "string" && shell.terminal_id.trim()) {
190
- params.set("terminal_id", shell.terminal_id.trim());
191
- }
192
- if (!params.has("input")) {
193
- params.set("input", "1");
194
- }
195
- const queryString = params.toString();
196
- let route = "";
197
- if (base.startsWith("/shell/")) {
198
- const shellId = base.slice("/shell/".length);
199
- route = shellId.includes("/")
200
- ? `/shell/${encodeURIComponent(shellId)}`
201
- : base;
202
- } else if (base.startsWith("shell/")) {
203
- route = `/shell/${encodeURIComponent(base.slice("shell/".length))}`;
204
- } else {
205
- route = `/shell/${encodeURIComponent(base)}`;
206
- }
207
- return queryString ? `${route}?${queryString}` : route;
208
- };
209
-
210
- const buildRunUrl = (id) => {
211
- const raw = typeof id === "string" ? id.trim() : "";
212
- if (!raw) {
213
- return "";
214
- }
215
- const index = raw.indexOf("?");
216
- const scriptPath = resolveCandidatePath(index >= 0 ? raw.slice(0, index) : raw);
217
- const query = index >= 0 ? raw.slice(index + 1) : "";
218
- if (!scriptPath) {
219
- return "";
220
- }
221
- const roots = [
222
- { name: "api", path: kernel.path("api") },
223
- { name: "plugin", path: kernel.path("plugin") },
224
- { name: "scripts", path: kernel.path("scripts") }
225
- ].filter((root) => typeof root.path === "string" && root.path.trim());
226
- for (const root of roots) {
227
- const rootPath = path.resolve(root.path);
228
- const relative = path.relative(rootPath, scriptPath);
229
- if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
230
- continue;
231
- }
232
- const params = new URLSearchParams(query);
233
- if (!params.has("chrome")) {
234
- params.set("chrome", "full");
235
- }
236
- const route = relative.split(path.sep).map(encodeURIComponent).join("/");
237
- const queryString = params.toString();
238
- return `/run/${root.name}/${route}${queryString ? `?${queryString}` : ""}`;
239
- }
240
- return "";
241
- };
242
-
243
- const shellTitle = (shell) => {
244
- if (shell && shell.params && typeof shell.params.$title === "string" && shell.params.$title.trim()) {
245
- return shell.params.$title.trim();
246
- }
247
- if (shell && typeof shell.cmd === "string" && shell.cmd.trim()) {
248
- return shell.cmd.trim().slice(0, 120);
249
- }
250
- return "Terminal";
251
- };
252
-
253
- const scriptTitle = (id) => {
254
- const raw = typeof id === "string" ? id.trim() : "";
255
- if (!raw) {
256
- return "Script";
257
- }
258
- const pathPart = raw.split("?")[0];
259
- if (pathPart && path.isAbsolute(pathPart)) {
260
- return path.basename(pathPart) || "Script";
261
- }
262
- return raw.slice(0, 120);
263
- };
264
-
265
- const createGroup = (workspace) => ({
266
- cwd: workspace.cwd,
267
- name: workspace.name,
268
- root: workspace.root,
269
- rootLabel: workspace.rootLabel,
270
- running: true,
271
- shells: [],
272
- scripts: []
273
- });
274
-
275
- const list = () => {
276
- const groups = new Map();
277
- const unscoped = {
278
- shells: [],
279
- scripts: []
280
- };
281
- const getGroup = (workspace) => {
282
- if (!workspace || !workspace.key) {
283
- return null;
284
- }
285
- if (!groups.has(workspace.key)) {
286
- groups.set(workspace.key, createGroup(workspace));
287
- }
288
- return groups.get(workspace.key);
289
- };
290
-
291
- const shells = kernel.shell && Array.isArray(kernel.shell.shells)
292
- ? kernel.shell.shells
293
- : [];
294
- for (const shell of shells) {
295
- if (!shell || shell.done === true || !shell.ptyProcess) {
296
- continue;
297
- }
298
- const item = {
299
- id: typeof shell.id === "string" ? shell.id : "",
300
- group: typeof shell.group === "string" ? shell.group : "",
301
- title: shellTitle(shell),
302
- cwd: typeof shell.path === "string" ? shell.path : "",
303
- state: shell.state || null,
304
- start_time: Number.isFinite(shell.start_time) ? shell.start_time : null,
305
- terminal_id: shell.terminal_id || parseTerminalIdFromText(shell.id) || parseTerminalIdFromText(shell.group) || null,
306
- url: buildRunUrl(shell.group) || buildShellUrl(shell)
307
- };
308
- const workspace = firstWorkspaceFromCandidates(getShellCandidates(shell));
309
- const group = getGroup(workspace);
310
- if (group) {
311
- group.shells.push(item);
312
- } else {
313
- unscoped.shells.push(item);
314
- }
315
- }
316
-
317
- const running = kernel.api && kernel.api.running && typeof kernel.api.running === "object"
318
- ? kernel.api.running
319
- : {};
320
- for (const id of Object.keys(running)) {
321
- if (typeof id !== "string" || !id || id.startsWith("shell/")) {
322
- continue;
323
- }
324
- const item = {
325
- id,
326
- title: scriptTitle(id),
327
- path: id.split("?")[0],
328
- cwd: "",
329
- url: buildRunUrl(id)
330
- };
331
- const workspace = firstWorkspaceFromCandidates(getScriptCandidates(id));
332
- if (workspace) {
333
- item.cwd = workspace.cwd;
334
- }
335
- const group = getGroup(workspace);
336
- if (group) {
337
- group.scripts.push(item);
338
- } else {
339
- unscoped.scripts.push(item);
340
- }
341
- }
342
-
343
- const workspaces = Array.from(groups.values())
344
- .map((workspace) => ({
345
- ...workspace,
346
- counts: {
347
- shells: workspace.shells.length,
348
- scripts: workspace.scripts.length
349
- }
350
- }))
351
- .sort((a, b) => {
352
- const totalA = a.counts.shells + a.counts.scripts;
353
- const totalB = b.counts.shells + b.counts.scripts;
354
- if (totalA !== totalB) {
355
- return totalB - totalA;
356
- }
357
- return String(a.name || "").localeCompare(String(b.name || ""));
358
- });
359
-
360
- return {
361
- workspaces,
362
- unscoped,
363
- counts: {
364
- workspaces: workspaces.length,
365
- shells: workspaces.reduce((total, workspace) => total + workspace.counts.shells, 0) + unscoped.shells.length,
366
- scripts: workspaces.reduce((total, workspace) => total + workspace.counts.scripts, 0) + unscoped.scripts.length
367
- }
368
- };
369
- };
370
-
371
- const summary = () => {
372
- const runtime = list();
373
- return {
374
- runningWorkspaces: runtime.counts.workspaces,
375
- runningShells: runtime.counts.shells,
376
- runningScripts: runtime.counts.scripts,
377
- unscopedShells: runtime.unscoped.shells.length,
378
- unscopedScripts: runtime.unscoped.scripts.length
379
- };
380
- };
381
-
382
- return {
383
- list,
384
- summary
385
- };
386
- }
387
-
388
- module.exports = {
389
- createWorkspaceRuntimeService
390
- };
@@ -1,44 +0,0 @@
1
- const express = require("express")
2
-
3
- function registerWorkspacesRoutes(app, options = {}) {
4
- const {
5
- workspaceCatalog,
6
- composePeerAccessPayload,
7
- getTheme,
8
- getPeers,
9
- getCurrentHost,
10
- getPortal,
11
- } = options
12
-
13
- if (!workspaceCatalog) {
14
- throw new Error("workspaceCatalog is required")
15
- }
16
-
17
- const router = express.Router()
18
-
19
- router.get("/workspaces", async (req, res, next) => {
20
- try {
21
- const catalog = await workspaceCatalog.list({ sort: req.query.sort })
22
- res.render("workspaces", {
23
- title: "Workspaces",
24
- sidebarSelected: "workspaces",
25
- workspaceCatalog: catalog,
26
- theme: getTheme ? getTheme(req) : null,
27
- peers: getPeers ? getPeers() : [],
28
- currentHost: getCurrentHost ? getCurrentHost(req) : null,
29
- portal: getPortal ? getPortal(req) : null,
30
- peerAccess: composePeerAccessPayload ? composePeerAccessPayload(req) : null,
31
- })
32
- } catch (err) {
33
- next(err)
34
- }
35
- })
36
-
37
- router.get("/activity", (req, res) => {
38
- res.redirect("/workspaces")
39
- })
40
-
41
- app.use(router)
42
- }
43
-
44
- module.exports = registerWorkspacesRoutes
@@ -1,61 +0,0 @@
1
- <%
2
- const shellCount = workspace.counts && Number.isFinite(workspace.counts.shells) ? workspace.counts.shells : 0;
3
- const scriptCount = workspace.counts && Number.isFinite(workspace.counts.scripts) ? workspace.counts.scripts : 0;
4
- const draftCount = workspace.counts && Number.isFinite(workspace.counts.drafts) ? workspace.counts.drafts : 0;
5
- const shellTitles = Array.isArray(workspace.shells) ? workspace.shells.map((shell) => shell.title || shell.id || "").join(" ") : "";
6
- const scriptTitles = Array.isArray(workspace.scripts) ? workspace.scripts.map((script) => script.title || script.id || "").join(" ") : "";
7
- const draft = workspace.draft || null;
8
- const draftId = draft && draft.id ? draft.id : `draft-${index}`;
9
- const searchText = [workspace.name, workspace.cwd, shellTitles, scriptTitles, draft && draft.title].filter(Boolean).join(" ");
10
- const modifiedLabel = dateLabel(workspace.modifiedAt);
11
- const details = [];
12
- if (shellCount > 0) details.push(plural(shellCount, "terminal"));
13
- if (scriptCount > 0) details.push(plural(scriptCount, "script"));
14
- if (draftCount > 0) details.push(draftCount === 1 ? "Draft ready" : plural(draftCount, "draft"));
15
- if (modifiedLabel) details.push(modifiedLabel);
16
- %>
17
- <div
18
- class="workspace-card workspace-line line align-top"
19
- data-cwd="<%= workspace.cwd %>"
20
- data-name="<%= workspace.name %>"
21
- data-index="<%= index %>"
22
- data-launch-count-total="<%= workspace.usageCount || 0 %>"
23
- data-last-launch-at="<%= workspace.lastOpenedAt || workspace.modifiedAt || "" %>"
24
- data-search="<%= searchText %>"
25
- >
26
- <h3>
27
- <div class="workspace-icon item-icon">
28
- <i class="fa-solid <%= workspace.running ? "fa-folder-open" : "fa-folder" %>" aria-hidden="true"></i>
29
- </div>
30
- <div class="col">
31
- <div class="title">
32
- <i class="fa-solid fa-circle" aria-hidden="true"></i>
33
- <span><%= workspace.name || "Workspace" %></span>
34
- </div>
35
- <div class="uri"><%= workspace.cwd %></div>
36
- <% if (details.length) { %>
37
- <div class="description"><%= details.join(" / ") %></div>
38
- <% } %>
39
- <div class="menu-btns">
40
- <% if (workspace.primaryUrl && shellCount === 1) { %>
41
- <a class="btn" href="<%= workspace.primaryUrl %>" title="Open terminal"><i class="fa-solid fa-terminal" aria-hidden="true"></i> Terminal</a>
42
- <% } else if (shellCount > 1) { %>
43
- <button class="btn" type="button" data-open-workspace="<%= workspace.cwd %>" data-workspace-modal-mode="terminals" title="Open terminals"><i class="fa-solid fa-terminal" aria-hidden="true"></i> Terminals</button>
44
- <% } %>
45
- <% if (workspace.launchUrl) { %>
46
- <button class="btn" type="button" data-open-workspace="<%= workspace.cwd %>" data-workspace-modal-mode="session" title="Start session"><i class="fa-solid fa-play" aria-hidden="true"></i> Start</button>
47
- <% } %>
48
- <button class="btn" type="button" data-open-path="<%= workspace.cwd %>" title="Open folder"><i class="fa-solid fa-folder-open" aria-hidden="true"></i> Folder</button>
49
- <% if (draft && draft.postPath) { %>
50
- <button class="btn" type="button" data-open-path="<%= draft.postPath %>" title="Open draft"><i class="fa-solid fa-file-lines" aria-hidden="true"></i> Draft</button>
51
- <% if (draft.excerpt) { %>
52
- <button class="btn" type="button" data-preview-toggle="<%= draftId %>"><i class="fa-solid fa-eye" aria-hidden="true"></i> Preview</button>
53
- <% } %>
54
- <% } %>
55
- </div>
56
- <% if (draft && draft.excerpt) { %>
57
- <div class="workspace-draft-preview" data-preview-panel="<%= draftId %>" hidden><%= draft.excerpt %></div>
58
- <% } %>
59
- </div>
60
- </h3>
61
- </div>