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.
- 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-CcL4MDxZ.js +572 -0
- package/agent-pane/frontend/dist/assets/index-Cr-XES2b.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
|
@@ -11520,7 +11520,7 @@ var require_thread_stream = __commonJS({
|
|
|
11520
11520
|
var { version } = require_package();
|
|
11521
11521
|
var { EventEmitter: EventEmitter2 } = __require("events");
|
|
11522
11522
|
var { Worker } = __require("worker_threads");
|
|
11523
|
-
var { join:
|
|
11523
|
+
var { join: join4 } = __require("path");
|
|
11524
11524
|
var { pathToFileURL } = __require("url");
|
|
11525
11525
|
var { wait } = require_wait();
|
|
11526
11526
|
var {
|
|
@@ -11571,7 +11571,7 @@ var require_thread_stream = __commonJS({
|
|
|
11571
11571
|
function createWorker(stream, opts) {
|
|
11572
11572
|
const { filename, workerData } = opts;
|
|
11573
11573
|
const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
|
|
11574
|
-
const toExecute = bundlerOverrides["thread-stream-worker"] ||
|
|
11574
|
+
const toExecute = bundlerOverrides["thread-stream-worker"] || join4(__dirname, "lib", "worker.js");
|
|
11575
11575
|
const worker = new Worker(toExecute, {
|
|
11576
11576
|
...opts.workerOpts,
|
|
11577
11577
|
name: opts.workerOpts?.name || "thread-stream",
|
|
@@ -12037,9 +12037,9 @@ var require_transport = __commonJS({
|
|
|
12037
12037
|
"node_modules/pino/lib/transport.js"(exports, module) {
|
|
12038
12038
|
"use strict";
|
|
12039
12039
|
var { createRequire } = __require("module");
|
|
12040
|
-
var { existsSync:
|
|
12040
|
+
var { existsSync: existsSync3 } = __require("node:fs");
|
|
12041
12041
|
var getCallers = require_caller();
|
|
12042
|
-
var { join:
|
|
12042
|
+
var { join: join4, isAbsolute, sep } = __require("node:path");
|
|
12043
12043
|
var { fileURLToPath: fileURLToPath3 } = __require("node:url");
|
|
12044
12044
|
var sleep = require_atomic_sleep();
|
|
12045
12045
|
var onExit = require_on_exit_leak_free();
|
|
@@ -12111,7 +12111,7 @@ var require_transport = __commonJS({
|
|
|
12111
12111
|
return false;
|
|
12112
12112
|
}
|
|
12113
12113
|
}
|
|
12114
|
-
return isAbsolute(path9) && !
|
|
12114
|
+
return isAbsolute(path9) && !existsSync3(path9);
|
|
12115
12115
|
}
|
|
12116
12116
|
function stripQuotes(value) {
|
|
12117
12117
|
const first = value[0];
|
|
@@ -12192,7 +12192,7 @@ var require_transport = __commonJS({
|
|
|
12192
12192
|
throw new Error("only one of target or targets can be specified");
|
|
12193
12193
|
}
|
|
12194
12194
|
if (targets) {
|
|
12195
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
12195
|
+
target = bundlerOverrides["pino-worker"] || join4(__dirname, "worker.js");
|
|
12196
12196
|
options.targets = targets.filter((dest) => dest.target).map((dest) => {
|
|
12197
12197
|
return {
|
|
12198
12198
|
...dest,
|
|
@@ -12210,7 +12210,7 @@ var require_transport = __commonJS({
|
|
|
12210
12210
|
});
|
|
12211
12211
|
});
|
|
12212
12212
|
} else if (pipeline) {
|
|
12213
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
12213
|
+
target = bundlerOverrides["pino-worker"] || join4(__dirname, "worker.js");
|
|
12214
12214
|
options.pipelines = [pipeline.map((dest) => {
|
|
12215
12215
|
return {
|
|
12216
12216
|
...dest,
|
|
@@ -12233,7 +12233,7 @@ var require_transport = __commonJS({
|
|
|
12233
12233
|
return origin;
|
|
12234
12234
|
}
|
|
12235
12235
|
if (origin === "pino/file") {
|
|
12236
|
-
return
|
|
12236
|
+
return join4(__dirname, "..", "file.js");
|
|
12237
12237
|
}
|
|
12238
12238
|
let fixTarget2;
|
|
12239
12239
|
for (const filePath of callers) {
|
|
@@ -13213,7 +13213,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
13213
13213
|
return circularValue;
|
|
13214
13214
|
}
|
|
13215
13215
|
let res = "";
|
|
13216
|
-
let
|
|
13216
|
+
let join4 = ",";
|
|
13217
13217
|
const originalIndentation = indentation;
|
|
13218
13218
|
if (Array.isArray(value)) {
|
|
13219
13219
|
if (value.length === 0) {
|
|
@@ -13227,7 +13227,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
13227
13227
|
indentation += spacer;
|
|
13228
13228
|
res += `
|
|
13229
13229
|
${indentation}`;
|
|
13230
|
-
|
|
13230
|
+
join4 = `,
|
|
13231
13231
|
${indentation}`;
|
|
13232
13232
|
}
|
|
13233
13233
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -13235,13 +13235,13 @@ ${indentation}`;
|
|
|
13235
13235
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
13236
13236
|
const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
13237
13237
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
13238
|
-
res +=
|
|
13238
|
+
res += join4;
|
|
13239
13239
|
}
|
|
13240
13240
|
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
13241
13241
|
res += tmp !== void 0 ? tmp : "null";
|
|
13242
13242
|
if (value.length - 1 > maximumBreadth) {
|
|
13243
13243
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
13244
|
-
res += `${
|
|
13244
|
+
res += `${join4}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
13245
13245
|
}
|
|
13246
13246
|
if (spacer !== "") {
|
|
13247
13247
|
res += `
|
|
@@ -13262,7 +13262,7 @@ ${originalIndentation}`;
|
|
|
13262
13262
|
let separator = "";
|
|
13263
13263
|
if (spacer !== "") {
|
|
13264
13264
|
indentation += spacer;
|
|
13265
|
-
|
|
13265
|
+
join4 = `,
|
|
13266
13266
|
${indentation}`;
|
|
13267
13267
|
whitespace = " ";
|
|
13268
13268
|
}
|
|
@@ -13276,13 +13276,13 @@ ${indentation}`;
|
|
|
13276
13276
|
const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
|
|
13277
13277
|
if (tmp !== void 0) {
|
|
13278
13278
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
13279
|
-
separator =
|
|
13279
|
+
separator = join4;
|
|
13280
13280
|
}
|
|
13281
13281
|
}
|
|
13282
13282
|
if (keyLength > maximumBreadth) {
|
|
13283
13283
|
const removedKeys = keyLength - maximumBreadth;
|
|
13284
13284
|
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
13285
|
-
separator =
|
|
13285
|
+
separator = join4;
|
|
13286
13286
|
}
|
|
13287
13287
|
if (spacer !== "" && separator.length > 1) {
|
|
13288
13288
|
res = `
|
|
@@ -13323,7 +13323,7 @@ ${originalIndentation}`;
|
|
|
13323
13323
|
}
|
|
13324
13324
|
const originalIndentation = indentation;
|
|
13325
13325
|
let res = "";
|
|
13326
|
-
let
|
|
13326
|
+
let join4 = ",";
|
|
13327
13327
|
if (Array.isArray(value)) {
|
|
13328
13328
|
if (value.length === 0) {
|
|
13329
13329
|
return "[]";
|
|
@@ -13336,7 +13336,7 @@ ${originalIndentation}`;
|
|
|
13336
13336
|
indentation += spacer;
|
|
13337
13337
|
res += `
|
|
13338
13338
|
${indentation}`;
|
|
13339
|
-
|
|
13339
|
+
join4 = `,
|
|
13340
13340
|
${indentation}`;
|
|
13341
13341
|
}
|
|
13342
13342
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -13344,13 +13344,13 @@ ${indentation}`;
|
|
|
13344
13344
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
13345
13345
|
const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
13346
13346
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
13347
|
-
res +=
|
|
13347
|
+
res += join4;
|
|
13348
13348
|
}
|
|
13349
13349
|
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
13350
13350
|
res += tmp !== void 0 ? tmp : "null";
|
|
13351
13351
|
if (value.length - 1 > maximumBreadth) {
|
|
13352
13352
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
13353
|
-
res += `${
|
|
13353
|
+
res += `${join4}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
13354
13354
|
}
|
|
13355
13355
|
if (spacer !== "") {
|
|
13356
13356
|
res += `
|
|
@@ -13363,7 +13363,7 @@ ${originalIndentation}`;
|
|
|
13363
13363
|
let whitespace = "";
|
|
13364
13364
|
if (spacer !== "") {
|
|
13365
13365
|
indentation += spacer;
|
|
13366
|
-
|
|
13366
|
+
join4 = `,
|
|
13367
13367
|
${indentation}`;
|
|
13368
13368
|
whitespace = " ";
|
|
13369
13369
|
}
|
|
@@ -13372,7 +13372,7 @@ ${indentation}`;
|
|
|
13372
13372
|
const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
|
|
13373
13373
|
if (tmp !== void 0) {
|
|
13374
13374
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
13375
|
-
separator =
|
|
13375
|
+
separator = join4;
|
|
13376
13376
|
}
|
|
13377
13377
|
}
|
|
13378
13378
|
if (spacer !== "" && separator.length > 1) {
|
|
@@ -13430,20 +13430,20 @@ ${originalIndentation}`;
|
|
|
13430
13430
|
indentation += spacer;
|
|
13431
13431
|
let res2 = `
|
|
13432
13432
|
${indentation}`;
|
|
13433
|
-
const
|
|
13433
|
+
const join5 = `,
|
|
13434
13434
|
${indentation}`;
|
|
13435
13435
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
13436
13436
|
let i = 0;
|
|
13437
13437
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
13438
13438
|
const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
13439
13439
|
res2 += tmp2 !== void 0 ? tmp2 : "null";
|
|
13440
|
-
res2 +=
|
|
13440
|
+
res2 += join5;
|
|
13441
13441
|
}
|
|
13442
13442
|
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
13443
13443
|
res2 += tmp !== void 0 ? tmp : "null";
|
|
13444
13444
|
if (value.length - 1 > maximumBreadth) {
|
|
13445
13445
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
13446
|
-
res2 += `${
|
|
13446
|
+
res2 += `${join5}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
13447
13447
|
}
|
|
13448
13448
|
res2 += `
|
|
13449
13449
|
${originalIndentation}`;
|
|
@@ -13459,16 +13459,16 @@ ${originalIndentation}`;
|
|
|
13459
13459
|
return '"[Object]"';
|
|
13460
13460
|
}
|
|
13461
13461
|
indentation += spacer;
|
|
13462
|
-
const
|
|
13462
|
+
const join4 = `,
|
|
13463
13463
|
${indentation}`;
|
|
13464
13464
|
let res = "";
|
|
13465
13465
|
let separator = "";
|
|
13466
13466
|
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
13467
13467
|
if (isTypedArrayWithEntries(value)) {
|
|
13468
|
-
res += stringifyTypedArray(value,
|
|
13468
|
+
res += stringifyTypedArray(value, join4, maximumBreadth);
|
|
13469
13469
|
keys = keys.slice(value.length);
|
|
13470
13470
|
maximumPropertiesToStringify -= value.length;
|
|
13471
|
-
separator =
|
|
13471
|
+
separator = join4;
|
|
13472
13472
|
}
|
|
13473
13473
|
if (deterministic) {
|
|
13474
13474
|
keys = sort(keys, comparator);
|
|
@@ -13479,13 +13479,13 @@ ${indentation}`;
|
|
|
13479
13479
|
const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
|
|
13480
13480
|
if (tmp !== void 0) {
|
|
13481
13481
|
res += `${separator}${strEscape(key2)}: ${tmp}`;
|
|
13482
|
-
separator =
|
|
13482
|
+
separator = join4;
|
|
13483
13483
|
}
|
|
13484
13484
|
}
|
|
13485
13485
|
if (keyLength > maximumBreadth) {
|
|
13486
13486
|
const removedKeys = keyLength - maximumBreadth;
|
|
13487
13487
|
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
13488
|
-
separator =
|
|
13488
|
+
separator = join4;
|
|
13489
13489
|
}
|
|
13490
13490
|
if (separator !== "") {
|
|
13491
13491
|
res = `
|
|
@@ -41109,6 +41109,7 @@ function createTables(database) {
|
|
|
41109
41109
|
status TEXT NOT NULL DEFAULT 'open',
|
|
41110
41110
|
resolved_at TEXT,
|
|
41111
41111
|
external_thread_id TEXT,
|
|
41112
|
+
kind TEXT NOT NULL DEFAULT 'discussion',
|
|
41112
41113
|
created_at TEXT NOT NULL,
|
|
41113
41114
|
updated_at TEXT NOT NULL,
|
|
41114
41115
|
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
@@ -41172,6 +41173,9 @@ CREATE INDEX IF NOT EXISTS idx_workspaces_path ON workspaces(path);
|
|
|
41172
41173
|
if (!sessColumns.some((c) => c.name === "origin_app_id")) {
|
|
41173
41174
|
database.exec("ALTER TABLE sessions ADD COLUMN origin_app_id TEXT");
|
|
41174
41175
|
}
|
|
41176
|
+
if (!sessColumns.some((c) => c.name === "user_touched")) {
|
|
41177
|
+
database.exec("ALTER TABLE sessions ADD COLUMN user_touched INTEGER NOT NULL DEFAULT 0");
|
|
41178
|
+
}
|
|
41175
41179
|
const turnColumns = database.prepare("PRAGMA table_info(turns)").all();
|
|
41176
41180
|
if (!turnColumns.some((c) => c.name === "thread_id")) {
|
|
41177
41181
|
database.exec("ALTER TABLE turns ADD COLUMN thread_id TEXT");
|
|
@@ -41253,6 +41257,10 @@ CREATE INDEX IF NOT EXISTS idx_workspaces_path ON workspaces(path);
|
|
|
41253
41257
|
CREATE INDEX IF NOT EXISTS idx_discussion_threads_item_id ON discussion_threads(item_id);
|
|
41254
41258
|
`);
|
|
41255
41259
|
}
|
|
41260
|
+
const threadKindCols = database.prepare("PRAGMA table_info(discussion_threads)").all();
|
|
41261
|
+
if (!threadKindCols.some((c) => c.name === "kind")) {
|
|
41262
|
+
database.exec("ALTER TABLE discussion_threads ADD COLUMN kind TEXT NOT NULL DEFAULT 'discussion'");
|
|
41263
|
+
}
|
|
41256
41264
|
}
|
|
41257
41265
|
|
|
41258
41266
|
// node_modules/uuid/dist/esm/stringify.js
|
|
@@ -41780,6 +41788,16 @@ var import_cors = __toESM(require_cors(), 1);
|
|
|
41780
41788
|
|
|
41781
41789
|
// src/routes/sessions.ts
|
|
41782
41790
|
import path from "node:path";
|
|
41791
|
+
|
|
41792
|
+
// src/routes/session-touch.ts
|
|
41793
|
+
function markSessionTouched(db2, sessionId) {
|
|
41794
|
+
const { changes } = db2.prepare("UPDATE sessions SET user_touched = 1 WHERE id = ? AND user_touched = 0").run(sessionId);
|
|
41795
|
+
if (changes === 0) return false;
|
|
41796
|
+
broadcast("session:touched", { sessionId });
|
|
41797
|
+
return true;
|
|
41798
|
+
}
|
|
41799
|
+
|
|
41800
|
+
// src/routes/sessions.ts
|
|
41783
41801
|
async function registerSessionRoutes(fastify) {
|
|
41784
41802
|
fastify.get("/api/sessions", async () => {
|
|
41785
41803
|
const rows = getDb().prepare("SELECT * FROM sessions ORDER BY created_at DESC").all();
|
|
@@ -41983,6 +42001,7 @@ async function registerSessionRoutes(fastify) {
|
|
|
41983
42001
|
params.push(runtime_config);
|
|
41984
42002
|
}
|
|
41985
42003
|
db2.prepare(`UPDATE sessions SET ${updates.join(", ")} WHERE id = ?`).run(...params, id);
|
|
42004
|
+
if (title !== void 0) markSessionTouched(db2, id);
|
|
41986
42005
|
if (providerChanged || workspaceChanged) {
|
|
41987
42006
|
if (existing.external_thread_id) {
|
|
41988
42007
|
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);
|
|
@@ -42037,6 +42056,7 @@ async function registerSessionRoutes(fastify) {
|
|
|
42037
42056
|
db2.prepare(
|
|
42038
42057
|
"UPDATE sessions SET rewound_at_turn_id = NULL, pre_rewind_thread_id = NULL, updated_at = ? WHERE id = ?"
|
|
42039
42058
|
).run(now2, id);
|
|
42059
|
+
markSessionTouched(db2, id);
|
|
42040
42060
|
const truncated = db2.prepare("SELECT * FROM sessions WHERE id = ?").get(id);
|
|
42041
42061
|
return truncated;
|
|
42042
42062
|
}
|
|
@@ -42066,6 +42086,7 @@ async function registerSessionRoutes(fastify) {
|
|
|
42066
42086
|
}
|
|
42067
42087
|
}
|
|
42068
42088
|
provider.clearThread(id);
|
|
42089
|
+
markSessionTouched(db2, id);
|
|
42069
42090
|
const updated = db2.prepare("SELECT * FROM sessions WHERE id = ?").get(id);
|
|
42070
42091
|
return updated;
|
|
42071
42092
|
}
|
|
@@ -42090,6 +42111,7 @@ async function registerSessionRoutes(fastify) {
|
|
|
42090
42111
|
"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 = ?"
|
|
42091
42112
|
).run(now, id);
|
|
42092
42113
|
getProvider(session.runtime_type).clearThread(id);
|
|
42114
|
+
markSessionTouched(db2, id);
|
|
42093
42115
|
const updated = db2.prepare("SELECT * FROM sessions WHERE id = ?").get(id);
|
|
42094
42116
|
return updated;
|
|
42095
42117
|
});
|
|
@@ -42218,14 +42240,15 @@ async function registerTurnRoutes(fastify) {
|
|
|
42218
42240
|
data: { type: "string" }
|
|
42219
42241
|
}
|
|
42220
42242
|
}
|
|
42221
|
-
}
|
|
42243
|
+
},
|
|
42244
|
+
origin_app_id: { type: ["string", "null"] }
|
|
42222
42245
|
}
|
|
42223
42246
|
}
|
|
42224
42247
|
}
|
|
42225
42248
|
},
|
|
42226
42249
|
async (request, reply) => {
|
|
42227
42250
|
const { id } = request.params;
|
|
42228
|
-
const { user_prompt, attachments } = request.body || {};
|
|
42251
|
+
const { user_prompt, attachments, origin_app_id } = request.body || {};
|
|
42229
42252
|
if (!user_prompt || !user_prompt.trim()) {
|
|
42230
42253
|
return reply.code(400).send({ error: "user_prompt is required" });
|
|
42231
42254
|
}
|
|
@@ -42245,6 +42268,7 @@ async function registerTurnRoutes(fastify) {
|
|
|
42245
42268
|
VALUES (?, ?, ?, NULL, NULL, NULL, NULL, 'pending', NULL, ?, ?, ?)`
|
|
42246
42269
|
).run(turnId, id, user_prompt, attachmentsJson, now, now);
|
|
42247
42270
|
const turn = db2.prepare("SELECT * FROM turns WHERE id = ?").get(turnId);
|
|
42271
|
+
if (!origin_app_id) markSessionTouched(db2, id);
|
|
42248
42272
|
const rawTurn = turn;
|
|
42249
42273
|
const parsedTurn = {
|
|
42250
42274
|
...turn,
|
|
@@ -42291,6 +42315,7 @@ async function registerTurnRoutes(fastify) {
|
|
|
42291
42315
|
if (!cancelled) {
|
|
42292
42316
|
return reply.code(409).send({ error: "No running turn to cancel" });
|
|
42293
42317
|
}
|
|
42318
|
+
markSessionTouched(db2, id);
|
|
42294
42319
|
return { success: true };
|
|
42295
42320
|
});
|
|
42296
42321
|
fastify.post(
|
|
@@ -42311,7 +42336,7 @@ async function registerTurnRoutes(fastify) {
|
|
|
42311
42336
|
);
|
|
42312
42337
|
}
|
|
42313
42338
|
|
|
42314
|
-
// src/routes/
|
|
42339
|
+
// src/routes/thread-turns.ts
|
|
42315
42340
|
function parseTurnRow(row, items = []) {
|
|
42316
42341
|
return {
|
|
42317
42342
|
...row,
|
|
@@ -42320,6 +42345,22 @@ function parseTurnRow(row, items = []) {
|
|
|
42320
42345
|
items
|
|
42321
42346
|
};
|
|
42322
42347
|
}
|
|
42348
|
+
function startThreadTurn(db2, session, threadId, prompt, attachments) {
|
|
42349
|
+
const turnId = v4_default();
|
|
42350
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
42351
|
+
const attachmentsJson = attachments && attachments.length > 0 ? JSON.stringify(attachments) : null;
|
|
42352
|
+
db2.prepare(
|
|
42353
|
+
`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)
|
|
42354
|
+
VALUES (?, ?, ?, NULL, NULL, NULL, NULL, 'pending', NULL, ?, ?, ?, ?)`
|
|
42355
|
+
).run(turnId, session.id, prompt, threadId, attachmentsJson, now, now);
|
|
42356
|
+
const rawTurn = db2.prepare("SELECT * FROM turns WHERE id = ?").get(turnId);
|
|
42357
|
+
getProvider(session.runtime_type).startTurn(session, rawTurn).catch((err) => {
|
|
42358
|
+
console.error(`[threads] turn error for session ${session.id} (thread ${threadId}):`, err);
|
|
42359
|
+
});
|
|
42360
|
+
return parseTurnRow(rawTurn);
|
|
42361
|
+
}
|
|
42362
|
+
|
|
42363
|
+
// src/routes/threads.ts
|
|
42323
42364
|
async function registerThreadRoutes(fastify) {
|
|
42324
42365
|
fastify.post(
|
|
42325
42366
|
"/api/sessions/:sessionId/threads",
|
|
@@ -42415,22 +42456,13 @@ async function registerThreadRoutes(fastify) {
|
|
|
42415
42456
|
> ${selectedText}
|
|
42416
42457
|
|
|
42417
42458
|
${message}` : message;
|
|
42418
|
-
const
|
|
42419
|
-
const attachmentsJson = attachments && attachments.length > 0 ? JSON.stringify(attachments) : null;
|
|
42420
|
-
db2.prepare(
|
|
42421
|
-
`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)
|
|
42422
|
-
VALUES (?, ?, ?, NULL, NULL, NULL, NULL, 'pending', NULL, ?, ?, ?, ?)`
|
|
42423
|
-
).run(newTurnId, sessionId, formattedPrompt, threadId, attachmentsJson, now, now);
|
|
42424
|
-
const rawTurn = db2.prepare("SELECT * FROM turns WHERE id = ?").get(newTurnId);
|
|
42425
|
-
provider.startTurn(session, rawTurn).catch((err) => {
|
|
42426
|
-
console.error(`[threads] Unhandled error for session ${sessionId}:`, err);
|
|
42427
|
-
});
|
|
42459
|
+
const turn = startThreadTurn(db2, session, threadId, formattedPrompt, attachments);
|
|
42428
42460
|
const threadRow = db2.prepare("SELECT * FROM discussion_threads WHERE id = ?").get(threadId);
|
|
42429
|
-
const turn = parseTurnRow(rawTurn);
|
|
42430
42461
|
const thread = {
|
|
42431
42462
|
...threadRow,
|
|
42432
42463
|
turns: [turn]
|
|
42433
42464
|
};
|
|
42465
|
+
markSessionTouched(db2, sessionId);
|
|
42434
42466
|
broadcast("thread:created", { sessionId, thread, turn });
|
|
42435
42467
|
return { thread, turn };
|
|
42436
42468
|
}
|
|
@@ -42479,18 +42511,8 @@ ${message}` : message;
|
|
|
42479
42511
|
if (thread.status !== "open") {
|
|
42480
42512
|
return reply.code(409).send({ error: "Thread is resolved \u2014 reopen it first" });
|
|
42481
42513
|
}
|
|
42482
|
-
const
|
|
42483
|
-
|
|
42484
|
-
const attachmentsJson = attachments && attachments.length > 0 ? JSON.stringify(attachments) : null;
|
|
42485
|
-
db2.prepare(
|
|
42486
|
-
`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)
|
|
42487
|
-
VALUES (?, ?, ?, NULL, NULL, NULL, NULL, 'pending', NULL, ?, ?, ?, ?)`
|
|
42488
|
-
).run(newTurnId, sessionId, message, threadId, attachmentsJson, now, now);
|
|
42489
|
-
const rawTurn = db2.prepare("SELECT * FROM turns WHERE id = ?").get(newTurnId);
|
|
42490
|
-
getProvider(session.runtime_type).startTurn(session, rawTurn).catch((err) => {
|
|
42491
|
-
console.error(`[threads] followup error for session ${sessionId}:`, err);
|
|
42492
|
-
});
|
|
42493
|
-
const turn = parseTurnRow(rawTurn);
|
|
42514
|
+
const turn = startThreadTurn(db2, session, threadId, message, attachments);
|
|
42515
|
+
markSessionTouched(db2, sessionId);
|
|
42494
42516
|
broadcast("thread:followup", { sessionId, threadId, turn });
|
|
42495
42517
|
return { turn };
|
|
42496
42518
|
}
|
|
@@ -42613,7 +42635,7 @@ Agent: ${agent}`;
|
|
|
42613
42635
|
if (!session) {
|
|
42614
42636
|
return reply.code(404).send({ error: "Session not found" });
|
|
42615
42637
|
}
|
|
42616
|
-
const threadRows = db2.prepare("SELECT * FROM discussion_threads WHERE session_id = ? ORDER BY created_at ASC").all(sessionId);
|
|
42638
|
+
const threadRows = db2.prepare("SELECT * FROM discussion_threads WHERE session_id = ? AND kind != 'sidecar' ORDER BY created_at ASC").all(sessionId);
|
|
42617
42639
|
const result = [];
|
|
42618
42640
|
for (const tr of threadRows) {
|
|
42619
42641
|
const turnRows = db2.prepare("SELECT * FROM turns WHERE thread_id = ? ORDER BY created_at ASC").all(tr.id);
|
|
@@ -44983,8 +45005,8 @@ async function registerAppRoutes(fastify, opts) {
|
|
|
44983
45005
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
44984
45006
|
const maxOrder = db2.prepare("SELECT COALESCE(MAX(sort_order), 0) AS m FROM sessions WHERE cwd = ?").get(dir);
|
|
44985
45007
|
db2.prepare(
|
|
44986
|
-
`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)
|
|
44987
|
-
VALUES (?, ?, ?, ?, ?, ?, NULL, 'active', 0, ?, ?, ?,
|
|
45008
|
+
`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)
|
|
45009
|
+
VALUES (?, ?, ?, ?, ?, ?, NULL, 'active', 0, ?, ?, ?, ?, 1)`
|
|
44988
45010
|
).run(
|
|
44989
45011
|
sessionId,
|
|
44990
45012
|
`Edit: ${manifest.title}`,
|
|
@@ -45002,6 +45024,135 @@ async function registerAppRoutes(fastify, opts) {
|
|
|
45002
45024
|
);
|
|
45003
45025
|
}
|
|
45004
45026
|
|
|
45027
|
+
// src/sidecar/transcript-locator.ts
|
|
45028
|
+
import { existsSync as existsSync2, readdirSync } from "node:fs";
|
|
45029
|
+
import { homedir as homedir2 } from "node:os";
|
|
45030
|
+
import { join as join2 } from "node:path";
|
|
45031
|
+
function claudeConfigDir() {
|
|
45032
|
+
return process.env.CLAUDE_CONFIG_DIR || join2(homedir2(), ".claude");
|
|
45033
|
+
}
|
|
45034
|
+
function codexHome() {
|
|
45035
|
+
return process.env.CODEX_HOME || join2(homedir2(), ".codex");
|
|
45036
|
+
}
|
|
45037
|
+
function encodeClaudeProjectDir(cwd) {
|
|
45038
|
+
return cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
45039
|
+
}
|
|
45040
|
+
function listDir(dir) {
|
|
45041
|
+
try {
|
|
45042
|
+
return readdirSync(dir);
|
|
45043
|
+
} catch {
|
|
45044
|
+
return [];
|
|
45045
|
+
}
|
|
45046
|
+
}
|
|
45047
|
+
function findClaudeTranscript(externalId, cwd) {
|
|
45048
|
+
const projects = join2(claudeConfigDir(), "projects");
|
|
45049
|
+
const fileName = `${externalId}.jsonl`;
|
|
45050
|
+
if (cwd) {
|
|
45051
|
+
const direct = join2(projects, encodeClaudeProjectDir(cwd), fileName);
|
|
45052
|
+
if (existsSync2(direct)) return direct;
|
|
45053
|
+
}
|
|
45054
|
+
for (const dir of listDir(projects)) {
|
|
45055
|
+
const candidate = join2(projects, dir, fileName);
|
|
45056
|
+
if (existsSync2(candidate)) return candidate;
|
|
45057
|
+
}
|
|
45058
|
+
return null;
|
|
45059
|
+
}
|
|
45060
|
+
function findCodexTranscript(externalId) {
|
|
45061
|
+
const root = join2(codexHome(), "sessions");
|
|
45062
|
+
const suffix = `-${externalId}.jsonl`;
|
|
45063
|
+
const desc = (dir) => listDir(dir).sort().reverse();
|
|
45064
|
+
for (const year of desc(root)) {
|
|
45065
|
+
for (const month of desc(join2(root, year))) {
|
|
45066
|
+
for (const day of desc(join2(root, year, month))) {
|
|
45067
|
+
const dayDir = join2(root, year, month, day);
|
|
45068
|
+
const match = listDir(dayDir).find((f) => f.endsWith(suffix));
|
|
45069
|
+
if (match) return join2(dayDir, match);
|
|
45070
|
+
}
|
|
45071
|
+
}
|
|
45072
|
+
}
|
|
45073
|
+
return null;
|
|
45074
|
+
}
|
|
45075
|
+
function locateTranscript(session) {
|
|
45076
|
+
const externalId = session.external_thread_id;
|
|
45077
|
+
if (!externalId) return null;
|
|
45078
|
+
switch (session.runtime_type) {
|
|
45079
|
+
case "claude":
|
|
45080
|
+
return findClaudeTranscript(externalId, session.cwd);
|
|
45081
|
+
case "codex":
|
|
45082
|
+
return findCodexTranscript(externalId);
|
|
45083
|
+
default:
|
|
45084
|
+
return null;
|
|
45085
|
+
}
|
|
45086
|
+
}
|
|
45087
|
+
|
|
45088
|
+
// src/sidecar/prompt.ts
|
|
45089
|
+
var SIDECAR_QUESTION_MARKER = "Understand the user's question below, read the session file given above, and answer.";
|
|
45090
|
+
function buildSidecarPrompt(externalSessionId, transcriptPath, question) {
|
|
45091
|
+
return [
|
|
45092
|
+
`Your job is to answer questions about this session: ${externalSessionId}`,
|
|
45093
|
+
`Session file: ${transcriptPath}`,
|
|
45094
|
+
"",
|
|
45095
|
+
SIDECAR_QUESTION_MARKER,
|
|
45096
|
+
"",
|
|
45097
|
+
question
|
|
45098
|
+
].join("\n");
|
|
45099
|
+
}
|
|
45100
|
+
|
|
45101
|
+
// src/routes/sidecar.ts
|
|
45102
|
+
var SIDECAR_RUNTIMES = /* @__PURE__ */ new Set(["claude"]);
|
|
45103
|
+
async function registerSidecarRoutes(fastify) {
|
|
45104
|
+
fastify.post(
|
|
45105
|
+
"/api/sessions/:sessionId/sidecar",
|
|
45106
|
+
{
|
|
45107
|
+
schema: {
|
|
45108
|
+
body: {
|
|
45109
|
+
type: "object",
|
|
45110
|
+
required: ["message"],
|
|
45111
|
+
properties: { message: { type: "string", minLength: 1 } }
|
|
45112
|
+
}
|
|
45113
|
+
}
|
|
45114
|
+
},
|
|
45115
|
+
async (request, reply) => {
|
|
45116
|
+
const { sessionId } = request.params;
|
|
45117
|
+
const message = request.body.message.trim();
|
|
45118
|
+
if (!message) return reply.code(400).send({ error: "Message is empty" });
|
|
45119
|
+
const db2 = getDb();
|
|
45120
|
+
const session = db2.prepare("SELECT * FROM sessions WHERE id = ?").get(sessionId);
|
|
45121
|
+
if (!session) return reply.code(404).send({ error: "Session not found" });
|
|
45122
|
+
if (!SIDECAR_RUNTIMES.has(session.runtime_type)) {
|
|
45123
|
+
return reply.code(422).send({ error: `Sidecar is not available for ${session.runtime_type} sessions yet` });
|
|
45124
|
+
}
|
|
45125
|
+
const existing = db2.prepare("SELECT * FROM discussion_threads WHERE session_id = ? AND kind = 'sidecar' ORDER BY created_at DESC LIMIT 1").get(sessionId);
|
|
45126
|
+
if (existing) {
|
|
45127
|
+
if (isSessionBusy(db2, session, { threadId: existing.id })) {
|
|
45128
|
+
return reply.code(409).send({ error: "The sidecar is still answering" });
|
|
45129
|
+
}
|
|
45130
|
+
const turn2 = startThreadTurn(db2, session, existing.id, message);
|
|
45131
|
+
markSessionTouched(db2, sessionId);
|
|
45132
|
+
broadcast("thread:followup", { sessionId, threadId: existing.id, turn: turn2 });
|
|
45133
|
+
return { threadId: existing.id, turn: turn2 };
|
|
45134
|
+
}
|
|
45135
|
+
const transcriptPath = locateTranscript(session);
|
|
45136
|
+
if (!session.external_thread_id || !transcriptPath) {
|
|
45137
|
+
return reply.code(409).send({ error: "This session has no transcript yet \u2014 the sidecar can answer once it has run a turn" });
|
|
45138
|
+
}
|
|
45139
|
+
const threadId = v4_default();
|
|
45140
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
45141
|
+
db2.prepare(
|
|
45142
|
+
`INSERT INTO discussion_threads (id, session_id, kind, status, created_at, updated_at)
|
|
45143
|
+
VALUES (?, ?, 'sidecar', 'open', ?, ?)`
|
|
45144
|
+
).run(threadId, sessionId, now, now);
|
|
45145
|
+
const prompt = buildSidecarPrompt(session.external_thread_id, transcriptPath, message);
|
|
45146
|
+
const turn = startThreadTurn(db2, session, threadId, prompt);
|
|
45147
|
+
const threadRow = db2.prepare("SELECT * FROM discussion_threads WHERE id = ?").get(threadId);
|
|
45148
|
+
const thread = { ...threadRow, turns: [turn] };
|
|
45149
|
+
markSessionTouched(db2, sessionId);
|
|
45150
|
+
broadcast("thread:created", { sessionId, thread, turn });
|
|
45151
|
+
return { threadId, turn };
|
|
45152
|
+
}
|
|
45153
|
+
);
|
|
45154
|
+
}
|
|
45155
|
+
|
|
45005
45156
|
// src/codex/item-mapper.ts
|
|
45006
45157
|
function mapItemData(item) {
|
|
45007
45158
|
switch (item.type) {
|
|
@@ -45735,7 +45886,7 @@ var codexProvider = {
|
|
|
45735
45886
|
import { query, forkSession as sdkForkSession } from "@anthropic-ai/claude-agent-sdk";
|
|
45736
45887
|
import { readFileSync as readFileSync2 } from "fs";
|
|
45737
45888
|
import { tmpdir } from "os";
|
|
45738
|
-
import { join as
|
|
45889
|
+
import { join as join3 } from "path";
|
|
45739
45890
|
|
|
45740
45891
|
// src/claude/claude-message-mapper.ts
|
|
45741
45892
|
function mapAssistantContent(content, messageId, thinkingTexts) {
|
|
@@ -46449,6 +46600,10 @@ async function handleMessage(message, sessionId, turnId, entry, db2) {
|
|
|
46449
46600
|
now,
|
|
46450
46601
|
sessionId
|
|
46451
46602
|
);
|
|
46603
|
+
} else {
|
|
46604
|
+
db2.prepare(
|
|
46605
|
+
"UPDATE discussion_threads SET external_thread_id = ?, updated_at = ? WHERE id = ? AND external_thread_id IS NULL"
|
|
46606
|
+
).run(message.session_id, (/* @__PURE__ */ new Date()).toISOString(), entry.threadId);
|
|
46452
46607
|
}
|
|
46453
46608
|
} else if (sub === "compact_boundary") {
|
|
46454
46609
|
handleCompactBoundary(
|
|
@@ -46672,7 +46827,7 @@ function constructMonitorOutputPath(entry, taskId) {
|
|
|
46672
46827
|
if (!entry.sessionId) return "";
|
|
46673
46828
|
const uid = typeof process.getuid === "function" ? process.getuid() : 0;
|
|
46674
46829
|
const encodedCwd = entry.cwd.replace(/\//g, "-");
|
|
46675
|
-
return
|
|
46830
|
+
return join3(tmpdir(), `claude-${uid}`, encodedCwd, entry.sessionId, "tasks", `${taskId}.output`);
|
|
46676
46831
|
}
|
|
46677
46832
|
function handleTaskStarted(message, sessionId, turnId, entry, db2) {
|
|
46678
46833
|
const m = message;
|
|
@@ -48854,6 +49009,7 @@ async function createAgentPaneApp(dbPath) {
|
|
|
48854
49009
|
await registerMaintenanceRoutes(fastify);
|
|
48855
49010
|
await registerVscodeWebRoutes(fastify);
|
|
48856
49011
|
await registerAppRoutes(fastify);
|
|
49012
|
+
await registerSidecarRoutes(fastify);
|
|
48857
49013
|
const wss2 = initWs();
|
|
48858
49014
|
wss2.on("connection", (ws) => {
|
|
48859
49015
|
ws.send(JSON.stringify({ event: "background_tasks:snapshot", data: { sessions: listAllBackgroundTasks() } }));
|