@rely-ai/caliber 1.40.4 → 1.41.1

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/bin.js +160 -8
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -2720,7 +2720,8 @@ function isCursorAgentAvailable() {
2720
2720
  function isCursorLoggedIn() {
2721
2721
  try {
2722
2722
  const result = execSync5(`${AGENT_BIN} status`, {
2723
- stdio: ["ignore", "pipe", "ignore"],
2723
+ input: "",
2724
+ stdio: ["pipe", "pipe", "pipe"],
2724
2725
  timeout: 5e3
2725
2726
  });
2726
2727
  return !result.toString().includes("not logged in");
@@ -2891,7 +2892,8 @@ function isClaudeCliLoggedIn() {
2891
2892
  if (cachedLoggedIn !== null) return cachedLoggedIn;
2892
2893
  try {
2893
2894
  const result = execSync6(`${CLAUDE_CLI_BIN} auth status`, {
2894
- stdio: ["ignore", "pipe", "pipe"],
2895
+ input: "",
2896
+ stdio: ["pipe", "pipe", "pipe"],
2895
2897
  timeout: 5e3
2896
2898
  });
2897
2899
  const output = result.toString().trim();
@@ -4945,6 +4947,37 @@ var CORE_MAX_TOKENS = 16e3;
4945
4947
  var GENERATION_MAX_TOKENS = 64e3;
4946
4948
  var MODEL_MAX_OUTPUT_TOKENS = 128e3;
4947
4949
  var MAX_RETRIES2 = 5;
4950
+ var DEFAULT_INACTIVITY_TIMEOUT_MS = 12e4;
4951
+ var DEFAULT_TOTAL_TIMEOUT_MS = 6e5;
4952
+ function parseEnvTimeout(envVar, defaultMs, minMs = 5e3) {
4953
+ const val = process.env[envVar];
4954
+ if (!val) return defaultMs;
4955
+ const parsed = parseInt(val, 10);
4956
+ if (!Number.isFinite(parsed) || parsed < minMs) return defaultMs;
4957
+ return parsed;
4958
+ }
4959
+ function buildDiagnostic(stopReason, raw, charsReceived) {
4960
+ if (stopReason === "timeout_inactivity") {
4961
+ const timeoutSec = Math.round(
4962
+ parseEnvTimeout("CALIBER_STREAM_INACTIVITY_TIMEOUT_MS", DEFAULT_INACTIVITY_TIMEOUT_MS) / 1e3
4963
+ );
4964
+ if (charsReceived === 0) {
4965
+ return `Model produced no output for ${timeoutSec}s. Check your API key and model name, or increase timeout with CALIBER_STREAM_INACTIVITY_TIMEOUT_MS.`;
4966
+ }
4967
+ return `Model stopped responding for ${timeoutSec}s after producing ${charsReceived} chars. The model may be stuck. Try a different model or increase timeout with CALIBER_STREAM_INACTIVITY_TIMEOUT_MS.`;
4968
+ }
4969
+ if (stopReason === "timeout_total") {
4970
+ const timeoutSec = Math.round(
4971
+ parseEnvTimeout("CALIBER_GENERATION_TIMEOUT_MS", DEFAULT_TOTAL_TIMEOUT_MS) / 1e3
4972
+ );
4973
+ return `Generation exceeded ${timeoutSec}s total time limit. Try a different model or increase timeout with CALIBER_GENERATION_TIMEOUT_MS.`;
4974
+ }
4975
+ if (!raw || raw.trim().length === 0) {
4976
+ return "Model produced no output. Check your API key and model name.";
4977
+ }
4978
+ return `Model responded but output was not valid JSON. First 200 chars:
4979
+ ${raw.slice(0, 200)}`;
4980
+ }
4948
4981
  function isTransientError2(error) {
4949
4982
  const msg = error.message.toLowerCase();
4950
4983
  return TRANSIENT_ERRORS.some((e) => msg.includes(e.toLowerCase()));
@@ -5126,18 +5159,59 @@ Generate the skill content following the instructions in the system prompt.`;
5126
5159
  async function streamGeneration(config) {
5127
5160
  const provider = getProvider();
5128
5161
  let attempt = 0;
5162
+ const inactivityTimeoutMs = parseEnvTimeout(
5163
+ "CALIBER_STREAM_INACTIVITY_TIMEOUT_MS",
5164
+ DEFAULT_INACTIVITY_TIMEOUT_MS
5165
+ );
5166
+ const totalTimeoutMs = parseEnvTimeout("CALIBER_GENERATION_TIMEOUT_MS", DEFAULT_TOTAL_TIMEOUT_MS);
5167
+ let totalTimedOut = false;
5168
+ let totalResolve = null;
5169
+ const totalTimer = setTimeout(() => {
5170
+ totalTimedOut = true;
5171
+ if (config.callbacks) config.callbacks.onError(buildDiagnostic("timeout_total", "", 0));
5172
+ if (totalResolve) {
5173
+ totalResolve({ setup: null, raw: "", stopReason: "timeout_total" });
5174
+ totalResolve = null;
5175
+ }
5176
+ }, totalTimeoutMs);
5129
5177
  const attemptGeneration = async () => {
5178
+ if (totalTimedOut) {
5179
+ return { setup: null, raw: "", stopReason: "timeout_total" };
5180
+ }
5130
5181
  attempt++;
5131
5182
  const maxTokensForAttempt = Math.min(
5132
5183
  config.baseMaxTokens + attempt * config.tokenIncrement,
5133
5184
  config.maxTokensCap
5134
5185
  );
5135
5186
  return new Promise((resolve3) => {
5187
+ totalResolve = resolve3;
5136
5188
  let preJsonBuffer = "";
5137
5189
  let jsonContent = "";
5138
5190
  let inJson = false;
5139
5191
  let sentStatuses = 0;
5140
5192
  let stopReason = null;
5193
+ let charsReceived = 0;
5194
+ let settled = false;
5195
+ let inactivityTimer = null;
5196
+ function clearInactivityTimer() {
5197
+ if (inactivityTimer) {
5198
+ clearTimeout(inactivityTimer);
5199
+ inactivityTimer = null;
5200
+ }
5201
+ }
5202
+ function resetInactivityTimer() {
5203
+ if (inactivityTimer) clearTimeout(inactivityTimer);
5204
+ inactivityTimer = setTimeout(() => {
5205
+ if (settled) return;
5206
+ settled = true;
5207
+ clearInactivityTimer();
5208
+ const raw = preJsonBuffer + jsonContent;
5209
+ if (config.callbacks)
5210
+ config.callbacks.onError(buildDiagnostic("timeout_inactivity", raw, charsReceived));
5211
+ resolve3({ setup: null, raw, stopReason: "timeout_inactivity" });
5212
+ }, inactivityTimeoutMs);
5213
+ }
5214
+ resetInactivityTimer();
5141
5215
  provider.stream(
5142
5216
  {
5143
5217
  system: config.systemPrompt,
@@ -5146,6 +5220,9 @@ async function streamGeneration(config) {
5146
5220
  },
5147
5221
  {
5148
5222
  onText: (text) => {
5223
+ if (settled || totalTimedOut) return;
5224
+ charsReceived += text.length;
5225
+ resetInactivityTimer();
5149
5226
  if (!inJson) {
5150
5227
  preJsonBuffer += text;
5151
5228
  const lines = preJsonBuffer.split("\n");
@@ -5173,6 +5250,9 @@ async function streamGeneration(config) {
5173
5250
  }
5174
5251
  },
5175
5252
  onEnd: (meta) => {
5253
+ clearInactivityTimer();
5254
+ if (settled || totalTimedOut) return;
5255
+ settled = true;
5176
5256
  stopReason = meta?.stopReason ?? null;
5177
5257
  let setup = null;
5178
5258
  let jsonToParse = (jsonContent || preJsonBuffer).replace(/```\s*$/g, "").trim();
@@ -5215,23 +5295,37 @@ async function streamGeneration(config) {
5215
5295
  }
5216
5296
  },
5217
5297
  onError: (error) => {
5298
+ clearInactivityTimer();
5299
+ if (settled || totalTimedOut) return;
5218
5300
  if (isTransientError2(error) && attempt < MAX_RETRIES2) {
5301
+ settled = true;
5219
5302
  if (config.callbacks)
5220
5303
  config.callbacks.onStatus("Connection interrupted, retrying...");
5221
5304
  setTimeout(() => attemptGeneration().then(resolve3), 2e3);
5222
5305
  return;
5223
5306
  }
5307
+ settled = true;
5224
5308
  if (config.callbacks) config.callbacks.onError(error.message);
5225
5309
  resolve3({ setup: null, raw: error.message, stopReason: "error" });
5226
5310
  }
5227
5311
  }
5228
5312
  ).catch((error) => {
5313
+ clearInactivityTimer();
5314
+ if (settled || totalTimedOut) return;
5315
+ settled = true;
5229
5316
  if (config.callbacks) config.callbacks.onError(error.message);
5230
5317
  resolve3({ setup: null, raw: error.message, stopReason: "error" });
5231
5318
  });
5232
5319
  });
