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.
@@ -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: turnRows.map((row) => ({
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: detail.turns.filter((t) => t.thread_id === tr.id)
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().prepare(
41346
- `INSERT INTO sessions (id, title, runtime_type, model, model_reasoning_effort, cwd, external_thread_id, status, is_running, created_at, updated_at, runtime_config)
41347
- VALUES (?, ?, ?, ?, ?, ?, NULL, 'active', 0, ?, ?, ?)`
41348
- ).run(id, title, runtime_type, model, model_reasoning_effort, cwd, now, now, runtime_config);
41349
- const session = getDb().prepare("SELECT * FROM sessions WHERE id = ?").get(id);
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
- ...process.env.CLAUDE_BIN ? { pathToClaudeCodeExecutable: process.env.CLAUDE_BIN } : {},
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}