claude-rpc 0.12.0 → 0.12.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 +2 -1
- package/package.json +1 -1
- package/src/cli.js +38 -3
- package/src/install.js +29 -0
- package/src/version.js +1 -1
package/README.md
CHANGED
|
@@ -258,7 +258,8 @@ The full default config is in [`src/default-config.js`](src/default-config.js)
|
|
|
258
258
|
| `calendar` | Year activity heatmap SVG (`--out` `--gist`) |
|
|
259
259
|
| `session-card` | Recap card for the current session (`--out`) |
|
|
260
260
|
| `statusline` | One-line status for tmux/shell prompts (`--template`) |
|
|
261
|
-
| `mcp`
|
|
261
|
+
| `mcp install` | Wire the stats MCP server into Claude Code (one command) |
|
|
262
|
+
| `mcp` | Run the MCP server (stdio) for Claude Code |
|
|
262
263
|
| `wrapped` | Open your animated year-in-review (Claude Wrapped) |
|
|
263
264
|
| `private` / `public` / `privacy` | Per-cwd visibility toggles + status |
|
|
264
265
|
| `community` | Opt-in community totals — `on` \| `off` \| `status` \| `report` |
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -15,7 +15,7 @@ import { readState } from './state.js';
|
|
|
15
15
|
import { buildVars, fillTemplate, humanProject, humanTool, applyIdle, framePasses } from './format.js';
|
|
16
16
|
import { scan, readAggregate, findLiveSessions, dayKey, weekKey } from './scanner.js';
|
|
17
17
|
import { runHookCli } from './hook.js';
|
|
18
|
-
import { install as runInstall, uninstall as runUninstall, isInstalled, migrateConfig, installHooks, ensureCanonicalExe } from './install.js';
|
|
18
|
+
import { install as runInstall, uninstall as runUninstall, isInstalled, migrateConfig, installHooks, ensureCanonicalExe, installMcp, uninstallMcp, mcpServerCommand } from './install.js';
|
|
19
19
|
import { startTui } from './tui.js';
|
|
20
20
|
import { generateInsights } from './insights.js';
|
|
21
21
|
import { badgeSvg } from './badge.js';
|
|
@@ -847,6 +847,34 @@ async function doMcp() {
|
|
|
847
847
|
runMcpServer();
|
|
848
848
|
}
|
|
849
849
|
|
|
850
|
+
// One-command wiring into Claude Code — runs `claude mcp add` for the user.
|
|
851
|
+
function doMcpInstall(argv) {
|
|
852
|
+
const scope = argv.includes('--project') ? 'project' : argv.includes('--local') ? 'local' : 'user';
|
|
853
|
+
const res = installMcp({ exePath: EXE_PATH || process.execPath, scope });
|
|
854
|
+
const manual = (r) => `claude mcp add claude-rpc --scope ${scope} -- ${r.command} ${r.args.join(' ')}`;
|
|
855
|
+
if (res.ok) {
|
|
856
|
+
console.log('');
|
|
857
|
+
console.log(` ${c.green}✓${c.reset} Registered the ${c.cyan}claude-rpc${c.reset} MCP server with Claude Code (scope: ${scope}).`);
|
|
858
|
+
console.log(` ${c.dim}Restart Claude Code (or run /mcp), then ask: "how long have I coded today?"${c.reset}`);
|
|
859
|
+
console.log('');
|
|
860
|
+
} else if (res.reason === 'no-claude') {
|
|
861
|
+
fail('the `claude` CLI was not found on your PATH', {
|
|
862
|
+
hint: `install Claude Code first, then run: ${manual(res)}`,
|
|
863
|
+
code: EX_USER_ERROR,
|
|
864
|
+
});
|
|
865
|
+
} else {
|
|
866
|
+
fail(`\`claude mcp add\` failed (exit ${res.code})`, { hint: `try it manually: ${manual(res)}`, code: EX_USER_ERROR });
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
function doMcpUninstall(argv) {
|
|
871
|
+
const scope = argv.includes('--project') ? 'project' : argv.includes('--local') ? 'local' : 'user';
|
|
872
|
+
const res = uninstallMcp({ scope });
|
|
873
|
+
if (res.ok) console.log(`${c.green}✓${c.reset} Removed the claude-rpc MCP server (scope: ${scope}).`);
|
|
874
|
+
else if (res.reason === 'no-claude') fail('the `claude` CLI was not found on your PATH', { code: EX_USER_ERROR });
|
|
875
|
+
else fail('could not remove the MCP server', { hint: 'claude mcp remove claude-rpc', code: EX_USER_ERROR });
|
|
876
|
+
}
|
|
877
|
+
|
|
850
878
|
// ── Privacy commands ─────────────────────────────────────────────────────
|
|
851
879
|
//
|
|
852
880
|
// `claude-rpc private` → add current cwd to ~/.claude-rpc/private-list.json
|
|
@@ -1140,7 +1168,8 @@ function help() {
|
|
|
1140
1168
|
['statusline', 'One-line status for tmux/shell prompts (--template)'],
|
|
1141
1169
|
['calendar', 'Year activity heatmap SVG (--out --gist)'],
|
|
1142
1170
|
['session-card', 'Recap card for the current session (--out)'],
|
|
1143
|
-
['mcp',
|
|
1171
|
+
['mcp install', 'Wire the stats MCP server into Claude Code (one command)'],
|
|
1172
|
+
['mcp', 'Run the MCP server (stdio) — exposes your stats to Claude'],
|
|
1144
1173
|
['wrapped', 'Open your animated year-in-review (Claude Wrapped)'],
|
|
1145
1174
|
['private', 'Mark the current directory as private (hide from Discord)'],
|
|
1146
1175
|
['public', 'Un-mark the current directory'],
|
|
@@ -1218,7 +1247,13 @@ const packagedDefault = IS_PACKAGED && !cmd;
|
|
|
1218
1247
|
case 'statusline': doStatusline(process.argv.slice(3)); break;
|
|
1219
1248
|
case 'calendar': await doCalendar(process.argv.slice(3)); break;
|
|
1220
1249
|
case 'session-card': await doSessionCard(process.argv.slice(3)); break;
|
|
1221
|
-
case 'mcp':
|
|
1250
|
+
case 'mcp': {
|
|
1251
|
+
const sub = process.argv[3];
|
|
1252
|
+
if (sub === 'install') { doMcpInstall(process.argv.slice(4)); break; }
|
|
1253
|
+
if (sub === 'uninstall') { doMcpUninstall(process.argv.slice(4)); break; }
|
|
1254
|
+
await doMcp();
|
|
1255
|
+
break;
|
|
1256
|
+
}
|
|
1222
1257
|
case 'wrapped': process.env.CLAUDE_RPC_OPEN_PATH = '/wrapped'; await import('./server/index.js'); break;
|
|
1223
1258
|
case 'private': doPrivate(); break;
|
|
1224
1259
|
case 'public': doPublic(); break;
|
package/src/install.js
CHANGED
|
@@ -235,6 +235,35 @@ export function seedConfig() {
|
|
|
235
235
|
// without clobbering the user's customizations. Anything the user already
|
|
236
236
|
// has — including a pre-existing byStatus, custom rotation array, custom
|
|
237
237
|
// appName etc. — is left untouched.
|
|
238
|
+
// How Claude Code should invoke the MCP server — same three-mode resolution
|
|
239
|
+
// as the hook commands (packaged exe / npm bin / dev source).
|
|
240
|
+
export function mcpServerCommand(exePath) {
|
|
241
|
+
if (IS_PACKAGED) return { command: exePath, args: ['mcp'] };
|
|
242
|
+
if (IS_NPM_INSTALL) return { command: 'claude-rpc', args: ['mcp'] };
|
|
243
|
+
const cli = join(dirname(HOOK_SCRIPT), 'cli.js').replace(/\\/g, '/');
|
|
244
|
+
return { command: 'node', args: [cli, 'mcp'] };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Register the MCP server with Claude Code via its own `claude mcp add`, so a
|
|
248
|
+
// user never has to hand-type the command. Best-effort: returns { ok, reason,
|
|
249
|
+
// command, args }. Needs the `claude` CLI on PATH.
|
|
250
|
+
export function installMcp({ exePath, scope = 'user' } = {}) {
|
|
251
|
+
const { command, args } = mcpServerCommand(exePath);
|
|
252
|
+
const winShell = process.platform === 'win32';
|
|
253
|
+
// Replace any stale entry first so re-running is idempotent (ignore failure).
|
|
254
|
+
spawnSync('claude', ['mcp', 'remove', 'claude-rpc', '--scope', scope], { stdio: 'ignore', shell: winShell });
|
|
255
|
+
const r = spawnSync('claude', ['mcp', 'add', 'claude-rpc', '--scope', scope, '--', command, ...args], { stdio: 'inherit', shell: winShell });
|
|
256
|
+
if (r.error && r.error.code === 'ENOENT') return { ok: false, reason: 'no-claude', command, args };
|
|
257
|
+
if (r.status !== 0) return { ok: false, reason: 'add-failed', code: r.status, command, args };
|
|
258
|
+
return { ok: true, command, args, scope };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export function uninstallMcp({ scope = 'user' } = {}) {
|
|
262
|
+
const r = spawnSync('claude', ['mcp', 'remove', 'claude-rpc', '--scope', scope], { stdio: 'inherit', shell: process.platform === 'win32' });
|
|
263
|
+
if (r.error && r.error.code === 'ENOENT') return { ok: false, reason: 'no-claude' };
|
|
264
|
+
return { ok: r.status === 0 };
|
|
265
|
+
}
|
|
266
|
+
|
|
238
267
|
export function migrateConfig({ silent = false } = {}) {
|
|
239
268
|
if (!existsSync(CONFIG_PATH)) return false;
|
|
240
269
|
let cfg;
|