repoburg 1.3.219 → 1.3.220
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-pane/backend/dist/index.js +373 -18
- package/agent-pane/backend/dist/server.js +373 -18
- package/agent-pane/frontend/dist/assets/index-lc9eQnqi.css +1 -0
- package/agent-pane/frontend/dist/assets/index-vR3SdkR-.js +418 -0
- package/agent-pane/frontend/dist/index.html +2 -2
- package/daemon/dist/remote/cloudflared.js +16 -10
- package/package.json +3 -2
- package/agent-pane/frontend/dist/assets/index-BUkOj2Cb.js +0 -392
- package/agent-pane/frontend/dist/assets/index-gAFaOmjN.css +0 -1
|
@@ -41076,6 +41076,14 @@ function createTables(database) {
|
|
|
41076
41076
|
created_at TEXT NOT NULL
|
|
41077
41077
|
);
|
|
41078
41078
|
|
|
41079
|
+
CREATE TABLE IF NOT EXISTS sidebar_folders (
|
|
41080
|
+
id TEXT PRIMARY KEY,
|
|
41081
|
+
workspace_path TEXT NOT NULL,
|
|
41082
|
+
name TEXT NOT NULL,
|
|
41083
|
+
sort_order INTEGER NOT NULL DEFAULT 0,
|
|
41084
|
+
created_at TEXT NOT NULL
|
|
41085
|
+
);
|
|
41086
|
+
|
|
41079
41087
|
CREATE TABLE IF NOT EXISTS discussion_threads (
|
|
41080
41088
|
id TEXT PRIMARY KEY,
|
|
41081
41089
|
session_id TEXT NOT NULL,
|
|
@@ -41094,6 +41102,8 @@ function createTables(database) {
|
|
|
41094
41102
|
CREATE INDEX IF NOT EXISTS idx_turns_session_id ON turns(session_id);
|
|
41095
41103
|
CREATE INDEX IF NOT EXISTS idx_items_turn_id ON items(turn_id);
|
|
41096
41104
|
CREATE INDEX IF NOT EXISTS idx_workspaces_path ON workspaces(path);
|
|
41105
|
+
CREATE INDEX IF NOT EXISTS idx_workspaces_path ON workspaces(path);
|
|
41106
|
+
CREATE INDEX IF NOT EXISTS idx_sidebar_folders_workspace_path ON sidebar_folders(workspace_path);
|
|
41097
41107
|
CREATE INDEX IF NOT EXISTS idx_discussion_threads_session_id ON discussion_threads(session_id);
|
|
41098
41108
|
CREATE INDEX IF NOT EXISTS idx_discussion_threads_item_id ON discussion_threads(item_id);
|
|
41099
41109
|
`);
|
|
@@ -41123,6 +41133,15 @@ function createTables(database) {
|
|
|
41123
41133
|
if (!sessColumns.some((c) => c.name === "context_usage")) {
|
|
41124
41134
|
database.exec("ALTER TABLE sessions ADD COLUMN context_usage TEXT");
|
|
41125
41135
|
}
|
|
41136
|
+
if (!sessColumns.some((c) => c.name === "folder_id")) {
|
|
41137
|
+
database.exec("ALTER TABLE sessions ADD COLUMN folder_id TEXT");
|
|
41138
|
+
}
|
|
41139
|
+
if (!sessColumns.some((c) => c.name === "sort_order")) {
|
|
41140
|
+
database.exec("ALTER TABLE sessions ADD COLUMN sort_order INTEGER NOT NULL DEFAULT 0");
|
|
41141
|
+
}
|
|
41142
|
+
if (!sessColumns.some((c) => c.name === "starred")) {
|
|
41143
|
+
database.exec("ALTER TABLE sessions ADD COLUMN starred INTEGER NOT NULL DEFAULT 0");
|
|
41144
|
+
}
|
|
41126
41145
|
const turnColumns = database.prepare("PRAGMA table_info(turns)").all();
|
|
41127
41146
|
if (!turnColumns.some((c) => c.name === "thread_id")) {
|
|
41128
41147
|
database.exec("ALTER TABLE turns ADD COLUMN thread_id TEXT");
|
|
@@ -41304,21 +41323,30 @@ async function registerSessionRoutes(fastify) {
|
|
|
41304
41323
|
list.push(item);
|
|
41305
41324
|
itemsByTurn.set(item.turn_id, list);
|
|
41306
41325
|
}
|
|
41326
|
+
const hydrateTurn = (row) => ({
|
|
41327
|
+
...row,
|
|
41328
|
+
token_usage: row.token_usage ? JSON.parse(row.token_usage) : null,
|
|
41329
|
+
attachments: row.attachments ? JSON.parse(row.attachments) : null,
|
|
41330
|
+
runtime_input_ids: row.runtime_input_ids ? JSON.parse(row.runtime_input_ids) : null,
|
|
41331
|
+
items: itemsByTurn.get(row.id) ?? []
|
|
41332
|
+
});
|
|
41333
|
+
const mainTurns = turnRows.filter((row) => row.thread_id == null).map(hydrateTurn);
|
|
41334
|
+
const threadTurns = turnRows.filter((row) => row.thread_id != null).map(hydrateTurn);
|
|
41307
41335
|
const detail = {
|
|
41308
41336
|
...session,
|
|
41309
|
-
turns:
|
|
41310
|
-
...row,
|
|
41311
|
-
token_usage: row.token_usage ? JSON.parse(row.token_usage) : null,
|
|
41312
|
-
attachments: row.attachments ? JSON.parse(row.attachments) : null,
|
|
41313
|
-
runtime_input_ids: row.runtime_input_ids ? JSON.parse(row.runtime_input_ids) : null,
|
|
41314
|
-
items: itemsByTurn.get(row.id) ?? []
|
|
41315
|
-
}))
|
|
41337
|
+
turns: mainTurns
|
|
41316
41338
|
};
|
|
41317
41339
|
const threadRows = db2.prepare("SELECT * FROM discussion_threads WHERE session_id = ? ORDER BY created_at ASC").all(id);
|
|
41340
|
+
const turnsByThread = /* @__PURE__ */ new Map();
|
|
41341
|
+
for (const t of threadTurns) {
|
|
41342
|
+
const list = turnsByThread.get(t.thread_id) ?? [];
|
|
41343
|
+
list.push(t);
|
|
41344
|
+
turnsByThread.set(t.thread_id, list);
|
|
41345
|
+
}
|
|
41318
41346
|
if (threadRows.length > 0) {
|
|
41319
41347
|
detail.threads = threadRows.map((tr) => ({
|
|
41320
41348
|
...tr,
|
|
41321
|
-
turns:
|
|
41349
|
+
turns: turnsByThread.get(tr.id) ?? []
|
|
41322
41350
|
}));
|
|
41323
41351
|
}
|
|
41324
41352
|
const cuRow = db2.prepare("SELECT context_usage FROM sessions WHERE id = ?").get(id);
|
|
@@ -41355,11 +41383,13 @@ async function registerSessionRoutes(fastify) {
|
|
|
41355
41383
|
} = request.body || {};
|
|
41356
41384
|
const id = v4_default();
|
|
41357
41385
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
41358
|
-
getDb()
|
|
41359
|
-
|
|
41360
|
-
|
|
41361
|
-
|
|
41362
|
-
|
|
41386
|
+
const db2 = getDb();
|
|
41387
|
+
const maxOrder = db2.prepare("SELECT COALESCE(MAX(sort_order), 0) AS m FROM sessions WHERE cwd = ?").get(cwd ?? null);
|
|
41388
|
+
db2.prepare(
|
|
41389
|
+
`INSERT INTO sessions (id, title, runtime_type, model, model_reasoning_effort, cwd, external_thread_id, status, is_running, sort_order, created_at, updated_at, runtime_config)
|
|
41390
|
+
VALUES (?, ?, ?, ?, ?, ?, NULL, 'active', 0, ?, ?, ?, ?)`
|
|
41391
|
+
).run(id, title, runtime_type, model, model_reasoning_effort, cwd, maxOrder.m + 1, now, now, runtime_config);
|
|
41392
|
+
const session = db2.prepare("SELECT * FROM sessions WHERE id = ?").get(id);
|
|
41363
41393
|
return session;
|
|
41364
41394
|
});
|
|
41365
41395
|
fastify.delete("/api/sessions/:id", async (request, reply) => {
|
|
@@ -41386,13 +41416,14 @@ async function registerSessionRoutes(fastify) {
|
|
|
41386
41416
|
model_reasoning_effort: { type: ["string", "null"] },
|
|
41387
41417
|
runtime_config: { type: ["string", "null"] },
|
|
41388
41418
|
runtime_type: { type: "string" },
|
|
41389
|
-
cwd: { type: ["string", "null"] }
|
|
41419
|
+
cwd: { type: ["string", "null"] },
|
|
41420
|
+
starred: { type: "number" }
|
|
41390
41421
|
}
|
|
41391
41422
|
}
|
|
41392
41423
|
}
|
|
41393
41424
|
}, async (request, reply) => {
|
|
41394
41425
|
const { id } = request.params;
|
|
41395
|
-
const { title, lifecycle, has_unreviewed, model, model_reasoning_effort, runtime_config, runtime_type, cwd } = request.body || {};
|
|
41426
|
+
const { title, lifecycle, has_unreviewed, model, model_reasoning_effort, runtime_config, runtime_type, cwd, starred } = request.body || {};
|
|
41396
41427
|
const db2 = getDb();
|
|
41397
41428
|
const existing = db2.prepare("SELECT * FROM sessions WHERE id = ?").get(id);
|
|
41398
41429
|
if (!existing) {
|
|
@@ -41417,6 +41448,10 @@ async function registerSessionRoutes(fastify) {
|
|
|
41417
41448
|
updates.push("has_unreviewed = ?");
|
|
41418
41449
|
params.push(has_unreviewed);
|
|
41419
41450
|
}
|
|
41451
|
+
if (starred !== void 0) {
|
|
41452
|
+
updates.push("starred = ?");
|
|
41453
|
+
params.push(starred);
|
|
41454
|
+
}
|
|
41420
41455
|
if (runtime_type !== void 0 && runtime_type !== existing.runtime_type) {
|
|
41421
41456
|
providerChanged = true;
|
|
41422
41457
|
updates.push("runtime_type = ?");
|
|
@@ -41877,6 +41912,60 @@ ${message}`;
|
|
|
41877
41912
|
return { turn };
|
|
41878
41913
|
}
|
|
41879
41914
|
);
|
|
41915
|
+
fastify.post(
|
|
41916
|
+
"/api/sessions/:sessionId/threads/:threadId/summarize",
|
|
41917
|
+
{
|
|
41918
|
+
schema: {
|
|
41919
|
+
body: {
|
|
41920
|
+
type: "object",
|
|
41921
|
+
properties: {
|
|
41922
|
+
directives: { type: "string" }
|
|
41923
|
+
}
|
|
41924
|
+
}
|
|
41925
|
+
}
|
|
41926
|
+
},
|
|
41927
|
+
async (request, reply) => {
|
|
41928
|
+
const { sessionId, threadId } = request.params;
|
|
41929
|
+
const { directives } = request.body || {};
|
|
41930
|
+
const db2 = getDb();
|
|
41931
|
+
const session = db2.prepare("SELECT * FROM sessions WHERE id = ?").get(sessionId);
|
|
41932
|
+
if (!session) {
|
|
41933
|
+
return reply.code(404).send({ error: "Session not found" });
|
|
41934
|
+
}
|
|
41935
|
+
const thread = db2.prepare("SELECT * FROM discussion_threads WHERE id = ? AND session_id = ?").get(threadId, sessionId);
|
|
41936
|
+
if (!thread) {
|
|
41937
|
+
return reply.code(404).send({ error: "Thread not found" });
|
|
41938
|
+
}
|
|
41939
|
+
if (thread.status !== "open") {
|
|
41940
|
+
return reply.code(409).send({ error: "Thread is already resolved" });
|
|
41941
|
+
}
|
|
41942
|
+
const runningTurn = db2.prepare(`SELECT id FROM turns WHERE thread_id = ? AND status IN ('pending', 'running') LIMIT 1`).get(threadId);
|
|
41943
|
+
if (runningTurn) {
|
|
41944
|
+
return reply.code(409).send({ error: "A thread turn is still running \u2014 wait for it to finish first" });
|
|
41945
|
+
}
|
|
41946
|
+
const provider = getProvider(session.runtime_type);
|
|
41947
|
+
if (!provider.summarizeThread) {
|
|
41948
|
+
return reply.code(501).send({ error: `Summarization is not supported for runtime "${session.runtime_type}" yet` });
|
|
41949
|
+
}
|
|
41950
|
+
const turnRows = db2.prepare("SELECT user_prompt, agent_response, status FROM turns WHERE thread_id = ? ORDER BY created_at ASC").all(threadId);
|
|
41951
|
+
const transcript = turnRows.map((t) => {
|
|
41952
|
+
const agent = t.agent_response?.trim() || "(no response)";
|
|
41953
|
+
return `User: ${t.user_prompt}
|
|
41954
|
+
|
|
41955
|
+
Agent: ${agent}`;
|
|
41956
|
+
}).join("\n\n---\n\n");
|
|
41957
|
+
const summary = await provider.summarizeThread(session, thread, transcript, directives ?? "");
|
|
41958
|
+
if (!summary) {
|
|
41959
|
+
return reply.code(500).send({ error: "Summarization failed \u2014 thread was not resolved. Try again or resolve without sharing." });
|
|
41960
|
+
}
|
|
41961
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
41962
|
+
db2.prepare(
|
|
41963
|
+
"UPDATE discussion_threads SET status = ?, resolved_at = ?, updated_at = ? WHERE id = ?"
|
|
41964
|
+
).run("resolved", now, now, threadId);
|
|
41965
|
+
broadcast("thread:resolved", { sessionId, threadId, status: "resolved" });
|
|
41966
|
+
return { summary, resolved: true };
|
|
41967
|
+
}
|
|
41968
|
+
);
|
|
41880
41969
|
fastify.patch(
|
|
41881
41970
|
"/api/sessions/:sessionId/threads/:threadId",
|
|
41882
41971
|
{
|
|
@@ -42066,6 +42155,137 @@ async function registerWorkspaceRoutes(fastify) {
|
|
|
42066
42155
|
});
|
|
42067
42156
|
}
|
|
42068
42157
|
|
|
42158
|
+
// src/routes/folders.ts
|
|
42159
|
+
async function registerFolderRoutes(fastify) {
|
|
42160
|
+
fastify.get("/api/folders", async () => {
|
|
42161
|
+
const rows = getDb().prepare("SELECT * FROM sidebar_folders ORDER BY workspace_path ASC, sort_order ASC").all();
|
|
42162
|
+
return rows;
|
|
42163
|
+
});
|
|
42164
|
+
fastify.post("/api/folders", {
|
|
42165
|
+
schema: {
|
|
42166
|
+
body: {
|
|
42167
|
+
type: "object",
|
|
42168
|
+
required: ["workspace_path", "name"],
|
|
42169
|
+
properties: {
|
|
42170
|
+
workspace_path: { type: "string" },
|
|
42171
|
+
name: { type: "string" }
|
|
42172
|
+
}
|
|
42173
|
+
}
|
|
42174
|
+
}
|
|
42175
|
+
}, async (request, reply) => {
|
|
42176
|
+
const { workspace_path, name } = request.body || {};
|
|
42177
|
+
if (!workspace_path?.trim() || !name?.trim()) {
|
|
42178
|
+
return reply.code(400).send({ error: "workspace_path and name are required" });
|
|
42179
|
+
}
|
|
42180
|
+
const db2 = getDb();
|
|
42181
|
+
const id = v4_default();
|
|
42182
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
42183
|
+
const maxOrder = db2.prepare("SELECT COALESCE(MAX(sort_order), -1) AS m FROM sidebar_folders WHERE workspace_path = ?").get(workspace_path.trim());
|
|
42184
|
+
db2.prepare(
|
|
42185
|
+
"INSERT INTO sidebar_folders (id, workspace_path, name, sort_order, created_at) VALUES (?, ?, ?, ?, ?)"
|
|
42186
|
+
).run(id, workspace_path.trim(), name.trim(), maxOrder.m + 1, now);
|
|
42187
|
+
const folder = db2.prepare("SELECT * FROM sidebar_folders WHERE id = ?").get(id);
|
|
42188
|
+
return folder;
|
|
42189
|
+
});
|
|
42190
|
+
fastify.patch("/api/folders/:id", {
|
|
42191
|
+
schema: {
|
|
42192
|
+
body: {
|
|
42193
|
+
type: "object",
|
|
42194
|
+
properties: {
|
|
42195
|
+
name: { type: "string" },
|
|
42196
|
+
sort_order: { type: "number" }
|
|
42197
|
+
}
|
|
42198
|
+
}
|
|
42199
|
+
}
|
|
42200
|
+
}, async (request, reply) => {
|
|
42201
|
+
const { id } = request.params;
|
|
42202
|
+
const { name, sort_order } = request.body || {};
|
|
42203
|
+
const db2 = getDb();
|
|
42204
|
+
const existing = db2.prepare("SELECT * FROM sidebar_folders WHERE id = ?").get(id);
|
|
42205
|
+
if (!existing) {
|
|
42206
|
+
return reply.code(404).send({ error: "Folder not found" });
|
|
42207
|
+
}
|
|
42208
|
+
if (name !== void 0 && !name.trim()) {
|
|
42209
|
+
return reply.code(400).send({ error: "name cannot be empty" });
|
|
42210
|
+
}
|
|
42211
|
+
const updates = [];
|
|
42212
|
+
const params = [];
|
|
42213
|
+
if (name !== void 0) {
|
|
42214
|
+
updates.push("name = ?");
|
|
42215
|
+
params.push(name.trim());
|
|
42216
|
+
}
|
|
42217
|
+
if (sort_order !== void 0) {
|
|
42218
|
+
updates.push("sort_order = ?");
|
|
42219
|
+
params.push(sort_order);
|
|
42220
|
+
}
|
|
42221
|
+
if (updates.length > 0) {
|
|
42222
|
+
db2.prepare(`UPDATE sidebar_folders SET ${updates.join(", ")} WHERE id = ?`).run(...params, id);
|
|
42223
|
+
}
|
|
42224
|
+
return db2.prepare("SELECT * FROM sidebar_folders WHERE id = ?").get(id);
|
|
42225
|
+
});
|
|
42226
|
+
fastify.delete("/api/folders/:id", async (request, reply) => {
|
|
42227
|
+
const { id } = request.params;
|
|
42228
|
+
const db2 = getDb();
|
|
42229
|
+
const existing = db2.prepare("SELECT id FROM sidebar_folders WHERE id = ?").get(id);
|
|
42230
|
+
if (!existing) {
|
|
42231
|
+
return reply.code(404).send({ error: "Folder not found" });
|
|
42232
|
+
}
|
|
42233
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
42234
|
+
const move = db2.transaction(() => {
|
|
42235
|
+
db2.prepare(
|
|
42236
|
+
"UPDATE sessions SET folder_id = NULL, updated_at = ? WHERE folder_id = ?"
|
|
42237
|
+
).run(now, id);
|
|
42238
|
+
db2.prepare("DELETE FROM sidebar_folders WHERE id = ?").run(id);
|
|
42239
|
+
});
|
|
42240
|
+
move();
|
|
42241
|
+
return { success: true };
|
|
42242
|
+
});
|
|
42243
|
+
fastify.post("/api/sessions/reorder", {
|
|
42244
|
+
schema: {
|
|
42245
|
+
body: {
|
|
42246
|
+
type: "object",
|
|
42247
|
+
required: ["moves"],
|
|
42248
|
+
properties: {
|
|
42249
|
+
moves: {
|
|
42250
|
+
type: "array",
|
|
42251
|
+
items: {
|
|
42252
|
+
type: "object",
|
|
42253
|
+
required: ["id", "sort_order"],
|
|
42254
|
+
properties: {
|
|
42255
|
+
id: { type: "string" },
|
|
42256
|
+
folder_id: { type: ["string", "null"] },
|
|
42257
|
+
sort_order: { type: "number" }
|
|
42258
|
+
}
|
|
42259
|
+
}
|
|
42260
|
+
}
|
|
42261
|
+
}
|
|
42262
|
+
}
|
|
42263
|
+
}
|
|
42264
|
+
}, async (request, reply) => {
|
|
42265
|
+
const { moves } = request.body || {};
|
|
42266
|
+
const db2 = getDb();
|
|
42267
|
+
for (const m of moves) {
|
|
42268
|
+
if (!db2.prepare("SELECT id FROM sessions WHERE id = ?").get(m.id)) {
|
|
42269
|
+
return reply.code(404).send({ error: `Session not found: ${m.id}` });
|
|
42270
|
+
}
|
|
42271
|
+
if (m.folder_id && !db2.prepare("SELECT id FROM sidebar_folders WHERE id = ?").get(m.folder_id)) {
|
|
42272
|
+
return reply.code(404).send({ error: `Folder not found: ${m.folder_id}` });
|
|
42273
|
+
}
|
|
42274
|
+
}
|
|
42275
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
42276
|
+
const stmt = db2.prepare(
|
|
42277
|
+
"UPDATE sessions SET folder_id = ?, sort_order = ?, updated_at = ? WHERE id = ?"
|
|
42278
|
+
);
|
|
42279
|
+
const apply = db2.transaction(() => {
|
|
42280
|
+
for (const m of moves) {
|
|
42281
|
+
stmt.run(m.folder_id ?? null, m.sort_order, now, m.id);
|
|
42282
|
+
}
|
|
42283
|
+
});
|
|
42284
|
+
apply();
|
|
42285
|
+
return { success: true, updated: moves.length };
|
|
42286
|
+
});
|
|
42287
|
+
}
|
|
42288
|
+
|
|
42069
42289
|
// src/routes/providers.ts
|
|
42070
42290
|
var CODEX_PROVIDER = {
|
|
42071
42291
|
id: "codex",
|
|
@@ -42966,6 +43186,75 @@ Agent responded: "${truncatedResponse}"`;
|
|
|
42966
43186
|
}
|
|
42967
43187
|
}
|
|
42968
43188
|
}
|
|
43189
|
+
async function summarizeCodexThread(session, _thread, transcript, directives) {
|
|
43190
|
+
let client = null;
|
|
43191
|
+
try {
|
|
43192
|
+
client = new AppServerClient({ cwd: session.cwd ?? process.cwd() });
|
|
43193
|
+
await client.initialize();
|
|
43194
|
+
const initResult = await client.request("thread/start", {
|
|
43195
|
+
cwd: session.cwd ?? process.cwd(),
|
|
43196
|
+
approvalPolicy: "never",
|
|
43197
|
+
sandbox: "read-only"
|
|
43198
|
+
});
|
|
43199
|
+
const threadId = initResult.thread.id;
|
|
43200
|
+
const directiveLine = directives.trim() ? `
|
|
43201
|
+
|
|
43202
|
+
The user has given these summarization directives \u2014 follow them exactly:
|
|
43203
|
+
"${directives.trim()}"` : "";
|
|
43204
|
+
const summaryPrompt = `You are summarizing a side discussion thread that forked from a main agent session. The discussion begins at the FIRST message of the transcript below \u2014 summarize ONLY the discussion itself, from its beginning up to now.${directiveLine}
|
|
43205
|
+
|
|
43206
|
+
The discussion transcript (from the discussion's beginning):
|
|
43207
|
+
|
|
43208
|
+
${transcript}
|
|
43209
|
+
|
|
43210
|
+
Produce a concise summary of the discussion that preserves: concrete findings, file paths, decisions, and any unresolved questions. Reply with only the summary text, nothing else.`;
|
|
43211
|
+
let summaryResolve;
|
|
43212
|
+
let summaryReject;
|
|
43213
|
+
const summaryPromise = new Promise((resolve, reject) => {
|
|
43214
|
+
summaryResolve = resolve;
|
|
43215
|
+
summaryReject = reject;
|
|
43216
|
+
});
|
|
43217
|
+
let summaryResponse = "";
|
|
43218
|
+
client.onNotification("item/completed", (params) => {
|
|
43219
|
+
const p = params;
|
|
43220
|
+
if (p.threadId !== threadId) return;
|
|
43221
|
+
if ((p.item.type === "agentMessage" || p.item.type === "agent_message") && p.item.text) {
|
|
43222
|
+
summaryResponse = p.item.text;
|
|
43223
|
+
}
|
|
43224
|
+
});
|
|
43225
|
+
client.onNotification("turn/completed", (params) => {
|
|
43226
|
+
const p = params;
|
|
43227
|
+
if (p.threadId !== threadId) return;
|
|
43228
|
+
summaryResolve(summaryResponse);
|
|
43229
|
+
});
|
|
43230
|
+
client.onNotification("turn/failed", (params) => {
|
|
43231
|
+
const p = params;
|
|
43232
|
+
if (p.threadId !== threadId) return;
|
|
43233
|
+
summaryReject(new Error(p.error.message));
|
|
43234
|
+
});
|
|
43235
|
+
const timeout = setTimeout(() => {
|
|
43236
|
+
summaryReject(new Error("Thread summarization timed out"));
|
|
43237
|
+
}, 6e4);
|
|
43238
|
+
await client.request("turn/start", {
|
|
43239
|
+
threadId,
|
|
43240
|
+
input: [{ type: "text", text: summaryPrompt }],
|
|
43241
|
+
approvalPolicy: "never",
|
|
43242
|
+
sandbox: { type: "read-only" }
|
|
43243
|
+
});
|
|
43244
|
+
const summary = await summaryPromise;
|
|
43245
|
+
clearTimeout(timeout);
|
|
43246
|
+
const clean = summary.trim();
|
|
43247
|
+
return clean || null;
|
|
43248
|
+
} catch (err) {
|
|
43249
|
+
console.error("[codex] summarizeThread failed:", err);
|
|
43250
|
+
return null;
|
|
43251
|
+
} finally {
|
|
43252
|
+
if (client) {
|
|
43253
|
+
await client.close().catch(() => {
|
|
43254
|
+
});
|
|
43255
|
+
}
|
|
43256
|
+
}
|
|
43257
|
+
}
|
|
42969
43258
|
var EFFORT_LABELS = {
|
|
42970
43259
|
minimal: "Minimal",
|
|
42971
43260
|
low: "Low",
|
|
@@ -43002,6 +43291,7 @@ var codexProvider = {
|
|
|
43002
43291
|
clearThread,
|
|
43003
43292
|
clearAllThreads,
|
|
43004
43293
|
getModels,
|
|
43294
|
+
summarizeThread: summarizeCodexThread,
|
|
43005
43295
|
shutdown
|
|
43006
43296
|
};
|
|
43007
43297
|
|
|
@@ -43209,6 +43499,7 @@ var PromptQueue = class {
|
|
|
43209
43499
|
};
|
|
43210
43500
|
}
|
|
43211
43501
|
};
|
|
43502
|
+
var CLI_OVERRIDE = process.env.CLAUDE_BIN ? { pathToClaudeCodeExecutable: process.env.CLAUDE_BIN } : {};
|
|
43212
43503
|
var sessionMap2 = /* @__PURE__ */ new Map();
|
|
43213
43504
|
var titleGenerating2 = /* @__PURE__ */ new Set();
|
|
43214
43505
|
var cachedModels = null;
|
|
@@ -43242,7 +43533,7 @@ async function ensureSessionStarted(session, mapKey, resumeSessionId) {
|
|
|
43242
43533
|
permissionMode: "bypassPermissions",
|
|
43243
43534
|
allowDangerouslySkipPermissions: true,
|
|
43244
43535
|
includePartialMessages: true,
|
|
43245
|
-
...
|
|
43536
|
+
...CLI_OVERRIDE,
|
|
43246
43537
|
...session.model_reasoning_effort ? { effort: session.model_reasoning_effort } : {},
|
|
43247
43538
|
...resumeId ? { resume: resumeId } : {}
|
|
43248
43539
|
};
|
|
@@ -43853,7 +44144,8 @@ async function getModels2() {
|
|
|
43853
44144
|
options: {
|
|
43854
44145
|
cwd: process.cwd(),
|
|
43855
44146
|
permissionMode: "bypassPermissions",
|
|
43856
|
-
allowDangerouslySkipPermissions: true
|
|
44147
|
+
allowDangerouslySkipPermissions: true,
|
|
44148
|
+
...CLI_OVERRIDE
|
|
43857
44149
|
}
|
|
43858
44150
|
});
|
|
43859
44151
|
const initResult = await q.initializationResult();
|
|
@@ -43917,7 +44209,8 @@ Agent responded: "${truncatedResponse}"`;
|
|
|
43917
44209
|
options: {
|
|
43918
44210
|
cwd: process.cwd(),
|
|
43919
44211
|
permissionMode: "bypassPermissions",
|
|
43920
|
-
allowDangerouslySkipPermissions: true
|
|
44212
|
+
allowDangerouslySkipPermissions: true,
|
|
44213
|
+
...CLI_OVERRIDE
|
|
43921
44214
|
}
|
|
43922
44215
|
});
|
|
43923
44216
|
let titleResponse = "";
|
|
@@ -43944,6 +44237,66 @@ Agent responded: "${truncatedResponse}"`;
|
|
|
43944
44237
|
}
|
|
43945
44238
|
}
|
|
43946
44239
|
}
|
|
44240
|
+
function buildThreadSummaryPrompt(transcript, directives, hasNativeContext) {
|
|
44241
|
+
const directiveLine = directives.trim() ? `
|
|
44242
|
+
|
|
44243
|
+
The user has given these summarization directives \u2014 follow them exactly:
|
|
44244
|
+
"${directives.trim()}"` : "";
|
|
44245
|
+
const contextBlock = hasNativeContext ? "" : `
|
|
44246
|
+
|
|
44247
|
+
The discussion transcript (from the discussion's beginning):
|
|
44248
|
+
|
|
44249
|
+
${transcript}`;
|
|
44250
|
+
return `You are summarizing a side discussion thread that forked from a main agent session. The discussion begins at the message that quotes a passage from a previous response (prefixed "[Quoting from your previous response]") \u2014 everything in the conversation BEFORE that message is the main session's earlier context and must NOT be included in the summary. Summarize ONLY the discussion itself, from its first message up to now \u2014 do not summarize the full conversation history.${contextBlock}${directiveLine}
|
|
44251
|
+
|
|
44252
|
+
Produce a concise summary of the discussion that preserves: concrete findings, file paths, decisions, and any unresolved questions. The summary will be quoted back into the main session's conversation. Reply with only the summary text, nothing else.`;
|
|
44253
|
+
}
|
|
44254
|
+
async function summarizeClaudeThread(session, thread, transcript, directives) {
|
|
44255
|
+
let q = null;
|
|
44256
|
+
try {
|
|
44257
|
+
let resumeId;
|
|
44258
|
+
if (thread.external_thread_id) {
|
|
44259
|
+
try {
|
|
44260
|
+
const forked = await sdkForkSession(thread.external_thread_id, {
|
|
44261
|
+
dir: session.cwd ?? process.cwd()
|
|
44262
|
+
});
|
|
44263
|
+
resumeId = forked.sessionId;
|
|
44264
|
+
} catch (err) {
|
|
44265
|
+
console.error("[claude] summarizeThread fork failed \u2014 falling back to embedded transcript:", err);
|
|
44266
|
+
}
|
|
44267
|
+
}
|
|
44268
|
+
const prompt = buildThreadSummaryPrompt(transcript, directives, !!resumeId);
|
|
44269
|
+
q = query({
|
|
44270
|
+
prompt,
|
|
44271
|
+
options: {
|
|
44272
|
+
cwd: session.cwd ?? process.cwd(),
|
|
44273
|
+
permissionMode: "bypassPermissions",
|
|
44274
|
+
allowDangerouslySkipPermissions: true,
|
|
44275
|
+
...CLI_OVERRIDE,
|
|
44276
|
+
...resumeId ? { resume: resumeId } : {}
|
|
44277
|
+
}
|
|
44278
|
+
});
|
|
44279
|
+
let summary = "";
|
|
44280
|
+
for await (const message of q) {
|
|
44281
|
+
if (message.type === "assistant") {
|
|
44282
|
+
for (const block of message.message.content) {
|
|
44283
|
+
if (block.type === "text") {
|
|
44284
|
+
summary += block.text;
|
|
44285
|
+
}
|
|
44286
|
+
}
|
|
44287
|
+
}
|
|
44288
|
+
}
|
|
44289
|
+
const clean = summary.trim();
|
|
44290
|
+
return clean || null;
|
|
44291
|
+
} catch (err) {
|
|
44292
|
+
console.error("[claude] summarizeThread failed:", err);
|
|
44293
|
+
return null;
|
|
44294
|
+
} finally {
|
|
44295
|
+
if (q) {
|
|
44296
|
+
q.close();
|
|
44297
|
+
}
|
|
44298
|
+
}
|
|
44299
|
+
}
|
|
43947
44300
|
async function forkClaudeSession(session, targetTurn) {
|
|
43948
44301
|
if (!session.external_thread_id) return null;
|
|
43949
44302
|
try {
|
|
@@ -43966,6 +44319,7 @@ var claudeProvider = {
|
|
|
43966
44319
|
getModels: getModels2,
|
|
43967
44320
|
getCommands,
|
|
43968
44321
|
forkSession: forkClaudeSession,
|
|
44322
|
+
summarizeThread: summarizeClaudeThread,
|
|
43969
44323
|
setModel,
|
|
43970
44324
|
stopTask,
|
|
43971
44325
|
shutdown: shutdown2
|
|
@@ -45484,6 +45838,7 @@ async function createAgentPaneApp(dbPath) {
|
|
|
45484
45838
|
await registerTurnRoutes(fastify);
|
|
45485
45839
|
await registerThreadRoutes(fastify);
|
|
45486
45840
|
await registerWorkspaceRoutes(fastify);
|
|
45841
|
+
await registerFolderRoutes(fastify);
|
|
45487
45842
|
await registerProviderRoutes(fastify);
|
|
45488
45843
|
await registerModelRoutes(fastify);
|
|
45489
45844
|
await registerSkillRoutes(fastify);
|