pinokiod 7.2.18 → 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 (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-python.js +30 -0
  5. package/kernel/bin/conda.js +22 -3
  6. package/kernel/bin/huggingface.js +1 -1
  7. package/kernel/bin/index.js +11 -1
  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,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,336 +0,0 @@
1
- body.tasker-page {
2
- --tasker-bg: #f5f6f8;
3
- --tasker-panel: #ffffff;
4
- --tasker-row: #f8fafc;
5
- --tasker-row-hover: #f1f5f9;
6
- --tasker-row-selected: #e8edf4;
7
- --tasker-control: #ffffff;
8
- --tasker-icon-bg: #ffffff;
9
- --tasker-icon-selected-bg: #f8fafc;
10
- --tasker-border: rgba(15, 23, 42, 0.1);
11
- --tasker-border-strong: rgba(15, 23, 42, 0.18);
12
- --tasker-text: rgba(15, 23, 42, 0.9);
13
- --tasker-text-strong: rgba(15, 23, 42, 0.98);
14
- --tasker-muted: rgba(71, 85, 105, 0.78);
15
- --tasker-muted-strong: rgba(51, 65, 85, 0.82);
16
- --tasker-focus: rgba(15, 23, 42, 0.1);
17
- --tasker-focus-border: rgba(15, 23, 42, 0.28);
18
- --tasker-clear-hover: rgba(15, 23, 42, 0.06);
19
- --tasker-selection-bar: rgba(15, 23, 42, 0.48);
20
- --tasker-shadow: 0 28px 80px rgba(15, 23, 42, 0.12);
21
- min-height: 100vh;
22
- margin: 0;
23
- background: var(--tasker-bg);
24
- color: var(--tasker-text);
25
- font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
26
- font-size: 14px;
27
- display: block;
28
- }
29
-
30
- body.dark.tasker-page {
31
- --tasker-bg: #050607;
32
- --tasker-panel: #0d0d0f;
33
- --tasker-row: #141416;
34
- --tasker-row-hover: #18181b;
35
- --tasker-row-selected: #202024;
36
- --tasker-control: #111114;
37
- --tasker-icon-bg: #08090b;
38
- --tasker-icon-selected-bg: #0c0d10;
39
- --tasker-border: rgba(255, 255, 255, 0.09);
40
- --tasker-border-strong: rgba(255, 255, 255, 0.18);
41
- --tasker-text: rgba(255, 255, 255, 0.88);
42
- --tasker-text-strong: rgba(255, 255, 255, 0.96);
43
- --tasker-muted: rgba(255, 255, 255, 0.48);
44
- --tasker-muted-strong: rgba(255, 255, 255, 0.62);
45
- --tasker-focus: rgba(255, 255, 255, 0.14);
46
- --tasker-focus-border: rgba(255, 255, 255, 0.24);
47
- --tasker-clear-hover: rgba(255, 255, 255, 0.06);
48
- --tasker-selection-bar: rgba(255, 255, 255, 0.64);
49
- --tasker-shadow: 0 32px 90px rgba(0, 0, 0, 0.42);
50
- }
51
-
52
- body.tasker-page .tasker-main {
53
- min-height: calc(100vh - 44px);
54
- box-sizing: border-box;
55
- display: grid;
56
- place-items: center;
57
- padding: 32px 16px;
58
- }
59
-
60
- .tasker-panel {
61
- width: min(760px, calc(100vw - 32px));
62
- max-height: min(660px, calc(100vh - 96px));
63
- box-sizing: border-box;
64
- display: grid;
65
- grid-template-rows: auto auto minmax(0, 1fr);
66
- overflow: hidden;
67
- padding: 14px;
68
- border: 1px solid var(--tasker-border);
69
- border-radius: 8px;
70
- background: var(--tasker-panel);
71
- box-shadow: var(--tasker-shadow);
72
- }
73
-
74
- .tasker-search-wrap {
75
- padding: 0 0 14px;
76
- }
77
-
78
- .tasker-search-field {
79
- min-height: 42px;
80
- box-sizing: border-box;
81
- display: grid;
82
- grid-template-columns: auto minmax(0, 1fr) auto;
83
- align-items: center;
84
- gap: 10px;
85
- padding: 0 12px;
86
- border: 1px solid var(--tasker-border-strong);
87
- border-radius: 7px;
88
- background: var(--tasker-control);
89
- }
90
-
91
- .tasker-search-field:focus-within {
92
- border-color: var(--tasker-focus-border);
93
- box-shadow: 0 0 0 3px var(--tasker-focus);
94
- }
95
-
96
- .tasker-search-field > i {
97
- color: var(--tasker-muted);
98
- font-size: 13px;
99
- }
100
-
101
- .tasker-search-input {
102
- width: 100%;
103
- min-width: 0;
104
- min-height: 40px;
105
- padding: 0;
106
- border: 0;
107
- outline: 0;
108
- background: transparent;
109
- color: var(--tasker-text);
110
- font: inherit;
111
- font-size: 14px;
112
- line-height: 1.4;
113
- }
114
-
115
- .tasker-search-input::placeholder {
116
- color: var(--tasker-muted);
117
- }
118
-
119
- .tasker-search-input::-webkit-search-cancel-button {
120
- appearance: none;
121
- -webkit-appearance: none;
122
- }
123
-
124
- .tasker-search-clear {
125
- appearance: none;
126
- width: 28px;
127
- height: 28px;
128
- display: inline-flex;
129
- align-items: center;
130
- justify-content: center;
131
- border: 0;
132
- border-radius: 6px;
133
- background: transparent;
134
- color: var(--tasker-muted);
135
- cursor: pointer;
136
- }
137
-
138
- .tasker-search-clear:hover,
139
- .tasker-search-clear:focus-visible {
140
- background: var(--tasker-clear-hover);
141
- color: var(--tasker-text);
142
- outline: none;
143
- }
144
-
145
- .tasker-search-clear[hidden] {
146
- display: none !important;
147
- }
148
-
149
- .tasker-status {
150
- padding: 0 2px 12px;
151
- color: var(--tasker-muted-strong);
152
- font-size: 12px;
153
- font-weight: 750;
154
- line-height: 1.2;
155
- letter-spacing: 0;
156
- text-transform: uppercase;
157
- }
158
-
159
- .tasker-status[hidden] {
160
- display: none !important;
161
- }
162
-
163
- .tasker-list {
164
- min-height: 0;
165
- display: grid;
166
- gap: 0;
167
- overflow: auto;
168
- border: 1px solid var(--tasker-border);
169
- border-radius: 7px;
170
- background: var(--tasker-row);
171
- }
172
-
173
- .tasker-list[hidden] {
174
- display: none !important;
175
- }
176
-
177
- .tasker-row {
178
- position: relative;
179
- width: 100%;
180
- min-width: 0;
181
- box-sizing: border-box;
182
- display: grid;
183
- grid-template-columns: auto minmax(0, 1fr) auto;
184
- align-items: center;
185
- gap: 13px;
186
- padding: 15px 14px;
187
- border-bottom: 1px solid var(--tasker-border);
188
- background: var(--tasker-row);
189
- color: var(--tasker-text);
190
- text-align: left;
191
- text-decoration: none;
192
- }
193
-
194
- .tasker-row:last-child {
195
- border-bottom: 0;
196
- }
197
-
198
- .tasker-row:hover,
199
- .tasker-row:focus-visible {
200
- background: var(--tasker-row-hover);
201
- color: var(--tasker-text);
202
- outline: none;
203
- }
204
-
205
- .tasker-row.selected {
206
- background: var(--tasker-row-selected);
207
- color: var(--tasker-text);
208
- outline: none;
209
- }
210
-
211
- .tasker-row.selected::before {
212
- content: "";
213
- position: absolute;
214
- top: 12px;
215
- bottom: 12px;
216
- left: 0;
217
- width: 3px;
218
- border-radius: 0 3px 3px 0;
219
- background: var(--tasker-selection-bar);
220
- }
221
-
222
- .tasker-row.selected .tasker-row-icon {
223
- border-color: var(--tasker-border-strong);
224
- background: var(--tasker-icon-selected-bg);
225
- color: var(--tasker-text-strong);
226
- }
227
-
228
- .tasker-row.selected .tasker-row-label {
229
- color: var(--tasker-text-strong);
230
- }
231
-
232
- .tasker-row.selected .tasker-row-meta {
233
- color: var(--tasker-muted-strong);
234
- }
235
-
236
- .tasker-row-icon {
237
- width: 29px;
238
- height: 29px;
239
- display: inline-flex;
240
- align-items: center;
241
- justify-content: center;
242
- border: 1px solid var(--tasker-border);
243
- border-radius: 7px;
244
- background: var(--tasker-icon-bg);
245
- color: var(--tasker-muted-strong);
246
- font-size: 12px;
247
- }
248
-
249
- .tasker-row-copy {
250
- min-width: 0;
251
- display: grid;
252
- gap: 3px;
253
- }
254
-
255
- .tasker-row-label {
256
- min-width: 0;
257
- overflow: hidden;
258
- color: var(--tasker-text);
259
- font-size: 15px;
260
- font-weight: 750;
261
- line-height: 1.25;
262
- letter-spacing: 0;
263
- text-overflow: ellipsis;
264
- white-space: nowrap;
265
- }
266
-
267
- .tasker-row-meta {
268
- min-width: 0;
269
- overflow: hidden;
270
- display: -webkit-box;
271
- -webkit-box-orient: vertical;
272
- -webkit-line-clamp: 2;
273
- color: var(--tasker-muted);
274
- font-size: 13px;
275
- font-weight: 600;
276
- line-height: 1.38;
277
- }
278
-
279
- .tasker-row-hint {
280
- color: var(--tasker-muted);
281
- font-size: 11px;
282
- opacity: 0;
283
- }
284
-
285
- .tasker-row:hover .tasker-row-hint,
286
- .tasker-row:focus-visible .tasker-row-hint,
287
- .tasker-row.selected .tasker-row-hint {
288
- opacity: 1;
289
- }
290
-
291
- .tasker-empty {
292
- padding: 18px 14px;
293
- border: 1px solid var(--tasker-border);
294
- border-radius: 7px;
295
- background: var(--tasker-row);
296
- color: var(--tasker-muted);
297
- font-size: 13px;
298
- line-height: 1.45;
299
- text-align: center;
300
- }
301
-
302
- .tasker-empty[hidden] {
303
- display: none !important;
304
- }
305
-
306
- @media (max-width: 768px) {
307
- body.tasker-page {
308
- display: block !important;
309
- }
310
-
311
- body.tasker-page .tasker-main {
312
- align-items: start;
313
- padding: 16px 10px 24px;
314
- }
315
-
316
- .tasker-panel {
317
- width: min(100%, calc(100vw - 20px));
318
- max-height: none;
319
- }
320
- }
321
-
322
- @media (max-width: 520px) {
323
- .tasker-panel {
324
- padding: 10px;
325
- }
326
-
327
- .tasker-row {
328
- grid-template-columns: minmax(0, 1fr) auto;
329
- gap: 8px;
330
- padding: 13px 12px;
331
- }
332
-
333
- .tasker-row-icon {
334
- display: none;
335
- }
336
- }