@cortexkit/anthropic-auth-core 1.10.3 → 1.11.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.
- package/dist/accounts.d.ts +52 -0
- package/dist/accounts.js +392 -94
- package/dist/auth.d.ts +8 -0
- package/dist/auth.js +8 -1
- package/dist/cachekeep.d.ts +3 -1
- package/dist/cachekeep.js +34 -7
- package/dist/commands/account.d.ts +56 -0
- package/dist/commands/account.js +219 -0
- package/dist/dump.js +3 -2
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/logger.d.ts +25 -1
- package/dist/logger.js +238 -18
- package/dist/logging.d.ts +19 -0
- package/dist/logging.js +59 -0
- package/dist/provider.d.ts +19 -0
- package/dist/provider.js +0 -0
- package/dist/quota-manager.d.ts +1 -0
- package/dist/quota-manager.js +16 -7
- package/dist/routing.js +2 -6
- package/package.json +1 -1
package/dist/auth.d.ts
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
|
+
export declare function parseRetryAfterHeader(value: string | undefined | null): number | undefined;
|
|
1
2
|
export declare class ClaudeOAuthRefreshError extends Error {
|
|
2
3
|
readonly status: number;
|
|
3
4
|
readonly body: string;
|
|
4
5
|
/** Parsed Retry-After value in seconds, if the server provided one. */
|
|
5
6
|
readonly retryAfter: number | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* Duck-typed marker: any error carrying `isRefreshError: true` arms the
|
|
9
|
+
* refresh backoff in consumers that receive it (recordQuotaRefreshError).
|
|
10
|
+
* Provider-agnostic — shared-core extraction of anthropic-auth and
|
|
11
|
+
* openai-auth relies on this field instead of instanceof.
|
|
12
|
+
*/
|
|
13
|
+
readonly isRefreshError = true;
|
|
6
14
|
constructor(status: number, body: string, retryAfterHeader?: string | null);
|
|
7
15
|
}
|
|
8
16
|
export type ClaudeOAuthRefreshResult = {
|
package/dist/auth.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AUTHORIZE_URLS, AXIOS_USER_AGENT, CLIENT_ID, CODE_CALLBACK_URL, OAUTH_SCOPES, REFRESH_SCOPE, TOKEN_URL, } from "./constants.js";
|
|
2
2
|
import { generatePKCE } from "./pkce.js";
|
|
3
|
-
function parseRetryAfterHeader(value) {
|
|
3
|
+
export function parseRetryAfterHeader(value) {
|
|
4
4
|
if (!value)
|
|
5
5
|
return undefined;
|
|
6
6
|
const seconds = Number(value);
|
|
@@ -18,6 +18,13 @@ export class ClaudeOAuthRefreshError extends Error {
|
|
|
18
18
|
body;
|
|
19
19
|
/** Parsed Retry-After value in seconds, if the server provided one. */
|
|
20
20
|
retryAfter;
|
|
21
|
+
/**
|
|
22
|
+
* Duck-typed marker: any error carrying `isRefreshError: true` arms the
|
|
23
|
+
* refresh backoff in consumers that receive it (recordQuotaRefreshError).
|
|
24
|
+
* Provider-agnostic — shared-core extraction of anthropic-auth and
|
|
25
|
+
* openai-auth relies on this field instead of instanceof.
|
|
26
|
+
*/
|
|
27
|
+
isRefreshError = true;
|
|
21
28
|
constructor(status, body, retryAfterHeader) {
|
|
22
29
|
super(`Claude OAuth refresh failed: ${status} — ${body}`);
|
|
23
30
|
this.status = status;
|
package/dist/cachekeep.d.ts
CHANGED
|
@@ -21,6 +21,9 @@ export type CacheKeepCommandAction = {
|
|
|
21
21
|
endHour: number;
|
|
22
22
|
} | {
|
|
23
23
|
type: 'usage';
|
|
24
|
+
} | {
|
|
25
|
+
type: 'subagents';
|
|
26
|
+
enabled: boolean;
|
|
24
27
|
};
|
|
25
28
|
export type CacheKeepStatus = {
|
|
26
29
|
enabled: boolean;
|
|
@@ -68,7 +71,6 @@ export declare class CacheKeepManager {
|
|
|
68
71
|
fetchImpl?: typeof fetch;
|
|
69
72
|
now?: () => number;
|
|
70
73
|
prepareHeaders?: (headers: Headers, target: CacheKeepTarget) => Promise<Headers> | Headers;
|
|
71
|
-
log?: (message: string, data?: Record<string, unknown>) => void;
|
|
72
74
|
});
|
|
73
75
|
start(): void;
|
|
74
76
|
stop(): void;
|
package/dist/cachekeep.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { signRequestBody } from "./cch.js";
|
|
2
2
|
import { orderClaudeCodeBody } from "./claude-code.js";
|
|
3
|
+
import { logger } from "./logger.js";
|
|
3
4
|
export const CLAUDE_CACHE_KEEP_COMMAND_NAME = 'claude-cachekeep';
|
|
4
5
|
export const CACHE_KEEP_TTL_MS = 60 * 60_000;
|
|
5
6
|
export const CACHE_KEEP_PREWARM_LEAD_MS = 5 * 60_000;
|
|
@@ -22,6 +23,10 @@ export function parseCacheKeepCommandAction(input) {
|
|
|
22
23
|
return { type: 'status' };
|
|
23
24
|
if (trimmed === 'off')
|
|
24
25
|
return { type: 'disable' };
|
|
26
|
+
if (trimmed === 'subagents on')
|
|
27
|
+
return { type: 'subagents', enabled: true };
|
|
28
|
+
if (trimmed === 'subagents off')
|
|
29
|
+
return { type: 'subagents', enabled: false };
|
|
25
30
|
const match = /^(\d{1,2})-(\d{1,2})$/.exec(trimmed);
|
|
26
31
|
if (!match)
|
|
27
32
|
return { type: 'usage' };
|
|
@@ -132,6 +137,15 @@ export function executeCacheKeepCommand(input) {
|
|
|
132
137
|
}),
|
|
133
138
|
].join('\n');
|
|
134
139
|
}
|
|
140
|
+
if (action.type === 'subagents') {
|
|
141
|
+
return [
|
|
142
|
+
STATUS_TITLE,
|
|
143
|
+
'',
|
|
144
|
+
buildCacheKeepStatusSummary(status),
|
|
145
|
+
'',
|
|
146
|
+
`Subagent tracking: ${action.enabled ? 'enabled' : 'disabled'}`,
|
|
147
|
+
].join('\n');
|
|
148
|
+
}
|
|
135
149
|
return [USAGE_TITLE, '', USAGE, '', buildCacheKeepStatusSummary(status)].join('\n');
|
|
136
150
|
}
|
|
137
151
|
function hasExplicitCacheControl(value) {
|
|
@@ -185,9 +199,10 @@ export class CacheKeepManager {
|
|
|
185
199
|
start() {
|
|
186
200
|
if (this.timer)
|
|
187
201
|
return;
|
|
202
|
+
logger.debug('cachekeep', 'started');
|
|
188
203
|
this.timer = setInterval(() => {
|
|
189
204
|
void this.tick().catch((error) => {
|
|
190
|
-
|
|
205
|
+
logger.warn('cachekeep', 'tick failed', {
|
|
191
206
|
error: error instanceof Error ? error.message : String(error),
|
|
192
207
|
});
|
|
193
208
|
});
|
|
@@ -196,8 +211,10 @@ export class CacheKeepManager {
|
|
|
196
211
|
this.timer.unref();
|
|
197
212
|
}
|
|
198
213
|
stop() {
|
|
199
|
-
if (this.timer)
|
|
200
|
-
|
|
214
|
+
if (!this.timer)
|
|
215
|
+
return;
|
|
216
|
+
logger.debug('cachekeep', 'stopped');
|
|
217
|
+
clearInterval(this.timer);
|
|
201
218
|
this.timer = null;
|
|
202
219
|
}
|
|
203
220
|
stats(window, now = this.options.now?.() ?? Date.now()) {
|
|
@@ -289,6 +306,7 @@ export class CacheKeepManager {
|
|
|
289
306
|
return;
|
|
290
307
|
if (!isWithinCacheKeepWindow(window, new Date(now)))
|
|
291
308
|
return;
|
|
309
|
+
logger.debug('cachekeep', 'fired', { targets: this.targets.size });
|
|
292
310
|
const dueAt = now + CACHE_KEEP_PREWARM_LEAD_MS;
|
|
293
311
|
for (const target of this.targets.values()) {
|
|
294
312
|
if (target.cacheExpiresAt > dueAt)
|
|
@@ -299,7 +317,7 @@ export class CacheKeepManager {
|
|
|
299
317
|
async prewarm(target, now) {
|
|
300
318
|
const prewarm = await buildCacheKeepPrewarmBody(target.bodyText);
|
|
301
319
|
if (!prewarm.ok) {
|
|
302
|
-
|
|
320
|
+
logger.debug('cachekeep', 'prewarm skipped', {
|
|
303
321
|
session: target.id,
|
|
304
322
|
reason: prewarm.reason,
|
|
305
323
|
});
|
|
@@ -319,7 +337,7 @@ export class CacheKeepManager {
|
|
|
319
337
|
body: prewarm.bodyText,
|
|
320
338
|
});
|
|
321
339
|
if (!response.ok) {
|
|
322
|
-
|
|
340
|
+
logger.warn('cachekeep', 'prewarm failed', {
|
|
323
341
|
session: target.id,
|
|
324
342
|
status: response.status,
|
|
325
343
|
body: await response.text().catch(() => ''),
|
|
@@ -327,8 +345,17 @@ export class CacheKeepManager {
|
|
|
327
345
|
target.cacheExpiresAt = now + CACHE_KEEP_PREWARM_LEAD_MS + 5 * 60_000;
|
|
328
346
|
return;
|
|
329
347
|
}
|
|
330
|
-
await response.
|
|
348
|
+
const data = (await response.json().catch(() => null));
|
|
349
|
+
const usage = data?.usage;
|
|
331
350
|
target.cacheExpiresAt = now + CACHE_KEEP_TTL_MS;
|
|
332
|
-
|
|
351
|
+
if (usage) {
|
|
352
|
+
logger.debug('cachekeep', 'prewarm succeeded', {
|
|
353
|
+
session: target.id,
|
|
354
|
+
usage,
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
logger.debug('cachekeep', 'prewarm succeeded', { session: target.id });
|
|
359
|
+
}
|
|
333
360
|
}
|
|
334
361
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { AccountStorage } from '../accounts.ts';
|
|
2
|
+
export declare const CLAUDE_ACCOUNT_COMMAND_NAME = "claude-account";
|
|
3
|
+
export type AccountCommandAction = {
|
|
4
|
+
type: 'status';
|
|
5
|
+
} | {
|
|
6
|
+
type: 'enable';
|
|
7
|
+
id: string;
|
|
8
|
+
} | {
|
|
9
|
+
type: 'disable';
|
|
10
|
+
id: string;
|
|
11
|
+
} | {
|
|
12
|
+
type: 'remove';
|
|
13
|
+
id: string;
|
|
14
|
+
} | {
|
|
15
|
+
type: 'move-up';
|
|
16
|
+
id: string;
|
|
17
|
+
} | {
|
|
18
|
+
type: 'move-down';
|
|
19
|
+
id: string;
|
|
20
|
+
} | {
|
|
21
|
+
type: 'add-apikey';
|
|
22
|
+
apiKey: string;
|
|
23
|
+
label?: string;
|
|
24
|
+
baseURL?: string;
|
|
25
|
+
authHeader?: 'authorization-bearer' | 'x-api-key';
|
|
26
|
+
} | {
|
|
27
|
+
type: 'add-oauth-start';
|
|
28
|
+
} | {
|
|
29
|
+
type: 'add-oauth-finish';
|
|
30
|
+
code: string;
|
|
31
|
+
label?: string;
|
|
32
|
+
} | {
|
|
33
|
+
type: 'usage';
|
|
34
|
+
};
|
|
35
|
+
export declare function parseAccountCommandAction(argumentsText: string): AccountCommandAction;
|
|
36
|
+
export interface AccountListItem {
|
|
37
|
+
id: string;
|
|
38
|
+
label: string;
|
|
39
|
+
role: 'main' | 'fallback';
|
|
40
|
+
enabled: boolean;
|
|
41
|
+
quotaPercent: number | null;
|
|
42
|
+
}
|
|
43
|
+
export declare function buildAccountList(storage: AccountStorage): AccountListItem[];
|
|
44
|
+
export declare function executeAccountCommand(input: {
|
|
45
|
+
argumentsText: string;
|
|
46
|
+
storage: AccountStorage;
|
|
47
|
+
}): {
|
|
48
|
+
text: string;
|
|
49
|
+
updated?: {
|
|
50
|
+
id: string;
|
|
51
|
+
action: 'enable' | 'disable' | 'remove' | 'reorder';
|
|
52
|
+
enabled?: boolean;
|
|
53
|
+
previousOrder?: string[];
|
|
54
|
+
newOrder?: string[];
|
|
55
|
+
};
|
|
56
|
+
};
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
export const CLAUDE_ACCOUNT_COMMAND_NAME = 'claude-account';
|
|
2
|
+
export function parseAccountCommandAction(argumentsText) {
|
|
3
|
+
const parts = argumentsText.trim().split(/\s+/).filter(Boolean);
|
|
4
|
+
if (parts.length === 0)
|
|
5
|
+
return { type: 'status' };
|
|
6
|
+
const action = parts[0];
|
|
7
|
+
const rest = parts.slice(1).join(' ');
|
|
8
|
+
if (action === 'enable' && rest)
|
|
9
|
+
return { type: 'enable', id: rest };
|
|
10
|
+
if (action === 'disable' && rest)
|
|
11
|
+
return { type: 'disable', id: rest };
|
|
12
|
+
if (action === 'remove' && rest)
|
|
13
|
+
return { type: 'remove', id: rest };
|
|
14
|
+
if (action === 'move-up' && rest)
|
|
15
|
+
return { type: 'move-up', id: rest };
|
|
16
|
+
if (action === 'move-down' && rest)
|
|
17
|
+
return { type: 'move-down', id: rest };
|
|
18
|
+
if (action === 'add-apikey' && rest) {
|
|
19
|
+
let remaining = rest;
|
|
20
|
+
let baseURL;
|
|
21
|
+
let authHeader;
|
|
22
|
+
// Parse --base-url flag
|
|
23
|
+
const baseUrlMatch = remaining.match(/--base-url\s+(\S+)/);
|
|
24
|
+
if (baseUrlMatch) {
|
|
25
|
+
baseURL = baseUrlMatch[1];
|
|
26
|
+
remaining = remaining.replace(baseUrlMatch[0], '').trim();
|
|
27
|
+
}
|
|
28
|
+
// Parse --auth-header flag
|
|
29
|
+
const authMatch = remaining.match(/--auth-header\s+(authorization-bearer|x-api-key)/);
|
|
30
|
+
if (authMatch) {
|
|
31
|
+
authHeader = authMatch[1];
|
|
32
|
+
remaining = remaining.replace(authMatch[0], '').trim();
|
|
33
|
+
}
|
|
34
|
+
// Parse --label flag
|
|
35
|
+
let label;
|
|
36
|
+
const labelMatch = remaining.match(/--label\s+(.+)/);
|
|
37
|
+
if (labelMatch) {
|
|
38
|
+
label = labelMatch[1]?.trim() || undefined;
|
|
39
|
+
remaining = remaining.replace(labelMatch[0], '').trim();
|
|
40
|
+
}
|
|
41
|
+
// First remaining token is the API key; rest (if any) is label
|
|
42
|
+
const firstSpace = remaining.indexOf(' ');
|
|
43
|
+
if (firstSpace === -1) {
|
|
44
|
+
if (!remaining)
|
|
45
|
+
return { type: 'usage' };
|
|
46
|
+
return {
|
|
47
|
+
type: 'add-apikey',
|
|
48
|
+
apiKey: remaining,
|
|
49
|
+
baseURL,
|
|
50
|
+
authHeader,
|
|
51
|
+
label,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const apiKey = remaining.slice(0, firstSpace);
|
|
55
|
+
const tail = remaining.slice(firstSpace + 1).trim();
|
|
56
|
+
return {
|
|
57
|
+
type: 'add-apikey',
|
|
58
|
+
apiKey,
|
|
59
|
+
label: label ?? (tail || undefined),
|
|
60
|
+
baseURL,
|
|
61
|
+
authHeader,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (action === 'add-oauth-start')
|
|
65
|
+
return { type: 'add-oauth-start' };
|
|
66
|
+
if (action === 'add-oauth-finish' && rest) {
|
|
67
|
+
let remaining = rest;
|
|
68
|
+
// Parse --label flag (mirrors add-apikey). The OAuth code is opaque (may
|
|
69
|
+
// contain a #state segment) so the label is collected via the flag, never
|
|
70
|
+
// positionally.
|
|
71
|
+
let label;
|
|
72
|
+
const labelMatch = remaining.match(/--label\s+(.+)/);
|
|
73
|
+
if (labelMatch) {
|
|
74
|
+
label = labelMatch[1]?.trim() || undefined;
|
|
75
|
+
remaining = remaining.replace(labelMatch[0], '').trim();
|
|
76
|
+
}
|
|
77
|
+
if (!remaining)
|
|
78
|
+
return { type: 'usage' };
|
|
79
|
+
return { type: 'add-oauth-finish', code: remaining, label };
|
|
80
|
+
}
|
|
81
|
+
return { type: 'usage' };
|
|
82
|
+
}
|
|
83
|
+
export function buildAccountList(storage) {
|
|
84
|
+
const list = [];
|
|
85
|
+
const fiveHour = storage.quota?.mainQuota?.five_hour;
|
|
86
|
+
list.push({
|
|
87
|
+
id: 'main',
|
|
88
|
+
label: storage.main?.provider === 'anthropic' ? 'OpenCode anthropic' : 'Main',
|
|
89
|
+
role: 'main',
|
|
90
|
+
enabled: true,
|
|
91
|
+
quotaPercent: fiveHour?.usedPercent ?? null,
|
|
92
|
+
});
|
|
93
|
+
for (const account of storage.accounts) {
|
|
94
|
+
const fiveHourQuota = account.quota?.five_hour;
|
|
95
|
+
list.push({
|
|
96
|
+
id: account.id,
|
|
97
|
+
label: account.label ?? account.id,
|
|
98
|
+
role: 'fallback',
|
|
99
|
+
enabled: account.enabled !== false,
|
|
100
|
+
quotaPercent: fiveHourQuota?.usedPercent ?? null,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return list;
|
|
104
|
+
}
|
|
105
|
+
const USAGE_TEXT = [
|
|
106
|
+
'Usage:',
|
|
107
|
+
' /claude-account Show account list',
|
|
108
|
+
' /claude-account enable <id> Enable a fallback account',
|
|
109
|
+
' /claude-account disable <id> Disable a fallback account',
|
|
110
|
+
' /claude-account remove <id> Remove a fallback account',
|
|
111
|
+
' /claude-account move-up <id> Move a fallback account up',
|
|
112
|
+
' /claude-account move-down <id> Move a fallback account down',
|
|
113
|
+
' /claude-account add-apikey <key> Add an API key fallback account',
|
|
114
|
+
' /claude-account add-oauth-start Start OAuth device flow',
|
|
115
|
+
' /claude-account add-oauth-finish <code> Complete OAuth flow',
|
|
116
|
+
].join('\n');
|
|
117
|
+
export function executeAccountCommand(input) {
|
|
118
|
+
const action = parseAccountCommandAction(input.argumentsText);
|
|
119
|
+
const accounts = input.storage.accounts;
|
|
120
|
+
const mainId = 'main';
|
|
121
|
+
if (action.type === 'status') {
|
|
122
|
+
const list = buildAccountList(input.storage);
|
|
123
|
+
const lines = ['## Claude Accounts', ''];
|
|
124
|
+
for (const a of list) {
|
|
125
|
+
const pct = a.quotaPercent != null ? ` ${Math.round(a.quotaPercent)}%` : '';
|
|
126
|
+
const status = !a.enabled ? ' (disabled)' : '';
|
|
127
|
+
lines.push(`- **${a.label}** [${a.role}]${status}${pct}`);
|
|
128
|
+
}
|
|
129
|
+
lines.push('', USAGE_TEXT);
|
|
130
|
+
return { text: lines.join('\n') };
|
|
131
|
+
}
|
|
132
|
+
if (action.type === 'usage') {
|
|
133
|
+
return { text: USAGE_TEXT };
|
|
134
|
+
}
|
|
135
|
+
if (action.type === 'add-apikey') {
|
|
136
|
+
return { text: 'add-apikey' };
|
|
137
|
+
}
|
|
138
|
+
if (action.type === 'add-oauth-start') {
|
|
139
|
+
return { text: 'add-oauth-start' };
|
|
140
|
+
}
|
|
141
|
+
if (action.type === 'add-oauth-finish') {
|
|
142
|
+
return { text: 'add-oauth-finish' };
|
|
143
|
+
}
|
|
144
|
+
const id = action.id;
|
|
145
|
+
if (id === mainId) {
|
|
146
|
+
return {
|
|
147
|
+
text: `Cannot ${action.type} the main account (OpenCode managed).`,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
if (action.type === 'enable' || action.type === 'disable') {
|
|
151
|
+
const target = accounts.find((a) => a.id === id);
|
|
152
|
+
if (!target) {
|
|
153
|
+
return { text: `Account "${id}" not found.` };
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
text: `Account "${target.label ?? id}" ${action.type}d.`,
|
|
157
|
+
updated: {
|
|
158
|
+
id,
|
|
159
|
+
action: action.type,
|
|
160
|
+
enabled: action.type === 'enable',
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
if (action.type === 'remove') {
|
|
165
|
+
const target = accounts.find((a) => a.id === id);
|
|
166
|
+
if (!target) {
|
|
167
|
+
return { text: `Account "${id}" not found.` };
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
text: `Account "${target.label ?? id}" removed.`,
|
|
171
|
+
updated: { id, action: 'remove' },
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
if (action.type === 'move-up') {
|
|
175
|
+
const idx = accounts.findIndex((a) => a.id === id);
|
|
176
|
+
if (idx < 0) {
|
|
177
|
+
return { text: `Account "${id}" not found.` };
|
|
178
|
+
}
|
|
179
|
+
if (idx === 0) {
|
|
180
|
+
return {
|
|
181
|
+
text: `Account "${accounts[idx]?.label ?? id}" is already first.`,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
const previousOrder = accounts.map((a) => a.id);
|
|
185
|
+
const newAccounts = [...accounts];
|
|
186
|
+
[newAccounts[idx - 1], newAccounts[idx]] = [
|
|
187
|
+
newAccounts[idx],
|
|
188
|
+
newAccounts[idx - 1],
|
|
189
|
+
];
|
|
190
|
+
const newOrder = newAccounts.map((a) => a.id);
|
|
191
|
+
return {
|
|
192
|
+
text: `Account "${accounts[idx]?.label ?? id}" moved up.`,
|
|
193
|
+
updated: { id, action: 'reorder', previousOrder, newOrder },
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
if (action.type === 'move-down') {
|
|
197
|
+
const idx = accounts.findIndex((a) => a.id === id);
|
|
198
|
+
if (idx < 0) {
|
|
199
|
+
return { text: `Account "${id}" not found.` };
|
|
200
|
+
}
|
|
201
|
+
if (idx === accounts.length - 1) {
|
|
202
|
+
return {
|
|
203
|
+
text: `Account "${accounts[idx]?.label ?? id}" is already last.`,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
const previousOrder = accounts.map((a) => a.id);
|
|
207
|
+
const newAccounts = [...accounts];
|
|
208
|
+
[newAccounts[idx], newAccounts[idx + 1]] = [
|
|
209
|
+
newAccounts[idx + 1],
|
|
210
|
+
newAccounts[idx],
|
|
211
|
+
];
|
|
212
|
+
const newOrder = newAccounts.map((a) => a.id);
|
|
213
|
+
return {
|
|
214
|
+
text: `Account "${accounts[idx]?.label ?? id}" moved down.`,
|
|
215
|
+
updated: { id, action: 'reorder', previousOrder, newOrder },
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
return { text: USAGE_TEXT };
|
|
219
|
+
}
|
package/dist/dump.js
CHANGED
|
@@ -3,7 +3,7 @@ import { mkdir, writeFile } from 'node:fs/promises';
|
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import { extractBillingHeaderCCH } from "./cch.js";
|
|
6
|
-
import { relayLog } from "./logger.js";
|
|
6
|
+
import { isSecretKey, relayLog } from "./logger.js";
|
|
7
7
|
export const CLAUDE_DUMP_COMMAND_NAME = 'claude-dump';
|
|
8
8
|
const DUMP_STATUS_TITLE = '## Claude Dump Status';
|
|
9
9
|
const DUMP_ENABLED_TITLE = '## Claude Dump Enabled';
|
|
@@ -214,7 +214,8 @@ function redactForDump(value) {
|
|
|
214
214
|
if (lower === 'authorization' ||
|
|
215
215
|
lower === 'x-api-key' ||
|
|
216
216
|
lower === 'cookie' ||
|
|
217
|
-
lower === 'set-cookie'
|
|
217
|
+
lower === 'set-cookie' ||
|
|
218
|
+
isSecretKey(key)) {
|
|
218
219
|
redacted[key] = '[redacted]';
|
|
219
220
|
continue;
|
|
220
221
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,13 +4,16 @@ export * from './cache1h.ts';
|
|
|
4
4
|
export * from './cachekeep.ts';
|
|
5
5
|
export * from './cch.ts';
|
|
6
6
|
export * from './claude-code.ts';
|
|
7
|
+
export * from './commands/account.ts';
|
|
7
8
|
export * from './constants.ts';
|
|
8
9
|
export * from './dump.ts';
|
|
9
10
|
export * from './fast.ts';
|
|
10
11
|
export * from './killswitch.ts';
|
|
11
12
|
export * from './logger.ts';
|
|
13
|
+
export * from './logging.ts';
|
|
12
14
|
export * from './models.ts';
|
|
13
15
|
export * from './pkce.ts';
|
|
16
|
+
export * from './provider.ts';
|
|
14
17
|
export * from './quota-manager.ts';
|
|
15
18
|
export * from './quotas.ts';
|
|
16
19
|
export * from './relay.ts';
|
package/dist/index.js
CHANGED
|
@@ -4,13 +4,16 @@ export * from "./cache1h.js";
|
|
|
4
4
|
export * from "./cachekeep.js";
|
|
5
5
|
export * from "./cch.js";
|
|
6
6
|
export * from "./claude-code.js";
|
|
7
|
+
export * from "./commands/account.js";
|
|
7
8
|
export * from "./constants.js";
|
|
8
9
|
export * from "./dump.js";
|
|
9
10
|
export * from "./fast.js";
|
|
10
11
|
export * from "./killswitch.js";
|
|
11
12
|
export * from "./logger.js";
|
|
13
|
+
export * from "./logging.js";
|
|
12
14
|
export * from "./models.js";
|
|
13
15
|
export * from "./pkce.js";
|
|
16
|
+
export * from "./provider.js";
|
|
14
17
|
export * from "./quota-manager.js";
|
|
15
18
|
export * from "./quotas.js";
|
|
16
19
|
export * from "./relay.js";
|
package/dist/logger.d.ts
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
export type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace';
|
|
2
|
+
declare function parseLogLevel(value: string | undefined): LogLevel | null;
|
|
3
|
+
export declare function setLogLevel(level: LogLevel): void;
|
|
4
|
+
export declare function getLogLevel(): LogLevel;
|
|
5
|
+
export { parseLogLevel };
|
|
6
|
+
export declare function shouldEmit(level: LogLevel): boolean;
|
|
7
|
+
export declare function getLogFilePath(): string;
|
|
8
|
+
export declare const SECRET_KEY_EXACT: RegExp;
|
|
9
|
+
export declare function isSecretKey(key: string): boolean;
|
|
10
|
+
export declare function redactPayload(payload?: Record<string, unknown>): Record<string, unknown> | undefined;
|
|
11
|
+
export declare function formatLogLine(level: LogLevel, channel: string, message: string, payload?: Record<string, unknown>): string;
|
|
12
|
+
export type LogTestRecord = {
|
|
13
|
+
level: LogLevel;
|
|
14
|
+
channel: string;
|
|
15
|
+
message: string;
|
|
16
|
+
payload?: Record<string, unknown>;
|
|
17
|
+
};
|
|
18
|
+
export declare function __setLogTestSink(sink: ((record: LogTestRecord) => void) | null): void;
|
|
19
|
+
export declare const logger: {
|
|
20
|
+
error(channel: string, message: string, payload?: Record<string, unknown>): void;
|
|
21
|
+
warn(channel: string, message: string, payload?: Record<string, unknown>): void;
|
|
22
|
+
info(channel: string, message: string, payload?: Record<string, unknown>): void;
|
|
23
|
+
debug(channel: string, message: string, payload?: Record<string, unknown>): void;
|
|
24
|
+
trace(channel: string, message: string, payload?: Record<string, unknown>): void;
|
|
25
|
+
};
|
|
1
26
|
export declare function log(message: string, data?: unknown): void;
|
|
2
27
|
export declare function relayLog(message: string, data?: unknown): void;
|
|
3
|
-
export declare function getLogFilePath(): string;
|