@claudetools/cli 0.13.12 → 0.13.15
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/dist/__tests__/factories.d.ts +173 -0
- package/dist/__tests__/factories.d.ts.map +1 -0
- package/dist/__tests__/factories.js +150 -0
- package/dist/__tests__/factories.js.map +1 -0
- package/dist/__tests__/helpers.d.ts +36 -0
- package/dist/__tests__/helpers.d.ts.map +1 -0
- package/dist/__tests__/helpers.js +52 -0
- package/dist/__tests__/helpers.js.map +1 -0
- package/dist/analytics/index.d.ts +14 -0
- package/dist/analytics/index.d.ts.map +1 -0
- package/dist/analytics/index.js +259 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/analytics/session.d.ts +17 -0
- package/dist/analytics/session.d.ts.map +1 -0
- package/dist/analytics/session.js +130 -0
- package/dist/analytics/session.js.map +1 -0
- package/dist/analytics/token-tracker.d.ts +48 -0
- package/dist/analytics/token-tracker.d.ts.map +1 -0
- package/dist/analytics/token-tracker.js +269 -0
- package/dist/analytics/token-tracker.js.map +1 -0
- package/dist/analytics/tracker.d.ts +33 -0
- package/dist/analytics/tracker.d.ts.map +1 -0
- package/dist/analytics/tracker.js +210 -0
- package/dist/analytics/tracker.js.map +1 -0
- package/dist/api-keys/index.d.ts +15 -0
- package/dist/api-keys/index.d.ts.map +1 -0
- package/dist/api-keys/index.js +228 -0
- package/dist/api-keys/index.js.map +1 -0
- package/dist/auth/config.d.ts +15 -0
- package/dist/auth/config.d.ts.map +1 -0
- package/dist/auth/config.js +67 -0
- package/dist/auth/config.js.map +1 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +299 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/keychain.d.ts +21 -0
- package/dist/auth/keychain.d.ts.map +1 -0
- package/dist/auth/keychain.js +256 -0
- package/dist/auth/keychain.js.map +1 -0
- package/dist/billing/index.d.ts +7 -0
- package/dist/billing/index.d.ts.map +1 -0
- package/dist/billing/index.js +233 -0
- package/dist/billing/index.js.map +1 -0
- package/dist/cli.js +291 -43
- package/dist/cli.js.map +1 -1
- package/dist/commands/hook.d.ts +12 -0
- package/dist/commands/hook.d.ts.map +1 -0
- package/dist/commands/hook.js +190 -0
- package/dist/commands/hook.js.map +1 -0
- package/dist/commands/keys.d.ts +4 -0
- package/dist/commands/keys.d.ts.map +1 -0
- package/dist/commands/keys.js +43 -0
- package/dist/commands/keys.js.map +1 -0
- package/dist/commands/mcp.d.ts +4 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +43 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/project.d.ts +4 -0
- package/dist/commands/project.d.ts.map +1 -0
- package/dist/commands/project.js +68 -0
- package/dist/commands/project.js.map +1 -0
- package/dist/commands/skill.d.ts +4 -0
- package/dist/commands/skill.d.ts.map +1 -0
- package/dist/commands/skill.js +37 -0
- package/dist/commands/skill.js.map +1 -0
- package/dist/commands/stacks.d.ts +4 -0
- package/dist/commands/stacks.d.ts.map +1 -0
- package/dist/commands/stacks.js +103 -0
- package/dist/commands/stacks.js.map +1 -0
- package/dist/commands/stats.d.ts +4 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +6 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/sync.d.ts +4 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +60 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/update.d.ts +4 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +63 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/daemon/client.d.ts +107 -0
- package/dist/daemon/client.d.ts.map +1 -0
- package/dist/daemon/client.js +250 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/health.d.ts +38 -0
- package/dist/daemon/health.d.ts.map +1 -0
- package/dist/daemon/health.js +212 -0
- package/dist/daemon/health.js.map +1 -0
- package/dist/daemon/index.d.ts +34 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +197 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/protocol.d.ts +144 -0
- package/dist/daemon/protocol.d.ts.map +1 -0
- package/dist/daemon/protocol.js +5 -0
- package/dist/daemon/protocol.js.map +1 -0
- package/dist/gamification/index.d.ts +13 -0
- package/dist/gamification/index.d.ts.map +1 -0
- package/dist/gamification/index.js +120 -0
- package/dist/gamification/index.js.map +1 -0
- package/dist/gamification/types.d.ts +34 -0
- package/dist/gamification/types.d.ts.map +1 -0
- package/dist/gamification/types.js +5 -0
- package/dist/gamification/types.js.map +1 -0
- package/dist/hooks/index.d.ts +65 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +403 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/lib/api.d.ts +29 -0
- package/dist/lib/api.d.ts.map +1 -0
- package/dist/lib/api.js +213 -0
- package/dist/lib/api.js.map +1 -0
- package/dist/lib/browser.d.ts +6 -0
- package/dist/lib/browser.d.ts.map +1 -0
- package/dist/lib/browser.js +14 -0
- package/dist/lib/browser.js.map +1 -0
- package/dist/lib/channel-config.d.ts +10 -0
- package/dist/lib/channel-config.d.ts.map +1 -0
- package/dist/lib/channel-config.js +48 -0
- package/dist/lib/channel-config.js.map +1 -0
- package/dist/lib/command-runner.d.ts +16 -0
- package/dist/lib/command-runner.d.ts.map +1 -0
- package/dist/lib/command-runner.js +59 -0
- package/dist/lib/command-runner.js.map +1 -0
- package/dist/lib/command-utils.d.ts +22 -0
- package/dist/lib/command-utils.d.ts.map +1 -0
- package/dist/lib/command-utils.js +88 -0
- package/dist/lib/command-utils.js.map +1 -0
- package/dist/lib/error-handler.d.ts +13 -0
- package/dist/lib/error-handler.d.ts.map +1 -0
- package/dist/lib/error-handler.js +70 -0
- package/dist/lib/error-handler.js.map +1 -0
- package/dist/lib/errors.d.ts +35 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +70 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/exit.d.ts +10 -0
- package/dist/lib/exit.d.ts.map +1 -0
- package/dist/lib/exit.js +21 -0
- package/dist/lib/exit.js.map +1 -0
- package/dist/lib/formatters.d.ts +65 -0
- package/dist/lib/formatters.d.ts.map +1 -0
- package/dist/lib/formatters.js +180 -0
- package/dist/lib/formatters.js.map +1 -0
- package/dist/lib/hybrid-data.d.ts +47 -0
- package/dist/lib/hybrid-data.d.ts.map +1 -0
- package/dist/lib/hybrid-data.js +326 -0
- package/dist/lib/hybrid-data.js.map +1 -0
- package/dist/lib/local-store.d.ts +113 -0
- package/dist/lib/local-store.d.ts.map +1 -0
- package/dist/lib/local-store.js +220 -0
- package/dist/lib/local-store.js.map +1 -0
- package/dist/lib/machine-id.d.ts +8 -0
- package/dist/lib/machine-id.d.ts.map +1 -0
- package/dist/lib/machine-id.js +39 -0
- package/dist/lib/machine-id.js.map +1 -0
- package/dist/lib/network.d.ts +15 -0
- package/dist/lib/network.d.ts.map +1 -0
- package/dist/lib/network.js +46 -0
- package/dist/lib/network.js.map +1 -0
- package/dist/lib/theme.d.ts +77 -0
- package/dist/lib/theme.d.ts.map +1 -0
- package/dist/lib/theme.js +137 -0
- package/dist/lib/theme.js.map +1 -0
- package/dist/lib/tool-availability.d.ts +13 -0
- package/dist/lib/tool-availability.d.ts.map +1 -0
- package/dist/lib/tool-availability.js +48 -0
- package/dist/lib/tool-availability.js.map +1 -0
- package/dist/lib/update-checker.d.ts +21 -0
- package/dist/lib/update-checker.d.ts.map +1 -0
- package/dist/lib/update-checker.js +110 -0
- package/dist/lib/update-checker.js.map +1 -0
- package/dist/lib/validation.d.ts +30 -0
- package/dist/lib/validation.d.ts.map +1 -0
- package/dist/lib/validation.js +82 -0
- package/dist/lib/validation.js.map +1 -0
- package/dist/lib/validators.d.ts +18 -0
- package/dist/lib/validators.d.ts.map +1 -0
- package/dist/lib/validators.js +30 -0
- package/dist/lib/validators.js.map +1 -0
- package/dist/marketplace/api.d.ts +24 -0
- package/dist/marketplace/api.d.ts.map +1 -0
- package/dist/marketplace/api.js +92 -0
- package/dist/marketplace/api.js.map +1 -0
- package/dist/marketplace/index.d.ts +13 -0
- package/dist/marketplace/index.d.ts.map +1 -0
- package/dist/marketplace/index.js +155 -0
- package/dist/marketplace/index.js.map +1 -0
- package/dist/marketplace/installer.d.ts +18 -0
- package/dist/marketplace/installer.d.ts.map +1 -0
- package/dist/marketplace/installer.js +184 -0
- package/dist/marketplace/installer.js.map +1 -0
- package/dist/mcp/api.d.ts +93 -0
- package/dist/mcp/api.d.ts.map +1 -0
- package/dist/mcp/api.js +106 -0
- package/dist/mcp/api.js.map +1 -0
- package/dist/mcp/config.d.ts +72 -0
- package/dist/mcp/config.d.ts.map +1 -0
- package/dist/mcp/config.js +156 -0
- package/dist/mcp/config.js.map +1 -0
- package/dist/mcp/index.d.ts +54 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +381 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/prompt.clean.d.ts +25 -0
- package/dist/mcp/prompt.clean.d.ts.map +1 -0
- package/dist/mcp/prompt.clean.js +206 -0
- package/dist/mcp/prompt.clean.js.map +1 -0
- package/dist/mcp/prompt.d.ts +52 -0
- package/dist/mcp/prompt.d.ts.map +1 -0
- package/dist/mcp/prompt.js +210 -0
- package/dist/mcp/prompt.js.map +1 -0
- package/dist/mcp/secrets.clean.d.ts +18 -0
- package/dist/mcp/secrets.clean.d.ts.map +1 -0
- package/dist/mcp/secrets.clean.js +357 -0
- package/dist/mcp/secrets.clean.js.map +1 -0
- package/dist/mcp/secrets.d.ts +46 -0
- package/dist/mcp/secrets.d.ts.map +1 -0
- package/dist/mcp/secrets.js +339 -0
- package/dist/mcp/secrets.js.map +1 -0
- package/dist/memory/index.d.ts +14 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +98 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/onboard/agents-md-builder.d.ts.map +1 -1
- package/dist/onboard/agents-md-builder.js +45 -0
- package/dist/onboard/agents-md-builder.js.map +1 -1
- package/dist/onboard/claude-inference.d.ts.map +1 -1
- package/dist/onboard/claude-inference.js +31 -5
- package/dist/onboard/claude-inference.js.map +1 -1
- package/dist/onboard/context7-fetcher.d.ts +1 -1
- package/dist/onboard/context7-fetcher.d.ts.map +1 -1
- package/dist/onboard/context7-fetcher.js +50 -16
- package/dist/onboard/context7-fetcher.js.map +1 -1
- package/dist/onboard/docs-builder.d.ts.map +1 -1
- package/dist/onboard/docs-builder.js +523 -50
- package/dist/onboard/docs-builder.js.map +1 -1
- package/dist/onboard/index.d.ts.map +1 -1
- package/dist/onboard/index.js +74 -25
- package/dist/onboard/index.js.map +1 -1
- package/dist/onboard/stack-detector.d.ts.map +1 -1
- package/dist/onboard/stack-detector.js +5 -55
- package/dist/onboard/stack-detector.js.map +1 -1
- package/dist/project/constants.d.ts +21 -0
- package/dist/project/constants.d.ts.map +1 -0
- package/dist/project/constants.js +21 -0
- package/dist/project/constants.js.map +1 -0
- package/dist/project/format.d.ts +16 -0
- package/dist/project/format.d.ts.map +1 -0
- package/dist/project/format.js +40 -0
- package/dist/project/format.js.map +1 -0
- package/dist/project/git.d.ts +28 -0
- package/dist/project/git.d.ts.map +1 -0
- package/dist/project/git.js +93 -0
- package/dist/project/git.js.map +1 -0
- package/dist/project/index.d.ts +36 -0
- package/dist/project/index.d.ts.map +1 -0
- package/dist/project/index.js +272 -0
- package/dist/project/index.js.map +1 -0
- package/dist/project/mapper.d.ts +27 -0
- package/dist/project/mapper.d.ts.map +1 -0
- package/dist/project/mapper.js +64 -0
- package/dist/project/mapper.js.map +1 -0
- package/dist/project/storage.d.ts +71 -0
- package/dist/project/storage.d.ts.map +1 -0
- package/dist/project/storage.js +274 -0
- package/dist/project/storage.js.map +1 -0
- package/dist/project/sync-bridge.d.ts +33 -0
- package/dist/project/sync-bridge.d.ts.map +1 -0
- package/dist/project/sync-bridge.js +155 -0
- package/dist/project/sync-bridge.js.map +1 -0
- package/dist/project/types.d.ts +107 -0
- package/dist/project/types.d.ts.map +1 -0
- package/dist/project/types.js +77 -0
- package/dist/project/types.js.map +1 -0
- package/dist/publish/index.d.ts +4 -0
- package/dist/publish/index.d.ts.map +1 -0
- package/dist/publish/index.js +92 -0
- package/dist/publish/index.js.map +1 -0
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +29 -10
- package/dist/setup.js.map +1 -1
- package/dist/skills/index.d.ts +51 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +509 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/stacks/check.d.ts +2 -0
- package/dist/stacks/check.d.ts.map +1 -0
- package/dist/stacks/check.js +144 -0
- package/dist/stacks/check.js.map +1 -0
- package/dist/stacks/diff.d.ts +11 -0
- package/dist/stacks/diff.d.ts.map +1 -0
- package/dist/stacks/diff.js +123 -0
- package/dist/stacks/diff.js.map +1 -0
- package/dist/stacks/index.d.ts +17 -0
- package/dist/stacks/index.d.ts.map +1 -0
- package/dist/stacks/index.js +525 -0
- package/dist/stacks/index.js.map +1 -0
- package/dist/stacks/index.refactored.d.ts.map +1 -0
- package/dist/stacks/index.refactored.js.map +1 -0
- package/dist/stacks/io.d.ts +11 -0
- package/dist/stacks/io.d.ts.map +1 -0
- package/dist/stacks/io.js +179 -0
- package/dist/stacks/io.js.map +1 -0
- package/dist/stacks/rollback.d.ts +5 -0
- package/dist/stacks/rollback.d.ts.map +1 -0
- package/dist/stacks/rollback.js +162 -0
- package/dist/stacks/rollback.js.map +1 -0
- package/dist/stacks/types.d.ts +70 -0
- package/dist/stacks/types.d.ts.map +1 -0
- package/dist/stacks/types.js +6 -0
- package/dist/stacks/types.js.map +1 -0
- package/dist/stacks/utils.d.ts +9 -0
- package/dist/stacks/utils.d.ts.map +1 -0
- package/dist/stacks/utils.js +11 -0
- package/dist/stacks/utils.js.map +1 -0
- package/dist/start/index.d.ts +23 -0
- package/dist/start/index.d.ts.map +1 -0
- package/dist/start/index.js +386 -0
- package/dist/start/index.js.map +1 -0
- package/dist/sync/index.d.ts +49 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +207 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync-engine/__tests__/test-helpers.d.ts +14 -0
- package/dist/sync-engine/__tests__/test-helpers.d.ts.map +1 -0
- package/dist/sync-engine/__tests__/test-helpers.js +73 -0
- package/dist/sync-engine/__tests__/test-helpers.js.map +1 -0
- package/dist/sync-engine/client.d.ts +128 -0
- package/dist/sync-engine/client.d.ts.map +1 -0
- package/dist/sync-engine/client.js +289 -0
- package/dist/sync-engine/client.js.map +1 -0
- package/dist/sync-engine/health.d.ts +38 -0
- package/dist/sync-engine/health.d.ts.map +1 -0
- package/dist/sync-engine/health.js +259 -0
- package/dist/sync-engine/health.js.map +1 -0
- package/dist/sync-engine/index.d.ts +34 -0
- package/dist/sync-engine/index.d.ts.map +1 -0
- package/dist/sync-engine/index.js +197 -0
- package/dist/sync-engine/index.js.map +1 -0
- package/dist/sync-engine/protocol.d.ts +153 -0
- package/dist/sync-engine/protocol.d.ts.map +1 -0
- package/dist/sync-engine/protocol.js +5 -0
- package/dist/sync-engine/protocol.js.map +1 -0
- package/dist/tasks/index.d.ts +14 -0
- package/dist/tasks/index.d.ts.map +1 -0
- package/dist/tasks/index.js +109 -0
- package/dist/tasks/index.js.map +1 -0
- package/dist/team/index.d.ts +12 -0
- package/dist/team/index.d.ts.map +1 -0
- package/dist/team/index.js +151 -0
- package/dist/team/index.js.map +1 -0
- package/dist/updater.d.ts +5 -5
- package/dist/updater.d.ts.map +1 -1
- package/dist/updater.js +24 -88
- package/dist/updater.js.map +1 -1
- package/dist/usage/index.d.ts +10 -0
- package/dist/usage/index.d.ts.map +1 -0
- package/dist/usage/index.js +104 -0
- package/dist/usage/index.js.map +1 -0
- package/dist/webhooks/index.d.ts +7 -0
- package/dist/webhooks/index.d.ts.map +1 -0
- package/dist/webhooks/index.js +81 -0
- package/dist/webhooks/index.js.map +1 -0
- package/package.json +26 -15
- package/scripts/postinstall.js +282 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import ora from 'ora';
|
|
2
|
+
import { getApiClient, ApiError } from '../lib/api.js';
|
|
3
|
+
import { requireAuth } from '../auth/config.js';
|
|
4
|
+
import { getCredential } from '../auth/keychain.js';
|
|
5
|
+
import { theme, formatError, formatWarning } from '../lib/theme.js';
|
|
6
|
+
import * as readline from 'readline';
|
|
7
|
+
/**
|
|
8
|
+
* Mask an API key for display
|
|
9
|
+
*/
|
|
10
|
+
function maskKey(keyPrefix) {
|
|
11
|
+
return `${keyPrefix}****`;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Prompt for confirmation
|
|
15
|
+
*/
|
|
16
|
+
async function confirm(question) {
|
|
17
|
+
const rl = readline.createInterface({
|
|
18
|
+
input: process.stdin,
|
|
19
|
+
output: process.stdout,
|
|
20
|
+
});
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
rl.question(`${question} (y/N) `, (answer) => {
|
|
23
|
+
rl.close();
|
|
24
|
+
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* List all API keys
|
|
30
|
+
*/
|
|
31
|
+
export async function runKeysList() {
|
|
32
|
+
await requireAuth();
|
|
33
|
+
const spinner = ora('Loading API keys...').start();
|
|
34
|
+
try {
|
|
35
|
+
const api = getApiClient();
|
|
36
|
+
const { data } = await api.get('/keys');
|
|
37
|
+
if (!data) {
|
|
38
|
+
spinner.fail('Failed to load API keys');
|
|
39
|
+
console.error(` ${formatError('No data received from server', 'ERR_NO_DATA')}`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
spinner.stop();
|
|
43
|
+
console.log();
|
|
44
|
+
console.log(` ${theme.bold('API Keys')}`);
|
|
45
|
+
const keysLimitDisplay = data.quota.limit === null ? 'unlimited' : String(data.quota.limit);
|
|
46
|
+
console.log(` ${theme.muted(`${data.quota.used}/${keysLimitDisplay} keys used`)}`);
|
|
47
|
+
console.log();
|
|
48
|
+
if (data.keys.length === 0) {
|
|
49
|
+
console.log(` ${theme.muted('No API keys created yet.')}`);
|
|
50
|
+
console.log();
|
|
51
|
+
console.log(` ${theme.muted(`Run ${theme.command('claudetools keys create <name>')} to create one.`)}`);
|
|
52
|
+
console.log();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
// Get current key to mark it
|
|
56
|
+
const currentKey = await getCredential();
|
|
57
|
+
const currentKeyPrefix = currentKey ? currentKey.substring(0, 8) : null;
|
|
58
|
+
// Display keys
|
|
59
|
+
data.keys.forEach((key) => {
|
|
60
|
+
const isCurrent = currentKeyPrefix && key.keyPrefix === currentKeyPrefix;
|
|
61
|
+
const indicator = isCurrent ? theme.success('*') : ' ';
|
|
62
|
+
const maskedKey = maskKey(key.keyPrefix);
|
|
63
|
+
const lastUsed = key.lastUsedAt
|
|
64
|
+
? new Date(key.lastUsedAt).toLocaleDateString()
|
|
65
|
+
: 'Never';
|
|
66
|
+
console.log(` ${indicator} ${theme.bold(key.name)}`);
|
|
67
|
+
console.log(` ${theme.muted('Key:')} ${maskedKey}`);
|
|
68
|
+
console.log(` ${theme.muted('ID:')} ${key.id}`);
|
|
69
|
+
console.log(` ${theme.muted('Last used:')} ${lastUsed}`);
|
|
70
|
+
console.log(` ${theme.muted('Created:')} ${new Date(key.createdAt).toLocaleDateString()}`);
|
|
71
|
+
console.log();
|
|
72
|
+
});
|
|
73
|
+
if (currentKeyPrefix) {
|
|
74
|
+
console.log(` ${theme.muted('* = Currently active key')}`);
|
|
75
|
+
console.log();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
spinner.fail('Failed to load API keys');
|
|
80
|
+
if (error instanceof ApiError && error.code === 'AUTH_REQUIRED') {
|
|
81
|
+
console.log();
|
|
82
|
+
console.log(` ${formatWarning('Session expired. Please log in again.')}`);
|
|
83
|
+
console.log(` ${theme.muted(`Run ${theme.command('claudetools login')}`)}`);
|
|
84
|
+
console.log();
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
console.error(` ${formatError(error instanceof Error ? error.message : 'Unknown error', 'ERR_API')}`);
|
|
88
|
+
}
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Create a new API key
|
|
94
|
+
*/
|
|
95
|
+
export async function runKeysCreate(name) {
|
|
96
|
+
await requireAuth();
|
|
97
|
+
if (!name) {
|
|
98
|
+
console.log();
|
|
99
|
+
console.log(` ${formatError('Key name is required', 'ERR_MISSING_NAME')}`);
|
|
100
|
+
console.log();
|
|
101
|
+
console.log(` ${theme.muted('Usage: claudetools keys create <name>')}`);
|
|
102
|
+
console.log();
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
const spinner = ora(`Creating API key "${name}"...`).start();
|
|
106
|
+
try {
|
|
107
|
+
const api = getApiClient();
|
|
108
|
+
const { data } = await api.post('/keys', {
|
|
109
|
+
name,
|
|
110
|
+
scopes: ['*'], // Default to all scopes
|
|
111
|
+
});
|
|
112
|
+
if (!data) {
|
|
113
|
+
spinner.fail('Failed to create API key');
|
|
114
|
+
console.error(` ${formatError('No data received from server', 'ERR_NO_DATA')}`);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
spinner.succeed(`API key "${name}" created`);
|
|
118
|
+
console.log();
|
|
119
|
+
console.log(` ${theme.warning(theme.bold('Save this key now - it will not be shown again!'))}`);
|
|
120
|
+
console.log();
|
|
121
|
+
console.log(` ${theme.bold('Your API key:')}`);
|
|
122
|
+
console.log(` ${theme.success(data.key)}`);
|
|
123
|
+
console.log();
|
|
124
|
+
console.log(` ${theme.muted('Copy to clipboard:')}`);
|
|
125
|
+
console.log(` ${theme.muted(`echo "${data.key}" | pbcopy`)}`);
|
|
126
|
+
console.log();
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
spinner.fail('Failed to create API key');
|
|
130
|
+
if (error instanceof ApiError && error.code === 'AUTH_REQUIRED') {
|
|
131
|
+
console.log();
|
|
132
|
+
console.log(` ${formatWarning('Session expired. Please log in again.')}`);
|
|
133
|
+
console.log(` ${theme.muted(`Run ${theme.command('claudetools login')}`)}`);
|
|
134
|
+
console.log();
|
|
135
|
+
}
|
|
136
|
+
else if (error instanceof ApiError && error.code === 'QUOTA_EXCEEDED') {
|
|
137
|
+
console.log();
|
|
138
|
+
console.log(` ${formatWarning('API key quota exceeded.')}`);
|
|
139
|
+
console.log(` ${theme.muted('Delete an existing key or upgrade your plan.')}`);
|
|
140
|
+
console.log();
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
console.error(` ${formatError(error instanceof Error ? error.message : 'Unknown error', 'ERR_API')}`);
|
|
144
|
+
}
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Revoke an API key
|
|
150
|
+
*/
|
|
151
|
+
export async function runKeysRevoke(keyId, options = {}) {
|
|
152
|
+
await requireAuth();
|
|
153
|
+
if (!keyId) {
|
|
154
|
+
console.log();
|
|
155
|
+
console.log(` ${formatError('Key ID is required', 'ERR_MISSING_ID')}`);
|
|
156
|
+
console.log();
|
|
157
|
+
console.log(` ${theme.muted('Usage: claudetools keys revoke <id>')}`);
|
|
158
|
+
console.log(` ${theme.muted(`Run ${theme.command('claudetools keys list')} to see key IDs`)}`);
|
|
159
|
+
console.log();
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
// Check if trying to revoke current key
|
|
163
|
+
const currentKey = await getCredential();
|
|
164
|
+
if (currentKey) {
|
|
165
|
+
// Get the key details first to check the prefix
|
|
166
|
+
const spinner = ora('Checking key...').start();
|
|
167
|
+
try {
|
|
168
|
+
const api = getApiClient();
|
|
169
|
+
const { data } = await api.get('/keys');
|
|
170
|
+
spinner.stop();
|
|
171
|
+
if (data) {
|
|
172
|
+
const keyToRevoke = data.keys.find(k => k.id === keyId);
|
|
173
|
+
if (keyToRevoke) {
|
|
174
|
+
const currentKeyPrefix = currentKey.substring(0, 8);
|
|
175
|
+
if (keyToRevoke.keyPrefix === currentKeyPrefix) {
|
|
176
|
+
console.log();
|
|
177
|
+
console.log(` ${formatError('Cannot revoke the currently active key', 'ERR_ACTIVE_KEY')}`);
|
|
178
|
+
console.log(` ${theme.muted('Log in with a different key or create a new one first')}`);
|
|
179
|
+
console.log();
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
spinner.stop();
|
|
187
|
+
// Continue - we'll let the API handle validation
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Prompt for confirmation unless --force
|
|
191
|
+
if (!options.force) {
|
|
192
|
+
console.log();
|
|
193
|
+
const confirmed = await confirm(` ${theme.warning('Are you sure you want to revoke this API key?')}`);
|
|
194
|
+
if (!confirmed) {
|
|
195
|
+
console.log();
|
|
196
|
+
console.log(` ${theme.muted('Cancelled.')}`);
|
|
197
|
+
console.log();
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const spinner = ora('Revoking API key...').start();
|
|
202
|
+
try {
|
|
203
|
+
const api = getApiClient();
|
|
204
|
+
await api.delete(`/keys/${keyId}`);
|
|
205
|
+
spinner.succeed('API key revoked');
|
|
206
|
+
console.log();
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
spinner.fail('Failed to revoke API key');
|
|
210
|
+
if (error instanceof ApiError && error.code === 'AUTH_REQUIRED') {
|
|
211
|
+
console.log();
|
|
212
|
+
console.log(` ${formatWarning('Session expired. Please log in again.')}`);
|
|
213
|
+
console.log(` ${theme.muted(`Run ${theme.command('claudetools login')}`)}`);
|
|
214
|
+
console.log();
|
|
215
|
+
}
|
|
216
|
+
else if (error instanceof ApiError && error.code === 'NOT_FOUND') {
|
|
217
|
+
console.log();
|
|
218
|
+
console.log(` ${formatWarning('Key not found.')}`);
|
|
219
|
+
console.log(` ${theme.muted(`Run ${theme.command('claudetools keys list')} to see available keys`)}`);
|
|
220
|
+
console.log();
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
console.error(` ${formatError(error instanceof Error ? error.message : 'Unknown error', 'ERR_API')}`);
|
|
224
|
+
}
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api-keys/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface UserConfig {
|
|
2
|
+
userId?: string;
|
|
3
|
+
email?: string;
|
|
4
|
+
name?: string;
|
|
5
|
+
tier?: string;
|
|
6
|
+
activeTeam?: string;
|
|
7
|
+
tokenExpiresAt?: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function loadConfig(): UserConfig;
|
|
10
|
+
export declare function saveConfig(config: UserConfig): void;
|
|
11
|
+
export declare function clearConfig(): void;
|
|
12
|
+
export declare function isLoggedIn(): Promise<boolean>;
|
|
13
|
+
export declare function requireAuth(): Promise<UserConfig>;
|
|
14
|
+
export declare function getConfigDir(): string;
|
|
15
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/auth/config.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAQD,wBAAgB,UAAU,IAAI,UAAU,CAUvC;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAOnD;AAED,wBAAgB,WAAW,IAAI,IAAI,CAQlC;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC,CAanD;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,UAAU,CAAC,CASvD;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { hasCredential } from './keychain.js';
|
|
5
|
+
const CONFIG_DIR = join(homedir(), '.claudetools');
|
|
6
|
+
const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
|
|
7
|
+
function ensureConfigDir() {
|
|
8
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
9
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function loadConfig() {
|
|
13
|
+
try {
|
|
14
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
15
|
+
return {};
|
|
16
|
+
}
|
|
17
|
+
const content = readFileSync(CONFIG_FILE, 'utf-8');
|
|
18
|
+
return JSON.parse(content);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function saveConfig(config) {
|
|
25
|
+
ensureConfigDir();
|
|
26
|
+
const existing = loadConfig();
|
|
27
|
+
const merged = { ...existing, ...config };
|
|
28
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2), {
|
|
29
|
+
mode: 0o600,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export function clearConfig() {
|
|
33
|
+
try {
|
|
34
|
+
if (existsSync(CONFIG_FILE)) {
|
|
35
|
+
unlinkSync(CONFIG_FILE);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Ignore errors
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export async function isLoggedIn() {
|
|
43
|
+
const config = loadConfig();
|
|
44
|
+
if (!config.userId || !config.email) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
// Verify an actual credential exists (not just a crafted config)
|
|
48
|
+
const credentialExists = await hasCredential();
|
|
49
|
+
if (!credentialExists) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
export async function requireAuth() {
|
|
55
|
+
if (!(await isLoggedIn())) {
|
|
56
|
+
console.log();
|
|
57
|
+
console.log(' Authentication required.');
|
|
58
|
+
console.log(' Run: claudetools login');
|
|
59
|
+
console.log();
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
return loadConfig();
|
|
63
|
+
}
|
|
64
|
+
export function getConfigDir() {
|
|
65
|
+
return CONFIG_DIR;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/auth/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACpF,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;AACnD,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAWpD,SAAS,eAAe;IACtB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC7B,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAkB;IAC3C,eAAe,EAAE,CAAC;IAClB,MAAM,QAAQ,GAAG,UAAU,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,MAAM,EAAE,CAAC;IAC1C,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;QAC1D,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5B,UAAU,CAAC,WAAW,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,gBAAgB;IAClB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACpC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,iEAAiE;IACjE,MAAM,gBAAgB,GAAG,MAAM,aAAa,EAAE,CAAC;IAC/C,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC,CAAC,MAAM,UAAU,EAAE,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function runLogin(options?: {
|
|
2
|
+
noBrowser?: boolean;
|
|
3
|
+
}): Promise<void>;
|
|
4
|
+
export declare function runLogout(): Promise<void>;
|
|
5
|
+
export declare function runWhoami(options?: {
|
|
6
|
+
json?: boolean;
|
|
7
|
+
}): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAoDA,wBAAsB,QAAQ,CAAC,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAoFnF;AA+HD,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAmC/C;AAED,wBAAsB,SAAS,CAAC,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAkE/E"}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { createServer } from 'node:http';
|
|
2
|
+
import { URL } from 'node:url';
|
|
3
|
+
import crypto from 'node:crypto';
|
|
4
|
+
import ora from 'ora';
|
|
5
|
+
import { getApiClient, ApiError } from '../lib/api.js';
|
|
6
|
+
import { saveConfig, clearConfig, isLoggedIn } from './config.js';
|
|
7
|
+
import { storeCredential, deleteCredential } from './keychain.js';
|
|
8
|
+
import { theme, formatError, formatSuccess, formatWarning, formatInfo } from '../lib/theme.js';
|
|
9
|
+
import { openBrowser } from '../lib/browser.js';
|
|
10
|
+
function formatTier(tier) {
|
|
11
|
+
switch (tier) {
|
|
12
|
+
case 'free':
|
|
13
|
+
return theme.muted('🆓 Free');
|
|
14
|
+
case 'pro':
|
|
15
|
+
return theme.highlight('⭐ Pro');
|
|
16
|
+
case 'team':
|
|
17
|
+
return theme.brand('👥 Team');
|
|
18
|
+
case 'enterprise':
|
|
19
|
+
return theme.warning('🏢 Enterprise');
|
|
20
|
+
default:
|
|
21
|
+
return tier;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export async function runLogin(options = {}) {
|
|
25
|
+
// Check if already logged in
|
|
26
|
+
if (await isLoggedIn()) {
|
|
27
|
+
console.log();
|
|
28
|
+
console.log(` ${formatInfo('Already logged in.')}`);
|
|
29
|
+
console.log(` ${theme.muted(`Run ${theme.command('claudetools logout')} to sign out first.`)}`);
|
|
30
|
+
console.log();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
// Generate a random state for CSRF protection
|
|
34
|
+
const state = crypto.randomUUID();
|
|
35
|
+
// Start local HTTP server on a random available port
|
|
36
|
+
const { port, waitForCallback, close } = await startCallbackServer(state);
|
|
37
|
+
// Build the auth URL — derive web origin from the API base URL
|
|
38
|
+
const apiBase = process.env.CLAUDETOOLS_API_URL || 'https://claudetools.com/api';
|
|
39
|
+
const webBase = apiBase.replace(/\/api\/?$/, '');
|
|
40
|
+
const authUrl = `${webBase}/cli-auth?port=${port}&state=${state}`;
|
|
41
|
+
console.log();
|
|
42
|
+
console.log(` ${theme.bold('To authenticate, visit:')}`);
|
|
43
|
+
console.log();
|
|
44
|
+
console.log(` ${theme.highlight(authUrl)}`);
|
|
45
|
+
console.log();
|
|
46
|
+
// Open browser automatically unless --no-browser
|
|
47
|
+
if (!options.noBrowser) {
|
|
48
|
+
try {
|
|
49
|
+
await openBrowser(authUrl);
|
|
50
|
+
console.log(` ${theme.muted('Browser opened automatically.')}`);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
console.log(` ${theme.muted('Could not open browser. Please visit the URL above.')}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
console.log();
|
|
57
|
+
const spinner = ora('Waiting for authentication...').start();
|
|
58
|
+
try {
|
|
59
|
+
// Wait for the redirect callback (timeout after 5 minutes)
|
|
60
|
+
const credentials = await waitForCallback(5 * 60 * 1000);
|
|
61
|
+
spinner.succeed('Authenticated successfully!');
|
|
62
|
+
// Store credentials in keychain
|
|
63
|
+
const tokenExpiresAt = Date.now() + credentials.expiresIn * 1000;
|
|
64
|
+
await storeCredential(credentials.token);
|
|
65
|
+
saveConfig({
|
|
66
|
+
userId: credentials.userId,
|
|
67
|
+
email: credentials.email,
|
|
68
|
+
name: credentials.name || undefined,
|
|
69
|
+
tier: credentials.tier,
|
|
70
|
+
tokenExpiresAt,
|
|
71
|
+
});
|
|
72
|
+
// Push credentials to sync engine for cloud sync
|
|
73
|
+
try {
|
|
74
|
+
const { isSyncEngineRunning, getSyncEngineClient } = await import('../sync-engine/client.js');
|
|
75
|
+
if (await isSyncEngineRunning()) {
|
|
76
|
+
const syncClient = getSyncEngineClient();
|
|
77
|
+
await syncClient.authStore({
|
|
78
|
+
token: credentials.token,
|
|
79
|
+
userId: credentials.userId,
|
|
80
|
+
email: credentials.email,
|
|
81
|
+
tier: credentials.tier,
|
|
82
|
+
expiresAt: new Date(tokenExpiresAt).toISOString(),
|
|
83
|
+
refreshToken: undefined,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// Best-effort — cloud sync will work when engine starts
|
|
89
|
+
}
|
|
90
|
+
console.log();
|
|
91
|
+
console.log(` ${formatSuccess(`Welcome, ${theme.bold(credentials.name || credentials.email)}!`)}`);
|
|
92
|
+
console.log();
|
|
93
|
+
}
|
|
94
|
+
catch (authError) {
|
|
95
|
+
spinner.fail(authError instanceof Error ? authError.message : 'Authentication failed');
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
close();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// ── Local callback server ─────────────────────────────────────────────
|
|
103
|
+
async function startCallbackServer(expectedState) {
|
|
104
|
+
return new Promise((resolveServer, rejectServer) => {
|
|
105
|
+
let callbackResolve;
|
|
106
|
+
let timeoutId;
|
|
107
|
+
const server = createServer(async (req, res) => {
|
|
108
|
+
const requestUrl = new URL(req.url || '/', 'http://localhost');
|
|
109
|
+
if (requestUrl.pathname === '/callback') {
|
|
110
|
+
try {
|
|
111
|
+
let params;
|
|
112
|
+
if (req.method === 'POST') {
|
|
113
|
+
// Parse URL-encoded form body with size limit
|
|
114
|
+
const MAX_BODY_SIZE = 8192;
|
|
115
|
+
let body;
|
|
116
|
+
try {
|
|
117
|
+
body = await new Promise((resolve, reject) => {
|
|
118
|
+
let formData = '';
|
|
119
|
+
req.on('data', (chunk) => {
|
|
120
|
+
formData += chunk.toString();
|
|
121
|
+
if (formData.length > MAX_BODY_SIZE) {
|
|
122
|
+
req.destroy();
|
|
123
|
+
reject(new Error('Body too large'));
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
req.on('end', () => { resolve(formData); });
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
res.writeHead(413, { 'Content-Type': 'text/html' });
|
|
131
|
+
res.end('<html><body><h2>Authentication failed</h2>' +
|
|
132
|
+
'<p>Request body too large.</p></body></html>');
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
params = new URLSearchParams(body);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
// GET fallback for backwards compatibility
|
|
139
|
+
params = requestUrl.searchParams;
|
|
140
|
+
}
|
|
141
|
+
const receivedState = params.get('state');
|
|
142
|
+
const token = params.get('token');
|
|
143
|
+
const userId = params.get('userId');
|
|
144
|
+
const email = params.get('email');
|
|
145
|
+
const name = params.get('name') || '';
|
|
146
|
+
const tier = params.get('tier') || 'free';
|
|
147
|
+
const expiresIn = parseInt(params.get('expiresIn') || '604800', 10);
|
|
148
|
+
// Validate state to prevent CSRF
|
|
149
|
+
if (receivedState !== expectedState) {
|
|
150
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
151
|
+
res.end('<html><body><h2>Authentication failed</h2>' +
|
|
152
|
+
'<p>Invalid state parameter. Please try again.</p></body></html>');
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (!token || !userId || !email) {
|
|
156
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
157
|
+
res.end('<html><body><h2>Authentication failed</h2>' +
|
|
158
|
+
'<p>Missing required parameters.</p></body></html>');
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
// Send success page to browser
|
|
162
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
163
|
+
res.end('<html><body style="text-align:center;padding:40px;font-family:system-ui;">' +
|
|
164
|
+
'<h2>Authentication successful!</h2>' +
|
|
165
|
+
'<p>You can close this tab and return to your terminal.</p>' +
|
|
166
|
+
'</body></html>');
|
|
167
|
+
// Resolve the callback promise
|
|
168
|
+
callbackResolve({ token, userId, email, name, tier, expiresIn });
|
|
169
|
+
clearTimeout(timeoutId);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
res.writeHead(500, { 'Content-Type': 'text/html' });
|
|
173
|
+
res.end('<html><body><h2>Authentication failed</h2><p>Internal error. Please try again.</p></body></html>');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
res.writeHead(404);
|
|
178
|
+
res.end();
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
// Listen on random available port (0 = OS assigns)
|
|
182
|
+
server.listen(0, '127.0.0.1', () => {
|
|
183
|
+
const address = server.address();
|
|
184
|
+
if (!address || typeof address === 'string') {
|
|
185
|
+
rejectServer(new Error('Failed to start callback server'));
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
resolveServer({
|
|
189
|
+
port: address.port,
|
|
190
|
+
waitForCallback: (timeoutMs) => {
|
|
191
|
+
return new Promise((resolve, reject) => {
|
|
192
|
+
callbackResolve = resolve;
|
|
193
|
+
timeoutId = setTimeout(() => {
|
|
194
|
+
reject(new Error('Authentication timed out. Please try again.'));
|
|
195
|
+
server.close();
|
|
196
|
+
}, timeoutMs);
|
|
197
|
+
});
|
|
198
|
+
},
|
|
199
|
+
close: () => {
|
|
200
|
+
clearTimeout(timeoutId);
|
|
201
|
+
server.close();
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
server.on('error', (serverError) => {
|
|
206
|
+
rejectServer(new Error(`Failed to start callback server: ${serverError.message}`));
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
export async function runLogout() {
|
|
211
|
+
if (!(await isLoggedIn())) {
|
|
212
|
+
console.log();
|
|
213
|
+
console.log(` ${theme.muted('Not logged in.')}`);
|
|
214
|
+
console.log();
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const spinner = ora('Signing out...').start();
|
|
218
|
+
try {
|
|
219
|
+
// Clear stored credentials
|
|
220
|
+
await deleteCredential();
|
|
221
|
+
clearConfig();
|
|
222
|
+
// Clear sync engine credentials
|
|
223
|
+
try {
|
|
224
|
+
const { isSyncEngineRunning, getSyncEngineClient } = await import('../sync-engine/client.js');
|
|
225
|
+
if (await isSyncEngineRunning()) {
|
|
226
|
+
const syncClient = getSyncEngineClient();
|
|
227
|
+
await syncClient.authClear();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
// Best-effort — sync engine may not be running
|
|
232
|
+
}
|
|
233
|
+
spinner.succeed('Signed out successfully');
|
|
234
|
+
console.log();
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
spinner.fail('Failed to sign out');
|
|
238
|
+
console.error(` ${formatError(error instanceof Error ? error.message : 'Unknown error', 'ERR_LOGOUT')}`);
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
export async function runWhoami(options = {}) {
|
|
243
|
+
if (!(await isLoggedIn())) {
|
|
244
|
+
console.log();
|
|
245
|
+
console.log(` ${formatWarning('Not logged in.')}`);
|
|
246
|
+
console.log(` ${theme.muted(`Run ${theme.command('claudetools login')} to authenticate.`)}`);
|
|
247
|
+
console.log();
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const spinner = ora('Loading user info...').start();
|
|
251
|
+
try {
|
|
252
|
+
const api = getApiClient();
|
|
253
|
+
const { data: user } = await api.get('/users/me');
|
|
254
|
+
if (!user) {
|
|
255
|
+
spinner.fail('Failed to load user info');
|
|
256
|
+
console.error(` ${formatError('No data received from server', 'ERR_NO_DATA')}`);
|
|
257
|
+
process.exit(1);
|
|
258
|
+
}
|
|
259
|
+
spinner.stop();
|
|
260
|
+
if (options.json) {
|
|
261
|
+
console.log(JSON.stringify(user, null, 2));
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
console.log();
|
|
265
|
+
console.log(` ${theme.bold('Name:')} ${user.name || theme.muted('Not set')}`);
|
|
266
|
+
console.log(` ${theme.bold('Email:')} ${user.email}`);
|
|
267
|
+
console.log(` ${theme.bold('Tier:')} ${formatTier(user.tier)}`);
|
|
268
|
+
// Show subscription info for paid tiers
|
|
269
|
+
if (user.tier !== 'free' && user.subscriptionCurrentPeriodEnd) {
|
|
270
|
+
const renewDate = new Date(user.subscriptionCurrentPeriodEnd).toLocaleDateString();
|
|
271
|
+
console.log(` ${theme.bold('Renews:')} ${renewDate}`);
|
|
272
|
+
if (user.subscriptionStatus && user.subscriptionStatus !== 'active') {
|
|
273
|
+
console.log(` ${theme.bold('Status:')} ${theme.warning(user.subscriptionStatus)}`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
console.log(` ${theme.bold('ID:')} ${theme.muted(user.id)}`);
|
|
277
|
+
console.log();
|
|
278
|
+
// Show upgrade prompt for free users
|
|
279
|
+
if (user.tier === 'free') {
|
|
280
|
+
console.log(` ${theme.muted('Upgrade to Pro for cloud sync and unlimited stacks:')}`);
|
|
281
|
+
console.log(` ${theme.command('claudetools upgrade')}`);
|
|
282
|
+
console.log();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
spinner.fail('Failed to load user info');
|
|
287
|
+
if (error instanceof ApiError && error.code === 'AUTH_REQUIRED') {
|
|
288
|
+
console.log();
|
|
289
|
+
console.log(` ${formatWarning('Session expired. Please log in again.')}`);
|
|
290
|
+
console.log(` ${theme.muted(`Run ${theme.command('claudetools login')}`)}`);
|
|
291
|
+
console.log();
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
console.error(` ${formatError(error instanceof Error ? error.message : 'Unknown error', 'ERR_WHOAMI')}`);
|
|
295
|
+
}
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
//# sourceMappingURL=index.js.map
|