claude-code-hub 0.37.0 → 0.39.0-rc.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 +110 -40
- package/lib/net-guard.js +20 -3
- package/package.json +7 -5
- package/public/app.js +206 -47
- package/public/index.html +131 -10
- package/public/locked.html +169 -0
- package/public/sw.js +12 -2
- package/server.js +367 -58
package/README.md
CHANGED
|
@@ -4,85 +4,155 @@
|
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://www.npmjs.com/package/claude-code-hub)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
One window for your Claude Code tools: Kanban, Marketplace, Cost, and Memory Diagnoser, in a single chromeless PWA that you drive from the keyboard.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Website: [nikiforovall.blog/claude-code-hub](https://nikiforovall.blog/claude-code-hub/)
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## The tools
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-

|
|
13
|
+
### Kanban
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-

|
|
15
|
+
See tasks, sessions, and live agent activity as a board. Open a Claude Code session in the embedded terminal.
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
<picture>
|
|
18
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/kanban-dark.webp">
|
|
19
|
+
<img alt="Kanban board with sessions and tasks" src="assets/kanban-light.webp">
|
|
20
|
+
</picture>
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
### Marketplace
|
|
23
|
+
|
|
24
|
+
Browse and manage Claude Code marketplace plugins.
|
|
25
|
+
|
|
26
|
+
<picture>
|
|
27
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/marketplace-dark.webp">
|
|
28
|
+
<img alt="Marketplace with the plugin list" src="assets/marketplace-light.webp">
|
|
29
|
+
</picture>
|
|
30
|
+
|
|
31
|
+
### Cost
|
|
32
|
+
|
|
33
|
+
See what your Claude Code usage costs, per session and per project.
|
|
34
|
+
|
|
35
|
+
<picture>
|
|
36
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/cost-dark.webp">
|
|
37
|
+
<img alt="Cost dashboard with usage charts" src="assets/cost-light.webp">
|
|
38
|
+
</picture>
|
|
39
|
+
|
|
40
|
+
### Memory Diagnoser
|
|
41
|
+
|
|
42
|
+
Explore the memory files that Claude Code loads for a project.
|
|
43
|
+
|
|
44
|
+
<picture>
|
|
45
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/memory-dark.webp">
|
|
46
|
+
<img alt="Memory Diagnoser with loaded memory files" src="assets/memory-light.webp">
|
|
47
|
+
</picture>
|
|
48
|
+
|
|
49
|
+
## Quick start
|
|
23
50
|
|
|
24
51
|
```bash
|
|
25
52
|
npx claude-code-hub --open
|
|
26
53
|
```
|
|
27
54
|
|
|
28
|
-
|
|
55
|
+
The hub starts on `http://localhost:3540` and opens the browser. To get a window with no browser UI, install the page as an app from the browser menu.
|
|
56
|
+
|
|
57
|
+
### From source
|
|
29
58
|
|
|
30
59
|
```bash
|
|
31
60
|
git clone --recurse-submodules https://github.com/NikiforovAll/claude-code-hub.git
|
|
32
61
|
cd claude-code-hub
|
|
33
|
-
npm install && npm install --prefix marketplace && npm install --prefix cck && npm install --prefix memory
|
|
62
|
+
npm install && npm install --prefix marketplace && npm install --prefix cck && npm install --prefix cost && npm install --prefix memory
|
|
34
63
|
npm start # http://localhost:3540
|
|
35
64
|
```
|
|
36
65
|
|
|
37
|
-
## Agent
|
|
66
|
+
## Agent observability (one-time setup)
|
|
38
67
|
|
|
39
|
-
For the full Kanban
|
|
68
|
+
For the full Kanban view (agent log, live subagent tracking, waiting-for-user indicators, and context window use), install the hooks:
|
|
40
69
|
|
|
41
70
|
```bash
|
|
42
71
|
npx claude-code-kanban --install
|
|
43
72
|
```
|
|
44
73
|
|
|
45
|
-
Without hooks you still get the task board, but no agent activity
|
|
74
|
+
Without the hooks you still get the task board and sessions, but no live agent activity. The hooks and status line are installed per Claude config dir, so run the command again for each dir you use. See the [Kanban docs](https://nikiforovall.blog/claude-code-kanban/) for details.
|
|
75
|
+
|
|
76
|
+
## Hub token
|
|
77
|
+
|
|
78
|
+
The hub page and its API need a token. Any local account can reach a loopback port, and the API carries the terminal token.
|
|
79
|
+
|
|
80
|
+
- The token is in `~/.claude-hub/token`. The hub creates it on the first run and keeps it across restarts.
|
|
81
|
+
- The startup banner prints the URL with the token, `http://localhost:3540/?token=…`, and `--open` uses that URL. The hub sets a cookie and then removes the token from the address bar, so later visits and the installed app need no token.
|
|
82
|
+
- Without the token, the page shows a locked screen.
|
|
83
|
+
- To change the token, delete the file and restart the hub.
|
|
46
84
|
|
|
47
|
-
##
|
|
85
|
+
## Config dirs
|
|
48
86
|
|
|
49
|
-
|
|
50
|
-
| ---------------- | ----------------------- |
|
|
51
|
-
| `Alt+1` | Switch to Kanban |
|
|
52
|
-
| `Alt+2` | Switch to Marketplace |
|
|
53
|
-
| `Alt+3` | Switch to Cost |
|
|
54
|
-
| `Alt+4` | Switch to Memory Diagnoser |
|
|
55
|
-
| `Ctrl+M` | Open Memory Diagnoser for current session (Kanban) |
|
|
56
|
-
| `Ctrl+Alt+Right` | Switch to next tool |
|
|
57
|
-
| `Ctrl+Alt+Left` | Switch to previous tool |
|
|
58
|
-
| `Ctrl+Alt+P` | Switch project |
|
|
59
|
-
| `Ctrl+Alt+W` | Switch Claude config dir (`CLAUDE_CONFIG_DIR`); restarts the sub-apps |
|
|
87
|
+
The hub can run the tools against more than one Claude config dir (`CLAUDE_CONFIG_DIR`), for example a work dir and a personal dir.
|
|
60
88
|
|
|
61
|
-
|
|
89
|
+
- Press <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>W</kbd> to open the config-dir palette. Pick a dir to switch to it, or type a path to add a new one. <kbd>Ctrl</kbd>+<kbd>D</kbd> removes the selected dir.
|
|
90
|
+
- Each dir gets its own set of the four tools. When you switch, the hub keeps the old set running, so switching back is instant. `--pool-size` sets how many sets stay alive (default 3). When the pool is full, the hub stops the least recently used set, but not a set whose Kanban has open terminals.
|
|
91
|
+
- The list and the active dir are saved in `~/.claude-hub/config.json`.
|
|
62
92
|
|
|
63
|
-
|
|
93
|
+
## Embedded terminal
|
|
64
94
|
|
|
65
|
-
|
|
95
|
+
Under the hub, Kanban has an embedded terminal, on by default, so you can start or resume Claude Code sessions from the board. While a terminal is attached, the hub asks before it closes the window, because <kbd>Ctrl</kbd>+<kbd>W</kbd> meant for the terminal would close it.
|
|
66
96
|
|
|
67
|
-
|
|
68
|
-
| ---------------------------------------------------------------------- | -------------- | ------------ |
|
|
69
|
-
| [Marketplace](https://github.com/NikiforovAll/claude-code-marketplace) | `marketplace/` | 3542 |
|
|
70
|
-
| [Kanban](https://github.com/NikiforovAll/claude-task-viewer) | `cck/` | 3541 |
|
|
71
|
-
| [Cost](https://github.com/NikiforovAll/claude-code-cost) | `cost/` | 3543 |
|
|
72
|
-
| [Memory Diagnoser](https://github.com/NikiforovAll/claude-code-memory) | `memory/` | 3544 |
|
|
97
|
+
To turn the terminal off, start the hub with `--disable-terminal`, or add this to `~/.claude-hub/config.json`:
|
|
73
98
|
|
|
74
|
-
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"terminal": { "enabled": false }
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Keyboard shortcuts
|
|
106
|
+
|
|
107
|
+
The hub has no visible UI of its own. Use these shortcuts:
|
|
108
|
+
|
|
109
|
+
| Shortcut | Action |
|
|
110
|
+
| --- | --- |
|
|
111
|
+
| <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>→</kbd> | Next tool |
|
|
112
|
+
| <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>←</kbd> | Previous tool |
|
|
113
|
+
| <kbd>Alt</kbd>+<kbd>1</kbd> | Kanban |
|
|
114
|
+
| <kbd>Alt</kbd>+<kbd>2</kbd> | Marketplace |
|
|
115
|
+
| <kbd>Alt</kbd>+<kbd>3</kbd> | Cost |
|
|
116
|
+
| <kbd>Alt</kbd>+<kbd>4</kbd> | Memory Diagnoser |
|
|
117
|
+
| <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>P</kbd> | Project palette: set the project for all tools |
|
|
118
|
+
| <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>W</kbd> | Config-dir palette: switch, add, or remove a config dir |
|
|
119
|
+
|
|
120
|
+
In a palette, use <kbd>↑</kbd>/<kbd>↓</kbd> or <kbd>Tab</kbd> to move, <kbd>Enter</kbd> to select, and <kbd>Esc</kbd> to close.
|
|
121
|
+
|
|
122
|
+
The shortcuts also work when focus is inside a tool. Kanban keeps <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>N</kbd> (new session), <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>R</kbd> (resume session), and <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>S</kbd> (previous session) for itself. From Kanban you can also jump to another tool for the selected session:
|
|
123
|
+
|
|
124
|
+
| Shortcut | Action |
|
|
125
|
+
| --- | --- |
|
|
126
|
+
| <kbd>M</kbd> | Open Marketplace for the session's project |
|
|
127
|
+
| <kbd>$</kbd> | Open Cost for the session |
|
|
128
|
+
| <kbd>Ctrl</kbd>+<kbd>M</kbd> | Open Memory Diagnoser for the session's project |
|
|
129
|
+
|
|
130
|
+
## CLI flags
|
|
75
131
|
|
|
76
132
|
```
|
|
77
133
|
--port <n> Hub port (default: 3540)
|
|
78
|
-
--marketplace-port <n> Marketplace port (default: 3542)
|
|
79
134
|
--kanban-port <n> Kanban port (default: 3541)
|
|
135
|
+
--marketplace-port <n> Marketplace port (default: 3542)
|
|
80
136
|
--cost-port <n> Cost port (default: 3543)
|
|
81
137
|
--memory-port <n> Memory Diagnoser port (default: 3544)
|
|
82
|
-
--pool-size <n> Config
|
|
83
|
-
--
|
|
138
|
+
--pool-size <n> Config-dir sets kept running after a switch (default: 3)
|
|
139
|
+
--disable-terminal Turn off the embedded terminal in Kanban
|
|
140
|
+
--host <addr> Bind address (default: 127.0.0.1)
|
|
141
|
+
--allowed-hosts <list> Extra host names to accept, comma-separated
|
|
142
|
+
--open Open the browser on start
|
|
84
143
|
```
|
|
85
144
|
|
|
145
|
+
If a port is busy, the hub uses a free port and reports it.
|
|
146
|
+
|
|
147
|
+
## Included tools
|
|
148
|
+
|
|
149
|
+
| Tool | Docs | Repo | Submodule | Default port |
|
|
150
|
+
| --- | --- | --- | --- | --- |
|
|
151
|
+
| Kanban | [Docs](https://nikiforovall.blog/claude-code-kanban/) | [claude-code-kanban](https://github.com/NikiforovAll/claude-code-kanban) | `cck/` | 3541 |
|
|
152
|
+
| Marketplace | [Docs](https://nikiforovall.blog/claude-code-marketplace/) | [claude-code-marketplace](https://github.com/NikiforovAll/claude-code-marketplace) | `marketplace/` | 3542 |
|
|
153
|
+
| Cost | [Docs](https://nikiforovall.blog/claude-code-cost/) | [claude-code-cost](https://github.com/NikiforovAll/claude-code-cost) | `cost/` | 3543 |
|
|
154
|
+
| Memory Diagnoser | [Docs](https://nikiforovall.blog/claude-code-memory/) | [claude-code-memory](https://github.com/NikiforovAll/claude-code-memory) | `memory/` | 3544 |
|
|
155
|
+
|
|
86
156
|
## License
|
|
87
157
|
|
|
88
158
|
MIT
|
package/lib/net-guard.js
CHANGED
|
@@ -181,6 +181,16 @@ function createNetGuard(config = {}) {
|
|
|
181
181
|
return next();
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
// For a WebSocket upgrade, which originGuard must not judge: the handshake is a
|
|
185
|
+
// GET, and WebSocket has no CORS, so any page can open one. Browsers always send
|
|
186
|
+
// Origin on the handshake, so a missing or `null` one is refused, not trusted.
|
|
187
|
+
// Returns null when allowed, or the reason it was refused.
|
|
188
|
+
function upgradeVerdict(req) {
|
|
189
|
+
if (!hostAllowed(parseHostHeader(req.headers.host))) return 'unrecognized Host header';
|
|
190
|
+
if (originVerdict(req.headers.origin) !== true) return 'cross-origin or missing Origin';
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
|
|
184
194
|
// Constant for the life of the process, and frameGuard runs ahead of
|
|
185
195
|
// express.static — so this is built once rather than per asset fetch.
|
|
186
196
|
//
|
|
@@ -229,12 +239,19 @@ function createNetGuard(config = {}) {
|
|
|
229
239
|
* @param {any} app express app (or any http request handler)
|
|
230
240
|
* @param {number} port 0 selects a free port
|
|
231
241
|
* @param {(port: number) => void} [onReady]
|
|
232
|
-
*
|
|
242
|
+
* `onUpgrade` is attached to both servers; a caller that attached it to the
|
|
243
|
+
* returned one alone would drop every WebSocket that arrives over the other family.
|
|
244
|
+
*
|
|
245
|
+
* @param {{maxHeaderSize?: number, onUpgrade?: (req: any, socket: any, head: Buffer) => void}} [opts]
|
|
233
246
|
*/
|
|
234
247
|
function listenLoopback(app, port, onReady, opts = {}) {
|
|
235
248
|
const http = require('http');
|
|
236
249
|
const serverOpts = opts.maxHeaderSize ? { maxHeaderSize: opts.maxHeaderSize } : {};
|
|
237
|
-
const makeServer = (handler) =>
|
|
250
|
+
const makeServer = (handler) => {
|
|
251
|
+
const s = http.createServer(serverOpts, handler);
|
|
252
|
+
if (opts.onUpgrade) s.on('upgrade', opts.onUpgrade);
|
|
253
|
+
return s;
|
|
254
|
+
};
|
|
238
255
|
const server = makeServer(app);
|
|
239
256
|
let secondary = null;
|
|
240
257
|
|
|
@@ -261,7 +278,7 @@ function createNetGuard(config = {}) {
|
|
|
261
278
|
return `WARNING: listening on ${BIND_HOST} - reachable from your network, with no authentication.`;
|
|
262
279
|
}
|
|
263
280
|
|
|
264
|
-
return { BIND_HOST, ALLOWED_HOSTS, hostGuard, originGuard, frameGuard, listenLoopback, exposureWarning };
|
|
281
|
+
return { BIND_HOST, ALLOWED_HOSTS, EXPOSED, hostGuard, originGuard, upgradeVerdict, frameGuard, listenLoopback, exposureWarning };
|
|
265
282
|
}
|
|
266
283
|
|
|
267
284
|
module.exports = { createNetGuard, parseHostHeader, isLoopbackAddress };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-hub",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.0-rc.1",
|
|
4
4
|
"description": "Unified hub for Claude Code tools — Marketplace + Kanban in one PWA",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"bin": {
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"start": "node server.js",
|
|
11
11
|
"dev": "node server.js --open",
|
|
12
|
+
"update": "bash scripts/update-submodules.sh",
|
|
13
|
+
"update:check": "bash scripts/update-submodules.sh --check",
|
|
12
14
|
"lint": "npx @biomejs/biome check public/app.js server.js && npm run check:escaping && npm run check:security-lib",
|
|
13
15
|
"lint:fix": "npx @biomejs/biome check --fix public/app.js server.js",
|
|
14
16
|
"prepare": "husky",
|
|
@@ -37,10 +39,10 @@
|
|
|
37
39
|
},
|
|
38
40
|
"homepage": "https://github.com/NikiforovAll/claude-code-hub#readme",
|
|
39
41
|
"dependencies": {
|
|
40
|
-
"claude-code-cost": "^0.
|
|
41
|
-
"claude-code-kanban": "^4.
|
|
42
|
-
"claude-code-marketplace": "^0.
|
|
43
|
-
"claude-code-memory-explorer": "^0.
|
|
42
|
+
"claude-code-cost": "^0.24.0-rc.1",
|
|
43
|
+
"claude-code-kanban": "^4.28.0-rc.1",
|
|
44
|
+
"claude-code-marketplace": "^0.20.0-rc.1",
|
|
45
|
+
"claude-code-memory-explorer": "^0.15.0-rc.1",
|
|
44
46
|
"express": "^4.21.0",
|
|
45
47
|
"open": "^10.1.0"
|
|
46
48
|
},
|