replicas-engine 0.1.276 → 0.1.278

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.
Files changed (2) hide show
  1. package/dist/src/index.js +90 -733
  2. package/package.json +1 -2
package/dist/src/index.js CHANGED
@@ -286,7 +286,7 @@ var WORKSPACE_SIZES = ["small", "large"];
286
286
  var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
287
287
 
288
288
  // ../shared/src/e2b.ts
289
- var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-07-v1";
289
+ var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-07-v3";
290
290
 
291
291
  // ../shared/src/runtime-env.ts
292
292
  function parsePosixEnvFile(content) {
@@ -3236,6 +3236,14 @@ async function getCurrentBranch(cwd) {
3236
3236
  return null;
3237
3237
  }
3238
3238
  }
3239
+ async function resolveDiffBase(repoPath, defaultBranch) {
3240
+ const baseBranch = `origin/${defaultBranch}`;
3241
+ try {
3242
+ return await runGitCommand(["merge-base", baseBranch, "HEAD"], repoPath);
3243
+ } catch {
3244
+ }
3245
+ return await branchExists(baseBranch, repoPath) ? baseBranch : "HEAD";
3246
+ }
3239
3247
 
3240
3248
  // src/git/service.ts
3241
3249
  var FULL_DIFF_MAX_BUFFER = 50 * 1024 * 1024;
