replicas-engine 0.1.673 → 0.1.676
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/src/{chunk-5NBVP6A2.js → chunk-OLZ7JWCU.js} +741 -199
- package/dist/src/headless-agent.js +48 -49
- package/dist/src/index.js +757 -244
- package/package.json +1 -1
- package/dist/src/app-server-process-EVCFSBVG.js +0 -10
- package/dist/src/chunk-2CFOJHNH.js +0 -162
- package/dist/src/chunk-A2ZICXOK.js +0 -407
- package/dist/src/chunk-CKJJIOSE.js +0 -448
- package/dist/src/chunk-XQW4B35Y.js +0 -108
- package/dist/src/codex-token-manager-VIZLBLS2.js +0 -13
- package/dist/src/engine-env-3AQ2O2WZ.js +0 -14
package/package.json
CHANGED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
REPLICAS_RUNTIME_ENV_ALIASES,
|
|
4
|
-
agentCredentialSnapshotSchema,
|
|
5
|
-
isValidAgentProvider,
|
|
6
|
-
parsePosixEnvFile,
|
|
7
|
-
readReplicasRuntimeEnv
|
|
8
|
-
} from "./chunk-5NBVP6A2.js";
|
|
9
|
-
|
|
10
|
-
// src/engine-env.ts
|
|
11
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
12
|
-
import { homedir as homedir2 } from "os";
|
|
13
|
-
import { join as join2 } from "path";
|
|
14
|
-
|
|
15
|
-
// src/runtime-env-loader.ts
|
|
16
|
-
import { readFileSync } from "fs";
|
|
17
|
-
import { homedir } from "os";
|
|
18
|
-
import { join } from "path";
|
|
19
|
-
function loadRuntimeEnvFile() {
|
|
20
|
-
let content;
|
|
21
|
-
try {
|
|
22
|
-
content = readFileSync(join(homedir(), ".replicas", "runtime-env.sh"), "utf-8");
|
|
23
|
-
} catch {
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
for (const [key, value] of Object.entries(parsePosixEnvFile(content))) {
|
|
27
|
-
process.env[key] = value;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// src/utils/type-guards.ts
|
|
32
|
-
function isRecord(value) {
|
|
33
|
-
return typeof value === "object" && value !== null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// src/engine-env.ts
|
|
37
|
-
var SANDBOX_IMAGE_VERSION_FILE = "/usr/local/lib/replicas-sandbox-image-version";
|
|
38
|
-
function readEnv(name) {
|
|
39
|
-
const value = process.env[name]?.trim();
|
|
40
|
-
return value ? value : void 0;
|
|
41
|
-
}
|
|
42
|
-
function readSandboxImageVersion() {
|
|
43
|
-
const environmentVersion = readEnv("REPLICAS_SANDBOX_IMAGE_VERSION");
|
|
44
|
-
if (environmentVersion) return environmentVersion;
|
|
45
|
-
try {
|
|
46
|
-
return readFileSync2(SANDBOX_IMAGE_VERSION_FILE, "utf8").trim() || "development";
|
|
47
|
-
} catch {
|
|
48
|
-
return "development";
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
function parsePort(value) {
|
|
52
|
-
if (!value) {
|
|
53
|
-
return 3737;
|
|
54
|
-
}
|
|
55
|
-
const parsed = Number(value);
|
|
56
|
-
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
57
|
-
throw new Error("Invalid engine environment: REPLICAS_ENGINE_PORT must be a positive integer");
|
|
58
|
-
}
|
|
59
|
-
return parsed;
|
|
60
|
-
}
|
|
61
|
-
function requireDefined(value, name) {
|
|
62
|
-
if (value === void 0 || value === null) {
|
|
63
|
-
throw new Error(`Invalid engine environment: ${name} is required`);
|
|
64
|
-
}
|
|
65
|
-
return value;
|
|
66
|
-
}
|
|
67
|
-
function requireValidURL(value, name) {
|
|
68
|
-
try {
|
|
69
|
-
new URL(value);
|
|
70
|
-
return value;
|
|
71
|
-
} catch {
|
|
72
|
-
throw new Error(`Invalid engine environment: ${name} must be a valid URL`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
function parseClaudeAuthMethod(value) {
|
|
76
|
-
if (value === "oauth" || value === "api_key" || value === "bedrock" || value === "foundry") {
|
|
77
|
-
return value;
|
|
78
|
-
}
|
|
79
|
-
return void 0;
|
|
80
|
-
}
|
|
81
|
-
function parseCodexAuthMethod(value) {
|
|
82
|
-
if (value === "oauth" || value === "api_key" || value === "foundry") {
|
|
83
|
-
return value;
|
|
84
|
-
}
|
|
85
|
-
return void 0;
|
|
86
|
-
}
|
|
87
|
-
function parseAgentCredentialSnapshots(value) {
|
|
88
|
-
if (!value) return {};
|
|
89
|
-
try {
|
|
90
|
-
const parsed = JSON.parse(value);
|
|
91
|
-
if (!isRecord(parsed)) return {};
|
|
92
|
-
const snapshots = {};
|
|
93
|
-
for (const [provider, snapshot] of Object.entries(parsed)) {
|
|
94
|
-
if (!isValidAgentProvider(provider)) continue;
|
|
95
|
-
const parsedSnapshot = agentCredentialSnapshotSchema.safeParse(snapshot);
|
|
96
|
-
if (parsedSnapshot.success) snapshots[provider] = parsedSnapshot.data;
|
|
97
|
-
}
|
|
98
|
-
return snapshots;
|
|
99
|
-
} catch {
|
|
100
|
-
return {};
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
var IS_WARMING_MODE = process.argv.includes("--warming");
|
|
104
|
-
function loadEngineEnv() {
|
|
105
|
-
loadRuntimeEnvFile();
|
|
106
|
-
const HOME_DIR = homedir2();
|
|
107
|
-
const env = {
|
|
108
|
-
// Defined: always available
|
|
109
|
-
REPLICAS_ENGINE_SECRET: requireDefined(readEnv("REPLICAS_ENGINE_SECRET"), "REPLICAS_ENGINE_SECRET"),
|
|
110
|
-
REPLICAS_ENGINE_PORT: parsePort(readEnv("REPLICAS_ENGINE_PORT")),
|
|
111
|
-
REPLICAS_MONOLITH_URL: requireValidURL(
|
|
112
|
-
requireDefined(readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.monolithUrl), "REPLICAS_MONOLITH_URL"),
|
|
113
|
-
"REPLICAS_MONOLITH_URL"
|
|
114
|
-
),
|
|
115
|
-
HOME_DIR,
|
|
116
|
-
WORKSPACE_ROOT: join2(HOME_DIR, "workspaces"),
|
|
117
|
-
REPLICAS_SANDBOX_IMAGE_VERSION: readSandboxImageVersion(),
|
|
118
|
-
// Runtime: may not be set during warming
|
|
119
|
-
REPLICAS_WORKSPACE_ID: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.workspaceId),
|
|
120
|
-
REPLICAS_LINEAR_SESSION_ID: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.linearSessionId),
|
|
121
|
-
REPLICAS_LINEAR_ACCESS_TOKEN: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.linearAccessToken),
|
|
122
|
-
REPLICAS_SLACK_BOT_TOKEN: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.slackBotToken),
|
|
123
|
-
REPLICAS_SLACK_CHANNEL_ID: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.slackChannelId),
|
|
124
|
-
REPLICAS_SLACK_THREAD_TS: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.slackThreadTs),
|
|
125
|
-
ANTHROPIC_API_KEY: readEnv("ANTHROPIC_API_KEY"),
|
|
126
|
-
OPENAI_API_KEY: readEnv("OPENAI_API_KEY"),
|
|
127
|
-
CURSOR_API_KEY: readEnv("CURSOR_API_KEY"),
|
|
128
|
-
AI_GATEWAY_API_KEY: readEnv("AI_GATEWAY_API_KEY"),
|
|
129
|
-
CLAUDE_CODE_USE_BEDROCK: readEnv("CLAUDE_CODE_USE_BEDROCK"),
|
|
130
|
-
AWS_ACCESS_KEY_ID: readEnv("AWS_ACCESS_KEY_ID"),
|
|
131
|
-
AWS_SECRET_ACCESS_KEY: readEnv("AWS_SECRET_ACCESS_KEY"),
|
|
132
|
-
AWS_REGION: readEnv("AWS_REGION"),
|
|
133
|
-
ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION: readEnv("ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION"),
|
|
134
|
-
REPLICAS_CLAUDE_AUTH_METHOD: parseClaudeAuthMethod(readEnv("REPLICAS_CLAUDE_AUTH_METHOD")),
|
|
135
|
-
REPLICAS_CODEX_AUTH_METHOD: parseCodexAuthMethod(readEnv("REPLICAS_CODEX_AUTH_METHOD")),
|
|
136
|
-
REPLICAS_AGENT_CREDENTIALS: parseAgentCredentialSnapshots(readEnv("REPLICAS_AGENT_CREDENTIALS")),
|
|
137
|
-
REPLICAS_ENV_SYSTEM_PROMPT: readEnv("REPLICAS_ENV_SYSTEM_PROMPT"),
|
|
138
|
-
REPLICAS_ENV_START_HOOK: readEnv("REPLICAS_ENV_START_HOOK"),
|
|
139
|
-
REPLICAS_DISABLE_AUTO_START_HOOKS: readEnv("REPLICAS_DISABLE_AUTO_START_HOOKS")?.toLowerCase() === "true",
|
|
140
|
-
REPLICAS_ENGINE_DEFER_INITIALIZATION: readEnv("REPLICAS_ENGINE_DEFER_INITIALIZATION")?.toLowerCase() === "true"
|
|
141
|
-
};
|
|
142
|
-
if (!IS_WARMING_MODE && !env.REPLICAS_WORKSPACE_ID) {
|
|
143
|
-
console.error("REPLICAS_WORKSPACE_ID is not set \u2014 this is required in normal (non-warming) mode");
|
|
144
|
-
}
|
|
145
|
-
return env;
|
|
146
|
-
}
|
|
147
|
-
var ENGINE_ENV = loadEngineEnv();
|
|
148
|
-
function setAgentCredentialSnapshot(provider, snapshot) {
|
|
149
|
-
ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS = {
|
|
150
|
-
...ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS,
|
|
151
|
-
[provider]: snapshot
|
|
152
|
-
};
|
|
153
|
-
process.env.REPLICAS_AGENT_CREDENTIALS = JSON.stringify(ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export {
|
|
157
|
-
isRecord,
|
|
158
|
-
IS_WARMING_MODE,
|
|
159
|
-
loadEngineEnv,
|
|
160
|
-
ENGINE_ENV,
|
|
161
|
-
setAgentCredentialSnapshot
|
|
162
|
-
};
|
|
@@ -1,407 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
ENGINE_ENV,
|
|
4
|
-
setAgentCredentialSnapshot
|
|
5
|
-
} from "./chunk-2CFOJHNH.js";
|
|
6
|
-
import {
|
|
7
|
-
CODEX_AUTH_ENV_KEYS,
|
|
8
|
-
CODEX_AUTH_ENV_KEYS_BY_METHOD,
|
|
9
|
-
codexAuthEnvFromResponse,
|
|
10
|
-
createErrorResult,
|
|
11
|
-
createSuccessResult,
|
|
12
|
-
isRecord,
|
|
13
|
-
isValidAgentProvider
|
|
14
|
-
} from "./chunk-5NBVP6A2.js";
|
|
15
|
-
|
|
16
|
-
// src/managers/codex-token-manager.ts
|
|
17
|
-
import { promises as fs } from "fs";
|
|
18
|
-
import path from "path";
|
|
19
|
-
|
|
20
|
-
// src/managers/auth-env-transition.ts
|
|
21
|
-
function applyAuthEnvTransition(params) {
|
|
22
|
-
const newOwned = new Set(params.authKeysByMethod[params.newMethod]);
|
|
23
|
-
const prevOwned = new Set(params.authKeysByMethod[params.prevMethod]);
|
|
24
|
-
for (const key of params.authKeys) {
|
|
25
|
-
const value = params.newEnvVars[key];
|
|
26
|
-
if (value !== void 0) {
|
|
27
|
-
for (const env of params.envs) {
|
|
28
|
-
env[key] = value;
|
|
29
|
-
}
|
|
30
|
-
} else if (prevOwned.has(key) && !newOwned.has(key)) {
|
|
31
|
-
for (const env of params.envs) {
|
|
32
|
-
delete env[key];
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// src/services/credential-fallbacks.ts
|
|
39
|
-
var fallbacksByAgent = /* @__PURE__ */ new Map();
|
|
40
|
-
var exhaustedByAgent = /* @__PURE__ */ new Map();
|
|
41
|
-
function recordCredentialFallback(notice) {
|
|
42
|
-
fallbacksByAgent.set(notice.provider, notice);
|
|
43
|
-
}
|
|
44
|
-
function listCredentialFallbacks() {
|
|
45
|
-
return [...fallbacksByAgent.values()].filter((notice) => {
|
|
46
|
-
const live = ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS[notice.provider];
|
|
47
|
-
if (!live) return false;
|
|
48
|
-
return notice.status === "switched" ? live.method === notice.candidateMethod && live.scope === notice.candidateScope : live.method === notice.exhaustedMethod && live.scope === notice.exhaustedScope;
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
function listExhaustedCredentials(provider) {
|
|
52
|
-
return [...exhaustedByAgent.get(provider)?.values() ?? []];
|
|
53
|
-
}
|
|
54
|
-
function recordExhaustedCredential(provider, credential) {
|
|
55
|
-
const spent = exhaustedByAgent.get(provider) ?? /* @__PURE__ */ new Map();
|
|
56
|
-
spent.set(`${credential.method}|${credential.scope}`, credential);
|
|
57
|
-
exhaustedByAgent.set(provider, spent);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// src/managers/base-refresh-manager.ts
|
|
61
|
-
var BaseRefreshManager = class {
|
|
62
|
-
constructor(managerName, intervalMs = 15 * 60 * 1e3) {
|
|
63
|
-
this.managerName = managerName;
|
|
64
|
-
this.intervalMs = intervalMs;
|
|
65
|
-
this.health = {
|
|
66
|
-
isRunning: false,
|
|
67
|
-
intervalMs: this.intervalMs,
|
|
68
|
-
lastAttemptAt: null,
|
|
69
|
-
lastSuccessAt: null,
|
|
70
|
-
lastErrorAt: null,
|
|
71
|
-
lastErrorMessage: null
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
managerName;
|
|
75
|
-
intervalMs;
|
|
76
|
-
intervalHandle = null;
|
|
77
|
-
health;
|
|
78
|
-
async start() {
|
|
79
|
-
if (this.intervalHandle) {
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
const skipReason = this.getSkipReason();
|
|
83
|
-
if (skipReason) {
|
|
84
|
-
console.log(`[${this.managerName}] Skipping: ${skipReason}`);
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
console.log(`[${this.managerName}] Starting token refresh service`);
|
|
88
|
-
this.health.isRunning = true;
|
|
89
|
-
const config = this.getRuntimeConfig();
|
|
90
|
-
if (config) {
|
|
91
|
-
this.health.lastAttemptAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
92
|
-
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
93
|
-
try {
|
|
94
|
-
await this.doRefresh(config);
|
|
95
|
-
this.health.lastSuccessAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
96
|
-
this.health.lastErrorAt = null;
|
|
97
|
-
this.health.lastErrorMessage = null;
|
|
98
|
-
break;
|
|
99
|
-
} catch (error) {
|
|
100
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
101
|
-
this.health.lastErrorAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
102
|
-
this.health.lastErrorMessage = message;
|
|
103
|
-
if (attempt < 3) {
|
|
104
|
-
console.warn(`[${this.managerName}] Initial refresh attempt ${attempt} failed, retrying in 2s...`);
|
|
105
|
-
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
106
|
-
} else {
|
|
107
|
-
console.error(`[${this.managerName}] Initial refresh failed after 3 attempts:`, error);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
this.scheduleNextRefresh();
|
|
113
|
-
}
|
|
114
|
-
async swapCredentials(params) {
|
|
115
|
-
if (!this.getRuntimeConfig()) {
|
|
116
|
-
return createErrorResult({ message: `${this.managerName} has no runtime config`, code: "not_configured" });
|
|
117
|
-
}
|
|
118
|
-
try {
|
|
119
|
-
console.log(`[${this.managerName}] Fetching fresh credentials from monolith (${params.failureKind})...`);
|
|
120
|
-
const excludeCredentials = listExhaustedCredentials(params.provider);
|
|
121
|
-
await params.refresh(excludeCredentials.length > 0 ? { excludeCredentials } : {});
|
|
122
|
-
if (params.isOauthNow()) {
|
|
123
|
-
this.start().catch((error) => {
|
|
124
|
-
console.error(`[${this.managerName}] Failed to restart OAuth refresh service after fallback:`, error);
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
return createSuccessResult();
|
|
128
|
-
} catch (error) {
|
|
129
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
130
|
-
console.error(`[${this.managerName}] Failed to fetch fresh credentials:`, error);
|
|
131
|
-
return createErrorResult({
|
|
132
|
-
message,
|
|
133
|
-
code: message.includes('"code":"no_credentials"') ? "no_credentials" : "refresh_failed"
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
stop() {
|
|
138
|
-
if (!this.intervalHandle) {
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
clearTimeout(this.intervalHandle);
|
|
142
|
-
this.intervalHandle = null;
|
|
143
|
-
this.health.isRunning = false;
|
|
144
|
-
console.log(`[${this.managerName}] Stopped`);
|
|
145
|
-
}
|
|
146
|
-
getHealthStatus() {
|
|
147
|
-
return { ...this.health };
|
|
148
|
-
}
|
|
149
|
-
getSkipReason() {
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
getNextRefreshDelayMs() {
|
|
153
|
-
return this.intervalMs;
|
|
154
|
-
}
|
|
155
|
-
getRuntimeConfig() {
|
|
156
|
-
if (!ENGINE_ENV.REPLICAS_WORKSPACE_ID) {
|
|
157
|
-
return null;
|
|
158
|
-
}
|
|
159
|
-
return {
|
|
160
|
-
monolithUrl: ENGINE_ENV.REPLICAS_MONOLITH_URL,
|
|
161
|
-
workspaceId: ENGINE_ENV.REPLICAS_WORKSPACE_ID,
|
|
162
|
-
engineSecret: ENGINE_ENV.REPLICAS_ENGINE_SECRET
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
scheduleNextRefresh() {
|
|
166
|
-
const delayMs = this.getNextRefreshDelayMs();
|
|
167
|
-
this.health.intervalMs = delayMs;
|
|
168
|
-
this.intervalHandle = setTimeout(async () => {
|
|
169
|
-
await this.refreshOnce();
|
|
170
|
-
if (this.intervalHandle) this.scheduleNextRefresh();
|
|
171
|
-
}, delayMs);
|
|
172
|
-
console.log(`[${this.managerName}] Token refresh scheduled in ${Math.round(delayMs / 1e3)} seconds`);
|
|
173
|
-
}
|
|
174
|
-
async refreshOnce() {
|
|
175
|
-
if (this.getSkipReason()) {
|
|
176
|
-
return createSuccessResult();
|
|
177
|
-
}
|
|
178
|
-
const config = this.getRuntimeConfig();
|
|
179
|
-
if (!config) return createSuccessResult();
|
|
180
|
-
this.health.lastAttemptAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
181
|
-
try {
|
|
182
|
-
await this.doRefresh(config);
|
|
183
|
-
this.health.lastSuccessAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
184
|
-
this.health.lastErrorAt = null;
|
|
185
|
-
this.health.lastErrorMessage = null;
|
|
186
|
-
return createSuccessResult();
|
|
187
|
-
} catch (error) {
|
|
188
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
189
|
-
this.health.lastErrorAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
190
|
-
this.health.lastErrorMessage = message;
|
|
191
|
-
console.error(`[${this.managerName}] Failed to refresh credentials:`, error);
|
|
192
|
-
return createErrorResult({ message });
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
// src/services/monolith-service.ts
|
|
198
|
-
async function monolithRequest(path2, init = {}) {
|
|
199
|
-
if (!ENGINE_ENV.REPLICAS_WORKSPACE_ID) {
|
|
200
|
-
throw new Error("REPLICAS_WORKSPACE_ID is not set; cannot call monolith");
|
|
201
|
-
}
|
|
202
|
-
const headers = {
|
|
203
|
-
Authorization: `Bearer ${ENGINE_ENV.REPLICAS_ENGINE_SECRET}`,
|
|
204
|
-
"X-Workspace-Id": ENGINE_ENV.REPLICAS_WORKSPACE_ID
|
|
205
|
-
};
|
|
206
|
-
if (!(init.body instanceof FormData)) headers["Content-Type"] = "application/json";
|
|
207
|
-
return fetch(`${ENGINE_ENV.REPLICAS_MONOLITH_URL}${path2}`, {
|
|
208
|
-
method: init.method ?? "POST",
|
|
209
|
-
headers,
|
|
210
|
-
body: init.body === void 0 ? void 0 : init.body instanceof FormData ? init.body : JSON.stringify(init.body),
|
|
211
|
-
signal: init.signal
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
var MonolithService = class {
|
|
215
|
-
async getRelaySubagentProviders() {
|
|
216
|
-
try {
|
|
217
|
-
const response = await monolithRequest("/v1/engine/relay-subagent-providers", { method: "GET" });
|
|
218
|
-
if (!response.ok) {
|
|
219
|
-
return null;
|
|
220
|
-
}
|
|
221
|
-
const body = await response.json();
|
|
222
|
-
return isRecord(body) && Array.isArray(body.providers) && body.providers.every((provider) => typeof provider === "string" && isValidAgentProvider(provider)) ? body.providers : null;
|
|
223
|
-
} catch {
|
|
224
|
-
return null;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
async getOpenRouterModels() {
|
|
228
|
-
try {
|
|
229
|
-
const response = await monolithRequest("/v1/engine/openrouter-models", { method: "GET" });
|
|
230
|
-
if (!response.ok) {
|
|
231
|
-
return null;
|
|
232
|
-
}
|
|
233
|
-
const body = await response.json();
|
|
234
|
-
return isRecord(body) && Array.isArray(body.models) && body.models.every((model) => typeof model === "string") ? body.models : null;
|
|
235
|
-
} catch {
|
|
236
|
-
return null;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
async sendEvent(event) {
|
|
240
|
-
if (!ENGINE_ENV.REPLICAS_WORKSPACE_ID) {
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
try {
|
|
244
|
-
const response = await monolithRequest("/v1/engine/webhook", { body: event });
|
|
245
|
-
if (!response.ok) {
|
|
246
|
-
const errorText = await response.text();
|
|
247
|
-
console.error(`[MonolithService] Failed to send event: ${response.status} ${errorText}`);
|
|
248
|
-
}
|
|
249
|
-
} catch (error) {
|
|
250
|
-
console.error("[MonolithService] Failed to send event:", error);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
var monolithService = new MonolithService();
|
|
255
|
-
|
|
256
|
-
// src/managers/codex-token-manager.ts
|
|
257
|
-
var CodexAspAuthMethodChangedError = class extends Error {
|
|
258
|
-
};
|
|
259
|
-
var CodexTokenManager = class extends BaseRefreshManager {
|
|
260
|
-
constructor() {
|
|
261
|
-
super("CodexTokenManager");
|
|
262
|
-
}
|
|
263
|
-
getSkipReason() {
|
|
264
|
-
if (ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "api_key" || ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "foundry") {
|
|
265
|
-
return `auth method is ${ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD}`;
|
|
266
|
-
}
|
|
267
|
-
if (!ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD && ENGINE_ENV.OPENAI_API_KEY) {
|
|
268
|
-
return "OPENAI_API_KEY is set";
|
|
269
|
-
}
|
|
270
|
-
return null;
|
|
271
|
-
}
|
|
272
|
-
async doRefresh(_config) {
|
|
273
|
-
await this.refreshWithRequest();
|
|
274
|
-
}
|
|
275
|
-
async refreshWithRequest(request) {
|
|
276
|
-
console.log("[CodexTokenManager] Refreshing Codex credentials...");
|
|
277
|
-
const response = await monolithRequest("/v1/engine/codex/refresh-credentials", {
|
|
278
|
-
body: request
|
|
279
|
-
});
|
|
280
|
-
if (!response.ok) {
|
|
281
|
-
const errorText = await response.text();
|
|
282
|
-
throw new Error(`Credentials refresh failed: ${response.status} ${errorText}`);
|
|
283
|
-
}
|
|
284
|
-
const data = await response.json();
|
|
285
|
-
await this.applyCredentialsResponse(data);
|
|
286
|
-
if (data.scope) {
|
|
287
|
-
setAgentCredentialSnapshot("codex", {
|
|
288
|
-
method: data.type,
|
|
289
|
-
scope: data.scope,
|
|
290
|
-
...data.revision ? { revision: data.revision } : {}
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
console.log(`[CodexTokenManager] Credentials refreshed (method=${data.type})`);
|
|
294
|
-
return data;
|
|
295
|
-
}
|
|
296
|
-
async prepareAspOauthOptions() {
|
|
297
|
-
if (ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD !== "oauth") return {};
|
|
298
|
-
const response = await this.refreshWithRequest();
|
|
299
|
-
if (response.type !== "oauth") return {};
|
|
300
|
-
const login = this.buildAspOauthLogin(response);
|
|
301
|
-
let credential = login.credential;
|
|
302
|
-
return {
|
|
303
|
-
chatgptAuthTokens: login.tokens,
|
|
304
|
-
refreshChatgptAuthTokens: async (params) => {
|
|
305
|
-
const refreshed = await this.refreshAspOauthCredentials(
|
|
306
|
-
credential,
|
|
307
|
-
`Codex ASP requested an external token refresh (${params.reason})`
|
|
308
|
-
);
|
|
309
|
-
if (!refreshed.ok) {
|
|
310
|
-
if (refreshed.error.code === "method_changed") {
|
|
311
|
-
throw new CodexAspAuthMethodChangedError(refreshed.error.message);
|
|
312
|
-
}
|
|
313
|
-
throw new Error(refreshed.error.message);
|
|
314
|
-
}
|
|
315
|
-
credential = refreshed.data.credential;
|
|
316
|
-
return refreshed.data.tokens;
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
async refreshAspOauthCredentials(failedCredential, failureReason) {
|
|
321
|
-
try {
|
|
322
|
-
const response = await this.refreshWithRequest({
|
|
323
|
-
failedMethod: "oauth",
|
|
324
|
-
...failedCredential?.method === "oauth" ? { failedCredential } : {},
|
|
325
|
-
failureKind: "rejected",
|
|
326
|
-
failureReason
|
|
327
|
-
});
|
|
328
|
-
if (response.type !== "oauth") {
|
|
329
|
-
return createErrorResult({
|
|
330
|
-
message: `${failureReason}; credentials changed to ${response.type}, so the app server must restart`,
|
|
331
|
-
code: "method_changed"
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
return createSuccessResult(this.buildAspOauthLogin(response));
|
|
335
|
-
} catch (error) {
|
|
336
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
337
|
-
return createErrorResult({
|
|
338
|
-
message,
|
|
339
|
-
code: message.includes('"code":"no_credentials"') ? "no_credentials" : "refresh_failed"
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
async fetchFreshCredentials(failureReason, failureKind = "rejected", failedCredential = ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS.codex) {
|
|
344
|
-
const failedMethod = failedCredential?.method === "oauth" || failedCredential?.method === "api_key" || failedCredential?.method === "foundry" ? failedCredential.method : ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD;
|
|
345
|
-
return this.swapCredentials({
|
|
346
|
-
provider: "codex",
|
|
347
|
-
failureKind,
|
|
348
|
-
refresh: async (exclusions) => {
|
|
349
|
-
await this.refreshWithRequest(
|
|
350
|
-
failedMethod === "oauth" || failedMethod === "api_key" || failedMethod === "foundry" ? {
|
|
351
|
-
failedMethod,
|
|
352
|
-
...failedCredential?.method === failedMethod ? { failedCredential } : {},
|
|
353
|
-
failureReason,
|
|
354
|
-
failureKind,
|
|
355
|
-
...exclusions
|
|
356
|
-
} : exclusions
|
|
357
|
-
);
|
|
358
|
-
},
|
|
359
|
-
isOauthNow: () => ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "oauth"
|
|
360
|
-
});
|
|
361
|
-
}
|
|
362
|
-
async applyCredentialsResponse(response) {
|
|
363
|
-
await this.removeOauthCredentialsFile();
|
|
364
|
-
const envVars = codexAuthEnvFromResponse(response);
|
|
365
|
-
applyAuthEnvTransition({
|
|
366
|
-
prevMethod: ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD ?? "none",
|
|
367
|
-
newMethod: envVars.REPLICAS_CODEX_AUTH_METHOD ?? "none",
|
|
368
|
-
authKeys: CODEX_AUTH_ENV_KEYS,
|
|
369
|
-
authKeysByMethod: CODEX_AUTH_ENV_KEYS_BY_METHOD,
|
|
370
|
-
newEnvVars: envVars,
|
|
371
|
-
envs: [ENGINE_ENV, process.env]
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
buildAspOauthLogin(response) {
|
|
375
|
-
const credential = ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS.codex;
|
|
376
|
-
return {
|
|
377
|
-
tokens: {
|
|
378
|
-
accessToken: response.accessToken,
|
|
379
|
-
chatgptAccountId: response.accountId,
|
|
380
|
-
chatgptPlanType: null
|
|
381
|
-
},
|
|
382
|
-
...credential?.method === "oauth" ? { credential } : {}
|
|
383
|
-
};
|
|
384
|
-
}
|
|
385
|
-
async removeOauthCredentialsFile() {
|
|
386
|
-
const authPath = path.join(ENGINE_ENV.HOME_DIR, ".codex", "auth.json");
|
|
387
|
-
try {
|
|
388
|
-
await fs.unlink(authPath);
|
|
389
|
-
} catch (error) {
|
|
390
|
-
if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) throw error;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
};
|
|
394
|
-
var codexTokenManager = new CodexTokenManager();
|
|
395
|
-
|
|
396
|
-
export {
|
|
397
|
-
applyAuthEnvTransition,
|
|
398
|
-
recordCredentialFallback,
|
|
399
|
-
listCredentialFallbacks,
|
|
400
|
-
recordExhaustedCredential,
|
|
401
|
-
BaseRefreshManager,
|
|
402
|
-
monolithRequest,
|
|
403
|
-
monolithService,
|
|
404
|
-
CodexAspAuthMethodChangedError,
|
|
405
|
-
CodexTokenManager,
|
|
406
|
-
codexTokenManager
|
|
407
|
-
};
|