agent-from-zero 0.32.3 → 0.32.4
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/ink/app.js +29 -6
- package/package.json +1 -1
package/dist/ink/app.js
CHANGED
|
@@ -98,6 +98,7 @@ export function App({ session, runTurn }) {
|
|
|
98
98
|
const [status, setStatus] = useState(null); // the live spinner line
|
|
99
99
|
const [live, setLive] = useState(null); // the streaming answer
|
|
100
100
|
const [input, setInput] = useState(""); // the current input buffer
|
|
101
|
+
const [cursor, setCursor] = useState(0); // caret position WITHIN `input` (0..input.length), for ←/→ editing
|
|
101
102
|
const [busy, setBusy] = useState(false); // a turn is in flight
|
|
102
103
|
const [pending, setPending] = useState(null); // a prompt/menu blocking input
|
|
103
104
|
const [menuSel, setMenuSel] = useState(0); // the select menu's cursor
|
|
@@ -465,6 +466,7 @@ export function App({ session, runTurn }) {
|
|
|
465
466
|
setSubAgentFocus(null);
|
|
466
467
|
const text = input.trim();
|
|
467
468
|
setInput("");
|
|
469
|
+
setCursor(0);
|
|
468
470
|
setHistIdx(null);
|
|
469
471
|
if (!text)
|
|
470
472
|
return;
|
|
@@ -472,13 +474,26 @@ export function App({ session, runTurn }) {
|
|
|
472
474
|
history.push(text); // remember non-empty entries for ↑/↓
|
|
473
475
|
void submitLine(text);
|
|
474
476
|
}
|
|
477
|
+
else if (key.leftArrow) {
|
|
478
|
+
setCursor((c) => Math.max(0, c - 1)); // move the caret left within the line
|
|
479
|
+
}
|
|
480
|
+
else if (key.rightArrow) {
|
|
481
|
+
setCursor((c) => Math.min(input.length, c + 1)); // ...and right
|
|
482
|
+
}
|
|
483
|
+
else if (key.ctrl && char === "a") {
|
|
484
|
+
setCursor(0); // Home — jump to the start of the line
|
|
485
|
+
}
|
|
486
|
+
else if (key.ctrl && char === "e") {
|
|
487
|
+
setCursor(input.length); // End — jump to the end of the line
|
|
488
|
+
}
|
|
475
489
|
else if (key.upArrow) {
|
|
476
|
-
// ↑ recall an earlier prompt (newest-first), like a shell.
|
|
490
|
+
// ↑ recall an earlier prompt (newest-first), like a shell; caret to its end.
|
|
477
491
|
if (!history.length)
|
|
478
492
|
return;
|
|
479
493
|
const idx = histIdx === null ? history.length - 1 : Math.max(0, histIdx - 1);
|
|
480
494
|
setHistIdx(idx);
|
|
481
495
|
setInput(history[idx]);
|
|
496
|
+
setCursor(history[idx].length);
|
|
482
497
|
}
|
|
483
498
|
else if (key.downArrow) {
|
|
484
499
|
// ↓ walk back toward the fresh line.
|
|
@@ -488,24 +503,32 @@ export function App({ session, runTurn }) {
|
|
|
488
503
|
if (idx >= history.length) {
|
|
489
504
|
setHistIdx(null);
|
|
490
505
|
setInput("");
|
|
506
|
+
setCursor(0);
|
|
491
507
|
}
|
|
492
508
|
else {
|
|
493
509
|
setHistIdx(idx);
|
|
494
510
|
setInput(history[idx]);
|
|
511
|
+
setCursor(history[idx].length);
|
|
495
512
|
}
|
|
496
513
|
}
|
|
497
514
|
else if (key.backspace || key.delete) {
|
|
498
|
-
|
|
515
|
+
// Delete the char BEFORE the caret. Both Backspace and macOS DEL land here,
|
|
516
|
+
// so this is always a backward delete (forward-delete is rare; we skip it).
|
|
517
|
+
if (cursor > 0) {
|
|
518
|
+
setInput(input.slice(0, cursor - 1) + input.slice(cursor));
|
|
519
|
+
setCursor(cursor - 1);
|
|
520
|
+
}
|
|
499
521
|
}
|
|
500
522
|
else if (char && !key.ctrl && !key.meta) {
|
|
501
|
-
//
|
|
502
|
-
// file becomes a clean absolute path;
|
|
523
|
+
// Insert at the caret (a bulk chunk — paste / dropped file path — is
|
|
524
|
+
// normalized: a dropped file becomes a clean absolute path; prose unchanged).
|
|
503
525
|
const add = char.length > 1 ? normalizeDroppedPaths(char) : char;
|
|
504
526
|
setHistIdx(null);
|
|
505
|
-
setInput((
|
|
527
|
+
setInput(input.slice(0, cursor) + add + input.slice(cursor));
|
|
528
|
+
setCursor(cursor + add.length);
|
|
506
529
|
}
|
|
507
530
|
});
|
|
508
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Static, { items: items, children: (item, i) => _jsx(ItemView, { item: item }, i) }), live !== null && (_jsxs(Box, { marginTop: 1, flexDirection: "row", children: [_jsx(Text, { color: "green", children: "\u23FA " }), _jsx(Box, { flexGrow: 1, children: _jsx(Text, { children: live === "" ? chalk.dim("…") : liveTail(live) }) })] })), (status !== null || (busy && live === null)) && (_jsxs(Box, { marginTop: live === null ? 1 : 0, children: [_jsx(Spinner, {}), _jsxs(Text, { children: [" ", status ?? chalk.dim("working…")] })] })), pending?.kind === "select" && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "yellow", children: pending.header }), _jsx(Text, { children: renderMenu(pending.options, menuSel) }), _jsx(Text, { children: MENU_HINT })] })), pending?.kind === "form" && formState && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { children: renderForm(pending.questions, formState) }) })), _jsxs(Box, { borderStyle: "round", borderColor: planMode ? "magenta" : "cyan", paddingX: 1, marginTop: 1, children: [_jsx(Text, { color: planMode ? "magenta" : "cyan", children: planMode ? "plan ❯ " : "❯ " }), _jsx(Text, { children: input }), _jsx(Text, { inverse: true, children: " " })] }), (() => {
|
|
531
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Static, { items: items, children: (item, i) => _jsx(ItemView, { item: item }, i) }), live !== null && (_jsxs(Box, { marginTop: 1, flexDirection: "row", children: [_jsx(Text, { color: "green", children: "\u23FA " }), _jsx(Box, { flexGrow: 1, children: _jsx(Text, { children: live === "" ? chalk.dim("…") : liveTail(live) }) })] })), (status !== null || (busy && live === null)) && (_jsxs(Box, { marginTop: live === null ? 1 : 0, children: [_jsx(Spinner, {}), _jsxs(Text, { children: [" ", status ?? chalk.dim("working…")] })] })), pending?.kind === "select" && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "yellow", children: pending.header }), _jsx(Text, { children: renderMenu(pending.options, menuSel) }), _jsx(Text, { children: MENU_HINT })] })), pending?.kind === "form" && formState && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { children: renderForm(pending.questions, formState) }) })), _jsxs(Box, { borderStyle: "round", borderColor: planMode ? "magenta" : "cyan", paddingX: 1, marginTop: 1, children: [_jsx(Text, { color: planMode ? "magenta" : "cyan", children: planMode ? "plan ❯ " : "❯ " }), _jsx(Text, { children: input.slice(0, cursor) }), _jsx(Text, { inverse: true, children: input.slice(cursor, cursor + 1) || " " }), _jsx(Text, { children: input.slice(cursor + 1) })] }), (() => {
|
|
509
532
|
const agents = listSubAgents();
|
|
510
533
|
if (!agents.length)
|
|
511
534
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-from-zero",
|
|
3
|
-
"version": "0.32.
|
|
3
|
+
"version": "0.32.4",
|
|
4
4
|
"description": "Build a Claude Code-style CLI agent from scratch, with AI as your pair programmer — companion code for a 10-day tutorial (DeepSeek by default, any OpenAI-compatible model)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|