@aigne/cli 1.1.0 → 1.3.0
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 +22 -0
- package/dist/cli.js +7 -1
- package/dist/commands/run.js +76 -23
- package/dist/tracer/terminal.d.ts +52 -0
- package/dist/tracer/terminal.js +179 -0
- package/dist/utils/agent-v1.d.ts +134 -0
- package/dist/utils/agent-v1.js +209 -0
- package/dist/utils/download.d.ts +1 -0
- package/dist/utils/download.js +21 -0
- package/dist/utils/run-chat-loop.d.ts +10 -0
- package/dist/utils/run-chat-loop.js +76 -0
- package/dist/utils/time.d.ts +1 -0
- package/dist/utils/time.js +12 -0
- package/package.json +17 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.3.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.2.0...cli-v1.3.0) (2025-04-17)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **ci:** support coverage examples with model matrix ([#59](https://github.com/AIGNE-io/aigne-framework/issues/59)) ([1edd704](https://github.com/AIGNE-io/aigne-framework/commit/1edd70426b80a69e3751b2d5fe818297711d0777))
|
|
9
|
+
* **cli:** support convert agents from studio ([#64](https://github.com/AIGNE-io/aigne-framework/issues/64)) ([f544bc7](https://github.com/AIGNE-io/aigne-framework/commit/f544bc77a2fb07e034b317ceb6a46aadd35830c9))
|
|
10
|
+
* **cli:** support model and download customization for aigne run ([#61](https://github.com/AIGNE-io/aigne-framework/issues/61)) ([51f6619](https://github.com/AIGNE-io/aigne-framework/commit/51f6619e6c591a84f1f2339b26ef66d89fa9486e))
|
|
11
|
+
|
|
12
|
+
## [1.2.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.1.0...cli-v1.2.0) (2025-04-15)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* add TerminalTracer for better UX in terminal ([#56](https://github.com/AIGNE-io/aigne-framework/issues/56)) ([9875a5d](https://github.com/AIGNE-io/aigne-framework/commit/9875a5d46abb55073340ffae841fed6bd6b83ff4))
|
|
18
|
+
* **cli:** support run agents from remote URL ([#60](https://github.com/AIGNE-io/aigne-framework/issues/60)) ([5f49920](https://github.com/AIGNE-io/aigne-framework/commit/5f4992089d36f9e780ba55a912a1d35508cad28e))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Bug Fixes
|
|
22
|
+
|
|
23
|
+
* remove usage of new Node.js exists API for compatibility ([#57](https://github.com/AIGNE-io/aigne-framework/issues/57)) ([c10cc08](https://github.com/AIGNE-io/aigne-framework/commit/c10cc086d8ecd0744f38cdb1367d4c8816b723b3))
|
|
24
|
+
|
|
3
25
|
## [1.1.0](https://github.com/AIGNE-io/aigne-framework/compare/cli-v1.0.0...cli-v1.1.0) (2025-04-08)
|
|
4
26
|
|
|
5
27
|
|
package/dist/cli.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import PrettyError from "pretty-error";
|
|
2
3
|
import { createAIGNECommand } from "./commands/aigne.js";
|
|
3
|
-
createAIGNECommand()
|
|
4
|
+
createAIGNECommand()
|
|
5
|
+
.parseAsync()
|
|
6
|
+
.catch((error) => {
|
|
7
|
+
console.error(new PrettyError().render(error));
|
|
8
|
+
process.exit(1);
|
|
9
|
+
});
|
package/dist/commands/run.js
CHANGED
|
@@ -1,35 +1,88 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cp, mkdir, rm } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
2
4
|
import { ExecutionEngine } from "@aigne/core";
|
|
3
|
-
import {
|
|
5
|
+
import { loadModel } from "@aigne/core/loader/index.js";
|
|
6
|
+
import { isNonNullable } from "@aigne/core/utils/type-utils.js";
|
|
4
7
|
import { Command } from "commander";
|
|
8
|
+
import { isV1Package, toAIGNEPackage } from "../utils/agent-v1.js";
|
|
9
|
+
import { downloadAndExtract } from "../utils/download.js";
|
|
10
|
+
import { runChatLoopInTerminal } from "../utils/run-chat-loop.js";
|
|
5
11
|
export function createRunCommand() {
|
|
6
12
|
return new Command("run")
|
|
7
13
|
.description("Run a chat loop with the specified agent")
|
|
8
|
-
.argument("[path]", "Path to the agents directory", ".")
|
|
14
|
+
.argument("[path]", "Path to the agents directory or URL to aigne project", ".")
|
|
9
15
|
.option("--agent <agent>", "Name of the agent to use (defaults to the first agent found)")
|
|
16
|
+
.option("--download-dir <dir>", "Directory to download the package to (defaults to the ~/.aigne/xxx)")
|
|
17
|
+
.option("--model-provider <provider>", "Model provider to use, available providers: openai, claude, xai (defaults to the aigne.yaml definition or openai)")
|
|
18
|
+
.option("--model-name <model>", "Model name to use, available models depend on the provider (defaults to the aigne.yaml definition or gpt-4o-mini)")
|
|
10
19
|
.action(async (path, options) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (options.agent) {
|
|
15
|
-
agent = engine.agents[options.agent];
|
|
16
|
-
if (!agent) {
|
|
17
|
-
console.error(`Agent "${options.agent}" not found.`);
|
|
18
|
-
console.log("Available agents:");
|
|
19
|
-
for (const agent of engine.agents) {
|
|
20
|
-
console.log(`- ${agent.name}`);
|
|
21
|
-
}
|
|
22
|
-
throw new Error(`Agent "${options.agent}" not found`);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
agent = engine.agents[0];
|
|
27
|
-
if (!agent)
|
|
28
|
-
throw new Error("No agents found in the specified path");
|
|
20
|
+
if (path.startsWith("http")) {
|
|
21
|
+
await downloadAndRunPackage(path, options);
|
|
22
|
+
return;
|
|
29
23
|
}
|
|
30
|
-
const
|
|
31
|
-
await
|
|
24
|
+
const absolutePath = isAbsolute(path) ? path : resolve(process.cwd(), path);
|
|
25
|
+
await runEngine(path, absolutePath, options);
|
|
32
26
|
})
|
|
33
27
|
.showHelpAfterError(true)
|
|
34
28
|
.showSuggestionAfterError(true);
|
|
35
29
|
}
|
|
30
|
+
async function runEngine(originalPath, path, options) {
|
|
31
|
+
if (options.modelName && !options.modelProvider) {
|
|
32
|
+
throw new Error("please specify --model-provider when using the --model-name option");
|
|
33
|
+
}
|
|
34
|
+
const model = options.modelProvider
|
|
35
|
+
? await loadModel({ provider: options.modelProvider, name: options.modelName })
|
|
36
|
+
: undefined;
|
|
37
|
+
const engine = await ExecutionEngine.load({ path, model });
|
|
38
|
+
let agent;
|
|
39
|
+
if (options.agent) {
|
|
40
|
+
agent = engine.agents[options.agent];
|
|
41
|
+
if (!agent) {
|
|
42
|
+
console.error(`Agent "${options.agent}" not found in ${originalPath}`);
|
|
43
|
+
console.log("Available agents:");
|
|
44
|
+
for (const agent of engine.agents) {
|
|
45
|
+
console.log(`- ${agent.name}`);
|
|
46
|
+
}
|
|
47
|
+
throw new Error(`Agent "${options.agent}" not found in ${originalPath}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
agent = engine.agents[0];
|
|
52
|
+
if (!agent)
|
|
53
|
+
throw new Error(`No agents found in ${originalPath}`);
|
|
54
|
+
}
|
|
55
|
+
const user = engine.call(agent);
|
|
56
|
+
await runChatLoopInTerminal(user, {});
|
|
57
|
+
}
|
|
58
|
+
async function downloadAndRunPackage(url, options) {
|
|
59
|
+
let dir;
|
|
60
|
+
let downloadDir;
|
|
61
|
+
if (options.downloadDir) {
|
|
62
|
+
dir = isAbsolute(options.downloadDir)
|
|
63
|
+
? options.downloadDir
|
|
64
|
+
: resolve(process.cwd(), options.downloadDir);
|
|
65
|
+
downloadDir = join(dir, ".download");
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
dir = getLocalPackagePathFromUrl(url);
|
|
69
|
+
downloadDir = getLocalPackagePathFromUrl(url, { subdir: ".download" });
|
|
70
|
+
}
|
|
71
|
+
// clean up the download directory
|
|
72
|
+
await rm(downloadDir, { recursive: true, force: true });
|
|
73
|
+
await mkdir(dir, { recursive: true });
|
|
74
|
+
await mkdir(downloadDir, { recursive: true });
|
|
75
|
+
await downloadAndExtract(url, downloadDir);
|
|
76
|
+
if (await isV1Package(downloadDir)) {
|
|
77
|
+
await toAIGNEPackage(downloadDir, dir);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
await cp(downloadDir, dir, { recursive: true, force: true });
|
|
81
|
+
}
|
|
82
|
+
await runEngine(url, dir, options);
|
|
83
|
+
}
|
|
84
|
+
function getLocalPackagePathFromUrl(url, { subdir } = {}) {
|
|
85
|
+
const root = [homedir(), ".aigne", subdir].filter(isNonNullable);
|
|
86
|
+
const u = new URL(url);
|
|
87
|
+
return join(...root, u.hostname, u.pathname);
|
|
88
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type Agent, type Context, type Message } from "@aigne/core";
|
|
2
|
+
import type { ContextUsage } from "@aigne/core/execution-engine/usage";
|
|
3
|
+
import { type DefaultRenderer, Listr, type ListrRenderer, type ListrTaskWrapper } from "@aigne/listr2";
|
|
4
|
+
export interface TerminalTracerOptions {
|
|
5
|
+
verbose?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare class TerminalTracer {
|
|
8
|
+
readonly context: Context;
|
|
9
|
+
readonly options: TerminalTracerOptions;
|
|
10
|
+
constructor(context: Context, options?: TerminalTracerOptions);
|
|
11
|
+
private spinner;
|
|
12
|
+
private tasks;
|
|
13
|
+
run(agent: Agent, input: Message): Promise<{
|
|
14
|
+
result: any;
|
|
15
|
+
context: Context;
|
|
16
|
+
}>;
|
|
17
|
+
protected newListr(): MyListr;
|
|
18
|
+
formatAgentStartedOutput(agent: Agent, data: Message): string;
|
|
19
|
+
formatAgentSucceedOutput(agent: Agent, data: Message): string;
|
|
20
|
+
formatAgentFailedOutput(agent: Agent, data: Error): string;
|
|
21
|
+
formatMessage(data: unknown): string;
|
|
22
|
+
formatTokenUsage(usage: Partial<ContextUsage>, extra?: {
|
|
23
|
+
[key: string]: string;
|
|
24
|
+
}): string;
|
|
25
|
+
formatTimeUsage(startTime: number, endTime: number): string;
|
|
26
|
+
formatTaskTitle(agent: Agent, { task, usage, time }?: {
|
|
27
|
+
task?: Task;
|
|
28
|
+
usage?: boolean;
|
|
29
|
+
time?: boolean;
|
|
30
|
+
}): string;
|
|
31
|
+
}
|
|
32
|
+
type Task = ReturnType<typeof Promise.withResolvers<void>> & {
|
|
33
|
+
listr: ReturnType<typeof Promise.withResolvers<{
|
|
34
|
+
ctx: object;
|
|
35
|
+
subtask: Listr;
|
|
36
|
+
taskWrapper: ListrTaskWrapper<unknown, typeof DefaultRenderer, typeof ListrRenderer>;
|
|
37
|
+
}>>;
|
|
38
|
+
startTime?: number;
|
|
39
|
+
endTime?: number;
|
|
40
|
+
usage?: Partial<ContextUsage>;
|
|
41
|
+
extraTitleMetadata?: {
|
|
42
|
+
[key: string]: string;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
declare class MyListr extends Listr {
|
|
46
|
+
private taskPromise;
|
|
47
|
+
private isTaskPromiseResolved;
|
|
48
|
+
resolveWaitingTask(): void;
|
|
49
|
+
add(...args: Parameters<Listr["add"]>): ReturnType<Listr["add"]>;
|
|
50
|
+
waitTaskAndRun(ctx?: unknown): Promise<any>;
|
|
51
|
+
}
|
|
52
|
+
export {};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { inspect } from "node:util";
|
|
2
|
+
import { ChatModel, } from "@aigne/core";
|
|
3
|
+
import { Listr, ListrDefaultRendererLogLevels, Spinner, figures, } from "@aigne/listr2";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { parseDuration } from "../utils/time.js";
|
|
7
|
+
const DEBUG_DEPTH = z.number().int().default(2).safeParse(Number(process.env.DEBUG_DEPTH)).data;
|
|
8
|
+
export class TerminalTracer {
|
|
9
|
+
context;
|
|
10
|
+
options;
|
|
11
|
+
constructor(context, options = {}) {
|
|
12
|
+
this.context = context;
|
|
13
|
+
this.options = options;
|
|
14
|
+
}
|
|
15
|
+
spinner = new Spinner();
|
|
16
|
+
tasks = {};
|
|
17
|
+
async run(agent, input) {
|
|
18
|
+
try {
|
|
19
|
+
this.spinner.start();
|
|
20
|
+
const context = this.context.newContext({ reset: true });
|
|
21
|
+
const listr = this.newListr();
|
|
22
|
+
context.on("agentStarted", async ({ contextId, parentContextId, agent, input, timestamp }) => {
|
|
23
|
+
const task = {
|
|
24
|
+
...Promise.withResolvers(),
|
|
25
|
+
listr: Promise.withResolvers(),
|
|
26
|
+
startTime: timestamp,
|
|
27
|
+
};
|
|
28
|
+
this.tasks[contextId] = task;
|
|
29
|
+
const listrTask = {
|
|
30
|
+
title: this.formatTaskTitle(agent),
|
|
31
|
+
task: (ctx, taskWrapper) => {
|
|
32
|
+
const subtask = taskWrapper.newListr([{ task: () => task.promise }]);
|
|
33
|
+
task.listr.resolve({ subtask, taskWrapper, ctx });
|
|
34
|
+
return subtask;
|
|
35
|
+
},
|
|
36
|
+
rendererOptions: {
|
|
37
|
+
persistentOutput: true,
|
|
38
|
+
outputBar: Number.POSITIVE_INFINITY,
|
|
39
|
+
bottomBar: Number.POSITIVE_INFINITY,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
const parentTask = parentContextId ? this.tasks[parentContextId] : undefined;
|
|
43
|
+
if (parentTask) {
|
|
44
|
+
parentTask.listr.promise.then(({ subtask }) => {
|
|
45
|
+
subtask.add(listrTask);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
listr.add(listrTask);
|
|
50
|
+
}
|
|
51
|
+
const { taskWrapper } = await task.listr.promise;
|
|
52
|
+
if (this.options.verbose) {
|
|
53
|
+
taskWrapper.output = this.formatAgentStartedOutput(agent, input);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
context.on("agentSucceed", async ({ agent, contextId, parentContextId, output, timestamp }) => {
|
|
57
|
+
const task = this.tasks[contextId];
|
|
58
|
+
if (!task)
|
|
59
|
+
return;
|
|
60
|
+
task.endTime = timestamp;
|
|
61
|
+
const { taskWrapper, ctx } = await task.listr.promise;
|
|
62
|
+
if (agent instanceof ChatModel) {
|
|
63
|
+
const { usage, model } = output;
|
|
64
|
+
task.usage = usage;
|
|
65
|
+
task.extraTitleMetadata ??= {};
|
|
66
|
+
if (model)
|
|
67
|
+
task.extraTitleMetadata.model = model;
|
|
68
|
+
}
|
|
69
|
+
taskWrapper.title = this.formatTaskTitle(agent, { task, usage: true, time: true });
|
|
70
|
+
if (this.options.verbose) {
|
|
71
|
+
taskWrapper.output = this.formatAgentSucceedOutput(agent, output);
|
|
72
|
+
}
|
|
73
|
+
if (!parentContextId || !this.tasks[parentContextId]) {
|
|
74
|
+
Object.assign(ctx, output);
|
|
75
|
+
}
|
|
76
|
+
task.resolve();
|
|
77
|
+
});
|
|
78
|
+
context.on("agentFailed", async ({ agent, contextId, error, timestamp }) => {
|
|
79
|
+
const task = this.tasks[contextId];
|
|
80
|
+
if (!task)
|
|
81
|
+
return;
|
|
82
|
+
task.endTime = timestamp;
|
|
83
|
+
const { taskWrapper } = await task.listr.promise;
|
|
84
|
+
taskWrapper.title = this.formatTaskTitle(agent, { task, usage: true, time: true });
|
|
85
|
+
taskWrapper.output = this.formatAgentFailedOutput(agent, error);
|
|
86
|
+
task.reject(error);
|
|
87
|
+
});
|
|
88
|
+
const [result] = await Promise.all([
|
|
89
|
+
listr.waitTaskAndRun(),
|
|
90
|
+
context.call(agent, input).finally(() => {
|
|
91
|
+
listr.resolveWaitingTask();
|
|
92
|
+
}),
|
|
93
|
+
]);
|
|
94
|
+
return { result, context };
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
this.spinner.stop();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
newListr() {
|
|
101
|
+
return new MyListr([], {
|
|
102
|
+
concurrent: true,
|
|
103
|
+
rendererOptions: {
|
|
104
|
+
collapseSubtasks: false,
|
|
105
|
+
writeBottomBarDirectly: true,
|
|
106
|
+
icon: {
|
|
107
|
+
[ListrDefaultRendererLogLevels.PENDING]: () => this.spinner.fetch(),
|
|
108
|
+
[ListrDefaultRendererLogLevels.OUTPUT_WITH_BOTTOMBAR]: "",
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
formatAgentStartedOutput(agent, data) {
|
|
114
|
+
return `\
|
|
115
|
+
${chalk.grey(figures.pointer)} call agent ${agent.name} started with input:
|
|
116
|
+
${this.formatMessage(data)}`;
|
|
117
|
+
}
|
|
118
|
+
formatAgentSucceedOutput(agent, data) {
|
|
119
|
+
return `\
|
|
120
|
+
${chalk.grey(figures.tick)} call agent ${agent.name} succeed with output:
|
|
121
|
+
${this.formatMessage(data)}`;
|
|
122
|
+
}
|
|
123
|
+
formatAgentFailedOutput(agent, data) {
|
|
124
|
+
return `\
|
|
125
|
+
${chalk.grey(figures.cross)} call agent ${agent.name} failed with error:
|
|
126
|
+
${this.formatMessage(data)}`;
|
|
127
|
+
}
|
|
128
|
+
formatMessage(data) {
|
|
129
|
+
return inspect(data, { colors: true, depth: DEBUG_DEPTH });
|
|
130
|
+
}
|
|
131
|
+
formatTokenUsage(usage, extra) {
|
|
132
|
+
const items = [
|
|
133
|
+
[chalk.yellow(usage.inputTokens), chalk.grey("input tokens")],
|
|
134
|
+
[chalk.cyan(usage.outputTokens), chalk.grey("output tokens")],
|
|
135
|
+
usage.agentCalls ? [chalk.magenta(usage.agentCalls), chalk.grey("agent calls")] : undefined,
|
|
136
|
+
];
|
|
137
|
+
const content = items.filter((i) => !!i).map((i) => i.join(" "));
|
|
138
|
+
if (extra) {
|
|
139
|
+
content.unshift(...Object.entries(extra)
|
|
140
|
+
.filter(([k, v]) => k && v)
|
|
141
|
+
.map(([k, v]) => `${chalk.grey(k)}: ${v}`));
|
|
142
|
+
}
|
|
143
|
+
return `${chalk.grey("(")}${content.join(chalk.green(", "))}${chalk.grey(")")}`;
|
|
144
|
+
}
|
|
145
|
+
formatTimeUsage(startTime, endTime) {
|
|
146
|
+
const duration = endTime - startTime;
|
|
147
|
+
return chalk.grey(`[${parseDuration(duration)}]`);
|
|
148
|
+
}
|
|
149
|
+
formatTaskTitle(agent, { task, usage, time } = {}) {
|
|
150
|
+
let title = `call agent ${agent.name}`;
|
|
151
|
+
if (usage && task?.usage)
|
|
152
|
+
title += ` ${this.formatTokenUsage(task.usage, task.extraTitleMetadata)}`;
|
|
153
|
+
if (time && task?.startTime && task.endTime)
|
|
154
|
+
title += ` ${this.formatTimeUsage(task.startTime, task.endTime)}`;
|
|
155
|
+
return title;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
class MyListr extends Listr {
|
|
159
|
+
taskPromise = Promise.withResolvers();
|
|
160
|
+
isTaskPromiseResolved = false;
|
|
161
|
+
resolveWaitingTask() {
|
|
162
|
+
if (!this.isTaskPromiseResolved) {
|
|
163
|
+
this.taskPromise.resolve();
|
|
164
|
+
this.isTaskPromiseResolved = true;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
add(...args) {
|
|
168
|
+
const result = super.add(...args);
|
|
169
|
+
this.resolveWaitingTask();
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
172
|
+
async waitTaskAndRun(ctx) {
|
|
173
|
+
if (!this.tasks.length)
|
|
174
|
+
await this.taskPromise.promise;
|
|
175
|
+
if (!this.tasks.length)
|
|
176
|
+
return ctx;
|
|
177
|
+
return super.run(ctx);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
export declare function isV1Package(src: string): Promise<boolean>;
|
|
2
|
+
export declare function toAIGNEPackage(src: string, dst: string): Promise<void>;
|
|
3
|
+
export type Parameter = {
|
|
4
|
+
id: string;
|
|
5
|
+
key?: string;
|
|
6
|
+
hidden?: boolean;
|
|
7
|
+
required?: boolean;
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
} & ({
|
|
10
|
+
type?: "string" | "number" | "boolean" | "language";
|
|
11
|
+
} | {
|
|
12
|
+
type?: "select";
|
|
13
|
+
options?: {
|
|
14
|
+
id: string;
|
|
15
|
+
label?: string;
|
|
16
|
+
value?: string;
|
|
17
|
+
}[];
|
|
18
|
+
});
|
|
19
|
+
export interface VariableTypeBase {
|
|
20
|
+
id: string;
|
|
21
|
+
name?: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
required?: boolean;
|
|
24
|
+
hidden?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export type OutputVariable = VariableTypeBase & ({
|
|
27
|
+
type?: undefined;
|
|
28
|
+
} | {
|
|
29
|
+
type: "string";
|
|
30
|
+
defaultValue?: string;
|
|
31
|
+
} | {
|
|
32
|
+
type: "number";
|
|
33
|
+
defaultValue?: number;
|
|
34
|
+
} | {
|
|
35
|
+
type: "boolean";
|
|
36
|
+
defaultValue?: boolean;
|
|
37
|
+
} | {
|
|
38
|
+
type: "object";
|
|
39
|
+
properties?: OutputVariable[];
|
|
40
|
+
} | {
|
|
41
|
+
type: "array";
|
|
42
|
+
element?: OutputVariable;
|
|
43
|
+
});
|
|
44
|
+
export type AgentV1 = {
|
|
45
|
+
id: string;
|
|
46
|
+
name?: string;
|
|
47
|
+
description?: string;
|
|
48
|
+
parameters?: Parameter[];
|
|
49
|
+
outputVariables?: OutputVariable[];
|
|
50
|
+
} & ({
|
|
51
|
+
type: "prompt";
|
|
52
|
+
prompts?: Prompt[];
|
|
53
|
+
temperature?: number;
|
|
54
|
+
topP?: number;
|
|
55
|
+
presencePenalty?: number;
|
|
56
|
+
frequencyPenalty?: number;
|
|
57
|
+
maxTokens?: number;
|
|
58
|
+
model?: string;
|
|
59
|
+
} | {
|
|
60
|
+
type: "router";
|
|
61
|
+
defaultToolId?: string;
|
|
62
|
+
prompt?: string;
|
|
63
|
+
decisionType?: "ai";
|
|
64
|
+
routes?: Tool[];
|
|
65
|
+
temperature?: number;
|
|
66
|
+
topP?: number;
|
|
67
|
+
presencePenalty?: number;
|
|
68
|
+
frequencyPenalty?: number;
|
|
69
|
+
maxTokens?: number;
|
|
70
|
+
model?: string;
|
|
71
|
+
} | {
|
|
72
|
+
type: "image";
|
|
73
|
+
prompt?: string;
|
|
74
|
+
model?: string;
|
|
75
|
+
n?: number;
|
|
76
|
+
quality?: string;
|
|
77
|
+
style?: string;
|
|
78
|
+
size?: string;
|
|
79
|
+
modelSettings?: {
|
|
80
|
+
[key: string]: unknown;
|
|
81
|
+
};
|
|
82
|
+
} | {
|
|
83
|
+
type: "api";
|
|
84
|
+
requestParameters?: {
|
|
85
|
+
id: string;
|
|
86
|
+
key?: string;
|
|
87
|
+
value?: string;
|
|
88
|
+
}[];
|
|
89
|
+
requestMethod?: string;
|
|
90
|
+
requestUrl?: string;
|
|
91
|
+
requestHeaders: {
|
|
92
|
+
id: string;
|
|
93
|
+
key?: string;
|
|
94
|
+
value?: string;
|
|
95
|
+
}[];
|
|
96
|
+
} | {
|
|
97
|
+
type: "function";
|
|
98
|
+
code?: string;
|
|
99
|
+
} | {
|
|
100
|
+
type: "callAgent";
|
|
101
|
+
agents?: Tool[];
|
|
102
|
+
});
|
|
103
|
+
export interface ProjectDefinitionV1 {
|
|
104
|
+
project: {
|
|
105
|
+
name?: string;
|
|
106
|
+
description?: string;
|
|
107
|
+
};
|
|
108
|
+
agents: AgentV1[];
|
|
109
|
+
}
|
|
110
|
+
export type Prompt = {
|
|
111
|
+
type: "message";
|
|
112
|
+
data: PromptMessage;
|
|
113
|
+
visibility?: "hidden";
|
|
114
|
+
} | {
|
|
115
|
+
type: "executeBlock";
|
|
116
|
+
visibility?: "hidden";
|
|
117
|
+
};
|
|
118
|
+
export type PromptMessage = {
|
|
119
|
+
id: string;
|
|
120
|
+
role: Role;
|
|
121
|
+
content?: string;
|
|
122
|
+
name?: string;
|
|
123
|
+
};
|
|
124
|
+
export type Role = "system" | "user" | "assistant";
|
|
125
|
+
export type Tool = {
|
|
126
|
+
blockletDid?: string;
|
|
127
|
+
projectId?: string;
|
|
128
|
+
id: string;
|
|
129
|
+
from?: "assistant" | "blockletAPI" | "knowledge";
|
|
130
|
+
parameters?: {
|
|
131
|
+
[key: string]: unknown;
|
|
132
|
+
};
|
|
133
|
+
functionName?: string;
|
|
134
|
+
};
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { readFile, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { glob } from "glob";
|
|
4
|
+
import { parse, stringify } from "yaml";
|
|
5
|
+
export async function isV1Package(src) {
|
|
6
|
+
return stat(join(src, "project.yaml"))
|
|
7
|
+
.then((res) => res.isFile())
|
|
8
|
+
.catch((error) => {
|
|
9
|
+
if (error.code === "ENOENT")
|
|
10
|
+
return false;
|
|
11
|
+
throw error;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export async function toAIGNEPackage(src, dst) {
|
|
15
|
+
const definition = await loadAgentV1Package(src);
|
|
16
|
+
const aigne = {
|
|
17
|
+
chat_model: {
|
|
18
|
+
name: "gpt-4o-mini", // TODO: get from config
|
|
19
|
+
},
|
|
20
|
+
agents: [],
|
|
21
|
+
};
|
|
22
|
+
for (const agent of definition.agents) {
|
|
23
|
+
const { content } = await assistantToAigneV2(agent, definition);
|
|
24
|
+
const filename = getAgentFilename(agent);
|
|
25
|
+
await writeFile(join(dst, filename), content);
|
|
26
|
+
aigne.agents.push(filename);
|
|
27
|
+
}
|
|
28
|
+
await writeFile(join(dst, "aigne.yaml"), stringify(aigne));
|
|
29
|
+
}
|
|
30
|
+
async function loadAgentV1Package(path) {
|
|
31
|
+
const agentFilePaths = await glob("prompts/**/*.yaml", {
|
|
32
|
+
cwd: path,
|
|
33
|
+
});
|
|
34
|
+
const project = parse(await readFile(join(path, "project.yaml"), "utf8"));
|
|
35
|
+
const definition = {
|
|
36
|
+
project,
|
|
37
|
+
agents: [],
|
|
38
|
+
};
|
|
39
|
+
for (const filename of agentFilePaths) {
|
|
40
|
+
const agent = parse(await readFile(join(path, filename), "utf8"));
|
|
41
|
+
definition.agents.push(agent);
|
|
42
|
+
}
|
|
43
|
+
return definition;
|
|
44
|
+
}
|
|
45
|
+
function assistantToAigneV2(agent, project) {
|
|
46
|
+
const converter = RUNNABLE_MAP[agent.type];
|
|
47
|
+
if (!converter)
|
|
48
|
+
throw new Error(`Unsupported runnable type: ${agent.type}`);
|
|
49
|
+
return converter(agent, project);
|
|
50
|
+
}
|
|
51
|
+
const RUNNABLE_MAP = {
|
|
52
|
+
prompt: (agent) => {
|
|
53
|
+
if (agent.type !== "prompt")
|
|
54
|
+
throw new Error(`Expected runnable type 'prompt', but got '${agent.type}'`);
|
|
55
|
+
const obj = {
|
|
56
|
+
name: agent.name || agent.id,
|
|
57
|
+
description: agent.description,
|
|
58
|
+
input_schema: convertInputSchema(agent),
|
|
59
|
+
output_schema: convertOutputSchema(agent),
|
|
60
|
+
instructions: agent.prompts
|
|
61
|
+
?.filter((i) => i.visibility !== "hidden" && i.type === "message")
|
|
62
|
+
.map((i) => i.data.content) // TODO: should support multiple messages with different roles
|
|
63
|
+
.join("\n"),
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
content: stringify(obj),
|
|
67
|
+
};
|
|
68
|
+
},
|
|
69
|
+
function: async (agent) => {
|
|
70
|
+
if (agent.type !== "function")
|
|
71
|
+
throw new Error(`Expected runnable type 'function', but got '${agent.type}'`);
|
|
72
|
+
const inputNames = agent.parameters?.map((i) => i.key).filter(Boolean) ?? [];
|
|
73
|
+
return {
|
|
74
|
+
content: await formatCode(`\
|
|
75
|
+
export default async function agent({${inputNames.join(", ")}}) {
|
|
76
|
+
${agent.code}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
agent.agent_name = ${JSON.stringify(agent.name || agent.id)};
|
|
80
|
+
|
|
81
|
+
agent.description = ${agent.description ? JSON.stringify(agent.description) : "undefined"};
|
|
82
|
+
|
|
83
|
+
agent.input_schema = ${JSON.stringify(convertInputSchema(agent))};
|
|
84
|
+
|
|
85
|
+
agent.output_schema = ${JSON.stringify(convertOutputSchema(agent))};
|
|
86
|
+
`),
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
router: (agent, project) => {
|
|
90
|
+
if (agent.type !== "router")
|
|
91
|
+
throw new Error(`Expected runnable type 'router', but got '${agent.type}'`);
|
|
92
|
+
return {
|
|
93
|
+
content: stringify({
|
|
94
|
+
name: agent.name || agent.id,
|
|
95
|
+
description: agent.description,
|
|
96
|
+
instructions: agent.prompt,
|
|
97
|
+
input_schema: convertInputSchema(agent),
|
|
98
|
+
output_schema: convertOutputSchema(agent),
|
|
99
|
+
tools: agent.routes?.map((i) => {
|
|
100
|
+
const tool = project.agents.find((j) => j.id === i.id);
|
|
101
|
+
if (!tool)
|
|
102
|
+
throw new Error(`Tool ${i.id} not found in project definition`);
|
|
103
|
+
return getAgentFilename(tool);
|
|
104
|
+
}),
|
|
105
|
+
tool_choice: "router",
|
|
106
|
+
}),
|
|
107
|
+
};
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
function getAgentFilename(agent) {
|
|
111
|
+
switch (agent.type) {
|
|
112
|
+
case "prompt":
|
|
113
|
+
case "router":
|
|
114
|
+
return `${agent.name || agent.id}.yaml`;
|
|
115
|
+
case "function":
|
|
116
|
+
return `${agent.name || agent.id}.js`;
|
|
117
|
+
default:
|
|
118
|
+
throw new Error(`Unsupported agent type: ${agent.type}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async function formatCode(code) {
|
|
122
|
+
const [prettier, typescriptPlugin, estreePlugin] = await Promise.all([
|
|
123
|
+
import("prettier"),
|
|
124
|
+
import("prettier/plugins/typescript"),
|
|
125
|
+
import("prettier/plugins/estree"),
|
|
126
|
+
]);
|
|
127
|
+
return prettier.format(code, {
|
|
128
|
+
parser: "typescript",
|
|
129
|
+
plugins: [typescriptPlugin, estreePlugin.default],
|
|
130
|
+
printWidth: 120,
|
|
131
|
+
useTabs: false,
|
|
132
|
+
tabWidth: 2,
|
|
133
|
+
trailingComma: "es5",
|
|
134
|
+
bracketSameLine: true,
|
|
135
|
+
semi: true,
|
|
136
|
+
singleQuote: true,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function convertInputSchema(agent) {
|
|
140
|
+
const parameters = (agent.parameters ?? []).filter((i) => !!i.key && !i.hidden);
|
|
141
|
+
const properties = parameters.map((i) => [i.key, parameterToJsonSchema(i)]);
|
|
142
|
+
return {
|
|
143
|
+
type: "object",
|
|
144
|
+
properties: Object.fromEntries(properties),
|
|
145
|
+
required: parameters.filter((i) => i.required).map((i) => i.key),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function parameterToJsonSchema(parameter) {
|
|
149
|
+
switch (parameter.type) {
|
|
150
|
+
case undefined:
|
|
151
|
+
case "string":
|
|
152
|
+
case "language":
|
|
153
|
+
return {
|
|
154
|
+
type: "string",
|
|
155
|
+
description: parameter.placeholder,
|
|
156
|
+
};
|
|
157
|
+
case "select":
|
|
158
|
+
return {
|
|
159
|
+
type: "string",
|
|
160
|
+
enum: parameter.options?.map((i) => i.value),
|
|
161
|
+
description: parameter.placeholder,
|
|
162
|
+
};
|
|
163
|
+
case "number":
|
|
164
|
+
case "boolean":
|
|
165
|
+
return {
|
|
166
|
+
type: parameter.type,
|
|
167
|
+
description: parameter.placeholder,
|
|
168
|
+
};
|
|
169
|
+
default:
|
|
170
|
+
throw new Error(`Unsupported parameter type: ${parameter.type}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function convertOutputSchema(agent) {
|
|
174
|
+
const outputs = agent.outputVariables?.filter((i) => !!i.name && !i.hidden) ?? [];
|
|
175
|
+
const properties = outputs
|
|
176
|
+
.map((i) => [i.name, variableTypeToJsonSchema(i)])
|
|
177
|
+
.filter((i) => !!i[1]);
|
|
178
|
+
return {
|
|
179
|
+
type: "object",
|
|
180
|
+
properties: Object.fromEntries(properties),
|
|
181
|
+
required: outputs.filter((i) => i.required).map((i) => i.name),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function variableTypeToJsonSchema(output) {
|
|
185
|
+
if (output.type === "object") {
|
|
186
|
+
if (!output.properties)
|
|
187
|
+
return undefined;
|
|
188
|
+
return {
|
|
189
|
+
type: "object",
|
|
190
|
+
properties: Object.fromEntries(output.properties
|
|
191
|
+
.filter((i) => !!i.name)
|
|
192
|
+
.map((i) => [i.name, variableTypeToJsonSchema(i)])
|
|
193
|
+
.filter((i) => !!i[1])),
|
|
194
|
+
required: output.properties.filter((i) => i.required && i.name).map((i) => i.name),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
if (output.type === "array") {
|
|
198
|
+
if (!output.element)
|
|
199
|
+
return undefined;
|
|
200
|
+
return {
|
|
201
|
+
type: "array",
|
|
202
|
+
items: variableTypeToJsonSchema(output.element),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
type: output.type || "string",
|
|
207
|
+
description: output.description,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function downloadAndExtract(url: string, dir: string): Promise<void>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Readable } from "node:stream";
|
|
2
|
+
import { finished } from "node:stream/promises";
|
|
3
|
+
import { x } from "tar";
|
|
4
|
+
export async function downloadAndExtract(url, dir) {
|
|
5
|
+
const response = await fetch(url).catch((error) => {
|
|
6
|
+
throw new Error(`Failed to download package from ${url}: ${error.message}`);
|
|
7
|
+
});
|
|
8
|
+
if (!response.ok) {
|
|
9
|
+
throw new Error(`Failed to download package from ${url}: ${response.statusText}`);
|
|
10
|
+
}
|
|
11
|
+
if (!response.body) {
|
|
12
|
+
throw new Error(`Failed to download package from ${url}: Unexpected to get empty response`);
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
await finished(Readable.fromWeb(response.body).pipe(x({ C: dir })));
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
error.message = `Failed to extract package from ${url}: ${error.message}`;
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Message, type UserAgent as input } from "@aigne/core";
|
|
2
|
+
export interface ChatLoopOptions {
|
|
3
|
+
initialCall?: Message | string;
|
|
4
|
+
welcome?: string;
|
|
5
|
+
defaultQuestion?: string;
|
|
6
|
+
inputKey?: string;
|
|
7
|
+
verbose?: boolean;
|
|
8
|
+
skipLoop?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function runChatLoopInTerminal(userAgent: input, options?: ChatLoopOptions): Promise<void>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { inspect } from "node:util";
|
|
2
|
+
import { MESSAGE_KEY, createMessage } from "@aigne/core";
|
|
3
|
+
import { logger } from "@aigne/core/utils/logger.js";
|
|
4
|
+
import { figures } from "@aigne/listr2";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import inquirer from "inquirer";
|
|
7
|
+
import { TerminalTracer } from "../tracer/terminal.js";
|
|
8
|
+
export async function runChatLoopInTerminal(userAgent, options = {}) {
|
|
9
|
+
const { initialCall = process.env.INITIAL_CALL, skipLoop = process.env.SKIP_LOOP === "true" } = options;
|
|
10
|
+
options.verbose ??= logger.enabled("aigne:core");
|
|
11
|
+
// Disable the logger, use TerminalTracer instead
|
|
12
|
+
logger.disable();
|
|
13
|
+
let prompt;
|
|
14
|
+
if (options?.welcome)
|
|
15
|
+
console.log(options.welcome);
|
|
16
|
+
if (initialCall) {
|
|
17
|
+
await callAgent(userAgent, initialCall, { ...options });
|
|
18
|
+
if (skipLoop)
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
for (let i = 0;; i++) {
|
|
22
|
+
prompt = inquirer.prompt([
|
|
23
|
+
{
|
|
24
|
+
type: "input",
|
|
25
|
+
name: "question",
|
|
26
|
+
message: "💬",
|
|
27
|
+
default: i === 0 ? options?.defaultQuestion : undefined,
|
|
28
|
+
},
|
|
29
|
+
]);
|
|
30
|
+
let question;
|
|
31
|
+
try {
|
|
32
|
+
question = (await prompt).question;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// ignore abort error from inquirer
|
|
36
|
+
}
|
|
37
|
+
if (!question?.trim())
|
|
38
|
+
continue;
|
|
39
|
+
const cmd = COMMANDS[question.trim()];
|
|
40
|
+
if (cmd) {
|
|
41
|
+
const result = cmd();
|
|
42
|
+
if (result.message)
|
|
43
|
+
console.log(result.message);
|
|
44
|
+
if (result?.exit)
|
|
45
|
+
break;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
await callAgent(userAgent, question, { ...options });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function callAgent(userAgent, input, options) {
|
|
52
|
+
const tracer = new TerminalTracer(userAgent.context, { verbose: options.verbose });
|
|
53
|
+
const { result, context } = await tracer.run(userAgent, options.inputKey && typeof input === "string"
|
|
54
|
+
? { [options.inputKey]: input }
|
|
55
|
+
: createMessage(input));
|
|
56
|
+
console.log(`
|
|
57
|
+
${chalk.grey(figures.tick)} 💬 ${inspect(input, { colors: true })}
|
|
58
|
+
${chalk.grey(figures.tick)} 🤖 ${tracer.formatTokenUsage(context.usage)}
|
|
59
|
+
${formatAIResponse(result)}
|
|
60
|
+
`);
|
|
61
|
+
}
|
|
62
|
+
const COMMANDS = {
|
|
63
|
+
"/exit": () => ({ exit: true }),
|
|
64
|
+
"/help": () => ({
|
|
65
|
+
message: `\
|
|
66
|
+
Commands:
|
|
67
|
+
/exit - exit the chat loop
|
|
68
|
+
/help - show this help message
|
|
69
|
+
`,
|
|
70
|
+
}),
|
|
71
|
+
};
|
|
72
|
+
function formatAIResponse({ [MESSAGE_KEY]: msg, ...message } = {}) {
|
|
73
|
+
const text = msg && typeof msg === "string" ? msg : undefined;
|
|
74
|
+
const json = Object.keys(message).length > 0 ? inspect(message, { colors: true }) : undefined;
|
|
75
|
+
return [text, json].filter(Boolean).join("\n");
|
|
76
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function parseDuration(duration: number): string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function parseDuration(duration) {
|
|
2
|
+
const milliseconds = duration % 1000;
|
|
3
|
+
const seconds = Math.floor(duration / 1000);
|
|
4
|
+
const minutes = Math.floor(seconds / 60);
|
|
5
|
+
const ms = Math.round(milliseconds / 10)
|
|
6
|
+
.toString()
|
|
7
|
+
.padStart(2, "0");
|
|
8
|
+
const s = `${Number.parseFloat(`${seconds % 60}.${ms}`)}s`;
|
|
9
|
+
if (minutes === 0)
|
|
10
|
+
return s;
|
|
11
|
+
return `${minutes}m${s}`;
|
|
12
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "cli for AIGNE framework",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -34,27 +34,34 @@
|
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@
|
|
37
|
+
"@aigne/listr2": "^1.0.7",
|
|
38
|
+
"@modelcontextprotocol/sdk": "^1.9.0",
|
|
38
39
|
"chalk": "^5.4.1",
|
|
39
40
|
"commander": "^13.1.0",
|
|
40
41
|
"express": "^5.1.0",
|
|
42
|
+
"glob": "^11.0.1",
|
|
41
43
|
"gradient-string": "^3.0.0",
|
|
42
|
-
"inquirer": "^12.5.
|
|
43
|
-
"openai": "^4.
|
|
44
|
+
"inquirer": "^12.5.2",
|
|
45
|
+
"openai": "^4.94.0",
|
|
46
|
+
"prettier": "^3.5.3",
|
|
47
|
+
"pretty-error": "^4.0.0",
|
|
48
|
+
"tar": "^7.4.3",
|
|
44
49
|
"zod": "^3.24.2",
|
|
45
|
-
"@aigne/core": "^1.
|
|
50
|
+
"@aigne/core": "^1.8.0"
|
|
46
51
|
},
|
|
47
52
|
"devDependencies": {
|
|
48
|
-
"@types/
|
|
53
|
+
"@types/archiver": "^6.0.3",
|
|
54
|
+
"@types/bun": "^1.2.9",
|
|
49
55
|
"@types/express": "^5.0.1",
|
|
56
|
+
"@types/glob": "^8.1.0",
|
|
50
57
|
"@types/gradient-string": "^1.1.6",
|
|
51
|
-
"@types/node": "^22.14.
|
|
58
|
+
"@types/node": "^22.14.1",
|
|
59
|
+
"archiver": "^7.0.1",
|
|
52
60
|
"detect-port": "^2.1.0",
|
|
53
61
|
"npm-run-all": "^4.1.5",
|
|
54
62
|
"rimraf": "^6.0.1",
|
|
55
|
-
"typescript": "^5.8.
|
|
56
|
-
"ufo": "^1.6.
|
|
57
|
-
"@aigne/test-utils": "^1.0.0"
|
|
63
|
+
"typescript": "^5.8.3",
|
|
64
|
+
"ufo": "^1.6.1"
|
|
58
65
|
},
|
|
59
66
|
"scripts": {
|
|
60
67
|
"lint": "tsc --noEmit",
|