5233
5320
  };
5234
- return attemptGeneration();
5321
+ try {
5322
+ const result = await attemptGeneration();
5323
+ clearTimeout(totalTimer);
5324
+ return totalTimedOut ? { setup: null, raw: result.raw, stopReason: "timeout_total" } : result;
5325
+ } catch (err) {
5326
+ clearTimeout(totalTimer);
5327
+ throw err;
5328
+ }
5235
5329
  }
5236
5330
  async function generateCore(fingerprint, targetAgent, prompt, callbacks, failingChecks, currentScore, passingChecks) {
5237
5331
  const userMessage = buildGeneratePrompt(
@@ -9501,6 +9595,10 @@ import fs30 from "fs";
9501
9595
  // src/ai/refine.ts
9502
9596
  async function refineSetup(currentSetup, message, conversationHistory, callbacks) {
9503
9597
  const provider = getProvider();
9598
+ const inactivityTimeoutMs = parseEnvTimeout(
9599
+ "CALIBER_STREAM_INACTIVITY_TIMEOUT_MS",
9600
+ DEFAULT_INACTIVITY_TIMEOUT_MS
9601
+ );
9504
9602
  const prompt = `Current setup:
9505
9603
  ${JSON.stringify(currentSetup, null, 2)}
9506
9604
 
@@ -9509,6 +9607,25 @@ User request: ${message}
9509
9607
  Return the complete updated AgentSetup JSON incorporating the user's changes. Respond with ONLY the JSON.`;
9510
9608
  return new Promise((resolve3) => {
9511
9609
  let buffer = "";
9610
+ let settled = false;
9611
+ let inactivityTimer = null;
9612
+ function clearInactivityTimer() {
9613
+ if (inactivityTimer) {
9614
+ clearTimeout(inactivityTimer);
9615
+ inactivityTimer = null;
9616
+ }
9617
+ }
9618
+ function resetInactivityTimer() {
9619
+ clearInactivityTimer();
9620
+ inactivityTimer = setTimeout(() => {
9621
+ if (settled) return;
9622
+ settled = true;
9623
+ const msg = buffer.length === 0 ? "Model produced no output. Try a different model." : "Model stopped responding. Try rephrasing your request or using a different model.";
9624
+ if (callbacks) callbacks.onError(msg);
9625
+ resolve3(null);
9626
+ }, inactivityTimeoutMs);
9627
+ }
9628
+ resetInactivityTimer();
9512
9629
  provider.stream(
9513
9630
  {
9514
9631
  system: REFINE_SYSTEM_PROMPT,
@@ -9518,9 +9635,14 @@ Return the complete updated AgentSetup JSON incorporating the user's changes. Re
9518
9635
  },
9519
9636
  {
9520
9637
  onText: (text) => {
9638
+ if (settled) return;
9521
9639
  buffer += text;
9640
+ resetInactivityTimer();
9522
9641
  },
9523
9642
  onEnd: () => {
9643
+ clearInactivityTimer();
9644
+ if (settled) return;
9645
+ settled = true;
9524
9646
  const cleaned = stripMarkdownFences(buffer);
9525
9647
  const jsonStart = cleaned.indexOf("{");
9526
9648
  const jsonToParse = jsonStart !== -1 ? cleaned.slice(jsonStart) : cleaned;
@@ -9529,16 +9651,23 @@ Return the complete updated AgentSetup JSON incorporating the user's changes. Re
9529
9651
  if (callbacks) callbacks.onComplete(setup);
9530
9652
  resolve3(setup);
9531
9653
  } catch {
9532
- if (callbacks) callbacks.onError("Failed to parse AI response. Try rephrasing your request.");
9654
+ if (callbacks)
9655
+ callbacks.onError("Failed to parse AI response. Try rephrasing your request.");
9533
9656
  resolve3(null);
9534
9657
  }
9535
9658
  },
9536
9659
  onError: (error) => {
9660
+ clearInactivityTimer();
9661
+ if (settled) return;
9662
+ settled = true;
9537
9663
  if (callbacks) callbacks.onError(error.message);
9538
9664
  resolve3(null);
9539
9665
  }
9540
9666
  }
9541
9667
  ).catch((error) => {
9668
+ clearInactivityTimer();
9669
+ if (settled) return;
9670
+ settled = true;
9542
9671
  if (callbacks) callbacks.onError(error.message);
9543
9672
  resolve3(null);
9544
9673
  });
@@ -10033,6 +10162,18 @@ function writeErrorLog(config, rawOutput, error, stopReason) {
10033
10162
  lines.push("## Error", "```", error, "```", "");
10034
10163
  }
10035
10164
  lines.push("## Raw LLM Output", "```", rawOutput || "(empty)", "```");
10165
+ if (stopReason?.startsWith("timeout")) {
10166
+ lines.push("", "## Troubleshooting", "");
10167
+ lines.push("This failure was caused by a timeout. You can adjust timeouts with:");
10168
+ lines.push("```bash");
10169
+ lines.push("# Increase inactivity timeout (default: 120s)");
10170
+ lines.push("export CALIBER_STREAM_INACTIVITY_TIMEOUT_MS=180000");
10171
+ lines.push("");
10172
+ lines.push("# Increase total generation timeout (default: 600s)");
10173
+ lines.push("export CALIBER_GENERATION_TIMEOUT_MS=900000");
10174
+ lines.push("```");
10175
+ lines.push("", "If timeouts persist, try a different model.");
10176
+ }
10036
10177
  fs32.mkdirSync(path26.join(process.cwd(), ".caliber"), { recursive: true });
10037
10178
  fs32.writeFileSync(logPath, lines.join("\n"));
10038
10179
  console.log(chalk13.dim(`
@@ -10049,7 +10190,9 @@ async function evaluateDismissals(failingChecks, fingerprint) {
10049
10190
  suggestion: c.suggestion
10050
10191
  }));
10051
10192
  const hasBuildFiles = fingerprint.fileTree.some(
10052
- (f) => /^(package\.json|Makefile|Cargo\.toml|go\.mod|pyproject\.toml|requirements\.txt|build\.gradle|pom\.xml)$/i.test(f.split("/").pop() || "")
10193
+ (f) => /^(package\.json|Makefile|Cargo\.toml|go\.mod|pyproject\.toml|requirements\.txt|build\.gradle|pom\.xml)$/i.test(
10194
+ f.split("/").pop() || ""
10195
+ )
10053
10196
  );
10054
10197
  const topFiles = fingerprint.fileTree.slice(0, 30).join(", ");
10055
10198
  try {
@@ -10284,8 +10427,16 @@ async function initCommand(options) {
10284
10427
  installSessionStartHook();
10285
10428
  console.log(` ${chalk14.green("\u2713")} Freshness hook \u2014 warns when configs are stale`);
10286
10429
  if (IS_WINDOWS5) {
10287
- console.log(chalk14.yellow("\n Note: hooks use shell syntax and require Git Bash (included with Git for Windows)."));
10288
- console.log(chalk14.dim(" If hooks don't run, ensure Git for Windows is installed and git is using its bundled sh."));
10430
+ console.log(
10431
+ chalk14.yellow(
10432
+ "\n Note: hooks use shell syntax and require Git Bash (included with Git for Windows)."
10433
+ )
10434
+ );
10435
+ console.log(
10436
+ chalk14.dim(
10437
+ " If hooks don't run, ensure Git for Windows is installed and git is using its bundled sh."
10438
+ )
10439
+ );
10289
10440
  }
10290
10441
  const { ensureBuiltinSkills: ensureBuiltinSkills2 } = await Promise.resolve().then(() => (init_builtin_skills(), builtin_skills_exports));
10291
10442
  for (const agent of targetAgent) {
@@ -10584,7 +10735,8 @@ async function initCommand(options) {
10584
10735
  rawOutput = result.raw;
10585
10736
  genStopReason = result.stopReason;
10586
10737
  if (!generatedSetup) {
10587
- display.update(TASK_CONFIG, "failed", "Could not parse LLM response");
10738
+ const diagnostic = buildDiagnostic(genStopReason, rawOutput, rawOutput?.length ?? 0);
10739
+ display.update(TASK_CONFIG, "failed", diagnostic.split("\n")[0].slice(0, 80));
10588
10740
  display.update(TASK_SKILLS_GEN, "failed", "Skipped");
10589
10741
  return;
10590
10742
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rely-ai/caliber",
3
- "version": "1.40.4",
3
+ "version": "1.41.1",
4
4
  "description": "AI context infrastructure for coding agents — keeps CLAUDE.md, Cursor rules, and skills in sync as your codebase evolves",
5
5
  "type": "module",
6
6
  "bin": {