@monotykamary/pi-better-grok 0.2.1 → 0.3.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/README.md +6 -1
- package/index.ts +6 -0
- package/package.json +1 -1
- package/src/config.ts +13 -0
- package/src/resets.ts +33 -2
package/README.md
CHANGED
|
@@ -36,6 +36,10 @@ SuperGrok plans earn banked rate-limit reset tokens: redeeming one restores the
|
|
|
36
36
|
|
|
37
37
|
The inventory and redeem calls use the grok.com consumer billing gRPC-Web service (`prod_mc_billing.ConsumerUiSvc/GetRemainingResets` and `RedeemReset`) that the web usage page itself calls, authenticated with the same xAI OAuth token as the usage meter. This surface is undocumented; request shapes are pinned in `src/resets.ts` and schema drift is expected.
|
|
38
38
|
|
|
39
|
+
**Cloudflare requirement (worked around):** grok.com fronts this RPC with a managed challenge that non-browser clients cannot solve — even a perfect Chrome TLS impersonation (curl-impersonate) is challenged, because the site requires a `cf_clearance` cookie issued after a browser solves the challenge once. The cookie is bound to the browser's user-agent and IP. This is the same mechanism community Grok proxies (e.g. grok2api) rely on.
|
|
40
|
+
|
|
41
|
+
Because pi runs on the same machine (and IP) as your browser, supplying both values in config unlocks the surface. To get them: open grok.com in your browser, DevTools → Application → Cookies → copy `cf_clearance`; Network → any request → copy the `User-Agent` request header. When the clearance expires, `/grok-resets` says so explicitly and you re-copy the cookie. Without a clearance configured, the widget hides the count and `/grok-resets` explains the challenge instead of misreporting it as an auth failure.
|
|
42
|
+
|
|
39
43
|
## pi-multiprovider
|
|
40
44
|
|
|
41
45
|
When [pi-multiprovider](https://github.com/monotykamary/pi-multiprovider) pools several `xai` accounts, the session's active account (chosen with `/switch-account`) is resolved first for usage display and banked resets, and the usage widget refreshes on every switch. Without that extension, credential resolution is unchanged: pi's native `xai` OAuth, then `xai-oauth`/`xai-auth` auth-file entries, then the Grok CLI store.
|
|
@@ -56,7 +60,8 @@ JSON config at `~/.pi/agent/extensions/pi-better-grok.json` (global) or `<projec
|
|
|
56
60
|
"showResetTimes": true,
|
|
57
61
|
"showBankedResets": true
|
|
58
62
|
},
|
|
59
|
-
"footer": { "mode": "status" }
|
|
63
|
+
"footer": { "mode": "status" },
|
|
64
|
+
"resets": { "cookies": "", "userAgent": "" }
|
|
60
65
|
}
|
|
61
66
|
```
|
|
62
67
|
|
package/index.ts
CHANGED
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
formatGrokResetOutcome,
|
|
30
30
|
redeemGrokResetForSession,
|
|
31
31
|
selectGrokResetToken,
|
|
32
|
+
setGrokResetNetworkProfile,
|
|
32
33
|
} from "./src/resets.ts";
|
|
33
34
|
import { ResetController } from "./src/reset-controller.ts";
|
|
34
35
|
import {
|
|
@@ -194,6 +195,11 @@ export default function betterGrok(pi: ExtensionAPI): void {
|
|
|
194
195
|
|
|
195
196
|
function refresh(ctx: ExtensionContext): ResolvedConfig {
|
|
196
197
|
cachedConfig = resolveConfig(ctx.cwd || process.cwd());
|
|
198
|
+
setGrokResetNetworkProfile(
|
|
199
|
+
cachedConfig.resets.cookies || cachedConfig.resets.userAgent
|
|
200
|
+
? { cookies: cachedConfig.resets.cookies, userAgent: cachedConfig.resets.userAgent }
|
|
201
|
+
: undefined,
|
|
202
|
+
);
|
|
197
203
|
return cachedConfig;
|
|
198
204
|
}
|
|
199
205
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monotykamary/pi-better-grok",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Improve Grok/xAI in pi with fast mode, subscription usage stats, banked reset redemption, multiprovider pools, footer polish, and settings — mirroring pi-better-openai.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"footer",
|
package/src/config.ts
CHANGED
|
@@ -29,6 +29,14 @@ export type UsageConfig = {
|
|
|
29
29
|
};
|
|
30
30
|
export type FooterConfig = { mode?: FooterMode };
|
|
31
31
|
|
|
32
|
+
// Cloudflare fronts the grok.com billing gRPC with a managed challenge that
|
|
33
|
+
// non-browser runtimes cannot solve. A clearance cookie captured from a grok.com
|
|
34
|
+
// browser session (bound to the browser user-agent and IP) unlocks the fetch.
|
|
35
|
+
export type ResetConfig = {
|
|
36
|
+
cookies?: string;
|
|
37
|
+
userAgent?: string;
|
|
38
|
+
};
|
|
39
|
+
|
|
32
40
|
export interface ConfigFile {
|
|
33
41
|
persistState?: boolean;
|
|
34
42
|
active?: boolean;
|
|
@@ -37,6 +45,7 @@ export interface ConfigFile {
|
|
|
37
45
|
fast?: FastConfig;
|
|
38
46
|
usage?: UsageConfig;
|
|
39
47
|
footer?: FooterConfig;
|
|
48
|
+
resets?: ResetConfig;
|
|
40
49
|
}
|
|
41
50
|
|
|
42
51
|
export interface SupportedModel {
|
|
@@ -57,6 +66,7 @@ export interface ResolvedConfig {
|
|
|
57
66
|
fast: Required<FastConfig>;
|
|
58
67
|
usage: Required<UsageConfig>;
|
|
59
68
|
footer: Required<FooterConfig>;
|
|
69
|
+
resets: Required<ResetConfig>;
|
|
60
70
|
}
|
|
61
71
|
|
|
62
72
|
export const DEFAULT_FAST_CONFIG: Required<FastConfig> = { effort: "low" };
|
|
@@ -68,6 +78,7 @@ export const DEFAULT_USAGE_CONFIG: Required<UsageConfig> = {
|
|
|
68
78
|
showBankedResets: true,
|
|
69
79
|
};
|
|
70
80
|
export const DEFAULT_FOOTER_CONFIG: Required<FooterConfig> = { mode: "status" };
|
|
81
|
+
export const DEFAULT_RESET_CONFIG: Required<ResetConfig> = { cookies: "", userAgent: "" };
|
|
71
82
|
export const DEFAULT_CONFIG: ConfigFile = {
|
|
72
83
|
persistState: true,
|
|
73
84
|
active: false,
|
|
@@ -76,6 +87,7 @@ export const DEFAULT_CONFIG: ConfigFile = {
|
|
|
76
87
|
fast: DEFAULT_FAST_CONFIG,
|
|
77
88
|
usage: DEFAULT_USAGE_CONFIG,
|
|
78
89
|
footer: DEFAULT_FOOTER_CONFIG,
|
|
90
|
+
resets: DEFAULT_RESET_CONFIG,
|
|
79
91
|
};
|
|
80
92
|
|
|
81
93
|
type SettingsOptionSection = "footer" | "usage" | "fast";
|
|
@@ -322,5 +334,6 @@ export function resolveConfig(cwd: string, home = homedir(), env = process.env):
|
|
|
322
334
|
fast: mergedSection(DEFAULT_FAST_CONFIG, globalRaw.fast, projectRaw.fast),
|
|
323
335
|
usage: mergedSection(DEFAULT_USAGE_CONFIG, globalRaw.usage, projectRaw.usage),
|
|
324
336
|
footer: mergedSection(DEFAULT_FOOTER_CONFIG, globalRaw.footer, projectRaw.footer),
|
|
337
|
+
resets: mergedSection(DEFAULT_RESET_CONFIG, globalRaw.resets, projectRaw.resets),
|
|
325
338
|
};
|
|
326
339
|
}
|
package/src/resets.ts
CHANGED
|
@@ -42,7 +42,14 @@ export type GrokRedeemCode = "reset" | "no_credit" | "already_redeemed";
|
|
|
42
42
|
|
|
43
43
|
export type GrokRedeemResult = { code: GrokRedeemCode };
|
|
44
44
|
|
|
45
|
-
export type ResetErrorCode =
|
|
45
|
+
export type ResetErrorCode =
|
|
46
|
+
| "auth"
|
|
47
|
+
| "challenge"
|
|
48
|
+
| "http"
|
|
49
|
+
| "grpc"
|
|
50
|
+
| "invalid"
|
|
51
|
+
| "oversize"
|
|
52
|
+
| "transport";
|
|
46
53
|
|
|
47
54
|
export class ResetError extends Error {
|
|
48
55
|
readonly code: ResetErrorCode;
|
|
@@ -353,13 +360,28 @@ export function mapGrokRedeemStatus(
|
|
|
353
360
|
);
|
|
354
361
|
}
|
|
355
362
|
|
|
363
|
+
export type ResetNetworkProfile = { cookies?: string; userAgent?: string };
|
|
364
|
+
|
|
365
|
+
let networkProfile: ResetNetworkProfile | undefined;
|
|
366
|
+
|
|
367
|
+
// Optional Cloudflare clearance profile: cookies captured from a grok.com
|
|
368
|
+
// browser session (at minimum cf_clearance) plus the user-agent that solved
|
|
369
|
+
// the challenge. Cloudflare binds the clearance to the user-agent and IP, and
|
|
370
|
+
// pi runs on the same machine as the browser, so only the user-agent must match.
|
|
371
|
+
export function setGrokResetNetworkProfile(profile: ResetNetworkProfile | undefined): void {
|
|
372
|
+
networkProfile = profile?.cookies || profile?.userAgent ? profile : undefined;
|
|
373
|
+
}
|
|
374
|
+
|
|
356
375
|
function resetHeaders(credential: GrokCredential): Record<string, string> {
|
|
357
|
-
|
|
376
|
+
const headers: Record<string, string> = {
|
|
358
377
|
Authorization: `Bearer ${credential.token}`,
|
|
359
378
|
"X-XAI-Token-Auth": GROK_CLI_AUTH_HEADER,
|
|
360
379
|
"Content-Type": GRPC_WEB_CONTENT_TYPE,
|
|
361
380
|
"x-grpc-web": "1",
|
|
362
381
|
};
|
|
382
|
+
if (networkProfile?.cookies) headers.Cookie = networkProfile.cookies;
|
|
383
|
+
if (networkProfile?.userAgent) headers["User-Agent"] = networkProfile.userAgent;
|
|
384
|
+
return headers;
|
|
363
385
|
}
|
|
364
386
|
|
|
365
387
|
async function postGrokRpc(
|
|
@@ -383,6 +405,15 @@ async function postGrokRpc(
|
|
|
383
405
|
throw new ResetError("transport", `Grok reset request failed: ${message}`);
|
|
384
406
|
}
|
|
385
407
|
if (!response.ok) {
|
|
408
|
+
if (response.headers.get("cf-mitigated") === "challenge") {
|
|
409
|
+
throw new ResetError(
|
|
410
|
+
"challenge",
|
|
411
|
+
networkProfile?.cookies
|
|
412
|
+
? `grok.com answered with a Cloudflare challenge even with the configured clearance cookie (HTTP ${response.status}); it likely expired or no longer matches the browser user-agent. Re-copy it from a grok.com browser session.`
|
|
413
|
+
: `grok.com is serving a Cloudflare browser challenge (HTTP ${response.status}); banked reset data cannot be fetched from a non-browser client. Set resets.cookies and resets.userAgent in the Better Grok config from a grok.com browser session to enable it.`,
|
|
414
|
+
response.status,
|
|
415
|
+
);
|
|
416
|
+
}
|
|
386
417
|
if (response.status === 401 || response.status === 403) {
|
|
387
418
|
throw new ResetError(
|
|
388
419
|
"auth",
|