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/index.js CHANGED
@@ -1,51 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ACCOUNT_RATE_LIMITS_UPDATED_METHOD,
4
- AGENT_MESSAGE_DELTA_METHOD,
5
- COMMAND_EXECUTION_OUTPUT_DELTA_METHOD,
6
- FILE_CHANGE_OUTPUT_DELTA_METHOD,
7
- ITEM_COMPLETED_METHOD,
8
- ITEM_STARTED_METHOD,
9
- REASONING_SUMMARY_PART_ADDED_METHOD,
10
- REASONING_SUMMARY_TEXT_DELTA_METHOD,
11
- REASONING_TEXT_DELTA_METHOD,
12
- THREAD_COMPACTED_METHOD,
13
- THREAD_GOAL_CLEARED_METHOD,
14
- THREAD_GOAL_UPDATED_METHOD,
15
- THREAD_TOKEN_USAGE_UPDATED_METHOD,
16
- TURN_COMPLETED_METHOD,
17
- TURN_PLAN_UPDATED_METHOD,
18
- TURN_STARTED_METHOD,
19
- buildCodexAgentEnv,
20
- dispatchAspNotification,
21
- putPresignedFile,
22
- recoverCompletedTurn
23
- } from "./chunk-XQW4B35Y.js";
24
- import {
25
- AppServerProcess,
26
- SUBPROCESS_MAX_BUFFER,
27
- execAsync,
28
- execFileAsync
29
- } from "./chunk-CKJJIOSE.js";
30
- import {
31
- BaseRefreshManager,
32
- CodexAspAuthMethodChangedError,
33
- applyAuthEnvTransition,
34
- codexTokenManager,
35
- listCredentialFallbacks,
36
- monolithRequest,
37
- monolithService,
38
- recordCredentialFallback,
39
- recordExhaustedCredential
40
- } from "./chunk-A2ZICXOK.js";
41
- import {
42
- ENGINE_ENV,
43
- IS_WARMING_MODE,
44
- isRecord as isRecord2,
45
- setAgentCredentialSnapshot
46
- } from "./chunk-2CFOJHNH.js";
47
- import {
48
4
  AGENT,
5
+ AGENT_MESSAGE_DELTA_METHOD,
49
6
  AGENT_MODELS,
50
7
  AI_GATEWAY_BASE_URL,
51
8
  ASTER_BASE_URL,
@@ -54,6 +11,7 @@ import {
54
11
  ASTER_PROVIDER,
55
12
  AUTH_FALLBACK_EVENT_TYPE,
56
13
  AUTH_RETRY_STATUS_EVENT_TYPE,
14
+ AppServerProcess,
57
15
  CHAT_GOAL_EVENT_TYPE,
58
16
  CHAT_INTERRUPTED_EVENT_TYPE,
59
17
  CLAUDE_AUTH_ENV_KEYS,
@@ -70,7 +28,10 @@ import {
70
28
  CLAUDE_SONNET_5_BEDROCK_MODEL,
71
29
  CLAUDE_SONNET_5_MODEL,
72
30
  CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE,
31
+ CODEX_AUTH_ENV_KEYS,
32
+ CODEX_AUTH_ENV_KEYS_BY_METHOD,
73
33
  CODEX_QUOTA_STATUS_EVENT_TYPE,
34
+ COMMAND_EXECUTION_OUTPUT_DELTA_METHOD,
74
35
  COMPACTION_STATUS_EVENT_TYPE,
75
36
  CONTEXT_USAGE_EVENT_TYPE,
76
37
  CURSOR_CONNECTION_STATUS_EVENT_TYPE,
@@ -90,11 +51,14 @@ import {
90
51
  ENGINE_HEALTH_MAX_WAIT_MS,
91
52
  ENGINE_HEALTH_WAIT_HEADER,
92
53
  ENGINE_HEALTH_WAIT_QUERY_PARAM,
54
+ FILE_CHANGE_OUTPUT_DELTA_METHOD,
93
55
  GITHUB_CREDENTIAL_REFRESH_PATH,
94
56
  GITLAB_CREDENTIAL_REFRESH_PATH,
95
57
  GIT_CREDENTIAL_HELPER_FILENAME,
96
58
  HOOK_EXEC_MAX_BUFFER_BYTES,
97
59
  IMAGE_MEDIA_TYPES,
60
+ ITEM_COMPLETED_METHOD,
61
+ ITEM_STARTED_METHOD,
98
62
  InFlightMap,
99
63
  MAX_CANVAS_FILE_BYTES,
100
64
  MAX_CANVAS_PREVIEW_BYTES,
@@ -103,18 +67,32 @@ import {
103
67
  MEMORY_ROOT,
104
68
  MEMORY_SUMMARY_FILENAME,
105
69
  MERGED_MESSAGE_SEPARATOR,
70
+ REASONING_SUMMARY_PART_ADDED_METHOD,
71
+ REASONING_SUMMARY_TEXT_DELTA_METHOD,
72
+ REASONING_TEXT_DELTA_METHOD,
106
73
  REPLICAS_CONFIG_FILENAMES,
74
+ REPLICAS_RUNTIME_ENV_ALIASES,
107
75
  SANDBOX_PATHS,
76
+ SUBPROCESS_MAX_BUFFER,
77
+ THREAD_COMPACTED_METHOD,
78
+ THREAD_GOAL_CLEARED_METHOD,
79
+ THREAD_GOAL_UPDATED_METHOD,
80
+ THREAD_TOKEN_USAGE_UPDATED_METHOD,
108
81
  TIMEOUT,
82
+ TURN_COMPLETED_METHOD,
83
+ TURN_PLAN_UPDATED_METHOD,
84
+ TURN_STARTED_METHOD,
109
85
  TaskAccumulator,
110
86
  USER_MESSAGE_ID_PAYLOAD_KEY,
111
87
  VALID_AGENT_PROVIDERS,
112
88
  VALID_RELAY_SUBAGENT_PROVIDERS,
113
89
  VALID_THINKING_LEVELS,
90
+ agentCredentialSnapshotSchema,
114
91
  applyCodexAspTranscriptDelta,
115
92
  areSameUserMessageEvents,
116
93
  areUserMessagesWithinMatchWindow,
117
94
  autoCompactThresholdField,
95
+ buildCodexAgentEnv,
118
96
  buildCodexTokenUsageContextUsagePayload,
119
97
  buildGitCredentialHelperScript,
120
98
  buildHookOutputPreview,
@@ -125,6 +103,7 @@ import {
125
103
  clampWarmHookTimeoutMs,
126
104
  classifyCanvasFilename,
127
105
  claudeAuthEnvFromResponse,
106
+ codexAuthEnvFromResponse,
128
107
  codexReasoningEffortForThinkingLevel,
129
108
  coerceBackgroundTaskPayload,
130
109
  coerceClaudeResultPayload,
@@ -138,6 +117,9 @@ import {
138
117
  decodePathSegments,
139
118
  detectAgentQuotaLimit,
140
119
  detectLanguageByPath,
120
+ dispatchAspNotification,
121
+ execAsync,
122
+ execFileAsync,
141
123
  extractCommandProtectionCommandText,
142
124
  extractErrorText,
143
125
  extractToolResultText,
@@ -193,17 +175,21 @@ import {
193
175
  parseGitRemote,
194
176
  parseLatestCodexAspTranscriptTurn,
195
177
  parseMcpToolName,
178
+ parsePosixEnvFile,
196
179
  parseReplicasConfigString,
197
180
  percentage,
181
+ putPresignedFile,
198
182
  raceWithTimeout,
199
183
  readJsonlPage,
184
+ readReplicasRuntimeEnv,
185
+ recoverCompletedTurn,
200
186
  renumberCodexAspTranscriptItems,
201
187
  resolveWarmHookConfig,
202
188
  sanitizeCanvasFilename,
203
189
  serializeCanvasContentResponse,
204
190
  shellQuotePosix,
205
191
  stripAgentDiagnosticErrors
206
- } from "./chunk-5NBVP6A2.js";
192
+ } from "./chunk-OLZ7JWCU.js";
207
193
 
208
194
  // src/index.ts
209
195
  import { serve } from "@hono/node-server";
@@ -215,9 +201,373 @@ import { connect } from "net";
215
201
  // src/managers/github-token-manager.ts
216
202
  import path from "path";
217
203
 
204
+ // src/engine-env.ts
205
+ import { readFileSync as readFileSync2 } from "fs";
206
+ import { homedir as homedir2 } from "os";
207
+ import { join as join2 } from "path";
208
+
209
+ // src/runtime-env-loader.ts
210
+ import { readFileSync } from "fs";
211
+ import { homedir } from "os";
212
+ import { join } from "path";
213
+ function loadRuntimeEnvFile() {
214
+ let content;
215
+ try {
216
+ content = readFileSync(join(homedir(), ".replicas", "runtime-env.sh"), "utf-8");
217
+ } catch {
218
+ return;
219
+ }
220
+ for (const [key, value] of Object.entries(parsePosixEnvFile(content))) {
221
+ process.env[key] = value;
222
+ }
223
+ }
224
+
225
+ // src/utils/type-guards.ts
226
+ function isRecord2(value) {
227
+ return typeof value === "object" && value !== null;
228
+ }
229
+
230
+ // src/engine-env.ts
231
+ var SANDBOX_IMAGE_VERSION_FILE = "/usr/local/lib/replicas-sandbox-image-version";
232
+ function readEnv(name) {
233
+ const value = process.env[name]?.trim();
234
+ return value ? value : void 0;
235
+ }
236
+ function readSandboxImageVersion() {
237
+ const environmentVersion = readEnv("REPLICAS_SANDBOX_IMAGE_VERSION");
238
+ if (environmentVersion) return environmentVersion;
239
+ try {
240
+ return readFileSync2(SANDBOX_IMAGE_VERSION_FILE, "utf8").trim() || "development";
241
+ } catch {
242
+ return "development";
243
+ }
244
+ }
245
+ function parsePort(value) {
246
+ if (!value) {
247
+ return 3737;
248
+ }
249
+ const parsed = Number(value);
250
+ if (!Number.isInteger(parsed) || parsed <= 0) {
251
+ throw new Error("Invalid engine environment: REPLICAS_ENGINE_PORT must be a positive integer");
252
+ }
253
+ return parsed;
254
+ }
255
+ function requireDefined(value, name) {
256
+ if (value === void 0 || value === null) {
257
+ throw new Error(`Invalid engine environment: ${name} is required`);
258
+ }
259
+ return value;
260
+ }
261
+ function requireValidURL(value, name) {
262
+ try {
263
+ new URL(value);
264
+ return value;
265
+ } catch {
266
+ throw new Error(`Invalid engine environment: ${name} must be a valid URL`);
267
+ }
268
+ }
269
+ function parseClaudeAuthMethod(value) {
270
+ if (value === "oauth" || value === "api_key" || value === "bedrock" || value === "foundry") {
271
+ return value;
272
+ }
273
+ return void 0;
274
+ }
275
+ function parseCodexAuthMethod(value) {
276
+ if (value === "oauth" || value === "api_key" || value === "foundry") {
277
+ return value;
278
+ }
279
+ return void 0;
280
+ }
281
+ function parseAgentCredentialSnapshots(value) {
282
+ if (!value) return {};
283
+ try {
284
+ const parsed = JSON.parse(value);
285
+ if (!isRecord2(parsed)) return {};
286
+ const snapshots = {};
287
+ for (const [provider, snapshot] of Object.entries(parsed)) {
288
+ if (!isValidAgentProvider(provider)) continue;
289
+ const parsedSnapshot = agentCredentialSnapshotSchema.safeParse(snapshot);
290
+ if (parsedSnapshot.success) snapshots[provider] = parsedSnapshot.data;
291
+ }
292
+ return snapshots;
293
+ } catch {
294
+ return {};
295
+ }
296
+ }
297
+ var IS_WARMING_MODE = process.argv.includes("--warming");
298
+ function loadEngineEnv() {
299
+ loadRuntimeEnvFile();
300
+ const HOME_DIR = homedir2();
301
+ const env = {
302
+ // Defined: always available
303
+ REPLICAS_ENGINE_SECRET: requireDefined(readEnv("REPLICAS_ENGINE_SECRET"), "REPLICAS_ENGINE_SECRET"),
304
+ REPLICAS_ENGINE_PORT: parsePort(readEnv("REPLICAS_ENGINE_PORT")),
305
+ REPLICAS_MONOLITH_URL: requireValidURL(
306
+ requireDefined(readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.monolithUrl), "REPLICAS_MONOLITH_URL"),
307
+ "REPLICAS_MONOLITH_URL"
308
+ ),
309
+ HOME_DIR,
310
+ WORKSPACE_ROOT: join2(HOME_DIR, "workspaces"),
311
+ REPLICAS_SANDBOX_IMAGE_VERSION: readSandboxImageVersion(),
312
+ // Runtime: may not be set during warming
313
+ REPLICAS_WORKSPACE_ID: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.workspaceId),
314
+ REPLICAS_LINEAR_SESSION_ID: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.linearSessionId),
315
+ REPLICAS_LINEAR_ACCESS_TOKEN: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.linearAccessToken),
316
+ REPLICAS_SLACK_BOT_TOKEN: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.slackBotToken),
317
+ REPLICAS_SLACK_CHANNEL_ID: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.slackChannelId),
318
+ REPLICAS_SLACK_THREAD_TS: readReplicasRuntimeEnv(readEnv, REPLICAS_RUNTIME_ENV_ALIASES.slackThreadTs),
319
+ ANTHROPIC_API_KEY: readEnv("ANTHROPIC_API_KEY"),
320
+ OPENAI_API_KEY: readEnv("OPENAI_API_KEY"),
321
+ CURSOR_API_KEY: readEnv("CURSOR_API_KEY"),
322
+ AI_GATEWAY_API_KEY: readEnv("AI_GATEWAY_API_KEY"),
323
+ CLAUDE_CODE_USE_BEDROCK: readEnv("CLAUDE_CODE_USE_BEDROCK"),
324
+ AWS_ACCESS_KEY_ID: readEnv("AWS_ACCESS_KEY_ID"),
325
+ AWS_SECRET_ACCESS_KEY: readEnv("AWS_SECRET_ACCESS_KEY"),
326
+ AWS_REGION: readEnv("AWS_REGION"),
327
+ ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION: readEnv("ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION"),
328
+ REPLICAS_CLAUDE_AUTH_METHOD: parseClaudeAuthMethod(readEnv("REPLICAS_CLAUDE_AUTH_METHOD")),
329
+ REPLICAS_CODEX_AUTH_METHOD: parseCodexAuthMethod(readEnv("REPLICAS_CODEX_AUTH_METHOD")),
330
+ REPLICAS_AGENT_CREDENTIALS: parseAgentCredentialSnapshots(readEnv("REPLICAS_AGENT_CREDENTIALS")),
331
+ REPLICAS_ENV_SYSTEM_PROMPT: readEnv("REPLICAS_ENV_SYSTEM_PROMPT"),
332
+ REPLICAS_ENV_START_HOOK: readEnv("REPLICAS_ENV_START_HOOK"),
333
+ REPLICAS_DISABLE_AUTO_START_HOOKS: readEnv("REPLICAS_DISABLE_AUTO_START_HOOKS")?.toLowerCase() === "true",
334
+ REPLICAS_ENGINE_DEFER_INITIALIZATION: readEnv("REPLICAS_ENGINE_DEFER_INITIALIZATION")?.toLowerCase() === "true"
335
+ };
336
+ if (!IS_WARMING_MODE && !env.REPLICAS_WORKSPACE_ID) {
337
+ console.error("REPLICAS_WORKSPACE_ID is not set \u2014 this is required in normal (non-warming) mode");
338
+ }
339
+ return env;
340
+ }
341
+ var ENGINE_ENV = loadEngineEnv();
342
+ function setAgentCredentialSnapshot(provider, snapshot) {
343
+ ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS = {
344
+ ...ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS,
345
+ [provider]: snapshot
346
+ };
347
+ process.env.REPLICAS_AGENT_CREDENTIALS = JSON.stringify(ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS);
348
+ }
349
+
350
+ // src/services/credential-fallbacks.ts
351
+ var fallbacksByAgent = /* @__PURE__ */ new Map();
352
+ var exhaustedByAgent = /* @__PURE__ */ new Map();
353
+ function recordCredentialFallback(notice) {
354
+ fallbacksByAgent.set(notice.provider, notice);
355
+ }
356
+ function listCredentialFallbacks() {
357
+ return [...fallbacksByAgent.values()].filter((notice) => {
358
+ const live = ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS[notice.provider];
359
+ if (!live) return false;
360
+ return notice.status === "switched" ? live.method === notice.candidateMethod && live.scope === notice.candidateScope : live.method === notice.exhaustedMethod && live.scope === notice.exhaustedScope;
361
+ });
362
+ }
363
+ function listExhaustedCredentials(provider) {
364
+ return [...exhaustedByAgent.get(provider)?.values() ?? []];
365
+ }
366
+ function recordExhaustedCredential(provider, credential) {
367
+ const spent = exhaustedByAgent.get(provider) ?? /* @__PURE__ */ new Map();
368
+ spent.set(`${credential.method}|${credential.scope}`, credential);
369
+ exhaustedByAgent.set(provider, spent);
370
+ }
371
+
372
+ // src/managers/base-refresh-manager.ts
373
+ var BaseRefreshManager = class {
374
+ constructor(managerName, intervalMs = 15 * 60 * 1e3) {
375
+ this.managerName = managerName;
376
+ this.intervalMs = intervalMs;
377
+ this.health = {
378
+ isRunning: false,
379
+ intervalMs: this.intervalMs,
380
+ lastAttemptAt: null,
381
+ lastSuccessAt: null,
382
+ lastErrorAt: null,
383
+ lastErrorMessage: null
384
+ };
385
+ }
386
+ managerName;
387
+ intervalMs;
388
+ intervalHandle = null;
389
+ health;
390
+ async start() {
391
+ if (this.intervalHandle) {
392
+ return;
393
+ }
394
+ const skipReason = this.getSkipReason();
395
+ if (skipReason) {
396
+ console.log(`[${this.managerName}] Skipping: ${skipReason}`);
397
+ return;
398
+ }
399
+ console.log(`[${this.managerName}] Starting token refresh service`);
400
+ this.health.isRunning = true;
401
+ const config = this.getRuntimeConfig();
402
+ if (config) {
403
+ this.health.lastAttemptAt = (/* @__PURE__ */ new Date()).toISOString();
404
+ for (let attempt = 1; attempt <= 3; attempt++) {
405
+ try {
406
+ await this.doRefresh(config);
407
+ this.health.lastSuccessAt = (/* @__PURE__ */ new Date()).toISOString();
408
+ this.health.lastErrorAt = null;
409
+ this.health.lastErrorMessage = null;
410
+ break;
411
+ } catch (error) {
412
+ const message = error instanceof Error ? error.message : "Unknown error";
413
+ this.health.lastErrorAt = (/* @__PURE__ */ new Date()).toISOString();
414
+ this.health.lastErrorMessage = message;
415
+ if (attempt < 3) {
416
+ console.warn(`[${this.managerName}] Initial refresh attempt ${attempt} failed, retrying in 2s...`);
417
+ await new Promise((resolve5) => setTimeout(resolve5, 2e3));
418
+ } else {
419
+ console.error(`[${this.managerName}] Initial refresh failed after 3 attempts:`, error);
420
+ }
421
+ }
422
+ }
423
+ }
424
+ this.scheduleNextRefresh();
425
+ }
426
+ async swapCredentials(params) {
427
+ if (!this.getRuntimeConfig()) {
428
+ return createErrorResult({ message: `${this.managerName} has no runtime config`, code: "not_configured" });
429
+ }
430
+ try {
431
+ console.log(`[${this.managerName}] Fetching fresh credentials from monolith (${params.failureKind})...`);
432
+ const excludeCredentials = listExhaustedCredentials(params.provider);
433
+ await params.refresh(excludeCredentials.length > 0 ? { excludeCredentials } : {});
434
+ if (params.isOauthNow()) {
435
+ this.start().catch((error) => {
436
+ console.error(`[${this.managerName}] Failed to restart OAuth refresh service after fallback:`, error);
437
+ });
438
+ }
439
+ return createSuccessResult();
440
+ } catch (error) {
441
+ const message = error instanceof Error ? error.message : String(error);
442
+ console.error(`[${this.managerName}] Failed to fetch fresh credentials:`, error);
443
+ return createErrorResult({
444
+ message,
445
+ code: message.includes('"code":"no_credentials"') ? "no_credentials" : "refresh_failed"
446
+ });
447
+ }
448
+ }
449
+ stop() {
450
+ if (!this.intervalHandle) {
451
+ return;
452
+ }
453
+ clearTimeout(this.intervalHandle);
454
+ this.intervalHandle = null;
455
+ this.health.isRunning = false;
456
+ console.log(`[${this.managerName}] Stopped`);
457
+ }
458
+ getHealthStatus() {
459
+ return { ...this.health };
460
+ }
461
+ getSkipReason() {
462
+ return null;
463
+ }
464
+ getNextRefreshDelayMs() {
465
+ return this.intervalMs;
466
+ }
467
+ getRuntimeConfig() {
468
+ if (!ENGINE_ENV.REPLICAS_WORKSPACE_ID) {
469
+ return null;
470
+ }
471
+ return {
472
+ monolithUrl: ENGINE_ENV.REPLICAS_MONOLITH_URL,
473
+ workspaceId: ENGINE_ENV.REPLICAS_WORKSPACE_ID,
474
+ engineSecret: ENGINE_ENV.REPLICAS_ENGINE_SECRET
475
+ };
476
+ }
477
+ scheduleNextRefresh() {
478
+ const delayMs = this.getNextRefreshDelayMs();
479
+ this.health.intervalMs = delayMs;
480
+ this.intervalHandle = setTimeout(async () => {
481
+ await this.refreshOnce();
482
+ if (this.intervalHandle) this.scheduleNextRefresh();
483
+ }, delayMs);
484
+ console.log(`[${this.managerName}] Token refresh scheduled in ${Math.round(delayMs / 1e3)} seconds`);
485
+ }
486
+ async refreshOnce() {
487
+ if (this.getSkipReason()) {
488
+ return createSuccessResult();
489
+ }
490
+ const config = this.getRuntimeConfig();
491
+ if (!config) return createSuccessResult();
492
+ this.health.lastAttemptAt = (/* @__PURE__ */ new Date()).toISOString();
493
+ try {
494
+ await this.doRefresh(config);
495
+ this.health.lastSuccessAt = (/* @__PURE__ */ new Date()).toISOString();
496
+ this.health.lastErrorAt = null;
497
+ this.health.lastErrorMessage = null;
498
+ return createSuccessResult();
499
+ } catch (error) {
500
+ const message = error instanceof Error ? error.message : "Unknown error";
501
+ this.health.lastErrorAt = (/* @__PURE__ */ new Date()).toISOString();
502
+ this.health.lastErrorMessage = message;
503
+ console.error(`[${this.managerName}] Failed to refresh credentials:`, error);
504
+ return createErrorResult({ message });
505
+ }
506
+ }
507
+ };
508
+
509
+ // src/services/monolith-service.ts
510
+ async function monolithRequest(path6, init = {}) {
511
+ if (!ENGINE_ENV.REPLICAS_WORKSPACE_ID) {
512
+ throw new Error("REPLICAS_WORKSPACE_ID is not set; cannot call monolith");
513
+ }
514
+ const headers = {
515
+ Authorization: `Bearer ${ENGINE_ENV.REPLICAS_ENGINE_SECRET}`,
516
+ "X-Workspace-Id": ENGINE_ENV.REPLICAS_WORKSPACE_ID
517
+ };
518
+ if (!(init.body instanceof FormData)) headers["Content-Type"] = "application/json";
519
+ return fetch(`${ENGINE_ENV.REPLICAS_MONOLITH_URL}${path6}`, {
520
+ method: init.method ?? "POST",
521
+ headers,
522
+ body: init.body === void 0 ? void 0 : init.body instanceof FormData ? init.body : JSON.stringify(init.body),
523
+ signal: init.signal
524
+ });
525
+ }
526
+ var MonolithService = class {
527
+ async getRelaySubagentProviders() {
528
+ try {
529
+ const response = await monolithRequest("/v1/engine/relay-subagent-providers", { method: "GET" });
530
+ if (!response.ok) {
531
+ return null;
532
+ }
533
+ const body = await response.json();
534
+ return isRecord(body) && Array.isArray(body.providers) && body.providers.every((provider) => typeof provider === "string" && isValidAgentProvider(provider)) ? body.providers : null;
535
+ } catch {
536
+ return null;
537
+ }
538
+ }
539
+ async getOpenRouterModels() {
540
+ try {
541
+ const response = await monolithRequest("/v1/engine/openrouter-models", { method: "GET" });
542
+ if (!response.ok) {
543
+ return null;
544
+ }
545
+ const body = await response.json();
546
+ return isRecord(body) && Array.isArray(body.models) && body.models.every((model) => typeof model === "string") ? body.models : null;
547
+ } catch {
548
+ return null;
549
+ }
550
+ }
551
+ async sendEvent(event) {
552
+ if (!ENGINE_ENV.REPLICAS_WORKSPACE_ID) {
553
+ return;
554
+ }
555
+ try {
556
+ const response = await monolithRequest("/v1/engine/webhook", { body: event });
557
+ if (!response.ok) {
558
+ const errorText = await response.text();
559
+ console.error(`[MonolithService] Failed to send event: ${response.status} ${errorText}`);
560
+ }
561
+ } catch (error) {
562
+ console.error("[MonolithService] Failed to send event:", error);
563
+ }
564
+ }
565
+ };
566
+ var monolithService = new MonolithService();
567
+
218
568
  // src/utils/file.ts
