@poncho-ai/harness 0.29.0 → 0.31.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/dist/index.js CHANGED
@@ -134,7 +134,7 @@ var parseAgentMarkdown = (content) => {
134
134
  if (typeof parsed.name !== "string" || parsed.name.trim() === "") {
135
135
  throw new Error("Invalid AGENT.md: frontmatter requires a non-empty `name`.");
136
136
  }
137
- const KNOWN_PROVIDERS = /* @__PURE__ */ new Set(["anthropic", "openai"]);
137
+ const KNOWN_PROVIDERS = /* @__PURE__ */ new Set(["anthropic", "openai", "openai-codex"]);
138
138
  const splitProviderPrefix = (raw) => {
139
139
  const slashIdx = raw.indexOf("/");
140
140
  if (slashIdx > 0) {
@@ -1440,6 +1440,11 @@ All credentials in \`poncho.config.js\` use **env var name** fields (\`*Env\` su
1440
1440
  |---|---|---|
1441
1441
  | \`providers.anthropic.apiKeyEnv\` | \`ANTHROPIC_API_KEY\` | Anthropic model API key |
1442
1442
  | \`providers.openai.apiKeyEnv\` | \`OPENAI_API_KEY\` | OpenAI model API key |
1443
+ | \`providers.openaiCodex.refreshTokenEnv\` | \`OPENAI_CODEX_REFRESH_TOKEN\` | OpenAI Codex OAuth refresh token |
1444
+ | \`providers.openaiCodex.accountIdEnv\` | \`OPENAI_CODEX_ACCOUNT_ID\` | OpenAI Codex account/org routing header (optional) |
1445
+ | \`providers.openaiCodex.accessTokenEnv\` | \`OPENAI_CODEX_ACCESS_TOKEN\` | OpenAI Codex OAuth access token seed (optional) |
1446
+ | \`providers.openaiCodex.accessTokenExpiresAtEnv\` | \`OPENAI_CODEX_ACCESS_TOKEN_EXPIRES_AT\` | Access token epoch expiry in ms (optional) |
1447
+ | \`providers.openaiCodex.authFilePathEnv\` | \`OPENAI_CODEX_AUTH_FILE\` | Overrides local auth file path used by \`poncho auth\` |
1443
1448
  | \`auth.tokenEnv\` | \`PONCHO_AUTH_TOKEN\` | Auth passphrase / bearer token |
1444
1449
  | \`storage.urlEnv\` | \`UPSTASH_REDIS_REST_URL\` / \`REDIS_URL\` | Storage connection URL |
1445
1450
  | \`storage.tokenEnv\` | \`UPSTASH_REDIS_REST_TOKEN\` | Upstash REST token |
@@ -1511,6 +1516,10 @@ export default {
1511
1516
  providers: {
1512
1517
  // anthropic: { apiKeyEnv: 'ANTHROPIC_API_KEY' }, // default
1513
1518
  // openai: { apiKeyEnv: 'OPENAI_API_KEY' }, // default
1519
+ // openaiCodex: {
1520
+ // refreshTokenEnv: 'OPENAI_CODEX_REFRESH_TOKEN',
1521
+ // accountIdEnv: 'OPENAI_CODEX_ACCOUNT_ID', // optional
1522
+ // },
1514
1523
  },
1515
1524
 
1516
1525
  // Unified storage (preferred). Replaces separate \`state\` and \`memory\` blocks.
@@ -1609,6 +1618,11 @@ Remote storage keys are namespaced and versioned, for example \`poncho:v1:<agent
1609
1618
  |----------|----------|-------------|
1610
1619
  | \`ANTHROPIC_API_KEY\` | Yes* | Claude API key |
1611
1620
  | \`OPENAI_API_KEY\` | No | OpenAI API key (if using OpenAI) |
1621
+ | \`OPENAI_CODEX_REFRESH_TOKEN\` | No | OpenAI Codex OAuth refresh token (if using \`model.provider: openai-codex\`) |
1622
+ | \`OPENAI_CODEX_ACCOUNT_ID\` | No | OpenAI Codex account/org id for request routing (optional) |
1623
+ | \`OPENAI_CODEX_ACCESS_TOKEN\` | No | Optional pre-seeded short-lived access token |
1624
+ | \`OPENAI_CODEX_ACCESS_TOKEN_EXPIRES_AT\` | No | Epoch millis expiry for \`OPENAI_CODEX_ACCESS_TOKEN\` |
1625
+ | \`OPENAI_CODEX_AUTH_FILE\` | No | Local auth store override for \`poncho auth\` commands |
1612
1626
  | \`PONCHO_AUTH_TOKEN\` | No | Unified auth token (Web UI passphrase + API Bearer token) |
1613
1627
  | \`PONCHO_INTERNAL_SECRET\` | No | Shared secret used by internal serverless callbacks (recommended for Vercel/Lambda) |
1614
1628
  | \`PONCHO_SELF_BASE_URL\` | No | Explicit base URL for internal self-callbacks when auto-detection is unavailable |
@@ -1833,6 +1847,36 @@ Make sure you have a \`.env\` file with your API key:
1833
1847
  echo "ANTHROPIC_API_KEY=sk-ant-..." > .env
1834
1848
  \`\`\`
1835
1849
 
1850
+ ### "OpenAI Codex credentials not found"
1851
+
1852
+ Bootstrap credentials with device auth, then export env values:
1853
+
1854
+ \`\`\`bash
1855
+ poncho auth login --provider openai-codex --device
1856
+ poncho auth export --provider openai-codex --format env
1857
+ \`\`\`
1858
+
1859
+ For production, copy exported values into your deployment secret manager (not committed files).
1860
+
1861
+ ### "OpenAI Codex token refresh failed" / \`invalid_grant\`
1862
+
1863
+ Your refresh token is expired or rotated. Re-run one-time auth and rotate deployment secrets:
1864
+
1865
+ \`\`\`bash
1866
+ poncho auth login --provider openai-codex --device
1867
+ poncho auth export --provider openai-codex --format env
1868
+ \`\`\`
1869
+
1870
+ Then restart your deployment so new secrets are loaded.
1871
+
1872
+ ### "Missing scopes: model.request / api.model.read / api.responses.write"
1873
+
1874
+ Re-authenticate and ensure the OAuth flow requested required scopes. Then verify:
1875
+
1876
+ \`\`\`bash
1877
+ poncho auth status --provider openai-codex
1878
+ \`\`\`
1879
+
1836
1880
  ### "MCP server failed to connect"
1837
1881
 
1838
1882
  Check that:
@@ -2064,8 +2108,8 @@ var ponchoDocsTool = defineTool({
2064
2108
 
2065
2109
  // src/harness.ts
2066
2110
  import { randomUUID as randomUUID3 } from "crypto";
2067
- import { readFile as readFile8 } from "fs/promises";
2068
- import { resolve as resolve10 } from "path";
2111
+ import { readFile as readFile9 } from "fs/promises";
2112
+ import { resolve as resolve11 } from "path";
2069
2113
  import { getTextContent as getTextContent2 } from "@poncho-ai/sdk";
2070
2114
 
2071
2115
  // src/upload-store.ts
@@ -3572,6 +3616,252 @@ var LocalMcpBridge = class {
3572
3616
  // src/model-factory.ts
3573
3617
  import { createOpenAI } from "@ai-sdk/openai";
3574
3618
  import { createAnthropic } from "@ai-sdk/anthropic";
3619
+
3620
+ // src/openai-codex-auth.ts
3621
+ import { homedir as homedir3 } from "os";
3622
+ import { dirname as dirname4, resolve as resolve8 } from "path";
3623
+ import { mkdir as mkdir5, readFile as readFile7, chmod, writeFile as writeFile6, rm as rm3 } from "fs/promises";
3624
+ var OPENAI_CODEX_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
3625
+ var OPENAI_AUTH_ISSUER = "https://auth.openai.com";
3626
+ var REFRESH_TOKEN_GRACE_MS = 5 * 60 * 1e3;
3627
+ var DEVICE_POLLING_SAFETY_MARGIN_MS = 3e3;
3628
+ var DEVICE_FLOW_TIMEOUT_MS = 10 * 60 * 1e3;
3629
+ var REQUIRED_SCOPES = [
3630
+ "openid",
3631
+ "profile",
3632
+ "email",
3633
+ "offline_access",
3634
+ "api.responses.write",
3635
+ "model.request",
3636
+ "api.model.read"
3637
+ ];
3638
+ var defaultedConfig = (config) => ({
3639
+ refreshTokenEnv: config?.refreshTokenEnv ?? "OPENAI_CODEX_REFRESH_TOKEN",
3640
+ accessTokenEnv: config?.accessTokenEnv ?? "OPENAI_CODEX_ACCESS_TOKEN",
3641
+ accessTokenExpiresAtEnv: config?.accessTokenExpiresAtEnv ?? "OPENAI_CODEX_ACCESS_TOKEN_EXPIRES_AT",
3642
+ accountIdEnv: config?.accountIdEnv ?? "OPENAI_CODEX_ACCOUNT_ID",
3643
+ authFilePathEnv: config?.authFilePathEnv ?? "OPENAI_CODEX_AUTH_FILE"
3644
+ });
3645
+ var parseEpochMillis = (value) => {
3646
+ if (!value) return void 0;
3647
+ const parsed = Number.parseInt(value, 10);
3648
+ if (Number.isNaN(parsed) || parsed <= 0) return void 0;
3649
+ return parsed;
3650
+ };
3651
+ var getOpenAICodexAuthFilePath = (config) => {
3652
+ const env = defaultedConfig(config);
3653
+ const fromEnv = process.env[env.authFilePathEnv];
3654
+ if (typeof fromEnv === "string" && fromEnv.trim().length > 0) {
3655
+ return resolve8(fromEnv);
3656
+ }
3657
+ return resolve8(homedir3(), ".poncho", "auth", "openai-codex.json");
3658
+ };
3659
+ var readOpenAICodexSession = async (config) => {
3660
+ const filePath = getOpenAICodexAuthFilePath(config);
3661
+ try {
3662
+ const content = await readFile7(filePath, "utf8");
3663
+ const parsed = JSON.parse(content);
3664
+ if (typeof parsed.refreshToken !== "string" || parsed.refreshToken.length === 0) {
3665
+ return void 0;
3666
+ }
3667
+ return {
3668
+ refreshToken: parsed.refreshToken,
3669
+ accessToken: typeof parsed.accessToken === "string" && parsed.accessToken.length > 0 ? parsed.accessToken : void 0,
3670
+ accessTokenExpiresAt: typeof parsed.accessTokenExpiresAt === "number" && parsed.accessTokenExpiresAt > 0 ? parsed.accessTokenExpiresAt : void 0,
3671
+ accountId: typeof parsed.accountId === "string" && parsed.accountId.length > 0 ? parsed.accountId : void 0
3672
+ };
3673
+ } catch {
3674
+ return void 0;
3675
+ }
3676
+ };
3677
+ var writeOpenAICodexSession = async (session, config) => {
3678
+ const filePath = getOpenAICodexAuthFilePath(config);
3679
+ await mkdir5(dirname4(filePath), { recursive: true });
3680
+ const payload = {
3681
+ ...session,
3682
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
3683
+ };
3684
+ await writeFile6(filePath, `${JSON.stringify(payload, null, 2)}
3685
+ `, "utf8");
3686
+ await chmod(filePath, 384);
3687
+ };
3688
+ var deleteOpenAICodexSession = async (config) => {
3689
+ const filePath = getOpenAICodexAuthFilePath(config);
3690
+ await rm3(filePath, { force: true });
3691
+ };
3692
+ var parseAccountIdFromJwt = (token) => {
3693
+ if (!token) return void 0;
3694
+ const parts = token.split(".");
3695
+ if (parts.length !== 3) return void 0;
3696
+ try {
3697
+ const claims = JSON.parse(Buffer.from(parts[1] ?? "", "base64url").toString("utf8"));
3698
+ return claims.chatgpt_account_id ?? claims["https://api.openai.com/auth"]?.chatgpt_account_id ?? claims.organizations?.[0]?.id;
3699
+ } catch {
3700
+ return void 0;
3701
+ }
3702
+ };
3703
+ var exchangeRefreshToken = async (refreshToken) => {
3704
+ const response = await fetch(`${OPENAI_AUTH_ISSUER}/oauth/token`, {
3705
+ method: "POST",
3706
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
3707
+ body: new URLSearchParams({
3708
+ grant_type: "refresh_token",
3709
+ refresh_token: refreshToken,
3710
+ client_id: OPENAI_CODEX_CLIENT_ID
3711
+ }).toString()
3712
+ });
3713
+ if (!response.ok) {
3714
+ const body = await response.text();
3715
+ throw new Error(
3716
+ `OpenAI Codex token refresh failed (${response.status}). Re-run \`poncho auth login --provider openai-codex --device\`, export the new token, and update deployment secrets. Details: ${body.slice(0, 240)}`
3717
+ );
3718
+ }
3719
+ return await response.json();
3720
+ };
3721
+ var exchangeAuthorizationCode = async (code, codeVerifier) => {
3722
+ const response = await fetch(`${OPENAI_AUTH_ISSUER}/oauth/token`, {
3723
+ method: "POST",
3724
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
3725
+ body: new URLSearchParams({
3726
+ grant_type: "authorization_code",
3727
+ code,
3728
+ redirect_uri: `${OPENAI_AUTH_ISSUER}/deviceauth/callback`,
3729
+ client_id: OPENAI_CODEX_CLIENT_ID,
3730
+ code_verifier: codeVerifier
3731
+ }).toString()
3732
+ });
3733
+ if (!response.ok) {
3734
+ const body = await response.text();
3735
+ throw new Error(
3736
+ `OpenAI Codex device token exchange failed (${response.status}): ${body.slice(0, 240)}`
3737
+ );
3738
+ }
3739
+ return await response.json();
3740
+ };
3741
+ var readSessionFromEnv = (config) => {
3742
+ const env = defaultedConfig(config);
3743
+ const refreshToken = process.env[env.refreshTokenEnv];
3744
+ if (!refreshToken || refreshToken.trim().length === 0) return void 0;
3745
+ return {
3746
+ refreshToken: refreshToken.trim(),
3747
+ accessToken: process.env[env.accessTokenEnv]?.trim() || void 0,
3748
+ accessTokenExpiresAt: parseEpochMillis(process.env[env.accessTokenExpiresAtEnv]),
3749
+ accountId: process.env[env.accountIdEnv]?.trim() || void 0
3750
+ };
3751
+ };
3752
+ var shouldRefresh = (expiresAt) => !expiresAt || Date.now() + REFRESH_TOKEN_GRACE_MS >= expiresAt;
3753
+ var runtimeCachedSession;
3754
+ var readSession = async (config) => {
3755
+ const envSession = readSessionFromEnv(config);
3756
+ if (envSession) return { session: envSession, source: "env" };
3757
+ if (runtimeCachedSession) {
3758
+ return { session: runtimeCachedSession, source: "file" };
3759
+ }
3760
+ const fileSession = await readOpenAICodexSession(config);
3761
+ if (!fileSession) {
3762
+ throw new Error(
3763
+ "OpenAI Codex credentials not found. Run `poncho auth login --provider openai-codex --device` locally, or set OPENAI_CODEX_REFRESH_TOKEN in your environment."
3764
+ );
3765
+ }
3766
+ runtimeCachedSession = fileSession;
3767
+ return { session: fileSession, source: "file" };
3768
+ };
3769
+ var getOpenAICodexAccessToken = async (config) => {
3770
+ const { session, source } = await readSession(config);
3771
+ if (session.accessToken && !shouldRefresh(session.accessTokenExpiresAt)) {
3772
+ return { accessToken: session.accessToken, accountId: session.accountId };
3773
+ }
3774
+ const refreshed = await exchangeRefreshToken(session.refreshToken);
3775
+ const nextSession = {
3776
+ refreshToken: refreshed.refresh_token ?? session.refreshToken,
3777
+ accessToken: refreshed.access_token,
3778
+ accessTokenExpiresAt: Date.now() + (refreshed.expires_in ?? 3600) * 1e3,
3779
+ accountId: session.accountId ?? parseAccountIdFromJwt(refreshed.id_token) ?? parseAccountIdFromJwt(refreshed.access_token)
3780
+ };
3781
+ runtimeCachedSession = nextSession;
3782
+ if (source === "file") {
3783
+ await writeOpenAICodexSession(nextSession, config);
3784
+ }
3785
+ return {
3786
+ accessToken: nextSession.accessToken,
3787
+ accountId: nextSession.accountId
3788
+ };
3789
+ };
3790
+ var getOpenAICodexRequiredScopes = () => [...REQUIRED_SCOPES];
3791
+ var startOpenAICodexDeviceAuth = async () => {
3792
+ const response = await fetch(`${OPENAI_AUTH_ISSUER}/api/accounts/deviceauth/usercode`, {
3793
+ method: "POST",
3794
+ headers: {
3795
+ "Content-Type": "application/json",
3796
+ "User-Agent": "poncho/1.0"
3797
+ },
3798
+ body: JSON.stringify({
3799
+ client_id: OPENAI_CODEX_CLIENT_ID,
3800
+ scope: REQUIRED_SCOPES.join(" ")
3801
+ })
3802
+ });
3803
+ if (!response.ok) {
3804
+ const body = await response.text();
3805
+ throw new Error(
3806
+ `OpenAI Codex device authorization start failed (${response.status}): ${body.slice(0, 240)}`
3807
+ );
3808
+ }
3809
+ const data = await response.json();
3810
+ const intervalRaw = typeof data.interval === "number" ? data.interval : Number.parseInt(String(data.interval ?? "5"), 10);
3811
+ const intervalMs = Math.max(Number.isNaN(intervalRaw) ? 5 : intervalRaw, 1) * 1e3;
3812
+ return {
3813
+ deviceAuthId: data.device_auth_id,
3814
+ userCode: data.user_code,
3815
+ verificationUrl: `${OPENAI_AUTH_ISSUER}/codex/device`,
3816
+ intervalMs
3817
+ };
3818
+ };
3819
+ var completeOpenAICodexDeviceAuth = async (request) => {
3820
+ const startedAt = Date.now();
3821
+ while (Date.now() - startedAt < DEVICE_FLOW_TIMEOUT_MS) {
3822
+ const response = await fetch(`${OPENAI_AUTH_ISSUER}/api/accounts/deviceauth/token`, {
3823
+ method: "POST",
3824
+ headers: {
3825
+ "Content-Type": "application/json",
3826
+ "User-Agent": "poncho/1.0"
3827
+ },
3828
+ body: JSON.stringify({
3829
+ device_auth_id: request.deviceAuthId,
3830
+ user_code: request.userCode
3831
+ })
3832
+ });
3833
+ if (response.ok) {
3834
+ const data = await response.json();
3835
+ const tokens = await exchangeAuthorizationCode(
3836
+ data.authorization_code,
3837
+ data.code_verifier
3838
+ );
3839
+ if (!tokens.refresh_token || tokens.refresh_token.length === 0) {
3840
+ throw new Error("OpenAI Codex device auth succeeded but no refresh token was returned.");
3841
+ }
3842
+ return {
3843
+ refreshToken: tokens.refresh_token,
3844
+ accessToken: tokens.access_token,
3845
+ accessTokenExpiresAt: Date.now() + (tokens.expires_in ?? 3600) * 1e3,
3846
+ accountId: parseAccountIdFromJwt(tokens.id_token) ?? parseAccountIdFromJwt(tokens.access_token)
3847
+ };
3848
+ }
3849
+ if (response.status !== 403 && response.status !== 404) {
3850
+ const body = await response.text();
3851
+ throw new Error(
3852
+ `OpenAI Codex device authorization polling failed (${response.status}): ${body.slice(0, 240)}`
3853
+ );
3854
+ }
3855
+ await new Promise((resolveWait) => {
3856
+ setTimeout(resolveWait, request.intervalMs + DEVICE_POLLING_SAFETY_MARGIN_MS);
3857
+ });
3858
+ }
3859
+ throw new Error(
3860
+ "OpenAI Codex device authorization timed out. Re-run `poncho auth login --provider openai-codex --device`."
3861
+ );
3862
+ };
3863
+
3864
+ // src/model-factory.ts
3575
3865
  var MODEL_CONTEXT_WINDOWS = {
3576
3866
  "claude-opus-4-6": 2e5,
3577
3867
  "claude-sonnet-4-6": 2e5,
@@ -3596,6 +3886,29 @@ var MODEL_CONTEXT_WINDOWS = {
3596
3886
  "o3": 2e5
3597
3887
  };
3598
3888
  var DEFAULT_CONTEXT_WINDOW = 2e5;
3889
+ var OPENAI_CODEX_DEFAULT_INSTRUCTIONS = "You are Codex, based on GPT-5. You are running as a coding agent in Poncho.";
3890
+ var extractSystemInstructionFromInput = (input) => {
3891
+ if (!Array.isArray(input)) return void 0;
3892
+ for (const message of input) {
3893
+ if (!message || typeof message !== "object") continue;
3894
+ const candidate = message;
3895
+ if (candidate.role !== "system") continue;
3896
+ if (typeof candidate.content === "string" && candidate.content.trim().length > 0) {
3897
+ return candidate.content;
3898
+ }
3899
+ if (Array.isArray(candidate.content)) {
3900
+ const textParts = candidate.content.map((part) => {
3901
+ if (!part || typeof part !== "object") return "";
3902
+ const p = part;
3903
+ return typeof p.text === "string" ? p.text : "";
3904
+ }).filter((text) => text.trim().length > 0);
3905
+ if (textParts.length > 0) {
3906
+ return textParts.join("\n");
3907
+ }
3908
+ }
3909
+ }
3910
+ return void 0;
3911
+ };
3599
3912
  var getModelContextWindow = (modelName) => {
3600
3913
  if (MODEL_CONTEXT_WINDOWS[modelName] !== void 0) {
3601
3914
  return MODEL_CONTEXT_WINDOWS[modelName];
@@ -3610,6 +3923,39 @@ var getModelContextWindow = (modelName) => {
3610
3923
  };
3611
3924
  var createModelProvider = (provider, config) => {
3612
3925
  const normalized = (provider ?? "anthropic").toLowerCase();
3926
+ if (normalized === "openai-codex") {
3927
+ const openai = createOpenAI({
3928
+ apiKey: "oauth-placeholder",
3929
+ fetch: async (input, init) => {
3930
+ const { accessToken, accountId } = await getOpenAICodexAccessToken(config?.openaiCodex);
3931
+ const headers = new Headers(init?.headers);
3932
+ headers.set("Authorization", `Bearer ${accessToken}`);
3933
+ headers.set("originator", "poncho");
3934
+ headers.set("User-Agent", "poncho/1.0");
3935
+ if (accountId) {
3936
+ headers.set("ChatGPT-Account-Id", accountId);
3937
+ }
3938
+ const originalUrl = input instanceof URL ? input.toString() : typeof input === "string" ? input : input.url;
3939
+ const parsed = new URL(originalUrl);
3940
+ const shouldRewrite = parsed.pathname.includes("/v1/responses") || parsed.pathname.includes("/chat/completions");
3941
+ const targetUrl = shouldRewrite ? "https://chatgpt.com/backend-api/codex/responses" : originalUrl;
3942
+ let body = init?.body;
3943
+ if (shouldRewrite && typeof body === "string" && headers.get("Content-Type")?.includes("application/json")) {
3944
+ try {
3945
+ const payload = JSON.parse(body);
3946
+ if (typeof payload.instructions !== "string" || payload.instructions.trim() === "") {
3947
+ payload.instructions = extractSystemInstructionFromInput(payload.input) ?? OPENAI_CODEX_DEFAULT_INSTRUCTIONS;
3948
+ }
3949
+ payload.store = false;
3950
+ body = JSON.stringify(payload);
3951
+ } catch {
3952
+ }
3953
+ }
3954
+ return fetch(targetUrl, { ...init, headers, body });
3955
+ }
3956
+ });
3957
+ return (modelName) => openai(modelName);
3958
+ }
3613
3959
  if (normalized === "openai") {
3614
3960
  const apiKeyEnv2 = config?.openai?.apiKeyEnv ?? "OPENAI_API_KEY";
3615
3961
  const openai = createOpenAI({
@@ -3626,8 +3972,8 @@ var createModelProvider = (provider, config) => {
3626
3972
  };
3627
3973
 
3628
3974
  // src/skill-context.ts
3629
- import { readFile as readFile7, readdir as readdir2, stat } from "fs/promises";
3630
- import { dirname as dirname4, resolve as resolve8, normalize } from "path";
3975
+ import { readFile as readFile8, readdir as readdir2, stat } from "fs/promises";
3976
+ import { dirname as dirname5, resolve as resolve9, normalize } from "path";
3631
3977
  import YAML3 from "yaml";
3632
3978
  var DEFAULT_SKILL_DIRS = ["skills"];
3633
3979
  var resolveSkillDirs = (workingDir, extraPaths) => {
@@ -3639,7 +3985,7 @@ var resolveSkillDirs = (workingDir, extraPaths) => {
3639
3985
  }
3640
3986
  }
3641
3987
  }
3642
- return dirs.map((d) => resolve8(workingDir, d));
3988
+ return dirs.map((d) => resolve9(workingDir, d));
3643
3989
  };
3644
3990
  var FRONTMATTER_PATTERN3 = /^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/;
3645
3991
  var asRecord2 = (value) => typeof value === "object" && value !== null ? value : {};
@@ -3708,7 +4054,7 @@ var collectSkillManifests = async (directory) => {
3708
4054
  const entries = await readdir2(directory, { withFileTypes: true });
3709
4055
  const files = [];
3710
4056
  for (const entry of entries) {
3711
- const fullPath = resolve8(directory, entry.name);
4057
+ const fullPath = resolve9(directory, entry.name);
3712
4058
  let isDir = entry.isDirectory();
3713
4059
  let isFile = entry.isFile();
3714
4060
  if (entry.isSymbolicLink()) {
@@ -3743,13 +4089,13 @@ var loadSkillMetadata = async (workingDir, extraSkillPaths) => {
3743
4089
  const seen = /* @__PURE__ */ new Set();
3744
4090
  for (const manifest of allManifests) {
3745
4091
  try {
3746
- const content = await readFile7(manifest, "utf8");
4092
+ const content = await readFile8(manifest, "utf8");
3747
4093
  const parsed = parseSkillFrontmatter(content);
3748
4094
  if (parsed && !seen.has(parsed.name)) {
3749
4095
  seen.add(parsed.name);
3750
4096
  skills.push({
3751
4097
  ...parsed,
3752
- skillDir: dirname4(manifest),
4098
+ skillDir: dirname5(manifest),
3753
4099
  skillPath: manifest
3754
4100
  });
3755
4101
  }
@@ -3788,7 +4134,7 @@ ${xmlSkills}
3788
4134
  };
3789
4135
  var escapeXml = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
3790
4136
  var loadSkillInstructions = async (skill) => {
3791
- const content = await readFile7(skill.skillPath, "utf8");
4137
+ const content = await readFile8(skill.skillPath, "utf8");
3792
4138
  const match = content.match(FRONTMATTER_PATTERN3);
3793
4139
  return match ? match[2].trim() : content.trim();
3794
4140
  };
@@ -3797,11 +4143,11 @@ var readSkillResource = async (skill, relativePath) => {
3797
4143
  if (normalized.startsWith("..") || normalized.startsWith("/")) {
3798
4144
  throw new Error("Path must be relative and within the skill directory");
3799
4145
  }
3800
- const fullPath = resolve8(skill.skillDir, normalized);
4146
+ const fullPath = resolve9(skill.skillDir, normalized);
3801
4147
  if (!fullPath.startsWith(skill.skillDir)) {
3802
4148
  throw new Error("Path escapes the skill directory");
3803
4149
  }
3804
- return await readFile7(fullPath, "utf8");
4150
+ return await readFile8(fullPath, "utf8");
3805
4151
  };
3806
4152
  var MAX_INSTRUCTIONS_PER_SKILL = 1200;
3807
4153
  var loadSkillContext = async (workingDir) => {
@@ -3920,7 +4266,7 @@ function convertSchema(schema) {
3920
4266
  // src/skill-tools.ts
3921
4267
  import { defineTool as defineTool4 } from "@poncho-ai/sdk";
3922
4268
  import { access as access2, readdir as readdir3, stat as stat2 } from "fs/promises";
3923
- import { extname, normalize as normalize2, resolve as resolve9, sep as sep2 } from "path";
4269
+ import { extname, normalize as normalize2, resolve as resolve10, sep as sep2 } from "path";
3924
4270
  import { pathToFileURL } from "url";
3925
4271
  import { createJiti as createJiti2 } from "jiti";
3926
4272
  var createSkillTools = (skills, options) => {
@@ -4178,7 +4524,7 @@ var collectScriptFiles = async (directory) => {
4178
4524
  if (entry.name === "node_modules") {
4179
4525
  continue;
4180
4526
  }
4181
- const fullPath = resolve9(directory, entry.name);
4527
+ const fullPath = resolve10(directory, entry.name);
4182
4528
  let isDir = entry.isDirectory();
4183
4529
  let isFile = entry.isFile();
4184
4530
  if (entry.isSymbolicLink()) {
@@ -4217,8 +4563,8 @@ var normalizeScriptPolicyPath = (relativePath) => {
4217
4563
  };
4218
4564
  var resolveScriptPath = (baseDir, relativePath, containmentDir) => {
4219
4565
  const normalized = normalizeScriptPolicyPath(relativePath);
4220
- const fullPath = resolve9(baseDir, normalized);
4221
- const boundary = resolve9(containmentDir ?? baseDir);
4566
+ const fullPath = resolve10(baseDir, normalized);
4567
+ const boundary = resolve10(containmentDir ?? baseDir);
4222
4568
  if (!fullPath.startsWith(`${boundary}${sep2}`) && fullPath !== boundary) {
4223
4569
  throw new Error("Script path must stay inside the allowed directory");
4224
4570
  }
@@ -4324,8 +4670,8 @@ function applyRateLimitCooldown(retryAfterHeader) {
4324
4670
  async function runWithSearchThrottle(fn) {
4325
4671
  const previous = searchQueue;
4326
4672
  let release;
4327
- searchQueue = new Promise((resolve12) => {
4328
- release = resolve12;
4673
+ searchQueue = new Promise((resolve13) => {
4674
+ release = resolve13;
4329
4675
  });
4330
4676
  await previous.catch(() => {
4331
4677
  });
@@ -5122,6 +5468,8 @@ export default {
5122
5468
  providers: {
5123
5469
  anthropic: { apiKeyEnv: "ANTHROPIC_API_KEY" },
5124
5470
  openai: { apiKeyEnv: "OPENAI_API_KEY" },
5471
+ // openai-codex provider reads OAuth tokens from env vars by default:
5472
+ // openaiCodex: { refreshTokenEnv: "OPENAI_CODEX_REFRESH_TOKEN", accountIdEnv: "OPENAI_CODEX_ACCOUNT_ID" },
5125
5473
  },
5126
5474
  auth: {
5127
5475
  required: true,
@@ -5524,8 +5872,8 @@ var AgentHarness = class _AgentHarness {
5524
5872
  return false;
5525
5873
  }
5526
5874
  try {
5527
- const agentFilePath = resolve10(this.workingDir, "AGENT.md");
5528
- const rawContent = await readFile8(agentFilePath, "utf8");
5875
+ const agentFilePath = resolve11(this.workingDir, "AGENT.md");
5876
+ const rawContent = await readFile9(agentFilePath, "utf8");
5529
5877
  if (rawContent === this.agentFileFingerprint) {
5530
5878
  return false;
5531
5879
  }
@@ -5594,8 +5942,8 @@ var AgentHarness = class _AgentHarness {
5594
5942
  }
5595
5943
  }
5596
5944
  async initialize() {
5597
- const agentFilePath = resolve10(this.workingDir, "AGENT.md");
5598
- const agentRawContent = await readFile8(agentFilePath, "utf8");
5945
+ const agentFilePath = resolve11(this.workingDir, "AGENT.md");
5946
+ const agentRawContent = await readFile9(agentFilePath, "utf8");
5599
5947
  this.parsedAgent = parseAgentMarkdown(agentRawContent);
5600
5948
  this.agentFileFingerprint = agentRawContent;
5601
5949
  const identity = await ensureAgentIdentity(this.workingDir);
@@ -5702,14 +6050,14 @@ var AgentHarness = class _AgentHarness {
5702
6050
  const filePath = pathResolve(stateDir, `${sessionId}.json`);
5703
6051
  return {
5704
6052
  async save(json) {
5705
- const { mkdir: mkdir6, writeFile: writeFile7 } = await import("fs/promises");
5706
- await mkdir6(stateDir, { recursive: true });
5707
- await writeFile7(filePath, json, "utf8");
6053
+ const { mkdir: mkdir7, writeFile: writeFile8 } = await import("fs/promises");
6054
+ await mkdir7(stateDir, { recursive: true });
6055
+ await writeFile8(filePath, json, "utf8");
5708
6056
  },
5709
6057
  async load() {
5710
- const { readFile: readFile10 } = await import("fs/promises");
6058
+ const { readFile: readFile11 } = await import("fs/promises");
5711
6059
  try {
5712
- return await readFile10(filePath, "utf8");
6060
+ return await readFile11(filePath, "utf8");
5713
6061
  } catch {
5714
6062
  return void 0;
5715
6063
  }
@@ -5775,7 +6123,7 @@ var AgentHarness = class _AgentHarness {
5775
6123
  let browserMod;
5776
6124
  try {
5777
6125
  const { existsSync } = await import("fs");
5778
- const { join, dirname: dirname6 } = await import("path");
6126
+ const { join, dirname: dirname7 } = await import("path");
5779
6127
  const { pathToFileURL: pathToFileURL2 } = await import("url");
5780
6128
  let searchDir = this.workingDir;
5781
6129
  let entryPath;
@@ -5785,7 +6133,7 @@ var AgentHarness = class _AgentHarness {
5785
6133
  entryPath = candidate;
5786
6134
  break;
5787
6135
  }
5788
- const parent = dirname6(searchDir);
6136
+ const parent = dirname7(searchDir);
5789
6137
  if (parent === searchDir) break;
5790
6138
  searchDir = parent;
5791
6139
  }
@@ -5890,9 +6238,9 @@ var AgentHarness = class _AgentHarness {
5890
6238
  for await (const event of this.run(input)) {
5891
6239
  eventQueue.push(event);
5892
6240
  if (queueResolve) {
5893
- const resolve12 = queueResolve;
6241
+ const resolve13 = queueResolve;
5894
6242
  queueResolve = null;
5895
- resolve12();
6243
+ resolve13();
5896
6244
  }
5897
6245
  }
5898
6246
  } catch (error) {
@@ -5911,8 +6259,8 @@ var AgentHarness = class _AgentHarness {
5911
6259
  if (eventQueue.length > 0) {
5912
6260
  yield eventQueue.shift();
5913
6261
  } else if (!generatorDone) {
5914
- await new Promise((resolve12) => {
5915
- queueResolve = resolve12;
6262
+ await new Promise((resolve13) => {
6263
+ queueResolve = resolve13;
5916
6264
  });
5917
6265
  }
5918
6266
  }
@@ -6131,7 +6479,7 @@ ${this.skillFingerprint}`;
6131
6479
  if (lastMsg && lastMsg.role !== "user") {
6132
6480
  messages.push({
6133
6481
  role: "user",
6134
- content: "[System: Your previous turn was interrupted by a time limit. Continue from where you left off \u2014 do NOT repeat what you already said. Proceed directly with the next action or tool call.]",
6482
+ content: "[System: Your previous turn was interrupted by a time limit. Your partial response above is already visible to the user. Continue EXACTLY from where you left off \u2014 do NOT restart, re-summarize, or repeat any content you already produced. If you were mid-sentence or mid-table, continue that sentence or table. Proceed directly with the next action or output.]",
6135
6483
  metadata: { timestamp: now(), id: randomUUID3() }
6136
6484
  });
6137
6485
  }
@@ -6461,7 +6809,10 @@ ${textContent}` };
6461
6809
  let chunkCount = 0;
6462
6810
  const hasRunTimeout = timeoutMs > 0;
6463
6811
  const streamDeadline = hasRunTimeout ? start + timeoutMs : 0;
6812
+ const hasSoftDeadline = softDeadlineMs > 0;
6813
+ const INTER_CHUNK_TIMEOUT_MS = 6e4;
6464
6814
  const fullStreamIterator = result.fullStream[Symbol.asyncIterator]();
6815
+ let softDeadlineFiredDuringStream = false;
6465
6816
  try {
6466
6817
  while (true) {
6467
6818
  if (isCancelled()) {
@@ -6469,8 +6820,8 @@ ${textContent}` };
6469
6820
  return;
6470
6821
  }
6471
6822
  if (hasRunTimeout) {
6472
- const remaining2 = streamDeadline - now();
6473
- if (remaining2 <= 0) {
6823
+ const remaining = streamDeadline - now();
6824
+ if (remaining <= 0) {
6474
6825
  yield pushEvent({
6475
6826
  type: "run:error",
6476
6827
  runId,
@@ -6485,22 +6836,33 @@ ${textContent}` };
6485
6836
  return;
6486
6837
  }
6487
6838
  }
6488
- const remaining = hasRunTimeout ? streamDeadline - now() : Infinity;
6489
- const timeout = chunkCount === 0 ? Math.min(remaining, FIRST_CHUNK_TIMEOUT_MS) : hasRunTimeout ? remaining : 0;
6839
+ if (hasSoftDeadline && chunkCount > 0 && now() - start >= softDeadlineMs) {
6840
+ softDeadlineFiredDuringStream = true;
6841
+ break;
6842
+ }
6843
+ const hardRemaining = hasRunTimeout ? streamDeadline - now() : Infinity;
6844
+ const softRemaining = hasSoftDeadline ? Math.max(0, start + softDeadlineMs - now()) : Infinity;
6845
+ const deadlineRemaining = Math.min(hardRemaining, softRemaining);
6846
+ const timeout = chunkCount === 0 ? Math.min(deadlineRemaining, FIRST_CHUNK_TIMEOUT_MS) : Math.min(deadlineRemaining, INTER_CHUNK_TIMEOUT_MS);
6490
6847
  let nextPart;
6491
- if (timeout <= 0 && chunkCount > 0) {
6848
+ if (timeout <= 0 && chunkCount > 0 && !hasSoftDeadline) {
6492
6849
  nextPart = await fullStreamIterator.next();
6493
6850
  } else {
6851
+ const effectiveTimeout = Math.max(timeout, 1);
6494
6852
  let timer;
6495
6853
  nextPart = await Promise.race([
6496
6854
  fullStreamIterator.next(),
6497
- new Promise((resolve12) => {
6498
- timer = setTimeout(() => resolve12(null), timeout);
6855
+ new Promise((resolve13) => {
6856
+ timer = setTimeout(() => resolve13(null), effectiveTimeout);
6499
6857
  })
6500
6858
  ]);
6501
6859
  clearTimeout(timer);
6502
6860
  }
6503
6861
  if (nextPart === null) {
6862
+ if (hasSoftDeadline && deadlineRemaining <= INTER_CHUNK_TIMEOUT_MS) {
6863
+ softDeadlineFiredDuringStream = true;
6864
+ break;
6865
+ }
6504
6866
  const isFirstChunk = chunkCount === 0;
6505
6867
  console.error(
6506
6868
  `[poncho][harness] Stream timeout waiting for ${isFirstChunk ? "first" : "next"} chunk: model="${modelName}", step=${step}, chunks=${chunkCount}, elapsed=${now() - start}ms`
@@ -6533,11 +6895,42 @@ ${textContent}` };
6533
6895
  fullStreamIterator.return?.(void 0)?.catch?.(() => {
6534
6896
  });
6535
6897
  }
6898
+ if (softDeadlineFiredDuringStream) {
6899
+ if (fullText.length > 0) {
6900
+ messages.push({
6901
+ role: "assistant",
6902
+ content: fullText,
6903
+ metadata: { timestamp: now(), id: randomUUID3(), step }
6904
+ });
6905
+ }
6906
+ const result_ = {
6907
+ status: "completed",
6908
+ response: responseText + fullText,
6909
+ steps: step,
6910
+ tokens: { input: totalInputTokens, output: totalOutputTokens, cached: totalCachedTokens },
6911
+ duration: now() - start,
6912
+ continuation: true,
6913
+ continuationMessages: [...messages],
6914
+ maxSteps,
6915
+ contextTokens: latestContextTokens + toolOutputEstimateSinceModel,
6916
+ contextWindow
6917
+ };
6918
+ console.info(`[poncho][harness] Soft deadline fired mid-stream at step ${step} (${(now() - start).toFixed(0)}ms). Checkpointing with ${fullText.length} chars of partial text.`);
6919
+ yield pushEvent({ type: "run:completed", runId, result: result_ });
6920
+ return;
6921
+ }
6536
6922
  if (isCancelled()) {
6537
6923
  yield emitCancellation();
6538
6924
  return;
6539
6925
  }
6540
6926
  if (softDeadlineMs > 0 && now() - start > softDeadlineMs) {
6927
+ if (fullText.length > 0) {
6928
+ messages.push({
6929
+ role: "assistant",
6930
+ content: fullText,
6931
+ metadata: { timestamp: now(), id: randomUUID3(), step }
6932
+ });
6933
+ }
6541
6934
  const result_ = {
6542
6935
  status: "completed",
6543
6936
  response: responseText + fullText,
@@ -6777,7 +7170,7 @@ ${textContent}` };
6777
7170
  const raced = await Promise.race([
6778
7171
  this.dispatcher.executeBatch(approvedCalls, toolContext),
6779
7172
  new Promise(
6780
- (resolve12) => setTimeout(() => resolve12(TOOL_DEADLINE_SENTINEL), toolDeadlineRemainingMs)
7173
+ (resolve13) => setTimeout(() => resolve13(TOOL_DEADLINE_SENTINEL), toolDeadlineRemainingMs)
6781
7174
  )
6782
7175
  ]);
6783
7176
  if (raced === TOOL_DEADLINE_SENTINEL) {
@@ -6789,6 +7182,13 @@ ${textContent}` };
6789
7182
  batchResults = await this.dispatcher.executeBatch(approvedCalls, toolContext);
6790
7183
  }
6791
7184
  if (batchResults === TOOL_DEADLINE_SENTINEL) {
7185
+ if (fullText.length > 0) {
7186
+ messages.push({
7187
+ role: "assistant",
7188
+ content: fullText,
7189
+ metadata: { timestamp: now(), id: randomUUID3(), step }
7190
+ });
7191
+ }
6792
7192
  const result_ = {
6793
7193
  status: "completed",
6794
7194
  response: responseText + fullText,
@@ -7111,8 +7511,8 @@ var LatitudeCapture = class {
7111
7511
 
7112
7512
  // src/state.ts
7113
7513
  import { randomUUID as randomUUID4 } from "crypto";
7114
- import { mkdir as mkdir5, readFile as readFile9, readdir as readdir4, rename as rename3, rm as rm3, writeFile as writeFile6 } from "fs/promises";
7115
- import { dirname as dirname5, resolve as resolve11 } from "path";
7514
+ import { mkdir as mkdir6, readFile as readFile10, readdir as readdir4, rename as rename3, rm as rm4, writeFile as writeFile7 } from "fs/promises";
7515
+ import { dirname as dirname6, resolve as resolve12 } from "path";
7116
7516
  var DEFAULT_OWNER = "local-owner";
7117
7517
  var LOCAL_STATE_FILE = "state.json";
7118
7518
  var CONVERSATIONS_DIRECTORY = "conversations";
@@ -7128,9 +7528,9 @@ var toStoreIdentity = async ({
7128
7528
  return { name: ensured.name, id: agentId };
7129
7529
  };
7130
7530
  var writeJsonAtomic3 = async (filePath, payload) => {
7131
- await mkdir5(dirname5(filePath), { recursive: true });
7531
+ await mkdir6(dirname6(filePath), { recursive: true });
7132
7532
  const tmpPath = `${filePath}.tmp`;
7133
- await writeFile6(tmpPath, JSON.stringify(payload, null, 2), "utf8");
7533
+ await writeFile7(tmpPath, JSON.stringify(payload, null, 2), "utf8");
7134
7534
  await rename3(tmpPath, filePath);
7135
7535
  };
7136
7536
  var formatUtcTimestamp = (value) => new Date(value).toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
@@ -7319,8 +7719,8 @@ var FileConversationStore = class {
7319
7719
  agentId: this.agentId
7320
7720
  });
7321
7721
  const agentDir = getAgentStoreDirectory(identity);
7322
- const conversationsDir = resolve11(agentDir, CONVERSATIONS_DIRECTORY);
7323
- const indexPath = resolve11(conversationsDir, LOCAL_CONVERSATION_INDEX_FILE);
7722
+ const conversationsDir = resolve12(agentDir, CONVERSATIONS_DIRECTORY);
7723
+ const indexPath = resolve12(conversationsDir, LOCAL_CONVERSATION_INDEX_FILE);
7324
7724
  this.paths = { conversationsDir, indexPath };
7325
7725
  return this.paths;
7326
7726
  }
@@ -7334,9 +7734,9 @@ var FileConversationStore = class {
7334
7734
  }
7335
7735
  async readConversationFile(fileName) {
7336
7736
  const { conversationsDir } = await this.resolvePaths();
7337
- const filePath = resolve11(conversationsDir, fileName);
7737
+ const filePath = resolve12(conversationsDir, fileName);
7338
7738
  try {
7339
- const raw = await readFile9(filePath, "utf8");
7739
+ const raw = await readFile10(filePath, "utf8");
7340
7740
  return JSON.parse(raw);
7341
7741
  } catch {
7342
7742
  return void 0;
@@ -7382,7 +7782,7 @@ var FileConversationStore = class {
7382
7782
  this.loaded = true;
7383
7783
  const { indexPath } = await this.resolvePaths();
7384
7784
  try {
7385
- const raw = await readFile9(indexPath, "utf8");
7785
+ const raw = await readFile10(indexPath, "utf8");
7386
7786
  const parsed = JSON.parse(raw);
7387
7787
  for (const conversation of parsed.conversations ?? []) {
7388
7788
  this.conversations.set(conversation.conversationId, conversation);
@@ -7405,7 +7805,7 @@ var FileConversationStore = class {
7405
7805
  const { conversationsDir } = await this.resolvePaths();
7406
7806
  const existing = this.conversations.get(conversation.conversationId);
7407
7807
  const fileName = existing?.fileName ?? this.resolveConversationFileName(conversation);
7408
- const filePath = resolve11(conversationsDir, fileName);
7808
+ const filePath = resolve12(conversationsDir, fileName);
7409
7809
  this.writing = this.writing.then(async () => {
7410
7810
  await writeJsonAtomic3(filePath, conversation);
7411
7811
  this.conversations.set(conversation.conversationId, {
@@ -7503,7 +7903,7 @@ var FileConversationStore = class {
7503
7903
  if (removed) {
7504
7904
  this.writing = this.writing.then(async () => {
7505
7905
  if (existing) {
7506
- await rm3(resolve11(conversationsDir, existing.fileName), { force: true });
7906
+ await rm4(resolve12(conversationsDir, existing.fileName), { force: true });
7507
7907
  }
7508
7908
  await this.writeIndex();
7509
7909
  });
@@ -7525,7 +7925,7 @@ var FileConversationStore = class {
7525
7925
  const summary = this.conversations.get(conversationId);
7526
7926
  if (!summary) return void 0;
7527
7927
  const { conversationsDir } = await this.resolvePaths();
7528
- const filePath = resolve11(conversationsDir, summary.fileName);
7928
+ const filePath = resolve12(conversationsDir, summary.fileName);
7529
7929
  let result;
7530
7930
  this.writing = this.writing.then(async () => {
7531
7931
  const conv = await this.readConversationFile(summary.fileName);
@@ -7564,7 +7964,7 @@ var FileStateStore = class {
7564
7964
  workingDir: this.workingDir,
7565
7965
  agentId: this.agentId
7566
7966
  });
7567
- this.filePath = resolve11(getAgentStoreDirectory(identity), LOCAL_STATE_FILE);
7967
+ this.filePath = resolve12(getAgentStoreDirectory(identity), LOCAL_STATE_FILE);
7568
7968
  }
7569
7969
  isExpired(state) {
7570
7970
  return typeof this.ttlMs === "number" && Date.now() - state.updatedAt > this.ttlMs;
@@ -7576,7 +7976,7 @@ var FileStateStore = class {
7576
7976
  }
7577
7977
  this.loaded = true;
7578
7978
  try {
7579
- const raw = await readFile9(this.filePath, "utf8");
7979
+ const raw = await readFile10(this.filePath, "utf8");
7580
7980
  const parsed = JSON.parse(raw);
7581
7981
  for (const state of parsed.states ?? []) {
7582
7982
  this.states.set(state.runId, state);
@@ -8285,6 +8685,7 @@ export {
8285
8685
  LatitudeCapture,
8286
8686
  LocalMcpBridge,
8287
8687
  LocalUploadStore,
8688
+ OPENAI_CODEX_CLIENT_ID,
8288
8689
  PONCHO_UPLOAD_SCHEME,
8289
8690
  S3UploadStore,
8290
8691
  STORAGE_SCHEMA_VERSION,
@@ -8294,6 +8695,7 @@ export {
8294
8695
  buildAgentDirectoryName,
8295
8696
  buildSkillContextWindow,
8296
8697
  compactMessages,
8698
+ completeOpenAICodexDeviceAuth,
8297
8699
  createConversationStore,
8298
8700
  createDefaultTools,
8299
8701
  createDeleteDirectoryTool,
@@ -8309,6 +8711,7 @@ export {
8309
8711
  createUploadStore,
8310
8712
  createWriteTool,
8311
8713
  defineTool7 as defineTool,
8714
+ deleteOpenAICodexSession,
8312
8715
  deriveUploadKey,
8313
8716
  ensureAgentIdentity,
8314
8717
  estimateTokens,
@@ -8317,6 +8720,9 @@ export {
8317
8720
  generateAgentId,
8318
8721
  getAgentStoreDirectory,
8319
8722
  getModelContextWindow,
8723
+ getOpenAICodexAccessToken,
8724
+ getOpenAICodexAuthFilePath,
8725
+ getOpenAICodexRequiredScopes,
8320
8726
  getPonchoStoreRoot,
8321
8727
  jsonSchemaToZod,
8322
8728
  loadPonchoConfig,
@@ -8328,6 +8734,7 @@ export {
8328
8734
  parseAgentFile,
8329
8735
  parseAgentMarkdown,
8330
8736
  ponchoDocsTool,
8737
+ readOpenAICodexSession,
8331
8738
  readSkillResource,
8332
8739
  renderAgentPrompt,
8333
8740
  resolveAgentIdentity,
@@ -8335,5 +8742,7 @@ export {
8335
8742
  resolveMemoryConfig,
8336
8743
  resolveSkillDirs,
8337
8744
  resolveStateConfig,
8338
- slugifyStorageComponent
8745
+ slugifyStorageComponent,
8746
+ startOpenAICodexDeviceAuth,
8747
+ writeOpenAICodexSession
8339
8748
  };