@leeandrew94/ccm 0.3.1 → 0.4.0
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/bin/ccm.js +134 -110
- package/package.json +1 -1
package/bin/ccm.js
CHANGED
|
@@ -446,6 +446,8 @@ function cmdList() {
|
|
|
446
446
|
// src/commands/init.ts
|
|
447
447
|
import https from "https";
|
|
448
448
|
import http from "http";
|
|
449
|
+
import fs4 from "fs";
|
|
450
|
+
import path4 from "path";
|
|
449
451
|
function httpRequest(url, token, timeout = 8e3) {
|
|
450
452
|
return new Promise((resolve) => {
|
|
451
453
|
const parsed = new URL(url);
|
|
@@ -475,6 +477,33 @@ function httpRequest(url, token, timeout = 8e3) {
|
|
|
475
477
|
req.end();
|
|
476
478
|
});
|
|
477
479
|
}
|
|
480
|
+
var MODEL_CACHE_FILE = path4.join(CONFIG_DIR, "model-cache.json");
|
|
481
|
+
function loadModelCache() {
|
|
482
|
+
try {
|
|
483
|
+
if (fs4.existsSync(MODEL_CACHE_FILE)) {
|
|
484
|
+
return JSON.parse(fs4.readFileSync(MODEL_CACHE_FILE, "utf-8"));
|
|
485
|
+
}
|
|
486
|
+
} catch {
|
|
487
|
+
}
|
|
488
|
+
return {};
|
|
489
|
+
}
|
|
490
|
+
function saveModelCache(cache) {
|
|
491
|
+
fs4.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
492
|
+
fs4.writeFileSync(MODEL_CACHE_FILE, JSON.stringify(cache, null, 2) + "\n", "utf-8");
|
|
493
|
+
}
|
|
494
|
+
function getCachedModels(endpoint) {
|
|
495
|
+
return loadModelCache()[endpoint]?.models;
|
|
496
|
+
}
|
|
497
|
+
function setCachedModels(endpoint, models) {
|
|
498
|
+
const cache = loadModelCache();
|
|
499
|
+
cache[endpoint] = { models, updatedAt: Date.now() };
|
|
500
|
+
saveModelCache(cache);
|
|
501
|
+
}
|
|
502
|
+
var FALLBACK_MODELS = [
|
|
503
|
+
"claude-sonnet-4-20250514",
|
|
504
|
+
"claude-opus-4-20250514",
|
|
505
|
+
"claude-haiku-4-20250501"
|
|
506
|
+
];
|
|
478
507
|
async function fetchModels(baseUrl, token) {
|
|
479
508
|
const url = baseUrl.replace(/\/+$/, "");
|
|
480
509
|
for (const suffix of ["/anthropic", "/v1/chat/completions"]) {
|
|
@@ -496,6 +525,7 @@ async function selectModel(models, label) {
|
|
|
496
525
|
if (models.length === 0) {
|
|
497
526
|
return await ask("Model name");
|
|
498
527
|
}
|
|
528
|
+
const options = [...models, "Custom model..."];
|
|
499
529
|
console.log(`
|
|
500
530
|
\x1B[1m${label}\x1B[0m (\u2191\u2193 navigate, Enter to select):
|
|
501
531
|
`);
|
|
@@ -505,20 +535,20 @@ async function selectModel(models, label) {
|
|
|
505
535
|
function render() {
|
|
506
536
|
process.stdout.write("\x1B[?25l");
|
|
507
537
|
const start = offset;
|
|
508
|
-
const end = Math.min(offset + PAGE,
|
|
538
|
+
const end = Math.min(offset + PAGE, options.length);
|
|
509
539
|
for (let i = start; i < end; i++) {
|
|
510
540
|
process.stdout.write("\x1B[2K");
|
|
511
541
|
if (i === selected) {
|
|
512
|
-
console.log(` \x1B[36m\u276F\x1B[0m \x1B[1m${
|
|
542
|
+
console.log(` \x1B[36m\u276F\x1B[0m \x1B[1m${options[i]}\x1B[0m`);
|
|
513
543
|
} else {
|
|
514
|
-
console.log(` \x1B[90m${
|
|
544
|
+
console.log(` \x1B[90m${options[i]}\x1B[0m`);
|
|
515
545
|
}
|
|
516
546
|
}
|
|
517
547
|
process.stdout.write("\x1B[2K");
|
|
518
|
-
if (
|
|
519
|
-
console.log(` \x1B[90m${selected + 1}/${
|
|
548
|
+
if (options.length > PAGE) {
|
|
549
|
+
console.log(` \x1B[90m${selected + 1}/${options.length} \u2014 \u2191\u2193 scroll, Enter select\x1B[0m`);
|
|
520
550
|
}
|
|
521
|
-
const lines = end - start + (
|
|
551
|
+
const lines = end - start + (options.length > PAGE ? 1 : 0);
|
|
522
552
|
process.stdout.write(`\x1B[${lines}A`);
|
|
523
553
|
}
|
|
524
554
|
return new Promise((resolve) => {
|
|
@@ -526,18 +556,17 @@ async function selectModel(models, label) {
|
|
|
526
556
|
process.stdin.resume();
|
|
527
557
|
process.stdin.setEncoding("utf-8");
|
|
528
558
|
render();
|
|
529
|
-
let buf = "";
|
|
530
559
|
process.stdin.on("data", function onData(key) {
|
|
531
560
|
if (key === "\x1B[A") {
|
|
532
561
|
selected = Math.max(0, selected - 1);
|
|
533
562
|
if (selected < offset) offset = selected;
|
|
534
563
|
render();
|
|
535
564
|
} else if (key === "\x1B[B") {
|
|
536
|
-
selected = Math.min(
|
|
565
|
+
selected = Math.min(options.length - 1, selected + 1);
|
|
537
566
|
if (selected >= offset + PAGE) offset = selected - PAGE + 1;
|
|
538
567
|
render();
|
|
539
568
|
} else if (key === "\r" || key === "\n") {
|
|
540
|
-
const lines = Math.min(PAGE,
|
|
569
|
+
const lines = Math.min(PAGE, options.length - offset) + (options.length > PAGE ? 1 : 0);
|
|
541
570
|
for (let i = 0; i < lines; i++) {
|
|
542
571
|
process.stdout.write("\x1B[2K\n");
|
|
543
572
|
}
|
|
@@ -546,13 +575,18 @@ async function selectModel(models, label) {
|
|
|
546
575
|
process.stdout.write("\x1B[2K\n");
|
|
547
576
|
}
|
|
548
577
|
process.stdout.write(`\x1B[${lines}A`);
|
|
549
|
-
process.stdout.write(` \x1B[36m\u276F\x1B[0m \x1B[1m${
|
|
578
|
+
process.stdout.write(` \x1B[36m\u276F\x1B[0m \x1B[1m${options[selected]}\x1B[0m
|
|
550
579
|
`);
|
|
551
580
|
process.stdout.write("\x1B[?25h");
|
|
552
581
|
process.stdin.setRawMode(false);
|
|
553
582
|
process.stdin.removeListener("data", onData);
|
|
554
583
|
process.stdin.pause();
|
|
555
|
-
|
|
584
|
+
const chosen = options[selected];
|
|
585
|
+
if (chosen === "Custom model...") {
|
|
586
|
+
ask("Model name").then(resolve);
|
|
587
|
+
} else {
|
|
588
|
+
resolve(chosen);
|
|
589
|
+
}
|
|
556
590
|
} else if (key === "") {
|
|
557
591
|
process.stdout.write("\x1B[?25h");
|
|
558
592
|
process.exit(0);
|
|
@@ -585,33 +619,23 @@ async function cmdInit() {
|
|
|
585
619
|
}
|
|
586
620
|
console.log();
|
|
587
621
|
info("Validating connection...");
|
|
588
|
-
const
|
|
589
|
-
let models =
|
|
590
|
-
if (
|
|
591
|
-
models
|
|
592
|
-
|
|
593
|
-
ok(`Found \x1B[1m${models.length}\x1B[0m models`);
|
|
594
|
-
} else {
|
|
595
|
-
info("Could not fetch model list (enter manually)");
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
let model;
|
|
599
|
-
if (isAnthropic) {
|
|
600
|
-
const anthropicModels = [
|
|
601
|
-
"claude-sonnet-4-20250514",
|
|
602
|
-
"claude-opus-4-20250514",
|
|
603
|
-
"claude-haiku-4-20250501"
|
|
604
|
-
];
|
|
605
|
-
model = await selectModel(anthropicModels, "Select a model");
|
|
606
|
-
} else if (models.length > 0) {
|
|
607
|
-
model = await selectModel(models, "Select a model");
|
|
622
|
+
const endpoint = baseUrl.replace(/\/+$/, "");
|
|
623
|
+
let models = await fetchModels(baseUrl, token);
|
|
624
|
+
if (models.length > 0) {
|
|
625
|
+
ok(`Found \x1B[1m${models.length}\x1B[0m models`);
|
|
626
|
+
setCachedModels(endpoint, models);
|
|
608
627
|
} else {
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
628
|
+
info("Could not fetch model list");
|
|
629
|
+
const cached = getCachedModels(endpoint);
|
|
630
|
+
if (cached && cached.length > 0) {
|
|
631
|
+
info(`Loaded \x1B[1m${cached.length}\x1B[0m models from cache`);
|
|
632
|
+
models = cached;
|
|
633
|
+
} else {
|
|
634
|
+
info("Using built-in model list");
|
|
635
|
+
models = FALLBACK_MODELS;
|
|
613
636
|
}
|
|
614
637
|
}
|
|
638
|
+
const model = await selectModel(models, "Select a model");
|
|
615
639
|
console.log();
|
|
616
640
|
info("Optional: model mappings for Haiku/Sonnet/Opus (Enter to skip)\n");
|
|
617
641
|
const haiku = await ask("Haiku model");
|
|
@@ -1032,17 +1056,17 @@ var BASH_COMPLETION = `_ccm_completions() {
|
|
|
1032
1056
|
complete -F _ccm_completions ccm`;
|
|
1033
1057
|
|
|
1034
1058
|
// src/session-data.ts
|
|
1035
|
-
import
|
|
1036
|
-
import
|
|
1059
|
+
import fs5 from "fs";
|
|
1060
|
+
import path5 from "path";
|
|
1037
1061
|
import os2 from "os";
|
|
1038
|
-
var CLAUDE_DIR =
|
|
1039
|
-
var HISTORY_FILE =
|
|
1040
|
-
var PROJECTS_DIR =
|
|
1041
|
-
var TRASH_DIR =
|
|
1062
|
+
var CLAUDE_DIR = path5.join(os2.homedir(), ".claude");
|
|
1063
|
+
var HISTORY_FILE = path5.join(CLAUDE_DIR, "history.jsonl");
|
|
1064
|
+
var PROJECTS_DIR = path5.join(CLAUDE_DIR, "projects");
|
|
1065
|
+
var TRASH_DIR = path5.join(os2.homedir(), ".ccm", "session-trash");
|
|
1042
1066
|
var TRASH_EXPIRE_DAYS = 30;
|
|
1043
1067
|
function readJsonl(filePath) {
|
|
1044
|
-
if (!
|
|
1045
|
-
const lines =
|
|
1068
|
+
if (!fs5.existsSync(filePath)) return [];
|
|
1069
|
+
const lines = fs5.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
1046
1070
|
const results = [];
|
|
1047
1071
|
for (const line of lines) {
|
|
1048
1072
|
try {
|
|
@@ -1054,8 +1078,8 @@ function readJsonl(filePath) {
|
|
|
1054
1078
|
}
|
|
1055
1079
|
function atomicWriteJsonl(filePath, lines) {
|
|
1056
1080
|
const tmp = filePath + ".tmp";
|
|
1057
|
-
|
|
1058
|
-
|
|
1081
|
+
fs5.writeFileSync(tmp, lines.join("\n"), "utf-8");
|
|
1082
|
+
fs5.renameSync(tmp, filePath);
|
|
1059
1083
|
}
|
|
1060
1084
|
function getHistoryEntries() {
|
|
1061
1085
|
const entries = readJsonl(HISTORY_FILE);
|
|
@@ -1093,11 +1117,11 @@ function getSessionsList() {
|
|
|
1093
1117
|
return sessions;
|
|
1094
1118
|
}
|
|
1095
1119
|
function findSessionJsonl(sessionId) {
|
|
1096
|
-
if (!
|
|
1097
|
-
const projectDirs =
|
|
1120
|
+
if (!fs5.existsSync(PROJECTS_DIR)) return null;
|
|
1121
|
+
const projectDirs = fs5.readdirSync(PROJECTS_DIR);
|
|
1098
1122
|
for (const dir of projectDirs) {
|
|
1099
|
-
const filePath =
|
|
1100
|
-
if (
|
|
1123
|
+
const filePath = path5.join(PROJECTS_DIR, dir, `${sessionId}.jsonl`);
|
|
1124
|
+
if (fs5.existsSync(filePath)) return filePath;
|
|
1101
1125
|
}
|
|
1102
1126
|
return null;
|
|
1103
1127
|
}
|
|
@@ -1166,11 +1190,11 @@ function getSessionTitle(sessionId) {
|
|
|
1166
1190
|
return null;
|
|
1167
1191
|
}
|
|
1168
1192
|
function ensureTrashDir() {
|
|
1169
|
-
|
|
1193
|
+
fs5.mkdirSync(TRASH_DIR, { recursive: true });
|
|
1170
1194
|
}
|
|
1171
1195
|
function extractHistoryForSession(sessionId) {
|
|
1172
|
-
if (!
|
|
1173
|
-
const lines =
|
|
1196
|
+
if (!fs5.existsSync(HISTORY_FILE)) return [];
|
|
1197
|
+
const lines = fs5.readFileSync(HISTORY_FILE, "utf-8").split("\n").filter(Boolean);
|
|
1174
1198
|
const matched = [];
|
|
1175
1199
|
for (const line of lines) {
|
|
1176
1200
|
try {
|
|
@@ -1182,8 +1206,8 @@ function extractHistoryForSession(sessionId) {
|
|
|
1182
1206
|
return matched;
|
|
1183
1207
|
}
|
|
1184
1208
|
function filterHistoryBySession(sessionId) {
|
|
1185
|
-
if (!
|
|
1186
|
-
const lines =
|
|
1209
|
+
if (!fs5.existsSync(HISTORY_FILE)) return;
|
|
1210
|
+
const lines = fs5.readFileSync(HISTORY_FILE, "utf-8").split("\n");
|
|
1187
1211
|
const filtered = lines.filter((line) => {
|
|
1188
1212
|
if (!line.trim()) return false;
|
|
1189
1213
|
try {
|
|
@@ -1201,15 +1225,15 @@ function deleteSession(sessionId) {
|
|
|
1201
1225
|
const filePath = findSessionJsonl(sessionId);
|
|
1202
1226
|
let originalProject = "";
|
|
1203
1227
|
if (filePath) {
|
|
1204
|
-
originalProject =
|
|
1205
|
-
const destJsonl =
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
const sessionDir =
|
|
1209
|
-
if (
|
|
1210
|
-
const destDir =
|
|
1211
|
-
|
|
1212
|
-
|
|
1228
|
+
originalProject = path5.basename(path5.dirname(filePath));
|
|
1229
|
+
const destJsonl = path5.join(TRASH_DIR, `${sessionId}.jsonl`);
|
|
1230
|
+
fs5.copyFileSync(filePath, destJsonl);
|
|
1231
|
+
fs5.unlinkSync(filePath);
|
|
1232
|
+
const sessionDir = path5.join(path5.dirname(filePath), sessionId);
|
|
1233
|
+
if (fs5.existsSync(sessionDir)) {
|
|
1234
|
+
const destDir = path5.join(TRASH_DIR, sessionId);
|
|
1235
|
+
fs5.cpSync(sessionDir, destDir, { recursive: true });
|
|
1236
|
+
fs5.rmSync(sessionDir, { recursive: true, force: true });
|
|
1213
1237
|
}
|
|
1214
1238
|
}
|
|
1215
1239
|
const meta = {
|
|
@@ -1218,8 +1242,8 @@ function deleteSession(sessionId) {
|
|
|
1218
1242
|
originalProject,
|
|
1219
1243
|
historyEntries
|
|
1220
1244
|
};
|
|
1221
|
-
|
|
1222
|
-
|
|
1245
|
+
fs5.writeFileSync(
|
|
1246
|
+
path5.join(TRASH_DIR, `${sessionId}.meta.json`),
|
|
1223
1247
|
JSON.stringify(meta, null, 2),
|
|
1224
1248
|
"utf-8"
|
|
1225
1249
|
);
|
|
@@ -1232,14 +1256,14 @@ function deleteAllSessions() {
|
|
|
1232
1256
|
const historyEntries = extractHistoryForSession(session.sessionId);
|
|
1233
1257
|
const filePath = findSessionJsonl(session.sessionId);
|
|
1234
1258
|
if (filePath) {
|
|
1235
|
-
const destJsonl =
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
const sessionDir =
|
|
1239
|
-
if (
|
|
1240
|
-
const destDir =
|
|
1241
|
-
|
|
1242
|
-
|
|
1259
|
+
const destJsonl = path5.join(TRASH_DIR, `${session.sessionId}.jsonl`);
|
|
1260
|
+
fs5.copyFileSync(filePath, destJsonl);
|
|
1261
|
+
fs5.unlinkSync(filePath);
|
|
1262
|
+
const sessionDir = path5.join(path5.dirname(filePath), session.sessionId);
|
|
1263
|
+
if (fs5.existsSync(sessionDir)) {
|
|
1264
|
+
const destDir = path5.join(TRASH_DIR, session.sessionId);
|
|
1265
|
+
fs5.cpSync(sessionDir, destDir, { recursive: true });
|
|
1266
|
+
fs5.rmSync(sessionDir, { recursive: true, force: true });
|
|
1243
1267
|
}
|
|
1244
1268
|
}
|
|
1245
1269
|
const meta = {
|
|
@@ -1248,68 +1272,68 @@ function deleteAllSessions() {
|
|
|
1248
1272
|
originalProject: session.projectName,
|
|
1249
1273
|
historyEntries
|
|
1250
1274
|
};
|
|
1251
|
-
|
|
1252
|
-
|
|
1275
|
+
fs5.writeFileSync(
|
|
1276
|
+
path5.join(TRASH_DIR, `${session.sessionId}.meta.json`),
|
|
1253
1277
|
JSON.stringify(meta, null, 2),
|
|
1254
1278
|
"utf-8"
|
|
1255
1279
|
);
|
|
1256
1280
|
}
|
|
1257
|
-
if (
|
|
1281
|
+
if (fs5.existsSync(HISTORY_FILE)) {
|
|
1258
1282
|
atomicWriteJsonl(HISTORY_FILE, []);
|
|
1259
1283
|
}
|
|
1260
1284
|
}
|
|
1261
1285
|
function restoreSession(sessionId) {
|
|
1262
|
-
const metaPath =
|
|
1263
|
-
if (!
|
|
1264
|
-
const meta = JSON.parse(
|
|
1286
|
+
const metaPath = path5.join(TRASH_DIR, `${sessionId}.meta.json`);
|
|
1287
|
+
if (!fs5.existsSync(metaPath)) return false;
|
|
1288
|
+
const meta = JSON.parse(fs5.readFileSync(metaPath, "utf-8"));
|
|
1265
1289
|
const destDir = findProjectDirForRestore(meta.originalProject);
|
|
1266
|
-
const trashJsonl =
|
|
1267
|
-
if (
|
|
1268
|
-
|
|
1269
|
-
|
|
1290
|
+
const trashJsonl = path5.join(TRASH_DIR, `${sessionId}.jsonl`);
|
|
1291
|
+
if (fs5.existsSync(trashJsonl) && destDir) {
|
|
1292
|
+
fs5.copyFileSync(trashJsonl, path5.join(destDir, `${sessionId}.jsonl`));
|
|
1293
|
+
fs5.unlinkSync(trashJsonl);
|
|
1270
1294
|
}
|
|
1271
|
-
const trashSessionDir =
|
|
1272
|
-
if (
|
|
1273
|
-
const restoredDir =
|
|
1274
|
-
|
|
1275
|
-
|
|
1295
|
+
const trashSessionDir = path5.join(TRASH_DIR, sessionId);
|
|
1296
|
+
if (fs5.existsSync(trashSessionDir) && destDir) {
|
|
1297
|
+
const restoredDir = path5.join(destDir, sessionId);
|
|
1298
|
+
fs5.cpSync(trashSessionDir, restoredDir, { recursive: true });
|
|
1299
|
+
fs5.rmSync(trashSessionDir, { recursive: true, force: true });
|
|
1276
1300
|
}
|
|
1277
1301
|
if (meta.historyEntries && meta.historyEntries.length > 0) {
|
|
1278
1302
|
const newLines = meta.historyEntries.map((e) => JSON.stringify(e));
|
|
1279
|
-
if (
|
|
1280
|
-
const existing =
|
|
1303
|
+
if (fs5.existsSync(HISTORY_FILE)) {
|
|
1304
|
+
const existing = fs5.readFileSync(HISTORY_FILE, "utf-8");
|
|
1281
1305
|
const combined = existing.trimEnd() + "\n" + newLines.join("\n") + "\n";
|
|
1282
1306
|
atomicWriteJsonl(HISTORY_FILE, combined.split("\n"));
|
|
1283
1307
|
} else {
|
|
1284
1308
|
atomicWriteJsonl(HISTORY_FILE, newLines);
|
|
1285
1309
|
}
|
|
1286
1310
|
}
|
|
1287
|
-
|
|
1311
|
+
fs5.unlinkSync(metaPath);
|
|
1288
1312
|
return true;
|
|
1289
1313
|
}
|
|
1290
1314
|
function findProjectDirForRestore(projectName) {
|
|
1291
|
-
if (!
|
|
1292
|
-
const dirs =
|
|
1315
|
+
if (!fs5.existsSync(PROJECTS_DIR)) return null;
|
|
1316
|
+
const dirs = fs5.readdirSync(PROJECTS_DIR);
|
|
1293
1317
|
for (const dir of dirs) {
|
|
1294
1318
|
if (dir.endsWith(projectName) || dir.includes(projectName)) {
|
|
1295
|
-
const fullPath =
|
|
1296
|
-
if (
|
|
1319
|
+
const fullPath = path5.join(PROJECTS_DIR, dir);
|
|
1320
|
+
if (fs5.statSync(fullPath).isDirectory()) return fullPath;
|
|
1297
1321
|
}
|
|
1298
1322
|
}
|
|
1299
1323
|
if (dirs.length > 0) {
|
|
1300
|
-
const first =
|
|
1301
|
-
if (
|
|
1324
|
+
const first = path5.join(PROJECTS_DIR, dirs[0]);
|
|
1325
|
+
if (fs5.statSync(first).isDirectory()) return first;
|
|
1302
1326
|
}
|
|
1303
1327
|
return null;
|
|
1304
1328
|
}
|
|
1305
1329
|
function getTrashSessions() {
|
|
1306
1330
|
ensureTrashDir();
|
|
1307
|
-
const files =
|
|
1331
|
+
const files = fs5.readdirSync(TRASH_DIR);
|
|
1308
1332
|
const metas = [];
|
|
1309
1333
|
for (const file of files) {
|
|
1310
1334
|
if (file.endsWith(".meta.json")) {
|
|
1311
1335
|
try {
|
|
1312
|
-
const meta = JSON.parse(
|
|
1336
|
+
const meta = JSON.parse(fs5.readFileSync(path5.join(TRASH_DIR, file), "utf-8"));
|
|
1313
1337
|
metas.push(meta);
|
|
1314
1338
|
} catch {
|
|
1315
1339
|
}
|
|
@@ -1320,13 +1344,13 @@ function getTrashSessions() {
|
|
|
1320
1344
|
}
|
|
1321
1345
|
function purgeTrash() {
|
|
1322
1346
|
ensureTrashDir();
|
|
1323
|
-
const files =
|
|
1347
|
+
const files = fs5.readdirSync(TRASH_DIR);
|
|
1324
1348
|
for (const file of files) {
|
|
1325
|
-
const fullPath =
|
|
1326
|
-
if (
|
|
1327
|
-
|
|
1349
|
+
const fullPath = path5.join(TRASH_DIR, file);
|
|
1350
|
+
if (fs5.statSync(fullPath).isDirectory()) {
|
|
1351
|
+
fs5.rmSync(fullPath, { recursive: true, force: true });
|
|
1328
1352
|
} else {
|
|
1329
|
-
|
|
1353
|
+
fs5.unlinkSync(fullPath);
|
|
1330
1354
|
}
|
|
1331
1355
|
}
|
|
1332
1356
|
}
|
|
@@ -1337,12 +1361,12 @@ function cleanupOldTrash() {
|
|
|
1337
1361
|
let cleaned = 0;
|
|
1338
1362
|
for (const meta of metas) {
|
|
1339
1363
|
if (meta.deletedAt < cutoff) {
|
|
1340
|
-
const jsonlPath =
|
|
1341
|
-
if (
|
|
1342
|
-
const sessionDir =
|
|
1343
|
-
if (
|
|
1344
|
-
const metaPath =
|
|
1345
|
-
if (
|
|
1364
|
+
const jsonlPath = path5.join(TRASH_DIR, `${meta.sessionId}.jsonl`);
|
|
1365
|
+
if (fs5.existsSync(jsonlPath)) fs5.unlinkSync(jsonlPath);
|
|
1366
|
+
const sessionDir = path5.join(TRASH_DIR, meta.sessionId);
|
|
1367
|
+
if (fs5.existsSync(sessionDir)) fs5.rmSync(sessionDir, { recursive: true, force: true });
|
|
1368
|
+
const metaPath = path5.join(TRASH_DIR, `${meta.sessionId}.meta.json`);
|
|
1369
|
+
if (fs5.existsSync(metaPath)) fs5.unlinkSync(metaPath);
|
|
1346
1370
|
cleaned++;
|
|
1347
1371
|
}
|
|
1348
1372
|
}
|