@blockrun/runcode 2.5.1 → 2.5.2

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.
@@ -179,7 +179,9 @@ const DIRECT_COMMANDS = {
179
179
  catch {
180
180
  checks.push('⚠ ripgrep not found (using native grep fallback)');
181
181
  }
182
- checks.push(fs.existsSync(path.join(BLOCKRUN_DIR, 'wallet.json')) ? '✓ wallet configured' : '⚠ no wallet — run: runcode setup');
182
+ const hasWallet = fs.existsSync(path.join(BLOCKRUN_DIR, 'wallet.json'))
183
+ || fs.existsSync(path.join(BLOCKRUN_DIR, 'solana-wallet.json'));
184
+ checks.push(hasWallet ? '✓ wallet configured' : '⚠ no wallet — run: runcode setup');
183
185
  checks.push(fs.existsSync(path.join(BLOCKRUN_DIR, 'runcode-config.json')) ? '✓ config file exists' : '⚠ no config — using defaults');
184
186
  // Check MCP
185
187
  const { listMcpServers } = await import('../mcp/client.js');
package/dist/agent/llm.js CHANGED
@@ -64,9 +64,16 @@ export class ModelClient {
64
64
  }
65
65
  if (!response.ok) {
66
66
  const errorBody = await response.text().catch(() => 'unknown error');
67
+ // Extract human-readable message from JSON error bodies ({"error":{"message":"..."}})
68
+ let message = errorBody;
69
+ try {
70
+ const parsed = JSON.parse(errorBody);
71
+ message = parsed?.error?.message || parsed?.message || errorBody;
72
+ }
73
+ catch { /* not JSON — use raw text */ }
67
74
  yield {
68
75
  kind: 'error',
69
- payload: { status: response.status, message: errorBody },
76
+ payload: { status: response.status, message },
70
77
  };
71
78
  return;
72
79
  }
@@ -396,18 +396,21 @@ export async function interactiveSession(config, getUserInput, onEvent, onAbortR
396
396
  onEvent({ kind: 'turn_done', reason: 'error', error: errMsg + suggestion });
397
397
  break;
398
398
  }
399
+ // When API doesn't return input tokens (some models return 0), estimate from history
400
+ const inputTokens = usage.inputTokens > 0
401
+ ? usage.inputTokens
402
+ : estimateHistoryTokens(history);
399
403
  // Anchor token tracking to actual API counts
400
- updateActualTokens(usage.inputTokens, usage.outputTokens, history.length);
404
+ updateActualTokens(inputTokens, usage.outputTokens, history.length);
401
405
  onEvent({
402
406
  kind: 'usage',
403
- inputTokens: usage.inputTokens,
407
+ inputTokens,
404
408
  outputTokens: usage.outputTokens,
405
409
  model: config.model,
406
410
  });
407
411
  // Record usage for stats tracking (runcode stats command)
408
- // Rough cost estimate: use typical pricing if unknown
409
- const costEstimate = estimateCost(config.model, usage.inputTokens, usage.outputTokens);
410
- recordUsage(config.model, usage.inputTokens, usage.outputTokens, costEstimate, 0);
412
+ const costEstimate = estimateCost(config.model, inputTokens, usage.outputTokens);
413
+ recordUsage(config.model, inputTokens, usage.outputTokens, costEstimate, 0);
411
414
  // ── Max output tokens recovery ──
412
415
  if (stopReason === 'max_tokens' && recoveryAttempts < 3) {
413
416
  recoveryAttempts++;
@@ -177,10 +177,17 @@ export class PermissionManager {
177
177
  }
178
178
  // ─── Helpers ───────────────────────────────────────────────────────────────
179
179
  function askQuestion(prompt) {
180
+ // Non-TTY (piped/scripted) input: cannot ask interactively — auto-allow.
181
+ // The caller (permissionMode logic in start.ts) already routes piped sessions
182
+ // to trust mode, so this path is rarely hit. Guard here for safety.
183
+ if (!process.stdin.isTTY) {
184
+ process.stderr.write(prompt + 'y (auto-approved: non-interactive mode)\n');
185
+ return Promise.resolve('y');
186
+ }
180
187
  const rl = readline.createInterface({
181
188
  input: process.stdin,
182
189
  output: process.stderr,
183
- terminal: process.stdin.isTTY ?? false,
190
+ terminal: true,
184
191
  });
185
192
  return new Promise((resolve) => {
186
193
  let answered = false;
@@ -191,7 +198,7 @@ function askQuestion(prompt) {
191
198
  });
192
199
  rl.on('close', () => {
193
200
  if (!answered)
194
- resolve('n'); // Default deny on EOF (piped input) for safety
201
+ resolve('n'); // Default deny on EOF for safety
195
202
  });
196
203
  });
197
204
  }
@@ -123,7 +123,9 @@ export async function startCommand(options) {
123
123
  capabilities,
124
124
  maxTurns: 100,
125
125
  workingDir: workDir,
126
- permissionMode: options.trust ? 'trust' : 'default',
126
+ // Non-TTY (piped) input = scripted mode → trust all tools automatically.
127
+ // Interactive TTY = default mode (prompts for Bash/Write/Edit).
128
+ permissionMode: (options.trust || !process.stdin.isTTY) ? 'trust' : 'default',
127
129
  debug: options.debug,
128
130
  };
129
131
  // Use ink UI if TTY, fallback to basic readline for piped input
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/runcode",
3
- "version": "2.5.1",
3
+ "version": "2.5.2",
4
4
  "description": "RunCode — AI coding agent powered by 41+ models. Pay per use with USDC.",
5
5
  "type": "module",
6
6
  "bin": {