repoburg 1.3.268 → 1.3.269
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-pane/backend/dist/index.js +214 -60
- package/agent-pane/backend/dist/server.js +216 -60
- package/agent-pane/frontend/dist/assets/index-BaBO6I13.js +567 -0
- package/agent-pane/frontend/dist/assets/index-K4hE7q_n.css +1 -0
- package/agent-pane/frontend/dist/index.html +2 -2
- package/package.json +1 -1
- package/tabtape/extension/dist/build-info.json +3 -3
- package/tabtape/extension/dist/manifest.json +1 -1
- package/tabtape/ui/dist/build-info.json +3 -3
- package/agent-pane/frontend/dist/assets/index-CGMuuJwp.css +0 -1
- package/agent-pane/frontend/dist/assets/index-DJdEb4sk.js +0 -567
|
@@ -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:
|
|
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"] ||
|
|
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:
|
|
8370
|
+
var { existsSync: existsSync3 } = __require("node:fs");
|
|
8371
8371
|
var getCallers = require_caller();
|
|
8372
|
-
var { join:
|
|
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) && !
|
|
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"] ||
|
|
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"] ||
|
|
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
|
|
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
|
|
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
|
-
|
|
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 +=
|
|
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 += `${
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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 +=
|
|
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 += `${
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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 +=
|
|
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 += `${
|
|
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
|
|
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,
|
|
9798
|
+
res += stringifyTypedArray(value, join4, maximumBreadth);
|
|
9799
9799
|
keys = keys.slice(value.length);
|
|
9800
9800
|
maximumPropertiesToStringify -= value.length;
|
|
9801
|
-
separator =
|
|
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 =
|
|
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 =
|
|
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/
|
|
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
|
|
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
|
|
42498
|
-
|
|
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
|
|
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
|
|
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() } }));
|