@poncho-ai/harness 0.30.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/.turbo/turbo-build.log +5 -5
- package/.turbo/turbo-lint.log +6 -0
- package/.turbo/turbo-test.log +34 -0
- package/CHANGELOG.md +13 -0
- package/dist/index.d.ts +41 -1
- package/dist/index.js +408 -51
- package/package.json +2 -2
- package/src/agent-parser.ts +1 -1
- package/src/config.ts +7 -0
- package/src/harness.ts +2 -0
- package/src/index.ts +1 -0
- package/src/model-factory.ts +87 -0
- package/src/openai-codex-auth.ts +362 -0
- package/test/agent-parser.test.ts +12 -0
- package/test/model-factory.test.ts +12 -2
- package/test/openai-codex-auth.test.ts +82 -0
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
|
|
2068
|
-
import { resolve as
|
|
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
|
|
3630
|
-
import { dirname as
|
|
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) =>
|
|
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 =
|
|
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
|
|
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:
|
|
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, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
3790
4136
|
var loadSkillInstructions = async (skill) => {
|
|
3791
|
-
const content = await
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
4221
|
-
const boundary =
|
|
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((
|
|
4328
|
-
release =
|
|
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 =
|
|
5528
|
-
const rawContent = await
|
|
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 =
|
|
5598
|
-
const agentRawContent = await
|
|
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:
|
|
5706
|
-
await
|
|
5707
|
-
await
|
|
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:
|
|
6058
|
+
const { readFile: readFile11 } = await import("fs/promises");
|
|
5711
6059
|
try {
|
|
5712
|
-
return await
|
|
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:
|
|
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 =
|
|
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
|
|
6241
|
+
const resolve13 = queueResolve;
|
|
5894
6242
|
queueResolve = null;
|
|
5895
|
-
|
|
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((
|
|
5915
|
-
queueResolve =
|
|
6262
|
+
await new Promise((resolve13) => {
|
|
6263
|
+
queueResolve = resolve13;
|
|
5916
6264
|
});
|
|
5917
6265
|
}
|
|
5918
6266
|
}
|
|
@@ -6504,8 +6852,8 @@ ${textContent}` };
|
|
|
6504
6852
|
let timer;
|
|
6505
6853
|
nextPart = await Promise.race([
|
|
6506
6854
|
fullStreamIterator.next(),
|
|
6507
|
-
new Promise((
|
|
6508
|
-
timer = setTimeout(() =>
|
|
6855
|
+
new Promise((resolve13) => {
|
|
6856
|
+
timer = setTimeout(() => resolve13(null), effectiveTimeout);
|
|
6509
6857
|
})
|
|
6510
6858
|
]);
|
|
6511
6859
|
clearTimeout(timer);
|
|
@@ -6822,7 +7170,7 @@ ${textContent}` };
|
|
|
6822
7170
|
const raced = await Promise.race([
|
|
6823
7171
|
this.dispatcher.executeBatch(approvedCalls, toolContext),
|
|
6824
7172
|
new Promise(
|
|
6825
|
-
(
|
|
7173
|
+
(resolve13) => setTimeout(() => resolve13(TOOL_DEADLINE_SENTINEL), toolDeadlineRemainingMs)
|
|
6826
7174
|
)
|
|
6827
7175
|
]);
|
|
6828
7176
|
if (raced === TOOL_DEADLINE_SENTINEL) {
|
|
@@ -7163,8 +7511,8 @@ var LatitudeCapture = class {
|
|
|
7163
7511
|
|
|
7164
7512
|
// src/state.ts
|
|
7165
7513
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
7166
|
-
import { mkdir as
|
|
7167
|
-
import { dirname as
|
|
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";
|
|
7168
7516
|
var DEFAULT_OWNER = "local-owner";
|
|
7169
7517
|
var LOCAL_STATE_FILE = "state.json";
|
|
7170
7518
|
var CONVERSATIONS_DIRECTORY = "conversations";
|
|
@@ -7180,9 +7528,9 @@ var toStoreIdentity = async ({
|
|
|
7180
7528
|
return { name: ensured.name, id: agentId };
|
|
7181
7529
|
};
|
|
7182
7530
|
var writeJsonAtomic3 = async (filePath, payload) => {
|
|
7183
|
-
await
|
|
7531
|
+
await mkdir6(dirname6(filePath), { recursive: true });
|
|
7184
7532
|
const tmpPath = `${filePath}.tmp`;
|
|
7185
|
-
await
|
|
7533
|
+
await writeFile7(tmpPath, JSON.stringify(payload, null, 2), "utf8");
|
|
7186
7534
|
await rename3(tmpPath, filePath);
|
|
7187
7535
|
};
|
|
7188
7536
|
var formatUtcTimestamp = (value) => new Date(value).toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
@@ -7371,8 +7719,8 @@ var FileConversationStore = class {
|
|
|
7371
7719
|
agentId: this.agentId
|
|
7372
7720
|
});
|
|
7373
7721
|
const agentDir = getAgentStoreDirectory(identity);
|
|
7374
|
-
const conversationsDir =
|
|
7375
|
-
const indexPath =
|
|
7722
|
+
const conversationsDir = resolve12(agentDir, CONVERSATIONS_DIRECTORY);
|
|
7723
|
+
const indexPath = resolve12(conversationsDir, LOCAL_CONVERSATION_INDEX_FILE);
|
|
7376
7724
|
this.paths = { conversationsDir, indexPath };
|
|
7377
7725
|
return this.paths;
|
|
7378
7726
|
}
|
|
@@ -7386,9 +7734,9 @@ var FileConversationStore = class {
|
|
|
7386
7734
|
}
|
|
7387
7735
|
async readConversationFile(fileName) {
|
|
7388
7736
|
const { conversationsDir } = await this.resolvePaths();
|
|
7389
|
-
const filePath =
|
|
7737
|
+
const filePath = resolve12(conversationsDir, fileName);
|
|
7390
7738
|
try {
|
|
7391
|
-
const raw = await
|
|
7739
|
+
const raw = await readFile10(filePath, "utf8");
|
|
7392
7740
|
return JSON.parse(raw);
|
|
7393
7741
|
} catch {
|
|
7394
7742
|
return void 0;
|
|
@@ -7434,7 +7782,7 @@ var FileConversationStore = class {
|
|
|
7434
7782
|
this.loaded = true;
|
|
7435
7783
|
const { indexPath } = await this.resolvePaths();
|
|
7436
7784
|
try {
|
|
7437
|
-
const raw = await
|
|
7785
|
+
const raw = await readFile10(indexPath, "utf8");
|
|
7438
7786
|
const parsed = JSON.parse(raw);
|
|
7439
7787
|
for (const conversation of parsed.conversations ?? []) {
|
|
7440
7788
|
this.conversations.set(conversation.conversationId, conversation);
|
|
@@ -7457,7 +7805,7 @@ var FileConversationStore = class {
|
|
|
7457
7805
|
const { conversationsDir } = await this.resolvePaths();
|
|
7458
7806
|
const existing = this.conversations.get(conversation.conversationId);
|
|
7459
7807
|
const fileName = existing?.fileName ?? this.resolveConversationFileName(conversation);
|
|
7460
|
-
const filePath =
|
|
7808
|
+
const filePath = resolve12(conversationsDir, fileName);
|
|
7461
7809
|
this.writing = this.writing.then(async () => {
|
|
7462
7810
|
await writeJsonAtomic3(filePath, conversation);
|
|
7463
7811
|
this.conversations.set(conversation.conversationId, {
|
|
@@ -7555,7 +7903,7 @@ var FileConversationStore = class {
|
|
|
7555
7903
|
if (removed) {
|
|
7556
7904
|
this.writing = this.writing.then(async () => {
|
|
7557
7905
|
if (existing) {
|
|
7558
|
-
await
|
|
7906
|
+
await rm4(resolve12(conversationsDir, existing.fileName), { force: true });
|
|
7559
7907
|
}
|
|
7560
7908
|
await this.writeIndex();
|
|
7561
7909
|
});
|
|
@@ -7577,7 +7925,7 @@ var FileConversationStore = class {
|
|
|
7577
7925
|
const summary = this.conversations.get(conversationId);
|
|
7578
7926
|
if (!summary) return void 0;
|
|
7579
7927
|
const { conversationsDir } = await this.resolvePaths();
|
|
7580
|
-
const filePath =
|
|
7928
|
+
const filePath = resolve12(conversationsDir, summary.fileName);
|
|
7581
7929
|
let result;
|
|
7582
7930
|
this.writing = this.writing.then(async () => {
|
|
7583
7931
|
const conv = await this.readConversationFile(summary.fileName);
|
|
@@ -7616,7 +7964,7 @@ var FileStateStore = class {
|
|
|
7616
7964
|
workingDir: this.workingDir,
|
|
7617
7965
|
agentId: this.agentId
|
|
7618
7966
|
});
|
|
7619
|
-
this.filePath =
|
|
7967
|
+
this.filePath = resolve12(getAgentStoreDirectory(identity), LOCAL_STATE_FILE);
|
|
7620
7968
|
}
|
|
7621
7969
|
isExpired(state) {
|
|
7622
7970
|
return typeof this.ttlMs === "number" && Date.now() - state.updatedAt > this.ttlMs;
|
|
@@ -7628,7 +7976,7 @@ var FileStateStore = class {
|
|
|
7628
7976
|
}
|
|
7629
7977
|
this.loaded = true;
|
|
7630
7978
|
try {
|
|
7631
|
-
const raw = await
|
|
7979
|
+
const raw = await readFile10(this.filePath, "utf8");
|
|
7632
7980
|
const parsed = JSON.parse(raw);
|
|
7633
7981
|
for (const state of parsed.states ?? []) {
|
|
7634
7982
|
this.states.set(state.runId, state);
|
|
@@ -8337,6 +8685,7 @@ export {
|
|
|
8337
8685
|
LatitudeCapture,
|
|
8338
8686
|
LocalMcpBridge,
|
|
8339
8687
|
LocalUploadStore,
|
|
8688
|
+
OPENAI_CODEX_CLIENT_ID,
|
|
8340
8689
|
PONCHO_UPLOAD_SCHEME,
|
|
8341
8690
|
S3UploadStore,
|
|
8342
8691
|
STORAGE_SCHEMA_VERSION,
|
|
@@ -8346,6 +8695,7 @@ export {
|
|
|
8346
8695
|
buildAgentDirectoryName,
|
|
8347
8696
|
buildSkillContextWindow,
|
|
8348
8697
|
compactMessages,
|
|
8698
|
+
completeOpenAICodexDeviceAuth,
|
|
8349
8699
|
createConversationStore,
|
|
8350
8700
|
createDefaultTools,
|
|
8351
8701
|
createDeleteDirectoryTool,
|
|
@@ -8361,6 +8711,7 @@ export {
|
|
|
8361
8711
|
createUploadStore,
|
|
8362
8712
|
createWriteTool,
|
|
8363
8713
|
defineTool7 as defineTool,
|
|
8714
|
+
deleteOpenAICodexSession,
|
|
8364
8715
|
deriveUploadKey,
|
|
8365
8716
|
ensureAgentIdentity,
|
|
8366
8717
|
estimateTokens,
|
|
@@ -8369,6 +8720,9 @@ export {
|
|
|
8369
8720
|
generateAgentId,
|
|
8370
8721
|
getAgentStoreDirectory,
|
|
8371
8722
|
getModelContextWindow,
|
|
8723
|
+
getOpenAICodexAccessToken,
|
|
8724
|
+
getOpenAICodexAuthFilePath,
|
|
8725
|
+
getOpenAICodexRequiredScopes,
|
|
8372
8726
|
getPonchoStoreRoot,
|
|
8373
8727
|
jsonSchemaToZod,
|
|
8374
8728
|
loadPonchoConfig,
|
|
@@ -8380,6 +8734,7 @@ export {
|
|
|
8380
8734
|
parseAgentFile,
|
|
8381
8735
|
parseAgentMarkdown,
|
|
8382
8736
|
ponchoDocsTool,
|
|
8737
|
+
readOpenAICodexSession,
|
|
8383
8738
|
readSkillResource,
|
|
8384
8739
|
renderAgentPrompt,
|
|
8385
8740
|
resolveAgentIdentity,
|
|
@@ -8387,5 +8742,7 @@ export {
|
|
|
8387
8742
|
resolveMemoryConfig,
|
|
8388
8743
|
resolveSkillDirs,
|
|
8389
8744
|
resolveStateConfig,
|
|
8390
|
-
slugifyStorageComponent
|
|
8745
|
+
slugifyStorageComponent,
|
|
8746
|
+
startOpenAICodexDeviceAuth,
|
|
8747
|
+
writeOpenAICodexSession
|
|
8391
8748
|
};
|