pinokiod 7.2.18 → 7.3.1

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 (89) hide show
  1. package/Dockerfile +2 -0
  2. package/kernel/api/index.js +13 -179
  3. package/kernel/api/process/index.js +44 -99
  4. package/kernel/bin/conda-pins.js +53 -0
  5. package/kernel/bin/conda.js +35 -6
  6. package/kernel/bin/huggingface.js +1 -1
  7. package/kernel/bin/index.js +15 -2
  8. package/kernel/environment.js +11 -205
  9. package/kernel/git.js +13 -0
  10. package/kernel/index.js +1 -64
  11. package/kernel/plugin.js +58 -6
  12. package/kernel/prototype.js +0 -4
  13. package/kernel/shell.js +2 -23
  14. package/kernel/util.js +0 -60
  15. package/package.json +1 -1
  16. package/server/index.js +171 -229
  17. package/server/lib/content_validation.js +33 -47
  18. package/server/public/common.js +29 -103
  19. package/server/public/create-launcher.js +31 -4
  20. package/server/public/electron.css +6 -0
  21. package/server/public/style.css +0 -337
  22. package/server/public/task-launcher.css +3 -11
  23. package/server/public/task-launcher.js +32 -5
  24. package/server/public/universal-launcher.js +26 -3
  25. package/server/socket.js +11 -22
  26. package/server/views/app.ejs +30 -167
  27. package/server/views/d.ejs +35 -33
  28. package/server/views/editor.ejs +4 -25
  29. package/server/views/partials/main_sidebar.ejs +0 -1
  30. package/server/views/partials/menu.ejs +1 -1
  31. package/server/views/pre.ejs +1 -1
  32. package/server/views/shell.ejs +3 -11
  33. package/server/views/task_launch.ejs +10 -10
  34. package/server/views/terminal.ejs +5 -34
  35. package/spec/INSTRUCTION_SYNC.md +5 -5
  36. package/kernel/agent_instructions.js +0 -166
  37. package/kernel/api/shell_run_template.js +0 -273
  38. package/kernel/api/uri/index.js +0 -51
  39. package/kernel/plugin_sources.js +0 -289
  40. package/kernel/watch/context.js +0 -42
  41. package/kernel/watch/drivers/fs.js +0 -71
  42. package/kernel/watch/drivers/poll.js +0 -33
  43. package/kernel/watch/index.js +0 -185
  44. package/server/features/index.js +0 -13
  45. package/server/features/notes/index.js +0 -41
  46. package/server/features/notes/parser.js +0 -174
  47. package/server/features/notes/public/notes.css +0 -955
  48. package/server/features/notes/public/notes.js +0 -1149
  49. package/server/features/notes/registry_import.js +0 -412
  50. package/server/features/notes/routes.js +0 -156
  51. package/server/features/notes/service.js +0 -326
  52. package/server/features/notes/watcher.js +0 -74
  53. package/server/lib/workspace_catalog.js +0 -151
  54. package/server/lib/workspace_runtime.js +0 -390
  55. package/server/public/tasker.css +0 -336
  56. package/server/public/tasker.js +0 -407
  57. package/server/routes/workspaces.js +0 -44
  58. package/server/views/partials/workspace_row.ejs +0 -61
  59. package/server/views/tasker.ejs +0 -40
  60. package/server/views/workspaces.ejs +0 -813
  61. package/system/plugin/antigravity/antigravity.png +0 -0
  62. package/system/plugin/antigravity/pinokio.js +0 -35
  63. package/system/plugin/claude/claude.png +0 -0
  64. package/system/plugin/claude/pinokio.js +0 -61
  65. package/system/plugin/claude-auto/claude.png +0 -0
  66. package/system/plugin/claude-auto/pinokio.js +0 -72
  67. package/system/plugin/claude-desktop/icon.jpeg +0 -0
  68. package/system/plugin/claude-desktop/pinokio.js +0 -37
  69. package/system/plugin/codex/openai.webp +0 -0
  70. package/system/plugin/codex/pinokio.js +0 -56
  71. package/system/plugin/codex-auto/openai.webp +0 -0
  72. package/system/plugin/codex-auto/pinokio.js +0 -63
  73. package/system/plugin/codex-desktop/icon.png +0 -0
  74. package/system/plugin/codex-desktop/pinokio.js +0 -37
  75. package/system/plugin/crush/crush.png +0 -0
  76. package/system/plugin/crush/pinokio.js +0 -29
  77. package/system/plugin/cursor/cursor.jpeg +0 -0
  78. package/system/plugin/cursor/pinokio.js +0 -37
  79. package/system/plugin/gemini/gemini.jpeg +0 -0
  80. package/system/plugin/gemini/pinokio.js +0 -38
  81. package/system/plugin/gemini-auto/gemini.jpeg +0 -0
  82. package/system/plugin/gemini-auto/pinokio.js +0 -41
  83. package/system/plugin/qwen/pinokio.js +0 -48
  84. package/system/plugin/qwen/qwen.png +0 -0
  85. package/system/plugin/vscode/pinokio.js +0 -34
  86. package/system/plugin/vscode/vscode.png +0 -0
  87. package/system/plugin/windsurf/pinokio.js +0 -37
  88. package/system/plugin/windsurf/windsurf.png +0 -0
  89. package/test/plugin-sources.test.js +0 -45
