repoburg 1.3.219 → 1.3.221
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/agent-pane/backend/dist/index.js +373 -18
- package/agent-pane/backend/dist/server.js +373 -18
- package/agent-pane/frontend/dist/assets/index-lc9eQnqi.css +1 -0
- package/agent-pane/frontend/dist/assets/index-vR3SdkR-.js +418 -0
- package/agent-pane/frontend/dist/index.html +2 -2
- package/daemon/dist/remote/cloudflared.js +16 -10
- package/package.json +3 -2
- package/agent-pane/frontend/dist/assets/index-BUkOj2Cb.js +0 -392
- package/agent-pane/frontend/dist/assets/index-gAFaOmjN.css +0 -1
|
@@ -41076,6 +41076,14 @@ function createTables(database) {
|
|
|
41076
41076
|
created_at TEXT NOT NULL
|
|
41077
41077
|
);
|
|
41078
41078
|
|
|
41079
|
+
CREATE TABLE IF NOT EXISTS sidebar_folders (
|
|
41080
|
+
id TEXT PRIMARY KEY,
|
|
41081
|
+
workspace_path TEXT NOT NULL,
|
|
41082
|
+
name TEXT NOT NULL,
|
|
41083
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
41084
|
+
created_at TEXT NOT NULL
|
|
41085
|
+
);
|
|
41086
|
+
|
|
41079
41087
|
CREATE TABLE IF NOT EXISTS discussion_threads (
|
|
41080
41088
|
id TEXT PRIMARY KEY,
|
|
41081
41089
|
session_id TEXT NOT NULL,
|
|
@@ -41094,6 +41102,8 @@ function createTables(database) {
|
|
|
41094
41102
|
CREATE INDEX IF NOT EXISTS idx_turns_session_id ON turns(session_id);
|
|
41095
41103
|
CREATE INDEX IF NOT EXISTS idx_items_turn_id ON items(turn_id);
|
|
41096
41104
|
CREATE INDEX IF NOT EXISTS idx_workspaces_path ON workspaces(path);
|
|
41105
|
+
CREATE INDEX IF NOT EXISTS idx_workspaces_path ON workspaces(path);
|
|
41106
|
+
CREATE INDEX IF NOT EXISTS idx_sidebar_folders_workspace_path ON sidebar_folders(workspace_path);
|
|
41097
41107
|
CREATE INDEX IF NOT EXISTS idx_discussion_threads_session_id ON discussion_threads(session_id);
|
|
41098
41108
|
CREATE INDEX IF NOT EXISTS idx_discussion_threads_item_id ON discussion_threads(item_id);
|
|
41099
41109
|
`);
|
|
@@ -41123,6 +41133,15 @@ function createTables(database) {
|
|
|
41123
41133
|
if (!sessColumns.some((c) => c.name === "context_usage")) {
|
|
41124
41134
|
database.exec("ALTER TABLE sessions ADD COLUMN context_usage TEXT");
|
|
41125
41135
|
}
|
|
41136
|
+
if (!sessColumns.some((c) => c.name === "folder_id")) {
|
|
41137
|
+
database.exec("ALTER TABLE sessions ADD COLUMN folder_id TEXT");
|
|
41138
|
+
}
|
|
41139
|
+
if (!sessColumns.some((c) => c.name === "sort_order")) {
|
|
41140
|
+
database.exec("ALTER TABLE sessions ADD COLUMN sort_order INTEGER NOT NULL DEFAULT 0");
|
|
41141
|
+
}
|
|
41142
|
+
if (!sessColumns.some((c) => c.name === "starred")) {
|
|
41143
|
+
database.exec("ALTER TABLE sessions ADD COLUMN starred INTEGER NOT NULL DEFAULT 0");
|
|
41144
|
+
}
|
|
41126
41145
|
const turnColumns = database.prepare("PRAGMA table_info(turns)").all();
|
|
41127
41146
|
if (!turnColumns.some((c) => c.name === "thread_id")) {
|
|
41128
41147
|
database.exec("ALTER TABLE turns ADD COLUMN thread_id TEXT");
|
|
@@ -41291,21 +41310,30 @@ async function registerSessionRoutes(fastify) {
|
|
|
41291
41310
|
list.push(item);
|
|
41292
41311
|
itemsByTurn.set(item.turn_id, list);
|
|
41293
41312
|
}
|
|
41313
|
+
const hydrateTurn = (row) => ({
|
|
41314
|
+
...row,
|
|
41315
|
+
token_usage: row.token_usage ? JSON.parse(row.token_usage) : null,
|
|
41316
|
+
attachments: row.attachments ? JSON.parse(row.attachments) : null,
|
|
41317
|
+
runtime_input_ids: row.runtime_input_ids ? JSON.parse(row.runtime_input_ids) : null,
|
|
41318
|
+
items: itemsByTurn.get(row.id) ?? []
|
|
41319
|
+
});
|
|
41320
|
+
const mainTurns = turnRows.filter((row) => row.thread_id == null).map(hydrateTurn);
|
|
41321
|
+
const threadTurns = turnRows.filter((row) => row.thread_id != null).map(hydrateTurn);
|
|
41294
41322
|
const detail = {
|
|
41295
41323
|
...session,
|
|
41296
|
-
turns:
|
|
41297
|
-
...row,
|
|
41298
|
-
token_usage: row.token_usage ? JSON.parse(row.token_usage) : null,
|
|
41299
|
-
attachments: row.attachments ? JSON.parse(row.attachments) : null,
|
|
41300
|
-
runtime_input_ids: row.runtime_input_ids ? JSON.parse(row.runtime_input_ids) : null,
|
|
41301
|
-
items: itemsByTurn.get(row.id) ?? []
|
|
41302
|
-
}))
|
|
41324
|
+
turns: mainTurns
|
|
41303
41325
|
};
|
|
41304
41326
|
const threadRows = db2.prepare("SELECT * FROM discussion_threads WHERE session_id = ? ORDER BY created_at ASC").all(id);
|
|
41327
|
+
const turnsByThread = /* @__PURE__ */ new Map();
|
|
41328
|
+
for (const t of threadTurns) {
|
|
41329
|
+
const list = turnsByThread.get(t.thread_id) ?? [];
|
|
41330
|
+
list.push(t);
|
|
41331
|
+
turnsByThread.set(t.thread_id, list);
|
|
41332
|
+
}
|
|
41305
41333
|
if (threadRows.length > 0) {
|
|
41306
41334
|
detail.threads = threadRows.map((tr) => ({
|
|
41307
41335
|
...tr,
|
|
41308
|
-
turns:
|
|
41336
|
+
turns: turnsByThread.get(tr.id) ?? []
|
|
41309
41337
|
}));
|
|
41310
41338
|
}
|
|
41311
41339
|
const cuRow = db2.prepare("SELECT context_usage FROM sessions WHERE id = ?").get(id);
|
|
@@ -41342,11 +41370,13 @@ async function registerSessionRoutes(fastify) {
|
|
|
41342
41370
|
} = request.body || {};
|
|
41343
41371
|
const id = v4_default();
|
|
41344
41372
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
41345
|
-
getDb()
|
|
41346
|
-
|
|
41347
|
-
|
|
41348
|
-
|
|
41349
|
-
|
|
41373
|
+
const db2 = getDb();
|
|
41374
|
+
const maxOrder = db2.prepare("SELECT COALESCE(MAX(sort_order), 0) AS m FROM sessions WHERE cwd = ?").get(cwd ?? null);
|
|
41375
|
+
db2.prepare(
|
|
41376
|
+
`INSERT INTO sessions (id, title, runtime_type, model, model_reasoning_effort, cwd, external_thread_id, status, is_running, sort_order, created_at, updated_at, runtime_config)
|
|
41377
|
+
VALUES (?, ?, ?, ?, ?, ?, NULL, 'active', 0, ?, ?, ?, ?)`
|
|
41378
|
+
).run(id, title, runtime_type, model, model_reasoning_effort, cwd, maxOrder.m + 1, now, now, runtime_config);
|
|
41379
|
+
const session = db2.prepare("SELECT * FROM sessions WHERE id = ?").get(id);
|
|
41350
41380
|
return session;
|
|
41351
41381
|
});
|
|
41352
41382
|
fastify.delete("/api/sessions/:id", async (request, reply) => {
|
|
@@ -41373,13 +41403,14 @@ async function registerSessionRoutes(fastify) {
|
|
|
41373
41403
|
model_reasoning_effort: { type: ["string", "null"] },
|
|
41374
41404
|
runtime_config: { type: ["string", "null"] },
|
|
41375
41405
|
runtime_type: { type: "string" },
|
|
41376
|
-
cwd: { type: ["string", "null"] }
|
|
41406
|
+
cwd: { type: ["string", "null"] },
|
|
41407
|
+
starred: { type: "number" }
|
|
41377
41408
|
}
|
|
41378
41409
|
}
|
|
41379
41410
|
}
|
|
41380
41411
|
}, async (request, reply) => {
|
|
41381
41412
|
const { id } = request.params;
|
|
41382
|
-
const { title, lifecycle, has_unreviewed, model, model_reasoning_effort, runtime_config, runtime_type, cwd } = request.body || {};
|
|
41413
|
+
const { title, lifecycle, has_unreviewed, model, model_reasoning_effort, runtime_config, runtime_type, cwd, starred } = request.body || {};
|
|
41383
41414
|
const db2 = getDb();
|
|
41384
41415
|
const existing = db2.prepare("SELECT * FROM sessions WHERE id = ?").get(id);
|
|
41385
41416
|
if (!existing) {
|
|
@@ -41404,6 +41435,10 @@ async function registerSessionRoutes(fastify) {
|
|
|
41404
41435
|
updates.push("has_unreviewed = ?");
|
|
41405
41436
|
params.push(has_unreviewed);
|
|
41406
41437
|
}
|
|
41438
|
+
if (starred !== void 0) {
|
|
41439
|
+
updates.push("starred = ?");
|
|
41440
|
+
params.push(starred);
|
|
41441
|
+
}
|
|
41407
41442
|
if (runtime_type !== void 0 && runtime_type !== existing.runtime_type) {
|
|
41408
41443
|
providerChanged = true;
|
|
41409
41444
|
updates.push("runtime_type = ?");
|
|
@@ -41864,6 +41899,60 @@ ${message}`;
|
|
|
41864
41899
|
return { turn };
|
|
41865
41900
|
}
|
|
41866
41901
|
);
|
|
41902
|
+
fastify.post(
|
|
41903
|
+
"/api/sessions/:sessionId/threads/:threadId/summarize",
|
|
41904
|
+
{
|
|
41905
|
+
schema: {
|
|
41906
|
+
body: {
|
|
41907
|
+
type: "object",
|
|
41908
|
+
properties: {
|
|
41909
|
+
directives: { type: "string" }
|
|
41910
|
+
}
|
|
41911
|
+
}
|
|
41912
|
+
}
|
|
41913
|
+
},
|
|
41914
|
+
async (request, reply) => {
|
|
41915
|
+
const { sessionId, threadId } = request.params;
|
|
41916
|
+
const { directives } = request.body || {};
|
|
41917
|
+
const db2 = getDb();
|
|
41918
|
+
const session = db2.prepare("SELECT * FROM sessions WHERE id = ?").get(sessionId);
|
|
41919
|
+
if (!session) {
|
|
41920
|
+
return reply.code(404).send({ error: "Session not found" });
|
|
41921
|
+
}
|
|
41922
|
+
const thread = db2.prepare("SELECT * FROM discussion_threads WHERE id = ? AND session_id = ?").get(threadId, sessionId);
|
|
41923
|
+
if (!thread) {
|
|
41924
|
+
return reply.code(404).send({ error: "Thread not found" });
|
|
41925
|
+
}
|
|
41926
|
+
if (thread.status !== "open") {
|
|
41927
|
+
return reply.code(409).send({ error: "Thread is already resolved" });
|
|
41928
|
+
}
|
|
41929
|
+
const runningTurn = db2.prepare(`SELECT id FROM turns WHERE thread_id = ? AND status IN ('pending', 'running') LIMIT 1`).get(threadId);
|
|
41930
|
+
if (runningTurn) {
|
|
41931
|
+
return reply.code(409).send({ error: "A thread turn is still running \u2014 wait for it to finish first" });
|
|
41932
|
+
}
|
|
41933
|
+
const provider = getProvider(session.runtime_type);
|
|
41934
|
+
if (!provider.summarizeThread) {
|
|
41935
|
+
return reply.code(501).send({ error: `Summarization is not supported for runtime "${session.runtime_type}" yet` });
|
|
41936
|
+
}
|
|
41937
|
+
const turnRows = db2.prepare("SELECT user_prompt, agent_response, status FROM turns WHERE thread_id = ? ORDER BY created_at ASC").all(threadId);
|
|
41938
|
+
const transcript = turnRows.map((t) => {
|
|
41939
|
+
const agent = t.agent_response?.trim() || "(no response)";
|
|
41940
|
+
return `User: ${t.user_prompt}
|
|
41941
|
+
|
|
41942
|
+
Agent: ${agent}`;
|
|
41943
|
+
}).join("\n\n---\n\n");
|
|
41944
|
+
const summary = await provider.summarizeThread(session, thread, transcript, directives ?? "");
|
|
41945
|
+
if (!summary) {
|
|
41946
|
+
return reply.code(500).send({ error: "Summarization failed \u2014 thread was not resolved. Try again or resolve without sharing." });
|
|
41947
|
+
}
|
|
41948
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
41949
|
+
db2.prepare(
|
|
41950
|
+
"UPDATE discussion_threads SET status = ?, resolved_at = ?, updated_at = ? WHERE id = ?"
|
|
41951
|
+
).run("resolved", now, now, threadId);
|
|
41952
|
+
broadcast("thread:resolved", { sessionId, threadId, status: "resolved" });
|
|
41953
|
+
return { summary, resolved: true };
|
|
41954
|
+
}
|
|
41955
|
+
);
|
|
41867
41956
|
fastify.patch(
|
|
41868
41957
|
"/api/sessions/:sessionId/threads/:threadId",
|
|
41869
41958
|
{
|
|
@@ -42053,6 +42142,137 @@ async function registerWorkspaceRoutes(fastify) {
|
|
|
42053
42142
|
});
|
|
42054
42143
|
}
|
|
42055
42144
|
|
|
42145
|
+
// src/routes/folders.ts
|
|
42146
|
+
async function registerFolderRoutes(fastify) {
|
|
42147
|
+
fastify.get("/api/folders", async () => {
|
|
42148
|
+
const rows = getDb().prepare("SELECT * FROM sidebar_folders ORDER BY workspace_path ASC, sort_order ASC").all();
|
|
42149
|
+
return rows;
|
|
42150
|
+
});
|
|
42151
|
+
fastify.post("/api/folders", {
|
|
42152
|
+
schema: {
|
|
42153
|
+
body: {
|
|
42154
|
+
type: "object",
|
|
42155
|
+
required: ["workspace_path", "name"],
|
|
42156
|
+
properties: {
|
|
42157
|
+
workspace_path: { type: "string" },
|
|
42158
|
+
name: { type: "string" }
|
|
42159
|
+
}
|
|
42160
|
+
}
|
|
42161
|
+
}
|
|
42162
|
+
}, async (request, reply) => {
|
|
42163
|
+
const { workspace_path, name } = request.body || {};
|
|
42164
|
+
if (!workspace_path?.trim() || !name?.trim()) {
|
|
42165
|
+
return reply.code(400).send({ error: "workspace_path and name are required" });
|
|
42166
|
+
}
|
|
42167
|
+
const db2 = getDb();
|
|
42168
|
+
const id = v4_default();
|
|
42169
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
42170
|
+
const maxOrder = db2.prepare("SELECT COALESCE(MAX(sort_order), -1) AS m FROM sidebar_folders WHERE workspace_path = ?").get(workspace_path.trim());
|
|
42171
|
+
db2.prepare(
|
|
42172
|
+
"INSERT INTO sidebar_folders (id, workspace_path, name, sort_order, created_at) VALUES (?, ?, ?, ?, ?)"
|
|
42173
|
+
).run(id, workspace_path.trim(), name.trim(), maxOrder.m + 1, now);
|
|
42174
|
+
const folder = db2.prepare("SELECT * FROM sidebar_folders WHERE id = ?").get(id);
|
|
42175
|
+
return folder;
|
|
42176
|
+
});
|
|
42177
|
+
fastify.patch("/api/folders/:id", {
|
|
42178
|
+
schema: {
|
|
42179
|
+
body: {
|
|
42180
|
+
type: "object",
|
|
42181
|
+
properties: {
|
|
42182
|
+
name: { type: "string" },
|
|
42183
|
+
sort_order: { type: "number" }
|
|
42184
|
+
}
|
|
42185
|
+
}
|
|
42186
|
+
}
|
|
42187
|
+
}, async (request, reply) => {
|
|
42188
|
+
const { id } = request.params;
|
|
42189
|
+
const { name, sort_order } = request.body || {};
|
|
42190
|
+
const db2 = getDb();
|
|
42191
|
+
const existing = db2.prepare("SELECT * FROM sidebar_folders WHERE id = ?").get(id);
|
|
42192
|
+
if (!existing) {
|
|
42193
|
+
return reply.code(404).send({ error: "Folder not found" });
|
|
42194
|
+
}
|
|
42195
|
+
if (name !== void 0 && !name.trim()) {
|
|
42196
|
+
return reply.code(400).send({ error: "name cannot be empty" });
|
|
42197
|
+
}
|
|
42198
|
+
const updates = [];
|
|
42199
|
+
const params = [];
|
|
42200
|
+
if (name !== void 0) {
|
|
42201
|
+
updates.push("name = ?");
|
|
42202
|
+
params.push(name.trim());
|
|
42203
|
+
}
|
|
42204
|
+
if (sort_order !== void 0) {
|
|
42205
|
+
updates.push("sort_order = ?");
|
|
42206
|
+
params.push(sort_order);
|
|
42207
|
+
}
|
|
42208
|
+
if (updates.length > 0) {
|
|
42209
|
+
db2.prepare(`UPDATE sidebar_folders SET ${updates.join(", ")} WHERE id = ?`).run(...params, id);
|
|
42210
|
+
}
|
|
42211
|
+
return db2.prepare("SELECT * FROM sidebar_folders WHERE id = ?").get(id);
|
|
42212
|
+
});
|
|
42213
|
+
fastify.delete("/api/folders/:id", async (request, reply) => {
|
|
42214
|
+
const { id } = request.params;
|
|
42215
|
+
const db2 = getDb();
|
|
42216
|
+
const existing = db2.prepare("SELECT id FROM sidebar_folders WHERE id = ?").get(id);
|
|
42217
|
+
if (!existing) {
|
|
42218
|
+
return reply.code(404).send({ error: "Folder not found" });
|
|
42219
|
+
}
|
|
42220
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
42221
|
+
const move = db2.transaction(() => {
|
|
42222
|
+
db2.prepare(
|
|
42223
|
+
"UPDATE sessions SET folder_id = NULL, updated_at = ? WHERE folder_id = ?"
|
|
42224
|
+
).run(now, id);
|
|
42225
|
+
db2.prepare("DELETE FROM sidebar_folders WHERE id = ?").run(id);
|
|
42226
|
+
});
|
|
42227
|
+
move();
|
|
42228
|
+
return { success: true };
|
|
42229
|
+
});
|
|
42230
|
+
fastify.post("/api/sessions/reorder", {
|
|
42231
|
+
schema: {
|
|
42232
|
+
body: {
|
|
42233
|
+
type: "object",
|
|
42234
|
+
required: ["moves"],
|
|
42235
|
+
properties: {
|
|
42236
|
+
moves: {
|
|
42237
|
+
type: "array",
|
|
42238
|
+
items: {
|
|
42239
|
+
type: "object",
|
|
42240
|
+
required: ["id", "sort_order"],
|
|
42241
|
+
properties: {
|
|
42242
|
+
id: { type: "string" },
|
|
42243
|
+
folder_id: { type: ["string", "null"] },
|
|
42244
|
+
sort_order: { type: "number" }
|
|
42245
|
+
}
|
|
42246
|
+
}
|
|
42247
|
+
}
|
|
42248
|
+
}
|
|
42249
|
+
}
|
|
42250
|
+
}
|
|
42251
|
+
}, async (request, reply) => {
|
|
42252
|
+
const { moves } = request.body || {};
|
|
42253
|
+
const db2 = getDb();
|
|
42254
|
+
for (const m of moves) {
|
|
42255
|
+
if (!db2.prepare("SELECT id FROM sessions WHERE id = ?").get(m.id)) {
|
|
42256
|
+
return reply.code(404).send({ error: `Session not found: ${m.id}` });
|
|
42257
|
+
}
|
|
42258
|
+
if (m.folder_id && !db2.prepare("SELECT id FROM sidebar_folders WHERE id = ?").get(m.folder_id)) {
|
|
42259
|
+
return reply.code(404).send({ error: `Folder not found: ${m.folder_id}` });
|
|
42260
|
+
}
|
|
42261
|
+
}
|
|
42262
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
42263
|
+
const stmt = db2.prepare(
|
|
42264
|
+
"UPDATE sessions SET folder_id = ?, sort_order = ?, updated_at = ? WHERE id = ?"
|
|
42265
|
+
);
|
|
42266
|
+
const apply = db2.transaction(() => {
|
|
42267
|
+
for (const m of moves) {
|
|
42268
|
+
stmt.run(m.folder_id ?? null, m.sort_order, now, m.id);
|
|
42269
|
+
}
|
|
42270
|
+
});
|
|
42271
|
+
apply();
|
|
42272
|
+
return { success: true, updated: moves.length };
|
|
42273
|
+
});
|
|
42274
|
+
}
|
|
42275
|
+
|
|
42056
42276
|
// src/routes/providers.ts
|
|
42057
42277
|
var CODEX_PROVIDER = {
|
|
42058
42278
|
id: "codex",
|
|
@@ -42953,6 +43173,75 @@ Agent responded: "${truncatedResponse}"`;
|
|
|
42953
43173
|
}
|
|
42954
43174
|
}
|
|
42955
43175
|
}
|
|
43176
|
+
async function summarizeCodexThread(session, _thread, transcript, directives) {
|
|
43177
|
+
let client = null;
|
|
43178
|
+
try {
|
|
43179
|
+
client = new AppServerClient({ cwd: session.cwd ?? process.cwd() });
|
|
43180
|
+
await client.initialize();
|
|
43181
|
+
const initResult = await client.request("thread/start", {
|
|
43182
|
+
cwd: session.cwd ?? process.cwd(),
|
|
43183
|
+
approvalPolicy: "never",
|
|
43184
|
+
sandbox: "read-only"
|
|
43185
|
+
});
|
|
43186
|
+
const threadId = initResult.thread.id;
|
|
43187
|
+
const directiveLine = directives.trim() ? `
|
|
43188
|
+
|
|
43189
|
+
The user has given these summarization directives \u2014 follow them exactly:
|
|
43190
|
+
"${directives.trim()}"` : "";
|
|
43191
|
+
const summaryPrompt = `You are summarizing a side discussion thread that forked from a main agent session. The discussion begins at the FIRST message of the transcript below \u2014 summarize ONLY the discussion itself, from its beginning up to now.${directiveLine}
|
|
43192
|
+
|
|
43193
|
+
The discussion transcript (from the discussion's beginning):
|
|
43194
|
+
|
|
43195
|
+
${transcript}
|
|
43196
|
+
|
|
43197
|
+
Produce a concise summary of the discussion that preserves: concrete findings, file paths, decisions, and any unresolved questions. Reply with only the summary text, nothing else.`;
|
|
43198
|
+
let summaryResolve;
|
|
43199
|
+
let summaryReject;
|
|
43200
|
+
const summaryPromise = new Promise((resolve, reject) => {
|
|
43201
|
+
summaryResolve = resolve;
|
|
43202
|
+
summaryReject = reject;
|
|
43203
|
+
});
|
|
43204
|
+
let summaryResponse = "";
|
|
43205
|
+
client.onNotification("item/completed", (params) => {
|
|
43206
|
+
const p = params;
|
|
43207
|
+
if (p.threadId !== threadId) return;
|
|
43208
|
+
if ((p.item.type === "agentMessage" || p.item.type === "agent_message") && p.item.text) {
|
|
43209
|
+
summaryResponse = p.item.text;
|
|
43210
|
+
}
|
|
43211
|
+
});
|
|
43212
|
+
client.onNotification("turn/completed", (params) => {
|
|
43213
|
+
const p = params;
|
|
43214
|
+
if (p.threadId !== threadId) return;
|
|
43215
|
+
summaryResolve(summaryResponse);
|
|
43216
|
+
});
|
|
43217
|
+
client.onNotification("turn/failed", (params) => {
|
|
43218
|
+
const p = params;
|
|
43219
|
+
if (p.threadId !== threadId) return;
|
|
43220
|
+
summaryReject(new Error(p.error.message));
|
|
43221
|
+
});
|
|
43222
|
+
const timeout = setTimeout(() => {
|
|
43223
|
+
summaryReject(new Error("Thread summarization timed out"));
|
|
43224
|
+
}, 6e4);
|
|
43225
|
+
await client.request("turn/start", {
|
|
43226
|
+
threadId,
|
|
43227
|
+
input: [{ type: "text", text: summaryPrompt }],
|
|
43228
|
+
approvalPolicy: "never",
|
|
43229
|
+
sandbox: { type: "read-only" }
|
|
43230
|
+
});
|
|
43231
|
+
const summary = await summaryPromise;
|
|
43232
|
+
clearTimeout(timeout);
|
|
43233
|
+
const clean = summary.trim();
|
|
43234
|
+
return clean || null;
|
|
43235
|
+
} catch (err) {
|
|
43236
|
+
console.error("[codex] summarizeThread failed:", err);
|
|
43237
|
+
return null;
|
|
43238
|
+
} finally {
|
|
43239
|
+
if (client) {
|
|
43240
|
+
await client.close().catch(() => {
|
|
43241
|
+
});
|
|
43242
|
+
}
|
|
43243
|
+
}
|
|
43244
|
+
}
|
|
42956
43245
|
var EFFORT_LABELS = {
|
|
42957
43246
|
minimal: "Minimal",
|
|
42958
43247
|
low: "Low",
|
|
@@ -42989,6 +43278,7 @@ var codexProvider = {
|
|
|
42989
43278
|
clearThread,
|
|
42990
43279
|
clearAllThreads,
|
|
42991
43280
|
getModels,
|
|
43281
|
+
summarizeThread: summarizeCodexThread,
|
|
42992
43282
|
shutdown
|
|
42993
43283
|
};
|
|
42994
43284
|
|
|
@@ -43196,6 +43486,7 @@ var PromptQueue = class {
|
|
|
43196
43486
|
};
|
|
43197
43487
|
}
|
|
43198
43488
|
};
|
|
43489
|
+
var CLI_OVERRIDE = process.env.CLAUDE_BIN ? { pathToClaudeCodeExecutable: process.env.CLAUDE_BIN } : {};
|
|
43199
43490
|
var sessionMap2 = /* @__PURE__ */ new Map();
|
|
43200
43491
|
var titleGenerating2 = /* @__PURE__ */ new Set();
|
|
43201
43492
|
var cachedModels = null;
|
|
@@ -43229,7 +43520,7 @@ async function ensureSessionStarted(session, mapKey, resumeSessionId) {
|
|
|
43229
43520
|
permissionMode: "bypassPermissions",
|
|
43230
43521
|
allowDangerouslySkipPermissions: true,
|
|
43231
43522
|
includePartialMessages: true,
|
|
43232
|
-
...
|
|
43523
|
+
...CLI_OVERRIDE,
|
|
43233
43524
|
...session.model_reasoning_effort ? { effort: session.model_reasoning_effort } : {},
|
|
43234
43525
|
...resumeId ? { resume: resumeId } : {}
|
|
43235
43526
|
};
|
|
@@ -43840,7 +44131,8 @@ async function getModels2() {
|
|
|
43840
44131
|
options: {
|
|
43841
44132
|
cwd: process.cwd(),
|
|
43842
44133
|
permissionMode: "bypassPermissions",
|
|
43843
|
-
allowDangerouslySkipPermissions: true
|
|
44134
|
+
allowDangerouslySkipPermissions: true,
|
|
44135
|
+
...CLI_OVERRIDE
|
|
43844
44136
|
}
|
|
43845
44137
|
});
|
|
43846
44138
|
const initResult = await q.initializationResult();
|
|
@@ -43904,7 +44196,8 @@ Agent responded: "${truncatedResponse}"`;
|
|
|
43904
44196
|
options: {
|
|
43905
44197
|
cwd: process.cwd(),
|
|
43906
44198
|
permissionMode: "bypassPermissions",
|
|
43907
|
-
allowDangerouslySkipPermissions: true
|
|
44199
|
+
allowDangerouslySkipPermissions: true,
|
|
44200
|
+
...CLI_OVERRIDE
|
|
43908
44201
|
}
|
|
43909
44202
|
});
|
|
43910
44203
|
let titleResponse = "";
|
|
@@ -43931,6 +44224,66 @@ Agent responded: "${truncatedResponse}"`;
|
|
|
43931
44224
|
}
|
|
43932
44225
|
}
|
|
43933
44226
|
}
|
|
44227
|
+
function buildThreadSummaryPrompt(transcript, directives, hasNativeContext) {
|
|
44228
|
+
const directiveLine = directives.trim() ? `
|
|
44229
|
+
|
|
44230
|
+
The user has given these summarization directives \u2014 follow them exactly:
|
|
44231
|
+
"${directives.trim()}"` : "";
|
|
44232
|
+
const contextBlock = hasNativeContext ? "" : `
|
|
44233
|
+
|
|
44234
|
+
The discussion transcript (from the discussion's beginning):
|
|
44235
|
+
|
|
44236
|
+
${transcript}`;
|
|
44237
|
+
return `You are summarizing a side discussion thread that forked from a main agent session. The discussion begins at the message that quotes a passage from a previous response (prefixed "[Quoting from your previous response]") \u2014 everything in the conversation BEFORE that message is the main session's earlier context and must NOT be included in the summary. Summarize ONLY the discussion itself, from its first message up to now \u2014 do not summarize the full conversation history.${contextBlock}${directiveLine}
|
|
44238
|
+
|
|
44239
|
+
Produce a concise summary of the discussion that preserves: concrete findings, file paths, decisions, and any unresolved questions. The summary will be quoted back into the main session's conversation. Reply with only the summary text, nothing else.`;
|
|
44240
|
+
}
|
|
44241
|
+
async function summarizeClaudeThread(session, thread, transcript, directives) {
|
|
44242
|
+
let q = null;
|
|
44243
|
+
try {
|
|
44244
|
+
let resumeId;
|
|
44245
|
+
if (thread.external_thread_id) {
|
|
44246
|
+
try {
|
|
44247
|
+
const forked = await sdkForkSession(thread.external_thread_id, {
|
|
44248
|
+
dir: session.cwd ?? process.cwd()
|
|
44249
|
+
});
|
|
44250
|
+
resumeId = forked.sessionId;
|
|
44251
|
+
} catch (err) {
|
|
44252
|
+
console.error("[claude] summarizeThread fork failed \u2014 falling back to embedded transcript:", err);
|
|
44253
|
+
}
|
|
44254
|
+
}
|
|
44255
|
+
const prompt = buildThreadSummaryPrompt(transcript, directives, !!resumeId);
|
|
44256
|
+
q = query({
|
|
44257
|
+
prompt,
|
|
44258
|
+
options: {
|
|
44259
|
+
cwd: session.cwd ?? process.cwd(),
|
|
44260
|
+
permissionMode: "bypassPermissions",
|
|
44261
|
+
allowDangerouslySkipPermissions: true,
|
|
44262
|
+
...CLI_OVERRIDE,
|
|
44263
|
+
...resumeId ? { resume: resumeId } : {}
|
|
44264
|
+
}
|
|
44265
|
+
});
|
|
44266
|
+
let summary = "";
|
|
44267
|
+
for await (const message of q) {
|
|
44268
|
+
if (message.type === "assistant") {
|
|
44269
|
+
for (const block of message.message.content) {
|
|
44270
|
+
if (block.type === "text") {
|
|
44271
|
+
summary += block.text;
|
|
44272
|
+
}
|
|
44273
|
+
}
|
|
44274
|
+
}
|
|
44275
|
+
}
|
|
44276
|
+
const clean = summary.trim();
|
|
44277
|
+
return clean || null;
|
|
44278
|
+
} catch (err) {
|
|
44279
|
+
console.error("[claude] summarizeThread failed:", err);
|
|
44280
|
+
return null;
|
|
44281
|
+
} finally {
|
|
44282
|
+
if (q) {
|
|
44283
|
+
q.close();
|
|
44284
|
+
}
|
|
44285
|
+
}
|
|
44286
|
+
}
|
|
43934
44287
|
async function forkClaudeSession(session, targetTurn) {
|
|
43935
44288
|
if (!session.external_thread_id) return null;
|
|
43936
44289
|
try {
|
|
@@ -43953,6 +44306,7 @@ var claudeProvider = {
|
|
|
43953
44306
|
getModels: getModels2,
|
|
43954
44307
|
getCommands,
|
|
43955
44308
|
forkSession: forkClaudeSession,
|
|
44309
|
+
summarizeThread: summarizeClaudeThread,
|
|
43956
44310
|
setModel,
|
|
43957
44311
|
stopTask,
|
|
43958
44312
|
shutdown: shutdown2
|
|
@@ -45471,6 +45825,7 @@ async function createAgentPaneApp(dbPath) {
|
|
|
45471
45825
|
await registerTurnRoutes(fastify);
|
|
45472
45826
|
await registerThreadRoutes(fastify);
|
|
45473
45827
|
await registerWorkspaceRoutes(fastify);
|
|
45828
|
+
await registerFolderRoutes(fastify);
|
|
45474
45829
|
await registerProviderRoutes(fastify);
|
|
45475
45830
|
await registerModelRoutes(fastify);
|
|
45476
45831
|
await registerSkillRoutes(fastify);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@import"https://fonts.googleapis.com/css2?family=Inter:wght@400;450;510;590;600&family=JetBrains+Mono:wght@400;500&display=swap";:root{--canvas: #fdfdfc;--surface-0: #f8f7f5;--surface-1: #f0efed;--surface-2: #e6e4e0;--surface-3: #d6d3cd;--border: #e2e0db;--border-muted: #edebe7;--border-hover: #ccc8c0;--text: #1c1b18;--text-2: #54504a;--text-3: #78736c;--text-muted: #a8a399;--accent: #d97706;--accent-hover: #b45309;--accent-soft: rgba(217, 119, 6, .08);--accent-glow: rgba(217, 119, 6, .2);--green: #16a34a;--amber: #ca8a04;--red: #dc2626;--green-soft: rgba(22, 163, 74, .08);--amber-soft: rgba(202, 138, 4, .08);--red-soft: rgba(220, 38, 38, .08);--ic-claude: #c2410c;--ic-codex: #6366f1;--ic-repoburg: #059669;--ic-cursor: #db2777;--font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--font-mono: "JetBrains Mono", "SF Mono", "Fira Code", monospace;--r-sm: 4px;--r-md: 6px;--r-lg: 8px;--r-xl: 12px;--r-pill: 9999px;--ease: cubic-bezier(.25, .46, .45, .94);--ease-out: cubic-bezier(.22, 1, .36, 1);--dur-fast: .1s;--dur-normal: .15s;--dur-slow: .25s;--inset-highlight: inset 0 1px 0 rgba(0, 0, 0, .03);--inset-strong: inset 0 1px 0 rgba(0, 0, 0, .05);--focus-ring: 0 0 0 3px var(--accent-glow)}*{margin:0;padding:0;box-sizing:border-box}html,body{height:100%;overflow:hidden}body{font-family:var(--font-sans);font-size:13px;font-weight:400;background:var(--canvas);color:var(--text-2);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility;font-feature-settings:"ss03","cv11";font-variant-numeric:tabular-nums;letter-spacing:-.01em}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--surface-3);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--border-hover)}:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:var(--r-md)}.ide-root{display:flex;flex-direction:column;height:100vh}.ide-layout{display:grid;grid-template-columns:240px 6px 1fr 6px 300px;flex:1;overflow:hidden}.resize-handle{width:6px;cursor:col-resize;background:transparent;flex-shrink:0;transition:background var(--dur-fast) var(--ease)}.resize-handle:hover,.resize-handle.dragging{background:var(--border-hover)}body.is-resizing{-webkit-user-select:none;user-select:none}body.is-resizing *{cursor:col-resize!important}.ide-sidebar{background:var(--surface-0);border-right:1px solid var(--border);overflow-y:auto;display:flex;flex-direction:column}.sidebar-header{padding:10px 12px 8px;display:flex;align-items:center;justify-content:space-between}.sidebar-header-title{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted)}.sidebar-add{width:20px;height:20px;border-radius:var(--r-sm);border:none;background:transparent;color:var(--text-muted);cursor:pointer;font-size:15px;display:flex;align-items:center;justify-content:center;transition:all var(--dur-normal) var(--ease)}.sidebar-add:hover{background:#0000000f;color:var(--text)}.tree-section{margin-bottom:2px}.tree-section-header{padding:5px 8px;display:flex;align-items:center;gap:6px;font-size:11px;font-weight:590;color:var(--text-2);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:var(--r-sm);transition:background var(--dur-fast) var(--ease)}.tree-section-header:hover{background:#0000000a}.tree-chevron{font-size:9px;color:var(--text-muted);width:10px;transition:transform var(--dur-normal) var(--ease)}.tree-section.collapsed .tree-chevron{transform:rotate(-90deg)}.tree-section.collapsed .tree-children{display:none}.tree-count{margin-left:auto;font-size:10px;background:var(--surface-2);padding:1px 6px;border-radius:var(--r-pill);color:var(--text-muted);font-variant-numeric:tabular-nums}.tree-children{padding-left:4px}.tree-item{padding:4px 8px 4px 26px;border-radius:var(--r-sm);font-size:12px;cursor:pointer;display:flex;align-items:center;gap:6px;color:var(--text-2);-webkit-user-select:none;user-select:none;transition:all var(--dur-fast) var(--ease);position:relative}.tree-item:hover{background:#0000000a;color:var(--text)}.tree-item.active{background:var(--accent-soft);color:var(--text)}.tree-item.active:before{content:"";position:absolute;left:0;top:4px;bottom:4px;width:2px;background:var(--accent);border-radius:var(--r-pill)}.tree-item .ri{width:16px;height:16px;border-radius:3px;display:flex;align-items:center;justify-content:center;font-size:8px;font-weight:700;color:#fff;flex-shrink:0}.tree-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.star-btn{display:flex;align-items:center;justify-content:center;width:14px;height:14px;border:none;border-radius:3px;background:none;padding:0;color:var(--text-muted);opacity:0;cursor:pointer;flex-shrink:0;transition:opacity var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}.tree-item:hover .star-btn,.star-btn:focus-visible{opacity:1}.star-btn:hover{color:var(--amber);opacity:.75}.star-btn.starred{opacity:1;color:#ca8a04a6}.tree-item-starred{background:#d9770609}.tree-item-starred:hover{background:#d9770612}.tree-item.active.tree-item-starred{background:var(--accent-soft)}.sidebar-footer{margin-top:auto;padding:8px 12px;border-top:1px solid var(--border-muted);font-size:11px;color:var(--text-muted);display:flex;align-items:center;gap:6px;cursor:pointer}.sidebar-footer:hover{color:var(--text-2)}.ide-center{display:flex;flex-direction:column;background:var(--canvas);overflow:hidden;min-height:0}.ide-tabs{display:flex;background:var(--surface-0);border-bottom:1px solid var(--border);overflow-x:auto;flex-shrink:0;scrollbar-width:none}.ide-tabs::-webkit-scrollbar{display:none}.ide-tab{padding:8px 12px;font-size:12px;color:var(--text-3);border-right:1px solid var(--border-muted);cursor:pointer;display:flex;align-items:center;gap:6px;white-space:nowrap;-webkit-user-select:none;user-select:none;transition:all var(--dur-fast) var(--ease);position:relative}.ide-tab:hover{background:#00000008;color:var(--text-2)}.ide-tab.active{color:var(--text);background:var(--canvas)}.ide-tab.active:after{content:"";position:absolute;left:0;right:0;top:0;height:2px;background:var(--accent)}.ide-tab .ri{width:14px;height:14px;font-size:7px;border-radius:3px}.ide-tab-close{margin-left:4px;color:var(--text-muted);font-size:14px;opacity:0;transition:opacity var(--dur-fast) var(--ease);display:flex;align-items:center}.ide-tab:hover .ide-tab-close{opacity:1}.ide-tab-close:hover{color:var(--red)}.ide-tab-add{padding:8px 10px;color:var(--text-muted);cursor:pointer;font-size:14px;transition:color var(--dur-fast) var(--ease);display:flex;align-items:center}.ide-tab-add:hover{color:var(--text)}.ide-render{flex:1;overflow:hidden;display:flex;flex-direction:column;position:relative;min-height:0}.render-scroll{flex:1;padding:20px 28px;overflow-y:auto;font-size:14px;line-height:1.7;color:var(--text);min-height:0}.render-content{max-width:720px}.render-content h1,.render-content h2,.render-content h3{margin:20px 0 8px;font-weight:600;color:var(--text);line-height:1.3}.render-content h1{font-size:20px}.render-content h2{font-size:17px}.render-content h3{font-size:15px}.render-content p{margin-bottom:12px;color:var(--text-2)}.render-content ul,.render-content ol{margin-bottom:12px;padding-left:24px}.render-content li{margin-bottom:4px;color:var(--text-2)}.render-content code{font-family:var(--font-mono);font-size:12px;background:var(--surface-1);padding:2px 6px;border-radius:var(--r-sm);color:var(--accent)}.render-content pre{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-md);padding:12px 16px;overflow-x:auto;margin-bottom:12px}.render-content pre code{background:none;padding:0;color:var(--text);font-size:12.5px;line-height:1.6}.render-content a{color:var(--accent);text-decoration:none}.render-content a:hover{text-decoration:underline}.render-content blockquote{border-left:3px solid var(--border);padding-left:14px;color:var(--text-3);margin-bottom:12px}.render-content table{width:100%;border-collapse:collapse;margin-bottom:12px}.render-content th,.render-content td{border:1px solid var(--border);padding:6px 10px;font-size:13px}.render-content th{background:var(--surface-1);font-weight:510}.turn-header{display:flex;align-items:center;gap:8px;margin-bottom:14px}.turn-header-icon{width:24px;height:24px;border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:9px;font-weight:700;color:#fff}.turn-header-title{font-size:14px;font-weight:600;color:var(--text)}.turn-header-meta{font-size:11px;color:var(--text-muted)}.tool-calls{margin-bottom:16px}.tool-calls-header{display:flex;align-items:center;gap:8px;padding:6px 12px;background:var(--surface-1);border:1px solid var(--border);border-radius:var(--r-sm);cursor:pointer;transition:background .15s ease-out;-webkit-user-select:none;user-select:none}.tool-calls-header:hover{background:var(--surface-2)}.tool-calls-icon{display:flex;align-items:center;color:var(--text-3);flex-shrink:0}.tool-calls-summary{font-size:13px;font-weight:500;color:var(--text-2);flex:1}.tool-calls-chevron{color:var(--text-muted);transition:transform .15s ease-out;flex-shrink:0}.tool-calls-body{margin-top:8px;padding-left:16px;border-left:2px solid var(--border)}.intermediate-segment{margin-bottom:16px}.intermediate-segment:last-child{margin-bottom:0}.user-message{font-size:14px;color:var(--text);background:var(--accent-soft);padding:12px 16px;border-radius:var(--r-md);border:1px solid rgba(217,119,6,.15)}.cmd-bar{position:relative;display:flex;flex-direction:column;padding:0;background:var(--surface-0);border-top:1px solid var(--border);flex-shrink:0}.cmd-input-row{display:flex;align-items:flex-end;gap:8px;padding:8px 12px}.cmd-bar:focus-within{box-shadow:inset 0 0 0 1px #d9770666}.cmd-textarea{flex:1;border:none;background:transparent;color:var(--text);font-size:13px;font-family:var(--font-sans);outline:none;resize:none;overflow-y:auto;line-height:1.5;padding:6px 0}.cmd-textarea::placeholder{color:var(--text-muted)}.cmd-textarea:disabled{opacity:.5}.cmd-textarea:focus-visible{box-shadow:none}.cmd-send-btn{width:28px;height:28px;border:none;border-radius:var(--r-sm);background:var(--surface-2);color:var(--text-muted);cursor:default;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:all var(--dur-fast) var(--ease)}.cmd-send-btn:not(:disabled){background:var(--accent);color:#fff;cursor:pointer}.cmd-send-btn:not(:disabled):hover{background:var(--accent-hover)}.cmd-send-btn:disabled{opacity:.4}.cmd-stop-btn{width:28px;height:28px;border:none;border-radius:var(--r-sm);background:var(--red);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:all var(--dur-fast) var(--ease)}.cmd-stop-btn:hover{background:#b91c1c}.ide-right{background:var(--surface-0);border-left:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden}.right-tabs{display:flex;padding:0 8px;border-bottom:1px solid var(--border);flex-shrink:0;gap:2px}.right-tab{padding:7px 10px;font-size:11px;font-weight:510;color:var(--text-3);cursor:pointer;border-bottom:2px solid transparent;-webkit-user-select:none;user-select:none;transition:all var(--dur-fast) var(--ease);margin-bottom:-1px}.right-tab:hover{color:var(--text-2)}.right-tab.active{color:var(--text);border-bottom-color:var(--accent)}.right-content{flex:1;overflow-y:auto;padding:14px}.right-section{margin-bottom:20px}.right-section-title{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);margin-bottom:8px}.turn-item{display:flex;align-items:center;gap:8px;padding:7px 10px;border-radius:var(--r-sm);cursor:pointer;font-size:12px;color:var(--text-3);transition:all var(--dur-fast) var(--ease);position:relative}.turn-item:hover{background:#0000000a;color:var(--text-2)}.turn-item.active{background:var(--accent-soft);color:var(--text)}.turn-item.active:before{content:"";position:absolute;left:0;top:4px;bottom:4px;width:2px;background:var(--accent);border-radius:var(--r-pill)}.turn-item-icon{width:18px;height:18px;border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:8px;font-weight:700;color:#fff}.turn-item-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.turn-item-status{font-size:10px;color:var(--amber);flex-shrink:0}.turn-item-meta{font-size:10px;color:var(--text-muted);flex-shrink:0}.file-change{display:flex;align-items:center;gap:8px;padding:5px 0;font-size:12px;border-bottom:1px solid var(--border-muted)}.file-change:last-child{border:none}.file-change.clickable{cursor:pointer;transition:background var(--dur-fast) var(--ease)}.file-change.clickable:hover{background:#00000008}.fc-status{width:14px;text-align:center;font-weight:700;font-size:11px;flex-shrink:0}.fc-add{color:var(--green)}.fc-mod{color:var(--amber)}.fc-del{color:var(--red)}.fc-name{flex:1;color:var(--text-2);font-family:var(--font-mono);font-size:11px}.fc-delta{font-size:10px;color:var(--text-muted);flex-shrink:0;font-variant-numeric:tabular-nums}.diff-file-header{display:flex;align-items:center;gap:10px;padding:10px 14px;background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-md) var(--r-md) 0 0;border-bottom:none}.diff-file-status{width:16px;height:16px;border-radius:3px;display:flex;align-items:center;justify-content:center;font-size:9px;font-weight:700;flex-shrink:0}.diff-file-name{font-family:var(--font-mono);font-size:13px;font-weight:510;color:var(--text)}.diff-file-stats{display:flex;align-items:center;gap:6px;margin-left:auto;font-size:11px;font-variant-numeric:tabular-nums}.diff-file-badge{padding:1px 7px;border-radius:var(--r-pill);background:var(--surface-2);color:var(--text-3);font-size:10px}.diff-body{border:1px solid var(--border);border-radius:0 0 var(--r-md) var(--r-md);overflow:hidden;margin-bottom:20px}.diff-line{display:flex;align-items:flex-start;font-family:var(--font-mono);font-size:12px;line-height:1.6}.diff-line-num{width:42px;flex-shrink:0;text-align:right;padding:0 8px;color:var(--text-muted);background:var(--surface-0);-webkit-user-select:none;user-select:none;border-right:1px solid var(--border-muted)}.diff-sign{width:20px;flex-shrink:0;text-align:center;-webkit-user-select:none;user-select:none;font-weight:700}.diff-line-content{flex:1;padding:0 8px;white-space:pre-wrap;word-break:break-all;min-width:0}.diff-line-add{background:#16a34a0f}.diff-line-add .diff-sign{color:var(--green)}.diff-line-del{background:#dc26260f}.diff-line-del .diff-sign{color:var(--red)}.diff-line-ctx .diff-sign{color:var(--text-muted)}.diff-line-ctx .diff-line-content{color:var(--text-3)}.changes-scope-toggle{display:flex;gap:2px;margin-bottom:12px;padding:2px;background:var(--surface-1);border-radius:var(--r-md)}.scope-btn{flex:1;padding:5px 10px;border:none;background:transparent;color:var(--text-3);font-size:11px;font-weight:510;cursor:pointer;border-radius:var(--r-sm);font-family:var(--font-sans);transition:all var(--dur-fast) var(--ease)}.scope-btn:hover{color:var(--text-2)}.scope-btn.active{background:var(--surface-0);color:var(--text);box-shadow:var(--inset-highlight)}.ide-statusbar{display:flex;align-items:center;gap:12px;padding:0 12px;height:24px;background:var(--surface-0);border-top:1px solid var(--border);font-size:11px;color:var(--text-muted);flex-shrink:0;font-variant-numeric:tabular-nums}.sb-item{display:flex;align-items:center;gap:3px;cursor:pointer;transition:color var(--dur-fast) var(--ease)}.sb-item:hover{color:var(--text-2)}.sb-spacer{flex:1}.sb-divider{color:var(--border)}.sb-context{display:flex;align-items:center;gap:5px}.sb-context-text{font-size:10px;color:var(--text-muted);font-variant-numeric:tabular-nums}.model-selector{position:relative}.model-selector-btn{display:flex;align-items:center;gap:4px;background:none;border:none;cursor:pointer;color:var(--text-muted);font-size:11px;padding:2px 6px;border-radius:3px;transition:background var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease)}.model-selector-btn:hover{background:var(--surface-1);color:var(--text-2)}.model-selector-provider{font-weight:500;color:var(--accent)}.model-selector-sep{color:var(--border);margin:0 1px}.model-selector-model{color:var(--text-2)}.model-selector-reasoning{color:var(--text-muted);font-style:italic}.model-selector-chevron{opacity:.5;flex-shrink:0}.model-selector-popover{position:absolute;bottom:calc(100% + 4px);left:0;display:flex;gap:1px;background:var(--surface-0);border:1px solid var(--border);border-radius:6px;box-shadow:0 4px 16px #0003;z-index:100;min-width:0;overflow:hidden}.model-selector-column{min-width:140px;max-width:220px;max-height:280px;overflow-y:auto;padding:4px 0;background:var(--surface-0)}.model-selector-col-header{position:sticky;top:0;background:var(--surface-0);padding:4px 10px;font-size:9px;font-weight:600;text-transform:uppercase;color:var(--text-muted);letter-spacing:.5px}.model-selector-item{display:flex;align-items:center;gap:6px;padding:6px 10px;cursor:pointer;font-size:11px;color:var(--text-2);transition:background var(--dur-fast) var(--ease)}.model-selector-item:hover{background:var(--surface-1)}.model-selector-item.selected{color:var(--accent)}.model-selector-item.disabled{cursor:default;opacity:.5}.model-selector-item.disabled:hover{background:none}.model-selector-item-main{display:flex;flex-direction:column;gap:1px;flex:1;min-width:0}.model-selector-item-name{font-weight:500;white-space:nowrap}.model-selector-item-desc{font-size:9px;color:var(--text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.model-selector-coming-soon{display:flex;align-items:center;gap:2px;font-size:9px;color:var(--text-muted);font-style:italic}.model-selector-empty{padding:8px 10px;font-size:10px;color:var(--text-muted);font-style:italic}.dialog-select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 8px center;padding-right:26px}.badge{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:var(--r-pill);font-size:11px;font-weight:510;white-space:nowrap}.badge-running{background:var(--green-soft);color:var(--green)}.badge-queued{background:var(--amber-soft);color:var(--amber)}.badge-done{background:var(--accent-soft);color:var(--accent)}.badge-failed{background:var(--red-soft);color:var(--red)}.badge-paused{background:#a8a3991f;color:var(--text-muted)}.runtime-icon{width:20px;height:20px;border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center;font-size:9px;font-weight:700;color:#fff;flex-shrink:0;letter-spacing:0}.ic-claude{background:var(--ic-claude)}.ic-codex{background:var(--ic-codex)}.ic-repoburg{background:var(--ic-repoburg)}.ic-cursor{background:var(--ic-cursor)}.status-dot{width:6px;height:6px;border-radius:50%;display:inline-block;flex-shrink:0}.status-dot.running{background:var(--green);animation:dot-pulse 1.5s ease-in-out infinite}.status-dot.queued{background:var(--amber)}.status-dot.error{background:var(--red)}.status-dot.done{background:var(--accent)}.status-dot.paused{background:var(--text-muted)}[data-lucide],svg.lucide{width:16px;height:16px;stroke-width:1.5;flex-shrink:0}.icon-xs{width:12px!important;height:12px!important}.icon-sm{width:14px!important;height:14px!important}.icon-lg{width:20px!important;height:20px!important}.dialog-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#0000004d;display:flex;align-items:center;justify-content:center;z-index:100}.dialog{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-lg);width:400px;max-width:90vw;box-shadow:0 8px 32px #00000029}.dialog-header{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--border-muted)}.dialog-title{font-size:14px;font-weight:600;color:var(--text)}.dialog-close{border:none;background:transparent;color:var(--text-muted);cursor:pointer;padding:4px;border-radius:var(--r-sm);display:flex;align-items:center;transition:all var(--dur-fast) var(--ease)}.dialog-close:hover{background:#0000000f;color:var(--text)}.dialog-body{padding:16px;display:flex;flex-direction:column;gap:14px}.dialog-label{display:flex;flex-direction:column;gap:4px;font-size:11px;font-weight:510;color:var(--text-muted)}.dialog-input{border:1px solid var(--border);border-radius:var(--r-sm);padding:8px 10px;font-size:13px;font-family:var(--font-sans);color:var(--text);background:var(--canvas);outline:none;transition:border-color var(--dur-fast) var(--ease)}.dialog-input:focus{border-color:var(--accent);box-shadow:var(--focus-ring)}.dialog-footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--border-muted)}.dialog-btn-cancel{padding:6px 14px;border-radius:var(--r-sm);border:1px solid var(--border);background:transparent;color:var(--text-2);font-size:12px;cursor:pointer;font-family:var(--font-sans);transition:all var(--dur-fast) var(--ease);display:inline-flex;align-items:center;justify-content:center;gap:6px}.dialog-btn-cancel:hover{background:var(--surface-2);color:var(--text)}.dialog-btn-create{padding:6px 14px;border-radius:var(--r-sm);border:none;background:var(--accent);color:#fff;font-size:12px;font-weight:510;cursor:pointer;font-family:var(--font-sans);transition:all var(--dur-fast) var(--ease);display:inline-flex;align-items:center;justify-content:center;gap:6px}.dialog-btn-create:hover{background:var(--accent-hover)}.dialog-hint{font-size:12px;color:var(--text-2);line-height:1.5}.share-directives-input{resize:vertical;min-height:56px;font-family:var(--font-sans)}.spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.turn-group{margin-bottom:24px}.turn-block{margin-bottom:32px;padding-bottom:8px;border-bottom:1px solid var(--border)}.turn-block:last-child{border-bottom:none}.cmd-block{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-md);padding:10px 14px;overflow-x:auto;margin-bottom:12px}.cmd-block code{font-family:var(--font-mono);font-size:12px;color:var(--text)}.cmd-output{background:var(--surface-0);border:1px solid var(--border-muted);border-radius:var(--r-md);padding:10px 14px;overflow-x:auto;margin-bottom:12px;max-height:200px;overflow-y:auto}.cmd-output code{font-family:var(--font-mono);font-size:12px;color:var(--text-3)}.cmd-output-toggle{border:1px solid var(--border);border-radius:var(--r-sm);background:var(--surface-1);color:var(--text-muted);font-size:11px;font-family:var(--font-sans);padding:4px 10px;cursor:pointer;margin-bottom:12px;transition:all var(--dur-fast) var(--ease)}.cmd-output-toggle:hover{background:var(--surface-2);color:var(--text-2)}.mcp-args{margin-bottom:12px}.mcp-arg{margin-bottom:6px}.mcp-arg-key{font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.04em;display:block;margin-bottom:3px}.mcp-arg-value{font-size:12px;color:var(--text-2);white-space:pre-wrap;word-break:break-word}.file-change-list{display:flex;flex-direction:column;gap:2px}.todo-list{list-style:none;padding-left:0}.todo-done{color:var(--text-3);text-decoration:line-through}.todo-pending{color:var(--text-2)}.empty-state{padding:40px 20px;text-align:center;color:var(--text-muted);font-size:13px}.palette-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#00000040;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);display:flex;align-items:flex-start;justify-content:center;padding-top:120px;z-index:200}.palette{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-lg);width:520px;max-width:90vw;box-shadow:0 12px 40px #0003;overflow:hidden}.palette-search{display:flex;align-items:center;gap:8px;padding:12px 16px;border-bottom:1px solid var(--border-muted)}.palette-search input{flex:1;border:none;background:transparent;color:var(--text);font-size:15px;font-family:var(--font-sans);outline:none}.palette-search input::placeholder{color:var(--text-muted)}.palette-esc{font-size:10px;font-weight:600;color:var(--text-muted);background:var(--surface-2);padding:2px 6px;border-radius:var(--r-sm)}.palette-list{max-height:360px;overflow-y:auto;padding:4px}.palette-empty{padding:24px;text-align:center;color:var(--text-muted);font-size:13px}.palette-item{display:flex;align-items:center;gap:10px;padding:8px 12px;border-radius:var(--r-sm);cursor:pointer;transition:background var(--dur-fast) var(--ease)}.palette-item.selected{background:var(--accent-soft)}.palette-item-icon{color:var(--text-muted);flex-shrink:0;display:flex;align-items:center}.palette-item.selected .palette-item-icon{color:var(--accent)}.palette-item-label{font-size:13px;color:var(--text);font-weight:510}.palette-item-hint{font-size:11px;color:var(--text-muted);margin-left:auto}.palette-item-enter{color:var(--text-muted);flex-shrink:0}.toast-container{position:fixed;bottom:36px;right:16px;display:flex;flex-direction:column-reverse;gap:8px;z-index:300;pointer-events:none}.toast{display:flex;align-items:center;gap:8px;padding:10px 14px;border-radius:var(--r-md);font-size:12px;font-weight:500;min-width:280px;max-width:400px;pointer-events:auto;animation:toast-in .2s ease-out;border:1px solid var(--border);background:var(--surface-0);box-shadow:0 4px 16px #0000001f}@keyframes toast-in{0%{opacity:0;transform:translate(20px)}to{opacity:1;transform:translate(0)}}.toast-success{border-left:3px solid var(--green)}.toast-success svg{color:var(--green)}.toast-error{border-left:3px solid var(--red)}.toast-error svg{color:var(--red)}.toast-info{border-left:3px solid var(--accent)}.toast-info svg{color:var(--accent)}.toast-warn{border-left:3px solid var(--amber)}.toast-warn svg{color:var(--amber)}.toast-message{flex:1;color:var(--text-2)}.toast-close{border:none;background:transparent;color:var(--text-muted);cursor:pointer;padding:2px;border-radius:var(--r-sm);display:flex;align-items:center;transition:color var(--dur-fast) var(--ease)}.toast-close:hover{color:var(--text)}.error-banner{display:flex;align-items:center;gap:10px;padding:10px 16px;background:#dc262614;border:1px solid rgba(220,38,38,.2);border-radius:var(--r-md);margin-bottom:16px}.banner-icon{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;flex-shrink:0}.error-banner .banner-icon{background:var(--red);color:#fff}.error-banner .banner-text{color:var(--red);font-size:13px;font-weight:500}.aborted-banner{display:flex;align-items:center;gap:10px;padding:10px 16px;background:#d9770614;border:1px solid rgba(217,119,6,.2);border-radius:var(--r-md);margin-bottom:16px}.aborted-banner .banner-icon{background:var(--amber);color:#fff}.aborted-banner .banner-text{color:var(--amber);font-size:13px;font-weight:500}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}.skeleton-bars{width:80%;max-width:500px;margin:20px 0}.skeleton-bar{height:10px;border-radius:var(--r-sm);background:var(--surface-1);margin-bottom:8px;animation:shimmer 1.2s infinite}.skeleton-bar:nth-child(1){width:60%}.skeleton-bar:nth-child(2){width:85%}.skeleton-bar:nth-child(3){width:70%}.skeleton-bar:nth-child(4){width:90%}.skeleton-bar:nth-child(5){width:50%}@keyframes shimmer{0%{opacity:.3}50%{opacity:.6}to{opacity:.3}}@keyframes dot-pulse{0%{opacity:1}to{opacity:.4}}.diff-file-header{transition:background .3s ease-out}.diff-file-header.diff-highlight{background:var(--accent-soft)}.palette-footer{display:flex;gap:16px;padding:8px 16px;border-top:1px solid var(--border-muted);font-size:11px;color:var(--text-muted)}.palette-footer-hint{display:flex;align-items:center;gap:4px}.kbd{font-family:var(--font-mono);font-size:10px;padding:1px 5px;border-radius:var(--r-sm);background:var(--surface-2);border:1px solid var(--border)}.toast-undo{font-size:12px;font-weight:500;color:var(--accent);background:transparent;border:none;cursor:pointer;padding:2px 8px;border-radius:var(--r-sm);display:flex;align-items:center;gap:4px;transition:background var(--dur-fast) var(--ease)}.toast-undo:hover{background:var(--accent-soft)}.tree-section-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px}.tree-section-add{width:18px;height:18px;border:none;border-radius:var(--r-sm);background:transparent;color:var(--text-muted);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all var(--dur-fast) var(--ease);flex-shrink:0}.tree-section-add:hover{background:var(--accent-soft);color:var(--accent)}.tree-empty{padding:4px 8px 4px 26px;font-size:11px;color:var(--text-muted);font-style:italic}.tree-subgroup{margin-bottom:1px}.tree-subgroup-header{padding:3px 8px 3px 18px;display:flex;align-items:center;gap:5px;font-size:10px;font-weight:590;color:var(--text-muted);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:var(--r-sm);transition:background var(--dur-fast) var(--ease)}.tree-subgroup-header:hover{background:#0000000a;color:var(--text-2)}.tree-subgroup.collapsed .tree-chevron{transform:rotate(-90deg)}.tree-subgroup.collapsed .tree-subgroup-items{display:none}.tree-subgroup-label{text-transform:uppercase;letter-spacing:.05em}.tree-subgroup-count{margin-left:auto;font-size:9px;color:var(--text-muted);font-variant-numeric:tabular-nums}.tree-subgroup-items{padding-left:0}.tree-item-finished .tree-label{color:var(--text-muted);opacity:.6}.tree-item-finished:hover .tree-label{opacity:.85}.ctx-menu{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-md);box-shadow:0 4px 16px #0000001f;padding:4px;min-width:160px}.ctx-menu-item{display:flex;align-items:center;gap:8px;padding:6px 10px;border-radius:var(--r-sm);font-size:12px;color:var(--text-2);cursor:pointer;transition:background var(--dur-fast) var(--ease)}.ctx-menu-item:hover{background:var(--accent-soft);color:var(--text)}.ctx-menu-item.ctx-danger:hover{background:#dc262614;color:var(--red)}.ctx-menu-item.ctx-disabled{opacity:.4;cursor:default}.ctx-menu-item.ctx-disabled:hover{background:transparent;color:var(--text-2)}.tree-folder{margin-bottom:1px}.tree-folder-header{padding:3px 8px 3px 18px;display:flex;align-items:center;gap:5px;font-size:11px;font-weight:590;color:var(--text-2);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:var(--r-sm);transition:background var(--dur-fast) var(--ease)}.tree-folder-header:hover{background:#0000000a}.tree-folder.collapsed .tree-chevron{transform:rotate(-90deg)}.tree-folder.collapsed .tree-folder-children{display:none}.tree-folder-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tree-folder-children{padding-left:8px}.tree-folder-header.drop-over{background:var(--accent-soft);box-shadow:inset 0 0 0 1px var(--accent);color:var(--text)}.drop-over{background:var(--accent-soft);border-radius:var(--r-sm)}.tree-item.dragging,.tree-folder.dragging{opacity:.35}.drag-overlay{display:flex;align-items:center;gap:6px;background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-sm);padding:4px 10px;font-size:12px;color:var(--text);box-shadow:0 4px 12px #00000026;max-width:200px}.drag-overlay span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tree-rename-input{flex:1;border:1px solid var(--accent);border-radius:var(--r-sm);padding:1px 6px;font-size:12px;font-family:var(--font-sans);color:var(--text);background:var(--canvas);outline:none;box-shadow:var(--focus-ring);min-width:0}.slash-popup{position:absolute;bottom:100%;left:12px;right:12px;margin-bottom:4px;background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-md);box-shadow:0 4px 16px #0000001f;max-height:280px;overflow-y:auto;z-index:100}.slash-popup-header{padding:6px 10px;font-size:10px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.05em;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:4px}.slash-popup-back{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:11px;padding:2px 4px;border-radius:var(--r-sm)}.slash-popup-back:hover{background:var(--surface-1);color:var(--text-2)}.slash-popup-empty{padding:12px 10px;font-size:12px;color:var(--text-muted);text-align:center}.slash-popup-item{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 10px;cursor:pointer;border-radius:var(--r-sm);transition:background var(--dur-fast) var(--ease)}.slash-popup-item:hover,.slash-popup-item.selected{background:var(--accent-soft)}.slash-popup-label{font-size:12px;font-weight:500;color:var(--text-2);font-family:var(--font-mono)}.slash-popup-hint{font-size:11px;color:var(--text-muted)}.slash-popup-item-main{display:flex;flex-direction:column;gap:1px}.slash-popup-check{color:var(--accent);font-size:13px}.skill-badges{display:flex;flex-wrap:wrap;gap:4px;padding:6px 12px 0}.skill-badge{display:inline-flex;align-items:center;gap:4px;padding:2px 6px;font-size:11px;font-family:var(--font-mono);color:var(--accent);background:var(--accent-soft);border-radius:var(--r-sm)}.skill-badge-remove{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:13px;line-height:1;padding:0}.skill-badge-remove:hover{color:var(--red)}.attachment-preview-area{display:flex;flex-wrap:wrap;gap:4px;padding:6px 12px 0}.attachment-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 6px 2px 2px;border:1px solid var(--border);border-radius:var(--r-pill);background:var(--surface-1);max-width:180px;position:relative;transition:border-color var(--dur-fast) var(--ease)}.attachment-chip:hover{border-color:var(--accent)}.attachment-thumb{width:18px;height:18px;object-fit:cover;border-radius:50%;flex-shrink:0}.attachment-file-icon{width:14px;height:14px;color:var(--text-muted);flex-shrink:0}.attachment-info{display:flex;flex-direction:column;gap:0;overflow:hidden;min-width:0}.attachment-name{font-size:10px;font-family:var(--font-mono);color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100px}.attachment-size{font-size:9px;color:var(--text-muted);font-variant-numeric:tabular-nums}.attachment-remove{background:none;border:none;color:var(--text-muted);cursor:pointer;padding:1px;display:flex;align-items:center;justify-content:center;border-radius:var(--r-xs);transition:all var(--dur-fast) var(--ease);flex-shrink:0}.attachment-remove:hover{color:var(--red);background:#ef44441a}.attachment-clip-btn{width:28px;height:28px;border:none;border-radius:var(--r-sm);background:transparent;color:var(--text-muted);cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:all var(--dur-fast) var(--ease)}.attachment-clip-btn:hover{color:var(--accent);background:var(--surface-2)}.attachment-clip-btn:disabled{opacity:.3;cursor:default}.cmd-bar.drag-over{box-shadow:inset 0 0 0 2px var(--accent);background:var(--accent-soft)}.image-preview-modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:10000;background:#000c;display:flex;align-items:center;justify-content:center;padding:32px;animation:modal-fade-in .15s ease-out}@keyframes modal-fade-in{0%{opacity:0}to{opacity:1}}.image-preview-content{position:relative;max-width:90vw;max-height:90vh;display:flex;flex-direction:column;align-items:center;gap:8px}.image-preview-content img{max-width:100%;max-height:80vh;object-fit:contain;border-radius:var(--r-sm);border:1px solid var(--border)}.image-preview-info{display:flex;gap:12px;font-size:12px;color:var(--text-muted);font-family:var(--font-mono)}.image-preview-close{position:absolute;top:-12px;right:-12px;width:28px;height:28px;border:none;border-radius:50%;background:var(--surface-2);color:var(--text);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all var(--dur-fast) var(--ease)}.image-preview-close:hover{background:var(--red);color:#fff}.attachment-pills{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}.attachment-pill{display:inline-flex;align-items:center;gap:4px;padding:2px 8px 2px 2px;border:1px solid var(--border);border-radius:var(--r-pill);background:var(--surface-1);font-size:10px;font-family:var(--font-mono);color:var(--text-muted);transition:border-color var(--dur-fast) var(--ease)}.attachment-pill:hover{border-color:var(--accent)}.attachment-pill-thumb{width:16px;height:16px;object-fit:cover;border-radius:50%;flex-shrink:0}.attachment-pill-icon{color:var(--text-muted);flex-shrink:0}.attachment-pill-name{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100px}.right-tab-badge{display:inline-flex;align-items:center;justify-content:center;min-width:16px;height:16px;padding:0 4px;margin-left:4px;font-size:10px;font-weight:600;color:#fff;background:var(--accent);border-radius:8px}.task-count-badge{font-size:10px;font-weight:500}.task-card{border:1px solid var(--border);border-radius:var(--r-md);padding:10px 12px;margin-bottom:10px;transition:border-color var(--dur-fast) var(--ease)}.task-card.task-running{border-color:var(--accent)}.task-card.task-failed{border-color:var(--red)}.task-card-header{display:flex;align-items:center;gap:8px}.task-card-icon{display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:var(--r-sm);background:var(--surface-2);color:var(--text-3);flex-shrink:0}.task-card-type{font-size:13px;font-weight:600;color:var(--text)}.task-card-status{display:flex;align-items:center;gap:3px;font-size:11px;padding:2px 6px;border-radius:var(--r-sm);flex-shrink:0}.task-status-running{color:var(--accent);background:var(--accent-soft)}.task-status-done{color:var(--green);background:var(--green-soft)}.task-status-failed{color:var(--red);background:var(--red-soft)}.task-card-chevron{color:var(--text-muted);flex-shrink:0;transition:transform var(--dur-fast) var(--ease)}.task-card-desc{font-size:12px;color:var(--text-2);margin-top:6px;font-family:var(--font-mono)}.task-card-meta{font-size:11px;color:var(--text-muted);margin-top:4px}.task-card-body{margin-top:8px}.task-output{max-height:300px}.task-card-placeholder{font-size:12px;color:var(--text-muted);font-style:italic;padding:8px 0}.task-card-context{font-size:10px;color:var(--text-muted);margin-top:6px;padding-top:6px;border-top:1px solid var(--border-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}mark[data-thread-id]{background:#d977062e;border-radius:2px;cursor:pointer;padding:0 1px;transition:background var(--dur-fast) var(--ease)}mark[data-thread-id]:hover{background:#d977064d}mark[data-thread-id].thread-mark-resolved{background:transparent;border-bottom:2px dashed var(--text-muted)}.selection-actions{position:fixed;z-index:9999;display:flex;gap:4px}.discuss-button{display:flex;align-items:center;gap:4px;padding:4px 10px;border:1px solid var(--border);border-radius:var(--r-sm);background:var(--surface-0);color:var(--accent);font-size:11px;font-weight:500;cursor:pointer;box-shadow:0 2px 8px #0000001f;transition:all var(--dur-fast) var(--ease)}.discuss-button:hover{background:var(--accent-soft);border-color:var(--accent)}.copy-text-btn{position:absolute;top:-4px;right:-4px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;border:1px solid var(--border);border-radius:var(--r-sm);background:var(--surface-0);color:var(--text-3);cursor:pointer;opacity:0;z-index:5;box-shadow:0 1px 4px #00000014;transition:all var(--dur-fast) var(--ease)}.copy-text-wrapper:hover .copy-text-btn,.copy-text-btn:focus-visible,.copy-text-btn.copied{opacity:1}.copy-text-btn:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-soft)}.copy-text-btn.copied{border-color:var(--green);color:var(--green);background:var(--surface-0)}.thread-create-popover{position:fixed;z-index:9999;min-width:280px;max-width:360px;background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-md);box-shadow:0 4px 16px #00000026;padding:10px;display:flex;flex-direction:column;gap:8px;transform:translate(-100%)}.thread-create-header{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}.thread-create-quote{font-size:11px;color:var(--text-muted);font-style:italic;flex:1;line-height:1.4}.thread-create-close{border:none;background:transparent;color:var(--text-muted);cursor:pointer;padding:2px;border-radius:var(--r-sm);flex-shrink:0}.thread-create-close:hover{background:var(--surface-1);color:var(--text)}.thread-create-input{border:1px solid var(--border);border-radius:var(--r-sm);padding:8px 10px;font-size:13px;font-family:var(--font-sans);color:var(--text);background:var(--canvas);outline:none;resize:none;line-height:1.5;transition:border-color var(--dur-fast) var(--ease)}.thread-create-input:focus{border-color:var(--accent);box-shadow:var(--focus-ring)}.thread-create-footer{display:flex;align-items:center;justify-content:space-between}.thread-create-hint{font-size:10px;color:var(--text-muted)}.thread-create-send{display:flex;align-items:center;gap:4px;padding:4px 10px;border:none;border-radius:var(--r-sm);background:var(--accent);color:#fff;font-size:11px;font-weight:500;cursor:pointer;transition:background var(--dur-fast) var(--ease)}.thread-create-send:disabled{opacity:.4;cursor:default}.thread-create-send:not(:disabled):hover{background:var(--accent-hover)}.thread-filter-tabs{display:flex;gap:2px;margin-bottom:12px;padding:2px;background:var(--surface-1);border-radius:var(--r-md)}.thread-filter-tab{flex:1;padding:4px 8px;border:none;background:transparent;color:var(--text-3);font-size:10px;font-weight:500;cursor:pointer;border-radius:var(--r-sm);font-family:var(--font-sans);transition:all var(--dur-fast) var(--ease)}.thread-filter-tab:hover{color:var(--text-2)}.thread-filter-tab.active{background:var(--surface-0);color:var(--text);box-shadow:var(--inset-highlight)}.thread-card{border:1px solid var(--border);border-radius:var(--r-md);padding:10px 12px;margin-bottom:10px;transition:border-color var(--dur-fast) var(--ease),background var(--dur-fast) var(--ease)}.thread-card.thread-resolved{opacity:.7}.thread-card-highlighted{border-color:var(--accent);background:var(--accent-soft)}.thread-card-header{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;cursor:pointer}.thread-card-quote{font-size:11px;color:var(--text-muted);font-style:italic;line-height:1.4;flex:1}.thread-card-header-right{display:flex;align-items:center;gap:4px;flex-shrink:0}.thread-status-badge{font-size:10px;font-weight:600;padding:2px 8px;border-radius:var(--r-pill)}.thread-status-open{background:var(--accent-soft);color:var(--accent)}.thread-status-resolved{background:var(--green-soft);color:var(--green)}.thread-card-conversation{margin-top:8px;max-height:300px;overflow-y:auto}.thread-card-turn{margin-bottom:8px;padding-bottom:8px;border-bottom:1px solid var(--border-muted)}.thread-card-turn:last-child{border-bottom:none;margin-bottom:0;padding-bottom:0}.thread-card-user-message{font-size:12px;color:var(--text);background:var(--accent-soft);padding:6px 10px;border-radius:var(--r-sm);border:1px solid rgba(217,119,6,.15);margin-bottom:4px}.thread-card-ai-response{font-size:12px;color:var(--text-2);padding:4px 0;line-height:1.5}.thread-card-ai-response p{margin-bottom:6px}.thread-card-ai-response code{font-family:var(--font-mono);font-size:11px;background:var(--surface-1);padding:1px 4px;border-radius:var(--r-sm);color:var(--accent)}.thread-card-ai-response pre{background:var(--surface-0);border:1px solid var(--border);border-radius:var(--r-sm);padding:8px;overflow-x:auto;margin-bottom:6px}.thread-card-ai-response pre code{background:none;padding:0}.thread-card-pending{font-size:11px;color:var(--text-muted);font-style:italic;padding:4px 0}.thread-card-placeholder{font-size:11px;color:var(--text-muted);font-style:italic;padding:8px 0}.thread-card-followup{display:flex;gap:4px;margin-top:8px}.thread-card-followup-input{flex:1;border:1px solid var(--border);border-radius:var(--r-sm);padding:6px 8px;font-size:12px;font-family:var(--font-sans);color:var(--text);background:var(--canvas);outline:none;resize:none;line-height:1.5;transition:border-color var(--dur-fast) var(--ease)}.thread-card-followup-input:focus{border-color:var(--accent)}.thread-card-followup-input:disabled{opacity:.5}.thread-card-followup-send{width:28px;height:28px;border:none;border-radius:var(--r-sm);background:var(--accent);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:background var(--dur-fast) var(--ease)}.thread-card-followup-send:disabled{opacity:.4;cursor:default}.thread-card-followup-send:not(:disabled):hover{background:var(--accent-hover)}.thread-locate-btn{background:none;border:none;color:var(--text-muted);cursor:pointer;padding:2px;border-radius:3px;display:flex;align-items:center;transition:all var(--dur-fast) var(--ease);flex-shrink:0}.thread-locate-btn:hover{color:var(--accent);background:var(--accent-soft)}.thread-mark-flash{animation:mark-flash 1.5s ease-out}@keyframes mark-flash{0%{background:#d9770680}to{background:#d977062e}}.thread-card-actions{display:flex;gap:6px;margin-top:8px;padding-top:8px;border-top:1px solid var(--border-muted)}.thread-action-btn{display:flex;align-items:center;gap:4px;padding:4px 8px;border:1px solid var(--border);border-radius:var(--r-sm);background:transparent;color:var(--text-3);font-size:11px;cursor:pointer;font-family:var(--font-sans);transition:all var(--dur-fast) var(--ease)}.thread-action-btn:hover{background:var(--surface-1);color:var(--text)}.thread-action-btn.thread-action-danger:hover{background:#dc262614;color:var(--red);border-color:#dc262633}.agent-call-card{display:flex;align-items:center;gap:8px;padding:8px 14px;border-left:3px solid var(--accent);background:var(--surface);border-radius:0 var(--r-sm) var(--r-sm) 0}.agent-call-icon{color:var(--text-2);display:flex;align-items:center}.agent-call-desc{font-size:13px;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.agent-call-status{font-size:10px;font-family:var(--font-mono);padding:1px 6px;border-radius:var(--r-sm)}.agent-call-status.running{color:var(--accent);background:var(--accent-soft)}.agent-call-status.done{color:var(--green);background:#22c55e14}.agent-call-status.failed{color:var(--red);background:#ef444414}.ask-user-card{border-left:3px solid var(--accent)}.ask-user-groups{display:flex;flex-direction:column;gap:10px;margin-top:6px}.ask-user-group{display:flex;flex-direction:column;gap:6px}.ask-user-question{font-size:12px;font-weight:600;color:var(--text-2)}.ask-user-options{display:flex;flex-wrap:wrap;gap:6px}.ask-user-option{padding:4px 10px;font-size:12px;font-family:var(--font-sans);color:var(--text-2);background:var(--canvas);border:1px solid var(--border);border-radius:var(--r-sm);cursor:pointer;transition:all var(--dur-fast) var(--ease)}.ask-user-option:not(:disabled):hover{border-color:var(--accent);color:var(--accent)}.ask-user-option.selected{background:var(--accent);border-color:var(--accent);color:#fff}.ask-user-option:disabled{opacity:.55;cursor:default}.ask-user-option.selected:disabled{opacity:.8}.ask-user-send{display:inline-flex;align-items:center;gap:5px;padding:4px 12px;font-size:12px;font-family:var(--font-sans);color:#fff;background:var(--accent);border:none;border-radius:var(--r-sm);cursor:pointer;align-self:flex-start;transition:background var(--dur-fast) var(--ease)}.ask-user-send:disabled{opacity:.4;cursor:default}.ask-user-send:not(:disabled):hover{background:var(--accent-hover)}.ask-user-submitted{font-size:11px;color:var(--text-muted);font-style:italic}
|