@blockrun/runcode 2.2.0 → 2.2.2
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 +24 -1
- package/dist/tools/bash.js +1 -1
- package/dist/tools/edit.js +1 -1
- package/dist/ui/app.js +7 -60
- package/dist/ui/terminal.js +10 -1
- package/package.json +1 -1
package/dist/agent/commands.js
CHANGED
|
@@ -271,6 +271,29 @@ export async function handleSlashCommand(input, ctx) {
|
|
|
271
271
|
return { handled: false, rewritten: rewrite(arg) };
|
|
272
272
|
}
|
|
273
273
|
}
|
|
274
|
-
// Not a recognized command
|
|
274
|
+
// Not a recognized command — suggest closest match
|
|
275
|
+
const allCommands = [
|
|
276
|
+
...Object.keys(DIRECT_COMMANDS),
|
|
277
|
+
...Object.keys(REWRITE_COMMANDS),
|
|
278
|
+
...ARG_COMMANDS.map(c => c.prefix.trim()),
|
|
279
|
+
'/branch', '/resume', '/model', '/wallet', '/cost', '/help', '/clear', '/retry', '/exit',
|
|
280
|
+
];
|
|
281
|
+
const cmd = input.split(/\s/)[0];
|
|
282
|
+
const close = allCommands.filter(c => {
|
|
283
|
+
// Simple distance: share >= 50% of characters
|
|
284
|
+
const shorter = Math.min(cmd.length, c.length);
|
|
285
|
+
let matches = 0;
|
|
286
|
+
for (let i = 0; i < shorter; i++) {
|
|
287
|
+
if (cmd[i] === c[i])
|
|
288
|
+
matches++;
|
|
289
|
+
}
|
|
290
|
+
return matches >= shorter * 0.5 && matches >= 3;
|
|
291
|
+
});
|
|
292
|
+
if (close.length > 0) {
|
|
293
|
+
ctx.onEvent({ kind: 'text_delta', text: `Unknown command: ${cmd}. Did you mean: ${close.slice(0, 3).join(', ')}?\n` });
|
|
294
|
+
emitDone(ctx);
|
|
295
|
+
return { handled: true };
|
|
296
|
+
}
|
|
297
|
+
// Truly unknown — pass through as regular input
|
|
275
298
|
return { handled: false };
|
|
276
299
|
}
|
package/dist/tools/bash.js
CHANGED
package/dist/tools/edit.js
CHANGED
|
@@ -26,7 +26,7 @@ async function execute(input, ctx) {
|
|
|
26
26
|
if (!content.includes(oldStr)) {
|
|
27
27
|
// Find lines containing fragments of old_string for helpful context
|
|
28
28
|
const lines = content.split('\n');
|
|
29
|
-
const searchTerms = oldStr.split('\n').map(l => l.trim()).filter(l => l.length >
|
|
29
|
+
const searchTerms = oldStr.split('\n').map(l => l.trim()).filter(l => l.length > 3);
|
|
30
30
|
const matchedLines = [];
|
|
31
31
|
if (searchTerms.length > 0) {
|
|
32
32
|
for (let i = 0; i < lines.length && matchedLines.length < 5; i++) {
|
package/dist/ui/app.js
CHANGED
|
@@ -13,8 +13,8 @@ import { estimateCost } from '../pricing.js';
|
|
|
13
13
|
function InputBox({ input, setInput, onSubmit, model, balance, focused }) {
|
|
14
14
|
const { stdout } = useStdout();
|
|
15
15
|
const cols = stdout?.columns ?? 80;
|
|
16
|
-
const innerWidth = Math.max(
|
|
17
|
-
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { dimColor: true, children: '╭' + '─'.repeat(cols - 2) + '╮' }), _jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: "\u2502 " }), _jsx(Box, { width: innerWidth, children: _jsx(TextInput, { value: input, onChange: setInput, onSubmit: onSubmit, placeholder: "Ask anything... (/
|
|
16
|
+
const innerWidth = Math.min(Math.max(30, cols - 4), cols - 2);
|
|
17
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { dimColor: true, children: '╭' + '─'.repeat(cols - 2) + '╮' }), _jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: "\u2502 " }), _jsx(Box, { width: innerWidth, children: _jsx(TextInput, { value: input, onChange: setInput, onSubmit: onSubmit, placeholder: "Ask anything... (/help for commands)", focus: focused !== false }) }), _jsxs(Text, { dimColor: true, children: [' '.repeat(Math.max(0, cols - innerWidth - 4)), "\u2502"] })] }), _jsx(Text, { dimColor: true, children: '╰' + '─'.repeat(cols - 2) + '╯' }), _jsx(Box, { marginLeft: 1, children: _jsxs(Text, { dimColor: true, children: [model, " \u00B7 ", balance, " \u00B7 esc to abort/quit"] }) })] }));
|
|
18
18
|
}
|
|
19
19
|
// ─── Model picker data ─────────────────────────────────────────────────────
|
|
20
20
|
const PICKER_MODELS = [
|
|
@@ -167,45 +167,6 @@ function RunCodeApp({ initialModel, workDir, walletAddress, walletBalance, chain
|
|
|
167
167
|
setShowHelp(true);
|
|
168
168
|
setShowWallet(false);
|
|
169
169
|
return;
|
|
170
|
-
case '/commit':
|
|
171
|
-
case '/push':
|
|
172
|
-
case '/pr':
|
|
173
|
-
case '/undo':
|
|
174
|
-
case '/review':
|
|
175
|
-
case '/test':
|
|
176
|
-
case '/fix':
|
|
177
|
-
case '/debug':
|
|
178
|
-
case '/init':
|
|
179
|
-
case '/todo':
|
|
180
|
-
case '/deps':
|
|
181
|
-
case '/tasks':
|
|
182
|
-
case '/status':
|
|
183
|
-
case '/diff':
|
|
184
|
-
case '/log':
|
|
185
|
-
case '/stash':
|
|
186
|
-
case '/unstash':
|
|
187
|
-
case '/security':
|
|
188
|
-
case '/lint':
|
|
189
|
-
case '/optimize':
|
|
190
|
-
case '/migrate':
|
|
191
|
-
case '/clean':
|
|
192
|
-
case '/context':
|
|
193
|
-
case '/doctor':
|
|
194
|
-
case '/bug':
|
|
195
|
-
case '/version':
|
|
196
|
-
case '/plan':
|
|
197
|
-
case '/execute':
|
|
198
|
-
onSubmit(trimmed);
|
|
199
|
-
setStreamText('');
|
|
200
|
-
setWaiting(true);
|
|
201
|
-
setReady(false);
|
|
202
|
-
return;
|
|
203
|
-
case '/sessions':
|
|
204
|
-
setStreamText('');
|
|
205
|
-
setWaiting(true);
|
|
206
|
-
setReady(false);
|
|
207
|
-
onSubmit('/sessions');
|
|
208
|
-
return;
|
|
209
170
|
case '/clear':
|
|
210
171
|
setStreamText('');
|
|
211
172
|
setTools(new Map());
|
|
@@ -228,29 +189,15 @@ function RunCodeApp({ initialModel, workDir, walletAddress, walletBalance, chain
|
|
|
228
189
|
setTurnTokens({ input: 0, output: 0 });
|
|
229
190
|
onSubmit(lastPrompt);
|
|
230
191
|
return;
|
|
231
|
-
|
|
192
|
+
default:
|
|
193
|
+
// All other slash commands pass through to the agent loop's command registry
|
|
232
194
|
setStreamText('');
|
|
233
195
|
setThinking(false);
|
|
234
196
|
setThinkingText('');
|
|
235
197
|
setTools(new Map());
|
|
236
198
|
setWaiting(true);
|
|
237
199
|
setReady(false);
|
|
238
|
-
onSubmit(
|
|
239
|
-
return;
|
|
240
|
-
default:
|
|
241
|
-
// Commands with arguments that pass through to the loop
|
|
242
|
-
if (trimmed.startsWith('/resume ') || trimmed.startsWith('/branch ')
|
|
243
|
-
|| trimmed.startsWith('/explain ') || trimmed.startsWith('/search ')
|
|
244
|
-
|| trimmed.startsWith('/find ') || trimmed.startsWith('/refactor ')
|
|
245
|
-
|| trimmed.startsWith('/scaffold ') || trimmed.startsWith('/doc ')) {
|
|
246
|
-
setStreamText('');
|
|
247
|
-
setWaiting(true);
|
|
248
|
-
setReady(false);
|
|
249
|
-
onSubmit(trimmed);
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
setStatusMsg(`Unknown command: ${cmd}. Try /help`);
|
|
253
|
-
setTimeout(() => setStatusMsg(''), 3000);
|
|
200
|
+
onSubmit(trimmed);
|
|
254
201
|
return;
|
|
255
202
|
}
|
|
256
203
|
}
|
|
@@ -270,7 +217,7 @@ function RunCodeApp({ initialModel, workDir, walletAddress, walletBalance, chain
|
|
|
270
217
|
setShowWallet(false);
|
|
271
218
|
setTurnTokens({ input: 0, output: 0 });
|
|
272
219
|
onSubmit(trimmed);
|
|
273
|
-
}, [currentModel, totalCost, onSubmit, onModelChange, onExit, exit]);
|
|
220
|
+
}, [currentModel, totalCost, onSubmit, onModelChange, onAbort, onExit, exit, lastPrompt, inputHistory]);
|
|
274
221
|
// Expose event handler + balance updater
|
|
275
222
|
useEffect(() => {
|
|
276
223
|
globalThis.__runcode_ui = {
|
|
@@ -348,7 +295,7 @@ function RunCodeApp({ initialModel, workDir, walletAddress, walletBalance, chain
|
|
|
348
295
|
// ── Normal Mode ──
|
|
349
296
|
return (_jsxs(Box, { flexDirection: "column", children: [statusMsg && (_jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "green", children: statusMsg }) })), showHelp && (_jsxs(Box, { flexDirection: "column", marginLeft: 2, marginTop: 1, marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Commands" }), _jsx(Text, { children: " " }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/model" }), " [name] Switch model (picker if no name)"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/wallet" }), " Show wallet address & balance"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/cost" }), " Session cost & savings"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/retry" }), " Retry the last prompt"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/compact" }), " Compress conversation history"] }), _jsx(Text, { dimColor: true, children: " \u2500\u2500 Coding \u2500\u2500" }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/test" }), " Run tests"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/fix" }), " Fix last error"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/review" }), " Code review"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/explain" }), " file Explain code"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/search" }), " query Search codebase"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/refactor" }), " desc Refactor code"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/scaffold" }), " desc Generate boilerplate"] }), _jsx(Text, { dimColor: true, children: " \u2500\u2500 Git \u2500\u2500" }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/commit" }), " Commit changes"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/push" }), " Push to remote"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/pr" }), " Create pull request"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/status" }), " Git status"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/diff" }), " Git diff"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/log" }), " Git log"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/branch" }), " [name] Branches"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/stash" }), " Stash changes"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/undo" }), " Undo last commit"] }), _jsx(Text, { dimColor: true, children: " \u2500\u2500 Analysis \u2500\u2500" }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/security" }), " Security audit"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/lint" }), " Quality check"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/optimize" }), " Performance check"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/todo" }), " Find TODOs"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/deps" }), " Dependencies"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/clean" }), " Dead code removal"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/context" }), " Session info (model, tokens, mode)"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/plan" }), " Enter plan mode (read-only tools)"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/execute" }), " Exit plan mode (enable all tools)"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/sessions" }), " List saved sessions"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/resume" }), " id Resume a saved session"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/clear" }), " Clear conversation display"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/doctor" }), " Diagnose setup issues"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/help" }), " This help"] }), _jsxs(Text, { children: [" ", _jsx(Text, { color: "cyan", children: "/exit" }), " Quit"] }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: " Shortcuts: sonnet, opus, gpt, gemini, deepseek, flash, free, r1, o4, nano, mini, haiku" })] })), showWallet && (_jsxs(Box, { flexDirection: "column", marginLeft: 2, marginTop: 1, marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Wallet" }), _jsx(Text, { children: " " }), _jsxs(Text, { children: [" Chain: ", _jsx(Text, { color: "magenta", children: chain })] }), _jsxs(Text, { children: [" Address: ", _jsx(Text, { color: "cyan", children: walletAddress })] }), _jsxs(Text, { children: [" Balance: ", _jsx(Text, { color: "green", children: balance })] })] })), Array.from(tools.values()).map((tool, i) => (_jsx(Box, { marginLeft: 1, children: tool.done ? (tool.error
|
|
350
297
|
? _jsxs(Text, { color: "red", children: [" \u2717 ", tool.name, " ", _jsxs(Text, { dimColor: true, children: [tool.elapsed, "ms"] })] })
|
|
351
|
-
: _jsxs(Text, { color: "green", children: [" \u2713 ", tool.name, " ", _jsxs(Text, { dimColor: true, children: [tool.elapsed, "ms \u2014 ", tool.preview.slice(0, 200), tool.preview.length > 200 ? '...' : ''] })] })) : (_jsxs(Text, { color: "cyan", children: [" ", _jsx(Spinner, { type: "dots" }), " ", tool.name, "... ",
|
|
298
|
+
: _jsxs(Text, { color: "green", children: [" \u2713 ", tool.name, " ", _jsxs(Text, { dimColor: true, children: [tool.elapsed, "ms \u2014 ", tool.preview.slice(0, 200), tool.preview.length > 200 ? '...' : ''] })] })) : (_jsxs(Text, { color: "cyan", children: [" ", _jsx(Spinner, { type: "dots" }), " ", tool.name, "... ", _jsx(Text, { dimColor: true, children: (() => { const s = Math.round((Date.now() - tool.startTime) / 1000); return s > 0 ? `${s}s` : ''; })() })] })) }, i))), thinking && (_jsxs(Box, { flexDirection: "column", marginLeft: 1, children: [_jsxs(Text, { color: "magenta", children: [" ", _jsx(Spinner, { type: "dots" }), " thinking..."] }), thinkingText && (_jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [" ", thinkingText.split('\n').pop()?.slice(0, 80)] }))] })), waiting && !thinking && tools.size === 0 && (_jsx(Box, { marginLeft: 1, children: _jsxs(Text, { color: "yellow", children: [" ", _jsx(Spinner, { type: "dots" }), " ", _jsx(Text, { dimColor: true, children: currentModel })] }) })), streamText && (_jsx(Box, { marginTop: 0, marginBottom: 0, children: _jsx(Text, { children: streamText }) })), ready && (turnTokens.input > 0 || turnTokens.output > 0) && streamText && (_jsx(Box, { marginLeft: 1, marginTop: 0, children: _jsxs(Text, { dimColor: true, children: [turnTokens.input.toLocaleString(), " in / ", turnTokens.output.toLocaleString(), " out", totalCost > 0 ? ` · $${totalCost.toFixed(4)} session` : ''] }) })), ready && (_jsx(InputBox, { input: input, setInput: setInput, onSubmit: handleSubmit, model: currentModel, balance: balance, focused: mode === 'input' }))] }));
|
|
352
299
|
}
|
|
353
300
|
export function launchInkUI(opts) {
|
|
354
301
|
let resolveInput = null;
|
package/dist/ui/terminal.js
CHANGED
|
@@ -95,7 +95,14 @@ class MarkdownRenderer {
|
|
|
95
95
|
if (line.match(/^(\s*)[-*] /)) {
|
|
96
96
|
return line.replace(/^(\s*)[-*] /, '$1• ');
|
|
97
97
|
}
|
|
98
|
-
// Numbered lists
|
|
98
|
+
// Numbered lists
|
|
99
|
+
if (/^\s*\d+\.\s/.test(line)) {
|
|
100
|
+
return this.renderInline(line);
|
|
101
|
+
}
|
|
102
|
+
// Blockquotes
|
|
103
|
+
if (line.startsWith('> ')) {
|
|
104
|
+
return chalk.dim('│ ') + chalk.italic(this.renderInline(line.slice(2)));
|
|
105
|
+
}
|
|
99
106
|
// Tables — leave as-is (chalk doesn't help much)
|
|
100
107
|
// Inline formatting
|
|
101
108
|
return this.renderInline(line);
|
|
@@ -109,6 +116,8 @@ class MarkdownRenderer {
|
|
|
109
116
|
.replace(/\*\*([^*]+)\*\*/g, (_, t) => chalk.bold(t))
|
|
110
117
|
// Italic (only single * not preceded/followed by *)
|
|
111
118
|
.replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, (_, t) => chalk.italic(t))
|
|
119
|
+
// Strikethrough
|
|
120
|
+
.replace(/~~([^~]+)~~/g, (_, t) => chalk.strikethrough(t))
|
|
112
121
|
// Links
|
|
113
122
|
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, label, url) => chalk.blue.underline(label) + chalk.dim(` (${url})`))
|
|
114
123
|
// Restore code markers
|