@claudetools/cli 0.13.13 → 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 +15 -4
- 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,403 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hooks management for ClaudeTools CLI
|
|
3
|
+
*
|
|
4
|
+
* Hooks are automation scripts that run in response to Claude events.
|
|
5
|
+
* The sync engine acts as a single dispatcher that executes hook chains.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, rmSync, readdirSync, copyFileSync, chmodSync } from 'fs';
|
|
8
|
+
import { homedir } from 'os';
|
|
9
|
+
import { join, basename } from 'path';
|
|
10
|
+
import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
|
|
11
|
+
const HOOKS_DIR = join(homedir(), '.claude', 'hooks');
|
|
12
|
+
const SETTINGS_PATH = join(homedir(), '.claude', 'settings.json');
|
|
13
|
+
// Ensure hooks directory exists
|
|
14
|
+
if (!existsSync(HOOKS_DIR)) {
|
|
15
|
+
mkdirSync(HOOKS_DIR, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* List installed hooks
|
|
19
|
+
*/
|
|
20
|
+
export async function runHooksList(options) {
|
|
21
|
+
const hooks = listInstalledHooks();
|
|
22
|
+
if (options?.json) {
|
|
23
|
+
console.log(JSON.stringify(hooks, null, 2));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
console.log();
|
|
27
|
+
if (hooks.length === 0) {
|
|
28
|
+
console.log(' No hooks installed.');
|
|
29
|
+
console.log(' Add with: claudetools hook add <name>');
|
|
30
|
+
console.log();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
console.log(` Installed hooks (${hooks.length}):`);
|
|
34
|
+
console.log();
|
|
35
|
+
for (const hook of hooks) {
|
|
36
|
+
const eventIcon = getEventIcon(hook.event);
|
|
37
|
+
const asyncBadge = hook.async ? ' [async]' : '';
|
|
38
|
+
console.log(` ${eventIcon} ${hook.name}${asyncBadge}`);
|
|
39
|
+
console.log(` Event: ${hook.event}`);
|
|
40
|
+
if (hook.matcher && hook.matcher !== '*') {
|
|
41
|
+
console.log(` Matcher: ${hook.matcher}`);
|
|
42
|
+
}
|
|
43
|
+
console.log(` Command: ${hook.command}`);
|
|
44
|
+
console.log();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Add a hook to the hooks directory
|
|
49
|
+
*/
|
|
50
|
+
export async function runHookAdd(name, options) {
|
|
51
|
+
if (!name) {
|
|
52
|
+
console.error('Error: Missing hook name');
|
|
53
|
+
console.log('Usage: claudetools hook add <name> [options]');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
// If it's a path, copy the hook script
|
|
57
|
+
if (name.startsWith('./') || name.startsWith('/') || name.startsWith('~')) {
|
|
58
|
+
await copyHookScript(name);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// Otherwise create a new hook config
|
|
62
|
+
const event = options?.event || 'PreToolUse';
|
|
63
|
+
const matcher = options?.matcher || '*';
|
|
64
|
+
const command = options?.command;
|
|
65
|
+
if (!command) {
|
|
66
|
+
console.error('Error: Missing --command option');
|
|
67
|
+
console.log('Usage: claudetools hook add <name> --event <event> --command "<command>"');
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
const config = {
|
|
71
|
+
name,
|
|
72
|
+
event,
|
|
73
|
+
matcher,
|
|
74
|
+
command,
|
|
75
|
+
priority: options?.priority,
|
|
76
|
+
async: options?.async,
|
|
77
|
+
onFailure: options?.onFailure,
|
|
78
|
+
};
|
|
79
|
+
const configPath = join(HOOKS_DIR, `${name}.yaml`);
|
|
80
|
+
writeFileSync(configPath, stringifyYaml(config), 'utf-8');
|
|
81
|
+
console.log();
|
|
82
|
+
console.log(` Added hook: ${name}`);
|
|
83
|
+
console.log(` Event: ${event}`);
|
|
84
|
+
console.log(` Command: ${command}`);
|
|
85
|
+
console.log();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Remove a hook
|
|
89
|
+
*/
|
|
90
|
+
export async function runHookRemove(name) {
|
|
91
|
+
if (!name) {
|
|
92
|
+
console.error('Error: Missing hook name');
|
|
93
|
+
console.log('Usage: claudetools hook remove <name>');
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
const configPath = join(HOOKS_DIR, `${name}.yaml`);
|
|
97
|
+
const scriptPath = join(HOOKS_DIR, `${name}.sh`);
|
|
98
|
+
let removed = false;
|
|
99
|
+
if (existsSync(configPath)) {
|
|
100
|
+
rmSync(configPath);
|
|
101
|
+
removed = true;
|
|
102
|
+
}
|
|
103
|
+
if (existsSync(scriptPath)) {
|
|
104
|
+
rmSync(scriptPath);
|
|
105
|
+
removed = true;
|
|
106
|
+
}
|
|
107
|
+
if (removed) {
|
|
108
|
+
console.log();
|
|
109
|
+
console.log(` Removed hook: ${name}`);
|
|
110
|
+
console.log();
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
console.error(`Hook not found: ${name}`);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Sanitize hook command for safe execution
|
|
119
|
+
* Validates against command injection patterns
|
|
120
|
+
*/
|
|
121
|
+
function sanitizeHookCommand(command) {
|
|
122
|
+
// Block shell injection patterns
|
|
123
|
+
const dangerousPatterns = [
|
|
124
|
+
/[;&|`$(){}[\]<>]/, // Shell metacharacters
|
|
125
|
+
/\n|\r/, // Newlines
|
|
126
|
+
];
|
|
127
|
+
for (const pattern of dangerousPatterns) {
|
|
128
|
+
if (pattern.test(command)) {
|
|
129
|
+
throw new Error('Hook command contains potentially dangerous characters');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return command.trim();
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Test a hook
|
|
136
|
+
*/
|
|
137
|
+
export async function runHookTest(name, options) {
|
|
138
|
+
if (!name) {
|
|
139
|
+
console.error('Error: Missing hook name');
|
|
140
|
+
console.log('Usage: claudetools hook test <name> --tool <tool>');
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
const config = loadHookConfig(name);
|
|
144
|
+
if (!config) {
|
|
145
|
+
console.error(`Hook not found: ${name}`);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
const event = options?.event || config.event;
|
|
149
|
+
const tool = options?.tool || 'TestTool';
|
|
150
|
+
console.log();
|
|
151
|
+
console.log(` Testing hook: ${name}`);
|
|
152
|
+
console.log(` Event: ${event}`);
|
|
153
|
+
console.log(` Tool: ${tool}`);
|
|
154
|
+
console.log();
|
|
155
|
+
// Check if matcher would match
|
|
156
|
+
const wouldMatch = matchesPattern(config.matcher || '*', tool);
|
|
157
|
+
console.log(` Matcher: ${config.matcher || '*'}`);
|
|
158
|
+
console.log(` Would match: ${wouldMatch ? 'Yes' : 'No'}`);
|
|
159
|
+
console.log();
|
|
160
|
+
if (!wouldMatch) {
|
|
161
|
+
console.log(' Hook would not execute for this tool.');
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
// Execute the hook
|
|
165
|
+
console.log(' Executing command...');
|
|
166
|
+
console.log();
|
|
167
|
+
try {
|
|
168
|
+
const sanitizedCommand = sanitizeHookCommand(config.command);
|
|
169
|
+
const { spawn } = await import('child_process');
|
|
170
|
+
const child = spawn('sh', ['-c', sanitizedCommand], {
|
|
171
|
+
env: {
|
|
172
|
+
...process.env,
|
|
173
|
+
CLAUDETOOLS_EVENT: event,
|
|
174
|
+
CLAUDETOOLS_TOOL: tool,
|
|
175
|
+
},
|
|
176
|
+
stdio: 'inherit',
|
|
177
|
+
});
|
|
178
|
+
await new Promise((resolve) => {
|
|
179
|
+
child.on('close', (code) => {
|
|
180
|
+
console.log();
|
|
181
|
+
console.log(` Exit code: ${code}`);
|
|
182
|
+
console.log();
|
|
183
|
+
resolve();
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
console.log();
|
|
189
|
+
console.error(` Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
190
|
+
console.log();
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Install hook dispatchers in settings.json
|
|
196
|
+
*/
|
|
197
|
+
export async function runHooksInstall() {
|
|
198
|
+
console.log();
|
|
199
|
+
console.log(' Installing hook dispatchers...');
|
|
200
|
+
let settings = {};
|
|
201
|
+
if (existsSync(SETTINGS_PATH)) {
|
|
202
|
+
const content = readFileSync(SETTINGS_PATH, 'utf-8');
|
|
203
|
+
settings = JSON.parse(content);
|
|
204
|
+
}
|
|
205
|
+
// Create hooks section with single dispatcher per event
|
|
206
|
+
settings.hooks = {
|
|
207
|
+
PreToolUse: [
|
|
208
|
+
{
|
|
209
|
+
matcher: '*',
|
|
210
|
+
hooks: [{ type: 'command', command: 'claudetools hook dispatch PreToolUse' }],
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
PostToolUse: [
|
|
214
|
+
{
|
|
215
|
+
matcher: '*',
|
|
216
|
+
hooks: [{ type: 'command', command: 'claudetools hook dispatch PostToolUse' }],
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
};
|
|
220
|
+
writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2), 'utf-8');
|
|
221
|
+
console.log(' Hook dispatchers installed in settings.json');
|
|
222
|
+
console.log();
|
|
223
|
+
console.log(' The sync engine will now execute hook chains for:');
|
|
224
|
+
console.log(' - PreToolUse: Before each tool execution');
|
|
225
|
+
console.log(' - PostToolUse: After each tool execution');
|
|
226
|
+
console.log();
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Uninstall hook dispatchers from settings.json
|
|
230
|
+
*/
|
|
231
|
+
export async function runHooksUninstall() {
|
|
232
|
+
console.log();
|
|
233
|
+
console.log(' Removing hook dispatchers...');
|
|
234
|
+
if (!existsSync(SETTINGS_PATH)) {
|
|
235
|
+
console.log(' settings.json not found');
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const content = readFileSync(SETTINGS_PATH, 'utf-8');
|
|
239
|
+
const settings = JSON.parse(content);
|
|
240
|
+
delete settings.hooks;
|
|
241
|
+
writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2), 'utf-8');
|
|
242
|
+
console.log(' Hook dispatchers removed from settings.json');
|
|
243
|
+
console.log();
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Dispatch hook execution (called by Claude Code)
|
|
247
|
+
*/
|
|
248
|
+
export async function runHookDispatch(event) {
|
|
249
|
+
if (!event) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
// This would communicate with the sync engine to execute the hook chain
|
|
253
|
+
// For now, just execute hooks directly
|
|
254
|
+
const hooks = listInstalledHooks().filter((h) => h.event === event);
|
|
255
|
+
if (hooks.length === 0) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
// Sort by priority
|
|
259
|
+
hooks.sort((a, b) => (a.priority || 100) - (b.priority || 100));
|
|
260
|
+
const tool = process.env.CLAUDE_TOOL_NAME || '';
|
|
261
|
+
for (const hook of hooks) {
|
|
262
|
+
if (!matchesPattern(hook.matcher || '*', tool)) {
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
const sanitizedCommand = sanitizeHookCommand(hook.command);
|
|
267
|
+
const { spawnSync } = await import('child_process');
|
|
268
|
+
const result = spawnSync('sh', ['-c', sanitizedCommand], {
|
|
269
|
+
env: {
|
|
270
|
+
...process.env,
|
|
271
|
+
CLAUDETOOLS_EVENT: event,
|
|
272
|
+
CLAUDETOOLS_TOOL: tool,
|
|
273
|
+
},
|
|
274
|
+
timeout: (hook.timeout || 30) * 1000,
|
|
275
|
+
});
|
|
276
|
+
if (result.status !== 0 && hook.onFailure === 'block') {
|
|
277
|
+
process.stderr.write(result.stderr || '');
|
|
278
|
+
process.exit(2);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
// Hook command validation failed
|
|
283
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
284
|
+
if (hook.onFailure === 'block') {
|
|
285
|
+
process.stderr.write(`Hook '${hook.name}' failed: ${message}\n`);
|
|
286
|
+
process.exit(2);
|
|
287
|
+
}
|
|
288
|
+
// Warn or ignore based on onFailure setting
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// Helper functions
|
|
293
|
+
function listInstalledHooks() {
|
|
294
|
+
const hooks = [];
|
|
295
|
+
if (!existsSync(HOOKS_DIR)) {
|
|
296
|
+
return hooks;
|
|
297
|
+
}
|
|
298
|
+
const entries = readdirSync(HOOKS_DIR);
|
|
299
|
+
for (const entry of entries) {
|
|
300
|
+
if (entry.endsWith('.yaml') || entry.endsWith('.yml')) {
|
|
301
|
+
const config = loadHookConfig(entry.replace(/\.(yaml|yml)$/, ''));
|
|
302
|
+
if (config) {
|
|
303
|
+
hooks.push(config);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return hooks;
|
|
308
|
+
}
|
|
309
|
+
function loadHookConfig(name) {
|
|
310
|
+
const yamlPath = join(HOOKS_DIR, `${name}.yaml`);
|
|
311
|
+
const ymlPath = join(HOOKS_DIR, `${name}.yml`);
|
|
312
|
+
let configPath = null;
|
|
313
|
+
if (existsSync(yamlPath)) {
|
|
314
|
+
configPath = yamlPath;
|
|
315
|
+
}
|
|
316
|
+
else if (existsSync(ymlPath)) {
|
|
317
|
+
configPath = ymlPath;
|
|
318
|
+
}
|
|
319
|
+
if (!configPath) {
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
const content = readFileSync(configPath, 'utf-8');
|
|
323
|
+
return parseYaml(content);
|
|
324
|
+
}
|
|
325
|
+
async function copyHookScript(path) {
|
|
326
|
+
const resolvedPath = path.startsWith('~')
|
|
327
|
+
? join(homedir(), path.slice(1))
|
|
328
|
+
: path;
|
|
329
|
+
if (!existsSync(resolvedPath)) {
|
|
330
|
+
throw new Error(`File not found: ${resolvedPath}`);
|
|
331
|
+
}
|
|
332
|
+
const name = basename(resolvedPath, '.sh');
|
|
333
|
+
const targetPath = join(HOOKS_DIR, `${name}.sh`);
|
|
334
|
+
copyFileSync(resolvedPath, targetPath);
|
|
335
|
+
chmodSync(targetPath, 0o755);
|
|
336
|
+
console.log();
|
|
337
|
+
console.log(` Copied hook script: ${name}`);
|
|
338
|
+
console.log(` Location: ${targetPath}`);
|
|
339
|
+
console.log();
|
|
340
|
+
}
|
|
341
|
+
function matchesPattern(pattern, value) {
|
|
342
|
+
if (pattern === '*') {
|
|
343
|
+
return true;
|
|
344
|
+
}
|
|
345
|
+
// Support pipe-separated patterns like "Write|Edit"
|
|
346
|
+
const patterns = pattern.split('|').map((p) => p.trim());
|
|
347
|
+
for (const p of patterns) {
|
|
348
|
+
if (p === value) {
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
351
|
+
// Basic glob support
|
|
352
|
+
const regex = new RegExp('^' + p.replace(/\*/g, '.*').replace(/\?/g, '.') + '$');
|
|
353
|
+
if (regex.test(value)) {
|
|
354
|
+
return true;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
function getEventIcon(event) {
|
|
360
|
+
switch (event) {
|
|
361
|
+
case 'PreToolUse':
|
|
362
|
+
return '⏵';
|
|
363
|
+
case 'PostToolUse':
|
|
364
|
+
return '⏹';
|
|
365
|
+
default:
|
|
366
|
+
return '•';
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Show hooks help
|
|
371
|
+
*/
|
|
372
|
+
export function showHookHelp() {
|
|
373
|
+
console.log(`
|
|
374
|
+
claudetools hook - Manage hooks (automation scripts)
|
|
375
|
+
|
|
376
|
+
Usage:
|
|
377
|
+
claudetools hook list List installed hooks
|
|
378
|
+
claudetools hook add <name> Add a hook
|
|
379
|
+
claudetools hook remove <name> Remove a hook
|
|
380
|
+
claudetools hook test <name> Test a hook
|
|
381
|
+
claudetools hooks install Install dispatchers in settings.json
|
|
382
|
+
claudetools hooks uninstall Remove dispatchers from settings.json
|
|
383
|
+
|
|
384
|
+
Hook Events:
|
|
385
|
+
PreToolUse - Runs before each tool execution
|
|
386
|
+
PostToolUse - Runs after each tool execution
|
|
387
|
+
|
|
388
|
+
Options (for add):
|
|
389
|
+
--event <event> Event to trigger on (default: PreToolUse)
|
|
390
|
+
--matcher <pattern> Tool pattern to match (default: *)
|
|
391
|
+
--command "<cmd>" Command to execute
|
|
392
|
+
--priority <n> Execution order (lower = first)
|
|
393
|
+
--async Run asynchronously
|
|
394
|
+
--on-failure <action> block|warn|ignore (default: warn)
|
|
395
|
+
|
|
396
|
+
Examples:
|
|
397
|
+
claudetools hook add pre-lint --event PreToolUse --matcher "Write|Edit" --command "eslint \${FILE}"
|
|
398
|
+
claudetools hook test pre-lint --tool Write
|
|
399
|
+
claudetools hook remove pre-lint
|
|
400
|
+
claudetools hooks install
|
|
401
|
+
`);
|
|
402
|
+
}
|
|
403
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface ApiClientOptions {
|
|
2
|
+
authenticated?: boolean;
|
|
3
|
+
}
|
|
4
|
+
export interface ApiResponse<T> {
|
|
5
|
+
success: boolean;
|
|
6
|
+
data?: T;
|
|
7
|
+
error?: {
|
|
8
|
+
code: string;
|
|
9
|
+
message: string;
|
|
10
|
+
details?: Record<string, unknown>;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export declare class ApiError extends Error {
|
|
14
|
+
code: string;
|
|
15
|
+
details?: Record<string, unknown> | undefined;
|
|
16
|
+
constructor(code: string, message: string, details?: Record<string, unknown> | undefined);
|
|
17
|
+
}
|
|
18
|
+
export declare function getApiClient(options?: ApiClientOptions): {
|
|
19
|
+
get<T>(endpoint: string): Promise<ApiResponse<T>>;
|
|
20
|
+
post<T>(endpoint: string, body: unknown): Promise<ApiResponse<T>>;
|
|
21
|
+
put<T>(endpoint: string, body: unknown): Promise<ApiResponse<T>>;
|
|
22
|
+
delete<T>(endpoint: string): Promise<ApiResponse<T>>;
|
|
23
|
+
getRaw(endpoint: string): Promise<{
|
|
24
|
+
status: number;
|
|
25
|
+
body: string;
|
|
26
|
+
headers: Headers;
|
|
27
|
+
}>;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,gBAAgB;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC,CAAC;CACH;AAED,qBAAa,QAAS,SAAQ,KAAK;IAExB,IAAI,EAAE,MAAM;IAEZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAFjC,IAAI,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACR,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA;CAK3C;AAED,wBAAgB,YAAY,CAAC,OAAO,GAAE,gBAA0C;QAElE,CAAC,YAAY,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;SAI5C,CAAC,YAAY,MAAM,QAAQ,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAI7D,CAAC,YAAY,MAAM,QAAQ,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;WAIzD,CAAC,YAAY,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;qBAInC,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;EAI9F"}
|
package/dist/lib/api.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { getCredential, getRefreshToken, storeCredential } from '../auth/keychain.js';
|
|
5
|
+
import { loadConfig, saveConfig } from '../auth/config.js';
|
|
6
|
+
const API_BASE = process.env.CLAUDETOOLS_API_URL || 'https://claudetools.com/api';
|
|
7
|
+
// Read CLI version from package.json for User-Agent header
|
|
8
|
+
const __api_filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __api_dirname = dirname(__api_filename);
|
|
10
|
+
const cliVersion = (() => {
|
|
11
|
+
try {
|
|
12
|
+
const pkg = JSON.parse(readFileSync(join(__api_dirname, '..', '..', 'package.json'), 'utf-8'));
|
|
13
|
+
return pkg.version;
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return '0.0.0';
|
|
17
|
+
}
|
|
18
|
+
})();
|
|
19
|
+
const USER_AGENT = `claudetools-cli/${cliVersion}`;
|
|
20
|
+
export class ApiError extends Error {
|
|
21
|
+
code;
|
|
22
|
+
details;
|
|
23
|
+
constructor(code, message, details) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.code = code;
|
|
26
|
+
this.details = details;
|
|
27
|
+
this.name = 'ApiError';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function getApiClient(options = { authenticated: true }) {
|
|
31
|
+
return {
|
|
32
|
+
async get(endpoint) {
|
|
33
|
+
return makeRequest('GET', endpoint, undefined, options.authenticated);
|
|
34
|
+
},
|
|
35
|
+
async post(endpoint, body) {
|
|
36
|
+
return makeRequest('POST', endpoint, body, options.authenticated);
|
|
37
|
+
},
|
|
38
|
+
async put(endpoint, body) {
|
|
39
|
+
return makeRequest('PUT', endpoint, body, options.authenticated);
|
|
40
|
+
},
|
|
41
|
+
async delete(endpoint) {
|
|
42
|
+
return makeRequest('DELETE', endpoint, undefined, options.authenticated);
|
|
43
|
+
},
|
|
44
|
+
async getRaw(endpoint) {
|
|
45
|
+
return makeRawRequest('GET', endpoint, undefined, options.authenticated);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Refresh access token using refresh token
|
|
51
|
+
*/
|
|
52
|
+
async function refreshAccessToken() {
|
|
53
|
+
const refreshToken = await getRefreshToken();
|
|
54
|
+
if (!refreshToken) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const response = await fetch(`${API_BASE}/auth/refresh`, {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
headers: {
|
|
61
|
+
'Content-Type': 'application/json',
|
|
62
|
+
'User-Agent': USER_AGENT,
|
|
63
|
+
},
|
|
64
|
+
body: JSON.stringify({ refresh_token: refreshToken }),
|
|
65
|
+
});
|
|
66
|
+
if (!response.ok) {
|
|
67
|
+
// Refresh token is invalid or expired
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const json = (await response.json());
|
|
71
|
+
if (!json.data) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
const { access_token, expires_in } = json.data;
|
|
75
|
+
// Calculate new expiration
|
|
76
|
+
const expiresAt = Date.now() + (expires_in * 1000);
|
|
77
|
+
// Store new access token (keep same refresh token)
|
|
78
|
+
await storeCredential(access_token, refreshToken);
|
|
79
|
+
saveConfig({
|
|
80
|
+
tokenExpiresAt: expiresAt,
|
|
81
|
+
});
|
|
82
|
+
return access_token;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Check if token is expired or will expire soon (within 5 minutes)
|
|
90
|
+
*/
|
|
91
|
+
function isTokenExpired() {
|
|
92
|
+
const config = loadConfig();
|
|
93
|
+
if (!config.tokenExpiresAt) {
|
|
94
|
+
return false; // Let server validate — don't assume expired
|
|
95
|
+
}
|
|
96
|
+
const bufferMs = 5 * 60 * 1000; // 5 minutes
|
|
97
|
+
return Date.now() >= (config.tokenExpiresAt - bufferMs);
|
|
98
|
+
}
|
|
99
|
+
const MAX_RETRIES = 3;
|
|
100
|
+
/**
|
|
101
|
+
* Wait for the specified duration in milliseconds
|
|
102
|
+
*/
|
|
103
|
+
function delay(ms) {
|
|
104
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
105
|
+
}
|
|
106
|
+
const MAX_RETRY_AFTER_MS = 60_000;
|
|
107
|
+
/**
|
|
108
|
+
* Parse Retry-After header value into milliseconds.
|
|
109
|
+
* Supports both delta-seconds (e.g. "5") and HTTP-date formats.
|
|
110
|
+
* Falls back to the provided default if unparseable.
|
|
111
|
+
* Capped at 60 seconds to prevent a malicious server from blocking the client.
|
|
112
|
+
*/
|
|
113
|
+
function parseRetryAfter(headerValue, fallbackMs) {
|
|
114
|
+
if (!headerValue) {
|
|
115
|
+
return Math.min(fallbackMs, MAX_RETRY_AFTER_MS);
|
|
116
|
+
}
|
|
117
|
+
const seconds = Number(headerValue);
|
|
118
|
+
if (!Number.isNaN(seconds) && seconds >= 0) {
|
|
119
|
+
return Math.min(seconds * 1000, MAX_RETRY_AFTER_MS);
|
|
120
|
+
}
|
|
121
|
+
// Try HTTP-date format
|
|
122
|
+
const dateMs = Date.parse(headerValue);
|
|
123
|
+
if (!Number.isNaN(dateMs)) {
|
|
124
|
+
const waitMs = dateMs - Date.now();
|
|
125
|
+
return Math.min(Math.max(waitMs, 0), MAX_RETRY_AFTER_MS);
|
|
126
|
+
}
|
|
127
|
+
return Math.min(fallbackMs, MAX_RETRY_AFTER_MS);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Shared logic: refresh token if needed, build headers, execute fetch with
|
|
131
|
+
* 429 retry. Returns the raw Response for callers to process.
|
|
132
|
+
*/
|
|
133
|
+
async function fetchWithRetry(method, endpoint, body, authenticated = true) {
|
|
134
|
+
// Check if token needs refresh before making request
|
|
135
|
+
if (authenticated && isTokenExpired()) {
|
|
136
|
+
await refreshAccessToken();
|
|
137
|
+
// If refresh fails, still try with existing token — server may accept it
|
|
138
|
+
// (session tokens with 7-day expiry may still be valid even if client thinks expired)
|
|
139
|
+
}
|
|
140
|
+
const requestHeaders = {
|
|
141
|
+
'Content-Type': 'application/json',
|
|
142
|
+
'User-Agent': USER_AGENT,
|
|
143
|
+
};
|
|
144
|
+
if (authenticated) {
|
|
145
|
+
const accessToken = await getCredential();
|
|
146
|
+
if (!accessToken) {
|
|
147
|
+
throw new ApiError('AUTH_REQUIRED', 'No stored credentials found. Run: claudetools login');
|
|
148
|
+
}
|
|
149
|
+
requestHeaders['Authorization'] = `Bearer ${accessToken}`;
|
|
150
|
+
}
|
|
151
|
+
const url = `${API_BASE}${endpoint}`;
|
|
152
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
153
|
+
const response = await fetch(url, {
|
|
154
|
+
method,
|
|
155
|
+
headers: requestHeaders,
|
|
156
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
157
|
+
});
|
|
158
|
+
// Handle 429 rate limiting with retry
|
|
159
|
+
if (response.status === 429 && attempt < MAX_RETRIES) {
|
|
160
|
+
const retryAfterMs = parseRetryAfter(response.headers.get('Retry-After'), (attempt + 1) * 1000);
|
|
161
|
+
await delay(retryAfterMs);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
return response;
|
|
165
|
+
}
|
|
166
|
+
// Should not reach here, but handle gracefully
|
|
167
|
+
throw new ApiError('RATE_LIMITED', 'Request rate limited after maximum retries. Try again later.');
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Throw an ApiError from a JSON error payload (string or structured object).
|
|
171
|
+
*/
|
|
172
|
+
function throwApiError(rawError, json, status, statusText) {
|
|
173
|
+
if (rawError) {
|
|
174
|
+
if (typeof rawError === 'string') {
|
|
175
|
+
throw new ApiError(rawError, rawError);
|
|
176
|
+
}
|
|
177
|
+
if (json.error && typeof json.error === 'object') {
|
|
178
|
+
throw new ApiError(json.error.code, json.error.message, json.error.details);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
throw new ApiError('UNKNOWN_ERROR', `HTTP ${status}: ${statusText}`);
|
|
182
|
+
}
|
|
183
|
+
async function makeRawRequest(method, endpoint, body, authenticated = true) {
|
|
184
|
+
const response = await fetchWithRetry(method, endpoint, body, authenticated);
|
|
185
|
+
const responseBody = await response.text();
|
|
186
|
+
if (!response.ok) {
|
|
187
|
+
try {
|
|
188
|
+
const json = JSON.parse(responseBody);
|
|
189
|
+
throwApiError(json.error, json, response.status, response.statusText);
|
|
190
|
+
}
|
|
191
|
+
catch (parseError) {
|
|
192
|
+
if (parseError instanceof ApiError)
|
|
193
|
+
throw parseError;
|
|
194
|
+
// Not JSON, throw generic error
|
|
195
|
+
}
|
|
196
|
+
throw new ApiError('UNKNOWN_ERROR', `HTTP ${response.status}: ${response.statusText}`);
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
status: response.status,
|
|
200
|
+
body: responseBody,
|
|
201
|
+
headers: response.headers,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
async function makeRequest(method, endpoint, body, authenticated = true) {
|
|
205
|
+
const response = await fetchWithRetry(method, endpoint, body, authenticated);
|
|
206
|
+
const json = (await response.json());
|
|
207
|
+
if (!response.ok) {
|
|
208
|
+
const rawError = json.error;
|
|
209
|
+
throwApiError(rawError, json, response.status, response.statusText);
|
|
210
|
+
}
|
|
211
|
+
return json;
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=api.js.map
|