@falkenslab/agent-kit 0.10.1 → 0.10.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.
|
@@ -34,7 +34,8 @@ export declare const SHORTCUTS: string[];
|
|
|
34
34
|
* blocks folded into a token, multi-line input (`\` + Enter or Ctrl+J), word and line
|
|
35
35
|
* shortcuts (Ctrl+W/K/U, Ctrl+←/→, Home/End, Ctrl+A/E), reverse history search (Ctrl+R)
|
|
36
36
|
* and taking a queued line back (↑ on an empty prompt). Written here rather than taken from
|
|
37
|
-
* @inkjs/ui because its TextInput is uncontrolled. Backspace
|
|
38
|
-
*
|
|
37
|
+
* @inkjs/ui because its TextInput is uncontrolled. Ink reports Backspace and Delete both as
|
|
38
|
+
* `key.delete`: the raw input chunk (read before Ink parses it) tells Delete apart, which
|
|
39
|
+
* erases forwards; anything else reported as delete erases backwards.
|
|
39
40
|
*/
|
|
40
41
|
export declare function PromptInput({ label, inset, suggestion, history, commands, onSubmit, onExit, onRecallQueued, files }: PromptInputProps): import("react").JSX.Element;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useContext, useLayoutEffect, useReducer, useRef } from "react";
|
|
3
|
-
import { Box, Text, useInput, useStdout } from "ink";
|
|
3
|
+
import { Box, Text, useInput, useStdin, useStdout } from "ink";
|
|
4
4
|
import stringWidth from "string-width";
|
|
5
5
|
import { fitWidth, stripAnsi } from "./lineBuffer.js";
|
|
6
6
|
import { liveWidth } from "./sessionModel.js";
|
|
@@ -8,7 +8,7 @@ import { isMouseReport } from "./fullscreen.js";
|
|
|
8
8
|
import { CursorContext } from "./terminalCursor.js";
|
|
9
9
|
import { isFocusReport } from "./terminalStatus.js";
|
|
10
10
|
import { matchingFiles, mentionAt } from "./fileMentions.js";
|
|
11
|
-
import { continueLine, createPasteRegistry, cursorLine, deleteBack, deleteWordBack, insert, isBlockPaste, killToLineEnd, moveLine, normalizePaste, searchHistory, toLineEnd, toLineStart, wordLeft, wordRight, } from "./promptEditing.js";
|
|
11
|
+
import { continueLine, createPasteRegistry, cursorLine, deleteBack, deleteForward, deleteWordBack, insert, isBlockPaste, isForwardDelete, killToLineEnd, moveLine, normalizePaste, searchHistory, toLineEnd, toLineStart, wordLeft, wordRight, } from "./promptEditing.js";
|
|
12
12
|
import * as ui from "../ui.js";
|
|
13
13
|
const MAX_SUGGESTIONS = 6;
|
|
14
14
|
/** Commands (names without "/") a partial "/name" line could still become. */
|
|
@@ -56,13 +56,15 @@ export const SHORTCUTS = [
|
|
|
56
56
|
// A paste can reach us in several chunks; pieces this close together extend the same one.
|
|
57
57
|
const PASTE_CHUNK_MS = 100;
|
|
58
58
|
const PASTE_TOKEN_BEFORE = /\[Pasted text #\d+ \+\d+ lines?\]$/;
|
|
59
|
+
const PASTE_TOKEN_AFTER = /^\[Pasted text #\d+ \+\d+ lines?\]/;
|
|
59
60
|
/**
|
|
60
61
|
* The chat's prompt: history (↑/↓), "/command" completion and suggestions (Tab), pasted
|
|
61
62
|
* blocks folded into a token, multi-line input (`\` + Enter or Ctrl+J), word and line
|
|
62
63
|
* shortcuts (Ctrl+W/K/U, Ctrl+←/→, Home/End, Ctrl+A/E), reverse history search (Ctrl+R)
|
|
63
64
|
* and taking a queued line back (↑ on an empty prompt). Written here rather than taken from
|
|
64
|
-
* @inkjs/ui because its TextInput is uncontrolled. Backspace
|
|
65
|
-
*
|
|
65
|
+
* @inkjs/ui because its TextInput is uncontrolled. Ink reports Backspace and Delete both as
|
|
66
|
+
* `key.delete`: the raw input chunk (read before Ink parses it) tells Delete apart, which
|
|
67
|
+
* erases forwards; anything else reported as delete erases backwards.
|
|
66
68
|
*/
|
|
67
69
|
export function PromptInput({ label, inset = 0, suggestion, history, commands, onSubmit, onExit, onRecallQueued, files = [] }) {
|
|
68
70
|
// Kept in a ref, not in state: two keystrokes can arrive before React re-renders, and a
|
|
@@ -78,6 +80,19 @@ export function PromptInput({ label, inset = 0, suggestion, history, commands, o
|
|
|
78
80
|
});
|
|
79
81
|
const pastes = useRef(createPasteRegistry()).current;
|
|
80
82
|
const [, rerender] = useReducer((n) => n + 1, 0);
|
|
83
|
+
// Whether the chunk being handled is the Delete key. Prepended, so it runs before the
|
|
84
|
+
// useInput listener below, which reads it (both listen to the same chunk on Ink's emitter).
|
|
85
|
+
const forwardDelete = useRef(false);
|
|
86
|
+
const { internal_eventEmitter: stdinEvents } = useStdin();
|
|
87
|
+
useLayoutEffect(() => {
|
|
88
|
+
const onInput = (data) => {
|
|
89
|
+
forwardDelete.current = isForwardDelete(String(data));
|
|
90
|
+
};
|
|
91
|
+
stdinEvents.prependListener("input", onInput);
|
|
92
|
+
return () => {
|
|
93
|
+
stdinEvents.removeListener("input", onInput);
|
|
94
|
+
};
|
|
95
|
+
}, [stdinEvents]);
|
|
81
96
|
function apply(next) {
|
|
82
97
|
state.current.value = next.value;
|
|
83
98
|
state.current.cursor = next.cursor;
|
|
@@ -106,6 +121,9 @@ export function PromptInput({ label, inset = 0, suggestion, history, commands, o
|
|
|
106
121
|
else if (key.return) {
|
|
107
122
|
finish(true);
|
|
108
123
|
}
|
|
124
|
+
else if (key.delete && forwardDelete.current) {
|
|
125
|
+
// The search query has no cursor inside it: Delete has nothing after it to erase.
|
|
126
|
+
}
|
|
109
127
|
else if (key.backspace || key.delete) {
|
|
110
128
|
search.query = search.query.slice(0, -1);
|
|
111
129
|
search.index = searchHistory(history, search.query);
|
|
@@ -242,6 +260,11 @@ export function PromptInput({ label, inset = 0, suggestion, history, commands, o
|
|
|
242
260
|
else if (key.end || (key.ctrl && input === "e")) {
|
|
243
261
|
apply(toLineEnd(current));
|
|
244
262
|
}
|
|
263
|
+
else if (key.delete && forwardDelete.current) {
|
|
264
|
+
// A pasted block goes away whole, as with Backspace.
|
|
265
|
+
const token = PASTE_TOKEN_AFTER.exec(value.slice(cursor))?.[0];
|
|
266
|
+
apply(token ? { value: value.slice(0, cursor) + value.slice(cursor + token.length), cursor } : deleteForward(current));
|
|
267
|
+
}
|
|
245
268
|
else if (key.backspace || key.delete) {
|
|
246
269
|
// A pasted block goes away whole.
|
|
247
270
|
const token = PASTE_TOKEN_BEFORE.exec(value.slice(0, cursor))?.[0];
|
|
@@ -9,6 +9,15 @@ export interface EditState {
|
|
|
9
9
|
}
|
|
10
10
|
export declare function insert({ value, cursor }: EditState, text: string): EditState;
|
|
11
11
|
export declare function deleteBack({ value, cursor }: EditState): EditState;
|
|
12
|
+
/** Delete (Supr): removes the character after the cursor, which stays where it is. */
|
|
13
|
+
export declare function deleteForward({ value, cursor }: EditState): EditState;
|
|
14
|
+
/**
|
|
15
|
+
* Whether a raw input chunk is the Delete key: `ESC [ 3 ~`, with modifiers `ESC [ 3 ; 5 ~`,
|
|
16
|
+
* rxvt's `ESC [ 3 $` / `ESC [ 3 ^`, or the kitty protocol's `ESC [ 3 ; …~`. Ink reports it and
|
|
17
|
+
* Backspace (`DEL`, 0x7f, which Windows terminals send too) both as `key.delete`, so only the
|
|
18
|
+
* raw sequence tells them apart.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isForwardDelete(data: string): boolean;
|
|
12
21
|
/** Ctrl+W: deletes the word before the cursor. */
|
|
13
22
|
export declare function deleteWordBack({ value, cursor }: EditState): EditState;
|
|
14
23
|
/** Ctrl+K: deletes from the cursor to the end of its line. */
|
|
@@ -6,6 +6,23 @@ export function deleteBack({ value, cursor }) {
|
|
|
6
6
|
return { value, cursor };
|
|
7
7
|
return { value: value.slice(0, cursor - 1) + value.slice(cursor), cursor: cursor - 1 };
|
|
8
8
|
}
|
|
9
|
+
/** Delete (Supr): removes the character after the cursor, which stays where it is. */
|
|
10
|
+
export function deleteForward({ value, cursor }) {
|
|
11
|
+
if (cursor >= value.length)
|
|
12
|
+
return { value, cursor };
|
|
13
|
+
return { value: value.slice(0, cursor) + value.slice(cursor + 1), cursor };
|
|
14
|
+
}
|
|
15
|
+
// eslint-disable-next-line no-control-regex -- \x1b is the ESC byte the Delete key's sequence starts with
|
|
16
|
+
const FORWARD_DELETE = /^\x1b\[3(;[\d:]*)?[~$^]$/;
|
|
17
|
+
/**
|
|
18
|
+
* Whether a raw input chunk is the Delete key: `ESC [ 3 ~`, with modifiers `ESC [ 3 ; 5 ~`,
|
|
19
|
+
* rxvt's `ESC [ 3 $` / `ESC [ 3 ^`, or the kitty protocol's `ESC [ 3 ; …~`. Ink reports it and
|
|
20
|
+
* Backspace (`DEL`, 0x7f, which Windows terminals send too) both as `key.delete`, so only the
|
|
21
|
+
* raw sequence tells them apart.
|
|
22
|
+
*/
|
|
23
|
+
export function isForwardDelete(data) {
|
|
24
|
+
return FORWARD_DELETE.test(data);
|
|
25
|
+
}
|
|
9
26
|
const isSpace = (char) => char !== undefined && /\s/.test(char);
|
|
10
27
|
/** Where the word before the cursor starts (spaces right before it skipped). */
|
|
11
28
|
function wordStartBefore(value, cursor) {
|