agentus 0.3.8 → 0.4.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/README.md +35 -0
- package/README.zh-CN.md +31 -0
- package/bin/agentus.mjs +27 -0
- package/bin/cli.mjs +339 -0
- package/docs/installation.md +1 -0
- package/package.json +3 -1
- package/packages/server/mcp/plan-server.mjs +18 -3
- package/packages/server/mock/agent.mjs +19 -0
- package/packages/server/src/acp/backends.ts +25 -0
- package/packages/server/src/acp/registry.ts +6 -0
- package/packages/server/src/acp/session-manager.ts +269 -25
- package/packages/server/src/cockpit/api.ts +402 -0
- package/packages/server/src/index.ts +293 -7
- package/packages/server/src/notify/center.ts +55 -4
- package/packages/server/src/notify/types.ts +6 -1
- package/packages/server/src/observer/hub.ts +327 -0
- package/packages/server/src/plan/plan.ts +16 -0
- package/packages/server/src/settings.ts +166 -8
- package/packages/server/src/skills/install.ts +102 -0
- package/packages/server/src/store/store.ts +51 -13
- package/packages/shared/src/index.ts +34 -1
- package/packages/web/dist/assets/index-CRo7LVdP.css +32 -0
- package/packages/web/dist/assets/index-q4g0lPdX.js +123 -0
- package/packages/web/dist/index.html +2 -2
- package/skills/agentus-cockpit/SKILL.md +183 -0
- package/packages/web/dist/assets/index-DgPLH0bG.css +0 -32
- package/packages/web/dist/assets/index-x3AVKD8Y.js +0 -122
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ship the cockpit's own skills to the agents it spawns.
|
|
3
|
+
*
|
|
4
|
+
* WHY A SKILL AND NOT A PROMPT
|
|
5
|
+
* The cockpit CLI can only be used if the agent knows it exists, and the two ways of telling it are
|
|
6
|
+
* not equal. Pasting the manual into every first prompt costs tokens forever and goes stale the
|
|
7
|
+
* moment a command changes; a file the agent reads WHEN it matters costs nothing until then. Which
|
|
8
|
+
* of the two is even possible depends on the backend — the ACP protocol has no skill object at all,
|
|
9
|
+
* so each product invents one (see `docs/refs/aionui-acp-rules.md`; AionCore keys it off a per-agent
|
|
10
|
+
* `native_skills_dirs`, symlinking skills into the workspace and falling back to a prompt-injected
|
|
11
|
+
* index). That is exactly the split here:
|
|
12
|
+
*
|
|
13
|
+
* · `BackendSpec.skillsDir` — the agent discovers `<dir>/<name>/SKILL.md` natively (Hermes reads
|
|
14
|
+
* `$HERMES_HOME/skills`). We install into that dir at spawn.
|
|
15
|
+
* · no `skillsDir` — nothing native exists (Qoder ships `--plugin-dir`/`AGENTS.md`, not skill
|
|
16
|
+
* folders). The agent gets one line in the plan reminder and pulls the document from the CLI
|
|
17
|
+
* itself (`agentus cockpit skill`), which is the same bytes with no prompt cost at all.
|
|
18
|
+
*
|
|
19
|
+
* WHAT THIS IS NOT
|
|
20
|
+
* Not a package manager and not a syncer. It writes the cockpit's OWN skill directories, compares
|
|
21
|
+
* bytes so a second call is a no-op, and never deletes or rewrites anything it did not put there —
|
|
22
|
+
* the agent's home belongs to the operator.
|
|
23
|
+
*/
|
|
24
|
+
import fs from "node:fs";
|
|
25
|
+
import path from "node:path";
|
|
26
|
+
import { fileURLToPath } from "node:url";
|
|
27
|
+
|
|
28
|
+
/** `<pkg>/skills`. Resolved from this file, so a global install, an `npx` checkout and a source
|
|
29
|
+
* worktree all find the same corpus (`packages/server/src/skills/` → up four). */
|
|
30
|
+
export const SKILLS_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../../skills");
|
|
31
|
+
|
|
32
|
+
export interface BundledSkill {
|
|
33
|
+
/** directory name == the skill's `name:` in its frontmatter */
|
|
34
|
+
name: string;
|
|
35
|
+
/** absolute path of its SKILL.md */
|
|
36
|
+
file: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface InstallResult {
|
|
40
|
+
/** the skills dir we wrote into */
|
|
41
|
+
dir: string;
|
|
42
|
+
installed: string[];
|
|
43
|
+
updated: string[];
|
|
44
|
+
unchanged: string[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** The skills this package carries. A directory counts only if it holds a `SKILL.md` — an empty or
|
|
48
|
+
* half-written folder must not become an empty skill in someone's home. */
|
|
49
|
+
export function bundledSkills(root: string = SKILLS_ROOT): BundledSkill[] {
|
|
50
|
+
let names: string[] = [];
|
|
51
|
+
try {
|
|
52
|
+
names = fs.readdirSync(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
53
|
+
} catch {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
return names
|
|
57
|
+
.map((name) => ({ name, file: path.join(root, name, "SKILL.md") }))
|
|
58
|
+
.filter((s) => fs.existsSync(s.file))
|
|
59
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Install (or refresh) this package's skills into `dir`, which is the agent's own skills directory.
|
|
64
|
+
*
|
|
65
|
+
* Idempotent by CONTENT, not by presence: a skill whose text changed in a release is rewritten, one
|
|
66
|
+
* that did not is left untouched — so calling this on every spawn costs one `readFileSync` per skill
|
|
67
|
+
* and produces no disk churn, no mtime churn, and nothing for the agent to re-index.
|
|
68
|
+
*
|
|
69
|
+
* Throws only on an unusable `dir`. Callers treat a failure as a warning: a session whose skill
|
|
70
|
+
* could not be installed still WORKS, it just has to discover the CLI from the prompt line.
|
|
71
|
+
*/
|
|
72
|
+
export function installSkills(dir: string, root: string = SKILLS_ROOT): InstallResult {
|
|
73
|
+
const skills = bundledSkills(root);
|
|
74
|
+
const result: InstallResult = { dir, installed: [], updated: [], unchanged: [] };
|
|
75
|
+
if (!skills.length) return result;
|
|
76
|
+
|
|
77
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
78
|
+
for (const skill of skills) {
|
|
79
|
+
const target = path.join(dir, skill.name, "SKILL.md");
|
|
80
|
+
const wanted = fs.readFileSync(skill.file, "utf8");
|
|
81
|
+
let current: string | null = null;
|
|
82
|
+
try {
|
|
83
|
+
current = fs.readFileSync(target, "utf8");
|
|
84
|
+
} catch {
|
|
85
|
+
current = null;
|
|
86
|
+
}
|
|
87
|
+
if (current === wanted) {
|
|
88
|
+
result.unchanged.push(skill.name);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
92
|
+
fs.writeFileSync(target, wanted);
|
|
93
|
+
(current === null ? result.installed : result.updated).push(skill.name);
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** `"{home}/skills"` → the real path. Kept tiny and separate so a spec's template cannot be
|
|
99
|
+
* half-interpreted in one call site and not another. */
|
|
100
|
+
export function resolveSkillsDir(template: string, home: string): string {
|
|
101
|
+
return template.replaceAll("{home}", home);
|
|
102
|
+
}
|
|
@@ -71,6 +71,8 @@ export interface SessionRow {
|
|
|
71
71
|
/** the generated name, kept aside so a rename is reversible and an automatic title can
|
|
72
72
|
* never stomp the operator's own (see the interface comment in @agentus/shared) */
|
|
73
73
|
autoTitle?: string | null;
|
|
74
|
+
/** session id of whoever renamed it through the cockpit CLI; null = the operator's own name */
|
|
75
|
+
titleBy?: string | null;
|
|
74
76
|
status: SessionStatus;
|
|
75
77
|
pid: number | null;
|
|
76
78
|
createdAt: number;
|
|
@@ -78,6 +80,10 @@ export interface SessionRow {
|
|
|
78
80
|
/** When the OPERATOR put this session away (已归档). Null = it belongs in 工作空间. A storage
|
|
79
81
|
* state: it says nothing about whether a process is running (see SessionInfo.archivedAt). */
|
|
80
82
|
archivedAt: number | null;
|
|
83
|
+
/** A session the COCKPIT owns rather than the operator (issue #16's observer): a real ACP
|
|
84
|
+
* session, kept out of the rail and out of the cockpit CLI's scope. Written on insert only —
|
|
85
|
+
* like `home`, it is a fact about how the row was born, not something a rename can change. */
|
|
86
|
+
system?: boolean;
|
|
81
87
|
/** JSON round-trip of the ACP mode state + config options, so a resumed
|
|
82
88
|
* session (M4-lite) comes back with the operator's mode/effort intact. */
|
|
83
89
|
modes?: unknown;
|
|
@@ -107,13 +113,14 @@ export interface SessionRow {
|
|
|
107
113
|
|
|
108
114
|
interface RawSessionRow {
|
|
109
115
|
id: string; backend: BackendId; acp_session_id: string | null; cwd: string;
|
|
110
|
-
title: string; auto_title?: string | null; status: SessionStatus; pid: number | null;
|
|
116
|
+
title: string; auto_title?: string | null; title_by?: string | null; status: SessionStatus; pid: number | null;
|
|
111
117
|
created_at: number; closed_at: number | null; archived_at?: number | null;
|
|
112
118
|
modes?: string | null; config_options?: string | null;
|
|
113
119
|
usage?: string | null; commands?: string | null;
|
|
114
120
|
workspace?: string | null;
|
|
115
121
|
home?: string | null;
|
|
116
122
|
models?: string | null; context_limit?: number | null;
|
|
123
|
+
system?: number | null;
|
|
117
124
|
}
|
|
118
125
|
|
|
119
126
|
function parseJson(v: string | null | undefined): unknown {
|
|
@@ -171,12 +178,13 @@ function blockKeyOf(kind: string, payload: unknown): string | null {
|
|
|
171
178
|
function rowToSession(r: RawSessionRow): SessionRow {
|
|
172
179
|
return {
|
|
173
180
|
id: r.id, backend: r.backend, acpSessionId: r.acp_session_id, cwd: r.cwd,
|
|
174
|
-
title: r.title, autoTitle: r.auto_title ?? null, status: r.status, pid: r.pid,
|
|
181
|
+
title: r.title, autoTitle: r.auto_title ?? null, titleBy: r.title_by ?? null, status: r.status, pid: r.pid,
|
|
175
182
|
createdAt: r.created_at, closedAt: r.closed_at, archivedAt: r.archived_at ?? null,
|
|
176
183
|
modes: parseJson(r.modes), configOptions: parseJson(r.config_options) ?? [],
|
|
177
184
|
usage: parseJson(r.usage), commands: parseJson(r.commands) ?? [],
|
|
178
185
|
workspace: r.workspace ?? null,
|
|
179
186
|
home: r.home ?? null,
|
|
187
|
+
system: Boolean(r.system),
|
|
180
188
|
models: parseJson(r.models),
|
|
181
189
|
contextLimit: r.context_limit ?? null,
|
|
182
190
|
};
|
|
@@ -242,6 +250,7 @@ interface RawPlanRow {
|
|
|
242
250
|
session_id: string;
|
|
243
251
|
revision: number;
|
|
244
252
|
items: string;
|
|
253
|
+
title: string | null;
|
|
245
254
|
explanation: string | null;
|
|
246
255
|
source: string;
|
|
247
256
|
terminal: string | null;
|
|
@@ -252,6 +261,9 @@ interface RawPlanRow {
|
|
|
252
261
|
* (only an agent writes one, and most plan updates carry none) — see `upsertPlan`. */
|
|
253
262
|
export interface PlanPatch {
|
|
254
263
|
items: unknown;
|
|
264
|
+
/** `undefined` keeps the title that is there — the same rule as `explanation`, and the reason a
|
|
265
|
+
* routine `items`-only update does not erase the one phrase the completion card reads. */
|
|
266
|
+
title?: string | null;
|
|
255
267
|
explanation?: string | null;
|
|
256
268
|
source: PlanSnapshot["source"];
|
|
257
269
|
terminal?: string | null;
|
|
@@ -262,6 +274,7 @@ function rowToPlan(r: RawPlanRow): PlanSnapshot {
|
|
|
262
274
|
sessionId: r.session_id,
|
|
263
275
|
revision: r.revision,
|
|
264
276
|
items: normalizeItems(parseJson(r.items)),
|
|
277
|
+
title: r.title,
|
|
265
278
|
explanation: r.explanation,
|
|
266
279
|
source: r.source === "acp" || r.source === "mcp" ? r.source : "server",
|
|
267
280
|
terminal: r.terminal,
|
|
@@ -282,7 +295,10 @@ export class Store {
|
|
|
282
295
|
create table if not exists sessions (
|
|
283
296
|
id text primary key, backend text not null, acp_session_id text,
|
|
284
297
|
cwd text not null, title text not null, status text not null,
|
|
285
|
-
pid integer, created_at integer not null, closed_at integer, home text
|
|
298
|
+
pid integer, created_at integer not null, closed_at integer, home text,
|
|
299
|
+
-- 1 = a session the COCKPIT spawned for itself (the 工作播报 observer), never the operator's
|
|
300
|
+
-- work: filtered out of the rail and out of the cockpit CLI's scope. See SessionRow.system.
|
|
301
|
+
system integer not null default 0
|
|
286
302
|
);
|
|
287
303
|
create table if not exists messages (
|
|
288
304
|
seq integer not null, session_id text not null, kind text not null,
|
|
@@ -322,7 +338,7 @@ export class Store {
|
|
|
322
338
|
-- its process and the frames on screen are stale (design-plan-service.md §1).
|
|
323
339
|
create table if not exists plans (
|
|
324
340
|
session_id text primary key, revision integer not null default 0,
|
|
325
|
-
items text not null, explanation text, source text not null,
|
|
341
|
+
items text not null, title text, explanation text, source text not null,
|
|
326
342
|
terminal text, updated_at integer not null
|
|
327
343
|
);
|
|
328
344
|
`);
|
|
@@ -343,6 +359,11 @@ export class Store {
|
|
|
343
359
|
this.#db.exec("update sessions set auto_title = title where auto_title is null or auto_title = ''");
|
|
344
360
|
// integer column, so it gets its own migration (the loop above assumes text)
|
|
345
361
|
if (!cols.has("context_limit")) this.#db.exec("alter table sessions add column context_limit integer");
|
|
362
|
+
// WHICH SESSIONS THE COCKPIT OWNS (issue #16): 1 = the 工作播报 observer, 0 = the operator's work.
|
|
363
|
+
// Its own column rather than a title convention, because this flag decides whether a row is
|
|
364
|
+
// allowed into the rail, the warm-slot ranking and the cockpit CLI's scope — a rename must not be
|
|
365
|
+
// able to move a session between those worlds.
|
|
366
|
+
if (!cols.has("system")) this.#db.exec("alter table sessions add column system integer not null default 0");
|
|
346
367
|
// WHEN THE OPERATOR PUT THE SESSION AWAY (已归档 — a STORAGE state). Before this column the rail
|
|
347
368
|
// inferred "archived" from "has no process", so a slot that merely crashed (or was killed by an
|
|
348
369
|
// idle reap) filed itself under 已归档 next to the ones the operator really put away, and
|
|
@@ -350,6 +371,11 @@ export class Store {
|
|
|
350
371
|
// row: nobody ever archived them, they were just dead. The 已归档 section starts empty and fills
|
|
351
372
|
// with what the operator actually archives.
|
|
352
373
|
if (!cols.has("archived_at")) this.#db.exec("alter table sessions add column archived_at integer");
|
|
374
|
+
// WHO GAVE THIS SESSION ITS NAME. `title` says what a slot is called; nothing said who called it
|
|
375
|
+
// that, so another agent could quietly rename the operator's conversation to 「已完成 ✓」 and the
|
|
376
|
+
// rail would show it as fact. NULL = the operator (every existing row), a session id = that
|
|
377
|
+
// session's agent renamed it through the cockpit CLI.
|
|
378
|
+
if (!cols.has("title_by")) this.#db.exec("alter table sessions add column title_by text");
|
|
353
379
|
// The session's own ACTIVITY clock — when the operator or the agent last really said something
|
|
354
380
|
// in it. A COLUMN, not a derived `max(messages.created_at)` (AionUi's model: `modified_at` on
|
|
355
381
|
// the conversation row, indexed, which is what its sidebar sorts by): every ingestion path
|
|
@@ -365,6 +391,13 @@ export class Store {
|
|
|
365
391
|
);
|
|
366
392
|
if (!mcols.has("block_key")) this.#db.exec("alter table messages add column block_key text");
|
|
367
393
|
this.#db.exec("create index if not exists idx_messages_block on messages (session_id, block_key)");
|
|
394
|
+
// plans: the one-line TITLE a completion notification reads (issue #11). Additive, and null for
|
|
395
|
+
// every existing plan — a card that has never been given a title falls back to its remark, and
|
|
396
|
+
// then to the last step it closed, so an old store keeps behaving exactly as before.
|
|
397
|
+
const pcols = new Set(
|
|
398
|
+
(this.#db.prepare("pragma table_info(plans)").all() as { name: string }[]).map((c) => c.name),
|
|
399
|
+
);
|
|
400
|
+
if (!pcols.has("title")) this.#db.exec("alter table plans add column title text");
|
|
368
401
|
// additive migration (M6.1): the health snapshot + cached handshake on a backend row. Kept
|
|
369
402
|
// as its own column block so a row insert/update never has to carry them (they are written
|
|
370
403
|
// by recordBackendCheck alone, and by nothing else).
|
|
@@ -702,13 +735,13 @@ export class Store {
|
|
|
702
735
|
} else {
|
|
703
736
|
this.#db
|
|
704
737
|
.prepare(
|
|
705
|
-
`insert into sessions (id, backend, acp_session_id, cwd, title, status, pid, created_at, closed_at, modes, config_options, usage, commands, models, auto_title, home)
|
|
706
|
-
values (
|
|
738
|
+
`insert into sessions (id, backend, acp_session_id, cwd, title, status, pid, created_at, closed_at, modes, config_options, usage, commands, models, auto_title, home, system)
|
|
739
|
+
values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
|
|
707
740
|
)
|
|
708
741
|
.run(s.id, s.backend, s.acpSessionId, s.cwd, s.title, s.status, s.pid, s.createdAt, s.closedAt,
|
|
709
742
|
JSON.stringify(s.modes ?? null), JSON.stringify(s.configOptions ?? []),
|
|
710
743
|
JSON.stringify(s.usage ?? null), JSON.stringify(s.commands ?? []),
|
|
711
|
-
JSON.stringify(s.models ?? null), s.title, s.home ?? null);
|
|
744
|
+
JSON.stringify(s.models ?? null), s.title, s.home ?? null, s.system ? 1 : 0);
|
|
712
745
|
}
|
|
713
746
|
}
|
|
714
747
|
|
|
@@ -819,7 +852,7 @@ export class Store {
|
|
|
819
852
|
getPlan(sessionId: string): PlanSnapshot | null {
|
|
820
853
|
const row = this.#db
|
|
821
854
|
.prepare(
|
|
822
|
-
`select session_id, revision, items, explanation, source, terminal, updated_at
|
|
855
|
+
`select session_id, revision, items, title, explanation, source, terminal, updated_at
|
|
823
856
|
from plans where session_id = ?`,
|
|
824
857
|
)
|
|
825
858
|
.get(sessionId) as RawPlanRow | undefined;
|
|
@@ -834,18 +867,21 @@ export class Store {
|
|
|
834
867
|
const prev = this.getPlan(sessionId);
|
|
835
868
|
const explanation =
|
|
836
869
|
patch.explanation === undefined ? (prev?.explanation ?? null) : patch.explanation;
|
|
870
|
+
const title = patch.title === undefined ? (prev?.title ?? null) : patch.title;
|
|
837
871
|
this.#db
|
|
838
872
|
.prepare(
|
|
839
|
-
`insert into plans (session_id, revision, items, explanation, source, terminal, updated_at)
|
|
840
|
-
values (?, ?, ?, ?, ?, ?, ?)
|
|
873
|
+
`insert into plans (session_id, revision, items, title, explanation, source, terminal, updated_at)
|
|
874
|
+
values (?, ?, ?, ?, ?, ?, ?, ?)
|
|
841
875
|
on conflict(session_id) do update set
|
|
842
|
-
revision = excluded.revision, items = excluded.items,
|
|
876
|
+
revision = excluded.revision, items = excluded.items, title = excluded.title,
|
|
877
|
+
explanation = excluded.explanation,
|
|
843
878
|
source = excluded.source, terminal = excluded.terminal, updated_at = excluded.updated_at`,
|
|
844
879
|
)
|
|
845
880
|
.run(
|
|
846
881
|
sessionId,
|
|
847
882
|
(prev?.revision ?? 0) + 1,
|
|
848
883
|
JSON.stringify(normalizeItems(patch.items)),
|
|
884
|
+
title,
|
|
849
885
|
explanation,
|
|
850
886
|
patch.source,
|
|
851
887
|
patch.terminal ?? null,
|
|
@@ -1058,13 +1094,15 @@ export class Store {
|
|
|
1058
1094
|
* Only `title` changes — `auto_title` is what the generated name survives in, so a
|
|
1059
1095
|
* rename is always reversible (studio keeps the two apart the same way: a null title
|
|
1060
1096
|
* falls back to the first-message preview). Returns false when the id is unknown. */
|
|
1061
|
-
renameSession(id: string, title: string | null): boolean {
|
|
1097
|
+
renameSession(id: string, title: string | null, by: string | null = null): boolean {
|
|
1062
1098
|
const row = this.#db.prepare("select title, auto_title from sessions where id = ?").get(id) as
|
|
1063
1099
|
| { title: string; auto_title: string | null }
|
|
1064
1100
|
| undefined;
|
|
1065
1101
|
if (!row) return false;
|
|
1066
1102
|
const next = title == null || !title.length ? (row.auto_title ?? row.title) : title;
|
|
1067
|
-
|
|
1103
|
+
// `by` rides along on every write, including a reset: after `--auto` the name is generated again,
|
|
1104
|
+
// and the note that an agent once renamed it would be a lie about the CURRENT name.
|
|
1105
|
+
const info = this.#db.prepare("update sessions set title = ?, title_by = ? where id = ?").run(next, by, id);
|
|
1068
1106
|
return Number(info.changes ?? 0) > 0;
|
|
1069
1107
|
}
|
|
1070
1108
|
|
|
@@ -46,6 +46,11 @@ export interface SessionInfo {
|
|
|
46
46
|
status: SessionStatus;
|
|
47
47
|
pid: number | null;
|
|
48
48
|
title: string;
|
|
49
|
+
/** WHO named this session's CURRENT title: null = the operator (or nobody in particular), a
|
|
50
|
+
* session id = that session's agent renamed it through the cockpit CLI. The rail shows a note
|
|
51
|
+
* when a name came from another agent — a rename is a claim about what a conversation IS, and
|
|
52
|
+
* nothing else in this product says who made one. */
|
|
53
|
+
titleBy?: string | null;
|
|
49
54
|
/** The GENERATED name (what the agent announced via ACP `session_info_update`, or our
|
|
50
55
|
* own derivation from the first prompt). `title` is what the rail shows — normally the
|
|
51
56
|
* same string, but the operator's rename lives only in `title`, so a hand-written name
|
|
@@ -84,6 +89,12 @@ export interface SessionInfo {
|
|
|
84
89
|
* Derived server-side and sent with the row, so the client never infers liveness from which
|
|
85
90
|
* list a row arrived in (that inference is what merged 已归档 with 死了). */
|
|
86
91
|
cold?: boolean;
|
|
92
|
+
/** A SYSTEM session: the cockpit spawned it for itself, not for the operator (issue #16 — the
|
|
93
|
+
* 工作播报 observer is the first one). It is a real ACP session with a real transcript, but it
|
|
94
|
+
* is NOT work in flight: the rail never draws it, the cockpit CLI never lists it, and it never
|
|
95
|
+
* occupies a warm-slot seat. Kept in the same table (and filtered at the emit boundary) so the
|
|
96
|
+
* idle reaper, close and resume keep working on it unchanged. */
|
|
97
|
+
system?: boolean;
|
|
87
98
|
}
|
|
88
99
|
|
|
89
100
|
export interface AvailableCommandView {
|
|
@@ -180,6 +191,14 @@ export type ServerEvent =
|
|
|
180
191
|
* `actual` is what the session really runs with, so the cockpit can put the control back and say
|
|
181
192
|
* so instead of pretending the pick landed. */
|
|
182
193
|
| { t: "config-rejected"; sessionId: string; configId: string; value: string; actual: string; name?: string }
|
|
194
|
+
/** ONE line the cockpit wants spoken (issue #16). The server owns every decision behind it —
|
|
195
|
+
* which events are worth a voice, the per-session throttle, the observer agent's wording — so
|
|
196
|
+
* the page only has to hand `text` to the speaker in 工作播报 mode. Zero-cost events (an
|
|
197
|
+
* approval is waiting, a step just completed) arrive here too, with no model call behind them. */
|
|
198
|
+
| { t: "speak"; id: string; sessionId: string; text: string;
|
|
199
|
+
kind: "approval" | "plan-step" | "brief" | "fallback";
|
|
200
|
+
/** Higher wins when two lines compete for the speaker. An approval (2) interrupts a brief (1). */
|
|
201
|
+
priority: 1 | 2 }
|
|
183
202
|
| { t: "turn-end"; sessionId: string; stopReason?: string; error?: string;
|
|
184
203
|
/** Wall time from the moment the turn was announced to the moment the agent answered (ms).
|
|
185
204
|
* Exists so a notification can say "用时 1m12s" instead of a protocol token like `end_turn`,
|
|
@@ -188,6 +207,13 @@ export type ServerEvent =
|
|
|
188
207
|
/** per-turn trace: what model/effort/mode this turn is actually running with
|
|
189
208
|
* (AionUi F-DISPLAY-11 lineage — "why did it behave differently?" ) */
|
|
190
209
|
| { t: "turn-start"; sessionId: string; trace?: TurnTrace }
|
|
210
|
+
/** A one-line status from the AGENT itself (issue #18): `👁️ Hindsight — recalled 8 memories`,
|
|
211
|
+
* a compaction countdown, a provider wait. Deliberately NOT a transcript row and not persisted —
|
|
212
|
+
* it describes what the process is doing NOW, so the page shows the latest one beside the running
|
|
213
|
+
* turn and forgets it at turn-end (stored, it would put 「recalled 8 memories」 above a
|
|
214
|
+
* conversation from last week). Carrier on the ACP side: an empty thought chunk tagged
|
|
215
|
+
* `_meta.hermes.kind = "status"`. */
|
|
216
|
+
| { t: "status"; sessionId: string; text: string; statusKind?: string }
|
|
191
217
|
/** The session's plan object — the TRUTH the card renders, not the transcript's frames. Sent on
|
|
192
218
|
* every change, and the same object is available over GET /api/sessions/:id/plan, so a page that
|
|
193
219
|
* loads after the agent process died still renders the real plan instead of nothing. */
|
|
@@ -264,6 +290,11 @@ export interface PlanSnapshot {
|
|
|
264
290
|
sessionId: string;
|
|
265
291
|
revision: number;
|
|
266
292
|
items: PlanItem[];
|
|
293
|
+
/** WHAT this piece of work is, in one action phrase (≤40 chars) — the slot a completion
|
|
294
|
+
* notification reads. A step list answers "how far", a remark answers "why it changed"; neither
|
|
295
|
+
* answers "what finished", which is the only question a phone card asks (issue #11). Written by
|
|
296
|
+
* the plan writer, carried as `undefined` when not given so a later `items`-only write keeps it. */
|
|
297
|
+
title?: string | null;
|
|
267
298
|
/** plan-level remark, Studio-style ("brief reason for the update or scope change"), ≤1000 chars */
|
|
268
299
|
explanation?: string | null;
|
|
269
300
|
/** who wrote it: a native ACP frame, the plan MCP tool, or the server's own turn lifecycle */
|
|
@@ -302,7 +333,9 @@ export const PLAN_GUIDANCE_INTRO = [
|
|
|
302
333
|
"`update_plan` and update it as you go: mark a step completed only once its work is actually",
|
|
303
334
|
"verified, and drop or cancel what you are no longer doing. If `update_plan` is not in your",
|
|
304
335
|
"tool list it is deferred — search for `agentus_plan update_plan` to find it, then call it by",
|
|
305
|
-
"that exact name.
|
|
336
|
+
"that exact name. On that first call also give a `title`: one short action phrase (≤40 chars)",
|
|
337
|
+
"naming the job — it is the line the operator's completion notification shows, so the phone says",
|
|
338
|
+
"what finished instead of just which conversation ended. A one-step request needs no plan.",
|
|
306
339
|
].join("\n");
|
|
307
340
|
|
|
308
341
|
/** Injected when the session HAS an open plan and the backend is MCP-driven. */
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
|
3
|
+
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
|
4
|
+
* https://github.com/chjj/term.js
|
|
5
|
+
* @license MIT
|
|
6
|
+
*
|
|
7
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
* in the Software without restriction, including without limitation the rights
|
|
10
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
* furnished to do so, subject to the following conditions:
|
|
13
|
+
*
|
|
14
|
+
* The above copyright notice and this permission notice shall be included in
|
|
15
|
+
* all copies or substantial portions of the Software.
|
|
16
|
+
*
|
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
23
|
+
* THE SOFTWARE.
|
|
24
|
+
*
|
|
25
|
+
* Originally forked from (with the author's permission):
|
|
26
|
+
* Fabrice Bellard's javascript vt100 for jslinux:
|
|
27
|
+
* http://bellard.org/jslinux/
|
|
28
|
+
* Copyright (c) 2011 Fabrice Bellard
|
|
29
|
+
* The original design remains. The terminal itself
|
|
30
|
+
* has been extended to include xterm CSI codes, among
|
|
31
|
+
* other features.
|
|
32
|
+
*/.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;inset:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;inset:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{font-family:monospace;user-select:text;white-space:pre}.xterm .xterm-accessibility-tree>div{transform-origin:left;width:fit-content}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;background:#0000;transition:opacity .1s linear;z-index:11}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{position:absolute;display:none}.xterm .xterm-scrollable-element>.shadow.top{display:block;top:0;left:3px;height:3px;width:100%;box-shadow:var(--vscode-scrollbar-shadow, #000) 0 6px 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.left{display:block;top:3px;left:0;height:100%;width:3px;box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.top-left-corner{display:block;top:0;left:0;height:3px;width:3px}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}:root{--bg: #0c1116;--bg-panel: #121a22;--bg-raised: #182430;--line: #223140;--text: #e3ecf3;--text-dim: #b6bec3;--accent: #4aacdf;--accent-rgb: 74, 172, 223;--accent-dim: #295f7b;--ok: #4ec9a0;--err: #e57373;--err-rgb: 229, 115, 115;--thought: #8f7bd7;--tool: #5ba8d4;--code-bg: #0a0f14;--code-fg: #d7e2ea;--code-bar: rgba(255, 255, 255, .06);--code-line: rgba(255, 255, 255, .1);--chip-bg: #1e2b38;--on-accent: #101820;--accent-text: #4aacdf;--scrim: rgba(0, 0, 0, .55);--shadow: 0 18px 40px rgba(0, 0, 0, .45);--scroll-thumb: rgba(255, 255, 255, .18);--scroll-thumb-hover: rgba(255, 255, 255, .34);--mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace}:root[data-theme=light]{--bg: #f4f6f9;--bg-panel: #ffffff;--bg-raised: #eaeef4;--line: #d7dde6;--text: #1c2735;--text-dim: #3f4750;--accent: #4aacdf;--accent-rgb: 74, 172, 223;--accent-dim: #9bd1ed;--ok: #1f9d75;--err: #c2453f;--err-rgb: 194, 69, 63;--thought: #6d5bc4;--tool: #2f7fb5;--code-bg: #10171f;--code-fg: #cfd8e3;--code-bar: rgba(255, 255, 255, .07);--code-line: rgba(255, 255, 255, .12);--chip-bg: #e8ecf2;--accent-text: #16659b;--on-accent: #101820;--scrim: rgba(12, 17, 22, .42);--shadow: 0 18px 40px rgba(23, 36, 48, .18);--scroll-thumb: rgba(12, 17, 22, .22);--scroll-thumb-hover: rgba(12, 17, 22, .38)}@media (prefers-color-scheme: light){:root[data-theme=system]{--bg: #f4f6f9;--bg-panel: #ffffff;--bg-raised: #eaeef4;--line: #d7dde6;--text: #1c2735;--text-dim: #3f4750;--accent: #4aacdf;--accent-rgb: 74, 172, 223;--accent-dim: #9bd1ed;--ok: #1f9d75;--err: #c2453f;--err-rgb: 194, 69, 63;--thought: #6d5bc4;--tool: #2f7fb5;--code-bg: #10171f;--code-fg: #cfd8e3;--code-bar: rgba(255, 255, 255, .07);--code-line: rgba(255, 255, 255, .12);--chip-bg: #e8ecf2;--accent-text: #16659b;--on-accent: #101820;--scrim: rgba(12, 17, 22, .42);--shadow: 0 18px 40px rgba(23, 36, 48, .18);--scroll-thumb: rgba(12, 17, 22, .22);--scroll-thumb-hover: rgba(12, 17, 22, .38)}}*{box-sizing:border-box}*::-webkit-scrollbar{width:8px;height:8px}*::-webkit-scrollbar-track{background:transparent}*::-webkit-scrollbar-corner{background:transparent}*::-webkit-scrollbar-thumb{background-color:transparent;border:2px solid transparent;border-radius:999px;background-clip:padding-box}*:hover::-webkit-scrollbar-thumb{background-color:var(--scroll-thumb)}*::-webkit-scrollbar-thumb:hover{background-color:var(--scroll-thumb-hover)}html,body,#root{height:100%;margin:0}body{background:var(--bg);color:var(--text);font:15px/1.5 -apple-system,Segoe UI,PingFang SC,Noto Sans SC,sans-serif;-webkit-font-smoothing:antialiased}button{font:inherit}.app{display:flex;height:100%;overflow:hidden}.sidebar{width:var(--rail-w, 268px);flex:0 0 var(--rail-w, 268px);background:var(--bg-panel);border-right:1px solid var(--line);display:flex;flex-direction:column;position:relative}.sidebar header{padding:14px 16px 10px;display:flex;align-items:baseline;gap:8px}.sidebar header .logo{color:var(--accent-text);font-weight:700;letter-spacing:.5px;display:inline-flex;align-items:center;gap:7px}.brand-mark{display:block;flex:0 0 auto}.sidebar header .tagline{font-size:11px;color:var(--text-dim)}.new-btn{margin:0 12px 10px;padding:9px;border-radius:8px;cursor:pointer;border:1px dashed var(--accent-dim);background:transparent;color:var(--accent-text)}.new-btn:hover{background:rgba(var(--accent-rgb),.08)}.rail-search{margin:0 8px 6px;padding:7px 9px;border-radius:8px;background:var(--bg-raised);color:var(--text);border:1px solid var(--line);font-size:12.5px;font-family:var(--mono)}.rail-search:focus{outline:none;border-color:var(--accent-dim)}.rail-search::placeholder{color:var(--text-dim);opacity:1}.load-earlier{display:flex;justify-content:center;margin-bottom:10px}.load-earlier-busy,.load-earlier-end{font-size:11px;color:var(--text-dim);line-height:1.6}.cold-purge{margin-left:auto;background:transparent;border:1px solid transparent;color:var(--text-dim);font-size:11px;line-height:1;padding:2px 5px;border-radius:5px;cursor:pointer}.session-item.cold:hover .cold-purge{border-color:var(--line);color:var(--err)}.session-list{flex:1;overflow-y:auto;padding:0 8px 8px}.session-item{padding:10px;border-radius:8px;cursor:pointer;margin-bottom:4px;border:1px solid transparent}.session-item:hover{background:var(--bg-raised)}.session-item.active{background:var(--bg-raised);border-color:var(--line)}.session-item .title{font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.session-item .meta{font-size:11.5px;color:var(--text-dim);display:flex;gap:8px;margin-top:3px;align-items:center}.dot{width:8px;height:8px;border-radius:50%;flex:0 0 8px}.dot.ready{background:var(--ok)}.dot.running{background:var(--accent);animation:pulse 1s infinite}.dot.starting{background:var(--text-dim)}.dot.error,.dot.closed{background:var(--err)}.rail-sep{display:flex;justify-content:space-between;align-items:baseline;padding:12px 10px 6px;font-size:11px;letter-spacing:.4px;text-transform:uppercase;color:var(--text-dim);border-top:1px solid var(--line);margin:8px 4px 0}.session-item.cold:hover{background:rgba(var(--accent-rgb),.06)}.dot.cold{background:transparent;border:1px solid var(--text-dim)}.hint{color:var(--text-dim)}@keyframes pulse{50%{opacity:.35}}.badge{font-size:10.5px;border:1px solid var(--line);border-radius:5px;padding:0 5px;color:var(--text-dim)}.badge.perm{border-color:var(--accent-dim);color:var(--accent-text)}.sidebar footer{padding:10px 14px;font-size:11.5px;color:var(--text-dim);border-top:1px solid var(--line)}.sidebar footer .conn.off{color:var(--err)}.main{flex:1;display:flex;flex-direction:column;min-width:0}.chat-head{padding:7px 10px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:6px;flex-wrap:nowrap;background:var(--bg-panel);min-height:46px}.chat-head .title{font-weight:600;font-size:14px;flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.icon-btn .spin,.sess-menu-item .spin{animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion: reduce){.icon-btn .spin,.sess-menu-item .spin{animation:none}}.head-spacer{flex:1 1 auto;min-width:4px}.speak-wrap{position:relative;display:inline-flex}.speak-dot{position:absolute;top:4px;right:4px;width:5px;height:5px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 1.5px var(--bg-panel)}.speak-menu{position:absolute;top:calc(100% + 6px);right:0;z-index:40;min-width:240px;background:var(--bg-raised);border:1px solid var(--line);border-radius:10px;box-shadow:0 10px 30px #00000052;padding:3px;display:flex;flex-direction:column}.speak-menu-item{display:flex;align-items:center;gap:7px;text-align:left;width:100%;background:none;border:1px solid transparent;border-radius:7px;color:var(--text);font:inherit;font-size:12.5px;padding:7px 8px;cursor:pointer}.speak-menu-item:hover{background:var(--bg-panel);border-color:var(--line)}.speak-menu-item.on{color:var(--text);font-weight:600}.speak-check{width:10px;flex:0 0 10px;color:var(--accent);font-size:11px}.speak-hint{margin:2px 4px 4px;padding-top:6px;border-top:1px solid var(--line);font-size:11px;line-height:1.5;color:var(--text-dim)}.turn-pulse{flex:0 0 auto;width:8px;height:8px;border-radius:50%;background:var(--ok);animation:pulse 1.4s infinite}.turn-pulse.quiet{background:var(--accent);animation-duration:2.6s}@media (prefers-reduced-motion: reduce){.turn-pulse{animation:none}}.head-actions{display:inline-flex;align-items:center;gap:0;flex:0 0 auto}.head-actions .icon-btn{width:28px;height:28px}.chat-head .icon-btn svg{width:18px;height:18px}.icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;flex:0 0 auto;padding:0;background:transparent;border:1px solid transparent;border-radius:8px;color:var(--text-dim);cursor:pointer}.icon-btn:hover{background:var(--bg-raised);border-color:var(--line);color:var(--text)}.icon-btn.danger:hover{color:var(--err);border-color:var(--err)}.chip{display:inline-flex;align-items:center;gap:4px;flex:0 0 auto;font-size:11px;padding:2px 7px;border-radius:999px}.perm-chip{border:1px solid var(--accent-dim);color:var(--accent-text)}.perm-pulse{width:6px;height:6px;border-radius:50%;background:var(--accent);animation:pulse 1.2s infinite}.ghost-btn{background:transparent;border:1px solid var(--line);color:var(--text-dim);border-radius:6px;padding:4px 10px;cursor:pointer;font-size:12.5px}.ghost-btn:hover{color:var(--text);border-color:var(--text-dim)}.ghost-btn.danger:hover{color:var(--err);border-color:var(--err)}.stream-wrap{flex:1;min-height:0;position:relative;display:flex}.stream{flex:1;overflow-y:auto;padding:18px 0;overscroll-behavior:contain}.stream:focus{outline:none}.stream-hint{display:flex;align-items:center;gap:7px;padding:2px 0;color:var(--text-dim);font-size:12.5px}.stream-hint .elapsed{opacity:.75;font-variant-numeric:tabular-nums}.stream-hint .turn-status{max-width:46ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding-left:7px;border-left:1px solid var(--line)}.stream-spin{flex:0 0 auto;width:11px;height:11px;border-radius:50%;border:1.5px solid var(--line);border-top-color:var(--accent);animation:spin .8s linear infinite}@media (prefers-reduced-motion: reduce){.stream-spin{animation:none}}.jump-latest{position:absolute;left:50%;bottom:14px;transform:translate(-50%);width:34px;height:34px;border-radius:50%;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;background:var(--bg-raised);border:1px solid var(--line);color:var(--text-dim);box-shadow:0 6px 18px #0006}.jump-latest:hover{color:var(--text);border-color:var(--text-dim)}.jump-latest.has-new{color:var(--accent-text);border-color:var(--accent-dim)}.jump-dot{position:absolute;top:3px;right:3px;width:7px;height:7px;border-radius:50%;background:var(--accent);animation:pulse 1.2s infinite}.rail-search-wrap{position:relative;margin:0 8px 6px;display:flex;align-items:center}.rail-search-wrap>svg{position:absolute;left:9px;color:var(--text-dim);pointer-events:none}.rail-search-wrap .rail-search{margin:0;padding-left:27px;width:100%}.cold-resume{background:transparent;border:1px solid transparent;color:var(--text-dim);padding:2px 4px;border-radius:5px;cursor:pointer;line-height:1;display:inline-flex;align-items:center}.session-item.cold:hover .cold-resume{border-color:var(--line);color:var(--ok)}.stream-inner{margin:0;padding:0 20px}.msg{margin-bottom:14px;display:flex;flex-direction:column;align-items:flex-start;min-width:0}.msg>*{max-width:100%}.msg.user{align-items:flex-end}.msg.user.from-agent .role{color:var(--accent, #6ea8fe);letter-spacing:.2px}.msg.user.from-agent .bubble{border-style:dashed;border-color:var(--accent, #6ea8fe)}.msg.plan,.msg.meta{align-items:stretch}.msg .role{font-size:11px;color:var(--text-dim);margin-bottom:3px;letter-spacing:.4px}.msg .role.with-mark{display:flex;align-items:center;gap:5px}.agent-mark{flex:0 0 auto;width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center;font-size:9.5px}.agent-mark img{display:block;width:16px;height:16px;border-radius:4px;object-fit:contain}.msg .bubble{border-radius:10px;padding:10px 14px;white-space:pre-wrap;overflow-wrap:anywhere}.msg .bubble:has(.md),.msg .bubble>.md{white-space:normal}.msg.user .bubble{background:var(--bg-raised);border:1px solid var(--line)}.msg.agent .bubble{background:transparent}.msg.thought .bubble{background:#8f7bd712;border-left:3px solid var(--thought);color:var(--text-dim);font-size:13.5px;white-space:pre-wrap}.thought-head{display:flex;align-items:center;gap:5px;background:none;border:none;padding:2px 4px;border-radius:6px;cursor:pointer;color:var(--text-dim);font:inherit;font-size:11px;letter-spacing:.4px}.thought-head:hover{background:var(--bg-raised);color:var(--text)}.thought-chev,.tool-chev{flex:0 0 auto;color:var(--text-dim);transition:transform .15s ease}.thought-chev.open,.tool-chev.open{transform:rotate(90deg)}.thought-meta{color:var(--text-dim);opacity:.75;font-variant-numeric:tabular-nums}.msg.thought.live .thought-head{color:var(--thought)}.msg.thought .bubble.live{max-height:6.6em;overflow-y:auto}.thought-stick{align-self:flex-start;display:inline-flex;align-items:center;gap:4px;margin:2px 0 0;padding:2px 8px;border-radius:999px;cursor:pointer;background:var(--bg-raised);border:1px solid var(--line);color:var(--text-dim);font:inherit;font-size:11px;letter-spacing:.3px}.thought-stick:hover{color:var(--text);border-color:var(--text-dim)}.work-run-head{display:flex;align-items:center;gap:6px;width:fit-content;max-width:100%;min-height:30px;padding:4px 8px;border:1px solid var(--line);border-radius:8px;background:var(--bg-raised);color:var(--text-dim);font:inherit;font-size:11.5px;text-align:left;cursor:pointer}.work-run.active{align-self:stretch}.work-run-head:hover,.work-run-head:focus-visible{outline:none;border-color:var(--accent-dim);background:rgba(var(--accent-rgb),.055)}.work-run.active .work-run-head{border-color:var(--accent-dim)}.work-chev{flex:0 0 auto;color:var(--text-dim);transition:transform .15s ease}.work-chev.open{transform:rotate(90deg)}.work-run-icon{flex:0 0 auto;color:var(--accent-text)}.work-run-count{flex:0 0 auto;font-weight:600;color:var(--text)}.work-run-names,.work-run-chars{flex:1 1 auto;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.work-run-state{flex:0 0 auto}.work-run-state.ok{color:var(--ok)}.work-run-state.err{color:var(--err)}.work-run-state.run{color:var(--accent-text)}.work-run-items{display:flex;flex-direction:column;gap:2px;margin:4px 0 0 11px;padding:3px 4px 3px 12px;border-left:1px solid var(--line);max-height:42vh;overflow-y:auto}.work-run-items .msg{margin-bottom:4px}.work-run-items .bubble{max-height:none}@media (max-width: 700px){.work-run-head{min-height:34px}.work-run-items{max-height:38vh}.msg.thought .bubble.live{max-height:7.4em}}.msg.meta .bubble{color:var(--err);font-size:13px;background:#e5737314}.usage-note{color:var(--text-dim);font-size:11.5px;line-height:1.5;max-width:46ch}.msg.plan .bubble{border-left:3px solid var(--ok);background:#4ec9a00f;font-size:13.5px}.plan-card{border:1px solid var(--line);border-left:3px solid var(--accent);border-radius:8px;padding:3px 8px;background:var(--bg-panel)}.plan-card.completed{border-left-color:var(--ok)}.plan-head{display:flex;align-items:center;gap:8px;width:100%;padding:3px 0;border:0;background:none;color:var(--text);font:inherit;font-size:13px;cursor:pointer;text-align:start}.plan-head:hover{color:var(--accent-text)}.plan-title{font-weight:600;flex:0 0 auto}.plan-count{font-size:12px;color:var(--text-dim);font-variant-numeric:tabular-nums}.plan-state{font-size:11.5px;padding:0 6px;border-radius:999px;line-height:18px}.plan-state.running{color:var(--accent-text);background:rgba(var(--accent-rgb, 90, 140, 255),.12)}.plan-state.done{color:var(--ok);background:#4ec9a01f}.plan-state.terminal{color:var(--err);background:rgba(var(--err-rgb),.1)}.plan-head .tool-chev{margin-inline-start:auto}.plan-body{list-style:none;margin:2px 0 4px;padding:4px 0 0;border-top:1px dashed var(--line)}.plan-name{padding:1px 0 6px;margin-bottom:2px;border-bottom:1px dotted var(--line);font-weight:600;font-size:13px;overflow-wrap:anywhere}.plan-step{display:flex;align-items:baseline;gap:8px;padding:2.5px 0;font-size:13px}.plan-step .step-icon{flex:0 0 14px;text-align:center;color:var(--text-dim)}.plan-step.completed .step-icon{color:var(--ok)}.plan-step.completed .step-title{color:var(--text-dim)}.plan-step.in_progress .step-icon{color:var(--accent);animation:pulse 1.2s infinite}.plan-step.cancelled .step-icon{color:var(--err)}.plan-step.cancelled .step-title{color:var(--text-dim);text-decoration:line-through}.plan-step .step-title{flex:1;min-width:0;overflow-wrap:anywhere}.plan-explanation{margin:6px 0 2px;padding-top:4px;border-top:1px dashed var(--line);font-size:12px;opacity:.7;overflow-wrap:anywhere}.plan-bar{border:1px solid var(--line);border-left:3px solid var(--accent);border-radius:8px;padding:1px 8px;margin-bottom:6px;background:var(--bg-panel)}.plan-bar.completed{border-left-color:var(--ok)}.plan-bar .plan-body{max-height:40vh;overflow-y:auto}.plan-dots{display:inline-flex;align-items:center;gap:2.5px;margin-inline-start:2px}.plan-dots .dot{width:5px;height:5px;border-radius:50%;background:var(--line);border:1px solid var(--text-dim);box-sizing:border-box}.plan-dots .dot.completed{background:var(--ok);border-color:var(--ok)}.plan-dots .dot.in_progress{background:var(--accent);border-color:var(--accent);animation:pulse 1.2s infinite}.plan-dots .dot.cancelled{background:var(--err);border-color:var(--err)}@media (max-width: 700px){.plan-step{font-size:12px;padding:2px 0;gap:6px}.plan-step .step-icon{flex-basis:12px}.plan-name{font-size:12.5px;padding-bottom:5px}.plan-explanation{font-size:11.5px}.plan-head{font-size:12.5px}}pre.code{background:var(--code-bg);color:var(--code-fg);border:1px solid var(--line);border-radius:8px;padding:10px 12px;overflow-x:auto;font-family:var(--mono);font-size:12.8px}code.inline{font-family:var(--mono);background:var(--chip-bg);color:var(--text);border:1px solid var(--line);padding:1px 5px;border-radius:4px;font-size:.92em}.bubble-actions{display:flex;align-items:center;gap:4px;margin-top:4px;opacity:0;transition:opacity .12s}.msg:hover .bubble-actions{opacity:1}@media (hover: none){.bubble-actions{opacity:.75}}.msg-at{font-size:10.5px;color:var(--text-dim);opacity:.9;font-variant-numeric:tabular-nums;white-space:nowrap;flex:0 0 auto}.bubble-actions .msg-at{flex:1 1 auto;text-align:left}.bubble-note{font-size:10.5px;color:var(--text-dim)}.bubble-files{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:6px}.bubble-file{display:inline-flex;align-items:center;gap:4px;font-size:11px;border:1px solid var(--line);border-radius:6px;padding:1px 6px;color:var(--text-dim)}.tool-card{border:1px solid var(--line);border-left:3px solid var(--tool);border-radius:8px;padding:3px 8px;background:var(--bg-panel)}.tool-head{display:flex;align-items:center;gap:6px;width:100%;min-width:0;background:transparent;border:none;padding:2px 0;cursor:pointer;color:var(--text);font-family:var(--mono);font-size:11.5px;text-align:left}.tool-head:hover{color:var(--accent-text)}.tool-title{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tool-chev{flex:0 0 auto;opacity:.5;transition:transform .12s ease}.tool-chev.open{transform:rotate(90deg)}.tool-dot{flex:0 0 auto;width:7px;height:7px;border-radius:50%;background:var(--text-dim)}.tool-dot.running{background:var(--accent);animation:pulse 1.2s infinite}.tool-dot.ok{background:var(--ok)}.tool-dot.err{background:var(--err)}.tool-card.completed{border-left-color:var(--ok)}.tool-card.failed{border-left-color:var(--err)}.tool-card .tool-body{margin-top:8px;border-top:1px dashed var(--line);padding-top:6px}.tool-card .tool-body .lbl{font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--text-dim)}.tool-card .tool-body pre{margin:4px 0 8px;padding:6px 9px;max-height:260px;overflow:auto;background:var(--bg);border:1px solid var(--line);border-radius:6px;font-family:var(--mono);font-size:11px;line-height:1.45;white-space:pre-wrap;word-break:break-word}.tool-card .tool-body pre.tool-meta{color:var(--text-dim);margin-bottom:6px}.ctx{display:inline-flex;align-items:center;gap:5px;flex:0 0 auto;color:var(--ok)}.ctx.warn{color:#d9a03a}.ctx.hot{color:var(--err)}.ctx .ctx-text{font-size:11px;font-family:var(--mono);color:var(--text-dim)}.slash-palette{position:absolute;bottom:calc(100% + 6px);left:0;right:0;max-height:260px;overflow:auto;background:var(--bg-panel);border:1px solid var(--line);border-radius:10px;padding:4px;box-shadow:0 10px 26px #00000059;z-index:5}.slash-item{display:flex;align-items:baseline;gap:8px;padding:6px 9px;border-radius:6px;cursor:pointer}.slash-item.sel{background:#ffffff0f}.slash-item .cmd{font-family:var(--mono);font-size:12.5px;color:var(--accent-text)}.slash-item .desc{font-size:11.5px;color:var(--text-dim);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.slash-item .src{font-size:10px;color:var(--text-dim);border:1px solid var(--line);border-radius:4px;padding:0 4px}.slash-item.empty{color:var(--text-dim);font-size:12px;cursor:default}.perm-card{border:1px solid var(--accent-dim);border-radius:10px;padding:12px 14px;background:rgba(var(--accent-rgb),.05)}.perm-card .q{font-size:13.5px;margin-bottom:4px}.perm-card .tc{font-family:var(--mono);font-size:12.5px;color:var(--text-dim);margin-bottom:10px;overflow-wrap:anywhere}.perm-card .opts{display:flex;gap:8px;flex-wrap:wrap}.perm-card .opts button{border-radius:7px;padding:6px 12px;cursor:pointer;font-size:13px;border:1px solid var(--line);background:var(--bg-raised);color:var(--text)}.perm-card .opts button.allow{border-color:var(--ok);color:var(--ok)}.perm-card .opts button.reject{border-color:var(--err);color:var(--err)}.perm-card.resolved{opacity:.55}.perm-card.resolved .picked{font-size:12px;color:var(--accent-text);margin-top:8px}.perm-dialog{max-width:560px;max-height:92vh;overflow-y:auto}.perm-ask{font-size:13px;line-height:1.5;color:var(--text)}.perm-file{display:flex;align-items:center;gap:6px;margin-top:10px;padding:6px 8px;border:1px solid var(--line);border-radius:8px;background:var(--bg-raised)}.perm-file code{font-family:var(--mono);font-size:12px;word-break:break-all;color:var(--accent-text)}.perm-changes{margin-top:10px}.perm-change-row{display:flex;align-items:center;gap:7px;width:100%;text-align:left;cursor:pointer;padding:7px 9px;border:1px solid var(--line);border-radius:8px;background:var(--bg-raised);color:var(--text);font:inherit}.perm-change-row:hover{border-color:var(--accent-dim)}.perm-change-row code{font-family:var(--mono);font-size:12px;color:var(--accent-text);flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.perm-counts{display:flex;gap:6px;font-family:var(--mono);font-size:11.5px;flex:0 0 auto}.perm-counts .add{color:var(--ok)}.perm-counts .del{color:var(--err)}.perm-caret{color:var(--text-dim);font-size:11px;flex:0 0 auto}.perm-diff{margin-top:6px;border:1px solid var(--line);border-radius:8px;background:var(--bg);max-height:34vh;overflow:auto;font-family:var(--mono);font-size:11.5px;line-height:1.5}.perm-diff-line{display:grid;grid-template-columns:3.2em 3.2em 1.2em 1fr;white-space:pre-wrap;overflow-wrap:anywhere;padding:0 6px}.perm-diff-line .no{color:var(--text-dim);text-align:right;padding-right:6px;user-select:none}.perm-diff-line .sig{text-align:center}.perm-diff-line.add{background:#30a46c1f}.perm-diff-line.add .sig{color:var(--ok)}.perm-diff-line.del{background:#e25a501f}.perm-diff-line.del .sig{color:var(--err)}.perm-diff-line.ctx{color:var(--text-dim)}.perm-diff-gap{color:var(--text-dim);font-size:10.5px;text-align:center;padding:3px 0;background:#7f7f7f0f}.perm-cut{font-size:11px;color:var(--text-dim);margin-top:4px}.stale-banner{position:fixed;left:50%;transform:translate(-50%);bottom:calc(10px + env(safe-area-inset-bottom,0px));z-index:80;cursor:pointer;border:1px solid var(--accent-dim);border-radius:999px;background:var(--accent);color:var(--on-accent);font-weight:700;font-size:12.5px;padding:9px 16px;box-shadow:0 6px 18px #00000059}.stale-banner:hover{filter:brightness(1.06)}.perm-opts{margin-top:14px}.perm-note{font-size:11.5px;color:var(--text-dim);margin-top:10px;line-height:1.5}.perm-answered{display:inline-flex;align-items:center;gap:7px;font-size:12.5px;color:var(--ok);border:1px solid var(--ok);border-radius:7px;padding:6px 11px;background:#4ec9a014}.perm-answered-tick{font-weight:700}.perm-queue{margin-top:10px;font-size:12px;color:var(--accent-text);line-height:1.5}.perm-unconfirmed{margin-top:10px;font-size:12.5px;color:var(--warn, #d08a2a);border:1px solid var(--warn, #d08a2a);border-radius:7px;padding:6px 10px;line-height:1.5}.ns-fixed-dir{display:flex;align-items:center;gap:6px;padding:9px 10px;border:1px solid var(--line);border-radius:8px;background:var(--bg-raised);color:var(--text-dim)}.ns-fixed-dir code{font-family:var(--mono);font-size:12px;word-break:break-all;color:var(--accent-text)}.composer{border-top:1px solid var(--line);background:var(--bg-panel);padding:8px 20px calc(10px + env(safe-area-inset-bottom))}.composer.drop-active .composer-box{border-color:var(--accent-text);background:rgba(var(--accent-rgb),.06)}.composer-inner{position:relative;display:flex;flex-direction:column;gap:6px}.composer-box{display:flex;flex-direction:column;background:var(--bg-raised);border:1px solid var(--line);border-radius:10px}.composer-box:focus-within{border-color:var(--accent-dim)}.composer textarea{flex:0 0 auto;resize:none;background:transparent;color:var(--text);border:none;padding:10px 12px 4px;font:inherit;min-height:42px;max-height:40vh;overflow-y:auto}.composer textarea:focus{outline:none}.composer-bar{display:flex;align-items:center;gap:6px;padding:2px 6px 6px}.icon-btn.on{background:var(--bg-panel);border-color:var(--accent-dim);color:var(--accent-text)}.icon-btn.rec{color:var(--err);border-color:var(--err);animation:pulse 1.4s infinite}.icon-btn.tiny{width:22px;height:22px;border-radius:6px}.send-btn{border:none;background:var(--accent);color:var(--on-accent);font-weight:700;border-radius:9px;padding:0;cursor:pointer;width:40px;height:34px;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto}.send-btn.stop{background:var(--err);color:#180e0e}.send-btn:disabled{opacity:.4;cursor:default}.usage-row{display:flex;align-items:center;gap:8px;padding:0 2px;position:relative}.usage-text{background:transparent;border:none;padding:0;cursor:pointer;font-size:11px;color:var(--text-dim);font-family:var(--mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-align:left;display:inline-flex;align-items:center;gap:5px}.usage-text:hover{color:var(--text)}.usage-row.warn .usage-text{color:var(--accent-text)}.usage-row.hot .usage-text{color:var(--err)}.usage-icon{flex:none;opacity:.75}.usage-bar{flex:1 1 auto;max-width:220px;height:5px;border-radius:3px;background:var(--line);overflow:hidden}.usage-bar>i{display:block;height:100%;background:var(--ok);transition:width .22s ease}.usage-row.warn .usage-bar>i{background:var(--accent)}.usage-row.hot .usage-bar>i{background:var(--err)}.usage-set{margin-bottom:8px;padding-bottom:8px;border-bottom:1px solid var(--line)}.usage-set-head{display:flex;align-items:center;gap:5px;color:var(--text);margin-bottom:6px}.usage-set-scope{margin-left:auto;font-size:10px;color:var(--text-dim);border:1px solid var(--line);border-radius:999px;padding:0 6px}.usage-set-chips{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:6px}.usage-chip{background:var(--chip-bg);border:1px solid var(--line);border-radius:6px;color:var(--text-dim);font-family:inherit;font-size:11px;padding:4px 8px;cursor:pointer}.usage-chip:hover{color:var(--text);border-color:var(--accent-dim)}.usage-chip.sel{color:var(--bg);background:var(--accent);border-color:var(--accent)}.settings-dot{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--effort, var(--text-dim));margin-right:6px}.usage-detail{position:absolute;left:0;right:auto;width:min(560px,100%);bottom:calc(100% + 8px);z-index:12;max-height:min(60vh,420px);overflow-y:auto;background:var(--bg-raised);border:1px solid var(--line);border-radius:10px;padding:8px 10px;font-size:11.5px;color:var(--text-dim);font-family:var(--mono);box-shadow:0 12px 30px #00000059}.draft-row{display:flex;flex-wrap:wrap;align-items:center;gap:5px}.draft{display:inline-flex;align-items:center;gap:5px;max-width:220px;border:1px solid var(--line);border-radius:8px;padding:2px 4px 2px 5px;background:var(--bg-raised);font-size:11.5px;color:var(--text-dim)}.draft img{width:20px;height:20px;object-fit:cover;border-radius:4px}.draft-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.draft-x{background:transparent;border:none;color:var(--text-dim);cursor:pointer;display:inline-flex;padding:0 2px}.draft-x:hover{color:var(--err)}.draft-clear{background:transparent;border:none;color:var(--text-dim);cursor:pointer;font-size:11px;text-decoration:underline}.draft-clear:hover{color:var(--text)}.queue-list{display:flex;flex-direction:column;gap:4px}.queue-head{display:flex;align-items:baseline;gap:8px;font-size:11px;color:var(--text-dim)}.queue-title{font-weight:600;letter-spacing:.3px;text-transform:uppercase}.queue-hint{opacity:.85}.queue-row{display:flex;align-items:flex-start;gap:7px;padding:5px 6px 5px 8px;border:1px solid var(--line);border-left:3px solid var(--accent-dim);border-radius:8px;background:var(--bg-raised);font-size:12.5px;color:var(--text)}.queue-row.inflight{border-left-color:var(--accent);opacity:.75}.queue-idx{flex:0 0 auto;min-width:14px;text-align:right;font-size:10.5px;color:var(--text-dim);font-variant-numeric:tabular-nums;padding-top:2px}.queue-text{flex:1 1 auto;min-width:0;white-space:pre-wrap;overflow-wrap:anywhere;max-height:5.6em;overflow:hidden}.queue-edit{flex:1 1 auto;min-width:0;font:inherit;font-size:12.5px;color:var(--text);background:var(--bg-panel);border:1px solid var(--accent-dim);border-radius:6px;padding:2px 6px;resize:vertical}.queue-actions{flex:0 0 auto;display:flex;align-items:center;gap:2px}.queue-btn{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border:1px solid var(--line);border-radius:6px;background:var(--bg-panel);color:var(--text-dim);cursor:pointer}.queue-btn:hover{color:var(--text);border-color:var(--accent-dim);background:rgba(var(--accent-rgb),.08)}.queue-btn.danger:hover{color:var(--err);border-color:var(--err);background:#e5737314}@media (max-width: 720px){.queue-btn{width:28px;height:28px}.queue-text{max-height:3.6em}}.composer-note{font-size:11.5px;color:var(--text-dim)}.composer-note.err{color:var(--err)}.dict-chip{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--accent-text);border:1px dashed var(--accent-dim);border-radius:8px;padding:4px 8px}.dict-chip.err{color:var(--err);border-color:var(--err)}.dict-chip .interim{color:var(--text-dim)}.dict-stop{margin-left:auto;background:transparent;border:1px solid var(--line);color:var(--text-dim);border-radius:6px;padding:1px 8px;cursor:pointer;font-size:11px}.dict-stop:hover{color:var(--err);border-color:var(--err)}.settings-pop{position:absolute;left:0;bottom:calc(100% + 8px);z-index:14;width:min(340px,92vw);max-height:70vh;overflow-y:auto;background:var(--bg-raised);border:1px solid var(--line);border-radius:12px;padding:8px 10px 10px;box-shadow:0 16px 40px #00000073}.settings-head{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--text-dim);text-transform:uppercase;letter-spacing:.06em;margin-bottom:6px}.settings-group{border-top:1px solid var(--line);padding:7px 0 4px}.settings-group:first-of-type{border-top:none}.settings-label{display:flex;align-items:center;gap:5px;font-size:11px;color:var(--text-dim);margin-bottom:5px}.settings-opt{display:block;width:100%;text-align:left;margin:2px 0;cursor:pointer;background:transparent;border:1px solid transparent;border-radius:7px;color:var(--text);font-size:12.5px;padding:5px 8px;font-family:inherit}.settings-opt:hover{background:var(--bg-panel);border-color:var(--line)}.settings-opt.sel{background:rgba(var(--accent-rgb),.1);border-color:var(--accent-dim);color:var(--accent-text)}.settings-toggle{display:flex;align-items:center;gap:7px;font-size:12.5px;margin:5px 0;cursor:pointer}.settings-select,.settings-input{width:100%;margin:3px 0;background:var(--bg-panel);color:var(--text);border:1px solid var(--line);border-radius:7px;padding:5px 7px;font-size:12px;font-family:inherit}.settings-select:focus,.settings-input:focus{outline:none;border-color:var(--accent-dim)}.settings-freeform{display:flex;gap:6px;align-items:center;margin-top:6px}.settings-freeform .settings-input{flex:1 1 auto;min-width:0}.settings-note{font-size:10.5px;color:var(--text-dim);margin-top:4px}.settings-range{display:block;font-size:11.5px;color:var(--text-dim);margin:5px 0}.settings-range input{width:100%}.empty{margin:auto;text-align:center;color:var(--text-dim)}.empty .big{font-size:42px;display:flex;justify-content:center;margin-bottom:4px}.modal-bg{position:fixed;inset:0;background:#0000008c;display:flex;align-items:center;justify-content:center;z-index:35;padding:16px;overflow-y:auto;overscroll-behavior:contain}.modal{background:var(--bg-panel);border:1px solid var(--line);border-radius:14px;padding:20px;width:100%;max-width:420px;max-height:calc(100dvh - 32px);overflow-y:auto}.modal.start-page{max-width:560px}.start-head{display:flex;align-items:center;gap:10px;margin-bottom:12px}.start-head h3{margin:0;flex:1;min-width:0}.ws-pill{display:inline-flex;align-items:center;gap:6px;max-width:58%;flex:0 1 auto;background:var(--bg-raised);color:var(--text);border:1px solid var(--line);border-radius:999px;padding:5px 10px;font:inherit;font-size:12.5px;cursor:pointer}.ws-pill:hover{border-color:var(--accent-dim)}.ws-pill.empty{color:var(--text-dim);border-style:dashed}.ws-pill.locked{cursor:default;color:var(--text-dim);background:transparent}.ws-pill.locked:hover{border-color:var(--line)}.ws-pill-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ws-modal-bg{z-index:60}.ws-modal{max-width:520px}.composer.start-composer{border-top:none;background:transparent;padding:0}.start-page .backend-pick{margin-top:14px}.start-input{width:100%;box-sizing:border-box;resize:vertical;min-height:86px;background:var(--bg-raised);color:var(--text);border:1px solid var(--line);border-radius:10px;padding:11px 12px;font:inherit;line-height:1.5}.start-input:focus{outline:none;border-color:var(--accent-dim)}.start-hold{display:flex;align-items:center;justify-content:center;gap:8px;color:var(--text-dim);font-size:12.5px;padding:22px 8px}.start-fail{border:1px solid var(--err);border-radius:10px;padding:12px 14px;margin:8px 0 12px;background:color-mix(in srgb,var(--err) 10%,transparent)}.start-fail-why{color:var(--err);font-size:12.5px;line-height:1.5;white-space:pre-wrap;overflow-wrap:anywhere}.start-fail-act{display:flex;gap:8px;margin-top:10px}.modal h3{margin:0 0 14px;font-size:16px}.modal label{display:block;font-size:12.5px;color:var(--text-dim);margin:10px 0 4px}.modal input,.modal select{width:100%;background:var(--bg-raised);color:var(--text);border:1px solid var(--line);border-radius:8px;padding:9px 10px;font:inherit}.modal .row{display:flex;gap:10px;margin-top:18px}.modal .row button{flex:1;padding:9px;border-radius:8px;cursor:pointer}.modal .row .cancel{background:transparent;border:1px solid var(--line);color:var(--text-dim)}.modal .row .go{background:var(--accent);border:none;color:var(--on-accent);font-weight:700}.modal .row .go.danger{background:var(--err);color:#fff}.modal .err{color:var(--err);font-size:12.5px;margin-top:10px}@media (max-width: 520px){.modal-bg{align-items:flex-start;padding:10px}.modal{padding:14px;border-radius:12px}.modal h3{margin:0 0 8px;font-size:15px}.modal label{margin:8px 0 3px}.modal input,.modal select{padding:8px 9px}.modal .row{margin-top:12px}.backend-pick .be-card{width:68px;min-height:58px}}.blocked-homes{margin-top:12px;display:flex;flex-direction:column;gap:6px}.blocked-homes div{display:flex;gap:8px;align-items:baseline;font-size:12px}.blocked-homes span{color:var(--text-dim);min-width:104px;flex:none}.blocked-homes code{font-family:var(--mono);word-break:break-all}.backend-pick{display:flex;gap:8px;overflow-x:auto;overscroll-behavior-x:contain;padding-bottom:2px}.backend-pick .be-card{flex:0 0 auto;width:74px;min-height:62px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;padding:8px 6px;border-radius:10px;cursor:pointer;background:var(--bg-raised);border:1px solid var(--line);color:var(--text-dim);font:inherit}.backend-pick .be-card.sel{border-color:var(--accent-text);color:var(--accent-text);background:rgba(var(--accent-rgb),.1)}.be-card-mark{flex:0 0 auto;width:26px;height:26px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;font-size:13px;font-weight:700;color:var(--be-tone, var(--text-dim));background:color-mix(in srgb,var(--be-tone, var(--text-dim)) 16%,transparent);border:1px solid color-mix(in srgb,var(--be-tone, var(--text-dim)) 40%,transparent)}.be-card-mark img{width:100%;height:100%;object-fit:cover;border-radius:inherit;display:block}.be-card-label{max-width:100%;font-size:11.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.backend-pick .be-card.reload{width:42px;font-size:15px}.be-detail{margin-top:6px}.be-detail-head{display:inline-flex;align-items:center;gap:4px;background:transparent;border:none;padding:2px 0;cursor:pointer;color:var(--text-dim);font-size:11.5px}.be-detail-head:hover{color:var(--accent-text)}.be-detail-arrow{transition:transform .12s}.be-detail.open .be-detail-arrow{transform:rotate(90deg)}.dim{color:var(--text-dim);font-size:12.5px;align-self:center}.hint{color:var(--text-dim);font-size:11.5px;margin-top:8px;font-family:ui-monospace,monospace;word-break:break-all}.net-banner{margin:8px 12px 0;padding:8px 10px;border-radius:8px;font-size:12.5px;background:rgba(var(--err-rgb),.12);border:1px solid rgba(var(--err-rgb),.45);color:var(--err);display:flex;gap:8px;align-items:center;justify-content:space-between}.net-banner button{background:transparent;border:1px solid rgba(var(--err-rgb),.55);color:var(--err);border-radius:6px;padding:3px 9px;cursor:pointer;font-size:12px}.menu-btn{display:none;background:none;border:none;color:var(--text);font-size:20px;padding:2px 8px;cursor:pointer}@media (max-width: 720px){.sidebar{position:fixed;inset:0 auto 0 0;z-index:30;width:min(82vw,320px);transform:translate(-105%);transition:transform .22s ease}.sidebar.open{transform:translate(0);box-shadow:0 0 40px #0009}.menu-btn{display:block}.scrim{position:fixed;inset:0;background:#00000073;z-index:25}.chip{padding:2px 6px}.perm-card button{min-height:44px;padding:10px 14px;font-size:14px}.perm-dialog{max-width:none;max-height:100%}.perm-dialog .perm-opts button{min-height:44px;padding:10px 14px;font-size:14px}.perm-diff{max-height:42vh}.perm-change-row{min-height:44px}.rail-group .group-add{width:32px;height:30px}.rail-section{min-height:34px;margin-top:6px}.slash-palette{max-height:40vh}.slash-item{min-height:44px}.msg{max-width:100%}.empty .big{font-size:42px}}.sidebar footer{display:flex;align-items:center;gap:6px}.sidebar footer .logout-btn{margin-left:auto;background:transparent;border:1px solid var(--line);color:var(--text-dim);border-radius:6px;padding:2px 8px;cursor:pointer;line-height:1.4}.sidebar footer .logout-btn:hover{color:var(--err);border-color:var(--err)}.auth-wrap{min-height:100%;display:flex;align-items:center;justify-content:center;padding:24px;background:radial-gradient(1000px 500px at 50% -10%,rgba(var(--accent-rgb),.07),transparent 60%),var(--bg)}.auth-card{width:100%;max-width:360px;background:var(--bg-panel);border:1px solid var(--line);border-radius:14px;padding:26px 24px 20px;display:flex;flex-direction:column;gap:12px;box-shadow:0 18px 50px #00000073}.auth-logo{color:var(--accent-text);font-weight:700;font-size:20px;letter-spacing:.5px;display:flex;align-items:center;justify-content:center;gap:9px}.auth-sub{font-size:11.5px;color:var(--text-dim);margin-top:-8px}.auth-note{font-size:12.5px;color:var(--text-dim);padding:6px 0}.auth-field{display:flex;flex-direction:column;gap:5px;font-size:12px;color:var(--text-dim)}.auth-field input{font:inherit;font-size:16px;padding:10px 11px;border-radius:8px;border:1px solid var(--line);background:var(--bg-raised);color:var(--text)}.auth-field input:focus{outline:none;border-color:var(--accent-dim)}.auth-btn{margin-top:4px;padding:11px;min-height:44px;border-radius:8px;cursor:pointer;border:1px solid var(--accent-dim);background:rgba(var(--accent-rgb),.12);color:var(--accent-text);font-weight:600}.auth-btn:disabled{opacity:.6;cursor:default}.auth-err{color:var(--err);font-size:12.5px;border-left:2px solid var(--err);padding-left:8px}.auth-warn{color:var(--accent-text);font-size:11.5px;line-height:1.5;opacity:.9}.auth-foot{color:var(--text-dim);font-size:11px;line-height:1.5;border-top:1px solid var(--line);padding-top:10px}.auth-card code{font-family:var(--mono);font-size:11px;color:var(--text)}@media (max-width: 480px){.auth-card{padding:20px 16px 16px}.sidebar footer .logout-btn{min-height:44px;padding:2px 12px}}.wp{display:flex;flex-direction:column;gap:5px}.wp-bar{display:flex;align-items:center;gap:6px}.wp-bar>svg{color:var(--text-dim);flex:0 0 auto}.wp-path{flex:1;min-width:0;padding:8px 10px;border-radius:8px;font-size:13px;background:var(--bg-raised);color:var(--text);border:1px solid var(--line);font-family:var(--mono)}.wp-path:focus{outline:none;border-color:var(--accent-dim)}.wp-list{max-height:210px;overflow-y:auto;border:1px solid var(--line);border-radius:8px;background:#0000002e;padding:3px}.wp-row{display:flex;align-items:center;gap:6px;padding:4px 7px;border-radius:6px;cursor:pointer;font-size:12.5px;color:var(--text)}.wp-row>svg{color:var(--text-dim);flex:0 0 auto}.wp-row:hover{background:var(--bg-raised)}.wp-row.sel{background:rgba(var(--accent-rgb),.1);outline:1px solid var(--accent-dim)}.wp-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wp-enter{background:transparent;border:1px solid transparent;border-radius:5px;color:var(--text-dim);cursor:pointer;padding:1px 3px;display:inline-flex}.wp-enter:hover{color:var(--accent-text);border-color:var(--line)}.wp-note{padding:10px;font-size:12px;color:var(--text-dim);text-align:center}.wp-note.err{color:var(--err)}.wp-recent{display:flex;flex-wrap:nowrap;align-items:center;gap:4px;overflow-x:auto;overscroll-behavior-x:contain;padding-bottom:1px}.wp-recent-label{font-size:11px;color:var(--text-dim)}.wp-chip{flex:0 0 auto;border:1px solid var(--line);background:var(--bg-raised);color:var(--text-dim);border-radius:999px;padding:1px 8px;font-size:10.5px;line-height:1.5;cursor:pointer;font-family:var(--mono);max-width:116px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wp-chip:hover{color:var(--text);border-color:var(--text-dim)}.wp-chip.sel{color:var(--accent-text);border-color:var(--accent-dim)}.wp-use{display:inline-flex;align-items:center;gap:5px;flex:0 0 auto;border:1px solid var(--line);background:transparent;color:var(--text-dim);border-radius:7px;padding:5px 9px;font-size:12px;cursor:pointer}.wp-use:hover:not(:disabled){color:var(--accent-text);border-color:var(--accent-dim)}.wp-use:disabled{opacity:.5;cursor:default}@media (max-width: 480px){.wp-row{min-height:40px}.wp-chip{min-height:26px}.wp-path{font-size:16px}.wp-list{max-height:150px}}.main-body{flex:1;display:flex;min-height:0}.chat-col{flex:1;display:flex;flex-direction:column;min-width:0;container-type:inline-size}.tool-panel{width:var(--panel-w, 430px);flex:0 0 auto;display:flex;flex-direction:column;min-height:0;border-left:1px solid var(--line);background:var(--bg-panel);position:relative}.panel-split{flex:1;display:flex;min-height:0;position:relative}.preview-col{flex:1 1 auto;min-width:0;display:flex;flex-direction:column}.explorer-col{position:relative;flex:0 0 auto;width:var(--explorer-w, 300px);display:flex;flex-direction:column;min-height:0}.panel-split:not(.has-preview) .explorer-col{width:100%}.panel-split.tree-folded .explorer-col,.panel-split.preview-folded .preview-col{display:none}.panel-split.preview-folded .explorer-col{width:100%}.pane-handle{position:absolute;top:0;bottom:0;width:12px;z-index:12;display:flex;align-items:center;justify-content:center;cursor:col-resize;touch-action:none}.sidebar>.pane-handle{right:-6px}.tool-panel>.pane-handle{left:-6px}.explorer-col>.pane-handle{left:-6px}.pane-handle-line{width:2px;height:100%;background:transparent;transition:background .15s ease}.pane-handle:hover .pane-handle-line,.pane-handle:active .pane-handle-line{background:var(--accent-dim)}body.pane-dragging{cursor:col-resize;user-select:none}body.pane-dragging *{cursor:col-resize!important}@media (max-width: 720px){.pane-handle{display:none}}@media (hover: none){.pane-handle{display:none}}.tool-tabs{display:flex;align-items:center;gap:3px;padding:4px 6px;border-bottom:1px solid var(--line)}.tool-tab{display:inline-flex;align-items:center;gap:5px;cursor:pointer;background:transparent;border:1px solid transparent;border-radius:7px;color:var(--text-dim);font-size:12px;padding:3px 8px;font-family:inherit}.tool-tab:hover{background:var(--bg-raised);color:var(--text)}.tool-tab.active{background:var(--bg-raised);border-color:var(--line);color:var(--accent-text)}.tool-body{flex:1;display:flex;flex-direction:column;min-height:0;overflow:hidden}.ws-root{display:flex;align-items:center;gap:5px;padding:6px 9px 0;font-size:11px;color:var(--text-dim);font-family:var(--mono)}.ws-root-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-bar{display:flex;align-items:center;gap:2px;padding:3px 6px;border-bottom:1px solid var(--line)}.file-bar-path{flex:1;min-width:0;font-size:10.5px;color:var(--text-dim);font-family:var(--mono);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-list{flex:1;overflow-y:auto;padding:4px}.file-row{display:flex;align-items:center;gap:7px;width:100%;text-align:left;background:transparent;border:none;border-radius:6px;color:var(--text);font-size:12.5px;padding:4px 7px;cursor:pointer;font-family:inherit}.file-row:hover{background:var(--bg-raised)}.file-row.sel{background:rgba(var(--accent-rgb),.1)}.file-row>svg:first-child{color:var(--text-dim);flex:0 0 auto}.file-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-size{font-size:10.5px;color:var(--text-dim);font-family:var(--mono)}.file-enter{opacity:.45}.file-preview{flex:1;min-height:0;display:flex;flex-direction:column}.file-preview-head{display:flex;align-items:center;gap:6px;padding:4px 8px;font-size:11.5px;border-bottom:1px solid var(--line)}.file-preview-body{flex:1;min-height:0;overflow:auto;display:flex;flex-direction:column}.file-preview-body>*{min-height:0}.file-text{margin:0;padding:4px 9px 10px;overflow:auto;white-space:pre;font-family:var(--mono);font-size:11.5px;line-height:1.45;color:var(--text)}.file-image-wrap{display:flex;padding:8px;align-items:flex-start}.file-image{max-width:100%;border-radius:6px;border:1px solid var(--line)}.file-frame{flex:1;min-height:260px;width:100%;border:0;background:var(--bg-raised)}.file-audio{width:calc(100% - 16px);margin:8px}.file-video{max-width:100%;max-height:100%;margin:8px}.file-fallback{padding-top:6px}.file-view-toggle{display:flex;gap:6px;padding:4px 8px 0}.file-source{font-family:var(--mono);font-size:11.5px;line-height:1.45;padding:4px 0 10px;overflow-x:auto}.file-line{display:flex;gap:8px;padding:0 9px;white-space:pre}.file-line.hit{background:rgba(var(--accent-rgb),.14);box-shadow:inset 2px 0 0 var(--accent-text)}.file-ln{flex:0 0 34px;text-align:right;color:var(--text-dim);opacity:.6;user-select:none}.file-lt{flex:1}.file-edit{flex:1;min-height:220px;border:0;outline:0;resize:none;padding:8px 10px;background:var(--code-bg);color:var(--code-fg);white-space:pre;overflow:auto;font-family:var(--mono);font-size:11.5px;line-height:1.5}.file-dirty{color:var(--accent-text)}.file-conflict{display:flex;align-items:center;gap:6px;padding:5px 8px;font-size:11.5px;color:var(--text);background:rgba(var(--accent-rgb),.12);border-bottom:1px solid var(--line)}.file-md{padding:6px 10px 12px}.tool-note{padding:8px;font-size:11.5px;color:var(--text-dim)}.tool-error{padding:6px 9px;font-size:11.5px;color:var(--err)}.term-bar{display:flex;align-items:center;gap:6px;padding:4px 8px;border-bottom:1px solid var(--line);font-size:11.5px;color:var(--text-dim)}.term-dot{width:8px;height:8px;border-radius:50%;background:var(--text-dim)}.term-dot.ready{background:var(--ok)}.term-dot.error{background:var(--err)}.term-dot.closed{background:var(--accent)}.term-cwd{font-family:var(--mono);color:var(--text)}.term-body{display:flex;flex-direction:column;min-height:0;padding:0}.term-host{flex:1;min-height:0;min-width:0;overflow:hidden;padding:4px 0 0 6px;background:var(--bg-panel)}.term-host .xterm{height:100%}.term-host .xterm-viewport{background:transparent!important}.term-note{padding:4px 9px 7px;font-size:10.5px;color:var(--text-dim)}@media (max-width: 720px){.chat-head{padding:5px 8px;min-height:44px}.chat-head .title{font-size:14px}.chat-head .menu-btn,.chat-head .icon-btn{width:40px;height:40px}.chat-head .head-actions .icon-btn{width:28px;height:28px}.chat-head .head-actions .icon-btn svg{width:18px;height:18px}.composer{padding:6px 8px calc(8px + env(safe-area-inset-bottom,0px))}.composer textarea{font-size:16px;min-height:44px}.composer-bar .icon-btn{width:38px;height:38px}.send-btn{width:46px;height:38px}.usage-row .usage-bar{max-width:90px}.tb-list,.tb-list.wide{position:fixed;left:8px;right:8px;width:auto;max-width:none;bottom:calc(76px + env(safe-area-inset-bottom,0px));max-height:52vh}.settings-pop{width:min(340px,94vw);bottom:calc(100% + 6px)}.tool-panel{position:fixed;inset:44px 0 0;z-index:22;width:auto;max-width:none;border-left:none}.panel-split.has-preview .explorer-col{display:none}.file-row{min-height:42px}.term-host{min-height:30vh}}.md{font-size:13.5px;line-height:1.55;overflow-wrap:anywhere;white-space:normal}.md>:first-child{margin-top:0}.md>:last-child{margin-bottom:0}.md h1,.md h2,.md h3,.md h4{margin:12px 0 6px;line-height:1.3;font-weight:650}.md h1{font-size:18px}.md h2{font-size:16px}.md h3{font-size:14.5px}.md h4{font-size:13.5px}.md p{margin:6px 0}.md ul,.md ol{margin:6px 0;padding-left:20px}.md li{margin:2px 0}.md li>ul,.md li>ol{margin:2px 0}.md blockquote{margin:6px 0;padding:2px 10px;color:var(--text-dim);border-left:3px solid var(--line)}.md a{color:var(--accent-text);text-decoration:none;border-bottom:1px solid var(--accent-dim)}.md a:hover{border-bottom-color:var(--accent-text)}.md a.md-file-link{font-family:var(--mono);font-size:.94em;padding:0 3px;border-bottom-color:transparent;border-radius:4px;background:rgba(var(--accent-rgb),.1)}.md a.md-file-link:hover{background:rgba(var(--accent-rgb),.2)}.md-file-line{color:var(--text-dim)}.md a.md-img-link{border-bottom:none;display:inline-block;max-width:100%}.md img.md-img{max-width:100%;border-radius:6px;border:1px solid var(--line);display:block;margin:6px 0}.md hr{border:none;border-top:1px solid var(--line);margin:10px 0}.md code{font-family:var(--mono);font-size:12px;padding:1px 4px;border-radius:4px;background:var(--chip-bg);color:var(--text);border:1px solid var(--line)}.md pre{margin:0;padding:8px 10px;overflow-x:auto;background:var(--code-bg);color:var(--code-fg)}.md pre code{padding:0;background:transparent;border:none;color:inherit;font-size:12px;line-height:1.5}.md table{border-collapse:collapse;margin:8px 0;font-size:12.5px;display:block;overflow-x:auto;max-width:100%}.md-table-bar{display:flex;align-items:center;gap:6px;margin:8px 0 -2px}.md-table-filter{flex:1;min-width:0;max-width:240px;font-size:11.5px;padding:3px 7px;background:var(--bg-input, var(--bg-raised));color:var(--text);border:1px solid var(--line);border-radius:5px}.md-table-btn{font-size:11px;line-height:1;padding:3px 7px;cursor:pointer;background:var(--bg-raised);color:var(--text-dim);border:1px solid var(--line);border-radius:5px}.md-table-btn:hover{color:var(--text);border-color:var(--accent-dim)}.md-table-sort{display:inline-flex;align-items:center;gap:4px;width:100%;font:inherit;font-weight:inherit;text-align:left;cursor:pointer;background:none;border:0;padding:0;color:inherit}.md-table-sort:hover{color:var(--accent-text)}.md-table-sort-indicator{font-size:9px;opacity:.55}.md th[aria-sort=ascending] .md-table-sort-indicator,.md th[aria-sort=descending] .md-table-sort-indicator{opacity:1;color:var(--accent-text)}.md-table-overlay{position:fixed;inset:0;z-index:60;display:flex;flex-direction:column;background:#0000009e;backdrop-filter:blur(1.5px)}.md-table-overlay .md-table-bar{margin:8px}.md-table-overlay .md-table-btn{background:var(--bg-panel);font-size:12px;padding:5px 10px}.md-table-stage{flex:1;min-height:0;position:relative;overflow:hidden}.md-table-zoom{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);max-width:96vw;max-height:96vh;overflow:auto;background:var(--bg-panel);border:1px solid var(--line);border-radius:8px;padding:8px}.md-table-zoom.rot{width:96vh;height:96vw;max-width:none;max-height:none;transform:translate(-50%,-50%) rotate(90deg);transform-origin:center}.md-table-zoom table{display:table;max-width:none;margin:0}.md th,.md td{border:1px solid var(--line);padding:4px 8px;text-align:left}.md th{background:var(--bg-raised);font-weight:600}.md-code{margin:8px 0;border:1px solid var(--line);border-radius:8px;overflow:hidden;background:var(--code-bg);color:var(--code-fg)}.md-code-bar{display:flex;align-items:center;gap:6px;padding:3px 8px;background:var(--code-bar);border-bottom:1px solid var(--code-line)}.md-lang{font-family:var(--mono);font-size:10.5px;color:#9fb0c0;text-transform:lowercase}.md-copy{margin-left:auto;background:transparent;border:1px solid transparent;border-radius:5px;color:#9fb0c0;font-size:10.5px;padding:0 5px;cursor:pointer;font-family:inherit}.md-copy:hover{color:#e3ebf4;border-color:var(--code-line)}.md .hljs-comment,.md .hljs-quote{color:#7f8c98;font-style:italic}.md .hljs-keyword,.md .hljs-selector-tag,.md .hljs-literal,.md .hljs-section,.md .hljs-doctag,.md .hljs-name{color:#c792ea}.md .hljs-string,.md .hljs-regexp,.md .hljs-addition,.md .hljs-attribute,.md .hljs-meta .hljs-string{color:#a5d6a7}.md .hljs-number,.md .hljs-symbol,.md .hljs-bullet,.md .hljs-variable,.md .hljs-template-variable{color:#f0a35e}.md .hljs-title,.md .hljs-title.class_,.md .hljs-title.function_{color:#82b1ff}.md .hljs-built_in,.md .hljs-type,.md .hljs-class .hljs-title{color:#ffd479}.md .hljs-attr,.md .hljs-property,.md .hljs-params{color:#ffcb6b}.md .hljs-deletion{color:#ff6b6b}.md .hljs-emphasis{font-style:italic}.md .hljs-strong{font-weight:700}.tb-wrap{position:relative;flex:0 0 auto}.tb-btn{display:inline-flex;align-items:center;gap:5px;max-width:190px;height:30px;padding:0 7px;background:transparent;border:1px solid transparent;border-radius:8px;color:var(--text-dim);font-size:12px;font-family:inherit;cursor:pointer}.tb-btn:hover{background:var(--bg-panel);border-color:var(--line);color:var(--text)}.tb-btn.on{background:var(--bg-panel);border-color:var(--accent-dim);color:var(--accent-text)}.tb-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tb-chev{opacity:.55}.tb-list{position:fixed;z-index:15;min-width:180px;max-width:min(420px,78vw);max-height:46vh;overflow-y:auto;background:var(--bg-raised);border:1px solid var(--line);border-radius:10px;padding:4px;box-shadow:0 14px 34px #00000073}.tb-list.wide{min-width:320px}.tb-list.stacked{display:flex;flex-direction:column;overflow:hidden}.tb-list.stacked .tb-err,.tb-list.stacked .tb-search{flex:0 0 auto}.tb-scroll{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain}.tb-list.stacked .tb-group{border-top:1px solid var(--line)}.tb-list.stacked .tb-group:first-child{border-top:none}.tb-list.stacked .tb-group-head{position:sticky;top:0;z-index:1;background:var(--bg-raised)}.tb-search{width:100%;margin-bottom:3px;background:var(--bg-panel);color:var(--text);border:1px solid var(--line);border-radius:6px;padding:4px 6px;font-size:12px}.tb-search:focus{outline:none;border-color:var(--accent-dim)}.tb-opt{display:flex;flex-direction:column;gap:1px;width:100%;text-align:left;background:transparent;border:1px solid transparent;border-radius:7px;color:var(--text);font-size:12.5px;padding:4px 7px;cursor:pointer;font-family:inherit}.tb-opt:hover{background:var(--bg-panel);border-color:var(--line)}.tb-opt.sel{background:rgba(var(--accent-rgb),.1);border-color:var(--accent-dim);color:var(--accent-text)}.tb-opt.bad{border-color:var(--err);color:var(--err)}.tb-opt.bad:hover{background:rgba(var(--err-rgb),.08)}.tb-err{display:flex;flex-direction:column;gap:2px;margin:6px 4px;padding:6px 8px;border:1px solid var(--err);border-radius:7px;background:rgba(var(--err-rgb),.08);color:var(--err);font-size:11.5px;line-height:1.4;white-space:pre-wrap;word-break:break-word}.tb-err-id{font-family:var(--mono, monospace);font-size:11px;opacity:.85}.tb-err-text{color:var(--text)}.tb-opt-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tb-opt-hint{font-size:10.5px;color:var(--text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tb-empty{padding:8px;font-size:11.5px;color:var(--text-dim);text-align:center}.usage-edit{display:flex;align-items:center;gap:5px;margin:6px 0 2px}.usage-edit input{flex:1;min-width:0;background:var(--bg-panel);color:var(--text);border:1px solid var(--line);border-radius:6px;padding:3px 6px;font-family:var(--mono);font-size:12px}.usage-edit input:focus{outline:none;border-color:var(--accent-dim)}.usage-edit-btn{background:transparent;border:1px solid var(--line);border-radius:6px;color:var(--text-dim);font-size:11px;padding:2px 8px;cursor:pointer;font-family:inherit}.usage-edit-btn:hover:not(:disabled){color:var(--accent-text);border-color:var(--accent-dim)}.usage-edit-btn:disabled{opacity:.45;cursor:default}.usage-edit-err{color:var(--err);font-size:11px;margin-top:3px}.usage-note{margin-top:6px;color:var(--text-dim);font-size:10.5px;line-height:1.4}@media (max-width: 720px){.tb-list,.tb-list.wide{min-width:0;width:min(86vw,420px)}.tb-btn{max-width:34vw}.md{font-size:14px}}.tb-wrap{flex:0 1 auto;min-width:0}.tb-btn,.tb-label{min-width:0}.tb-wrap>.tb-btn{max-width:100%}.tb-effort{padding:0 5px;gap:4px}.tb-pips{display:inline-flex;align-items:flex-end;gap:2px;height:12px}.tb-pips i{display:block;width:3px;border-radius:1px;background:var(--line)}.tb-pips i:nth-child(1){height:4px}.tb-pips i:nth-child(2){height:5px}.tb-pips i:nth-child(3){height:6px}.tb-pips i:nth-child(4){height:7px}.tb-pips i:nth-child(5){height:9px}.tb-pips i:nth-child(6){height:11px}.tb-pips i:nth-child(7){height:13px}.tb-dot{width:7px;height:7px;border-radius:50%;display:inline-block;margin-right:6px;vertical-align:middle}.tb-group{border-top:1px solid var(--line)}.tb-group:first-of-type{border-top:none}.tb-group-head{display:flex;align-items:center;gap:5px;width:100%;text-align:left;background:transparent;border:none;color:var(--text-dim);cursor:pointer;font-family:inherit;font-size:11px;letter-spacing:.03em;text-transform:uppercase;padding:5px 6px;border-radius:6px}.tb-group-head:hover{background:var(--bg-panel);color:var(--text)}.tb-group-chev{transition:transform .12s ease}.tb-group-chev.open{transform:rotate(90deg)}.tb-group-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tb-group-count{font-size:10px;color:var(--text-dim)}.tb-group-body{padding:0 0 4px 8px}@media (max-width: 720px){.tb-btn{max-width:34vw;padding:0 4px;gap:3px}.tb-btn .tb-chev{display:none}.tb-effort{max-width:none}.composer-bar{gap:6px;padding:2px 5px 5px}.composer-bar .icon-btn{width:32px;height:32px}.send-btn{width:40px;height:36px}.composer-bar .tb-wrap:has([data-testid=start-model]),.composer-bar .tb-wrap:has([data-testid=tb-model]){flex-shrink:6}.composer-bar .tb-wrap:has([data-testid=start-mode]){flex-shrink:0;max-width:42vw}}@media (max-width: 420px){.tb-pips{gap:1px}.tb-pips i{width:2px}}@media (max-width: 340px){.composer-bar .tb-wrap:has([data-testid=start-model]),.composer-bar .tb-wrap:has([data-testid=tb-model]){flex-shrink:1}.composer-bar .tb-wrap:has([data-testid=start-model]) .tb-label,.composer-bar .tb-wrap:has([data-testid=tb-model]) .tb-label{display:none}.composer-bar .tb-wrap:has([data-testid=start-model]) .tb-btn,.composer-bar .tb-wrap:has([data-testid=tb-model]) .tb-btn{min-width:0}.composer-bar{gap:4px;padding:2px 4px 4px}.composer-bar .icon-btn{width:30px;height:30px}.composer-bar .send-btn{width:36px}}.rail-section{display:flex;align-items:center;gap:4px;width:calc(100% - 10px);margin:9px 10px 3px 0;background:transparent;border:none;font-family:inherit;text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--text-dim);padding:3px 2px;border-radius:6px;cursor:pointer}.rail-section:hover{color:var(--text)}.rail-section-chev{flex:0 0 auto;transition:transform .12s ease}.rail-section-chev.open{transform:rotate(90deg)}.rail-section-count{margin-left:auto;letter-spacing:0;font-variant-numeric:tabular-nums}.rail-section:first-child{margin-top:3px}.rail-placeholder{display:flex;align-items:center;gap:6px;margin:0 10px 2px;padding:5px 7px;border-radius:6px;border:1px dashed var(--line);color:var(--text-dim);font-size:11px;cursor:default}.rail-placeholder-name{color:var(--text);opacity:.75}.rail-placeholder-note{margin-left:auto;font-size:11px}.rail-group{margin-bottom:2px}.rail-group-row{display:flex;align-items:center;gap:2px}.rail-group-head{display:flex;align-items:center;gap:6px;flex:1 1 auto;min-width:0;text-align:left;background:transparent;border:none;cursor:pointer;color:var(--text);font-family:inherit;font-size:12px;padding:5px 6px;border-radius:6px;margin-left:0}.rail-group-head:hover{background:var(--bg-raised)}.group-add{flex:0 0 auto;opacity:0;transition:opacity .12s}.rail-group:hover .group-add,.rail-group:focus-within .group-add{opacity:1}@media (hover: none){.group-add{opacity:.7}}.rail-group-folder{flex:0 0 auto;color:var(--text-dim)}.rail-group-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rail-group-count{font-size:11px;color:var(--text-dim)}.rail-group-body{padding-left:28px}.rail-more{display:flex;align-items:center;gap:5px;width:calc(100% - 28px);margin:1px 0 4px 28px;padding:3px 6px;background:transparent;border:none;border-radius:6px;cursor:pointer;color:var(--text-dim);font-family:inherit;font-size:11px;text-align:left}.rail-more:hover{background:var(--bg-raised);color:var(--text)}.rail-more-chev{transition:transform .12s ease;opacity:.7}.rail-more-chev.open{transform:rotate(90deg)}.item-actions{display:inline-flex;align-items:center;gap:2px;margin-left:auto}.item-btn{display:inline-flex;align-items:center;justify-content:center;width:22px;height:20px;padding:0;background:transparent;border:1px solid transparent;border-radius:5px;color:var(--text-dim);cursor:pointer;font-family:inherit;font-size:11px}.item-btn:hover{background:var(--bg-panel);border-color:var(--line);color:var(--accent-text)}.item-btn.danger:hover{color:var(--err);border-color:var(--err)}.item-btn:disabled{opacity:.5;cursor:default}.rail-error{margin:4px 8px;padding:5px 7px;border:1px solid var(--err);border-radius:6px;color:var(--err);font-size:11px;display:flex;align-items:center;gap:6px}.rail-error .draft-x{margin-left:auto}.rail-empty{padding:14px 10px;color:var(--text-dim);font-size:12.5px}.rail-gear{margin-left:auto;width:26px;height:26px;border-radius:7px}.set-head .title{display:inline-flex;align-items:center;gap:6px}.set-save{padding:6px 14px;border-radius:8px;cursor:pointer;font-weight:600;font-size:12.5px;background:var(--accent);color:var(--on-accent);border:1px solid var(--accent)}.set-save:disabled{background:transparent;color:var(--text-dim);border-color:var(--line);cursor:default}.set-toast{font-size:12px;color:var(--ok)}.set-body{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:14px}.set-main{flex:1;display:flex;min-height:0}.set-nav{width:196px;flex:0 0 auto;overflow-y:auto;padding:14px 10px 18px;border-right:1px solid var(--line);display:flex;flex-direction:column}.set-nav-group{display:flex;flex-direction:column;margin-bottom:10px}.set-nav-cat{text-align:left;font-size:11px;font-weight:600;color:var(--text-dim);background:none;border:0;cursor:pointer;padding:4px 8px 3px;border-radius:6px}.set-nav-cat:hover{color:var(--text);background:var(--chip-bg)}.set-nav-cat.on{color:var(--text);background:var(--chip-bg);box-shadow:inset 2px 0 0 var(--accent)}.set-nav-item{text-align:left;font-size:12.5px;color:var(--text-dim);background:none;border:0;border-left:2px solid transparent;cursor:pointer;padding:5px 8px;border-radius:0 6px 6px 0;line-height:1.4}.set-nav-item:hover{color:var(--text);background:var(--chip-bg)}.set-nav-item.on{color:var(--text);font-weight:600;border-left-color:var(--accent);background:var(--chip-bg)}.set-group{margin:4px 0 -6px;font-size:11.5px;font-weight:600;letter-spacing:.06em;color:var(--text-dim);max-width:900px;width:100%;align-self:center}.set-body[data-cat=account]>[data-setgroup]:not([data-setgroup=account]),.set-body[data-cat=agent]>[data-setgroup]:not([data-setgroup=agent]),.set-body[data-cat=notify]>[data-setgroup]:not([data-setgroup=notify]),.set-body[data-cat=look]>[data-setgroup]:not([data-setgroup=look]),.set-body[data-cat=voice]>[data-setgroup]:not([data-setgroup=voice]){display:none}.set-card{background:var(--bg-panel);border:1px solid var(--line);border-radius:12px;padding:14px 16px 16px;max-width:900px;width:100%;align-self:center}.set-card h3{margin:0 0 6px;font-size:13.5px}.set-hint{margin:6px 0 0;font-size:12px;color:var(--text-dim);line-height:1.6;display:flex;flex-wrap:wrap;gap:8px;align-items:center}.set-hint code{font-family:var(--mono);background:var(--chip-bg);color:var(--text);border:1px solid var(--line);padding:1px 5px;border-radius:4px;font-size:11.5px}.set-row{display:flex;gap:12px;align-items:flex-start;margin-top:12px}.set-row>label{flex:0 0 84px;font-size:12.5px;color:var(--text-dim);padding-top:7px}.set-input,.set-select,.set-textarea,.set-num{background:var(--bg-raised);color:var(--text);border:1px solid var(--line);border-radius:8px;padding:7px 9px;font-size:12.5px;font-family:var(--mono);min-width:0;flex:1 1 auto}.set-textarea{width:100%;margin-top:10px;resize:vertical;line-height:1.6}.set-builtin{margin-top:10px;border:1px solid var(--line);border-radius:8px;background:var(--bg-raised)}.set-builtin>summary{padding:8px 10px;font-size:12.5px;color:var(--text-dim);cursor:pointer}.set-builtin[open]>summary{border-bottom:1px solid var(--line)}.set-builtin>.set-hint{padding:8px 10px 0;margin:0}.set-builtin-item{padding:8px 10px 0}.set-builtin-item:last-child{padding-bottom:10px}.set-builtin-when{font-size:12px;color:var(--text-dim);margin-bottom:5px}.set-builtin-text{margin:0;padding:8px 10px;border-radius:6px;background:var(--bg-panel);border:1px solid var(--line);color:var(--text);font-family:var(--mono);font-size:11.5px;line-height:1.6;white-space:pre-wrap;word-break:break-word}.set-num{flex:0 0 70px}.set-input:focus,.set-select:focus,.set-textarea:focus{outline:none;border-color:var(--accent-dim)}.set-pair{display:flex;gap:10px;flex-wrap:wrap;flex:1 1 320px;align-items:center;min-width:0}.set-check{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:var(--text-dim);white-space:nowrap}.set-seg{display:inline-flex;border:1px solid var(--line);border-radius:8px;overflow:hidden}.set-seg button{padding:6px 12px;background:transparent;color:var(--text-dim);border:none;border-right:1px solid var(--line);cursor:pointer;font-size:12.5px}.set-seg button:last-child{border-right:none}.set-seg button.on{background:var(--accent);color:var(--on-accent);font-weight:600}.set-swatches{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.set-swatch{width:22px;height:22px;border-radius:50%;border:2px solid transparent;cursor:pointer;padding:0}.set-swatch.on{border-color:var(--text)}.set-color{width:26px;height:24px;padding:0;border:1px solid var(--line);border-radius:6px;background:var(--bg-raised)}.set-mini{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;padding:5px 9px;border-radius:7px;border:1px solid var(--line);background:var(--bg-raised);color:var(--text-dim);cursor:pointer}.set-mini:hover:not(:disabled){color:var(--text);border-color:var(--accent-dim)}.set-mini:disabled{opacity:.55;cursor:default}.set-hot{margin-top:12px;border-top:1px dashed var(--line);padding-top:10px}.set-hot-title{font-size:12px;color:var(--text-dim)}.set-hot-list{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px}.set-chip{font-size:11.5px;font-family:var(--mono);padding:2px 7px;border-radius:6px;border:1px solid var(--line);background:var(--bg-raised);color:var(--text-dim)}.set-chip.fixed{border-color:var(--accent-dim);color:var(--text)}.set-chip.dynamic{border-style:dashed}.set-chip b{color:var(--accent-text);margin-left:4px;font-size:10.5px}.set-err{max-width:900px;width:100%;align-self:center;display:flex;gap:8px;align-items:center;font-size:12.5px;color:var(--err);background:var(--bg-panel);border:1px solid var(--err);border-radius:10px;padding:9px 12px}.set-inline-err{color:var(--err);font-size:12px}.set-actions{display:flex;gap:10px;align-items:center;max-width:900px;width:100%;align-self:center;padding-bottom:8px}@media (max-width: 720px){.set-row{flex-direction:column;gap:6px}.set-row>label{padding-top:0}.set-body{padding:10px}.set-main{flex-direction:column}.set-nav{width:auto;flex-direction:row;align-items:center;gap:6px;overflow-x:auto;overflow-y:hidden;padding:8px 10px;border-right:0;border-bottom:1px solid var(--line)}.set-nav-group{flex-direction:row;align-items:center;gap:6px;margin-bottom:0}.set-nav-cat{white-space:nowrap;font-size:12px;padding:4px 10px;border-radius:999px;border:1px solid var(--line);background:var(--chip-bg)}.set-nav-item{display:none}}.usage-row .usage-act{display:inline-flex;align-items:center;gap:4px;flex:0 0 auto;font-size:10.5px;padding:2px 7px;border-radius:6px;cursor:pointer;border:1px solid var(--line);background:var(--bg-raised);color:var(--text-dim)}.usage-row.hot .usage-act{border-color:rgba(var(--err-rgb),.5);color:var(--err)}.usage-row .usage-act:hover{color:var(--text);border-color:var(--accent-dim)}.usage-actions{display:flex;gap:6px;margin:6px 0 2px;flex-wrap:wrap}.usage-check{display:inline-flex;align-items:center;gap:4px;font-size:11px;color:var(--text-dim)}.usage-note code{background:var(--chip-bg);border:1px solid var(--line);border-radius:4px;padding:0 4px}@media (max-width: 720px){.usage-text{padding:9px 2px;margin:-9px -2px}.tb-btn,.tb-effort{min-width:40px}.item-btn{min-width:34px;min-height:32px}.set-swatch{width:32px;height:32px}.set-color{width:36px;height:32px}.set-seg button{padding:8px 12px}.usage-act{padding:5px 9px}}.acct-list{display:flex;flex-direction:column;gap:6px;margin-top:10px}.acct-row{display:flex;align-items:center;gap:10px;padding:8px 10px;background:var(--bg-raised);border:1px solid var(--line);border-radius:10px}.acct-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.acct-name{font-size:12.5px;color:var(--text);display:inline-flex;align-items:center;gap:6px}.acct-sub{font-size:11px;color:var(--text-dim);font-family:var(--mono);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.acct-badge{font-size:10px;padding:1px 5px;border-radius:999px;color:var(--ok);border:1px solid rgba(var(--accent-rgb),.4);background:rgba(var(--accent-rgb),.12)}.acct-badge.danger{color:var(--err);border-color:rgba(var(--err-rgb),.45);background:rgba(var(--err-rgb),.12)}.acct-when{font-size:11px;color:var(--text-dim);font-family:var(--mono)}.acct-empty{font-size:12px;color:var(--text-dim);padding:6px 2px}.set-mini.danger{color:var(--err);border-color:rgba(var(--err-rgb),.35)}.set-mini.danger:hover:not(:disabled){color:var(--err);border-color:var(--err)}.pw-wrap{position:relative;display:flex;align-items:center}.pw-wrap input{padding-right:34px}.pw-eye{position:absolute;right:4px;display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;background:transparent;color:var(--text-dim);cursor:pointer;border-radius:6px}.pw-eye:hover{color:var(--text);background:var(--bg-raised)}.modal-head{display:flex;align-items:center;gap:8px;margin-bottom:6px}.modal-head h3{margin:0;flex:1}@media (max-width: 720px){.pw-eye{width:34px;height:34px}.acct-row{padding:10px}.acct-row .set-mini{min-height:34px}.set-row .set-pair{flex:0 0 auto}.set-row>label{flex:0 0 auto}}.session-item{display:flex;align-items:center;gap:8px;padding:4px 6px;min-height:30px}.session-item .title{flex:1 1 auto;min-width:0}.session-item .badge.perm{flex:0 0 auto}.rail-at{flex:0 0 auto;font-size:11px;color:var(--text-dim);font-variant-numeric:tabular-nums;white-space:nowrap}.session-item.active .rail-at{color:var(--text-dim)}.unread-dot{flex:0 0 auto;width:8px;height:8px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 2px rgba(var(--accent-rgb),.18)}.be-avatar{position:relative;flex:0 0 auto;width:20px;height:20px;border-radius:6px;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;letter-spacing:.2px;color:var(--be-tone, var(--text-dim));background:color-mix(in srgb,var(--be-tone, var(--text-dim)) 16%,transparent);border:1px solid color-mix(in srgb,var(--be-tone, var(--text-dim)) 40%,transparent)}.be-avatar.be-hermes,.be-card-mark[data-backend=hermes]{--be-tone: #a98bff}.be-avatar.be-qoder,.be-card-mark[data-backend=qoder]{--be-tone: #4f9bf5}.be-avatar.be-mock,.be-card-mark[data-backend=mock]{--be-tone: #94a3b8}.be-avatar img{width:100%;height:100%;object-fit:cover;border-radius:inherit;display:block}.be-avatar .be-dot{position:absolute;right:-2px;bottom:-2px;width:7px;height:7px;border-radius:50%;border:1px solid var(--bg);background:var(--text-dim)}.be-avatar .be-dot.running{background:var(--ok)}.be-avatar.live{animation:rail-live 1.8s ease-in-out infinite}@keyframes rail-live{0%,to{box-shadow:0 0 0 1.5px color-mix(in srgb,var(--ok) 55%,transparent)}50%{box-shadow:0 0 0 4px color-mix(in srgb,var(--ok) 10%,transparent)}}@media (prefers-reduced-motion: reduce){.be-avatar.live{animation:none;box-shadow:0 0 0 2px color-mix(in srgb,var(--ok) 55%,transparent)}}.title-input{flex:1 1 auto;min-width:0;font:inherit;font-size:13.5px;color:var(--text);background:var(--bg-panel);border:1px solid var(--accent-dim);border-radius:6px;padding:2px 6px}.title-input:focus{outline:none;border-color:var(--accent)}.row-menu{flex:0 0 auto;opacity:0;transition:opacity .12s}.session-item:hover .row-menu,.session-item.active .row-menu,.session-item:focus-within .row-menu{opacity:1}@media (hover: none){.row-menu{opacity:.7}}.sess-menu{position:fixed;z-index:40;width:max-content;max-width:min(320px,calc(100vw - 12px));background:var(--bg-panel);border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow);padding:5px;display:flex;flex-direction:column;gap:1px}.sess-menu-head{display:flex;align-items:center;gap:8px;padding:6px 7px 8px;margin-bottom:3px;border-bottom:1px solid var(--line)}.sess-menu-title{font-size:12.5px;color:var(--text);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sess-menu-item{display:flex;align-items:center;gap:9px;width:100%;padding:7px 8px;text-align:left;background:transparent;border:1px solid transparent;border-radius:7px;color:var(--text);font:inherit;font-size:13px;cursor:pointer}.sess-menu-item:hover{background:var(--bg-raised);border-color:var(--line)}.sess-menu-item.danger{color:var(--err)}.sess-menu-item.danger:hover{border-color:var(--err);background:rgba(var(--err-rgb),.08)}.sess-menu-item svg{flex:0 0 auto;color:var(--text-dim)}.sess-menu-item.danger svg{color:var(--err)}.bubble-btn{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;padding:0;background:transparent;border:1px solid transparent;border-radius:6px;color:var(--text-dim);font:inherit;cursor:pointer}.bubble-btn:hover{background:var(--bg-panel);border-color:var(--line);color:var(--text)}.bubble-btn.copy.ok{color:var(--ok);border-color:var(--ok)}.bubble-btn.copy.no{color:var(--err);border-color:var(--err)}.bubble-btn.speak.on,.bubble-btn.fork:hover{color:var(--accent-text);border-color:var(--accent-dim)}.bubble-btn.fork.failed{color:var(--err);border-color:var(--err)}.bubble-btn.fork.working{opacity:.55}.bubble-btn:disabled{opacity:.55;cursor:default}@media (max-width: 720px){.sess-menu{left:8px!important;right:8px;top:auto!important;bottom:calc(10px + env(safe-area-inset-bottom,0px));width:auto!important;max-width:none;min-width:0}.sess-menu-item{padding:11px 10px;font-size:14px}.session-item{min-height:36px}.bubble-btn{width:34px;height:30px}}.call-mode{position:fixed;inset:0;z-index:60;--bg-panel: rgba(255,255,255,.07);--bg-raised: rgba(255,255,255,.14);--line: rgba(255,255,255,.16);--text: #eef2f7;--text-dim: rgba(238,242,247,.6);--err: #f2555a;--on-accent: #0b1220;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:max(20px,env(safe-area-inset-top)) 18px calc(20px + env(safe-area-inset-bottom));background:radial-gradient(120% 90% at 50% 33%,#111827,#080a12 60%,#05060b);color:var(--text);overflow:hidden;animation:call-in .24s ease-out}@keyframes call-in{0%{opacity:0;transform:scale(1.015)}to{opacity:1;transform:none}}.call-mode[data-phase=connecting]{--call-tone: #7d91c8}.call-mode[data-phase=listening]{--call-tone: #38bdf8}.call-mode[data-phase=thinking]{--call-tone: #a78bfa}.call-mode[data-phase=speaking]{--call-tone: #fbbf24}.call-mode[data-phase=error]{--call-tone: #f87171}.call-mode:before{content:"";position:absolute;inset:0;pointer-events:none;background:radial-gradient(26% 19% at 50% 37%,color-mix(in srgb,var(--call-tone, #38bdf8) 26%,transparent) 0%,transparent 100%),radial-gradient(62% 44% at 50% 37%,color-mix(in srgb,var(--call-tone, #38bdf8) 15%,transparent) 0%,transparent 74%);transition:background .5s ease}.call-head,.call-orb,.call-lines,.call-wave,.call-controls{position:relative}.call-head{display:flex;flex-direction:column;align-items:center;gap:4px}.call-title{font-size:17px;font-weight:600;letter-spacing:.03em;color:var(--call-tone, var(--text));text-shadow:0 0 18px color-mix(in srgb,var(--call-tone, #38bdf8) 45%,transparent)}.call-sub{font-size:11.5px;color:var(--text-dim);letter-spacing:.04em}.call-orb{height:min(46vh,76vw,380px);aspect-ratio:1;flex:0 1 auto;padding:0;border:none;background:transparent;cursor:pointer;-webkit-tap-highlight-color:transparent}.call-orb-canvas{display:block;width:100%;height:100%}.call-orb:focus-visible{outline:2px solid var(--call-tone, var(--accent));outline-offset:6px;border-radius:50%}.call-lines{display:flex;flex-direction:column;align-items:center;gap:6px;width:min(560px,92vw);min-height:60px;flex:0 1 auto;overflow:hidden}.call-heard{margin:0;font-size:15px;line-height:1.45;text-align:center}.call-reply{margin:0;font-size:13.5px;line-height:1.5;color:var(--text-dim);text-align:center;max-height:24vh;overflow-y:auto;white-space:pre-wrap}.call-hint{margin:0;font-size:12.5px;color:var(--text-dim)}.call-err{margin:0;font-size:12.5px;color:var(--err)}.call-note{margin:0;font-size:12.5px;color:var(--warn, #d08a2a)}.call-wave{width:min(420px,80vw);height:46px;display:block;flex:0 1 auto;min-height:34px;border-radius:12px;background:linear-gradient(to bottom,#ffffff03,#ffffff09)}.call-hist{width:min(560px,92vw);flex:0 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--line);border-radius:14px;background:#ffffff0a}.call-hist-bar{display:flex;align-items:center;gap:8px;width:100%;min-height:44px;padding:0 12px;border:0;background:transparent;color:var(--text-dim);cursor:pointer;text-align:left}.call-hist-bar:hover{color:var(--text)}.call-hist-title{font-size:12.5px;color:var(--text)}.call-hist-n{font-size:11.5px;color:var(--text-dim)}.call-hist-peek{flex:1 1 auto;min-width:0;font-size:11.5px;color:var(--text-dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.call-hist-chev{margin-left:auto;display:inline-flex;transition:transform .18s ease}.call-hist[data-open=true] .call-hist-chev{transform:rotate(180deg)}.call-hist-list{flex:1 1 auto;min-height:0;max-height:min(38vh,300px);overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding:10px 12px 12px;display:flex;flex-direction:column;gap:9px;border-top:1px solid var(--line)}.call-hm{font-size:12.5px;line-height:1.5;color:var(--text)}.call-hm-who{display:block;margin-bottom:2px;font-size:10.5px;letter-spacing:.08em;color:var(--text-dim);opacity:.7}.call-hm.meta,.call-hm.tool{font-size:11.5px;font-style:italic;color:var(--text-dim)}.call-hm.current{border-left:2px solid var(--call-tone, #38bdf8);margin-left:-12px;padding-left:10px}.call-hm .code{margin:4px 0;padding:6px 8px;font-size:11.5px;color:var(--text)}.call-hist-back{align-self:center;margin:0 0 10px;min-height:32px;padding:0 12px;border-radius:999px;border:1px solid var(--line);background:#ffffff0f;color:var(--text);font-size:12px;cursor:pointer}.call-hist-back:hover{background:var(--bg-raised)}.call-modes{display:inline-flex;align-items:center;gap:2px;margin-top:6px;padding:2px;border:1px solid var(--line);border-radius:999px;background:#ffffff0a}.call-mode-btn{min-height:28px;padding:0 11px;border:0;border-radius:999px;cursor:pointer;background:transparent;color:var(--text-dim);font-size:12px;letter-spacing:.02em}.call-mode-btn:hover{color:var(--text)}.call-mode-btn.on{background:var(--call-tone, #38bdf8);color:#0b1220;font-weight:600;box-shadow:0 0 12px color-mix(in srgb,var(--call-tone, #38bdf8) 40%,transparent)}.call-controls{display:flex;align-items:center;gap:16px;margin-top:2px}.call-btn{width:52px;height:52px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);background:var(--bg-panel);color:var(--text);cursor:pointer}.call-btn:hover{background:var(--bg-raised);border-color:var(--text-dim)}.call-btn.on{background:var(--accent);color:var(--on-accent);border-color:transparent}.call-btn.hangup{width:60px;height:60px;background:var(--err);border-color:transparent;color:#fff}.call-btn.hangup:hover{background:var(--err);filter:brightness(1.1)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.call-gear{position:absolute;z-index:2;top:max(14px,env(safe-area-inset-top));right:14px;width:38px;height:38px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);background:var(--bg-panel);color:var(--text-dim);cursor:pointer}.call-gear:hover{color:var(--text);background:var(--bg-raised)}.call-cc-btn{position:absolute;z-index:3;top:max(14px,env(safe-area-inset-top));right:60px;width:38px;height:38px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);background:var(--bg-panel);color:var(--text-dim);cursor:pointer}.call-cc-btn:hover{color:var(--text);background:var(--bg-raised)}.call-cc-btn.on{color:#0b1220;background:var(--call-tone, #38bdf8);border-color:transparent}.call-mode[data-caption=true]{gap:10px;padding-top:calc(max(14px,env(safe-area-inset-top)) + 44px)}.call-mode[data-caption=true] .call-gear{z-index:3}.call-mode[data-caption=true] .call-orb{position:absolute;inset:0;z-index:0;width:auto;height:auto;aspect-ratio:auto;pointer-events:none;cursor:default}.call-mode[data-caption=true] .call-orb-canvas{width:100%;height:100%;filter:blur(34px) saturate(1.3) brightness(1.35);transform:scale(1.08)}.call-mode[data-caption=true]:before{z-index:1}.call-mode[data-caption=true] .call-wave{display:none}.call-cc{position:relative;z-index:2;width:min(560px,94vw);flex:1 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden;border:1px solid rgba(255,255,255,.14);border-radius:18px;background:linear-gradient(180deg,#1218264d,#090c1494);-webkit-backdrop-filter:blur(22px) saturate(1.35);backdrop-filter:blur(22px) saturate(1.35);box-shadow:inset 0 1px #ffffff12,0 20px 60px #0000006b}.call-cc-head{display:flex;align-items:center;gap:10px;padding:7px 12px;border-bottom:1px solid rgba(255,255,255,.07)}.call-cc-head .call-modes{margin-top:0}.call-cc-state{display:inline-flex;align-items:center;gap:7px;min-height:30px;padding:0 4px;border:0;background:transparent;cursor:pointer;color:var(--call-tone, #38bdf8);font-size:12.5px;font-weight:600;letter-spacing:.02em}.call-cc-dot{width:7px;height:7px;border-radius:50%;background:currentColor;box-shadow:0 0 10px currentColor;animation:cc-pulse 2.4s ease-in-out infinite}@keyframes cc-pulse{0%,to{opacity:.5;transform:scale(.8)}50%{opacity:1;transform:scale(1.2)}}.call-cc-n{margin-left:auto;font-size:11.5px;font-variant-numeric:tabular-nums;color:var(--text-dim)}.call-cc-latest{position:absolute;left:50%;bottom:58px;transform:translate(-50%);z-index:3;min-height:28px;padding:0 12px;border-radius:999px;border:1px solid var(--line);background:#141a28d1;color:var(--text);font-size:11.5px;cursor:pointer;backdrop-filter:blur(8px)}.call-cc-latest:hover{background:var(--bg-raised)}.call-cc-list{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding:12px 14px 16px;display:flex;flex-direction:column;gap:12px}.call-cc-inner{display:flex;flex-direction:column}.call-cc-inner .msg{margin-bottom:13px}.call-cc-inner .msg:last-child{margin-bottom:2px}.call-cc-inner .msg .role{color:#ffffff85}.call-cc-inner .msg .bubble{color:#fffffff2}.call-cc-inner .msg.user .bubble{background:#ffffff12;border:1px solid rgba(255,255,255,.09)}.call-cc-inner .msg.agent .bubble{background:transparent;border:0}.call-cc-inner .msg.meta .bubble{color:#fca5a5;background:#f871711a}.call-cc-inner .tool-card,.call-cc-inner .plan-card,.call-cc-inner .thought .bubble{background:#ffffff0b;border-color:#ffffff17}.call-floor-row{flex:0 0 auto;display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:8px 10px;border-top:1px solid rgba(255,255,255,.09)}.call-floor-row.single{grid-template-columns:1fr}.call-floor{flex:0 0 auto;display:flex;align-items:center;justify-content:center;gap:8px;width:100%;min-height:46px;margin:0;padding:0 12px;border:0;border-radius:12px;background:#ffffff0d;color:var(--text);font-size:14px;font-weight:650;letter-spacing:.01em;cursor:pointer;-webkit-tap-highlight-color:transparent;touch-action:manipulation;user-select:none;-webkit-user-select:none}.call-floor:hover:not(:disabled){background:#ffffff17}.call-floor.is-take{background:color-mix(in srgb,var(--call-tone, #fbbf24) 88%,#000);color:#0b1220}.call-floor.is-take:hover{background:var(--call-tone, #fbbf24)}.call-floor.is-send{background:color-mix(in srgb,var(--call-tone, #38bdf8) 88%,#000);color:#0b1220}.call-floor.is-send:hover{background:var(--call-tone, #38bdf8)}.call-floor.is-retry{background:#ffffff1a}.call-floor:disabled{color:var(--text-dim);background:#ffffff08;cursor:default}.call-floor.is-done{background:color-mix(in srgb,var(--call-tone, #38bdf8) 80%,#000);color:#0b1220}.call-floor.is-done:hover{background:var(--call-tone, #38bdf8)}.call-floor.is-ptt{background:#ffffff17}.call-floor.is-ptt.on{background:color-mix(in srgb,var(--call-tone, #38bdf8) 82%,#000);color:#0b1220;box-shadow:0 0 0 2px color-mix(in srgb,var(--call-tone, #38bdf8) 45%,transparent)}.call-cc-list .call-hm{font-size:13.5px;line-height:1.62}.call-cc-list .call-hm.meta,.call-cc-list .call-hm.tool{font-size:12px}.call-cc-list .call-hint,.call-cc-list .call-err,.call-cc-list .call-note{margin:0}.call-hm.live .call-hm-who:after{content:" · 在说";color:var(--call-tone, #38bdf8)}.call-sheet{position:absolute;inset:0;z-index:3;display:flex;align-items:center;justify-content:center;padding:16px;background:#04060cbd;animation:call-in .16s ease-out}.call-sheet-card{width:min(460px,100%);max-height:88%;overflow-y:auto;display:flex;flex-direction:column;gap:14px;padding:16px;border:1px solid var(--line);border-radius:18px;background:#0d1220;box-shadow:0 24px 60px #0000008c}.call-sheet-head{display:flex;align-items:center;justify-content:space-between;font-size:15px;font-weight:600}.call-sheet-x{width:30px;height:30px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);background:transparent;color:var(--text-dim);cursor:pointer}.call-sheet-note{margin:0;font-size:11.5px;line-height:1.5;color:var(--text-dim)}.call-knob{display:flex;flex-direction:column;gap:4px}.call-knob-top{display:flex;align-items:baseline;justify-content:space-between;gap:10px}.call-knob-name{font-size:13.5px}.call-knob-val{font-size:13px;font-variant-numeric:tabular-nums;color:var(--call-tone, #38bdf8)}.call-knob input[type=range]{width:100%;height:30px;accent-color:var(--call-tone, #38bdf8);background:transparent;cursor:pointer}.call-knob-ends{display:flex;justify-content:space-between;font-size:10.5px;color:var(--text-dim)}.call-knob-hint{font-size:11px;line-height:1.45;color:var(--text-dim)}.call-knob.off{opacity:.45}.call-knob.off input[type=range]{cursor:not-allowed}.call-sheet-warn{margin:0;padding:9px 11px;border-radius:10px;font-size:11.5px;line-height:1.5;border:1px solid color-mix(in srgb,var(--call-tone, #38bdf8) 35%,transparent);background:color-mix(in srgb,var(--call-tone, #38bdf8) 12%,transparent);color:var(--text)}.call-sheet-echo{margin:0;font-size:11.5px;line-height:1.5;color:var(--text-dim)}.call-sheet-echo.bad{color:#fbbf24}.call-sheet-foot{display:flex;gap:10px;justify-content:flex-end;margin-top:2px}.call-sheet-btn{min-height:40px;padding:0 14px;border-radius:10px;font-size:13px;border:1px solid var(--line);background:transparent;color:var(--text);cursor:pointer}.call-sheet-btn:hover{background:var(--bg-raised)}.call-sheet-btn.primary{background:var(--call-tone, #38bdf8);border-color:transparent;color:#0b1220;font-weight:600}@media (max-width: 720px){.call-mode{gap:8px}.call-sheet{align-items:flex-end;padding:0}.call-sheet-card{width:100%;max-height:84%;border-radius:20px 20px 0 0;padding-bottom:calc(16px + env(safe-area-inset-bottom))}.call-gear{width:42px;height:42px}.call-cc-btn{width:42px;height:42px;right:64px}.call-mode[data-caption=true]{padding-top:calc(max(14px,env(safe-area-inset-top)) + 48px)}.call-cc-head .call-mode-btn{min-height:26px;padding:0 9px;font-size:11.5px}.call-cc-head .call-cc-state{font-size:12px;gap:6px}.call-cc{width:94vw;border-radius:16px}.call-cc-head{padding:5px 10px;gap:8px}.call-cc-list{padding:10px 12px 14px;gap:11px}.call-cc-list .call-hm{font-size:13px}.call-floor{min-height:48px;font-size:14px}.call-floor span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.call-cc-inner .msg .bubble{font-size:13.5px;padding:9px 12px}.call-knob input[type=range]{height:34px}.call-orb{height:min(42vh,72vw,300px)}.call-lines{min-height:88px}.call-reply{max-height:20vh}.call-hist-list{max-height:min(30vh,240px)}.call-hist-peek{display:none}.call-btn{width:56px;height:56px}.call-btn.hangup{width:64px;height:64px}}@media (prefers-reduced-motion: reduce){.call-mode,.call-cc-dot{animation:none}}.be-list{display:flex;flex-direction:column;gap:8px;margin-top:12px}.be-row{display:flex;gap:12px;align-items:flex-start;justify-content:space-between;background:var(--bg-raised);border:1px solid var(--line);border-radius:10px;padding:10px 12px}.be-row-main{min-width:0;display:flex;flex-direction:column;gap:3px}.be-row-title{display:flex;gap:8px;align-items:center;flex-wrap:wrap;font-size:13px}.be-row-sub{font-size:11.5px;color:var(--text-dim);font-family:var(--mono);word-break:break-all}.be-row-note{font-size:11.5px;color:var(--text-dim)}.be-kind-help{display:block;margin:6px 0 0;padding:8px 10px;border-left:2px solid var(--accent-dim);background:var(--chip-bg);border-radius:0 8px 8px 0;line-height:1.75}.be-kind-help b{color:var(--text)}.be-kind-help code{font-size:11px}.be-row-actions{display:flex;gap:6px;flex-shrink:0;flex-wrap:wrap}.be-badge{font-size:10.5px;padding:1px 6px;border-radius:999px;border:1px solid var(--line);color:var(--text-dim);background:var(--chip-bg)}.be-badge.be-warn{color:var(--accent);border-color:var(--accent-dim)}.be-badge.be-danger,.be-danger{color:var(--err)}.be-badge.be-dim{opacity:.75}.be-badge.be-ok{color:var(--ok, #3fb950);border-color:var(--ok, #3fb950)}.be-health{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:5px;font-size:11.5px}.be-code{font-family:var(--mono);font-size:10.5px;padding:0 4px;border:1px solid var(--line);border-radius:4px;color:var(--text-dim)}.be-guidance{flex-basis:100%;color:var(--text-dim);font-size:11.5px}.be-handshake{margin-top:4px;font-size:11.5px;color:var(--text-dim)}.be-handshake code{font-family:var(--mono)}.be-dim{color:var(--text-dim);font-size:11.5px}.hint-warn{color:var(--accent);font-size:11.5px;margin-top:4px}.be-hint{display:block}.be-hint code,.be-inspect code,.be-inspect-out{font-family:var(--mono)}.be-hint code{word-break:break-all}.be-inspect{margin-top:12px;border:1px dashed var(--line);border-radius:10px;padding:10px 12px;font-size:12px;background:var(--bg-raised)}.be-inspect-head{display:flex;justify-content:space-between;align-items:center;gap:8px}.be-inspect ul{margin:8px 0 0;padding-left:18px;display:flex;flex-direction:column;gap:4px}.be-inspect-out{margin-top:4px;font-size:11px;color:var(--text-dim);white-space:pre-wrap;word-break:break-all}.be-backdrop{position:fixed;inset:0;z-index:60;background:#00000073;display:flex;align-items:center;justify-content:center;padding:20px}.be-modal{background:var(--bg-panel);border:1px solid var(--line);border-radius:14px;width:min(560px,100%);max-height:min(86vh,780px);display:flex;flex-direction:column;box-shadow:0 18px 48px #00000080}.be-modal-head{display:flex;align-items:center;gap:8px;padding:12px 16px;border-bottom:1px solid var(--line);font-size:13.5px}.be-modal-head b{font-size:13.5px}.be-modal-head code{font-family:var(--mono);font-size:11.5px;color:var(--text-dim)}.be-modal-x{margin-left:auto}.be-modal-body{overflow:auto;overscroll-behavior:contain;padding:2px 16px 14px}.be-modal-foot{display:flex;align-items:center;gap:8px;padding:12px 16px;border-top:1px solid var(--line)}.be-modal-foot button{flex:0 0 auto;white-space:nowrap}.be-modal-foot .set-mini{margin-left:auto}.be-modal-err{flex:1 1 auto;min-width:0;font-size:11.5px;color:var(--err);border:none;padding:0;background:none}@media (max-width: 720px){.be-backdrop{padding:0;align-items:flex-end}.be-modal{width:100%;max-height:92vh;border-radius:14px 14px 0 0}}@media (max-width: 720px){.be-row{flex-direction:column}}
|