claude-home 1.1.1 → 1.2.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 +7 -3
- package/bin/cli.js +80 -10
- package/package.json +1 -1
- package/public/index.html +37 -0
package/README.md
CHANGED
|
@@ -62,13 +62,16 @@ Opens `http://localhost:3141` in your browser automatically.
|
|
|
62
62
|
|
|
63
63
|
### Auto-launch on every Claude session
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
On first run, claude-home will ask if you want to register a hook that starts the dashboard automatically whenever Claude Code opens. You can also manage this anytime:
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
-
claude-home setup-hook
|
|
68
|
+
claude-home setup-hook # enable auto-start
|
|
69
|
+
claude-home remove-hook # disable auto-start
|
|
69
70
|
```
|
|
70
71
|
|
|
71
|
-
|
|
72
|
+
Or toggle it directly from the **Hooks** section in the UI.
|
|
73
|
+
|
|
74
|
+
`setup-hook` also creates a `/claude-home` slash command so you can trigger it from any Claude session.
|
|
72
75
|
|
|
73
76
|
### CLI flags
|
|
74
77
|
|
|
@@ -82,6 +85,7 @@ claude-home [options]
|
|
|
82
85
|
|
|
83
86
|
Commands:
|
|
84
87
|
setup-hook Add SessionStart hook + /claude-home slash command
|
|
88
|
+
remove-hook Remove SessionStart hook + /claude-home slash command
|
|
85
89
|
```
|
|
86
90
|
|
|
87
91
|
---
|
package/bin/cli.js
CHANGED
|
@@ -44,29 +44,36 @@ if (args.includes('--help') || args.includes('-h')) {
|
|
|
44
44
|
|
|
45
45
|
Commands:
|
|
46
46
|
setup-hook Add SessionStart hook and /claude-home slash command
|
|
47
|
+
remove-hook Remove SessionStart hook and /claude-home slash command
|
|
47
48
|
`);
|
|
48
49
|
process.exit(0);
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
// ─── Setup-hook
|
|
52
|
+
// ─── Setup-hook / remove-hook subcommands ────────────────────────────────────
|
|
52
53
|
|
|
53
54
|
if (subcommand === 'setup-hook') {
|
|
54
55
|
setupHook();
|
|
55
56
|
process.exit(0);
|
|
56
57
|
}
|
|
57
58
|
|
|
59
|
+
if (subcommand === 'remove-hook') {
|
|
60
|
+
removeHook();
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
63
|
+
|
|
58
64
|
// ─── Main: start server or reuse existing ────────────────────────────────────
|
|
59
65
|
|
|
60
66
|
checkForUpdates(); // async, non-blocking
|
|
61
|
-
|
|
62
|
-
isPortFree(port).then(free => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
promptSetupHookIfNeeded().then(() => {
|
|
68
|
+
isPortFree(port).then(free => {
|
|
69
|
+
if (free) {
|
|
70
|
+
const { startServer } = require('../server.js');
|
|
71
|
+
startServer(port);
|
|
72
|
+
} else {
|
|
73
|
+
console.log(`claude-home already running at http://localhost:${port}`);
|
|
74
|
+
}
|
|
75
|
+
if (!noOpen) openBrowser(`http://localhost:${port}`);
|
|
76
|
+
});
|
|
70
77
|
});
|
|
71
78
|
|
|
72
79
|
// ─── Update check ────────────────────────────────────────────────────────────
|
|
@@ -118,6 +125,34 @@ function isPortFree(p) {
|
|
|
118
125
|
});
|
|
119
126
|
}
|
|
120
127
|
|
|
128
|
+
function promptSetupHookIfNeeded() {
|
|
129
|
+
const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
|
|
130
|
+
const sentinelPath = path.join(os.homedir(), '.claude', 'claude-home', '.hook-prompted');
|
|
131
|
+
|
|
132
|
+
// Already prompted before, or hook already set up
|
|
133
|
+
if (fs.existsSync(sentinelPath)) return Promise.resolve();
|
|
134
|
+
try {
|
|
135
|
+
const s = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
136
|
+
const already = s.hooks?.SessionStart?.some(e => e.hooks?.some(h => h.command?.includes('claude-home')));
|
|
137
|
+
if (already) { fs.writeFileSync(sentinelPath, '1'); return Promise.resolve(); }
|
|
138
|
+
} catch { /* settings.json may not exist */ }
|
|
139
|
+
|
|
140
|
+
return new Promise(resolve => {
|
|
141
|
+
process.stdout.write('\n Auto-start claude-home when Claude Code opens? (y/n) ');
|
|
142
|
+
process.stdin.setEncoding('utf8');
|
|
143
|
+
process.stdin.once('data', d => {
|
|
144
|
+
process.stdin.pause();
|
|
145
|
+
if (d.trim().toLowerCase() === 'y') {
|
|
146
|
+
setupHook();
|
|
147
|
+
} else {
|
|
148
|
+
console.log(' Skipped. Run `claude-home setup-hook` anytime to enable it.\n');
|
|
149
|
+
}
|
|
150
|
+
fs.writeFileSync(sentinelPath, '1');
|
|
151
|
+
resolve();
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
121
156
|
function openBrowser(url) {
|
|
122
157
|
const cmd = process.platform === 'darwin' ? `open "${url}"`
|
|
123
158
|
: process.platform === 'win32' ? `start "" "${url}"`
|
|
@@ -175,3 +210,38 @@ function setupHook() {
|
|
|
175
210
|
|
|
176
211
|
console.log('\nDone! Restart Claude Code for the hook to take effect.');
|
|
177
212
|
}
|
|
213
|
+
|
|
214
|
+
function removeHook() {
|
|
215
|
+
const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
|
|
216
|
+
const commandPath = path.join(os.homedir(), '.claude', 'commands', 'claude-home.md');
|
|
217
|
+
const sentinelPath = path.join(os.homedir(), '.claude', 'claude-home', '.hook-prompted');
|
|
218
|
+
|
|
219
|
+
// Remove SessionStart hook
|
|
220
|
+
let removed = false;
|
|
221
|
+
try {
|
|
222
|
+
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
223
|
+
if (settings.hooks?.SessionStart) {
|
|
224
|
+
const before = settings.hooks.SessionStart.length;
|
|
225
|
+
settings.hooks.SessionStart = settings.hooks.SessionStart.filter(
|
|
226
|
+
e => !e.hooks?.some(h => h.command?.includes('claude-home'))
|
|
227
|
+
);
|
|
228
|
+
if (settings.hooks.SessionStart.length < before) {
|
|
229
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
|
230
|
+
console.log(`✓ SessionStart hook removed from ${settingsPath}`);
|
|
231
|
+
removed = true;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (!removed) console.log(' No claude-home hook found — skipped');
|
|
235
|
+
} catch { console.log(' Could not read settings.json — skipped'); }
|
|
236
|
+
|
|
237
|
+
// Remove slash command
|
|
238
|
+
if (fs.existsSync(commandPath)) {
|
|
239
|
+
fs.unlinkSync(commandPath);
|
|
240
|
+
console.log(`✓ Slash command removed from ${commandPath}`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Reset sentinel so setup prompt can appear again
|
|
244
|
+
try { fs.unlinkSync(sentinelPath); } catch { /* ignore */ }
|
|
245
|
+
|
|
246
|
+
console.log('\nDone! Restart Claude Code for the change to take effect.');
|
|
247
|
+
}
|
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -3121,6 +3121,18 @@
|
|
|
3121
3121
|
<div class="perm-pipeline-note">Hooks reciben el evento como JSON por stdin. Usar matcher para filtrar por tool (Bash, Edit…)</div>
|
|
3122
3122
|
</div>
|
|
3123
3123
|
|
|
3124
|
+
<!-- Auto-start toggle -->
|
|
3125
|
+
<div style="display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border:1px solid var(--rule-2);border-radius:6px;margin-bottom:16px;background:var(--canvas)">
|
|
3126
|
+
<div>
|
|
3127
|
+
<div style="font-size:12px;font-weight:600;color:var(--ink)">Auto-start claude-home</div>
|
|
3128
|
+
<div style="font-size:11px;color:var(--ink-3);margin-top:2px">Start the dashboard automatically when Claude Code opens</div>
|
|
3129
|
+
</div>
|
|
3130
|
+
<label style="display:flex;align-items:center;gap:8px;cursor:pointer">
|
|
3131
|
+
<span style="font-size:11px;color:var(--ink-3)" x-text="isAutoStartEnabled() ? 'On' : 'Off'"></span>
|
|
3132
|
+
<input type="checkbox" :checked="isAutoStartEnabled()" @change="toggleAutoStart($event.target.checked)" style="cursor:pointer;width:16px;height:16px;accent-color:var(--accent,#4a9)">
|
|
3133
|
+
</label>
|
|
3134
|
+
</div>
|
|
3135
|
+
|
|
3124
3136
|
<!-- Hooks section -->
|
|
3125
3137
|
<div class="config-section" style="margin-bottom:16px">
|
|
3126
3138
|
<div class="config-section-title" style="display:flex;align-items:center;justify-content:space-between">
|
|
@@ -5191,6 +5203,31 @@
|
|
|
5191
5203
|
return ordered;
|
|
5192
5204
|
},
|
|
5193
5205
|
|
|
5206
|
+
isAutoStartEnabled() {
|
|
5207
|
+
const hooks = this.configHooks();
|
|
5208
|
+
return hooks.some(h => h.event === 'SessionStart' && h.command?.includes('claude-home'));
|
|
5209
|
+
},
|
|
5210
|
+
|
|
5211
|
+
async toggleAutoStart(enable) {
|
|
5212
|
+
if (enable) {
|
|
5213
|
+
await fetch('/api/config/hooks', {
|
|
5214
|
+
method: 'POST',
|
|
5215
|
+
headers: { 'Content-Type': 'application/json' },
|
|
5216
|
+
body: JSON.stringify({
|
|
5217
|
+
scope: 'user',
|
|
5218
|
+
event: 'SessionStart',
|
|
5219
|
+
matcher: '',
|
|
5220
|
+
type: 'command',
|
|
5221
|
+
command: `lsof -ti:3141 >/dev/null 2>&1 || (claude-home --no-open &>/dev/null &)`,
|
|
5222
|
+
}),
|
|
5223
|
+
});
|
|
5224
|
+
} else {
|
|
5225
|
+
const hook = this.configHooks().find(h => h.event === 'SessionStart' && h.command?.includes('claude-home'));
|
|
5226
|
+
if (hook) await this.deleteHook(hook);
|
|
5227
|
+
}
|
|
5228
|
+
await this.loadConfig();
|
|
5229
|
+
},
|
|
5230
|
+
|
|
5194
5231
|
configHooks() {
|
|
5195
5232
|
if (!this.config?.settings) return [];
|
|
5196
5233
|
const result = [];
|