replicas-engine 0.1.667 → 0.1.671

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,8 +1,51 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ACCOUNT_RATE_LIMITS_UPDATED_METHOD,
4
- AGENT,
5
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-6GXXZQID.js";
30
+ import {
31
+ BaseRefreshManager,
32
+ CodexAspAuthMethodChangedError,
33
+ applyAuthEnvTransition,
34
+ codexTokenManager,
35
+ listCredentialFallbacks,
36
+ monolithRequest,
37
+ monolithService,
38
+ recordCredentialFallback,
39
+ recordExhaustedCredential
40
+ } from "./chunk-6WY7NPCL.js";
41
+ import {
42
+ ENGINE_ENV,
43
+ IS_WARMING_MODE,
44
+ isRecord as isRecord2,
45
+ setAgentCredentialSnapshot
46
+ } from "./chunk-4FTBKGMO.js";
47
+ import {
48
+ AGENT,
6
49
  AGENT_MODELS,
7
50
  AI_GATEWAY_BASE_URL,
8
51
  ASTER_BASE_URL,
@@ -11,7 +54,6 @@ import {
11
54
  ASTER_PROVIDER,
12
55
  AUTH_FALLBACK_EVENT_TYPE,
13
56
  AUTH_RETRY_STATUS_EVENT_TYPE,
14
- AppServerProcess,
15
57
  CHAT_GOAL_EVENT_TYPE,
16
58
  CHAT_INTERRUPTED_EVENT_TYPE,
17
59
  CLAUDE_AUTH_ENV_KEYS,
@@ -28,12 +70,10 @@ import {
28
70
  CLAUDE_SONNET_5_BEDROCK_MODEL,
29
71
  CLAUDE_SONNET_5_MODEL,
30
72
  CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE,
31
- CODEX_AUTH_ENV_KEYS,
32
- CODEX_AUTH_ENV_KEYS_BY_METHOD,
33
73
  CODEX_QUOTA_STATUS_EVENT_TYPE,
34
- COMMAND_EXECUTION_OUTPUT_DELTA_METHOD,
35
74
  COMPACTION_STATUS_EVENT_TYPE,
36
75
  CONTEXT_USAGE_EVENT_TYPE,
76
+ CURSOR_CONNECTION_STATUS_EVENT_TYPE,
37
77
  DEFAULT_ASTER_MODEL,
38
78
  DEFAULT_CHAT_TITLES,
39
79
  DEFAULT_CLAUDE_MODEL,
@@ -50,14 +90,11 @@ import {
50
90
  ENGINE_HEALTH_MAX_WAIT_MS,
51
91
  ENGINE_HEALTH_WAIT_HEADER,
52
92
  ENGINE_HEALTH_WAIT_QUERY_PARAM,
53
- FILE_CHANGE_OUTPUT_DELTA_METHOD,
54
93
  GITHUB_CREDENTIAL_REFRESH_PATH,
55
94
  GITLAB_CREDENTIAL_REFRESH_PATH,
56
95
  GIT_CREDENTIAL_HELPER_FILENAME,
57
96
  HOOK_EXEC_MAX_BUFFER_BYTES,
58
97
  IMAGE_MEDIA_TYPES,
59
- ITEM_COMPLETED_METHOD,
60
- ITEM_STARTED_METHOD,
61
98
  InFlightMap,
62
99
  MAX_CANVAS_FILE_BYTES,
63
100
  MAX_CANVAS_PREVIEW_BYTES,
@@ -66,32 +103,18 @@ import {
66
103
  MEMORY_ROOT,
67
104
  MEMORY_SUMMARY_FILENAME,
68
105
  MERGED_MESSAGE_SEPARATOR,
69
- REASONING_SUMMARY_PART_ADDED_METHOD,
70
- REASONING_SUMMARY_TEXT_DELTA_METHOD,
71
- REASONING_TEXT_DELTA_METHOD,
72
106
  REPLICAS_CONFIG_FILENAMES,
73
- REPLICAS_RUNTIME_ENV_ALIASES,
74
107
  SANDBOX_PATHS,
75
- SUBPROCESS_MAX_BUFFER,
76
- THREAD_COMPACTED_METHOD,
77
- THREAD_GOAL_CLEARED_METHOD,
78
- THREAD_GOAL_UPDATED_METHOD,
79
- THREAD_TOKEN_USAGE_UPDATED_METHOD,
80
108
  TIMEOUT,
81
- TURN_COMPLETED_METHOD,
82
- TURN_PLAN_UPDATED_METHOD,
83
- TURN_STARTED_METHOD,
84
109
  TaskAccumulator,
85
110
  USER_MESSAGE_ID_PAYLOAD_KEY,
86
111
  VALID_AGENT_PROVIDERS,
87
112
  VALID_RELAY_SUBAGENT_PROVIDERS,
88
113
  VALID_THINKING_LEVELS,
89
- agentCredentialSnapshotSchema,
90
114
  applyCodexAspTranscriptDelta,
91
115
  areSameUserMessageEvents,
92
116
  areUserMessagesWithinMatchWindow,
93
117
  autoCompactThresholdField,
94
- buildCodexAgentEnv,
95
118
  buildCodexTokenUsageContextUsagePayload,
96
119
  buildGitCredentialHelperScript,
97
120
  buildHookOutputPreview,
@@ -102,7 +125,6 @@ import {
102
125
  clampWarmHookTimeoutMs,
103
126
  classifyCanvasFilename,
104
127
  claudeAuthEnvFromResponse,
105
- codexAuthEnvFromResponse,
106
128
  codexReasoningEffortForThinkingLevel,
107
129
  coerceBackgroundTaskPayload,
108
130
  coerceClaudeResultPayload,
@@ -116,9 +138,6 @@ import {
116
138
  decodePathSegments,
117
139
  detectAgentQuotaLimit,
118
140
  detectLanguageByPath,
119
- dispatchAspNotification,
120
- execAsync,
121
- execFileAsync,
122
141
  extractCommandProtectionCommandText,
123
142
  extractErrorText,
124
143
  extractToolResultText,
@@ -170,26 +189,21 @@ import {
170
189
  parseAgentEvents,
171
190
  parseChatHistoryCursor,
172
191
  parseChatTranscriptArtifact,
173
- parseCodeHostPrUrl,
174
192
  parseDisplayMessages,
175
193
  parseGitRemote,
176
194
  parseLatestCodexAspTranscriptTurn,
177
195
  parseMcpToolName,
178
- parsePosixEnvFile,
179
196
  parseReplicasConfigString,
180
197
  percentage,
181
- putPresignedFile,
182
198
  raceWithTimeout,
183
199
  readJsonlPage,
184
- readReplicasRuntimeEnv,
185
- recoverCompletedTurn,
186
200
  renumberCodexAspTranscriptItems,
187
201
  resolveWarmHookConfig,
188
202
  sanitizeCanvasFilename,
189
203
  serializeCanvasContentResponse,
190
204
  shellQuotePosix,
191
205
  stripAgentDiagnosticErrors
192
- } from "./chunk-P2Q47GLV.js";
206
+ } from "./chunk-TMERKNQV.js";
193
207
 
194
208
  // src/index.ts
195
209
  import { serve } from "@hono/node-server";
@@ -201,373 +215,9 @@ import { connect } from "net";
201
215
  // src/managers/github-token-manager.ts
202
216
  import path from "path";
203
217
 
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
-
568
218
  // src/utils/file.ts
569
219
  import { mkdir, readFile, rename, unlink, writeFile } from "fs/promises";
570
- import { dirname, join as join3 } from "path";
220
+ import { dirname, join } from "path";
571
221
 
572
222
  // src/utils/async-lock.ts
573
223
  var AsyncLock = class {
@@ -583,11 +233,11 @@ var AsyncLock = class {
583
233
  };
584
234
 
585
235
  // src/utils/file.ts
586
- async function atomicWriteFile(path6, data, options) {
587
- const tmpFile = `${path6}.${process.pid}.${Date.now()}.tmp`;
236
+ async function atomicWriteFile(path5, data, options) {
237
+ const tmpFile = `${path5}.${process.pid}.${Date.now()}.tmp`;
588
238
  try {
589
239
  await writeFile(tmpFile, data, { encoding: "utf-8", mode: options?.mode });
590
- await rename(tmpFile, path6);
240
+ await rename(tmpFile, path5);
591
241
  } catch (error) {
592
242
  await unlink(tmpFile).catch(() => void 0);
593
243
  throw error;
@@ -600,8 +250,8 @@ async function writeSecureCredentialFile(filePath, content, options) {
600
250
  await atomicWriteFile(filePath, content, { mode: 384 });
601
251
  }
602
252
  async function configureManagedGitCredentialHelper(homeDir) {
603
- const credentialsPath = join3(homeDir, ".git-credentials");
604
- const helperPath = join3(homeDir, GIT_CREDENTIAL_HELPER_FILENAME);
253
+ const credentialsPath = join(homeDir, ".git-credentials");
254
+ const helperPath = join(homeDir, GIT_CREDENTIAL_HELPER_FILENAME);
605
255
  await atomicWriteFile(helperPath, buildGitCredentialHelperScript(credentialsPath), { mode: 448 });
606
256
  await execFileAsync("git", ["config", "--global", "credential.helper", helperPath], {
607
257
  env: { ...process.env, HOME: homeDir }
@@ -636,15 +286,15 @@ function removeCredentialFileLines(filePath, shouldRemove) {
636
286
  // src/git/service.ts
637
287
  import { readdir, readFile as readFile3, stat } from "fs/promises";
638
288
  import { spawn } from "child_process";
639
- import { join as join6 } from "path";
289
+ import { join as join4 } from "path";
640
290
 
641
291
  // src/utils/state.ts
642
292
  import { readFile as readFile2, mkdir as mkdir2 } from "fs/promises";
643
293
  import { existsSync } from "fs";
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");
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");
648
298
  var DEFAULT_STATE = {
649
299
  repos: {}
650
300
  };
@@ -741,8 +391,8 @@ async function saveRepoState(repoName, state, fallbackState) {
741
391
  }
742
392
 
743
393
  // src/git/commands.ts
744
- import { readFileSync as readFileSync3 } from "fs";
745
- import { join as join5 } from "path";
394
+ import { readFileSync } from "fs";
395
+ import { join as join3 } from "path";
746
396
  async function runGitCommand(args, cwd, options = {}) {
747
397
  const { stdout } = await execFileAsync("git", args, {
748
398
  cwd,
@@ -753,7 +403,7 @@ async function runGitCommand(args, cwd, options = {}) {
753
403
  }
754
404
  function readRepoHeadBranch(repoPath) {
755
405
  try {
756
- const contents = readFileSync3(join5(repoPath, ".git", "HEAD"), "utf-8").trim();
406
+ const contents = readFileSync(join3(repoPath, ".git", "HEAD"), "utf-8").trim();
757
407
  const match = contents.match(/^ref:\s+refs\/heads\/(.+)$/);
758
408
  return match ? match[1] : null;
759
409
  } catch {
@@ -815,13 +465,13 @@ var GitService = class {
815
465
  const repos = [];
816
466
  let complete = true;
817
467
  for (const entry of entries) {
818
- const fullPath = join6(root, entry);
468
+ const fullPath = join4(root, entry);
819
469
  try {
820
470
  const entryStat = await stat(fullPath);
821
471
  if (!entryStat.isDirectory()) {
822
472
  continue;
823
473
  }
824
- const hasGit = Boolean(await this.safeStat(join6(fullPath, ".git")));
474
+ const hasGit = Boolean(await this.safeStat(join4(fullPath, ".git")));
825
475
  if (!hasGit) {
826
476
  continue;
827
477
  }
@@ -1010,9 +660,9 @@ var GitService = class {
1010
660
  try {
1011
661
  const paths = await this.listUntrackedPaths(repoPath);
1012
662
  let total = 0;
1013
- for (const path6 of paths) {
663
+ for (const path5 of paths) {
1014
664
  try {
1015
- const contents = await readFile3(join6(repoPath, path6));
665
+ const contents = await readFile3(join4(repoPath, path5));
1016
666
  if (contents.length === 0 || contents.includes(0)) {
1017
667
  continue;
1018
668
  }
@@ -1200,7 +850,7 @@ var GitService = class {
1200
850
  }
1201
851
  async getGitLabAccessToken(host) {
1202
852
  try {
1203
- const credentials = await readFile3(join6(ENGINE_ENV.HOME_DIR, ".git-credentials"), "utf-8");
853
+ const credentials = await readFile3(join4(ENGINE_ENV.HOME_DIR, ".git-credentials"), "utf-8");
1204
854
  for (const line of credentials.split("\n")) {
1205
855
  const trimmed = line.trim();
1206
856
  if (!trimmed) continue;
@@ -1268,9 +918,9 @@ var GitService = class {
1268
918
  await saveRepoState(repo.name, state, state);
1269
919
  return state;
1270
920
  }
1271
- async safeStat(path6) {
921
+ async safeStat(path5) {
1272
922
  try {
1273
- return await stat(path6);
923
+ return await stat(path5);
1274
924
  } catch {
1275
925
  return null;
1276
926
  }
@@ -1421,26 +1071,6 @@ var gitlabTokenManager = new GitLabTokenManager();
1421
1071
  // src/managers/claude-token-manager.ts
1422
1072
  import { promises as fs } from "fs";
1423
1073
  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
1444
1074
  var ClaudeTokenManager = class extends BaseRefreshManager {
1445
1075
  constructor() {
1446
1076
  super("ClaudeTokenManager");
@@ -1544,114 +1174,9 @@ var ClaudeTokenManager = class extends BaseRefreshManager {
1544
1174
  };
1545
1175
  var claudeTokenManager = new ClaudeTokenManager();
1546
1176
 
1547
- // src/managers/codex-token-manager.ts
1548
- import { promises as fs2 } from "fs";
1549
- import path4 from "path";
1550
- var CodexTokenManager = class extends BaseRefreshManager {
1551
- constructor() {
1552
- super("CodexTokenManager");
1553
- }
1554
- getSkipReason() {
1555
- if (ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "api_key" || ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "foundry") {
1556
- return `auth method is ${ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD}`;
1557
- }
1558
- if (!ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD && ENGINE_ENV.OPENAI_API_KEY) {
1559
- return "OPENAI_API_KEY is set";
1560
- }
1561
- return null;
1562
- }
1563
- async doRefresh(_config) {
1564
- await this.refreshWithRequest();
1565
- }
1566
- async refreshWithRequest(request) {
1567
- console.log("[CodexTokenManager] Refreshing Codex credentials...");
1568
- const response = await monolithRequest("/v1/engine/codex/refresh-credentials", {
1569
- body: request
1570
- });
1571
- if (!response.ok) {
1572
- const errorText = await response.text();
1573
- throw new Error(`Credentials refresh failed: ${response.status} ${errorText}`);
1574
- }
1575
- const data = await response.json();
1576
- await this.applyCredentialsResponse(data);
1577
- if (data.scope) {
1578
- setAgentCredentialSnapshot("codex", {
1579
- method: data.type,
1580
- scope: data.scope,
1581
- ...data.revision ? { revision: data.revision } : {}
1582
- });
1583
- }
1584
- console.log(`[CodexTokenManager] Credentials refreshed (method=${data.type})`);
1585
- }
1586
- async fetchFreshCredentials(failureReason, failureKind = "rejected", failedCredential = ENGINE_ENV.REPLICAS_AGENT_CREDENTIALS.codex) {
1587
- const failedMethod = failedCredential?.method === "oauth" || failedCredential?.method === "api_key" || failedCredential?.method === "foundry" ? failedCredential.method : ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD;
1588
- return this.swapCredentials({
1589
- provider: "codex",
1590
- failureKind,
1591
- refresh: (exclusions) => this.refreshWithRequest(
1592
- failedMethod === "oauth" || failedMethod === "api_key" || failedMethod === "foundry" ? {
1593
- failedMethod,
1594
- ...failedCredential?.method === failedMethod ? { failedCredential } : {},
1595
- failureReason,
1596
- failureKind,
1597
- ...exclusions
1598
- } : exclusions
1599
- ),
1600
- isOauthNow: () => ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "oauth"
1601
- });
1602
- }
1603
- async applyCredentialsResponse(response) {
1604
- if (response.type === "oauth") {
1605
- await this.writeOauthCredentialsFile(response);
1606
- } else {
1607
- await this.removeOauthCredentialsFile();
1608
- }
1609
- const envVars = codexAuthEnvFromResponse(response);
1610
- applyAuthEnvTransition({
1611
- prevMethod: ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD ?? "none",
1612
- newMethod: envVars.REPLICAS_CODEX_AUTH_METHOD ?? "none",
1613
- authKeys: CODEX_AUTH_ENV_KEYS,
1614
- authKeysByMethod: CODEX_AUTH_ENV_KEYS_BY_METHOD,
1615
- newEnvVars: envVars,
1616
- envs: [ENGINE_ENV, process.env]
1617
- });
1618
- }
1619
- async writeOauthCredentialsFile(credentials) {
1620
- const authPath = path4.join(ENGINE_ENV.HOME_DIR, ".codex", "auth.json");
1621
- const codexAuthConfig = {
1622
- OPENAI_API_KEY: null,
1623
- tokens: {
1624
- id_token: credentials.idToken,
1625
- access_token: credentials.accessToken,
1626
- refresh_token: credentials.refreshToken,
1627
- account_id: credentials.accountId
1628
- },
1629
- last_refresh: (/* @__PURE__ */ new Date()).toISOString()
1630
- };
1631
- try {
1632
- await writeSecureCredentialFile(
1633
- authPath,
1634
- JSON.stringify(codexAuthConfig, null, 2),
1635
- { ensureParentDir: true }
1636
- );
1637
- console.log(`[CodexTokenManager] Updated ${authPath}`);
1638
- } catch (error) {
1639
- console.error("[CodexTokenManager] Failed to update credentials file:", error);
1640
- }
1641
- }
1642
- async removeOauthCredentialsFile() {
1643
- const authPath = path4.join(ENGINE_ENV.HOME_DIR, ".codex", "auth.json");
1644
- try {
1645
- await fs2.unlink(authPath);
1646
- } catch {
1647
- }
1648
- }
1649
- };
1650
- var codexTokenManager = new CodexTokenManager();
1651
-
1652
1177
  // src/managers/infisical-token-manager.ts
1653
1178
  import { rm } from "fs/promises";
1654
- import path5 from "path";
1179
+ import path4 from "path";
1655
1180
  var InfisicalTokenManager = class extends BaseRefreshManager {
1656
1181
  constructor(request = monolithRequest, paths = {
1657
1182
  homeDir: ENGINE_ENV.HOME_DIR,
@@ -1679,8 +1204,8 @@ var InfisicalTokenManager = class extends BaseRefreshManager {
1679
1204
  }
1680
1205
  };
1681
1206
  async function applyInfisicalCredentials(data, paths) {
1682
- const credentialPath = path5.join(paths.homeDir, ".replicas", "infisical-env.sh");
1683
- const configPath = path5.join(paths.workspaceRoot, ".infisical.json");
1207
+ const credentialPath = path4.join(paths.homeDir, ".replicas", "infisical-env.sh");
1208
+ const configPath = path4.join(paths.workspaceRoot, ".infisical.json");
1684
1209
  if (!data.configured) {
1685
1210
  delete process.env.INFISICAL_TOKEN;
1686
1211
  delete process.env.INFISICAL_DOMAIN;
@@ -1709,8 +1234,8 @@ var infisicalTokenManager = new InfisicalTokenManager();
1709
1234
 
1710
1235
  // src/utils/logger.ts
1711
1236
  import { mkdir as mkdir3, writeFile as writeFile2 } from "fs/promises";
1712
- import { homedir as homedir4 } from "os";
1713
- import { join as join7 } from "path";
1237
+ import { homedir as homedir2 } from "os";
1238
+ import { join as join5 } from "path";
1714
1239
  import { format } from "util";
1715
1240
  import { randomBytes } from "crypto";
1716
1241
 
@@ -1722,8 +1247,8 @@ var StreamWriter = class {
1722
1247
  backpressured = false;
1723
1248
  droppedCount = 0;
1724
1249
  flushTimer = null;
1725
- open(path6, highWaterMark = DEFAULT_HIGH_WATER) {
1726
- this.stream = createWriteStream(path6, { flags: "a", highWaterMark });
1250
+ open(path5, highWaterMark = DEFAULT_HIGH_WATER) {
1251
+ this.stream = createWriteStream(path5, { flags: "a", highWaterMark });
1727
1252
  this.stream.on("error", () => {
1728
1253
  this.stream = null;
1729
1254
  });
@@ -1785,7 +1310,7 @@ var StreamWriter = class {
1785
1310
  };
1786
1311
 
1787
1312
  // src/utils/logger.ts
1788
- var LOG_DIR = join7(homedir4(), ".replicas", "logs");
1313
+ var LOG_DIR = join5(homedir2(), ".replicas", "logs");
1789
1314
  var EngineLogger = class {
1790
1315
  _sessionId = null;
1791
1316
  patched = false;
@@ -1796,7 +1321,7 @@ var EngineLogger = class {
1796
1321
  async initialize() {
1797
1322
  await mkdir3(LOG_DIR, { recursive: true });
1798
1323
  this._sessionId = this.createSessionId();
1799
- const logPath = join7(LOG_DIR, `${this._sessionId}.log`);
1324
+ const logPath = join5(LOG_DIR, `${this._sessionId}.log`);
1800
1325
  await writeFile2(logPath, `=== Replicas Engine Session ${this._sessionId} ===
1801
1326
  `, "utf-8");
1802
1327
  this.writer.open(logPath);
@@ -1843,45 +1368,49 @@ var engineLogger = new EngineLogger();
1843
1368
  // src/services/replicas-config-service.ts
1844
1369
  import { readFile as readFile6, appendFile, writeFile as writeFile4, mkdir as mkdir6 } from "fs/promises";
1845
1370
  import { existsSync as existsSync3 } from "fs";
1846
- import { join as join11 } from "path";
1847
- import { homedir as homedir8 } from "os";
1371
+ import { join as join9 } from "path";
1372
+ import { homedir as homedir6 } from "os";
1848
1373
  import { spawn as spawn2 } from "child_process";
1849
1374
 
1850
1375
  // src/services/environment-details-service.ts
1851
1376
  import { mkdir as mkdir4, readFile as readFile4 } from "fs/promises";
1852
1377
  import { existsSync as existsSync2 } from "fs";
1853
- import { homedir as homedir6 } from "os";
1854
- import { join as join9 } from "path";
1378
+ import { homedir as homedir4 } from "os";
1379
+ import { join as join7 } from "path";
1855
1380
 
1856
1381
  // src/managers/agent-auth-paths.ts
1857
- import { homedir as homedir5 } from "os";
1858
- import { join as join8 } from "path";
1859
- var OPENCODE_AUTH_PATH = join8(homedir5(), ".local", "share", "opencode", "auth.json");
1860
- var PI_AUTH_PATH = join8(homedir5(), ".pi", "agent", "auth.json");
1861
- var DEEPSEEK_AUTH_PATH = join8(homedir5(), ".replicas", "deepseek-auth.json");
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");
1862
1387
 
1863
1388
  // src/managers/deepseek-auth.ts
1864
- import { readFileSync as readFileSync4 } from "fs";
1389
+ import { readFileSync as readFileSync2 } from "fs";
1865
1390
  import { z } from "zod";
1866
1391
  var authSchema = z.object({
1867
1392
  openrouter: z.object({ type: z.literal("api"), key: z.string().min(1) })
1868
1393
  });
1869
1394
  function getDeepseekApiKey() {
1870
1395
  try {
1871
- const parsed = authSchema.safeParse(JSON.parse(readFileSync4(DEEPSEEK_AUTH_PATH, "utf8")));
1396
+ const parsed = authSchema.safeParse(JSON.parse(readFileSync2(DEEPSEEK_AUTH_PATH, "utf8")));
1872
1397
  return parsed.success ? parsed.data.openrouter.key : null;
1873
1398
  } catch {
1874
1399
  return null;
1875
1400
  }
1876
1401
  }
1877
1402
 
1403
+ // src/managers/codex-auth.ts
1404
+ function detectCodexAuthMethod() {
1405
+ return ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD ?? (ENGINE_ENV.OPENAI_API_KEY ? "api_key" : "none");
1406
+ }
1407
+
1878
1408
  // src/services/environment-details-service.ts
1879
- var REPLICAS_DIR = join9(homedir6(), ".replicas");
1880
- var DETAILS_FILE = join9(REPLICAS_DIR, "environment-details.json");
1881
- var CLAUDE_CREDENTIALS_PATH = join9(homedir6(), ".claude", ".credentials.json");
1882
- var CODEX_AUTH_PATH = join9(homedir6(), ".codex", "auth.json");
1883
- var GH_HOSTS_PATH = join9(homedir6(), ".config", "gh", "hosts.yml");
1884
- var GIT_CREDENTIALS_PATH = join9(homedir6(), ".git-credentials");
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");
1885
1414
  function detectClaudeAuthMethod() {
1886
1415
  if (existsSync2(CLAUDE_CREDENTIALS_PATH)) {
1887
1416
  return "oauth";
@@ -1897,16 +1426,6 @@ function detectClaudeAuthMethod() {
1897
1426
  }
1898
1427
  return "none";
1899
1428
  }
1900
- function detectCodexAuthMethod() {
1901
- if (existsSync2(CODEX_AUTH_PATH)) {
1902
- return "oauth";
1903
- }
1904
- if (ENGINE_ENV.OPENAI_API_KEY) {
1905
- return "api_key";
1906
- }
1907
- if (ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "foundry") return "foundry";
1908
- return "none";
1909
- }
1910
1429
  function detectCursorAuthMethod() {
1911
1430
  return ENGINE_ENV.CURSOR_API_KEY ? "api_key" : "none";
1912
1431
  }
@@ -2103,8 +1622,8 @@ var environmentDetailsService = new EnvironmentDetailsService();
2103
1622
 
2104
1623
  // src/services/start-hook-logs-service.ts
2105
1624
  import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile3, readdir as readdir2 } from "fs/promises";
2106
- import { homedir as homedir7 } from "os";
2107
- import { join as join10 } from "path";
1625
+ import { homedir as homedir5 } from "os";
1626
+ import { join as join8 } from "path";
2108
1627
 
2109
1628
  // src/services/hook-log-files.ts
2110
1629
  import { createHash } from "crypto";
@@ -2116,7 +1635,7 @@ function repoHookLogFilename(repoName) {
2116
1635
  }
2117
1636
 
2118
1637
  // src/services/start-hook-logs-service.ts
2119
- var LOGS_DIR = join10(homedir7(), ".replicas", "start-hook-logs");
1638
+ var LOGS_DIR = join8(homedir5(), ".replicas", "start-hook-logs");
2120
1639
  function withPreview(stored) {
2121
1640
  const preview = buildHookOutputPreview(stored.output);
2122
1641
  return { ...stored, ...preview };
@@ -2154,7 +1673,7 @@ var StartHookLogsService = class {
2154
1673
  await this.ensureDir();
2155
1674
  const log = { hookType, hookName, repoName: hookName, ...entry };
2156
1675
  const filename = hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
2157
- await writeFile3(join10(LOGS_DIR, filename), `${JSON.stringify(log, null, 2)}
1676
+ await writeFile3(join8(LOGS_DIR, filename), `${JSON.stringify(log, null, 2)}
2158
1677
  `, "utf-8");
2159
1678
  }
2160
1679
  async saveEnvironmentLog(entry) {
@@ -2179,7 +1698,7 @@ var StartHookLogsService = class {
2179
1698
  continue;
2180
1699
  }
2181
1700
  try {
2182
- const raw = await readFile5(join10(LOGS_DIR, file), "utf-8");
1701
+ const raw = await readFile5(join8(LOGS_DIR, file), "utf-8");
2183
1702
  const stored = normalizeStored(JSON.parse(raw));
2184
1703
  if (stored) {
2185
1704
  logs.push(withPreview(stored));
@@ -2198,7 +1717,7 @@ var StartHookLogsService = class {
2198
1717
  async getFullOutput(hookType, hookName) {
2199
1718
  const filename = hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
2200
1719
  try {
2201
- const raw = await readFile5(join10(LOGS_DIR, filename), "utf-8");
1720
+ const raw = await readFile5(join8(LOGS_DIR, filename), "utf-8");
2202
1721
  const stored = normalizeStored(JSON.parse(raw));
2203
1722
  if (!stored || stored.hookType !== hookType || stored.hookName !== hookName) {
2204
1723
  return null;
@@ -2215,7 +1734,7 @@ var StartHookLogsService = class {
2215
1734
  var startHookLogsService = new StartHookLogsService();
2216
1735
 
2217
1736
  // src/services/replicas-config-service.ts
2218
- var START_HOOKS_LOG = join11(homedir8(), ".replicas", "startHooks.log");
1737
+ var START_HOOKS_LOG = join9(homedir6(), ".replicas", "startHooks.log");
2219
1738
  var START_HOOKS_RUNNING_PROMPT = `IMPORTANT - Start Hooks Running:
2220
1739
  Start hooks are shell commands/scripts set by repository owners that run on workspace startup.
2221
1740
  These hooks are currently executing in the background. You can:
@@ -2226,7 +1745,7 @@ The start hooks may install dependencies, build projects, or perform other setup
2226
1745
  If your task depends on setup being complete, check the log file before proceeding.`;
2227
1746
  async function readReplicasConfigFromDir(dirPath) {
2228
1747
  for (const filename of REPLICAS_CONFIG_FILENAMES) {
2229
- const configPath = join11(dirPath, filename);
1748
+ const configPath = join9(dirPath, filename);
2230
1749
  if (!existsSync3(configPath)) {
2231
1750
  continue;
2232
1751
  }
@@ -2296,7 +1815,7 @@ var ReplicasConfigService = class {
2296
1815
  const logLine = `[${timestamp}] ${message}
2297
1816
  `;
2298
1817
  try {
2299
- await mkdir6(join11(homedir8(), ".replicas"), { recursive: true });
1818
+ await mkdir6(join9(homedir6(), ".replicas"), { recursive: true });
2300
1819
  await appendFile(START_HOOKS_LOG, logLine, "utf-8");
2301
1820
  } catch (error) {
2302
1821
  console.error("Failed to write to start hooks log:", error);
@@ -2308,7 +1827,7 @@ var ReplicasConfigService = class {
2308
1827
  command: params.content,
2309
1828
  label: "env start hook",
2310
1829
  repoName: "environment",
2311
- cwd: homedir8(),
1830
+ cwd: homedir6(),
2312
1831
  timeout: params.timeoutMs ?? DEFAULT_START_HOOK_TIMEOUT_MS,
2313
1832
  onOutputChunk: params.onOutputChunk
2314
1833
  });
@@ -2431,7 +1950,7 @@ var ReplicasConfigService = class {
2431
1950
  this.hooksCompleted = false;
2432
1951
  this.hooksFailed = false;
2433
1952
  try {
2434
- await mkdir6(join11(homedir8(), ".replicas"), { recursive: true });
1953
+ await mkdir6(join9(homedir6(), ".replicas"), { recursive: true });
2435
1954
  await writeFile4(
2436
1955
  START_HOOKS_LOG,
2437
1956
  `=== Start Hooks Execution Log ===
@@ -2626,11 +2145,11 @@ var replicasConfigService = new ReplicasConfigService();
2626
2145
 
2627
2146
  // src/services/event-service.ts
2628
2147
  import { mkdir as mkdir7 } from "fs/promises";
2629
- import { homedir as homedir9 } from "os";
2630
- import { join as join12 } from "path";
2148
+ import { homedir as homedir7 } from "os";
2149
+ import { join as join10 } from "path";
2631
2150
  import { randomUUID } from "crypto";
2632
- var ENGINE_DIR = join12(homedir9(), ".replicas", "engine");
2633
- var EVENTS_FILE = join12(ENGINE_DIR, "events.jsonl");
2151
+ var ENGINE_DIR = join10(homedir7(), ".replicas", "engine");
2152
+ var EVENTS_FILE = join10(ENGINE_DIR, "events.jsonl");
2634
2153
  var EventService = class {
2635
2154
  subscribers = /* @__PURE__ */ new Map();
2636
2155
  writer = new StreamWriter();
@@ -2664,9 +2183,9 @@ var eventService = new EventService();
2664
2183
  import { mkdir as mkdir8, readFile as readFile7 } from "fs/promises";
2665
2184
  import { existsSync as existsSync4 } from "fs";
2666
2185
  import { randomUUID as randomUUID2 } from "crypto";
2667
- import { homedir as homedir10 } from "os";
2668
- import { dirname as dirname2, join as join13 } from "path";
2669
- var PREVIEW_PORTS_FILE = join13(homedir10(), ".replicas", "preview-ports.json");
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");
2670
2189
  async function readPreviewsFile() {
2671
2190
  try {
2672
2191
  if (!existsSync4(PREVIEW_PORTS_FILE)) {
@@ -2778,8 +2297,7 @@ async function registerDesktopPreview() {
2778
2297
  // src/services/chat/chat-service.ts
2779
2298
  import { existsSync as existsSync8 } from "fs";
2780
2299
  import { appendFile as appendFile4, copyFile, mkdir as mkdir17, readFile as readFile17, rename as rename3, rm as rm2 } from "fs/promises";
2781
- import { homedir as homedir15 } from "os";
2782
- import { join as join29 } from "path";
2300
+ import { join as join27 } from "path";
2783
2301
  import { randomUUID as randomUUID8 } from "crypto";
2784
2302
 
2785
2303
  // src/managers/claude-manager.ts
@@ -2787,9 +2305,9 @@ import {
2787
2305
  query
2788
2306
  } from "@anthropic-ai/claude-agent-sdk";
2789
2307
  import { randomUUID as randomUUID4 } from "crypto";
2790
- import { dirname as dirname4, join as join17 } from "path";
2308
+ import { dirname as dirname4, join as join15 } from "path";
2791
2309
  import { mkdir as mkdir10 } from "fs/promises";
2792
- import { homedir as homedir12 } from "os";
2310
+ import { homedir as homedir10 } from "os";
2793
2311
 
2794
2312
  // src/utils/linear-converter.ts
2795
2313
  function linearThoughtToResponse(thought) {
@@ -3174,8 +2692,8 @@ function extractPlanFromCodexAspNotification(notification) {
3174
2692
  // src/utils/image-utils.ts
3175
2693
  import { randomUUID as randomUUID3 } from "crypto";
3176
2694
  import { mkdir as mkdir9, unlink as unlink2, writeFile as writeFile5 } from "fs/promises";
3177
- import { homedir as homedir11 } from "os";
3178
- import { join as join14 } from "path";
2695
+ import { homedir as homedir9 } from "os";
2696
+ import { join as join12 } from "path";
3179
2697
  function isImageMediaType(value) {
3180
2698
  return IMAGE_MEDIA_TYPES.includes(value);
3181
2699
  }
@@ -3275,14 +2793,14 @@ async function normalizeImages(images) {
3275
2793
  }
3276
2794
  return normalized;
3277
2795
  }
3278
- async function saveNormalizedImagesToTempFiles(images, tempImageDir = join14(homedir11(), ".replicas", "codex", "temp-images")) {
2796
+ async function saveNormalizedImagesToTempFiles(images, tempImageDir = join12(homedir9(), ".replicas", "codex", "temp-images")) {
3279
2797
  await mkdir9(tempImageDir, { recursive: true });
3280
2798
  const tempPaths = [];
3281
2799
  try {
3282
2800
  for (const image of images) {
3283
2801
  const ext = image.source.media_type.split("/")[1] || "png";
3284
2802
  const filename = `img_${randomUUID3()}.${ext}`;
3285
- const filepath = join14(tempImageDir, filename);
2803
+ const filepath = join12(tempImageDir, filename);
3286
2804
  await writeFile5(filepath, Buffer.from(image.source.data, "base64"));
3287
2805
  tempPaths.push(filepath);
3288
2806
  }
@@ -3293,12 +2811,12 @@ async function saveNormalizedImagesToTempFiles(images, tempImageDir = join14(hom
3293
2811
  return tempPaths;
3294
2812
  }
3295
2813
  async function removeTempImageFiles(paths) {
3296
- await Promise.allSettled(paths.map((path6) => unlink2(path6)));
2814
+ await Promise.allSettled(paths.map((path5) => unlink2(path5)));
3297
2815
  }
3298
2816
 
3299
2817
  // src/managers/coding-agent-manager.ts
3300
- import { readFileSync as readFileSync5 } from "fs";
3301
- import { join as join15 } from "path";
2818
+ import { readFileSync as readFileSync3 } from "fs";
2819
+ import { join as join13 } from "path";
3302
2820
 
3303
2821
  // src/managers/auth-fallback.ts
3304
2822
  var SWAPPABLE_AGENTS = {
@@ -3756,7 +3274,7 @@ var CodingAgentManager = class {
3756
3274
  buildMemoryInstruction() {
3757
3275
  const readSummary = (scope) => {
3758
3276
  try {
3759
- return readFileSync5(join15(MEMORY_ROOT, scope, MEMORY_SUMMARY_FILENAME), "utf8").trim();
3277
+ return readFileSync3(join13(MEMORY_ROOT, scope, MEMORY_SUMMARY_FILENAME), "utf8").trim();
3760
3278
  } catch {
3761
3279
  return "";
3762
3280
  }
@@ -3767,10 +3285,10 @@ var CodingAgentManager = class {
3767
3285
  const parts = [
3768
3286
  `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.`
3769
3287
  ];
3770
- if (organization) parts.push(`<replicas-organization-memory root="${join15(MEMORY_ROOT, "organization")}">
3288
+ if (organization) parts.push(`<replicas-organization-memory root="${join13(MEMORY_ROOT, "organization")}">
3771
3289
  ${organization}
3772
3290
  </replicas-organization-memory>`);
3773
- if (seat) parts.push(`<replicas-personal-memory root="${join15(MEMORY_ROOT, "seat")}">
3291
+ if (seat) parts.push(`<replicas-personal-memory root="${join13(MEMORY_ROOT, "seat")}">
3774
3292
  ${seat}
3775
3293
  </replicas-personal-memory>`);
3776
3294
  return parts.join("\n\n");
@@ -3952,7 +3470,7 @@ function reportCommandProtectionBlock(options) {
3952
3470
 
3953
3471
  // src/services/skill-registry-service.ts
3954
3472
  import { readFile as readFile8, readdir as readdir3, stat as stat2 } from "fs/promises";
3955
- import { dirname as dirname3, isAbsolute, join as join16, relative, resolve } from "path";
3473
+ import { dirname as dirname3, isAbsolute, join as join14, relative, resolve } from "path";
3956
3474
  var REGISTRY_ROOT_DIR = ".replicas/skill-registries";
3957
3475
  var REGISTRY_MANIFEST = "manifest.json";
3958
3476
  async function getSkillRegistryInventory(homeDir) {
@@ -3985,7 +3503,7 @@ async function getSkillRegistryInventory(homeDir) {
3985
3503
  async function buildClaudeRegistryConfig(homeDir) {
3986
3504
  const inventory = await getSkillRegistryInventory(homeDir);
3987
3505
  return {
3988
- plugins: inventory.claudePluginRoots.map((path6) => ({ type: "local", path: path6 })),
3506
+ plugins: inventory.claudePluginRoots.map((path5) => ({ type: "local", path: path5 })),
3989
3507
  enableAllSkills: inventory.claudePluginRoots.length > 0 || inventory.standaloneSkills.length > 0
3990
3508
  };
3991
3509
  }
@@ -4013,10 +3531,10 @@ async function scanRegistry(registryDir) {
4013
3531
  }
4014
3532
  async function findSkillCollections(registryDir) {
4015
3533
  const candidateRoots = [
4016
- { source: "skills", root: join16(registryDir, "skills") },
4017
- { source: "agents", root: join16(registryDir, ".agents", "skills") },
4018
- { source: "codex", root: join16(registryDir, ".codex", "skills") },
4019
- { source: "claude", root: join16(registryDir, ".claude", "skills") }
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") }
4020
3538
  ];
4021
3539
  const collections = [];
4022
3540
  for (const { source, root } of candidateRoots) {
@@ -4030,9 +3548,9 @@ async function findSkillCollections(registryDir) {
4030
3548
  async function findSkillDirsInRoot(root) {
4031
3549
  const skillDirs = [];
4032
3550
  for (const dirent of await safeReadDir(root)) {
4033
- const skillDir = join16(root, dirent.name);
3551
+ const skillDir = join14(root, dirent.name);
4034
3552
  if (!await isDirectoryDirent(dirent, skillDir)) continue;
4035
- if (await fileExists(join16(skillDir, "SKILL.md"))) {
3553
+ if (await fileExists(join14(skillDir, "SKILL.md"))) {
4036
3554
  skillDirs.push(skillDir);
4037
3555
  }
4038
3556
  }
@@ -4042,9 +3560,9 @@ async function findTopLevelSkills(registryDir) {
4042
3560
  const skills = [];
4043
3561
  for (const dirent of await safeReadDir(registryDir)) {
4044
3562
  if (dirent.name.startsWith(".") || dirent.name === "skills" || dirent.name === "plugins") continue;
4045
- const skillDir = join16(registryDir, dirent.name);
3563
+ const skillDir = join14(registryDir, dirent.name);
4046
3564
  if (!await isDirectoryDirent(dirent, skillDir)) continue;
4047
- if (await fileExists(join16(skillDir, "SKILL.md"))) {
3565
+ if (await fileExists(join14(skillDir, "SKILL.md"))) {
4048
3566
  skills.push({ source: "root", skillDir });
4049
3567
  }
4050
3568
  }
@@ -4055,10 +3573,10 @@ async function findClaudePluginRoots(registryDir) {
4055
3573
  async function walk(dir) {
4056
3574
  for (const dirent of await safeReadDir(dir)) {
4057
3575
  if (dirent.name === ".git") continue;
4058
- const child = join16(dir, dirent.name);
3576
+ const child = join14(dir, dirent.name);
4059
3577
  if (!await isDirectoryDirent(dirent, child)) continue;
4060
3578
  if (dirent.name === ".claude-plugin") {
4061
- if (await fileExists(join16(child, "plugin.json"))) {
3579
+ if (await fileExists(join14(child, "plugin.json"))) {
4062
3580
  roots.push(dirname3(child));
4063
3581
  }
4064
3582
  continue;
@@ -4070,7 +3588,7 @@ async function findClaudePluginRoots(registryDir) {
4070
3588
  return uniqueStrings(roots);
4071
3589
  }
4072
3590
  async function hasCodexMarketplace(registryDir) {
4073
- return await fileExists(join16(registryDir, ".agents", "plugins", "marketplace.json")) || await fileExists(join16(registryDir, ".codex", "plugins", "marketplace.json"));
3591
+ return await fileExists(join14(registryDir, ".agents", "plugins", "marketplace.json")) || await fileExists(join14(registryDir, ".codex", "plugins", "marketplace.json"));
4074
3592
  }
4075
3593
  async function installCodexRegistryPlugins(client2, inventory) {
4076
3594
  const cwds = inventory.codexMarketplaceCwds;
@@ -4112,10 +3630,10 @@ async function readManifest(homeDir) {
4112
3630
  }
4113
3631
  }
4114
3632
  function getRegistryRoot(homeDir) {
4115
- return join16(homeDir, REGISTRY_ROOT_DIR);
3633
+ return join14(homeDir, REGISTRY_ROOT_DIR);
4116
3634
  }
4117
3635
  function getManifestPath(homeDir) {
4118
- return join16(getRegistryRoot(homeDir), REGISTRY_MANIFEST);
3636
+ return join14(getRegistryRoot(homeDir), REGISTRY_MANIFEST);
4119
3637
  }
4120
3638
  function emptyInventory(registryRoot) {
4121
3639
  return {
@@ -4143,31 +3661,31 @@ function uniqueStandaloneSkills(skills) {
4143
3661
  }
4144
3662
  return unique;
4145
3663
  }
4146
- async function safeReadDir(path6) {
3664
+ async function safeReadDir(path5) {
4147
3665
  try {
4148
- return await readdir3(path6, { withFileTypes: true });
3666
+ return await readdir3(path5, { withFileTypes: true });
4149
3667
  } catch (error) {
4150
3668
  if (isNotFoundError(error)) return [];
4151
3669
  throw error;
4152
3670
  }
4153
3671
  }
4154
- async function isDirectoryDirent(dirent, path6) {
3672
+ async function isDirectoryDirent(dirent, path5) {
4155
3673
  if (dirent.isDirectory()) return true;
4156
3674
  if (!dirent.isSymbolicLink()) return false;
4157
- return directoryExists(path6);
3675
+ return directoryExists(path5);
4158
3676
  }
4159
- async function directoryExists(path6) {
3677
+ async function directoryExists(path5) {
4160
3678
  try {
4161
- const pathStat = await stat2(path6);
3679
+ const pathStat = await stat2(path5);
4162
3680
  return pathStat.isDirectory();
4163
3681
  } catch (error) {
4164
3682
  if (isNotFoundError(error)) return false;
4165
3683
  throw error;
4166
3684
  }
4167
3685
  }
4168
- async function fileExists(path6) {
3686
+ async function fileExists(path5) {
4169
3687
  try {
4170
- const pathStat = await stat2(path6);
3688
+ const pathStat = await stat2(path5);
4171
3689
  return pathStat.isFile();
4172
3690
  } catch (error) {
4173
3691
  if (isNotFoundError(error)) return false;
@@ -4562,7 +4080,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
4562
4080
  authRetrying = false;
4563
4081
  constructor(options) {
4564
4082
  super({ ...options, provider: AGENT.CLAUDE });
4565
- this.historyFilePath = options.historyFilePath ?? join17(homedir12(), ".replicas", "claude", "history.jsonl");
4083
+ this.historyFilePath = options.historyFilePath ?? join15(homedir10(), ".replicas", "claude", "history.jsonl");
4566
4084
  this.historyFile = new CodexHistoryFile(this.historyFilePath);
4567
4085
  this.systemPromptOverride = options.systemPromptOverride;
4568
4086
  this.toolsOverride = options.tools;
@@ -5616,7 +5134,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
5616
5134
 
5617
5135
  // src/managers/codex-asp/codex-asp-manager.ts
5618
5136
  import { readdir as readdir4 } from "fs/promises";
5619
- import { join as join19 } from "path";
5137
+ import { join as join17 } from "path";
5620
5138
 
5621
5139
  // src/managers/codex-asp/asp-host.ts
5622
5140
  var hostPromise = null;
@@ -5628,9 +5146,11 @@ async function getCodexAspHost() {
5628
5146
  }
5629
5147
  hostPromise ??= (async () => {
5630
5148
  try {
5149
+ const oauthOptions = await codexTokenManager.prepareAspOauthOptions();
5631
5150
  const process2 = new AppServerProcess({
5632
5151
  cwd: ENGINE_ENV.WORKSPACE_ROOT,
5633
- env: buildCodexAgentEnv()
5152
+ env: buildCodexAgentEnv(),
5153
+ ...oauthOptions
5634
5154
  });
5635
5155
  const { client: client2 } = await process2.start();
5636
5156
  activeProcess = process2;
@@ -5729,7 +5249,7 @@ var CodexQuotaStatusTracker = class {
5729
5249
  };
5730
5250
 
5731
5251
  // src/managers/codex-asp/mappers.ts
5732
- import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
5252
+ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
5733
5253
  var localImageCache = /* @__PURE__ */ new Map();
5734
5254
  var DEFAULT_MODEL = DEFAULT_CODEX_MODEL;
5735
5255
  var THREAD_START_METHOD = "thread/start";
@@ -5851,16 +5371,16 @@ function transcriptItemsForTurn(turn) {
5851
5371
  const otherItems = turn.items.filter((item) => item.type !== "userMessage");
5852
5372
  return [...userItems, ...otherItems];
5853
5373
  }
5854
- function userImageForLocalPath(path6) {
5855
- const cached = localImageCache.get(path6);
5374
+ function userImageForLocalPath(path5) {
5375
+ const cached = localImageCache.get(path5);
5856
5376
  if (cached) return cached;
5857
- if (!existsSync5(path6)) return null;
5377
+ if (!existsSync5(path5)) return null;
5858
5378
  const image = {
5859
5379
  type: "image",
5860
- mediaType: inferMediaType(path6),
5861
- data: readFileSync6(path6).toString("base64")
5380
+ mediaType: inferMediaType(path5),
5381
+ data: readFileSync4(path5).toString("base64")
5862
5382
  };
5863
- if (image.data.length > 0) localImageCache.set(path6, image);
5383
+ if (image.data.length > 0) localImageCache.set(path5, image);
5864
5384
  return image;
5865
5385
  }
5866
5386
  function userImagesForInput(input) {
@@ -6258,9 +5778,9 @@ async function buildTurnInput(request) {
6258
5778
  }
6259
5779
  const normalizedImages = await normalizeImages(request.images);
6260
5780
  const tempImagePaths = await saveNormalizedImagesToTempFiles(normalizedImages);
6261
- input.push(...tempImagePaths.map((path6) => ({
5781
+ input.push(...tempImagePaths.map((path5) => ({
6262
5782
  type: "localImage",
6263
- path: path6
5783
+ path: path5
6264
5784
  })));
6265
5785
  return { input, tempImagePaths };
6266
5786
  }
@@ -6349,19 +5869,19 @@ var TranscriptUpdateCoalescer = class {
6349
5869
  };
6350
5870
 
6351
5871
  // src/services/chat/history-paths.ts
6352
- import { homedir as homedir13 } from "os";
6353
- import { join as join18 } from "path";
6354
- var ENGINE_DIR2 = join18(homedir13(), ".replicas", "engine");
6355
- var CHATS_FILE = join18(ENGINE_DIR2, "chats.json");
6356
- var CLAUDE_HISTORY_DIR = join18(ENGINE_DIR2, "claude-histories");
6357
- var RELAY_HISTORY_DIR = join18(ENGINE_DIR2, "relay-histories");
6358
- var CODEX_HISTORY_DIR = join18(ENGINE_DIR2, "codex-histories");
6359
- var CURSOR_HISTORY_DIR = join18(ENGINE_DIR2, "cursor-histories");
6360
- var OPENCODE_HISTORY_DIR = join18(ENGINE_DIR2, "opencode-histories");
6361
- var PI_HISTORY_DIR = join18(ENGINE_DIR2, "pi-histories");
6362
- var DEEPSEEK_HISTORY_DIR = join18(ENGINE_DIR2, "deepseek-histories");
6363
- var FX_HISTORY_DIR = join18(ENGINE_DIR2, "fx-histories");
6364
- var KIMI_HISTORY_DIR = join18(ENGINE_DIR2, "kimi-histories");
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");
6365
5885
  var HISTORY_DIR_BY_PROVIDER = {
6366
5886
  claude: CLAUDE_HISTORY_DIR,
6367
5887
  relay: RELAY_HISTORY_DIR,
@@ -6420,7 +5940,7 @@ async function readCodexAspThreadHistory(threadId) {
6420
5940
  }
6421
5941
  for (const entry of entries) {
6422
5942
  if (!entry.isFile() || !entry.name.endsWith(".jsonl") || entry.name.endsWith(".pages.jsonl")) continue;
6423
- const history = await new CodexHistoryFile(join19(CODEX_HISTORY_DIR, entry.name)).load();
5943
+ const history = await new CodexHistoryFile(join17(CODEX_HISTORY_DIR, entry.name)).load();
6424
5944
  const transcript = history.transcriptsByThreadId.get(threadId);
6425
5945
  if (transcript) {
6426
5946
  return {
@@ -6799,6 +6319,11 @@ var CodexAspManager = class extends CodingAgentManager {
6799
6319
  return;
6800
6320
  }
6801
6321
  }
6322
+ if (terminalError instanceof CodexAspAuthMethodChangedError) {
6323
+ const retryFailure = await this.restartAndRetry(dispatch);
6324
+ if (!retryFailure) return;
6325
+ terminalError = retryFailure.error;
6326
+ }
6802
6327
  if (isCodexAuthError(terminalError)) {
6803
6328
  const refreshed = await codexTokenManager.fetchFreshCredentials(
6804
6329
  terminalError instanceof Error ? terminalError.message : String(terminalError),
@@ -7163,6 +6688,7 @@ var CodexAspManager = class extends CodingAgentManager {
7163
6688
  dispatchAspNotification(notification, handlers);
7164
6689
  };
7165
6690
  const onServerRequest = (serverRequest) => {
6691
+ if (serverRequest.method === "account/chatgptAuthTokens/refresh") return;
7166
6692
  void this.respondToServerRequest(host, serverRequest).catch((error) => {
7167
6693
  console.warn(`[CodexAspManager] Failed to handle ASP server request ${serverRequest.method}:`, error);
7168
6694
  host.client.reject(serverRequest.id, -32603, `Failed to handle ${serverRequest.method}`);
@@ -7171,6 +6697,10 @@ var CodexAspManager = class extends CodingAgentManager {
7171
6697
  const onDispose = (reason) => {
7172
6698
  this.threadAttached = false;
7173
6699
  this.activeTurnId = null;
6700
+ if (reason instanceof CodexAspAuthMethodChangedError) {
6701
+ rejectDisposed(reason);
6702
+ return;
6703
+ }
7174
6704
  const turnLabel = observedTurnId ? ` ${observedTurnId}` : "";
7175
6705
  rejectDisposed(new Error(`Codex ASP client disposed before turn${turnLabel} completed: ${reason.message}`));
7176
6706
  };
@@ -7320,7 +6850,6 @@ var CodexAspManager = class extends CodingAgentManager {
7320
6850
  return;
7321
6851
  }
7322
6852
  case "item/tool/requestUserInput":
7323
- case "account/chatgptAuthTokens/refresh":
7324
6853
  case "attestation/generate":
7325
6854
  host.client.reject(requestId, -32601, `Replicas does not support ASP server request ${method}`);
7326
6855
  return;
@@ -7762,13 +7291,14 @@ var CodexAspManager = class extends CodingAgentManager {
7762
7291
 
7763
7292
  // src/managers/cursor-manager.ts
7764
7293
  import { mkdir as mkdir11, readFile as readFile10, readdir as readdir5 } from "fs/promises";
7765
- import { basename, dirname as dirname5, extname, join as join20 } from "path";
7294
+ import { basename, dirname as dirname5, extname, join as join18 } from "path";
7766
7295
  import { parse as parseYaml } from "yaml";
7767
7296
  import { Agent as CursorAgent } from "@cursor/sdk";
7768
7297
  var CURSOR_SLASH_COMMANDS_CACHE_MS = 3e4;
7769
7298
  var CURSOR_STREAM_INACTIVITY_TIMEOUT_MS = 30 * 6e4;
7770
7299
  var CURSOR_RUN_SETTLE_TIMEOUT_MS = 3e4;
7771
7300
  var CURSOR_CANCEL_TIMEOUT_MS = 1e4;
7301
+ var CURSOR_RECONNECT_NOTICE_DELAY_MS = 15e3;
7772
7302
  var TURN_ABORTED = /* @__PURE__ */ Symbol("cursor-turn-aborted");
7773
7303
  var CURSOR_COMPOSER_CONTEXT_WINDOW = 2e5;
7774
7304
  var CURSOR_CATEGORY_COLORS = {
@@ -7777,6 +7307,19 @@ var CURSOR_CATEGORY_COLORS = {
7777
7307
  cacheWrite: "#e5c07b",
7778
7308
  output: "#56b6c2"
7779
7309
  };
7310
+ var CURSOR_TRANSPORT_ERROR_PATTERNS = [
7311
+ /connection failed/,
7312
+ /connection stalled/,
7313
+ /cursor run stalled/,
7314
+ /stream closed/,
7315
+ /stream ended/,
7316
+ /nghttp2_/,
7317
+ /err_http2_stream_error/,
7318
+ /write ecanceled/
7319
+ ];
7320
+ function isCursorTransportError(text) {
7321
+ return isTransientErrorText(text, { extraPatterns: CURSOR_TRANSPORT_ERROR_PATTERNS });
7322
+ }
7780
7323
  function finiteNumber(value) {
7781
7324
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
7782
7325
  }
@@ -7821,7 +7364,7 @@ async function listCursorCommandsInDirectory(directory) {
7821
7364
  const name = basename(entry.name, ".md");
7822
7365
  let description;
7823
7366
  try {
7824
- description = extractCursorCommandDescription(await readFile10(join20(directory, entry.name), "utf8"));
7367
+ description = extractCursorCommandDescription(await readFile10(join18(directory, entry.name), "utf8"));
7825
7368
  } catch (error) {
7826
7369
  console.warn("[CursorManager] Failed to read slash command file:", error);
7827
7370
  }
@@ -7836,14 +7379,16 @@ var CursorManager = class extends CodingAgentManager {
7836
7379
  abortActiveTurn = null;
7837
7380
  blockedToolCallIds = /* @__PURE__ */ new Set();
7838
7381
  pendingCursorBlockReason = null;
7382
+ reconnectNoticeVisible = false;
7839
7383
  instructionsDelivered = false;
7384
+ resumeSessionId = null;
7840
7385
  historyFilePath;
7841
7386
  historyFile;
7842
7387
  slashCommandsCache = null;
7843
7388
  slashCommandsRequest = null;
7844
7389
  constructor(options) {
7845
7390
  super(options);
7846
- this.historyFilePath = options.historyFilePath ?? join20(ENGINE_ENV.HOME_DIR, ".replicas", "cursor", "history.jsonl");
7391
+ this.historyFilePath = options.historyFilePath ?? join18(ENGINE_ENV.HOME_DIR, ".replicas", "cursor", "history.jsonl");
7847
7392
  this.historyFile = new CodexHistoryFile(this.historyFilePath);
7848
7393
  this.initializeManager(this.processMessageInternal.bind(this));
7849
7394
  }
@@ -7868,19 +7413,42 @@ var CursorManager = class extends CodingAgentManager {
7868
7413
  console.error("[CursorManager] Failed to cancel Cursor run:", error);
7869
7414
  }
7870
7415
  }
7871
- dispose() {
7416
+ closeAgent() {
7417
+ const agent = this.agent;
7418
+ this.agent = null;
7872
7419
  try {
7873
- this.agent?.close();
7420
+ agent?.close();
7874
7421
  } catch (error) {
7875
7422
  console.error("[CursorManager] Failed to close Cursor agent:", error);
7876
7423
  }
7877
- this.agent = null;
7424
+ }
7425
+ dispose() {
7426
+ this.closeAgent();
7427
+ }
7428
+ mayBeReconnecting() {
7429
+ return this.reconnectNoticeVisible;
7430
+ }
7431
+ setReconnectNoticeVisible(value) {
7432
+ if (this.reconnectNoticeVisible === value) return;
7433
+ this.reconnectNoticeVisible = value;
7434
+ this.emitSyntheticEvent(CURSOR_CONNECTION_STATUS_EVENT_TYPE, { mayBeReconnecting: value });
7435
+ }
7436
+ // Cursor keeps a thread's partial response and tool results, so once the model
7437
+ // has acted the session must stay resumable even if the run later fails or is
7438
+ // interrupted — otherwise a later user retry strands that work on an orphaned
7439
+ // thread. The same activity proves the instruction-bearing
7440
+ // first message reached the thread, so instructions must not be re-sent.
7441
+ async retainThread(agentId) {
7442
+ if (this.instructionsDelivered && this.resumeSessionId === agentId) return;
7443
+ this.instructionsDelivered = true;
7444
+ this.resumeSessionId = agentId;
7445
+ await this.onSaveSessionId(agentId);
7878
7446
  }
7879
7447
  async getHistory(page = {}) {
7880
7448
  await this.historyFile.flush();
7881
7449
  const history = await this.historyFile.loadEventsPage(page);
7882
7450
  return {
7883
- thread_id: this.agent?.agentId ?? this.initialSessionId,
7451
+ thread_id: this.agent?.agentId ?? this.resumeSessionId ?? this.initialSessionId,
7884
7452
  ...history,
7885
7453
  goal: null
7886
7454
  };
@@ -7894,7 +7462,7 @@ var CursorManager = class extends CodingAgentManager {
7894
7462
  this.slashCommandsRequest ??= (async () => {
7895
7463
  try {
7896
7464
  const repoDirectories = await getAgentAdditionalDirectories();
7897
- const commandDirectories = [this.workingDirectory, ...repoDirectories, ENGINE_ENV.HOME_DIR].map((directory) => join20(directory, ".cursor", "commands"));
7465
+ const commandDirectories = [this.workingDirectory, ...repoDirectories, ENGINE_ENV.HOME_DIR].map((directory) => join18(directory, ".cursor", "commands"));
7898
7466
  const commands = mergeSlashCommands(
7899
7467
  ...await Promise.all(commandDirectories.map(listCursorCommandsInDirectory))
7900
7468
  );
@@ -7914,8 +7482,9 @@ var CursorManager = class extends CodingAgentManager {
7914
7482
  }
7915
7483
  const model = { id: request.model ?? DEFAULT_CURSOR_MODEL };
7916
7484
  const settingSources = ["project", "user"];
7917
- const local = { cwd: this.workingDirectory, settingSources };
7918
- this.agent = this.initialSessionId ? await CursorAgent.resume(this.initialSessionId, {
7485
+ const local = { cwd: this.workingDirectory, settingSources, enableAgentRetries: true };
7486
+ const resumeId = this.resumeSessionId ?? this.initialSessionId;
7487
+ this.agent = resumeId ? await CursorAgent.resume(resumeId, {
7919
7488
  apiKey,
7920
7489
  model,
7921
7490
  local
@@ -7924,89 +7493,142 @@ var CursorManager = class extends CodingAgentManager {
7924
7493
  model,
7925
7494
  local
7926
7495
  });
7927
- if (this.initialSessionId) await this.onSaveSessionId(this.agent.agentId);
7496
+ if (resumeId) await this.onSaveSessionId(this.agent.agentId);
7928
7497
  return this.agent;
7929
7498
  }
7930
7499
  async processMessageInternal(request) {
7931
7500
  let run = null;
7501
+ let agent = null;
7502
+ let sawCursorActivity = false;
7503
+ let reconnectNoticeTimer = null;
7932
7504
  const aborted = new Promise((resolve5) => {
7933
7505
  this.abortActiveTurn = () => resolve5(TURN_ABORTED);
7934
7506
  });
7935
7507
  const linearSessionId = ENGINE_ENV.REPLICAS_LINEAR_SESSION_ID;
7936
7508
  const linearForwarder = new LinearEventForwarder(linearSessionId);
7509
+ const clearReconnectNoticeTimer = () => {
7510
+ if (!reconnectNoticeTimer) return;
7511
+ clearTimeout(reconnectNoticeTimer);
7512
+ reconnectNoticeTimer = null;
7513
+ };
7514
+ const markCursorActivity = () => {
7515
+ sawCursorActivity = true;
7516
+ clearReconnectNoticeTimer();
7517
+ this.setReconnectNoticeVisible(false);
7518
+ };
7937
7519
  try {
7938
7520
  const includeInstructions = !this.initialSessionId && !this.instructionsDelivered;
7939
7521
  const message = await this.toCursorMessage(request, includeInstructions);
7940
- const agent = await this.ensureAgent(request);
7941
7522
  const model = request.model ?? DEFAULT_CURSOR_MODEL;
7942
7523
  this.activeModel = model;
7943
- this.recordHistoryEvent("event_msg", {
7944
- type: "user_message",
7945
- message: request.message
7946
- }, this.historyFile);
7947
- run = await agent.send(message, {
7948
- model: { id: model },
7949
- mode: request.planMode ? "plan" : "agent",
7950
- onDelta: async (args) => {
7951
- this.recordCursorContextUsage(args.update);
7952
- await this.handleCursorToolCall(cursorToolInputFromDelta(args.update));
7953
- }
7954
- });
7955
- this.activeRun = run;
7956
- if (this.pendingCursorBlockReason) {
7957
- await run.cancel();
7958
- throw new Error(this.pendingCursorBlockReason);
7959
- }
7960
- const events = run.stream()[Symbol.asyncIterator]();
7961
- let interrupted = false;
7962
- while (true) {
7963
- const nextPromise = events.next();
7964
- nextPromise.catch(() => {
7524
+ let failure = null;
7525
+ try {
7526
+ reconnectNoticeTimer = setTimeout(() => {
7527
+ if (!sawCursorActivity && this.abortActiveTurn) {
7528
+ this.setReconnectNoticeVisible(true);
7529
+ }
7530
+ }, CURSOR_RECONNECT_NOTICE_DELAY_MS);
7531
+ agent = await this.ensureAgent(request);
7532
+ this.recordHistoryEvent("event_msg", {
7533
+ type: "user_message",
7534
+ message: request.message
7535
+ }, this.historyFile);
7536
+ run = await agent.send(message, {
7537
+ model: { id: model },
7538
+ mode: request.planMode ? "plan" : "agent",
7539
+ onDelta: async (args) => {
7540
+ markCursorActivity();
7541
+ this.recordCursorContextUsage(args.update);
7542
+ await this.handleCursorToolCall(cursorToolInputFromDelta(args.update));
7543
+ }
7965
7544
  });
7966
- const next = await raceWithTimeout(
7967
- Promise.race([nextPromise, aborted]),
7968
- CURSOR_STREAM_INACTIVITY_TIMEOUT_MS
7969
- );
7970
- if (next === TIMEOUT) {
7971
- throw new Error(`Cursor run stalled: no events for ${CURSOR_STREAM_INACTIVITY_TIMEOUT_MS / 6e4} minutes; cancelling the run`);
7545
+ this.activeRun = run;
7546
+ if (this.pendingCursorBlockReason) {
7547
+ await run.cancel();
7548
+ throw new Error(this.pendingCursorBlockReason);
7972
7549
  }
7973
- if (next === TURN_ABORTED) {
7974
- interrupted = true;
7975
- break;
7550
+ const events = run.stream()[Symbol.asyncIterator]();
7551
+ let interrupted = false;
7552
+ while (true) {
7553
+ const nextPromise = events.next();
7554
+ nextPromise.catch(() => {
7555
+ });
7556
+ const next = await raceWithTimeout(
7557
+ Promise.race([nextPromise, aborted]),
7558
+ CURSOR_STREAM_INACTIVITY_TIMEOUT_MS
7559
+ );
7560
+ if (next === TIMEOUT) {
7561
+ throw new Error(`Cursor run stalled: no events for ${CURSOR_STREAM_INACTIVITY_TIMEOUT_MS / 6e4} minutes; cancelling the run`);
7562
+ }
7563
+ if (next === TURN_ABORTED) {
7564
+ interrupted = true;
7565
+ break;
7566
+ }
7567
+ if (next.done) break;
7568
+ markCursorActivity();
7569
+ const event = next.value;
7570
+ this.recordHistoryEvent(`cursor-${event.type}`, event, this.historyFile);
7571
+ if (event.type === "tool_call" && event.status === "running") {
7572
+ await this.handleCursorToolCall(cursorToolInputFromMessage(event));
7573
+ }
7574
+ if (linearSessionId) {
7575
+ linearForwarder.sendEvent(convertCursorEvent(event, linearSessionId));
7576
+ }
7976
7577
  }
7977
- if (next.done) break;
7978
- const event = next.value;
7979
- this.recordHistoryEvent(`cursor-${event.type}`, event, this.historyFile);
7980
- if (event.type === "tool_call" && event.status === "running") {
7981
- await this.handleCursorToolCall(cursorToolInputFromMessage(event));
7578
+ if (interrupted) {
7579
+ if (sawCursorActivity) await this.retainThread(agent.agentId);
7580
+ await this.cancelRun(run);
7581
+ return;
7982
7582
  }
7983
- if (linearSessionId) {
7984
- linearForwarder.sendEvent(convertCursorEvent(event, linearSessionId));
7583
+ const result = await raceWithTimeout(run.wait(), CURSOR_RUN_SETTLE_TIMEOUT_MS);
7584
+ if (result === TIMEOUT) {
7585
+ throw new Error("Cursor run stalled after its event stream ended");
7985
7586
  }
7986
- }
7987
- if (interrupted) {
7587
+ if (result.status === "error") {
7588
+ const detail = await this.readRunErrorDetail(agent.agentId, result.id);
7589
+ const text = detail || result.result || "Cursor run failed";
7590
+ failure = {
7591
+ text,
7592
+ runId: result.id,
7593
+ ...result.requestId ? { requestId: result.requestId } : {},
7594
+ transport: isCursorTransportError(text)
7595
+ };
7596
+ } else {
7597
+ await this.retainThread(agent.agentId);
7598
+ linearForwarder.flushThoughtAsResponse();
7599
+ return;
7600
+ }
7601
+ } catch (error) {
7988
7602
  await this.cancelRun(run);
7989
- return;
7603
+ const text = extractErrorText(error) || "Cursor run failed";
7604
+ failure = {
7605
+ text,
7606
+ ...run ? { runId: run.id } : {},
7607
+ ...run?.requestId ? { requestId: run.requestId } : {},
7608
+ transport: isCursorTransportError(text)
7609
+ };
7990
7610
  }
7991
- const result = await raceWithTimeout(run.wait(), CURSOR_RUN_SETTLE_TIMEOUT_MS);
7992
- if (result === TIMEOUT) {
7993
- throw new Error("Cursor run did not report a result after its event stream ended");
7994
- }
7995
- if (includeInstructions) {
7996
- this.instructionsDelivered = true;
7997
- await this.onSaveSessionId(agent.agentId);
7998
- }
7999
- if (result.status === "error") {
8000
- const detail = await this.readRunErrorDetail(agent.agentId, result.id);
8001
- console.error("[CursorManager] Cursor run failed:", { runId: result.id, model, detail });
8002
- this.recordHistoryEvent("cursor-error", {
8003
- type: "error",
8004
- message: detail || result.result || "Cursor run failed",
8005
- runId: result.id
8006
- }, this.historyFile);
8007
- } else {
8008
- linearForwarder.flushThoughtAsResponse();
7611
+ if (agent && sawCursorActivity) await this.retainThread(agent.agentId);
7612
+ if (!failure) return;
7613
+ console.error("[CursorManager] Cursor run failed:", {
7614
+ runId: failure.runId,
7615
+ requestId: failure.requestId,
7616
+ model,
7617
+ detail: failure.text,
7618
+ transport: failure.transport
7619
+ });
7620
+ const displayMessage = failure.transport ? sawCursorActivity ? "Cursor couldn't reconnect after its automatic retries. Retry the message to continue from the same chat." : run ? "Cursor couldn't connect after its automatic retries. Retry the message or start a new Cursor chat if the problem continues." : "The connection to Cursor failed. Retry the message or start a new Cursor chat if the problem continues." : failure.text;
7621
+ if (failure.transport) {
7622
+ this.activeRun = null;
7623
+ this.closeAgent();
8009
7624
  }
7625
+ this.recordHistoryEvent("cursor-error", {
7626
+ type: "error",
7627
+ message: displayMessage,
7628
+ ...failure.transport ? { detail: failure.text } : {},
7629
+ ...failure.runId ? { runId: failure.runId } : {},
7630
+ ...failure.requestId ? { requestId: failure.requestId } : {}
7631
+ }, this.historyFile);
8010
7632
  } catch (error) {
8011
7633
  await this.cancelRun(run);
8012
7634
  this.recordHistoryEvent("cursor-error", {
@@ -8014,6 +7636,8 @@ var CursorManager = class extends CodingAgentManager {
8014
7636
  message: error instanceof Error ? error.message : String(error)
8015
7637
  }, this.historyFile);
8016
7638
  } finally {
7639
+ clearReconnectNoticeTimer();
7640
+ this.setReconnectNoticeVisible(false);
8017
7641
  this.abortActiveTurn = null;
8018
7642
  this.activeRun = null;
8019
7643
  this.activeModel = null;
@@ -8156,7 +7780,7 @@ ${instructions}
8156
7780
  import { spawn as spawn3 } from "child_process";
8157
7781
  import { randomUUID as randomUUID5 } from "crypto";
8158
7782
  import { createRequire } from "module";
8159
- import { dirname as dirname6, join as join21 } from "path";
7783
+ import { dirname as dirname6, join as join19 } from "path";
8160
7784
  import { fileURLToPath } from "url";
8161
7785
  import { existsSync as existsSync6 } from "fs";
8162
7786
  import { mkdir as mkdir12 } from "fs/promises";
@@ -8171,11 +7795,11 @@ var questionSelectionSchema = z2.record(z2.string(), z2.object({
8171
7795
  custom: z2.string().optional()
8172
7796
  }));
8173
7797
  var require2 = createRequire(import.meta.url);
8174
- var DSH_BIN = join21(dirname6(require2.resolve("@deepseek-ai/dsh/package.json")), "lib", "bin.js");
7798
+ var DSH_BIN = join19(dirname6(require2.resolve("@deepseek-ai/dsh/package.json")), "lib", "bin.js");
8175
7799
  var MANAGER_DIR = dirname6(fileURLToPath(import.meta.url));
8176
7800
  var DSH_PATCH = [
8177
- join21(MANAGER_DIR, "..", "..", "scripts", "deepseek", "replicas.cordis.patch.yml"),
8178
- join21(MANAGER_DIR, "..", "..", "..", "scripts", "deepseek", "replicas.cordis.patch.yml")
7801
+ join19(MANAGER_DIR, "..", "..", "scripts", "deepseek", "replicas.cordis.patch.yml"),
7802
+ join19(MANAGER_DIR, "..", "..", "..", "scripts", "deepseek", "replicas.cordis.patch.yml")
8179
7803
  ].find(existsSync6) ?? "";
8180
7804
  var DeepseekApiClient = class extends AbstractApiClient {
8181
7805
  constructor(baseUrl) {
@@ -8215,8 +7839,8 @@ var DeepseekApiClient = class extends AbstractApiClient {
8215
7839
  if (!execution.success) throw new Error(`DeepSeek Harness did not recognize ${line}.`);
8216
7840
  if (execution.data.result.kind === "error") throw new Error(execution.data.result.text ?? `DeepSeek Harness rejected ${line}.`);
8217
7841
  }
8218
- async *readWebSocket(path6, signal, schema, onOpen) {
8219
- const url = new URL(path6, this.baseUrl);
7842
+ async *readWebSocket(path5, signal, schema, onOpen) {
7843
+ const url = new URL(path5, this.baseUrl);
8220
7844
  url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
8221
7845
  const socket = new WebSocket(url);
8222
7846
  const inbox = [];
@@ -8289,7 +7913,7 @@ var DeepseekManager = class extends CodingAgentManager {
8289
7913
  constructor(options) {
8290
7914
  super(options);
8291
7915
  this.sessionId = options.initialSessionId ? sessionIdSchema.parse(options.initialSessionId) : null;
8292
- this.historyFilePath = options.historyFilePath ?? join21(ENGINE_ENV.HOME_DIR, ".replicas", "deepseek", "history.jsonl");
7916
+ this.historyFilePath = options.historyFilePath ?? join19(ENGINE_ENV.HOME_DIR, ".replicas", "deepseek", "history.jsonl");
8293
7917
  this.historyFile = new CodexHistoryFile(this.historyFilePath);
8294
7918
  this.initializeManager(this.processMessageInternal.bind(this));
8295
7919
  }
@@ -8376,7 +8000,7 @@ var DeepseekManager = class extends CodingAgentManager {
8376
8000
  ...process.env,
8377
8001
  DEEPSEEK_API_KEY: apiKey,
8378
8002
  DEEPSEEK_BASE_URL: "https://openrouter.ai/api/v1",
8379
- DSH_HOME: join21(ENGINE_ENV.HOME_DIR, ".replicas", "deepseek"),
8003
+ DSH_HOME: join19(ENGINE_ENV.HOME_DIR, ".replicas", "deepseek"),
8380
8004
  DSH_PERMISSION_MODE: "danger-full-access",
8381
8005
  DSH_TELEMETRY_DISABLED: "true"
8382
8006
  },
@@ -9086,7 +8710,7 @@ var KimiManager = class extends AcpManager {
9086
8710
  // src/managers/opencode-manager.ts
9087
8711
  import { existsSync as existsSync7 } from "fs";
9088
8712
  import { mkdir as mkdir14, readFile as readFile13 } from "fs/promises";
9089
- import { delimiter, dirname as dirname8, join as join22 } from "path";
8713
+ import { delimiter, dirname as dirname8, join as join20 } from "path";
9090
8714
  import { randomBytes as randomBytes2 } from "crypto";
9091
8715
  import { fileURLToPath as fileURLToPath2 } from "url";
9092
8716
  import { Agent } from "undici";
@@ -9133,7 +8757,7 @@ async function getAllowedOpenRouterModels() {
9133
8757
 
9134
8758
  // src/managers/opencode-manager.ts
9135
8759
  var OPENCODE_SHIM_DIR = dirname8(fileURLToPath2(new URL("../../scripts/opencode", import.meta.url)));
9136
- var OPENCODE_CONFIG_PATH = join22(ENGINE_ENV.HOME_DIR, ".config", "opencode", "opencode.json");
8760
+ var OPENCODE_CONFIG_PATH = join20(ENGINE_ENV.HOME_DIR, ".config", "opencode", "opencode.json");
9137
8761
  var OPENCODE_FETCH_DISPATCHER = new Agent({ headersTimeout: 0, bodyTimeout: 0 });
9138
8762
  var OPENCODE_SERVER_STARTUP_TIMEOUT_MS = 3e4;
9139
8763
  var OPENCODE_WORKSPACE_PERMISSION = {
@@ -9383,7 +9007,7 @@ var OpencodeManager = class extends CodingAgentManager {
9383
9007
  constructor(options) {
9384
9008
  super(options);
9385
9009
  this.sessionId = options.initialSessionId;
9386
- this.historyFilePath = options.historyFilePath ?? join22(ENGINE_ENV.HOME_DIR, ".replicas", "opencode", "history.jsonl");
9010
+ this.historyFilePath = options.historyFilePath ?? join20(ENGINE_ENV.HOME_DIR, ".replicas", "opencode", "history.jsonl");
9387
9011
  this.historyFile = new CodexHistoryFile(this.historyFilePath);
9388
9012
  this.initializeManager(this.processMessageInternal.bind(this));
9389
9013
  }
@@ -9893,7 +9517,7 @@ var OpencodeManager = class extends CodingAgentManager {
9893
9517
 
9894
9518
  // src/managers/pi-manager.ts
9895
9519
  import { mkdir as mkdir15 } from "fs/promises";
9896
- import { dirname as dirname9, join as join23 } from "path";
9520
+ import { dirname as dirname9, join as join21 } from "path";
9897
9521
  import {
9898
9522
  AuthStorage,
9899
9523
  createAgentSession,
@@ -9976,7 +9600,7 @@ var PiManager = class extends CodingAgentManager {
9976
9600
  providerApiKey = null;
9977
9601
  constructor(options) {
9978
9602
  super(options);
9979
- this.historyFilePath = options.historyFilePath ?? join23(PI_HISTORY_DIR, `${Date.now()}.jsonl`);
9603
+ this.historyFilePath = options.historyFilePath ?? join21(PI_HISTORY_DIR, `${Date.now()}.jsonl`);
9980
9604
  this.historyFile = new CodexHistoryFile(this.historyFilePath);
9981
9605
  this.initializeManager(this.processMessageInternal.bind(this));
9982
9606
  }
@@ -10076,7 +9700,7 @@ var PiManager = class extends CodingAgentManager {
10076
9700
  const sessionManager = this.initialSessionId ? SessionManager.open(this.initialSessionId, PI_HISTORY_DIR, this.workingDirectory) : SessionManager.create(this.workingDirectory, PI_HISTORY_DIR);
10077
9701
  const resourceLoader = new DefaultResourceLoader({
10078
9702
  cwd: this.workingDirectory,
10079
- agentDir: join23(ENGINE_ENV.HOME_DIR, ".pi", "agent"),
9703
+ agentDir: join21(ENGINE_ENV.HOME_DIR, ".pi", "agent"),
10080
9704
  extensionFactories: [registerCommandProtection(
10081
9705
  this.workingDirectory,
10082
9706
  this.historyFile,
@@ -10176,9 +9800,9 @@ function extractTextBlocks(content, textBlockType, separator = "\n") {
10176
9800
  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);
10177
9801
  return texts.length > 0 ? texts.join(separator) : null;
10178
9802
  }
10179
- async function engineFetch(path6, options) {
9803
+ async function engineFetch(path5, options) {
10180
9804
  const baseUrl = `http://localhost:${ENGINE_ENV.REPLICAS_ENGINE_PORT}`;
10181
- return fetch(`${baseUrl}${path6}`, {
9805
+ return fetch(`${baseUrl}${path5}`, {
10182
9806
  ...options,
10183
9807
  headers: {
10184
9808
  "Content-Type": "application/json",
@@ -10798,7 +10422,7 @@ import {
10798
10422
  rename as rename2,
10799
10423
  unlink as unlink3
10800
10424
  } from "fs/promises";
10801
- import { join as join24 } from "path";
10425
+ import { join as join22 } from "path";
10802
10426
  import { randomUUID as randomUUID7 } from "crypto";
10803
10427
 
10804
10428
  // src/analytics/agent/activity/skill-mcp-call-extractor.ts
@@ -10849,7 +10473,7 @@ var AgentChatActivityBuffer = class {
10849
10473
  options.storageName,
10850
10474
  ...options.legacyStorageNames ?? []
10851
10475
  ];
10852
- this.liveFile = join24(ENGINE_DIR2, `${options.storageName}.jsonl`);
10476
+ this.liveFile = join22(ENGINE_DIR2, `${options.storageName}.jsonl`);
10853
10477
  this.segmentFilePatterns = this.storageNames.map(
10854
10478
  (storageName) => new RegExp(`^${storageName}\\.(\\d+)\\.jsonl$`)
10855
10479
  );
@@ -10908,8 +10532,8 @@ var AgentChatActivityBuffer = class {
10908
10532
  await Promise.allSettled([...this.pendingAppends]);
10909
10533
  for (const storageName of this.storageNames) {
10910
10534
  await rename2(
10911
- join24(ENGINE_DIR2, `${storageName}.jsonl`),
10912
- join24(ENGINE_DIR2, `${storageName}.${Date.now()}.jsonl`)
10535
+ join22(ENGINE_DIR2, `${storageName}.jsonl`),
10536
+ join22(ENGINE_DIR2, `${storageName}.${Date.now()}.jsonl`)
10913
10537
  ).catch(() => {
10914
10538
  });
10915
10539
  }
@@ -10920,7 +10544,7 @@ var AgentChatActivityBuffer = class {
10920
10544
  if (!this.segmentFilePatterns.some((pattern) => pattern.test(entry)))
10921
10545
  continue;
10922
10546
  try {
10923
- await this.uploadSegment(join24(ENGINE_DIR2, entry));
10547
+ await this.uploadSegment(join22(ENGINE_DIR2, entry));
10924
10548
  flushed++;
10925
10549
  } catch (error) {
10926
10550
  failed++;
@@ -10952,7 +10576,7 @@ var AgentChatActivityBuffer = class {
10952
10576
  ) && entry.endsWith(UPLOADED_SUFFIX)
10953
10577
  ).sort();
10954
10578
  for (const entry of uploaded.slice(0, -MAX_UPLOADED_SEGMENTS)) {
10955
- await unlink3(join24(ENGINE_DIR2, entry)).catch(() => {
10579
+ await unlink3(join22(ENGINE_DIR2, entry)).catch(() => {
10956
10580
  });
10957
10581
  }
10958
10582
  return { flushed, failed };
@@ -11184,18 +10808,18 @@ var keepAliveService = new KeepAliveService();
11184
10808
 
11185
10809
  // src/services/canvas-service.ts
11186
10810
  import { readdir as readdir7, readFile as readFile15, stat as stat3 } from "fs/promises";
11187
- import { homedir as homedir14 } from "os";
11188
- import { join as join25 } from "path";
10811
+ import { homedir as homedir12 } from "os";
10812
+ import { join as join23 } from "path";
11189
10813
  var GLOBAL_CANVAS_DIRECTORIES = [
11190
- join25(homedir14(), ".claude", "plans"),
11191
- join25(process.env.XDG_DATA_HOME ?? join25(homedir14(), ".local", "share"), "opencode", "plans"),
11192
- join25(homedir14(), ".replicas", "canvas")
10814
+ join23(homedir12(), ".claude", "plans"),
10815
+ join23(process.env.XDG_DATA_HOME ?? join23(homedir12(), ".local", "share"), "opencode", "plans"),
10816
+ join23(homedir12(), ".replicas", "canvas")
11193
10817
  ];
11194
10818
  async function canvasDirectories() {
11195
10819
  const repositories = await gitService.listRepositories().catch(() => []);
11196
10820
  return [
11197
10821
  ...GLOBAL_CANVAS_DIRECTORIES,
11198
- ...repositories.map((repository) => join25(repository.path, ".opencode", "plans"))
10822
+ ...repositories.map((repository) => join23(repository.path, ".opencode", "plans"))
11199
10823
  ];
11200
10824
  }
11201
10825
  var CanvasService = class {
@@ -11219,7 +10843,7 @@ var CanvasService = class {
11219
10843
  for (const entry of entries) {
11220
10844
  if (entry.name.startsWith(".")) continue;
11221
10845
  const filename = current.relativePath ? `${current.relativePath}/${entry.name}` : entry.name;
11222
- const filePath = join25(current.directory, entry.name);
10846
+ const filePath = join23(current.directory, entry.name);
11223
10847
  if (entry.isDirectory()) {
11224
10848
  pending.push({ directory: filePath, relativePath: filename });
11225
10849
  continue;
@@ -11244,7 +10868,7 @@ var CanvasService = class {
11244
10868
  if (!safe) return null;
11245
10869
  const { kind, mimeType } = classifyCanvasFilename(safe);
11246
10870
  for (const directory of await this.directories()) {
11247
- const filePath = join25(directory, safe);
10871
+ const filePath = join23(directory, safe);
11248
10872
  let sizeBytes = 0;
11249
10873
  let updatedAt = "";
11250
10874
  try {
@@ -11416,13 +11040,13 @@ async function reconcileCanvasItems(filenames) {
11416
11040
  import { createReadStream } from "fs";
11417
11041
  import { createHash as createHash2 } from "crypto";
11418
11042
  import { readFile as readFile16, readdir as readdir8, stat as stat4 } from "fs/promises";
11419
- import { basename as basename2, join as join27 } from "path";
11043
+ import { basename as basename2, join as join25 } from "path";
11420
11044
 
11421
11045
  // src/services/chat/chat-senders.ts
11422
- import { join as join26 } from "path";
11423
- var CHAT_SENDERS_DIR = join26(ENGINE_DIR2, "chat-senders");
11046
+ import { join as join24 } from "path";
11047
+ var CHAT_SENDERS_DIR = join24(ENGINE_DIR2, "chat-senders");
11424
11048
  function chatMessageSendersFilePath(chatId) {
11425
- return join26(CHAT_SENDERS_DIR, `${chatId}.jsonl`);
11049
+ return join24(CHAT_SENDERS_DIR, `${chatId}.jsonl`);
11426
11050
  }
11427
11051
  function parseChatMessageSendersJsonl(content) {
11428
11052
  return content.split("\n").flatMap((line) => {
@@ -11438,9 +11062,9 @@ function parseChatMessageSendersJsonl(content) {
11438
11062
 
11439
11063
  // src/services/upload-chat-transcripts.ts
11440
11064
  var HISTORY_DIRS = [
11441
- join27(ENGINE_DIR2, "claude-histories"),
11442
- join27(ENGINE_DIR2, "relay-histories"),
11443
- join27(ENGINE_DIR2, "codex-histories")
11065
+ join25(ENGINE_DIR2, "claude-histories"),
11066
+ join25(ENGINE_DIR2, "relay-histories"),
11067
+ join25(ENGINE_DIR2, "codex-histories")
11444
11068
  ];
11445
11069
  async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map(), capture) {
11446
11070
  let flushed = 0;
@@ -11458,7 +11082,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map(), ca
11458
11082
  if (!entry.endsWith(".jsonl")) continue;
11459
11083
  const chatId = basename2(entry, ".jsonl");
11460
11084
  tasks.push(
11461
- uploadChatTranscript(chatId, join27(dir, entry), chatsById.get(chatId), capture).then((artifact) => {
11085
+ uploadChatTranscript(chatId, join25(dir, entry), chatsById.get(chatId), capture).then((artifact) => {
11462
11086
  flushed++;
11463
11087
  if (artifact && capture) revisions.push(artifact);
11464
11088
  }).catch((err) => {
@@ -11576,7 +11200,7 @@ async function flushRepoState() {
11576
11200
  // src/services/upload-engine-logs.ts
11577
11201
  import { createReadStream as createReadStream2 } from "fs";
11578
11202
  import { readdir as readdir9, stat as stat5 } from "fs/promises";
11579
- import { join as join28 } from "path";
11203
+ import { join as join26 } from "path";
11580
11204
  var MAX_ENGINE_LOG_FLUSH_SESSIONS = 10;
11581
11205
  var MAX_ENGINE_LOG_FLUSH_BYTES = 5 * 1024 * 1024;
11582
11206
  var ENGINE_LOG_FLUSH_TIMEOUT_MS = 2e4;
@@ -11605,7 +11229,7 @@ async function flushAllEngineLogs() {
11605
11229
  const candidates = (await Promise.all(filenames.slice(0, MAX_ENGINE_LOG_FLUSH_SESSIONS).map(async (filename) => {
11606
11230
  try {
11607
11231
  const sessionId = filename.slice(0, -".log".length);
11608
- const filePath = join28(LOG_DIR, filename);
11232
+ const filePath = join26(LOG_DIR, filename);
11609
11233
  const fileStat = await runBeforeDeadline(() => stat5(filePath), deadline);
11610
11234
  if (!fileStat.isFile()) {
11611
11235
  skipped++;
@@ -11701,10 +11325,9 @@ async function uploadEngineLog(input, timeoutMs) {
11701
11325
  }
11702
11326
 
11703
11327
  // src/services/chat/chat-service.ts
11704
- var CODEX_AUTH_PATH2 = join29(homedir15(), ".codex", "auth.json");
11705
11328
  var CHATS_BACKUP_FILE = `${CHATS_FILE}.bak`;
11706
11329
  function isCodexAvailable() {
11707
- return existsSync8(CODEX_AUTH_PATH2) || Boolean(ENGINE_ENV.OPENAI_API_KEY);
11330
+ return detectCodexAuthMethod() !== "none";
11708
11331
  }
11709
11332
  function isOpencodeAvailable() {
11710
11333
  return existsSync8(OPENCODE_AUTH_PATH);
@@ -12227,12 +11850,12 @@ var ChatService = class {
12227
11850
  return descendants;
12228
11851
  }
12229
11852
  async deleteHistoryFile(persisted) {
12230
- const historyPath = join29(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`);
11853
+ const historyPath = join27(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`);
12231
11854
  await Promise.all([
12232
11855
  historyPath,
12233
11856
  `${historyPath}.pages.jsonl`,
12234
11857
  `${historyPath}.pages.index.json`
12235
- ].map((path6) => rm2(path6, { force: true })));
11858
+ ].map((path5) => rm2(path5, { force: true })));
12236
11859
  await rm2(chatMessageSendersFilePath(persisted.id), { force: true });
12237
11860
  }
12238
11861
  async getChatHistory(chatId, page = {}) {
@@ -12350,7 +11973,7 @@ var ChatService = class {
12350
11973
  if (persisted.provider === "claude") {
12351
11974
  provider = new ClaudeManager({
12352
11975
  workingDirectory: this.workingDirectory,
12353
- historyFilePath: join29(CLAUDE_HISTORY_DIR, `${persisted.id}.jsonl`),
11976
+ historyFilePath: join27(CLAUDE_HISTORY_DIR, `${persisted.id}.jsonl`),
12354
11977
  initialSessionId: persisted.providerSessionId,
12355
11978
  onSaveSessionId: saveSession,
12356
11979
  onTurnComplete: onProviderTurnComplete,
@@ -12369,7 +11992,7 @@ var ChatService = class {
12369
11992
  });
12370
11993
  provider = new RelayManager({
12371
11994
  workingDirectory: this.workingDirectory,
12372
- historyFilePath: join29(RELAY_HISTORY_DIR, `${persisted.id}.jsonl`),
11995
+ historyFilePath: join27(RELAY_HISTORY_DIR, `${persisted.id}.jsonl`),
12373
11996
  initialSessionId: persisted.providerSessionId,
12374
11997
  onSaveSessionId: saveSession,
12375
11998
  onTurnComplete: onProviderTurnComplete,
@@ -12382,7 +12005,7 @@ var ChatService = class {
12382
12005
  } else if (persisted.provider === "cursor") {
12383
12006
  provider = new CursorManager({
12384
12007
  workingDirectory: this.workingDirectory,
12385
- historyFilePath: join29(CURSOR_HISTORY_DIR, `${persisted.id}.jsonl`),
12008
+ historyFilePath: join27(CURSOR_HISTORY_DIR, `${persisted.id}.jsonl`),
12386
12009
  initialSessionId: persisted.providerSessionId,
12387
12010
  onSaveSessionId: saveSession,
12388
12011
  onTurnComplete: onProviderTurnComplete,
@@ -12392,7 +12015,7 @@ var ChatService = class {
12392
12015
  } else if (persisted.provider === "deepseek") {
12393
12016
  provider = new DeepseekManager({
12394
12017
  workingDirectory: this.workingDirectory,
12395
- historyFilePath: join29(DEEPSEEK_HISTORY_DIR, `${persisted.id}.jsonl`),
12018
+ historyFilePath: join27(DEEPSEEK_HISTORY_DIR, `${persisted.id}.jsonl`),
12396
12019
  initialSessionId: persisted.providerSessionId,
12397
12020
  onSaveSessionId: saveSession,
12398
12021
  onTurnComplete: onProviderTurnComplete,
@@ -12402,7 +12025,7 @@ var ChatService = class {
12402
12025
  } else if (persisted.provider === "fx") {
12403
12026
  provider = new FxManager({
12404
12027
  workingDirectory: this.workingDirectory,
12405
- historyFilePath: join29(FX_HISTORY_DIR, `${persisted.id}.jsonl`),
12028
+ historyFilePath: join27(FX_HISTORY_DIR, `${persisted.id}.jsonl`),
12406
12029
  initialSessionId: persisted.providerSessionId,
12407
12030
  onSaveSessionId: saveSession,
12408
12031
  onTurnComplete: onProviderTurnComplete,
@@ -12412,7 +12035,7 @@ var ChatService = class {
12412
12035
  } else if (persisted.provider === "kimi") {
12413
12036
  provider = new KimiManager({
12414
12037
  workingDirectory: this.workingDirectory,
12415
- historyFilePath: join29(KIMI_HISTORY_DIR, `${persisted.id}.jsonl`),
12038
+ historyFilePath: join27(KIMI_HISTORY_DIR, `${persisted.id}.jsonl`),
12416
12039
  initialSessionId: persisted.providerSessionId,
12417
12040
  onSaveSessionId: saveSession,
12418
12041
  onTurnComplete: onProviderTurnComplete,
@@ -12422,7 +12045,7 @@ var ChatService = class {
12422
12045
  } else if (persisted.provider === "opencode") {
12423
12046
  provider = new OpencodeManager({
12424
12047
  workingDirectory: this.workingDirectory,
12425
- historyFilePath: join29(OPENCODE_HISTORY_DIR, `${persisted.id}.jsonl`),
12048
+ historyFilePath: join27(OPENCODE_HISTORY_DIR, `${persisted.id}.jsonl`),
12426
12049
  initialSessionId: persisted.providerSessionId,
12427
12050
  onSaveSessionId: saveSession,
12428
12051
  onTurnComplete: onProviderTurnComplete,
@@ -12432,7 +12055,7 @@ var ChatService = class {
12432
12055
  } else if (persisted.provider === "pi") {
12433
12056
  provider = new PiManager({
12434
12057
  workingDirectory: this.workingDirectory,
12435
- historyFilePath: join29(PI_HISTORY_DIR, `${persisted.id}.jsonl`),
12058
+ historyFilePath: join27(PI_HISTORY_DIR, `${persisted.id}.jsonl`),
12436
12059
  initialSessionId: persisted.providerSessionId,
12437
12060
  onSaveSessionId: saveSession,
12438
12061
  onTurnComplete: onProviderTurnComplete,
@@ -12442,7 +12065,7 @@ var ChatService = class {
12442
12065
  } else {
12443
12066
  provider = new CodexAspManager({
12444
12067
  workingDirectory: this.workingDirectory,
12445
- historyFilePath: join29(CODEX_HISTORY_DIR, `${persisted.id}.jsonl`),
12068
+ historyFilePath: join27(CODEX_HISTORY_DIR, `${persisted.id}.jsonl`),
12446
12069
  initialSessionId: persisted.providerSessionId,
12447
12070
  onSaveSessionId: saveSession,
12448
12071
  onTurnComplete: onProviderTurnComplete,
@@ -12481,6 +12104,7 @@ var ChatService = class {
12481
12104
  awaitingInput: chat.provider.isAwaitingInput?.() ?? false,
12482
12105
  isCompacting: chat.provider.isCompacting?.() ?? false,
12483
12106
  isAuthRetrying: chat.provider.isAuthRetrying?.() ?? false,
12107
+ mayBeReconnecting: chat.provider.mayBeReconnecting?.() ?? false,
12484
12108
  goal: chat.provider.getGoal?.() ?? null,
12485
12109
  parentChatId: chat.persisted.parentChatId,
12486
12110
  lastMessageText: chat.persisted.lastMessageText ?? null,
@@ -12570,7 +12194,7 @@ var ChatService = class {
12570
12194
  }
12571
12195
  }).catch(() => {
12572
12196
  });
12573
- if (event.type === "replicas-tool-input-request" || event.type === "replicas-tool-input-resolved" || event.type === "compaction-status" || event.type === AUTH_RETRY_STATUS_EVENT_TYPE || event.type === AUTH_FALLBACK_EVENT_TYPE || event.type === CHAT_GOAL_EVENT_TYPE || event.type === CLAUDE_ACTIVITY_STATUS_EVENT_TYPE || event.type === "claude-result" || event.type === "claude-system" && (event.payload.subtype === "init" || event.payload.subtype === "session_state_changed" || event.payload.subtype === "background_tasks_changed" || coerceBackgroundTaskPayload(event.payload) !== null)) {
12197
+ if (event.type === "replicas-tool-input-request" || event.type === "replicas-tool-input-resolved" || event.type === "compaction-status" || event.type === AUTH_RETRY_STATUS_EVENT_TYPE || event.type === AUTH_FALLBACK_EVENT_TYPE || event.type === CURSOR_CONNECTION_STATUS_EVENT_TYPE || event.type === CHAT_GOAL_EVENT_TYPE || event.type === CLAUDE_ACTIVITY_STATUS_EVENT_TYPE || event.type === "claude-result" || event.type === "claude-system" && (event.payload.subtype === "init" || event.payload.subtype === "session_state_changed" || event.payload.subtype === "background_tasks_changed" || coerceBackgroundTaskPayload(event.payload) !== null)) {
12574
12198
  this.publish({
12575
12199
  type: "chat.updated",
12576
12200
  payload: { chat: this.toSummary(chat) }
@@ -12607,7 +12231,7 @@ var ChatService = class {
12607
12231
  });
12608
12232
  uploadChatTranscript(
12609
12233
  chatId,
12610
- join29(HISTORY_DIR_BY_PROVIDER[chat.persisted.provider], `${chatId}.jsonl`),
12234
+ join27(HISTORY_DIR_BY_PROVIDER[chat.persisted.provider], `${chatId}.jsonl`),
12611
12235
  this.toSummary(chat)
12612
12236
  ).catch((err) => {
12613
12237
  console.error("[ChatService] Failed to upload chat transcript:", { chatId, err });
@@ -12745,7 +12369,7 @@ var ChatService = class {
12745
12369
  // src/services/repo-file-service.ts
12746
12370
  import { execFile } from "child_process";
12747
12371
  import { readFile as readFile18, realpath, stat as stat6 } from "fs/promises";
12748
- import { join as join30, resolve as resolve2, extname as extname2 } from "path";
12372
+ import { join as join28, resolve as resolve2, extname as extname2 } from "path";
12749
12373
  var CACHE_TTL_MS = 3e4;
12750
12374
  var SEARCH_TIMEOUT_MS = 15e3;
12751
12375
  var MAX_CONTENT_BYTES = 256 * 1024;
@@ -12897,7 +12521,7 @@ var RepoFileService = class {
12897
12521
  const repo = repos.find((r) => r.name === repoName);
12898
12522
  if (!repo) return null;
12899
12523
  try {
12900
- const fullPath = await realpath(resolve2(join30(repo.path, filePath)));
12524
+ const fullPath = await realpath(resolve2(join28(repo.path, filePath)));
12901
12525
  const repoRoot = await realpath(repo.path);
12902
12526
  const repoPrefix = repoRoot.endsWith("/") ? repoRoot : repoRoot + "/";
12903
12527
  if (!fullPath.startsWith(repoPrefix) && fullPath !== repoRoot) return null;
@@ -13032,20 +12656,20 @@ var RepoFileService = class {
13032
12656
  import { Hono } from "hono";
13033
12657
  import { z as z6 } from "zod";
13034
12658
  import { readdir as readdir11, stat as stat7, readFile as readFile21 } from "fs/promises";
13035
- import { join as join33, resolve as resolve3 } from "path";
12659
+ import { join as join31, resolve as resolve3 } from "path";
13036
12660
 
13037
12661
  // src/services/warm-hooks-service.ts
13038
12662
  import { spawn as spawn6 } from "child_process";
13039
12663
  import { readFile as readFile20 } from "fs/promises";
13040
12664
  import { existsSync as existsSync9 } from "fs";
13041
- import { join as join32 } from "path";
12665
+ import { join as join30 } from "path";
13042
12666
 
13043
12667
  // src/services/warm-hook-logs-service.ts
13044
12668
  import { mkdir as mkdir18, readFile as readFile19, writeFile as writeFile7, readdir as readdir10, appendFile as appendFile5, unlink as unlink4 } from "fs/promises";
13045
- import { homedir as homedir16 } from "os";
13046
- import { join as join31 } from "path";
13047
- var LOGS_DIR2 = join31(homedir16(), ".replicas", "warm-hook-logs");
13048
- var CURRENT_RUN_LOG = join31(LOGS_DIR2, "current-run.log");
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");
13049
12673
  var GLOBAL_FILENAME = "global.json";
13050
12674
  function withPreview2(stored) {
13051
12675
  const preview = buildHookOutputPreview(stored.output);
@@ -13062,7 +12686,7 @@ var WarmHookLogsService = class {
13062
12686
  hookName: "organization",
13063
12687
  ...entry
13064
12688
  };
13065
- await writeFile7(join31(LOGS_DIR2, GLOBAL_FILENAME), `${JSON.stringify(log, null, 2)}
12689
+ await writeFile7(join29(LOGS_DIR2, GLOBAL_FILENAME), `${JSON.stringify(log, null, 2)}
13066
12690
  `, "utf-8");
13067
12691
  }
13068
12692
  async saveEnvironmentHookLog(entry) {
@@ -13072,7 +12696,7 @@ var WarmHookLogsService = class {
13072
12696
  hookName: "environment",
13073
12697
  ...entry
13074
12698
  };
13075
- await writeFile7(join31(LOGS_DIR2, ENVIRONMENT_HOOK_LOG_FILENAME), `${JSON.stringify(log, null, 2)}
12699
+ await writeFile7(join29(LOGS_DIR2, ENVIRONMENT_HOOK_LOG_FILENAME), `${JSON.stringify(log, null, 2)}
13076
12700
  `, "utf-8");
13077
12701
  }
13078
12702
  async saveRepoHookLog(repoName, entry) {
@@ -13082,7 +12706,7 @@ var WarmHookLogsService = class {
13082
12706
  hookName: repoName,
13083
12707
  ...entry
13084
12708
  };
13085
- await writeFile7(join31(LOGS_DIR2, repoHookLogFilename(repoName)), `${JSON.stringify(log, null, 2)}
12709
+ await writeFile7(join29(LOGS_DIR2, repoHookLogFilename(repoName)), `${JSON.stringify(log, null, 2)}
13086
12710
  `, "utf-8");
13087
12711
  }
13088
12712
  async getAllLogs() {
@@ -13101,7 +12725,7 @@ var WarmHookLogsService = class {
13101
12725
  continue;
13102
12726
  }
13103
12727
  try {
13104
- const raw = await readFile19(join31(LOGS_DIR2, file), "utf-8");
12728
+ const raw = await readFile19(join29(LOGS_DIR2, file), "utf-8");
13105
12729
  const stored = JSON.parse(raw);
13106
12730
  logs.push(withPreview2(stored));
13107
12731
  } catch {
@@ -13139,7 +12763,7 @@ var WarmHookLogsService = class {
13139
12763
  async getFullOutput(hookType, hookName) {
13140
12764
  const filename = hookType === "global" ? GLOBAL_FILENAME : hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
13141
12765
  try {
13142
- const raw = await readFile19(join31(LOGS_DIR2, filename), "utf-8");
12766
+ const raw = await readFile19(join29(LOGS_DIR2, filename), "utf-8");
13143
12767
  const stored = JSON.parse(raw);
13144
12768
  if (stored.hookType !== hookType || stored.hookName !== hookName) {
13145
12769
  return null;
@@ -13158,7 +12782,7 @@ var warmHookLogsService = new WarmHookLogsService();
13158
12782
  // src/services/warm-hooks-service.ts
13159
12783
  async function readRepoWarmHook(repoPath) {
13160
12784
  for (const filename of REPLICAS_CONFIG_FILENAMES) {
13161
- const configPath = join32(repoPath, filename);
12785
+ const configPath = join30(repoPath, filename);
13162
12786
  if (!existsSync9(configPath)) {
13163
12787
  continue;
13164
12788
  }
@@ -13552,9 +13176,6 @@ var writeTerminalSessionSchema = z6.object({
13552
13176
  generation: z6.number().int().nonnegative(),
13553
13177
  sequence: z6.number().int().nonnegative()
13554
13178
  });
13555
- var mergePullRequestSchema = z6.object({
13556
- prUrl: z6.string().url()
13557
- });
13558
13179
  var sendMessageSchema = z6.object({
13559
13180
  messageId: z6.string().min(1).optional(),
13560
13181
  submittedAt: z6.string().datetime().optional(),
@@ -13973,42 +13594,16 @@ function createV1Routes(deps) {
13973
13594
  });
13974
13595
  app2.get("/repo-files/content", async (c) => {
13975
13596
  const repoName = c.req.query("repoName");
13976
- const path6 = c.req.query("path");
13977
- if (!repoName || !path6) {
13597
+ const path5 = c.req.query("path");
13598
+ if (!repoName || !path5) {
13978
13599
  return c.json(jsonError("repoName and path are required"), 400);
13979
13600
  }
13980
- const result = await deps.repoFileService.readFile(repoName, path6);
13601
+ const result = await deps.repoFileService.readFile(repoName, path5);
13981
13602
  if (!result) {
13982
13603
  return c.json(jsonError("File not found"), 404);
13983
13604
  }
13984
13605
  return c.json(result);
13985
13606
  });
13986
- app2.post("/pull-requests/merge", async (c) => {
13987
- const body = mergePullRequestSchema.parse(await c.req.json());
13988
- const parsed = parseCodeHostPrUrl(body.prUrl);
13989
- if (parsed?.provider !== "github") {
13990
- return c.json(jsonError("Only GitHub pull requests are supported"), 400);
13991
- }
13992
- const repository = (await gitService.listRepositories()).find(
13993
- (repo) => repo.name.toLowerCase() === parsed.repo.toLowerCase()
13994
- );
13995
- if (!repository) {
13996
- return c.json(jsonError("Pull request repository is not available in this workspace"), 404);
13997
- }
13998
- try {
13999
- await githubTokenManager.refreshCredentials();
14000
- await execFileAsync("gh", ["pr", "merge", body.prUrl, "--squash"], {
14001
- cwd: repository.path,
14002
- encoding: "utf-8",
14003
- timeout: 12e4,
14004
- maxBuffer: SUBPROCESS_MAX_BUFFER
14005
- });
14006
- return c.json({ success: true });
14007
- } catch (error) {
14008
- const detail = error && typeof error === "object" && "stderr" in error && typeof error.stderr === "string" ? error.stderr.trim() : error instanceof Error ? error.message : "GitHub CLI merge failed";
14009
- return c.json(jsonError("Failed to merge pull request", detail), 409);
14010
- }
14011
- });
14012
13607
  app2.get("/terminal/sessions", (c) => {
14013
13608
  return c.json({ sessions: terminalService.list() });
14014
13609
  });
@@ -14442,7 +14037,7 @@ data: ${JSON.stringify("Terminal session not found")}
14442
14037
  const logFiles = files.filter((f) => f.endsWith(".log"));
14443
14038
  const sessions = await Promise.all(
14444
14039
  logFiles.map(async (filename) => {
14445
- const filePath = join33(LOG_DIR, filename);
14040
+ const filePath = join31(LOG_DIR, filename);
14446
14041
  const fileStat = await stat7(filePath);
14447
14042
  const sessionId = filename.replace(/\.log$/, "");
14448
14043
  return {