pinokiod 7.2.17 → 7.2.18
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/agent_instructions.js +166 -0
- package/kernel/api/index.js +137 -12
- package/kernel/bin/huggingface.js +1 -1
- package/kernel/environment.js +23 -9
- package/kernel/plugin_sources.js +57 -4
- package/kernel/prototype.js +4 -0
- package/kernel/shell.js +2 -0
- package/kernel/watch/index.js +31 -4
- package/package.json +1 -1
- package/server/features/index.js +4 -4
- package/server/features/{drafts → notes}/index.js +9 -9
- package/server/features/{drafts → notes}/parser.js +12 -7
- package/server/features/notes/public/notes.css +955 -0
- package/server/features/notes/public/notes.js +1149 -0
- package/server/features/{drafts → notes}/registry_import.js +22 -22
- package/server/features/notes/routes.js +156 -0
- package/server/features/notes/service.js +326 -0
- package/server/features/{drafts → notes}/watcher.js +14 -16
- package/server/index.js +61 -30
- package/server/lib/content_validation.js +19 -8
- package/server/lib/workspace_catalog.js +18 -18
- package/server/public/task-launcher.css +11 -3
- package/server/public/tasker.css +336 -0
- package/server/public/tasker.js +407 -0
- package/server/views/d.ejs +33 -2
- package/server/views/partials/menu.ejs +1 -1
- package/server/views/partials/workspace_row.ejs +11 -11
- package/server/views/pre.ejs +1 -1
- package/server/views/task_launch.ejs +10 -10
- package/server/views/tasker.ejs +40 -0
- package/server/views/terminal.ejs +15 -6
- package/server/views/terminals.ejs +0 -1
- package/server/views/workspaces.ejs +2 -1
- package/system/plugin/antigravity/pinokio.js +2 -4
- package/system/plugin/claude/pinokio.js +2 -4
- package/system/plugin/claude-auto/pinokio.js +2 -4
- package/system/plugin/claude-desktop/pinokio.js +2 -4
- package/system/plugin/codex/pinokio.js +2 -4
- package/system/plugin/codex-auto/pinokio.js +2 -4
- package/system/plugin/codex-desktop/pinokio.js +2 -4
- package/system/plugin/crush/pinokio.js +2 -4
- package/system/plugin/cursor/pinokio.js +2 -4
- package/system/plugin/gemini/pinokio.js +2 -4
- package/system/plugin/gemini-auto/pinokio.js +2 -4
- package/system/plugin/qwen/pinokio.js +2 -4
- package/system/plugin/vscode/pinokio.js +2 -4
- package/system/plugin/windsurf/pinokio.js +2 -4
- package/test/plugin-sources.test.js +45 -0
- package/server/features/drafts/public/drafts.js +0 -1504
- package/server/features/drafts/routes.js +0 -68
- package/server/features/drafts/service.js +0 -261
|
@@ -0,0 +1,407 @@
|
|
|
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);
|
package/server/views/d.ejs
CHANGED
|
@@ -11,13 +11,26 @@
|
|
|
11
11
|
<link href="/markdown.css" rel="stylesheet"/>
|
|
12
12
|
<link href="/noty.css" rel="stylesheet"/>
|
|
13
13
|
<link href="/style.css" rel="stylesheet"/>
|
|
14
|
+
<link href="/notes.css?v=d-launcher-notes" rel="stylesheet"/>
|
|
14
15
|
<% if (agent === "electron") { %>
|
|
15
16
|
<link href="/electron.css" rel="stylesheet"/>
|
|
16
17
|
<% } %>
|
|
17
18
|
<style>
|
|
19
|
+
html,
|
|
20
|
+
body {
|
|
21
|
+
height: 100%;
|
|
22
|
+
}
|
|
23
|
+
body {
|
|
24
|
+
display: flex;
|
|
25
|
+
flex-direction: column;
|
|
26
|
+
}
|
|
18
27
|
main {
|
|
19
28
|
box-sizing: border-box;
|
|
20
29
|
padding: 0;
|
|
30
|
+
flex: 1 1 auto;
|
|
31
|
+
min-height: 0;
|
|
32
|
+
display: flex;
|
|
33
|
+
flex-direction: column;
|
|
21
34
|
/*
|
|
22
35
|
flex-wrap: wrap;
|
|
23
36
|
*/
|
|
@@ -258,8 +271,10 @@ body.dark .column-subtitle-link:focus-visible {
|
|
|
258
271
|
}
|
|
259
272
|
.menu-grid {
|
|
260
273
|
display: grid;
|
|
274
|
+
flex: 1 1 auto;
|
|
261
275
|
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
|
262
|
-
align-items:
|
|
276
|
+
align-items: stretch;
|
|
277
|
+
min-height: 0;
|
|
263
278
|
}
|
|
264
279
|
.menu-grid.menu-grid--triptych {
|
|
265
280
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
@@ -508,6 +523,8 @@ body.dark form.search {
|
|
|
508
523
|
background: rgba(255,255,255,0.07);
|
|
509
524
|
}
|
|
510
525
|
form.search {
|
|
526
|
+
flex: 0 0 auto;
|
|
527
|
+
align-items: center;
|
|
511
528
|
padding: 10px;
|
|
512
529
|
background: #F1F1F1;
|
|
513
530
|
}
|
|
@@ -540,7 +557,8 @@ body.dark #update-spec {
|
|
|
540
557
|
<script src="/nav.js"></script>
|
|
541
558
|
</head>
|
|
542
559
|
<body class='<%=theme%>' data-agent="<%=agent%>">
|
|
543
|
-
<main>
|
|
560
|
+
<main data-pinokio-notes-scope="true">
|
|
561
|
+
<div id="pinokio-notes-slot" class="pinokio-notes-slot" aria-live="polite"></div>
|
|
544
562
|
<form class='search'>
|
|
545
563
|
<input type='search' class="flexible" placeholder='Filter tools'>
|
|
546
564
|
</form>
|
|
@@ -739,6 +757,18 @@ body.dark #update-spec {
|
|
|
739
757
|
<% } %>
|
|
740
758
|
</main>
|
|
741
759
|
<script>
|
|
760
|
+
const pinokioNotePublish = { target: "registry", type: "post" }
|
|
761
|
+
const pinokioNoteParentUrl = <%- JSON.stringify(typeof registry_parent_url !== 'undefined' ? registry_parent_url || '' : '').replace(/</g, '\\u003c') %>
|
|
762
|
+
if (pinokioNoteParentUrl) {
|
|
763
|
+
pinokioNotePublish.parent = { type: "app", url: pinokioNoteParentUrl }
|
|
764
|
+
}
|
|
765
|
+
window.PinokioNoteContext = {
|
|
766
|
+
cwd: <%- JSON.stringify(filepath || '').replace(/</g, '\\u003c') %>,
|
|
767
|
+
publish: pinokioNotePublish
|
|
768
|
+
}
|
|
769
|
+
</script>
|
|
770
|
+
<script src="/notes.js?v=d-launcher-notes"></script>
|
|
771
|
+
<script>
|
|
742
772
|
<% if (retry) { %>
|
|
743
773
|
setTimeout(() => {
|
|
744
774
|
location.href = location.href
|
|
@@ -890,6 +920,7 @@ const appendWorkspaceCwd = (value, cwd = workspaceCwd) => {
|
|
|
890
920
|
try {
|
|
891
921
|
const parsed = new URL(raw, window.location.origin)
|
|
892
922
|
const isPluginLauncher = parsed.pathname.startsWith("/run/plugin/")
|
|
923
|
+
|| parsed.pathname.startsWith("/pinokio/run/plugin/")
|
|
893
924
|
|| (parsed.pathname.startsWith("/run/api/") && /\/pinokio\.js$/i.test(parsed.pathname))
|
|
894
925
|
if (parsed.origin !== window.location.origin || !isPluginLauncher) {
|
|
895
926
|
return value
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
<i class="fa-solid fa-angle-right"></i>
|
|
19
19
|
<% } %>
|
|
20
20
|
</div>
|
|
21
|
-
<% } else if (item.run) { %>
|
|
21
|
+
<% } else if (item.run && typeof item.run === 'string') { %>
|
|
22
22
|
<div data-run="<%=item.run%>" data-cwd="<%=item.cwd%>" class='btn header-item frame-link <%=item.display || ""%>'>
|
|
23
23
|
<div class='tab'><%-item.btn%></div>
|
|
24
24
|
<% if (item.arrow) { %>
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
<%
|
|
2
2
|
const shellCount = workspace.counts && Number.isFinite(workspace.counts.shells) ? workspace.counts.shells : 0;
|
|
3
3
|
const scriptCount = workspace.counts && Number.isFinite(workspace.counts.scripts) ? workspace.counts.scripts : 0;
|
|
4
|
-
const
|
|
4
|
+
const noteCount = workspace.counts && Number.isFinite(workspace.counts.notes) ? workspace.counts.notes : 0;
|
|
5
5
|
const shellTitles = Array.isArray(workspace.shells) ? workspace.shells.map((shell) => shell.title || shell.id || "").join(" ") : "";
|
|
6
6
|
const scriptTitles = Array.isArray(workspace.scripts) ? workspace.scripts.map((script) => script.title || script.id || "").join(" ") : "";
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const searchText = [workspace.name, workspace.cwd, shellTitles, scriptTitles,
|
|
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
10
|
const modifiedLabel = dateLabel(workspace.modifiedAt);
|
|
11
11
|
const details = [];
|
|
12
12
|
if (shellCount > 0) details.push(plural(shellCount, "terminal"));
|
|
13
13
|
if (scriptCount > 0) details.push(plural(scriptCount, "script"));
|
|
14
|
-
if (
|
|
14
|
+
if (noteCount > 0) details.push(noteCount === 1 ? "Note ready" : plural(noteCount, "note"));
|
|
15
15
|
if (modifiedLabel) details.push(modifiedLabel);
|
|
16
16
|
%>
|
|
17
17
|
<div
|
|
@@ -46,15 +46,15 @@
|
|
|
46
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
47
|
<% } %>
|
|
48
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 (
|
|
50
|
-
<button class="btn" type="button" data-open-path="<%=
|
|
51
|
-
<% if (
|
|
52
|
-
<button class="btn" type="button" data-preview-toggle="<%=
|
|
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
53
|
<% } %>
|
|
54
54
|
<% } %>
|
|
55
55
|
</div>
|
|
56
|
-
<% if (
|
|
57
|
-
<div class="workspace-
|
|
56
|
+
<% if (note && note.excerpt) { %>
|
|
57
|
+
<div class="workspace-note-preview" data-preview-panel="<%= noteId %>" hidden><%= note.excerpt %></div>
|
|
58
58
|
<% } %>
|
|
59
59
|
</div>
|
|
60
60
|
</h3>
|
package/server/views/pre.ejs
CHANGED
|
@@ -117,7 +117,7 @@ footer a.btn {
|
|
|
117
117
|
</div>
|
|
118
118
|
<div class='items'>
|
|
119
119
|
<% items.forEach((item) => { %>
|
|
120
|
-
<% if (item.href) { %>
|
|
120
|
+
<% if (typeof item.href === "string" && item.href) { %>
|
|
121
121
|
<div class='item'>
|
|
122
122
|
<% if (item.icon) { %>
|
|
123
123
|
<img src="<%=item.icon%>">
|
|
@@ -125,16 +125,6 @@
|
|
|
125
125
|
<div class="task-detail-main">
|
|
126
126
|
<section class="task-section task-prompt-section">
|
|
127
127
|
<pre class="task-code task-prompt-code" data-task-rendered-prompt><%= renderedPrompt %></pre>
|
|
128
|
-
<div class="task-prompt-actions">
|
|
129
|
-
<button class="task-button primary task-run-button" type="submit">
|
|
130
|
-
<i class="fa-solid fa-bolt" aria-hidden="true"></i>
|
|
131
|
-
<span>Run</span>
|
|
132
|
-
</button>
|
|
133
|
-
<p class="task-inline-help">Tool and folder stay local. The permalink tracks only the task inputs.</p>
|
|
134
|
-
<p class="task-submit-feedback" data-task-submit-feedback aria-live="polite" aria-hidden="true">
|
|
135
|
-
<span data-task-submit-feedback-text></span>
|
|
136
|
-
</p>
|
|
137
|
-
</div>
|
|
138
128
|
</section>
|
|
139
129
|
</div>
|
|
140
130
|
|
|
@@ -164,6 +154,16 @@
|
|
|
164
154
|
<span class="task-label">Folder<% if (folderRequired) { %><span class="task-label-required">*</span><% } %><% if (folderMeta) { %><span class="task-label-meta"><%= folderMeta %></span><% } %></span>
|
|
165
155
|
<input class="task-input" type="text" name="folderName" value="<%= folderName || '' %>" placeholder="<%= folderPlaceholder %>" <%= folderRequired ? 'required' : '' %>>
|
|
166
156
|
</label>
|
|
157
|
+
<div class="task-run-footer">
|
|
158
|
+
<button class="task-button primary task-run-button task-run-actions" type="submit">
|
|
159
|
+
<i class="fa-solid fa-bolt" aria-hidden="true"></i>
|
|
160
|
+
<span>Run</span>
|
|
161
|
+
</button>
|
|
162
|
+
<p class="task-inline-help">Tool and folder stay local. The permalink tracks only the task inputs.</p>
|
|
163
|
+
<p class="task-submit-feedback" data-task-submit-feedback aria-live="polite" aria-hidden="true">
|
|
164
|
+
<span data-task-submit-feedback-text></span>
|
|
165
|
+
</p>
|
|
166
|
+
</div>
|
|
167
167
|
</div>
|
|
168
168
|
</section>
|
|
169
169
|
</aside>
|
|
@@ -0,0 +1,40 @@
|
|
|
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>
|