chatccc 0.2.181 → 0.2.183
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/README.md +69 -69
- package/package.json +1 -1
- package/src/__tests__/card-plain-text.test.ts +5 -5
- package/src/__tests__/cards.test.ts +77 -77
- package/src/__tests__/codex-reset-actions.test.ts +40 -7
- package/src/__tests__/feishu-avatar.test.ts +115 -115
- package/src/__tests__/feishu-platform.test.ts +22 -22
- package/src/__tests__/format-message.test.ts +316 -273
- package/src/__tests__/orchestrator.test.ts +117 -117
- package/src/__tests__/shared-prefix.test.ts +36 -36
- package/src/cards.ts +89 -89
- package/src/codex-reset-actions.ts +19 -6
- package/src/feishu-api.ts +184 -184
- package/src/feishu-platform.ts +20 -20
- package/src/format-message.ts +293 -214
- package/src/index.ts +2 -0
- package/src/orchestrator.ts +120 -120
- package/src/shared-prefix.ts +29 -29
- package/src/sim-platform.ts +20 -20
package/src/feishu-api.ts
CHANGED
|
@@ -302,10 +302,10 @@ const AVATAR_DIR = resolvePath(PROJECT_ROOT, "images", "avatars");
|
|
|
302
302
|
const AVATAR_BADGE_DIR = resolvePath(AVATAR_DIR, "badges");
|
|
303
303
|
const AVATAR_COMBINATIONS_DIR = resolvePath(AVATAR_DIR, "combinations");
|
|
304
304
|
const AVATAR_KEY_CACHE_FILE = resolvePath(USER_DATA_DIR, "state", "avatar-image-keys.json");
|
|
305
|
-
const CODEX_AUTH_FILE = resolvePath(homedir(), ".codex", "auth.json");
|
|
306
|
-
const CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
|
|
307
|
-
const CODEX_RESET_CREDITS_URL = "https://chatgpt.com/backend-api/wham/rate-limit-reset-credits";
|
|
308
|
-
const CODEX_RESET_CONSUME_URL = "https://chatgpt.com/backend-api/wham/rate-limit-reset-credits/consume";
|
|
305
|
+
const CODEX_AUTH_FILE = resolvePath(homedir(), ".codex", "auth.json");
|
|
306
|
+
const CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
|
|
307
|
+
const CODEX_RESET_CREDITS_URL = "https://chatgpt.com/backend-api/wham/rate-limit-reset-credits";
|
|
308
|
+
const CODEX_RESET_CONSUME_URL = "https://chatgpt.com/backend-api/wham/rate-limit-reset-credits/consume";
|
|
309
309
|
const AVATAR_SOURCES: Record<string, string> = {
|
|
310
310
|
new: resolvePath(AVATAR_DIR, "status_new.png"),
|
|
311
311
|
busy: resolvePath(AVATAR_DIR, "status_busy.png"),
|
|
@@ -322,31 +322,31 @@ const AVATAR_BADGE_MARGIN = 10;
|
|
|
322
322
|
const CODEX_AVATAR_USAGE_STYLE_VERSION = "usage-ring-gray-consumed-v13";
|
|
323
323
|
const CURSOR_AVATAR_USAGE_STYLE_VERSION = "usage-battery-v1";
|
|
324
324
|
|
|
325
|
-
export interface CodexUsageBalance {
|
|
326
|
-
usedPercent: number;
|
|
327
|
-
remainingPercent: number;
|
|
328
|
-
resetAtEpochSeconds: number | null;
|
|
329
|
-
resetAfterSeconds: number | null;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
export interface CodexRateLimitResetCredit {
|
|
333
|
-
grantedAt: string | null;
|
|
334
|
-
expiresAt: string;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
export interface CodexUsageSummary {
|
|
338
|
-
fiveHour: CodexUsageBalance;
|
|
339
|
-
weekly: CodexUsageBalance | null;
|
|
340
|
-
rateLimitResetCreditsAvailable: number | null;
|
|
341
|
-
rateLimitResetCredits: CodexRateLimitResetCredit[] | null;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
export type CodexResetConsumeCode = "reset" | "nothing_to_reset" | "no_credit" | "already_redeemed";
|
|
345
|
-
|
|
346
|
-
export interface CodexResetConsumeResult {
|
|
347
|
-
code: CodexResetConsumeCode;
|
|
348
|
-
windowsReset: number;
|
|
349
|
-
}
|
|
325
|
+
export interface CodexUsageBalance {
|
|
326
|
+
usedPercent: number;
|
|
327
|
+
remainingPercent: number;
|
|
328
|
+
resetAtEpochSeconds: number | null;
|
|
329
|
+
resetAfterSeconds: number | null;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export interface CodexRateLimitResetCredit {
|
|
333
|
+
grantedAt: string | null;
|
|
334
|
+
expiresAt: string;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export interface CodexUsageSummary {
|
|
338
|
+
fiveHour: CodexUsageBalance;
|
|
339
|
+
weekly: CodexUsageBalance | null;
|
|
340
|
+
rateLimitResetCreditsAvailable: number | null;
|
|
341
|
+
rateLimitResetCredits: CodexRateLimitResetCredit[] | null;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export type CodexResetConsumeCode = "reset" | "nothing_to_reset" | "no_credit" | "already_redeemed";
|
|
345
|
+
|
|
346
|
+
export interface CodexResetConsumeResult {
|
|
347
|
+
code: CodexResetConsumeCode;
|
|
348
|
+
windowsReset: number;
|
|
349
|
+
}
|
|
350
350
|
|
|
351
351
|
const avatarKeyCache = new Map<string, string>();
|
|
352
352
|
let avatarKeyCacheLoaded = false;
|
|
@@ -427,167 +427,167 @@ function usageBalanceFromWindow(raw: Record<string, unknown>, fieldName: string)
|
|
|
427
427
|
};
|
|
428
428
|
}
|
|
429
429
|
|
|
430
|
-
function parseOptionalUsageWindow(rateLimit: Record<string, unknown>, keys: string[]): CodexUsageBalance | null {
|
|
430
|
+
function parseOptionalUsageWindow(rateLimit: Record<string, unknown>, keys: string[]): CodexUsageBalance | null {
|
|
431
431
|
for (const key of keys) {
|
|
432
432
|
const raw = rateLimit[key];
|
|
433
433
|
if (!raw || typeof raw !== "object") continue;
|
|
434
434
|
if ((raw as { used_percent?: unknown }).used_percent === undefined) continue;
|
|
435
435
|
return usageBalanceFromWindow(raw as Record<string, unknown>, `rate_limit.${key}`);
|
|
436
436
|
}
|
|
437
|
-
return null;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
function parseRateLimitResetCredits(data: Record<string, unknown>): number | null {
|
|
441
|
-
const raw = data.rate_limit_reset_credits;
|
|
442
|
-
if (!raw || typeof raw !== "object") return null;
|
|
443
|
-
const availableCount = Number((raw as { available_count?: unknown }).available_count);
|
|
444
|
-
if (!Number.isFinite(availableCount)) return null;
|
|
445
|
-
return Math.max(0, Math.trunc(availableCount));
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
interface CodexAuth {
|
|
449
|
-
accessToken: string;
|
|
450
|
-
accountId?: string;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
async function getCodexAuth(): Promise<CodexAuth | null> {
|
|
454
|
-
try {
|
|
455
|
-
const raw = await readFile(CODEX_AUTH_FILE, "utf-8");
|
|
456
|
-
const parsed = JSON.parse(raw) as { tokens?: { access_token?: unknown; account_id?: unknown } };
|
|
457
|
-
const token = parsed.tokens?.access_token;
|
|
458
|
-
if (typeof token !== "string" || !token.trim()) return null;
|
|
459
|
-
const accountId = parsed.tokens?.account_id;
|
|
460
|
-
return {
|
|
461
|
-
accessToken: token,
|
|
462
|
-
accountId: typeof accountId === "string" && accountId.trim() ? accountId : undefined,
|
|
463
|
-
};
|
|
464
|
-
} catch {
|
|
465
|
-
return null;
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
async function getCodexAccessToken(): Promise<string | null> {
|
|
470
|
-
return (await getCodexAuth())?.accessToken ?? null;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
function codexAuthHeaders(auth: CodexAuth): Record<string, string> {
|
|
474
|
-
const headers: Record<string, string> = {
|
|
475
|
-
Authorization: `Bearer ${auth.accessToken}`,
|
|
476
|
-
"OpenAI-Beta": "codex-1",
|
|
477
|
-
originator: "Codex Desktop",
|
|
478
|
-
};
|
|
479
|
-
if (auth.accountId) headers["ChatGPT-Account-ID"] = auth.accountId;
|
|
480
|
-
return headers;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
function parseCodexResetCreditDetails(data: Record<string, unknown>): {
|
|
484
|
-
availableCount: number | null;
|
|
485
|
-
availableCredits: CodexRateLimitResetCredit[];
|
|
486
|
-
} {
|
|
487
|
-
const availableCount = Number(data.available_count);
|
|
488
|
-
const credits = Array.isArray(data.credits) ? data.credits : [];
|
|
489
|
-
return {
|
|
490
|
-
availableCount: Number.isFinite(availableCount) ? Math.max(0, Math.trunc(availableCount)) : null,
|
|
491
|
-
availableCredits: credits.flatMap((raw) => {
|
|
492
|
-
if (!raw || typeof raw !== "object") return [];
|
|
493
|
-
const credit = raw as { status?: unknown; granted_at?: unknown; expires_at?: unknown };
|
|
494
|
-
if (credit.status !== "available") return [];
|
|
495
|
-
if (typeof credit.expires_at !== "string" || !credit.expires_at.trim()) return [];
|
|
496
|
-
return [{
|
|
497
|
-
grantedAt: typeof credit.granted_at === "string" && credit.granted_at.trim() ? credit.granted_at : null,
|
|
498
|
-
expiresAt: credit.expires_at,
|
|
499
|
-
}];
|
|
500
|
-
}),
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
async function fetchCodexRateLimitResetCredits(auth: CodexAuth): Promise<{
|
|
505
|
-
availableCount: number | null;
|
|
506
|
-
availableCredits: CodexRateLimitResetCredit[];
|
|
507
|
-
} | null> {
|
|
508
|
-
try {
|
|
509
|
-
const resp = await fetch(CODEX_RESET_CREDITS_URL, {
|
|
510
|
-
headers: codexAuthHeaders(auth),
|
|
511
|
-
});
|
|
512
|
-
const text = await resp.text();
|
|
513
|
-
if (!resp.ok) throw new Error(`HTTP ${resp.status}: ${text.slice(0, 160)}`);
|
|
514
|
-
return parseCodexResetCreditDetails(JSON.parse(text) as Record<string, unknown>);
|
|
515
|
-
} catch (err) {
|
|
516
|
-
console.warn(`[Codex] reset credits lookup failed: ${(err as Error).message}`);
|
|
517
|
-
return null;
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
export async function getCodexUsageSummary(): Promise<CodexUsageSummary> {
|
|
522
|
-
const auth = await getCodexAuth();
|
|
523
|
-
if (!auth) throw new Error("missing ~/.codex/auth.json access token");
|
|
524
|
-
|
|
525
|
-
const resetCreditsPromise = fetchCodexRateLimitResetCredits(auth);
|
|
526
|
-
|
|
527
|
-
const resp = await fetch(CODEX_USAGE_URL, {
|
|
528
|
-
headers: { Authorization: `Bearer ${auth.accessToken}` },
|
|
529
|
-
});
|
|
530
|
-
const text = await resp.text();
|
|
531
|
-
if (!resp.ok) throw new Error(`HTTP ${resp.status}: ${text.slice(0, 160)}`);
|
|
532
|
-
|
|
533
|
-
const data = JSON.parse(text) as {
|
|
534
|
-
rate_limit?: Record<string, unknown>;
|
|
535
|
-
rate_limit_reset_credits?: unknown;
|
|
536
|
-
};
|
|
537
|
-
const rateLimit = data.rate_limit;
|
|
538
|
-
if (!rateLimit || typeof rateLimit !== "object") throw new Error("missing rate_limit");
|
|
539
|
-
|
|
540
|
-
const fiveHour = parseOptionalUsageWindow(rateLimit, ["primary_window"]);
|
|
541
|
-
if (!fiveHour) throw new Error("missing rate_limit.primary_window.used_percent");
|
|
542
|
-
const resetCredits = await resetCreditsPromise;
|
|
543
|
-
|
|
544
|
-
return {
|
|
545
|
-
fiveHour,
|
|
546
|
-
weekly: parseOptionalUsageWindow(rateLimit, [
|
|
547
|
-
"secondary_window",
|
|
548
|
-
"weekly_window",
|
|
549
|
-
"week_window",
|
|
550
|
-
"long_window",
|
|
551
|
-
]),
|
|
552
|
-
rateLimitResetCreditsAvailable: resetCredits?.availableCount ?? parseRateLimitResetCredits(data),
|
|
553
|
-
rateLimitResetCredits: resetCredits?.availableCredits ?? null,
|
|
554
|
-
};
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
export async function consumeCodexRateLimitResetCredit(redeemRequestId: string): Promise<CodexResetConsumeResult> {
|
|
558
|
-
if (!redeemRequestId.trim()) throw new Error("missing redeem_request_id");
|
|
559
|
-
const token = await getCodexAccessToken();
|
|
560
|
-
if (!token) throw new Error("missing ~/.codex/auth.json access token");
|
|
561
|
-
|
|
562
|
-
const resp = await fetch(CODEX_RESET_CONSUME_URL, {
|
|
563
|
-
method: "POST",
|
|
564
|
-
headers: {
|
|
565
|
-
Authorization: `Bearer ${token}`,
|
|
566
|
-
"Content-Type": "application/json",
|
|
567
|
-
},
|
|
568
|
-
body: JSON.stringify({ redeem_request_id: redeemRequestId }),
|
|
569
|
-
});
|
|
570
|
-
const text = await resp.text();
|
|
571
|
-
if (!resp.ok) throw new Error(`HTTP ${resp.status}: ${text.slice(0, 160)}`);
|
|
572
|
-
|
|
573
|
-
const data = JSON.parse(text) as { code?: unknown; windows_reset?: unknown };
|
|
574
|
-
const code = data.code;
|
|
575
|
-
if (
|
|
576
|
-
code !== "reset"
|
|
577
|
-
&& code !== "nothing_to_reset"
|
|
578
|
-
&& code !== "no_credit"
|
|
579
|
-
&& code !== "already_redeemed"
|
|
580
|
-
) {
|
|
581
|
-
throw new Error("missing or unknown reset result code");
|
|
582
|
-
}
|
|
583
|
-
const windowsReset = Number(data.windows_reset);
|
|
584
|
-
return {
|
|
585
|
-
code,
|
|
586
|
-
windowsReset: Number.isFinite(windowsReset) ? Math.max(0, Math.trunc(windowsReset)) : 0,
|
|
587
|
-
};
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
async function fetchCodexAvatarUsage(): Promise<CodexUsageSummary | null> {
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function parseRateLimitResetCredits(data: Record<string, unknown>): number | null {
|
|
441
|
+
const raw = data.rate_limit_reset_credits;
|
|
442
|
+
if (!raw || typeof raw !== "object") return null;
|
|
443
|
+
const availableCount = Number((raw as { available_count?: unknown }).available_count);
|
|
444
|
+
if (!Number.isFinite(availableCount)) return null;
|
|
445
|
+
return Math.max(0, Math.trunc(availableCount));
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
interface CodexAuth {
|
|
449
|
+
accessToken: string;
|
|
450
|
+
accountId?: string;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
async function getCodexAuth(): Promise<CodexAuth | null> {
|
|
454
|
+
try {
|
|
455
|
+
const raw = await readFile(CODEX_AUTH_FILE, "utf-8");
|
|
456
|
+
const parsed = JSON.parse(raw) as { tokens?: { access_token?: unknown; account_id?: unknown } };
|
|
457
|
+
const token = parsed.tokens?.access_token;
|
|
458
|
+
if (typeof token !== "string" || !token.trim()) return null;
|
|
459
|
+
const accountId = parsed.tokens?.account_id;
|
|
460
|
+
return {
|
|
461
|
+
accessToken: token,
|
|
462
|
+
accountId: typeof accountId === "string" && accountId.trim() ? accountId : undefined,
|
|
463
|
+
};
|
|
464
|
+
} catch {
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
async function getCodexAccessToken(): Promise<string | null> {
|
|
470
|
+
return (await getCodexAuth())?.accessToken ?? null;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function codexAuthHeaders(auth: CodexAuth): Record<string, string> {
|
|
474
|
+
const headers: Record<string, string> = {
|
|
475
|
+
Authorization: `Bearer ${auth.accessToken}`,
|
|
476
|
+
"OpenAI-Beta": "codex-1",
|
|
477
|
+
originator: "Codex Desktop",
|
|
478
|
+
};
|
|
479
|
+
if (auth.accountId) headers["ChatGPT-Account-ID"] = auth.accountId;
|
|
480
|
+
return headers;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function parseCodexResetCreditDetails(data: Record<string, unknown>): {
|
|
484
|
+
availableCount: number | null;
|
|
485
|
+
availableCredits: CodexRateLimitResetCredit[];
|
|
486
|
+
} {
|
|
487
|
+
const availableCount = Number(data.available_count);
|
|
488
|
+
const credits = Array.isArray(data.credits) ? data.credits : [];
|
|
489
|
+
return {
|
|
490
|
+
availableCount: Number.isFinite(availableCount) ? Math.max(0, Math.trunc(availableCount)) : null,
|
|
491
|
+
availableCredits: credits.flatMap((raw) => {
|
|
492
|
+
if (!raw || typeof raw !== "object") return [];
|
|
493
|
+
const credit = raw as { status?: unknown; granted_at?: unknown; expires_at?: unknown };
|
|
494
|
+
if (credit.status !== "available") return [];
|
|
495
|
+
if (typeof credit.expires_at !== "string" || !credit.expires_at.trim()) return [];
|
|
496
|
+
return [{
|
|
497
|
+
grantedAt: typeof credit.granted_at === "string" && credit.granted_at.trim() ? credit.granted_at : null,
|
|
498
|
+
expiresAt: credit.expires_at,
|
|
499
|
+
}];
|
|
500
|
+
}),
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
async function fetchCodexRateLimitResetCredits(auth: CodexAuth): Promise<{
|
|
505
|
+
availableCount: number | null;
|
|
506
|
+
availableCredits: CodexRateLimitResetCredit[];
|
|
507
|
+
} | null> {
|
|
508
|
+
try {
|
|
509
|
+
const resp = await fetch(CODEX_RESET_CREDITS_URL, {
|
|
510
|
+
headers: codexAuthHeaders(auth),
|
|
511
|
+
});
|
|
512
|
+
const text = await resp.text();
|
|
513
|
+
if (!resp.ok) throw new Error(`HTTP ${resp.status}: ${text.slice(0, 160)}`);
|
|
514
|
+
return parseCodexResetCreditDetails(JSON.parse(text) as Record<string, unknown>);
|
|
515
|
+
} catch (err) {
|
|
516
|
+
console.warn(`[Codex] reset credits lookup failed: ${(err as Error).message}`);
|
|
517
|
+
return null;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
export async function getCodexUsageSummary(): Promise<CodexUsageSummary> {
|
|
522
|
+
const auth = await getCodexAuth();
|
|
523
|
+
if (!auth) throw new Error("missing ~/.codex/auth.json access token");
|
|
524
|
+
|
|
525
|
+
const resetCreditsPromise = fetchCodexRateLimitResetCredits(auth);
|
|
526
|
+
|
|
527
|
+
const resp = await fetch(CODEX_USAGE_URL, {
|
|
528
|
+
headers: { Authorization: `Bearer ${auth.accessToken}` },
|
|
529
|
+
});
|
|
530
|
+
const text = await resp.text();
|
|
531
|
+
if (!resp.ok) throw new Error(`HTTP ${resp.status}: ${text.slice(0, 160)}`);
|
|
532
|
+
|
|
533
|
+
const data = JSON.parse(text) as {
|
|
534
|
+
rate_limit?: Record<string, unknown>;
|
|
535
|
+
rate_limit_reset_credits?: unknown;
|
|
536
|
+
};
|
|
537
|
+
const rateLimit = data.rate_limit;
|
|
538
|
+
if (!rateLimit || typeof rateLimit !== "object") throw new Error("missing rate_limit");
|
|
539
|
+
|
|
540
|
+
const fiveHour = parseOptionalUsageWindow(rateLimit, ["primary_window"]);
|
|
541
|
+
if (!fiveHour) throw new Error("missing rate_limit.primary_window.used_percent");
|
|
542
|
+
const resetCredits = await resetCreditsPromise;
|
|
543
|
+
|
|
544
|
+
return {
|
|
545
|
+
fiveHour,
|
|
546
|
+
weekly: parseOptionalUsageWindow(rateLimit, [
|
|
547
|
+
"secondary_window",
|
|
548
|
+
"weekly_window",
|
|
549
|
+
"week_window",
|
|
550
|
+
"long_window",
|
|
551
|
+
]),
|
|
552
|
+
rateLimitResetCreditsAvailable: resetCredits?.availableCount ?? parseRateLimitResetCredits(data),
|
|
553
|
+
rateLimitResetCredits: resetCredits?.availableCredits ?? null,
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
export async function consumeCodexRateLimitResetCredit(redeemRequestId: string): Promise<CodexResetConsumeResult> {
|
|
558
|
+
if (!redeemRequestId.trim()) throw new Error("missing redeem_request_id");
|
|
559
|
+
const token = await getCodexAccessToken();
|
|
560
|
+
if (!token) throw new Error("missing ~/.codex/auth.json access token");
|
|
561
|
+
|
|
562
|
+
const resp = await fetch(CODEX_RESET_CONSUME_URL, {
|
|
563
|
+
method: "POST",
|
|
564
|
+
headers: {
|
|
565
|
+
Authorization: `Bearer ${token}`,
|
|
566
|
+
"Content-Type": "application/json",
|
|
567
|
+
},
|
|
568
|
+
body: JSON.stringify({ redeem_request_id: redeemRequestId }),
|
|
569
|
+
});
|
|
570
|
+
const text = await resp.text();
|
|
571
|
+
if (!resp.ok) throw new Error(`HTTP ${resp.status}: ${text.slice(0, 160)}`);
|
|
572
|
+
|
|
573
|
+
const data = JSON.parse(text) as { code?: unknown; windows_reset?: unknown };
|
|
574
|
+
const code = data.code;
|
|
575
|
+
if (
|
|
576
|
+
code !== "reset"
|
|
577
|
+
&& code !== "nothing_to_reset"
|
|
578
|
+
&& code !== "no_credit"
|
|
579
|
+
&& code !== "already_redeemed"
|
|
580
|
+
) {
|
|
581
|
+
throw new Error("missing or unknown reset result code");
|
|
582
|
+
}
|
|
583
|
+
const windowsReset = Number(data.windows_reset);
|
|
584
|
+
return {
|
|
585
|
+
code,
|
|
586
|
+
windowsReset: Number.isFinite(windowsReset) ? Math.max(0, Math.trunc(windowsReset)) : 0,
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
async function fetchCodexAvatarUsage(): Promise<CodexUsageSummary | null> {
|
|
591
591
|
try {
|
|
592
592
|
const summary = await getCodexUsageSummary();
|
|
593
593
|
if (!summary.weekly) throw new Error("missing weekly usage window");
|
package/src/feishu-platform.ts
CHANGED
|
@@ -29,10 +29,10 @@ export interface FeishuPlatform {
|
|
|
29
29
|
updateChatInfo: typeof realApi.updateChatInfo;
|
|
30
30
|
getChatInfo: typeof realApi.getChatInfo;
|
|
31
31
|
disbandChat: typeof realApi.disbandChat;
|
|
32
|
-
setChatAvatar: typeof realApi.setChatAvatar;
|
|
33
|
-
getCodexUsageSummary: typeof realApi.getCodexUsageSummary;
|
|
34
|
-
consumeCodexRateLimitResetCredit: typeof realApi.consumeCodexRateLimitResetCredit;
|
|
35
|
-
getOrDownloadImage: typeof realApi.getOrDownloadImage;
|
|
32
|
+
setChatAvatar: typeof realApi.setChatAvatar;
|
|
33
|
+
getCodexUsageSummary: typeof realApi.getCodexUsageSummary;
|
|
34
|
+
consumeCodexRateLimitResetCredit: typeof realApi.consumeCodexRateLimitResetCredit;
|
|
35
|
+
getOrDownloadImage: typeof realApi.getOrDownloadImage;
|
|
36
36
|
verifyAllPermissions: typeof realApi.verifyAllPermissions;
|
|
37
37
|
reportPermissionResults: typeof realApi.reportPermissionResults;
|
|
38
38
|
extractSessionInfo: typeof realApi.extractSessionInfo;
|
|
@@ -110,21 +110,21 @@ export function disbandChat(...args: Parameters<typeof realApi.disbandChat>): Re
|
|
|
110
110
|
return _impl.disbandChat(...args);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
export function setChatAvatar(...args: Parameters<typeof realApi.setChatAvatar>): ReturnType<typeof realApi.setChatAvatar> {
|
|
114
|
-
return _impl.setChatAvatar(...args);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export function getCodexUsageSummary(...args: Parameters<typeof realApi.getCodexUsageSummary>): ReturnType<typeof realApi.getCodexUsageSummary> {
|
|
118
|
-
return _impl.getCodexUsageSummary(...args);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export function consumeCodexRateLimitResetCredit(...args: Parameters<typeof realApi.consumeCodexRateLimitResetCredit>): ReturnType<typeof realApi.consumeCodexRateLimitResetCredit> {
|
|
122
|
-
return _impl.consumeCodexRateLimitResetCredit(...args);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export function getOrDownloadImage(...args: Parameters<typeof realApi.getOrDownloadImage>): ReturnType<typeof realApi.getOrDownloadImage> {
|
|
126
|
-
return _impl.getOrDownloadImage(...args);
|
|
127
|
-
}
|
|
113
|
+
export function setChatAvatar(...args: Parameters<typeof realApi.setChatAvatar>): ReturnType<typeof realApi.setChatAvatar> {
|
|
114
|
+
return _impl.setChatAvatar(...args);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function getCodexUsageSummary(...args: Parameters<typeof realApi.getCodexUsageSummary>): ReturnType<typeof realApi.getCodexUsageSummary> {
|
|
118
|
+
return _impl.getCodexUsageSummary(...args);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function consumeCodexRateLimitResetCredit(...args: Parameters<typeof realApi.consumeCodexRateLimitResetCredit>): ReturnType<typeof realApi.consumeCodexRateLimitResetCredit> {
|
|
122
|
+
return _impl.consumeCodexRateLimitResetCredit(...args);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function getOrDownloadImage(...args: Parameters<typeof realApi.getOrDownloadImage>): ReturnType<typeof realApi.getOrDownloadImage> {
|
|
126
|
+
return _impl.getOrDownloadImage(...args);
|
|
127
|
+
}
|
|
128
128
|
|
|
129
129
|
export function verifyAllPermissions(...args: Parameters<typeof realApi.verifyAllPermissions>): ReturnType<typeof realApi.verifyAllPermissions> {
|
|
130
130
|
return _impl.verifyAllPermissions(...args);
|
|
@@ -156,4 +156,4 @@ export function sendRestartCard(...args: Parameters<typeof realApi.sendRestartCa
|
|
|
156
156
|
|
|
157
157
|
export function getMergeForwardMessages(...args: Parameters<typeof realApi.getMergeForwardMessages>): ReturnType<typeof realApi.getMergeForwardMessages> {
|
|
158
158
|
return _impl.getMergeForwardMessages(...args);
|
|
159
|
-
}
|
|
159
|
+
}
|