@alexkroman1/aai-cli 0.10.2 → 0.10.4
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/_api-client-Br1a_Dsp.mjs +36 -0
- package/dist/_bundler-BM-vnJUp.mjs +117 -0
- package/dist/{_discover-D7HCLa_N.mjs → _discover-DiRl7b_K.mjs} +51 -28
- package/dist/_init-CVkKf8t_.mjs +56 -0
- package/dist/_templates-s5MYfWS9.mjs +63 -0
- package/dist/_ui-Cu-v_Bzz.mjs +13 -0
- package/dist/cli.mjs +49 -191
- package/dist/delete-CSPF9vdh.mjs +34 -0
- package/dist/deploy-C2s4C_ff.mjs +92 -0
- package/dist/dev-CBKWhwaQ.mjs +20 -0
- package/dist/{generate-D7zJtqoC.mjs → generate-DQt7C4zz.mjs} +33 -38
- package/dist/init-BAYELcXE.mjs +112 -0
- package/dist/secret-CRLbxN5P.mjs +44 -0
- package/dist/{test-9fFn9DCf.mjs → test-CuMTKw38.mjs} +8 -10
- package/package.json +8 -13
- package/dist/_build-aW_zyPpr.mjs +0 -176
- package/dist/_init-CweK2mJJ.mjs +0 -108
- package/dist/_link-D6mmDQ0B.mjs +0 -49
- package/dist/_server-common-B6EXxxB2.mjs +0 -105
- package/dist/_ui-C9IvR7Fh.mjs +0 -50
- package/dist/delete-DxECFYOp.mjs +0 -40
- package/dist/deploy-DB0PeNtc.mjs +0 -90
- package/dist/dev-DCtHG1pz.mjs +0 -60
- package/dist/doctor-bWuArZi6.mjs +0 -215
- package/dist/init-COkINbH_.mjs +0 -61
- package/dist/rag-BNfrEr4A.mjs +0 -178
- package/dist/secret-Zzv7fJ_3.mjs +0 -50
- package/dist/start-DQypQkOq.mjs +0 -23
package/dist/_ui-C9IvR7Fh.mjs
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { colorize } from "consola/utils";
|
|
3
|
-
//#region _ui.ts
|
|
4
|
-
/** Interactive/info color wrapper (blue). */
|
|
5
|
-
function interactive(s) {
|
|
6
|
-
return colorize("blueBright", s);
|
|
7
|
-
}
|
|
8
|
-
/** Colored step message: bold action label + message. */
|
|
9
|
-
function step(action, msg) {
|
|
10
|
-
return `${colorize("bold", colorize("cyanBright", action))} ${msg}`;
|
|
11
|
-
}
|
|
12
|
-
/** Informational step message: bold blue action + message. */
|
|
13
|
-
function stepInfo(action, msg) {
|
|
14
|
-
return `${colorize("bold", colorize("blueBright", action))} ${msg}`;
|
|
15
|
-
}
|
|
16
|
-
/** Dimmed info sub-line (indented). */
|
|
17
|
-
function info(msg) {
|
|
18
|
-
return colorize("dim", ` ${msg}`);
|
|
19
|
-
}
|
|
20
|
-
/** Detail sub-line (indented). */
|
|
21
|
-
function detail(msg) {
|
|
22
|
-
return ` ${msg}`;
|
|
23
|
-
}
|
|
24
|
-
/** Warning message. */
|
|
25
|
-
function warn(msg) {
|
|
26
|
-
return `${colorize("yellowBright", "!")} ${msg}`;
|
|
27
|
-
}
|
|
28
|
-
/** Parse and validate a port string. Returns the numeric port or throws. */
|
|
29
|
-
function parsePort(raw) {
|
|
30
|
-
const port = Number.parseInt(raw, 10);
|
|
31
|
-
if (Number.isNaN(port) || port < 0 || port > 65535) throw new Error(`Invalid port: ${raw}. Must be a number between 0 and 65535.`);
|
|
32
|
-
return port;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Run an async command function, logging each step to stdout.
|
|
36
|
-
* Replaces the Ink `runWithInk` pattern.
|
|
37
|
-
*/
|
|
38
|
-
async function runCommand(fn) {
|
|
39
|
-
const log = (msg) => console.log(msg);
|
|
40
|
-
const setStatus = (msg) => {
|
|
41
|
-
if (msg) process.stdout.write(`\r${colorize("dim", msg)}`);
|
|
42
|
-
else process.stdout.write("\r\x1B[K");
|
|
43
|
-
};
|
|
44
|
-
await fn({
|
|
45
|
-
log,
|
|
46
|
-
setStatus
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
//#endregion
|
|
50
|
-
export { runCommand as a, warn as c, parsePort as i, info as n, step as o, interactive as r, stepInfo as s, detail as t };
|
package/dist/delete-DxECFYOp.mjs
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { a as getServerInfo } from "./_discover-D7HCLa_N.mjs";
|
|
3
|
-
import { a as runCommand, o as step } from "./_ui-C9IvR7Fh.mjs";
|
|
4
|
-
//#region _delete.ts
|
|
5
|
-
async function runDelete(opts) {
|
|
6
|
-
const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
7
|
-
let resp;
|
|
8
|
-
try {
|
|
9
|
-
resp = await fetchFn(`${opts.url}/${opts.slug}`, {
|
|
10
|
-
method: "DELETE",
|
|
11
|
-
headers: { Authorization: `Bearer ${opts.apiKey}` }
|
|
12
|
-
});
|
|
13
|
-
} catch (err) {
|
|
14
|
-
const hint = opts.url.startsWith("http://localhost") ? "Is the local dev server running? Start it with `aai dev`." : "Check your network connection and verify the server URL is correct.";
|
|
15
|
-
throw new Error(`delete failed: could not reach ${opts.url}\n ${hint}`, { cause: err });
|
|
16
|
-
}
|
|
17
|
-
if (resp.ok) return;
|
|
18
|
-
const text = await resp.text();
|
|
19
|
-
let hint = "";
|
|
20
|
-
if (resp.status === 401) hint = "Your API key may be invalid. Check ~/.config/aai/config.json or set ASSEMBLYAI_API_KEY.";
|
|
21
|
-
else if (resp.status === 404) hint = "The agent may not be deployed. Check `.aai/project.json` for the correct slug.";
|
|
22
|
-
throw new Error(`delete failed (HTTP ${resp.status}): ${text}${hint ? `\n ${hint}` : ""}`);
|
|
23
|
-
}
|
|
24
|
-
//#endregion
|
|
25
|
-
//#region delete.ts
|
|
26
|
-
async function runDeleteCommand(opts) {
|
|
27
|
-
const { cwd } = opts;
|
|
28
|
-
const { serverUrl, slug, apiKey } = await getServerInfo(cwd, opts.server);
|
|
29
|
-
await runCommand(async ({ log }) => {
|
|
30
|
-
log(step("Delete", slug));
|
|
31
|
-
await runDelete({
|
|
32
|
-
url: serverUrl,
|
|
33
|
-
slug,
|
|
34
|
-
apiKey
|
|
35
|
-
});
|
|
36
|
-
log(step("Deleted", `${serverUrl}/${slug}`));
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
//#endregion
|
|
40
|
-
export { runDeleteCommand };
|
package/dist/deploy-DB0PeNtc.mjs
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { c as readProjectConfig, d as writeProjectConfig, i as getApiKey, r as generateSlug, u as resolveServerUrl } from "./_discover-D7HCLa_N.mjs";
|
|
3
|
-
import { a as runCommand, o as step, s as stepInfo } from "./_ui-C9IvR7Fh.mjs";
|
|
4
|
-
import { buildAgentBundle } from "./_build-aW_zyPpr.mjs";
|
|
5
|
-
//#region _deploy.ts
|
|
6
|
-
async function attemptDeploy(fetchFn, url, slug, apiKey, env, worker, clientFiles) {
|
|
7
|
-
try {
|
|
8
|
-
return await fetchFn(`${url}/${slug}/deploy`, {
|
|
9
|
-
method: "POST",
|
|
10
|
-
headers: {
|
|
11
|
-
"Content-Type": "application/json",
|
|
12
|
-
Authorization: `Bearer ${apiKey}`
|
|
13
|
-
},
|
|
14
|
-
body: JSON.stringify({
|
|
15
|
-
env,
|
|
16
|
-
worker,
|
|
17
|
-
clientFiles
|
|
18
|
-
})
|
|
19
|
-
});
|
|
20
|
-
} catch (err) {
|
|
21
|
-
const hint = url.startsWith("http://localhost") ? "Is the local dev server running? Start it with `aai dev`." : "Check your network connection and verify the server URL is correct.";
|
|
22
|
-
throw new Error(`deployment failed: could not reach ${url}\n ${hint}`, { cause: err });
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
const MAX_RETRIES = 20;
|
|
26
|
-
async function runDeploy(opts) {
|
|
27
|
-
const { worker, clientFiles } = opts.bundle;
|
|
28
|
-
const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
29
|
-
let slug = opts.slug;
|
|
30
|
-
for (let i = 0; i < MAX_RETRIES; i++) {
|
|
31
|
-
const resp = await attemptDeploy(fetchFn, opts.url, slug, opts.apiKey, opts.env, worker, clientFiles);
|
|
32
|
-
if (resp.ok) return { slug };
|
|
33
|
-
const text = await resp.text();
|
|
34
|
-
if (resp.status === 403 && text.includes("Slug")) {
|
|
35
|
-
slug = generateSlug();
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
let hint = "";
|
|
39
|
-
if (resp.status === 401) hint = "Your API key may be invalid. Check ~/.config/aai/config.json or set ASSEMBLYAI_API_KEY.";
|
|
40
|
-
else if (resp.status === 413) hint = "Your bundle is too large. Try reducing dependencies or splitting your agent.";
|
|
41
|
-
throw new Error(`deploy failed (HTTP ${resp.status}): ${text}${hint ? `\n ${hint}` : ""}`);
|
|
42
|
-
}
|
|
43
|
-
throw new Error(`deploy failed: could not find an available agent slug after ${MAX_RETRIES} attempts. Try setting a custom slug in .aai/project.json.`);
|
|
44
|
-
}
|
|
45
|
-
//#endregion
|
|
46
|
-
//#region deploy.ts
|
|
47
|
-
async function deployBundle(opts) {
|
|
48
|
-
const { bundle, serverUrl, apiKey, cwd, log } = opts;
|
|
49
|
-
let { slug } = opts;
|
|
50
|
-
log(step("Deploy", slug));
|
|
51
|
-
slug = (await runDeploy({
|
|
52
|
-
url: serverUrl,
|
|
53
|
-
bundle,
|
|
54
|
-
env: { ASSEMBLYAI_API_KEY: apiKey },
|
|
55
|
-
slug,
|
|
56
|
-
apiKey
|
|
57
|
-
})).slug;
|
|
58
|
-
await writeProjectConfig(cwd, {
|
|
59
|
-
slug,
|
|
60
|
-
serverUrl
|
|
61
|
-
});
|
|
62
|
-
const agentUrl = `${serverUrl}/${slug}`;
|
|
63
|
-
log(step("Ready", agentUrl));
|
|
64
|
-
return agentUrl;
|
|
65
|
-
}
|
|
66
|
-
async function runDeployCommand(opts) {
|
|
67
|
-
const { cwd } = opts;
|
|
68
|
-
const dryRun = opts.dryRun ?? false;
|
|
69
|
-
const apiKey = dryRun ? "" : await getApiKey();
|
|
70
|
-
const projectConfig = await readProjectConfig(cwd);
|
|
71
|
-
const serverUrl = resolveServerUrl(opts.server, projectConfig?.serverUrl);
|
|
72
|
-
const slug = projectConfig?.slug ?? generateSlug();
|
|
73
|
-
await runCommand(async ({ log }) => {
|
|
74
|
-
const bundle = await buildAgentBundle(cwd, log);
|
|
75
|
-
if (dryRun) {
|
|
76
|
-
log(stepInfo("Dry run", `would deploy as ${slug}`));
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
await deployBundle({
|
|
80
|
-
bundle,
|
|
81
|
-
serverUrl,
|
|
82
|
-
apiKey,
|
|
83
|
-
slug,
|
|
84
|
-
cwd,
|
|
85
|
-
log
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
//#endregion
|
|
90
|
-
export { runDeployCommand };
|
package/dist/dev-DCtHG1pz.mjs
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { s as loadAgent } from "./_discover-D7HCLa_N.mjs";
|
|
3
|
-
import { a as runCommand, i as parsePort, n as info, o as step } from "./_ui-C9IvR7Fh.mjs";
|
|
4
|
-
import { buildAgentBundle, t as createClientDevServer } from "./_build-aW_zyPpr.mjs";
|
|
5
|
-
import { a as resolveServerEnv, i as loadAgentDef, n as bootServer, t as bootBackendServer } from "./_server-common-B6EXxxB2.mjs";
|
|
6
|
-
//#region dev.ts
|
|
7
|
-
/** Build, boot, and verify the server — used by `--check` mode. */
|
|
8
|
-
async function runCheckMode(cwd, port, log) {
|
|
9
|
-
const bundle = await buildAgentBundle(cwd, log);
|
|
10
|
-
const agentDef = await loadAgentDef(cwd);
|
|
11
|
-
const env = await resolveServerEnv(cwd);
|
|
12
|
-
const server = await bootServer(agentDef, bundle.clientDir, env, port);
|
|
13
|
-
log(step("Ready", `http://localhost:${port}`));
|
|
14
|
-
const base = `http://localhost:${port}`;
|
|
15
|
-
try {
|
|
16
|
-
const healthRes = await fetch(`${base}/health`);
|
|
17
|
-
if (!healthRes.ok) throw new Error(`GET /health returned ${healthRes.status}. The server started but the health endpoint failed.`);
|
|
18
|
-
const health = await healthRes.json();
|
|
19
|
-
if (health.status !== "ok") throw new Error(`GET /health returned unhealthy status: ${JSON.stringify(health)}. Check your agent.ts for errors.`);
|
|
20
|
-
log(step("Health", health.name ?? "ok"));
|
|
21
|
-
const pageRes = await fetch(`${base}/`);
|
|
22
|
-
if (!pageRes.ok) throw new Error(`GET / returned ${pageRes.status}. The client page failed to load.`);
|
|
23
|
-
const html = await pageRes.text();
|
|
24
|
-
if (!(html.includes("<") && html.includes("html"))) throw new Error("GET / did not return valid HTML. Check that client.tsx exists and builds correctly.");
|
|
25
|
-
log(step("Client", "ok"));
|
|
26
|
-
} catch (err) {
|
|
27
|
-
await server.close();
|
|
28
|
-
throw err;
|
|
29
|
-
}
|
|
30
|
-
await server.close();
|
|
31
|
-
}
|
|
32
|
-
async function _startDevServer(cwd, port, log, opts) {
|
|
33
|
-
if (opts?.check) {
|
|
34
|
-
await runCheckMode(cwd, port, log);
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
const agent = await loadAgent(cwd);
|
|
38
|
-
if (!agent) throw new Error("No agent found — run `aai init` first");
|
|
39
|
-
const agentDef = await loadAgentDef(cwd);
|
|
40
|
-
const env = await resolveServerEnv();
|
|
41
|
-
const backendPort = port + 1;
|
|
42
|
-
await bootBackendServer(agentDef, env, backendPort);
|
|
43
|
-
if (agent.clientEntry) {
|
|
44
|
-
await (await createClientDevServer(cwd, backendPort, port)).listen();
|
|
45
|
-
log(step("Ready", `http://localhost:${port}`));
|
|
46
|
-
log(info("Client HMR enabled — edits to client.tsx update instantly"));
|
|
47
|
-
} else {
|
|
48
|
-
log(step("Ready", `http://localhost:${backendPort}`));
|
|
49
|
-
log(info("No client.tsx found — serving agent API only"));
|
|
50
|
-
}
|
|
51
|
-
log(info("Ctrl-C to quit"));
|
|
52
|
-
}
|
|
53
|
-
async function runDevCommand(opts) {
|
|
54
|
-
const port = parsePort(opts.port);
|
|
55
|
-
await runCommand(async ({ log }) => {
|
|
56
|
-
await _startDevServer(opts.cwd, port, log, opts.check ? { check: true } : void 0);
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
//#endregion
|
|
60
|
-
export { runDevCommand };
|
package/dist/doctor-bWuArZi6.mjs
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { n as fileExists } from "./_discover-D7HCLa_N.mjs";
|
|
3
|
-
import { a as runCommand, i as parsePort, o as step } from "./_ui-C9IvR7Fh.mjs";
|
|
4
|
-
import { i as loadAgentDef, r as envFileKeys } from "./_server-common-B6EXxxB2.mjs";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import fs from "node:fs/promises";
|
|
7
|
-
import { colorize } from "consola/utils";
|
|
8
|
-
import net from "node:net";
|
|
9
|
-
//#region doctor.ts
|
|
10
|
-
const PASS = colorize("greenBright", "✓");
|
|
11
|
-
const WARN = colorize("yellowBright", "!");
|
|
12
|
-
const FAIL = colorize("redBright", "✗");
|
|
13
|
-
function statusIcon(status) {
|
|
14
|
-
if (status === "pass") return PASS;
|
|
15
|
-
if (status === "warn") return WARN;
|
|
16
|
-
return FAIL;
|
|
17
|
-
}
|
|
18
|
-
async function checkNodeVersion() {
|
|
19
|
-
const version = process.version;
|
|
20
|
-
const match = version.match(/^v(\d+)\.(\d+)/);
|
|
21
|
-
if (!match) return {
|
|
22
|
-
name: "Node.js",
|
|
23
|
-
status: "fail",
|
|
24
|
-
message: `Unknown version: ${version}`
|
|
25
|
-
};
|
|
26
|
-
const [major, minor] = [Number(match[1]), Number(match[2])];
|
|
27
|
-
if (major > 22 || major === 22 && minor >= 6) return {
|
|
28
|
-
name: "Node.js",
|
|
29
|
-
status: "pass",
|
|
30
|
-
message: `${version} (>=22.6 required)`
|
|
31
|
-
};
|
|
32
|
-
return {
|
|
33
|
-
name: "Node.js",
|
|
34
|
-
status: "fail",
|
|
35
|
-
message: `${version} — Node >=22.6 is required`,
|
|
36
|
-
fix: "Install Node.js 22.6+ from https://nodejs.org or via nvm: nvm install 22"
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
async function checkApiKey() {
|
|
40
|
-
const key = process.env.ASSEMBLYAI_API_KEY || await (async () => {
|
|
41
|
-
try {
|
|
42
|
-
const configPath = path.join(process.env.HOME ?? process.env.USERPROFILE ?? ".", ".config", "aai", "config.json");
|
|
43
|
-
return JSON.parse(await fs.readFile(configPath, "utf-8")).assemblyai_api_key;
|
|
44
|
-
} catch {}
|
|
45
|
-
})();
|
|
46
|
-
if (!key) return {
|
|
47
|
-
name: "API key",
|
|
48
|
-
status: "fail",
|
|
49
|
-
message: "ASSEMBLYAI_API_KEY not found",
|
|
50
|
-
fix: "Run `aai init` to set up your API key, or set the ASSEMBLYAI_API_KEY environment variable"
|
|
51
|
-
};
|
|
52
|
-
if (key.length < 10) return {
|
|
53
|
-
name: "API key",
|
|
54
|
-
status: "warn",
|
|
55
|
-
message: "ASSEMBLYAI_API_KEY looks too short — may be invalid",
|
|
56
|
-
fix: "Get a valid key from https://www.assemblyai.com/dashboard/signup"
|
|
57
|
-
};
|
|
58
|
-
return {
|
|
59
|
-
name: "API key",
|
|
60
|
-
status: "pass",
|
|
61
|
-
message: "ASSEMBLYAI_API_KEY is set"
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
async function checkDependencies(cwd) {
|
|
65
|
-
if (!await fileExists(path.join(cwd, "package.json"))) return {
|
|
66
|
-
name: "Dependencies",
|
|
67
|
-
status: "warn",
|
|
68
|
-
message: "No package.json found",
|
|
69
|
-
fix: "Run `aai init` to scaffold a project, or `npm init` to create package.json"
|
|
70
|
-
};
|
|
71
|
-
const nodeModules = path.join(cwd, "node_modules");
|
|
72
|
-
if (!await fileExists(nodeModules)) return {
|
|
73
|
-
name: "Dependencies",
|
|
74
|
-
status: "fail",
|
|
75
|
-
message: "node_modules/ not found — dependencies not installed",
|
|
76
|
-
fix: "Run `npm install` to install dependencies"
|
|
77
|
-
};
|
|
78
|
-
if (!await fileExists(path.join(nodeModules, "@alexkroman1", "aai"))) return {
|
|
79
|
-
name: "Dependencies",
|
|
80
|
-
status: "fail",
|
|
81
|
-
message: "@alexkroman1/aai package not found in node_modules",
|
|
82
|
-
fix: "Run `npm install @alexkroman1/aai` to add the SDK"
|
|
83
|
-
};
|
|
84
|
-
return {
|
|
85
|
-
name: "Dependencies",
|
|
86
|
-
status: "pass",
|
|
87
|
-
message: "node_modules/ present, SDK installed"
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
async function checkEnvFile(cwd) {
|
|
91
|
-
const envPath = path.join(cwd, ".env");
|
|
92
|
-
if (!await fileExists(envPath)) {
|
|
93
|
-
if (await fileExists(path.join(cwd, ".env.example"))) return {
|
|
94
|
-
name: ".env file",
|
|
95
|
-
status: "warn",
|
|
96
|
-
message: ".env not found, but .env.example exists",
|
|
97
|
-
fix: "Copy .env.example to .env and fill in the values: cp .env.example .env"
|
|
98
|
-
};
|
|
99
|
-
return {
|
|
100
|
-
name: ".env file",
|
|
101
|
-
status: "pass",
|
|
102
|
-
message: "No .env file (using environment variables or aai config)"
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
try {
|
|
106
|
-
const content = await fs.readFile(envPath, "utf-8");
|
|
107
|
-
const keys = envFileKeys(content);
|
|
108
|
-
if (keys.length === 0) return {
|
|
109
|
-
name: ".env file",
|
|
110
|
-
status: "warn",
|
|
111
|
-
message: ".env file is empty (no keys declared)"
|
|
112
|
-
};
|
|
113
|
-
const emptyKeys = [];
|
|
114
|
-
for (const line of content.split("\n")) {
|
|
115
|
-
const trimmed = line.trim();
|
|
116
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
117
|
-
const eq = trimmed.indexOf("=");
|
|
118
|
-
if (eq === -1) continue;
|
|
119
|
-
const val = trimmed.slice(eq + 1).trim();
|
|
120
|
-
if (!val || val === "\"\"" || val === "''") emptyKeys.push(trimmed.slice(0, eq).trim());
|
|
121
|
-
}
|
|
122
|
-
if (emptyKeys.length > 0) return {
|
|
123
|
-
name: ".env file",
|
|
124
|
-
status: "warn",
|
|
125
|
-
message: `${keys.length} key(s) declared, ${emptyKeys.length} empty: ${emptyKeys.join(", ")}`,
|
|
126
|
-
fix: "Fill in the empty values in your .env file"
|
|
127
|
-
};
|
|
128
|
-
return {
|
|
129
|
-
name: ".env file",
|
|
130
|
-
status: "pass",
|
|
131
|
-
message: `${keys.length} key(s) declared`
|
|
132
|
-
};
|
|
133
|
-
} catch {
|
|
134
|
-
return {
|
|
135
|
-
name: ".env file",
|
|
136
|
-
status: "fail",
|
|
137
|
-
message: "Failed to read .env file"
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
async function checkPortAvailable(port) {
|
|
142
|
-
if (await new Promise((resolve) => {
|
|
143
|
-
const server = net.createServer();
|
|
144
|
-
server.once("error", () => resolve(false));
|
|
145
|
-
server.once("listening", () => {
|
|
146
|
-
server.close(() => resolve(true));
|
|
147
|
-
});
|
|
148
|
-
server.listen(port, "127.0.0.1");
|
|
149
|
-
})) return {
|
|
150
|
-
name: "Port",
|
|
151
|
-
status: "pass",
|
|
152
|
-
message: `Port ${port} is available`
|
|
153
|
-
};
|
|
154
|
-
return {
|
|
155
|
-
name: "Port",
|
|
156
|
-
status: "warn",
|
|
157
|
-
message: `Port ${port} is in use`,
|
|
158
|
-
fix: `Use a different port: aai dev --port <number>, or stop the process using port ${port}`
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
async function checkAgentSyntax(cwd) {
|
|
162
|
-
if (!await fileExists(path.join(cwd, "agent.ts"))) return {
|
|
163
|
-
name: "agent.ts",
|
|
164
|
-
status: "fail",
|
|
165
|
-
message: "agent.ts not found",
|
|
166
|
-
fix: "Run `aai init` to scaffold a new agent project"
|
|
167
|
-
};
|
|
168
|
-
try {
|
|
169
|
-
await loadAgentDef(cwd);
|
|
170
|
-
return {
|
|
171
|
-
name: "agent.ts",
|
|
172
|
-
status: "pass",
|
|
173
|
-
message: "Valid agent definition"
|
|
174
|
-
};
|
|
175
|
-
} catch (err) {
|
|
176
|
-
return {
|
|
177
|
-
name: "agent.ts",
|
|
178
|
-
status: "fail",
|
|
179
|
-
message: `Invalid: ${err instanceof Error ? err.message : String(err)}`,
|
|
180
|
-
fix: "Check agent.ts — ensure it exports a default defineAgent() call with name, instructions, greeting, maxSteps, and tools"
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
async function _runDoctor(cwd, port, log) {
|
|
185
|
-
log("");
|
|
186
|
-
log(step("Doctor", "Checking environment health..."));
|
|
187
|
-
log("");
|
|
188
|
-
const results = [];
|
|
189
|
-
results.push(await checkNodeVersion());
|
|
190
|
-
results.push(await checkApiKey());
|
|
191
|
-
results.push(await checkDependencies(cwd));
|
|
192
|
-
results.push(await checkEnvFile(cwd));
|
|
193
|
-
results.push(await checkPortAvailable(port));
|
|
194
|
-
results.push(await checkAgentSyntax(cwd));
|
|
195
|
-
for (const r of results) {
|
|
196
|
-
log(` ${statusIcon(r.status)} ${colorize("bold", r.name)}: ${r.message}`);
|
|
197
|
-
if (r.fix) log(colorize("dim", ` → ${r.fix}`));
|
|
198
|
-
}
|
|
199
|
-
log("");
|
|
200
|
-
const fails = results.filter((r) => r.status === "fail").length;
|
|
201
|
-
const warns = results.filter((r) => r.status === "warn").length;
|
|
202
|
-
if (fails > 0) log(` ${FAIL} ${fails} issue(s) found. Fix them to proceed.`);
|
|
203
|
-
else if (warns > 0) log(` ${WARN} All clear with ${warns} warning(s).`);
|
|
204
|
-
else log(` ${PASS} Everything looks good!`);
|
|
205
|
-
log("");
|
|
206
|
-
if (fails > 0) process.exitCode = 1;
|
|
207
|
-
}
|
|
208
|
-
async function runDoctorCommand(opts) {
|
|
209
|
-
const port = parsePort(opts.port);
|
|
210
|
-
await runCommand(async ({ log }) => {
|
|
211
|
-
await _runDoctor(opts.cwd, port, log);
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
//#endregion
|
|
215
|
-
export { runDoctorCommand };
|
package/dist/init-COkINbH_.mjs
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { l as resolveCwd, n as fileExists, o as isDevMode, p as askText, t as ensureApiKeyInEnv } from "./_discover-D7HCLa_N.mjs";
|
|
3
|
-
import { a as runCommand, c as warn, o as step, r as interactive } from "./_ui-C9IvR7Fh.mjs";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import fs from "node:fs/promises";
|
|
6
|
-
import { execFile } from "node:child_process";
|
|
7
|
-
import { promisify } from "node:util";
|
|
8
|
-
//#region init.ts
|
|
9
|
-
const execFileAsync = promisify(execFile);
|
|
10
|
-
/** Install deps — uses `aai link` in dev mode, `npm install` otherwise. */
|
|
11
|
-
async function installDeps(cwd, log) {
|
|
12
|
-
if (await fileExists(path.join(cwd, "node_modules"))) return;
|
|
13
|
-
if (isDevMode()) {
|
|
14
|
-
log(step("Link", "local workspace packages (dev mode)"));
|
|
15
|
-
const { runLinkCommand } = await import("./_link-D6mmDQ0B.mjs");
|
|
16
|
-
runLinkCommand(cwd);
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
let pkgJson;
|
|
20
|
-
try {
|
|
21
|
-
pkgJson = JSON.parse(await fs.readFile(path.join(cwd, "package.json"), "utf-8"));
|
|
22
|
-
} catch {
|
|
23
|
-
pkgJson = {};
|
|
24
|
-
}
|
|
25
|
-
const deps = Object.keys(pkgJson.dependencies ?? {});
|
|
26
|
-
const devDeps = Object.keys(pkgJson.devDependencies ?? {});
|
|
27
|
-
if (deps.length > 0) log(step("Install", deps.join(", ")));
|
|
28
|
-
if (devDeps.length > 0) log(step("Install", `dev: ${devDeps.join(", ")}`));
|
|
29
|
-
try {
|
|
30
|
-
await execFileAsync("npm", ["install"], { cwd });
|
|
31
|
-
} catch (err) {
|
|
32
|
-
log(warn(`npm install failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
33
|
-
log(warn("Run `npm install` manually in the project directory to install dependencies."));
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
async function runInitCommand(opts, extra) {
|
|
37
|
-
if (!opts.skipApi) await ensureApiKeyInEnv();
|
|
38
|
-
let dir = opts.dir;
|
|
39
|
-
if (!dir) dir = await askText("What is your project named?", "my-voice-agent");
|
|
40
|
-
const cwd = path.resolve(resolveCwd(), dir);
|
|
41
|
-
if (!opts.force && await fileExists(path.join(cwd, "agent.ts"))) throw new Error(`agent.ts already exists in this directory. Use ${interactive("--force")} to overwrite.`);
|
|
42
|
-
const { runInit } = await import("./_init-CweK2mJJ.mjs");
|
|
43
|
-
const template = opts.template ?? "simple";
|
|
44
|
-
await runCommand(async ({ log }) => {
|
|
45
|
-
log(step("Create", dir));
|
|
46
|
-
await runInit({
|
|
47
|
-
targetDir: cwd,
|
|
48
|
-
template
|
|
49
|
-
});
|
|
50
|
-
await installDeps(cwd, log);
|
|
51
|
-
});
|
|
52
|
-
process.chdir(cwd);
|
|
53
|
-
delete process.env.INIT_CWD;
|
|
54
|
-
if (!(opts.skipDeploy || extra?.quiet)) {
|
|
55
|
-
const { runDeployCommand } = await import("./deploy-DB0PeNtc.mjs");
|
|
56
|
-
await runDeployCommand({ cwd });
|
|
57
|
-
}
|
|
58
|
-
return cwd;
|
|
59
|
-
}
|
|
60
|
-
//#endregion
|
|
61
|
-
export { runInitCommand };
|
package/dist/rag-BNfrEr4A.mjs
DELETED
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { a as getServerInfo } from "./_discover-D7HCLa_N.mjs";
|
|
3
|
-
import { a as runCommand, c as warn, n as info, o as step, t as detail } from "./_ui-C9IvR7Fh.mjs";
|
|
4
|
-
import { errorMessage } from "@alexkroman1/aai/utils";
|
|
5
|
-
import pLimit from "p-limit";
|
|
6
|
-
//#region rag.ts
|
|
7
|
-
const FETCH_TIMEOUT_MS = 6e4;
|
|
8
|
-
async function runRag(opts) {
|
|
9
|
-
const { url, apiKey, serverUrl, slug, chunkSize, log, setStatus } = opts;
|
|
10
|
-
log(step("Fetch", url));
|
|
11
|
-
const resp = await fetch(url, {
|
|
12
|
-
headers: { "User-Agent": "aai-cli/1.0" },
|
|
13
|
-
redirect: "follow",
|
|
14
|
-
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
15
|
-
});
|
|
16
|
-
if (!resp.ok) throw new Error(`Failed to fetch: ${resp.status} ${resp.statusText}`);
|
|
17
|
-
const content = await resp.text();
|
|
18
|
-
if (content.length === 0) {
|
|
19
|
-
log(warn("File is empty"));
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
log(info(`${(content.length / 1024).toFixed(0)} KB`));
|
|
23
|
-
const origin = new URL(url).origin;
|
|
24
|
-
const pages = splitPages(content);
|
|
25
|
-
log(step("Parse", `${pages.length} pages`));
|
|
26
|
-
const { RecursiveChunker } = await import("@chonkiejs/core");
|
|
27
|
-
const allChunks = await chunkPages(pages, await RecursiveChunker.create({ chunkSize }), origin, slugify(origin));
|
|
28
|
-
log(step("Chunk", `${allChunks.length} chunks`));
|
|
29
|
-
const vectorUrl = `${serverUrl}/${slug}/vector`;
|
|
30
|
-
log(info(`target: ${vectorUrl}`));
|
|
31
|
-
const result = await upsertChunks(allChunks, vectorUrl, apiKey, setStatus);
|
|
32
|
-
log(step("Done", `${result.upserted} chunks upserted`));
|
|
33
|
-
if (result.errors > 0) {
|
|
34
|
-
log(warn(`${result.errors} failed`));
|
|
35
|
-
if (result.lastError) log(info(`last error: ${result.lastError}`));
|
|
36
|
-
}
|
|
37
|
-
log(detail(`Agent: ${slug}`));
|
|
38
|
-
}
|
|
39
|
-
async function chunkPages(pages, chunker, origin, siteSlug) {
|
|
40
|
-
const allChunks = [];
|
|
41
|
-
for (const page of pages) {
|
|
42
|
-
page.body = stripNoise(page.body);
|
|
43
|
-
if (!page.body) continue;
|
|
44
|
-
const raw = await chunker.chunk(page.body);
|
|
45
|
-
for (const [i, c] of raw.entries()) {
|
|
46
|
-
const data = page.title ? `${page.title}\n\n${c.text}` : c.text;
|
|
47
|
-
const id = `${siteSlug}:${slugify(page.title || "page")}:${i}`;
|
|
48
|
-
allChunks.push({
|
|
49
|
-
id,
|
|
50
|
-
data,
|
|
51
|
-
metadata: {
|
|
52
|
-
source: origin,
|
|
53
|
-
...page.title ? { title: page.title } : {},
|
|
54
|
-
tokenCount: c.tokenCount
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return allChunks;
|
|
60
|
-
}
|
|
61
|
-
async function upsertChunks(chunks, vectorUrl, apiKey, setStatus, fetchFn = globalThis.fetch) {
|
|
62
|
-
const total = chunks.length;
|
|
63
|
-
let completed = 0;
|
|
64
|
-
let upserted = 0;
|
|
65
|
-
let errors = 0;
|
|
66
|
-
let lastError = "";
|
|
67
|
-
let lastStatusUpdate = 0;
|
|
68
|
-
const updateStatus = (force = false) => {
|
|
69
|
-
const now = Date.now();
|
|
70
|
-
if (!force && now - lastStatusUpdate < 100) return;
|
|
71
|
-
lastStatusUpdate = now;
|
|
72
|
-
const pct = Math.round(completed / total * 100);
|
|
73
|
-
setStatus(` Upsert ${completed}/${total} (${pct}%)`);
|
|
74
|
-
};
|
|
75
|
-
updateStatus(true);
|
|
76
|
-
const limit = pLimit(5);
|
|
77
|
-
await Promise.all(chunks.map((chunk) => limit(async () => {
|
|
78
|
-
try {
|
|
79
|
-
const r = await fetchFn(vectorUrl, {
|
|
80
|
-
method: "POST",
|
|
81
|
-
headers: {
|
|
82
|
-
"Content-Type": "application/json",
|
|
83
|
-
Authorization: `Bearer ${apiKey}`
|
|
84
|
-
},
|
|
85
|
-
body: JSON.stringify({
|
|
86
|
-
op: "upsert",
|
|
87
|
-
id: chunk.id,
|
|
88
|
-
data: chunk.data,
|
|
89
|
-
metadata: chunk.metadata
|
|
90
|
-
})
|
|
91
|
-
});
|
|
92
|
-
if (!r.ok) {
|
|
93
|
-
lastError = await r.text();
|
|
94
|
-
errors++;
|
|
95
|
-
} else upserted++;
|
|
96
|
-
} catch (err) {
|
|
97
|
-
lastError = errorMessage(err);
|
|
98
|
-
errors++;
|
|
99
|
-
}
|
|
100
|
-
completed++;
|
|
101
|
-
updateStatus();
|
|
102
|
-
})));
|
|
103
|
-
setStatus(null);
|
|
104
|
-
return {
|
|
105
|
-
upserted,
|
|
106
|
-
errors,
|
|
107
|
-
lastError
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
async function runRagCommand(opts) {
|
|
111
|
-
const { url, cwd } = opts;
|
|
112
|
-
try {
|
|
113
|
-
new URL(url);
|
|
114
|
-
} catch (err) {
|
|
115
|
-
throw new Error(`Invalid URL: ${url}\n Provide a fully qualified URL including the protocol (e.g., https://example.com/docs).`, { cause: err });
|
|
116
|
-
}
|
|
117
|
-
const chunkSize = Number.parseInt(opts.chunkSize ?? "512", 10);
|
|
118
|
-
if (Number.isNaN(chunkSize) || chunkSize <= 0) throw new Error(`Invalid chunk size: "${opts.chunkSize}". Must be a positive integer.`);
|
|
119
|
-
const { apiKey, serverUrl, slug } = await getServerInfo(cwd, opts.server);
|
|
120
|
-
await runCommand(async ({ log, setStatus }) => {
|
|
121
|
-
await runRag({
|
|
122
|
-
url,
|
|
123
|
-
apiKey,
|
|
124
|
-
serverUrl,
|
|
125
|
-
slug,
|
|
126
|
-
chunkSize,
|
|
127
|
-
log,
|
|
128
|
-
setStatus
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
/** Split llms-full.txt on `***` page separators and extract titles. */
|
|
133
|
-
function splitPages(content) {
|
|
134
|
-
const raw = content.split(/^\*{3,}$/m);
|
|
135
|
-
const pages = [];
|
|
136
|
-
for (const section of raw) {
|
|
137
|
-
const trimmed = section.trim();
|
|
138
|
-
if (!trimmed) continue;
|
|
139
|
-
const page = parsePage(trimmed);
|
|
140
|
-
if (page.body.length > 0) pages.push(page);
|
|
141
|
-
}
|
|
142
|
-
return pages;
|
|
143
|
-
}
|
|
144
|
-
/** Extract title and body from a single page section. */
|
|
145
|
-
function parsePage(trimmed) {
|
|
146
|
-
let title = "";
|
|
147
|
-
let body = trimmed;
|
|
148
|
-
const dashIndex = trimmed.search(/^-{3,}$/m);
|
|
149
|
-
if (dashIndex !== -1) {
|
|
150
|
-
const frontmatter = trimmed.slice(0, dashIndex);
|
|
151
|
-
body = trimmed.slice(dashIndex).replace(/^-+$/m, "").trim();
|
|
152
|
-
const titleMatch = frontmatter.match(/^title:\s*(.+)$/m);
|
|
153
|
-
if (titleMatch) title = titleMatch[1]?.trim() ?? "";
|
|
154
|
-
}
|
|
155
|
-
if (!title) {
|
|
156
|
-
const titleLineMatch = body.match(/^#{1,2}\s+title:\s*(.+)$/m);
|
|
157
|
-
if (titleLineMatch) {
|
|
158
|
-
title = titleLineMatch[1]?.trim() ?? "";
|
|
159
|
-
body = body.replace(/^#{1,2}\s+title:\s*.+\n?/m, "").trim();
|
|
160
|
-
} else {
|
|
161
|
-
const headingMatch = body.match(/^(#{1,3})\s+(.+)$/m);
|
|
162
|
-
if (headingMatch) title = headingMatch[2]?.trim() ?? "";
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
return {
|
|
166
|
-
title,
|
|
167
|
-
body
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
/** Strip code blocks, HTML/JSX tags, and collapse whitespace from markdown. */
|
|
171
|
-
function stripNoise(text) {
|
|
172
|
-
return text.replace(/^(`{3,}|~{3,}).*[\s\S]*?^\1/gm, "").replace(/^(?:[ ]{4,}|\t).+$/gm, "").replace(/`[^`]+`/g, "").replace(/\{\/\*[\s\S]*?\*\/\}/g, "").replace(/<[^>]+>/g, "").replace(/^\s*\}[^}\n]*$/gm, "").replace(/^\s+$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
173
|
-
}
|
|
174
|
-
function slugify(s) {
|
|
175
|
-
return s.replace(/^https?:\/\//, "").replace(/^#+\s*/, "").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase().slice(0, 80);
|
|
176
|
-
}
|
|
177
|
-
//#endregion
|
|
178
|
-
export { runRagCommand };
|