@aigne/cli 1.50.0-beta.1 → 1.50.0-beta.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/CHANGELOG.md +7 -0
- package/dist/commands/aigne.d.ts +1 -2
- package/dist/tracer/terminal.js +5 -2
- package/dist/ui/utils/error.d.ts +2 -0
- package/dist/ui/utils/error.js +2 -0
- package/dist/ui/utils/terminal-input.d.ts +4 -0
- package/dist/ui/utils/terminal-input.js +63 -0
- package/dist/ui/utils/text-buffer.d.ts +87 -0
- package/dist/ui/utils/text-buffer.js +1059 -0
- package/dist/ui/utils/text-utils.d.ts +37 -0
- package/dist/ui/utils/text-utils.js +185 -0
- package/dist/utils/listr.d.ts +1 -1
- package/dist/utils/run-chat-loop.js +5 -17
- package/dist/utils/workers/run-aigne-in-child-process-worker.js +4 -1
- package/dist/utils/workers/run-aigne-in-child-process.js +2 -1
- package/package.json +9 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.50.0-beta.2](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.50.0-beta.1...cli-v1.50.0-beta.2) (2025-09-30)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add multiline support for prompts.input ([#570](https://github.com/AIGNE-io/aigne-framework/issues/570)) ([520d985](https://github.com/AIGNE-io/aigne-framework/commit/520d9859770cc553b551a4a58c7e392b39f53b37))
|
|
9
|
+
|
|
3
10
|
## [1.50.0-beta.1](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.49.2-beta.1...cli-v1.50.0-beta.1) (2025-09-30)
|
|
4
11
|
|
|
5
12
|
|
package/dist/commands/aigne.d.ts
CHANGED
package/dist/tracer/terminal.js
CHANGED
|
@@ -12,6 +12,7 @@ import terminalImage from "terminal-image";
|
|
|
12
12
|
import terminalLink from "terminal-link";
|
|
13
13
|
import { withProtocol } from "ufo";
|
|
14
14
|
import { AIGNE_HUB_CREDITS_NOT_ENOUGH_ERROR_TYPE } from "../constants.js";
|
|
15
|
+
import { terminalInput } from "../ui/utils/terminal-input.js";
|
|
15
16
|
import checkbox from "../utils/inquirer/checkbox.js";
|
|
16
17
|
import { AIGNEListr, AIGNEListrRenderer } from "../utils/listr.js";
|
|
17
18
|
import { highlightUrl } from "../utils/string-utils.js";
|
|
@@ -195,8 +196,10 @@ export class TerminalTracer {
|
|
|
195
196
|
get: (_target, prop) => {
|
|
196
197
|
const method = prop === "checkbox"
|
|
197
198
|
? checkbox
|
|
198
|
-
:
|
|
199
|
-
|
|
199
|
+
: prop === "input"
|
|
200
|
+
? terminalInput
|
|
201
|
+
: // biome-ignore lint/performance/noDynamicNamespaceImportAccess: we need to access prompts dynamically
|
|
202
|
+
prompts[prop];
|
|
200
203
|
if (typeof method !== "function")
|
|
201
204
|
throw new Error(`Unsupported prompt method ${String(prop)}`);
|
|
202
205
|
return async (config) => {
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { render, Text, useInput } from "ink";
|
|
4
|
+
import { SIGINTError } from "./error.js";
|
|
5
|
+
import { useTextBuffer } from "./text-buffer.js";
|
|
6
|
+
export async function terminalInput(options = {}) {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
process.addListener("SIGINT", () => {
|
|
9
|
+
reject(new Error("Input aborted"));
|
|
10
|
+
});
|
|
11
|
+
const app = render(_jsx(Input, { ...options, onSubmit: (value) => {
|
|
12
|
+
app.clear();
|
|
13
|
+
app.unmount();
|
|
14
|
+
console.log(`${options.message} ${value}`); // echo the input back to terminal
|
|
15
|
+
resolve(value);
|
|
16
|
+
}, onError: (error) => {
|
|
17
|
+
app.unmount();
|
|
18
|
+
reject(error);
|
|
19
|
+
} }), { exitOnCtrlC: false });
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function Input(props) {
|
|
23
|
+
const buffer = useTextBuffer({
|
|
24
|
+
initialText: props.default || "",
|
|
25
|
+
isValidPath: () => false,
|
|
26
|
+
viewport: { width: 80, height: 1 },
|
|
27
|
+
});
|
|
28
|
+
useInput((character, key) => {
|
|
29
|
+
if (character === "c" && key.ctrl) {
|
|
30
|
+
props.onError(new SIGINTError("Input aborted by user"));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (key.return) {
|
|
34
|
+
props.onSubmit(buffer.text);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
else if (key.backspace)
|
|
38
|
+
buffer.backspace();
|
|
39
|
+
else if (key.delete)
|
|
40
|
+
buffer.backspace();
|
|
41
|
+
else if (key.downArrow)
|
|
42
|
+
buffer.move("down");
|
|
43
|
+
else if (key.upArrow)
|
|
44
|
+
buffer.move("up");
|
|
45
|
+
else if (key.leftArrow)
|
|
46
|
+
buffer.move("left");
|
|
47
|
+
else if (key.rightArrow)
|
|
48
|
+
buffer.move("right");
|
|
49
|
+
else if (character === "a" && key.ctrl)
|
|
50
|
+
buffer.move("home");
|
|
51
|
+
else if (character === "e" && key.ctrl)
|
|
52
|
+
buffer.move("end");
|
|
53
|
+
else {
|
|
54
|
+
buffer.handleInput({ ...key, name: character, sequence: character, paste: false });
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
const lines = [...buffer.lines];
|
|
58
|
+
const [row, col] = buffer.cursor;
|
|
59
|
+
const currentLine = lines[row] || "";
|
|
60
|
+
lines[row] =
|
|
61
|
+
currentLine.slice(0, col) + chalk.inverse(currentLine[col] || " ") + currentLine.slice(col + 1);
|
|
62
|
+
return (_jsxs(Text, { children: [props.message, " ", lines.join("\n")] }));
|
|
63
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export type Direction = "left" | "right" | "up" | "down" | "wordLeft" | "wordRight" | "home" | "end";
|
|
2
|
+
interface Viewport {
|
|
3
|
+
height: number;
|
|
4
|
+
width: number;
|
|
5
|
+
}
|
|
6
|
+
interface UseTextBufferProps {
|
|
7
|
+
initialText?: string;
|
|
8
|
+
initialCursorOffset?: number;
|
|
9
|
+
viewport: Viewport;
|
|
10
|
+
onChange?: (text: string) => void;
|
|
11
|
+
isValidPath: (path: string) => boolean;
|
|
12
|
+
shellModeActive?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function useTextBuffer({ initialText, initialCursorOffset, viewport, onChange, isValidPath, shellModeActive, }: UseTextBufferProps): TextBuffer;
|
|
15
|
+
export interface TextBuffer {
|
|
16
|
+
lines: string[];
|
|
17
|
+
text: string;
|
|
18
|
+
cursor: [number, number];
|
|
19
|
+
/**
|
|
20
|
+
* When the user moves the caret vertically we try to keep their original
|
|
21
|
+
* horizontal column even when passing through shorter lines. We remember
|
|
22
|
+
* that *preferred* column in this field while the user is still travelling
|
|
23
|
+
* vertically. Any explicit horizontal movement resets the preference.
|
|
24
|
+
*/
|
|
25
|
+
preferredCol: number | null;
|
|
26
|
+
selectionAnchor: [number, number] | null;
|
|
27
|
+
allVisualLines: string[];
|
|
28
|
+
viewportVisualLines: string[];
|
|
29
|
+
visualCursor: [number, number];
|
|
30
|
+
visualScrollRow: number;
|
|
31
|
+
/**
|
|
32
|
+
* For each visual line (by absolute index in allVisualLines) provides a tuple
|
|
33
|
+
* [logicalLineIndex, startColInLogical] that maps where that visual line
|
|
34
|
+
* begins within the logical buffer. Indices are code-point based.
|
|
35
|
+
*/
|
|
36
|
+
visualToLogicalMap: Array<[number, number]>;
|
|
37
|
+
/**
|
|
38
|
+
* Replaces the entire buffer content with the provided text.
|
|
39
|
+
* The operation is undoable.
|
|
40
|
+
*/
|
|
41
|
+
setText: (text: string) => void;
|
|
42
|
+
/**
|
|
43
|
+
* Insert a single character or string without newlines.
|
|
44
|
+
*/
|
|
45
|
+
insert: (ch: string, opts?: {
|
|
46
|
+
paste?: boolean;
|
|
47
|
+
}) => void;
|
|
48
|
+
newline: () => void;
|
|
49
|
+
backspace: () => void;
|
|
50
|
+
del: () => void;
|
|
51
|
+
move: (dir: Direction) => void;
|
|
52
|
+
undo: () => void;
|
|
53
|
+
redo: () => void;
|
|
54
|
+
/**
|
|
55
|
+
* Delete the word to the *left* of the caret, mirroring common
|
|
56
|
+
* Ctrl/Alt+Backspace behaviour in editors & terminals. Both the adjacent
|
|
57
|
+
* whitespace *and* the word characters immediately preceding the caret are
|
|
58
|
+
* removed. If the caret is already at column‑0 this becomes a no-op.
|
|
59
|
+
*/
|
|
60
|
+
deleteWordLeft: () => void;
|
|
61
|
+
/**
|
|
62
|
+
* Delete the word to the *right* of the caret, akin to many editors'
|
|
63
|
+
* Ctrl/Alt+Delete shortcut. Removes any whitespace/punctuation that
|
|
64
|
+
* follows the caret and the next contiguous run of word characters.
|
|
65
|
+
*/
|
|
66
|
+
deleteWordRight: () => void;
|
|
67
|
+
/**
|
|
68
|
+
* Deletes text from the cursor to the end of the current line.
|
|
69
|
+
*/
|
|
70
|
+
killLineRight: () => void;
|
|
71
|
+
/**
|
|
72
|
+
* Deletes text from the start of the current line to the cursor.
|
|
73
|
+
*/
|
|
74
|
+
killLineLeft: () => void;
|
|
75
|
+
/**
|
|
76
|
+
* High level "handleInput" – receives what Ink gives us.
|
|
77
|
+
*/
|
|
78
|
+
handleInput: (key: {
|
|
79
|
+
name: string;
|
|
80
|
+
ctrl: boolean;
|
|
81
|
+
meta: boolean;
|
|
82
|
+
shift: boolean;
|
|
83
|
+
paste: boolean;
|
|
84
|
+
sequence: string;
|
|
85
|
+
}) => void;
|
|
86
|
+
}
|
|
87
|
+
export {};
|