aemeathcli 1.0.0

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.
Files changed (102) hide show
  1. package/README.md +607 -0
  2. package/dist/App-P4MYD4QY.js +2719 -0
  3. package/dist/App-P4MYD4QY.js.map +1 -0
  4. package/dist/api-key-fallback-YQQBOQIL.js +11 -0
  5. package/dist/api-key-fallback-YQQBOQIL.js.map +1 -0
  6. package/dist/chunk-4IJD72YB.js +184 -0
  7. package/dist/chunk-4IJD72YB.js.map +1 -0
  8. package/dist/chunk-6PDJ45T4.js +325 -0
  9. package/dist/chunk-6PDJ45T4.js.map +1 -0
  10. package/dist/chunk-CARHU3DO.js +562 -0
  11. package/dist/chunk-CARHU3DO.js.map +1 -0
  12. package/dist/chunk-CGEV3ARR.js +80 -0
  13. package/dist/chunk-CGEV3ARR.js.map +1 -0
  14. package/dist/chunk-CS5X3BWX.js +27 -0
  15. package/dist/chunk-CS5X3BWX.js.map +1 -0
  16. package/dist/chunk-CYQNBB25.js +44 -0
  17. package/dist/chunk-CYQNBB25.js.map +1 -0
  18. package/dist/chunk-DAHGLHNR.js +657 -0
  19. package/dist/chunk-DAHGLHNR.js.map +1 -0
  20. package/dist/chunk-H66O5Z2V.js +305 -0
  21. package/dist/chunk-H66O5Z2V.js.map +1 -0
  22. package/dist/chunk-HCIHOHLX.js +322 -0
  23. package/dist/chunk-HCIHOHLX.js.map +1 -0
  24. package/dist/chunk-HMJRPNPZ.js +1031 -0
  25. package/dist/chunk-HMJRPNPZ.js.map +1 -0
  26. package/dist/chunk-I5PZ4JTS.js +119 -0
  27. package/dist/chunk-I5PZ4JTS.js.map +1 -0
  28. package/dist/chunk-IYW62KKR.js +255 -0
  29. package/dist/chunk-IYW62KKR.js.map +1 -0
  30. package/dist/chunk-JAXXTYID.js +51 -0
  31. package/dist/chunk-JAXXTYID.js.map +1 -0
  32. package/dist/chunk-LSOYPSAT.js +183 -0
  33. package/dist/chunk-LSOYPSAT.js.map +1 -0
  34. package/dist/chunk-MFBHNWGV.js +416 -0
  35. package/dist/chunk-MFBHNWGV.js.map +1 -0
  36. package/dist/chunk-MXZSI3AY.js +311 -0
  37. package/dist/chunk-MXZSI3AY.js.map +1 -0
  38. package/dist/chunk-NBR3GHMT.js +72 -0
  39. package/dist/chunk-NBR3GHMT.js.map +1 -0
  40. package/dist/chunk-O3ZF22SW.js +246 -0
  41. package/dist/chunk-O3ZF22SW.js.map +1 -0
  42. package/dist/chunk-SUSJPZU2.js +181 -0
  43. package/dist/chunk-SUSJPZU2.js.map +1 -0
  44. package/dist/chunk-TEVZS4FA.js +310 -0
  45. package/dist/chunk-TEVZS4FA.js.map +1 -0
  46. package/dist/chunk-UY2SYSEZ.js +211 -0
  47. package/dist/chunk-UY2SYSEZ.js.map +1 -0
  48. package/dist/chunk-WAHVZH7V.js +260 -0
  49. package/dist/chunk-WAHVZH7V.js.map +1 -0
  50. package/dist/chunk-WPP3PEDE.js +234 -0
  51. package/dist/chunk-WPP3PEDE.js.map +1 -0
  52. package/dist/chunk-Y5XVD2CD.js +1610 -0
  53. package/dist/chunk-Y5XVD2CD.js.map +1 -0
  54. package/dist/chunk-YL5XFHR3.js +56 -0
  55. package/dist/chunk-YL5XFHR3.js.map +1 -0
  56. package/dist/chunk-ZGOHARPV.js +122 -0
  57. package/dist/chunk-ZGOHARPV.js.map +1 -0
  58. package/dist/claude-adapter-QMLFMSP3.js +6 -0
  59. package/dist/claude-adapter-QMLFMSP3.js.map +1 -0
  60. package/dist/claude-login-5WELXPKT.js +324 -0
  61. package/dist/claude-login-5WELXPKT.js.map +1 -0
  62. package/dist/cli.d.ts +1 -0
  63. package/dist/cli.js +703 -0
  64. package/dist/cli.js.map +1 -0
  65. package/dist/codex-login-7HHLJHBF.js +164 -0
  66. package/dist/codex-login-7HHLJHBF.js.map +1 -0
  67. package/dist/config-store-W6FBCQAQ.js +6 -0
  68. package/dist/config-store-W6FBCQAQ.js.map +1 -0
  69. package/dist/executor-6RIKIGXK.js +4 -0
  70. package/dist/executor-6RIKIGXK.js.map +1 -0
  71. package/dist/gemini-adapter-6JIHZ7WI.js +6 -0
  72. package/dist/gemini-adapter-6JIHZ7WI.js.map +1 -0
  73. package/dist/gemini-login-ZZLYC3J6.js +346 -0
  74. package/dist/gemini-login-ZZLYC3J6.js.map +1 -0
  75. package/dist/index.d.ts +2210 -0
  76. package/dist/index.js +1419 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/kimi-adapter-JN4HFFHU.js +6 -0
  79. package/dist/kimi-adapter-JN4HFFHU.js.map +1 -0
  80. package/dist/kimi-login-CZPS63NK.js +149 -0
  81. package/dist/kimi-login-CZPS63NK.js.map +1 -0
  82. package/dist/native-cli-adapters-OLW3XX57.js +6 -0
  83. package/dist/native-cli-adapters-OLW3XX57.js.map +1 -0
  84. package/dist/ollama-adapter-OJQ3FKWK.js +6 -0
  85. package/dist/ollama-adapter-OJQ3FKWK.js.map +1 -0
  86. package/dist/openai-adapter-XU46EN7B.js +6 -0
  87. package/dist/openai-adapter-XU46EN7B.js.map +1 -0
  88. package/dist/registry-4KD24ZC3.js +6 -0
  89. package/dist/registry-4KD24ZC3.js.map +1 -0
  90. package/dist/registry-H7B3AHPQ.js +5 -0
  91. package/dist/registry-H7B3AHPQ.js.map +1 -0
  92. package/dist/server-manager-PTGBHCLS.js +5 -0
  93. package/dist/server-manager-PTGBHCLS.js.map +1 -0
  94. package/dist/session-manager-ECEEACGY.js +12 -0
  95. package/dist/session-manager-ECEEACGY.js.map +1 -0
  96. package/dist/team-manager-HC4XGCFY.js +11 -0
  97. package/dist/team-manager-HC4XGCFY.js.map +1 -0
  98. package/dist/tmux-manager-GPYZ3WQH.js +6 -0
  99. package/dist/tmux-manager-GPYZ3WQH.js.map +1 -0
  100. package/dist/tools-TSMXMHIF.js +6 -0
  101. package/dist/tools-TSMXMHIF.js.map +1 -0
  102. package/package.json +89 -0
