@blockrun/franklin 3.15.34 → 3.15.35
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/loop.js +5 -0
- package/dist/commands/start.js +22 -1
- package/dist/session/storage.d.ts +12 -0
- package/dist/session/storage.js +6 -0
- package/package.json +1 -1
package/dist/agent/loop.js
CHANGED
|
@@ -431,6 +431,11 @@ export async function interactiveSession(config, getUserInput, onEvent, onAbortR
|
|
|
431
431
|
updateSessionMeta(sessionId, {
|
|
432
432
|
model: config.model,
|
|
433
433
|
workDir,
|
|
434
|
+
// Pin the session's chain so `franklin --resume` can restore it
|
|
435
|
+
// even after `franklin <chain>` shortcuts mutate the persisted
|
|
436
|
+
// default. updateSessionMeta treats this field as sticky once
|
|
437
|
+
// recorded — see storage.ts.
|
|
438
|
+
chain: config.chain,
|
|
434
439
|
turnCount,
|
|
435
440
|
messageCount: history.length,
|
|
436
441
|
inputTokens: sessionInputTokens,
|
package/dist/commands/start.js
CHANGED
|
@@ -46,7 +46,28 @@ export async function startCommand(options) {
|
|
|
46
46
|
const { findLatestSessionForDir } = await import('../ui/session-picker.js');
|
|
47
47
|
continueResolvedId = findLatestSessionForDir(process.cwd())?.id;
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
// Sessions are wallet-bound: the conversation, audit trail, and tool
|
|
50
|
+
// results live on whichever chain the session was started on. If
|
|
51
|
+
// we're resuming, prefer the session's recorded chain over the
|
|
52
|
+
// persisted default — `franklin solana` / `franklin base` shortcuts
|
|
53
|
+
// mutate that default, and a debug invocation between restarts
|
|
54
|
+
// shouldn't be able to silently move the user to a different wallet.
|
|
55
|
+
// Only sessions created in 3.15.35+ have the field; older sessions
|
|
56
|
+
// fall back to the persisted default (matches pre-3.15.35 behavior).
|
|
57
|
+
let chain = loadChain();
|
|
58
|
+
const resumeIdEarly = (typeof options.resume === 'string' && options.resume !== 'picker') ? options.resume
|
|
59
|
+
: continueResolvedId;
|
|
60
|
+
if (resumeIdEarly) {
|
|
61
|
+
const { loadSessionMeta } = await import('../session/storage.js');
|
|
62
|
+
const sessMeta = loadSessionMeta(resumeIdEarly);
|
|
63
|
+
if (sessMeta?.chain && sessMeta.chain !== chain) {
|
|
64
|
+
console.log(chalk.dim(` Restoring session's chain: ${sessMeta.chain} (default was ${chain}; session is wallet-bound to ${sessMeta.chain})`));
|
|
65
|
+
chain = sessMeta.chain;
|
|
66
|
+
}
|
|
67
|
+
else if (sessMeta?.chain) {
|
|
68
|
+
chain = sessMeta.chain;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
50
71
|
const apiUrl = API_URLS[chain];
|
|
51
72
|
const config = loadConfig();
|
|
52
73
|
// Resolve model. Priority: explicit --model > resumed session's model > user
|
|
@@ -13,6 +13,18 @@ export interface SessionMeta {
|
|
|
13
13
|
updatedAt: number;
|
|
14
14
|
turnCount: number;
|
|
15
15
|
messageCount: number;
|
|
16
|
+
/**
|
|
17
|
+
* Chain (`base` | `solana`) the session was started on. Captured at
|
|
18
|
+
* session creation so `franklin --resume` can restore the same chain
|
|
19
|
+
* even if the user later changed their default via
|
|
20
|
+
* `franklin solana` / `franklin base`. Verified 2026-05-04: a debug
|
|
21
|
+
* invocation flipped `~/.blockrun/.chain` to `solana`; the next
|
|
22
|
+
* `--resume` silently moved the user from their funded Base wallet
|
|
23
|
+
* to an underfunded Solana wallet. Sessions are wallet-bound by
|
|
24
|
+
* conversation context — switching chains mid-resume is a bug.
|
|
25
|
+
* Optional for back-compat with pre-3.15.35 sessions.
|
|
26
|
+
*/
|
|
27
|
+
chain?: 'base' | 'solana';
|
|
16
28
|
inputTokens?: number;
|
|
17
29
|
outputTokens?: number;
|
|
18
30
|
costUsd?: number;
|
package/dist/session/storage.js
CHANGED
|
@@ -113,6 +113,12 @@ export function updateSessionMeta(sessionId, meta) {
|
|
|
113
113
|
...(meta.channel !== undefined || existing?.channel !== undefined
|
|
114
114
|
? { channel: meta.channel ?? existing?.channel }
|
|
115
115
|
: {}),
|
|
116
|
+
// Chain (base / solana) is sticky once set. We never let a later
|
|
117
|
+
// update overwrite an existing value with undefined — that would
|
|
118
|
+
// silently drop the bind-to-original-chain guarantee.
|
|
119
|
+
...(meta.chain !== undefined || existing?.chain !== undefined
|
|
120
|
+
? { chain: existing?.chain ?? meta.chain }
|
|
121
|
+
: {}),
|
|
116
122
|
...(meta.toolCallCounts !== undefined || existing?.toolCallCounts !== undefined
|
|
117
123
|
? { toolCallCounts: meta.toolCallCounts ?? existing?.toolCallCounts }
|
|
118
124
|
: {}),
|
package/package.json
CHANGED