@alexkroman1/aai-cli 5.8.1 → 5.10.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/README.md +5 -1
- package/bin.mjs +32 -0
- package/dist/{_agent-2nVugrN3.mjs → _agent-DS2PUJcl.mjs} +1 -1
- package/dist/{_bundler-Cjaxa2wi.mjs → _bundler-DC17suWN.mjs} +2 -2
- package/dist/_config-DMyolIk9.mjs +242 -0
- package/dist/_config.d.ts +28 -9
- package/dist/_dev-env.d.ts +38 -0
- package/dist/{_dev-server-BB5N8kdh.mjs → _dev-server-B3ivqyEd.mjs} +75 -55
- package/dist/_dev-server.d.ts +2 -2
- package/dist/{_init-Dei2JRmn.mjs → _init-CYLvYU-B.mjs} +3 -3
- package/dist/{_ui-8kOEB-JH.mjs → _output-CC300DzW.mjs} +1 -42
- package/dist/{_server-common-CnaP_Urf.mjs → _server-common-DX8Bfrf5.mjs} +1 -1
- package/dist/{_slug-api-CGJSST9B.mjs → _slug-api-fRNNR8tz.mjs} +1 -1
- package/dist/{_templates-BfyRyE7z.mjs → _templates-BWJOiWOO.mjs} +2 -2
- package/dist/{_typecheck-gate-DvE8S3aQ.mjs → _typecheck-gate-DB-PY0A3.mjs} +2 -1
- package/dist/_ui-DfwfDbT-.mjs +68 -0
- package/dist/_ui.d.ts +19 -0
- package/dist/{_utils-Ch0J4s6a.mjs → _utils-8KKw-bzi.mjs} +9 -2
- package/dist/_utils.d.ts +9 -2
- package/dist/{build-BXwDB78d.mjs → build-CACFbdQ4.mjs} +5 -4
- package/dist/cli.mjs +21 -20
- package/dist/{client-bundler-yiWoXrgb.mjs → client-bundler-DONm-khu.mjs} +1 -1
- package/dist/client-bundler.mjs +1 -1
- package/dist/{delete-DRNfvczK.mjs → delete-DEZ7u3u4.mjs} +6 -4
- package/dist/delete.d.ts +5 -0
- package/dist/{deploy-Cp-wgME3.mjs → deploy-Ch0d_jje.mjs} +8 -7
- package/dist/{dev-C4KyxouE.mjs → dev-CdeRcYiQ.mjs} +7 -6
- package/dist/{init-BpBbttOv.mjs → init-Nc6fB774.mjs} +6 -5
- package/dist/{login-AA_UdRI-.mjs → login-BeFUiU6M.mjs} +9 -9
- package/dist/scaffold/CLAUDE.md +39 -14
- package/dist/scaffold/package.json +3 -3
- package/dist/{secret-Dr0qnxeb.mjs → secret-4_dYyrpA.mjs} +3 -2
- package/dist/{storage-CoQB8d-u.mjs → storage-BTfErOOW.mjs} +3 -2
- package/dist/{studio-_UBBvh5V.mjs → studio-LNvXtWak.mjs} +7 -6
- package/dist/templates/dispatch-center/agent.ts +4 -6
- package/dist/templates/retail/agent.ts +4 -6
- package/dist/templates/retail/registry.test.ts +5 -3
- package/dist/templates/retail/resolve.test.ts +6 -4
- package/dist/templates/retail/seed.test.ts +21 -13
- package/dist/templates/retail/shared.test.ts +9 -5
- package/dist/templates/solo-rpg/agent.test.ts +7 -5
- package/dist/templates/solo-rpg/shared.ts +2 -2
- package/dist/{test-3Gq4pqH_.mjs → test-C-V98oC-.mjs} +4 -4
- package/dist/typecheck.mjs +65 -14
- package/package.json +5 -4
- package/dist/_config-Y5V-5Krn.mjs +0 -173
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { n as log, o as CliError } from "./_ui-8kOEB-JH.mjs";
|
|
3
|
-
import { a as errorMessage, c as readJson, d as writeJson } from "./_utils-Ch0J4s6a.mjs";
|
|
4
|
-
import { mkdtempSync } from "node:fs";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import { tmpdir } from "node:os";
|
|
7
|
-
import envPaths from "env-paths";
|
|
8
|
-
import { z } from "zod";
|
|
9
|
-
//#region _config.ts
|
|
10
|
-
/**
|
|
11
|
-
* `.aai/project.json` lives in the working tree, so everything in it is
|
|
12
|
-
* untrusted input — a cloned repo can supply any value.
|
|
13
|
-
*
|
|
14
|
-
* `serverUrl` is deliberately NOT validated here. A failed field makes
|
|
15
|
-
* `readProjectConfig` return null for the whole file, which discards the
|
|
16
|
-
* `slug` too — and a deploy with no slug generates a fresh one, silently
|
|
17
|
-
* creating a duplicate agent and overwriting the config. The URL is instead
|
|
18
|
-
* validated where it is used, by `resolveServerUrl`, which rejects anything
|
|
19
|
-
* that isn't an approved http(s) origin.
|
|
20
|
-
*/
|
|
21
|
-
const ProjectConfigSchema = z.object({
|
|
22
|
-
/** Deployed agent slug — absent for a pulled project never published. */
|
|
23
|
-
slug: z.string().optional(),
|
|
24
|
-
serverUrl: z.string(),
|
|
25
|
-
/** Studio project this directory is linked to (`aai pull`/`aai push`). */
|
|
26
|
-
studioProject: z.string().optional(),
|
|
27
|
-
/**
|
|
28
|
-
* The workspace files hash at the last pull/push — `aai push` sends it
|
|
29
|
-
* back as the fast-forward token, so an edit made in the studio since
|
|
30
|
-
* then surfaces as a 409 instead of being silently overwritten.
|
|
31
|
-
*/
|
|
32
|
-
studioSourceHash: z.string().optional()
|
|
33
|
-
});
|
|
34
|
-
/**
|
|
35
|
-
* Resolve the global config directory (the platform-conventional env-paths
|
|
36
|
-
* location).
|
|
37
|
-
*
|
|
38
|
-
* `AAI_CONFIG_DIR` overrides everything — it exists so tests (and unusual
|
|
39
|
-
* setups) can redirect ALL global-config reads and writes away from the
|
|
40
|
-
* user's real config. The test suite's `approveServer` calls used to
|
|
41
|
-
* permanently pollute `~/.config/aai/config.json` with approved origins.
|
|
42
|
-
*/
|
|
43
|
-
function getConfigDir() {
|
|
44
|
-
const override = process.env.AAI_CONFIG_DIR?.trim();
|
|
45
|
-
if (override) return override;
|
|
46
|
-
if (process.env.VITEST) return testConfigDir();
|
|
47
|
-
return envPaths("aai", { suffix: "" }).config;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Per-process throwaway config dir used only under vitest. Memoized: callers
|
|
51
|
-
* read-modify-write the same config across calls, so a fresh dir per call
|
|
52
|
-
* would silently drop what the previous one wrote.
|
|
53
|
-
*/
|
|
54
|
-
let _testConfigDir;
|
|
55
|
-
function testConfigDir() {
|
|
56
|
-
_testConfigDir ??= mkdtempSync(path.join(tmpdir(), "aai-vitest-config-"));
|
|
57
|
-
return _testConfigDir;
|
|
58
|
-
}
|
|
59
|
-
async function readProjectConfig(agentDir) {
|
|
60
|
-
const file = path.join(agentDir, ".aai", "project.json");
|
|
61
|
-
let data;
|
|
62
|
-
try {
|
|
63
|
-
data = await readJson(file);
|
|
64
|
-
} catch (err) {
|
|
65
|
-
const reason = errorMessage(err).replace(`Invalid JSON in ${file}: `, "");
|
|
66
|
-
throw new Error(`project.json is corrupted at ${file}: ${reason}\n Fix or delete the file — deploying without it would create a new agent under a fresh slug.`, { cause: err });
|
|
67
|
-
}
|
|
68
|
-
if (data === null) return null;
|
|
69
|
-
const parsed = ProjectConfigSchema.safeParse(data);
|
|
70
|
-
if (!parsed.success) return null;
|
|
71
|
-
return parsed.data;
|
|
72
|
-
}
|
|
73
|
-
async function writeProjectConfig(agentDir, data) {
|
|
74
|
-
await writeJson(path.join(agentDir, ".aai", "project.json"), data);
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Merge `patch` into the existing project config rather than replacing the
|
|
78
|
-
* file — a publish recording its `slug` must not drop the studio link
|
|
79
|
-
* fields a pull wrote, and vice versa.
|
|
80
|
-
*/
|
|
81
|
-
async function updateProjectConfig(agentDir, patch) {
|
|
82
|
-
let existing = null;
|
|
83
|
-
try {
|
|
84
|
-
existing = await readProjectConfig(agentDir);
|
|
85
|
-
} catch {}
|
|
86
|
-
const merged = {
|
|
87
|
-
...existing,
|
|
88
|
-
...patch
|
|
89
|
-
};
|
|
90
|
-
await writeProjectConfig(agentDir, merged);
|
|
91
|
-
return merged;
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Origin of `url`, or `null` when it is not an absolute http(s) URL.
|
|
95
|
-
*
|
|
96
|
-
* Non-HTTP schemes are rejected rather than returned: `new URL()` yields the
|
|
97
|
-
* opaque origin `"null"` for them, which would otherwise flow on as if it
|
|
98
|
-
* were a real origin.
|
|
99
|
-
*/
|
|
100
|
-
function serverOrigin(url) {
|
|
101
|
-
let parsed;
|
|
102
|
-
try {
|
|
103
|
-
parsed = new URL(url);
|
|
104
|
-
} catch {
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
|
|
108
|
-
return parsed.origin;
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Record `url`'s origin as user-approved, so later commands in this project
|
|
112
|
-
* may send credentials there without re-passing `--server`.
|
|
113
|
-
*/
|
|
114
|
-
async function approveServer(url, configDir) {
|
|
115
|
-
const origin = serverOrigin(url);
|
|
116
|
-
if (!origin) return;
|
|
117
|
-
const dir = configDir ?? getConfigDir();
|
|
118
|
-
const config = await readGlobalConfig(dir);
|
|
119
|
-
const approved = config.approvedServers ?? [];
|
|
120
|
-
if (approved.includes(origin)) return;
|
|
121
|
-
await writeGlobalConfig(dir, {
|
|
122
|
-
...config,
|
|
123
|
-
approvedServers: [...approved, origin]
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
async function readGlobalConfig(configDir) {
|
|
127
|
-
const dir = configDir ?? getConfigDir();
|
|
128
|
-
return await readJson(path.join(dir, "config.json")) ?? {};
|
|
129
|
-
}
|
|
130
|
-
async function writeGlobalConfig(configDir, data) {
|
|
131
|
-
await writeJson(path.join(configDir, "config.json"), data, { mode: 384 });
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Persist the API key to the global config, warning (not failing) when the
|
|
135
|
-
* config dir is unwritable — the key in hand still works for this run.
|
|
136
|
-
*/
|
|
137
|
-
async function trySaveApiKey(dir, config, apiKey) {
|
|
138
|
-
try {
|
|
139
|
-
await writeGlobalConfig(dir, {
|
|
140
|
-
...config,
|
|
141
|
-
apiKey
|
|
142
|
-
});
|
|
143
|
-
} catch (err) {
|
|
144
|
-
log.warn(`Couldn't save your API key to ${path.join(dir, "config.json")}: ${errorMessage(err)} — you'll be prompted again next run.`);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* The credential every platform command runs on.
|
|
149
|
-
*
|
|
150
|
-
* Two sources, in order: the key `aai login` saved, then
|
|
151
|
-
* `ASSEMBLYAI_API_KEY` for non-interactive callers (CI, scripts, the eval
|
|
152
|
-
* harnesses).
|
|
153
|
-
*
|
|
154
|
-
* There is deliberately NO "paste a key" prompt. Pasting one produced a
|
|
155
|
-
* half-configured CLI — able to push and publish while linked to no account
|
|
156
|
-
* the user could see in the studio — and it made `aai login`, which is the
|
|
157
|
-
* real onboarding path, optional in practice. It was also the riskier code
|
|
158
|
-
* path: a hidden password prompt reads stdin, so a piped invocation could
|
|
159
|
-
* have its input eaten and persisted as the API key.
|
|
160
|
-
*/
|
|
161
|
-
async function ensureApiKey(configDir) {
|
|
162
|
-
const dir = configDir ?? getConfigDir();
|
|
163
|
-
const config = await readGlobalConfig(dir);
|
|
164
|
-
if (config.apiKey) return config.apiKey;
|
|
165
|
-
const envKey = process.env.ASSEMBLYAI_API_KEY;
|
|
166
|
-
if (envKey) {
|
|
167
|
-
await trySaveApiKey(dir, config, envKey);
|
|
168
|
-
return envKey;
|
|
169
|
-
}
|
|
170
|
-
throw new CliError("not_logged_in", "You're not logged in.", "Run `aai login` to link your account, or set ASSEMBLYAI_API_KEY for non-interactive use.");
|
|
171
|
-
}
|
|
172
|
-
//#endregion
|
|
173
|
-
export { readProjectConfig as a, writeGlobalConfig as c, readGlobalConfig as i, writeProjectConfig as l, ensureApiKey as n, serverOrigin as o, getConfigDir as r, updateProjectConfig as s, approveServer as t };
|