claudemon 0.3.3 → 0.4.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/extensions/claudemon.ts +13 -63
- package/package.json +1 -1
package/extensions/claudemon.ts
CHANGED
|
@@ -9,66 +9,16 @@
|
|
|
9
9
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
10
10
|
import { Type } from "@sinclair/typebox";
|
|
11
11
|
import { matchesKey, truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
|
|
12
|
-
import { execFileSync } from "node:child_process";
|
|
13
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
14
|
-
import { homedir, platform } from "node:os";
|
|
15
|
-
import { join } from "node:path";
|
|
16
12
|
|
|
17
13
|
// ---------------------------------------------------------------------------
|
|
18
|
-
// Token resolution
|
|
14
|
+
// Token resolution — uses pi's native auth via modelRegistry
|
|
19
15
|
// ---------------------------------------------------------------------------
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
if (platform() !== "darwin") return null;
|
|
23
|
-
try {
|
|
24
|
-
const raw = execFileSync(
|
|
25
|
-
"/usr/bin/security",
|
|
26
|
-
["find-generic-password", "-s", "Claude Code-credentials", "-w"],
|
|
27
|
-
{ timeout: 5000, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] },
|
|
28
|
-
);
|
|
29
|
-
if (!raw.trim()) return null;
|
|
30
|
-
return JSON.parse(raw.trim()) as Record<string, unknown>;
|
|
31
|
-
} catch {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function readFileCredentials(): Record<string, unknown> | null {
|
|
37
|
-
const credFile = join(homedir(), ".claude", ".credentials.json");
|
|
38
|
-
if (!existsSync(credFile)) return null;
|
|
39
|
-
try {
|
|
40
|
-
return JSON.parse(readFileSync(credFile, "utf-8")) as Record<string, unknown>;
|
|
41
|
-
} catch {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
17
|
+
type ModelRegistryCtx = { modelRegistry: { getApiKeyForProvider(p: string): Promise<string | undefined> } };
|
|
45
18
|
|
|
46
|
-
function
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
const data = JSON.parse(readFileSync(tokenFile, "utf-8"));
|
|
51
|
-
if (data.expires_at && data.expires_at < Date.now()) return null;
|
|
52
|
-
return data.oauth_token ?? null;
|
|
53
|
-
} catch {
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function getOAuthToken(): string | null {
|
|
59
|
-
// Prefer Claude Code's live credentials
|
|
60
|
-
for (const reader of [readKeychainCredentials, readFileCredentials]) {
|
|
61
|
-
const data = reader();
|
|
62
|
-
if (data) {
|
|
63
|
-
const oauth = data["claudeAiOauth"] as { accessToken?: string; expiresAt?: number } | undefined;
|
|
64
|
-
if (oauth?.accessToken) {
|
|
65
|
-
if (oauth.expiresAt && oauth.expiresAt < Date.now()) continue;
|
|
66
|
-
return oauth.accessToken;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
// Fallback to claudemon's own stored token
|
|
71
|
-
return readClaudemonToken();
|
|
19
|
+
async function getOAuthTokenFromCtx(ctx: ModelRegistryCtx): Promise<string | null> {
|
|
20
|
+
const apiKey = await ctx.modelRegistry.getApiKeyForProvider("anthropic");
|
|
21
|
+
return apiKey ?? null;
|
|
72
22
|
}
|
|
73
23
|
|
|
74
24
|
// ---------------------------------------------------------------------------
|
|
@@ -99,7 +49,7 @@ async function fetchQuota(token: string): Promise<QuotaData> {
|
|
|
99
49
|
});
|
|
100
50
|
|
|
101
51
|
if (resp.status === 401 || resp.status === 403) {
|
|
102
|
-
throw new Error("OAuth token expired.
|
|
52
|
+
throw new Error("OAuth token expired or invalid. Try `/login` to re-authenticate.");
|
|
103
53
|
}
|
|
104
54
|
if (resp.status === 429) {
|
|
105
55
|
const retryAfter = resp.headers.get("retry-after");
|
|
@@ -521,10 +471,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
521
471
|
|
|
522
472
|
// --tui flag: launch the native pi TUI dashboard
|
|
523
473
|
if (trimmed === "--tui" || trimmed === "-t") {
|
|
524
|
-
const token =
|
|
474
|
+
const token = await getOAuthTokenFromCtx(ctx);
|
|
525
475
|
if (!token) {
|
|
526
476
|
ctx.ui.notify(
|
|
527
|
-
"Not authenticated.
|
|
477
|
+
"Not authenticated. Make sure you're logged in (`/login`).",
|
|
528
478
|
"error",
|
|
529
479
|
);
|
|
530
480
|
return;
|
|
@@ -543,10 +493,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
543
493
|
}
|
|
544
494
|
|
|
545
495
|
// Default: fetch and display inline
|
|
546
|
-
const token =
|
|
496
|
+
const token = await getOAuthTokenFromCtx(ctx);
|
|
547
497
|
if (!token) {
|
|
548
498
|
ctx.ui.notify(
|
|
549
|
-
"Not authenticated.
|
|
499
|
+
"Not authenticated. Make sure you're logged in (`/login`).",
|
|
550
500
|
"error",
|
|
551
501
|
);
|
|
552
502
|
return;
|
|
@@ -571,14 +521,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
571
521
|
description:
|
|
572
522
|
"Check the user's Claude Pro/Max plan quota usage including 5-hour and 7-day windows and per-model breakdown. Use when the user asks about their Claude usage, quota, or remaining capacity.",
|
|
573
523
|
parameters: Type.Object({}),
|
|
574
|
-
async execute(_toolCallId, _params, signal) {
|
|
575
|
-
const token =
|
|
524
|
+
async execute(_toolCallId, _params, signal, _onUpdate, ctx) {
|
|
525
|
+
const token = await getOAuthTokenFromCtx(ctx as ModelRegistryCtx);
|
|
576
526
|
if (!token) {
|
|
577
527
|
return {
|
|
578
528
|
content: [
|
|
579
529
|
{
|
|
580
530
|
type: "text" as const,
|
|
581
|
-
text: "Not authenticated. The user needs to
|
|
531
|
+
text: "Not authenticated. The user needs to log in first (`/login`).",
|
|
582
532
|
},
|
|
583
533
|
],
|
|
584
534
|
isError: true,
|