claude-relay 2.2.0 → 2.2.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 +4 -0
- package/bin/cli.js +104 -0
- package/lib/public/app.js +1 -0
- package/lib/public/css/messages.css +15 -0
- package/lib/public/modules/tools.js +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -185,6 +185,10 @@ npx claude-relay -p 8080 # Specify port
|
|
|
185
185
|
npx claude-relay --no-https # Disable HTTPS
|
|
186
186
|
npx claude-relay --no-update # Skip update check
|
|
187
187
|
npx claude-relay --debug # Enable debug panel
|
|
188
|
+
npx claude-relay --add . # Add current directory to running daemon
|
|
189
|
+
npx claude-relay --add /path # Add a project by path
|
|
190
|
+
npx claude-relay --remove . # Remove a project
|
|
191
|
+
npx claude-relay --list # List registered projects
|
|
188
192
|
```
|
|
189
193
|
|
|
190
194
|
## Requirements
|
package/bin/cli.js
CHANGED
|
@@ -18,6 +18,9 @@ var debugMode = false;
|
|
|
18
18
|
var autoYes = false;
|
|
19
19
|
var cliPin = null;
|
|
20
20
|
var shutdownMode = false;
|
|
21
|
+
var addPath = null;
|
|
22
|
+
var removePath = null;
|
|
23
|
+
var listMode = false;
|
|
21
24
|
|
|
22
25
|
for (var i = 0; i < args.length; i++) {
|
|
23
26
|
if (args[i] === "-p" || args[i] === "--port") {
|
|
@@ -40,8 +43,19 @@ for (var i = 0; i < args.length; i++) {
|
|
|
40
43
|
i++;
|
|
41
44
|
} else if (args[i] === "--shutdown") {
|
|
42
45
|
shutdownMode = true;
|
|
46
|
+
} else if (args[i] === "--add") {
|
|
47
|
+
addPath = args[i + 1] || ".";
|
|
48
|
+
i++;
|
|
49
|
+
} else if (args[i] === "--remove") {
|
|
50
|
+
removePath = args[i + 1] || null;
|
|
51
|
+
i++;
|
|
52
|
+
} else if (args[i] === "--list") {
|
|
53
|
+
listMode = true;
|
|
43
54
|
} else if (args[i] === "-h" || args[i] === "--help") {
|
|
44
55
|
console.log("Usage: claude-relay [-p|--port <port>] [--no-https] [--no-update] [--debug] [-y|--yes] [--pin <pin>] [--shutdown]");
|
|
56
|
+
console.log(" claude-relay --add <path> Add a project to the running daemon");
|
|
57
|
+
console.log(" claude-relay --remove <path> Remove a project from the running daemon");
|
|
58
|
+
console.log(" claude-relay --list List registered projects");
|
|
45
59
|
console.log("");
|
|
46
60
|
console.log("Options:");
|
|
47
61
|
console.log(" -p, --port <port> Port to listen on (default: 2633)");
|
|
@@ -51,6 +65,9 @@ for (var i = 0; i < args.length; i++) {
|
|
|
51
65
|
console.log(" -y, --yes Skip interactive prompts (accept defaults)");
|
|
52
66
|
console.log(" --pin <pin> Set 6-digit PIN (use with --yes)");
|
|
53
67
|
console.log(" --shutdown Shut down the running relay daemon");
|
|
68
|
+
console.log(" --add <path> Add a project directory (use '.' for current)");
|
|
69
|
+
console.log(" --remove <path> Remove a project directory");
|
|
70
|
+
console.log(" --list List all registered projects");
|
|
54
71
|
process.exit(0);
|
|
55
72
|
}
|
|
56
73
|
}
|
|
@@ -75,6 +92,93 @@ if (shutdownMode) {
|
|
|
75
92
|
return;
|
|
76
93
|
}
|
|
77
94
|
|
|
95
|
+
// --- Handle --add before anything else ---
|
|
96
|
+
if (addPath !== null) {
|
|
97
|
+
var absAdd = path.resolve(addPath);
|
|
98
|
+
try {
|
|
99
|
+
var stat = fs.statSync(absAdd);
|
|
100
|
+
if (!stat.isDirectory()) {
|
|
101
|
+
console.error("Not a directory: " + absAdd);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
} catch (e) {
|
|
105
|
+
console.error("Directory not found: " + absAdd);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
var addConfig = loadConfig();
|
|
109
|
+
isDaemonAliveAsync(addConfig).then(function (alive) {
|
|
110
|
+
if (!alive) {
|
|
111
|
+
console.error("No running daemon. Start with: npx claude-relay");
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
sendIPCCommand(socketPath(), { cmd: "add_project", path: absAdd }).then(function (res) {
|
|
115
|
+
if (res.ok) {
|
|
116
|
+
if (res.existing) {
|
|
117
|
+
console.log("Already registered: " + res.slug);
|
|
118
|
+
} else {
|
|
119
|
+
console.log("Added: " + res.slug + " \u2192 " + absAdd);
|
|
120
|
+
}
|
|
121
|
+
process.exit(0);
|
|
122
|
+
} else {
|
|
123
|
+
console.error("Failed: " + (res.error || "unknown error"));
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// --- Handle --remove before anything else ---
|
|
132
|
+
if (removePath !== null) {
|
|
133
|
+
var absRemove = path.resolve(removePath);
|
|
134
|
+
var removeConfig = loadConfig();
|
|
135
|
+
isDaemonAliveAsync(removeConfig).then(function (alive) {
|
|
136
|
+
if (!alive) {
|
|
137
|
+
console.error("No running daemon. Start with: npx claude-relay");
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
sendIPCCommand(socketPath(), { cmd: "remove_project", path: absRemove }).then(function (res) {
|
|
141
|
+
if (res.ok) {
|
|
142
|
+
console.log("Removed: " + path.basename(absRemove));
|
|
143
|
+
process.exit(0);
|
|
144
|
+
} else {
|
|
145
|
+
console.error("Failed: " + (res.error || "project not found"));
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// --- Handle --list before anything else ---
|
|
154
|
+
if (listMode) {
|
|
155
|
+
var listConfig = loadConfig();
|
|
156
|
+
isDaemonAliveAsync(listConfig).then(function (alive) {
|
|
157
|
+
if (!alive) {
|
|
158
|
+
console.error("No running daemon. Start with: npx claude-relay");
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
sendIPCCommand(socketPath(), { cmd: "get_status" }).then(function (res) {
|
|
162
|
+
if (!res.ok || !res.projects || res.projects.length === 0) {
|
|
163
|
+
console.log("No projects registered.");
|
|
164
|
+
process.exit(0);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
console.log("Projects (" + res.projects.length + "):\n");
|
|
168
|
+
for (var p = 0; p < res.projects.length; p++) {
|
|
169
|
+
var proj = res.projects[p];
|
|
170
|
+
var label = " " + proj.slug;
|
|
171
|
+
if (proj.title) label += " (" + proj.title + ")";
|
|
172
|
+
label += "\n " + proj.path;
|
|
173
|
+
console.log(label);
|
|
174
|
+
}
|
|
175
|
+
console.log("");
|
|
176
|
+
process.exit(0);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
78
182
|
var cwd = process.cwd();
|
|
79
183
|
|
|
80
184
|
// --- ANSI helpers ---
|
package/lib/public/app.js
CHANGED
|
@@ -1623,6 +1623,7 @@ import { initTools, resetToolState, saveToolState, restoreToolState, renderAskUs
|
|
|
1623
1623
|
sessionListEl: sessionListEl,
|
|
1624
1624
|
scrollToBottom: scrollToBottom,
|
|
1625
1625
|
basePath: basePath,
|
|
1626
|
+
toggleUsagePanel: toggleUsagePanel,
|
|
1626
1627
|
});
|
|
1627
1628
|
|
|
1628
1629
|
// --- QR code ---
|
|
@@ -46,6 +46,21 @@
|
|
|
46
46
|
#todo-sticky .todo-sticky-chevron { display: inline-flex; color: var(--text-muted); transition: transform 0.2s; }
|
|
47
47
|
#todo-sticky .todo-sticky-chevron .lucide { width: 12px; height: 12px; }
|
|
48
48
|
#todo-sticky.collapsed .todo-sticky-chevron { transform: rotate(-90deg); }
|
|
49
|
+
#todo-sticky .todo-sticky-active { display: none; }
|
|
50
|
+
#todo-sticky.collapsed .todo-sticky-active {
|
|
51
|
+
display: inline-flex;
|
|
52
|
+
align-items: center;
|
|
53
|
+
gap: 4px;
|
|
54
|
+
flex: 1;
|
|
55
|
+
min-width: 0;
|
|
56
|
+
font-size: 11px;
|
|
57
|
+
color: var(--text-secondary);
|
|
58
|
+
overflow: hidden;
|
|
59
|
+
text-overflow: ellipsis;
|
|
60
|
+
white-space: nowrap;
|
|
61
|
+
}
|
|
62
|
+
#todo-sticky.collapsed .todo-sticky-active .lucide { width: 12px; height: 12px; color: var(--accent); flex-shrink: 0; }
|
|
63
|
+
#todo-sticky.collapsed .todo-sticky-title { flex: none; }
|
|
49
64
|
|
|
50
65
|
#todo-sticky .todo-sticky-progress { height: 2px; background: var(--border); }
|
|
51
66
|
#todo-sticky .todo-sticky-progress-bar { height: 100%; background: var(--success); transition: width 0.3s ease; }
|
|
@@ -693,10 +693,16 @@ function updateTodoSticky() {
|
|
|
693
693
|
var pct = Math.round(completed / todoItems.length * 100);
|
|
694
694
|
var wasCollapsed = stickyEl.classList.contains("collapsed");
|
|
695
695
|
|
|
696
|
+
var inProgressItem = null;
|
|
697
|
+
for (var j = 0; j < todoItems.length; j++) {
|
|
698
|
+
if (todoItems[j].status === "in_progress") { inProgressItem = todoItems[j]; break; }
|
|
699
|
+
}
|
|
700
|
+
|
|
696
701
|
var html = '<div class="todo-sticky-inner">' +
|
|
697
702
|
'<div class="todo-sticky-header">' +
|
|
698
703
|
'<span class="todo-sticky-icon">' + iconHtml("list-checks") + '</span>' +
|
|
699
704
|
'<span class="todo-sticky-title">Tasks</span>' +
|
|
705
|
+
(inProgressItem ? '<span class="todo-sticky-active">' + iconHtml("loader", "icon-spin") + ' ' + escapeHtml(inProgressItem.activeForm || inProgressItem.content) + '</span>' : '') +
|
|
700
706
|
'<span class="todo-sticky-count">' + completed + '/' + todoItems.length + '</span>' +
|
|
701
707
|
'<span class="todo-sticky-chevron">' + iconHtml("chevron-down") + '</span>' +
|
|
702
708
|
'</div>' +
|