@aigne/cli 1.27.1-0 → 1.27.1-1

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/dist/cli.d.ts CHANGED
@@ -1,2 +1,7 @@
1
1
  #!/usr/bin/env node
2
- export {};
2
+ declare const _default: Promise<{
3
+ [x: string]: unknown;
4
+ _: (string | number)[];
5
+ $0: string;
6
+ }>;
7
+ export default _default;
package/dist/cli.js CHANGED
@@ -16,7 +16,7 @@ function getAIGNEFilePath() {
16
16
  }
17
17
  }
18
18
  const aigneFilePath = getAIGNEFilePath();
19
- createAIGNECommand({ aigneFilePath })
19
+ export default createAIGNECommand({ aigneFilePath })
20
20
  .parseAsync(hideBin([...process.argv.slice(0, 2), ...process.argv.slice(aigneFilePath ? 3 : 2)]))
21
21
  .catch((error) => {
22
22
  console.log(""); // Add an empty line for better readability
@@ -1,66 +1,153 @@
1
1
  import assert from "node:assert";
2
2
  import { spawnSync } from "node:child_process";
3
- import { mkdir, readFile, stat } from "node:fs/promises";
3
+ import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
4
4
  import { homedir } from "node:os";
5
- import { join } from "node:path";
6
- import { AIGNE } from "@aigne/core";
5
+ import { extname, join } from "node:path";
6
+ import { isatty } from "node:tty";
7
+ import { AIAgent, AIGNE, readAllString } from "@aigne/core";
8
+ import { pick } from "@aigne/core/utils/type-utils.js";
9
+ import { Listr, PRESET_TIMER } from "@aigne/listr2";
7
10
  import { joinURL } from "ufo";
8
- import { ZodObject, ZodString } from "zod";
11
+ import { parse } from "yaml";
12
+ import { ZodObject } from "zod";
9
13
  import { availableModels } from "../constants.js";
10
14
  import { downloadAndExtract } from "../utils/download.js";
11
- import { runAgentWithAIGNE } from "../utils/run-with-aigne.js";
15
+ import { loadAIGNE } from "../utils/load-aigne.js";
16
+ import { runAgentWithAIGNE, stdinHasData } from "../utils/run-with-aigne.js";
12
17
  const NPM_PACKAGE_CACHE_TIME_MS = 1000 * 60 * 60 * 24; // 1 day
18
+ const builtinApps = [
19
+ {
20
+ name: "doc-smith",
21
+ describe: "Generate professional documents by doc-smith",
22
+ aliases: ["docsmith", "doc"],
23
+ },
24
+ ];
13
25
  export function createAppCommands() {
14
- return [
15
- {
16
- command: "doc-smith",
17
- describe: "Generate professional documents by doc-smith",
18
- aliases: ["docsmith", "doc"],
19
- builder: async (yargs) => {
20
- const aigne = await loadApplication({ name: "doc-smith" });
21
- for (const agent of aigne.agents) {
22
- yargs.command(agent.name, agent.description || "", (yargs) => {
23
- const options = Object.entries(agent.inputSchema instanceof ZodObject ? agent.inputSchema.shape : {});
24
- for (const [option, config] of options) {
25
- yargs.option(option, {
26
- // TODO: support more types
27
- type: config instanceof ZodString ? "string" : "string",
28
- description: config.description,
29
- });
30
- if (!(config.isNullable() || config.isOptional())) {
31
- yargs.demandOption(option);
32
- }
33
- }
34
- }, async (argv) => {
35
- try {
36
- await runAgentWithAIGNE(aigne, agent, { input: argv });
37
- }
38
- finally {
39
- await aigne.shutdown();
26
+ return builtinApps.map((app) => ({
27
+ command: app.name,
28
+ describe: app.describe,
29
+ aliases: app.aliases,
30
+ builder: async (yargs) => {
31
+ const { aigne, dir, version } = await loadApplication({ name: "doc-smith" });
32
+ for (const agent of aigne.agents) {
33
+ const inputSchema = Object.entries(agent.inputSchema instanceof ZodObject ? agent.inputSchema.shape : {});
34
+ yargs.command(agent.name, agent.description || "", (yargs) => {
35
+ for (const [option, config] of inputSchema) {
36
+ yargs.option(option, {
37
+ // TODO: support more types
38
+ type: "string",
39
+ description: config.description,
40
+ });
41
+ if (!(config.isNullable() || config.isOptional())) {
42
+ yargs.demandOption(option);
40
43
  }
44
+ }
45
+ yargs
46
+ .option("input", {
47
+ type: "array",
48
+ description: "Input to the agent, use @<file> to read from a file",
49
+ alias: ["i"],
50
+ })
51
+ .option("format", {
52
+ type: "string",
53
+ description: 'Input format, can be "json" or "yaml"',
54
+ choices: ["json", "yaml"],
41
55
  });
42
- }
43
- yargs.version('hello world');
44
- return yargs.demandCommand();
45
- },
46
- handler: () => { },
56
+ }, async (argv) => {
57
+ try {
58
+ const aigne = await loadAIGNE(dir);
59
+ const _agent = aigne.agents[agent.name];
60
+ assert(_agent, `Agent ${agent.name} not found in ${app.name}`);
61
+ const input = pick(argv, inputSchema.map(([key]) => key));
62
+ const rawInput = argv.input ||
63
+ (isatty(process.stdin.fd) || !(await stdinHasData())
64
+ ? null
65
+ : [await readAllString(process.stdin)].filter(Boolean));
66
+ if (rawInput) {
67
+ for (let raw of rawInput) {
68
+ let format = argv.format;
69
+ if (raw.startsWith("@")) {
70
+ raw = await readFile(raw.slice(1), "utf8");
71
+ if (!format) {
72
+ const ext = extname(raw);
73
+ if (ext === ".json")
74
+ format = "json";
75
+ else if (ext === ".yaml" || ext === ".yml")
76
+ format = "yaml";
77
+ }
78
+ }
79
+ const inputKey = agent instanceof AIAgent ? agent.inputKey : undefined;
80
+ if (format === "json") {
81
+ Object.assign(input, JSON.parse(raw));
82
+ }
83
+ else if (format === "yaml") {
84
+ Object.assign(input, parse(raw));
85
+ }
86
+ else if (inputKey) {
87
+ Object.assign(input, { [inputKey]: raw });
88
+ }
89
+ }
90
+ }
91
+ await runAgentWithAIGNE(aigne, _agent, { input });
92
+ }
93
+ finally {
94
+ await aigne.shutdown();
95
+ }
96
+ });
97
+ }
98
+ yargs.version(`${app.name} v${version}`);
99
+ return yargs.demandCommand();
47
100
  },
48
- ];
101
+ handler: () => { },
102
+ }));
49
103
  }
50
- async function loadApplication({ name }) {
51
- const info = await shouldDownloadNewVersion(name);
52
- if (info.shouldDownload) {
53
- assert(info.url, "Package URL should be defined when downloading");
54
- // TODO: clean up old versions
55
- await mkdir(info.dir, { recursive: true });
56
- await downloadAndExtract(info.url.toString(), info.dir, { strip: 1 });
57
- spawnSync("npm", ["install", "--omit", "dev"], { cwd: info.dir, stdio: "inherit" });
104
+ async function loadApplication({ name, }) {
105
+ name = `@aigne/${name}`;
106
+ const dir = join(homedir(), ".aigne", "registry.npmjs.org", name);
107
+ const check = await isInstallationAvailable(dir);
108
+ if (check?.available) {
109
+ return {
110
+ aigne: await AIGNE.load(dir, { models: availableModels() }),
111
+ dir,
112
+ version: check.version,
113
+ };
58
114
  }
59
- return AIGNE.load(info.dir, { models: availableModels() });
115
+ const result = await new Listr([
116
+ {
117
+ title: "Fetching application metadata",
118
+ task: async (ctx) => {
119
+ const info = await getNpmTgzInfo(name);
120
+ Object.assign(ctx, info);
121
+ },
122
+ },
123
+ {
124
+ title: "Downloading application",
125
+ skip: (ctx) => ctx.version === check?.version,
126
+ task: async (ctx) => {
127
+ await downloadApplication({ url: ctx.url, dir });
128
+ },
129
+ },
130
+ {
131
+ title: "Installing dependencies",
132
+ skip: (ctx) => ctx.version === check?.version,
133
+ task: async () => {
134
+ await installDependencies(dir);
135
+ },
136
+ },
137
+ ], {
138
+ rendererOptions: {
139
+ collapseSubtasks: false,
140
+ showErrorMessage: false,
141
+ timer: PRESET_TIMER,
142
+ },
143
+ }).run();
144
+ return {
145
+ aigne: await AIGNE.load(dir, { models: availableModels() }),
146
+ dir,
147
+ version: result.version,
148
+ };
60
149
  }
61
- async function shouldDownloadNewVersion(name, { cacheTimeMs = NPM_PACKAGE_CACHE_TIME_MS } = {}) {
62
- const nameWithOrg = `@aigne/${name}`;
63
- const dir = join(homedir(), ".aigne", "registry.npmjs.org", nameWithOrg);
150
+ async function isInstallationAvailable(dir, { cacheTimeMs = NPM_PACKAGE_CACHE_TIME_MS } = {}) {
64
151
  const s = await stat(join(dir, "package.json")).catch((error) => {
65
152
  if (error.code === "ENOENT") {
66
153
  return null;
@@ -68,21 +155,31 @@ async function shouldDownloadNewVersion(name, { cacheTimeMs = NPM_PACKAGE_CACHE_
68
155
  throw error;
69
156
  });
70
157
  if (!s)
71
- return {
72
- shouldDownload: true,
73
- dir,
74
- url: await getNpmTgzInfo(nameWithOrg).then((info) => info.tarballUrl),
75
- };
76
- const lastModified = s.mtimeMs;
158
+ return null;
159
+ const version = safeParseJSON(await readFile(join(dir, "package.json"), "utf-8"))?.version;
160
+ if (!version)
161
+ return null;
162
+ const installedAt = safeParseJSON(await readFile(join(dir, ".aigne-cli.json"), "utf-8").catch(() => "{}"))?.installedAt;
163
+ if (!installedAt)
164
+ return null;
77
165
  const now = Date.now();
78
- if (now - lastModified > cacheTimeMs) {
79
- const version = JSON.parse(await readFile(join(dir, "package.json"), "utf-8")).version;
80
- const latest = await getNpmTgzInfo(`@aigne/${name}`);
81
- if (version !== latest.version) {
82
- return { shouldDownload: true, url: latest.tarballUrl, dir };
83
- }
166
+ const available = installedAt ? now - installedAt < cacheTimeMs : false;
167
+ return { version, available };
168
+ }
169
+ async function downloadApplication({ url, dir }) {
170
+ await mkdir(dir, { recursive: true });
171
+ await downloadAndExtract(url, dir, { strip: 1 });
172
+ }
173
+ async function installDependencies(dir) {
174
+ const { stderr, status } = spawnSync("npm", ["install", "--omit", "dev"], {
175
+ cwd: dir,
176
+ stdio: "pipe",
177
+ });
178
+ if (status !== 0) {
179
+ console.error(stderr.toString());
180
+ throw new Error(`Failed to install dependencies in ${dir}`);
84
181
  }
85
- return { shouldDownload: false, dir };
182
+ await writeFile(join(dir, ".aigne-cli.json"), JSON.stringify({ installedAt: Date.now() }, null, 2));
86
183
  }
87
184
  async function getNpmTgzInfo(name) {
88
185
  const res = await fetch(joinURL("https://registry.npmjs.org", name));
@@ -90,9 +187,17 @@ async function getNpmTgzInfo(name) {
90
187
  throw new Error(`Failed to fetch package info for ${name}: ${res.statusText}`);
91
188
  const data = await res.json();
92
189
  const latestVersion = data["dist-tags"].latest;
93
- const tarballUrl = data.versions[latestVersion].dist.tarball;
190
+ const url = data.versions[latestVersion].dist.tarball;
94
191
  return {
95
192
  version: latestVersion,
96
- tarballUrl,
193
+ url,
97
194
  };
98
195
  }
196
+ function safeParseJSON(raw) {
197
+ try {
198
+ return JSON.parse(raw);
199
+ }
200
+ catch {
201
+ return null;
202
+ }
203
+ }
@@ -2,5 +2,5 @@ import type { CommandModule } from "yargs";
2
2
  interface ConnectOptions {
3
3
  url?: string;
4
4
  }
5
- export declare function createConnectCommand(): CommandModule<{}, ConnectOptions>;
5
+ export declare function createConnectCommand(): CommandModule<unknown, ConnectOptions>;
6
6
  export {};
@@ -2,5 +2,5 @@ import type { CommandModule } from "yargs";
2
2
  interface CreateOptions {
3
3
  path: string;
4
4
  }
5
- export declare function createCreateCommand(): CommandModule<{}, CreateOptions>;
5
+ export declare function createCreateCommand(): CommandModule<unknown, CreateOptions>;
6
6
  export {};
@@ -3,5 +3,5 @@ interface ServeMCPOptions {
3
3
  host: string;
4
4
  port?: number;
5
5
  }
6
- export declare function createObservabilityCommand(): CommandModule<{}, ServeMCPOptions>;
6
+ export declare function createObservabilityCommand(): CommandModule<unknown, ServeMCPOptions>;
7
7
  export {};
@@ -7,5 +7,5 @@ interface ServeMCPOptions {
7
7
  }
8
8
  export declare function createServeMCPCommand({ aigneFilePath, }?: {
9
9
  aigneFilePath?: string;
10
- }): CommandModule<{}, ServeMCPOptions>;
10
+ }): CommandModule<unknown, ServeMCPOptions>;
11
11
  export {};
@@ -4,5 +4,5 @@ interface TestOptions {
4
4
  }
5
5
  export declare function createTestCommand({ aigneFilePath, }?: {
6
6
  aigneFilePath?: string;
7
- }): CommandModule<{}, TestOptions>;
7
+ }): CommandModule<unknown, TestOptions>;
8
8
  export {};
@@ -65,3 +65,4 @@ export declare function runAgentWithAIGNE(aigne: AIGNE, agent: Agent, { outputKe
65
65
  } & Omit<RunAIGNECommandOptions, "input">): Promise<{
66
66
  result: Message;
67
67
  } | undefined>;
68
+ export declare function stdinHasData(): Promise<boolean>;
@@ -7,10 +7,11 @@ import { exists } from "@aigne/agent-library/utils/fs.js";
7
7
  import { AIAgent, AIGNE, DEFAULT_OUTPUT_KEY, readAllString, UserAgent, } from "@aigne/core";
8
8
  import { loadModel } from "@aigne/core/loader/index.js";
9
9
  import { getLevelFromEnv, LogLevel, logger } from "@aigne/core/utils/logger.js";
10
- import { flat, isEmpty, tryOrThrow, } from "@aigne/core/utils/type-utils.js";
10
+ import { flat, isEmpty, tryOrThrow } from "@aigne/core/utils/type-utils.js";
11
11
  import chalk from "chalk";
12
12
  import { parse } from "yaml";
13
13
  import yargs from "yargs";
14
+ import { hideBin } from "yargs/helpers";
14
15
  import { ZodError, ZodObject, z } from "zod";
15
16
  import { availableModels } from "../constants.js";
16
17
  import { TerminalTracer } from "../tracer/terminal.js";
@@ -157,7 +158,7 @@ export async function runWithAIGNE(agentCreator, { argv = process.argv, chatLoop
157
158
  })
158
159
  .alias("h", "help")
159
160
  .alias("v", "version")
160
- .parseAsync(argv)
161
+ .parseAsync(hideBin(argv))
161
162
  .catch((error) => {
162
163
  console.error(`${chalk.red("Error:")} ${error.message}`);
163
164
  process.exit(1);
@@ -209,7 +210,7 @@ export async function runAgentWithAIGNE(aigne, agent, { outputKey, chatLoopOptio
209
210
  }
210
211
  return { result };
211
212
  }
212
- async function stdinHasData() {
213
+ export async function stdinHasData() {
213
214
  const stats = await promisify(fstat)(0);
214
215
  return stats.isFIFO() || stats.isFile();
215
216
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/cli",
3
- "version": "1.27.1-0",
3
+ "version": "1.27.1-1",
4
4
  "description": "cli for AIGNE framework",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -70,20 +70,20 @@
70
70
  "yaml": "^2.8.0",
71
71
  "yargs": "^18.0.0",
72
72
  "zod": "^3.25.67",
73
- "@aigne/agent-library": "^1.21.6",
74
73
  "@aigne/agentic-memory": "^1.0.6",
75
- "@aigne/aigne-hub": "^0.3.0",
76
- "@aigne/anthropic": "^0.10.2",
74
+ "@aigne/agent-library": "^1.21.6",
77
75
  "@aigne/bedrock": "^0.8.6",
76
+ "@aigne/aigne-hub": "^0.3.0",
78
77
  "@aigne/core": "^1.39.0",
79
78
  "@aigne/deepseek": "^0.7.6",
79
+ "@aigne/anthropic": "^0.10.2",
80
80
  "@aigne/default-memory": "^1.0.6",
81
81
  "@aigne/gemini": "^0.8.6",
82
- "@aigne/ollama": "^0.7.6",
82
+ "@aigne/observability-api": "^0.8.2",
83
83
  "@aigne/open-router": "^0.7.6",
84
84
  "@aigne/openai": "^0.10.6",
85
85
  "@aigne/xai": "^0.7.6",
86
- "@aigne/observability-api": "^0.8.2"
86
+ "@aigne/ollama": "^0.7.6"
87
87
  },
88
88
  "devDependencies": {
89
89
  "@types/archiver": "^6.0.3",