@@ -3450,7 +3458,7 @@ var GitService = class {
3450
3458
  getGitDiffStats(repoPath, defaultBranch) {
3451
3459
  return this.diffStatsInFlight.run(repoPath, async () => {
3452
3460
  try {
3453
- const diffBase = await this.getDiffBase(repoPath, defaultBranch);
3461
+ const diffBase = await resolveDiffBase(repoPath, defaultBranch);
3454
3462
  const shortstat = await runGitCommand(["diff", diffBase, "--shortstat", "-M"], repoPath);
3455
3463
  let added = 0;
3456
3464
  let removed = 0;
@@ -3468,7 +3476,7 @@ var GitService = class {
3468
3476
  removed
3469
3477
  };
3470
3478
  } catch (error) {
3471
- console.error("Error getting git diff:", error);
3479
+ console.warn(`[GitService] getGitDiffStats failed for ${repoPath} (defaultBranch=${defaultBranch}):`, error instanceof Error ? error.message : error);
3472
3480
  return null;
3473
3481
  }
3474
3482
  });
@@ -3559,7 +3567,7 @@ var GitService = class {
3559
3567
  getFullGitDiff(repoPath, defaultBranch) {
3560
3568
  return this.fullDiffInFlight.run(repoPath, async () => {
3561
3569
  try {
3562
- const diffBase = await this.getDiffBase(repoPath, defaultBranch);
3570
+ const diffBase = await resolveDiffBase(repoPath, defaultBranch);
3563
3571
  const { stdout: trackedDiff } = await execFileAsync("git", ["diff", diffBase, "-M", "-C"], {
3564
3572
  cwd: repoPath,
3565
3573
  encoding: "utf-8",
@@ -3580,14 +3588,6 @@ var GitService = class {
3580
3588
  return "";
3581
3589
  }
3582
3590
  }
3583
- async getDiffBase(repoPath, defaultBranch) {
3584
- const baseBranch = `origin/${defaultBranch}`;
3585
- try {
3586
- return await runGitCommand(["merge-base", baseBranch, "HEAD"], repoPath);
3587
- } catch {
3588
- return baseBranch;
3589
- }
3590
- }
3591
3591
  async getPullRequestUrl(repoName, repoPath, currentBranchArg, persistedRepoStateArg) {
3592
3592
  try {
3593
3593
  const currentBranch = currentBranchArg ?? await getCurrentBranch(repoPath);
@@ -3676,9 +3676,7 @@ var GitService = class {
3676
3676
  this.defaultBranchCache.set(repoPath, fromSymbolicRef);
3677
3677
  return fromSymbolicRef;
3678
3678
  }
3679
- const fallback = "main";
3680
- this.defaultBranchCache.set(repoPath, fallback);
3681
- return fallback;
3679
+ return "main";
3682
3680
  }
3683
3681
  async resolveDefaultBranchFromSymbolicRef(repoPath) {
3684
3682
  try {
@@ -4666,10 +4664,10 @@ async function registerDesktopPreview() {
4666
4664
  }
4667
4665
 
4668
4666
  // src/services/chat/chat-service.ts
4669
- import { existsSync as existsSync8 } from "fs";
4670
- import { appendFile as appendFile5, copyFile, mkdir as mkdir12, readFile as readFile9, rename as rename2, rm } from "fs/promises";
4671
- import { homedir as homedir13 } from "os";
4672
- import { join as join15 } from "path";
4667
+ import { existsSync as existsSync7 } from "fs";
4668
+ import { appendFile as appendFile5, copyFile, mkdir as mkdir11, readFile as readFile8, rename as rename2, rm } from "fs/promises";
4669
+ import { homedir as homedir12 } from "os";
4670
+ import { join as join14 } from "path";
4673
4671
  import { randomUUID as randomUUID5 } from "crypto";
4674
4672
 
4675
4673
  // src/managers/claude-manager.ts
@@ -4849,212 +4847,6 @@ function mapTodoStatus(status) {
4849
4847
  }
4850
4848
  return "pending";
4851
4849
  }
4852
- function convertCodexEvent(event, linearSessionId) {
4853
- if (event.type === "turn.started") {
4854
- return {
4855
- linearSessionId,
4856
- content: {
4857
- type: "thought",
4858
- body: "Processing..."
4859
- }
4860
- };
4861
- }
4862
- if (event.type === "item.started") {
4863
- const item = event.item;
4864
- if (!item) return null;
4865
- if (item.type === "agent_message") {
4866
- const text = "text" in item ? String(item.text || "") : "";
4867
- if (text) {
4868
- return {
4869
- linearSessionId,
4870
- content: {
4871
- type: "thought",
4872
- body: text
4873
- }
4874
- };
4875
- }
4876
- }
4877
- if (item.type === "reasoning") {
4878
- const text = "text" in item ? String(item.text || "") : "";
4879
- if (text) {
4880
- return {
4881
- linearSessionId,
4882
- content: {
4883
- type: "thought",
4884
- body: text
4885
- }
4886
- };
4887
- }
4888
- }
4889
- if (item.type === "command_execution") {
4890
- const command = "command" in item ? String(item.command || "") : "";
4891
- return {
4892
- linearSessionId,
4893
- content: {
4894
- type: "action",
4895
- action: "Running command",
4896
- parameter: command
4897
- }
4898
- };
4899
- }
4900
- if (item.type === "file_change") {
4901
- const changes = "changes" in item && Array.isArray(item.changes) ? item.changes : [];
4902
- const paths = changes.map((c) => c.path || "").filter(Boolean);
4903
- return {
4904
- linearSessionId,
4905
- content: {
4906
- type: "action",
4907
- action: "File change",
4908
- parameter: paths.join(", ") || ""
4909
- }
4910
- };
4911
- }
4912
- if (item.type === "mcp_tool_call") {
4913
- const tool2 = "tool" in item ? String(item.tool || "") : "";
4914
- return {
4915
- linearSessionId,
4916
- content: {
4917
- type: "action",
4918
- action: tool2 || "MCP tool call",
4919
- parameter: ""
4920
- }
4921
- };
4922
- }
4923
- if (item.type === "web_search") {
4924
- const query2 = "query" in item ? String(item.query || "") : "";
4925
- return {
4926
- linearSessionId,
4927
- content: {
4928
- type: "action",
4929
- action: "Web search",
4930
- parameter: query2
4931
- }
4932
- };
4933
- }
4934
- if (item.type === "todo_list") {
4935
- const items = "items" in item && Array.isArray(item.items) ? item.items : [];
4936
- const completed = items.filter((t) => t.completed).length;
4937
- const total = items.length;
4938
- const currentTask = items.find((t) => !t.completed);
4939
- const summary = `${completed}/${total}`;
4940
- const parameter = currentTask?.text ? `${summary}: ${currentTask.text}` : summary;
4941
- return {
4942
- linearSessionId,
4943
- content: {
4944
- type: "action",
4945
- action: "Updating plan",
4946
- parameter
4947
- }
4948
- };
4949
- }
4950
- }
4951
- if (event.type === "item.completed") {
4952
- const item = event.item;
4953
- if (!item) return null;
4954
- if (item.type === "command_execution") {
4955
- const command = "command" in item ? String(item.command || "") : "";
4956
- const output = "aggregated_output" in item ? String(item.aggregated_output || "") : "";
4957
- const exitCode = "exit_code" in item ? item.exit_code : void 0;
4958
- const result = exitCode !== void 0 ? `Exit code: ${exitCode}` : output || "Done";
4959
- return {
4960
- linearSessionId,
4961
- content: {
4962
- type: "action",
4963
- action: "Running command",
4964
- parameter: command,
4965
- result
4966
- }
4967
- };
4968
- }
4969
- if (item.type === "file_change") {
4970
- const changes = "changes" in item && Array.isArray(item.changes) ? item.changes : [];
4971
- const paths = changes.map((c) => c.path || "").filter(Boolean);
4972
- const status = "status" in item ? String(item.status || "") : "";
4973
- return {
4974
- linearSessionId,
4975
- content: {
4976
- type: "action",
4977
- action: "File change",
4978
- parameter: paths.join(", ") || "",
4979
- result: status === "completed" ? "Done" : status || "Done"
4980
- }
4981
- };
4982
- }
4983
- if (item.type === "mcp_tool_call") {
4984
- const tool2 = "tool" in item ? String(item.tool || "") : "";
4985
- const status = "status" in item ? String(item.status || "") : "";
4986
- return {
4987
- linearSessionId,
4988
- content: {
4989
- type: "action",
4990
- action: tool2 || "MCP tool call",
4991
- parameter: "",
4992
- result: status === "completed" ? "Done" : status || "Done"
4993
- }
4994
- };
4995
- }
4996
- if (item.type === "web_search") {
4997
- const query2 = "query" in item ? String(item.query || "") : "";
4998
- return {
4999
- linearSessionId,
5000
- content: {
5001
- type: "action",
5002
- action: "Web search",
5003
- parameter: query2,
5004
- result: "Done"
5005
- }
5006
- };
5007
- }
5008
- if (item.type === "todo_list") {
5009
- const items = "items" in item && Array.isArray(item.items) ? item.items : [];
5010
- const completed = items.filter((t) => t.completed).length;
5011
- const total = items.length;
5012
- const currentTask = items.find((t) => !t.completed);
5013
- const summary = `${completed}/${total}`;
5014
- const parameter = currentTask?.text ? `${summary}: ${currentTask.text}` : summary;
5015
- return {
5016
- linearSessionId,
5017
- content: {
5018
- type: "action",
5019
- action: "Updating plan",
5020
- parameter,
5021
- result: "Done"
5022
- }
5023
- };
5024
- }
5025
- if (item.type === "agent_message") {
5026
- const text = "text" in item ? String(item.text || "") : "";
5027
- if (text) {
5028
- return {
5029
- linearSessionId,
5030
- content: {
5031
- type: "thought",
5032
- body: text
5033
- }
5034
- };
5035
- }
5036
- }
5037
- }
5038
- return null;
5039
- }
5040
- function extractPlanFromCodexEvent(event) {
5041
- if (event.type !== "item.started" && event.type !== "item.completed") {
5042
- return null;
5043
- }
5044
- const item = event.item;
5045
- if (!item || item.type !== "todo_list") {
5046
- return null;
5047
- }
5048
- const items = "items" in item && Array.isArray(item.items) ? item.items : [];
5049
- if (items.length === 0) {
5050
- return null;
5051
- }
5052
- const hasIncomplete = items.some((entry) => !entry.completed);
5053
- return items.filter((entry) => Boolean(entry.text && entry.text.trim().length > 0)).map((entry) => ({
5054
- content: entry.text.trim(),
5055
- status: entry.completed ? "completed" : hasIncomplete ? "inProgress" : "pending"
5056
- }));
5057
- }
5058
4850
  function codexAspReasoningText(item) {
5059
4851
  return [...item.summary, ...item.content].filter(Boolean).join("\n").trim();
5060
4852
  }
@@ -5618,12 +5410,6 @@ function buildCodexAgentEnv() {
5618
5410
  delete env.GH_CONFIG_DIR;
5619
5411
  return env;
5620
5412
  }
5621
- function resolveCodexApiKey() {
5622
- if (shouldStripOpenAIApiKey()) {
5623
- return void 0;
5624
- }
5625
- return ENGINE_ENV.OPENAI_API_KEY;
5626
- }
5627
5413
  function shouldStripAnthropicApiKey() {
5628
5414
  const method = ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD;
5629
5415
  return method === "oauth" || method === "bedrock";
@@ -6746,7 +6532,7 @@ var AspClient = class {
6746
6532
  // src/managers/codex-asp/app-server-process.ts
6747
6533
  var DEFAULT_CODEX_BINARY = "codex";
6748
6534
  var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
6749
- var ENGINE_PACKAGE_VERSION = "0.1.276";
6535
+ var ENGINE_PACKAGE_VERSION = "0.1.278";
6750
6536
  var INITIALIZE_METHOD = "initialize";
6751
6537
  var INITIALIZED_NOTIFICATION = "initialized";
6752
6538
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
@@ -6949,25 +6735,6 @@ function buildCodexRateLimitsSnapshot(fields) {
6949
6735
  planType: fields.planType
6950
6736
  };
6951
6737
  }
6952
- function extractCodexRateLimitsSnapshotFromJsonl(parsed) {
6953
- if (!isRecord4(parsed)) return null;
6954
- const payload = isRecord4(parsed.payload) ? parsed.payload : parsed;
6955
- const rateLimits = isRecord4(payload.rate_limits) ? payload.rate_limits : null;
6956
- if (!rateLimits) return null;
6957
- const credits = isRecord4(rateLimits.credits) ? rateLimits.credits : null;
6958
- const hasCredits = credits && typeof credits.has_credits === "boolean" ? credits.has_credits : null;
6959
- const unlimited = credits && typeof credits.unlimited === "boolean" ? credits.unlimited : null;
6960
- const balance = credits && typeof credits.balance === "string" ? credits.balance : null;
6961
- const rateLimitResetType = typeof rateLimits.rate_limit_reached_type === "string" && rateLimits.rate_limit_reached_type.length > 0 ? rateLimits.rate_limit_reached_type : null;
6962
- const planType = typeof rateLimits.plan_type === "string" ? rateLimits.plan_type : null;
6963
- return buildCodexRateLimitsSnapshot({
6964
- unlimited,
6965
- hasCredits,
6966
- balance,
6967
- rateLimitResetType,
6968
- planType
6969
- });
6970
- }
6971
6738
  var CodexQuotaStatusTracker = class {
6972
6739
  lastEmittedQuotaState = "ok";
6973
6740
  latestQuotaSnapshot = null;
@@ -8446,410 +8213,6 @@ var CodexAspManager = class extends CodingAgentManager {
8446
8213
  }
8447
8214
  };
8448
8215
 
8449
- // src/managers/codex-manager.ts
8450
- import { Codex } from "@openai/codex-sdk";
8451
- import { readdir as readdir3, stat as stat2, writeFile as writeFile6, mkdir as mkdir11, readFile as readFile8 } from "fs/promises";
8452
- import { existsSync as existsSync7 } from "fs";
8453
- import { join as join14 } from "path";
8454
- import { homedir as homedir12 } from "os";
8455
- import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
8456
- var CODEX_CONFIG_PATH = join14(homedir12(), ".codex", "config.toml");
8457
- function isJsonlEvent2(value) {
8458
- if (!isRecord4(value)) {
8459
- return false;
8460
- }
8461
- return typeof value.timestamp === "string" && typeof value.type === "string" && isRecord4(value.payload);
8462
- }
8463
- function sleep(ms) {
8464
- return new Promise((resolve3) => setTimeout(resolve3, ms));
8465
- }
8466
- var CodexManager = class extends CodingAgentManager {
8467
- codex;
8468
- currentThreadId = null;
8469
- currentThread = null;
8470
- activeAbortController = null;
8471
- quotaStatus = new CodexQuotaStatusTracker();
8472
- constructor(options) {
8473
- super(options);
8474
- this.codex = this.createCodexClient();
8475
- this.initializeManager(this.processMessageInternal.bind(this));
8476
- }
8477
- createCodexClient() {
8478
- const codexApiKey = resolveCodexApiKey();
8479
- return new Codex({
8480
- env: buildCodexAgentEnv(),
8481
- ...codexApiKey ? { apiKey: codexApiKey } : {}
8482
- });
8483
- }
8484
- resetCodexClient() {
8485
- this.codex = this.createCodexClient();
8486
- this.currentThread = null;
8487
- }
8488
- async initialize() {
8489
- if (this.initialSessionId) {
8490
- this.currentThreadId = this.initialSessionId;
8491
- console.log(`[CodexManager] Restored thread ID from persisted state: ${this.currentThreadId}`);
8492
- }
8493
- }
8494
- async flushQuotaSnapshotFromCurrentSession() {
8495
- if (!this.currentThreadId) return;
8496
- try {
8497
- const sessionFile = await this.findSessionFile(this.currentThreadId);
8498
- if (!sessionFile) return;
8499
- const content = await readFile8(sessionFile, "utf-8");
8500
- const lines = content.split("\n").map((line) => line.trim()).filter(Boolean);
8501
- let latest = null;
8502
- for (const line of lines) {
8503
- try {
8504
- const parsed = JSON.parse(line);
8505
- const snapshot = extractCodexRateLimitsSnapshotFromJsonl(parsed);
8506
- if (snapshot) {
8507
- latest = snapshot;
8508
- }
8509
- } catch {
8510
- }
8511
- }
8512
- if (latest) {
8513
- this.emitQuotaStatus(latest);
8514
- }
8515
- } catch (error) {
8516
- console.warn("[CodexManager] Failed to flush quota snapshot from session:", error);
8517
- }
8518
- }
8519
- emitQuotaStatus(snapshot, force = false) {
8520
- const event = this.quotaStatus.apply(snapshot, force);
8521
- if (event) this.onEvent(event);
8522
- }
8523
- async interruptActiveTurn() {
8524
- if (this.activeAbortController) {
8525
- this.activeAbortController.abort();
8526
- }
8527
- }
8528
- /**
8529
- * Update the developer_instructions in ~/.codex/config.toml
8530
- * This sets the system prompt that Codex will use for this turn
8531
- */
8532
- async updateCodexConfig(developerInstructions) {
8533
- try {
8534
- const codexDir = join14(homedir12(), ".codex");
8535
- await mkdir11(codexDir, { recursive: true });
8536
- let config = {};
8537
- if (existsSync7(CODEX_CONFIG_PATH)) {
8538
- try {
8539
- const existingContent = await readFile8(CODEX_CONFIG_PATH, "utf-8");
8540
- const parsed = parseToml(existingContent);
8541
- if (isRecord4(parsed)) {
8542
- config = parsed;
8543
- }
8544
- } catch (parseError) {
8545
- console.warn("[CodexManager] Failed to parse existing config.toml, starting fresh:", parseError);
8546
- }
8547
- }
8548
- if (developerInstructions) {
8549
- config.developer_instructions = developerInstructions;
8550
- } else {
8551
- delete config.developer_instructions;
8552
- }
8553
- const tomlContent = stringifyToml(config);
8554
- await writeFile6(CODEX_CONFIG_PATH, tomlContent, "utf-8");
8555
- console.log("[CodexManager] Updated config.toml with developer_instructions");
8556
- } catch (error) {
8557
- console.error("[CodexManager] Failed to update config.toml:", error);
8558
- }
8559
- }
8560
- async processMessageInternal(request) {
8561
- try {
8562
- await this.executeCodexTurn(request);
8563
- } catch (error) {
8564
- if (isCodexAuthError(error)) {
8565
- const refreshed = await codexTokenManager.fetchFreshCredentials(error instanceof Error ? error.message : String(error));
8566
- if (refreshed) {
8567
- this.resetCodexClient();
8568
- await this.executeCodexTurn(request);
8569
- return;
8570
- }
8571
- }
8572
- throw error;
8573
- }
8574
- }
8575
- async executeCodexTurn(request) {
8576
- if (this.quotaStatus.blocked && this.quotaStatus.latestSnapshot) {
8577
- await this.flushQuotaSnapshotFromCurrentSession();
8578
- if (this.quotaStatus.blocked && this.quotaStatus.latestSnapshot) {
8579
- this.emitQuotaStatus(this.quotaStatus.latestSnapshot, true);
8580
- try {
8581
- await this.onTurnComplete();
8582
- } catch (error) {
8583
- console.error("[CodexManager] onTurnComplete failed during quota-blocked turn:", error);
8584
- }
8585
- return;
8586
- }
8587
- }
8588
- const {
8589
- message,
8590
- model,
8591
- customInstructions,
8592
- images,
8593
- permissionMode,
8594
- thinkingLevel
8595
- } = request;
8596
- const linearSessionId = ENGINE_ENV.LINEAR_SESSION_ID;
8597
- let tempImagePaths = [];
8598
- let stopTail = null;
8599
- let abortController = null;
8600
- try {
8601
- if (images && images.length > 0) {
8602
- const normalizedImages = await normalizeImages(images);
8603
- tempImagePaths = await saveNormalizedImagesToTempFiles(normalizedImages);
8604
- }
8605
- const developerInstructions = this.buildCombinedInstructions(customInstructions);
8606
- await this.updateCodexConfig(developerInstructions);
8607
- const sandboxMode = "danger-full-access";
8608
- const webSearchMode = "live";
8609
- const codexReasoningEffort = codexReasoningEffortForThinkingLevel(thinkingLevel);
8610
- const additionalDirectories = await getAgentAdditionalDirectories();
8611
- const threadOptions = {
8612
- workingDirectory: this.workingDirectory,
8613
- skipGitRepoCheck: true,
8614
- sandboxMode,
8615
- model: model || DEFAULT_CODEX_MODEL,
8616
- webSearchMode,
8617
- additionalDirectories,
8618
- ...codexReasoningEffort ? { modelReasoningEffort: codexReasoningEffort } : {}
8619
- };
8620
- abortController = new AbortController();
8621
- this.activeAbortController = abortController;
8622
- if (this.currentThreadId) {
8623
- this.currentThread = this.codex.resumeThread(this.currentThreadId, threadOptions);
8624
- } else {
8625
- this.currentThread = this.codex.startThread(threadOptions);
8626
- const { events } = await this.currentThread.runStreamed("Hello", { signal: abortController.signal });
8627
- for await (const event of events) {
8628
- if (event.type === "thread.started") {
8629
- this.currentThreadId = event.thread_id;
8630
- await this.onSaveSessionId(this.currentThreadId);
8631
- console.log(`[CodexManager] Captured and persisted thread ID: ${this.currentThreadId}`);
8632
- }
8633
- }
8634
- if (!this.currentThreadId && this.currentThread.id) {
8635
- this.currentThreadId = this.currentThread.id;
8636
- await this.onSaveSessionId(this.currentThreadId);
8637
- console.log(`[CodexManager] Captured and persisted thread ID from thread.id: ${this.currentThreadId}`);
8638
- }
8639
- }
8640
- stopTail = this.currentThreadId ? await this.startSessionTail(this.currentThreadId) : null;
8641
- let input;
8642
- if (tempImagePaths.length > 0) {
8643
- const inputItems = [
8644
- { type: "text", text: message },
8645
- ...tempImagePaths.map((path4) => ({ type: "local_image", path: path4 }))
8646
- ];
8647
- input = inputItems;
8648
- } else {
8649
- input = message;
8650
- }
8651
- try {
8652
- const { events } = await this.currentThread.runStreamed(input, { signal: abortController.signal });
8653
- const linearForwarder = new LinearEventForwarder(linearSessionId);
8654
- for await (const event of events) {
8655
- if (linearSessionId) {
8656
- linearForwarder.sendPlan(extractPlanFromCodexEvent(event));
8657
- linearForwarder.sendEvent(convertCodexEvent(event, linearSessionId));
8658
- }
8659
- }
8660
- linearForwarder.flushThoughtAsResponse();
8661
- } catch (error) {
8662
- await this.flushQuotaSnapshotFromCurrentSession();
8663
- if (this.quotaStatus.blocked) {
8664
- return;
8665
- }
8666
- throw error;
8667
- }
8668
- } finally {
8669
- if (stopTail) {
8670
- await stopTail();
8671
- }
8672
- await removeTempImageFiles(tempImagePaths);
8673
- try {
8674
- await this.onTurnComplete();
8675
- } catch (error) {
8676
- console.error("[CodexManager] onTurnComplete failed:", error);
8677
- }
8678
- this.activeAbortController = null;
8679
- }
8680
- }
8681
- async getHistory() {
8682
- if (!this.currentThreadId) {
8683
- return {
8684
- thread_id: null,
8685
- events: []
8686
- };
8687
- }
8688
- const sessionFile = await this.findSessionFile(this.currentThreadId);
8689
- if (!sessionFile) {
8690
- return {
8691
- thread_id: this.currentThreadId,
8692
- events: []
8693
- };
8694
- }
8695
- const events = await readJSONL(sessionFile);
8696
- return {
8697
- thread_id: this.currentThreadId,
8698
- events
8699
- };
8700
- }
8701
- // Helper methods for finding session files
8702
- async findSessionFile(threadId) {
8703
- const sessionsDir = join14(homedir12(), ".codex", "sessions");
8704
- try {
8705
- const now = /* @__PURE__ */ new Date();
8706
- const year = now.getFullYear();
8707
- const month = String(now.getMonth() + 1).padStart(2, "0");
8708
- const day = String(now.getDate()).padStart(2, "0");
8709
- const todayDir = join14(sessionsDir, String(year), month, day);
8710
- const file = await this.findFileInDirectory(todayDir, threadId);
8711
- if (file) return file;
8712
- for (let daysAgo = 1; daysAgo <= 7; daysAgo++) {
8713
- const date = new Date(now);
8714
- date.setDate(date.getDate() - daysAgo);
8715
- const searchYear = date.getFullYear();
8716
- const searchMonth = String(date.getMonth() + 1).padStart(2, "0");
8717
- const searchDay = String(date.getDate()).padStart(2, "0");
8718
- const searchDir = join14(sessionsDir, String(searchYear), searchMonth, searchDay);
8719
- const file2 = await this.findFileInDirectory(searchDir, threadId);
8720
- if (file2) return file2;
8721
- }
8722
- return null;
8723
- } catch (error) {
8724
- return null;
8725
- }
8726
- }
8727
- async findFileInDirectory(directory, threadId) {
8728
- try {
8729
- const files = await readdir3(directory);
8730
- for (const file of files) {
8731
- if (file.endsWith(".jsonl") && file.includes(threadId)) {
8732
- const fullPath = join14(directory, file);
8733
- const stats = await stat2(fullPath);
8734
- if (stats.isFile()) {
8735
- return fullPath;
8736
- }
8737
- }
8738
- }
8739
- return null;
8740
- } catch (error) {
8741
- return null;
8742
- }
8743
- }
8744
- async waitForSessionFile(threadId, timeoutMs = 5e3) {
8745
- const start = Date.now();
8746
- while (Date.now() - start < timeoutMs) {
8747
- const sessionFile = await this.findSessionFile(threadId);
8748
- if (sessionFile) {
8749
- return sessionFile;
8750
- }
8751
- await sleep(100);
8752
- }
8753
- return null;
8754
- }
8755
- // @openai/codex-sdk doesn't expose manual /compact (TUI-only); we only mirror the auto-compaction rollout entries to the UI.
8756
- trackNativeCompaction(event) {
8757
- if (event.type === "compacted") {
8758
- this.setCompacting(false);
8759
- return;
8760
- }
8761
- if (event.type !== "event_msg") return;
8762
- const msg = event.payload.msg;
8763
- if (!msg) return;
8764
- const itemType = msg.payload?.item?.type;
8765
- if (itemType !== "context_compaction") return;
8766
- if (msg.type === "item_started") {
8767
- this.setCompacting(true);
8768
- } else if (msg.type === "item_completed") {
8769
- this.setCompacting(false);
8770
- }
8771
- }
8772
- async startSessionTail(threadId) {
8773
- const sessionFile = await this.waitForSessionFile(threadId);
8774
- if (!sessionFile) {
8775
- return async () => {
8776
- };
8777
- }
8778
- let active = true;
8779
- const seenLines = /* @__PURE__ */ new Set();
8780
- const seedSeenLines = async () => {
8781
- try {
8782
- const content = await readFile8(sessionFile, "utf-8");
8783
- const lines = content.split("\n").map((line) => line.trim()).filter(Boolean);
8784
- let latest = null;
8785
- for (const line of lines) {
8786
- seenLines.add(line);
8787
- try {
8788
- const parsed = JSON.parse(line);
8789
- const snapshot = extractCodexRateLimitsSnapshotFromJsonl(parsed);
8790
- if (snapshot) latest = snapshot;
8791
- } catch {
8792
- }
8793
- }
8794
- if (latest) {
8795
- this.quotaStatus.prime(latest);
8796
- }
8797
- } catch {
8798
- }
8799
- };
8800
- await seedSeenLines();
8801
- const pump = async () => {
8802
- let emitted = 0;
8803
- try {
8804
- const content = await readFile8(sessionFile, "utf-8");
8805
- const lines = content.split("\n");
8806
- const completeLines = content.endsWith("\n") ? lines : lines.slice(0, -1);
8807
- for (const line of completeLines) {
8808
- const trimmed = line.trim();
8809
- if (!trimmed || seenLines.has(trimmed)) {
8810
- continue;
8811
- }
8812
- seenLines.add(trimmed);
8813
- try {
8814
- const parsed = JSON.parse(trimmed);
8815
- const snapshot = extractCodexRateLimitsSnapshotFromJsonl(parsed);
8816
- if (snapshot) {
8817
- this.emitQuotaStatus(snapshot);
8818
- }
8819
- if (isJsonlEvent2(parsed)) {
8820
- this.trackNativeCompaction(parsed);
8821
- this.onEvent(parsed);
8822
- emitted += 1;
8823
- }
8824
- } catch {
8825
- }
8826
- }
8827
- } catch {
8828
- }
8829
- return emitted;
8830
- };
8831
- const loop = (async () => {
8832
- while (active) {
8833
- await pump();
8834
- await sleep(100);
8835
- }
8836
- await pump();
8837
- })();
8838
- return async () => {
8839
- active = false;
8840
- await loop;
8841
- const deadline = Date.now() + 1500;
8842
- while (Date.now() < deadline) {
8843
- const emitted = await pump();
8844
- if (emitted > 0) {
8845
- continue;
8846
- }
8847
- await sleep(100);
8848
- }
8849
- };
8850
- }
8851
- };
8852
-
8853
8216
  // src/managers/relay-tools.ts
8854
8217
  import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
8855
8218
  import { z } from "zod";
@@ -9451,19 +8814,19 @@ var DuplicateDefaultChatError = class extends Error {
9451
8814
  };
9452
8815
 
9453
8816
  // src/services/chat/chat-service.ts
9454
- var ENGINE_DIR2 = join15(homedir13(), ".replicas", "engine");
9455
- var CHATS_FILE = join15(ENGINE_DIR2, "chats.json");
9456
- var CLAUDE_HISTORY_DIR = join15(ENGINE_DIR2, "claude-histories");
9457
- var RELAY_HISTORY_DIR = join15(ENGINE_DIR2, "relay-histories");
9458
- var CHAT_SENDERS_DIR = join15(ENGINE_DIR2, "chat-senders");
9459
- var CODEX_AUTH_PATH2 = join15(homedir13(), ".codex", "auth.json");
8817
+ var ENGINE_DIR2 = join14(homedir12(), ".replicas", "engine");
8818
+ var CHATS_FILE = join14(ENGINE_DIR2, "chats.json");
8819
+ var CLAUDE_HISTORY_DIR = join14(ENGINE_DIR2, "claude-histories");
8820
+ var RELAY_HISTORY_DIR = join14(ENGINE_DIR2, "relay-histories");
8821
+ var CHAT_SENDERS_DIR = join14(ENGINE_DIR2, "chat-senders");
8822
+ var CODEX_AUTH_PATH2 = join14(homedir12(), ".codex", "auth.json");
9460
8823
  var CHATS_BACKUP_FILE = `${CHATS_FILE}.bak`;
9461
8824
  function isChatMessageSender(value) {
9462
8825
  if (!isRecord4(value)) return false;
9463
8826
  return typeof value.senderUserId === "string" && typeof value.senderEmail === "string" && typeof value.recordedAt === "string";
9464
8827
  }
9465
8828
  function isCodexAvailable() {
9466
- return existsSync8(CODEX_AUTH_PATH2) || Boolean(ENGINE_ENV.OPENAI_API_KEY);
8829
+ return existsSync7(CODEX_AUTH_PATH2) || Boolean(ENGINE_ENV.OPENAI_API_KEY);
9467
8830
  }
9468
8831
  function isSameAcceptedUserEvent(event, acceptedEvent) {
9469
8832
  if (areSameUserMessageEvents(event, acceptedEvent)) return true;
@@ -9505,18 +8868,18 @@ function isPersistedChat(value) {
9505
8868
  return false;
9506
8869
  }
9507
8870
  const candidate = value;
9508
- return typeof candidate.id === "string" && (candidate.provider === "claude" || candidate.provider === "codex" || candidate.provider === "relay") && typeof candidate.title === "string" && typeof candidate.createdAt === "string" && typeof candidate.updatedAt === "string" && (candidate.providerSessionId === null || typeof candidate.providerSessionId === "string") && (candidate.parentChatId === void 0 || candidate.parentChatId === null || typeof candidate.parentChatId === "string") && (candidate.codexBackend === void 0 || candidate.codexBackend === "sdk" || candidate.codexBackend === "asp");
9509
- }
9510
- function codexBackendForChat(chat) {
9511
- if (chat.provider !== "codex") return "asp";
9512
- if (chat.codexBackend) return chat.codexBackend;
9513
- return chat.providerSessionId ? "sdk" : "asp";
8871
+ return typeof candidate.id === "string" && (candidate.provider === "claude" || candidate.provider === "codex" || candidate.provider === "relay") && typeof candidate.title === "string" && typeof candidate.createdAt === "string" && typeof candidate.updatedAt === "string" && (candidate.providerSessionId === null || typeof candidate.providerSessionId === "string") && (candidate.parentChatId === void 0 || candidate.parentChatId === null || typeof candidate.parentChatId === "string");
9514
8872
  }
9515
8873
  function normalizePersistedChat(chat) {
8874
+ const isLegacyCodexSdkChat = chat.provider === "codex" && (chat.codexBackend === "sdk" || chat.codexBackend === void 0 && chat.providerSessionId !== null);
9516
8875
  return {
9517
- ...chat,
9518
- parentChatId: chat.parentChatId ?? null,
9519
- ...chat.provider === "codex" ? { codexBackend: codexBackendForChat(chat) } : {}
8876
+ id: chat.id,
8877
+ provider: chat.provider,
8878
+ title: chat.title,
8879
+ createdAt: chat.createdAt,
8880
+ updatedAt: chat.updatedAt,
8881
+ providerSessionId: isLegacyCodexSdkChat ? null : chat.providerSessionId,
8882
+ parentChatId: chat.parentChatId ?? null
9520
8883
  };
9521
8884
  }
9522
8885
  function parsePersistedChatsContent(content) {
@@ -9551,10 +8914,10 @@ var ChatService = class {
9551
8914
  chats = /* @__PURE__ */ new Map();
9552
8915
  writeChain = Promise.resolve();
9553
8916
  async initialize() {
9554
- await mkdir12(ENGINE_DIR2, { recursive: true });
9555
- await mkdir12(CLAUDE_HISTORY_DIR, { recursive: true });
9556
- await mkdir12(RELAY_HISTORY_DIR, { recursive: true });
9557
- await mkdir12(CHAT_SENDERS_DIR, { recursive: true });
8917
+ await mkdir11(ENGINE_DIR2, { recursive: true });
8918
+ await mkdir11(CLAUDE_HISTORY_DIR, { recursive: true });
8919
+ await mkdir11(RELAY_HISTORY_DIR, { recursive: true });
8920
+ await mkdir11(CHAT_SENDERS_DIR, { recursive: true });
9558
8921
  const persisted = await this.loadChats();
9559
8922
  for (const chat of persisted) {
9560
8923
  const runtime = this.createRuntimeChat(chat);
@@ -9606,8 +8969,7 @@ var ChatService = class {
9606
8969
  createdAt: now,
9607
8970
  updatedAt: now,
9608
8971
  providerSessionId: null,
9609
- parentChatId,
9610
- ...request.provider === "codex" ? { codexBackend: "asp" } : {}
8972
+ parentChatId
9611
8973
  };
9612
8974
  const runtime = this.createRuntimeChat(persisted);
9613
8975
  this.chats.set(persisted.id, runtime);
@@ -9653,7 +9015,7 @@ var ChatService = class {
9653
9015
  };
9654
9016
  }
9655
9017
  senderFilePath(chatId) {
9656
- return join15(CHAT_SENDERS_DIR, `${chatId}.jsonl`);
9018
+ return join14(CHAT_SENDERS_DIR, `${chatId}.jsonl`);
9657
9019
  }
9658
9020
  async appendSender(chatId, sender) {
9659
9021
  try {
@@ -9664,7 +9026,7 @@ var ChatService = class {
9664
9026
  }
9665
9027
  async readSenders(chatId) {
9666
9028
  try {
9667
- const content = await readFile9(this.senderFilePath(chatId), "utf-8");
9029
+ const content = await readFile8(this.senderFilePath(chatId), "utf-8");
9668
9030
  const lines = content.split("\n").filter((line) => line.trim().length > 0);
9669
9031
  const senders = [];
9670
9032
  for (const line of lines) {
@@ -9803,7 +9165,7 @@ var ChatService = class {
9803
9165
  async deleteHistoryFile(persisted) {
9804
9166
  if (persisted.provider === "claude" || persisted.provider === "relay") {
9805
9167
  const dir = persisted.provider === "claude" ? CLAUDE_HISTORY_DIR : RELAY_HISTORY_DIR;
9806
- await rm(join15(dir, `${persisted.id}.jsonl`), { force: true });
9168
+ await rm(join14(dir, `${persisted.id}.jsonl`), { force: true });
9807
9169
  }
9808
9170
  await rm(this.senderFilePath(persisted.id), { force: true });
9809
9171
  }
@@ -9860,7 +9222,7 @@ var ChatService = class {
9860
9222
  if (persisted.provider === "claude") {
9861
9223
  provider = new ClaudeManager({
9862
9224
  workingDirectory: this.workingDirectory,
9863
- historyFilePath: join15(CLAUDE_HISTORY_DIR, `${persisted.id}.jsonl`),
9225
+ historyFilePath: join14(CLAUDE_HISTORY_DIR, `${persisted.id}.jsonl`),
9864
9226
  initialSessionId: persisted.providerSessionId,
9865
9227
  onSaveSessionId: saveSession,
9866
9228
  onTurnComplete: onProviderTurnComplete,
@@ -9869,7 +9231,7 @@ var ChatService = class {
9869
9231
  } else if (persisted.provider === "relay") {
9870
9232
  provider = new RelayManager({
9871
9233
  workingDirectory: this.workingDirectory,
9872
- historyFilePath: join15(RELAY_HISTORY_DIR, `${persisted.id}.jsonl`),
9234
+ historyFilePath: join14(RELAY_HISTORY_DIR, `${persisted.id}.jsonl`),
9873
9235
  initialSessionId: persisted.providerSessionId,
9874
9236
  onSaveSessionId: saveSession,
9875
9237
  onTurnComplete: onProviderTurnComplete,
@@ -9878,8 +9240,7 @@ var ChatService = class {
9878
9240
  codexAvailable: isCodexAvailable()
9879
9241
  });
9880
9242
  } else {
9881
- const CodexProviderCtor = codexBackendForChat(persisted) === "sdk" ? CodexManager : CodexAspManager;
9882
- provider = new CodexProviderCtor({
9243
+ provider = new CodexAspManager({
9883
9244
  workingDirectory: this.workingDirectory,
9884
9245
  initialSessionId: persisted.providerSessionId,
9885
9246
  onSaveSessionId: saveSession,
@@ -10021,7 +9382,7 @@ var ChatService = class {
10021
9382
  }
10022
9383
  async loadChats() {
10023
9384
  try {
10024
- const content = await readFile9(CHATS_FILE, "utf-8");
9385
+ const content = await readFile8(CHATS_FILE, "utf-8");
10025
9386
  return parsePersistedChatsContent(content);
10026
9387
  } catch (error) {
10027
9388
  if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
@@ -10036,7 +9397,7 @@ var ChatService = class {
10036
9397
  console.error("[ChatService] Failed to quarantine corrupt chats file:", renameError);
10037
9398
  }
10038
9399
  try {
10039
- const backupContent = await readFile9(CHATS_BACKUP_FILE, "utf-8");
9400
+ const backupContent = await readFile8(CHATS_BACKUP_FILE, "utf-8");
10040
9401
  return parsePersistedChatsContent(backupContent);
10041
9402
  } catch (backupError) {
10042
9403
  if (backupError && typeof backupError === "object" && "code" in backupError && backupError.code === "ENOENT") {
@@ -10111,8 +9472,8 @@ var ChatService = class {
10111
9472
 
10112
9473
  // src/services/repo-file-service.ts
10113
9474
  import { execFile as execFile2 } from "child_process";
10114
- import { readFile as readFile10, realpath, stat as stat3 } from "fs/promises";
10115
- import { join as join16, resolve, extname } from "path";
9475
+ import { readFile as readFile9, realpath, stat as stat2 } from "fs/promises";
9476
+ import { join as join15, resolve, extname } from "path";
10116
9477
  var CACHE_TTL_MS = 3e4;
10117
9478
  var SEARCH_TIMEOUT_MS = 15e3;
10118
9479
  var MAX_CONTENT_BYTES = 256 * 1024;
@@ -10272,11 +9633,11 @@ var RepoFileService = class {
10272
9633
  const repo = repos.find((r) => r.name === repoName);
10273
9634
  if (!repo) return null;
10274
9635
  try {
10275
- const fullPath = await realpath(resolve(join16(repo.path, filePath)));
9636
+ const fullPath = await realpath(resolve(join15(repo.path, filePath)));
10276
9637
  const repoRoot = await realpath(repo.path);
10277
9638
  const repoPrefix = repoRoot.endsWith("/") ? repoRoot : repoRoot + "/";
10278
9639
  if (!fullPath.startsWith(repoPrefix) && fullPath !== repoRoot) return null;
10279
- const fileStat = await stat3(fullPath);
9640
+ const fileStat = await stat2(fullPath);
10280
9641
  if (!fileStat.isFile()) return null;
10281
9642
  const sizeBytes = fileStat.size;
10282
9643
  if (isBinaryExtension(filePath)) {
@@ -10301,7 +9662,7 @@ var RepoFileService = class {
10301
9662
  tooLarge: true
10302
9663
  };
10303
9664
  }
10304
- const content = await readFile10(fullPath, "utf-8");
9665
+ const content = await readFile9(fullPath, "utf-8");
10305
9666
  return {
10306
9667
  repoName,
10307
9668
  path: filePath,
@@ -10346,13 +9707,9 @@ var RepoFileService = class {
10346
9707
  async listChangedFiles(repoPath, defaultBranch) {
10347
9708
  const changedFiles = /* @__PURE__ */ new Set();
10348
9709
  try {
10349
- const mergeBase = await execGitAsync(
10350
- ["merge-base", `origin/${defaultBranch}`, "HEAD"],
10351
- repoPath,
10352
- SEARCH_TIMEOUT_MS
10353
- );
9710
+ const diffBase = await resolveDiffBase(repoPath, defaultBranch);
10354
9711
  const diffOutput = await execGitAsync(
10355
- ["diff", "--name-only", "-M", mergeBase.trim()],
9712
+ ["diff", "--name-only", "-M", diffBase],
10356
9713
  repoPath,
10357
9714
  SEARCH_TIMEOUT_MS
10358
9715
  );
@@ -10383,16 +9740,16 @@ var RepoFileService = class {
10383
9740
  // src/v1-routes.ts
10384
9741
  import { Hono } from "hono";
10385
9742
  import { z as z2 } from "zod";
10386
- import { readdir as readdir6, stat as stat5, readFile as readFile14 } from "fs/promises";
10387
- import { join as join20, resolve as resolve2 } from "path";
9743
+ import { readdir as readdir5, stat as stat4, readFile as readFile13 } from "fs/promises";
9744
+ import { join as join19, resolve as resolve2 } from "path";
10388
9745
 
10389
9746
  // src/services/canvas-service.ts
10390
- import { readdir as readdir4, readFile as readFile11, stat as stat4 } from "fs/promises";
10391
- import { homedir as homedir14 } from "os";
10392
- import { basename, join as join17 } from "path";
9747
+ import { readdir as readdir3, readFile as readFile10, stat as stat3 } from "fs/promises";
9748
+ import { homedir as homedir13 } from "os";
9749
+ import { basename, join as join16 } from "path";
10393
9750
  var CANVAS_DIRECTORIES = [
10394
- join17(homedir14(), ".claude", "plans"),
10395
- join17(homedir14(), ".replicas", "canvas")
9751
+ join16(homedir13(), ".claude", "plans"),
9752
+ join16(homedir13(), ".replicas", "canvas")
10396
9753
  ];
10397
9754
  var MAX_CANVAS_FILE_BYTES = 5 * 1024 * 1024;
10398
9755
  function isTextKind(kind) {
@@ -10407,7 +9764,7 @@ var CanvasService = class {
10407
9764
  for (const directory of CANVAS_DIRECTORIES) {
10408
9765
  let entries;
10409
9766
  try {
10410
- entries = await readdir4(directory, { withFileTypes: true });
9767
+ entries = await readdir3(directory, { withFileTypes: true });
10411
9768
  } catch {
10412
9769
  continue;
10413
9770
  }
@@ -10418,7 +9775,7 @@ var CanvasService = class {
10418
9775
  const { kind } = classifyCanvasFilename(entry.name);
10419
9776
  let sizeBytes = 0;
10420
9777
  try {
10421
- const s = await stat4(join17(directory, entry.name));
9778
+ const s = await stat3(join16(directory, entry.name));
10422
9779
  sizeBytes = s.size;
10423
9780
  } catch {
10424
9781
  continue;
@@ -10433,10 +9790,10 @@ var CanvasService = class {
10433
9790
  if (!safe || safe !== filename || safe.startsWith(".")) return null;
10434
9791
  const { kind, mimeType } = classifyCanvasFilename(safe);
10435
9792
  for (const directory of CANVAS_DIRECTORIES) {
10436
- const filePath = join17(directory, safe);
9793
+ const filePath = join16(directory, safe);
10437
9794
  let sizeBytes = 0;
10438
9795
  try {
10439
- const s = await stat4(filePath);
9796
+ const s = await stat3(filePath);
10440
9797
  sizeBytes = s.size;
10441
9798
  } catch {
10442
9799
  continue;
@@ -10452,10 +9809,10 @@ var CanvasService = class {
10452
9809
  }
10453
9810
  try {
10454
9811
  if (isTextKind(kind)) {
10455
- const content = await readFile11(filePath, "utf-8");
9812
+ const content = await readFile10(filePath, "utf-8");
10456
9813
  return { filename: safe, kind, sizeBytes, mimeType, content };
10457
9814
  }
10458
- const buf = await readFile11(filePath);
9815
+ const buf = await readFile10(filePath);
10459
9816
  return { filename: safe, kind, sizeBytes, mimeType, base64: buf.toString("base64") };
10460
9817
  } catch {
10461
9818
  continue;
@@ -10468,16 +9825,16 @@ var canvasService = new CanvasService();
10468
9825
 
10469
9826
  // src/services/warm-hooks-service.ts
10470
9827
  import { spawn as spawn4 } from "child_process";
10471
- import { readFile as readFile13 } from "fs/promises";
10472
- import { existsSync as existsSync9 } from "fs";
10473
- import { join as join19 } from "path";
9828
+ import { readFile as readFile12 } from "fs/promises";
9829
+ import { existsSync as existsSync8 } from "fs";
9830
+ import { join as join18 } from "path";
10474
9831
 
10475
9832
  // src/services/warm-hook-logs-service.ts
10476
- import { mkdir as mkdir13, readFile as readFile12, writeFile as writeFile7, readdir as readdir5, appendFile as appendFile6, unlink as unlink3 } from "fs/promises";
10477
- import { homedir as homedir15 } from "os";
10478
- import { join as join18 } from "path";
10479
- var LOGS_DIR2 = join18(homedir15(), ".replicas", "warm-hook-logs");
10480
- var CURRENT_RUN_LOG = join18(LOGS_DIR2, "current-run.log");
9833
+ import { mkdir as mkdir12, readFile as readFile11, writeFile as writeFile6, readdir as readdir4, appendFile as appendFile6, unlink as unlink3 } from "fs/promises";
9834
+ import { homedir as homedir14 } from "os";
9835
+ import { join as join17 } from "path";
9836
+ var LOGS_DIR2 = join17(homedir14(), ".replicas", "warm-hook-logs");
9837
+ var CURRENT_RUN_LOG = join17(LOGS_DIR2, "current-run.log");
10481
9838
  var GLOBAL_FILENAME = "global.json";
10482
9839
  function withPreview2(stored) {
10483
9840
  const preview = buildHookOutputPreview(stored.output);
@@ -10485,7 +9842,7 @@ function withPreview2(stored) {
10485
9842
  }
10486
9843
  var WarmHookLogsService = class {
10487
9844
  async ensureDir() {
10488
- await mkdir13(LOGS_DIR2, { recursive: true });
9845
+ await mkdir12(LOGS_DIR2, { recursive: true });
10489
9846
  }
10490
9847
  async saveGlobalHookLog(entry) {
10491
9848
  await this.ensureDir();
@@ -10494,7 +9851,7 @@ var WarmHookLogsService = class {
10494
9851
  hookName: "organization",
10495
9852
  ...entry
10496
9853
  };
10497
- await writeFile7(join18(LOGS_DIR2, GLOBAL_FILENAME), `${JSON.stringify(log, null, 2)}
9854
+ await writeFile6(join17(LOGS_DIR2, GLOBAL_FILENAME), `${JSON.stringify(log, null, 2)}
10498
9855
  `, "utf-8");
10499
9856
  }
10500
9857
  async saveEnvironmentHookLog(entry) {
@@ -10504,7 +9861,7 @@ var WarmHookLogsService = class {
10504
9861
  hookName: "environment",
10505
9862
  ...entry
10506
9863
  };
10507
- await writeFile7(join18(LOGS_DIR2, ENVIRONMENT_HOOK_LOG_FILENAME), `${JSON.stringify(log, null, 2)}
9864
+ await writeFile6(join17(LOGS_DIR2, ENVIRONMENT_HOOK_LOG_FILENAME), `${JSON.stringify(log, null, 2)}
10508
9865
  `, "utf-8");
10509
9866
  }
10510
9867
  async saveRepoHookLog(repoName, entry) {
@@ -10514,13 +9871,13 @@ var WarmHookLogsService = class {
10514
9871
  hookName: repoName,
10515
9872
  ...entry
10516
9873
  };
10517
- await writeFile7(join18(LOGS_DIR2, repoHookLogFilename(repoName)), `${JSON.stringify(log, null, 2)}
9874
+ await writeFile6(join17(LOGS_DIR2, repoHookLogFilename(repoName)), `${JSON.stringify(log, null, 2)}
10518
9875
  `, "utf-8");
10519
9876
  }
10520
9877
  async getAllLogs() {
10521
9878
  let files;
10522
9879
  try {
10523
- files = await readdir5(LOGS_DIR2);
9880
+ files = await readdir4(LOGS_DIR2);
10524
9881
  } catch (err) {
10525
9882
  if (err.code === "ENOENT") {
10526
9883
  return [];
@@ -10533,7 +9890,7 @@ var WarmHookLogsService = class {
10533
9890
  continue;
10534
9891
  }
10535
9892
  try {
10536
- const raw = await readFile12(join18(LOGS_DIR2, file), "utf-8");
9893
+ const raw = await readFile11(join17(LOGS_DIR2, file), "utf-8");
10537
9894
  const stored = JSON.parse(raw);
10538
9895
  logs.push(withPreview2(stored));
10539
9896
  } catch {
@@ -10562,7 +9919,7 @@ var WarmHookLogsService = class {
10562
9919
  }
10563
9920
  async getCurrentRunLog() {
10564
9921
  try {
10565
- return await readFile12(CURRENT_RUN_LOG, "utf-8");
9922
+ return await readFile11(CURRENT_RUN_LOG, "utf-8");
10566
9923
  } catch (err) {
10567
9924
  if (err.code === "ENOENT") return null;
10568
9925
  throw err;
@@ -10571,7 +9928,7 @@ var WarmHookLogsService = class {
10571
9928
  async getFullOutput(hookType, hookName) {
10572
9929
  const filename = hookType === "global" ? GLOBAL_FILENAME : hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
10573
9930
  try {
10574
- const raw = await readFile12(join18(LOGS_DIR2, filename), "utf-8");
9931
+ const raw = await readFile11(join17(LOGS_DIR2, filename), "utf-8");
10575
9932
  const stored = JSON.parse(raw);
10576
9933
  if (stored.hookType !== hookType || stored.hookName !== hookName) {
10577
9934
  return null;
@@ -10590,12 +9947,12 @@ var warmHookLogsService = new WarmHookLogsService();
10590
9947
  // src/services/warm-hooks-service.ts
10591
9948
  async function readRepoWarmHook(repoPath) {
10592
9949
  for (const filename of REPLICAS_CONFIG_FILENAMES) {
10593
- const configPath = join19(repoPath, filename);
10594
- if (!existsSync9(configPath)) {
9950
+ const configPath = join18(repoPath, filename);
9951
+ if (!existsSync8(configPath)) {
10595
9952
  continue;
10596
9953
  }
10597
9954
  try {
10598
- const raw = await readFile13(configPath, "utf-8");
9955
+ const raw = await readFile12(configPath, "utf-8");
10599
9956
  const config = parseReplicasConfigString(raw, filename);
10600
9957
  if (!config.warmHook) {
10601
9958
  return null;
@@ -11488,12 +10845,12 @@ function createV1Routes(deps) {
11488
10845
  });
11489
10846
  app2.get("/logs", async (c) => {
11490
10847
  try {
11491
- const files = await readdir6(LOG_DIR).catch(() => []);
10848
+ const files = await readdir5(LOG_DIR).catch(() => []);
11492
10849
  const logFiles = files.filter((f) => f.endsWith(".log"));
11493
10850
  const sessions = await Promise.all(
11494
10851
  logFiles.map(async (filename) => {
11495
- const filePath = join20(LOG_DIR, filename);
11496
- const fileStat = await stat5(filePath);
10852
+ const filePath = join19(LOG_DIR, filename);
10853
+ const fileStat = await stat4(filePath);
11497
10854
  const sessionId = filename.replace(/\.log$/, "");
11498
10855
  return {
11499
10856
  sessionId,
@@ -11529,7 +10886,7 @@ function createV1Routes(deps) {
11529
10886
  const limit = Math.min(parseInt(c.req.query("limit") || "500", 10), 5e3);
11530
10887
  let content;
11531
10888
  try {
11532
- content = await readFile14(filePath, "utf-8");
10889
+ content = await readFile13(filePath, "utf-8");
11533
10890
  } catch {
11534
10891
  return c.json(jsonError("Log session not found"), 404);
11535
10892
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.276",
3
+ "version": "0.1.278",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -32,7 +32,6 @@
32
32
  "dependencies": {
33
33
  "@anthropic-ai/claude-agent-sdk": "0.2.112",
34
34
  "@hono/node-server": "^1.19.5",
35
- "@openai/codex-sdk": "^0.124.0",
36
35
  "hono": "^4.10.3",
37
36
  "smol-toml": "^1.6.0",
38
37
  "yaml": "^2.8.2",