@blockrun/franklin 3.6.6 → 3.6.8
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/daemon.js +2 -2
- package/dist/commands/init.js +2 -2
- package/dist/commands/logs.js +11 -3
- package/dist/commands/proxy.js +3 -3
- package/dist/commands/setup.js +7 -7
- package/dist/panel/server.js +3 -1
- package/dist/stats/tracker.js +14 -2
- 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/daemon.js
CHANGED
|
@@ -3,8 +3,8 @@ import fs from 'node:fs';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import { BLOCKRUN_DIR, DEFAULT_PROXY_PORT } from '../config.js';
|
|
6
|
-
const PID_FILE = path.join(BLOCKRUN_DIR, '
|
|
7
|
-
const LOG_FILE = path.join(BLOCKRUN_DIR, '
|
|
6
|
+
const PID_FILE = path.join(BLOCKRUN_DIR, 'franklin.pid');
|
|
7
|
+
const LOG_FILE = path.join(BLOCKRUN_DIR, 'franklin-debug.log');
|
|
8
8
|
function readPid() {
|
|
9
9
|
try {
|
|
10
10
|
const raw = fs.readFileSync(PID_FILE, 'utf-8').trim();
|
package/dist/commands/init.js
CHANGED
|
@@ -63,9 +63,9 @@ export async function initCommand(options) {
|
|
|
63
63
|
<key>KeepAlive</key>
|
|
64
64
|
<false/>
|
|
65
65
|
<key>StandardOutPath</key>
|
|
66
|
-
<string>${os.homedir()}/.blockrun/
|
|
66
|
+
<string>${os.homedir()}/.blockrun/franklin-debug.log</string>
|
|
67
67
|
<key>StandardErrorPath</key>
|
|
68
|
-
<string>${os.homedir()}/.blockrun/
|
|
68
|
+
<string>${os.homedir()}/.blockrun/franklin-debug.log</string>
|
|
69
69
|
</dict>
|
|
70
70
|
</plist>`;
|
|
71
71
|
fs.mkdirSync(LAUNCH_AGENT_DIR, { recursive: true });
|
package/dist/commands/logs.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 LOG_FILE = path.join(BLOCKRUN_DIR, '
|
|
5
|
+
const LOG_FILE = path.join(BLOCKRUN_DIR, 'franklin-debug.log');
|
|
6
|
+
const LEGACY_LOG_FILE = path.join(BLOCKRUN_DIR, 'runcode-debug.log');
|
|
6
7
|
const MAX_LOG_SIZE = 10 * 1024 * 1024; // 10MB auto-rotate threshold
|
|
7
8
|
export function logsCommand(options) {
|
|
8
9
|
if (options.clear) {
|
|
@@ -15,9 +16,16 @@ export function logsCommand(options) {
|
|
|
15
16
|
}
|
|
16
17
|
return;
|
|
17
18
|
}
|
|
19
|
+
// Migrate legacy log file
|
|
20
|
+
if (!fs.existsSync(LOG_FILE) && fs.existsSync(LEGACY_LOG_FILE)) {
|
|
21
|
+
try {
|
|
22
|
+
fs.renameSync(LEGACY_LOG_FILE, LOG_FILE);
|
|
23
|
+
}
|
|
24
|
+
catch { /* best effort */ }
|
|
25
|
+
}
|
|
18
26
|
if (!fs.existsSync(LOG_FILE)) {
|
|
19
|
-
console.log(chalk.dim('No logs yet. Start
|
|
20
|
-
console.log(chalk.bold('
|
|
27
|
+
console.log(chalk.dim('No logs yet. Start franklin with --debug to enable logging:'));
|
|
28
|
+
console.log(chalk.bold(' franklin start --debug'));
|
|
21
29
|
return;
|
|
22
30
|
}
|
|
23
31
|
// Auto-rotate: if file is over threshold, keep only last half
|
package/dist/commands/proxy.js
CHANGED
|
@@ -87,10 +87,10 @@ function launchProxy(server, port, debug) {
|
|
|
87
87
|
});
|
|
88
88
|
server.listen(port, () => {
|
|
89
89
|
console.log(chalk.green(`✓ Proxy running on port ${port}`));
|
|
90
|
-
console.log(chalk.dim(` Usage tracking: ~/.blockrun/
|
|
90
|
+
console.log(chalk.dim(` Usage tracking: ~/.blockrun/franklin-stats.json`));
|
|
91
91
|
if (debug)
|
|
92
|
-
console.log(chalk.dim(` Debug log: ~/.blockrun/
|
|
93
|
-
console.log(chalk.dim(` Run '
|
|
92
|
+
console.log(chalk.dim(` Debug log: ~/.blockrun/franklin-debug.log`));
|
|
93
|
+
console.log(chalk.dim(` Run 'franklin stats' to view statistics\n`));
|
|
94
94
|
console.log('Set this in your shell to use with Claude Code:\n');
|
|
95
95
|
console.log(chalk.bold(` export ANTHROPIC_BASE_URL=http://localhost:${port}/api`));
|
|
96
96
|
console.log(chalk.bold(` export ANTHROPIC_AUTH_TOKEN=x402-proxy-handles-auth`));
|
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/dist/panel/server.js
CHANGED
|
@@ -158,7 +158,9 @@ export function createPanelServer(port) {
|
|
|
158
158
|
}
|
|
159
159
|
});
|
|
160
160
|
// Watch stats file for changes → push to SSE clients
|
|
161
|
-
const statsFile = path.join(BLOCKRUN_DIR, '
|
|
161
|
+
const statsFile = fs.existsSync(path.join(BLOCKRUN_DIR, 'franklin-stats.json'))
|
|
162
|
+
? path.join(BLOCKRUN_DIR, 'franklin-stats.json')
|
|
163
|
+
: path.join(BLOCKRUN_DIR, 'runcode-stats.json');
|
|
162
164
|
if (fs.existsSync(statsFile)) {
|
|
163
165
|
fs.watchFile(statsFile, { interval: 2000 }, () => {
|
|
164
166
|
try {
|
package/dist/stats/tracker.js
CHANGED
|
@@ -9,15 +9,27 @@ import { OPUS_PRICING } from '../pricing.js';
|
|
|
9
9
|
import { BLOCKRUN_DIR } from '../config.js';
|
|
10
10
|
let resolvedStatsFile = null;
|
|
11
11
|
function preferredStatsFile() {
|
|
12
|
+
return path.join(BLOCKRUN_DIR, 'franklin-stats.json');
|
|
13
|
+
}
|
|
14
|
+
function legacyStatsFile() {
|
|
12
15
|
return path.join(BLOCKRUN_DIR, 'runcode-stats.json');
|
|
13
16
|
}
|
|
14
17
|
function fallbackStatsFile() {
|
|
15
|
-
return path.join(os.tmpdir(), '
|
|
18
|
+
return path.join(os.tmpdir(), 'franklin', 'franklin-stats.json');
|
|
16
19
|
}
|
|
17
20
|
export function getStatsFilePath() {
|
|
18
21
|
if (resolvedStatsFile)
|
|
19
22
|
return resolvedStatsFile;
|
|
20
|
-
|
|
23
|
+
// Migrate legacy stats file if it exists and new one doesn't
|
|
24
|
+
const preferred = preferredStatsFile();
|
|
25
|
+
const legacy = legacyStatsFile();
|
|
26
|
+
if (!fs.existsSync(preferred) && fs.existsSync(legacy)) {
|
|
27
|
+
try {
|
|
28
|
+
fs.renameSync(legacy, preferred);
|
|
29
|
+
}
|
|
30
|
+
catch { /* best effort */ }
|
|
31
|
+
}
|
|
32
|
+
for (const file of [preferred, fallbackStatsFile()]) {
|
|
21
33
|
try {
|
|
22
34
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
23
35
|
resolvedStatsFile = file;
|
package/package.json
CHANGED