claude-pool 0.1.0 → 0.1.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 +11 -0
- package/bin/cli.js +52 -0
- package/package.json +1 -1
- package/src/runner.js +12 -0
- package/src/setup.js +31 -0
package/README.md
CHANGED
|
@@ -125,6 +125,7 @@ When an account reaches its 5-hour limit, `claude-pool` catches it and migrates
|
|
|
125
125
|
|---|---|
|
|
126
126
|
| `claude-pool` | Launch Claude session with active account & auto-failover |
|
|
127
127
|
| `claude-pool setup` | Interactive wizard to connect all accounts from scratch |
|
|
128
|
+
| `claude-pool switch [account]` | Manually switch active account with zero session loss |
|
|
128
129
|
| `claude-pool limits` / `remaining` | View exact % session and weekly quota remaining + reset countdowns |
|
|
129
130
|
| `claude-pool dashboard` | Unified pool dashboard with today's consumption & gauges |
|
|
130
131
|
| `claude-pool usage [account]` | Deep token breakdown (Input, Output, Cache Read/Create) per account |
|
|
@@ -138,6 +139,16 @@ When an account reaches its 5-hour limit, `claude-pool` catches it and migrates
|
|
|
138
139
|
|
|
139
140
|
---
|
|
140
141
|
|
|
142
|
+
## ⚡ In-Session Slash Commands
|
|
143
|
+
|
|
144
|
+
You don't need to exit an active Claude session to check limits or switch accounts! `claude-pool setup` automatically installs custom slash commands into all configured accounts:
|
|
145
|
+
|
|
146
|
+
- **`/limits`** (or `/pool-limits`): Prints real-time remaining quota percentages and reset timers across all accounts right inside your chat transcript.
|
|
147
|
+
- **`/pool`**: Displays the aggregated token usage dashboard.
|
|
148
|
+
- **`/switch <account>`** (or `/pool-switch <account>`): Transfers your active session transcript and working directory to the target account. Type `/exit` to seamlessly relaunch on the newly switched account with 100% memory preserved!
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
141
152
|
## 🧠 How It Works Under The Hood
|
|
142
153
|
|
|
143
154
|
Claude Code stores project sessions as local JSONL transcripts:
|
package/bin/cli.js
CHANGED
|
@@ -10,6 +10,8 @@ import { colors, formatTokenCount, makePill, makeGauge, printTable } from '../sr
|
|
|
10
10
|
const KNOWN_COMMANDS = new Set([
|
|
11
11
|
'start',
|
|
12
12
|
'setup',
|
|
13
|
+
'switch',
|
|
14
|
+
'use',
|
|
13
15
|
'limits',
|
|
14
16
|
'remaining',
|
|
15
17
|
'quota',
|
|
@@ -52,6 +54,55 @@ async function handleCommand() {
|
|
|
52
54
|
break;
|
|
53
55
|
}
|
|
54
56
|
|
|
57
|
+
case 'switch':
|
|
58
|
+
case 'use': {
|
|
59
|
+
let targetName = args[1];
|
|
60
|
+
const accounts = cfg.loadAccounts();
|
|
61
|
+
|
|
62
|
+
if (!targetName) {
|
|
63
|
+
console.log(`\n${colors.indigo}${colors.bold}Switch Active Claude Account:${colors.reset}\n`);
|
|
64
|
+
accounts.forEach((a, idx) => {
|
|
65
|
+
const activeTag = idx === 0 ? `${colors.emerald} [ACTIVE]${colors.reset}` : '';
|
|
66
|
+
const emailTag = a.email ? ` (${a.email})` : '';
|
|
67
|
+
console.log(` ${colors.bold}${idx + 1})${colors.reset} ${a.name}${emailTag}${activeTag}`);
|
|
68
|
+
});
|
|
69
|
+
console.log();
|
|
70
|
+
const { default: readline } = await import('readline/promises');
|
|
71
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
72
|
+
const choice = await rl.question(`Select account (1-${accounts.length}): `);
|
|
73
|
+
rl.close();
|
|
74
|
+
const chosenIdx = parseInt(choice.trim(), 10) - 1;
|
|
75
|
+
if (chosenIdx >= 0 && chosenIdx < accounts.length) {
|
|
76
|
+
targetName = accounts[chosenIdx].name;
|
|
77
|
+
} else {
|
|
78
|
+
console.log(`${colors.red}Invalid selection.${colors.reset}`);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const prevActive = accounts[0];
|
|
84
|
+
const target = accounts.find(a => a.name.toLowerCase() === targetName.toLowerCase());
|
|
85
|
+
if (!target) {
|
|
86
|
+
console.log(`${colors.red}Error: Account '${targetName}' not found in pool.${colors.reset}`);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
target.rateLimitedUntil = null;
|
|
91
|
+
cfg.updateAccountPriority(target.name, 1);
|
|
92
|
+
|
|
93
|
+
if (prevActive && prevActive.name.toLowerCase() !== target.name.toLowerCase()) {
|
|
94
|
+
const { SessionSyncEngine } = await import('../src/sessionSync.js');
|
|
95
|
+
const syncedId = SessionSyncEngine.transferSession(prevActive, target);
|
|
96
|
+
if (syncedId) {
|
|
97
|
+
console.log(`${colors.emerald}✓ Synchronized active session (${syncedId.slice(0, 12)}...) to ${target.name}.${colors.reset}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.log(`\n${colors.emerald}✓ Active account is now: ${colors.bold}${target.name} (Priority 1)${colors.reset}`);
|
|
102
|
+
console.log(`${colors.dim}Run ${colors.reset}${colors.indigo}claude-pool${colors.reset}${colors.dim} to start working on ${target.name}.${colors.reset}\n`);
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
|
|
55
106
|
case 'limits':
|
|
56
107
|
case 'remaining':
|
|
57
108
|
case 'quota': {
|
|
@@ -312,6 +363,7 @@ ${colors.bold}USAGE:${colors.reset}
|
|
|
312
363
|
|
|
313
364
|
${colors.bold}COMMANDS:${colors.reset}
|
|
314
365
|
${colors.indigo}claude-pool${colors.reset} Launch Claude session with pooled accounts & auto-failover
|
|
366
|
+
${colors.indigo}claude-pool switch [acct]${colors.reset} Manually switch active account (or interactive picker)
|
|
315
367
|
${colors.indigo}claude-pool setup${colors.reset} Guided setup wizard to connect accounts from scratch
|
|
316
368
|
${colors.indigo}claude-pool limits${colors.reset} Inspect remaining session/weekly % quota & reset timers
|
|
317
369
|
${colors.indigo}claude-pool dashboard${colors.reset} Real-time aggregated token metrics & model stats
|
package/package.json
CHANGED
package/src/runner.js
CHANGED
|
@@ -95,6 +95,18 @@ export class ProcessRunner {
|
|
|
95
95
|
break;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
// Check if user manually switched account during the session (e.g. via /pool-switch)
|
|
99
|
+
const refreshedAccounts = this.configManager.loadAccounts();
|
|
100
|
+
const readyRefreshed = this.getReadyAccounts(refreshedAccounts);
|
|
101
|
+
if (readyRefreshed.length > 0 && readyRefreshed[0].name.toLowerCase() !== activeAccount.name.toLowerCase()) {
|
|
102
|
+
const newActive = readyRefreshed[0];
|
|
103
|
+
console.log(`\n${colors.emerald}✓ Account switch detected! Continuing session on ${newActive.name}...${colors.reset}\n`);
|
|
104
|
+
const latestId = SessionSyncEngine.getLatestSessionId(newActive);
|
|
105
|
+
if (latestId) resumeSessionId = latestId;
|
|
106
|
+
activeAccount = newActive;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
|
|
98
110
|
if (exitCode === 0) {
|
|
99
111
|
console.log(`\n${colors.emerald}✓ Claude session finished normally.${colors.reset}`);
|
|
100
112
|
break;
|
package/src/setup.js
CHANGED
|
@@ -57,6 +57,34 @@ export function checkAuthStatus(configDir) {
|
|
|
57
57
|
return { ok: false, email: null, plan: null };
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
export function installSlashCommands(configDir) {
|
|
61
|
+
const cmdDir = path.join(configDir, 'commands');
|
|
62
|
+
try {
|
|
63
|
+
fs.mkdirSync(cmdDir, { recursive: true });
|
|
64
|
+
// /pool
|
|
65
|
+
fs.writeFileSync(
|
|
66
|
+
path.join(cmdDir, 'pool.md'),
|
|
67
|
+
'---\ndescription: View Claude Pool token dashboard and status\n---\nRun `claude-pool dashboard` using Bash and display the formatted output.\n',
|
|
68
|
+
'utf8'
|
|
69
|
+
);
|
|
70
|
+
// /limits
|
|
71
|
+
fs.writeFileSync(
|
|
72
|
+
path.join(cmdDir, 'limits.md'),
|
|
73
|
+
'---\ndescription: View remaining session and weekly quotas across all accounts in the pool\n---\nRun `claude-pool limits` using Bash and display the formatted output.\n',
|
|
74
|
+
'utf8'
|
|
75
|
+
);
|
|
76
|
+
// /switch
|
|
77
|
+
fs.writeFileSync(
|
|
78
|
+
path.join(cmdDir, 'switch.md'),
|
|
79
|
+
'---\ndescription: Switch active Claude account in the pool\n---\nRun `claude-pool switch $ARGUMENTS` using Bash and display the result.\nIf switched successfully, inform the user that their session was synchronized and they can run `/exit` to restart immediately on the new account.\n',
|
|
80
|
+
'utf8'
|
|
81
|
+
);
|
|
82
|
+
// Also include /pool-limits and /pool-switch aliases
|
|
83
|
+
fs.copyFileSync(path.join(cmdDir, 'limits.md'), path.join(cmdDir, 'pool-limits.md'));
|
|
84
|
+
fs.copyFileSync(path.join(cmdDir, 'switch.md'), path.join(cmdDir, 'pool-switch.md'));
|
|
85
|
+
} catch {}
|
|
86
|
+
}
|
|
87
|
+
|
|
60
88
|
export async function runSetupWizard() {
|
|
61
89
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
62
90
|
|
|
@@ -159,6 +187,9 @@ export async function runSetupWizard() {
|
|
|
159
187
|
rl.close();
|
|
160
188
|
|
|
161
189
|
if (accounts.length > 0) {
|
|
190
|
+
for (const a of accounts) {
|
|
191
|
+
installSlashCommands(a.configDir);
|
|
192
|
+
}
|
|
162
193
|
cfg.saveAccounts(accounts);
|
|
163
194
|
console.log(`\n${colors.emerald}✓ Setup complete! Your Claude Pool is configured:${colors.reset}\n`);
|
|
164
195
|
|