@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.
Files changed (36) hide show
  1. package/README.md +16 -7
  2. package/dist/{_agent-DMyOab9_.mjs → _agent-2nVugrN3.mjs} +22 -3
  3. package/dist/_agent.d.ts +3 -1
  4. package/dist/_api-client-B-upMGkc.mjs +104 -0
  5. package/dist/_api-client.d.ts +16 -0
  6. package/dist/_cli-common.d.ts +65 -0
  7. package/dist/{_config-5AEqhh-O.mjs → _config-Y5V-5Krn.mjs} +58 -9
  8. package/dist/_config.d.ts +23 -1
  9. package/dist/_deploy.d.ts +7 -0
  10. package/dist/{_dev-server-vV05Fnki.mjs → _dev-server-BB5N8kdh.mjs} +2 -2
  11. package/dist/{_init-BZ9t_Kz-.mjs → _init-D7JIT-IJ.mjs} +3 -3
  12. package/dist/{_slug-api-DaqQJHk8.mjs → _slug-api-CGJSST9B.mjs} +2 -2
  13. package/dist/_studio-commands.d.ts +73 -0
  14. package/dist/_studio.d.ts +64 -0
  15. package/dist/{_templates-Bv8CR800.mjs → _templates-Bt6u9_68.mjs} +19 -8
  16. package/dist/_templates.d.ts +9 -0
  17. package/dist/{_typecheck-gate-9IHWDnl1.mjs → _typecheck-gate-DvE8S3aQ.mjs} +1 -1
  18. package/dist/{build-D_PgQOD4.mjs → build-BXwDB78d.mjs} +1 -1
  19. package/dist/cli.mjs +264 -32
  20. package/dist/delete-DRNfvczK.mjs +53 -0
  21. package/dist/delete.d.ts +9 -2
  22. package/dist/{deploy-1eaXcfUw.mjs → deploy-Cp-wgME3.mjs} +7 -5
  23. package/dist/deploy.d.ts +2 -0
  24. package/dist/{dev-gVNdGFYY.mjs → dev-C4KyxouE.mjs} +1 -1
  25. package/dist/{init-DoU4_txp.mjs → init-BT-IU9AR.mjs} +15 -14
  26. package/dist/login-AA_UdRI-.mjs +172 -0
  27. package/dist/login.d.ts +33 -20
  28. package/dist/scaffold/package.json +4 -4
  29. package/dist/{secret-CGAIAbUx.mjs → secret-Dr0qnxeb.mjs} +1 -1
  30. package/dist/{storage-CnhOayhm.mjs → storage-CoQB8d-u.mjs} +1 -1
  31. package/dist/studio-sXvYUxr5.mjs +325 -0
  32. package/dist/studio.d.ts +54 -0
  33. package/package.json +4 -4
  34. package/dist/_api-client-MenP4-O7.mjs +0 -49
  35. package/dist/delete-DXilFBb1.mjs +0 -29
  36. 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 { c as writeProjectConfig } from "./_config-5AEqhh-O.mjs";
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-DMyOab9_.mjs";
8
- import { t as assertTypechecks } from "./_typecheck-gate-9IHWDnl1.mjs";
9
- import { n as apiRequest } from "./_api-client-MenP4-O7.mjs";
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 writeProjectConfig(cwd, {
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-vV05Fnki.mjs");
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-DMyOab9_.mjs";
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
- /** Run deploy after init and return deploy metadata if successful. */
76
- async function tryDeploy(cwd, server) {
77
- const { executeDeploy } = await import("./deploy-1eaXcfUw.mjs");
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 executeDeploy({
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(`Deploy failed: ${errorMessage(err)}`);
89
- log.warn("Your project was still created — run `aai deploy` in it to retry.");
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-BZ9t_Kz-.mjs");
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 deploy because dependencies were not installed.");
124
+ if (!installed) log.warn("Skipping publish because dependencies were not installed.");
124
125
  else if (!opts.skipDeploy) {
125
- const deployInfo = await tryDeploy(cwd, opts.server);
126
- if (deployInfo) {
126
+ const published = await tryPublish(cwd, opts.server);
127
+ if (published) {
127
128
  deployed = true;
128
- slug = deployInfo.slug;
129
- url = deployInfo.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` — email sign-in against the platform, ending with the
3
- * account's AssemblyAI API key stored in the global config (the same slot
4
- * `ensureApiKey` reads), so every other command is untouched by how the
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
- * Flow (the CLI mirror of the browser studio's two gates):
8
- * 1. `GET /studio/auth` names the login mode.
9
- * - `supabase`: Supabase email OTP `POST /auth/v1/otp` emails a
10
- * one-time code, the user types it here, `POST /auth/v1/verify`
11
- * returns the session. The magic LINK in the same email targets the
12
- * browser; the CLI uses the code because a terminal has no redirect
13
- * to land on. (The Supabase email template must include the
14
- * `{{ .Token }}` code for this to work.)
15
- * - `dev`: mint the same self-describing dev token the studio's local
16
- * login mints nothing is emailed anywhere.
17
- * 2. `GET /studio/account` when no key is on file yet, prompt for one
18
- * and `PUT /studio/account/key` (the same mandatory onboarding step
19
- * the browser shows after sign-in).
20
- * 3. `GET /studio/account/key`fetch the key and save it locally.
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
- "deploy": "aai deploy"
11
+ "publish:agent": "aai publish"
12
12
  },
13
13
  "dependencies": {
14
- "@alexkroman1/aai": "^5.5.1",
15
- "@alexkroman1/aai-ui": "^5.5.1",
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.5.1",
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-DaqQJHk8.mjs";
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-DaqQJHk8.mjs";
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) {