replicas-engine 0.1.16 → 0.1.18

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 +407 -52
  2. package/package.json +1 -1
package/dist/src/index.js CHANGED
@@ -384,7 +384,7 @@ function convertCodexEvent(event, linearSessionId) {
384
384
 
385
385
  // src/utils/git.ts
386
386
  import { execSync } from "child_process";
387
- var cachedPrUrl = null;
387
+ var cachedPr = null;
388
388
  function runGitCommand(command, cwd) {
389
389
  return execSync(command, {
390
390
  cwd,
@@ -443,16 +443,17 @@ function getGitDiff(cwd) {
443
443
  }
444
444
  }
445
445
  function getPullRequestUrl(cwd) {
446
- if (cachedPrUrl) {
447
- return cachedPrUrl;
448
- }
449
446
  try {
450
- const branch = getCurrentBranch(cwd);
451
- if (!branch) {
447
+ const currentBranch = getCurrentBranch(cwd);
448
+ if (!currentBranch) {
452
449
  return null;
453
450
  }
451
+ if (cachedPr && cachedPr.branch === currentBranch) {
452
+ return cachedPr.prUrl;
453
+ }
454
+ cachedPr = null;
454
455
  try {
455
- const remoteRef = execSync(`git ls-remote --heads origin ${branch}`, {
456
+ const remoteRef = execSync(`git ls-remote --heads origin ${currentBranch}`, {
456
457
  cwd,
457
458
  encoding: "utf-8",
458
459
  stdio: ["pipe", "pipe", "pipe"]
@@ -470,8 +471,11 @@ function getPullRequestUrl(cwd) {
470
471
  stdio: ["pipe", "pipe", "pipe"]
471
472
  }).trim();
472
473
  if (prInfo) {
473
- cachedPrUrl = prInfo;
474
- return cachedPrUrl;
474
+ cachedPr = {
475
+ prUrl: prInfo,
476
+ branch: currentBranch
477
+ };
478
+ return cachedPr.prUrl;
475
479
  }
476
480
  } catch {
477
481
  return null;
@@ -490,13 +494,120 @@ function getGitStatus(workingDirectory) {
490
494
  };
491
495
  }
492
496
 
497
+ // src/services/message-queue.ts
498
+ var MessageQueue = class {
499
+ queue = [];
500
+ processing = false;
501
+ currentMessageId = null;
502
+ messageIdCounter = 0;
503
+ processMessage;
504
+ constructor(processMessage) {
505
+ this.processMessage = processMessage;
506
+ }
507
+ generateMessageId() {
508
+ return `msg_${Date.now()}_${++this.messageIdCounter}`;
509
+ }
510
+ /**
511
+ * Add a message to the queue or start processing immediately if not busy
512
+ * @returns Object indicating whether the message was queued or started processing
513
+ */
514
+ async enqueue(message, model, customInstructions) {
515
+ const messageId = this.generateMessageId();
516
+ const queuedMessage = {
517
+ id: messageId,
518
+ message,
519
+ model,
520
+ customInstructions,
521
+ queuedAt: (/* @__PURE__ */ new Date()).toISOString()
522
+ };
523
+ if (this.processing) {
524
+ this.queue.push(queuedMessage);
525
+ return {
526
+ queued: true,
527
+ messageId,
528
+ position: this.queue.length
529
+ };
530
+ }
531
+ this.startProcessing(queuedMessage);
532
+ return {
533
+ queued: false,
534
+ messageId,
535
+ position: 0
536
+ };
537
+ }
538
+ async startProcessing(queuedMessage) {
539
+ this.processing = true;
540
+ this.currentMessageId = queuedMessage.id;
541
+ try {
542
+ await this.processMessage(
543
+ queuedMessage.message,
544
+ queuedMessage.model,
545
+ queuedMessage.customInstructions
546
+ );
547
+ } catch (error) {
548
+ console.error("[MessageQueue] Error processing message:", error);
549
+ } finally {
550
+ this.processing = false;
551
+ this.currentMessageId = null;
552
+ await this.processNextInQueue();
553
+ }
554
+ }
555
+ async processNextInQueue() {
556
+ const nextMessage = this.queue.shift();
557
+ if (nextMessage) {
558
+ await this.startProcessing(nextMessage);
559
+ }
560
+ }
561
+ /**
562
+ * Check if currently processing a message
563
+ */
564
+ isProcessing() {
565
+ return this.processing;
566
+ }
567
+ /**
568
+ * Get the current queue length
569
+ */
570
+ getQueueLength() {
571
+ return this.queue.length;
572
+ }
573
+ /**
574
+ * Get full queue status
575
+ */
576
+ getStatus() {
577
+ return {
578
+ isProcessing: this.processing,
579
+ queueLength: this.queue.length,
580
+ currentMessageId: this.currentMessageId,
581
+ queuedMessages: this.queue.map((msg, index) => ({
582
+ id: msg.id,
583
+ queuedAt: msg.queuedAt,
584
+ position: index + 1
585
+ }))
586
+ };
587
+ }
588
+ /**
589
+ * Clear the queue (does not stop current processing)
590
+ */
591
+ clearQueue() {
592
+ this.queue = [];
593
+ }
594
+ /**
595
+ * Reset everything including clearing processing state
596
+ */
597
+ reset() {
598
+ this.queue = [];
599
+ this.processing = false;
600
+ this.currentMessageId = null;
601
+ }
602
+ };
603
+
493
604
  // src/services/codex-manager.ts
494
605
  var CodexManager = class {
495
606
  codex;
496
607
  currentThreadId = null;
497
608
  currentThread = null;
498
609
  workingDirectory;
499
- processing = false;
610
+ messageQueue;
500
611
  constructor(workingDirectory) {
501
612
  this.codex = new Codex();
502
613
  if (workingDirectory) {
@@ -510,14 +621,38 @@ var CodexManager = class {
510
621
  this.workingDirectory = workspaceHome;
511
622
  }
512
623
  }
624
+ this.messageQueue = new MessageQueue(this.processMessageInternal.bind(this));
513
625
  }
514
626
  isProcessing() {
515
- return this.processing;
627
+ return this.messageQueue.isProcessing();
516
628
  }
629
+ /**
630
+ * Enqueue a message for processing. If not currently processing, starts immediately.
631
+ * If already processing, adds to queue.
632
+ * @returns Object with queued status, messageId, and position in queue
633
+ */
634
+ async enqueueMessage(message, model, customInstructions) {
635
+ return this.messageQueue.enqueue(message, model, customInstructions);
636
+ }
637
+ /**
638
+ * Get the current queue status
639
+ */
640
+ getQueueStatus() {
641
+ return this.messageQueue.getStatus();
642
+ }
643
+ /**
644
+ * Legacy sendMessage method - now uses the queue internally
645
+ * @deprecated Use enqueueMessage for better control over queue status
646
+ */
517
647
  async sendMessage(message, model, customInstructions) {
648
+ await this.enqueueMessage(message, model, customInstructions);
649
+ }
650
+ /**
651
+ * Internal method that actually processes the message
652
+ */
653
+ async processMessageInternal(message, model, customInstructions) {
518
654
  const linearSessionId = process.env.LINEAR_SESSION_ID;
519
655
  try {
520
- this.processing = true;
521
656
  if (!this.currentThread) {
522
657
  if (this.currentThreadId) {
523
658
  this.currentThread = this.codex.resumeThread(this.currentThreadId, {
@@ -559,7 +694,6 @@ var CodexManager = class {
559
694
  }
560
695
  }
561
696
  } finally {
562
- this.processing = false;
563
697
  if (linearSessionId) {
564
698
  const status = getGitStatus(this.workingDirectory);
565
699
  monolithService.sendEvent({ type: "agent_turn_complete", payload: { linearSessionId, status } }).catch(() => {
@@ -602,7 +736,7 @@ var CodexManager = class {
602
736
  async reset() {
603
737
  this.currentThread = null;
604
738
  this.currentThreadId = null;
605
- this.processing = false;
739
+ this.messageQueue.reset();
606
740
  }
607
741
  getThreadId() {
608
742
  return this.currentThreadId;
@@ -684,21 +818,15 @@ codex.post("/send", async (c) => {
684
818
  if (!message || typeof message !== "string") {
685
819
  return c.json({ error: "Message is required and must be a string" }, 400);
686
820
  }
687
- if (codexManager.isProcessing()) {
688
- return c.json(
689
- {
690
- error: "A turn is already in progress. Please wait."
691
- },
692
- 400
693
- );
694
- }
695
- codexManager.sendMessage(message, model, customInstructions).catch((error) => {
696
- console.error("[Codex Route] Error in background message processing:", error);
697
- });
698
- return c.json({
821
+ const result = await codexManager.enqueueMessage(message, model, customInstructions);
822
+ const response = {
699
823
  success: true,
700
- message: "Message sent successfully"
701
- });
824
+ message: result.queued ? `Message queued at position ${result.position}` : "Message sent successfully",
825
+ queued: result.queued,
826
+ messageId: result.messageId,
827
+ position: result.position
828
+ };
829
+ return c.json(response);
702
830
  } catch (error) {
703
831
  console.error("Error in /codex/send:", error);
704
832
  return c.json(
@@ -766,6 +894,21 @@ codex.get("/status", async (c) => {
766
894
  );
767
895
  }
768
896
  });
897
+ codex.get("/queue", async (c) => {
898
+ try {
899
+ const queueStatus = codexManager.getQueueStatus();
900
+ return c.json(queueStatus);
901
+ } catch (error) {
902
+ console.error("Error in /codex/queue:", error);
903
+ return c.json(
904
+ {
905
+ error: "Failed to retrieve queue status",
906
+ details: error instanceof Error ? error.message : "Unknown error"
907
+ },
908
+ 500
909
+ );
910
+ }
911
+ });
769
912
  codex.post("/reset", async (c) => {
770
913
  try {
771
914
  await codexManager.reset();
@@ -801,7 +944,7 @@ var ClaudeManager = class {
801
944
  historyFile;
802
945
  sessionId = null;
803
946
  initialized;
804
- processing = false;
947
+ messageQueue;
805
948
  constructor(workingDirectory) {
806
949
  if (workingDirectory) {
807
950
  this.workingDirectory = workingDirectory;
@@ -816,17 +959,42 @@ var ClaudeManager = class {
816
959
  }
817
960
  this.historyFile = join2(homedir2(), ".replicas", "claude", "history.jsonl");
818
961
  this.initialized = this.initialize();
962
+ this.messageQueue = new MessageQueue(this.processMessageInternal.bind(this));
819
963
  }
820
964
  isProcessing() {
821
- return this.processing;
965
+ return this.messageQueue.isProcessing();
822
966
  }
967
+ /**
968
+ * Enqueue a message for processing. If not currently processing, starts immediately.
969
+ * If already processing, adds to queue.
970
+ * @returns Object with queued status, messageId, and position in queue
971
+ */
972
+ async enqueueMessage(message, model, customInstructions) {
973
+ await this.initialized;
974
+ return this.messageQueue.enqueue(message, model, customInstructions);
975
+ }
976
+ /**
977
+ * Get the current queue status
978
+ */
979
+ getQueueStatus() {
980
+ return this.messageQueue.getStatus();
981
+ }
982
+ /**
983
+ * Legacy sendMessage method - now uses the queue internally
984
+ * @deprecated Use enqueueMessage for better control over queue status
985
+ */
823
986
  async sendMessage(message, model, customInstructions) {
987
+ await this.enqueueMessage(message, model, customInstructions);
988
+ }
989
+ /**
990
+ * Internal method that actually processes the message
991
+ */
992
+ async processMessageInternal(message, model, customInstructions) {
824
993
  const linearSessionId = process.env.LINEAR_SESSION_ID;
825
994
  if (!message || !message.trim()) {
826
995
  throw new Error("Message cannot be empty");
827
996
  }
828
997
  await this.initialized;
829
- this.processing = true;
830
998
  try {
831
999
  const userMessage = {
832
1000
  type: "user",
@@ -874,7 +1042,6 @@ var ClaudeManager = class {
874
1042
  }
875
1043
  }
876
1044
  } finally {
877
- this.processing = false;
878
1045
  if (linearSessionId) {
879
1046
  const status = getGitStatus(this.workingDirectory);
880
1047
  monolithService.sendEvent({ type: "agent_turn_complete", payload: { linearSessionId, status } }).catch(() => {
@@ -893,7 +1060,7 @@ var ClaudeManager = class {
893
1060
  async getStatus() {
894
1061
  await this.initialized;
895
1062
  const status = {
896
- has_active_thread: this.processing,
1063
+ has_active_thread: this.messageQueue.isProcessing(),
897
1064
  thread_id: this.sessionId,
898
1065
  working_directory: this.workingDirectory
899
1066
  };
@@ -903,13 +1070,13 @@ var ClaudeManager = class {
903
1070
  await this.initialized;
904
1071
  const allEvents = await readJSONL(this.historyFile);
905
1072
  const events = allEvents.filter((event) => event.timestamp > since);
906
- const isComplete = !this.processing;
1073
+ const isComplete = !this.messageQueue.isProcessing();
907
1074
  return { events, isComplete };
908
1075
  }
909
1076
  async reset() {
910
1077
  await this.initialized;
911
1078
  this.sessionId = null;
912
- this.processing = false;
1079
+ this.messageQueue.reset();
913
1080
  try {
914
1081
  await rm(this.historyFile, { force: true });
915
1082
  } catch {
@@ -946,21 +1113,15 @@ claude.post("/send", async (c) => {
946
1113
  if (!message || typeof message !== "string") {
947
1114
  return c.json({ error: "Message is required and must be a string" }, 400);
948
1115
  }
949
- if (claudeManager.isProcessing()) {
950
- return c.json(
951
- {
952
- error: "A turn is already in progress. Please wait."
953
- },
954
- 400
955
- );
956
- }
957
- claudeManager.sendMessage(message, model, customInstructions).catch((error) => {
958
- console.error("[Claude Route] Error in background message processing:", error);
959
- });
960
- return c.json({
1116
+ const result = await claudeManager.enqueueMessage(message, model, customInstructions);
1117
+ const response = {
961
1118
  success: true,
962
- message: "Message sent successfully"
963
- });
1119
+ message: result.queued ? `Message queued at position ${result.position}` : "Message sent successfully",
1120
+ queued: result.queued,
1121
+ messageId: result.messageId,
1122
+ position: result.position
1123
+ };
1124
+ return c.json(response);
964
1125
  } catch (error) {
965
1126
  console.error("Error in /claude/send:", error);
966
1127
  return c.json(
@@ -1028,6 +1189,21 @@ claude.get("/status", async (c) => {
1028
1189
  );
1029
1190
  }
1030
1191
  });
1192
+ claude.get("/queue", async (c) => {
1193
+ try {
1194
+ const queueStatus = claudeManager.getQueueStatus();
1195
+ return c.json(queueStatus);
1196
+ } catch (error) {
1197
+ console.error("Error in /claude/queue:", error);
1198
+ return c.json(
1199
+ {
1200
+ error: "Failed to retrieve queue status",
1201
+ details: error instanceof Error ? error.message : "Unknown error"
1202
+ },
1203
+ 500
1204
+ );
1205
+ }
1206
+ });
1031
1207
  claude.post("/reset", async (c) => {
1032
1208
  try {
1033
1209
  await claudeManager.reset();
@@ -1128,9 +1304,186 @@ var GitHubTokenManager = class {
1128
1304
  };
1129
1305
  var githubTokenManager = new GitHubTokenManager();
1130
1306
 
1307
+ // src/services/claude-token-manager.ts
1308
+ import { promises as fs2 } from "fs";
1309
+ import path2 from "path";
1310
+ var ClaudeTokenManager = class {
1311
+ refreshInterval = null;
1312
+ REFRESH_INTERVAL_MS = 45 * 60 * 1e3;
1313
+ // 45 minutes
1314
+ async start() {
1315
+ const monolithUrl = process.env.MONOLITH_URL;
1316
+ const workspaceId = process.env.WORKSPACE_ID;
1317
+ const engineSecret = process.env.REPLICAS_ENGINE_SECRET;
1318
+ if (!monolithUrl || !workspaceId || !engineSecret) {
1319
+ console.log("[ClaudeTokenManager] Skipping: missing MONOLITH_URL, WORKSPACE_ID, or REPLICAS_ENGINE_SECRET");
1320
+ return;
1321
+ }
1322
+ console.log("[ClaudeTokenManager] Starting token refresh service");
1323
+ await this.refreshCredentials();
1324
+ this.refreshInterval = setInterval(() => {
1325
+ this.refreshCredentials().catch((error) => {
1326
+ console.error("[ClaudeTokenManager] Scheduled refresh failed:", error);
1327
+ });
1328
+ }, this.REFRESH_INTERVAL_MS);
1329
+ console.log("[ClaudeTokenManager] Token refresh scheduled every 45 minutes");
1330
+ }
1331
+ stop() {
1332
+ if (this.refreshInterval) {
1333
+ clearInterval(this.refreshInterval);
1334
+ this.refreshInterval = null;
1335
+ console.log("[ClaudeTokenManager] Stopped");
1336
+ }
1337
+ }
1338
+ async refreshCredentials() {
1339
+ const monolithUrl = process.env.MONOLITH_URL;
1340
+ const workspaceId = process.env.WORKSPACE_ID;
1341
+ const engineSecret = process.env.REPLICAS_ENGINE_SECRET;
1342
+ if (!monolithUrl || !workspaceId || !engineSecret) {
1343
+ console.log("[ClaudeTokenManager] Refresh skipped: missing configuration");
1344
+ return;
1345
+ }
1346
+ console.log("[ClaudeTokenManager] Refreshing Claude credentials...");
1347
+ try {
1348
+ const response = await fetch(`${monolithUrl}/v1/engine/claude/refresh-credentials`, {
1349
+ method: "POST",
1350
+ headers: {
1351
+ "Authorization": `Bearer ${engineSecret}`,
1352
+ "X-Workspace-Id": workspaceId,
1353
+ "Content-Type": "application/json"
1354
+ }
1355
+ });
1356
+ if (!response.ok) {
1357
+ const errorText = await response.text();
1358
+ throw new Error(`Credentials refresh failed: ${response.status} ${errorText}`);
1359
+ }
1360
+ const data = await response.json();
1361
+ await this.updateClaudeCredentials(data);
1362
+ console.log(`[ClaudeTokenManager] Credentials refreshed successfully, expires at ${data.expiresAt}`);
1363
+ } catch (error) {
1364
+ console.error("[ClaudeTokenManager] Failed to refresh credentials:", error);
1365
+ }
1366
+ }
1367
+ async updateClaudeCredentials(credentials) {
1368
+ const workspaceHome = process.env.WORKSPACE_HOME || process.env.HOME;
1369
+ if (!workspaceHome) {
1370
+ console.warn("[ClaudeTokenManager] No WORKSPACE_HOME or HOME set, skipping credentials update");
1371
+ return;
1372
+ }
1373
+ const claudeDir = path2.join(workspaceHome, ".claude");
1374
+ const credentialsPath = path2.join(claudeDir, ".credentials.json");
1375
+ const claudeCliConfig = {
1376
+ claudeAiOauth: {
1377
+ accessToken: credentials.accessToken,
1378
+ refreshToken: credentials.refreshToken,
1379
+ expiresAt: new Date(credentials.expiresAt).getTime(),
1380
+ scopes: credentials.scopes,
1381
+ subscriptionType: credentials.subscriptionType
1382
+ }
1383
+ };
1384
+ try {
1385
+ await fs2.mkdir(claudeDir, { recursive: true, mode: 448 });
1386
+ await fs2.writeFile(credentialsPath, JSON.stringify(claudeCliConfig, null, 2), { mode: 384 });
1387
+ console.log(`[ClaudeTokenManager] Updated ${credentialsPath}`);
1388
+ } catch (error) {
1389
+ console.error("[ClaudeTokenManager] Failed to update credentials file:", error);
1390
+ }
1391
+ }
1392
+ };
1393
+ var claudeTokenManager = new ClaudeTokenManager();
1394
+
1395
+ // src/services/codex-token-manager.ts
1396
+ import { promises as fs3 } from "fs";
1397
+ import path3 from "path";
1398
+ var CodexTokenManager = class {
1399
+ refreshInterval = null;
1400
+ REFRESH_INTERVAL_MS = 45 * 60 * 1e3;
1401
+ // 45 minutes
1402
+ async start() {
1403
+ const monolithUrl = process.env.MONOLITH_URL;
1404
+ const workspaceId = process.env.WORKSPACE_ID;
1405
+ const engineSecret = process.env.REPLICAS_ENGINE_SECRET;
1406
+ if (!monolithUrl || !workspaceId || !engineSecret) {
1407
+ console.log("[CodexTokenManager] Skipping: missing MONOLITH_URL, WORKSPACE_ID, or REPLICAS_ENGINE_SECRET");
1408
+ return;
1409
+ }
1410
+ console.log("[CodexTokenManager] Starting token refresh service");
1411
+ await this.refreshCredentials();
1412
+ this.refreshInterval = setInterval(() => {
1413
+ this.refreshCredentials().catch((error) => {
1414
+ console.error("[CodexTokenManager] Scheduled refresh failed:", error);
1415
+ });
1416
+ }, this.REFRESH_INTERVAL_MS);
1417
+ console.log("[CodexTokenManager] Token refresh scheduled every 45 minutes");
1418
+ }
1419
+ stop() {
1420
+ if (this.refreshInterval) {
1421
+ clearInterval(this.refreshInterval);
1422
+ this.refreshInterval = null;
1423
+ console.log("[CodexTokenManager] Stopped");
1424
+ }
1425
+ }
1426
+ async refreshCredentials() {
1427
+ const monolithUrl = process.env.MONOLITH_URL;
1428
+ const workspaceId = process.env.WORKSPACE_ID;
1429
+ const engineSecret = process.env.REPLICAS_ENGINE_SECRET;
1430
+ if (!monolithUrl || !workspaceId || !engineSecret) {
1431
+ console.log("[CodexTokenManager] Refresh skipped: missing configuration");
1432
+ return;
1433
+ }
1434
+ console.log("[CodexTokenManager] Refreshing Codex credentials...");
1435
+ try {
1436
+ const response = await fetch(`${monolithUrl}/v1/engine/codex/refresh-credentials`, {
1437
+ method: "POST",
1438
+ headers: {
1439
+ "Authorization": `Bearer ${engineSecret}`,
1440
+ "X-Workspace-Id": workspaceId,
1441
+ "Content-Type": "application/json"
1442
+ }
1443
+ });
1444
+ if (!response.ok) {
1445
+ const errorText = await response.text();
1446
+ throw new Error(`Credentials refresh failed: ${response.status} ${errorText}`);
1447
+ }
1448
+ const data = await response.json();
1449
+ await this.updateCodexCredentials(data);
1450
+ console.log(`[CodexTokenManager] Credentials refreshed successfully, expires at ${data.expiresAt}`);
1451
+ } catch (error) {
1452
+ console.error("[CodexTokenManager] Failed to refresh credentials:", error);
1453
+ }
1454
+ }
1455
+ async updateCodexCredentials(credentials) {
1456
+ const workspaceHome = process.env.WORKSPACE_HOME || process.env.HOME;
1457
+ if (!workspaceHome) {
1458
+ console.warn("[CodexTokenManager] No WORKSPACE_HOME or HOME set, skipping credentials update");
1459
+ return;
1460
+ }
1461
+ const codexDir = path3.join(workspaceHome, ".codex");
1462
+ const authPath = path3.join(codexDir, "auth.json");
1463
+ const codexAuthConfig = {
1464
+ OPENAI_API_KEY: null,
1465
+ tokens: {
1466
+ id_token: credentials.idToken,
1467
+ access_token: credentials.accessToken,
1468
+ refresh_token: credentials.refreshToken,
1469
+ account_id: credentials.accountId
1470
+ },
1471
+ last_refresh: (/* @__PURE__ */ new Date()).toISOString()
1472
+ };
1473
+ try {
1474
+ await fs3.mkdir(codexDir, { recursive: true, mode: 448 });
1475
+ await fs3.writeFile(authPath, JSON.stringify(codexAuthConfig, null, 2), { mode: 384 });
1476
+ console.log(`[CodexTokenManager] Updated ${authPath}`);
1477
+ } catch (error) {
1478
+ console.error("[CodexTokenManager] Failed to update credentials file:", error);
1479
+ }
1480
+ }
1481
+ };
1482
+ var codexTokenManager = new CodexTokenManager();
1483
+
1131
1484
  // src/services/git-init.ts
1132
1485
  import { existsSync } from "fs";
1133
- import path2 from "path";
1486
+ import path4 from "path";
1134
1487
  var initializedBranch = null;
1135
1488
  function findAvailableBranchName(baseName, cwd) {
1136
1489
  if (!branchExists(baseName, cwd)) {
@@ -1164,7 +1517,7 @@ async function initializeGitRepository() {
1164
1517
  error: "No WORKSPACE_NAME environment variable set"
1165
1518
  };
1166
1519
  }
1167
- const repoPath = path2.join(workspaceHome, "workspaces", repoName);
1520
+ const repoPath = path4.join(workspaceHome, "workspaces", repoName);
1168
1521
  if (!existsSync(repoPath)) {
1169
1522
  console.log(`[GitInit] Repository directory does not exist: ${repoPath}`);
1170
1523
  console.log("[GitInit] Waiting for initializer to clone the repository...");
@@ -1173,7 +1526,7 @@ async function initializeGitRepository() {
1173
1526
  branch: null
1174
1527
  };
1175
1528
  }
1176
- if (!existsSync(path2.join(repoPath, ".git"))) {
1529
+ if (!existsSync(path4.join(repoPath, ".git"))) {
1177
1530
  return {
1178
1531
  success: false,
1179
1532
  branch: null,
@@ -1296,6 +1649,8 @@ serve(
1296
1649
  console.warn(`Git initialization warning: ${gitResult.error}`);
1297
1650
  }
1298
1651
  await githubTokenManager.start();
1652
+ await claudeTokenManager.start();
1653
+ await codexTokenManager.start();
1299
1654
  const monolithService2 = new MonolithService();
1300
1655
  await monolithService2.sendEvent({ type: "workspace_ready", payload: {} });
1301
1656
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",