@aigne/cli 1.49.2-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 +28 -0
- package/dist/commands/aigne.d.ts +1 -2
- package/dist/commands/app.d.ts +6 -1
- package/dist/commands/app.js +39 -2
- package/dist/commands/eval.js +3 -2
- package/dist/commands/run.js +11 -3
- 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.d.ts +3 -2
- package/dist/utils/workers/run-aigne-in-child-process-worker.js +21 -9
- package/dist/utils/workers/run-aigne-in-child-process.d.ts +5 -0
- package/dist/utils/workers/run-aigne-in-child-process.js +2 -1
- package/package.json +13 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
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
|
+
|
|
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)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* **cli:** support define nested commands for sub apps ([#568](https://github.com/AIGNE-io/aigne-framework/issues/568)) ([0693b80](https://github.com/AIGNE-io/aigne-framework/commit/0693b807e0f8d335010e6ad00763b07cf095e65b))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Dependencies
|
|
19
|
+
|
|
20
|
+
* The following workspace dependencies were updated
|
|
21
|
+
* dependencies
|
|
22
|
+
* @aigne/agent-library bumped to 1.21.47-beta.1
|
|
23
|
+
* @aigne/agentic-memory bumped to 1.0.47-beta.1
|
|
24
|
+
* @aigne/aigne-hub bumped to 0.10.1-beta.1
|
|
25
|
+
* @aigne/core bumped to 1.62.0-beta
|
|
26
|
+
* @aigne/default-memory bumped to 1.2.10-beta.1
|
|
27
|
+
* @aigne/openai bumped to 0.16.1-beta.1
|
|
28
|
+
* devDependencies
|
|
29
|
+
* @aigne/test-utils bumped to 0.5.54-beta.1
|
|
30
|
+
|
|
3
31
|
## [1.49.2-beta.1](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.49.2-beta...cli-v1.49.2-beta.1) (2025-09-29)
|
|
4
32
|
|
|
5
33
|
|
package/dist/commands/aigne.d.ts
CHANGED
package/dist/commands/app.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CommandModule } from "yargs";
|
|
2
|
-
import { type AgentInChildProcess, type LoadAIGNEInChildProcessResult } from "../utils/workers/run-aigne-in-child-process.js";
|
|
2
|
+
import { type AgentInChildProcess, type CLIAgentInChildProcess, type LoadAIGNEInChildProcessResult } from "../utils/workers/run-aigne-in-child-process.js";
|
|
3
3
|
import { type AgentRunCommonOptions } from "../utils/yargs.js";
|
|
4
4
|
export declare function createAppCommands({ argv }?: {
|
|
5
5
|
argv?: string[];
|
|
@@ -8,6 +8,11 @@ export declare const agentCommandModule: ({ dir, agent, }: {
|
|
|
8
8
|
dir: string;
|
|
9
9
|
agent: AgentInChildProcess;
|
|
10
10
|
}) => CommandModule<unknown, AgentRunCommonOptions>;
|
|
11
|
+
export declare const cliAgentCommandModule: ({ dir, parent, cliAgent, }: {
|
|
12
|
+
dir: string;
|
|
13
|
+
parent?: string[];
|
|
14
|
+
cliAgent: CLIAgentInChildProcess;
|
|
15
|
+
}) => CommandModule<unknown, AgentRunCommonOptions>;
|
|
11
16
|
interface LoadApplicationOptions {
|
|
12
17
|
packageName: string;
|
|
13
18
|
dir: string;
|
package/dist/commands/app.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
1
2
|
import { spawn } from "node:child_process";
|
|
2
3
|
import { mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
3
4
|
import { homedir } from "node:os";
|
|
@@ -53,8 +54,8 @@ export function createAppCommands({ argv } = {}) {
|
|
|
53
54
|
command: "$0",
|
|
54
55
|
});
|
|
55
56
|
}
|
|
56
|
-
for (const
|
|
57
|
-
y.command(
|
|
57
|
+
for (const cliAgent of aigne.cli?.agents ?? []) {
|
|
58
|
+
y.command(cliAgentCommandModule({ dir, cliAgent }));
|
|
58
59
|
}
|
|
59
60
|
y.option("model", {
|
|
60
61
|
type: "string",
|
|
@@ -152,6 +153,42 @@ export const agentCommandModule = ({ dir, agent, }) => {
|
|
|
152
153
|
},
|
|
153
154
|
};
|
|
154
155
|
};
|
|
156
|
+
export const cliAgentCommandModule = ({ dir, parent, cliAgent, }) => {
|
|
157
|
+
const { agent, agents } = cliAgent;
|
|
158
|
+
const name = cliAgent.name || agent?.name;
|
|
159
|
+
assert(name, "CLI agent must have a name");
|
|
160
|
+
return {
|
|
161
|
+
command: name,
|
|
162
|
+
aliases: cliAgent.alias || agent?.alias || [],
|
|
163
|
+
describe: cliAgent.description || agent?.description || "",
|
|
164
|
+
builder: async (yargs) => {
|
|
165
|
+
if (agent) {
|
|
166
|
+
withAgentInputSchema(yargs, { inputSchema: jsonSchemaToZod(agent.inputSchema) });
|
|
167
|
+
}
|
|
168
|
+
if (agents?.length) {
|
|
169
|
+
for (const cmd of agents) {
|
|
170
|
+
yargs.command(cliAgentCommandModule({ dir, parent: (parent ?? []).concat(name), cliAgent: cmd }));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (!agent)
|
|
174
|
+
yargs.demandCommand();
|
|
175
|
+
return yargs;
|
|
176
|
+
},
|
|
177
|
+
handler: async (options) => {
|
|
178
|
+
if (!agent)
|
|
179
|
+
throw new Error("CLI agent is not defined");
|
|
180
|
+
if (options.logLevel)
|
|
181
|
+
logger.level = options.logLevel;
|
|
182
|
+
await runAIGNEInChildProcess("invokeCLIAgentFromDir", {
|
|
183
|
+
dir,
|
|
184
|
+
parent,
|
|
185
|
+
agent: name,
|
|
186
|
+
input: options,
|
|
187
|
+
});
|
|
188
|
+
process.exit(0);
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
};
|
|
155
192
|
export async function loadApplication(options) {
|
|
156
193
|
const { dir, packageName } = options;
|
|
157
194
|
const check = await checkInstallation(dir);
|
package/dist/commands/eval.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isAbsolute, resolve } from "node:path";
|
|
2
2
|
import { exists } from "@aigne/agent-library/utils/fs.js";
|
|
3
|
+
import { findCliAgent } from "@aigne/core/utils/agent-utils.js";
|
|
3
4
|
import { z } from "zod";
|
|
4
5
|
import { runEvaluationPipeline } from "../utils/evaluation/core.js";
|
|
5
6
|
import { FileDataset } from "../utils/evaluation/dataset.js";
|
|
@@ -70,7 +71,7 @@ export function createEvalCommand({ aigneFilePath, } = {}) {
|
|
|
70
71
|
const { chat } = aigne.cli;
|
|
71
72
|
const agent = chat && chat.name === entryAgent
|
|
72
73
|
? chat
|
|
73
|
-
: aigne.cli
|
|
74
|
+
: findCliAgent(aigne.cli, "*", entryAgent) ||
|
|
74
75
|
aigne.agents[entryAgent] ||
|
|
75
76
|
aigne.skills[entryAgent] ||
|
|
76
77
|
aigne.mcpServer.agents[entryAgent];
|
|
@@ -80,7 +81,7 @@ export function createEvalCommand({ aigneFilePath, } = {}) {
|
|
|
80
81
|
let evaluatorAgent;
|
|
81
82
|
if (evaluatorName) {
|
|
82
83
|
evaluatorAgent =
|
|
83
|
-
aigne.cli
|
|
84
|
+
findCliAgent(aigne.cli, "*", evaluatorName) ||
|
|
84
85
|
aigne.agents[evaluatorName] ||
|
|
85
86
|
aigne.skills[evaluatorName] ||
|
|
86
87
|
aigne.mcpServer.agents[evaluatorName];
|
package/dist/commands/run.js
CHANGED
|
@@ -2,6 +2,7 @@ import { cp, mkdir, rm } from "node:fs/promises";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { isAbsolute, join, resolve } from "node:path";
|
|
4
4
|
import { exists } from "@aigne/agent-library/utils/fs.js";
|
|
5
|
+
import { mapCliAgent } from "@aigne/core/utils/agent-utils.js";
|
|
5
6
|
import { flat, isNonNullable } from "@aigne/core/utils/type-utils.js";
|
|
6
7
|
import { Listr, PRESET_TIMER } from "@aigne/listr2";
|
|
7
8
|
import { config } from "dotenv-flow";
|
|
@@ -11,7 +12,7 @@ import { downloadAndExtract } from "../utils/download.js";
|
|
|
11
12
|
import { loadAIGNE } from "../utils/load-aigne.js";
|
|
12
13
|
import { isUrl } from "../utils/url.js";
|
|
13
14
|
import { serializeAgent } from "../utils/workers/run-aigne-in-child-process.js";
|
|
14
|
-
import { agentCommandModule } from "./app.js";
|
|
15
|
+
import { agentCommandModule, cliAgentCommandModule } from "./app.js";
|
|
15
16
|
export function createRunCommand({ aigneFilePath, } = {}) {
|
|
16
17
|
return {
|
|
17
18
|
command: "run [path] [entry-agent]",
|
|
@@ -47,10 +48,16 @@ export function createRunCommand({ aigneFilePath, } = {}) {
|
|
|
47
48
|
});
|
|
48
49
|
}
|
|
49
50
|
// Allow user to run all of agents in the AIGNE instances
|
|
50
|
-
const allAgents = flat(aigne.
|
|
51
|
+
const allAgents = flat(aigne.agents, aigne.skills, aigne.cli.chat, aigne.mcpServer.agents);
|
|
51
52
|
for (const agent of allAgents) {
|
|
52
53
|
subYargs.command(agentCommandModule({ dir: path, agent: serializeAgent(agent) }));
|
|
53
54
|
}
|
|
55
|
+
for (const cliAgent of aigne.cli.agents ?? []) {
|
|
56
|
+
subYargs.command(cliAgentCommandModule({
|
|
57
|
+
dir: path,
|
|
58
|
+
cliAgent: mapCliAgent(cliAgent, (a) => (a ? serializeAgent(a) : undefined)),
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
54
61
|
const argv = process.argv.slice(aigneFilePath ? 3 : 2);
|
|
55
62
|
if (argv[0] === "run")
|
|
56
63
|
argv.shift(); // remove 'run' command
|
|
@@ -62,8 +69,9 @@ export function createRunCommand({ aigneFilePath, } = {}) {
|
|
|
62
69
|
if (argv[0] === "--entry-agent")
|
|
63
70
|
argv.shift();
|
|
64
71
|
const firstAgent = aigne.agents[0]?.name;
|
|
65
|
-
if (!options.entryAgent && firstAgent)
|
|
72
|
+
if (!options.entryAgent && firstAgent && !argv.some((i) => ["-h", "--help"].includes(i))) {
|
|
66
73
|
argv.unshift(firstAgent);
|
|
74
|
+
}
|
|
67
75
|
await subYargs
|
|
68
76
|
.strict()
|
|
69
77
|
.demandCommand()
|
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 {};
|