pullfrog 0.1.39 → 0.1.40
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/cli.mjs +18 -18
- package/dist/index.js +17 -17
- package/dist/utils/apiKeys.d.ts +12 -0
- package/dist/utils/claudeSubscription.d.ts +3 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -102494,7 +102494,7 @@ async function preflightClaudeSubscription(params) {
|
|
|
102494
102494
|
} catch {
|
|
102495
102495
|
return { usable: true };
|
|
102496
102496
|
}
|
|
102497
|
-
if (res.status !== 401 && res.status !== 429) return { usable: true };
|
|
102497
|
+
if (res.status !== 401 && res.status !== 403 && res.status !== 429) return { usable: true };
|
|
102498
102498
|
const body = await res.text().catch(() => "");
|
|
102499
102499
|
return { usable: false, reason: `${res.status}: ${extractApiErrorMessage(body)}` };
|
|
102500
102500
|
}
|
|
@@ -102997,7 +102997,7 @@ function extractExcerpt(text, matchIndex) {
|
|
|
102997
102997
|
}
|
|
102998
102998
|
return excerpt.trim();
|
|
102999
102999
|
}
|
|
103000
|
-
var ROUTER_KEYLIMIT_EXHAUSTED_PATTERN = /requires more credits.*?fewer max_tokens|requested up to \d+ tokens.*?can only afford/is;
|
|
103000
|
+
var ROUTER_KEYLIMIT_EXHAUSTED_PATTERN = /requires more credits.*?fewer max_tokens|requested up to \d+ tokens.*?can only afford|Key limit exceeded \(total limit\)/is;
|
|
103001
103001
|
function isRouterKeylimitExhaustedError(text) {
|
|
103002
103002
|
return ROUTER_KEYLIMIT_EXHAUSTED_PATTERN.test(text);
|
|
103003
103003
|
}
|
|
@@ -103022,7 +103022,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
103022
103022
|
// package.json
|
|
103023
103023
|
var package_default = {
|
|
103024
103024
|
name: "pullfrog",
|
|
103025
|
-
version: "0.1.
|
|
103025
|
+
version: "0.1.40",
|
|
103026
103026
|
type: "module",
|
|
103027
103027
|
bin: {
|
|
103028
103028
|
pullfrog: "dist/cli.mjs",
|
|
@@ -110466,7 +110466,6 @@ function newTurn() {
|
|
|
110466
110466
|
finalText: "",
|
|
110467
110467
|
tokens: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
110468
110468
|
costUsd: 0,
|
|
110469
|
-
sessionError: null,
|
|
110470
110469
|
lastToolError: null
|
|
110471
110470
|
};
|
|
110472
110471
|
}
|
|
@@ -110497,7 +110496,6 @@ async function dispatchEvent(ctx, event) {
|
|
|
110497
110496
|
if (sessionID !== ctx.orchestratorSessionID) return;
|
|
110498
110497
|
const err = event.properties.error;
|
|
110499
110498
|
const message = err ? extractErrorMessage(err) : "(no error payload)";
|
|
110500
|
-
if (ctx.currentTurn) ctx.currentTurn.sessionError = message;
|
|
110501
110499
|
log.info(`\xBB ${ctx.label} session error: ${message}`);
|
|
110502
110500
|
return;
|
|
110503
110501
|
}
|
|
@@ -110690,14 +110688,6 @@ async function runPromptTurn(ctx, params) {
|
|
|
110690
110688
|
usage
|
|
110691
110689
|
};
|
|
110692
110690
|
}
|
|
110693
|
-
if (turn.sessionError) {
|
|
110694
|
-
return {
|
|
110695
|
-
success: false,
|
|
110696
|
-
output: finalText,
|
|
110697
|
-
error: `session error: ${turn.sessionError}`,
|
|
110698
|
-
usage
|
|
110699
|
-
};
|
|
110700
|
-
}
|
|
110701
110691
|
return { success: true, output: finalText, usage };
|
|
110702
110692
|
}
|
|
110703
110693
|
async function aggregateTurnUsage(ctx, turnStartMs) {
|
|
@@ -164715,10 +164705,13 @@ function validateAgentApiKey(params) {
|
|
|
164715
164705
|
}
|
|
164716
164706
|
function isApiKeyAuthError(text) {
|
|
164717
164707
|
if (!text) return false;
|
|
164718
|
-
return text.includes(MISSING_KEY_MARKER) || /Invalid API key/i.test(text) || /\bUser not found\b/i.test(text) || /\bInvalid authentication\b/i.test(text) || /authentication_error/i.test(text) || /Invalid bearer token/i.test(text) || /api_error_status\s*=\s*401/i.test(text) || /API Error:\s*401/i.test(text) || /Failed to authenticate\. API Error:/i.test(text) || /Your api key:.*is invalid/i.test(text) || isOAuthCredentialExpiredError(text);
|
|
164708
|
+
return text.includes(MISSING_KEY_MARKER) || /Invalid API key/i.test(text) || /\bUser not found\b/i.test(text) || /\bInvalid authentication\b/i.test(text) || /authentication_error/i.test(text) || /Invalid bearer token/i.test(text) || /api_error_status\s*=\s*401/i.test(text) || /API Error:\s*401/i.test(text) || /Failed to authenticate\. API Error:/i.test(text) || /Your api key:.*is invalid/i.test(text) || isClaudeSubscriptionDisabledError(text) || isOAuthCredentialExpiredError(text);
|
|
164719
164709
|
}
|
|
164720
164710
|
function isOAuthCredentialExpiredError(text) {
|
|
164721
|
-
return /authentication token has expired/i.test(text) || /Token refresh failed/i.test(text);
|
|
164711
|
+
return /authentication token has (expired|been invalidated)/i.test(text) || /OAuth access token has expired/i.test(text) || /Token refresh failed/i.test(text);
|
|
164712
|
+
}
|
|
164713
|
+
function isClaudeSubscriptionDisabledError(text) {
|
|
164714
|
+
return /disabled Claude subscription access/i.test(text);
|
|
164722
164715
|
}
|
|
164723
164716
|
function formatApiKeyErrorSummary(params) {
|
|
164724
164717
|
if (params.raw.includes(MISSING_KEY_MARKER)) {
|
|
@@ -164727,11 +164720,18 @@ function formatApiKeyErrorSummary(params) {
|
|
|
164727
164720
|
}
|
|
164728
164721
|
const githubSecretsUrl = `https://github.com/${params.owner}/${params.name}/settings/secrets/actions`;
|
|
164729
164722
|
const settingsUrl = `${getApiUrl()}/console/${params.owner}/${params.name}`;
|
|
164723
|
+
if (isClaudeSubscriptionDisabledError(params.raw)) {
|
|
164724
|
+
return [
|
|
164725
|
+
`**Your organization has disabled Claude subscription access for Claude Code.** Ask your Claude organization's admin to re-enable it in the Claude Console, or set an \`ANTHROPIC_API_KEY\` for this repo instead, then re-trigger the run.`,
|
|
164726
|
+
"",
|
|
164727
|
+
`[Add repo secret \u2192](${githubSecretsUrl}) \xB7 [Model settings \u2192](${settingsUrl}) \xB7 [Setup docs \u2192](https://docs.pullfrog.com/keys) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`
|
|
164728
|
+
].join("\n");
|
|
164729
|
+
}
|
|
164730
164730
|
if (isOAuthCredentialExpiredError(params.raw)) {
|
|
164731
164731
|
return [
|
|
164732
|
-
`**Your provider OAuth credential has expired.** Re-authenticate the provider connection (e.g. \`pullfrog auth codex\`), then re-trigger the run.`,
|
|
164732
|
+
`**Your provider OAuth credential has expired or been revoked.** Re-authenticate the provider connection (e.g. \`pullfrog auth claude\` / \`pullfrog auth codex\`), then re-trigger the run.`,
|
|
164733
164733
|
"",
|
|
164734
|
-
`[
|
|
164734
|
+
`[Claude subscription \u2192](https://docs.pullfrog.com/claude-auth) \xB7 [ChatGPT subscription \u2192](https://docs.pullfrog.com/codex-auth) \xB7 [Model settings \u2192](${settingsUrl}) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`
|
|
164735
164735
|
].join("\n");
|
|
164736
164736
|
}
|
|
164737
164737
|
return [
|
|
@@ -168517,7 +168517,7 @@ async function runCli4(input) {
|
|
|
168517
168517
|
}
|
|
168518
168518
|
|
|
168519
168519
|
// cli.ts
|
|
168520
|
-
var VERSION10 = "0.1.
|
|
168520
|
+
var VERSION10 = "0.1.40";
|
|
168521
168521
|
var bin = basename2(process.argv[1] || "");
|
|
168522
168522
|
var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
|
|
168523
168523
|
var rawArgs = process.argv.slice(2);
|
package/dist/index.js
CHANGED
|
@@ -100565,7 +100565,7 @@ async function preflightClaudeSubscription(params) {
|
|
|
100565
100565
|
} catch {
|
|
100566
100566
|
return { usable: true };
|
|
100567
100567
|
}
|
|
100568
|
-
if (res.status !== 401 && res.status !== 429) return { usable: true };
|
|
100568
|
+
if (res.status !== 401 && res.status !== 403 && res.status !== 429) return { usable: true };
|
|
100569
100569
|
const body = await res.text().catch(() => "");
|
|
100570
100570
|
return { usable: false, reason: `${res.status}: ${extractApiErrorMessage(body)}` };
|
|
100571
100571
|
}
|
|
@@ -101068,7 +101068,7 @@ function extractExcerpt(text, matchIndex) {
|
|
|
101068
101068
|
}
|
|
101069
101069
|
return excerpt.trim();
|
|
101070
101070
|
}
|
|
101071
|
-
var ROUTER_KEYLIMIT_EXHAUSTED_PATTERN = /requires more credits.*?fewer max_tokens|requested up to \d+ tokens.*?can only afford/is;
|
|
101071
|
+
var ROUTER_KEYLIMIT_EXHAUSTED_PATTERN = /requires more credits.*?fewer max_tokens|requested up to \d+ tokens.*?can only afford|Key limit exceeded \(total limit\)/is;
|
|
101072
101072
|
function isRouterKeylimitExhaustedError(text) {
|
|
101073
101073
|
return ROUTER_KEYLIMIT_EXHAUSTED_PATTERN.test(text);
|
|
101074
101074
|
}
|
|
@@ -101093,7 +101093,7 @@ var import_semver = __toESM(require_semver2(), 1);
|
|
|
101093
101093
|
// package.json
|
|
101094
101094
|
var package_default = {
|
|
101095
101095
|
name: "pullfrog",
|
|
101096
|
-
version: "0.1.
|
|
101096
|
+
version: "0.1.40",
|
|
101097
101097
|
type: "module",
|
|
101098
101098
|
bin: {
|
|
101099
101099
|
pullfrog: "dist/cli.mjs",
|
|
@@ -108579,7 +108579,6 @@ function newTurn() {
|
|
|
108579
108579
|
finalText: "",
|
|
108580
108580
|
tokens: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
108581
108581
|
costUsd: 0,
|
|
108582
|
-
sessionError: null,
|
|
108583
108582
|
lastToolError: null
|
|
108584
108583
|
};
|
|
108585
108584
|
}
|
|
@@ -108610,7 +108609,6 @@ async function dispatchEvent(ctx, event) {
|
|
|
108610
108609
|
if (sessionID !== ctx.orchestratorSessionID) return;
|
|
108611
108610
|
const err = event.properties.error;
|
|
108612
108611
|
const message = err ? extractErrorMessage(err) : "(no error payload)";
|
|
108613
|
-
if (ctx.currentTurn) ctx.currentTurn.sessionError = message;
|
|
108614
108612
|
log.info(`\xBB ${ctx.label} session error: ${message}`);
|
|
108615
108613
|
return;
|
|
108616
108614
|
}
|
|
@@ -108803,14 +108801,6 @@ async function runPromptTurn(ctx, params) {
|
|
|
108803
108801
|
usage
|
|
108804
108802
|
};
|
|
108805
108803
|
}
|
|
108806
|
-
if (turn.sessionError) {
|
|
108807
|
-
return {
|
|
108808
|
-
success: false,
|
|
108809
|
-
output: finalText,
|
|
108810
|
-
error: `session error: ${turn.sessionError}`,
|
|
108811
|
-
usage
|
|
108812
|
-
};
|
|
108813
|
-
}
|
|
108814
108804
|
return { success: true, output: finalText, usage };
|
|
108815
108805
|
}
|
|
108816
108806
|
async function aggregateTurnUsage(ctx, turnStartMs) {
|
|
@@ -162828,10 +162818,13 @@ function validateAgentApiKey(params) {
|
|
|
162828
162818
|
}
|
|
162829
162819
|
function isApiKeyAuthError(text) {
|
|
162830
162820
|
if (!text) return false;
|
|
162831
|
-
return text.includes(MISSING_KEY_MARKER) || /Invalid API key/i.test(text) || /\bUser not found\b/i.test(text) || /\bInvalid authentication\b/i.test(text) || /authentication_error/i.test(text) || /Invalid bearer token/i.test(text) || /api_error_status\s*=\s*401/i.test(text) || /API Error:\s*401/i.test(text) || /Failed to authenticate\. API Error:/i.test(text) || /Your api key:.*is invalid/i.test(text) || isOAuthCredentialExpiredError(text);
|
|
162821
|
+
return text.includes(MISSING_KEY_MARKER) || /Invalid API key/i.test(text) || /\bUser not found\b/i.test(text) || /\bInvalid authentication\b/i.test(text) || /authentication_error/i.test(text) || /Invalid bearer token/i.test(text) || /api_error_status\s*=\s*401/i.test(text) || /API Error:\s*401/i.test(text) || /Failed to authenticate\. API Error:/i.test(text) || /Your api key:.*is invalid/i.test(text) || isClaudeSubscriptionDisabledError(text) || isOAuthCredentialExpiredError(text);
|
|
162832
162822
|
}
|
|
162833
162823
|
function isOAuthCredentialExpiredError(text) {
|
|
162834
|
-
return /authentication token has expired/i.test(text) || /Token refresh failed/i.test(text);
|
|
162824
|
+
return /authentication token has (expired|been invalidated)/i.test(text) || /OAuth access token has expired/i.test(text) || /Token refresh failed/i.test(text);
|
|
162825
|
+
}
|
|
162826
|
+
function isClaudeSubscriptionDisabledError(text) {
|
|
162827
|
+
return /disabled Claude subscription access/i.test(text);
|
|
162835
162828
|
}
|
|
162836
162829
|
function formatApiKeyErrorSummary(params) {
|
|
162837
162830
|
if (params.raw.includes(MISSING_KEY_MARKER)) {
|
|
@@ -162840,11 +162833,18 @@ function formatApiKeyErrorSummary(params) {
|
|
|
162840
162833
|
}
|
|
162841
162834
|
const githubSecretsUrl = `https://github.com/${params.owner}/${params.name}/settings/secrets/actions`;
|
|
162842
162835
|
const settingsUrl = `${getApiUrl()}/console/${params.owner}/${params.name}`;
|
|
162836
|
+
if (isClaudeSubscriptionDisabledError(params.raw)) {
|
|
162837
|
+
return [
|
|
162838
|
+
`**Your organization has disabled Claude subscription access for Claude Code.** Ask your Claude organization's admin to re-enable it in the Claude Console, or set an \`ANTHROPIC_API_KEY\` for this repo instead, then re-trigger the run.`,
|
|
162839
|
+
"",
|
|
162840
|
+
`[Add repo secret \u2192](${githubSecretsUrl}) \xB7 [Model settings \u2192](${settingsUrl}) \xB7 [Setup docs \u2192](https://docs.pullfrog.com/keys) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`
|
|
162841
|
+
].join("\n");
|
|
162842
|
+
}
|
|
162843
162843
|
if (isOAuthCredentialExpiredError(params.raw)) {
|
|
162844
162844
|
return [
|
|
162845
|
-
`**Your provider OAuth credential has expired.** Re-authenticate the provider connection (e.g. \`pullfrog auth codex\`), then re-trigger the run.`,
|
|
162845
|
+
`**Your provider OAuth credential has expired or been revoked.** Re-authenticate the provider connection (e.g. \`pullfrog auth claude\` / \`pullfrog auth codex\`), then re-trigger the run.`,
|
|
162846
162846
|
"",
|
|
162847
|
-
`[
|
|
162847
|
+
`[Claude subscription \u2192](https://docs.pullfrog.com/claude-auth) \xB7 [ChatGPT subscription \u2192](https://docs.pullfrog.com/codex-auth) \xB7 [Model settings \u2192](${settingsUrl}) \xB7 [Ask in Discord \u2192](https://discord.gg/8y96raFg8e)`
|
|
162848
162848
|
].join("\n");
|
|
162849
162849
|
}
|
|
162850
162850
|
return [
|
package/dist/utils/apiKeys.d.ts
CHANGED
|
@@ -37,6 +37,9 @@ export declare function validateAgentApiKey(params: {
|
|
|
37
37
|
* ****XXXX is invalid`. anchored to "Your api key: ... is invalid" so it
|
|
38
38
|
* can't collide with DeepSeek's already-handled `Insufficient balance`
|
|
39
39
|
* billing shape (which routes to formatProviderBillingExhausted).
|
|
40
|
+
* - org-disabled Claude subscription (#1072): `Your organization has
|
|
41
|
+
* disabled Claude subscription access for Claude Code`, an entitlement
|
|
42
|
+
* denial with its own remedy — see isClaudeSubscriptionDisabledError.
|
|
40
43
|
*/
|
|
41
44
|
export declare function isApiKeyAuthError(text: string): boolean;
|
|
42
45
|
/**
|
|
@@ -46,8 +49,17 @@ export declare function isApiKeyAuthError(text: string): boolean;
|
|
|
46
49
|
* distinct copy for these. Patterns are deliberately narrow:
|
|
47
50
|
* "authentication token has expired" (not bare "token has expired") so a
|
|
48
51
|
* GitHub installation-token expiry can't be misread as an LLM key problem.
|
|
52
|
+
* also covers server-side revocation ("authentication token has been
|
|
53
|
+
* invalidated", OpenAI `token_invalidated`, #1041) and the Claude CLI's
|
|
54
|
+
* "OAuth access token has expired" phrasing (#1072) — same remediation.
|
|
49
55
|
*/
|
|
50
56
|
export declare function isOAuthCredentialExpiredError(text: string): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Anthropic entitlement denial for Claude Pro/Max subscription auth (#1072):
|
|
59
|
+
* an org admin turned off Claude Code subscription access. no credential the
|
|
60
|
+
* user controls fixes it, so it gets its own copy instead of the re-auth CTA.
|
|
61
|
+
*/
|
|
62
|
+
export declare function isClaudeSubscriptionDisabledError(text: string): boolean;
|
|
51
63
|
/**
|
|
52
64
|
* Friendly Markdown summary for both the missing-key and invalid-key cases.
|
|
53
65
|
* Used in the catch / result-failure paths in `main.ts` to overwrite the raw
|
|
@@ -16,7 +16,9 @@ export type SubscriptionPreflight = {
|
|
|
16
16
|
* per-model ("You've hit your Opus limit"), so a cheaper stand-in could pass
|
|
17
17
|
* preflight and still leave the run dead on arrival.
|
|
18
18
|
*
|
|
19
|
-
* fail-open by design: only 401 (revoked/expired token)
|
|
19
|
+
* fail-open by design: only 401 (revoked/expired token), 403 (Anthropic
|
|
20
|
+
* `permission_error` — the credential isn't entitled to serve this run, e.g.
|
|
21
|
+
* an org disabled Claude Code subscription access, #1072) and 429
|
|
20
22
|
* (session/weekly/per-model limit) mark the token unusable. network errors,
|
|
21
23
|
* 5xx, and request-shape drift (400) all keep today's subscription-first
|
|
22
24
|
* behavior, so the preflight can never fail a run that would have worked —
|