@@ -0,0 +1,324 @@
1
+ import { CredentialStore } from './chunk-4IJD72YB.js';
2
+ import './chunk-CGEV3ARR.js';
3
+ import './chunk-CYQNBB25.js';
4
+ import './chunk-NBR3GHMT.js';
5
+ import './chunk-CS5X3BWX.js';
6
+ import './chunk-HCIHOHLX.js';
7
+ import { AuthenticationError } from './chunk-ZGOHARPV.js';
8
+ import { logger } from './chunk-JAXXTYID.js';
9
+ import { createServer } from 'http';
10
+ import { randomBytes, createHash } from 'crypto';
11
+ import { execFile } from 'child_process';
12
+ import { promisify } from 'util';
13
+ import { URL } from 'url';
14
+
15
+ var execFileAsync = promisify(execFile);
16
+ var CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
17
+ var AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
18
+ var TOKEN_URL = "https://platform.claude.com/v1/oauth/token";
19
+ var SCOPE = "user:inference";
20
+ var CALLBACK_TIMEOUT_MS = 3e5;
21
+ var LOCALHOST = "localhost";
22
+ var KEYCHAIN_SERVICE = "Claude Code-credentials";
23
+ function isRecord(value) {
24
+ return typeof value === "object" && value !== null;
25
+ }
26
+ function asString(value) {
27
+ return typeof value === "string" && value.length > 0 ? value : void 0;
28
+ }
29
+ function asDate(value) {
30
+ if (value instanceof Date) {
31
+ return Number.isNaN(value.getTime()) ? void 0 : value;
32
+ }
33
+ if (typeof value === "number" && Number.isFinite(value)) {
34
+ const millis = value > 1e10 ? value : value * 1e3;
35
+ const date = new Date(millis);
36
+ return Number.isNaN(date.getTime()) ? void 0 : date;
37
+ }
38
+ if (typeof value === "string" && value.length > 0) {
39
+ const numeric = Number(value);
40
+ if (Number.isFinite(numeric) && value.trim() !== "") {
41
+ return asDate(numeric);
42
+ }
43
+ const parsed = new Date(value);
44
+ return Number.isNaN(parsed.getTime()) ? void 0 : parsed;
45
+ }
46
+ return void 0;
47
+ }
48
+ function parseKeychainCredential(raw) {
49
+ if (raw.length === 0) {
50
+ return void 0;
51
+ }
52
+ let parsed;
53
+ try {
54
+ parsed = JSON.parse(raw);
55
+ } catch {
56
+ return void 0;
57
+ }
58
+ if (!isRecord(parsed)) {
59
+ return void 0;
60
+ }
61
+ const directPayload = parsed;
62
+ const nestedPayload = isRecord(parsed["claudeAiOauth"]) ? parsed["claudeAiOauth"] : void 0;
63
+ const payloads = nestedPayload ? [nestedPayload, directPayload] : [directPayload];
64
+ for (const payload of payloads) {
65
+ const accessToken = asString(payload["accessToken"]) ?? asString(payload["access_token"]);
66
+ if (!accessToken) {
67
+ continue;
68
+ }
69
+ const refreshToken = asString(payload["refreshToken"]) ?? asString(payload["refresh_token"]);
70
+ const expiresAt = asDate(payload["expiresAt"] ?? payload["expires_at"]);
71
+ const email = asString(payload["email"]);
72
+ const plan = asString(payload["plan"]) ?? asString(payload["subscriptionType"]) ?? asString(payload["subscription_type"]) ?? asString(payload["rateLimitTier"]) ?? asString(payload["rate_limit_tier"]);
73
+ return {
74
+ provider: "anthropic",
75
+ method: "native_login",
76
+ token: accessToken,
77
+ ...refreshToken !== void 0 ? { refreshToken } : {},
78
+ ...expiresAt !== void 0 ? { expiresAt } : {},
79
+ ...email !== void 0 ? { email } : {},
80
+ ...plan !== void 0 ? { plan } : {}
81
+ };
82
+ }
83
+ return void 0;
84
+ }
85
+ async function readKeychainCredential() {
86
+ if (process.platform !== "darwin") return void 0;
87
+ try {
88
+ const { stdout } = await execFileAsync("security", [
89
+ "find-generic-password",
90
+ "-s",
91
+ KEYCHAIN_SERVICE,
92
+ "-w"
93
+ ], { timeout: 5e3 });
94
+ return parseKeychainCredential(stdout.trim());
95
+ } catch {
96
+ return void 0;
97
+ }
98
+ }
99
+ function generateCodeVerifier() {
100
+ return randomBytes(32).toString("base64url");
101
+ }
102
+ function generateCodeChallenge(verifier) {
103
+ return createHash("sha256").update(verifier).digest("base64url");
104
+ }
105
+ function generateState() {
106
+ return randomBytes(16).toString("hex");
107
+ }
108
+ function escapeHtml(unsafe) {
109
+ return unsafe.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
110
+ }
111
+ function successHtml() {
112
+ return `<!DOCTYPE html>
113
+ <html><head><title>AemeathCLI \u2014 Login Successful</title></head>
114
+ <body style="font-family:system-ui;text-align:center;padding:40px">
115
+ <h1>Login Successful</h1>
116
+ <p>You can close this window and return to your terminal.</p>
117
+ </body></html>`;
118
+ }
119
+ function errorHtml(message) {
120
+ return `<!DOCTYPE html>
121
+ <html><head><title>AemeathCLI \u2014 Login Failed</title></head>
122
+ <body style="font-family:system-ui;text-align:center;padding:40px">
123
+ <h1>Login Failed</h1>
124
+ <p>${escapeHtml(message)}</p>
125
+ </body></html>`;
126
+ }
127
+ var ClaudeLogin = class {
128
+ credentialStore;
129
+ callbackServer;
130
+ constructor(store) {
131
+ this.credentialStore = store ?? new CredentialStore();
132
+ }
133
+ /**
134
+ * Run browser-based OAuth 2.0 + PKCE login using the same client ID
135
+ * as the official Claude Code CLI. Browser opens automatically.
136
+ */
137
+ async login() {
138
+ const existing = await readKeychainCredential();
139
+ if (existing && existing.token) {
140
+ const isExpired = existing.expiresAt ? /* @__PURE__ */ new Date() > existing.expiresAt : false;
141
+ if (!isExpired) {
142
+ logger.info("Imported existing Claude Code credentials from keychain");
143
+ await this.credentialStore.set("anthropic", existing);
144
+ return existing;
145
+ }
146
+ }
147
+ const codeVerifier = generateCodeVerifier();
148
+ const codeChallenge = generateCodeChallenge(codeVerifier);
149
+ const state = generateState();
150
+ const { port, server } = await this.startCallbackServer();
151
+ this.callbackServer = server;
152
+ const redirectUri = `http://${LOCALHOST}:${port}/callback`;
153
+ const authUrl = new URL(AUTHORIZE_URL);
154
+ authUrl.searchParams.set("code", "true");
155
+ authUrl.searchParams.set("client_id", CLIENT_ID);
156
+ authUrl.searchParams.set("response_type", "code");
157
+ authUrl.searchParams.set("redirect_uri", redirectUri);
158
+ authUrl.searchParams.set("scope", SCOPE);
159
+ authUrl.searchParams.set("code_challenge", codeChallenge);
160
+ authUrl.searchParams.set("code_challenge_method", "S256");
161
+ authUrl.searchParams.set("state", state);
162
+ logger.info("Opening browser for Claude OAuth login");
163
+ try {
164
+ const openModule = await import('open');
165
+ await openModule.default(authUrl.toString());
166
+ } catch {
167
+ this.stopServer();
168
+ throw new AuthenticationError("anthropic", "Failed to open browser for login");
169
+ }
170
+ try {
171
+ const code = await this.waitForCallback(state);
172
+ const credential = await this.exchangeCodeForToken(code, codeVerifier, redirectUri, state);
173
+ await this.credentialStore.set("anthropic", credential);
174
+ logger.info("Claude OAuth login successful");
175
+ return credential;
176
+ } finally {
177
+ this.stopServer();
178
+ }
179
+ }
180
+ async logout() {
181
+ await this.credentialStore.delete("anthropic");
182
+ logger.info("Claude session revoked");
183
+ }
184
+ async isLoggedIn() {
185
+ const credential = await this.getCachedCredential();
186
+ return credential !== void 0;
187
+ }
188
+ async getStatus() {
189
+ const loggedIn = await this.isLoggedIn();
190
+ if (!loggedIn) return { loggedIn: false };
191
+ const credential = await this.credentialStore.get("anthropic");
192
+ if (!credential) return { loggedIn: false };
193
+ return {
194
+ loggedIn: true,
195
+ ...credential.email !== void 0 ? { email: credential.email } : {},
196
+ ...credential.plan !== void 0 ? { plan: credential.plan } : {}
197
+ };
198
+ }
199
+ async getCachedCredential() {
200
+ const existing = await this.credentialStore.get("anthropic");
201
+ if (existing?.method === "native_login" && existing.token) {
202
+ const isExpired2 = existing.expiresAt ? /* @__PURE__ */ new Date() > existing.expiresAt : false;
203
+ if (!isExpired2) {
204
+ return existing;
205
+ }
206
+ }
207
+ const keychain = await readKeychainCredential();
208
+ if (!keychain?.token) {
209
+ return void 0;
210
+ }
211
+ const isExpired = keychain.expiresAt ? /* @__PURE__ */ new Date() > keychain.expiresAt : false;
212
+ if (isExpired) {
213
+ return void 0;
214
+ }
215
+ await this.credentialStore.set("anthropic", keychain);
216
+ return keychain;
217
+ }
218
+ // ── Internal ──────────────────────────────────────────────────────────
219
+ startCallbackServer() {
220
+ return new Promise((resolve, reject) => {
221
+ const server = createServer();
222
+ server.listen(0, LOCALHOST, () => {
223
+ const address = server.address();
224
+ if (address === null || typeof address === "string") {
225
+ server.close();
226
+ reject(new Error("Failed to bind callback server"));
227
+ return;
228
+ }
229
+ resolve({ port: address.port, server });
230
+ });
231
+ server.on("error", reject);
232
+ });
233
+ }
234
+ waitForCallback(expectedState) {
235
+ return new Promise((resolve, reject) => {
236
+ const server = this.callbackServer;
237
+ if (server === void 0) {
238
+ reject(new AuthenticationError("anthropic", "Callback server not started"));
239
+ return;
240
+ }
241
+ const timeout = setTimeout(() => {
242
+ reject(new AuthenticationError("anthropic", "Login timed out"));
243
+ }, CALLBACK_TIMEOUT_MS);
244
+ server.on("request", (req, res) => {
245
+ const requestUrl = new URL(req.url ?? "/", `http://${LOCALHOST}`);
246
+ if (requestUrl.pathname !== "/callback") {
247
+ res.writeHead(404);
248
+ res.end("Not found");
249
+ return;
250
+ }
251
+ clearTimeout(timeout);
252
+ const code = requestUrl.searchParams.get("code");
253
+ const state = requestUrl.searchParams.get("state");
254
+ const error = requestUrl.searchParams.get("error");
255
+ if (error) {
256
+ res.writeHead(400, { "Content-Type": "text/html" });
257
+ res.end(errorHtml(`OAuth error: ${error}`));
258
+ reject(new AuthenticationError("anthropic", `OAuth error: ${error}`));
259
+ return;
260
+ }
261
+ if (state !== expectedState) {
262
+ res.writeHead(400, { "Content-Type": "text/html" });
263
+ res.end(errorHtml("State mismatch"));
264
+ reject(new AuthenticationError("anthropic", "OAuth state mismatch"));
265
+ return;
266
+ }
267
+ if (!code) {
268
+ res.writeHead(400, { "Content-Type": "text/html" });
269
+ res.end(errorHtml("Missing authorization code"));
270
+ reject(new AuthenticationError("anthropic", "No authorization code received"));
271
+ return;
272
+ }
273
+ res.writeHead(200, { "Content-Type": "text/html" });
274
+ res.end(successHtml());
275
+ resolve(code);
276
+ });
277
+ });
278
+ }
279
+ async exchangeCodeForToken(code, codeVerifier, redirectUri, state) {
280
+ const body = {
281
+ grant_type: "authorization_code",
282
+ code,
283
+ redirect_uri: redirectUri,
284
+ client_id: CLIENT_ID,
285
+ code_verifier: codeVerifier,
286
+ state
287
+ };
288
+ const response = await fetch(TOKEN_URL, {
289
+ method: "POST",
290
+ headers: {
291
+ "Content-Type": "application/json"
292
+ },
293
+ body: JSON.stringify(body)
294
+ });
295
+ if (!response.ok) {
296
+ const text = await response.text();
297
+ throw new AuthenticationError("anthropic", `Token exchange failed: ${response.status} ${text}`);
298
+ }
299
+ const data = await response.json();
300
+ if (!data.access_token) {
301
+ throw new AuthenticationError("anthropic", "Token exchange returned no access_token");
302
+ }
303
+ const expiresAt = data.expires_in ? new Date(Date.now() + data.expires_in * 1e3) : void 0;
304
+ return {
305
+ provider: "anthropic",
306
+ method: "native_login",
307
+ token: data.access_token,
308
+ ...data.refresh_token !== void 0 ? { refreshToken: data.refresh_token } : {},
309
+ ...expiresAt !== void 0 ? { expiresAt } : {},
310
+ ...data.email !== void 0 ? { email: data.email } : {},
311
+ ...data.plan !== void 0 ? { plan: data.plan } : {}
312
+ };
313
+ }
314
+ stopServer() {
315
+ if (this.callbackServer !== void 0) {
316
+ this.callbackServer.close();
317
+ this.callbackServer = void 0;
318
+ }
319
+ }
320
+ };
321
+
322
+ export { ClaudeLogin };
323
+ //# sourceMappingURL=claude-login-5WELXPKT.js.map
324
+ //# sourceMappingURL=claude-login-5WELXPKT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/auth/providers/claude-login.ts"],"names":["isExpired"],"mappings":"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","file":"claude-login-5WELXPKT.js","sourcesContent":["/**\n * Claude Code OAuth 2.0 + PKCE login\n * Uses the same client ID as the official Claude Code CLI.\n * After login, stores tokens in our credential store AND writes to macOS Keychain\n * so credentials are shared with the official Claude Code CLI.\n */\n\nimport { createServer, type Server, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { randomBytes, createHash } from \"node:crypto\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { URL } from \"node:url\";\nimport type { ICredential } from \"../../types/index.js\";\nimport { AuthenticationError } from \"../../types/index.js\";\nimport { CredentialStore } from \"../credential-store.js\";\nimport { logger } from \"../../utils/index.js\";\n\nconst execFileAsync = promisify(execFile);\n\n// ── Claude Code OAuth Config (same as official Claude Code CLI) ─────────\n\nconst CLIENT_ID = \"9d1c250a-e61b-44d9-88ed-5944d1962f5e\";\nconst AUTHORIZE_URL = \"https://claude.ai/oauth/authorize\";\nconst TOKEN_URL = \"https://platform.claude.com/v1/oauth/token\";\nconst SCOPE = \"user:inference\";\nconst CALLBACK_TIMEOUT_MS = 300_000;\nconst LOCALHOST = \"localhost\";\n\n// ── Also try reading from official Claude Code CLI's keychain ───────────\n\nconst KEYCHAIN_SERVICE = \"Claude Code-credentials\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction asDate(value: unknown): Date | undefined {\n if (value instanceof Date) {\n return Number.isNaN(value.getTime()) ? undefined : value;\n }\n\n if (typeof value === \"number\" && Number.isFinite(value)) {\n const millis = value > 10_000_000_000 ? value : value * 1000;\n const date = new Date(millis);\n return Number.isNaN(date.getTime()) ? undefined : date;\n }\n\n if (typeof value === \"string\" && value.length > 0) {\n const numeric = Number(value);\n if (Number.isFinite(numeric) && value.trim() !== \"\") {\n return asDate(numeric);\n }\n\n const parsed = new Date(value);\n return Number.isNaN(parsed.getTime()) ? undefined : parsed;\n }\n\n return undefined;\n}\n\nfunction parseKeychainCredential(raw: string): ICredential | undefined {\n if (raw.length === 0) {\n return undefined;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw) as unknown;\n } catch {\n return undefined;\n }\n\n if (!isRecord(parsed)) {\n return undefined;\n }\n\n const directPayload = parsed;\n const nestedPayload = isRecord(parsed[\"claudeAiOauth\"])\n ? parsed[\"claudeAiOauth\"]\n : undefined;\n const payloads = nestedPayload ? [nestedPayload, directPayload] : [directPayload];\n\n for (const payload of payloads) {\n const accessToken = asString(payload[\"accessToken\"]) ?? asString(payload[\"access_token\"]);\n if (!accessToken) {\n continue;\n }\n\n const refreshToken = asString(payload[\"refreshToken\"]) ?? asString(payload[\"refresh_token\"]);\n const expiresAt = asDate(payload[\"expiresAt\"] ?? payload[\"expires_at\"]);\n const email = asString(payload[\"email\"]);\n const plan = asString(payload[\"plan\"])\n ?? asString(payload[\"subscriptionType\"])\n ?? asString(payload[\"subscription_type\"])\n ?? asString(payload[\"rateLimitTier\"])\n ?? asString(payload[\"rate_limit_tier\"]);\n\n return {\n provider: \"anthropic\",\n method: \"native_login\",\n token: accessToken,\n ...(refreshToken !== undefined ? { refreshToken } : {}),\n ...(expiresAt !== undefined ? { expiresAt } : {}),\n ...(email !== undefined ? { email } : {}),\n ...(plan !== undefined ? { plan } : {}),\n };\n }\n\n return undefined;\n}\n\nasync function readKeychainCredential(): Promise<ICredential | undefined> {\n if (process.platform !== \"darwin\") return undefined;\n\n try {\n const { stdout } = await execFileAsync(\"security\", [\n \"find-generic-password\", \"-s\", KEYCHAIN_SERVICE, \"-w\",\n ], { timeout: 5000 });\n\n return parseKeychainCredential(stdout.trim());\n } catch {\n return undefined;\n }\n}\n\n// ── PKCE Helpers ────────────────────────────────────────────────────────\n\nfunction generateCodeVerifier(): string {\n return randomBytes(32).toString(\"base64url\");\n}\n\nfunction generateCodeChallenge(verifier: string): string {\n return createHash(\"sha256\").update(verifier).digest(\"base64url\");\n}\n\nfunction generateState(): string {\n return randomBytes(16).toString(\"hex\");\n}\n\n// ── HTML Responses ──────────────────────────────────────────────────────\n\nfunction escapeHtml(unsafe: string): string {\n return unsafe\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\n\nfunction successHtml(): string {\n return `<!DOCTYPE html>\n<html><head><title>AemeathCLI — Login Successful</title></head>\n<body style=\"font-family:system-ui;text-align:center;padding:40px\">\n<h1>Login Successful</h1>\n<p>You can close this window and return to your terminal.</p>\n</body></html>`;\n}\n\nfunction errorHtml(message: string): string {\n return `<!DOCTYPE html>\n<html><head><title>AemeathCLI — Login Failed</title></head>\n<body style=\"font-family:system-ui;text-align:center;padding:40px\">\n<h1>Login Failed</h1>\n<p>${escapeHtml(message)}</p>\n</body></html>`;\n}\n\n// ── ClaudeLogin Class ───────────────────────────────────────────────────\n\nexport class ClaudeLogin {\n private readonly credentialStore: CredentialStore;\n private callbackServer: Server | undefined;\n\n constructor(store?: CredentialStore) {\n this.credentialStore = store ?? new CredentialStore();\n }\n\n /**\n * Run browser-based OAuth 2.0 + PKCE login using the same client ID\n * as the official Claude Code CLI. Browser opens automatically.\n */\n async login(): Promise<ICredential> {\n // First try importing existing credentials from Claude Code's keychain\n const existing = await readKeychainCredential();\n if (existing && existing.token) {\n const isExpired = existing.expiresAt ? new Date() > existing.expiresAt : false;\n if (!isExpired) {\n logger.info(\"Imported existing Claude Code credentials from keychain\");\n await this.credentialStore.set(\"anthropic\", existing);\n return existing;\n }\n }\n\n // Run the OAuth flow — browser opens automatically\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = generateCodeChallenge(codeVerifier);\n const state = generateState();\n\n const { port, server } = await this.startCallbackServer();\n this.callbackServer = server;\n\n const redirectUri = `http://${LOCALHOST}:${port}/callback`;\n\n const authUrl = new URL(AUTHORIZE_URL);\n authUrl.searchParams.set(\"code\", \"true\");\n authUrl.searchParams.set(\"client_id\", CLIENT_ID);\n authUrl.searchParams.set(\"response_type\", \"code\");\n authUrl.searchParams.set(\"redirect_uri\", redirectUri);\n authUrl.searchParams.set(\"scope\", SCOPE);\n authUrl.searchParams.set(\"code_challenge\", codeChallenge);\n authUrl.searchParams.set(\"code_challenge_method\", \"S256\");\n authUrl.searchParams.set(\"state\", state);\n\n logger.info(\"Opening browser for Claude OAuth login\");\n\n try {\n const openModule = await import(\"open\");\n await openModule.default(authUrl.toString());\n } catch {\n this.stopServer();\n throw new AuthenticationError(\"anthropic\", \"Failed to open browser for login\");\n }\n\n try {\n const code = await this.waitForCallback(state);\n const credential = await this.exchangeCodeForToken(code, codeVerifier, redirectUri, state);\n\n await this.credentialStore.set(\"anthropic\", credential);\n logger.info(\"Claude OAuth login successful\");\n\n return credential;\n } finally {\n this.stopServer();\n }\n }\n\n async logout(): Promise<void> {\n await this.credentialStore.delete(\"anthropic\");\n logger.info(\"Claude session revoked\");\n }\n\n async isLoggedIn(): Promise<boolean> {\n const credential = await this.getCachedCredential();\n return credential !== undefined;\n }\n\n async getStatus(): Promise<{ loggedIn: boolean; email?: string | undefined; plan?: string | undefined }> {\n const loggedIn = await this.isLoggedIn();\n if (!loggedIn) return { loggedIn: false };\n\n const credential = await this.credentialStore.get(\"anthropic\");\n if (!credential) return { loggedIn: false };\n\n return {\n loggedIn: true,\n ...(credential.email !== undefined ? { email: credential.email } : {}),\n ...(credential.plan !== undefined ? { plan: credential.plan } : {}),\n };\n }\n\n async getCachedCredential(): Promise<ICredential | undefined> {\n const existing = await this.credentialStore.get(\"anthropic\");\n if (existing?.method === \"native_login\" && existing.token) {\n const isExpired = existing.expiresAt ? new Date() > existing.expiresAt : false;\n if (!isExpired) {\n return existing;\n }\n }\n\n const keychain = await readKeychainCredential();\n if (!keychain?.token) {\n return undefined;\n }\n\n const isExpired = keychain.expiresAt ? new Date() > keychain.expiresAt : false;\n if (isExpired) {\n return undefined;\n }\n\n await this.credentialStore.set(\"anthropic\", keychain);\n return keychain;\n }\n\n // ── Internal ──────────────────────────────────────────────────────────\n\n private startCallbackServer(): Promise<{ port: number; server: Server }> {\n return new Promise((resolve, reject) => {\n const server = createServer();\n server.listen(0, LOCALHOST, () => {\n const address = server.address();\n if (address === null || typeof address === \"string\") {\n server.close();\n reject(new Error(\"Failed to bind callback server\"));\n return;\n }\n resolve({ port: address.port, server });\n });\n server.on(\"error\", reject);\n });\n }\n\n private waitForCallback(expectedState: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const server = this.callbackServer;\n if (server === undefined) {\n reject(new AuthenticationError(\"anthropic\", \"Callback server not started\"));\n return;\n }\n\n const timeout = setTimeout(() => {\n reject(new AuthenticationError(\"anthropic\", \"Login timed out\"));\n }, CALLBACK_TIMEOUT_MS);\n\n server.on(\"request\", (req: IncomingMessage, res: ServerResponse) => {\n const requestUrl = new URL(req.url ?? \"/\", `http://${LOCALHOST}`);\n if (requestUrl.pathname !== \"/callback\") {\n res.writeHead(404);\n res.end(\"Not found\");\n return;\n }\n\n clearTimeout(timeout);\n\n const code = requestUrl.searchParams.get(\"code\");\n const state = requestUrl.searchParams.get(\"state\");\n const error = requestUrl.searchParams.get(\"error\");\n\n if (error) {\n res.writeHead(400, { \"Content-Type\": \"text/html\" });\n res.end(errorHtml(`OAuth error: ${error}`));\n reject(new AuthenticationError(\"anthropic\", `OAuth error: ${error}`));\n return;\n }\n\n if (state !== expectedState) {\n res.writeHead(400, { \"Content-Type\": \"text/html\" });\n res.end(errorHtml(\"State mismatch\"));\n reject(new AuthenticationError(\"anthropic\", \"OAuth state mismatch\"));\n return;\n }\n\n if (!code) {\n res.writeHead(400, { \"Content-Type\": \"text/html\" });\n res.end(errorHtml(\"Missing authorization code\"));\n reject(new AuthenticationError(\"anthropic\", \"No authorization code received\"));\n return;\n }\n\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(successHtml());\n resolve(code);\n });\n });\n }\n\n private async exchangeCodeForToken(\n code: string,\n codeVerifier: string,\n redirectUri: string,\n state: string,\n ): Promise<ICredential> {\n const body = {\n grant_type: \"authorization_code\",\n code,\n redirect_uri: redirectUri,\n client_id: CLIENT_ID,\n code_verifier: codeVerifier,\n state,\n };\n\n const response = await fetch(TOKEN_URL, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new AuthenticationError(\"anthropic\", `Token exchange failed: ${response.status} ${text}`);\n }\n\n const data = (await response.json()) as {\n access_token?: string;\n refresh_token?: string;\n expires_in?: number;\n email?: string;\n plan?: string;\n };\n\n if (!data.access_token) {\n throw new AuthenticationError(\"anthropic\", \"Token exchange returned no access_token\");\n }\n\n const expiresAt = data.expires_in\n ? new Date(Date.now() + data.expires_in * 1000)\n : undefined;\n\n return {\n provider: \"anthropic\",\n method: \"native_login\",\n token: data.access_token,\n ...(data.refresh_token !== undefined ? { refreshToken: data.refresh_token } : {}),\n ...(expiresAt !== undefined ? { expiresAt } : {}),\n ...(data.email !== undefined ? { email: data.email } : {}),\n ...(data.plan !== undefined ? { plan: data.plan } : {}),\n };\n }\n\n private stopServer(): void {\n if (this.callbackServer !== undefined) {\n this.callbackServer.close();\n this.callbackServer = undefined;\n }\n }\n}\n"]}
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node