teleportation-cli 1.0.0 → 1.0.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/.claude/hooks/heartbeat.mjs +67 -2
- package/.claude/hooks/permission_request.mjs +55 -26
- package/.claude/hooks/pre_tool_use.mjs +29 -2
- package/.claude/hooks/session-register.mjs +64 -5
- package/.claude/hooks/user_prompt_submit.mjs +54 -0
- package/README.md +36 -12
- package/lib/auth/claude-key-extractor.js +196 -0
- package/lib/auth/credentials.js +7 -2
- package/lib/cli/remote-commands.js +649 -0
- package/lib/install/installer.js +22 -7
- package/lib/remote/code-sync.js +213 -0
- package/lib/remote/init-script-robust.js +187 -0
- package/lib/remote/liveport-client.js +417 -0
- package/lib/remote/orchestrator.js +480 -0
- package/lib/remote/pr-creator.js +382 -0
- package/lib/remote/providers/base-provider.js +407 -0
- package/lib/remote/providers/daytona-provider.js +506 -0
- package/lib/remote/providers/fly-provider.js +611 -0
- package/lib/remote/providers/provider-factory.js +228 -0
- package/lib/remote/results-delivery.js +333 -0
- package/lib/remote/session-manager.js +273 -0
- package/lib/remote/state-capture.js +324 -0
- package/lib/remote/vault-client.js +478 -0
- package/lib/session/metadata.js +80 -49
- package/lib/session/mute-checker.js +2 -1
- package/lib/utils/vault-errors.js +353 -0
- package/package.json +5 -5
- package/teleportation-cli.cjs +417 -7
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code API Key Extractor
|
|
3
|
+
*
|
|
4
|
+
* Extracts the ANTHROPIC_API_KEY from the user's local Claude Code installation.
|
|
5
|
+
* Tries multiple methods to find the key.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { exec } from 'child_process';
|
|
9
|
+
import { promisify } from 'util';
|
|
10
|
+
import fs from 'fs/promises';
|
|
11
|
+
import os from 'os';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
|
|
14
|
+
const execAsync = promisify(exec);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Try to get API key from macOS keychain
|
|
18
|
+
*/
|
|
19
|
+
async function getFromKeychain() {
|
|
20
|
+
try {
|
|
21
|
+
// Try common keychain entries for Claude/Anthropic
|
|
22
|
+
const services = [
|
|
23
|
+
'claude.ai',
|
|
24
|
+
'anthropic.com',
|
|
25
|
+
'Claude',
|
|
26
|
+
'Anthropic',
|
|
27
|
+
'claude-code',
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
for (const service of services) {
|
|
31
|
+
try {
|
|
32
|
+
const { stdout } = await execAsync(`security find-generic-password -s "${service}" -w 2>/dev/null`);
|
|
33
|
+
if (stdout && stdout.trim().startsWith('sk-ant-')) {
|
|
34
|
+
return stdout.trim();
|
|
35
|
+
}
|
|
36
|
+
} catch {}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Try finding by account name
|
|
40
|
+
const accounts = ['api-key', 'apikey', 'token'];
|
|
41
|
+
for (const acct of accounts) {
|
|
42
|
+
try {
|
|
43
|
+
const { stdout } = await execAsync(`security find-generic-password -a "${acct}" -w 2>/dev/null`);
|
|
44
|
+
if (stdout && stdout.trim().startsWith('sk-ant-')) {
|
|
45
|
+
return stdout.trim();
|
|
46
|
+
}
|
|
47
|
+
} catch {}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return null;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Try to get API key from environment
|
|
58
|
+
*/
|
|
59
|
+
function getFromEnvironment() {
|
|
60
|
+
return process.env.ANTHROPIC_API_KEY ||
|
|
61
|
+
process.env.CLAUDE_API_KEY ||
|
|
62
|
+
process.env.CLAUDE_CODE_API_KEY ||
|
|
63
|
+
null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Try to get API key from Claude Code config files
|
|
68
|
+
*/
|
|
69
|
+
async function getFromClaudeConfig() {
|
|
70
|
+
try {
|
|
71
|
+
const homeDir = os.homedir();
|
|
72
|
+
const configPaths = [
|
|
73
|
+
path.join(homeDir, '.claude', 'config.json'),
|
|
74
|
+
path.join(homeDir, '.claude', 'settings.json'),
|
|
75
|
+
path.join(homeDir, '.claude', 'credentials.json'),
|
|
76
|
+
path.join(homeDir, '.config', 'claude', 'config.json'),
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
for (const configPath of configPaths) {
|
|
80
|
+
try {
|
|
81
|
+
const content = await fs.readFile(configPath, 'utf-8');
|
|
82
|
+
const config = JSON.parse(content);
|
|
83
|
+
|
|
84
|
+
// Check various possible key names
|
|
85
|
+
const key = config.apiKey ||
|
|
86
|
+
config.anthropicApiKey ||
|
|
87
|
+
config.ANTHROPIC_API_KEY ||
|
|
88
|
+
config.api_key ||
|
|
89
|
+
config.token;
|
|
90
|
+
|
|
91
|
+
if (key && key.startsWith('sk-ant-')) {
|
|
92
|
+
return key;
|
|
93
|
+
}
|
|
94
|
+
} catch {}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return null;
|
|
98
|
+
} catch (error) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Try to get API key from running Claude Code process environment
|
|
105
|
+
*/
|
|
106
|
+
async function getFromRunningProcess() {
|
|
107
|
+
try {
|
|
108
|
+
// Get PID of running claude process
|
|
109
|
+
const { stdout: pids } = await execAsync(`pgrep -f "claude" 2>/dev/null || echo ""`);
|
|
110
|
+
|
|
111
|
+
if (!pids.trim()) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Try to read environment from process
|
|
116
|
+
for (const pid of pids.trim().split('\n')) {
|
|
117
|
+
if (!pid) continue;
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
// On macOS, we can try to read process environment via ps
|
|
121
|
+
const { stdout } = await execAsync(`ps eww ${pid} 2>/dev/null | grep -o "ANTHROPIC_API_KEY=[^ ]*" | cut -d= -f2`);
|
|
122
|
+
if (stdout && stdout.trim().startsWith('sk-ant-')) {
|
|
123
|
+
return stdout.trim();
|
|
124
|
+
}
|
|
125
|
+
} catch {}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return null;
|
|
129
|
+
} catch (error) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Main function to extract Claude Code API key
|
|
136
|
+
* Tries multiple methods in order of reliability
|
|
137
|
+
*
|
|
138
|
+
* @returns {Promise<string|null>} API key if found, null otherwise
|
|
139
|
+
*/
|
|
140
|
+
export async function extractClaudeApiKey() {
|
|
141
|
+
console.log('[claude-key-extractor] Attempting to extract API key from local Claude Code installation...');
|
|
142
|
+
|
|
143
|
+
// Method 1: Check environment first (fastest)
|
|
144
|
+
let apiKey = getFromEnvironment();
|
|
145
|
+
if (apiKey) {
|
|
146
|
+
console.log('[claude-key-extractor] ✅ Found API key in environment variables');
|
|
147
|
+
return apiKey;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Method 2: Check Claude Code config files
|
|
151
|
+
apiKey = await getFromClaudeConfig();
|
|
152
|
+
if (apiKey) {
|
|
153
|
+
console.log('[claude-key-extractor] ✅ Found API key in Claude Code config');
|
|
154
|
+
return apiKey;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Method 3: Check macOS keychain
|
|
158
|
+
apiKey = await getFromKeychain();
|
|
159
|
+
if (apiKey) {
|
|
160
|
+
console.log('[claude-key-extractor] ✅ Found API key in macOS keychain');
|
|
161
|
+
return apiKey;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Method 4: Try to read from running process
|
|
165
|
+
apiKey = await getFromRunningProcess();
|
|
166
|
+
if (apiKey) {
|
|
167
|
+
console.log('[claude-key-extractor] ✅ Found API key in running Claude Code process');
|
|
168
|
+
return apiKey;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
console.log('[claude-key-extractor] ⚠️ Could not find API key');
|
|
172
|
+
console.log('[claude-key-extractor] Please set ANTHROPIC_API_KEY environment variable');
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Get API key with fallback message
|
|
178
|
+
*/
|
|
179
|
+
export async function getClaudeApiKeyOrPrompt() {
|
|
180
|
+
const apiKey = await extractClaudeApiKey();
|
|
181
|
+
|
|
182
|
+
if (!apiKey) {
|
|
183
|
+
console.log('\n' + '='.repeat(60));
|
|
184
|
+
console.log('ANTHROPIC_API_KEY not found!');
|
|
185
|
+
console.log('='.repeat(60));
|
|
186
|
+
console.log('\nPlease set your API key using one of these methods:\n');
|
|
187
|
+
console.log('1. Environment variable:');
|
|
188
|
+
console.log(' export ANTHROPIC_API_KEY="sk-ant-..."');
|
|
189
|
+
console.log('\n2. Get your key from: https://console.anthropic.com/settings/keys');
|
|
190
|
+
console.log('\n3. If you\'re logged into Claude Code, try:');
|
|
191
|
+
console.log(' claude config show # (if supported)');
|
|
192
|
+
console.log('='.repeat(60) + '\n');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return apiKey;
|
|
196
|
+
}
|
package/lib/auth/credentials.js
CHANGED
|
@@ -27,8 +27,13 @@ async function getEncryptionKey(keyPath = DEFAULT_KEY_PATH) {
|
|
|
27
27
|
// For Windows: use Credential Manager or fallback to file
|
|
28
28
|
|
|
29
29
|
const platform = process.platform;
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
|
|
31
|
+
// Only attempt keychain when using the default key path. This allows tests and
|
|
32
|
+
// advanced callers to provide a custom key path without depending on keychain
|
|
33
|
+
// availability/behavior.
|
|
34
|
+
const shouldUseKeychain = keyPath === DEFAULT_KEY_PATH;
|
|
35
|
+
|
|
36
|
+
if (shouldUseKeychain && platform === 'darwin') {
|
|
32
37
|
// macOS - try to use keychain
|
|
33
38
|
try {
|
|
34
39
|
const { execSync } = await import('child_process');
|