claude-relay 2.3.1 → 2.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/README.md +20 -5
- package/bin/cli.js +206 -8
- package/lib/cli-sessions.js +270 -0
- package/lib/daemon.js +40 -0
- package/lib/project.js +121 -1
- package/lib/public/app.js +385 -76
- package/lib/public/css/base.css +41 -7
- package/lib/public/css/diff.css +6 -6
- package/lib/public/css/filebrowser.css +34 -54
- package/lib/public/css/highlight.css +144 -0
- package/lib/public/css/input.css +9 -9
- package/lib/public/css/menus.css +82 -23
- package/lib/public/css/messages.css +178 -34
- package/lib/public/css/overlays.css +166 -50
- package/lib/public/css/rewind.css +17 -17
- package/lib/public/css/sidebar.css +210 -137
- package/lib/public/index.html +73 -40
- package/lib/public/modules/filebrowser.js +2 -1
- package/lib/public/modules/markdown.js +10 -10
- package/lib/public/modules/notifications.js +38 -1
- package/lib/public/modules/sidebar.js +109 -31
- package/lib/public/modules/terminal.js +11 -23
- package/lib/public/modules/theme.js +622 -0
- package/lib/public/modules/tools.js +245 -4
- package/lib/public/modules/utils.js +21 -5
- package/lib/public/style.css +1 -0
- package/lib/sdk-bridge.js +95 -0
- package/lib/server.js +41 -0
- package/lib/sessions.js +16 -3
- package/lib/themes/ayu-light.json +9 -0
- package/lib/themes/catppuccin-latte.json +9 -0
- package/lib/themes/catppuccin-mocha.json +9 -0
- package/lib/themes/claude-light.json +9 -0
- package/lib/themes/claude.json +9 -0
- package/lib/themes/dracula.json +9 -0
- package/lib/themes/everforest-light.json +9 -0
- package/lib/themes/everforest.json +9 -0
- package/lib/themes/github-light.json +9 -0
- package/lib/themes/gruvbox-dark.json +9 -0
- package/lib/themes/gruvbox-light.json +9 -0
- package/lib/themes/monokai.json +9 -0
- package/lib/themes/nord-light.json +9 -0
- package/lib/themes/nord.json +9 -0
- package/lib/themes/one-dark.json +9 -0
- package/lib/themes/one-light.json +9 -0
- package/lib/themes/rose-pine-dawn.json +9 -0
- package/lib/themes/rose-pine.json +9 -0
- package/lib/themes/solarized-dark.json +9 -0
- package/lib/themes/solarized-light.json +9 -0
- package/lib/themes/tokyo-night-light.json +9 -0
- package/lib/themes/tokyo-night.json +9 -0
- package/package.json +2 -1
package/lib/project.js
CHANGED
|
@@ -320,10 +320,52 @@ function createProjectContext(opts) {
|
|
|
320
320
|
|
|
321
321
|
if (msg.type === "resume_session") {
|
|
322
322
|
if (!msg.cliSessionId) return;
|
|
323
|
-
|
|
323
|
+
var cliSess = require("./cli-sessions");
|
|
324
|
+
cliSess.readCliSessionHistory(cwd, msg.cliSessionId).then(function (history) {
|
|
325
|
+
var title = "Resumed session";
|
|
326
|
+
for (var i = 0; i < history.length; i++) {
|
|
327
|
+
if (history[i].type === "user_message" && history[i].text) {
|
|
328
|
+
title = history[i].text.substring(0, 50);
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
sm.resumeSession(msg.cliSessionId, { history: history, title: title });
|
|
333
|
+
}).catch(function () {
|
|
334
|
+
sm.resumeSession(msg.cliSessionId);
|
|
335
|
+
});
|
|
324
336
|
return;
|
|
325
337
|
}
|
|
326
338
|
|
|
339
|
+
if (msg.type === "list_cli_sessions") {
|
|
340
|
+
var cliSessions = require("./cli-sessions");
|
|
341
|
+
var _fs = require("fs");
|
|
342
|
+
var _path = require("path");
|
|
343
|
+
// Collect session IDs already in relay (in-memory + persisted on disk)
|
|
344
|
+
var relayIds = {};
|
|
345
|
+
sm.sessions.forEach(function (s) {
|
|
346
|
+
if (s.cliSessionId) relayIds[s.cliSessionId] = true;
|
|
347
|
+
});
|
|
348
|
+
try {
|
|
349
|
+
var sessDir = _path.join(cwd, ".claude-relay", "sessions");
|
|
350
|
+
var diskFiles = _fs.readdirSync(sessDir);
|
|
351
|
+
for (var fi = 0; fi < diskFiles.length; fi++) {
|
|
352
|
+
if (diskFiles[fi].endsWith(".jsonl")) {
|
|
353
|
+
relayIds[diskFiles[fi].replace(".jsonl", "")] = true;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
} catch (e) {}
|
|
357
|
+
cliSessions.listCliSessions(cwd).then(function (sessions) {
|
|
358
|
+
var filtered = sessions.filter(function (s) {
|
|
359
|
+
return !relayIds[s.sessionId];
|
|
360
|
+
});
|
|
361
|
+
sendTo(ws, { type: "cli_session_list", sessions: filtered });
|
|
362
|
+
}).catch(function () {
|
|
363
|
+
sendTo(ws, { type: "cli_session_list", sessions: [] });
|
|
364
|
+
});
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
|
|
327
369
|
if (msg.type === "switch_session") {
|
|
328
370
|
if (msg.id && sm.sessions.has(msg.id)) {
|
|
329
371
|
sm.switchSession(msg.id);
|
|
@@ -550,6 +592,84 @@ function createProjectContext(opts) {
|
|
|
550
592
|
return;
|
|
551
593
|
}
|
|
552
594
|
|
|
595
|
+
// --- Browse directories (for add-project autocomplete) ---
|
|
596
|
+
if (msg.type === "browse_dir") {
|
|
597
|
+
var rawPath = (msg.path || "").replace(/^~/, process.env.HOME || "/");
|
|
598
|
+
var absTarget = path.resolve(rawPath);
|
|
599
|
+
var parentDir, prefix;
|
|
600
|
+
try {
|
|
601
|
+
var stat = fs.statSync(absTarget);
|
|
602
|
+
if (stat.isDirectory()) {
|
|
603
|
+
// Input is an existing directory — list its children
|
|
604
|
+
parentDir = absTarget;
|
|
605
|
+
prefix = "";
|
|
606
|
+
} else {
|
|
607
|
+
parentDir = path.dirname(absTarget);
|
|
608
|
+
prefix = path.basename(absTarget).toLowerCase();
|
|
609
|
+
}
|
|
610
|
+
} catch (e) {
|
|
611
|
+
// Path doesn't exist — list parent and filter by typed prefix
|
|
612
|
+
parentDir = path.dirname(absTarget);
|
|
613
|
+
prefix = path.basename(absTarget).toLowerCase();
|
|
614
|
+
}
|
|
615
|
+
try {
|
|
616
|
+
var dirItems = fs.readdirSync(parentDir, { withFileTypes: true });
|
|
617
|
+
var dirEntries = [];
|
|
618
|
+
for (var di = 0; di < dirItems.length; di++) {
|
|
619
|
+
var d = dirItems[di];
|
|
620
|
+
if (!d.isDirectory()) continue;
|
|
621
|
+
if (d.name.charAt(0) === ".") continue;
|
|
622
|
+
if (IGNORED_DIRS.has(d.name)) continue;
|
|
623
|
+
if (prefix && !d.name.toLowerCase().startsWith(prefix)) continue;
|
|
624
|
+
dirEntries.push({ name: d.name, path: path.join(parentDir, d.name) });
|
|
625
|
+
}
|
|
626
|
+
dirEntries.sort(function (a, b) { return a.name.localeCompare(b.name); });
|
|
627
|
+
sendTo(ws, { type: "browse_dir_result", path: msg.path, entries: dirEntries });
|
|
628
|
+
} catch (e) {
|
|
629
|
+
sendTo(ws, { type: "browse_dir_result", path: msg.path, entries: [], error: e.message });
|
|
630
|
+
}
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// --- Add project from web UI ---
|
|
635
|
+
if (msg.type === "add_project") {
|
|
636
|
+
var addPath = (msg.path || "").replace(/^~/, process.env.HOME || "/");
|
|
637
|
+
var addAbs = path.resolve(addPath);
|
|
638
|
+
try {
|
|
639
|
+
var addStat = fs.statSync(addAbs);
|
|
640
|
+
if (!addStat.isDirectory()) {
|
|
641
|
+
sendTo(ws, { type: "add_project_result", ok: false, error: "Not a directory" });
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
} catch (e) {
|
|
645
|
+
sendTo(ws, { type: "add_project_result", ok: false, error: "Directory not found" });
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
if (typeof opts.onAddProject === "function") {
|
|
649
|
+
var result = opts.onAddProject(addAbs);
|
|
650
|
+
sendTo(ws, { type: "add_project_result", ok: result.ok, slug: result.slug, error: result.error, existing: result.existing });
|
|
651
|
+
} else {
|
|
652
|
+
sendTo(ws, { type: "add_project_result", ok: false, error: "Not supported" });
|
|
653
|
+
}
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// --- Remove project from web UI ---
|
|
658
|
+
if (msg.type === "remove_project") {
|
|
659
|
+
var removeSlug = msg.slug;
|
|
660
|
+
if (!removeSlug) {
|
|
661
|
+
sendTo(ws, { type: "remove_project_result", ok: false, error: "Missing slug" });
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
if (typeof opts.onRemoveProject === "function") {
|
|
665
|
+
var removeResult = opts.onRemoveProject(removeSlug);
|
|
666
|
+
sendTo(ws, { type: "remove_project_result", ok: removeResult.ok, slug: removeSlug, error: removeResult.error });
|
|
667
|
+
} else {
|
|
668
|
+
sendTo(ws, { type: "remove_project_result", ok: false, error: "Not supported" });
|
|
669
|
+
}
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
|
|
553
673
|
// --- File browser ---
|
|
554
674
|
if (msg.type === "fs_list") {
|
|
555
675
|
var fsDir = safePath(cwd, msg.path || ".");
|