repoburg 1.3.268 → 1.3.270

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.
@@ -7850,7 +7850,7 @@ var require_thread_stream = __commonJS({
7850
7850
  var { version } = require_package();
7851
7851
  var { EventEmitter: EventEmitter2 } = __require("events");
7852
7852
  var { Worker } = __require("worker_threads");
7853
- var { join: join3 } = __require("path");
7853
+ var { join: join4 } = __require("path");
7854
7854
  var { pathToFileURL } = __require("url");
7855
7855
  var { wait } = require_wait();
7856
7856
  var {
@@ -7901,7 +7901,7 @@ var require_thread_stream = __commonJS({
7901
7901
  function createWorker(stream, opts) {
7902
7902
  const { filename, workerData } = opts;
7903
7903
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
7904
- const toExecute = bundlerOverrides["thread-stream-worker"] || join3(__dirname, "lib", "worker.js");
7904
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join4(__dirname, "lib", "worker.js");
7905
7905
  const worker = new Worker(toExecute, {
7906
7906
  ...opts.workerOpts,
7907
7907
  name: opts.workerOpts?.name || "thread-stream",
@@ -8367,9 +8367,9 @@ var require_transport = __commonJS({
8367
8367
  "node_modules/pino/lib/transport.js"(exports, module) {
8368
8368
  "use strict";
8369
8369
  var { createRequire } = __require("module");
8370
- var { existsSync: existsSync2 } = __require("node:fs");
8370
+ var { existsSync: existsSync3 } = __require("node:fs");
8371
8371
  var getCallers = require_caller();
8372
- var { join: join3, isAbsolute, sep } = __require("node:path");
8372
+ var { join: join4, isAbsolute, sep } = __require("node:path");
8373
8373
  var { fileURLToPath: fileURLToPath3 } = __require("node:url");
8374
8374
  var sleep = require_atomic_sleep();
8375
8375
  var onExit = require_on_exit_leak_free();
@@ -8441,7 +8441,7 @@ var require_transport = __commonJS({
8441
8441
  return false;
8442
8442
  }
8443
8443
  }
8444
- return isAbsolute(path9) && !existsSync2(path9);
8444
+ return isAbsolute(path9) && !existsSync3(path9);
8445
8445
  }
8446
8446
  function stripQuotes(value) {
8447
8447
  const first = value[0];
@@ -8522,7 +8522,7 @@ var require_transport = __commonJS({
8522
8522
  throw new Error("only one of target or targets can be specified");
8523
8523
  }
8524
8524
  if (targets) {
8525
- target = bundlerOverrides["pino-worker"] || join3(__dirname, "worker.js");
8525
+ target = bundlerOverrides["pino-worker"] || join4(__dirname, "worker.js");
8526
8526
  options.targets = targets.filter((dest) => dest.target).map((dest) => {
8527
8527
  return {
8528
8528
  ...dest,
@@ -8540,7 +8540,7 @@ var require_transport = __commonJS({
8540
8540
  });
8541
8541
  });
8542
8542
  } else if (pipeline) {
8543
- target = bundlerOverrides["pino-worker"] || join3(__dirname, "worker.js");
8543
+ target = bundlerOverrides["pino-worker"] || join4(__dirname, "worker.js");
8544
8544
  options.pipelines = [pipeline.map((dest) => {
8545
8545
  return {
8546
8546
  ...dest,
@@ -8563,7 +8563,7 @@ var require_transport = __commonJS({
8563
8563
  return origin;
8564
8564
  }
8565
8565
  if (origin === "pino/file") {
8566
- return join3(__dirname, "..", "file.js");
8566
+ return join4(__dirname, "..", "file.js");
8567
8567
  }
8568
8568
  let fixTarget2;
8569
8569
  for (const filePath of callers) {
@@ -9543,7 +9543,7 @@ var require_safe_stable_stringify = __commonJS({
9543
9543
  return circularValue;
9544
9544
  }
9545
9545
  let res = "";
9546
- let join3 = ",";
9546
+ let join4 = ",";
9547
9547
  const originalIndentation = indentation;
9548
9548
  if (Array.isArray(value)) {
9549
9549
  if (value.length === 0) {
@@ -9557,7 +9557,7 @@ var require_safe_stable_stringify = __commonJS({
9557
9557
  indentation += spacer;
9558
9558
  res += `
9559
9559
  ${indentation}`;
9560
- join3 = `,
9560
+ join4 = `,
9561
9561
  ${indentation}`;
9562
9562
  }
9563
9563
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -9565,13 +9565,13 @@ ${indentation}`;
9565
9565
  for (; i < maximumValuesToStringify - 1; i++) {
9566
9566
  const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
9567
9567
  res += tmp2 !== void 0 ? tmp2 : "null";
9568
- res += join3;
9568
+ res += join4;
9569
9569
  }
9570
9570
  const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
9571
9571
  res += tmp !== void 0 ? tmp : "null";
9572
9572
  if (value.length - 1 > maximumBreadth) {
9573
9573
  const removedKeys = value.length - maximumBreadth - 1;
9574
- res += `${join3}"... ${getItemCount(removedKeys)} not stringified"`;
9574
+ res += `${join4}"... ${getItemCount(removedKeys)} not stringified"`;
9575
9575
  }
9576
9576
  if (spacer !== "") {
9577
9577
  res += `
@@ -9592,7 +9592,7 @@ ${originalIndentation}`;
9592
9592
  let separator = "";
9593
9593
  if (spacer !== "") {
9594
9594
  indentation += spacer;
9595
- join3 = `,
9595
+ join4 = `,
9596
9596
  ${indentation}`;
9597
9597
  whitespace = " ";
9598
9598
  }
@@ -9606,13 +9606,13 @@ ${indentation}`;
9606
9606
  const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
9607
9607
  if (tmp !== void 0) {
9608
9608
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
9609
- separator = join3;
9609
+ separator = join4;
9610
9610
  }
9611
9611
  }
9612
9612
  if (keyLength > maximumBreadth) {
9613
9613
  const removedKeys = keyLength - maximumBreadth;
9614
9614
  res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
9615
- separator = join3;
9615
+ separator = join4;
9616
9616
  }
9617
9617
  if (spacer !== "" && separator.length > 1) {
9618
9618
  res = `
@@ -9653,7 +9653,7 @@ ${originalIndentation}`;
9653
9653
  }
9654
9654
  const originalIndentation = indentation;
9655
9655
  let res = "";
9656
- let join3 = ",";
9656
+ let join4 = ",";
9657
9657
  if (Array.isArray(value)) {
9658
9658
  if (value.length === 0) {
9659
9659
  return "[]";
@@ -9666,7 +9666,7 @@ ${originalIndentation}`;
9666
9666
  indentation += spacer;
9667
9667
  res += `
9668
9668
  ${indentation}`;
9669
- join3 = `,
9669
+ join4 = `,
9670
9670
  ${indentation}`;
9671
9671
  }
9672
9672
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -9674,13 +9674,13 @@ ${indentation}`;
9674
9674
  for (; i < maximumValuesToStringify - 1; i++) {
9675
9675
  const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
9676
9676
  res += tmp2 !== void 0 ? tmp2 : "null";
9677
- res += join3;
9677
+ res += join4;
9678
9678
  }
9679
9679
  const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
9680
9680
  res += tmp !== void 0 ? tmp : "null";
9681
9681
  if (value.length - 1 > maximumBreadth) {
9682
9682
  const removedKeys = value.length - maximumBreadth - 1;
9683
- res += `${join3}"... ${getItemCount(removedKeys)} not stringified"`;
9683
+ res += `${join4}"... ${getItemCount(removedKeys)} not stringified"`;
9684
9684
  }
9685
9685
  if (spacer !== "") {
9686
9686
  res += `
@@ -9693,7 +9693,7 @@ ${originalIndentation}`;
9693
9693
  let whitespace = "";
9694
9694
  if (spacer !== "") {
9695
9695
  indentation += spacer;
9696
- join3 = `,
9696
+ join4 = `,
9697
9697
  ${indentation}`;
9698
9698
  whitespace = " ";
9699
9699
  }
@@ -9702,7 +9702,7 @@ ${indentation}`;
9702
9702
  const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
9703
9703
  if (tmp !== void 0) {
9704
9704
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
9705
- separator = join3;
9705
+ separator = join4;
9706
9706
  }
9707
9707
  }
9708
9708
  if (spacer !== "" && separator.length > 1) {
@@ -9760,20 +9760,20 @@ ${originalIndentation}`;
9760
9760
  indentation += spacer;
9761
9761
  let res2 = `
9762
9762
  ${indentation}`;
9763
- const join4 = `,
9763
+ const join5 = `,
9764
9764
  ${indentation}`;
9765
9765
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
9766
9766
  let i = 0;
9767
9767
  for (; i < maximumValuesToStringify - 1; i++) {
9768
9768
  const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
9769
9769
  res2 += tmp2 !== void 0 ? tmp2 : "null";
9770
- res2 += join4;
9770
+ res2 += join5;
9771
9771
  }
9772
9772
  const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
9773
9773
  res2 += tmp !== void 0 ? tmp : "null";
9774
9774
  if (value.length - 1 > maximumBreadth) {
9775
9775
  const removedKeys = value.length - maximumBreadth - 1;
9776
- res2 += `${join4}"... ${getItemCount(removedKeys)} not stringified"`;
9776
+ res2 += `${join5}"... ${getItemCount(removedKeys)} not stringified"`;
9777
9777
  }
9778
9778
  res2 += `
9779
9779
  ${originalIndentation}`;
@@ -9789,16 +9789,16 @@ ${originalIndentation}`;
9789
9789
  return '"[Object]"';
9790
9790
  }
9791
9791
  indentation += spacer;
9792
- const join3 = `,
9792
+ const join4 = `,
9793
9793
  ${indentation}`;
9794
9794
  let res = "";
9795
9795
  let separator = "";
9796
9796
  let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
9797
9797
  if (isTypedArrayWithEntries(value)) {
9798
- res += stringifyTypedArray(value, join3, maximumBreadth);
9798
+ res += stringifyTypedArray(value, join4, maximumBreadth);
9799
9799
  keys = keys.slice(value.length);
9800
9800
  maximumPropertiesToStringify -= value.length;
9801
- separator = join3;
9801
+ separator = join4;
9802
9802
  }
9803
9803
  if (deterministic) {
9804
9804
  keys = sort(keys, comparator);
@@ -9809,13 +9809,13 @@ ${indentation}`;
9809
9809
  const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
9810
9810
  if (tmp !== void 0) {
9811
9811
  res += `${separator}${strEscape(key2)}: ${tmp}`;
9812
- separator = join3;
9812
+ separator = join4;
9813
9813
  }
9814
9814
  }
9815
9815
  if (keyLength > maximumBreadth) {
9816
9816
  const removedKeys = keyLength - maximumBreadth;
9817
9817
  res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
9818
- separator = join3;
9818
+ separator = join4;
9819
9819
  }
9820
9820
  if (separator !== "") {
9821
9821
  res = `
@@ -41083,6 +41083,7 @@ function createTables(database) {
41083
41083
  status TEXT NOT NULL DEFAULT 'open',
41084
41084
  resolved_at TEXT,
41085
41085
  external_thread_id TEXT,
41086
+ kind TEXT NOT NULL DEFAULT 'discussion',
41086
41087
  created_at TEXT NOT NULL,
41087
41088
  updated_at TEXT NOT NULL,
41088
41089
  FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
@@ -41146,6 +41147,9 @@ CREATE INDEX IF NOT EXISTS idx_workspaces_path ON workspaces(path);
41146
41147
  if (!sessColumns.some((c) => c.name === "origin_app_id")) {
41147
41148
  database.exec("ALTER TABLE sessions ADD COLUMN origin_app_id TEXT");
41148
41149
  }
41150
+ if (!sessColumns.some((c) => c.name === "user_touched")) {
41151
+ database.exec("ALTER TABLE sessions ADD COLUMN user_touched INTEGER NOT NULL DEFAULT 0");
41152
+ }
41149
41153
  const turnColumns = database.prepare("PRAGMA table_info(turns)").all();
41150
41154
  if (!turnColumns.some((c) => c.name === "thread_id")) {
41151
41155
  database.exec("ALTER TABLE turns ADD COLUMN thread_id TEXT");
@@ -41227,6 +41231,10 @@ CREATE INDEX IF NOT EXISTS idx_workspaces_path ON workspaces(path);
41227
41231
  CREATE INDEX IF NOT EXISTS idx_discussion_threads_item_id ON discussion_threads(item_id);
41228
41232
  `);
41229
41233
  }
41234
+ const threadKindCols = database.prepare("PRAGMA table_info(discussion_threads)").all();
41235
+ if (!threadKindCols.some((c) => c.name === "kind")) {
41236
+ database.exec("ALTER TABLE discussion_threads ADD COLUMN kind TEXT NOT NULL DEFAULT 'discussion'");
41237
+ }
41230
41238
  }
41231
41239
 
41232
41240
  // node_modules/ws/wrapper.mjs
@@ -41352,6 +41360,14 @@ async function shutdownAllProviders() {
41352
41360
  }
41353
41361
  }
41354
41362
 
41363
+ // src/routes/session-touch.ts
41364
+ function markSessionTouched(db2, sessionId) {
41365
+ const { changes } = db2.prepare("UPDATE sessions SET user_touched = 1 WHERE id = ? AND user_touched = 0").run(sessionId);
41366
+ if (changes === 0) return false;
41367
+ broadcast("session:touched", { sessionId });
41368
+ return true;
41369
+ }
41370
+
41355
41371
  // src/routes/sessions.ts
41356
41372
  async function registerSessionRoutes(fastify) {
41357
41373
  fastify.get("/api/sessions", async () => {
@@ -41556,6 +41572,7 @@ async function registerSessionRoutes(fastify) {
41556
41572
  params.push(runtime_config);
41557
41573
  }
41558
41574
  db2.prepare(`UPDATE sessions SET ${updates.join(", ")} WHERE id = ?`).run(...params, id);
41575
+ if (title !== void 0) markSessionTouched(db2, id);
41559
41576
  if (providerChanged || workspaceChanged) {
41560
41577
  if (existing.external_thread_id) {
41561
41578
  db2.prepare("UPDATE sessions SET external_thread_id = NULL, rewound_at_turn_id = NULL, pre_rewind_thread_id = NULL, updated_at = ? WHERE id = ?").run(now, id);
@@ -41610,6 +41627,7 @@ async function registerSessionRoutes(fastify) {
41610
41627
  db2.prepare(
41611
41628
  "UPDATE sessions SET rewound_at_turn_id = NULL, pre_rewind_thread_id = NULL, updated_at = ? WHERE id = ?"
41612
41629
  ).run(now2, id);
41630
+ markSessionTouched(db2, id);
41613
41631
  const truncated = db2.prepare("SELECT * FROM sessions WHERE id = ?").get(id);
41614
41632
  return truncated;
41615
41633
  }
@@ -41639,6 +41657,7 @@ async function registerSessionRoutes(fastify) {
41639
41657
  }
41640
41658
  }
41641
41659
  provider.clearThread(id);
41660
+ markSessionTouched(db2, id);
41642
41661
  const updated = db2.prepare("SELECT * FROM sessions WHERE id = ?").get(id);
41643
41662
  return updated;
41644
41663
  }
@@ -41663,6 +41682,7 @@ async function registerSessionRoutes(fastify) {
41663
41682
  "UPDATE sessions SET rewound_at_turn_id = NULL, pre_rewind_thread_id = NULL, external_thread_id = COALESCE(pre_rewind_thread_id, external_thread_id), updated_at = ? WHERE id = ?"
41664
41683
  ).run(now, id);
41665
41684
  getProvider(session.runtime_type).clearThread(id);
41685
+ markSessionTouched(db2, id);
41666
41686
  const updated = db2.prepare("SELECT * FROM sessions WHERE id = ?").get(id);
41667
41687
  return updated;
41668
41688
  });
@@ -42233,14 +42253,15 @@ async function registerTurnRoutes(fastify) {
42233
42253
  data: { type: "string" }
42234
42254
  }
42235
42255
  }
42236
- }
42256
+ },
42257
+ origin_app_id: { type: ["string", "null"] }
42237
42258
  }
42238
42259
  }
42239
42260
  }
42240
42261
  },
42241
42262
  async (request, reply) => {
42242
42263
  const { id } = request.params;
42243
- const { user_prompt, attachments } = request.body || {};
42264
+ const { user_prompt, attachments, origin_app_id } = request.body || {};
42244
42265
  if (!user_prompt || !user_prompt.trim()) {
42245
42266
  return reply.code(400).send({ error: "user_prompt is required" });
42246
42267
  }
@@ -42260,6 +42281,7 @@ async function registerTurnRoutes(fastify) {
42260
42281
  VALUES (?, ?, ?, NULL, NULL, NULL, NULL, 'pending', NULL, ?, ?, ?)`
42261
42282
  ).run(turnId, id, user_prompt, attachmentsJson, now, now);
42262
42283
  const turn = db2.prepare("SELECT * FROM turns WHERE id = ?").get(turnId);
42284
+ if (!origin_app_id) markSessionTouched(db2, id);
42263
42285
  const rawTurn = turn;
42264
42286
  const parsedTurn = {
42265
42287
  ...turn,
@@ -42306,6 +42328,7 @@ async function registerTurnRoutes(fastify) {
42306
42328
  if (!cancelled) {
42307
42329
  return reply.code(409).send({ error: "No running turn to cancel" });
42308
42330
  }
42331
+ markSessionTouched(db2, id);
42309
42332
  return { success: true };
42310
42333
  });
42311
42334
  fastify.post(
@@ -42326,7 +42349,7 @@ async function registerTurnRoutes(fastify) {
42326
42349
  );
42327
42350
  }
42328
42351
 
42329
- // src/routes/threads.ts
42352
+ // src/routes/thread-turns.ts
42330
42353
  function parseTurnRow(row, items = []) {
42331
42354
  return {
42332
42355
  ...row,
@@ -42335,6 +42358,22 @@ function parseTurnRow(row, items = []) {
42335
42358
  items
42336
42359
  };
42337
42360
  }
42361
+ function startThreadTurn(db2, session, threadId, prompt, attachments) {
42362
+ const turnId = v4_default();
42363
+ const now = (/* @__PURE__ */ new Date()).toISOString();
42364
+ const attachmentsJson = attachments && attachments.length > 0 ? JSON.stringify(attachments) : null;
42365
+ db2.prepare(
42366
+ `INSERT INTO turns (id, session_id, user_prompt, agent_response, thoughts, token_usage, external_turn_id, status, error, thread_id, attachments, created_at, updated_at)
42367
+ VALUES (?, ?, ?, NULL, NULL, NULL, NULL, 'pending', NULL, ?, ?, ?, ?)`
42368
+ ).run(turnId, session.id, prompt, threadId, attachmentsJson, now, now);
42369
+ const rawTurn = db2.prepare("SELECT * FROM turns WHERE id = ?").get(turnId);
42370
+ getProvider(session.runtime_type).startTurn(session, rawTurn).catch((err) => {
42371
+ console.error(`[threads] turn error for session ${session.id} (thread ${threadId}):`, err);
42372
+ });
42373
+ return parseTurnRow(rawTurn);
42374
+ }
42375
+
42376
+ // src/routes/threads.ts
42338
42377
  async function registerThreadRoutes(fastify) {
42339
42378
  fastify.post(
42340
42379
  "/api/sessions/:sessionId/threads",
@@ -42430,22 +42469,13 @@ async function registerThreadRoutes(fastify) {
42430
42469
  > ${selectedText}
42431
42470
 
42432
42471
  ${message}` : message;
42433
- const newTurnId = v4_default();
42434
- const attachmentsJson = attachments && attachments.length > 0 ? JSON.stringify(attachments) : null;
42435
- db2.prepare(
42436
- `INSERT INTO turns (id, session_id, user_prompt, agent_response, thoughts, token_usage, external_turn_id, status, error, thread_id, attachments, created_at, updated_at)
42437
- VALUES (?, ?, ?, NULL, NULL, NULL, NULL, 'pending', NULL, ?, ?, ?, ?)`
42438
- ).run(newTurnId, sessionId, formattedPrompt, threadId, attachmentsJson, now, now);
42439
- const rawTurn = db2.prepare("SELECT * FROM turns WHERE id = ?").get(newTurnId);
42440
- provider.startTurn(session, rawTurn).catch((err) => {
42441
- console.error(`[threads] Unhandled error for session ${sessionId}:`, err);
42442
- });
42472
+ const turn = startThreadTurn(db2, session, threadId, formattedPrompt, attachments);
42443
42473
  const threadRow = db2.prepare("SELECT * FROM discussion_threads WHERE id = ?").get(threadId);
42444
- const turn = parseTurnRow(rawTurn);
42445
42474
  const thread = {
42446
42475
  ...threadRow,
42447
42476
  turns: [turn]
42448
42477
  };
42478
+ markSessionTouched(db2, sessionId);
42449
42479
  broadcast("thread:created", { sessionId, thread, turn });
42450
42480
  return { thread, turn };
42451
42481
  }
@@ -42494,18 +42524,8 @@ ${message}` : message;
42494
42524
  if (thread.status !== "open") {
42495
42525
  return reply.code(409).send({ error: "Thread is resolved \u2014 reopen it first" });
42496
42526
  }
42497
- const newTurnId = v4_default();
42498
- const now = (/* @__PURE__ */ new Date()).toISOString();
42499
- const attachmentsJson = attachments && attachments.length > 0 ? JSON.stringify(attachments) : null;
42500
- db2.prepare(
42501
- `INSERT INTO turns (id, session_id, user_prompt, agent_response, thoughts, token_usage, external_turn_id, status, error, thread_id, attachments, created_at, updated_at)
42502
- VALUES (?, ?, ?, NULL, NULL, NULL, NULL, 'pending', NULL, ?, ?, ?, ?)`
42503
- ).run(newTurnId, sessionId, message, threadId, attachmentsJson, now, now);
42504
- const rawTurn = db2.prepare("SELECT * FROM turns WHERE id = ?").get(newTurnId);
42505
- getProvider(session.runtime_type).startTurn(session, rawTurn).catch((err) => {
42506
- console.error(`[threads] followup error for session ${sessionId}:`, err);
42507
- });
42508
- const turn = parseTurnRow(rawTurn);
42527
+ const turn = startThreadTurn(db2, session, threadId, message, attachments);
42528
+ markSessionTouched(db2, sessionId);
42509
42529
  broadcast("thread:followup", { sessionId, threadId, turn });
42510
42530
  return { turn };
42511
42531
  }
@@ -42628,7 +42648,7 @@ Agent: ${agent}`;
42628
42648
  if (!session) {
42629
42649
  return reply.code(404).send({ error: "Session not found" });
42630
42650
  }
42631
- const threadRows = db2.prepare("SELECT * FROM discussion_threads WHERE session_id = ? ORDER BY created_at ASC").all(sessionId);
42651
+ const threadRows = db2.prepare("SELECT * FROM discussion_threads WHERE session_id = ? AND kind != 'sidecar' ORDER BY created_at ASC").all(sessionId);
42632
42652
  const result = [];
42633
42653
  for (const tr of threadRows) {
42634
42654
  const turnRows = db2.prepare("SELECT * FROM turns WHERE thread_id = ? ORDER BY created_at ASC").all(tr.id);
@@ -44998,8 +45018,8 @@ async function registerAppRoutes(fastify, opts) {
44998
45018
  const now = (/* @__PURE__ */ new Date()).toISOString();
44999
45019
  const maxOrder = db2.prepare("SELECT COALESCE(MAX(sort_order), 0) AS m FROM sessions WHERE cwd = ?").get(dir);
45000
45020
  db2.prepare(
45001
- `INSERT INTO sessions (id, title, runtime_type, model, model_reasoning_effort, cwd, external_thread_id, status, is_running, sort_order, created_at, updated_at, origin_app_id)
45002
- VALUES (?, ?, ?, ?, ?, ?, NULL, 'active', 0, ?, ?, ?, ?)`
45021
+ `INSERT INTO sessions (id, title, runtime_type, model, model_reasoning_effort, cwd, external_thread_id, status, is_running, sort_order, created_at, updated_at, origin_app_id, user_touched)
45022
+ VALUES (?, ?, ?, ?, ?, ?, NULL, 'active', 0, ?, ?, ?, ?, 1)`
45003
45023
  ).run(
45004
45024
  sessionId,
45005
45025
  `Edit: ${manifest.title}`,
@@ -45017,6 +45037,135 @@ async function registerAppRoutes(fastify, opts) {
45017
45037
  );
45018
45038
  }
45019
45039
 
45040
+ // src/sidecar/transcript-locator.ts
45041
+ import { existsSync as existsSync2, readdirSync } from "node:fs";
45042
+ import { homedir as homedir2 } from "node:os";
45043
+ import { join as join2 } from "node:path";
45044
+ function claudeConfigDir() {
45045
+ return process.env.CLAUDE_CONFIG_DIR || join2(homedir2(), ".claude");
45046
+ }
45047
+ function codexHome() {
45048
+ return process.env.CODEX_HOME || join2(homedir2(), ".codex");
45049
+ }
45050
+ function encodeClaudeProjectDir(cwd) {
45051
+ return cwd.replace(/[^a-zA-Z0-9]/g, "-");
45052
+ }
45053
+ function listDir(dir) {
45054
+ try {
45055
+ return readdirSync(dir);
45056
+ } catch {
45057
+ return [];
45058
+ }
45059
+ }
45060
+ function findClaudeTranscript(externalId, cwd) {
45061
+ const projects = join2(claudeConfigDir(), "projects");
45062
+ const fileName = `${externalId}.jsonl`;
45063
+ if (cwd) {
45064
+ const direct = join2(projects, encodeClaudeProjectDir(cwd), fileName);
45065
+ if (existsSync2(direct)) return direct;
45066
+ }
45067
+ for (const dir of listDir(projects)) {
45068
+ const candidate = join2(projects, dir, fileName);
45069
+ if (existsSync2(candidate)) return candidate;
45070
+ }
45071
+ return null;
45072
+ }
45073
+ function findCodexTranscript(externalId) {
45074
+ const root = join2(codexHome(), "sessions");
45075
+ const suffix = `-${externalId}.jsonl`;
45076
+ const desc = (dir) => listDir(dir).sort().reverse();
45077
+ for (const year of desc(root)) {
45078
+ for (const month of desc(join2(root, year))) {
45079
+ for (const day of desc(join2(root, year, month))) {
45080
+ const dayDir = join2(root, year, month, day);
45081
+ const match = listDir(dayDir).find((f) => f.endsWith(suffix));
45082
+ if (match) return join2(dayDir, match);
45083
+ }
45084
+ }
45085
+ }
45086
+ return null;
45087
+ }
45088
+ function locateTranscript(session) {
45089
+ const externalId = session.external_thread_id;
45090
+ if (!externalId) return null;
45091
+ switch (session.runtime_type) {
45092
+ case "claude":
45093
+ return findClaudeTranscript(externalId, session.cwd);
45094
+ case "codex":
45095
+ return findCodexTranscript(externalId);
45096
+ default:
45097
+ return null;
45098
+ }
45099
+ }
45100
+
45101
+ // src/sidecar/prompt.ts
45102
+ var SIDECAR_QUESTION_MARKER = "Understand the user's question below, read the session file given above, and answer.";
45103
+ function buildSidecarPrompt(externalSessionId, transcriptPath, question) {
45104
+ return [
45105
+ `Your job is to answer questions about this session: ${externalSessionId}`,
45106
+ `Session file: ${transcriptPath}`,
45107
+ "",
45108
+ SIDECAR_QUESTION_MARKER,
45109
+ "",
45110
+ question
45111
+ ].join("\n");
45112
+ }
45113
+
45114
+ // src/routes/sidecar.ts
45115
+ var SIDECAR_RUNTIMES = /* @__PURE__ */ new Set(["claude"]);
45116
+ async function registerSidecarRoutes(fastify) {
45117
+ fastify.post(
45118
+ "/api/sessions/:sessionId/sidecar",
45119
+ {
45120
+ schema: {
45121
+ body: {
45122
+ type: "object",
45123
+ required: ["message"],
45124
+ properties: { message: { type: "string", minLength: 1 } }
45125
+ }
45126
+ }
45127
+ },
45128
+ async (request, reply) => {
45129
+ const { sessionId } = request.params;
45130
+ const message = request.body.message.trim();
45131
+ if (!message) return reply.code(400).send({ error: "Message is empty" });
45132
+ const db2 = getDb();
45133
+ const session = db2.prepare("SELECT * FROM sessions WHERE id = ?").get(sessionId);
45134
+ if (!session) return reply.code(404).send({ error: "Session not found" });
45135
+ if (!SIDECAR_RUNTIMES.has(session.runtime_type)) {
45136
+ return reply.code(422).send({ error: `Sidecar is not available for ${session.runtime_type} sessions yet` });
45137
+ }
45138
+ const existing = db2.prepare("SELECT * FROM discussion_threads WHERE session_id = ? AND kind = 'sidecar' ORDER BY created_at DESC LIMIT 1").get(sessionId);
45139
+ if (existing) {
45140
+ if (isSessionBusy(db2, session, { threadId: existing.id })) {
45141
+ return reply.code(409).send({ error: "The sidecar is still answering" });
45142
+ }
45143
+ const turn2 = startThreadTurn(db2, session, existing.id, message);
45144
+ markSessionTouched(db2, sessionId);
45145
+ broadcast("thread:followup", { sessionId, threadId: existing.id, turn: turn2 });
45146
+ return { threadId: existing.id, turn: turn2 };
45147
+ }
45148
+ const transcriptPath = locateTranscript(session);
45149
+ if (!session.external_thread_id || !transcriptPath) {
45150
+ return reply.code(409).send({ error: "This session has no transcript yet \u2014 the sidecar can answer once it has run a turn" });
45151
+ }
45152
+ const threadId = v4_default();
45153
+ const now = (/* @__PURE__ */ new Date()).toISOString();
45154
+ db2.prepare(
45155
+ `INSERT INTO discussion_threads (id, session_id, kind, status, created_at, updated_at)
45156
+ VALUES (?, ?, 'sidecar', 'open', ?, ?)`
45157
+ ).run(threadId, sessionId, now, now);
45158
+ const prompt = buildSidecarPrompt(session.external_thread_id, transcriptPath, message);
45159
+ const turn = startThreadTurn(db2, session, threadId, prompt);
45160
+ const threadRow = db2.prepare("SELECT * FROM discussion_threads WHERE id = ?").get(threadId);
45161
+ const thread = { ...threadRow, turns: [turn] };
45162
+ markSessionTouched(db2, sessionId);
45163
+ broadcast("thread:created", { sessionId, thread, turn });
45164
+ return { threadId, turn };
45165
+ }
45166
+ );
45167
+ }
45168
+
45020
45169
  // src/codex/item-mapper.ts
45021
45170
  function mapItemData(item) {
45022
45171
  switch (item.type) {
@@ -45750,7 +45899,7 @@ var codexProvider = {
45750
45899
  import { query, forkSession as sdkForkSession } from "@anthropic-ai/claude-agent-sdk";
45751
45900
  import { readFileSync as readFileSync2 } from "fs";
45752
45901
  import { tmpdir } from "os";
45753
- import { join as join2 } from "path";
45902
+ import { join as join3 } from "path";
45754
45903
 
45755
45904
  // src/claude/claude-message-mapper.ts
45756
45905
  function mapAssistantContent(content, messageId, thinkingTexts) {
@@ -46464,6 +46613,10 @@ async function handleMessage(message, sessionId, turnId, entry, db2) {
46464
46613
  now,
46465
46614
  sessionId
46466
46615
  );
46616
+ } else {
46617
+ db2.prepare(
46618
+ "UPDATE discussion_threads SET external_thread_id = ?, updated_at = ? WHERE id = ? AND external_thread_id IS NULL"
46619
+ ).run(message.session_id, (/* @__PURE__ */ new Date()).toISOString(), entry.threadId);
46467
46620
  }
46468
46621
  } else if (sub === "compact_boundary") {
46469
46622
  handleCompactBoundary(
@@ -46687,7 +46840,7 @@ function constructMonitorOutputPath(entry, taskId) {
46687
46840
  if (!entry.sessionId) return "";
46688
46841
  const uid = typeof process.getuid === "function" ? process.getuid() : 0;
46689
46842
  const encodedCwd = entry.cwd.replace(/\//g, "-");
46690
- return join2(tmpdir(), `claude-${uid}`, encodedCwd, entry.sessionId, "tasks", `${taskId}.output`);
46843
+ return join3(tmpdir(), `claude-${uid}`, encodedCwd, entry.sessionId, "tasks", `${taskId}.output`);
46691
46844
  }
46692
46845
  function handleTaskStarted(message, sessionId, turnId, entry, db2) {
46693
46846
  const m = message;
@@ -48869,6 +49022,7 @@ async function createAgentPaneApp(dbPath) {
48869
49022
  await registerMaintenanceRoutes(fastify);
48870
49023
  await registerVscodeWebRoutes(fastify);
48871
49024
  await registerAppRoutes(fastify);
49025
+ await registerSidecarRoutes(fastify);
48872
49026
  const wss2 = initWs();
48873
49027
  wss2.on("connection", (ws) => {
48874
49028
  ws.send(JSON.stringify({ event: "background_tasks:snapshot", data: { sessions: listAllBackgroundTasks() } }));