@poncho-ai/harness 0.30.0 → 0.31.1
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 +19 -0
- package/dist/index.d.ts +41 -1
- package/dist/index.js +430 -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 +120 -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,42 @@ 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 OPENAI_CODEX_RESPONSES_URL = process.env.OPENAI_CODEX_RESPONSES_URL ?? "https://chatgpt.com/backend-api/codex/responses";
|
|
3891
|
+
var extractSystemInstructionFromInput = (input) => {
|
|
3892
|
+
if (!Array.isArray(input)) return void 0;
|
|
3893
|
+
for (const message of input) {
|
|
3894
|
+
if (!message || typeof message !== "object") continue;
|
|
3895
|
+
const candidate = message;
|
|
3896
|
+
if (candidate.role !== "system") continue;
|
|
3897
|
+
if (typeof candidate.content === "string" && candidate.content.trim().length > 0) {
|
|
3898
|
+
return candidate.content;
|
|
3899
|
+
}
|
|
3900
|
+
if (Array.isArray(candidate.content)) {
|
|
3901
|
+
const textParts = candidate.content.map((part) => {
|
|
3902
|
+
if (!part || typeof part !== "object") return "";
|
|
3903
|
+
const p = part;
|
|
3904
|
+
return typeof p.text === "string" ? p.text : "";
|
|
3905
|
+
}).filter((text) => text.trim().length > 0);
|
|
3906
|
+
if (textParts.length > 0) {
|
|
3907
|
+
return textParts.join("\n");
|
|
3908
|
+
}
|
|
3909
|
+
}
|
|
3910
|
+
}
|
|
3911
|
+
return void 0;
|
|
3912
|
+
};
|
|
3913
|
+
var normalizeToolParameterSchemas = (tools) => {
|
|
3914
|
+
if (!Array.isArray(tools)) return;
|
|
3915
|
+
for (const tool of tools) {
|
|
3916
|
+
if (!tool || typeof tool !== "object") continue;
|
|
3917
|
+
const entry = tool;
|
|
3918
|
+
if (!entry.parameters || typeof entry.parameters !== "object") continue;
|
|
3919
|
+
const schema = entry.parameters;
|
|
3920
|
+
if (schema.type === "object" && (typeof schema.properties !== "object" || schema.properties === null)) {
|
|
3921
|
+
schema.properties = {};
|
|
3922
|
+
}
|
|
3923
|
+
}
|
|
3924
|
+
};
|
|
3599
3925
|
var getModelContextWindow = (modelName) => {
|
|
3600
3926
|
if (MODEL_CONTEXT_WINDOWS[modelName] !== void 0) {
|
|
3601
3927
|
return MODEL_CONTEXT_WINDOWS[modelName];
|
|
@@ -3610,6 +3936,48 @@ var getModelContextWindow = (modelName) => {
|
|
|
3610
3936
|
};
|
|
3611
3937
|
var createModelProvider = (provider, config) => {
|
|
3612
3938
|
const normalized = (provider ?? "anthropic").toLowerCase();
|
|
3939
|
+
if (normalized === "openai-codex") {
|
|
3940
|
+
const openai = createOpenAI({
|
|
3941
|
+
apiKey: "oauth-placeholder",
|
|
3942
|
+
fetch: async (input, init) => {
|
|
3943
|
+
const { accessToken, accountId } = await getOpenAICodexAccessToken(config?.openaiCodex);
|
|
3944
|
+
const headers = new Headers(init?.headers);
|
|
3945
|
+
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
3946
|
+
headers.set("originator", "poncho");
|
|
3947
|
+
headers.set("User-Agent", "poncho/1.0");
|
|
3948
|
+
if (accountId) {
|
|
3949
|
+
headers.set("ChatGPT-Account-Id", accountId);
|
|
3950
|
+
}
|
|
3951
|
+
const originalUrl = input instanceof URL ? input.toString() : typeof input === "string" ? input : input.url;
|
|
3952
|
+
const parsed = new URL(originalUrl);
|
|
3953
|
+
const shouldRewrite = parsed.pathname.includes("/v1/responses") || parsed.pathname.includes("/chat/completions");
|
|
3954
|
+
const targetUrl = shouldRewrite ? OPENAI_CODEX_RESPONSES_URL : originalUrl;
|
|
3955
|
+
let body = init?.body;
|
|
3956
|
+
if (shouldRewrite && typeof body === "string" && headers.get("Content-Type")?.includes("application/json")) {
|
|
3957
|
+
try {
|
|
3958
|
+
const payload = JSON.parse(body);
|
|
3959
|
+
if (typeof payload.instructions !== "string" || payload.instructions.trim() === "") {
|
|
3960
|
+
payload.instructions = extractSystemInstructionFromInput(payload.input) ?? OPENAI_CODEX_DEFAULT_INSTRUCTIONS;
|
|
3961
|
+
}
|
|
3962
|
+
normalizeToolParameterSchemas(payload.tools);
|
|
3963
|
+
payload.store = false;
|
|
3964
|
+
body = JSON.stringify(payload);
|
|
3965
|
+
} catch {
|
|
3966
|
+
}
|
|
3967
|
+
}
|
|
3968
|
+
try {
|
|
3969
|
+
return await fetch(targetUrl, { ...init, headers, body });
|
|
3970
|
+
} catch (error) {
|
|
3971
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3972
|
+
if (shouldRewrite && targetUrl.includes("chatgpt.com") && message.includes("ENOTFOUND chatgpt.com")) {
|
|
3973
|
+
return fetch(originalUrl, { ...init, headers, body });
|
|
3974
|
+
}
|
|
3975
|
+
throw error;
|
|
3976
|
+
}
|
|
3977
|
+
}
|
|
3978
|
+
});
|
|
3979
|
+
return (modelName) => openai(modelName);
|
|
3980
|
+
}
|
|
3613
3981
|
if (normalized === "openai") {
|
|
3614
3982
|
const apiKeyEnv2 = config?.openai?.apiKeyEnv ?? "OPENAI_API_KEY";
|
|
3615
3983
|
const openai = createOpenAI({
|
|
@@ -3626,8 +3994,8 @@ var createModelProvider = (provider, config) => {
|
|
|
3626
3994
|
};
|
|
3627
3995
|
|
|
3628
3996
|
// src/skill-context.ts
|
|
3629
|
-
import { readFile as
|
|
3630
|
-
import { dirname as
|
|
3997
|
+
import { readFile as readFile8, readdir as readdir2, stat } from "fs/promises";
|
|
3998
|
+
import { dirname as dirname5, resolve as resolve9, normalize } from "path";
|
|
3631
3999
|
import YAML3 from "yaml";
|
|
3632
4000
|
var DEFAULT_SKILL_DIRS = ["skills"];
|
|
3633
4001
|
var resolveSkillDirs = (workingDir, extraPaths) => {
|
|
@@ -3639,7 +4007,7 @@ var resolveSkillDirs = (workingDir, extraPaths) => {
|
|
|
3639
4007
|
}
|
|
3640
4008
|
}
|
|
3641
4009
|
}
|
|
3642
|
-
return dirs.map((d) =>
|
|
4010
|
+
return dirs.map((d) => resolve9(workingDir, d));
|
|
3643
4011
|
};
|
|
3644
4012
|
var FRONTMATTER_PATTERN3 = /^---\s*\n([\s\S]*?)\n---\s*\n?([\s\S]*)$/;
|
|
3645
4013
|
var asRecord2 = (value) => typeof value === "object" && value !== null ? value : {};
|
|
@@ -3708,7 +4076,7 @@ var collectSkillManifests = async (directory) => {
|
|
|
3708
4076
|
const entries = await readdir2(directory, { withFileTypes: true });
|
|
3709
4077
|
const files = [];
|
|
3710
4078
|
for (const entry of entries) {
|
|
3711
|
-
const fullPath =
|
|
4079
|
+
const fullPath = resolve9(directory, entry.name);
|
|
3712
4080
|
let isDir = entry.isDirectory();
|
|
3713
4081
|
let isFile = entry.isFile();
|
|
3714
4082
|
if (entry.isSymbolicLink()) {
|
|
@@ -3743,13 +4111,13 @@ var loadSkillMetadata = async (workingDir, extraSkillPaths) => {
|
|
|
3743
4111
|
const seen = /* @__PURE__ */ new Set();
|
|
3744
4112
|
for (const manifest of allManifests) {
|
|
3745
4113
|
try {
|
|
3746
|
-
const content = await
|
|
4114
|
+
const content = await readFile8(manifest, "utf8");
|
|
3747
4115
|
const parsed = parseSkillFrontmatter(content);
|
|
3748
4116
|
if (parsed && !seen.has(parsed.name)) {
|
|
3749
4117
|
seen.add(parsed.name);
|
|
3750
4118
|
skills.push({
|
|
3751
4119
|
...parsed,
|
|
3752
|
-
skillDir:
|
|
4120
|
+
skillDir: dirname5(manifest),
|
|
3753
4121
|
skillPath: manifest
|
|
3754
4122
|
});
|
|
3755
4123
|
}
|
|
@@ -3788,7 +4156,7 @@ ${xmlSkills}
|
|
|
3788
4156
|
};
|
|
3789
4157
|
var escapeXml = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
3790
4158
|
var loadSkillInstructions = async (skill) => {
|
|
3791
|
-
const content = await
|
|
4159
|
+
const content = await readFile8(skill.skillPath, "utf8");
|
|
3792
4160
|
const match = content.match(FRONTMATTER_PATTERN3);
|
|
3793
4161
|
return match ? match[2].trim() : content.trim();
|
|
3794
4162
|
};
|
|
@@ -3797,11 +4165,11 @@ var readSkillResource = async (skill, relativePath) => {
|
|
|
3797
4165
|
if (normalized.startsWith("..") || normalized.startsWith("/")) {
|
|
3798
4166
|
throw new Error("Path must be relative and within the skill directory");
|
|
3799
4167
|
}
|
|
3800
|
-
const fullPath =
|
|
4168
|
+
const fullPath = resolve9(skill.skillDir, normalized);
|
|
3801
4169
|
if (!fullPath.startsWith(skill.skillDir)) {
|
|
3802
4170
|
throw new Error("Path escapes the skill directory");
|
|
3803
4171
|
}
|
|
3804
|
-
return await
|
|
4172
|
+
return await readFile8(fullPath, "utf8");
|
|
3805
4173
|
};
|
|
3806
4174
|
var MAX_INSTRUCTIONS_PER_SKILL = 1200;
|
|
3807
4175
|
var loadSkillContext = async (workingDir) => {
|
|
@@ -3920,7 +4288,7 @@ function convertSchema(schema) {
|
|
|
3920
4288
|
// src/skill-tools.ts
|
|
3921
4289
|
import { defineTool as defineTool4 } from "@poncho-ai/sdk";
|
|
3922
4290
|
import { access as access2, readdir as readdir3, stat as stat2 } from "fs/promises";
|
|
3923
|
-
import { extname, normalize as normalize2, resolve as
|
|
4291
|
+
import { extname, normalize as normalize2, resolve as resolve10, sep as sep2 } from "path";
|
|
3924
4292
|
import { pathToFileURL } from "url";
|
|
3925
4293
|
import { createJiti as createJiti2 } from "jiti";
|
|
3926
4294
|
var createSkillTools = (skills, options) => {
|
|
@@ -4178,7 +4546,7 @@ var collectScriptFiles = async (directory) => {
|
|
|
4178
4546
|
if (entry.name === "node_modules") {
|
|
4179
4547
|
continue;
|
|
4180
4548
|
}
|
|
4181
|
-
const fullPath =
|
|
4549
|
+
const fullPath = resolve10(directory, entry.name);
|
|
4182
4550
|
let isDir = entry.isDirectory();
|
|
4183
4551
|
let isFile = entry.isFile();
|
|
4184
4552
|
if (entry.isSymbolicLink()) {
|
|
@@ -4217,8 +4585,8 @@ var normalizeScriptPolicyPath = (relativePath) => {
|
|
|
4217
4585
|
};
|
|
4218
4586
|
var resolveScriptPath = (baseDir, relativePath, containmentDir) => {
|
|
4219
4587
|
const normalized = normalizeScriptPolicyPath(relativePath);
|
|
4220
|
-
const fullPath =
|
|
4221
|
-
const boundary =
|
|
4588
|
+
const fullPath = resolve10(baseDir, normalized);
|
|
4589
|
+
const boundary = resolve10(containmentDir ?? baseDir);
|
|
4222
4590
|
if (!fullPath.startsWith(`${boundary}${sep2}`) && fullPath !== boundary) {
|
|
4223
4591
|
throw new Error("Script path must stay inside the allowed directory");
|
|
4224
4592
|
}
|
|
@@ -4324,8 +4692,8 @@ function applyRateLimitCooldown(retryAfterHeader) {
|
|
|
4324
4692
|
async function runWithSearchThrottle(fn) {
|
|
4325
4693
|
const previous = searchQueue;
|
|
4326
4694
|
let release;
|
|
4327
|
-
searchQueue = new Promise((
|
|
4328
|
-
release =
|
|
4695
|
+
searchQueue = new Promise((resolve13) => {
|
|
4696
|
+
release = resolve13;
|
|
4329
4697
|
});
|
|
4330
4698
|
await previous.catch(() => {
|
|
4331
4699
|
});
|
|
@@ -5122,6 +5490,8 @@ export default {
|
|
|
5122
5490
|
providers: {
|
|
5123
5491
|
anthropic: { apiKeyEnv: "ANTHROPIC_API_KEY" },
|
|
5124
5492
|
openai: { apiKeyEnv: "OPENAI_API_KEY" },
|
|
5493
|
+
// openai-codex provider reads OAuth tokens from env vars by default:
|
|
5494
|
+
// openaiCodex: { refreshTokenEnv: "OPENAI_CODEX_REFRESH_TOKEN", accountIdEnv: "OPENAI_CODEX_ACCOUNT_ID" },
|
|
5125
5495
|
},
|
|
5126
5496
|
auth: {
|
|
5127
5497
|
required: true,
|
|
@@ -5524,8 +5894,8 @@ var AgentHarness = class _AgentHarness {
|
|
|
5524
5894
|
return false;
|
|
5525
5895
|
}
|
|
5526
5896
|
try {
|
|
5527
|
-
const agentFilePath =
|
|
5528
|
-
const rawContent = await
|
|
5897
|
+
const agentFilePath = resolve11(this.workingDir, "AGENT.md");
|
|
5898
|
+
const rawContent = await readFile9(agentFilePath, "utf8");
|
|
5529
5899
|
if (rawContent === this.agentFileFingerprint) {
|
|
5530
5900
|
return false;
|
|
5531
5901
|
}
|
|
@@ -5594,8 +5964,8 @@ var AgentHarness = class _AgentHarness {
|
|
|
5594
5964
|
}
|
|
5595
5965
|
}
|
|
5596
5966
|
async initialize() {
|
|
5597
|
-
const agentFilePath =
|
|
5598
|
-
const agentRawContent = await
|
|
5967
|
+
const agentFilePath = resolve11(this.workingDir, "AGENT.md");
|
|
5968
|
+
const agentRawContent = await readFile9(agentFilePath, "utf8");
|
|
5599
5969
|
this.parsedAgent = parseAgentMarkdown(agentRawContent);
|
|
5600
5970
|
this.agentFileFingerprint = agentRawContent;
|
|
5601
5971
|
const identity = await ensureAgentIdentity(this.workingDir);
|
|
@@ -5702,14 +6072,14 @@ var AgentHarness = class _AgentHarness {
|
|
|
5702
6072
|
const filePath = pathResolve(stateDir, `${sessionId}.json`);
|
|
5703
6073
|
return {
|
|
5704
6074
|
async save(json) {
|
|
5705
|
-
const { mkdir:
|
|
5706
|
-
await
|
|
5707
|
-
await
|
|
6075
|
+
const { mkdir: mkdir7, writeFile: writeFile8 } = await import("fs/promises");
|
|
6076
|
+
await mkdir7(stateDir, { recursive: true });
|
|
6077
|
+
await writeFile8(filePath, json, "utf8");
|
|
5708
6078
|
},
|
|
5709
6079
|
async load() {
|
|
5710
|
-
const { readFile:
|
|
6080
|
+
const { readFile: readFile11 } = await import("fs/promises");
|
|
5711
6081
|
try {
|
|
5712
|
-
return await
|
|
6082
|
+
return await readFile11(filePath, "utf8");
|
|
5713
6083
|
} catch {
|
|
5714
6084
|
return void 0;
|
|
5715
6085
|
}
|
|
@@ -5775,7 +6145,7 @@ var AgentHarness = class _AgentHarness {
|
|
|
5775
6145
|
let browserMod;
|
|
5776
6146
|
try {
|
|
5777
6147
|
const { existsSync } = await import("fs");
|
|
5778
|
-
const { join, dirname:
|
|
6148
|
+
const { join, dirname: dirname7 } = await import("path");
|
|
5779
6149
|
const { pathToFileURL: pathToFileURL2 } = await import("url");
|
|
5780
6150
|
let searchDir = this.workingDir;
|
|
5781
6151
|
let entryPath;
|
|
@@ -5785,7 +6155,7 @@ var AgentHarness = class _AgentHarness {
|
|
|
5785
6155
|
entryPath = candidate;
|
|
5786
6156
|
break;
|
|
5787
6157
|
}
|
|
5788
|
-
const parent =
|
|
6158
|
+
const parent = dirname7(searchDir);
|
|
5789
6159
|
if (parent === searchDir) break;
|
|
5790
6160
|
searchDir = parent;
|
|
5791
6161
|
}
|
|
@@ -5890,9 +6260,9 @@ var AgentHarness = class _AgentHarness {
|
|
|
5890
6260
|
for await (const event of this.run(input)) {
|
|
5891
6261
|
eventQueue.push(event);
|
|
5892
6262
|
if (queueResolve) {
|
|
5893
|
-
const
|
|
6263
|
+
const resolve13 = queueResolve;
|
|
5894
6264
|
queueResolve = null;
|
|
5895
|
-
|
|
6265
|
+
resolve13();
|
|
5896
6266
|
}
|
|
5897
6267
|
}
|
|
5898
6268
|
} catch (error) {
|
|
@@ -5911,8 +6281,8 @@ var AgentHarness = class _AgentHarness {
|
|
|
5911
6281
|
if (eventQueue.length > 0) {
|
|
5912
6282
|
yield eventQueue.shift();
|
|
5913
6283
|
} else if (!generatorDone) {
|
|
5914
|
-
await new Promise((
|
|
5915
|
-
queueResolve =
|
|
6284
|
+
await new Promise((resolve13) => {
|
|
6285
|
+
queueResolve = resolve13;
|
|
5916
6286
|
});
|
|
5917
6287
|
}
|
|
5918
6288
|
}
|
|
@@ -6504,8 +6874,8 @@ ${textContent}` };
|
|
|
6504
6874
|
let timer;
|
|
6505
6875
|
nextPart = await Promise.race([
|
|
6506
6876
|
fullStreamIterator.next(),
|
|
6507
|
-
new Promise((
|
|
6508
|
-
timer = setTimeout(() =>
|
|
6877
|
+
new Promise((resolve13) => {
|
|
6878
|
+
timer = setTimeout(() => resolve13(null), effectiveTimeout);
|
|
6509
6879
|
})
|
|
6510
6880
|
]);
|
|
6511
6881
|
clearTimeout(timer);
|
|
@@ -6822,7 +7192,7 @@ ${textContent}` };
|
|
|
6822
7192
|
const raced = await Promise.race([
|
|
6823
7193
|
this.dispatcher.executeBatch(approvedCalls, toolContext),
|
|
6824
7194
|
new Promise(
|
|
6825
|
-
(
|
|
7195
|
+
(resolve13) => setTimeout(() => resolve13(TOOL_DEADLINE_SENTINEL), toolDeadlineRemainingMs)
|
|
6826
7196
|
)
|
|
6827
7197
|
]);
|
|
6828
7198
|
if (raced === TOOL_DEADLINE_SENTINEL) {
|
|
@@ -7163,8 +7533,8 @@ var LatitudeCapture = class {
|
|
|
7163
7533
|
|
|
7164
7534
|
// src/state.ts
|
|
7165
7535
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
7166
|
-
import { mkdir as
|
|
7167
|
-
import { dirname as
|
|
7536
|
+
import { mkdir as mkdir6, readFile as readFile10, readdir as readdir4, rename as rename3, rm as rm4, writeFile as writeFile7 } from "fs/promises";
|
|
7537
|
+
import { dirname as dirname6, resolve as resolve12 } from "path";
|
|
7168
7538
|
var DEFAULT_OWNER = "local-owner";
|
|
7169
7539
|
var LOCAL_STATE_FILE = "state.json";
|
|
7170
7540
|
var CONVERSATIONS_DIRECTORY = "conversations";
|
|
@@ -7180,9 +7550,9 @@ var toStoreIdentity = async ({
|
|
|
7180
7550
|
return { name: ensured.name, id: agentId };
|
|
7181
7551
|
};
|
|
7182
7552
|
var writeJsonAtomic3 = async (filePath, payload) => {
|
|
7183
|
-
await
|
|
7553
|
+
await mkdir6(dirname6(filePath), { recursive: true });
|
|
7184
7554
|
const tmpPath = `${filePath}.tmp`;
|
|
7185
|
-
await
|
|
7555
|
+
await writeFile7(tmpPath, JSON.stringify(payload, null, 2), "utf8");
|
|
7186
7556
|
await rename3(tmpPath, filePath);
|
|
7187
7557
|
};
|
|
7188
7558
|
var formatUtcTimestamp = (value) => new Date(value).toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
@@ -7371,8 +7741,8 @@ var FileConversationStore = class {
|
|
|
7371
7741
|
agentId: this.agentId
|
|
7372
7742
|
});
|
|
7373
7743
|
const agentDir = getAgentStoreDirectory(identity);
|
|
7374
|
-
const conversationsDir =
|
|
7375
|
-
const indexPath =
|
|
7744
|
+
const conversationsDir = resolve12(agentDir, CONVERSATIONS_DIRECTORY);
|
|
7745
|
+
const indexPath = resolve12(conversationsDir, LOCAL_CONVERSATION_INDEX_FILE);
|
|
7376
7746
|
this.paths = { conversationsDir, indexPath };
|
|
7377
7747
|
return this.paths;
|
|
7378
7748
|
}
|
|
@@ -7386,9 +7756,9 @@ var FileConversationStore = class {
|
|
|
7386
7756
|
}
|
|
7387
7757
|
async readConversationFile(fileName) {
|
|
7388
7758
|
const { conversationsDir } = await this.resolvePaths();
|
|
7389
|
-
const filePath =
|
|
7759
|
+
const filePath = resolve12(conversationsDir, fileName);
|
|
7390
7760
|
try {
|
|
7391
|
-
const raw = await
|
|
7761
|
+
const raw = await readFile10(filePath, "utf8");
|
|
7392
7762
|
return JSON.parse(raw);
|
|
7393
7763
|
} catch {
|
|
7394
7764
|
return void 0;
|
|
@@ -7434,7 +7804,7 @@ var FileConversationStore = class {
|
|
|
7434
7804
|
this.loaded = true;
|
|
7435
7805
|
const { indexPath } = await this.resolvePaths();
|
|
7436
7806
|
try {
|
|
7437
|
-
const raw = await
|
|
7807
|
+
const raw = await readFile10(indexPath, "utf8");
|
|
7438
7808
|
const parsed = JSON.parse(raw);
|
|
7439
7809
|
for (const conversation of parsed.conversations ?? []) {
|
|
7440
7810
|
this.conversations.set(conversation.conversationId, conversation);
|
|
@@ -7457,7 +7827,7 @@ var FileConversationStore = class {
|
|
|
7457
7827
|
const { conversationsDir } = await this.resolvePaths();
|
|
7458
7828
|
const existing = this.conversations.get(conversation.conversationId);
|
|
7459
7829
|
const fileName = existing?.fileName ?? this.resolveConversationFileName(conversation);
|
|
7460
|
-
const filePath =
|
|
7830
|
+
const filePath = resolve12(conversationsDir, fileName);
|
|
7461
7831
|
this.writing = this.writing.then(async () => {
|
|
7462
7832
|
await writeJsonAtomic3(filePath, conversation);
|
|
7463
7833
|
this.conversations.set(conversation.conversationId, {
|
|
@@ -7555,7 +7925,7 @@ var FileConversationStore = class {
|
|
|
7555
7925
|
if (removed) {
|
|
7556
7926
|
this.writing = this.writing.then(async () => {
|
|
7557
7927
|
if (existing) {
|
|
7558
|
-
await
|
|
7928
|
+
await rm4(resolve12(conversationsDir, existing.fileName), { force: true });
|
|
7559
7929
|
}
|
|
7560
7930
|
await this.writeIndex();
|
|
7561
7931
|
});
|
|
@@ -7577,7 +7947,7 @@ var FileConversationStore = class {
|
|
|
7577
7947
|
const summary = this.conversations.get(conversationId);
|
|
7578
7948
|
if (!summary) return void 0;
|
|
7579
7949
|
const { conversationsDir } = await this.resolvePaths();
|
|
7580
|
-
const filePath =
|
|
7950
|
+
const filePath = resolve12(conversationsDir, summary.fileName);
|
|
7581
7951
|
let result;
|
|
7582
7952
|
this.writing = this.writing.then(async () => {
|
|
7583
7953
|
const conv = await this.readConversationFile(summary.fileName);
|
|
@@ -7616,7 +7986,7 @@ var FileStateStore = class {
|
|
|
7616
7986
|
workingDir: this.workingDir,
|
|
7617
7987
|
agentId: this.agentId
|
|
7618
7988
|
});
|
|
7619
|
-
this.filePath =
|
|
7989
|
+
this.filePath = resolve12(getAgentStoreDirectory(identity), LOCAL_STATE_FILE);
|
|
7620
7990
|
}
|
|
7621
7991
|
isExpired(state) {
|
|
7622
7992
|
return typeof this.ttlMs === "number" && Date.now() - state.updatedAt > this.ttlMs;
|
|
@@ -7628,7 +7998,7 @@ var FileStateStore = class {
|
|
|
7628
7998
|
}
|
|
7629
7999
|
this.loaded = true;
|
|
7630
8000
|
try {
|
|
7631
|
-
const raw = await
|
|
8001
|
+
const raw = await readFile10(this.filePath, "utf8");
|
|
7632
8002
|
const parsed = JSON.parse(raw);
|
|
7633
8003
|
for (const state of parsed.states ?? []) {
|
|
7634
8004
|
this.states.set(state.runId, state);
|
|
@@ -8337,6 +8707,7 @@ export {
|
|
|
8337
8707
|
LatitudeCapture,
|
|
8338
8708
|
LocalMcpBridge,
|
|
8339
8709
|
LocalUploadStore,
|
|
8710
|
+
OPENAI_CODEX_CLIENT_ID,
|
|
8340
8711
|
PONCHO_UPLOAD_SCHEME,
|
|
8341
8712
|
S3UploadStore,
|
|
8342
8713
|
STORAGE_SCHEMA_VERSION,
|
|
@@ -8346,6 +8717,7 @@ export {
|
|
|
8346
8717
|
buildAgentDirectoryName,
|
|
8347
8718
|
buildSkillContextWindow,
|
|
8348
8719
|
compactMessages,
|
|
8720
|
+
completeOpenAICodexDeviceAuth,
|
|
8349
8721
|
createConversationStore,
|
|
8350
8722
|
createDefaultTools,
|
|
8351
8723
|
createDeleteDirectoryTool,
|
|
@@ -8361,6 +8733,7 @@ export {
|
|
|
8361
8733
|
createUploadStore,
|
|
8362
8734
|
createWriteTool,
|
|
8363
8735
|
defineTool7 as defineTool,
|
|
8736
|
+
deleteOpenAICodexSession,
|
|
8364
8737
|
deriveUploadKey,
|
|
8365
8738
|
ensureAgentIdentity,
|
|
8366
8739
|
estimateTokens,
|
|
@@ -8369,6 +8742,9 @@ export {
|
|
|
8369
8742
|
generateAgentId,
|
|
8370
8743
|
getAgentStoreDirectory,
|
|
8371
8744
|
getModelContextWindow,
|
|
8745
|
+
getOpenAICodexAccessToken,
|
|
8746
|
+
getOpenAICodexAuthFilePath,
|
|
8747
|
+
getOpenAICodexRequiredScopes,
|
|
8372
8748
|
getPonchoStoreRoot,
|
|
8373
8749
|
jsonSchemaToZod,
|
|
8374
8750
|
loadPonchoConfig,
|
|
@@ -8380,6 +8756,7 @@ export {
|
|
|
8380
8756
|
parseAgentFile,
|
|
8381
8757
|
parseAgentMarkdown,
|
|
8382
8758
|
ponchoDocsTool,
|
|
8759
|
+
readOpenAICodexSession,
|
|
8383
8760
|
readSkillResource,
|
|
8384
8761
|
renderAgentPrompt,
|
|
8385
8762
|
resolveAgentIdentity,
|
|
@@ -8387,5 +8764,7 @@ export {
|
|
|
8387
8764
|
resolveMemoryConfig,
|
|
8388
8765
|
resolveSkillDirs,
|
|
8389
8766
|
resolveStateConfig,
|
|
8390
|
-
slugifyStorageComponent
|
|
8767
|
+
slugifyStorageComponent,
|
|
8768
|
+
startOpenAICodexDeviceAuth,
|
|
8769
|
+
writeOpenAICodexSession
|
|
8391
8770
|
};
|