@aisa-one/cli 0.2.1 → 0.2.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +144 -1
  2. package/README.md +249 -102
  3. package/dist/api.d.ts +46 -1
  4. package/dist/api.js +77 -8
  5. package/dist/cache.d.ts +18 -0
  6. package/dist/cache.js +65 -0
  7. package/dist/catalog.d.ts +90 -0
  8. package/dist/catalog.js +101 -0
  9. package/dist/commands/account.d.ts +4 -1
  10. package/dist/commands/account.js +36 -6
  11. package/dist/commands/api.d.ts +18 -4
  12. package/dist/commands/api.js +357 -24
  13. package/dist/commands/cacheCmd.d.ts +2 -0
  14. package/dist/commands/cacheCmd.js +10 -0
  15. package/dist/commands/completionCmd.d.ts +7 -0
  16. package/dist/commands/completionCmd.js +37 -0
  17. package/dist/commands/configCmd.js +19 -1
  18. package/dist/commands/finance.d.ts +4 -0
  19. package/dist/commands/finance.js +212 -29
  20. package/dist/commands/models.js +6 -0
  21. package/dist/commands/run.d.ts +21 -0
  22. package/dist/commands/run.js +113 -6
  23. package/dist/commands/search.js +8 -3
  24. package/dist/commands/skills.d.ts +6 -2
  25. package/dist/commands/skills.js +189 -134
  26. package/dist/commands/twitter.js +2 -3
  27. package/dist/commands/video.d.ts +40 -0
  28. package/dist/commands/video.js +272 -55
  29. package/dist/completion.d.ts +26 -0
  30. package/dist/completion.js +293 -0
  31. package/dist/constants.d.ts +55 -5
  32. package/dist/constants.js +136 -11
  33. package/dist/index.js +86 -23
  34. package/dist/skills-registry.d.ts +64 -0
  35. package/dist/skills-registry.js +219 -0
  36. package/dist/types.d.ts +32 -1
  37. package/dist/utils/file.d.ts +5 -1
  38. package/dist/utils/file.js +5 -1
  39. package/dist/utils/pool.d.ts +8 -0
  40. package/dist/utils/pool.js +27 -0
  41. package/package.json +9 -3
  42. package/dist/agent/env-setup.d.ts +0 -5
  43. package/dist/agent/env-setup.js +0 -49
  44. package/dist/agent/index-client.d.ts +0 -7
  45. package/dist/agent/index-client.js +0 -22
  46. package/dist/agent/installer.d.ts +0 -19
  47. package/dist/agent/installer.js +0 -70
  48. package/dist/agent/setup-python.d.ts +0 -15
  49. package/dist/agent/setup-python.js +0 -51
  50. package/dist/commands/agent.d.ts +0 -37
  51. package/dist/commands/agent.js +0 -129
  52. package/tests/streaming.test.ts +0 -73
