pullfrog 0.1.14 → 0.1.16
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 +1 -1
- package/dist/agents/claude.d.ts +1 -0
- package/dist/agents/claudePretoolGate.d.ts +69 -0
- package/dist/agents/gateServer.d.ts +6 -0
- package/dist/agents/nativeFsDenies.d.ts +28 -0
- package/dist/agents/opencodePlugin.d.ts +41 -16
- package/dist/agents/opencodeShared.d.ts +1 -1
- package/dist/agents/postRun.d.ts +13 -0
- package/dist/agents/reviewer.d.ts +19 -13
- package/dist/agents/subagentToolGates.d.ts +55 -0
- package/dist/cli.mjs +112698 -108140
- package/dist/external.d.ts +1 -1
- package/dist/index.js +112433 -107893
- package/dist/internal/index.d.ts +3 -1
- package/dist/internal.js +123 -17
- package/dist/mcp/comment.d.ts +3 -1
- package/dist/mcp/reviewComments.d.ts +4 -1
- package/dist/models.d.ts +2 -0
- package/dist/prep/types.d.ts +2 -0
- package/dist/toolState.d.ts +1 -1
- package/dist/utils/apiKeys.d.ts +11 -2
- package/dist/utils/assets.d.ts +8 -0
- package/dist/utils/body.d.ts +18 -0
- package/dist/utils/byokFallback.d.ts +14 -25
- package/dist/utils/codexHome.d.ts +17 -4
- package/dist/utils/codexOAuth.d.ts +60 -0
- package/dist/utils/instructions.d.ts +4 -0
- package/dist/utils/lifecycle.d.ts +19 -3
- package/dist/utils/openCodeModels.d.ts +11 -0
- package/dist/utils/packageManager.d.ts +49 -0
- package/dist/utils/run.d.ts +2 -2
- package/dist/utils/runErrorRenderer.d.ts +4 -2
- package/dist/utils/runLifecycle.d.ts +6 -5
- package/package.json +5 -3
package/dist/internal/index.d.ts
CHANGED
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
* Re-exports shared types, values, and utilities needed by the Next.js app.
|
|
4
4
|
*/
|
|
5
5
|
export type { AuthorPermission, ModelAlias, ModelProvider, Payload, PayloadEvent, ProviderConfig, PushPermission, ShellPermission, ToolPermission, WriteablePayload, } from "../external.ts";
|
|
6
|
-
export { DEFAULT_PROXY_MODEL, getModelEnvVars, getModelManagedCredentials, getModelProvider, getProviderDisplayName, modelAliases, parseModel, providers, pullfrogMcpName, resolveCliModel, resolveDisplayAlias, resolveModelSlug, resolveOpenRouterModel, } from "../external.ts";
|
|
6
|
+
export { DEFAULT_PROXY_MODEL, getAutoSelectHintModel, getModelEnvVars, getModelManagedCredentials, getModelProvider, getProviderDisplayName, modelAliases, parseModel, providers, pullfrogMcpName, resolveCliModel, resolveDisplayAlias, resolveModelSlug, resolveOpenRouterModel, } from "../external.ts";
|
|
7
7
|
export type { Mode } from "../modes.ts";
|
|
8
8
|
export { modes } from "../modes.ts";
|
|
9
9
|
export type { BuildPullfrogFooterParams, WorkflowRunFooterInfo, } from "../utils/buildPullfrogFooter.ts";
|
|
10
10
|
export { buildPullfrogFooter, PULLFROG_DIVIDER, stripExistingFooter, } from "../utils/buildPullfrogFooter.ts";
|
|
11
|
+
export type { CodexAuthBody } from "../utils/codexOAuth.ts";
|
|
12
|
+
export { decodeJwtExpMs, OAuthInvalidGrantError, parseCodexAuthBody, refreshCodexAuthBody, stringifyCodexAuthBody, } from "../utils/codexOAuth.ts";
|
|
11
13
|
export type { ResourceUsage, UsageSummary } from "../utils/github.ts";
|
|
12
14
|
export { isLeapingIntoActionCommentBody, LEAPING_INTO_ACTION_PREFIX, } from "../utils/leapingComment.ts";
|
|
13
15
|
export { MAX_LEARNINGS_LENGTH, truncateAtLineBoundary } from "../utils/learningsTruncate.ts";
|
package/dist/internal.js
CHANGED
|
@@ -11,8 +11,8 @@ var providers = {
|
|
|
11
11
|
models: {
|
|
12
12
|
"claude-opus": {
|
|
13
13
|
displayName: "Claude Opus",
|
|
14
|
-
resolve: "anthropic/claude-opus-4-
|
|
15
|
-
openRouterResolve: "openrouter/anthropic/claude-opus-4.
|
|
14
|
+
resolve: "anthropic/claude-opus-4-8",
|
|
15
|
+
openRouterResolve: "openrouter/anthropic/claude-opus-4.8",
|
|
16
16
|
preferred: true,
|
|
17
17
|
subagentModel: "claude-sonnet"
|
|
18
18
|
},
|
|
@@ -101,7 +101,7 @@ var providers = {
|
|
|
101
101
|
"gemini-flash": {
|
|
102
102
|
displayName: "Gemini Flash",
|
|
103
103
|
resolve: "google/gemini-3.5-flash",
|
|
104
|
-
openRouterResolve: "openrouter/google/gemini-3-flash
|
|
104
|
+
openRouterResolve: "openrouter/google/gemini-3.5-flash"
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
}),
|
|
@@ -190,8 +190,8 @@ var providers = {
|
|
|
190
190
|
},
|
|
191
191
|
"claude-opus": {
|
|
192
192
|
displayName: "Claude Opus",
|
|
193
|
-
resolve: "opencode/claude-opus-4-
|
|
194
|
-
openRouterResolve: "openrouter/anthropic/claude-opus-4.
|
|
193
|
+
resolve: "opencode/claude-opus-4-8",
|
|
194
|
+
openRouterResolve: "openrouter/anthropic/claude-opus-4.8",
|
|
195
195
|
subagentModel: "claude-sonnet"
|
|
196
196
|
},
|
|
197
197
|
"claude-sonnet": {
|
|
@@ -249,8 +249,8 @@ var providers = {
|
|
|
249
249
|
},
|
|
250
250
|
"gemini-flash": {
|
|
251
251
|
displayName: "Gemini Flash",
|
|
252
|
-
resolve: "opencode/gemini-3-flash",
|
|
253
|
-
openRouterResolve: "openrouter/google/gemini-3-flash
|
|
252
|
+
resolve: "opencode/gemini-3.5-flash",
|
|
253
|
+
openRouterResolve: "openrouter/google/gemini-3.5-flash"
|
|
254
254
|
},
|
|
255
255
|
"kimi-k2": {
|
|
256
256
|
displayName: "Kimi K2",
|
|
@@ -323,8 +323,8 @@ var providers = {
|
|
|
323
323
|
models: {
|
|
324
324
|
"claude-opus": {
|
|
325
325
|
displayName: "Claude Opus",
|
|
326
|
-
resolve: "openrouter/anthropic/claude-opus-4.
|
|
327
|
-
openRouterResolve: "openrouter/anthropic/claude-opus-4.
|
|
326
|
+
resolve: "openrouter/anthropic/claude-opus-4.8",
|
|
327
|
+
openRouterResolve: "openrouter/anthropic/claude-opus-4.8",
|
|
328
328
|
preferred: true,
|
|
329
329
|
subagentModel: "claude-sonnet"
|
|
330
330
|
},
|
|
@@ -388,8 +388,8 @@ var providers = {
|
|
|
388
388
|
},
|
|
389
389
|
"gemini-flash": {
|
|
390
390
|
displayName: "Gemini Flash",
|
|
391
|
-
resolve: "openrouter/google/gemini-3-flash
|
|
392
|
-
openRouterResolve: "openrouter/google/gemini-3-flash
|
|
391
|
+
resolve: "openrouter/google/gemini-3.5-flash",
|
|
392
|
+
openRouterResolve: "openrouter/google/gemini-3.5-flash"
|
|
393
393
|
},
|
|
394
394
|
grok: {
|
|
395
395
|
displayName: "Grok",
|
|
@@ -481,6 +481,16 @@ if (!defaultProxyAlias?.openRouterResolve) {
|
|
|
481
481
|
throw new Error("DEFAULT_PROXY_MODEL: moonshotai/kimi-k2 missing openRouterResolve");
|
|
482
482
|
}
|
|
483
483
|
var DEFAULT_PROXY_MODEL = defaultProxyAlias.openRouterResolve;
|
|
484
|
+
function getAutoSelectHintModel() {
|
|
485
|
+
const alias = defaultProxyAlias;
|
|
486
|
+
if (!alias) return "Kimi 2.6";
|
|
487
|
+
const modelId = alias.resolve.split("/")[1] ?? "kimi-k2.6";
|
|
488
|
+
const version = modelId.replace(/^kimi-k2\./, "");
|
|
489
|
+
if (version && version !== modelId) {
|
|
490
|
+
return `Kimi 2.${version}`;
|
|
491
|
+
}
|
|
492
|
+
return alias.displayName;
|
|
493
|
+
}
|
|
484
494
|
function resolveModelSlug(slug) {
|
|
485
495
|
return modelAliases.find((a) => a.slug === slug)?.resolve;
|
|
486
496
|
}
|
|
@@ -704,6 +714,8 @@ function computeModes(agentId) {
|
|
|
704
714
|
|
|
705
715
|
Otherwise delegate the \`${REVIEWER_AGENT_NAME}\` subagent to review your diff with fresh eyes against YOUR TASK. The subagent's baked-in system prompt enforces a non-mutative + non-recursive contract: read-only file/search/web tools and read-only MCP queries only; no writes, shell side effects, state-changing MCP calls, or nested subagent dispatch. Enforcement is prose-only \u2014 restate the constraint in your dispatch instructions and do not relax it.
|
|
706
716
|
|
|
717
|
+
Before dispatching, ensure \`origin/<base>\` is locally available \u2014 the runner is often a shallow single-branch \`actions/checkout\` (depth=1, head-only refspec), and the reviewer's \`git diff --merge-base origin/<base>\` will fail with \`ambiguous argument\` or \`no merge base\` otherwise. Run \`git fetch --no-tags --deepen=1000 origin <base>:refs/remotes/origin/<base>\` once (the explicit destination refspec is required \u2014 a shallow single-branch checkout configures a head-only refspec, so a bare \`origin <base>\` only updates \`FETCH_HEAD\` and never creates the \`origin/<base>\` tracking ref); it's a no-op if the ref already has enough history. (The reviewer is read-only by contract, so it cannot do this itself \u2014 fetching is the orchestrator's job.)
|
|
718
|
+
|
|
707
719
|
Compose your \`${REVIEWER_AGENT_NAME}\` dispatch prompt using this template verbatim, substituting the \`<...>\` placeholders. The preamble aligns the orchestrator side of the dispatch contract with the reviewer's baked-in system prompt \u2014 both ends say the same thing about where the work lives and what to do on an empty diff.
|
|
708
720
|
|
|
709
721
|
\`\`\`
|
|
@@ -711,9 +723,11 @@ function computeModes(agentId) {
|
|
|
711
723
|
This is a PRE-COMMIT Build-mode self-review. The work to review lives in the working tree (uncommitted), NOT in committed history.
|
|
712
724
|
|
|
713
725
|
Branch: <branch> (off <base>)
|
|
714
|
-
Canonical diff command: git diff origin/<base>
|
|
726
|
+
Canonical diff command: git diff --merge-base origin/<base>
|
|
727
|
+
|
|
728
|
+
Use \`--merge-base\` (single MCP \`git\` call, no shell substitution required). NOT bare \`git diff origin/<base>\` or two-dot \`git diff origin/<base>..HEAD\` \u2014 the symmetric forms include the inverse of every commit landed on \`<base>\` since this branch forked, which is noise (and the git tool will reject those forms when the divergence is detected). \`origin/<base>...HEAD\` (three-dot) and \`--cached\` both miss the uncommitted edits self-review runs on, so they're also wrong here.
|
|
715
729
|
|
|
716
|
-
If
|
|
730
|
+
If the merge-base diff returns empty, treat it as "no changes \u2014 nothing to review" and stop per your system prompt. Do not search for the work elsewhere.
|
|
717
731
|
|
|
718
732
|
## Your task
|
|
719
733
|
<YOUR TASK content>
|
|
@@ -722,7 +736,7 @@ function computeModes(agentId) {
|
|
|
722
736
|
<tight summary \u2014 what broke, root cause, the fix \u2014 or "no build-phase failures">
|
|
723
737
|
\`\`\`
|
|
724
738
|
|
|
725
|
-
Follow the template with the diff content (\`git diff origin/<base-branch
|
|
739
|
+
Follow the template with the diff content (\`git diff --merge-base origin/<base-branch>\` \u2014 single MCP \`git\` call, captures committed + staged + unstaged, excludes base-branch progress) and your task brief. Instruct the subagent to flag bugs, logic errors, missing edge cases, gaps between request and diff, and unintended changes.
|
|
726
740
|
|
|
727
741
|
Delegation + research discipline (distilled from \`/anneal\` canonical \u2014 these are codified learnings from many review rounds, not theoretical best practices):
|
|
728
742
|
- Do NOT summarize what you implemented \u2014 that biases the subagent toward validating the shape of your solution rather than questioning it.
|
|
@@ -864,7 +878,7 @@ For simple, well-defined tasks, skip the plan phase and go straight to build.`
|
|
|
864
878
|
You can also include your own \`read\` / \`grep\` / \`webfetch\` calls in the SAME turn as the parallel \`${REVIEWER_AGENT_NAME}\` dispatches \u2014 concurrent context-pulling on the orchestrator side runs in parallel with the lens fan-out and costs zero extra wall time.
|
|
865
879
|
|
|
866
880
|
if a subagent errors out, times out, or returns nothing usable, retry once with the same lens; if it still fails, proceed with partial coverage and note the missing lens in the review body \u2014 do not skip the fan-out entirely on a single subagent failure. each subagent gets:
|
|
867
|
-
- the
|
|
881
|
+
- **the absolute \`diffPath\` (and \`incrementalDiffPath\` if available) from step 2's \`${t("checkout_pr")}\` return, named verbatim in the dispatch prompt** (e.g. \`diffPath: /tmp/pullfrog-XXXX/pr-NNN-SHA.diff\`). the reviewer's baked-in system prompt selects its FIRST action on this token \u2014 paraphrasing ("review the diff", "look at this PR") sends it down the \`git diff origin/<base>\` fallback, which fails on shallow GHA checkouts. the subagent \`read\`s those files for scope; it must NOT re-derive the diff via \`git diff\` (bare \`git diff origin/<base>\` is symmetric and pulls in the inverse of any commits that landed on \`<base>\` since the branch forked \u2014 pure noise, and the git tool rejects it). reading and codebase exploration are still its job.
|
|
868
882
|
- **only one lens** \u2014 never a multi-section "review for X, Y, and Z" prompt
|
|
869
883
|
- **a Task \`description\` set to the lens name** (e.g. \`"security"\`, \`"correctness"\`, \`"billing-subsystem"\`) \u2014 the harness reads this field to label the subagent's log lines so parallel runs can be told apart in CI output. without it, every subagent shows up as \`subagent#N\`.
|
|
870
884
|
- if the lens touches external contracts, instruct the subagent to verify load-bearing claims via web search rather than trust training data, and to quote source URLs in its reasoning. action runs are non-interactive \u2014 there's no human in the loop to catch "I'm pretty sure Stripe does X."
|
|
@@ -974,7 +988,7 @@ ${PR_SUMMARY_FORMAT}`
|
|
|
974
988
|
You can also include your own \`read\` / \`grep\` / \`webfetch\` calls in the SAME turn as the parallel \`${REVIEWER_AGENT_NAME}\` dispatches.
|
|
975
989
|
|
|
976
990
|
if a subagent errors out, times out, or returns nothing usable, retry once with the same lens; if it still fails, proceed with partial coverage and note the missing lens in the review body. each subagent gets:
|
|
977
|
-
- the diff
|
|
991
|
+
- **the absolute diff path(s) from step 2's \`${t("checkout_pr")}\` return, named verbatim in the dispatch prompt.** when \`incrementalDiffPath\` is present, name BOTH (\`incrementalDiffPath: /tmp/.../pr-NNN-SHA-incremental.diff\` then \`diffPath: /tmp/.../pr-NNN-SHA.diff\`) \u2014 the reviewer's baked-in prompt reads incremental first and uses full for context; when only \`diffPath\` exists, name it alone. the subagent \`read\`s those files; it must NOT re-derive via \`git diff\` (bare \`git diff origin/<base>\` is symmetric and pulls in the inverse of base-branch progress \u2014 pure noise, and the git tool rejects it), and paraphrasing ("review the new commits") sends it down that fallback, which also fails on shallow GHA checkouts. do NOT tell them to skip pre-existing issues \u2014 that suppresses regressions the new commits amplified; the "issues must be NEW" filter lives at aggregation time (step 8), not in the subagent prompt.
|
|
978
992
|
- **only one lens** \u2014 never a multi-section "review for X, Y, and Z" prompt
|
|
979
993
|
- **a Task \`description\` set to the lens name** \u2014 the harness reads this field to label log lines so parallel runs can be told apart.
|
|
980
994
|
- if the lens touches external contracts, instruct the subagent to verify load-bearing claims via web search and quote source URLs.
|
|
@@ -1083,7 +1097,7 @@ ${PR_SUMMARY_FORMAT}`
|
|
|
1083
1097
|
|
|
1084
1098
|
1. **task list**: create your task list for this run as your first action.
|
|
1085
1099
|
|
|
1086
|
-
2. Analyze the task. For simple operations (labeling, commenting, answering questions, running a single command), handle directly.
|
|
1100
|
+
2. Analyze the task. For simple operations (labeling, commenting, answering questions, running a single command), handle directly \u2014 but your answer only reaches the user through \`${t("report_progress")}\` (step 4); raw assistant text is discarded.
|
|
1087
1101
|
|
|
1088
1102
|
3. For substantial work \u2014 code changes across multiple files, multi-step investigations:
|
|
1089
1103
|
- plan your approach before starting
|
|
@@ -1157,6 +1171,92 @@ function stripExistingFooter(body) {
|
|
|
1157
1171
|
return body.substring(0, dividerIndex).trimEnd();
|
|
1158
1172
|
}
|
|
1159
1173
|
|
|
1174
|
+
// utils/codexOAuth.ts
|
|
1175
|
+
var CODEX_OAUTH_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
1176
|
+
var CODEX_OAUTH_TOKEN_URL = "https://auth.openai.com/oauth/token";
|
|
1177
|
+
var OAuthInvalidGrantError = class extends Error {
|
|
1178
|
+
status;
|
|
1179
|
+
constructor(status, body) {
|
|
1180
|
+
super(`Codex token refresh failed: ${status} ${body}`);
|
|
1181
|
+
this.name = "OAuthInvalidGrantError";
|
|
1182
|
+
this.status = status;
|
|
1183
|
+
}
|
|
1184
|
+
};
|
|
1185
|
+
async function refreshCodexAuthBody(body) {
|
|
1186
|
+
const response = await fetch(CODEX_OAUTH_TOKEN_URL, {
|
|
1187
|
+
method: "POST",
|
|
1188
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1189
|
+
body: new URLSearchParams({
|
|
1190
|
+
grant_type: "refresh_token",
|
|
1191
|
+
refresh_token: body.tokens.refresh_token,
|
|
1192
|
+
client_id: CODEX_OAUTH_CLIENT_ID
|
|
1193
|
+
}).toString(),
|
|
1194
|
+
signal: AbortSignal.timeout(1e4)
|
|
1195
|
+
});
|
|
1196
|
+
if (!response.ok) {
|
|
1197
|
+
const text = await response.text().catch(() => "");
|
|
1198
|
+
if (response.status >= 400 && response.status < 500) {
|
|
1199
|
+
throw new OAuthInvalidGrantError(response.status, text);
|
|
1200
|
+
}
|
|
1201
|
+
throw new Error(`Codex token refresh failed: ${response.status} ${text}`);
|
|
1202
|
+
}
|
|
1203
|
+
const tokens = await response.json();
|
|
1204
|
+
const idToken = tokens.id_token ?? body.tokens.id_token;
|
|
1205
|
+
const accountId = body.tokens.account_id;
|
|
1206
|
+
return {
|
|
1207
|
+
auth_mode: "chatgpt",
|
|
1208
|
+
tokens: {
|
|
1209
|
+
access_token: tokens.access_token,
|
|
1210
|
+
refresh_token: tokens.refresh_token,
|
|
1211
|
+
...idToken ? { id_token: idToken } : {},
|
|
1212
|
+
...accountId ? { account_id: accountId } : {}
|
|
1213
|
+
},
|
|
1214
|
+
last_refresh: (/* @__PURE__ */ new Date()).toISOString()
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
function decodeJwtExpMs(token) {
|
|
1218
|
+
const parts = token.split(".");
|
|
1219
|
+
if (parts.length !== 3) return null;
|
|
1220
|
+
let payload;
|
|
1221
|
+
try {
|
|
1222
|
+
payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
|
|
1223
|
+
} catch {
|
|
1224
|
+
return null;
|
|
1225
|
+
}
|
|
1226
|
+
if (typeof payload.exp !== "number" || !Number.isFinite(payload.exp)) return null;
|
|
1227
|
+
return payload.exp * 1e3;
|
|
1228
|
+
}
|
|
1229
|
+
function parseCodexAuthBody(raw) {
|
|
1230
|
+
let parsed;
|
|
1231
|
+
try {
|
|
1232
|
+
parsed = JSON.parse(raw);
|
|
1233
|
+
} catch {
|
|
1234
|
+
return null;
|
|
1235
|
+
}
|
|
1236
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
1237
|
+
const v = parsed;
|
|
1238
|
+
if (v.auth_mode !== "chatgpt") return null;
|
|
1239
|
+
const tokens = v.tokens;
|
|
1240
|
+
if (!tokens || typeof tokens !== "object") return null;
|
|
1241
|
+
const t = tokens;
|
|
1242
|
+
if (typeof t.access_token !== "string" || t.access_token.length === 0) return null;
|
|
1243
|
+
if (typeof t.refresh_token !== "string" || t.refresh_token.length === 0) return null;
|
|
1244
|
+
return {
|
|
1245
|
+
auth_mode: "chatgpt",
|
|
1246
|
+
tokens: {
|
|
1247
|
+
access_token: t.access_token,
|
|
1248
|
+
refresh_token: t.refresh_token,
|
|
1249
|
+
...typeof t.id_token === "string" ? { id_token: t.id_token } : {},
|
|
1250
|
+
...typeof t.account_id === "string" ? { account_id: t.account_id } : {}
|
|
1251
|
+
},
|
|
1252
|
+
...typeof v.last_refresh === "string" ? { last_refresh: v.last_refresh } : {}
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
function stringifyCodexAuthBody(body) {
|
|
1256
|
+
return `${JSON.stringify(body, null, 2)}
|
|
1257
|
+
`;
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1160
1260
|
// utils/leapingComment.ts
|
|
1161
1261
|
var LEAPING_INTO_ACTION_PREFIX = "Leaping into action";
|
|
1162
1262
|
function isLeapingIntoActionCommentBody(body) {
|
|
@@ -1292,11 +1392,14 @@ export {
|
|
|
1292
1392
|
DEFAULT_PROXY_MODEL,
|
|
1293
1393
|
LEAPING_INTO_ACTION_PREFIX,
|
|
1294
1394
|
MAX_LEARNINGS_LENGTH,
|
|
1395
|
+
OAuthInvalidGrantError,
|
|
1295
1396
|
PULLFROG_DIVIDER,
|
|
1296
1397
|
TIMEOUT_DISABLED,
|
|
1297
1398
|
buildPullfrogFooter,
|
|
1298
1399
|
createLeapingProgressComment,
|
|
1400
|
+
decodeJwtExpMs,
|
|
1299
1401
|
deleteProgressCommentApi,
|
|
1402
|
+
getAutoSelectHintModel,
|
|
1300
1403
|
getModelEnvVars,
|
|
1301
1404
|
getModelManagedCredentials,
|
|
1302
1405
|
getModelProvider,
|
|
@@ -1306,14 +1409,17 @@ export {
|
|
|
1306
1409
|
isValidTimeString,
|
|
1307
1410
|
modelAliases,
|
|
1308
1411
|
modes,
|
|
1412
|
+
parseCodexAuthBody,
|
|
1309
1413
|
parseModel,
|
|
1310
1414
|
parseTimeString,
|
|
1311
1415
|
providers,
|
|
1312
1416
|
pullfrogMcpName,
|
|
1417
|
+
refreshCodexAuthBody,
|
|
1313
1418
|
resolveCliModel,
|
|
1314
1419
|
resolveDisplayAlias,
|
|
1315
1420
|
resolveModelSlug,
|
|
1316
1421
|
resolveOpenRouterModel,
|
|
1422
|
+
stringifyCodexAuthBody,
|
|
1317
1423
|
stripExistingFooter,
|
|
1318
1424
|
truncateAtLineBoundary,
|
|
1319
1425
|
updateProgressComment
|
package/dist/mcp/comment.d.ts
CHANGED
|
@@ -38,7 +38,8 @@ export declare const ReportProgress: import("arktype/internal/variants/object.ts
|
|
|
38
38
|
* - object: active comment — will update it in place via the right REST endpoint for its type
|
|
39
39
|
* - null: deliberately deleted (e.g. after submitting a PR review) — skips silently
|
|
40
40
|
*
|
|
41
|
-
* The body is
|
|
41
|
+
* The body is tracked in lastProgressBody for the job summary regardless of comment state,
|
|
42
|
+
* EXCEPT for `liveProgress` (todo-tracker) writes — see the param note below.
|
|
42
43
|
*
|
|
43
44
|
* The "existing plan comment" path always targets a top-level issue comment (plan comments are
|
|
44
45
|
* created by create_issue_comment with type:"Plan", never as review-thread replies).
|
|
@@ -46,6 +47,7 @@ export declare const ReportProgress: import("arktype/internal/variants/object.ts
|
|
|
46
47
|
export declare function reportProgress(ctx: ToolContext, params: {
|
|
47
48
|
body: string;
|
|
48
49
|
target_plan_comment?: boolean;
|
|
50
|
+
liveProgress?: boolean;
|
|
49
51
|
}): Promise<{
|
|
50
52
|
commentId?: number;
|
|
51
53
|
url?: string;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { Octokit } from "@octokit/rest";
|
|
2
2
|
import type { ToolContext } from "./server.ts";
|
|
3
|
-
export declare const REVIEW_THREADS_QUERY = "\nquery ($owner: String!, $name: String!, $prNumber: Int!) {\n repository(owner: $owner, name: $name) {\n pullRequest(number: $prNumber) {\n reviewThreads(first: 100) {\n nodes {\n id\n path\n line\n startLine\n diffSide\n isResolved\n isOutdated\n comments(first: 50) {\n nodes {\n fullDatabaseId\n body\n createdAt\n diffHunk\n line\n startLine\n originalLine\n originalStartLine\n author { login }\n pullRequestReview {\n databaseId\n author { login }\n }\n reactionGroups {\n content\n reactors(first: 10) {\n nodes {\n ... on Actor { login }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n}\n";
|
|
3
|
+
export declare const REVIEW_THREADS_QUERY = "\nquery ($owner: String!, $name: String!, $prNumber: Int!) {\n repository(owner: $owner, name: $name) {\n pullRequest(number: $prNumber) {\n reviewThreads(first: 100) {\n nodes {\n id\n path\n line\n startLine\n diffSide\n isResolved\n isOutdated\n comments(first: 50) {\n nodes {\n fullDatabaseId\n body\n bodyHTML\n createdAt\n diffHunk\n line\n startLine\n originalLine\n originalStartLine\n author { login }\n pullRequestReview {\n databaseId\n author { login }\n }\n reactionGroups {\n content\n reactors(first: 10) {\n nodes {\n ... on Actor { login }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n}\n";
|
|
4
4
|
export type ReviewThreadComment = {
|
|
5
5
|
fullDatabaseId: string | null;
|
|
6
6
|
body: string;
|
|
7
|
+
bodyHTML: string;
|
|
7
8
|
createdAt: string;
|
|
8
9
|
diffHunk: string;
|
|
9
10
|
line: number | null;
|
|
@@ -96,6 +97,8 @@ interface GetReviewDataInput {
|
|
|
96
97
|
pullNumber: number;
|
|
97
98
|
reviewId: number;
|
|
98
99
|
approvedBy?: string | undefined;
|
|
100
|
+
tmpdir: string;
|
|
101
|
+
githubToken: string;
|
|
99
102
|
}
|
|
100
103
|
export interface FormatReviewDataInput {
|
|
101
104
|
review: ReviewResponse;
|
package/dist/models.d.ts
CHANGED
|
@@ -104,6 +104,8 @@ export declare function getModelEnvVars(slug: string): string[];
|
|
|
104
104
|
export declare function getModelManagedCredentials(slug: string): string[];
|
|
105
105
|
export declare const modelAliases: ModelAlias[];
|
|
106
106
|
export declare const DEFAULT_PROXY_MODEL: string;
|
|
107
|
+
/** short label for the model auto-select picks today (console hint copy). */
|
|
108
|
+
export declare function getAutoSelectHintModel(): string;
|
|
107
109
|
/** resolve a model slug to its concrete models.dev specifier (e.g. "anthropic/claude-opus-4-6") */
|
|
108
110
|
export declare function resolveModelSlug(slug: string): string | undefined;
|
|
109
111
|
/**
|
package/dist/prep/types.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ export type PrepResult = NodePrepResult | PythonPrepResult | UnknownLanguagePrep
|
|
|
20
20
|
export type PrepOptions = {
|
|
21
21
|
/** when true, lifecycle scripts (postinstall, etc.) are suppressed */
|
|
22
22
|
ignoreScripts: boolean;
|
|
23
|
+
/** directory the corepack shim is installed into (see `packageManagerBinDir`) */
|
|
24
|
+
binDir: string;
|
|
23
25
|
};
|
|
24
26
|
export interface PrepDefinition {
|
|
25
27
|
name: string;
|
package/dist/toolState.d.ts
CHANGED
|
@@ -102,7 +102,7 @@ export interface ToolState {
|
|
|
102
102
|
learningsFilePath?: string;
|
|
103
103
|
learningsSeed?: string;
|
|
104
104
|
learningsPersistAttempted?: boolean;
|
|
105
|
-
output?: string;
|
|
105
|
+
output?: string | undefined;
|
|
106
106
|
usageEntries: AgentUsage[];
|
|
107
107
|
model?: string | undefined;
|
|
108
108
|
modelFallback?: {
|
package/dist/utils/apiKeys.d.ts
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Validate that the resolved model can actually be served by the chosen
|
|
3
|
+
* agent. For routing slugs (Bedrock / Vertex) the auth shape is multi-var
|
|
4
|
+
* (auth + region/location + model-id) and `opencode models` doesn't catch
|
|
5
|
+
* gaps in the latter two — keep dedicated setup validators. For the
|
|
6
|
+
* opencode path, the authoritative answer comes from OpenCode's own model
|
|
7
|
+
* introspection (`authorized` set captured in `openCodeModels.ts`). For
|
|
8
|
+
* the claude path, fall back to the static check (`ANTHROPIC_API_KEY` /
|
|
9
|
+
* `CLAUDE_CODE_OAUTH_TOKEN`).
|
|
10
|
+
*/
|
|
3
11
|
export declare function validateAgentApiKey(params: {
|
|
4
12
|
agent: {
|
|
5
13
|
name: string;
|
|
6
14
|
};
|
|
7
15
|
model: string | undefined;
|
|
16
|
+
authorized: Set<string>;
|
|
8
17
|
owner: string;
|
|
9
18
|
name: string;
|
|
10
19
|
}): void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* downloads any github-hosted image/video assets referenced in `markdown` to
|
|
3
|
+
* `<tmpdir>/assets` and rewrites the urls to the local file paths, so the agent can
|
|
4
|
+
* read screenshots directly instead of relying on remote (often short-lived, signed)
|
|
5
|
+
* urls. unique urls are downloaded once and every occurrence is rewritten. assets that
|
|
6
|
+
* fail to download are left untouched.
|
|
7
|
+
*/
|
|
8
|
+
export declare function downloadAssetsInMarkdown(markdown: string, tmpdir: string, githubToken: string): Promise<string>;
|
package/dist/utils/body.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ interface ResolveBodyContext {
|
|
|
5
5
|
event: PayloadEvent;
|
|
6
6
|
octokit: OctokitWithPlugins;
|
|
7
7
|
repo: RunContextData["repo"];
|
|
8
|
+
tmpdir: string;
|
|
9
|
+
githubToken: string;
|
|
8
10
|
}
|
|
9
11
|
/**
|
|
10
12
|
* resolves the body of an event by fetching body_html and converting to markdown.
|
|
@@ -13,4 +15,20 @@ interface ResolveBodyContext {
|
|
|
13
15
|
* broken user-attachments URLs.
|
|
14
16
|
*/
|
|
15
17
|
export declare function resolveBody(ctx: ResolveBodyContext): Promise<string | null>;
|
|
18
|
+
interface ResolveBodyAssetsContext {
|
|
19
|
+
body: string | null | undefined;
|
|
20
|
+
bodyHtml: string | null | undefined;
|
|
21
|
+
tmpdir: string;
|
|
22
|
+
githubToken: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* downloads github-hosted image assets in a body to disk and rewrites the urls to local
|
|
26
|
+
* paths so the agent can read them. when the body has images and a rendered `bodyHtml`
|
|
27
|
+
* is supplied, the html is turndowned first: github only exposes attachments as signed,
|
|
28
|
+
* self-authenticating `*.githubusercontent.com` urls through body_html — the raw
|
|
29
|
+
* `github.com/user-attachments/...` urls in unrendered markdown 404 for the installation
|
|
30
|
+
* token. callers that fetch a body should request it with the `application/vnd.github.full+json`
|
|
31
|
+
* media type and pass `body_html` here.
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveBodyAssets(ctx: ResolveBodyAssetsContext): Promise<string | null>;
|
|
16
34
|
export {};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Slug we fall back to when a BYOK-required model is configured but the
|
|
3
|
-
* runner has no provider key in env. Picked because it's free
|
|
4
|
-
* (`isFree: true`, `envVars: []` — see `action/models.ts`), stable, and
|
|
3
|
+
* runner has no provider key in env. Picked because it's free, stable, and
|
|
5
4
|
* currently served by OpenCode Zen without a key.
|
|
6
5
|
*
|
|
7
6
|
* The slug is intentionally hard-coded and not a config knob — the
|
|
@@ -18,32 +17,22 @@ export type FallbackDecision = {
|
|
|
18
17
|
to: string;
|
|
19
18
|
};
|
|
20
19
|
/**
|
|
21
|
-
* If the resolved model
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
20
|
+
* If the resolved model is NOT in OpenCode's `authorized` set (the
|
|
21
|
+
* authoritative "what can OpenCode route right now" snapshot captured
|
|
22
|
+
* after dbSecrets + Codex auth.json are in place), swap to a free
|
|
23
|
+
* OpenCode slug so the run can still produce value. Caller is responsible
|
|
24
|
+
* for surfacing the swap (log line + run summary).
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* no BYOK in play — never fall back.
|
|
34
|
-
* - No resolved model: keeps the existing auto-select-with-throw
|
|
35
|
-
* behavior in `validateAgentApiKey` for the "neither model nor
|
|
36
|
-
* key" case (genuine misconfig the user should see).
|
|
37
|
-
* - Resolved model is itself the free fallback: avoid suggesting we
|
|
38
|
-
* fell back to the model we're already running.
|
|
39
|
-
* - Resolved model is a Bedrock raw ID (no `/`): Bedrock has its own
|
|
40
|
-
* auth shape (`AWS_BEARER_TOKEN_BEDROCK` + region + model ID), and
|
|
41
|
-
* `validateBedrockSetup` already surfaces a tailored error. Skipping
|
|
42
|
-
* here also avoids `parseModel`'s slash requirement crashing inside
|
|
43
|
-
* `hasProviderKey`.
|
|
44
|
-
* - Resolved model has its provider key present: no fallback needed.
|
|
26
|
+
* Skip cases (return `fallback: false` without consulting `authorized`):
|
|
27
|
+
* - Router / proxy runs (`proxyModel` set): Pullfrog mints the key.
|
|
28
|
+
* - No resolved model: auto-select handles it downstream.
|
|
29
|
+
* - Resolved model is the free fallback already.
|
|
30
|
+
* - Resolved model is a raw Bedrock / Vertex ID (no `/`): the routing
|
|
31
|
+
* validators (`validateBedrockSetup` / `validateVertexSetup`) cover
|
|
32
|
+
* auth + region/location/model-id; `opencode models` does not.
|
|
45
33
|
*/
|
|
46
34
|
export declare function selectFallbackModelIfNeeded(input: {
|
|
47
35
|
resolvedModel: string | undefined;
|
|
48
36
|
proxyModel: string | undefined;
|
|
37
|
+
authorized: Set<string>;
|
|
49
38
|
}): FallbackDecision;
|
|
@@ -1,15 +1,28 @@
|
|
|
1
|
+
/** sandbox-hidden home for pullfrog-managed on-disk secrets in CI. bash via
|
|
2
|
+
* MCP shell tmpfs-overlays this path; opencode's internal auth module
|
|
3
|
+
* bypasses external_directory and reaches the real file. mirrors the
|
|
4
|
+
* pattern in action/agents/claude.ts installManagedSettings.
|
|
5
|
+
*
|
|
6
|
+
* not used for codex auth in local dev — the sandbox is no-op there, so
|
|
7
|
+
* the path doesn't matter. local dev keeps the existing $HOME path. */
|
|
8
|
+
export declare const PULLFROG_DATA_DIR = "/var/lib/pullfrog";
|
|
1
9
|
export interface InstalledCodexAuth {
|
|
2
10
|
/** absolute path of the auth.json we wrote — caller passes this to the
|
|
3
11
|
* post-hook via core.saveState for refresh-detection later. */
|
|
4
12
|
authPath: string;
|
|
5
13
|
/** value to set as XDG_DATA_HOME for the OpenCode subprocess. */
|
|
6
14
|
xdgDataHome: string;
|
|
7
|
-
/** refresh_token from the env at materialization time. post-hook
|
|
8
|
-
* against the on-disk file after the run to detect whether
|
|
9
|
-
* refreshed during the session
|
|
15
|
+
/** refresh_token from the env at materialization time. post-hook
|
|
16
|
+
* compares against the on-disk file after the run to detect whether
|
|
17
|
+
* OpenCode refreshed during the session (only happens on long runs
|
|
18
|
+
* that span >50min — see wiki/codex-auth.md "Concurrency"). */
|
|
10
19
|
originalRefresh: string;
|
|
11
20
|
}
|
|
12
21
|
/** materialize CODEX_AUTH_JSON from env into a disk path OpenCode reads from.
|
|
13
22
|
* returns null when the env var is absent, malformed, or wrong auth mode —
|
|
14
|
-
* caller treats null as "no codex auth, fall through to API key flow".
|
|
23
|
+
* caller treats null as "no codex auth, fall through to API key flow".
|
|
24
|
+
*
|
|
25
|
+
* The env value is server-side guaranteed fresh by `maybeRotateCodexSecret`
|
|
26
|
+
* in the run-context endpoint. We only parse + write it here; no refresh,
|
|
27
|
+
* no DB interaction. */
|
|
15
28
|
export declare function installCodexAuth(): InstalledCodexAuth | null;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure-stdlib (fetch + Buffer) Codex OAuth refresh + JWT exp decoding.
|
|
3
|
+
*
|
|
4
|
+
* Lives here (not in codexAuth.ts) so the Next.js server side can import it
|
|
5
|
+
* via pullfrog/internal without dragging in node:child_process / spawn /
|
|
6
|
+
* mkdtemp from the rest of codexAuth.ts. Used by:
|
|
7
|
+
* - action/utils/codexAuth.ts (re-exports refreshCodexAuthBody)
|
|
8
|
+
* - utils/codexSecretRotation.ts (server-side maybeRotate at run-context)
|
|
9
|
+
*
|
|
10
|
+
* See wiki/codex-auth.md for the end-to-end refresh lifecycle.
|
|
11
|
+
*/
|
|
12
|
+
export interface CodexAuthBody {
|
|
13
|
+
auth_mode: "chatgpt";
|
|
14
|
+
tokens: {
|
|
15
|
+
access_token: string;
|
|
16
|
+
refresh_token: string;
|
|
17
|
+
id_token?: string;
|
|
18
|
+
account_id?: string;
|
|
19
|
+
};
|
|
20
|
+
last_refresh?: string;
|
|
21
|
+
}
|
|
22
|
+
/** OAuth client id Codex CLI and OpenCode both use against `auth.openai.com`.
|
|
23
|
+
* Same chain — a refresh token minted via `codex login --device-auth` can be
|
|
24
|
+
* refreshed against this client_id. */
|
|
25
|
+
export declare const CODEX_OAUTH_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
26
|
+
export declare const CODEX_OAUTH_TOKEN_URL = "https://auth.openai.com/oauth/token";
|
|
27
|
+
/** thrown when the OAuth provider rejects the refresh token (4xx). callers
|
|
28
|
+
* can distinguish "race-lost / token revoked" from network errors via
|
|
29
|
+
* `instanceof OAuthInvalidGrantError`. */
|
|
30
|
+
export declare class OAuthInvalidGrantError extends Error {
|
|
31
|
+
readonly status: number;
|
|
32
|
+
constructor(status: number, body: string);
|
|
33
|
+
}
|
|
34
|
+
/** force one refresh round-trip against the OAuth provider. returns the
|
|
35
|
+
* rotated Codex-shaped blob (the auth.json body verbatim). does NOT persist
|
|
36
|
+
* — caller is responsible for writing back to wherever the token lives.
|
|
37
|
+
*
|
|
38
|
+
* server-side callers (maybeRotateCodexSecret) hold a DB row lock around
|
|
39
|
+
* this call so concurrent runs serialize: first one rotates, subsequent
|
|
40
|
+
* ones see the fresh value and skip. The 10s timeout is critical for that
|
|
41
|
+
* use: it caps how long a stalled auth.openai.com holds the row lock,
|
|
42
|
+
* keeping us well under the enclosing 30s transaction budget so the lock
|
|
43
|
+
* always releases and queued callers get a turn instead of timing out on
|
|
44
|
+
* the tx wrapper. Real OAuth latency is sub-second; 10s is generous. */
|
|
45
|
+
export declare function refreshCodexAuthBody(body: CodexAuthBody): Promise<CodexAuthBody>;
|
|
46
|
+
/** decode the access_token's JWT payload and return its `exp` claim in ms
|
|
47
|
+
* since epoch. returns null if the token isn't a parseable JWT or has no
|
|
48
|
+
* `exp` claim — caller falls back to "treat as expired".
|
|
49
|
+
*
|
|
50
|
+
* We don't verify the JWT signature (we'd need OpenAI's JWKS); we're only
|
|
51
|
+
* using the claim as a freshness hint. The actual auth check happens
|
|
52
|
+
* server-side at OpenAI when the token is used — trusting a fake JWT here
|
|
53
|
+
* would just delay the inevitable 401 from OpenAI. No security boundary
|
|
54
|
+
* at this decode step. */
|
|
55
|
+
export declare function decodeJwtExpMs(token: string): number | null;
|
|
56
|
+
/** parse + validate a Codex auth.json body from its JSON-string form.
|
|
57
|
+
* returns null on any shape mismatch — caller treats as "no codex auth". */
|
|
58
|
+
export declare function parseCodexAuthBody(raw: string): CodexAuthBody | null;
|
|
59
|
+
/** serialize a CodexAuthBody to its canonical on-disk form. */
|
|
60
|
+
export declare function stringifyCodexAuthBody(body: CodexAuthBody): string;
|
|
@@ -17,6 +17,10 @@ interface InstructionsContext {
|
|
|
17
17
|
* inline into the LEARNINGS prompt section so the agent can `read_file`
|
|
18
18
|
* targeted line ranges instead of pulling the whole file into context. */
|
|
19
19
|
learningsHeadings: LearningsHeading[];
|
|
20
|
+
/** agent-facing description of a setup lifecycle hook failure (see
|
|
21
|
+
* `describeSetupFailure`), rendered as a SETUP HOOK FAILED banner. empty
|
|
22
|
+
* string when the hook succeeded, was skipped, or wasn't configured. */
|
|
23
|
+
setupHookFailure: string;
|
|
20
24
|
}
|
|
21
25
|
export interface ResolvedInstructions {
|
|
22
26
|
full: string;
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
export interface ExecuteLifecycleHookParams {
|
|
2
2
|
event: string;
|
|
3
3
|
script: string | null;
|
|
4
|
+
/**
|
|
5
|
+
* when true, after the hook runs (success or failure), discard tracked-file
|
|
6
|
+
* mods so the agent doesn't see hook-generated drift (e.g. `pnpm install`
|
|
7
|
+
* rewriting a lockfile). untracked files are preserved — hooks that
|
|
8
|
+
* intentionally materialize files (e.g. a `.env` from a template) stay
|
|
9
|
+
* visible to the agent. skipped (with a warning) if the tree had
|
|
10
|
+
* pre-existing tracked changes before the hook ran, so we never clobber
|
|
11
|
+
* pre-existing work; pre-existing untracked files are ignored for this
|
|
12
|
+
* gate because `git restore --staged --worktree .` doesn't touch them
|
|
13
|
+
* anyway. no-op when no script was configured.
|
|
14
|
+
*/
|
|
15
|
+
normalizeWorkingTreeAfter?: boolean;
|
|
4
16
|
}
|
|
5
17
|
/** structured failure info — `output` on the `exit` variant is trimmed
|
|
6
18
|
* stderr, falling back to stdout when stderr is empty. */
|
|
@@ -14,6 +26,10 @@ export type LifecycleHookFailure = {
|
|
|
14
26
|
kind: "spawn";
|
|
15
27
|
spawnError: string;
|
|
16
28
|
};
|
|
29
|
+
/** one-line, agent-facing description of a hook failure. empty string when
|
|
30
|
+
* there was no failure, so callers can pass the result straight through to a
|
|
31
|
+
* prompt section that omits itself on empty. */
|
|
32
|
+
export declare function describeSetupFailure(failure: LifecycleHookFailure | undefined): string;
|
|
17
33
|
export interface LifecycleHookResult {
|
|
18
34
|
/**
|
|
19
35
|
* human-readable warning when the hook failed. includes retry guidance:
|
|
@@ -34,8 +50,8 @@ export interface LifecycleHookResult {
|
|
|
34
50
|
* execute a lifecycle hook script if one is configured.
|
|
35
51
|
*
|
|
36
52
|
* soft-fails: instead of throwing on hook errors, returns a warning string
|
|
37
|
-
* (and structured failure info) so callers can choose
|
|
38
|
-
*
|
|
39
|
-
* flagged as non-retryable in the warning text.
|
|
53
|
+
* (and structured failure info) so callers can choose how to surface it
|
|
54
|
+
* (mcp tools relay it to the agent; setup logs it and adds a prompt banner).
|
|
55
|
+
* timeouts are flagged as non-retryable in the warning text.
|
|
40
56
|
*/
|
|
41
57
|
export declare function executeLifecycleHook(params: ExecuteLifecycleHookParams): Promise<LifecycleHookResult>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Snapshot the set of models OpenCode can serve from the current env, BEFORE
|
|
2
|
+
* Pullfrog-stored credentials are merged in. Call once early in `main.ts`. */
|
|
3
|
+
export declare function captureBaselineModels(cliPath: string): void;
|
|
4
|
+
/** Snapshot the set of models OpenCode can serve AFTER dbSecrets +
|
|
5
|
+
* Codex auth.json are in place. Logs the diff against the baseline as
|
|
6
|
+
* `» BYOK auth enabled N model(s): …`. */
|
|
7
|
+
export declare function captureAuthorizedModels(cliPath: string): void;
|
|
8
|
+
/** Authorized set captured after Pullfrog-stored auth is applied. Throws if
|
|
9
|
+
* called before `captureAuthorizedModels` — the call sites (fallback gate,
|
|
10
|
+
* api-key validation, auto-select) all run strictly after capture. */
|
|
11
|
+
export declare function getAuthorizedModels(): Set<string>;
|