replicas-engine 0.1.60 → 0.1.61

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 +128 -3
  2. package/package.json +1 -1
package/dist/src/index.js CHANGED
@@ -78,7 +78,7 @@ var ENGINE_ENV = loadEngineEnv();
78
78
 
79
79
  // src/managers/base-refresh-manager.ts
80
80
  var BaseRefreshManager = class {
81
- constructor(managerName, intervalMs = 45 * 60 * 1e3) {
81
+ constructor(managerName, intervalMs = 15 * 60 * 1e3) {
82
82
  this.managerName = managerName;
83
83
  this.intervalMs = intervalMs;
84
84
  this.health = {
@@ -228,6 +228,28 @@ var ClaudeTokenManager = class extends BaseRefreshManager {
228
228
  await this.updateClaudeCredentials(data);
229
229
  console.log(`[ClaudeTokenManager] Credentials refreshed successfully, expires at ${data.expiresAt}`);
230
230
  }
231
+ /**
232
+ * Re-fetches credentials from the monolith after an auth failure is detected.
233
+ * With the 1-hour refresh threshold, the monolith will have already
234
+ * proactively refreshed the token, so this just pulls the latest.
235
+ *
236
+ * Returns true if credentials were successfully updated, false otherwise.
237
+ */
238
+ async fetchFreshCredentials() {
239
+ if (this.getSkipReason()) {
240
+ return false;
241
+ }
242
+ const config = this.getRuntimeConfig();
243
+ if (!config) return false;
244
+ try {
245
+ console.log("[ClaudeTokenManager] Fetching fresh credentials from monolith after auth failure...");
246
+ await this.doRefresh(config);
247
+ return true;
248
+ } catch (error) {
249
+ console.error("[ClaudeTokenManager] Failed to fetch fresh credentials:", error);
250
+ return false;
251
+ }
252
+ }
231
253
  async updateClaudeCredentials(credentials) {
232
254
  const workspaceHome = ENGINE_ENV.HOME_DIR;
233
255
  const claudeDir = path2.join(workspaceHome, ".claude");
@@ -839,6 +861,56 @@ import { homedir as homedir5 } from "os";
839
861
  import { exec } from "child_process";
840
862
  import { promisify as promisify2 } from "util";
841
863
 
864
+ // ../shared/src/pricing.ts
865
+ var PLANS = {
866
+ hobby: {
867
+ id: "hobby",
868
+ name: "Hobby",
869
+ monthlyPrice: 0,
870
+ seatPriceCents: 0,
871
+ creditsIncluded: 20,
872
+ features: ["20 hours of usage"]
873
+ },
874
+ developer: {
875
+ id: "developer",
876
+ name: "Developer",
877
+ monthlyPrice: 30,
878
+ seatPriceCents: 3e3,
879
+ creditsIncluded: 0,
880
+ features: ["Unlimited usage", "API access ($1/hr)"]
881
+ },
882
+ team: {
883
+ id: "team",
884
+ name: "Team",
885
+ monthlyPrice: 120,
886
+ seatPriceCents: 12e3,
887
+ creditsIncluded: 0,
888
+ features: [
889
+ "Unlimited usage",
890
+ "API access",
891
+ "Higher API rate limits",
892
+ "Warm hooks and pool access",
893
+ "Optional add-ons for higher resources, warm pools, rate limits, and SOC 2"
894
+ ]
895
+ },
896
+ enterprise: {
897
+ id: "enterprise",
898
+ name: "Enterprise",
899
+ monthlyPrice: 0,
900
+ seatPriceCents: 0,
901
+ creditsIncluded: 0,
902
+ features: [
903
+ "Unlimited usage",
904
+ "Custom API rates",
905
+ "Custom rate limits",
906
+ "Custom warm hooks and pools",
907
+ "SOC 2"
908
+ ]
909
+ }
910
+ };
911
+ var TEAM_PLAN = PLANS.team;
912
+ var ENTERPRISE_PLAN = PLANS.enterprise;
913
+
842
914
  // ../shared/src/sandbox.ts
843
915
  var SANDBOX_LIFECYCLE = {
844
916
  AUTO_STOP_MINUTES: 60,
@@ -2214,7 +2286,7 @@ var PromptStream = class {
2214
2286
  function isLinearThoughtEvent(event) {
2215
2287
  return event.content.type === "thought";
2216
2288
  }
2217
- var ClaudeManager = class extends CodingAgentManager {
2289
+ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
2218
2290
  historyFile;
2219
2291
  sessionId = null;
2220
2292
  activeQuery = null;
@@ -2233,9 +2305,28 @@ var ClaudeManager = class extends CodingAgentManager {
2233
2305
  }
2234
2306
  }
2235
2307
  /**
2236
- * Internal method that actually processes the message
2308
+ * Internal method that actually processes the message.
2309
+ * On auth failure, refreshes credentials and retries once.
2237
2310
  */
2238
2311
  async processMessageInternal(request) {
2312
+ try {
2313
+ await this.executeQuery(request);
2314
+ } catch (error) {
2315
+ if (_ClaudeManager.isAuthError(error)) {
2316
+ console.warn("[ClaudeManager] Auth failure detected, refreshing credentials and retrying...", error);
2317
+ const refreshed = await claudeTokenManager.fetchFreshCredentials();
2318
+ if (refreshed) {
2319
+ await this.executeQuery(request);
2320
+ return;
2321
+ }
2322
+ }
2323
+ throw error;
2324
+ }
2325
+ }
2326
+ /**
2327
+ * Executes a single query attempt against the Claude Agent SDK.
2328
+ */
2329
+ async executeQuery(request) {
2239
2330
  const {
2240
2331
  message,
2241
2332
  model,
@@ -2351,6 +2442,18 @@ var ClaudeManager = class extends CodingAgentManager {
2351
2442
  await this.onTurnComplete();
2352
2443
  }
2353
2444
  }
2445
+ /**
2446
+ * Determines if an error is an OAuth authentication failure from the Claude SDK.
2447
+ * Known patterns:
2448
+ * - "Not logged in · Please run /login"
2449
+ * - "authentication_failed"
2450
+ * - "unauthorized"
2451
+ */
2452
+ static isAuthError(error) {
2453
+ const msg = error instanceof Error ? error.message : String(error);
2454
+ const lower = msg.toLowerCase();
2455
+ return lower.includes("not logged in") || lower.includes("please run /login") || lower.includes("authentication_failed") || lower.includes("authentication failed");
2456
+ }
2354
2457
  async getHistory() {
2355
2458
  await this.initialized;
2356
2459
  const events = await readJSONL(this.historyFile);
@@ -2367,12 +2470,34 @@ var ClaudeManager = class extends CodingAgentManager {
2367
2470
  console.log(`[ClaudeManager] Restored session ID from persisted state: ${this.sessionId}`);
2368
2471
  }
2369
2472
  }
2473
+ /**
2474
+ * Checks if an SDK message indicates an OAuth authentication failure.
2475
+ * When detected, triggers a force-refresh of credentials from the monolith.
2476
+ */
2477
+ async checkForAuthFailure(message) {
2478
+ if (message.type === "assistant" && "error" in message && message.error === "authentication_failed") {
2479
+ console.warn("[ClaudeManager] Detected authentication_failed in assistant message, force-refreshing credentials...");
2480
+ await claudeTokenManager.fetchFreshCredentials();
2481
+ return;
2482
+ }
2483
+ if (message.type === "result" && "is_error" in message && message.is_error && "errors" in message) {
2484
+ const errors = message.errors ?? [];
2485
+ const hasAuthError = errors.some(
2486
+ (err) => err.toLowerCase().includes("authentication") || err.toLowerCase().includes("unauthorized") || err.toLowerCase().includes("not logged in") || err.toLowerCase().includes("login")
2487
+ );
2488
+ if (hasAuthError) {
2489
+ console.warn("[ClaudeManager] Detected auth-related error in result, force-refreshing credentials...");
2490
+ await claudeTokenManager.fetchFreshCredentials();
2491
+ }
2492
+ }
2493
+ }
2370
2494
  async handleMessage(message) {
2371
2495
  if ("session_id" in message && message.session_id && !this.sessionId) {
2372
2496
  this.sessionId = message.session_id;
2373
2497
  await this.onSaveSessionId(this.sessionId);
2374
2498
  console.log(`[ClaudeManager] Captured and persisted session ID: ${this.sessionId}`);
2375
2499
  }
2500
+ await this.checkForAuthFailure(message);
2376
2501
  await this.recordEvent(message);
2377
2502
  }
2378
2503
  async recordEvent(event) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.60",
3
+ "version": "0.1.61",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",