@blockrun/franklin 3.6.6 → 3.6.7

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.
@@ -290,7 +290,7 @@ const DIRECT_COMMANDS = {
290
290
  const hasWallet = fs.existsSync(path.join(BLOCKRUN_DIR, 'wallet.json'))
291
291
  || fs.existsSync(path.join(BLOCKRUN_DIR, 'solana-wallet.json'));
292
292
  checks.push(hasWallet ? '✓ wallet configured' : '⚠ no wallet — run: runcode setup');
293
- checks.push(fs.existsSync(path.join(BLOCKRUN_DIR, 'runcode-config.json')) ? '✓ config file exists' : '⚠ no config — using defaults');
293
+ checks.push(fs.existsSync(path.join(BLOCKRUN_DIR, 'franklin-config.json')) || fs.existsSync(path.join(BLOCKRUN_DIR, 'runcode-config.json')) ? '✓ config file exists' : '⚠ no config — using defaults');
294
294
  // Check MCP
295
295
  const { listMcpServers } = await import('../mcp/client.js');
296
296
  const mcpServers = listMcpServers();
@@ -398,49 +398,6 @@ const DIRECT_COMMANDS = {
398
398
  ctx.onEvent({ kind: 'text_delta', text });
399
399
  emitDone(ctx);
400
400
  },
401
- '/wallet': async (ctx) => {
402
- const chain = (await import('../config.js')).loadChain();
403
- try {
404
- let address;
405
- let balance;
406
- const fetchTimeout = (ms) => new Promise((_, rej) => setTimeout(() => rej(new Error('timeout')), ms));
407
- if (chain === 'solana') {
408
- const { getOrCreateSolanaWallet, setupAgentSolanaWallet } = await import('@blockrun/llm');
409
- const w = await getOrCreateSolanaWallet();
410
- address = w.address;
411
- try {
412
- const client = await setupAgentSolanaWallet({ silent: true });
413
- const bal = await Promise.race([client.getBalance(), fetchTimeout(5000)]);
414
- balance = `$${bal.toFixed(2)} USDC`;
415
- }
416
- catch {
417
- balance = '(unavailable)';
418
- }
419
- }
420
- else {
421
- const { getOrCreateWallet, setupAgentWallet } = await import('@blockrun/llm');
422
- const w = getOrCreateWallet();
423
- address = w.address;
424
- try {
425
- const client = setupAgentWallet({ silent: true });
426
- const bal = await Promise.race([client.getBalance(), fetchTimeout(5000)]);
427
- balance = `$${bal.toFixed(2)} USDC`;
428
- }
429
- catch {
430
- balance = '(unavailable)';
431
- }
432
- }
433
- ctx.onEvent({ kind: 'text_delta', text: `**Wallet**\n` +
434
- ` Chain: ${chain}\n` +
435
- ` Address: ${address}\n` +
436
- ` Balance: ${balance}\n`
437
- });
438
- }
439
- catch (err) {
440
- ctx.onEvent({ kind: 'text_delta', text: `Wallet error: ${err.message}\n` });
441
- }
442
- emitDone(ctx);
443
- },
444
401
  '/clear': (ctx) => {
445
402
  ctx.history.length = 0;
446
403
  resetTokenAnchor();
@@ -693,6 +650,135 @@ export async function handleSlashCommand(input, ctx) {
693
650
  emitDone(ctx);
694
651
  return { handled: true };
695
652
  }
653
+ // /wallet — show wallet info, import, or export
654
+ if (input === '/wallet' || input.startsWith('/wallet ')) {
655
+ const chain = (await import('../config.js')).loadChain();
656
+ const args = input.slice(7).trim();
657
+ // /wallet export — show private key
658
+ if (args === 'export') {
659
+ try {
660
+ if (chain === 'solana') {
661
+ const { loadSolanaWallet, getOrCreateSolanaWallet } = await import('@blockrun/llm');
662
+ const key = loadSolanaWallet();
663
+ if (!key) {
664
+ ctx.onEvent({ kind: 'text_delta', text: 'No Solana wallet found. Run `/wallet` first.\n' });
665
+ emitDone(ctx);
666
+ return { handled: true };
667
+ }
668
+ const w = await getOrCreateSolanaWallet();
669
+ ctx.onEvent({ kind: 'text_delta', text: `**Wallet Export (Solana)**\n` +
670
+ ` Address: ${w.address}\n` +
671
+ ` Private Key: ${key}\n\n` +
672
+ `⚠️ Keep this key safe. Anyone with it controls your funds.\n`
673
+ });
674
+ }
675
+ else {
676
+ const { loadWallet, getOrCreateWallet } = await import('@blockrun/llm');
677
+ const key = loadWallet();
678
+ if (!key) {
679
+ ctx.onEvent({ kind: 'text_delta', text: 'No wallet found. Run `/wallet` first.\n' });
680
+ emitDone(ctx);
681
+ return { handled: true };
682
+ }
683
+ const w = getOrCreateWallet();
684
+ ctx.onEvent({ kind: 'text_delta', text: `**Wallet Export (Base)**\n` +
685
+ ` Address: ${w.address}\n` +
686
+ ` Private Key: ${key}\n\n` +
687
+ `⚠️ Keep this key safe. Anyone with it controls your funds.\n`
688
+ });
689
+ }
690
+ }
691
+ catch (err) {
692
+ ctx.onEvent({ kind: 'text_delta', text: `Export error: ${err.message}\n` });
693
+ }
694
+ emitDone(ctx);
695
+ return { handled: true };
696
+ }
697
+ // /wallet import <private-key>
698
+ if (args.startsWith('import')) {
699
+ const key = args.slice(6).trim();
700
+ if (!key) {
701
+ ctx.onEvent({ kind: 'text_delta', text: `**Usage:** \`/wallet import <private-key>\`\n\n` +
702
+ ` Base: \`/wallet import 0x...\` (hex, 66 chars)\n` +
703
+ ` Solana: \`/wallet import <bs58-key>\` (base58 encoded)\n`
704
+ });
705
+ emitDone(ctx);
706
+ return { handled: true };
707
+ }
708
+ try {
709
+ if (chain === 'solana') {
710
+ const { saveSolanaWallet, solanaPublicKey } = await import('@blockrun/llm');
711
+ const address = await solanaPublicKey(key);
712
+ saveSolanaWallet(key);
713
+ ctx.onEvent({ kind: 'text_delta', text: `**Wallet Imported (Solana)**\n` +
714
+ ` Address: ${address}\n` +
715
+ ` Saved to: ~/.blockrun/\n\n` +
716
+ `Restart Franklin to use the new wallet.\n`
717
+ });
718
+ }
719
+ else {
720
+ const { privateKeyToAccount } = await import('viem/accounts');
721
+ const { saveWallet } = await import('@blockrun/llm');
722
+ const account = privateKeyToAccount(key);
723
+ saveWallet(key);
724
+ ctx.onEvent({ kind: 'text_delta', text: `**Wallet Imported (Base)**\n` +
725
+ ` Address: ${account.address}\n` +
726
+ ` Saved to: ~/.blockrun/\n\n` +
727
+ `Restart Franklin to use the new wallet.\n`
728
+ });
729
+ }
730
+ }
731
+ catch (err) {
732
+ ctx.onEvent({ kind: 'text_delta', text: `Import error: ${err.message}\n` });
733
+ }
734
+ emitDone(ctx);
735
+ return { handled: true };
736
+ }
737
+ // /wallet (no args) — show wallet info
738
+ try {
739
+ let address;
740
+ let balance;
741
+ const fetchTimeout = (ms) => new Promise((_, rej) => setTimeout(() => rej(new Error('timeout')), ms));
742
+ if (chain === 'solana') {
743
+ const { getOrCreateSolanaWallet, setupAgentSolanaWallet } = await import('@blockrun/llm');
744
+ const w = await getOrCreateSolanaWallet();
745
+ address = w.address;
746
+ try {
747
+ const client = await setupAgentSolanaWallet({ silent: true });
748
+ const bal = await Promise.race([client.getBalance(), fetchTimeout(5000)]);
749
+ balance = `$${bal.toFixed(2)} USDC`;
750
+ }
751
+ catch {
752
+ balance = '(unavailable)';
753
+ }
754
+ }
755
+ else {
756
+ const { getOrCreateWallet, setupAgentWallet } = await import('@blockrun/llm');
757
+ const w = getOrCreateWallet();
758
+ address = w.address;
759
+ try {
760
+ const client = setupAgentWallet({ silent: true });
761
+ const bal = await Promise.race([client.getBalance(), fetchTimeout(5000)]);
762
+ balance = `$${bal.toFixed(2)} USDC`;
763
+ }
764
+ catch {
765
+ balance = '(unavailable)';
766
+ }
767
+ }
768
+ ctx.onEvent({ kind: 'text_delta', text: `**Wallet**\n` +
769
+ ` Chain: ${chain}\n` +
770
+ ` Address: ${address}\n` +
771
+ ` Balance: ${balance}\n\n` +
772
+ ` \`/wallet import <key>\` — import a personal wallet\n` +
773
+ ` \`/wallet export\` — show private key\n`
774
+ });
775
+ }
776
+ catch (err) {
777
+ ctx.onEvent({ kind: 'text_delta', text: `Wallet error: ${err.message}\n` });
778
+ }
779
+ emitDone(ctx);
780
+ return { handled: true };
781
+ }
696
782
  // /delete <...>
697
783
  if (input.startsWith('/delete ')) {
698
784
  const arg = input.slice('/delete '.length).trim();
@@ -2,7 +2,8 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import chalk from 'chalk';
4
4
  import { BLOCKRUN_DIR } from '../config.js';
5
- const CONFIG_FILE = path.join(BLOCKRUN_DIR, 'runcode-config.json');
5
+ const CONFIG_FILE = path.join(BLOCKRUN_DIR, 'franklin-config.json');
6
+ const LEGACY_CONFIG_FILE = path.join(BLOCKRUN_DIR, 'runcode-config.json');
6
7
  const VALID_KEYS = [
7
8
  'default-model',
8
9
  'sonnet-model',
@@ -21,7 +22,14 @@ export function loadConfig() {
21
22
  return JSON.parse(content);
22
23
  }
23
24
  catch {
24
- return {};
25
+ // Fall back to legacy config file
26
+ try {
27
+ const legacy = fs.readFileSync(LEGACY_CONFIG_FILE, 'utf-8');
28
+ return JSON.parse(legacy);
29
+ }
30
+ catch {
31
+ return {};
32
+ }
25
33
  }
26
34
  }
27
35
  function saveConfig(config) {
@@ -47,7 +55,7 @@ export function configCommand(action, keyOrUndefined, value) {
47
55
  console.log(chalk.dim(`\nConfig file: ${CONFIG_FILE}`));
48
56
  return;
49
57
  }
50
- console.log(chalk.bold('runcode config\n'));
58
+ console.log(chalk.bold('franklin config\n'));
51
59
  for (const [k, v] of entries) {
52
60
  console.log(` ${chalk.cyan(k)} = ${chalk.green(v)}`);
53
61
  }
@@ -56,7 +64,7 @@ export function configCommand(action, keyOrUndefined, value) {
56
64
  }
57
65
  if (action === 'get') {
58
66
  if (!keyOrUndefined) {
59
- console.log(chalk.red('Usage: runcode config get <key>'));
67
+ console.log(chalk.red('Usage: franklin config get <key>'));
60
68
  process.exit(1);
61
69
  }
62
70
  const config = loadConfig();
@@ -71,7 +79,7 @@ export function configCommand(action, keyOrUndefined, value) {
71
79
  }
72
80
  if (action === 'set') {
73
81
  if (!keyOrUndefined || value === undefined) {
74
- console.log(chalk.red('Usage: runcode config set <key> <value>'));
82
+ console.log(chalk.red('Usage: franklin config set <key> <value>'));
75
83
  process.exit(1);
76
84
  }
77
85
  if (!isValidKey(keyOrUndefined)) {
@@ -87,7 +95,7 @@ export function configCommand(action, keyOrUndefined, value) {
87
95
  }
88
96
  if (action === 'unset') {
89
97
  if (!keyOrUndefined) {
90
- console.log(chalk.red('Usage: runcode config unset <key>'));
98
+ console.log(chalk.red('Usage: franklin config unset <key>'));
91
99
  process.exit(1);
92
100
  }
93
101
  if (!isValidKey(keyOrUndefined)) {
@@ -102,6 +110,6 @@ export function configCommand(action, keyOrUndefined, value) {
102
110
  return;
103
111
  }
104
112
  console.log(chalk.red(`Unknown action: ${action}`));
105
- console.log('Usage: runcode config <set|get|unset|list> [key] [value]');
113
+ console.log('Usage: franklin config <set|get|unset|list> [key] [value]');
106
114
  process.exit(1);
107
115
  }
@@ -9,9 +9,9 @@ export async function setupCommand(chainArg) {
9
9
  console.log(chalk.yellow('Solana wallet already exists.'));
10
10
  console.log(`Address: ${chalk.cyan(wallets[0].publicKey)}`);
11
11
  console.log(chalk.dim('\nNext steps:'));
12
- console.log(chalk.dim(' runcode start — start coding'));
13
- console.log(chalk.dim(' runcode balance — check USDC balance'));
14
- console.log(chalk.dim(' runcode start -m free — use free models (no USDC needed)'));
12
+ console.log(chalk.dim(' franklin start — start coding'));
13
+ console.log(chalk.dim(' franklin balance — check USDC balance'));
14
+ console.log(chalk.dim(' franklin start -m free — use free models (no USDC needed)'));
15
15
  saveChain('solana');
16
16
  return;
17
17
  }
@@ -29,9 +29,9 @@ export async function setupCommand(chainArg) {
29
29
  console.log(chalk.yellow('Wallet already exists.'));
30
30
  console.log(`Address: ${chalk.cyan(wallets[0].address)}`);
31
31
  console.log(chalk.dim('\nNext steps:'));
32
- console.log(chalk.dim(' runcode start — start coding'));
33
- console.log(chalk.dim(' runcode balance — check USDC balance'));
34
- console.log(chalk.dim(' runcode start -m free — use free models (no USDC needed)'));
32
+ console.log(chalk.dim(' franklin start — start coding'));
33
+ console.log(chalk.dim(' franklin balance — check USDC balance'));
34
+ console.log(chalk.dim(' franklin start -m free — use free models (no USDC needed)'));
35
35
  saveChain('base');
36
36
  return;
37
37
  }
@@ -44,6 +44,6 @@ export async function setupCommand(chainArg) {
44
44
  console.log(`\nSend USDC on Base to this address to fund your account.`);
45
45
  }
46
46
  saveChain(chain);
47
- console.log(`Then run ${chalk.bold('runcode start')} to begin.\n`);
47
+ console.log(`Then run ${chalk.bold('franklin start')} to begin.\n`);
48
48
  console.log(chalk.dim(`Chain: ${chain} — saved to ~/.blockrun/`));
49
49
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/franklin",
3
- "version": "3.6.6",
3
+ "version": "3.6.7",
4
4
  "description": "Franklin — The AI agent with a wallet. Spends USDC autonomously to get real work done. Pay per action, no subscriptions.",
5
5
  "type": "module",
6
6
  "exports": {