replicas-engine 0.1.17 → 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 +195 -12
  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;
@@ -1300,9 +1304,186 @@ var GitHubTokenManager = class {
1300
1304
  };
1301
1305
  var githubTokenManager = new GitHubTokenManager();
1302
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
+
1303
1484
  // src/services/git-init.ts
1304
1485
  import { existsSync } from "fs";
1305
- import path2 from "path";
1486
+ import path4 from "path";
1306
1487
  var initializedBranch = null;
1307
1488
  function findAvailableBranchName(baseName, cwd) {
1308
1489
  if (!branchExists(baseName, cwd)) {
@@ -1336,7 +1517,7 @@ async function initializeGitRepository() {
1336
1517
  error: "No WORKSPACE_NAME environment variable set"
1337
1518
  };
1338
1519
  }
1339
- const repoPath = path2.join(workspaceHome, "workspaces", repoName);
1520
+ const repoPath = path4.join(workspaceHome, "workspaces", repoName);
1340
1521
  if (!existsSync(repoPath)) {
1341
1522
  console.log(`[GitInit] Repository directory does not exist: ${repoPath}`);
1342
1523
  console.log("[GitInit] Waiting for initializer to clone the repository...");
@@ -1345,7 +1526,7 @@ async function initializeGitRepository() {
1345
1526
  branch: null
1346
1527
  };
1347
1528
  }
1348
- if (!existsSync(path2.join(repoPath, ".git"))) {
1529
+ if (!existsSync(path4.join(repoPath, ".git"))) {
1349
1530
  return {
1350
1531
  success: false,
1351
1532
  branch: null,
@@ -1468,6 +1649,8 @@ serve(
1468
1649
  console.warn(`Git initialization warning: ${gitResult.error}`);
1469
1650
  }
1470
1651
  await githubTokenManager.start();
1652
+ await claudeTokenManager.start();
1653
+ await codexTokenManager.start();
1471
1654
  const monolithService2 = new MonolithService();
1472
1655
  await monolithService2.sendEvent({ type: "workspace_ready", payload: {} });
1473
1656
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.17",
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",