replicas-engine 0.1.666 → 0.1.669

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.
@@ -0,0 +1,407 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ENGINE_ENV,
4
+ setAgentCredentialSnapshot
5
+ } from "./chunk-LO6ISJCF.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-6JWWD5NM.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
+ };
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ REPLICAS_RUNTIME_ENV_ALIASES,
4
+ agentCredentialSnapshotSchema,
5
+ isValidAgentProvider,
6
+ parsePosixEnvFile,
7
+ readReplicasRuntimeEnv
8
+ } from "./chunk-6JWWD5NM.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
+ };
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/utils/presigned-upload.ts
4
+ import { createReadStream } from "fs";
5
+ import { request as httpRequest } from "http";
6
+ import { request as httpsRequest } from "https";
7
+ async function putPresignedFile(urlValue, filePath, size, contentType) {
8
+ await new Promise((resolve, reject) => {
9
+ const url = new URL(urlValue);
10
+ const request = (url.protocol === "https:" ? httpsRequest : httpRequest)(url, {
11
+ method: "PUT",
12
+ headers: {
13
+ "content-length": String(size),
14
+ "content-type": contentType
15
+ }
16
+ }, (response) => {
17
+ response.setEncoding("utf8");
18
+ let body = "";
19
+ response.on("data", (chunk) => {
20
+ body += chunk;
21
+ });
22
+ response.on("end", () => {
23
+ const status = response.statusCode ?? 0;
24
+ if (status >= 200 && status < 300) resolve();
25
+ else reject(new Error(`upload failed: ${status} ${body}`));
26
+ });
27
+ response.on("error", reject);
28
+ });
29
+ request.on("error", reject);
30
+ const file = size > 0 ? createReadStream(filePath, { start: 0, end: size - 1 }) : createReadStream(filePath);
31
+ file.on("error", (error) => request.destroy(error));
32
+ file.pipe(request);
33
+ });
34
+ }
35
+
36
+ // src/utils/codex-agent-env.ts
37
+ function buildCodexAgentEnv(source = process.env) {
38
+ const env = Object.fromEntries(
39
+ Object.entries(source).filter((entry) => typeof entry[1] === "string")
40
+ );
41
+ if (env.REPLICAS_CODEX_AUTH_METHOD === "oauth" || env.REPLICAS_CODEX_AUTH_METHOD === "foundry") {
42
+ delete env.OPENAI_API_KEY;
43
+ }
44
+ delete env.GH_TOKEN;
45
+ delete env.GITHUB_TOKEN;
46
+ delete env.GH_CONFIG_DIR;
47
+ return env;
48
+ }
49
+
50
+ // src/managers/codex-asp/notification-dispatch.ts
51
+ var TURN_STARTED_METHOD = "turn/started";
52
+ var TURN_COMPLETED_METHOD = "turn/completed";
53
+ var TURN_PLAN_UPDATED_METHOD = "turn/plan/updated";
54
+ var THREAD_GOAL_UPDATED_METHOD = "thread/goal/updated";
55
+ var THREAD_GOAL_CLEARED_METHOD = "thread/goal/cleared";
56
+ var ITEM_STARTED_METHOD = "item/started";
57
+ var ITEM_COMPLETED_METHOD = "item/completed";
58
+ var AGENT_MESSAGE_DELTA_METHOD = "item/agentMessage/delta";
59
+ var REASONING_SUMMARY_TEXT_DELTA_METHOD = "item/reasoning/summaryTextDelta";
60
+ var REASONING_TEXT_DELTA_METHOD = "item/reasoning/textDelta";
61
+ var REASONING_SUMMARY_PART_ADDED_METHOD = "item/reasoning/summaryPartAdded";
62
+ var COMMAND_EXECUTION_OUTPUT_DELTA_METHOD = "item/commandExecution/outputDelta";
63
+ var FILE_CHANGE_OUTPUT_DELTA_METHOD = "item/fileChange/outputDelta";
64
+ var ACCOUNT_RATE_LIMITS_UPDATED_METHOD = "account/rateLimits/updated";
65
+ var THREAD_TOKEN_USAGE_UPDATED_METHOD = "thread/tokenUsage/updated";
66
+ var THREAD_COMPACTED_METHOD = "thread/compacted";
67
+ function dispatchAspNotification(notification, handlers) {
68
+ const handler = handlers[notification.method];
69
+ if (!handler) return;
70
+ handler(notification);
71
+ }
72
+ function recoverCompletedTurn(turn, completedItems, agentMessageDeltas) {
73
+ const items = turn.items.length > 0 ? [...turn.items] : [];
74
+ const itemIds = new Set(items.map((item) => item.id));
75
+ for (const item of completedItems) {
76
+ if (itemIds.has(item.id)) continue;
77
+ items.push(item);
78
+ itemIds.add(item.id);
79
+ }
80
+ for (const [itemId, text] of agentMessageDeltas) {
81
+ if (itemIds.has(itemId)) continue;
82
+ items.push({ type: "agentMessage", id: itemId, text, phase: null, memoryCitation: null });
83
+ }
84
+ return items.length > 0 ? { ...turn, items, itemsView: "full" } : turn;
85
+ }
86
+
87
+ export {
88
+ putPresignedFile,
89
+ buildCodexAgentEnv,
90
+ TURN_STARTED_METHOD,
91
+ TURN_COMPLETED_METHOD,
92
+ TURN_PLAN_UPDATED_METHOD,
93
+ THREAD_GOAL_UPDATED_METHOD,
94
+ THREAD_GOAL_CLEARED_METHOD,
95
+ ITEM_STARTED_METHOD,
96
+ ITEM_COMPLETED_METHOD,
97
+ AGENT_MESSAGE_DELTA_METHOD,
98
+ REASONING_SUMMARY_TEXT_DELTA_METHOD,
99
+ REASONING_TEXT_DELTA_METHOD,
100
+ REASONING_SUMMARY_PART_ADDED_METHOD,
101
+ COMMAND_EXECUTION_OUTPUT_DELTA_METHOD,
102
+ FILE_CHANGE_OUTPUT_DELTA_METHOD,
103
+ ACCOUNT_RATE_LIMITS_UPDATED_METHOD,
104
+ THREAD_TOKEN_USAGE_UPDATED_METHOD,
105
+ THREAD_COMPACTED_METHOD,
106
+ dispatchAspNotification,
107
+ recoverCompletedTurn
108
+ };
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ CodexAspAuthMethodChangedError,
4
+ CodexTokenManager,
5
+ codexTokenManager
6
+ } from "./chunk-IRM6KMN5.js";
7
+ import "./chunk-LO6ISJCF.js";
8
+ import "./chunk-6JWWD5NM.js";
9
+ export {
10
+ CodexAspAuthMethodChangedError,
11
+ CodexTokenManager,
12
+ codexTokenManager
13
+ };