conductor-remote 1.3.0 → 1.5.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.
- package/dist/assets/index-BcgS8jNR.css +1 -0
- package/dist/assets/{index-Dmz09b0W.js → index-Dza-b9zD.js} +24 -24
- package/dist/index.html +2 -2
- package/dist/sw.js +1 -1
- package/package.json +1 -1
- package/src/icons.ts +66 -0
- package/src/reads.ts +14 -1
- package/src/server.ts +14 -1
- package/src/writes.ts +36 -21
- package/dist/assets/index-XHgQUzQO.css +0 -1
package/dist/index.html
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
|
12
12
|
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
|
13
13
|
<title>Conductor Remote</title>
|
|
14
|
-
<script type="module" crossorigin src="/assets/index-
|
|
15
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
14
|
+
<script type="module" crossorigin src="/assets/index-Dza-b9zD.js"></script>
|
|
15
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BcgS8jNR.css">
|
|
16
16
|
<link rel="manifest" href="/manifest.webmanifest"></head>
|
|
17
17
|
<body>
|
|
18
18
|
<div id="root"></div>
|
package/dist/sw.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
if(!self.define){let e,i={};const n=(n,s)=>(n=new URL(n+".js",s).href,i[n]||new Promise(i=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=i,document.head.appendChild(e)}else e=n,importScripts(n),i()}).then(()=>{let e=i[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e}));self.define=(s,o)=>{const r=e||("document"in self?document.currentScript.src:"")||location.href;if(i[r])return;let
|
|
1
|
+
if(!self.define){let e,i={};const n=(n,s)=>(n=new URL(n+".js",s).href,i[n]||new Promise(i=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=i,document.head.appendChild(e)}else e=n,importScripts(n),i()}).then(()=>{let e=i[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e}));self.define=(s,o)=>{const r=e||("document"in self?document.currentScript.src:"")||location.href;if(i[r])return;let c={};const t=e=>n(e,r),l={module:{uri:r},exports:c,require:t};i[r]=Promise.all(s.map(e=>l[e]||t(e))).then(e=>(o(...e),c))}}define(["./workbox-9c191d2f"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"index.html",revision:"679c71c87637a7da381d770ba23bd4e3"},{url:"assets/workbox-window.prod.es5-BBnX5xw4.js",revision:null},{url:"assets/index-Dza-b9zD.js",revision:null},{url:"assets/index-BcgS8jNR.css",revision:null},{url:"apple-touch-icon.png",revision:"2b9301416b880d45d4bb655f2600d1f2"},{url:"icon-192.png",revision:"c5e01ac58768627e18ee7b8b6a9239ef"},{url:"icon-512.png",revision:"a40638c55e310312457a621c9a0002c8"},{url:"icon-maskable-512.png",revision:"a40638c55e310312457a621c9a0002c8"},{url:"icon.svg",revision:"c1aee186821798733dd477e69a0ef243"},{url:"manifest.webmanifest",revision:"cf88fbc5755108a7fe0616fa160a8a15"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/index.html"),{denylist:[/^\/api\//]}))});
|
package/package.json
CHANGED
package/src/icons.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Repo-icon resolution, mirroring Conductor's own logic so the phone sidebar shows
|
|
6
|
+
* the same avatar as the desktop app. Conductor looks for a known icon filename in
|
|
7
|
+
* the repository root and uses the first match — see
|
|
8
|
+
* https://www.conductor.build/docs/faq#where-does-conductor-get-the-repo-icon
|
|
9
|
+
*
|
|
10
|
+
* This reads from the repo's root checkout (the shared, canonical tree), not a
|
|
11
|
+
* per-workspace worktree, so every workspace of a repo resolves to one icon.
|
|
12
|
+
*/
|
|
13
|
+
const ICON_CANDIDATES = [
|
|
14
|
+
'public/apple-touch-icon.png',
|
|
15
|
+
'apple-touch-icon.png',
|
|
16
|
+
'public/favicon.svg',
|
|
17
|
+
'favicon.svg',
|
|
18
|
+
'public/favicon.png',
|
|
19
|
+
'public/icon.png',
|
|
20
|
+
'public/logo.png',
|
|
21
|
+
'favicon.png',
|
|
22
|
+
'app/icon.png',
|
|
23
|
+
'src/app/icon.png',
|
|
24
|
+
'public/favicon.ico',
|
|
25
|
+
'favicon.ico',
|
|
26
|
+
'app/favicon.ico',
|
|
27
|
+
'static/favicon.ico',
|
|
28
|
+
'src-tauri/icons/icon.png',
|
|
29
|
+
'assets/icon.png',
|
|
30
|
+
'src/assets/icon.png'
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
const CONTENT_TYPES: Record<string, string> = {
|
|
34
|
+
'.png': 'image/png',
|
|
35
|
+
'.svg': 'image/svg+xml',
|
|
36
|
+
'.ico': 'image/x-icon'
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ResolvedIcon {
|
|
40
|
+
/** Absolute path to the icon file on disk. */
|
|
41
|
+
path: string
|
|
42
|
+
contentType: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Icons rarely change; a short TTL keeps the 2.5s state poll from stat-storming the
|
|
46
|
+
// disk while still picking up a freshly-added icon within a tick or two.
|
|
47
|
+
const TTL_MS = 30_000
|
|
48
|
+
const cache = new Map<string, { at: number; icon: ResolvedIcon | null }>()
|
|
49
|
+
|
|
50
|
+
/** First matching icon under `repoRoot`, or null if the repo has none. Cached per root. */
|
|
51
|
+
export function resolveRepoIcon(repoRoot: string): ResolvedIcon | null {
|
|
52
|
+
const now = Date.now()
|
|
53
|
+
const hit = cache.get(repoRoot)
|
|
54
|
+
if (hit && now - hit.at < TTL_MS) return hit.icon
|
|
55
|
+
|
|
56
|
+
let icon: ResolvedIcon | null = null
|
|
57
|
+
for (const rel of ICON_CANDIDATES) {
|
|
58
|
+
const abs = path.join(repoRoot, rel)
|
|
59
|
+
if (fs.existsSync(abs)) {
|
|
60
|
+
icon = { path: abs, contentType: CONTENT_TYPES[path.extname(abs).toLowerCase()] ?? 'application/octet-stream' }
|
|
61
|
+
break
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
cache.set(repoRoot, { at: now, icon })
|
|
65
|
+
return icon
|
|
66
|
+
}
|
package/src/reads.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { execFileSync } from 'node:child_process'
|
|
|
2
2
|
import fs from 'node:fs'
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import type { ConductorDb } from './db.ts'
|
|
5
|
+
import { type ResolvedIcon, resolveRepoIcon } from './icons.ts'
|
|
5
6
|
import { parseMessage, type TranscriptEntry } from './transcript.ts'
|
|
6
7
|
|
|
7
8
|
export interface WorkspaceRow {
|
|
@@ -43,6 +44,8 @@ export interface Workspace extends WorkspaceRow {
|
|
|
43
44
|
/** Absolute path to the git worktree on disk, or null if it can't be resolved. */
|
|
44
45
|
worktree: string | null
|
|
45
46
|
baseBranch: string
|
|
47
|
+
/** Whether the repo has a resolvable icon (fetch it from `/api/repos/:name/icon`). */
|
|
48
|
+
hasRepoIcon: boolean
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
const worktreeCache = new Map<string, string | null>()
|
|
@@ -115,7 +118,8 @@ export class Reads {
|
|
|
115
118
|
return rows.map(r => ({
|
|
116
119
|
...r,
|
|
117
120
|
worktree: resolveWorktree(this.workspacesRoot, r.repo_name, r.directory_name, r.branch, r.repo_root),
|
|
118
|
-
baseBranch: r.intended_target_branch || r.default_branch || 'main'
|
|
121
|
+
baseBranch: r.intended_target_branch || r.default_branch || 'main',
|
|
122
|
+
hasRepoIcon: !!(r.repo_root && resolveRepoIcon(r.repo_root))
|
|
119
123
|
}))
|
|
120
124
|
}
|
|
121
125
|
|
|
@@ -123,6 +127,15 @@ export class Reads {
|
|
|
123
127
|
return this.listWorkspaces().find(w => w.id === id) ?? null
|
|
124
128
|
}
|
|
125
129
|
|
|
130
|
+
/** Resolve a repo's icon by its name (the sidebar avatar) — null if the repo or icon is unknown. */
|
|
131
|
+
resolveRepoIcon(repoName: string): ResolvedIcon | null {
|
|
132
|
+
const rows = this.db.query<{ root_path: string | null }>('SELECT root_path FROM repos WHERE name = ? LIMIT 1', [
|
|
133
|
+
repoName
|
|
134
|
+
])
|
|
135
|
+
const root = rows[0]?.root_path
|
|
136
|
+
return root ? resolveRepoIcon(root) : null
|
|
137
|
+
}
|
|
138
|
+
|
|
126
139
|
listSessions(workspaceId: string): SessionRow[] {
|
|
127
140
|
// created_at ASC keeps tab order stable (matches the desktop app) instead of jumping on activity.
|
|
128
141
|
return this.db.query<SessionRow>(
|
package/src/server.ts
CHANGED
|
@@ -98,8 +98,21 @@ const server = http.createServer(async (req, res) => {
|
|
|
98
98
|
})
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
// GET /api/repos/:name/icon — the repo's resolved sidebar icon (see src/icons.ts)
|
|
102
|
+
let m = pathname.match(/^\/api\/repos\/([^/]+)\/icon$/)
|
|
103
|
+
if (req.method === 'GET' && m) {
|
|
104
|
+
const icon = reads.resolveRepoIcon(decodeURIComponent(m[1]))
|
|
105
|
+
if (!icon) return json(res, 404, { error: 'no icon' })
|
|
106
|
+
return void fs.readFile(icon.path, (err, data) => {
|
|
107
|
+
if (err) return void json(res, 404, { error: 'no icon' })
|
|
108
|
+
// Cache briefly on the phone; the resolver itself refreshes within ~30s of an icon change.
|
|
109
|
+
res.writeHead(200, { 'content-type': icon.contentType, 'cache-control': 'public, max-age=300' })
|
|
110
|
+
res.end(data)
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
|
|
101
114
|
// GET /api/workspaces/:id/sessions
|
|
102
|
-
|
|
115
|
+
m = pathname.match(/^\/api\/workspaces\/([^/]+)\/sessions$/)
|
|
103
116
|
if (req.method === 'GET' && m) {
|
|
104
117
|
return json(res, 200, { sessions: reads.listSessions(decodeURIComponent(m[1])) })
|
|
105
118
|
}
|
package/src/writes.ts
CHANGED
|
@@ -62,29 +62,48 @@ export class SidecarActuator implements Actuator {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
* Drives Conductor's real send path via macOS Accessibility (AppleScript):
|
|
66
|
-
*
|
|
65
|
+
* Drives Conductor's real send path via macOS Accessibility (AppleScript): focus
|
|
66
|
+
* the target workspace, paste the prompt, press Enter. Uses whatever model /
|
|
67
67
|
* permission mode the session already has (zero risk of altering the agent),
|
|
68
|
-
* which is why it's the default.
|
|
69
|
-
*
|
|
68
|
+
* which is why it's the default.
|
|
69
|
+
*
|
|
70
|
+
* Precise targeting comes from focusing the intended workspace first through
|
|
71
|
+
* Conductor's command palette (Cmd+K → branch → Enter) before pasting, so the
|
|
72
|
+
* prompt lands in the right session regardless of what was focused — no private
|
|
73
|
+
* IPC and nothing to rebreak on a Conductor update (unlike the sidecar).
|
|
70
74
|
*/
|
|
71
75
|
export class AppleScriptActuator implements Actuator {
|
|
72
76
|
readonly name = 'applescript'
|
|
73
|
-
readonly caveat =
|
|
74
|
-
|
|
75
|
-
readonly precise = false
|
|
77
|
+
readonly caveat = 'Focuses the target workspace via the command palette (Cmd+K) before sending.'
|
|
78
|
+
readonly precise = true
|
|
76
79
|
|
|
77
|
-
async send(
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
+
async send(target: SendTarget, text: string): Promise<SendResult> {
|
|
81
|
+
// The branch is Conductor's unique per-workspace key in the command palette;
|
|
82
|
+
// anything less specific can match a *command* (e.g. unarchive) instead of a
|
|
83
|
+
// workspace, so prefer branch and pass it via env to dodge AppleScript escaping.
|
|
84
|
+
const ws = target.workspace
|
|
85
|
+
const navQuery = ws.branch || ws.workspace_name || ws.directory_name || ''
|
|
86
|
+
const navigate = navQuery
|
|
87
|
+
? `
|
|
88
|
+
key code 53
|
|
89
|
+
delay 0.25
|
|
90
|
+
keystroke "k" using {command down}
|
|
91
|
+
delay 0.7
|
|
92
|
+
keystroke (system attribute "RELAY_WS_QUERY")
|
|
93
|
+
delay 0.9
|
|
94
|
+
key code 36
|
|
95
|
+
delay 1.3`
|
|
96
|
+
: ''
|
|
97
|
+
// Paste beats keystroke for long/multibyte prompts. Stash the clipboard,
|
|
98
|
+
// focus the target workspace, paste, send, and restore.
|
|
80
99
|
const script = `
|
|
81
100
|
set savedClipboard to the clipboard
|
|
82
|
-
set the clipboard to (do shell script "cat" & " " & quoted form of (system attribute "RELAY_PROMPT_FILE"))
|
|
83
101
|
tell application "Conductor" to activate
|
|
84
|
-
delay 0.
|
|
85
|
-
tell application "System Events"
|
|
102
|
+
delay 0.4
|
|
103
|
+
tell application "System Events"${navigate}
|
|
104
|
+
set the clipboard to (do shell script "cat" & " " & quoted form of (system attribute "RELAY_PROMPT_FILE"))
|
|
86
105
|
keystroke "v" using {command down}
|
|
87
|
-
delay 0.
|
|
106
|
+
delay 0.15
|
|
88
107
|
key code 36
|
|
89
108
|
end tell
|
|
90
109
|
delay 0.1
|
|
@@ -98,14 +117,10 @@ set the clipboard to savedClipboard
|
|
|
98
117
|
await fs.writeFile(tmp, text, 'utf8')
|
|
99
118
|
try {
|
|
100
119
|
await exec('osascript', ['-e', script], {
|
|
101
|
-
env: { ...process.env, RELAY_PROMPT_FILE: tmp },
|
|
102
|
-
timeout:
|
|
120
|
+
env: { ...process.env, RELAY_PROMPT_FILE: tmp, RELAY_WS_QUERY: navQuery },
|
|
121
|
+
timeout: 15000
|
|
103
122
|
})
|
|
104
|
-
return {
|
|
105
|
-
ok: true,
|
|
106
|
-
strategy: this.name,
|
|
107
|
-
warning: 'Delivered to the focused Conductor session — confirm it landed in the intended workspace.'
|
|
108
|
-
}
|
|
123
|
+
return { ok: true, strategy: this.name }
|
|
109
124
|
} catch (err) {
|
|
110
125
|
return {
|
|
111
126
|
ok: false,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, -apple-system, "SF Pro Text", "Segoe UI", Roboto, sans-serif;--font-mono:ui-monospace, "SF Mono", "JetBrains Mono", "Fira Code", Menlo, monospace;--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--leading-tight:1.25;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--radius-3xl:1.5rem;--ease-out:cubic-bezier(0, 0, .2, 1);--animate-spin:spin 1s linear infinite;--blur-xl:24px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-bg:#0a0b0e;--color-surface:#14161b;--color-surface-2:#1b1e26;--color-border:#262a33;--color-border-soft:#1e222a;--color-text:#e7e9ee;--color-muted:#8b909d;--color-faint:#5c616d;--color-accent:#8b7dff;--color-accent-soft:#2a2650;--color-working:#f5a623;--color-idle:#3ecf8e;--color-done:#5b9dff;--color-add:#3ecf8e;--color-del:#ff6b6b}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*{-webkit-tap-highlight-color:transparent}html,body,#root{height:100%}body{background:var(--color-bg);color:var(--color-text);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;overscroll-behavior-y:none;margin:0;overflow-x:hidden}button{font:inherit;color:inherit;cursor:pointer}::-webkit-scrollbar{width:0;height:0}}@layer components{.card{align-items:center;gap:calc(var(--spacing) * 3);border-radius:var(--radius-2xl);border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-border);background-color:var(--color-surface);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3.5);text-align:left;transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));display:flex}.card:active{background-color:var(--color-surface-2);scale:.985}.pill{padding-inline:calc(var(--spacing) * 3.5);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--color-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));border-radius:3.40282e38px}.pill-active{background-color:var(--color-surface-2);color:var(--color-text)}.dot{width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5);background-color:var(--color-faint);border-radius:3.40282e38px;flex-shrink:0}.dot-working{background:var(--color-working);box-shadow:0 0 #f5a62399}@supports (color:color-mix(in lab,red,red)){.dot-working{box-shadow:0 0 color-mix(in srgb,var(--color-working) 60%,transparent)}}.dot-working{animation:1.6s ease-out infinite pulse}.dot-idle{background:var(--color-idle)}.dot-done{background:var(--color-done)}.md>:first-child{margin-top:0}.md>:last-child{margin-bottom:0}.md p{margin:.5em 0}.md h1,.md h2,.md h3,.md h4,.md h5,.md h6{margin:.9em 0 .4em;font-weight:600;line-height:1.3}.md h1{font-size:1.25em}.md h2{font-size:1.15em}.md h3{font-size:1.05em}.md ul,.md ol{margin:.5em 0;padding-left:1.4em}.md ul{list-style:outside}.md ol{list-style:decimal}.md li,.md li>ul,.md li>ol{margin:.2em 0}.md code{background:#1b1e26cc;border-radius:.3rem}@supports (color:color-mix(in lab,red,red)){.md code{background:color-mix(in srgb,var(--color-surface-2) 80%,transparent)}}.md code{font-family:var(--font-mono);padding:.1em .35em;font-size:.85em}.md pre{border:1px solid var(--color-border-soft);background:var(--color-bg);border-radius:.6rem;margin:.5em 0;padding:.6em .75em;overflow-x:auto}.md pre code{background:0 0;padding:0;font-size:12px;line-height:1.5}.md a{color:var(--color-accent);text-underline-offset:2px;text-decoration:underline}.md blockquote{border-left:2px solid var(--color-border);color:var(--color-muted);margin:.5em 0;padding-left:.75em}.md hr{border:0;border-top:1px solid var(--color-border-soft);margin:.75em 0}.md table{border-collapse:collapse;max-width:100%;margin:.5em 0;font-size:.9em;display:block;overflow-x:auto}.md th,.md td{border:1px solid var(--color-border);text-align:left;padding:.3em .6em}.md th{background:var(--color-surface-2);font-weight:600}.md strong{font-weight:600}.md input[type=checkbox]{margin-right:.4em}}@layer utilities{.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{inset-block:0}.top-0{top:0}.top-1\.5{top:calc(var(--spacing) * 1.5)}.top-full{top:100%}.right-1\.5{right:calc(var(--spacing) * 1.5)}.right-2{right:calc(var(--spacing) * 2)}.left-0{left:0}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.mx-auto{margin-inline:auto}.mt-1{margin-top:var(--spacing)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.-mr-1{margin-right:calc(var(--spacing) * -1)}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:var(--spacing)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.-ml-1{margin-left:calc(var(--spacing) * -1)}.ml-auto{margin-left:auto}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.size-1\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.size-1\.5\!{width:calc(var(--spacing) * 1.5)!important;height:calc(var(--spacing) * 1.5)!important}.size-2{width:calc(var(--spacing) * 2);height:calc(var(--spacing) * 2)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.size-20{width:calc(var(--spacing) * 20);height:calc(var(--spacing) * 20)}.h-full{height:100%}.max-h-40{max-height:calc(var(--spacing) * 40)}.w-1{width:var(--spacing)}.w-64{width:calc(var(--spacing) * 64)}.w-\[85\%\]{width:85%}.w-full{width:100%}.max-w-36{max-width:calc(var(--spacing) * 36)}.max-w-80{max-width:calc(var(--spacing) * 80)}.max-w-\[85\%\]{max-width:85%}.max-w-\[92\%\]{max-width:92%}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:0}.min-w-5{min-width:calc(var(--spacing) * 5)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-x-full{--tw-translate-x:-100%;translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-0{--tw-translate-x:0;translate:var(--tw-translate-x) var(--tw-translate-y)}.-rotate-90{rotate:-90deg}.animate-spin{animation:var(--animate-spin)}.resize-none{resize:none}.flex-col{flex-direction:column}.place-items-center{place-items:center}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-5{gap:calc(var(--spacing) * 5)}.self-start{align-self:flex-start}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-3xl{border-radius:var(--radius-3xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-accent\/50{border-color:#8b7dff80}@supports (color:color-mix(in lab,red,red)){.border-accent\/50{border-color:color-mix(in oklab,var(--color-accent) 50%,transparent)}}.border-border{border-color:var(--color-border)}.border-border-soft{border-color:var(--color-border-soft)}.border-faint{border-color:var(--color-faint)}.border-t-accent{border-top-color:var(--color-accent)}.bg-accent{background-color:var(--color-accent)}.bg-accent-soft{background-color:var(--color-accent-soft)}.bg-bg{background-color:var(--color-bg)}.bg-bg\/80{background-color:#0a0b0ecc}@supports (color:color-mix(in lab,red,red)){.bg-bg\/80{background-color:color-mix(in oklab,var(--color-bg) 80%,transparent)}}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab,red,red)){.bg-black\/50{background-color:color-mix(in oklab,var(--color-black) 50%,transparent)}}.bg-del\/10{background-color:#ff6b6b1a}@supports (color:color-mix(in lab,red,red)){.bg-del\/10{background-color:color-mix(in oklab,var(--color-del) 10%,transparent)}}.bg-idle\/10{background-color:#3ecf8e1a}@supports (color:color-mix(in lab,red,red)){.bg-idle\/10{background-color:color-mix(in oklab,var(--color-idle) 10%,transparent)}}.bg-surface{background-color:var(--color-surface)}.bg-surface-2{background-color:var(--color-surface-2)}.bg-surface\/60{background-color:#14161b99}@supports (color:color-mix(in lab,red,red)){.bg-surface\/60{background-color:color-mix(in oklab,var(--color-surface) 60%,transparent)}}.bg-transparent{background-color:#0000}.bg-working\/10{background-color:#f5a6231a}@supports (color:color-mix(in lab,red,red)){.bg-working\/10{background-color:color-mix(in oklab,var(--color-working) 10%,transparent)}}.p-3{padding:calc(var(--spacing) * 3)}.p-6{padding:calc(var(--spacing) * 6)}.px-1{padding-inline:var(--spacing)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-16{padding-block:calc(var(--spacing) * 16)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-2\.5{padding-bottom:calc(var(--spacing) * 2.5)}.pl-2{padding-left:calc(var(--spacing) * 2)}.text-center{text-align:center}.font-mono{font-family:var(--font-mono)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[11\.5px\]{font-size:11.5px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.leading-\[1\.5\]{--tw-leading:1.5;line-height:1.5}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.\[overflow-wrap\:anywhere\]{overflow-wrap:anywhere}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.text-accent{color:var(--color-accent)}.text-add{color:var(--color-add)}.text-del{color:var(--color-del)}.text-faint{color:var(--color-faint)}.text-idle{color:var(--color-idle)}.text-muted{color:var(--color-muted)}.text-text{color:var(--color-text)}.text-white{color:var(--color-white)}.text-working{color:var(--color-working)}.capitalize{text-transform:capitalize}.uppercase{text-transform:uppercase}.italic{font-style:italic}.\[color-scheme\:dark\]{color-scheme:dark}.opacity-60{opacity:.6}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur-xl{--tw-backdrop-blur:blur(var(--blur-xl));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.outline-none{--tw-outline-style:none;outline-style:none}.placeholder\:text-faint::placeholder{color:var(--color-faint)}.focus-within\:border-accent\/60:focus-within{border-color:#8b7dff99}@supports (color:color-mix(in lab,red,red)){.focus-within\:border-accent\/60:focus-within{border-color:color-mix(in oklab,var(--color-accent) 60%,transparent)}}.active\:scale-90:active{--tw-scale-x:90%;--tw-scale-y:90%;--tw-scale-z:90%;scale:var(--tw-scale-x) var(--tw-scale-y)}.active\:bg-surface-2:active,.disabled\:bg-surface-2:disabled{background-color:var(--color-surface-2)}.disabled\:text-faint:disabled{color:var(--color-faint)}.disabled\:opacity-50:disabled{opacity:.5}@media(min-width:48rem){.md\:static{position:static}.md\:z-auto{z-index:auto}.md\:block{display:block}.md\:hidden{display:none}.md\:w-72{width:calc(var(--spacing) * 72)}.md\:max-w-none{max-width:none}.md\:shrink-0{flex-shrink:0}.md\:translate-x-0{--tw-translate-x:0;translate:var(--tw-translate-x) var(--tw-translate-y)}.md\:transition-none{transition-property:none}}@media(min-width:64rem){.lg\:static{position:static}.lg\:z-auto{z-index:auto}.lg\:w-80{width:calc(var(--spacing) * 80)}.lg\:w-\[380px\]{width:380px}.lg\:shrink-0{flex-shrink:0}.lg\:border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.lg\:border-border-soft{border-color:var(--color-border-soft)}}@media(min-width:80rem){.xl\:w-\[460px\]{width:460px}}}@keyframes pulse{50%{opacity:.5}}@keyframes fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}.fade-in{animation:.18s ease-out fade-in}.pt-safe{padding-top:max(env(safe-area-inset-top),.5rem)}.pb-safe{padding-bottom:max(env(safe-area-inset-bottom),.5rem)}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@keyframes spin{to{transform:rotate(360deg)}}
|