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
package/server/index.js
CHANGED
|
@@ -2758,10 +2758,12 @@ class Server {
|
|
|
2758
2758
|
} else {
|
|
2759
2759
|
resolved = runner(this.kernel, this.kernel.info)
|
|
2760
2760
|
}
|
|
2761
|
-
|
|
2761
|
+
const action = resolved ? resolved[actionKey] : null
|
|
2762
|
+
runnable = typeof action === "function" || (Array.isArray(action) && action.length > 0)
|
|
2762
2763
|
} else {
|
|
2763
|
-
runnable = runner && Array.isArray(runner[actionKey]) && runner[actionKey].length > 0
|
|
2764
2764
|
resolved = runner
|
|
2765
|
+
const action = resolved ? resolved[actionKey] : null
|
|
2766
|
+
runnable = typeof action === "function" || (Array.isArray(action) && action.length > 0)
|
|
2765
2767
|
}
|
|
2766
2768
|
|
|
2767
2769
|
let template = "terminal"
|
|
@@ -2870,10 +2872,10 @@ class Server {
|
|
|
2870
2872
|
const protectionPreference = protectionAppId && this.appPreferences && typeof this.appPreferences.getPreference === "function"
|
|
2871
2873
|
? await this.appPreferences.getPreference(protectionAppId)
|
|
2872
2874
|
: null
|
|
2873
|
-
const
|
|
2874
|
-
? this.kernel.watch.hasHandler(resolved, "
|
|
2875
|
+
const noteWatchEnabled = this.kernel.watch && typeof this.kernel.watch.hasHandler === "function"
|
|
2876
|
+
? this.kernel.watch.hasHandler(resolved, "note")
|
|
2875
2877
|
: false
|
|
2876
|
-
const
|
|
2878
|
+
const noteWatchCwd = noteWatchEnabled
|
|
2877
2879
|
? (req.query.cwd || path.dirname(filepath))
|
|
2878
2880
|
: ""
|
|
2879
2881
|
const activeProcessWait = this.kernel.activeProcessWaits && this.kernel.activeProcessWaits[filepath]
|
|
@@ -2884,8 +2886,8 @@ class Server {
|
|
|
2884
2886
|
projectName: (pathComponents.length > 0 ? pathComponents[0] : ''),
|
|
2885
2887
|
protection_app_id: protectionAppId,
|
|
2886
2888
|
protection_enabled: protectionPreference ? protectionPreference.protection_enabled !== false : false,
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
+
note_watch_enabled: noteWatchEnabled,
|
|
2890
|
+
note_watch_cwd: noteWatchCwd,
|
|
2889
2891
|
active_process_wait: activeProcessWait ? {
|
|
2890
2892
|
title: activeProcessWait.title,
|
|
2891
2893
|
description: activeProcessWait.description,
|
|
@@ -5311,15 +5313,7 @@ class Server {
|
|
|
5311
5313
|
return normalized
|
|
5312
5314
|
}
|
|
5313
5315
|
isValidBundledPluginConfig(pluginConfig) {
|
|
5314
|
-
|
|
5315
|
-
return false
|
|
5316
|
-
}
|
|
5317
|
-
for (const key of Object.keys(pluginConfig)) {
|
|
5318
|
-
if (typeof pluginConfig[key] === "function") {
|
|
5319
|
-
return false
|
|
5320
|
-
}
|
|
5321
|
-
}
|
|
5322
|
-
return true
|
|
5316
|
+
return PluginSources.isValidPluginConfig(pluginConfig)
|
|
5323
5317
|
}
|
|
5324
5318
|
isPathInsideRootForBundledPlugin(candidatePath, rootPath) {
|
|
5325
5319
|
const relative = path.relative(rootPath, candidatePath)
|
|
@@ -6857,9 +6851,9 @@ class Server {
|
|
|
6857
6851
|
cwd: typeof pluginItem.ownerApp.cwd === "string" ? pluginItem.ownerApp.cwd : "",
|
|
6858
6852
|
}
|
|
6859
6853
|
: null,
|
|
6860
|
-
hasInstall:
|
|
6861
|
-
hasUninstall:
|
|
6862
|
-
hasUpdate:
|
|
6854
|
+
hasInstall: PluginSources.isAction(pluginItem?.install),
|
|
6855
|
+
hasUninstall: PluginSources.isAction(pluginItem?.uninstall),
|
|
6856
|
+
hasUpdate: PluginSources.isAction(pluginItem?.update),
|
|
6863
6857
|
category,
|
|
6864
6858
|
categoryTitle: category === "ide" ? "Desktop Plugin" : "Terminal Plugin",
|
|
6865
6859
|
categorySubtitle: category === "ide" ? "Launch externally" : "Launch in Pinokio",
|
|
@@ -8415,12 +8409,12 @@ class Server {
|
|
|
8415
8409
|
defaultRegistryUrl: DEFAULT_REGISTRY_URL
|
|
8416
8410
|
})
|
|
8417
8411
|
this.features = features
|
|
8418
|
-
const
|
|
8419
|
-
this.
|
|
8412
|
+
const notes = features.notes.service
|
|
8413
|
+
this.notes = notes
|
|
8420
8414
|
const workspaceCatalog = createWorkspaceCatalogService({
|
|
8421
8415
|
kernel: this.kernel,
|
|
8422
8416
|
workspaceRuntime,
|
|
8423
|
-
|
|
8417
|
+
notes
|
|
8424
8418
|
})
|
|
8425
8419
|
registerWorkspacesRoutes(this.app, {
|
|
8426
8420
|
workspaceCatalog,
|
|
@@ -9744,6 +9738,13 @@ class Server {
|
|
|
9744
9738
|
})
|
|
9745
9739
|
}))
|
|
9746
9740
|
|
|
9741
|
+
this.app.get("/tasker", ex(async (req, res) => {
|
|
9742
|
+
res.render("tasker", {
|
|
9743
|
+
theme: this.theme,
|
|
9744
|
+
agent: req.agent,
|
|
9745
|
+
})
|
|
9746
|
+
}))
|
|
9747
|
+
|
|
9747
9748
|
this.app.get("/tasks/new", ex(async (req, res) => {
|
|
9748
9749
|
const sourceWorkspace = normalizeTaskBuilderSourceWorkspace(req.query.sourceWorkspaceCwd)
|
|
9749
9750
|
const lockTargetSelection = req.query.lockTarget === "1" || req.query.lockTarget === "true"
|
|
@@ -13415,9 +13416,21 @@ class Server {
|
|
|
13415
13416
|
// }
|
|
13416
13417
|
// }))
|
|
13417
13418
|
this.app.post("/env", ex(async (req, res) => {
|
|
13418
|
-
|
|
13419
|
+
const requestFilepath = typeof req.body.filepath === "string" ? req.body.filepath : ""
|
|
13420
|
+
const requestRoot = path.resolve(this.kernel.homedir, requestFilepath)
|
|
13421
|
+
let fullpath = path.resolve(requestRoot, "ENVIRONMENT")
|
|
13422
|
+
if (!(await this.kernel.exists(fullpath))) {
|
|
13423
|
+
const normalizedFilepath = requestFilepath.replace(/\\/g, "/")
|
|
13424
|
+
const filepathParts = normalizedFilepath.split("/").filter(Boolean)
|
|
13425
|
+
if (filepathParts[0] === "api" && filepathParts[1] && filepathParts.length === 2) {
|
|
13426
|
+
const launcher = await this.kernel.api.launcher(filepathParts[1])
|
|
13427
|
+
if (launcher && launcher.launcher_root) {
|
|
13428
|
+
fullpath = path.resolve(launcher.root, launcher.launcher_root, "ENVIRONMENT")
|
|
13429
|
+
}
|
|
13430
|
+
}
|
|
13431
|
+
}
|
|
13419
13432
|
let updated = req.body.vals
|
|
13420
|
-
let hosts = req.body.hosts
|
|
13433
|
+
let hosts = req.body.hosts || {}
|
|
13421
13434
|
await Util.update_env(fullpath, updated)
|
|
13422
13435
|
const normalizedFilepath = typeof req.body.filepath === "string"
|
|
13423
13436
|
? req.body.filepath.replace(/\\/g, "/")
|
|
@@ -13570,14 +13583,15 @@ class Server {
|
|
|
13570
13583
|
this.app.get("/pre/api/:name", ex(async (req, res) => {
|
|
13571
13584
|
let launcher = await this.kernel.api.launcher(req.params.name)
|
|
13572
13585
|
let config = launcher.script
|
|
13573
|
-
if (config && config.pre) {
|
|
13574
|
-
config.pre.
|
|
13575
|
-
|
|
13586
|
+
if (config && Array.isArray(config.pre)) {
|
|
13587
|
+
const items = config.pre.filter((item) => item && typeof item === "object")
|
|
13588
|
+
items.forEach((item) => {
|
|
13589
|
+
if (typeof item.icon === "string" && item.icon) {
|
|
13576
13590
|
item.icon = `/api/${req.params.name}/${item.icon}?raw=true`
|
|
13577
13591
|
} else {
|
|
13578
13592
|
item.icon = "/pinokio-black.png"
|
|
13579
13593
|
}
|
|
13580
|
-
if (!item.href.startsWith("http")) {
|
|
13594
|
+
if (typeof item.href === "string" && item.href && !item.href.startsWith("http")) {
|
|
13581
13595
|
item.href = path.resolve(this.kernel.homedir, "api", req.params.name, item.href)
|
|
13582
13596
|
}
|
|
13583
13597
|
})
|
|
@@ -13588,7 +13602,7 @@ class Server {
|
|
|
13588
13602
|
theme: this.theme,
|
|
13589
13603
|
agent: req.agent,
|
|
13590
13604
|
name: req.params.name,
|
|
13591
|
-
items
|
|
13605
|
+
items,
|
|
13592
13606
|
env
|
|
13593
13607
|
})
|
|
13594
13608
|
} else {
|
|
@@ -14074,7 +14088,7 @@ class Server {
|
|
|
14074
14088
|
mode = "launch_type.desktop"
|
|
14075
14089
|
} else if (launchType === "terminal") {
|
|
14076
14090
|
mode = "launch_type.terminal"
|
|
14077
|
-
} else {
|
|
14091
|
+
} else if (Array.isArray(item.run)) {
|
|
14078
14092
|
for(let step of item.run) {
|
|
14079
14093
|
if (step.method === "exec") {
|
|
14080
14094
|
mode = "exec"
|
|
@@ -14089,6 +14103,8 @@ class Server {
|
|
|
14089
14103
|
break
|
|
14090
14104
|
}
|
|
14091
14105
|
}
|
|
14106
|
+
} else if (typeof item.run === "function") {
|
|
14107
|
+
mode = "shell"
|
|
14092
14108
|
}
|
|
14093
14109
|
if (mode === "launch_type.desktop" || mode === "exec" || mode === "launch") {
|
|
14094
14110
|
item.type = "Open"
|
|
@@ -14141,6 +14157,20 @@ class Server {
|
|
|
14141
14157
|
spec = await fs.promises.readFile(path.resolve(filepath, "SPEC.md"), "utf8")
|
|
14142
14158
|
} catch (e) {
|
|
14143
14159
|
}
|
|
14160
|
+
const registryEnabled = await this.isRegistryEnabled().catch(() => false)
|
|
14161
|
+
let registry_parent_url = ""
|
|
14162
|
+
if (registryEnabled) {
|
|
14163
|
+
try {
|
|
14164
|
+
registry_parent_url = await git.getConfig({
|
|
14165
|
+
fs,
|
|
14166
|
+
http,
|
|
14167
|
+
dir: filepath,
|
|
14168
|
+
path: "remote.origin.url"
|
|
14169
|
+
}) || ""
|
|
14170
|
+
} catch (_) {
|
|
14171
|
+
registry_parent_url = ""
|
|
14172
|
+
}
|
|
14173
|
+
}
|
|
14144
14174
|
res.render("d", {
|
|
14145
14175
|
filepath,
|
|
14146
14176
|
spec,
|
|
@@ -14151,6 +14181,7 @@ class Server {
|
|
|
14151
14181
|
install: this.install,
|
|
14152
14182
|
agent: req.agent,
|
|
14153
14183
|
theme: this.theme,
|
|
14184
|
+
registry_parent_url,
|
|
14154
14185
|
//dynamic: plugin_menu
|
|
14155
14186
|
dynamic,
|
|
14156
14187
|
})
|
|
@@ -147,9 +147,9 @@ function createContentValidationService({ kernel }) {
|
|
|
147
147
|
absolutePath,
|
|
148
148
|
dir: pluginDir,
|
|
149
149
|
config,
|
|
150
|
-
hasInstall:
|
|
151
|
-
hasUpdate:
|
|
152
|
-
hasUninstall:
|
|
150
|
+
hasInstall: PluginSources.isAction(config && config.install),
|
|
151
|
+
hasUpdate: PluginSources.isAction(config && config.update),
|
|
152
|
+
hasUninstall: PluginSources.isAction(config && config.uninstall),
|
|
153
153
|
image: null,
|
|
154
154
|
}
|
|
155
155
|
|
|
@@ -252,21 +252,32 @@ function createContentValidationService({ kernel }) {
|
|
|
252
252
|
{ file: absolutePath }
|
|
253
253
|
))
|
|
254
254
|
} else {
|
|
255
|
-
if (!
|
|
255
|
+
if (!PluginSources.isAction(config.run)) {
|
|
256
256
|
errors.push(buildError(
|
|
257
|
-
"Plugins must define a top-level run array.",
|
|
258
|
-
"Add `run: [...]` to pinokio.js.",
|
|
257
|
+
"Plugins must define a top-level run array or function.",
|
|
258
|
+
"Add `run: [...]` or `run: async (ctx) => [...]` to pinokio.js.",
|
|
259
259
|
{ file: absolutePath }
|
|
260
260
|
))
|
|
261
261
|
}
|
|
262
|
-
const topLevelFunctionKeys = Object.keys(config).filter((key) =>
|
|
262
|
+
const topLevelFunctionKeys = Object.keys(config).filter((key) => {
|
|
263
|
+
return typeof config[key] === "function" && !PluginSources.ACTION_KEYS.has(key)
|
|
264
|
+
})
|
|
263
265
|
if (topLevelFunctionKeys.length > 0) {
|
|
264
266
|
errors.push(buildError(
|
|
265
267
|
`Top-level function fields are not supported: ${topLevelFunctionKeys.join(", ")}.`,
|
|
266
|
-
"
|
|
268
|
+
"Only action fields such as run, install, uninstall, and update may be functions.",
|
|
267
269
|
{ file: absolutePath }
|
|
268
270
|
))
|
|
269
271
|
}
|
|
272
|
+
for (const key of PluginSources.ACTION_KEYS) {
|
|
273
|
+
if (key in config && !PluginSources.isAction(config[key])) {
|
|
274
|
+
errors.push(buildError(
|
|
275
|
+
`Plugin action ${key} must be an array or function.`,
|
|
276
|
+
`Set ${key} to an array or async function returning an array.`,
|
|
277
|
+
{ file: absolutePath }
|
|
278
|
+
))
|
|
279
|
+
}
|
|
280
|
+
}
|
|
270
281
|
if (normalizedPath.startsWith("/plugin/")) {
|
|
271
282
|
const declaredPath = typeof config.path === "string" ? config.path.trim() : ""
|
|
272
283
|
if (declaredPath !== "plugin") {
|
|
@@ -52,13 +52,13 @@ function sortWorkspaces(items, sort) {
|
|
|
52
52
|
return sorted
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
function
|
|
56
|
-
return [...
|
|
55
|
+
function newestNote(notes) {
|
|
56
|
+
return [...notes].sort((a, b) => {
|
|
57
57
|
return (new Date(b.updatedAt || 0).getTime() || 0) - (new Date(a.updatedAt || 0).getTime() || 0)
|
|
58
58
|
})[0] || null
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
function createWorkspaceCatalogService({ kernel, workspaceRuntime,
|
|
61
|
+
function createWorkspaceCatalogService({ kernel, workspaceRuntime, notes }) {
|
|
62
62
|
async function list(options = {}) {
|
|
63
63
|
const sort = normalizeSortMode(options.sort)
|
|
64
64
|
const root = path.resolve(kernel.path("workspaces"))
|
|
@@ -71,14 +71,14 @@ function createWorkspaceCatalogService({ kernel, workspaceRuntime, drafts }) {
|
|
|
71
71
|
liveByPath.set(normalizePathKey(group.cwd), group)
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
for (const
|
|
77
|
-
if (!
|
|
78
|
-
const key = normalizePathKey(
|
|
79
|
-
const list =
|
|
80
|
-
list.push(
|
|
81
|
-
|
|
74
|
+
const noteByPath = new Map()
|
|
75
|
+
const pendingNotes = notes ? await notes.listPending({}).catch(() => []) : []
|
|
76
|
+
for (const note of pendingNotes) {
|
|
77
|
+
if (!note.cwd) continue
|
|
78
|
+
const key = normalizePathKey(note.cwd)
|
|
79
|
+
const list = noteByPath.get(key) || []
|
|
80
|
+
list.push(note)
|
|
81
|
+
noteByPath.set(key, list)
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
const folders = entries.filter((entry) => entry.isDirectory())
|
|
@@ -91,13 +91,13 @@ function createWorkspaceCatalogService({ kernel, workspaceRuntime, drafts }) {
|
|
|
91
91
|
const live = liveByPath.get(key)
|
|
92
92
|
const shells = live?.shells || []
|
|
93
93
|
const scripts = live?.scripts || []
|
|
94
|
-
const
|
|
95
|
-
const
|
|
94
|
+
const workspaceNotes = noteByPath.get(key) || []
|
|
95
|
+
const note = newestNote(workspaceNotes)
|
|
96
96
|
const modifiedAtMs = stats?.mtimeMs || 0
|
|
97
97
|
const lastOpenedAtMs = latestTimestamp([
|
|
98
98
|
modifiedAtMs,
|
|
99
99
|
...shells.map((shell) => shell.start_time),
|
|
100
|
-
...
|
|
100
|
+
...workspaceNotes.map((item) => item.updatedAt),
|
|
101
101
|
])
|
|
102
102
|
const primaryShell = shells.length === 1 ? shells[0] : null
|
|
103
103
|
const primaryScript = scripts.length === 1 ? scripts[0] : null
|
|
@@ -116,12 +116,12 @@ function createWorkspaceCatalogService({ kernel, workspaceRuntime, drafts }) {
|
|
|
116
116
|
counts: {
|
|
117
117
|
shells: shells.length,
|
|
118
118
|
scripts: scripts.length,
|
|
119
|
-
|
|
119
|
+
notes: workspaceNotes.length,
|
|
120
120
|
},
|
|
121
121
|
shells,
|
|
122
122
|
scripts,
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
note,
|
|
124
|
+
noteReady: Boolean(note),
|
|
125
125
|
primaryUrl: primaryScript?.url || primaryShell?.url || null,
|
|
126
126
|
launchUrl: toRoutePath(cwd),
|
|
127
127
|
})
|
|
@@ -140,7 +140,7 @@ function createWorkspaceCatalogService({ kernel, workspaceRuntime, drafts }) {
|
|
|
140
140
|
total: items.length,
|
|
141
141
|
running: running.length,
|
|
142
142
|
offline: offline.length,
|
|
143
|
-
|
|
143
|
+
notes: items.filter((item) => item.noteReady).length,
|
|
144
144
|
},
|
|
145
145
|
}
|
|
146
146
|
}
|
|
@@ -1575,11 +1575,19 @@ body.dark .task-link-button.danger {
|
|
|
1575
1575
|
}
|
|
1576
1576
|
|
|
1577
1577
|
.task-run-footer {
|
|
1578
|
-
|
|
1578
|
+
display: grid;
|
|
1579
|
+
gap: 8px;
|
|
1580
|
+
margin-top: 2px;
|
|
1581
|
+
padding-top: 14px;
|
|
1582
|
+
border-top: 1px solid var(--task-border);
|
|
1579
1583
|
}
|
|
1580
1584
|
|
|
1581
|
-
.task-run-actions
|
|
1585
|
+
.task-run-actions,
|
|
1586
|
+
.task-run-footer .task-run-button {
|
|
1582
1587
|
margin: 0;
|
|
1588
|
+
width: 100%;
|
|
1589
|
+
min-height: 38px;
|
|
1590
|
+
font-size: 12px;
|
|
1583
1591
|
}
|
|
1584
1592
|
|
|
1585
1593
|
.task-submit-feedback {
|
|
@@ -1856,7 +1864,7 @@ body.dark .task-link-button.danger {
|
|
|
1856
1864
|
opacity: 0.55;
|
|
1857
1865
|
}
|
|
1858
1866
|
|
|
1859
|
-
.task-
|
|
1867
|
+
.task-run-footer .task-submit-feedback {
|
|
1860
1868
|
margin-top: 2px;
|
|
1861
1869
|
}
|
|
1862
1870
|
|
|
@@ -0,0 +1,336 @@
|
|
|
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
|
+
}
|