@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.
- package/dist/agent/commands.js +130 -44
- package/dist/commands/config.js +15 -7
- package/dist/commands/setup.js +7 -7
- package/package.json +1 -1
package/dist/agent/commands.js
CHANGED
|
@@ -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();
|
package/dist/commands/config.js
CHANGED
|
@@ -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, '
|
|
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
|
-
|
|
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('
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
113
|
+
console.log('Usage: franklin config <set|get|unset|list> [key] [value]');
|
|
106
114
|
process.exit(1);
|
|
107
115
|
}
|
package/dist/commands/setup.js
CHANGED
|
@@ -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('
|
|
13
|
-
console.log(chalk.dim('
|
|
14
|
-
console.log(chalk.dim('
|
|
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('
|
|
33
|
-
console.log(chalk.dim('
|
|
34
|
-
console.log(chalk.dim('
|
|
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('
|
|
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