@@ -1,129 +0,0 @@
1
- import chalk from "chalk";
2
- import { readFile, writeFile } from "node:fs/promises";
3
- import { existsSync } from "node:fs";
4
- import { join } from "node:path";
5
- import { execFile } from "node:child_process";
6
- import { table, success, hint, truncate } from "../utils/display.js";
7
- import { fetchIndex, requireAgent, siblingAssetUrl } from "../agent/index-client.js";
8
- import { hermesRoot, profileDir, downloadArtifact, extractBundle, readBundleManifest, writeMarker, listInstalled, } from "../agent/installer.js";
9
- import { collectEnv } from "../agent/env-setup.js";
10
- import { runPythonSetup } from "../agent/setup-python.js";
11
- const realExec = (cmd, args) => new Promise((resolve) => {
12
- execFile(cmd, args, (err, stdout, stderr) => resolve({ code: err ? 1 : 0, stdout: String(stdout), stderr: String(stderr) }));
13
- });
14
- export async function agentListAction(_opts, deps = {}) {
15
- const index = await fetchIndex(deps.fetchImpl);
16
- const rows = Object.entries(index.agents).sort(([a], [b]) => a.localeCompare(b))
17
- .map(([id, e]) => [id, e.name, e.latest, truncate(e.description, 60)]);
18
- console.log(table(["ID", "NAME", "LATEST", "DESCRIPTION"], rows));
19
- hint(`install one with: aisa agent install <id>`);
20
- return index;
21
- }
22
- export async function agentInfoAction(id, deps = {}) {
23
- const index = await fetchIndex(deps.fetchImpl);
24
- const e = requireAgent(index, id);
25
- console.log(`${chalk.bold(e.name)} (${id})`);
26
- console.log(` ${e.description}`);
27
- console.log(` repo: https://github.com/${e.repo}`);
28
- console.log(` latest: ${e.latest}`);
29
- for (const [v, spec] of Object.entries(e.versions))
30
- console.log(` ${v}: targets ${Object.keys(spec.targets).join(", ")}`);
31
- hint(`install with: aisa agent install ${id}`);
32
- return e;
33
- }
34
- export async function agentInstallAction(id, opts, deps = {}) {
35
- const runtime = opts.runtime ?? "hermes";
36
- if (runtime !== "hermes")
37
- throw new Error(`runtime "${runtime}" not supported yet — v1 supports: hermes`);
38
- if (!existsSync(hermesRoot()))
39
- throw new Error(`hermes not found at ${hermesRoot()} — install it first:\n` +
40
- ` curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash`);
41
- const index = await fetchIndex(deps.fetchImpl);
42
- const entry = requireAgent(index, id);
43
- const version = opts.version ?? entry.latest;
44
- const versionSpec = entry.versions[version];
45
- if (!versionSpec)
46
- throw new Error(`version ${version} not found for ${id} — available: ${Object.keys(entry.versions).join(", ")}`);
47
- const artifact = versionSpec.targets[runtime];
48
- if (!artifact)
49
- throw new Error(`no ${runtime} artifact for ${id}@${version}`);
50
- const dir = profileDir(id);
51
- const existingEnv = existsSync(join(dir, ".env"))
52
- ? await readFile(join(dir, ".env"), "utf8") : null;
53
- const buf = await downloadArtifact(artifact.url, artifact.sha256, deps.fetchImpl);
54
- await extractBundle(buf, dir);
55
- const manifest = await readBundleManifest(dir);
56
- const envText = await collectEnv(manifest, existingEnv, { prompt: deps.prompt });
57
- await writeFile(join(dir, ".env"), envText);
58
- const exec = deps.exec ?? realExec;
59
- // system vars go to render as process env, never into .env — new render.sh
60
- // reads them from the bundled agent.json itself, old artifacts (≤1.0.4)
61
- // still require them in the environment
62
- const r = await exec("env", [
63
- `PROFILE_ID=${manifest.id}`,
64
- `MODEL_DEFAULT=${manifest.models.default}`,
65
- `MODEL_PROVIDER=${manifest.models.provider}`,
66
- "bash", join(dir, "scripts", "render.sh"), dir,
67
- ]);
68
- if (r.code !== 0)
69
- throw new Error(`render failed: ${r.stderr}`);
70
- await runPythonSetup(manifest, dir, exec);
71
- await writeMarker(dir, {
72
- id, version, target: "hermes",
73
- pinned: !!opts.version || manifest.update.channel === "pinned",
74
- });
75
- success(`installed ${entry.name} ${version} -> ${dir}`);
76
- hint(`start it with: hermes --profile ${id}`);
77
- }
78
- export async function agentUpdateAction(id, _opts, deps = {}) {
79
- const installed = await listInstalled();
80
- const targets = id ? installed.filter((i) => i.marker.id === id) : installed;
81
- if (id && targets.length === 0)
82
- throw new Error(`agent "${id}" is not installed (no .agentspec.json marker found)`);
83
- if (targets.length === 0) {
84
- hint("no installed agents found");
85
- return [];
86
- }
87
- const index = await fetchIndex(deps.fetchImpl);
88
- const results = [];
89
- for (const { marker } of targets) {
90
- if (marker.pinned) {
91
- console.log(`${marker.id}: pinned at ${marker.version} — skipping`);
92
- results.push({ id: marker.id, from: marker.version, to: marker.version, status: "pinned" });
93
- continue;
94
- }
95
- const entry = index.agents[marker.id];
96
- if (!entry || entry.latest === marker.version) {
97
- results.push({ id: marker.id, from: marker.version, to: marker.version, status: "up-to-date" });
98
- continue;
99
- }
100
- await agentInstallAction(marker.id, {}, deps); // install 已保留 .env、更新 marker
101
- results.push({ id: marker.id, from: marker.version, to: entry.latest, status: "updated" });
102
- }
103
- for (const r of results)
104
- if (r.status === "updated")
105
- success(`${r.id}: ${r.from} -> ${r.to}`);
106
- return results;
107
- }
108
- export async function agentGuideAction(id, opts, deps = {}) {
109
- const fetchImpl = deps.fetchImpl ?? fetch;
110
- const index = await fetchIndex(deps.fetchImpl);
111
- const entry = requireAgent(index, id);
112
- const artifact = entry.versions[entry.latest]?.targets["hermes"];
113
- if (!artifact)
114
- throw new Error(`no hermes artifact for ${id}@${entry.latest}`);
115
- // 优先读索引携带的资产 URL(2026-07-15 起 publish 写入);老条目回落到
116
- // legacy 裸文件名拼接,保证旧版本 Release 仍可用
117
- const url = opts.md
118
- ? (artifact.installMd ?? siblingAssetUrl(artifact.url, "INSTALL.md"))
119
- : (artifact.guidePrompt ?? siblingAssetUrl(artifact.url, "guide-prompt.txt"));
120
- const filename = url.split("/").pop();
121
- const res = await fetchImpl(url);
122
- if (!res.ok)
123
- throw new Error(`failed to fetch ${filename} (${res.status}): ${url}`);
124
- const text = await res.text();
125
- console.log(text);
126
- if (!opts.md)
127
- hint("paste the text above into your local AI agent (Claude Code, hermes, …)");
128
- return text;
129
- }
@@ -1,73 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { handleSSEStream } from "../src/utils/streaming.js";
3
-
4
- function sseResponse(chunks: string[]): Response {
5
- const encoder = new TextEncoder();
6
- const stream = new ReadableStream<Uint8Array>({
7
- start(controller) {
8
- for (const chunk of chunks) {
9
- controller.enqueue(encoder.encode(chunk));
10
- }
11
- controller.close();
12
- },
13
- });
14
- return new Response(stream);
15
- }
16
-
17
- describe("handleSSEStream", () => {
18
- it("emits tokens from a native fetch Response body", async () => {
19
- const res = sseResponse([
20
- 'data: {"choices":[{"delta":{"content":"Hello"}}]}\n\n',
21
- 'data: {"choices":[{"delta":{"content":" world"}}]}\n\n',
22
- "data: [DONE]\n\n",
23
- ]);
24
-
25
- const tokens: string[] = [];
26
- let done = false;
27
- await handleSSEStream(
28
- res,
29
- (t) => tokens.push(t),
30
- () => {
31
- done = true;
32
- }
33
- );
34
-
35
- expect(tokens.join("")).toBe("Hello world");
36
- expect(done).toBe(true);
37
- });
38
-
39
- it("handles multi-byte characters split across chunks", async () => {
40
- const encoder = new TextEncoder();
41
- const line = encoder.encode(
42
- 'data: {"choices":[{"delta":{"content":"你好"}}]}\n\ndata: [DONE]\n\n'
43
- );
44
- // split in the middle of a multi-byte character
45
- const stream = new ReadableStream<Uint8Array>({
46
- start(controller) {
47
- controller.enqueue(line.slice(0, 40));
48
- controller.enqueue(line.slice(40));
49
- controller.close();
50
- },
51
- });
52
- const res = new Response(stream);
53
-
54
- const tokens: string[] = [];
55
- await handleSSEStream(res, (t) => tokens.push(t));
56
-
57
- expect(tokens.join("")).toBe("你好");
58
- });
59
-
60
- it("reports usage to onDone", async () => {
61
- const res = sseResponse([
62
- 'data: {"choices":[{"delta":{"content":"hi"}}],"usage":{"prompt_tokens":3,"completion_tokens":1}}\n\n',
63
- "data: [DONE]\n\n",
64
- ]);
65
-
66
- let usage: { prompt_tokens: number; completion_tokens: number } | undefined;
67
- await handleSSEStream(res, () => {}, (u) => {
68
- usage = u;
69
- });
70
-
71
- expect(usage).toEqual({ prompt_tokens: 3, completion_tokens: 1 });
72
- });
73
- });