@@ -1,407 +0,0 @@
1
- (function(window, document) {
2
- "use strict";
3
-
4
- const VARIABLE_FILTER_KEYS = new Set([
5
- "var",
6
- "vars",
7
- "variable",
8
- "variables",
9
- "require",
10
- "requires"
11
- ]);
12
- const PASSTHROUGH_KEYS = new Set([
13
- "tool",
14
- "folderName"
15
- ]);
16
- const TASK_INPUT_NAME_PATTERN = /^[a-zA-Z0-9_][a-zA-Z0-9_.-]*$/;
17
-
18
- function normalizeText(value) {
19
- return String(value || "").replace(/\s+/g, " ").trim();
20
- }
21
-
22
- function normalizeTaskInputName(value) {
23
- const normalized = String(value || "").trim();
24
- return TASK_INPUT_NAME_PATTERN.test(normalized) ? normalized : "";
25
- }
26
-
27
- function splitVariableList(value) {
28
- return String(value || "")
29
- .split(/[,\s]+/)
30
- .map(normalizeTaskInputName)
31
- .filter(Boolean);
32
- }
33
-
34
- function getRequiredVariables(params) {
35
- const variables = new Set();
36
- VARIABLE_FILTER_KEYS.forEach((key) => {
37
- params.getAll(key).forEach((value) => {
38
- splitVariableList(value).forEach((name) => variables.add(name));
39
- });
40
- });
41
- return Array.from(variables);
42
- }
43
-
44
- function getInitialSearchQuery(params) {
45
- return (params.get("q") || params.get("search") || "").trim();
46
- }
47
-
48
- function getTemplateVariableNames(template) {
49
- const names = new Set();
50
- const regex = /{{\s*([a-zA-Z0-9_][a-zA-Z0-9_.-]*)\s*}}/g;
51
- let match;
52
- while ((match = regex.exec(String(template || ""))) !== null) {
53
- names.add(match[1]);
54
- }
55
- return Array.from(names);
56
- }
57
-
58
- function getTaskVariableSet(task) {
59
- const names = new Set();
60
- const inputs = Array.isArray(task && task.inputs) ? task.inputs : [];
61
- inputs.forEach((input) => {
62
- const name = normalizeTaskInputName(input && input.name);
63
- if (name) {
64
- names.add(name);
65
- }
66
- });
67
- getTemplateVariableNames(task && task.template).forEach((name) => {
68
- names.add(name);
69
- });
70
- return names;
71
- }
72
-
73
- function taskMatchesRequiredVariables(task, requiredVariables) {
74
- if (!requiredVariables.length) {
75
- return true;
76
- }
77
- const taskVariables = getTaskVariableSet(task);
78
- return requiredVariables.every((name) => taskVariables.has(name));
79
- }
80
-
81
- function formatTaskTemplateSummary(task) {
82
- const preview = normalizeText((task && (task.template || task.description)) || "");
83
- if (!preview) {
84
- return "Task";
85
- }
86
- return preview.length > 150 ? `${preview.slice(0, 147).trimEnd()}...` : preview;
87
- }
88
-
89
- function formatRecentUsage(value) {
90
- const timestamp = Date.parse(typeof value === "string" ? value : "");
91
- if (!Number.isFinite(timestamp)) {
92
- return "";
93
- }
94
- const diffMs = Math.max(0, Date.now() - timestamp);
95
- const dayMs = 24 * 60 * 60 * 1000;
96
- const diffDays = Math.floor(diffMs / dayMs);
97
- if (diffDays === 0) return "Used today";
98
- if (diffDays === 1) return "Used yesterday";
99
- if (diffDays < 7) return `Used ${diffDays}d ago`;
100
- if (diffDays < 30) return `Used ${Math.floor(diffDays / 7)}w ago`;
101
- if (diffDays < 365) return `Used ${Math.floor(diffDays / 30)}mo ago`;
102
- return `Used ${Math.floor(diffDays / 365)}y ago`;
103
- }
104
-
105
- function getTaskHref(task, params) {
106
- const id = task && typeof task.id === "string" ? task.id.trim() : "";
107
- if (!id) {
108
- return "/tasks";
109
- }
110
-
111
- const taskVariables = getTaskVariableSet(task);
112
- const url = new URL("/task", window.location.origin);
113
- url.searchParams.set("id", id);
114
-
115
- params.forEach((value, key) => {
116
- if (key.startsWith("input.")) {
117
- const inputName = normalizeTaskInputName(key.slice("input.".length));
118
- if (inputName && taskVariables.has(inputName)) {
119
- url.searchParams.set(`input.${inputName}`, value);
120
- }
121
- return;
122
- }
123
- if (PASSTHROUGH_KEYS.has(key) && value) {
124
- url.searchParams.set(key, value);
125
- }
126
- });
127
-
128
- return `${url.pathname}${url.search}`;
129
- }
130
-
131
- function getSearchText(task) {
132
- const inputs = Array.isArray(task && task.inputs) ? task.inputs : [];
133
- return [
134
- task && task.id,
135
- task && task.ref,
136
- task && task.title,
137
- task && task.description,
138
- task && task.template,
139
- task && task.path,
140
- task && task.target,
141
- ...inputs.flatMap((input) => [
142
- input && input.name,
143
- input && input.label
144
- ])
145
- ].filter(Boolean).join(" ").toLowerCase();
146
- }
147
-
148
- function createTaskRow(task, params) {
149
- const row = document.createElement("a");
150
- row.className = "tasker-row";
151
- row.href = getTaskHref(task, params);
152
- row.tabIndex = -1;
153
-
154
- const icon = document.createElement("span");
155
- icon.className = "tasker-row-icon";
156
- icon.setAttribute("aria-hidden", "true");
157
- const iconGlyph = document.createElement("i");
158
- iconGlyph.className = "fa-solid fa-bookmark";
159
- icon.appendChild(iconGlyph);
160
- row.appendChild(icon);
161
-
162
- const copy = document.createElement("span");
163
- copy.className = "tasker-row-copy";
164
-
165
- const label = document.createElement("span");
166
- label.className = "tasker-row-label";
167
- label.textContent = (task && (task.title || task.id)) || "Untitled task";
168
- copy.appendChild(label);
169
-
170
- const meta = document.createElement("span");
171
- meta.className = "tasker-row-meta";
172
- const metaBits = [formatTaskTemplateSummary(task)];
173
- const inputs = Array.isArray(task && task.inputs) ? task.inputs : [];
174
- if (inputs.length > 0) {
175
- metaBits.push(`${inputs.length} input${inputs.length === 1 ? "" : "s"}`);
176
- }
177
- const usage = formatRecentUsage(task && task.last_used_at);
178
- if (usage) {
179
- metaBits.push(usage);
180
- }
181
- meta.textContent = metaBits.filter(Boolean).join(" - ");
182
- copy.appendChild(meta);
183
-
184
- row.appendChild(copy);
185
-
186
- const hint = document.createElement("span");
187
- hint.className = "tasker-row-hint";
188
- hint.setAttribute("aria-hidden", "true");
189
- const hintGlyph = document.createElement("i");
190
- hintGlyph.className = "fa-solid fa-chevron-right";
191
- hint.appendChild(hintGlyph);
192
- row.appendChild(hint);
193
-
194
- return row;
195
- }
196
-
197
- function initTasker() {
198
- const root = document.querySelector("[data-tasker]");
199
- if (!root) {
200
- return;
201
- }
202
-
203
- const searchInput = root.querySelector("[data-tasker-search]");
204
- const clearButton = root.querySelector("[data-tasker-clear]");
205
- const status = root.querySelector("[data-tasker-status]");
206
- const list = root.querySelector("[data-tasker-list]");
207
- const empty = root.querySelector("[data-tasker-empty]");
208
- const params = new URLSearchParams(window.location.search);
209
- const requiredVariables = getRequiredVariables(params);
210
- const initialSearchQuery = getInitialSearchQuery(params);
211
- let tasks = [];
212
- let sourceTaskCount = 0;
213
- let visibleTasks = [];
214
- let selectedIndex = -1;
215
- let loading = true;
216
- let error = "";
217
-
218
- if (searchInput && initialSearchQuery) {
219
- searchInput.value = initialSearchQuery;
220
- }
221
-
222
- function syncSelectedRow() {
223
- if (!list) {
224
- return;
225
- }
226
- const rows = Array.from(list.querySelectorAll(".tasker-row"));
227
- rows.forEach((row, index) => {
228
- const selected = index === selectedIndex;
229
- row.classList.toggle("selected", selected);
230
- row.setAttribute("aria-selected", selected ? "true" : "false");
231
- if (selected) {
232
- row.scrollIntoView({
233
- block: "nearest"
234
- });
235
- }
236
- });
237
- }
238
-
239
- function selectResult(index) {
240
- if (!visibleTasks.length) {
241
- selectedIndex = -1;
242
- syncSelectedRow();
243
- return;
244
- }
245
- const max = visibleTasks.length - 1;
246
- selectedIndex = Math.max(0, Math.min(index, max));
247
- syncSelectedRow();
248
- }
249
-
250
- function moveSelection(delta) {
251
- if (!visibleTasks.length) {
252
- return;
253
- }
254
- if (selectedIndex < 0) {
255
- selectResult(delta > 0 ? 0 : visibleTasks.length - 1);
256
- return;
257
- }
258
- const nextIndex = (selectedIndex + delta + visibleTasks.length) % visibleTasks.length;
259
- selectResult(nextIndex);
260
- }
261
-
262
- function openSelectedResult() {
263
- if (!visibleTasks.length || selectedIndex < 0) {
264
- return;
265
- }
266
- const row = list ? list.querySelectorAll(".tasker-row")[selectedIndex] : null;
267
- const href = row ? row.getAttribute("href") : "";
268
- if (href) {
269
- window.location.href = href;
270
- }
271
- }
272
-
273
- function setStatus(copy) {
274
- if (status) {
275
- status.textContent = copy || "";
276
- status.hidden = !copy;
277
- }
278
- }
279
-
280
- function render() {
281
- if (!list || !empty || !searchInput) {
282
- return;
283
- }
284
-
285
- const query = searchInput.value.trim().toLowerCase();
286
- visibleTasks = query
287
- ? tasks.filter((task) => getSearchText(task).includes(query))
288
- : tasks.slice();
289
- if (visibleTasks.length) {
290
- selectedIndex = selectedIndex < 0 ? 0 : Math.min(selectedIndex, visibleTasks.length - 1);
291
- } else {
292
- selectedIndex = -1;
293
- }
294
-
295
- list.innerHTML = "";
296
- visibleTasks.forEach((task, index) => {
297
- const row = createTaskRow(task, params);
298
- row.addEventListener("mouseenter", () => {
299
- selectedIndex = index;
300
- syncSelectedRow();
301
- });
302
- list.appendChild(row);
303
- });
304
- syncSelectedRow();
305
-
306
- const hasRows = visibleTasks.length > 0;
307
- list.hidden = !hasRows;
308
- empty.hidden = hasRows || loading || Boolean(error);
309
-
310
- if (clearButton) {
311
- clearButton.hidden = !query;
312
- }
313
-
314
- if (loading) {
315
- setStatus("Loading tasks...");
316
- } else if (error) {
317
- setStatus(error);
318
- } else if (!tasks.length) {
319
- setStatus("");
320
- empty.hidden = false;
321
- empty.textContent = requiredVariables.length && sourceTaskCount
322
- ? `No tasks match ${requiredVariables.join(", ")}.`
323
- : "No saved tasks yet.";
324
- } else if (query && !hasRows) {
325
- setStatus("");
326
- empty.hidden = false;
327
- empty.textContent = "No tasks match this search.";
328
- } else {
329
- const noun = visibleTasks.length === 1 ? "task" : "tasks";
330
- setStatus(`${visibleTasks.length} ${noun}`);
331
- }
332
- }
333
-
334
- async function loadTasks() {
335
- loading = true;
336
- error = "";
337
- render();
338
- try {
339
- const response = await fetch("/api/tasks", {
340
- cache: "no-store"
341
- });
342
- const payload = await response.json().catch(() => null);
343
- if (!response.ok || !payload || !Array.isArray(payload.items)) {
344
- throw new Error("Failed to load tasks.");
345
- }
346
- sourceTaskCount = payload.items.length;
347
- tasks = payload.items.filter((task) => taskMatchesRequiredVariables(task, requiredVariables));
348
- } catch (loadError) {
349
- tasks = [];
350
- sourceTaskCount = 0;
351
- error = loadError && loadError.message ? loadError.message : "Failed to load tasks.";
352
- } finally {
353
- loading = false;
354
- render();
355
- }
356
- }
357
-
358
- if (searchInput) {
359
- searchInput.addEventListener("input", render);
360
- searchInput.addEventListener("keydown", (event) => {
361
- if (event.key === "ArrowDown") {
362
- event.preventDefault();
363
- moveSelection(1);
364
- return;
365
- }
366
- if (event.key === "ArrowUp") {
367
- event.preventDefault();
368
- moveSelection(-1);
369
- return;
370
- }
371
- if (event.key === "Enter") {
372
- event.preventDefault();
373
- openSelectedResult();
374
- return;
375
- }
376
- if (event.key === "Home" && (event.metaKey || event.ctrlKey)) {
377
- event.preventDefault();
378
- selectResult(0);
379
- return;
380
- }
381
- if (event.key === "End" && (event.metaKey || event.ctrlKey)) {
382
- event.preventDefault();
383
- selectResult(visibleTasks.length - 1);
384
- }
385
- });
386
- window.requestAnimationFrame(() => {
387
- searchInput.focus();
388
- searchInput.select();
389
- });
390
- }
391
- if (clearButton && searchInput) {
392
- clearButton.addEventListener("click", () => {
393
- searchInput.value = "";
394
- render();
395
- searchInput.focus();
396
- });
397
- }
398
-
399
- loadTasks();
400
- }
401
-
402
- if (document.readyState === "loading") {
403
- document.addEventListener("DOMContentLoaded", initTasker, { once: true });
404
- } else {
405
- initTasker();
406
- }
407
- })(window, document);
@@ -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 noteCount = workspace.counts && Number.isFinite(workspace.counts.notes) ? workspace.counts.notes : 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 note = workspace.note || null;
8
- const noteId = note && note.id ? note.id : `note-${index}`;
9
- const searchText = [workspace.name, workspace.cwd, shellTitles, scriptTitles, note && note.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 (noteCount > 0) details.push(noteCount === 1 ? "Note ready" : plural(noteCount, "note"));
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 (note && note.notePath) { %>
50
- <button class="btn" type="button" data-open-path="<%= note.notePath %>" title="Open note"><i class="fa-solid fa-file-lines" aria-hidden="true"></i> Note</button>
51
- <% if (note.excerpt) { %>
52
- <button class="btn" type="button" data-preview-toggle="<%= noteId %>"><i class="fa-solid fa-eye" aria-hidden="true"></i> Preview</button>
53
- <% } %>
54
- <% } %>
55
- </div>
56
- <% if (note && note.excerpt) { %>
57
- <div class="workspace-note-preview" data-preview-panel="<%= noteId %>" hidden><%= note.excerpt %></div>
58
- <% } %>
59
- </div>
60
- </h3>
61
- </div>
@@ -1,40 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>Tasker</title>
7
- <link href="/css/fontawesome.min.css" rel="stylesheet">
8
- <link href="/css/solid.min.css" rel="stylesheet">
9
- <link href="/css/brands.min.css" rel="stylesheet">
10
- <link href="/noty.css" rel="stylesheet">
11
- <link href="/style.css" rel="stylesheet">
12
- <link href="/universal-launcher.css" rel="stylesheet">
13
- <link href="/tasker.css" rel="stylesheet">
14
- <script src="/tasker.js" defer></script>
15
- <% if (agent === "electron") { %>
16
- <link href="/electron.css" rel="stylesheet"/>
17
- <% } %>
18
- </head>
19
- <body class="<%= theme %> tasker-page" data-agent="<%= agent %>">
20
- <%- include('partials/app_navheader', { agent }) %>
21
- <main class="tasker-main" aria-label="Tasker">
22
- <section class="tasker-panel" data-tasker>
23
- <div class="tasker-search-wrap">
24
- <div class="tasker-search-field">
25
- <i class="fa-solid fa-magnifying-glass" aria-hidden="true"></i>
26
- <input class="tasker-search-input" type="search" aria-label="Search tasks" placeholder="Search tasks" autocomplete="off" spellcheck="false" data-tasker-search>
27
- <button class="tasker-search-clear" type="button" aria-label="Clear search" data-tasker-clear hidden>
28
- <i class="fa-solid fa-xmark" aria-hidden="true"></i>
29
- </button>
30
- </div>
31
- </div>
32
-
33
- <div class="tasker-status" role="status" data-tasker-status>Loading tasks...</div>
34
- <div class="tasker-list" data-tasker-list hidden></div>
35
- <div class="tasker-empty" data-tasker-empty hidden>No tasks found.</div>
36
- </section>
37
- </main>
38
- <%- include('partials/app_common_scripts') %>
39
- </body>
40
- </html>