pullfrog 0.1.56 → 0.1.59

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/internal.js CHANGED
@@ -531,6 +531,22 @@ var providers = {
531
531
  }
532
532
  }
533
533
  }),
534
+ azure: provider({
535
+ displayName: "Azure OpenAI",
536
+ // the resource name is half the endpoint URL and the deployment is the model
537
+ // id, so both are as load-bearing as the key. only the key is sensitive.
538
+ envVars: ["AZURE_API_KEY", "AZURE_RESOURCE_NAME", "AZURE_DEPLOYMENT"],
539
+ models: {
540
+ // single routing entry — the real model is the customer's deployment name,
541
+ // read from AZURE_DEPLOYMENT at run time. see ModelRouting docs for why
542
+ // Azure can't be cataloged even though models.dev lists it.
543
+ byok: {
544
+ displayName: "Azure OpenAI",
545
+ resolve: "azure",
546
+ routing: "azure"
547
+ }
548
+ }
549
+ }),
534
550
  "openai-compatible": provider({
535
551
  // "Custom" is the picker group, "OpenAI-compatible" the entry under it, so the
536
552
  // menu reads `Custom › OpenAI-compatible` and a second custom backend (a
@@ -878,6 +894,8 @@ function formatMcpToolRef(agentId, toolName) {
878
894
  switch (agentId) {
879
895
  case "claude":
880
896
  return `mcp__${pullfrogMcpName}__${toolName}`;
897
+ case "codex":
898
+ return `${pullfrogMcpName}__${toolName}`;
881
899
  case "opencode":
882
900
  return `${pullfrogMcpName}_${toolName}`;
883
901
  default:
package/dist/models.d.ts CHANGED
@@ -20,8 +20,16 @@ import { type EffortPosition } from "./effort.ts";
20
20
  * routing slugs, not model aliases: the harness reads the backend-specific
21
21
  * env var and routes to claude-code for Anthropic IDs or opencode for
22
22
  * everything else.
23
+ *
24
+ * `"azure"` is the same shape for a different reason. models.dev DOES carry an
25
+ * Azure catalog, but the id it lists is sent to Azure as the DEPLOYMENT NAME,
26
+ * and a deployment is named by whoever created it — so cataloging `azure/gpt-5`
27
+ * would only work for customers who kept the portal's default name. the
28
+ * deployment comes from `AZURE_DEPLOYMENT` instead. unlike bedrock/vertex it
29
+ * resolves to a provider-PREFIXED specifier (`azure/<deployment>`), matching
30
+ * openai-compatible, because `azure` is a real opencode provider id.
23
31
  */
24
- export type ModelRouting = "bedrock" | "vertex" | "openai-compatible";
32
+ export type ModelRouting = "bedrock" | "vertex" | "openai-compatible" | "azure";
25
33
  export interface ModelAlias {
26
34
  /** stable alias stored in DB, e.g. "anthropic/claude-opus" */
27
35
  slug: string;
@@ -115,6 +123,7 @@ export declare const providers: {
115
123
  "opencode-go": ProviderConfig;
116
124
  bedrock: ProviderConfig;
117
125
  vertex: ProviderConfig;
126
+ azure: ProviderConfig;
118
127
  "openai-compatible": ProviderConfig;
119
128
  openrouter: ProviderConfig;
120
129
  };
@@ -283,6 +292,38 @@ export declare function getAutoSelectHintModel(): string;
283
292
  export declare const BEDROCK_MODEL_ID_ENV = "BEDROCK_MODEL_ID";
284
293
  /** env var that supplies the Vertex AI model ID for the `vertex/byok` slug. */
285
294
  export declare const VERTEX_MODEL_ID_ENV = "VERTEX_MODEL_ID";
295
+ /** provider key + slug prefix for the Azure OpenAI BYOK backend. matches opencode's own provider id. */
296
+ export declare const AZURE_PROVIDER = "azure";
297
+ /** resource name in the endpoint `https://<name>.openai.azure.com` — plain config, not a credential. */
298
+ export declare const AZURE_RESOURCE_NAME_ENV = "AZURE_RESOURCE_NAME";
299
+ /** API key for the Azure OpenAI resource — the one sensitive value. */
300
+ export declare const AZURE_API_KEY_ENV = "AZURE_API_KEY";
301
+ /**
302
+ * the customer's Azure deployment name, supplied for the `azure/byok` slug.
303
+ * Azure takes the deployment name where every other provider takes a model id
304
+ * (`@ai-sdk/azure` types the argument `deploymentId`), and the name is whatever
305
+ * its creator typed — which is why Azure gets a routing slug instead of the
306
+ * catalog entries models.dev publishes for it.
307
+ */
308
+ export declare const AZURE_DEPLOYMENT_ENV = "AZURE_DEPLOYMENT";
309
+ /**
310
+ * context-window size of the model behind the deployment. required for the same
311
+ * reason as its `OPENAI_COMPATIBLE_*` twin: opencode holds no metadata for a
312
+ * deployment name, and an undeclared limit both caps completions at 32000 and
313
+ * disables auto-compaction. see `azureProvider()` in agents/opencodeShared.ts.
314
+ */
315
+ export declare const AZURE_CONTEXT_ENV = "AZURE_CONTEXT";
316
+ /** max completion tokens the model behind the deployment accepts. required. */
317
+ export declare const AZURE_MAX_OUTPUT_ENV = "AZURE_MAX_OUTPUT";
318
+ /**
319
+ * opt this deployment into Chat Completions. opencode's azure loader calls
320
+ * `sdk.responses(modelID)` unless its `useCompletionUrls` option is set
321
+ * (`selectAzureLanguageModel`), so a deployment serving a model that predates
322
+ * Azure's Responses API — gpt-4, gpt-35-turbo — fails on the wire dialect
323
+ * rather than on anything we control. optional, and the only value here that
324
+ * isn't required.
325
+ */
326
+ export declare const AZURE_USE_CHAT_COMPLETIONS_ENV = "AZURE_USE_CHAT_COMPLETIONS";
286
327
  /** provider key + slug prefix for the generic OpenAI-compatible BYOK backend. */
287
328
  export declare const OPENAI_COMPATIBLE_PROVIDER = "openai-compatible";
288
329
  /** base URL of the user's OpenAI-compatible endpoint (e.g. a Cloudflare AI Gateway URL). */
@@ -19,4 +19,14 @@ export declare function resolveModel(ctx: {
19
19
  }): string | undefined;
20
20
  export declare function resolveAgent(ctx: {
21
21
  model?: string | undefined;
22
+ /** set on router / OSS runs, where the model is served by OpenRouter. those
23
+ * pin no `model`, so without this the auto-select branches below would read
24
+ * a stored Anthropic or OpenAI credential as the routing signal for a run
25
+ * that isn't using it. */
26
+ proxyModel?: string | undefined;
27
+ /** the account opted in to the EXPERIMENTAL codex harness, already ANDed
28
+ * server-side with the global kill switch. false — the default for every
29
+ * account — routes OpenAI models to opencode exactly as before the harness
30
+ * existed. see wiki/codex-agent.md. */
31
+ codexAgent?: boolean | undefined;
22
32
  }): Agent;
@@ -17,6 +17,12 @@ export interface InstalledCodexAuth {
17
17
  * OpenCode refreshed during the session (only happens on long runs
18
18
  * that span >50min — see wiki/codex-auth.md "Concurrency"). */
19
19
  originalRefresh: string;
20
+ /** id_token from the env at materialization time. OpenCode's auth file has
21
+ * no slot for it, so the post-hook has to re-attach this one or the written
22
+ * back blob loses it — and the Codex CLI REFUSES an auth.json without
23
+ * `tokens.id_token` (measured: `missing field 'id_token'`), so dropping it
24
+ * silently disqualifies the account from the codex harness forever. */
25
+ originalIdToken: string | undefined;
20
26
  }
21
27
  /** materialize CODEX_AUTH_JSON from env into a disk path OpenCode reads from.
22
28
  * returns null when the env var is absent, malformed, or wrong auth mode —
@@ -27,3 +33,24 @@ export interface InstalledCodexAuth {
27
33
  * `process.env.XDG_DATA_HOME` so every opencode subprocess discovers the
28
34
  * auth.json; no refresh, no DB interaction. */
29
35
  export declare function installCodexAuth(): InstalledCodexAuth | null;
36
+ export interface InstalledCodexHome {
37
+ /** value to set as CODEX_HOME for the codex subprocess. holds auth.json,
38
+ * config.toml and the session rollouts the resume path reads. */
39
+ codexHome: string;
40
+ /** absolute path of the auth.json we wrote. the codex CLI rewrites this file
41
+ * in place when it refreshes, so the post-hook diffs it for a rotation. */
42
+ authPath: string;
43
+ originalRefresh: string;
44
+ }
45
+ /**
46
+ * materialize CODEX_AUTH_JSON into a CODEX_HOME the codex CLI reads directly.
47
+ * unlike {@link installCodexAuth} there is no shape conversion — the stored
48
+ * blob IS the codex CLI's own `auth.json`, so it round-trips verbatim.
49
+ *
50
+ * returns null when the env var is absent, malformed, or carries no
51
+ * `tokens.id_token`. that last one is not defensive: the CLI's `TokenData`
52
+ * makes `id_token` a required field with a JWT deserializer, so an auth.json
53
+ * without it fails to load with `missing field 'id_token'` before any model
54
+ * call. callers treat null as "codex CLI can't use this credential".
55
+ */
56
+ export declare function installCodexHome(): InstalledCodexHome | null;
@@ -17,6 +17,20 @@ import type { GitHubAppPermissions } from "./github.ts";
17
17
  * permissions have no object granularity — so those runs get no token and use
18
18
  * the object-scoped MCP tools instead.
19
19
  *
20
+ * `role` is the triggerer's EFFECTIVE permission on THIS repo, and where it
21
+ * came from is deliberately not asked. `getCollaboratorPermissionLevel` already
22
+ * folds direct grants, team grants and the org base permission into one answer,
23
+ * so an org member who is `write` org-wide and a user with a single direct
24
+ * grant resolve identically — which is correct, because on this repo they can
25
+ * do the same things. Nothing in the action queries org membership.
26
+ *
27
+ * The token is then scoped to the current repo UNCONDITIONALLY: `resolveTokens`
28
+ * passes no `repos`, and `acquireTokenViaOIDC` always appends
29
+ * `$GITHUB_REPOSITORY`, so the list is exactly `[this repo]` even when the
30
+ * triggerer holds org-wide admin over hundreds. That asymmetry is deliberate
31
+ * margin — the invariant is "never MORE than the user has", and one repo out of
32
+ * many satisfies it with room to spare.
33
+ *
20
34
  * The set is a strict SUBSET of what any qualifying role holds, so the mirror
21
35
  * is one-directional by construction — it can never over-grant:
22
36
  *
@@ -33,6 +33,7 @@ export interface RepoSettings {
33
33
  shell: ShellPermission;
34
34
  prApproveEnabled: boolean;
35
35
  autoMergeEnabled: boolean;
36
+ codexAgent: boolean;
36
37
  signedCommits: boolean;
37
38
  repoIntelligence: boolean;
38
39
  progressComments: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pullfrog",
3
- "version": "0.1.56",
3
+ "version": "0.1.59",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "pullfrog": "dist/cli.mjs",
@@ -32,6 +32,8 @@
32
32
  "@clack/prompts": "^1.2.0",
33
33
  "@modelcontextprotocol/sdk": "^1.26.0",
34
34
  "@opencode-ai/sdk": "1.18.5",
35
+ "@openai/codex": "0.147.0",
36
+ "@openai/codex-sdk": "0.147.0",
35
37
  "@octokit/plugin-throttling": "^11.0.3",
36
38
  "@octokit/rest": "^22.0.0",
37
39
  "@octokit/webhooks-types": "^7.6.1",