@teddysc/claude-run 0.13.0 → 0.14.1
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/README.md +7 -0
- package/dist/index.js +75 -2
- package/dist/web/assets/{index-Bz7pnCx9.js → index-CfXKVwHJ.js} +73 -68
- package/dist/web/index.html +1 -1
- package/package.json +3 -2
- package/spec.md +274 -0
package/README.md
CHANGED
|
@@ -36,6 +36,13 @@ See [spec.md](spec.md)
|
|
|
36
36
|
|
|
37
37
|
## Changelog
|
|
38
38
|
|
|
39
|
+
### 0.14.1
|
|
40
|
+
- Include spec.md in npm package files
|
|
41
|
+
|
|
42
|
+
### 0.14.0
|
|
43
|
+
- Add session deletion preview endpoint to see what files will be removed
|
|
44
|
+
- Enhance session deletion to remove related files and directories from disk
|
|
45
|
+
|
|
39
46
|
### 0.13.0
|
|
40
47
|
- Display message count, duration, and JSONL size in conversation header
|
|
41
48
|
- Sidebar shows compact message count, duration, and JSONL size per session
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { streamSSE } from "hono/streaming";
|
|
|
11
11
|
import { serve } from "@hono/node-server";
|
|
12
12
|
|
|
13
13
|
// api/storage.ts
|
|
14
|
-
import { readdir, readFile, stat, open, unlink, writeFile } from "fs/promises";
|
|
14
|
+
import { readdir, readFile, stat, open, unlink, writeFile, rm } from "fs/promises";
|
|
15
15
|
import { createReadStream } from "fs";
|
|
16
16
|
import { join, basename } from "path";
|
|
17
17
|
import { homedir } from "os";
|
|
@@ -480,10 +480,34 @@ async function getSessionsMetadata(ids) {
|
|
|
480
480
|
}))
|
|
481
481
|
);
|
|
482
482
|
}
|
|
483
|
+
async function getSessionDeletionPaths(sessionId) {
|
|
484
|
+
const relatedPaths = /* @__PURE__ */ new Set();
|
|
485
|
+
const filePath = await findSessionFile(sessionId);
|
|
486
|
+
if (filePath) {
|
|
487
|
+
relatedPaths.add(filePath);
|
|
488
|
+
relatedPaths.add(filePath.replace(/\.jsonl$/, ""));
|
|
489
|
+
}
|
|
490
|
+
const relatedRoots = ["session-env", "todos", "file-history", "debug"];
|
|
491
|
+
for (const root of relatedRoots) {
|
|
492
|
+
const rootPath = join(claudeDir, root);
|
|
493
|
+
try {
|
|
494
|
+
const entries = await readdir(rootPath);
|
|
495
|
+
for (const entry of entries) {
|
|
496
|
+
if (!entry.includes(sessionId)) {
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
relatedPaths.add(join(rootPath, entry));
|
|
500
|
+
}
|
|
501
|
+
} catch {
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
return [...relatedPaths].sort();
|
|
505
|
+
}
|
|
483
506
|
async function deleteSession(sessionId) {
|
|
484
507
|
console.log(`[deleteSession] Attempting to delete: ${sessionId}`);
|
|
485
508
|
const filePath = await findSessionFile(sessionId);
|
|
486
509
|
let fileDeleted = false;
|
|
510
|
+
let relatedDeleted = false;
|
|
487
511
|
if (filePath) {
|
|
488
512
|
console.log(`[deleteSession] Found file: ${filePath}`);
|
|
489
513
|
try {
|
|
@@ -502,6 +526,33 @@ async function deleteSession(sessionId) {
|
|
|
502
526
|
} else {
|
|
503
527
|
console.log(`[deleteSession] No file found for session: ${sessionId}`);
|
|
504
528
|
}
|
|
529
|
+
const relatedPaths = /* @__PURE__ */ new Set();
|
|
530
|
+
if (filePath) {
|
|
531
|
+
relatedPaths.add(filePath.replace(/\.jsonl$/, ""));
|
|
532
|
+
}
|
|
533
|
+
const relatedRoots = ["session-env", "todos", "file-history", "debug"];
|
|
534
|
+
for (const root of relatedRoots) {
|
|
535
|
+
const rootPath = join(claudeDir, root);
|
|
536
|
+
try {
|
|
537
|
+
const entries = await readdir(rootPath);
|
|
538
|
+
for (const entry of entries) {
|
|
539
|
+
if (!entry.includes(sessionId)) {
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
relatedPaths.add(join(rootPath, entry));
|
|
543
|
+
}
|
|
544
|
+
} catch {
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
for (const relatedPath of relatedPaths) {
|
|
548
|
+
try {
|
|
549
|
+
await rm(relatedPath, { recursive: true, force: true });
|
|
550
|
+
console.log(`[deleteSession] Deleted related: ${relatedPath}`);
|
|
551
|
+
relatedDeleted = true;
|
|
552
|
+
} catch (err) {
|
|
553
|
+
console.error(`[deleteSession] Failed to delete related ${relatedPath}:`, err);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
505
556
|
fileIndex.delete(sessionId);
|
|
506
557
|
summaryCache.delete(sessionId);
|
|
507
558
|
sessionStatsCache.delete(sessionId);
|
|
@@ -539,7 +590,7 @@ async function deleteSession(sessionId) {
|
|
|
539
590
|
} catch (err) {
|
|
540
591
|
console.error(`[deleteSession] Failed to update history.jsonl for ${sessionId}:`, err);
|
|
541
592
|
}
|
|
542
|
-
return fileDeleted || historyChanged;
|
|
593
|
+
return fileDeleted || historyChanged || relatedDeleted;
|
|
543
594
|
}
|
|
544
595
|
async function getSessionFilePath(sessionId) {
|
|
545
596
|
return findSessionFile(sessionId);
|
|
@@ -988,6 +1039,28 @@ function createServer(options) {
|
|
|
988
1039
|
console.log(`[/api/sessions/delete] Failed:`, failed);
|
|
989
1040
|
return c.json({ deleted, failed });
|
|
990
1041
|
});
|
|
1042
|
+
app.post("/api/sessions/delete/preview", async (c) => {
|
|
1043
|
+
let body;
|
|
1044
|
+
try {
|
|
1045
|
+
body = await c.req.json();
|
|
1046
|
+
} catch {
|
|
1047
|
+
return c.json({ error: "Invalid JSON body" }, 400);
|
|
1048
|
+
}
|
|
1049
|
+
if (!body || !Array.isArray(body.ids)) {
|
|
1050
|
+
return c.json({ error: "Missing ids" }, 400);
|
|
1051
|
+
}
|
|
1052
|
+
const paths = /* @__PURE__ */ new Set();
|
|
1053
|
+
for (const id of body.ids) {
|
|
1054
|
+
if (typeof id !== "string" || !id) {
|
|
1055
|
+
continue;
|
|
1056
|
+
}
|
|
1057
|
+
const entries = await getSessionDeletionPaths(id);
|
|
1058
|
+
for (const entry of entries) {
|
|
1059
|
+
paths.add(entry);
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
return c.json({ paths: [...paths].sort() });
|
|
1063
|
+
});
|
|
991
1064
|
app.post("/api/sessions/rename", async (c) => {
|
|
992
1065
|
let body;
|
|
993
1066
|
try {
|