@blockrun/franklin 3.15.49 → 3.15.50
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/ui/app.js +7 -1
- package/dist/ui/ask-user-answer.d.ts +24 -0
- package/dist/ui/ask-user-answer.js +34 -0
- package/package.json +1 -1
package/dist/ui/app.js
CHANGED
|
@@ -14,6 +14,7 @@ import { resolveModel, PICKER_CATEGORIES, PICKER_MODELS_FLAT, } from './model-pi
|
|
|
14
14
|
import { estimateCost } from '../pricing.js';
|
|
15
15
|
import { formatTokens, shortModelName } from '../stats/format.js';
|
|
16
16
|
import { mouse, forceDisableMouseTracking } from './mouse.js';
|
|
17
|
+
import { resolveAskUserAnswer } from './ask-user-answer.js';
|
|
17
18
|
// ─── Full-width input box ──────────────────────────────────────────────────
|
|
18
19
|
const DISABLE_AUTO_WRAP = '\x1b[?7l';
|
|
19
20
|
const ENABLE_AUTO_WRAP = '\x1b[?7h';
|
|
@@ -827,7 +828,12 @@ function RunCodeApp({ initialModel, workDir, walletAddress, walletBalance, chain
|
|
|
827
828
|
? _jsxs(Text, { color: r.ctxPct >= 80 ? 'red' : r.ctxPct >= 50 ? 'yellow' : undefined, dimColor: r.ctxPct < 50, children: [" \u00B7 ctx ", r.ctxPct, "%"] })
|
|
828
829
|
: ''] }) }))] }, r.key));
|
|
829
830
|
} }), permissionRequest && (_jsxs(Box, { flexDirection: "column", marginTop: 1, marginLeft: 2, children: [_jsx(Text, { color: "red", bold: true, children: "\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 \u26A0 ACTION REQUIRED \u26A0 \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501" }), _jsx(Text, { color: "yellow", children: "\u256D\u2500 Permission required \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }), _jsxs(Text, { color: "yellow", children: ["\u2502 ", _jsx(Text, { bold: true, children: permissionRequest.toolName })] }), permissionRequest.description.split('\n').map((line, i) => (_jsxs(Text, { dimColor: true, children: ["\u2502 ", line] }, i))), _jsx(Text, { color: "yellow", children: "\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }), _jsx(Box, { marginLeft: 2, children: _jsxs(Text, { children: [_jsx(Text, { bold: true, color: "green", children: "[y]" }), _jsx(Text, { dimColor: true, children: " yes " }), _jsx(Text, { bold: true, color: "cyan", children: "[a]" }), _jsx(Text, { dimColor: true, children: " always " }), _jsx(Text, { bold: true, color: "red", children: "[n]" }), _jsx(Text, { dimColor: true, children: " no" })] }) })] })), askUserRequest && (_jsxs(Box, { flexDirection: "column", marginTop: 1, marginLeft: 2, children: [_jsx(Text, { color: "magenta", bold: true, children: "\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 \u26A0 ANSWER REQUIRED \u26A0 \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501" }), _jsx(Text, { color: "cyan", children: "\u256D\u2500 Question \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }), _jsxs(Text, { color: "cyan", children: ["\u2502 ", _jsx(Text, { bold: true, children: askUserRequest.question })] }), askUserRequest.options && askUserRequest.options.length > 0 && (askUserRequest.options.map((opt, i) => (_jsxs(Text, { dimColor: true, children: ["\u2502 ", i + 1, ". ", opt] }, i)))), _jsx(Text, { color: "cyan", children: "\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }), _jsxs(Box, { marginLeft: 2, children: [_jsx(Text, { bold: true, children: "answer> " }), _jsx(TextInput, { value: askUserInput, onChange: setAskUserInput, onSubmit: (val) => {
|
|
830
|
-
|
|
831
|
+
// resolveAskUserAnswer translates "1" / "2" / ... into the
|
|
832
|
+
// matching label string when the dialog showed a numbered
|
|
833
|
+
// option list. Without it, every onAskUser caller's
|
|
834
|
+
// exact-label match fails for digit answers and silently
|
|
835
|
+
// falls through to the default branch (typically cancel).
|
|
836
|
+
const answer = resolveAskUserAnswer(val, askUserRequest.options);
|
|
831
837
|
const r = askUserRequest.resolve;
|
|
832
838
|
setAskUserRequest(null);
|
|
833
839
|
setAskUserInput('');
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a user-typed AskUser answer against the option list.
|
|
3
|
+
*
|
|
4
|
+
* The TUI renders option labels as a numbered list ("1. X", "2. Y", …),
|
|
5
|
+
* so users naturally type the digit. Every tool-side onAskUser caller
|
|
6
|
+
* (videogen.ts:113, modal.ts:371, jupiter.ts:368, zerox-base.ts:453,
|
|
7
|
+
* zerox-gasless.ts:446) does an exact-string match against the full
|
|
8
|
+
* label, so a bare "1" silently falls through to the caller's default
|
|
9
|
+
* branch — which is typically "cancel".
|
|
10
|
+
*
|
|
11
|
+
* Verified 2026-05-04 in a live session: user typed "1" twice in a
|
|
12
|
+
* VideoGen flow, both invocations returned "Video generation cancelled
|
|
13
|
+
* (No USDC was spent)" even though the wallet had $94.72 and the
|
|
14
|
+
* Content budget had $2.00 untouched.
|
|
15
|
+
*
|
|
16
|
+
* Translation rules:
|
|
17
|
+
* - "" → "(no response)" (preserve the existing empty-input fallback)
|
|
18
|
+
* - "<digit>" with options.length > 0 and 1 ≤ digit ≤ options.length
|
|
19
|
+
* → the matching label string
|
|
20
|
+
* - anything else → the trimmed input verbatim (callers that match
|
|
21
|
+
* against label can still get a literal answer when the user types
|
|
22
|
+
* it out, and free-form text questions still work the same way)
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveAskUserAnswer(raw: string, options: readonly string[] | undefined): string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a user-typed AskUser answer against the option list.
|
|
3
|
+
*
|
|
4
|
+
* The TUI renders option labels as a numbered list ("1. X", "2. Y", …),
|
|
5
|
+
* so users naturally type the digit. Every tool-side onAskUser caller
|
|
6
|
+
* (videogen.ts:113, modal.ts:371, jupiter.ts:368, zerox-base.ts:453,
|
|
7
|
+
* zerox-gasless.ts:446) does an exact-string match against the full
|
|
8
|
+
* label, so a bare "1" silently falls through to the caller's default
|
|
9
|
+
* branch — which is typically "cancel".
|
|
10
|
+
*
|
|
11
|
+
* Verified 2026-05-04 in a live session: user typed "1" twice in a
|
|
12
|
+
* VideoGen flow, both invocations returned "Video generation cancelled
|
|
13
|
+
* (No USDC was spent)" even though the wallet had $94.72 and the
|
|
14
|
+
* Content budget had $2.00 untouched.
|
|
15
|
+
*
|
|
16
|
+
* Translation rules:
|
|
17
|
+
* - "" → "(no response)" (preserve the existing empty-input fallback)
|
|
18
|
+
* - "<digit>" with options.length > 0 and 1 ≤ digit ≤ options.length
|
|
19
|
+
* → the matching label string
|
|
20
|
+
* - anything else → the trimmed input verbatim (callers that match
|
|
21
|
+
* against label can still get a literal answer when the user types
|
|
22
|
+
* it out, and free-form text questions still work the same way)
|
|
23
|
+
*/
|
|
24
|
+
export function resolveAskUserAnswer(raw, options) {
|
|
25
|
+
const trimmed = raw.trim();
|
|
26
|
+
if (!trimmed)
|
|
27
|
+
return '(no response)';
|
|
28
|
+
if (options && options.length > 0 && /^\d+$/.test(trimmed)) {
|
|
29
|
+
const idx = parseInt(trimmed, 10) - 1;
|
|
30
|
+
if (idx >= 0 && idx < options.length)
|
|
31
|
+
return options[idx];
|
|
32
|
+
}
|
|
33
|
+
return trimmed;
|
|
34
|
+
}
|
package/package.json
CHANGED