@sideboard-ai/core 0.1.133 → 0.1.136
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/dist/{agents-NHS6P25H.js → agents-ELWR7A2T.js} +5 -5
- package/dist/{agents-SOU5GPWI.js → agents-QNTTLMG2.js} +5 -5
- package/dist/{chunk-Y645NFYN.js → chunk-4XKUHP6G.js} +2 -2
- package/dist/{chunk-4YAVXWFR.js → chunk-CYM5DCHI.js} +39 -5
- package/dist/{chunk-LTP7GHIF.js → chunk-GSKRGF7B.js} +286 -5
- package/dist/{chunk-WEU5M7BW.js → chunk-HQQNLDVC.js} +1 -1
- package/dist/{chunk-IM36S4HZ.js → chunk-IFZ4MOTN.js} +3 -3
- package/dist/{chunk-G6X6UFJO.js → chunk-J5IBSVB3.js} +42 -12
- package/dist/{chunk-AK7SWE2U.js → chunk-JPBRMUM6.js} +9 -5
- package/dist/{chunk-YEIH7P7D.js → chunk-K5YT5GX2.js} +244 -5
- package/dist/{chunk-3UVVWNHF.js → chunk-MDCKV2NF.js} +2 -2
- package/dist/{chunk-HLJUNJBF.js → chunk-PM3C2J6K.js} +42 -12
- package/dist/{chunk-Q6XQXCOM.js → chunk-QAV3HGVS.js} +1 -1
- package/dist/{chunk-TG7YU2KG.js → chunk-TIGKDMIA.js} +144 -271
- package/dist/{chunk-6CRKPD4C.js → chunk-TQ4S5AGJ.js} +3 -3
- package/dist/{chunk-VSON7EJ6.js → chunk-WS5LFFU3.js} +140 -222
- package/dist/{coordinator-prompt-DXHEDRRN.js → coordinator-prompt-2OWSUAUR.js} +3 -3
- package/dist/{coordinator-prompt-XF7LVOUN.js → coordinator-prompt-IPL4Z6SL.js} +3 -3
- package/dist/{global-workspace-2LO5ATOH.js → global-workspace-JDUCUL7S.js} +4 -4
- package/dist/{global-workspace-MLQNULOU.js → global-workspace-NIKZAKOO.js} +4 -4
- package/dist/index.cjs +873 -628
- package/dist/index.d.cts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +42 -19
- package/dist/mcp/run-stdio.cjs +700 -498
- package/dist/mcp/run-stdio.js +22 -11
- package/dist/{orchestrator-P2SYHVLS.js → orchestrator-6I47JMU2.js} +7 -7
- package/dist/{orchestrator-KR5RA5B7.js → orchestrator-KK3CUW37.js} +7 -7
- package/dist/{thread-store-5MLYY35S.js → thread-store-CRLQJ2HM.js} +3 -1
- package/dist/{thread-store-F6BCARQG.js → thread-store-FADXSMEJ.js} +3 -1
- package/dist/{workspaces-MINB764G.js → workspaces-5EWNNALF.js} +5 -5
- package/dist/{workspaces-ARWPZG6F.js → workspaces-KZA3TCEE.js} +5 -5
- package/dist/{worktree-EBZMUUAL.js → worktree-BC6XDMQK.js} +2 -2
- package/dist/{worktree-S7MKMYAT.js → worktree-MX7XBX6Z.js} +2 -2
- package/package.json +1 -1
|
@@ -2,18 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
ensureGlobalCoordinatorCwd
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-TQ4S5AGJ.js";
|
|
6
6
|
import {
|
|
7
7
|
allocateTeamName,
|
|
8
8
|
takenSlugsFromThread,
|
|
9
9
|
teamSlugFromName
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-QAV3HGVS.js";
|
|
11
|
+
import {
|
|
12
|
+
ATTACHMENTS_DIR,
|
|
13
|
+
attachmentsGitignoreBody
|
|
14
|
+
} from "./chunk-B3SJXYIJ.js";
|
|
11
15
|
import {
|
|
12
16
|
createEmptyThread,
|
|
13
17
|
listThreads,
|
|
14
18
|
updateThread,
|
|
15
19
|
writeThread
|
|
16
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-J5IBSVB3.js";
|
|
17
21
|
import {
|
|
18
22
|
resolveNewThreadOptions,
|
|
19
23
|
resolveThreadDefaults
|
|
@@ -44,6 +48,233 @@ var CLOUD_COORDINATOR_TIMEOUT_REPLY = [
|
|
|
44
48
|
"What do you want me to do? (retry later, wait, force-stop, rephrase, or cancel)"
|
|
45
49
|
].join(" ");
|
|
46
50
|
|
|
51
|
+
// src/composer/stage-files.ts
|
|
52
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
53
|
+
import { basename, extname, join } from "path";
|
|
54
|
+
import { randomUUID } from "crypto";
|
|
55
|
+
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
56
|
+
"png",
|
|
57
|
+
"jpg",
|
|
58
|
+
"jpeg",
|
|
59
|
+
"gif",
|
|
60
|
+
"webp",
|
|
61
|
+
"svg",
|
|
62
|
+
"bmp",
|
|
63
|
+
"ico"
|
|
64
|
+
]);
|
|
65
|
+
var IMAGE_MIME_BY_EXT = {
|
|
66
|
+
png: "image/png",
|
|
67
|
+
jpg: "image/jpeg",
|
|
68
|
+
jpeg: "image/jpeg",
|
|
69
|
+
gif: "image/gif",
|
|
70
|
+
webp: "image/webp",
|
|
71
|
+
svg: "image/svg+xml",
|
|
72
|
+
bmp: "image/bmp",
|
|
73
|
+
ico: "image/x-icon"
|
|
74
|
+
};
|
|
75
|
+
var MAX_INLINE_BYTES = 4e5;
|
|
76
|
+
var MAX_PREVIEW_BYTES = 5e6;
|
|
77
|
+
function fileExtension(filePath) {
|
|
78
|
+
const base = basename(filePath).toLowerCase();
|
|
79
|
+
return base.includes(".") ? base.split(".").pop() || "" : "";
|
|
80
|
+
}
|
|
81
|
+
function isImageFilePath(filePath) {
|
|
82
|
+
return IMAGE_EXTENSIONS.has(fileExtension(filePath));
|
|
83
|
+
}
|
|
84
|
+
function imageMimeType(filePath) {
|
|
85
|
+
return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
|
|
86
|
+
}
|
|
87
|
+
function ensureAttachmentsDir(worktreePath) {
|
|
88
|
+
const dir = join(worktreePath, ATTACHMENTS_DIR);
|
|
89
|
+
mkdirSync(dir, { recursive: true });
|
|
90
|
+
const gi = join(dir, ".gitignore");
|
|
91
|
+
if (!existsSync(gi)) {
|
|
92
|
+
writeFileSync(gi, attachmentsGitignoreBody(), "utf8");
|
|
93
|
+
}
|
|
94
|
+
return dir;
|
|
95
|
+
}
|
|
96
|
+
function uniqueAttachmentName(dir, originalName) {
|
|
97
|
+
const safe = originalName.replace(/[/\\]/g, "_") || "file";
|
|
98
|
+
if (!existsSync(join(dir, safe))) return safe;
|
|
99
|
+
const ext = extname(safe);
|
|
100
|
+
const stem = ext ? safe.slice(0, -ext.length) : safe;
|
|
101
|
+
for (let i = 1; i < 1e4; i++) {
|
|
102
|
+
const candidate = `${stem}-${i}${ext}`;
|
|
103
|
+
if (!existsSync(join(dir, candidate))) return candidate;
|
|
104
|
+
}
|
|
105
|
+
return `${stem}-${randomUUID()}${ext}`;
|
|
106
|
+
}
|
|
107
|
+
function previewDataUrlFromBuf(filePath, buf) {
|
|
108
|
+
if (!isImageFilePath(filePath)) return void 0;
|
|
109
|
+
if (buf.length > MAX_PREVIEW_BYTES) return void 0;
|
|
110
|
+
return `data:${imageMimeType(filePath)};base64,${buf.toString("base64")}`;
|
|
111
|
+
}
|
|
112
|
+
function attachmentFromBuffer(name, buf, opts) {
|
|
113
|
+
const previewDataUrl = previewDataUrlFromBuf(name, buf);
|
|
114
|
+
if (isImageFilePath(name)) {
|
|
115
|
+
const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
|
|
116
|
+
return {
|
|
117
|
+
id: randomUUID(),
|
|
118
|
+
name,
|
|
119
|
+
kind: "file",
|
|
120
|
+
path: opts.path,
|
|
121
|
+
previewDataUrl,
|
|
122
|
+
content: [
|
|
123
|
+
`Image attached: ${pathHint}`,
|
|
124
|
+
opts.path ? `Use the Read tool on \`${opts.path}\` to view this image.` : "The image is shown in the composer; copy it into the worktree if you need to inspect pixels."
|
|
125
|
+
].join("\n")
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
if (buf.length > MAX_INLINE_BYTES) {
|
|
129
|
+
return {
|
|
130
|
+
id: randomUUID(),
|
|
131
|
+
name,
|
|
132
|
+
kind: "file",
|
|
133
|
+
path: opts.path,
|
|
134
|
+
content: opts.path ? `(file too large to attach inline: \`${opts.path}\`, ${buf.length} bytes \u2014 use the Read tool)` : `(file too large to attach inline: ${opts.sourceLabel || name}, ${buf.length} bytes)`
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
if (buf.includes(0)) {
|
|
138
|
+
return {
|
|
139
|
+
id: randomUUID(),
|
|
140
|
+
name,
|
|
141
|
+
kind: "file",
|
|
142
|
+
path: opts.path,
|
|
143
|
+
content: opts.path ? `(binary file at \`${opts.path}\` \u2014 use tools to inspect)` : `(binary file attached by path only: ${opts.sourceLabel || name})`
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
id: randomUUID(),
|
|
148
|
+
name,
|
|
149
|
+
kind: "file",
|
|
150
|
+
path: opts.path,
|
|
151
|
+
content: buf.toString("utf8")
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
|
|
155
|
+
if (absolutePaths.length === 0) return [];
|
|
156
|
+
const dir = ensureAttachmentsDir(worktreePath);
|
|
157
|
+
const out = [];
|
|
158
|
+
for (const abs of absolutePaths) {
|
|
159
|
+
const originalName = basename(abs);
|
|
160
|
+
try {
|
|
161
|
+
const st = statSync(abs);
|
|
162
|
+
if (!st.isFile()) continue;
|
|
163
|
+
const name = uniqueAttachmentName(dir, originalName);
|
|
164
|
+
const destAbs = join(dir, name);
|
|
165
|
+
copyFileSync(abs, destAbs);
|
|
166
|
+
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
167
|
+
const buf = readFileSync(destAbs);
|
|
168
|
+
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
169
|
+
} catch (err) {
|
|
170
|
+
out.push({
|
|
171
|
+
id: randomUUID(),
|
|
172
|
+
name: originalName,
|
|
173
|
+
kind: "file",
|
|
174
|
+
content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
function stageBuffersAsAttachments(worktreePath, buffers) {
|
|
181
|
+
if (buffers.length === 0) return [];
|
|
182
|
+
const dir = ensureAttachmentsDir(worktreePath);
|
|
183
|
+
const out = [];
|
|
184
|
+
for (const item of buffers) {
|
|
185
|
+
const originalName = (item.name || "file").replace(/[/\\]/g, "_") || "file";
|
|
186
|
+
try {
|
|
187
|
+
const buf = Buffer.from(item.dataBase64, "base64");
|
|
188
|
+
const name = uniqueAttachmentName(dir, originalName);
|
|
189
|
+
const destAbs = join(dir, name);
|
|
190
|
+
writeFileSync(destAbs, buf);
|
|
191
|
+
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
192
|
+
out.push(attachmentFromBuffer(name, buf, { path: rel }));
|
|
193
|
+
} catch (err) {
|
|
194
|
+
out.push({
|
|
195
|
+
id: randomUUID(),
|
|
196
|
+
name: originalName,
|
|
197
|
+
kind: "file",
|
|
198
|
+
content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return out;
|
|
203
|
+
}
|
|
204
|
+
function isWorktreeRelativePath(p) {
|
|
205
|
+
if (!p || p.includes("..")) return false;
|
|
206
|
+
if (p.startsWith("/")) return false;
|
|
207
|
+
if (/^[A-Za-z]:[\\/]/.test(p)) return false;
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
function dataUrlToBase64(url) {
|
|
211
|
+
if (!url) return null;
|
|
212
|
+
const m = /^data:[^;]+;base64,(.+)$/s.exec(url);
|
|
213
|
+
return m?.[1] ?? null;
|
|
214
|
+
}
|
|
215
|
+
var IMAGE_HINT_RE = /^Image attached:/;
|
|
216
|
+
var PLACEHOLDER_CONTENT_RE = /^\((could not |file too large|binary file|not a file|invalid path)/;
|
|
217
|
+
function persistPendingFileAttachments(worktreePath, attachments) {
|
|
218
|
+
if (attachments.length === 0) return attachments;
|
|
219
|
+
const keep = [];
|
|
220
|
+
const buffers = [];
|
|
221
|
+
for (const att of attachments) {
|
|
222
|
+
if (att.kind !== "file") {
|
|
223
|
+
keep.push(att);
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (att.path && isWorktreeRelativePath(att.path)) {
|
|
227
|
+
keep.push(att);
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
const fromPreview = dataUrlToBase64(att.previewDataUrl);
|
|
231
|
+
if (fromPreview) {
|
|
232
|
+
buffers.push({ name: att.name, dataBase64: fromPreview });
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
if (att.content && !IMAGE_HINT_RE.test(att.content) && !PLACEHOLDER_CONTENT_RE.test(att.content)) {
|
|
236
|
+
buffers.push({
|
|
237
|
+
name: att.name,
|
|
238
|
+
dataBase64: Buffer.from(att.content, "utf8").toString("base64")
|
|
239
|
+
});
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
keep.push(att);
|
|
243
|
+
}
|
|
244
|
+
if (buffers.length === 0) return attachments;
|
|
245
|
+
return [...keep, ...stageBuffersAsAttachments(worktreePath, buffers)];
|
|
246
|
+
}
|
|
247
|
+
function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
248
|
+
const out = [];
|
|
249
|
+
for (const rel of relativePaths) {
|
|
250
|
+
if (!rel || rel.includes("..") || rel.startsWith("/")) {
|
|
251
|
+
out.push({
|
|
252
|
+
id: randomUUID(),
|
|
253
|
+
name: basename(rel) || "file",
|
|
254
|
+
kind: "file",
|
|
255
|
+
content: `(invalid path: ${rel})`
|
|
256
|
+
});
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
const name = basename(rel);
|
|
260
|
+
try {
|
|
261
|
+
const abs = join(worktreePath, rel);
|
|
262
|
+
const st = statSync(abs);
|
|
263
|
+
if (!st.isFile()) continue;
|
|
264
|
+
const buf = readFileSync(abs);
|
|
265
|
+
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
266
|
+
} catch (err) {
|
|
267
|
+
out.push({
|
|
268
|
+
id: randomUUID(),
|
|
269
|
+
name,
|
|
270
|
+
kind: "file",
|
|
271
|
+
content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return out;
|
|
276
|
+
}
|
|
277
|
+
|
|
47
278
|
// src/agents/orchestrator-capable.ts
|
|
48
279
|
var ORCHESTRATOR_AGENT_KINDS = [
|
|
49
280
|
"claude",
|
|
@@ -139,6 +370,7 @@ function createGlobalChat(opts) {
|
|
|
139
370
|
fast: opts.fast
|
|
140
371
|
});
|
|
141
372
|
const agent = assertOrchestratorCapableAgent(resolved.agent);
|
|
373
|
+
const worktreePath = globalAgentCwd();
|
|
142
374
|
const thread = createEmptyThread({
|
|
143
375
|
title,
|
|
144
376
|
// Stick nicknames the same way chat tabs do (avoid later sync overwrites).
|
|
@@ -146,7 +378,7 @@ function createGlobalChat(opts) {
|
|
|
146
378
|
sourceType: "orchestration",
|
|
147
379
|
sourceRef,
|
|
148
380
|
branchName: "global",
|
|
149
|
-
worktreePath
|
|
381
|
+
worktreePath,
|
|
150
382
|
repoPath: GLOBAL_WORKSPACE_ID,
|
|
151
383
|
agent,
|
|
152
384
|
autonomy: opts.autonomy ?? "default",
|
|
@@ -154,7 +386,10 @@ function createGlobalChat(opts) {
|
|
|
154
386
|
effort: resolved.effort,
|
|
155
387
|
fast: resolved.fast,
|
|
156
388
|
planMode: Boolean(opts.planMode),
|
|
157
|
-
attachments:
|
|
389
|
+
attachments: persistPendingFileAttachments(
|
|
390
|
+
worktreePath,
|
|
391
|
+
opts.attachments ?? []
|
|
392
|
+
),
|
|
158
393
|
parentThreadId: opts.parentThreadId ?? null,
|
|
159
394
|
status: "idle"
|
|
160
395
|
});
|
|
@@ -276,6 +511,10 @@ function ensureCloudCoordinator(agent) {
|
|
|
276
511
|
}
|
|
277
512
|
|
|
278
513
|
export {
|
|
514
|
+
stageAbsolutePathsAsAttachments,
|
|
515
|
+
stageBuffersAsAttachments,
|
|
516
|
+
persistPendingFileAttachments,
|
|
517
|
+
attachmentsFromWorktreePaths,
|
|
279
518
|
ORCHESTRATOR_AGENT_KINDS,
|
|
280
519
|
isOrchestratorCapableAgent,
|
|
281
520
|
assertOrchestratorCapableAgent,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isGlobalRepoPath
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-GSKRGF7B.js";
|
|
4
4
|
import {
|
|
5
5
|
ensureGhPreferOrigin,
|
|
6
6
|
resolveRepoRoot
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-HQQNLDVC.js";
|
|
8
8
|
import {
|
|
9
9
|
appDataDir
|
|
10
10
|
} from "./chunk-QZQEXME2.js";
|
|
@@ -106,11 +106,29 @@ async function withThreadLock(id, fn) {
|
|
|
106
106
|
if (release) await release();
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
|
+
var listCache = null;
|
|
110
|
+
function cacheForDir() {
|
|
111
|
+
const dir = threadsDir();
|
|
112
|
+
if (!listCache || listCache.dir !== dir) {
|
|
113
|
+
listCache = { dir, byId: /* @__PURE__ */ new Map(), listed: false };
|
|
114
|
+
}
|
|
115
|
+
return listCache;
|
|
116
|
+
}
|
|
117
|
+
function invalidateThreadListCache() {
|
|
118
|
+
listCache = null;
|
|
119
|
+
}
|
|
120
|
+
function rememberThread(thread) {
|
|
121
|
+
cacheForDir().byId.set(thread.id, thread);
|
|
122
|
+
}
|
|
109
123
|
function readThread(id) {
|
|
124
|
+
const cached = cacheForDir().byId.get(id);
|
|
125
|
+
if (cached) return cached;
|
|
110
126
|
const path = threadFilePath(id);
|
|
111
127
|
if (!existsSync(path)) return null;
|
|
112
128
|
const raw = readFileSync(path, "utf8");
|
|
113
|
-
|
|
129
|
+
const thread = normalizeThread(JSON.parse(raw));
|
|
130
|
+
rememberThread(thread);
|
|
131
|
+
return thread;
|
|
114
132
|
}
|
|
115
133
|
function writeThread(thread) {
|
|
116
134
|
const path = threadFilePath(idPath(thread.id));
|
|
@@ -118,6 +136,7 @@ function writeThread(thread) {
|
|
|
118
136
|
const next = { ...thread, updatedAt: nowIso() };
|
|
119
137
|
writeFileSync(tmp, JSON.stringify(next, null, 2), "utf8");
|
|
120
138
|
renameSync(tmp, path);
|
|
139
|
+
rememberThread(next);
|
|
121
140
|
}
|
|
122
141
|
function idPath(id) {
|
|
123
142
|
return id;
|
|
@@ -127,22 +146,32 @@ function isThreadRecordFile(nameOrPath) {
|
|
|
127
146
|
return name.endsWith(".json") && !name.endsWith(".live.json");
|
|
128
147
|
}
|
|
129
148
|
function listThreads(opts) {
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
149
|
+
const cache = cacheForDir();
|
|
150
|
+
if (!cache.listed) {
|
|
151
|
+
const files = readdirSync(threadsDir()).filter(isThreadRecordFile);
|
|
152
|
+
const byId = /* @__PURE__ */ new Map();
|
|
153
|
+
for (const f of files) {
|
|
154
|
+
try {
|
|
155
|
+
const thread = normalizeThread(
|
|
156
|
+
JSON.parse(readFileSync(threadFilePath(f.replace(/\.json$/, "")), "utf8"))
|
|
157
|
+
);
|
|
158
|
+
if (typeof thread.id === "string" && thread.id.length > 0) {
|
|
159
|
+
byId.set(thread.id, thread);
|
|
160
|
+
}
|
|
161
|
+
} catch {
|
|
162
|
+
}
|
|
138
163
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
164
|
+
cache.byId = byId;
|
|
165
|
+
cache.listed = true;
|
|
166
|
+
}
|
|
167
|
+
const threads = [...cache.byId.values()].sort(
|
|
168
|
+
(a, b) => b.updatedAt.localeCompare(a.updatedAt)
|
|
169
|
+
);
|
|
142
170
|
if (opts?.includeArchived) return threads;
|
|
143
171
|
return threads.filter((t) => t.status !== "archived");
|
|
144
172
|
}
|
|
145
173
|
function deleteThreadRecord(id) {
|
|
174
|
+
cacheForDir().byId.delete(id);
|
|
146
175
|
const path = threadFilePath(id);
|
|
147
176
|
if (existsSync(path)) unlinkSync(path);
|
|
148
177
|
const lock = threadLockPath(id);
|
|
@@ -180,6 +209,7 @@ export {
|
|
|
180
209
|
normalizeThread,
|
|
181
210
|
createEmptyThread,
|
|
182
211
|
withThreadLock,
|
|
212
|
+
invalidateThreadListCache,
|
|
183
213
|
readThread,
|
|
184
214
|
writeThread,
|
|
185
215
|
isThreadRecordFile,
|