219
569
  import { mkdir, readFile, rename, unlink, writeFile } from "fs/promises";
220
- import { dirname, join } from "path";
570
+ import { dirname, join as join3 } from "path";
221
571
 
222
572
  // src/utils/async-lock.ts
223
573
  var AsyncLock = class {
@@ -233,11 +583,11 @@ var AsyncLock = class {
233
583
  };
234
584
 
235
585
  // src/utils/file.ts
236
- async function atomicWriteFile(path5, data, options) {
237
- const tmpFile = `${path5}.${process.pid}.${Date.now()}.tmp`;
586
+ async function atomicWriteFile(path6, data, options) {
587
+ const tmpFile = `${path6}.${process.pid}.${Date.now()}.tmp`;
238
588
  try {
239
589
  await writeFile(tmpFile, data, { encoding: "utf-8", mode: options?.mode });
240
- await rename(tmpFile, path5);
590
+ await rename(tmpFile, path6);
241
591
  } catch (error) {
242
592
  await unlink(tmpFile).catch(() => void 0);
243
593
  throw error;
@@ -250,8 +600,8 @@ async function writeSecureCredentialFile(filePath, content, options) {
250
600
  await atomicWriteFile(filePath, content, { mode: 384 });
251
601
  }
252
602
  async function configureManagedGitCredentialHelper(homeDir) {
253
- const credentialsPath = join(homeDir, ".git-credentials");
254
- const helperPath = join(homeDir, GIT_CREDENTIAL_HELPER_FILENAME);
603
+ const credentialsPath = join3(homeDir, ".git-credentials");
604
+ const helperPath = join3(homeDir, GIT_CREDENTIAL_HELPER_FILENAME);
255
605
  await atomicWriteFile(helperPath, buildGitCredentialHelperScript(credentialsPath), { mode: 448 });
256
606
  await execFileAsync("git", ["config", "--global", "credential.helper", helperPath], {
257
607
  env: { ...process.env, HOME: homeDir }
@@ -286,15 +636,15 @@ function removeCredentialFileLines(filePath, shouldRemove) {
286
636
  // src/git/service.ts
287
637
  import { readdir, readFile as readFile3, stat } from "fs/promises";
288
638
  import { spawn } from "child_process";
289
- import { join as join4 } from "path";
639
+ import { join as join6 } from "path";
290
640
 
291
641
  // src/utils/state.ts
292
642
  import { readFile as readFile2, mkdir as mkdir2 } from "fs/promises";
293
643
  import { existsSync } from "fs";
294
- import { join as join2 } from "path";
295
- import { homedir } from "os";
296
- var STATE_DIR = join2(homedir(), ".replicas");
297
- var STATE_FILE = join2(STATE_DIR, "engine-state.json");
644
+ import { join as join4 } from "path";
645
+ import { homedir as homedir3 } from "os";
646
+ var STATE_DIR = join4(homedir3(), ".replicas");
647
+ var STATE_FILE = join4(STATE_DIR, "engine-state.json");
298
648
  var DEFAULT_STATE = {
299
649
  repos: {}
300
650
  };
@@ -391,8 +741,8 @@ async function saveRepoState(repoName, state, fallbackState) {
391
741
  }
392
742
 
393
743
  // src/git/commands.ts
394
- import { readFileSync } from "fs";
395
- import { join as join3 } from "path";
744
+ import { readFileSync as readFileSync3 } from "fs";
745
+ import { join as join5 } from "path";
396
746
  async function runGitCommand(args, cwd, options = {}) {
397
747
  const { stdout } = await execFileAsync("git", args, {
398
748
  cwd,
@@ -403,7 +753,7 @@ async function runGitCommand(args, cwd, options = {}) {
403
753
  }
404
754
  function readRepoHeadBranch(repoPath) {
405
755
  try {
406
- const contents = readFileSync(join3(repoPath, ".git", "HEAD"), "utf-8").trim();
756
+ const contents = readFileSync3(join5(repoPath, ".git", "HEAD"), "utf-8").trim();
407
757
  const match = contents.match(/^ref:\s+refs\/heads\/(.+)$/);
408
758
  return match ? match[1] : null;
409
759
  } catch {
@@ -465,13 +815,13 @@ var GitService = class {
465
815
  const repos = [];
466
816
  let complete = true;
467
817
  for (const entry of entries) {
468
- const fullPath = join4(root, entry);
818
+ const fullPath = join6(root, entry);
469
819
  try {
470
820
  const entryStat = await stat(fullPath);
471
821
  if (!entryStat.isDirectory()) {
472
822
  continue;
473
823
  }
474
- const hasGit = Boolean(await this.safeStat(join4(fullPath, ".git")));
824
+ const hasGit = Boolean(await this.safeStat(join6(fullPath, ".git")));
475
825
  if (!hasGit) {
476
826
  continue;
477
827
  }
@@ -660,9 +1010,9 @@ var GitService = class {
660
1010
  try {
661
1011
  const paths = await this.listUntrackedPaths(repoPath);
662
1012
  let total = 0;
663
- for (const path5 of paths) {
1013
+ for (const path6 of paths) {
664
1014
  try {
665
- const contents = await readFile3(join4(repoPath, path5));
1015
+ const contents = await readFile3(join6(repoPath, path6));
666
1016
  if (contents.length === 0 || contents.includes(0)) {
667
1017
  continue;
668
1018
  }
@@ -850,7 +1200,7 @@ var GitService = class {
850
1200
  }
851
1201
  async getGitLabAccessToken(host) {
852
1202
  try {
853
- const credentials = await readFile3(join4(ENGINE_ENV.HOME_DIR, ".git-credentials"), "utf-8");
1203
+ const credentials = await readFile3(join6(ENGINE_ENV.HOME_DIR, ".git-credentials"), "utf-8");
854
1204
  for (const line of credentials.split("\n")) {
855
1205
  const trimmed = line.trim();
856
1206
  if (!trimmed) continue;
@@ -918,9 +1268,9 @@ var GitService = class {
918
1268
  await saveRepoState(repo.name, state, state);
919
1269
  return state;
920
1270
  }
921
- async safeStat(path5) {
1271
+ async safeStat(path6) {
922
1272
  try {
923
- return await stat(path5);
1273
+ return await stat(path6);
924
1274
  } catch {
925
1275
  return null;
926
1276
  }
@@ -1071,6 +1421,26 @@ var gitlabTokenManager = new GitLabTokenManager();
1071
1421
  // src/managers/claude-token-manager.ts
1072
1422
  import { promises as fs } from "fs";
1073
1423
  import path3 from "path";
1424
+
1425
+ // src/managers/auth-env-transition.ts
1426
+ function applyAuthEnvTransition(params) {
1427
+ const newOwned = new Set(params.authKeysByMethod[params.newMethod]);
1428
+ const prevOwned = new Set(params.authKeysByMethod[params.prevMethod]);
1429
+ for (const key of params.authKeys) {
1430
+ const value = params.newEnvVars[key];
1431
+ if (value !== void 0) {
1432
+ for (const env of params.envs) {
1433
+ env[key] = value;
1434
+ }
1435
+ } else if (prevOwned.has(key) && !newOwned.has(key)) {
1436
+ for (const env of params.envs) {
1437
+ delete env[key];
1438
+ }
1439
+ }
1440
+ }
1441
+ }
1442
+
1443
+ // src/managers/claude-token-manager.ts
1074
1444
  var ClaudeTokenManager = class extends BaseRefreshManager {
1075
1445
  constructor() {
1076
1446
  super("ClaudeTokenManager");
@@ -1174,9 +1544,152 @@ var ClaudeTokenManager = class extends BaseRefreshManager {
1174
1544
  };
1175
1545
  var claudeTokenManager = new ClaudeTokenManager();
1176
1546
 
1547
+ // src/managers/codex-token-manager.ts
1548
+ import { promises as fs2 } from "fs";
1549
+ import path4 from "path";
1550
+ var CodexAspAuthMethodChangedError = class extends Error {
1551
+ name = "CodexAspAuthMethodChangedError";
1552
+ };
1553
+ var CodexTokenManager = class extends BaseRefreshManager {
1554
+ constructor() {
1555
+ super("CodexTokenManager");
1556
+ }
1557
+ getSkipReason() {
1558
+ if (ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "api_key" || ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "foundry") {
1559
+ return `auth method is ${ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD}`;
1560
+ }
1561
+ if (!ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD && ENGINE_ENV.OPENAI_API_KEY) {
1562
+ return "OPENAI_API_KEY is set";
1563
+ }
1564
+ return null;
1565
+ }
1566
+ async doRefresh(_config) {
1567
+ await this.refreshWithRequest();
1568
+ }
1569
+ async refreshWithRequest(request) {
1570
+ console.log("[CodexTokenManager] Refreshing Codex credentials...");
1571
+ const response = await monolithRequest("/v1/engine/codex/refresh-credentials", {
1572
+ body: request
1573
+ });
1574
+ if (!response.ok) {
1575
+ const errorText = await response.text();
1576
+ throw new Error(`Credentials refresh failed: ${response.status} ${errorText}`);
1577
+ }
1578
+ const data = await response.json();
1579
+ await this.applyCredentialsResponse(data);
1580
+ if (data.scope) {
1581
+ setAgentCredentialSnapshot("codex", {
1582
+ method: data.type,
1583
+ scope: data.scope,
1584
+ ...data.revision ? { revision: data.revision } : {}
1585
+ });
1586
+ }
1587
+ console.log(`[CodexTokenManager] Credentials refreshed (method=${data.type})`);
1588
+ return data;
1589
+ }
1590
+ async prepareAspOauthOptions() {
1591
+ if (ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD !== "oauth") return {};
1592
+ const response = await this.refreshWithRequest();
1593
+ if (response.type !== "oauth") return {};
1594
+ const login = this.buildAspOauthLogin(response);
1595
+ let credential = login.credential;
1596
+ return {
1597
+ chatgptAuthTokens: login.tokens,
1598
+ refreshChatgptAuthTokens: async (params) => {
1599
+ const refreshed = await this.refreshAspOauthCredentials(
1600
+ credential,
1601
+ `Codex ASP requested an external token refresh (${params.reason})`
1602
+ );
1603
+ if (!refreshed.ok) {
1604
+ if (refreshed.error.code === "method_changed") {
1605
+ throw new CodexAspAuthMethodChangedError(refreshed.error.message);
1606
+ }
1607
+ throw new Error(refreshed.error.message);
1608
+ }
1609
+ credential = refreshed.data.credential;
1610
+ return refreshed.data.tokens;
1611
+ }
1612
+ };
1613
+ }
1614
+ async refreshAspOauthCredentials(failedCredential, failureReason) {
1615
+ try {
1616
+ const response = await this.refreshWithRequest({
1617
+ failedMethod: "oauth",
1618
+ ...failedCredential?.method === "oauth" ? { failedCredential } : {},
1619
+ failureKind: "rejected",
1620
+ failureReason
1621
+ });
1622
+ if (response.type !== "oauth") {
1623
+ return createErrorResult({
1624
+ message: `${failureReason}; credentials changed to ${response.type}, so the app server must restart`,
1625
+ code: "method_changed"
1626
+ });
1627
+ }
1628
+ return createSuccessResult(this.buildAspOauthLogin(response));
1629
+ } catch (error) {
1630
+ const message = error instanceof Error ? error.message : String(error);
1631
+ return createErrorResult({
1632
+ message,
1633
+ code: message.includes('"code":"no_credentials"') ? "no_credentials" : "refresh_failed"
1634
+ });
1635
+ }
1636
+ }
1637
+ async fetchFreshCredentials(failureReason, failureKind = "rejected", failedCredential = ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS.codex) {
1638
+ const failedMethod = failedCredential?.method === "oauth" || failedCredential?.method === "api_key" || failedCredential?.method === "foundry" ? failedCredential.method : ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD;
1639
+ return this.swapCredentials({
1640
+ provider: "codex",
1641
+ failureKind,
1642
+ refresh: async (exclusions) => {
1643
+ await this.refreshWithRequest(
1644
+ failedMethod === "oauth" || failedMethod === "api_key" || failedMethod === "foundry" ? {
1645
+ failedMethod,
1646
+ ...failedCredential?.method === failedMethod ? { failedCredential } : {},
1647
+ failureReason,
1648
+ failureKind,
1649
+ ...exclusions
1650
+ } : exclusions
1651
+ );
1652
+ },
1653
+ isOauthNow: () => ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "oauth"
1654
+ });
1655
+ }
1656
+ async applyCredentialsResponse(response) {
1657
+ await this.removeOauthCredentialsFile();
1658
+ const envVars = codexAuthEnvFromResponse(response);
1659
+ applyAuthEnvTransition({
1660
+ prevMethod: ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD ?? "none",
1661
+ newMethod: envVars.REPLICAS_CODEX_AUTH_METHOD ?? "none",
1662
+ authKeys: CODEX_AUTH_ENV_KEYS,
1663
+ authKeysByMethod: CODEX_AUTH_ENV_KEYS_BY_METHOD,
1664
+ newEnvVars: envVars,
1665
+ envs: [ENGINE_ENV, process.env]
1666
+ });
1667
+ }
1668
+ buildAspOauthLogin(response) {
1669
+ const credential = ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS.codex;
1670
+ return {
1671
+ tokens: {
1672
+ accessToken: response.accessToken,
1673
+ chatgptAccountId: response.accountId,
1674
+ chatgptPlanType: null
1675
+ },
1676
+ ...credential?.method === "oauth" ? { credential } : {}
1677
+ };
1678
+ }
1679
+ async removeOauthCredentialsFile() {
1680
+ const authPath = path4.join(ENGINE_ENV.HOME_DIR, ".codex", "auth.json");
1681
+ try {
1682
+ await fs2.unlink(authPath);
1683
+ } catch (error) {
1684
+ if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) throw error;
1685
+ }
1686
+ }
1687
+ };
1688
+ var codexTokenManager = new CodexTokenManager();
1689
+
1177
1690
  // src/managers/infisical-token-manager.ts
1178
1691
  import { rm } from "fs/promises";
1179
- import path4 from "path";
1692
+ import path5 from "path";
1180
1693
  var InfisicalTokenManager = class extends BaseRefreshManager {
1181
1694
  constructor(request = monolithRequest, paths = {
1182
1695
  homeDir: ENGINE_ENV.HOME_DIR,
@@ -1204,8 +1717,8 @@ var InfisicalTokenManager = class extends BaseRefreshManager {
1204
1717
  }
1205
1718
  };
1206
1719
  async function applyInfisicalCredentials(data, paths) {
1207
- const credentialPath = path4.join(paths.homeDir, ".replicas", "infisical-env.sh");
1208
- const configPath = path4.join(paths.workspaceRoot, ".infisical.json");
1720
+ const credentialPath = path5.join(paths.homeDir, ".replicas", "infisical-env.sh");
1721
+ const configPath = path5.join(paths.workspaceRoot, ".infisical.json");
1209
1722
  if (!data.configured) {
1210
1723
  delete process.env.INFISICAL_TOKEN;
1211
1724
  delete process.env.INFISICAL_DOMAIN;
@@ -1234,8 +1747,8 @@ var infisicalTokenManager = new InfisicalTokenManager();
1234
1747
 
1235
1748
  // src/utils/logger.ts
1236
1749
  import { mkdir as mkdir3, writeFile as writeFile2 } from "fs/promises";
1237
- import { homedir as homedir2 } from "os";
1238
- import { join as join5 } from "path";
1750
+ import { homedir as homedir4 } from "os";
1751
+ import { join as join7 } from "path";
1239
1752
  import { format } from "util";
1240
1753
  import { randomBytes } from "crypto";
1241
1754
 
@@ -1247,8 +1760,8 @@ var StreamWriter = class {
1247
1760
  backpressured = false;
1248
1761
  droppedCount = 0;
1249
1762
  flushTimer = null;
1250
- open(path5, highWaterMark = DEFAULT_HIGH_WATER) {
1251
- this.stream = createWriteStream(path5, { flags: "a", highWaterMark });
1763
+ open(path6, highWaterMark = DEFAULT_HIGH_WATER) {
1764
+ this.stream = createWriteStream(path6, { flags: "a", highWaterMark });
1252
1765
  this.stream.on("error", () => {
1253
1766
  this.stream = null;
1254
1767
  });
@@ -1310,7 +1823,7 @@ var StreamWriter = class {
1310
1823
  };
1311
1824
 
1312
1825
  // src/utils/logger.ts
1313
- var LOG_DIR = join5(homedir2(), ".replicas", "logs");
1826
+ var LOG_DIR = join7(homedir4(), ".replicas", "logs");
1314
1827
  var EngineLogger = class {
1315
1828
  _sessionId = null;
1316
1829
  patched = false;
@@ -1321,7 +1834,7 @@ var EngineLogger = class {
1321
1834
  async initialize() {
1322
1835
  await mkdir3(LOG_DIR, { recursive: true });
1323
1836
  this._sessionId = this.createSessionId();
1324
- const logPath = join5(LOG_DIR, `${this._sessionId}.log`);
1837
+ const logPath = join7(LOG_DIR, `${this._sessionId}.log`);
1325
1838
  await writeFile2(logPath, `=== Replicas Engine Session ${this._sessionId} ===
1326
1839
  `, "utf-8");
1327
1840
  this.writer.open(logPath);
@@ -1368,32 +1881,32 @@ var engineLogger = new EngineLogger();
1368
1881
  // src/services/replicas-config-service.ts
1369
1882
  import { readFile as readFile6, appendFile, writeFile as writeFile4, mkdir as mkdir6 } from "fs/promises";
1370
1883
  import { existsSync as existsSync3 } from "fs";
1371
- import { join as join9 } from "path";
1372
- import { homedir as homedir6 } from "os";
1884
+ import { join as join11 } from "path";
1885
+ import { homedir as homedir8 } from "os";
1373
1886
  import { spawn as spawn2 } from "child_process";
1374
1887
 
1375
1888
  // src/services/environment-details-service.ts
1376
1889
  import { mkdir as mkdir4, readFile as readFile4 } from "fs/promises";
1377
1890
  import { existsSync as existsSync2 } from "fs";
1378
- import { homedir as homedir4 } from "os";
1379
- import { join as join7 } from "path";
1891
+ import { homedir as homedir6 } from "os";
1892
+ import { join as join9 } from "path";
1380
1893
 
1381
1894
  // src/managers/agent-auth-paths.ts
1382
- import { homedir as homedir3 } from "os";
1383
- import { join as join6 } from "path";
1384
- var OPENCODE_AUTH_PATH = join6(homedir3(), ".local", "share", "opencode", "auth.json");
1385
- var PI_AUTH_PATH = join6(homedir3(), ".pi", "agent", "auth.json");
1386
- var DEEPSEEK_AUTH_PATH = join6(homedir3(), ".replicas", "deepseek-auth.json");
1895
+ import { homedir as homedir5 } from "os";
1896
+ import { join as join8 } from "path";
1897
+ var OPENCODE_AUTH_PATH = join8(homedir5(), ".local", "share", "opencode", "auth.json");
1898
+ var PI_AUTH_PATH = join8(homedir5(), ".pi", "agent", "auth.json");
1899
+ var DEEPSEEK_AUTH_PATH = join8(homedir5(), ".replicas", "deepseek-auth.json");
1387
1900
 
1388
1901
  // src/managers/deepseek-auth.ts
1389
- import { readFileSync as readFileSync2 } from "fs";
1902
+ import { readFileSync as readFileSync4 } from "fs";
1390
1903
  import { z } from "zod";
1391
1904
  var authSchema = z.object({
1392
1905
  openrouter: z.object({ type: z.literal("api"), key: z.string().min(1) })
1393
1906
  });
1394
1907
  function getDeepseekApiKey() {
1395
1908
  try {
1396
- const parsed = authSchema.safeParse(JSON.parse(readFileSync2(DEEPSEEK_AUTH_PATH, "utf8")));
1909
+ const parsed = authSchema.safeParse(JSON.parse(readFileSync4(DEEPSEEK_AUTH_PATH, "utf8")));
1397
1910
  return parsed.success ? parsed.data.openrouter.key : null;
1398
1911
  } catch {
1399
1912
  return null;
@@ -1406,11 +1919,11 @@ function detectCodexAuthMethod() {
1406
1919
  }
1407
1920
 
1408
1921
  // src/services/environment-details-service.ts
1409
- var REPLICAS_DIR = join7(homedir4(), ".replicas");
1410
- var DETAILS_FILE = join7(REPLICAS_DIR, "environment-details.json");
1411
- var CLAUDE_CREDENTIALS_PATH = join7(homedir4(), ".claude", ".credentials.json");
1412
- var GH_HOSTS_PATH = join7(homedir4(), ".config", "gh", "hosts.yml");
1413
- var GIT_CREDENTIALS_PATH = join7(homedir4(), ".git-credentials");
1922
+ var REPLICAS_DIR = join9(homedir6(), ".replicas");
1923
+ var DETAILS_FILE = join9(REPLICAS_DIR, "environment-details.json");
1924
+ var CLAUDE_CREDENTIALS_PATH = join9(homedir6(), ".claude", ".credentials.json");
1925
+ var GH_HOSTS_PATH = join9(homedir6(), ".config", "gh", "hosts.yml");
1926
+ var GIT_CREDENTIALS_PATH = join9(homedir6(), ".git-credentials");
1414
1927
  function detectClaudeAuthMethod() {
1415
1928
  if (existsSync2(CLAUDE_CREDENTIALS_PATH)) {
1416
1929
  return "oauth";
@@ -1622,8 +2135,8 @@ var environmentDetailsService = new EnvironmentDetailsService();
1622
2135
 
1623
2136
  // src/services/start-hook-logs-service.ts
1624
2137
  import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile3, readdir as readdir2 } from "fs/promises";
1625
- import { homedir as homedir5 } from "os";
1626
- import { join as join8 } from "path";
2138
+ import { homedir as homedir7 } from "os";
2139
+ import { join as join10 } from "path";
1627
2140
 
1628
2141
  // src/services/hook-log-files.ts
1629
2142
  import { createHash } from "crypto";
@@ -1635,7 +2148,7 @@ function repoHookLogFilename(repoName) {
1635
2148
  }
1636
2149
 
1637
2150
  // src/services/start-hook-logs-service.ts
1638
- var LOGS_DIR = join8(homedir5(), ".replicas", "start-hook-logs");
2151
+ var LOGS_DIR = join10(homedir7(), ".replicas", "start-hook-logs");
1639
2152
  function withPreview(stored) {
1640
2153
  const preview = buildHookOutputPreview(stored.output);
1641
2154
  return { ...stored, ...preview };
@@ -1673,7 +2186,7 @@ var StartHookLogsService = class {
1673
2186
  await this.ensureDir();
1674
2187
  const log = { hookType, hookName, repoName: hookName, ...entry };
1675
2188
  const filename = hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
1676
- await writeFile3(join8(LOGS_DIR, filename), `${JSON.stringify(log, null, 2)}
2189
+ await writeFile3(join10(LOGS_DIR, filename), `${JSON.stringify(log, null, 2)}
1677
2190
  `, "utf-8");
1678
2191
  }
1679
2192
  async saveEnvironmentLog(entry) {
@@ -1698,7 +2211,7 @@ var StartHookLogsService = class {
1698
2211
  continue;
1699
2212
  }
1700
2213
  try {
1701
- const raw = await readFile5(join8(LOGS_DIR, file), "utf-8");
2214
+ const raw = await readFile5(join10(LOGS_DIR, file), "utf-8");
1702
2215
  const stored = normalizeStored(JSON.parse(raw));
1703
2216
  if (stored) {
1704
2217
  logs.push(withPreview(stored));
@@ -1717,7 +2230,7 @@ var StartHookLogsService = class {
1717
2230
  async getFullOutput(hookType, hookName) {
1718
2231
  const filename = hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
1719
2232
  try {
1720
- const raw = await readFile5(join8(LOGS_DIR, filename), "utf-8");
2233
+ const raw = await readFile5(join10(LOGS_DIR, filename), "utf-8");
1721
2234
  const stored = normalizeStored(JSON.parse(raw));
1722
2235
  if (!stored || stored.hookType !== hookType || stored.hookName !== hookName) {
1723
2236
  return null;
@@ -1734,7 +2247,7 @@ var StartHookLogsService = class {
1734
2247
  var startHookLogsService = new StartHookLogsService();
1735
2248
 
1736
2249
  // src/services/replicas-config-service.ts
1737
- var START_HOOKS_LOG = join9(homedir6(), ".replicas", "startHooks.log");
2250
+ var START_HOOKS_LOG = join11(homedir8(), ".replicas", "startHooks.log");
1738
2251
  var START_HOOKS_RUNNING_PROMPT = `IMPORTANT - Start Hooks Running:
1739
2252
  Start hooks are shell commands/scripts set by repository owners that run on workspace startup.
1740
2253
  These hooks are currently executing in the background. You can:
@@ -1745,7 +2258,7 @@ The start hooks may install dependencies, build projects, or perform other setup
1745
2258
  If your task depends on setup being complete, check the log file before proceeding.`;
1746
2259
  async function readReplicasConfigFromDir(dirPath) {
1747
2260
  for (const filename of REPLICAS_CONFIG_FILENAMES) {
1748
- const configPath = join9(dirPath, filename);
2261
+ const configPath = join11(dirPath, filename);
1749
2262
  if (!existsSync3(configPath)) {
1750
2263
  continue;
1751
2264
  }
@@ -1815,7 +2328,7 @@ var ReplicasConfigService = class {
1815
2328
  const logLine = `[${timestamp}] ${message}
1816
2329
  `;
1817
2330
  try {
1818
- await mkdir6(join9(homedir6(), ".replicas"), { recursive: true });
2331
+ await mkdir6(join11(homedir8(), ".replicas"), { recursive: true });
1819
2332
  await appendFile(START_HOOKS_LOG, logLine, "utf-8");
1820
2333
  } catch (error) {
1821
2334
  console.error("Failed to write to start hooks log:", error);
@@ -1827,7 +2340,7 @@ var ReplicasConfigService = class {
1827
2340
  command: params.content,
1828
2341
  label: "env start hook",
1829
2342
  repoName: "environment",
1830
- cwd: homedir6(),
2343
+ cwd: homedir8(),
1831
2344
  timeout: params.timeoutMs ?? DEFAULT_START_HOOK_TIMEOUT_MS,
1832
2345
  onOutputChunk: params.onOutputChunk
1833
2346
  });
@@ -1950,7 +2463,7 @@ var ReplicasConfigService = class {
1950
2463
  this.hooksCompleted = false;
1951
2464
  this.hooksFailed = false;
1952
2465
  try {
1953
- await mkdir6(join9(homedir6(), ".replicas"), { recursive: true });
2466
+ await mkdir6(join11(homedir8(), ".replicas"), { recursive: true });
1954
2467
  await writeFile4(
1955
2468
  START_HOOKS_LOG,
1956
2469
  `=== Start Hooks Execution Log ===
@@ -2145,11 +2658,11 @@ var replicasConfigService = new ReplicasConfigService();
2145
2658
 
2146
2659
  // src/services/event-service.ts
2147
2660
  import { mkdir as mkdir7 } from "fs/promises";
2148
- import { homedir as homedir7 } from "os";
2149
- import { join as join10 } from "path";
2661
+ import { homedir as homedir9 } from "os";
2662
+ import { join as join12 } from "path";
2150
2663
  import { randomUUID } from "crypto";
2151
- var ENGINE_DIR = join10(homedir7(), ".replicas", "engine");
2152
- var EVENTS_FILE = join10(ENGINE_DIR, "events.jsonl");
2664
+ var ENGINE_DIR = join12(homedir9(), ".replicas", "engine");
2665
+ var EVENTS_FILE = join12(ENGINE_DIR, "events.jsonl");
2153
2666
  var EventService = class {
2154
2667
  subscribers = /* @__PURE__ */ new Map();
2155
2668
  writer = new StreamWriter();
@@ -2183,9 +2696,9 @@ var eventService = new EventService();
2183
2696
  import { mkdir as mkdir8, readFile as readFile7 } from "fs/promises";
2184
2697
  import { existsSync as existsSync4 } from "fs";
2185
2698
  import { randomUUID as randomUUID2 } from "crypto";
2186
- import { homedir as homedir8 } from "os";
2187
- import { dirname as dirname2, join as join11 } from "path";
2188
- var PREVIEW_PORTS_FILE = join11(homedir8(), ".replicas", "preview-ports.json");
2699
+ import { homedir as homedir10 } from "os";
2700
+ import { dirname as dirname2, join as join13 } from "path";
2701
+ var PREVIEW_PORTS_FILE = join13(homedir10(), ".replicas", "preview-ports.json");
2189
2702
  async function readPreviewsFile() {
2190
2703
  try {
2191
2704
  if (!existsSync4(PREVIEW_PORTS_FILE)) {
@@ -2297,7 +2810,7 @@ async function registerDesktopPreview() {
2297
2810
  // src/services/chat/chat-service.ts
2298
2811
  import { existsSync as existsSync8 } from "fs";
2299
2812
  import { appendFile as appendFile4, copyFile, mkdir as mkdir17, readFile as readFile17, rename as rename3, rm as rm2 } from "fs/promises";
2300
- import { join as join27 } from "path";
2813
+ import { join as join29 } from "path";
2301
2814
  import { randomUUID as randomUUID8 } from "crypto";
2302
2815
 
2303
2816
  // src/managers/claude-manager.ts
@@ -2305,9 +2818,9 @@ import {
2305
2818
  query
2306
2819
  } from "@anthropic-ai/claude-agent-sdk";
2307
2820
  import { randomUUID as randomUUID4 } from "crypto";
2308
- import { dirname as dirname4, join as join15 } from "path";
2821
+ import { dirname as dirname4, join as join17 } from "path";
2309
2822
  import { mkdir as mkdir10 } from "fs/promises";
2310
- import { homedir as homedir10 } from "os";
2823
+ import { homedir as homedir12 } from "os";
2311
2824
 
2312
2825
  // src/utils/linear-converter.ts
2313
2826
  function linearThoughtToResponse(thought) {
@@ -2692,8 +3205,8 @@ function extractPlanFromCodexAspNotification(notification) {
2692
3205
  // src/utils/image-utils.ts
2693
3206
  import { randomUUID as randomUUID3 } from "crypto";
2694
3207
  import { mkdir as mkdir9, unlink as unlink2, writeFile as writeFile5 } from "fs/promises";
2695
- import { homedir as homedir9 } from "os";
2696
- import { join as join12 } from "path";
3208
+ import { homedir as homedir11 } from "os";
3209
+ import { join as join14 } from "path";
2697
3210
  function isImageMediaType(value) {
2698
3211
  return IMAGE_MEDIA_TYPES.includes(value);
2699
3212
  }
@@ -2793,14 +3306,14 @@ async function normalizeImages(images) {
2793
3306
  }
2794
3307
  return normalized;
2795
3308
  }
2796
- async function saveNormalizedImagesToTempFiles(images, tempImageDir = join12(homedir9(), ".replicas", "codex", "temp-images")) {
3309
+ async function saveNormalizedImagesToTempFiles(images, tempImageDir = join14(homedir11(), ".replicas", "codex", "temp-images")) {
2797
3310
  await mkdir9(tempImageDir, { recursive: true });
2798
3311
  const tempPaths = [];
2799
3312
  try {
2800
3313
  for (const image of images) {
2801
3314
  const ext = image.source.media_type.split("/")[1] || "png";
2802
3315
  const filename = `img_${randomUUID3()}.${ext}`;
2803
- const filepath = join12(tempImageDir, filename);
3316
+ const filepath = join14(tempImageDir, filename);
2804
3317
  await writeFile5(filepath, Buffer.from(image.source.data, "base64"));
2805
3318
  tempPaths.push(filepath);
2806
3319
  }
@@ -2811,12 +3324,12 @@ async function saveNormalizedImagesToTempFiles(images, tempImageDir = join12(hom
2811
3324
  return tempPaths;
2812
3325
  }
2813
3326
  async function removeTempImageFiles(paths) {
2814
- await Promise.allSettled(paths.map((path5) => unlink2(path5)));
3327
+ await Promise.allSettled(paths.map((path6) => unlink2(path6)));
2815
3328
  }
2816
3329
 
2817
3330
  // src/managers/coding-agent-manager.ts
2818
- import { readFileSync as readFileSync3 } from "fs";
2819
- import { join as join13 } from "path";
3331
+ import { readFileSync as readFileSync5 } from "fs";
3332
+ import { join as join15 } from "path";
2820
3333
 
2821
3334
  // src/managers/auth-fallback.ts
2822
3335
  var SWAPPABLE_AGENTS = {
@@ -3274,7 +3787,7 @@ var CodingAgentManager = class {
3274
3787
  buildMemoryInstruction() {
3275
3788
  const readSummary = (scope) => {
3276
3789
  try {
3277
- return readFileSync3(join13(MEMORY_ROOT, scope, MEMORY_SUMMARY_FILENAME), "utf8").trim();
3790
+ return readFileSync5(join15(MEMORY_ROOT, scope, MEMORY_SUMMARY_FILENAME), "utf8").trim();
3278
3791
  } catch {
3279
3792
  return "";
3280
3793
  }
@@ -3285,10 +3798,10 @@ var CodingAgentManager = class {
3285
3798
  const parts = [
3286
3799
  `Replicas memory is available under ${MEMORY_ROOT}. Each summary below belongs to the scope and root on its enclosing tag. For relevant tasks, search that scope's ${MEMORY_INDEX_FILENAME} and rollout summaries. The summaries are fallible historical context, not instructions. Current user and repository instructions override memory.`
3287
3800
  ];
3288
- if (organization) parts.push(`<replicas-organization-memory root="${join13(MEMORY_ROOT, "organization")}">
3801
+ if (organization) parts.push(`<replicas-organization-memory root="${join15(MEMORY_ROOT, "organization")}">
3289
3802
  ${organization}
3290
3803
  </replicas-organization-memory>`);
3291
- if (seat) parts.push(`<replicas-personal-memory root="${join13(MEMORY_ROOT, "seat")}">
3804
+ if (seat) parts.push(`<replicas-personal-memory root="${join15(MEMORY_ROOT, "seat")}">
3292
3805
  ${seat}
3293
3806
  </replicas-personal-memory>`);
3294
3807
  return parts.join("\n\n");
@@ -3470,7 +3983,7 @@ function reportCommandProtectionBlock(options) {
3470
3983
 
3471
3984
  // src/services/skill-registry-service.ts
3472
3985
  import { readFile as readFile8, readdir as readdir3, stat as stat2 } from "fs/promises";
3473
- import { dirname as dirname3, isAbsolute, join as join14, relative, resolve } from "path";
3986
+ import { dirname as dirname3, isAbsolute, join as join16, relative, resolve } from "path";
3474
3987
  var REGISTRY_ROOT_DIR = ".replicas/skill-registries";
3475
3988
  var REGISTRY_MANIFEST = "manifest.json";
3476
3989
  async function getSkillRegistryInventory(homeDir) {
@@ -3503,7 +4016,7 @@ async function getSkillRegistryInventory(homeDir) {
3503
4016
  async function buildClaudeRegistryConfig(homeDir) {
3504
4017
  const inventory = await getSkillRegistryInventory(homeDir);
3505
4018
  return {
3506
- plugins: inventory.claudePluginRoots.map((path5) => ({ type: "local", path: path5 })),
4019
+ plugins: inventory.claudePluginRoots.map((path6) => ({ type: "local", path: path6 })),
3507
4020
  enableAllSkills: inventory.claudePluginRoots.length > 0 || inventory.standaloneSkills.length > 0
3508
4021
  };
3509
4022
  }
@@ -3531,10 +4044,10 @@ async function scanRegistry(registryDir) {
3531
4044
  }
3532
4045
  async function findSkillCollections(registryDir) {
3533
4046
  const candidateRoots = [
3534
- { source: "skills", root: join14(registryDir, "skills") },
3535
- { source: "agents", root: join14(registryDir, ".agents", "skills") },
3536
- { source: "codex", root: join14(registryDir, ".codex", "skills") },
3537
- { source: "claude", root: join14(registryDir, ".claude", "skills") }
4047
+ { source: "skills", root: join16(registryDir, "skills") },
4048
+ { source: "agents", root: join16(registryDir, ".agents", "skills") },
4049
+ { source: "codex", root: join16(registryDir, ".codex", "skills") },
4050
+ { source: "claude", root: join16(registryDir, ".claude", "skills") }
3538
4051
  ];
3539
4052
  const collections = [];
3540
4053
  for (const { source, root } of candidateRoots) {
@@ -3548,9 +4061,9 @@ async function findSkillCollections(registryDir) {
3548
4061
  async function findSkillDirsInRoot(root) {
3549
4062
  const skillDirs = [];
3550
4063
  for (const dirent of await safeReadDir(root)) {
3551
- const skillDir = join14(root, dirent.name);
4064
+ const skillDir = join16(root, dirent.name);
3552
4065
  if (!await isDirectoryDirent(dirent, skillDir)) continue;
3553
- if (await fileExists(join14(skillDir, "SKILL.md"))) {
4066
+ if (await fileExists(join16(skillDir, "SKILL.md"))) {
3554
4067
  skillDirs.push(skillDir);
3555
4068
  }
3556
4069
  }
@@ -3560,9 +4073,9 @@ async function findTopLevelSkills(registryDir) {
3560
4073
  const skills = [];
3561
4074
  for (const dirent of await safeReadDir(registryDir)) {
3562
4075
  if (dirent.name.startsWith(".") || dirent.name === "skills" || dirent.name === "plugins") continue;
3563
- const skillDir = join14(registryDir, dirent.name);
4076
+ const skillDir = join16(registryDir, dirent.name);
3564
4077
  if (!await isDirectoryDirent(dirent, skillDir)) continue;
3565
- if (await fileExists(join14(skillDir, "SKILL.md"))) {
4078
+ if (await fileExists(join16(skillDir, "SKILL.md"))) {
3566
4079
  skills.push({ source: "root", skillDir });
3567
4080
  }
3568
4081
  }
@@ -3573,10 +4086,10 @@ async function findClaudePluginRoots(registryDir) {
3573
4086
  async function walk(dir) {
3574
4087
  for (const dirent of await safeReadDir(dir)) {
3575
4088
  if (dirent.name === ".git") continue;
3576
- const child = join14(dir, dirent.name);
4089
+ const child = join16(dir, dirent.name);
3577
4090
  if (!await isDirectoryDirent(dirent, child)) continue;
3578
4091
  if (dirent.name === ".claude-plugin") {
3579
- if (await fileExists(join14(child, "plugin.json"))) {
4092
+ if (await fileExists(join16(child, "plugin.json"))) {
3580
4093
  roots.push(dirname3(child));
3581
4094
  }
3582
4095
  continue;
@@ -3588,7 +4101,7 @@ async function findClaudePluginRoots(registryDir) {
3588
4101
  return uniqueStrings(roots);
3589
4102
  }
3590
4103
  async function hasCodexMarketplace(registryDir) {
3591
- return await fileExists(join14(registryDir, ".agents", "plugins", "marketplace.json")) || await fileExists(join14(registryDir, ".codex", "plugins", "marketplace.json"));
4104
+ return await fileExists(join16(registryDir, ".agents", "plugins", "marketplace.json")) || await fileExists(join16(registryDir, ".codex", "plugins", "marketplace.json"));
3592
4105
  }
3593
4106
  async function installCodexRegistryPlugins(client2, inventory) {
3594
4107
  const cwds = inventory.codexMarketplaceCwds;
@@ -3630,10 +4143,10 @@ async function readManifest(homeDir) {
3630
4143
  }
3631
4144
  }
3632
4145
  function getRegistryRoot(homeDir) {
3633
- return join14(homeDir, REGISTRY_ROOT_DIR);
4146
+ return join16(homeDir, REGISTRY_ROOT_DIR);
3634
4147
  }
3635
4148
  function getManifestPath(homeDir) {
3636
- return join14(getRegistryRoot(homeDir), REGISTRY_MANIFEST);
4149
+ return join16(getRegistryRoot(homeDir), REGISTRY_MANIFEST);
3637
4150
  }
3638
4151
  function emptyInventory(registryRoot) {
3639
4152
  return {
@@ -3661,31 +4174,31 @@ function uniqueStandaloneSkills(skills) {
3661
4174
  }
3662
4175
  return unique;
3663
4176
  }
3664
- async function safeReadDir(path5) {
4177
+ async function safeReadDir(path6) {
3665
4178
  try {
3666
- return await readdir3(path5, { withFileTypes: true });
4179
+ return await readdir3(path6, { withFileTypes: true });
3667
4180
  } catch (error) {
3668
4181
  if (isNotFoundError(error)) return [];
3669
4182
  throw error;
3670
4183
  }
3671
4184
  }
3672
- async function isDirectoryDirent(dirent, path5) {
4185
+ async function isDirectoryDirent(dirent, path6) {
3673
4186
  if (dirent.isDirectory()) return true;
3674
4187
  if (!dirent.isSymbolicLink()) return false;
3675
- return directoryExists(path5);
4188
+ return directoryExists(path6);
3676
4189
  }
3677
- async function directoryExists(path5) {
4190
+ async function directoryExists(path6) {
3678
4191
  try {
3679
- const pathStat = await stat2(path5);
4192
+ const pathStat = await stat2(path6);
3680
4193
  return pathStat.isDirectory();
3681
4194
  } catch (error) {
3682
4195
  if (isNotFoundError(error)) return false;
3683
4196
  throw error;
3684
4197
  }
3685
4198
  }
3686
- async function fileExists(path5) {
4199
+ async function fileExists(path6) {
3687
4200
  try {
3688
- const pathStat = await stat2(path5);
4201
+ const pathStat = await stat2(path6);
3689
4202
  return pathStat.isFile();
3690
4203
  } catch (error) {
3691
4204
  if (isNotFoundError(error)) return false;
@@ -4080,7 +4593,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
4080
4593
  authRetrying = false;
4081
4594
  constructor(options) {
4082
4595
  super({ ...options, provider: AGENT.CLAUDE });
4083
- this.historyFilePath = options.historyFilePath ?? join15(homedir10(), ".replicas", "claude", "history.jsonl");
4596
+ this.historyFilePath = options.historyFilePath ?? join17(homedir12(), ".replicas", "claude", "history.jsonl");
4084
4597
  this.historyFile = new CodexHistoryFile(this.historyFilePath);
4085
4598
  this.systemPromptOverride = options.systemPromptOverride;
4086
4599
  this.toolsOverride = options.tools;
@@ -5134,7 +5647,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
5134
5647
 
5135
5648
  // src/managers/codex-asp/codex-asp-manager.ts
5136
5649
  import { readdir as readdir4 } from "fs/promises";
5137
- import { join as join17 } from "path";
5650
+ import { join as join19 } from "path";
5138
5651
 
5139
5652
  // src/managers/codex-asp/asp-host.ts
5140
5653
  var hostPromise = null;
@@ -5249,7 +5762,7 @@ var CodexQuotaStatusTracker = class {
5249
5762
  };
5250
5763
 
5251
5764
  // src/managers/codex-asp/mappers.ts
5252
- import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
5765
+ import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
5253
5766
  var localImageCache = /* @__PURE__ */ new Map();
5254
5767
  var DEFAULT_MODEL = DEFAULT_CODEX_MODEL;
5255
5768
  var THREAD_START_METHOD = "thread/start";
@@ -5371,16 +5884,16 @@ function transcriptItemsForTurn(turn) {
5371
5884
  const otherItems = turn.items.filter((item) => item.type !== "userMessage");
5372
5885
  return [...userItems, ...otherItems];
5373
5886
  }
5374
- function userImageForLocalPath(path5) {
5375
- const cached = localImageCache.get(path5);
5887
+ function userImageForLocalPath(path6) {
5888
+ const cached = localImageCache.get(path6);
5376
5889
  if (cached) return cached;
5377
- if (!existsSync5(path5)) return null;
5890
+ if (!existsSync5(path6)) return null;
5378
5891
  const image = {
5379
5892
  type: "image",
5380
- mediaType: inferMediaType(path5),
5381
- data: readFileSync4(path5).toString("base64")
5893
+ mediaType: inferMediaType(path6),
5894
+ data: readFileSync6(path6).toString("base64")
5382
5895
  };
5383
- if (image.data.length > 0) localImageCache.set(path5, image);
5896
+ if (image.data.length > 0) localImageCache.set(path6, image);
5384
5897
  return image;
5385
5898
  }
5386
5899
  function userImagesForInput(input) {
@@ -5778,9 +6291,9 @@ async function buildTurnInput(request) {
5778
6291
  }
5779
6292
  const normalizedImages = await normalizeImages(request.images);
5780
6293
  const tempImagePaths = await saveNormalizedImagesToTempFiles(normalizedImages);
5781
- input.push(...tempImagePaths.map((path5) => ({
6294
+ input.push(...tempImagePaths.map((path6) => ({
5782
6295
  type: "localImage",
5783
- path: path5
6296
+ path: path6
5784
6297
  })));
5785
6298
  return { input, tempImagePaths };
5786
6299
  }
@@ -5869,19 +6382,19 @@ var TranscriptUpdateCoalescer = class {
5869
6382
  };
5870
6383
 
5871
6384
  // src/services/chat/history-paths.ts
5872
- import { homedir as homedir11 } from "os";
5873
- import { join as join16 } from "path";
5874
- var ENGINE_DIR2 = join16(homedir11(), ".replicas", "engine");
5875
- var CHATS_FILE = join16(ENGINE_DIR2, "chats.json");
5876
- var CLAUDE_HISTORY_DIR = join16(ENGINE_DIR2, "claude-histories");
5877
- var RELAY_HISTORY_DIR = join16(ENGINE_DIR2, "relay-histories");
5878
- var CODEX_HISTORY_DIR = join16(ENGINE_DIR2, "codex-histories");
5879
- var CURSOR_HISTORY_DIR = join16(ENGINE_DIR2, "cursor-histories");
5880
- var OPENCODE_HISTORY_DIR = join16(ENGINE_DIR2, "opencode-histories");
5881
- var PI_HISTORY_DIR = join16(ENGINE_DIR2, "pi-histories");
5882
- var DEEPSEEK_HISTORY_DIR = join16(ENGINE_DIR2, "deepseek-histories");
5883
- var FX_HISTORY_DIR = join16(ENGINE_DIR2, "fx-histories");
5884
- var KIMI_HISTORY_DIR = join16(ENGINE_DIR2, "kimi-histories");
6385
+ import { homedir as homedir13 } from "os";
6386
+ import { join as join18 } from "path";
6387
+ var ENGINE_DIR2 = join18(homedir13(), ".replicas", "engine");
6388
+ var CHATS_FILE = join18(ENGINE_DIR2, "chats.json");
6389
+ var CLAUDE_HISTORY_DIR = join18(ENGINE_DIR2, "claude-histories");
6390
+ var RELAY_HISTORY_DIR = join18(ENGINE_DIR2, "relay-histories");
6391
+ var CODEX_HISTORY_DIR = join18(ENGINE_DIR2, "codex-histories");
6392
+ var CURSOR_HISTORY_DIR = join18(ENGINE_DIR2, "cursor-histories");
6393
+ var OPENCODE_HISTORY_DIR = join18(ENGINE_DIR2, "opencode-histories");
6394
+ var PI_HISTORY_DIR = join18(ENGINE_DIR2, "pi-histories");
6395
+ var DEEPSEEK_HISTORY_DIR = join18(ENGINE_DIR2, "deepseek-histories");
6396
+ var FX_HISTORY_DIR = join18(ENGINE_DIR2, "fx-histories");
6397
+ var KIMI_HISTORY_DIR = join18(ENGINE_DIR2, "kimi-histories");
5885
6398
  var HISTORY_DIR_BY_PROVIDER = {
5886
6399
  claude: CLAUDE_HISTORY_DIR,
5887
6400
  relay: RELAY_HISTORY_DIR,
@@ -5940,7 +6453,7 @@ async function readCodexAspThreadHistory(threadId) {
5940
6453
  }
5941
6454
  for (const entry of entries) {
5942
6455
  if (!entry.isFile() || !entry.name.endsWith(".jsonl") || entry.name.endsWith(".pages.jsonl")) continue;
5943
- const history = await new CodexHistoryFile(join17(CODEX_HISTORY_DIR, entry.name)).load();
6456
+ const history = await new CodexHistoryFile(join19(CODEX_HISTORY_DIR, entry.name)).load();
5944
6457
  const transcript = history.transcriptsByThreadId.get(threadId);
5945
6458
  if (transcript) {
5946
6459
  return {
@@ -7291,7 +7804,7 @@ var CodexAspManager = class extends CodingAgentManager {
7291
7804
 
7292
7805
  // src/managers/cursor-manager.ts
7293
7806
  import { mkdir as mkdir11, readFile as readFile10, readdir as readdir5 } from "fs/promises";
7294
- import { basename, dirname as dirname5, extname, join as join18 } from "path";
7807
+ import { basename, dirname as dirname5, extname, join as join20 } from "path";
7295
7808
  import { parse as parseYaml } from "yaml";
7296
7809
  import { Agent as CursorAgent } from "@cursor/sdk";
7297
7810
  var CURSOR_SLASH_COMMANDS_CACHE_MS = 3e4;
@@ -7364,7 +7877,7 @@ async function listCursorCommandsInDirectory(directory) {
7364
7877
  const name = basename(entry.name, ".md");
7365
7878
  let description;
7366
7879
  try {
7367
- description = extractCursorCommandDescription(await readFile10(join18(directory, entry.name), "utf8"));
7880
+ description = extractCursorCommandDescription(await readFile10(join20(directory, entry.name), "utf8"));
7368
7881
  } catch (error) {
7369
7882
  console.warn("[CursorManager] Failed to read slash command file:", error);
7370
7883
  }
@@ -7388,7 +7901,7 @@ var CursorManager = class extends CodingAgentManager {
7388
7901
  slashCommandsRequest = null;
7389
7902
  constructor(options) {
7390
7903
  super(options);
7391
- this.historyFilePath = options.historyFilePath ?? join18(ENGINE_ENV.HOME_DIR, ".replicas", "cursor", "history.jsonl");
7904
+ this.historyFilePath = options.historyFilePath ?? join20(ENGINE_ENV.HOME_DIR, ".replicas", "cursor", "history.jsonl");
7392
7905
  this.historyFile = new CodexHistoryFile(this.historyFilePath);
7393
7906
  this.initializeManager(this.processMessageInternal.bind(this));
7394
7907
  }
@@ -7462,7 +7975,7 @@ var CursorManager = class extends CodingAgentManager {
7462
7975
  this.slashCommandsRequest ??= (async () => {
7463
7976
  try {
7464
7977
  const repoDirectories = await getAgentAdditionalDirectories();
7465
- const commandDirectories = [this.workingDirectory, ...repoDirectories, ENGINE_ENV.HOME_DIR].map((directory) => join18(directory, ".cursor", "commands"));
7978
+ const commandDirectories = [this.workingDirectory, ...repoDirectories, ENGINE_ENV.HOME_DIR].map((directory) => join20(directory, ".cursor", "commands"));
7466
7979
  const commands = mergeSlashCommands(
7467
7980
  ...await Promise.all(commandDirectories.map(listCursorCommandsInDirectory))
7468
7981
  );
@@ -7780,7 +8293,7 @@ ${instructions}
7780
8293
  import { spawn as spawn3 } from "child_process";
7781
8294
  import { randomUUID as randomUUID5 } from "crypto";
7782
8295
  import { createRequire } from "module";
7783
- import { dirname as dirname6, join as join19 } from "path";
8296
+ import { dirname as dirname6, join as join21 } from "path";
7784
8297
  import { fileURLToPath } from "url";
7785
8298
  import { existsSync as existsSync6 } from "fs";
7786
8299
  import { mkdir as mkdir12 } from "fs/promises";
@@ -7795,11 +8308,11 @@ var questionSelectionSchema = z2.record(z2.string(), z2.object({
7795
8308
  custom: z2.string().optional()
7796
8309
  }));
7797
8310
  var require2 = createRequire(import.meta.url);
7798
- var DSH_BIN = join19(dirname6(require2.resolve("@deepseek-ai/dsh/package.json")), "lib", "bin.js");
8311
+ var DSH_BIN = join21(dirname6(require2.resolve("@deepseek-ai/dsh/package.json")), "lib", "bin.js");
7799
8312
  var MANAGER_DIR = dirname6(fileURLToPath(import.meta.url));
7800
8313
  var DSH_PATCH = [
7801
- join19(MANAGER_DIR, "..", "..", "scripts", "deepseek", "replicas.cordis.patch.yml"),
7802
- join19(MANAGER_DIR, "..", "..", "..", "scripts", "deepseek", "replicas.cordis.patch.yml")
8314
+ join21(MANAGER_DIR, "..", "..", "scripts", "deepseek", "replicas.cordis.patch.yml"),
8315
+ join21(MANAGER_DIR, "..", "..", "..", "scripts", "deepseek", "replicas.cordis.patch.yml")
7803
8316
  ].find(existsSync6) ?? "";
7804
8317
  var DeepseekApiClient = class extends AbstractApiClient {
7805
8318
  constructor(baseUrl) {
@@ -7839,8 +8352,8 @@ var DeepseekApiClient = class extends AbstractApiClient {
7839
8352
  if (!execution.success) throw new Error(`DeepSeek Harness did not recognize ${line}.`);
7840
8353
  if (execution.data.result.kind === "error") throw new Error(execution.data.result.text ?? `DeepSeek Harness rejected ${line}.`);
7841
8354
  }
7842
- async *readWebSocket(path5, signal, schema, onOpen) {
7843
- const url = new URL(path5, this.baseUrl);
8355
+ async *readWebSocket(path6, signal, schema, onOpen) {
8356
+ const url = new URL(path6, this.baseUrl);
7844
8357
  url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
7845
8358
  const socket = new WebSocket(url);
7846
8359
  const inbox = [];
@@ -7913,7 +8426,7 @@ var DeepseekManager = class extends CodingAgentManager {
7913
8426
  constructor(options) {
7914
8427
  super(options);
7915
8428
  this.sessionId = options.initialSessionId ? sessionIdSchema.parse(options.initialSessionId) : null;
7916
- this.historyFilePath = options.historyFilePath ?? join19(ENGINE_ENV.HOME_DIR, ".replicas", "deepseek", "history.jsonl");
8429
+ this.historyFilePath = options.historyFilePath ?? join21(ENGINE_ENV.HOME_DIR, ".replicas", "deepseek", "history.jsonl");
7917
8430
  this.historyFile = new CodexHistoryFile(this.historyFilePath);
7918
8431
  this.initializeManager(this.processMessageInternal.bind(this));
7919
8432
  }
@@ -8000,7 +8513,7 @@ var DeepseekManager = class extends CodingAgentManager {
8000
8513
  ...process.env,
8001
8514
  DEEPSEEK_API_KEY: apiKey,
8002
8515
  DEEPSEEK_BASE_URL: "https://openrouter.ai/api/v1",
8003
- DSH_HOME: join19(ENGINE_ENV.HOME_DIR, ".replicas", "deepseek"),
8516
+ DSH_HOME: join21(ENGINE_ENV.HOME_DIR, ".replicas", "deepseek"),
8004
8517
  DSH_PERMISSION_MODE: "danger-full-access",
8005
8518
  DSH_TELEMETRY_DISABLED: "true"
8006
8519
  },
@@ -8710,7 +9223,7 @@ var KimiManager = class extends AcpManager {
8710
9223
  // src/managers/opencode-manager.ts
8711
9224
  import { existsSync as existsSync7 } from "fs";
8712
9225
  import { mkdir as mkdir14, readFile as readFile13 } from "fs/promises";
8713
- import { delimiter, dirname as dirname8, join as join20 } from "path";
9226
+ import { delimiter, dirname as dirname8, join as join22 } from "path";
8714
9227
  import { randomBytes as randomBytes2 } from "crypto";
8715
9228
  import { fileURLToPath as fileURLToPath2 } from "url";
8716
9229
  import { Agent } from "undici";
@@ -8757,7 +9270,7 @@ async function getAllowedOpenRouterModels() {
8757
9270
 
8758
9271
  // src/managers/opencode-manager.ts
8759
9272
  var OPENCODE_SHIM_DIR = dirname8(fileURLToPath2(new URL("../../scripts/opencode", import.meta.url)));
8760
- var OPENCODE_CONFIG_PATH = join20(ENGINE_ENV.HOME_DIR, ".config", "opencode", "opencode.json");
9273
+ var OPENCODE_CONFIG_PATH = join22(ENGINE_ENV.HOME_DIR, ".config", "opencode", "opencode.json");
8761
9274
  var OPENCODE_FETCH_DISPATCHER = new Agent({ headersTimeout: 0, bodyTimeout: 0 });
8762
9275
  var OPENCODE_SERVER_STARTUP_TIMEOUT_MS = 3e4;
8763
9276
  var OPENCODE_WORKSPACE_PERMISSION = {
@@ -9007,7 +9520,7 @@ var OpencodeManager = class extends CodingAgentManager {
9007
9520
  constructor(options) {
9008
9521
  super(options);
9009
9522
  this.sessionId = options.initialSessionId;
9010
- this.historyFilePath = options.historyFilePath ?? join20(ENGINE_ENV.HOME_DIR, ".replicas", "opencode", "history.jsonl");
9523
+ this.historyFilePath = options.historyFilePath ?? join22(ENGINE_ENV.HOME_DIR, ".replicas", "opencode", "history.jsonl");
9011
9524
  this.historyFile = new CodexHistoryFile(this.historyFilePath);
9012
9525
  this.initializeManager(this.processMessageInternal.bind(this));
9013
9526
  }
@@ -9517,7 +10030,7 @@ var OpencodeManager = class extends CodingAgentManager {
9517
10030
 
9518
10031
  // src/managers/pi-manager.ts
9519
10032
  import { mkdir as mkdir15 } from "fs/promises";
9520
- import { dirname as dirname9, join as join21 } from "path";
10033
+ import { dirname as dirname9, join as join23 } from "path";
9521
10034
  import {
9522
10035
  AuthStorage,
9523
10036
  createAgentSession,
@@ -9600,7 +10113,7 @@ var PiManager = class extends CodingAgentManager {
9600
10113
  providerApiKey = null;
9601
10114
  constructor(options) {
9602
10115
  super(options);
9603
- this.historyFilePath = options.historyFilePath ?? join21(PI_HISTORY_DIR, `${Date.now()}.jsonl`);
10116
+ this.historyFilePath = options.historyFilePath ?? join23(PI_HISTORY_DIR, `${Date.now()}.jsonl`);
9604
10117
  this.historyFile = new CodexHistoryFile(this.historyFilePath);
9605
10118
  this.initializeManager(this.processMessageInternal.bind(this));
9606
10119
  }
@@ -9700,7 +10213,7 @@ var PiManager = class extends CodingAgentManager {
9700
10213
  const sessionManager = this.initialSessionId ? SessionManager.open(this.initialSessionId, PI_HISTORY_DIR, this.workingDirectory) : SessionManager.create(this.workingDirectory, PI_HISTORY_DIR);
9701
10214
  const resourceLoader = new DefaultResourceLoader({
9702
10215
  cwd: this.workingDirectory,
9703
- agentDir: join21(ENGINE_ENV.HOME_DIR, ".pi", "agent"),
10216
+ agentDir: join23(ENGINE_ENV.HOME_DIR, ".pi", "agent"),
9704
10217
  extensionFactories: [registerCommandProtection(
9705
10218
  this.workingDirectory,
9706
10219
  this.historyFile,
@@ -9800,9 +10313,9 @@ function extractTextBlocks(content, textBlockType, separator = "\n") {
9800
10313
  const texts = content.map((block) => block && typeof block === "object" && "type" in block && block.type === textBlockType && "text" in block && typeof block.text === "string" ? block.text : "").filter(Boolean);
9801
10314
  return texts.length > 0 ? texts.join(separator) : null;
9802
10315
  }
9803
- async function engineFetch(path5, options) {
10316
+ async function engineFetch(path6, options) {
9804
10317
  const baseUrl = `http://localhost:${ENGINE_ENV.REPLICAS_ENGINE_PORT}`;
9805
- return fetch(`${baseUrl}${path5}`, {
10318
+ return fetch(`${baseUrl}${path6}`, {
9806
10319
  ...options,
9807
10320
  headers: {
9808
10321
  "Content-Type": "application/json",
@@ -10422,7 +10935,7 @@ import {
10422
10935
  rename as rename2,
10423
10936
  unlink as unlink3
10424
10937
  } from "fs/promises";
10425
- import { join as join22 } from "path";
10938
+ import { join as join24 } from "path";
10426
10939
  import { randomUUID as randomUUID7 } from "crypto";
10427
10940
 
10428
10941
  // src/analytics/agent/activity/skill-mcp-call-extractor.ts
@@ -10473,7 +10986,7 @@ var AgentChatActivityBuffer = class {
10473
10986
  options.storageName,
10474
10987
  ...options.legacyStorageNames ?? []
10475
10988
  ];
10476
- this.liveFile = join22(ENGINE_DIR2, `${options.storageName}.jsonl`);
10989
+ this.liveFile = join24(ENGINE_DIR2, `${options.storageName}.jsonl`);
10477
10990
  this.segmentFilePatterns = this.storageNames.map(
10478
10991
  (storageName) => new RegExp(`^${storageName}\\.(\\d+)\\.jsonl$`)
10479
10992
  );
@@ -10532,8 +11045,8 @@ var AgentChatActivityBuffer = class {
10532
11045
  await Promise.allSettled([...this.pendingAppends]);
10533
11046
  for (const storageName of this.storageNames) {
10534
11047
  await rename2(
10535
- join22(ENGINE_DIR2, `${storageName}.jsonl`),
10536
- join22(ENGINE_DIR2, `${storageName}.${Date.now()}.jsonl`)
11048
+ join24(ENGINE_DIR2, `${storageName}.jsonl`),
11049
+ join24(ENGINE_DIR2, `${storageName}.${Date.now()}.jsonl`)
10537
11050
  ).catch(() => {
10538
11051
  });
10539
11052
  }
@@ -10544,7 +11057,7 @@ var AgentChatActivityBuffer = class {
10544
11057
  if (!this.segmentFilePatterns.some((pattern) => pattern.test(entry)))
10545
11058
  continue;
10546
11059
  try {
10547
- await this.uploadSegment(join22(ENGINE_DIR2, entry));
11060
+ await this.uploadSegment(join24(ENGINE_DIR2, entry));
10548
11061
  flushed++;
10549
11062
  } catch (error) {
10550
11063
  failed++;
@@ -10576,7 +11089,7 @@ var AgentChatActivityBuffer = class {
10576
11089
  ) && entry.endsWith(UPLOADED_SUFFIX)
10577
11090
  ).sort();
10578
11091
  for (const entry of uploaded.slice(0, -MAX_UPLOADED_SEGMENTS)) {
10579
- await unlink3(join22(ENGINE_DIR2, entry)).catch(() => {
11092
+ await unlink3(join24(ENGINE_DIR2, entry)).catch(() => {
10580
11093
  });
10581
11094
  }
10582
11095
  return { flushed, failed };
@@ -10808,18 +11321,18 @@ var keepAliveService = new KeepAliveService();
10808
11321
 
10809
11322
  // src/services/canvas-service.ts
10810
11323
  import { readdir as readdir7, readFile as readFile15, stat as stat3 } from "fs/promises";
10811
- import { homedir as homedir12 } from "os";
10812
- import { join as join23 } from "path";
11324
+ import { homedir as homedir14 } from "os";
11325
+ import { join as join25 } from "path";
10813
11326
  var GLOBAL_CANVAS_DIRECTORIES = [
10814
- join23(homedir12(), ".claude", "plans"),
10815
- join23(process.env.XDG_DATA_HOME ?? join23(homedir12(), ".local", "share"), "opencode", "plans"),
10816
- join23(homedir12(), ".replicas", "canvas")
11327
+ join25(homedir14(), ".claude", "plans"),
11328
+ join25(process.env.XDG_DATA_HOME ?? join25(homedir14(), ".local", "share"), "opencode", "plans"),
11329
+ join25(homedir14(), ".replicas", "canvas")
10817
11330
  ];
10818
11331
  async function canvasDirectories() {
10819
11332
  const repositories = await gitService.listRepositories().catch(() => []);
10820
11333
  return [
10821
11334
  ...GLOBAL_CANVAS_DIRECTORIES,
10822
- ...repositories.map((repository) => join23(repository.path, ".opencode", "plans"))
11335
+ ...repositories.map((repository) => join25(repository.path, ".opencode", "plans"))
10823
11336
  ];
10824
11337
  }
10825
11338
  var CanvasService = class {
@@ -10843,7 +11356,7 @@ var CanvasService = class {
10843
11356
  for (const entry of entries) {
10844
11357
  if (entry.name.startsWith(".")) continue;
10845
11358
  const filename = current.relativePath ? `${current.relativePath}/${entry.name}` : entry.name;
10846
- const filePath = join23(current.directory, entry.name);
11359
+ const filePath = join25(current.directory, entry.name);
10847
11360
  if (entry.isDirectory()) {
10848
11361
  pending.push({ directory: filePath, relativePath: filename });
10849
11362
  continue;
@@ -10868,7 +11381,7 @@ var CanvasService = class {
10868
11381
  if (!safe) return null;
10869
11382
  const { kind, mimeType } = classifyCanvasFilename(safe);
10870
11383
  for (const directory of await this.directories()) {
10871
- const filePath = join23(directory, safe);
11384
+ const filePath = join25(directory, safe);
10872
11385
  let sizeBytes = 0;
10873
11386
  let updatedAt = "";
10874
11387
  try {
@@ -11040,13 +11553,13 @@ async function reconcileCanvasItems(filenames) {
11040
11553
  import { createReadStream } from "fs";
11041
11554
  import { createHash as createHash2 } from "crypto";
11042
11555
  import { readFile as readFile16, readdir as readdir8, stat as stat4 } from "fs/promises";
11043
- import { basename as basename2, join as join25 } from "path";
11556
+ import { basename as basename2, join as join27 } from "path";
11044
11557
 
11045
11558
  // src/services/chat/chat-senders.ts
11046
- import { join as join24 } from "path";
11047
- var CHAT_SENDERS_DIR = join24(ENGINE_DIR2, "chat-senders");
11559
+ import { join as join26 } from "path";
11560
+ var CHAT_SENDERS_DIR = join26(ENGINE_DIR2, "chat-senders");
11048
11561
  function chatMessageSendersFilePath(chatId) {
11049
- return join24(CHAT_SENDERS_DIR, `${chatId}.jsonl`);
11562
+ return join26(CHAT_SENDERS_DIR, `${chatId}.jsonl`);
11050
11563
  }
11051
11564
  function parseChatMessageSendersJsonl(content) {
11052
11565
  return content.split("\n").flatMap((line) => {
@@ -11062,9 +11575,9 @@ function parseChatMessageSendersJsonl(content) {
11062
11575
 
11063
11576
  // src/services/upload-chat-transcripts.ts
11064
11577
  var HISTORY_DIRS = [
11065
- join25(ENGINE_DIR2, "claude-histories"),
11066
- join25(ENGINE_DIR2, "relay-histories"),
11067
- join25(ENGINE_DIR2, "codex-histories")
11578
+ join27(ENGINE_DIR2, "claude-histories"),
11579
+ join27(ENGINE_DIR2, "relay-histories"),
11580
+ join27(ENGINE_DIR2, "codex-histories")
11068
11581
  ];
11069
11582
  async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map(), capture) {
11070
11583
  let flushed = 0;
@@ -11082,7 +11595,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map(), ca
11082
11595
  if (!entry.endsWith(".jsonl")) continue;
11083
11596
  const chatId = basename2(entry, ".jsonl");
11084
11597
  tasks.push(
11085
- uploadChatTranscript(chatId, join25(dir, entry), chatsById.get(chatId), capture).then((artifact) => {
11598
+ uploadChatTranscript(chatId, join27(dir, entry), chatsById.get(chatId), capture).then((artifact) => {
11086
11599
  flushed++;
11087
11600
  if (artifact && capture) revisions.push(artifact);
11088
11601
  }).catch((err) => {
@@ -11200,7 +11713,7 @@ async function flushRepoState() {
11200
11713
  // src/services/upload-engine-logs.ts
11201
11714
  import { createReadStream as createReadStream2 } from "fs";
11202
11715
  import { readdir as readdir9, stat as stat5 } from "fs/promises";
11203
- import { join as join26 } from "path";
11716
+ import { join as join28 } from "path";
11204
11717
  var MAX_ENGINE_LOG_FLUSH_SESSIONS = 10;
11205
11718
  var MAX_ENGINE_LOG_FLUSH_BYTES = 5 * 1024 * 1024;
11206
11719
  var ENGINE_LOG_FLUSH_TIMEOUT_MS = 2e4;
@@ -11229,7 +11742,7 @@ async function flushAllEngineLogs() {
11229
11742
  const candidates = (await Promise.all(filenames.slice(0, MAX_ENGINE_LOG_FLUSH_SESSIONS).map(async (filename) => {
11230
11743
  try {
11231
11744
  const sessionId = filename.slice(0, -".log".length);
11232
- const filePath = join26(LOG_DIR, filename);
11745
+ const filePath = join28(LOG_DIR, filename);
11233
11746
  const fileStat = await runBeforeDeadline(() => stat5(filePath), deadline);
11234
11747
  if (!fileStat.isFile()) {
11235
11748
  skipped++;
@@ -11850,12 +12363,12 @@ var ChatService = class {
11850
12363
  return descendants;
11851
12364
  }
11852
12365
  async deleteHistoryFile(persisted) {
11853
- const historyPath = join27(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`);
12366
+ const historyPath = join29(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`);
11854
12367
  await Promise.all([
11855
12368
  historyPath,
11856
12369
  `${historyPath}.pages.jsonl`,
11857
12370
  `${historyPath}.pages.index.json`
11858
- ].map((path5) => rm2(path5, { force: true })));
12371
+ ].map((path6) => rm2(path6, { force: true })));
11859
12372
  await rm2(chatMessageSendersFilePath(persisted.id), { force: true });
11860
12373
  }
11861
12374
  async getChatHistory(chatId, page = {}) {
@@ -11973,7 +12486,7 @@ var ChatService = class {
11973
12486
  if (persisted.provider === "claude") {
11974
12487
  provider = new ClaudeManager({
11975
12488
  workingDirectory: this.workingDirectory,
11976
- historyFilePath: join27(CLAUDE_HISTORY_DIR, `${persisted.id}.jsonl`),
12489
+ historyFilePath: join29(CLAUDE_HISTORY_DIR, `${persisted.id}.jsonl`),
11977
12490
  initialSessionId: persisted.providerSessionId,
11978
12491
  onSaveSessionId: saveSession,
11979
12492
  onTurnComplete: onProviderTurnComplete,
@@ -11992,7 +12505,7 @@ var ChatService = class {
11992
12505
  });
11993
12506
  provider = new RelayManager({
11994
12507
  workingDirectory: this.workingDirectory,
11995
- historyFilePath: join27(RELAY_HISTORY_DIR, `${persisted.id}.jsonl`),
12508
+ historyFilePath: join29(RELAY_HISTORY_DIR, `${persisted.id}.jsonl`),
11996
12509
  initialSessionId: persisted.providerSessionId,
11997
12510
  onSaveSessionId: saveSession,
11998
12511
  onTurnComplete: onProviderTurnComplete,
@@ -12005,7 +12518,7 @@ var ChatService = class {
12005
12518
  } else if (persisted.provider === "cursor") {
12006
12519
  provider = new CursorManager({
12007
12520
  workingDirectory: this.workingDirectory,
12008
- historyFilePath: join27(CURSOR_HISTORY_DIR, `${persisted.id}.jsonl`),
12521
+ historyFilePath: join29(CURSOR_HISTORY_DIR, `${persisted.id}.jsonl`),
12009
12522
  initialSessionId: persisted.providerSessionId,
12010
12523
  onSaveSessionId: saveSession,
12011
12524
  onTurnComplete: onProviderTurnComplete,
@@ -12015,7 +12528,7 @@ var ChatService = class {
12015
12528
  } else if (persisted.provider === "deepseek") {
12016
12529
  provider = new DeepseekManager({
12017
12530
  workingDirectory: this.workingDirectory,
12018
- historyFilePath: join27(DEEPSEEK_HISTORY_DIR, `${persisted.id}.jsonl`),
12531
+ historyFilePath: join29(DEEPSEEK_HISTORY_DIR, `${persisted.id}.jsonl`),
12019
12532
  initialSessionId: persisted.providerSessionId,
12020
12533
  onSaveSessionId: saveSession,
12021
12534
  onTurnComplete: onProviderTurnComplete,
@@ -12025,7 +12538,7 @@ var ChatService = class {
12025
12538
  } else if (persisted.provider === "fx") {
12026
12539
  provider = new FxManager({
12027
12540
  workingDirectory: this.workingDirectory,
12028
- historyFilePath: join27(FX_HISTORY_DIR, `${persisted.id}.jsonl`),
12541
+ historyFilePath: join29(FX_HISTORY_DIR, `${persisted.id}.jsonl`),
12029
12542
  initialSessionId: persisted.providerSessionId,
12030
12543
  onSaveSessionId: saveSession,
12031
12544
  onTurnComplete: onProviderTurnComplete,
@@ -12035,7 +12548,7 @@ var ChatService = class {
12035
12548
  } else if (persisted.provider === "kimi") {
12036
12549
  provider = new KimiManager({
12037
12550
  workingDirectory: this.workingDirectory,
12038
- historyFilePath: join27(KIMI_HISTORY_DIR, `${persisted.id}.jsonl`),
12551
+ historyFilePath: join29(KIMI_HISTORY_DIR, `${persisted.id}.jsonl`),
12039
12552
  initialSessionId: persisted.providerSessionId,
12040
12553
  onSaveSessionId: saveSession,
12041
12554
  onTurnComplete: onProviderTurnComplete,
@@ -12045,7 +12558,7 @@ var ChatService = class {
12045
12558
  } else if (persisted.provider === "opencode") {
12046
12559
  provider = new OpencodeManager({
12047
12560
  workingDirectory: this.workingDirectory,
12048
- historyFilePath: join27(OPENCODE_HISTORY_DIR, `${persisted.id}.jsonl`),
12561
+ historyFilePath: join29(OPENCODE_HISTORY_DIR, `${persisted.id}.jsonl`),
12049
12562
  initialSessionId: persisted.providerSessionId,
12050
12563
  onSaveSessionId: saveSession,
12051
12564
  onTurnComplete: onProviderTurnComplete,
@@ -12055,7 +12568,7 @@ var ChatService = class {
12055
12568
  } else if (persisted.provider === "pi") {
12056
12569
  provider = new PiManager({
12057
12570
  workingDirectory: this.workingDirectory,
12058
- historyFilePath: join27(PI_HISTORY_DIR, `${persisted.id}.jsonl`),
12571
+ historyFilePath: join29(PI_HISTORY_DIR, `${persisted.id}.jsonl`),
12059
12572
  initialSessionId: persisted.providerSessionId,
12060
12573
  onSaveSessionId: saveSession,
12061
12574
  onTurnComplete: onProviderTurnComplete,
@@ -12065,7 +12578,7 @@ var ChatService = class {
12065
12578
  } else {
12066
12579
  provider = new CodexAspManager({
12067
12580
  workingDirectory: this.workingDirectory,
12068
- historyFilePath: join27(CODEX_HISTORY_DIR, `${persisted.id}.jsonl`),
12581
+ historyFilePath: join29(CODEX_HISTORY_DIR, `${persisted.id}.jsonl`),
12069
12582
  initialSessionId: persisted.providerSessionId,
12070
12583
  onSaveSessionId: saveSession,
12071
12584
  onTurnComplete: onProviderTurnComplete,
@@ -12231,7 +12744,7 @@ var ChatService = class {
12231
12744
  });
12232
12745
  uploadChatTranscript(
12233
12746
  chatId,
12234
- join27(HISTORY_DIR_BY_PROVIDER[chat.persisted.provider], `${chatId}.jsonl`),
12747
+ join29(HISTORY_DIR_BY_PROVIDER[chat.persisted.provider], `${chatId}.jsonl`),
12235
12748
  this.toSummary(chat)
12236
12749
  ).catch((err) => {
12237
12750
  console.error("[ChatService] Failed to upload chat transcript:", { chatId, err });
@@ -12369,7 +12882,7 @@ var ChatService = class {
12369
12882
  // src/services/repo-file-service.ts
12370
12883
  import { execFile } from "child_process";
12371
12884
  import { readFile as readFile18, realpath, stat as stat6 } from "fs/promises";
12372
- import { join as join28, resolve as resolve2, extname as extname2 } from "path";
12885
+ import { join as join30, resolve as resolve2, extname as extname2 } from "path";
12373
12886
  var CACHE_TTL_MS = 3e4;
12374
12887
  var SEARCH_TIMEOUT_MS = 15e3;
12375
12888
  var MAX_CONTENT_BYTES = 256 * 1024;
@@ -12521,7 +13034,7 @@ var RepoFileService = class {
12521
13034
  const repo = repos.find((r) => r.name === repoName);
12522
13035
  if (!repo) return null;
12523
13036
  try {
12524
- const fullPath = await realpath(resolve2(join28(repo.path, filePath)));
13037
+ const fullPath = await realpath(resolve2(join30(repo.path, filePath)));
12525
13038
  const repoRoot = await realpath(repo.path);
12526
13039
  const repoPrefix = repoRoot.endsWith("/") ? repoRoot : repoRoot + "/";
12527
13040
  if (!fullPath.startsWith(repoPrefix) && fullPath !== repoRoot) return null;
@@ -12656,20 +13169,20 @@ var RepoFileService = class {
12656
13169
  import { Hono } from "hono";
12657
13170
  import { z as z6 } from "zod";
12658
13171
  import { readdir as readdir11, stat as stat7, readFile as readFile21 } from "fs/promises";
12659
- import { join as join31, resolve as resolve3 } from "path";
13172
+ import { join as join33, resolve as resolve3 } from "path";
12660
13173
 
12661
13174
  // src/services/warm-hooks-service.ts
12662
13175
  import { spawn as spawn6 } from "child_process";
12663
13176
  import { readFile as readFile20 } from "fs/promises";
12664
13177
  import { existsSync as existsSync9 } from "fs";
12665
- import { join as join30 } from "path";
13178
+ import { join as join32 } from "path";
12666
13179
 
12667
13180
  // src/services/warm-hook-logs-service.ts
12668
13181
  import { mkdir as mkdir18, readFile as readFile19, writeFile as writeFile7, readdir as readdir10, appendFile as appendFile5, unlink as unlink4 } from "fs/promises";
12669
- import { homedir as homedir13 } from "os";
12670
- import { join as join29 } from "path";
12671
- var LOGS_DIR2 = join29(homedir13(), ".replicas", "warm-hook-logs");
12672
- var CURRENT_RUN_LOG = join29(LOGS_DIR2, "current-run.log");
13182
+ import { homedir as homedir15 } from "os";
13183
+ import { join as join31 } from "path";
13184
+ var LOGS_DIR2 = join31(homedir15(), ".replicas", "warm-hook-logs");
13185
+ var CURRENT_RUN_LOG = join31(LOGS_DIR2, "current-run.log");
12673
13186
  var GLOBAL_FILENAME = "global.json";
12674
13187
  function withPreview2(stored) {
12675
13188
  const preview = buildHookOutputPreview(stored.output);
@@ -12686,7 +13199,7 @@ var WarmHookLogsService = class {
12686
13199
  hookName: "organization",
12687
13200
  ...entry
12688
13201
  };
12689
- await writeFile7(join29(LOGS_DIR2, GLOBAL_FILENAME), `${JSON.stringify(log, null, 2)}
13202
+ await writeFile7(join31(LOGS_DIR2, GLOBAL_FILENAME), `${JSON.stringify(log, null, 2)}
12690
13203
  `, "utf-8");
12691
13204
  }
12692
13205
  async saveEnvironmentHookLog(entry) {
@@ -12696,7 +13209,7 @@ var WarmHookLogsService = class {
12696
13209
  hookName: "environment",
12697
13210
  ...entry
12698
13211
  };
12699
- await writeFile7(join29(LOGS_DIR2, ENVIRONMENT_HOOK_LOG_FILENAME), `${JSON.stringify(log, null, 2)}
13212
+ await writeFile7(join31(LOGS_DIR2, ENVIRONMENT_HOOK_LOG_FILENAME), `${JSON.stringify(log, null, 2)}
12700
13213
  `, "utf-8");
12701
13214
  }
12702
13215
  async saveRepoHookLog(repoName, entry) {
@@ -12706,7 +13219,7 @@ var WarmHookLogsService = class {
12706
13219
  hookName: repoName,
12707
13220
  ...entry
12708
13221
  };
12709
- await writeFile7(join29(LOGS_DIR2, repoHookLogFilename(repoName)), `${JSON.stringify(log, null, 2)}
13222
+ await writeFile7(join31(LOGS_DIR2, repoHookLogFilename(repoName)), `${JSON.stringify(log, null, 2)}
12710
13223
  `, "utf-8");
12711
13224
  }
12712
13225
  async getAllLogs() {
@@ -12725,7 +13238,7 @@ var WarmHookLogsService = class {
12725
13238
  continue;
12726
13239
  }
12727
13240
  try {
12728
- const raw = await readFile19(join29(LOGS_DIR2, file), "utf-8");
13241
+ const raw = await readFile19(join31(LOGS_DIR2, file), "utf-8");
12729
13242
  const stored = JSON.parse(raw);
12730
13243
  logs.push(withPreview2(stored));
12731
13244
  } catch {
@@ -12763,7 +13276,7 @@ var WarmHookLogsService = class {
12763
13276
  async getFullOutput(hookType, hookName) {
12764
13277
  const filename = hookType === "global" ? GLOBAL_FILENAME : hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
12765
13278
  try {
12766
- const raw = await readFile19(join29(LOGS_DIR2, filename), "utf-8");
13279
+ const raw = await readFile19(join31(LOGS_DIR2, filename), "utf-8");
12767
13280
  const stored = JSON.parse(raw);
12768
13281
  if (stored.hookType !== hookType || stored.hookName !== hookName) {
12769
13282
  return null;
@@ -12782,7 +13295,7 @@ var warmHookLogsService = new WarmHookLogsService();
12782
13295
  // src/services/warm-hooks-service.ts
12783
13296
  async function readRepoWarmHook(repoPath) {
12784
13297
  for (const filename of REPLICAS_CONFIG_FILENAMES) {
12785
- const configPath = join30(repoPath, filename);
13298
+ const configPath = join32(repoPath, filename);
12786
13299
  if (!existsSync9(configPath)) {
12787
13300
  continue;
12788
13301
  }
@@ -13594,11 +14107,11 @@ function createV1Routes(deps) {
13594
14107
  });
13595
14108
  app2.get("/repo-files/content", async (c) => {
13596
14109
  const repoName = c.req.query("repoName");
13597
- const path5 = c.req.query("path");
13598
- if (!repoName || !path5) {
14110
+ const path6 = c.req.query("path");
14111
+ if (!repoName || !path6) {
13599
14112
  return c.json(jsonError("repoName and path are required"), 400);
13600
14113
  }
13601
- const result = await deps.repoFileService.readFile(repoName, path5);
14114
+ const result = await deps.repoFileService.readFile(repoName, path6);
13602
14115
  if (!result) {
13603
14116
  return c.json(jsonError("File not found"), 404);
13604
14117
  }
@@ -14037,7 +14550,7 @@ data: ${JSON.stringify("Terminal session not found")}
14037
14550
  const logFiles = files.filter((f) => f.endsWith(".log"));
14038
14551
  const sessions = await Promise.all(
14039
14552
  logFiles.map(async (filename) => {
14040
- const filePath = join31(LOG_DIR, filename);
14553
+ const filePath = join33(LOG_DIR, filename);
14041
14554
  const fileStat = await stat7(filePath);
14042
14555
  const sessionId = filename.replace(/\.log$/, "");
14043
14556
  return {