claude-home 1.8.0 → 1.8.3

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 CHANGED
@@ -53,7 +53,7 @@ Direct links (`#/note/filename`) let you open a specific note instantly.
53
53
  Visual overview of all your Claude projects with session count, token usage, cost, and memory files. Drill into any project to browse its sessions, memory entries, and `CLAUDE.md` files.
54
54
 
55
55
  ### Plans
56
- Read and search your GSD/planning files from `~/.claude/plans/`. Export or publish as a Gist with one click.
56
+ Read and search your GSD/planning files from `~/.claude/plans/` (or your configured config dir). Export or publish as a Gist with one click.
57
57
 
58
58
  ### Memory
59
59
  Inspect your auto-memory entries across all projects.
@@ -68,7 +68,7 @@ Read and edit your `CLAUDE.md` files (global and per-project). Inspect permissio
68
68
 
69
69
  ## No tokens. No cloud. No tracking.
70
70
 
71
- claude-home is a local Express server that reads your `~/.claude/` directory directly. It never calls the Claude API, never sends data anywhere, and works completely offline (except for the marketplace and Gist sharing features).
71
+ claude-home is a local Express server that reads your Claude config directory (`~/.claude/` by default) directly. It never calls the Claude API, never sends data anywhere, and works completely offline (except for the marketplace and Gist sharing features).
72
72
 
73
73
  ---
74
74
 
@@ -86,15 +86,6 @@ npm install -g claude-home
86
86
 
87
87
  > Requires Node.js 18+.
88
88
 
89
- ### From source
90
-
91
- ```bash
92
- git clone https://github.com/ZenekeZene/claude-home
93
- cd claude-home
94
- npm install
95
- npm start
96
- ```
97
-
98
89
  ---
99
90
 
100
91
  ## Usage
@@ -123,10 +114,12 @@ Or toggle it directly from the **Hooks** section in the UI.
123
114
  ```
124
115
  claude-home [options]
125
116
 
126
- --port, -p <n> Port to use (default: 3141)
127
- --no-open Don't open the browser automatically
128
- --version, -v Print version
129
- --help, -h Show help
117
+ --port, -p <n> Port to use (default: 3141)
118
+ --no-open Don't open the browser automatically
119
+ --config-dir <path> Claude config directory (default: ~/.claude)
120
+ Also: CLAUDE_CONFIG_DIR env var
121
+ --version, -v Print version
122
+ --help, -h Show help
130
123
 
131
124
  Commands:
132
125
  setup-hook Add SessionStart hook + /claude-home slash command
@@ -134,11 +127,28 @@ Commands:
134
127
  stop Stop the running claude-home server
135
128
  ```
136
129
 
130
+ ### Multiple Claude installations
131
+
132
+ If you use separate Claude Code configurations (e.g. `~/.claude` for personal and `~/.claude-work` for work), you can point claude-home at any of them:
133
+
134
+ ```bash
135
+ # Via flag
136
+ claude-home --config-dir ~/.claude-work
137
+
138
+ # Via environment variable
139
+ CLAUDE_CONFIG_DIR=~/.claude-work claude-home
140
+
141
+ # Install the auto-start hook into the work config
142
+ claude-home --config-dir ~/.claude-work setup-hook
143
+ ```
144
+
145
+ The dashboard will read sessions, settings, skills, commands, agents, and plans from the specified directory. The UI will reflect the correct paths throughout.
146
+
137
147
  ---
138
148
 
139
149
  ## Claude integration (Notes & Today)
140
150
 
141
- claude-home can receive content directly from Claude during active sessions. Go to **Config → Integrations** and click **Set up** — this adds instructions to your `~/.claude/CLAUDE.md` and grants the necessary write permissions automatically.
151
+ claude-home can receive content directly from Claude during active sessions. Go to **Config → Integrations** and click **Set up** — this adds instructions to your `CLAUDE.md` and grants the necessary write permissions automatically.
142
152
 
143
153
  Once set up, from any Claude session you can say:
144
154
  - *"Save this as a note"* → creates a note in the Notes view
@@ -157,7 +167,7 @@ Publish sessions or plans as public GitHub Gists. Go to **Config → Sharing**,
157
167
 
158
168
  claude-home includes a marketplace to discover and install skills from GitHub repositories.
