@aigne/cli 1.50.0-beta.1 → 1.50.0-beta.3

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 CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.50.0-beta.3](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.50.0-beta.2...cli-v1.50.0-beta.3) (2025-10-01)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **ui:** enhance terminal input with status indicators and layout options ([#573](https://github.com/AIGNE-io/aigne-framework/issues/573)) ([31b83df](https://github.com/AIGNE-io/aigne-framework/commit/31b83df86fa959a37e6df2df516d7fc3015dc63b))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @aigne/agent-library bumped to 1.21.47-beta.2
16
+ * @aigne/agentic-memory bumped to 1.0.47-beta.2
17
+ * @aigne/aigne-hub bumped to 0.10.1-beta.2
18
+ * @aigne/core bumped to 1.62.0-beta.1
19
+ * @aigne/default-memory bumped to 1.2.10-beta.2
20
+ * @aigne/openai bumped to 0.16.1-beta.2
21
+ * devDependencies
22
+ * @aigne/test-utils bumped to 0.5.54-beta.2
23
+
24
+ ## [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)
25
+
26
+
27
+ ### Features
28
+
29
+ * 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))
30
+
3
31
  ## [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
32
 
5
33
 
@@ -1,5 +1,4 @@
1
- import yargs from "yargs";
2
1
  export declare function createAIGNECommand(options?: {
3
2
  argv?: string[];
4
3
  aigneFilePath?: string;
5
- }): yargs.Argv<{}>;
4
+ }): import("yargs").Argv<{}>;
@@ -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
- : // biome-ignore lint/performance/noDynamicNamespaceImportAccess: we need to access prompts dynamically
199
- prompts[prop];
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,2 @@
1
+ export declare class SIGINTError extends Error {
2
+ }
@@ -0,0 +1,2 @@
1
+ export class SIGINTError extends Error {
2
+ }
@@ -0,0 +1,5 @@
1
+ export declare function terminalInput(options?: {
2
+ message?: string;
3
+ default?: string;
4
+ inline?: boolean;
5
+ }): Promise<string>;
@@ -0,0 +1,81 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import chalk from "chalk";
3
+ import { Box, render, Text, useInput } from "ink";
4
+ import { useState } from "react";
5
+ import { SIGINTError } from "./error.js";
6
+ import { useTextBuffer } from "./text-buffer.js";
7
+ export async function terminalInput(options = {}) {
8
+ return new Promise((resolve, reject) => {
9
+ process.addListener("SIGINT", () => {
10
+ reject(new Error("Input aborted"));
11
+ });
12
+ const app = render(_jsx(Input, { ...options, onSubmit: (value) => {
13
+ app.unmount();
14
+ resolve(value);
15
+ }, onError: (error) => {
16
+ app.unmount();
17
+ reject(error);
18
+ } }), { exitOnCtrlC: false });
19
+ });
20
+ }
21
+ function Input(props) {
22
+ const buffer = useTextBuffer({
23
+ initialText: props.default || "",
24
+ initialCursorOffset: props.default?.length || 0,
25
+ isValidPath: () => false,
26
+ viewport: { width: 80, height: 1 },
27
+ });
28
+ const [status, setStatus] = useState("input");
29
+ useInput((character, key) => {
30
+ if (character === "c" && key.ctrl) {
31
+ setStatus("error");
32
+ setTimeout(() => {
33
+ props.onError(new SIGINTError("Input aborted by user"));
34
+ });
35
+ return;
36
+ }
37
+ if (key.return) {
38
+ setStatus("success");
39
+ setTimeout(() => {
40
+ props.onSubmit(buffer.text);
41
+ });
42
+ return;
43
+ }
44
+ else if (key.backspace)
45
+ buffer.backspace();
46
+ else if (key.delete)
47
+ buffer.backspace();
48
+ else if (key.downArrow)
49
+ buffer.move("down");
50
+ else if (key.upArrow)
51
+ buffer.move("up");
52
+ else if (key.leftArrow)
53
+ buffer.move("left");
54
+ else if (key.rightArrow)
55
+ buffer.move("right");
56
+ else if (character === "a" && key.ctrl)
57
+ buffer.move("home");
58
+ else if (character === "e" && key.ctrl)
59
+ buffer.move("end");
60
+ else {
61
+ buffer.handleInput({ ...key, name: character, sequence: character, paste: false });
62
+ }
63
+ });
64
+ const lines = [...buffer.lines];
65
+ if (status === "input") {
66
+ const [row, col] = buffer.cursor;
67
+ const currentLine = lines[row] || "";
68
+ lines[row] =
69
+ currentLine.slice(0, col) +
70
+ chalk.inverse(currentLine[col] || " ") +
71
+ currentLine.slice(col + 1);
72
+ }
73
+ const label = props.message && chalk.bold(props.message);
74
+ const inline = props.inline !== false;
75
+ return (_jsxs(Box, { flexDirection: inline ? "row" : "column", children: [_jsxs(Text, { children: [PREFIX[status], " ", !inline && label] }), _jsx(Box, { flexShrink: 1, flexGrow: 1, marginLeft: inline ? 0 : 2, children: _jsxs(Text, { children: [!!label && inline && `${label} `, lines.join("\n")] }) })] }));
76
+ }
77
+ const PREFIX = {
78
+ input: chalk.blue("?"),
79
+ success: chalk.green("✔"),
80
+ error: chalk.red("✘"),
81
+ };
@@ -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 {};