@alexkroman1/aai-cli 5.5.1 → 5.7.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 +16 -7
- package/dist/{_agent-DMyOab9_.mjs → _agent-2nVugrN3.mjs} +22 -3
- package/dist/_agent.d.ts +3 -1
- package/dist/_api-client-B-upMGkc.mjs +104 -0
- package/dist/_api-client.d.ts +16 -0
- package/dist/_cli-common.d.ts +65 -0
- package/dist/{_config-5AEqhh-O.mjs → _config-Y5V-5Krn.mjs} +58 -9
- package/dist/_config.d.ts +23 -1
- package/dist/_deploy.d.ts +7 -0
- package/dist/{_dev-server-vV05Fnki.mjs → _dev-server-BB5N8kdh.mjs} +2 -2
- package/dist/{_init-BZ9t_Kz-.mjs → _init-D7JIT-IJ.mjs} +3 -3
- package/dist/{_slug-api-DaqQJHk8.mjs → _slug-api-CGJSST9B.mjs} +2 -2
- package/dist/_studio-commands.d.ts +73 -0
- package/dist/_studio.d.ts +64 -0
- package/dist/{_templates-Bv8CR800.mjs → _templates-Bt6u9_68.mjs} +19 -8
- package/dist/_templates.d.ts +9 -0
- package/dist/{_typecheck-gate-9IHWDnl1.mjs → _typecheck-gate-DvE8S3aQ.mjs} +1 -1
- package/dist/{build-D_PgQOD4.mjs → build-BXwDB78d.mjs} +1 -1
- package/dist/cli.mjs +264 -32
- package/dist/delete-DRNfvczK.mjs +53 -0
- package/dist/delete.d.ts +9 -2
- package/dist/{deploy-1eaXcfUw.mjs → deploy-Cp-wgME3.mjs} +7 -5
- package/dist/deploy.d.ts +2 -0
- package/dist/{dev-gVNdGFYY.mjs → dev-C4KyxouE.mjs} +1 -1
- package/dist/{init-DoU4_txp.mjs → init-BT-IU9AR.mjs} +15 -14
- package/dist/login-AA_UdRI-.mjs +172 -0
- package/dist/login.d.ts +33 -20
- package/dist/scaffold/package.json +4 -4
- package/dist/{secret-CGAIAbUx.mjs → secret-Dr0qnxeb.mjs} +1 -1
- package/dist/{storage-CnhOayhm.mjs → storage-CoQB8d-u.mjs} +1 -1
- package/dist/studio-sXvYUxr5.mjs +325 -0
- package/dist/studio.d.ts +54 -0
- package/package.json +4 -4
- package/dist/_api-client-MenP4-O7.mjs +0 -49
- package/dist/delete-DXilFBb1.mjs +0 -29
- package/dist/login-C59ZHzuO.mjs +0 -109
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
import { n as log, t as fmtUrl, u as ok } from "./_ui-8kOEB-JH.mjs";
|
|
3
3
|
import { a as errorMessage } from "./_utils-Ch0J4s6a.mjs";
|
|
4
4
|
import { t as buildAgentBundle } from "./_bundler-Cjaxa2wi.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { s as updateProjectConfig } from "./_config-Y5V-5Krn.mjs";
|
|
6
6
|
import { t as resolveServerEnv } from "./_server-common-CnaP_Urf.mjs";
|
|
7
|
-
import { i as resolveDeployTarget } from "./_agent-
|
|
8
|
-
import {
|
|
9
|
-
import { n as apiRequest } from "./_api-client-
|
|
7
|
+
import { i as resolveDeployTarget } from "./_agent-2nVugrN3.mjs";
|
|
8
|
+
import { assertTypechecks } from "./_typecheck-gate-DvE8S3aQ.mjs";
|
|
9
|
+
import { n as apiRequest } from "./_api-client-B-upMGkc.mjs";
|
|
10
10
|
import { gzipSync } from "node:zlib";
|
|
11
11
|
//#region _deploy.ts
|
|
12
12
|
async function runDeploy(opts) {
|
|
13
13
|
const body = gzipSync(JSON.stringify({
|
|
14
14
|
...opts.slug ? { slug: opts.slug } : {},
|
|
15
15
|
...opts.allowMissingSecrets ? { credentialPolicy: "warn" } : {},
|
|
16
|
+
...opts.allowPreviewSlug ? { allowPreviewSlug: true } : {},
|
|
16
17
|
env: opts.env,
|
|
17
18
|
worker: opts.bundle.worker,
|
|
18
19
|
clientFiles: opts.bundle.clientFiles
|
|
@@ -55,11 +56,12 @@ async function executeDeploy(opts) {
|
|
|
55
56
|
},
|
|
56
57
|
...slug ? { slug } : {},
|
|
57
58
|
...opts.allowMissingSecrets ? { allowMissingSecrets: true } : {},
|
|
59
|
+
...opts.allowPreviewSlug ? { allowPreviewSlug: true } : {},
|
|
58
60
|
apiKey
|
|
59
61
|
});
|
|
60
62
|
const agentUrl = `${serverUrl}/${deployed.slug}`;
|
|
61
63
|
try {
|
|
62
|
-
await
|
|
64
|
+
await updateProjectConfig(cwd, {
|
|
63
65
|
slug: deployed.slug,
|
|
64
66
|
serverUrl
|
|
65
67
|
});
|
package/dist/deploy.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export declare function executeDeploy(opts: {
|
|
|
9
9
|
server?: string | undefined;
|
|
10
10
|
/** See DeployOpts.allowMissingSecrets (`--allow-missing-secrets`). */
|
|
11
11
|
allowMissingSecrets?: boolean | undefined;
|
|
12
|
+
/** See DeployOpts.allowPreviewSlug (`--allow-preview-slug`; studio-internal). */
|
|
13
|
+
allowPreviewSlug?: boolean | undefined;
|
|
12
14
|
/** `--skipTypecheck`: deploy without the tsc gate. */
|
|
13
15
|
skipTypecheck?: boolean | undefined;
|
|
14
16
|
}): Promise<CommandResult<DeployData>>;
|
|
@@ -11,7 +11,7 @@ import { styleText } from "node:util";
|
|
|
11
11
|
async function executeDev(opts) {
|
|
12
12
|
const port = parsePort(opts.port);
|
|
13
13
|
const agentName = path.basename(path.resolve(opts.cwd));
|
|
14
|
-
const { startDevServer } = await import("./_dev-server-
|
|
14
|
+
const { startDevServer } = await import("./_dev-server-BB5N8kdh.mjs");
|
|
15
15
|
let cleanup;
|
|
16
16
|
let shuttingDown = false;
|
|
17
17
|
const onSignal = () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { a as unwrapCancel, n as log, u as ok } from "./_ui-8kOEB-JH.mjs";
|
|
3
3
|
import { a as errorMessage, c as readJson, l as resolveCwd, o as fileExists, t as AGENT_ENTRY } from "./_utils-Ch0J4s6a.mjs";
|
|
4
|
-
import { r as isDevMode, t as getMonorepoRoot } from "./_agent-
|
|
4
|
+
import { r as isDevMode, t as getMonorepoRoot } from "./_agent-2nVugrN3.mjs";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { styleText } from "node:util";
|
|
7
7
|
import * as p from "@clack/prompts";
|
|
@@ -72,27 +72,28 @@ async function installDeps(cwd, silent) {
|
|
|
72
72
|
function resolveTargetDir(dir) {
|
|
73
73
|
return path.resolve(resolveCwd(), dir);
|
|
74
74
|
}
|
|
75
|
-
/**
|
|
76
|
-
async function
|
|
77
|
-
const {
|
|
75
|
+
/** Publish after init and return deploy metadata if successful. */
|
|
76
|
+
async function tryPublish(cwd, server) {
|
|
77
|
+
const { executePublish } = await import("./studio-sXvYUxr5.mjs");
|
|
78
78
|
try {
|
|
79
|
-
const result = await
|
|
79
|
+
const result = await executePublish({
|
|
80
80
|
cwd,
|
|
81
81
|
...server ? { server } : {}
|
|
82
82
|
});
|
|
83
83
|
return result.ok ? {
|
|
84
84
|
slug: result.data.slug,
|
|
85
|
-
url: result.data.url
|
|
85
|
+
url: result.data.url,
|
|
86
|
+
studioUrl: result.data.studioUrl
|
|
86
87
|
} : null;
|
|
87
88
|
} catch (err) {
|
|
88
|
-
log.warn(`
|
|
89
|
-
log.warn("Your project was still created — run `aai
|
|
89
|
+
log.warn(`Publish failed: ${errorMessage(err)}`);
|
|
90
|
+
log.warn("Your project was still created — run `aai publish` in it to retry.");
|
|
90
91
|
return null;
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
/** Scaffold the project, optionally showing a spinner. */
|
|
94
95
|
async function scaffoldProject(dir, cwd, template, silent) {
|
|
95
|
-
const { runInit } = await import("./_init-
|
|
96
|
+
const { runInit } = await import("./_init-D7JIT-IJ.mjs");
|
|
96
97
|
const s = silent ? void 0 : p.spinner();
|
|
97
98
|
s?.start(`Creating ${dir}`);
|
|
98
99
|
await runInit({
|
|
@@ -120,13 +121,13 @@ async function executeInit(opts, extra) {
|
|
|
120
121
|
let deployed = false;
|
|
121
122
|
let slug;
|
|
122
123
|
let url;
|
|
123
|
-
if (!installed) log.warn("Skipping
|
|
124
|
+
if (!installed) log.warn("Skipping publish because dependencies were not installed.");
|
|
124
125
|
else if (!opts.skipDeploy) {
|
|
125
|
-
const
|
|
126
|
-
if (
|
|
126
|
+
const published = await tryPublish(cwd, opts.server);
|
|
127
|
+
if (published) {
|
|
127
128
|
deployed = true;
|
|
128
|
-
slug =
|
|
129
|
-
url =
|
|
129
|
+
slug = published.slug;
|
|
130
|
+
url = published.url;
|
|
130
131
|
}
|
|
131
132
|
}
|
|
132
133
|
if (!suppressUi) printPostInitInfo(cwd, monorepoRoot);
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { n as log, o as CliError, u as ok } from "./_ui-8kOEB-JH.mjs";
|
|
3
|
+
import { c as writeGlobalConfig, i as readGlobalConfig, r as getConfigDir, t as approveServer } from "./_config-Y5V-5Krn.mjs";
|
|
4
|
+
import { a as resolveServerUrl } from "./_agent-2nVugrN3.mjs";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { setTimeout } from "node:timers/promises";
|
|
7
|
+
import { randomBytes } from "node:crypto";
|
|
8
|
+
//#region login.ts
|
|
9
|
+
/**
|
|
10
|
+
* `aai login` — link the CLI to an account that is ALREADY signed in to the
|
|
11
|
+
* browser studio, ending with the account's AssemblyAI API key stored in
|
|
12
|
+
* the global config (the same slot `ensureApiKey` reads), so every other
|
|
13
|
+
* command is untouched by how the key was acquired.
|
|
14
|
+
*
|
|
15
|
+
* The CLI deliberately performs no sign-in of its own — it cannot create an
|
|
16
|
+
* account, and it never sees a session token. Device-link flow:
|
|
17
|
+
* 1. `GET /studio/auth` — fail fast when the server has no browser login
|
|
18
|
+
* configured (nobody could ever approve the link).
|
|
19
|
+
* 2. Mint an unguessable one-shot code (32 random bytes, base64url) and
|
|
20
|
+
* open the browser at `<server>/?cli-link=<code>`. The studio — where
|
|
21
|
+
* the user signs in with GitHub (or the local-dev login) if they aren't
|
|
22
|
+
* already — shows a "link the CLI to this account?" approval displaying
|
|
23
|
+
* the same short confirmation code this terminal printed, so a phished
|
|
24
|
+
* approval link has a visible mismatch (no terminal to match against).
|
|
25
|
+
* 3. Poll `POST /studio/cli-link/exchange` with the code. Approval grants
|
|
26
|
+
* the code ONE exchange for the account's stored API key, which is
|
|
27
|
+
* saved locally. An account with no stored key can't approve — the
|
|
28
|
+
* studio's own onboarding gate runs first — so the CLI never sets keys.
|
|
29
|
+
*/
|
|
30
|
+
const LINK_POLL_INTERVAL_MS = 2e3;
|
|
31
|
+
const LINK_TIMEOUT_MS = 3e5;
|
|
32
|
+
async function jsonBody(res, what) {
|
|
33
|
+
const body = await res.json().catch(() => null);
|
|
34
|
+
if (!res.ok) throw new CliError("login_failed", `${what} failed: ${body?.error ?? body?.msg ?? `HTTP ${res.status}`}`);
|
|
35
|
+
if (body === null) throw new CliError("login_failed", `${what} returned an invalid response`);
|
|
36
|
+
return body;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Fetch, turning a transport failure into an error that names the server.
|
|
40
|
+
*
|
|
41
|
+
* A connection failure here is undici's bare `TypeError: fetch failed` — no
|
|
42
|
+
* URL, no cause worth printing — and `aai login` is exactly where it is least
|
|
43
|
+
* diagnosable: the target is resolved (dev mode pins `localhost:8080`
|
|
44
|
+
* whenever the CLI itself lives in the monorepo, whatever the cwd), so the
|
|
45
|
+
* user cannot tell which server was unreachable, or that a local one was
|
|
46
|
+
* expected at all. `apiRequest` has always said "could not reach <url>";
|
|
47
|
+
* login used raw fetch and said nothing.
|
|
48
|
+
*/
|
|
49
|
+
async function reachable(fetchFn, url, serverUrl) {
|
|
50
|
+
try {
|
|
51
|
+
return await fetchFn(url);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
throw unreachableError(serverUrl, err);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* "Could not reach <server>", with advice chosen by the kind of host and the
|
|
58
|
+
* original transport failure preserved as the cause.
|
|
59
|
+
*/
|
|
60
|
+
function unreachableError(serverUrl, cause) {
|
|
61
|
+
const hint = isLoopback(serverUrl) ? "That's a local server — start it with `pnpm dev:aai-server`, or pass `--server <url>` to log in elsewhere. (A CLI installed from the monorepo targets localhost by default; set AAI_NO_DEV=1 to use the hosted platform.)" : "Check your network connection and verify the server URL is correct.";
|
|
62
|
+
return new CliError("login_unreachable", `Could not reach ${serverUrl}.`, hint, { cause });
|
|
63
|
+
}
|
|
64
|
+
/** Whether `url`'s host is loopback — used only to pick a better hint. */
|
|
65
|
+
function isLoopback(url) {
|
|
66
|
+
try {
|
|
67
|
+
const { hostname } = new URL(url);
|
|
68
|
+
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
69
|
+
} catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Poll the exchange until the browser approves the link, or the deadline.
|
|
75
|
+
*
|
|
76
|
+
* A transport failure is retried rather than fatal: the user is off in a
|
|
77
|
+
* browser approving, and a dev server reloading in that window would
|
|
78
|
+
* otherwise lose a login that was about to succeed. The last one is
|
|
79
|
+
* remembered, so a server that never comes back is reported as unreachable
|
|
80
|
+
* rather than as "you didn't approve in time" — which would blame the user
|
|
81
|
+
* for someone else's outage.
|
|
82
|
+
*/
|
|
83
|
+
async function pollForGrant(fetchFn, serverUrl, code, opts) {
|
|
84
|
+
let lastTransportError;
|
|
85
|
+
for (;;) {
|
|
86
|
+
let res = null;
|
|
87
|
+
try {
|
|
88
|
+
res = await fetchFn(`${serverUrl}/studio/cli-link/exchange`, {
|
|
89
|
+
method: "POST",
|
|
90
|
+
headers: { "Content-Type": "application/json" },
|
|
91
|
+
body: JSON.stringify({ code })
|
|
92
|
+
});
|
|
93
|
+
lastTransportError = void 0;
|
|
94
|
+
} catch (err) {
|
|
95
|
+
lastTransportError = err;
|
|
96
|
+
}
|
|
97
|
+
if (res && res.status !== 404) return await jsonBody(res, "Linking your account");
|
|
98
|
+
if (Date.now() >= opts.deadline) {
|
|
99
|
+
if (lastTransportError !== void 0) throw unreachableError(serverUrl, lastTransportError);
|
|
100
|
+
throw new CliError("login_timeout", "Timed out waiting for the link to be approved in the browser.", "Run `aai login` again and approve the link within five minutes.");
|
|
101
|
+
}
|
|
102
|
+
await setTimeout(opts.intervalMs);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function requireTty() {
|
|
106
|
+
if (!process.stdin.isTTY) throw new CliError("login_interactive", "`aai login` is interactive and needs a TTY.", "Non-interactive setups can set the ASSEMBLYAI_API_KEY environment variable instead.");
|
|
107
|
+
}
|
|
108
|
+
function openerFor(platform) {
|
|
109
|
+
if (platform === "darwin") return ["open", []];
|
|
110
|
+
if (platform === "win32") return ["cmd", [
|
|
111
|
+
"/c",
|
|
112
|
+
"start",
|
|
113
|
+
""
|
|
114
|
+
]];
|
|
115
|
+
return ["xdg-open", []];
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Human-matchable confirmation derived from the link code — printed in the
|
|
119
|
+
* terminal AND shown on the browser approval gate (aai-studio-client's
|
|
120
|
+
* cli-link.ts derives the same value; keep the two in lockstep). Not a
|
|
121
|
+
* secret: both ends already hold the full code. It exists so someone who
|
|
122
|
+
* lands on an approval page they didn't cause has a concrete mismatch to
|
|
123
|
+
* notice ("what terminal?") instead of a bare Approve button.
|
|
124
|
+
*/
|
|
125
|
+
function linkConfirmationCode(code) {
|
|
126
|
+
const head = code.slice(0, 8).toUpperCase();
|
|
127
|
+
return `${head.slice(0, 4)}-${head.slice(4)}`;
|
|
128
|
+
}
|
|
129
|
+
/** Best-effort: the link URL is always printed, so a failure is fine. */
|
|
130
|
+
function defaultOpenBrowser(url) {
|
|
131
|
+
const [cmd, args] = openerFor(process.platform);
|
|
132
|
+
try {
|
|
133
|
+
const child = spawn(cmd, [...args, url], {
|
|
134
|
+
stdio: "ignore",
|
|
135
|
+
detached: true
|
|
136
|
+
});
|
|
137
|
+
child.on("error", () => {});
|
|
138
|
+
child.unref();
|
|
139
|
+
} catch {}
|
|
140
|
+
}
|
|
141
|
+
async function executeLogin(opts, deps = {}) {
|
|
142
|
+
const fetchFn = deps.fetchFn ?? globalThis.fetch;
|
|
143
|
+
requireTty();
|
|
144
|
+
const globalConfig = await readGlobalConfig();
|
|
145
|
+
const serverUrl = resolveServerUrl(opts.server, void 0, globalConfig.approvedServers ?? []);
|
|
146
|
+
if (opts.server) await approveServer(serverUrl);
|
|
147
|
+
if ((await jsonBody(await reachable(fetchFn, `${serverUrl}/studio/auth`, serverUrl), "Reading the server's login configuration")).mode === "none") throw new CliError("login_unavailable", "This server has no browser login configured, so there is no account to link.", "Set the ASSEMBLYAI_API_KEY environment variable instead — it's the only other way to authenticate.");
|
|
148
|
+
const code = randomBytes(32).toString("base64url");
|
|
149
|
+
const linkUrl = `${serverUrl}/?cli-link=${code}`;
|
|
150
|
+
log.info(`Opening the browser to link your account…\n ${linkUrl}`);
|
|
151
|
+
log.info(`Confirmation code: ${linkConfirmationCode(code)}`);
|
|
152
|
+
log.info("Approve the link in the browser (sign in there first if you need to) — the approval page shows the same code.");
|
|
153
|
+
(deps.openBrowser ?? defaultOpenBrowser)(linkUrl);
|
|
154
|
+
const granted = await pollForGrant(fetchFn, serverUrl, code, {
|
|
155
|
+
intervalMs: deps.pollIntervalMs ?? LINK_POLL_INTERVAL_MS,
|
|
156
|
+
deadline: Date.now() + (deps.timeoutMs ?? LINK_TIMEOUT_MS)
|
|
157
|
+
});
|
|
158
|
+
if (!granted.apiKey) throw new CliError("login_failed", "Linking your account did not return an API key.");
|
|
159
|
+
const dir = getConfigDir();
|
|
160
|
+
await writeGlobalConfig(dir, {
|
|
161
|
+
...await readGlobalConfig(dir),
|
|
162
|
+
apiKey: granted.apiKey
|
|
163
|
+
});
|
|
164
|
+
const email = granted.email ?? "your account";
|
|
165
|
+
log.success(`Linked ${email} — your API key is saved for future commands.`);
|
|
166
|
+
return ok({
|
|
167
|
+
email,
|
|
168
|
+
server: serverUrl
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
//#endregion
|
|
172
|
+
export { executeLogin };
|
package/dist/login.d.ts
CHANGED
|
@@ -1,31 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `aai login` —
|
|
3
|
-
* account's AssemblyAI API key stored in
|
|
4
|
-
* `ensureApiKey` reads), so every other
|
|
5
|
-
* key was acquired.
|
|
2
|
+
* `aai login` — link the CLI to an account that is ALREADY signed in to the
|
|
3
|
+
* browser studio, ending with the account's AssemblyAI API key stored in
|
|
4
|
+
* the global config (the same slot `ensureApiKey` reads), so every other
|
|
5
|
+
* command is untouched by how the key was acquired.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* Unlike the browser, the CLI needs the RAW key: `aai dev` runs the
|
|
22
|
-
* provider pipeline in-process on it.
|
|
7
|
+
* The CLI deliberately performs no sign-in of its own — it cannot create an
|
|
8
|
+
* account, and it never sees a session token. Device-link flow:
|
|
9
|
+
* 1. `GET /studio/auth` — fail fast when the server has no browser login
|
|
10
|
+
* configured (nobody could ever approve the link).
|
|
11
|
+
* 2. Mint an unguessable one-shot code (32 random bytes, base64url) and
|
|
12
|
+
* open the browser at `<server>/?cli-link=<code>`. The studio — where
|
|
13
|
+
* the user signs in with GitHub (or the local-dev login) if they aren't
|
|
14
|
+
* already — shows a "link the CLI to this account?" approval displaying
|
|
15
|
+
* the same short confirmation code this terminal printed, so a phished
|
|
16
|
+
* approval link has a visible mismatch (no terminal to match against).
|
|
17
|
+
* 3. Poll `POST /studio/cli-link/exchange` with the code. Approval grants
|
|
18
|
+
* the code ONE exchange for the account's stored API key, which is
|
|
19
|
+
* saved locally. An account with no stored key can't approve — the
|
|
20
|
+
* studio's own onboarding gate runs first — so the CLI never sets keys.
|
|
23
21
|
*/
|
|
24
22
|
import { type CommandResult } from "./_output.ts";
|
|
25
23
|
export type LoginDeps = {
|
|
26
24
|
/** Test seam — never set outside tests. */
|
|
27
25
|
fetchFn?: typeof globalThis.fetch;
|
|
26
|
+
/** Test seam — never set outside tests. */
|
|
27
|
+
openBrowser?: (url: string) => void;
|
|
28
|
+
/** Test seam — never set outside tests. */
|
|
29
|
+
pollIntervalMs?: number;
|
|
30
|
+
/** Test seam — never set outside tests. */
|
|
31
|
+
timeoutMs?: number;
|
|
28
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* Human-matchable confirmation derived from the link code — printed in the
|
|
35
|
+
* terminal AND shown on the browser approval gate (aai-studio-client's
|
|
36
|
+
* cli-link.ts derives the same value; keep the two in lockstep). Not a
|
|
37
|
+
* secret: both ends already hold the full code. It exists so someone who
|
|
38
|
+
* lands on an approval page they didn't cause has a concrete mismatch to
|
|
39
|
+
* notice ("what terminal?") instead of a bare Approve button.
|
|
40
|
+
*/
|
|
41
|
+
export declare function linkConfirmationCode(code: string): string;
|
|
29
42
|
export declare function executeLogin(opts: {
|
|
30
43
|
server?: string | undefined;
|
|
31
44
|
}, deps?: LoginDeps): Promise<CommandResult<{
|
|
@@ -8,18 +8,18 @@
|
|
|
8
8
|
"dev": "aai dev",
|
|
9
9
|
"build": "aai build",
|
|
10
10
|
"test": "aai test",
|
|
11
|
-
"
|
|
11
|
+
"publish:agent": "aai publish"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@alexkroman1/aai": "^5.
|
|
15
|
-
"@alexkroman1/aai-ui": "^5.
|
|
14
|
+
"@alexkroman1/aai": "^5.7.0",
|
|
15
|
+
"@alexkroman1/aai-ui": "^5.7.0",
|
|
16
16
|
"react": "^19.2.8",
|
|
17
17
|
"react-dom": "^19.2.8",
|
|
18
18
|
"tailwindcss": "^4.0.0",
|
|
19
19
|
"zod": "^4.4.3"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@alexkroman1/aai-cli": "^5.
|
|
22
|
+
"@alexkroman1/aai-cli": "^5.7.0",
|
|
23
23
|
"@tailwindcss/vite": "^4.3.3",
|
|
24
24
|
"@types/node": "^26.1.1",
|
|
25
25
|
"@types/react": "^19.2.17",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { a as unwrapCancel, n as log, s as fail, u as ok } from "./_ui-8kOEB-JH.mjs";
|
|
3
|
-
import { t as slugRequest } from "./_slug-api-
|
|
3
|
+
import { t as slugRequest } from "./_slug-api-CGJSST9B.mjs";
|
|
4
4
|
import * as p from "@clack/prompts";
|
|
5
5
|
import { text } from "node:stream/consumers";
|
|
6
6
|
//#region secret.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as log, s as fail, u as ok } from "./_ui-8kOEB-JH.mjs";
|
|
3
|
-
import { t as slugRequest } from "./_slug-api-
|
|
3
|
+
import { t as slugRequest } from "./_slug-api-CGJSST9B.mjs";
|
|
4
4
|
import * as p from "@clack/prompts";
|
|
5
5
|
//#region storage.ts
|
|
6
6
|
async function storageRequest(cwd, init, server) {
|