159
169
 
160
- On first run it comes pre-configured with the [Anthropic Official skills repo](https://github.com/anthropics/skills). You can add your own sources (including private repos) by editing `~/.claude/claude-home/marketplace.json`:
170
+ On first run it comes pre-configured with the [Anthropic Official skills repo](https://github.com/anthropics/skills). You can add your own sources (including private repos) by editing `~/.claude/claude-home/marketplace.json` (or the equivalent in your configured config dir):
161
171
 
162
172
  ```json
163
173
  {
@@ -175,7 +185,7 @@ On first run it comes pre-configured with the [Anthropic Official skills repo](h
175
185
  }
176
186
  ```
177
187
 
178
- For private repos, set your token in `~/.claude/claude-home/.env`:
188
+ For private repos, set your token in `~/.claude/claude-home/.env` (or your config dir equivalent):
179
189
 
180
190
  ```
181
191
  GITHUB_TOKEN=ghp_your_token_here
package/bin/cli.js CHANGED
@@ -9,18 +9,7 @@ const os = require('os');
9
9
 
10
10
  const pkg = require('../package.json');
11
11
 
12
- // ─── Ensure data dir exists (always, before any subcommand) ──────────────────
13
- const DATA_DIR = path.join(os.homedir(), '.claude', 'claude-home');
14
- try {
15
- if (!fs.existsSync(DATA_DIR)) fs.mkdirSync(DATA_DIR, { recursive: true });
16
- const marketplaceDest = path.join(DATA_DIR, 'marketplace.json');
17
- if (!fs.existsSync(marketplaceDest)) {
18
- const defaultSrc = path.join(__dirname, '..', 'marketplace.default.json');
19
- if (fs.existsSync(defaultSrc)) fs.copyFileSync(defaultSrc, marketplaceDest);
20
- }
21
- } catch { /* ignore */ }
22
-
23
- // ─── Arg parsing ─────────────────────────────────────────────────────────────
12
+ // ─── Arg parsing (must happen before path derivation) ────────────────────────
24
13
 
25
14
  const args = process.argv.slice(2);
26
15
  const subcommand = args[0];
@@ -31,9 +20,25 @@ function getFlag(name, def) {
31
20
  return args[idx + 1];
32
21
  }
33
22
 
23
+ const configDirFlag = getFlag('--config-dir', '');
24
+ if (configDirFlag) process.env.CLAUDE_CONFIG_DIR = path.resolve(configDirFlag);
25
+
34
26
  const port = parseInt(getFlag('--port', getFlag('-p', process.env.PORT || 3141)), 10);
35
27
  const noOpen = args.includes('--no-open');
36
28
 
29
+ // ─── Config directory + data dir ─────────────────────────────────────────────
30
+ const CLAUDE_DIR = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude');
31
+ const DATA_DIR = path.join(CLAUDE_DIR, 'claude-home');
32
+
33
+ try {
34
+ if (!fs.existsSync(DATA_DIR)) fs.mkdirSync(DATA_DIR, { recursive: true });
35
+ const marketplaceDest = path.join(DATA_DIR, 'marketplace.json');
36
+ if (!fs.existsSync(marketplaceDest)) {
37
+ const defaultSrc = path.join(__dirname, '..', 'marketplace.default.json');
38
+ if (fs.existsSync(defaultSrc)) fs.copyFileSync(defaultSrc, marketplaceDest);
39
+ }
40
+ } catch { /* ignore */ }
41
+
37
42
  if (args.includes('--version') || args.includes('-v')) {
38
43
  console.log(pkg.version);
39
44
  process.exit(0);
@@ -48,10 +53,12 @@ if (args.includes('--help') || args.includes('-h')) {
48
53
  claude-home setup-hook
49
54
 
50
55
  Options:
51
- --port, -p <n> Port to use (default: 3141)
52
- --no-open Don't open the browser automatically
53
- --version, -v Print version
54
- --help, -h Show help
56
+ --port, -p <n> Port to use (default: 3141)
57
+ --no-open Don't open the browser automatically
58
+ --config-dir <path> Claude config directory (default: ~/.claude)
59
+ Also: CLAUDE_CONFIG_DIR env var
60
+ --version, -v Print version
61
+ --help, -h Show help
55
62
 
56
63
  Commands:
57
64
  setup-hook Add SessionStart hook and /claude-home slash command
@@ -102,7 +109,7 @@ promptSetupHookIfNeeded().then(() => {
102
109
  // ─── Update check ────────────────────────────────────────────────────────────
103
110
 
104
111
  function checkForUpdates() {
105
- const cacheFile = path.join(os.homedir(), '.claude', 'claude-home', '.update-check');
112
+ const cacheFile = path.join(DATA_DIR, '.update-check');
106
113
  const TTL = 24 * 60 * 60 * 1000; // 24h
107
114
 
108
115
  try {
@@ -149,8 +156,8 @@ function isPortFree(p) {
149
156
  }
150
157
 
151
158
  function promptSetupHookIfNeeded() {
152
- const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
153
- const sentinelPath = path.join(os.homedir(), '.claude', 'claude-home', '.hook-prompted');
159
+ const settingsPath = path.join(CLAUDE_DIR, 'settings.json');
160
+ const sentinelPath = path.join(DATA_DIR, '.hook-prompted');
154
161
 
155
162
  // Already prompted before, or hook already set up
156
163
  if (fs.existsSync(sentinelPath)) return Promise.resolve();
@@ -186,8 +193,8 @@ function openBrowser(url) {
186
193
  }
187
194
 
188
195
  function setupHook() {
189
- const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
190
- const commandsDir = path.join(os.homedir(), '.claude', 'commands');
196
+ const settingsPath = path.join(CLAUDE_DIR, 'settings.json');
197
+ const commandsDir = path.join(CLAUDE_DIR, 'commands');
191
198
  const commandPath = path.join(commandsDir, 'claude-home.md');
192
199
  const hookCommand = `lsof -ti:${port} >/dev/null 2>&1 || (claude-home --no-open &>/dev/null &)`;
193
200
 
@@ -235,9 +242,9 @@ function setupHook() {
235
242
  }
236
243
 
237
244
  function removeHook() {
238
- const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
239
- const commandPath = path.join(os.homedir(), '.claude', 'commands', 'claude-home.md');
240
- const sentinelPath = path.join(os.homedir(), '.claude', 'claude-home', '.hook-prompted');
245
+ const settingsPath = path.join(CLAUDE_DIR, 'settings.json');
246
+ const commandPath = path.join(CLAUDE_DIR, 'commands', 'claude-home.md');
247
+ const sentinelPath = path.join(DATA_DIR, '.hook-prompted');
241
248
 
242
249
  // Remove SessionStart hook
243
250
  let removed = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-home",
3
- "version": "1.8.0",
3
+ "version": "1.8.3",
4
4
  "description": "Web dashboard for Claude Code — browse sessions, manage skills, hooks, commands, and agents",
5
5
  "main": "server.js",
6
6
  "bin": {
@@ -14,7 +14,12 @@
14
14
  "README.md"
15
15
  ],
16
16
  "scripts": {
17
- "start": "node server.js"
17
+ "start": "node server.js",
18
+ "dev": "vite",
19
+ "build": "vite build",
20
+ "preview": "vite preview",
21
+ "test": "vitest run",
22
+ "test:watch": "vitest"
18
23
  },
19
24
  "engines": {
20
25
  "node": ">=18"
@@ -35,6 +40,20 @@
35
40
  "author": "ZenekeZene",
36
41
  "license": "MIT",
37
42
  "dependencies": {
38
- "express": "^4.18.2"
43
+ "@tanstack/react-query": "^5.96.2",
44
+ "express": "^4.18.2",
45
+ "highlight.js": "^11.11.1",
46
+ "marked": "^17.0.6",
47
+ "react": "^18.3.1",
48
+ "react-dom": "^18.3.1",
49
+ "react-router-dom": "^6.30.3"
50
+ },
51
+ "devDependencies": {
52
+ "@testing-library/jest-dom": "^6.9.1",
53
+ "@testing-library/react": "^16.3.2",
54
+ "@testing-library/user-event": "^14.6.1",
55
+ "@vitejs/plugin-react": "^6.0.1",
56
+ "jsdom": "^29.0.2",
57
+ "vitest": "^3.2.4"
39
58
  }
40
59
  }