@alexkroman1/aai-cli 5.11.0 → 5.13.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/dist/{_agent-DS2PUJcl.mjs → _agent-C8Jk-ZcP.mjs} +3 -2
- package/dist/_agent.d.ts +1 -0
- package/dist/{_api-client-B-upMGkc.mjs → _api-client-BX8Qv51n.mjs} +2 -1
- package/dist/{_bundler-DC17suWN.mjs → _bundler-BuIyDdvs.mjs} +30 -11
- package/dist/_bundler.d.ts +16 -2
- package/dist/{_config-DMyolIk9.mjs → _config-CzwAWOWr.mjs} +3 -3
- package/dist/_deploy.d.ts +0 -10
- package/dist/_dev-restart.d.ts +59 -0
- package/dist/{_dev-server-B3ivqyEd.mjs → _dev-server-Ch7K8e8i.mjs} +181 -92
- package/dist/_dev-server.d.ts +17 -0
- package/dist/{_init-5hHkHe-V.mjs → _init-CbkrE2wq.mjs} +3 -3
- package/dist/_preflight-BtfaYtbE.mjs +46 -0
- package/dist/_preflight.d.ts +57 -0
- package/dist/{_server-common-DX8Bfrf5.mjs → _server-common-61fL__39.mjs} +1 -1
- package/dist/_slug-api-D30zPmsn.mjs +50 -0
- package/dist/_slug-api.d.ts +16 -0
- package/dist/_studio-D2ciIhbi.mjs +94 -0
- package/dist/_studio.d.ts +19 -16
- package/dist/{_templates-DmdG-voA.mjs → _templates-B1kt3BGt.mjs} +2 -2
- package/dist/{_typecheck-gate-DB-PY0A3.mjs → _typecheck-gate-4v9UBZHh.mjs} +1 -1
- package/dist/{_ui-DfwfDbT-.mjs → _ui-u7T4YooX.mjs} +5 -1
- package/dist/_ui.d.ts +2 -0
- package/dist/{_utils-8KKw-bzi.mjs → _utils-0DHbcqUb.mjs} +2 -2
- package/dist/{build-CACFbdQ4.mjs → build-DQJ1ZSm9.mjs} +4 -4
- package/dist/cli.d.ts +2 -1
- package/dist/cli.mjs +70 -34
- package/dist/{client-bundler-DONm-khu.mjs → client-bundler-C9qXL8A2.mjs} +1 -1
- package/dist/client-bundler.mjs +1 -1
- package/dist/{delete-DEZ7u3u4.mjs → delete-DCRX3d96.mjs} +4 -4
- package/dist/{deploy-Ch0d_jje.mjs → deploy-DjsEV-40.mjs} +27 -26
- package/dist/deploy.d.ts +0 -2
- package/dist/{dev-CdeRcYiQ.mjs → dev-CvPH5dbF.mjs} +3 -3
- package/dist/{eject-DSrAp8PL.mjs → eject-LgBRfnbH.mjs} +3 -3
- package/dist/{init-BBAoRI_f.mjs → init-BppxMR8r.mjs} +5 -5
- package/dist/{login-BeFUiU6M.mjs → login-BQQaxJhL.mjs} +4 -15
- package/dist/login.d.ts +0 -9
- package/dist/project-config.d.ts +23 -0
- package/dist/project-config.mjs +3 -0
- package/dist/scaffold/CLAUDE.md +60 -10
- package/dist/scaffold/package.json +3 -3
- package/dist/{secret-4_dYyrpA.mjs → secret-Ds9dvqAj.mjs} +7 -7
- package/dist/{storage-BTfErOOW.mjs → storage-DbrQSHFk.mjs} +2 -2
- package/dist/{studio-DPDFKZ9i.mjs → studio-GSFd4s5O.mjs} +12 -179
- package/dist/templates/dispatch-center/shared.ts +13 -15
- package/dist/templates/pizza-ordering/agent.test.ts +3 -0
- package/dist/templates/retail/store.ts +11 -17
- package/dist/templates/solo-rpg/agent.test.ts +3 -0
- package/dist/{test-C-V98oC-.mjs → test-2LWBcXvY.mjs} +2 -2
- package/dist/typecheck.mjs +1 -1
- package/package.json +8 -3
- package/dist/_slug-api-fRNNR8tz.mjs +0 -27
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The deploy-time credential preflight — the classic dev/prod failure, caught
|
|
3
|
+
* before the upload instead of at the deployed agent's first session.
|
|
4
|
+
*
|
|
5
|
+
* An agent that ran locally on shell-exported provider keys dies after deploy
|
|
6
|
+
* with what looks like a provider outage: `aai dev` falls back to the shell
|
|
7
|
+
* (`withHostCredentialFallback`), and the platform never will. Naming the key
|
|
8
|
+
* here turns that into one line of output while the developer is still in the
|
|
9
|
+
* directory that owns the `.env`.
|
|
10
|
+
*
|
|
11
|
+
* **This lives in the CLI because the agent's config does.** The platform
|
|
12
|
+
* stores no description of a bundle and never evaluates one (see "The
|
|
13
|
+
* platform stores no agent config" in packages/aai-server/CLAUDE.md), so the
|
|
14
|
+
* only place that knows an agent needs `CARTESIA_API_KEY` is the process that
|
|
15
|
+
* just built it.
|
|
16
|
+
*
|
|
17
|
+
* **It WARNS, and must not be turned into a hard failure.** The CLI sees the
|
|
18
|
+
* env it is about to upload; it cannot see what is already stored against the
|
|
19
|
+
* slug from an earlier `aai secret put`, so a key the platform holds looks
|
|
20
|
+
* missing from here. The server-side check this replaced could see both and
|
|
21
|
+
* so could reject — moving the config to where it is authored costs that
|
|
22
|
+
* accuracy, and a false rejection is worse than a false warning: it blocks a
|
|
23
|
+
* deploy that would have worked.
|
|
24
|
+
*/
|
|
25
|
+
import { requiredProviderEnvVars } from "@alexkroman1/aai/runtime";
|
|
26
|
+
/**
|
|
27
|
+
* The config shape read out of a bundle's `__aaiConfig` export: the provider
|
|
28
|
+
* descriptors the credential derivation needs, plus the agent's declared
|
|
29
|
+
* `requiredEnv`. Deliberately structural rather than the SDK's `AgentConfig` —
|
|
30
|
+
* the export comes from the USER's installed SDK, which may be older or newer
|
|
31
|
+
* than this CLI's, so anything beyond these is not ours to assume.
|
|
32
|
+
*
|
|
33
|
+
* **The `__aaiConfig` export, not the bundle's default export.** They look
|
|
34
|
+
* interchangeable — `evalWorkerBundle` already returns the `AgentDef`, and
|
|
35
|
+
* `agentEnvWarnings` (`_dev-server.ts`) derives the same key set from one —
|
|
36
|
+
* but `__aaiConfig` is `toAgentConfig(def)`, which has run
|
|
37
|
+
* `normalizeAgentConveniences` and `defaultProviders`. A def written with an
|
|
38
|
+
* author shorthand (`llm: "gpt-5"`) still carries a STRING there, and
|
|
39
|
+
* `descriptorKind` reads a string as no kind at all, so deriving from the raw
|
|
40
|
+
* def silently omits that provider's key. The normalized config is what the
|
|
41
|
+
* runtime will actually resolve against, so it is what the preflight checks.
|
|
42
|
+
*/
|
|
43
|
+
export type PreflightConfig = Parameters<typeof requiredProviderEnvVars>[0] & {
|
|
44
|
+
requiredEnv?: readonly string[] | undefined;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Env var names the agent needs that the env being uploaded doesn't supply.
|
|
48
|
+
* Empty values count as missing — an empty credential authenticates nothing.
|
|
49
|
+
*
|
|
50
|
+
* Two sources: provider credentials derived from the stt/llm/tts/s2s
|
|
51
|
+
* descriptors (the same registry-backed derivation the runtime resolves keys
|
|
52
|
+
* with), and the agent's own declared `requiredEnv` — an `agent()` field for
|
|
53
|
+
* custom keys tools read from `ctx.env`, which no static derivation can see.
|
|
54
|
+
*/
|
|
55
|
+
export declare function missingCredentials(config: PreflightConfig, env: Record<string, string>): string[];
|
|
56
|
+
/** One line naming the missing keys and what to do about them. */
|
|
57
|
+
export declare function missingCredentialMessage(missing: string[]): string;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { n as getServerInfo } from "./_agent-C8Jk-ZcP.mjs";
|
|
3
|
+
import { n as apiRequest, t as HINT_NOT_DEPLOYED } from "./_api-client-BX8Qv51n.mjs";
|
|
4
|
+
//#region _slug-api.ts
|
|
5
|
+
/**
|
|
6
|
+
* Authenticated request against a deployed agent's slug-scoped resource
|
|
7
|
+
* (`${serverUrl}/${slug}${resourcePath}`) — the one shape every per-agent
|
|
8
|
+
* command (secret, storage) shares, including the standard "not deployed"
|
|
9
|
+
* 404 hint.
|
|
10
|
+
*
|
|
11
|
+
* Its own module (rather than living beside `getServerInfo` in `_agent.ts`)
|
|
12
|
+
* so tests can mock `_agent.ts`/`_api-client.ts` while this composition
|
|
13
|
+
* stays real — an intra-module call would bypass those mocks.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* A SECRET request, routed to the project when this directory is linked to
|
|
17
|
+
* one and to the bare slug otherwise.
|
|
18
|
+
*
|
|
19
|
+
* A studio project deploys TWO agents — production and preview — and a
|
|
20
|
+
* secret has to reach both or the preview fails at its first session while
|
|
21
|
+
* production works. The project route fans out server-side
|
|
22
|
+
* (`aai-studio-server/studio-secrets.ts`); this CLI used to write the
|
|
23
|
+
* production slug alone, so a key set here was missing from the preview the
|
|
24
|
+
* user's own `aai publish` had created. An unlinked directory has one agent
|
|
25
|
+
* and keeps the per-slug route, which is the platform primitive underneath.
|
|
26
|
+
*/
|
|
27
|
+
async function secretRequest(cwd, resourcePath, init, server) {
|
|
28
|
+
const { serverUrl, slug, apiKey, studioProject } = await getServerInfo(cwd, server);
|
|
29
|
+
return {
|
|
30
|
+
data: await apiRequest(studioProject ? `${serverUrl}/studio/projects/${encodeURIComponent(studioProject)}/secret${resourcePath}` : `${serverUrl}/${slug}/secret${resourcePath}`, {
|
|
31
|
+
...init,
|
|
32
|
+
apiKey,
|
|
33
|
+
hints: { 404: HINT_NOT_DEPLOYED }
|
|
34
|
+
}),
|
|
35
|
+
target: studioProject ?? slug
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
async function slugRequest(cwd, resourcePath, init, server) {
|
|
39
|
+
const { serverUrl, slug, apiKey } = await getServerInfo(cwd, server);
|
|
40
|
+
return {
|
|
41
|
+
data: await apiRequest(`${serverUrl}/${slug}${resourcePath}`, {
|
|
42
|
+
...init,
|
|
43
|
+
apiKey,
|
|
44
|
+
hints: { 404: HINT_NOT_DEPLOYED }
|
|
45
|
+
}),
|
|
46
|
+
slug
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { slugRequest as n, secretRequest as t };
|
package/dist/_slug-api.d.ts
CHANGED
|
@@ -9,6 +9,22 @@ import { type ApiRequestOptions } from "./_api-client.ts";
|
|
|
9
9
|
* so tests can mock `_agent.ts`/`_api-client.ts` while this composition
|
|
10
10
|
* stays real — an intra-module call would bypass those mocks.
|
|
11
11
|
*/
|
|
12
|
+
/**
|
|
13
|
+
* A SECRET request, routed to the project when this directory is linked to
|
|
14
|
+
* one and to the bare slug otherwise.
|
|
15
|
+
*
|
|
16
|
+
* A studio project deploys TWO agents — production and preview — and a
|
|
17
|
+
* secret has to reach both or the preview fails at its first session while
|
|
18
|
+
* production works. The project route fans out server-side
|
|
19
|
+
* (`aai-studio-server/studio-secrets.ts`); this CLI used to write the
|
|
20
|
+
* production slug alone, so a key set here was missing from the preview the
|
|
21
|
+
* user's own `aai publish` had created. An unlinked directory has one agent
|
|
22
|
+
* and keeps the per-slug route, which is the platform primitive underneath.
|
|
23
|
+
*/
|
|
24
|
+
export declare function secretRequest<T = unknown>(cwd: string, resourcePath: string, init: Pick<ApiRequestOptions, "method" | "body" | "action">, server?: string): Promise<{
|
|
25
|
+
data: T;
|
|
26
|
+
target: string;
|
|
27
|
+
}>;
|
|
12
28
|
export declare function slugRequest<T = unknown>(cwd: string, resourcePath: string, init: Pick<ApiRequestOptions, "method" | "body" | "action">, server?: string): Promise<{
|
|
13
29
|
data: T;
|
|
14
30
|
slug: string;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { n as apiRequest } from "./_api-client-BX8Qv51n.mjs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { MAX_SLUG_LENGTH, PREVIEW_SLUG_SUFFIX, VALID_SLUG_RE } from "@alexkroman1/aai/utils";
|
|
5
|
+
import { slugifyName } from "@alexkroman1/aai/slugify";
|
|
6
|
+
import { isLocalOnlyFile, snapshotWorkspaceFiles } from "@alexkroman1/aai/workspace-files";
|
|
7
|
+
//#region _studio.ts
|
|
8
|
+
/**
|
|
9
|
+
* Internals of the studio-workspace commands (`aai list/pull/push/publish`):
|
|
10
|
+
* the local source-file walk and the thin clients for the platform's
|
|
11
|
+
* `/studio/projects` routes. The workspace is the single source of truth —
|
|
12
|
+
* these helpers only move files between a local directory and the project's
|
|
13
|
+
* workspace row; production deploys happen exclusively through the studio's
|
|
14
|
+
* Publish route (which runs the deploy machinery in the project's sandbox).
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Snapshot the local project into a workspace file map.
|
|
18
|
+
*
|
|
19
|
+
* The walk, the caps, the skip rules and the strict UTF-8 decode all come
|
|
20
|
+
* from the SDK (`@alexkroman1/aai/workspace-files`), which is also what the
|
|
21
|
+
* guest's end-of-turn sync uses — the two write the same map from opposite
|
|
22
|
+
* ends, and a disagreement between them is not an error but a file silently
|
|
23
|
+
* dropped here and resurrected there.
|
|
24
|
+
*
|
|
25
|
+
* `isLocalOnlyFile` is the one rule this side adds: `.env` rides the secret
|
|
26
|
+
* routes and lockfiles are install output, so neither belongs in a row.
|
|
27
|
+
*/
|
|
28
|
+
function collectSourceFiles(dir) {
|
|
29
|
+
return snapshotWorkspaceFiles(dir, {
|
|
30
|
+
subject: "Project",
|
|
31
|
+
skipFile: isLocalOnlyFile
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A studio project name derived from a directory name, or null if unusable.
|
|
36
|
+
*
|
|
37
|
+
* The normalization is the platform's own (`slugifyName`), not a local
|
|
38
|
+
* regex. This used to strip `[^a-z0-9-_]` by hand, which differs from the
|
|
39
|
+
* studio's slugifier on exactly the names people give agents: `Café
|
|
40
|
+
* Ordering` reduced to `caf-ordering` here and `cafe-ordering` there, so the
|
|
41
|
+
* same directory produced a different project depending on whether it was
|
|
42
|
+
* created by `aai push` or by typing the name into the studio.
|
|
43
|
+
*
|
|
44
|
+
* A `-preview` suffix is deliberately unusable. Publishing a project deploys
|
|
45
|
+
* it under the project's own name, so a `*-preview` project would claim a
|
|
46
|
+
* slug the studio's orphan-preview sweep reaps hourly — deleting the agent,
|
|
47
|
+
* its app-database schema, and its secrets on a schedule the user never
|
|
48
|
+
* asked for. Refusing the name is recoverable (rename the directory); losing
|
|
49
|
+
* a published agent to the reaper is not.
|
|
50
|
+
*/
|
|
51
|
+
function projectNameFromDir(dir) {
|
|
52
|
+
const name = slugifyName(path.basename(dir), MAX_SLUG_LENGTH);
|
|
53
|
+
if (name.endsWith(PREVIEW_SLUG_SUFFIX)) return null;
|
|
54
|
+
return VALID_SLUG_RE.test(name) ? name : null;
|
|
55
|
+
}
|
|
56
|
+
/** The shareable studio URL for a project — what every command prints. */
|
|
57
|
+
function studioProjectUrl(serverUrl, project) {
|
|
58
|
+
return `${serverUrl}/studio/chat/${project}`;
|
|
59
|
+
}
|
|
60
|
+
function listStudioProjects(serverUrl, apiKey) {
|
|
61
|
+
return apiRequest(`${serverUrl}/studio/projects`, {
|
|
62
|
+
apiKey,
|
|
63
|
+
action: "list"
|
|
64
|
+
}).then((res) => res.projects);
|
|
65
|
+
}
|
|
66
|
+
/** Fetch a project, or null when it doesn't exist (the push existence probe). */
|
|
67
|
+
function fetchStudioProject(serverUrl, apiKey, project) {
|
|
68
|
+
return apiRequest(`${serverUrl}/studio/projects/${encodeURIComponent(project)}`, {
|
|
69
|
+
apiKey,
|
|
70
|
+
action: "pull",
|
|
71
|
+
allow404: true
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/** `PUT /studio/projects/:project/source` — the atomic whole-tree push. */
|
|
75
|
+
function pushStudioSource(serverUrl, apiKey, project, body) {
|
|
76
|
+
return apiRequest(`${serverUrl}/studio/projects/${encodeURIComponent(project)}/source`, {
|
|
77
|
+
apiKey,
|
|
78
|
+
action: "push",
|
|
79
|
+
method: "PUT",
|
|
80
|
+
body,
|
|
81
|
+
hints: { 409: "The studio has newer changes. Run `aai pull` to fetch them, or `aai push --force` to overwrite." }
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/** `POST /studio/projects/:project/deploy` — Publish, in the project's sandbox. */
|
|
85
|
+
function publishStudioProject(serverUrl, apiKey, project) {
|
|
86
|
+
return apiRequest(`${serverUrl}/studio/projects/${encodeURIComponent(project)}/deploy`, {
|
|
87
|
+
apiKey,
|
|
88
|
+
action: "publish",
|
|
89
|
+
method: "POST",
|
|
90
|
+
retry: 0
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
export { publishStudioProject as a, projectNameFromDir as i, fetchStudioProject as n, pushStudioSource as o, listStudioProjects as r, studioProjectUrl as s, collectSourceFiles as t };
|
package/dist/_studio.d.ts
CHANGED
|
@@ -6,27 +6,30 @@
|
|
|
6
6
|
* workspace row; production deploys happen exclusively through the studio's
|
|
7
7
|
* Publish route (which runs the deploy machinery in the project's sandbox).
|
|
8
8
|
*/
|
|
9
|
+
import { type WorkspaceSnapshot } from "@alexkroman1/aai/workspace-files";
|
|
9
10
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* Snapshot the local project into a workspace file map.
|
|
12
|
+
*
|
|
13
|
+
* The walk, the caps, the skip rules and the strict UTF-8 decode all come
|
|
14
|
+
* from the SDK (`@alexkroman1/aai/workspace-files`), which is also what the
|
|
15
|
+
* guest's end-of-turn sync uses — the two write the same map from opposite
|
|
16
|
+
* ends, and a disagreement between them is not an error but a file silently
|
|
17
|
+
* dropped here and resurrected there.
|
|
18
|
+
*
|
|
19
|
+
* `isLocalOnlyFile` is the one rule this side adds: `.env` rides the secret
|
|
20
|
+
* routes and lockfiles are install output, so neither belongs in a row.
|
|
14
21
|
*/
|
|
15
|
-
export declare
|
|
16
|
-
export declare const MAX_STUDIO_FILES = 100;
|
|
17
|
-
/**
|
|
18
|
-
* Walk a local project into the path→content record a workspace stores —
|
|
19
|
-
* the CLI-side twin of the guest's `snapshotWorkspace`: same ignored
|
|
20
|
-
* directories, same caps, oversized and non-text files skipped with a
|
|
21
|
-
* warning rather than failing the whole push.
|
|
22
|
-
*/
|
|
23
|
-
export declare function collectSourceFiles(dir: string): Promise<{
|
|
24
|
-
files: Record<string, string>;
|
|
25
|
-
warnings: string[];
|
|
26
|
-
}>;
|
|
22
|
+
export declare function collectSourceFiles(dir: string): Promise<WorkspaceSnapshot>;
|
|
27
23
|
/**
|
|
28
24
|
* A studio project name derived from a directory name, or null if unusable.
|
|
29
25
|
*
|
|
26
|
+
* The normalization is the platform's own (`slugifyName`), not a local
|
|
27
|
+
* regex. This used to strip `[^a-z0-9-_]` by hand, which differs from the
|
|
28
|
+
* studio's slugifier on exactly the names people give agents: `Café
|
|
29
|
+
* Ordering` reduced to `caf-ordering` here and `cafe-ordering` there, so the
|
|
30
|
+
* same directory produced a different project depending on whether it was
|
|
31
|
+
* created by `aai push` or by typing the name into the studio.
|
|
32
|
+
*
|
|
30
33
|
* A `-preview` suffix is deliberately unusable. Publishing a project deploys
|
|
31
34
|
* it under the project's own name, so a `*-preview` project would claim a
|
|
32
35
|
* slug the studio's orphan-preview sweep reaps hourly — deleting the agent,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as errorMessage } from "./_utils-
|
|
3
|
-
import { t as getMonorepoRoot } from "./_agent-
|
|
2
|
+
import { a as errorMessage } from "./_utils-0DHbcqUb.mjs";
|
|
3
|
+
import { t as getMonorepoRoot } from "./_agent-C8Jk-ZcP.mjs";
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import fs from "node:fs/promises";
|
|
@@ -37,6 +37,10 @@ function notify(level, message) {
|
|
|
37
37
|
}
|
|
38
38
|
process.stderr.write(`${message}\n`);
|
|
39
39
|
}
|
|
40
|
+
/** Whether `silenceOutput()` has been called — i.e. we are in JSON mode. */
|
|
41
|
+
function outputSilenced() {
|
|
42
|
+
return silenced;
|
|
43
|
+
}
|
|
40
44
|
/**
|
|
41
45
|
* Unwrap a clack prompt result, exiting cleanly if the user cancelled.
|
|
42
46
|
* `message` lets the caller name what was cancelled (e.g. "Setup cancelled").
|
|
@@ -65,4 +69,4 @@ function parsePort(raw) {
|
|
|
65
69
|
return port;
|
|
66
70
|
}
|
|
67
71
|
//#endregion
|
|
68
|
-
export {
|
|
72
|
+
export { parsePort as a, outputSilenced as i, log as n, silenceOutput as o, notify as r, unwrapCancel as s, fmtUrl as t };
|
package/dist/_ui.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export declare function silenceOutput(): void;
|
|
|
23
23
|
* line — while a human tailing the log sees what happened.
|
|
24
24
|
*/
|
|
25
25
|
export declare function notify(level: "error" | "warn" | "info" | "success", message: string): void;
|
|
26
|
+
/** Whether `silenceOutput()` has been called — i.e. we are in JSON mode. */
|
|
27
|
+
export declare function outputSilenced(): boolean;
|
|
26
28
|
/**
|
|
27
29
|
* Unwrap a clack prompt result, exiting cleanly if the user cancelled.
|
|
28
30
|
* `message` lets the caller name what was cancelled (e.g. "Setup cancelled").
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
|
-
import { errorDetail, errorMessage, errorMessage as errorMessage$1 } from "@alexkroman1/aai/utils";
|
|
5
|
+
import { errorDetail, errorMessage, errorMessage as errorMessage$1, omitUndefined } from "@alexkroman1/aai/utils";
|
|
6
6
|
//#region _utils.ts
|
|
7
7
|
/**
|
|
8
8
|
* The file that marks a directory as an agent project — the single source
|
|
@@ -93,7 +93,7 @@ async function writeJson(filePath, data, opts = {}) {
|
|
|
93
93
|
...opts.mode !== void 0 ? { mode: 448 } : {}
|
|
94
94
|
});
|
|
95
95
|
const tmpPath = `${filePath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
96
|
-
await fs.writeFile(tmpPath, `${JSON.stringify(data, null, 2)}\n`, {
|
|
96
|
+
await fs.writeFile(tmpPath, `${JSON.stringify(data, null, 2)}\n`, omitUndefined({ mode: opts.mode }));
|
|
97
97
|
try {
|
|
98
98
|
await fs.rename(tmpPath, filePath);
|
|
99
99
|
} catch (err) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { a as ok, t as CliError } from "./_output-CC300DzW.mjs";
|
|
3
|
-
import { n as log } from "./_ui-
|
|
4
|
-
import { r as evalWorkerBundle, t as buildAgentBundle } from "./_bundler-
|
|
5
|
-
import { assertTypechecks } from "./_typecheck-gate-
|
|
6
|
-
import { classifyVitestError, runVitest } from "./test-
|
|
3
|
+
import { n as log } from "./_ui-u7T4YooX.mjs";
|
|
4
|
+
import { r as evalWorkerBundle, t as buildAgentBundle } from "./_bundler-BuIyDdvs.mjs";
|
|
5
|
+
import { assertTypechecks } from "./_typecheck-gate-4v9UBZHh.mjs";
|
|
6
|
+
import { classifyVitestError, runVitest } from "./test-2LWBcXvY.mjs";
|
|
7
7
|
//#region build.ts
|
|
8
8
|
/**
|
|
9
9
|
* `aai build` — bundle the agent without deploying, behind the same gates
|
package/dist/cli.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import { type ArgsDef, type CommandDef } from "citty";
|
|
2
|
+
export declare const mainCommand: CommandDef<ArgsDef>;
|
package/dist/cli.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { i as installStdoutGuard, n as fail, o as writeLine, r as getOutputMode, t as CliError } from "./_output-CC300DzW.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { a as errorMessage, l as resolveCwd, o as fileExists, t as AGENT_ENTRY } from "./_utils-
|
|
3
|
+
import { n as log, o as silenceOutput } from "./_ui-u7T4YooX.mjs";
|
|
4
|
+
import { a as errorMessage, l as resolveCwd, o as fileExists, t as AGENT_ENTRY } from "./_utils-0DHbcqUb.mjs";
|
|
5
5
|
import { existsSync, readFileSync } from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
|
-
import { defineCommand, runMain } from "citty";
|
|
8
|
+
import { defineCommand, runMain, showUsage } from "citty";
|
|
9
9
|
//#region _cli-common.ts
|
|
10
10
|
/** Shared arg definitions for citty commands. */
|
|
11
11
|
const sharedArgs = {
|
|
@@ -55,11 +55,11 @@ function findUnknownFlags(rawArgs, argsDef) {
|
|
|
55
55
|
* A flag's comparison key: dashes dropped and lower-cased, with a leading
|
|
56
56
|
* `no` negation removed.
|
|
57
57
|
*
|
|
58
|
-
* citty accepts both `--
|
|
59
|
-
*
|
|
60
|
-
* spawns the kebab-case spelling. Comparing the literal text rejected
|
|
61
|
-
*
|
|
62
|
-
*
|
|
58
|
+
* citty accepts both `--allowPreviewSlug` and `--allow-preview-slug` for an
|
|
59
|
+
* arg declared as `allowPreviewSlug`, and the guest's in-sandbox Publish
|
|
60
|
+
* spawns the kebab-case spelling. Comparing the literal text rejected the
|
|
61
|
+
* kebab-case form as unknown and broke Publish for every studio user, so both
|
|
62
|
+
* sides are normalized to one key.
|
|
63
63
|
*/
|
|
64
64
|
function canonicalFlag(flag) {
|
|
65
65
|
return flag.replace(/^--?/, "").replace(/^no-/, "").replace(/-/g, "").toLowerCase();
|
|
@@ -166,7 +166,7 @@ const list = defineCommand({
|
|
|
166
166
|
async run({ args }) {
|
|
167
167
|
await runCommand(args, async () => {
|
|
168
168
|
const cwd = resolveCwd();
|
|
169
|
-
const { executeList } = await import("./studio-
|
|
169
|
+
const { executeList } = await import("./studio-GSFd4s5O.mjs");
|
|
170
170
|
return executeList({
|
|
171
171
|
cwd,
|
|
172
172
|
server: args.server
|
|
@@ -201,7 +201,7 @@ const pull = defineCommand({
|
|
|
201
201
|
async run({ args }) {
|
|
202
202
|
await runCommand(args, async () => {
|
|
203
203
|
const cwd = resolveCwd();
|
|
204
|
-
const { executePull } = await import("./studio-
|
|
204
|
+
const { executePull } = await import("./studio-GSFd4s5O.mjs");
|
|
205
205
|
return executePull({
|
|
206
206
|
cwd,
|
|
207
207
|
project: args.project,
|
|
@@ -229,7 +229,7 @@ const push = defineCommand({
|
|
|
229
229
|
async run({ args }) {
|
|
230
230
|
await runCommand(args, async () => {
|
|
231
231
|
const cwd = await setup({ agent: true });
|
|
232
|
-
const { executePush } = await import("./studio-
|
|
232
|
+
const { executePush } = await import("./studio-GSFd4s5O.mjs");
|
|
233
233
|
return executePush({
|
|
234
234
|
cwd,
|
|
235
235
|
server: args.server,
|
|
@@ -259,7 +259,7 @@ const publish = defineCommand({
|
|
|
259
259
|
async run({ args }) {
|
|
260
260
|
await runCommand(args, async () => {
|
|
261
261
|
const cwd = await setup({ agent: true });
|
|
262
|
-
const { executePublish } = await import("./studio-
|
|
262
|
+
const { executePublish } = await import("./studio-GSFd4s5O.mjs");
|
|
263
263
|
return executePublish({
|
|
264
264
|
cwd,
|
|
265
265
|
server: args.server,
|
|
@@ -286,6 +286,22 @@ function readCliVersion(dir) {
|
|
|
286
286
|
return "unknown";
|
|
287
287
|
}
|
|
288
288
|
const VERSION = readCliVersion(cliDir);
|
|
289
|
+
/**
|
|
290
|
+
* `aai secret put` for a subcommand, `aai` for the root — the name to put in
|
|
291
|
+
* front of `--help` when telling someone which usage to read.
|
|
292
|
+
*
|
|
293
|
+
* `meta` is a `Resolvable`, so it can be a function or a promise; only the
|
|
294
|
+
* plain-object form carries a name synchronously and anything else degrades
|
|
295
|
+
* to the binary name rather than blocking the error path on a resolve.
|
|
296
|
+
*/
|
|
297
|
+
function commandPath(cmd, parent) {
|
|
298
|
+
const nameOf = (c) => {
|
|
299
|
+
const meta = c?.meta;
|
|
300
|
+
return meta && typeof meta === "object" && "name" in meta && typeof meta.name === "string" ? meta.name : void 0;
|
|
301
|
+
};
|
|
302
|
+
const path = [nameOf(parent), nameOf(cmd)].filter((n) => n !== void 0).join(" ");
|
|
303
|
+
return path.startsWith("aai") ? path : `aai ${path}`.trim();
|
|
304
|
+
}
|
|
289
305
|
const init = defineCommand({
|
|
290
306
|
meta: {
|
|
291
307
|
name: "init",
|
|
@@ -317,7 +333,7 @@ const init = defineCommand({
|
|
|
317
333
|
},
|
|
318
334
|
async run({ args }) {
|
|
319
335
|
await runCommand(args, async (mode) => {
|
|
320
|
-
const { executeInit } = await import("./init-
|
|
336
|
+
const { executeInit } = await import("./init-BppxMR8r.mjs");
|
|
321
337
|
return executeInit({
|
|
322
338
|
dir: args.dir,
|
|
323
339
|
force: args.force,
|
|
@@ -346,7 +362,7 @@ const dev = defineCommand({
|
|
|
346
362
|
async run({ args }) {
|
|
347
363
|
await runCommand(args, async () => {
|
|
348
364
|
const cwd = await setup({ agent: true });
|
|
349
|
-
const { executeDev } = await import("./dev-
|
|
365
|
+
const { executeDev } = await import("./dev-CvPH5dbF.mjs");
|
|
350
366
|
return executeDev({
|
|
351
367
|
cwd,
|
|
352
368
|
port: args.port
|
|
@@ -362,8 +378,8 @@ const test = defineCommand({
|
|
|
362
378
|
args: { json: sharedArgs.json },
|
|
363
379
|
async run({ args }) {
|
|
364
380
|
await runCommand(args, async () => {
|
|
365
|
-
const cwd = await setup();
|
|
366
|
-
const { executeTest } = await import("./test-
|
|
381
|
+
const cwd = await setup({ agent: true });
|
|
382
|
+
const { executeTest } = await import("./test-2LWBcXvY.mjs");
|
|
367
383
|
return executeTest(cwd);
|
|
368
384
|
});
|
|
369
385
|
}
|
|
@@ -387,7 +403,7 @@ const build = defineCommand({
|
|
|
387
403
|
async run({ args }) {
|
|
388
404
|
await runCommand(args, async () => {
|
|
389
405
|
const cwd = await setup({ agent: true });
|
|
390
|
-
const { executeBuild } = await import("./build-
|
|
406
|
+
const { executeBuild } = await import("./build-DQJ1ZSm9.mjs");
|
|
391
407
|
return executeBuild({
|
|
392
408
|
cwd,
|
|
393
409
|
skipTests: args.skipTests,
|
|
@@ -412,7 +428,7 @@ const eject = defineCommand({
|
|
|
412
428
|
async run({ args }) {
|
|
413
429
|
await runCommand(args, async () => {
|
|
414
430
|
const cwd = await setup({ agent: true });
|
|
415
|
-
const { executeEject } = await import("./eject-
|
|
431
|
+
const { executeEject } = await import("./eject-LgBRfnbH.mjs");
|
|
416
432
|
return executeEject({
|
|
417
433
|
cwd,
|
|
418
434
|
force: args.force
|
|
@@ -429,10 +445,6 @@ const deploy = defineCommand({
|
|
|
429
445
|
args: {
|
|
430
446
|
server: sharedArgs.server,
|
|
431
447
|
json: sharedArgs.json,
|
|
432
|
-
allowMissingSecrets: {
|
|
433
|
-
type: "boolean",
|
|
434
|
-
description: "Deploy even when the agent's providers are missing credentials (the server warns instead of rejecting; set them afterwards with `aai secret put`)"
|
|
435
|
-
},
|
|
436
448
|
allowPreviewSlug: {
|
|
437
449
|
type: "boolean",
|
|
438
450
|
description: "Permit a `-preview`-suffixed slug (reserved for studio auto-previews; studio-internal — a slug you claim this way is subject to the preview reaper)"
|
|
@@ -445,11 +457,10 @@ const deploy = defineCommand({
|
|
|
445
457
|
async run({ args }) {
|
|
446
458
|
await runCommand(args, async () => {
|
|
447
459
|
const cwd = await setup({ agent: true });
|
|
448
|
-
const { executeDeploy } = await import("./deploy-
|
|
460
|
+
const { executeDeploy } = await import("./deploy-DjsEV-40.mjs");
|
|
449
461
|
return executeDeploy({
|
|
450
462
|
cwd,
|
|
451
463
|
server: args.server,
|
|
452
|
-
allowMissingSecrets: args.allowMissingSecrets,
|
|
453
464
|
allowPreviewSlug: args.allowPreviewSlug,
|
|
454
465
|
skipTypecheck: args.skipTypecheck
|
|
455
466
|
});
|
|
@@ -468,7 +479,7 @@ const del = defineCommand({
|
|
|
468
479
|
async run({ args }) {
|
|
469
480
|
await runCommand(args, async () => {
|
|
470
481
|
const cwd = await setup();
|
|
471
|
-
const { executeDelete } = await import("./delete-
|
|
482
|
+
const { executeDelete } = await import("./delete-DCRX3d96.mjs");
|
|
472
483
|
return executeDelete({
|
|
473
484
|
cwd,
|
|
474
485
|
server: args.server
|
|
@@ -499,7 +510,7 @@ const secret = defineCommand({
|
|
|
499
510
|
async run({ args }) {
|
|
500
511
|
await runCommand(args, async (mode) => {
|
|
501
512
|
const cwd = await setup();
|
|
502
|
-
const { executeSecretPut, NO_INPUT, readStdin } = await import("./secret-
|
|
513
|
+
const { executeSecretPut, NO_INPUT, readStdin } = await import("./secret-Ds9dvqAj.mjs");
|
|
503
514
|
const value = mode === "json" ? await readStdin() : void 0;
|
|
504
515
|
if (mode === "json" && !value) throw new CliError(...NO_INPUT);
|
|
505
516
|
return executeSecretPut(cwd, args.name, value, args.server);
|
|
@@ -523,7 +534,7 @@ const secret = defineCommand({
|
|
|
523
534
|
async run({ args }) {
|
|
524
535
|
await runCommand(args, async () => {
|
|
525
536
|
const cwd = await setup();
|
|
526
|
-
const { executeSecretDelete } = await import("./secret-
|
|
537
|
+
const { executeSecretDelete } = await import("./secret-Ds9dvqAj.mjs");
|
|
527
538
|
return executeSecretDelete(cwd, args.name, args.server);
|
|
528
539
|
});
|
|
529
540
|
}
|
|
@@ -540,7 +551,7 @@ const secret = defineCommand({
|
|
|
540
551
|
async run({ args }) {
|
|
541
552
|
await runCommand(args, async () => {
|
|
542
553
|
const cwd = await setup();
|
|
543
|
-
const { executeSecretList } = await import("./secret-
|
|
554
|
+
const { executeSecretList } = await import("./secret-Ds9dvqAj.mjs");
|
|
544
555
|
return executeSecretList(cwd, args.server);
|
|
545
556
|
});
|
|
546
557
|
}
|
|
@@ -575,7 +586,7 @@ const storage = defineCommand({
|
|
|
575
586
|
},
|
|
576
587
|
async run({ args }) {
|
|
577
588
|
await runCommand(args, async () => {
|
|
578
|
-
const { executeStorageStatus } = await import("./storage-
|
|
589
|
+
const { executeStorageStatus } = await import("./storage-DbrQSHFk.mjs");
|
|
579
590
|
return executeStorageStatus(resolveStorageCwd(args.dir), args.server);
|
|
580
591
|
});
|
|
581
592
|
}
|
|
@@ -592,7 +603,7 @@ const storage = defineCommand({
|
|
|
592
603
|
},
|
|
593
604
|
async run({ args }) {
|
|
594
605
|
await runCommand(args, async () => {
|
|
595
|
-
const { executeStorageEnable } = await import("./storage-
|
|
606
|
+
const { executeStorageEnable } = await import("./storage-DbrQSHFk.mjs");
|
|
596
607
|
return executeStorageEnable(resolveStorageCwd(args.dir), args.server);
|
|
597
608
|
});
|
|
598
609
|
}
|
|
@@ -614,7 +625,7 @@ const storage = defineCommand({
|
|
|
614
625
|
},
|
|
615
626
|
async run({ args }) {
|
|
616
627
|
await runCommand(args, async () => {
|
|
617
|
-
const { executeStorageDisable } = await import("./storage-
|
|
628
|
+
const { executeStorageDisable } = await import("./storage-DbrQSHFk.mjs");
|
|
618
629
|
return executeStorageDisable(resolveStorageCwd(args.dir), {
|
|
619
630
|
server: args.server,
|
|
620
631
|
force: args.force
|
|
@@ -635,7 +646,7 @@ const login = defineCommand({
|
|
|
635
646
|
},
|
|
636
647
|
async run({ args }) {
|
|
637
648
|
await runCommand(args, async () => {
|
|
638
|
-
const { executeLogin } = await import("./login-
|
|
649
|
+
const { executeLogin } = await import("./login-BQQaxJhL.mjs");
|
|
639
650
|
return executeLogin({ server: args.server });
|
|
640
651
|
});
|
|
641
652
|
}
|
|
@@ -648,7 +659,7 @@ const templates = defineCommand({
|
|
|
648
659
|
args: { json: sharedArgs.json },
|
|
649
660
|
async run({ args }) {
|
|
650
661
|
await runCommand(args, async (mode) => {
|
|
651
|
-
const { listTemplates } = await import("./_templates-
|
|
662
|
+
const { listTemplates } = await import("./_templates-B1kt3BGt.mjs");
|
|
652
663
|
const names = await listTemplates();
|
|
653
664
|
if (mode === "human") {
|
|
654
665
|
for (const name of names) log.message(name);
|
|
@@ -702,6 +713,31 @@ if (process.env.VITEST !== "true") {
|
|
|
702
713
|
process.argv.splice(2, 0, "publish");
|
|
703
714
|
};
|
|
704
715
|
/**
|
|
716
|
+
* Render usage the way the active output mode allows.
|
|
717
|
+
*
|
|
718
|
+
* citty calls `showUsage` from two places: the `--help` path, and its
|
|
719
|
+
* `catch` for a `CLIError` (a missing positional, an unknown subcommand) —
|
|
720
|
+
* where it writes the usage block to STDOUT and the reason to stderr. That
|
|
721
|
+
* second one breaks JSON mode's contract of exactly one result line on
|
|
722
|
+
* stdout, and JSON mode is auto-detected on a pipe: `aai secret put --json`
|
|
723
|
+
* put a usage block where a script's `jq` expected a result, with no JSON
|
|
724
|
+
* emitted at all. Every other failure path in this CLI converges on one
|
|
725
|
+
* emitter and gets this right.
|
|
726
|
+
*
|
|
727
|
+
* `--help` is explicitly still the human block whatever the mode — piping
|
|
728
|
+
* it into a pager is the normal way to read it, and it is not an error.
|
|
729
|
+
* The specific reason keeps going to stderr as citty already writes it, so
|
|
730
|
+
* nothing is lost to a human watching the terminal.
|
|
731
|
+
*/
|
|
732
|
+
const usageForMode = async (cmd, parent) => {
|
|
733
|
+
const argv = process.argv.slice(2);
|
|
734
|
+
if (argv.includes("--help") || argv.includes("-h") || getOutputMode({}) === "human") {
|
|
735
|
+
await showUsage(cmd, parent);
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
await writeLine(`${JSON.stringify(fail("usage", `Invalid arguments for \`${commandPath(cmd, parent)}\`.`, `Run \`${commandPath(cmd, parent)} --help\` to see the arguments it accepts.`))}\n`);
|
|
739
|
+
};
|
|
740
|
+
/**
|
|
705
741
|
* Refuse an unrecognized flag instead of ignoring it.
|
|
706
742
|
*
|
|
707
743
|
* citty drops one silently, so `aai push --serverr=http://x` exited 0 having
|
|
@@ -715,7 +751,7 @@ if (process.env.VITEST !== "true") {
|
|
|
715
751
|
log.info("Run `aai <command> --help` to see the options it accepts.");
|
|
716
752
|
process.exit(1);
|
|
717
753
|
};
|
|
718
|
-
runDefault().then(assertKnownFlags).then(() => runMain(mainCommand)).catch((err) => {
|
|
754
|
+
runDefault().then(assertKnownFlags).then(() => runMain(mainCommand, { showUsage: usageForMode })).catch((err) => {
|
|
719
755
|
log.error(errorMessage(err));
|
|
720
756
|
process.exitCode = 1;
|
|
721
757
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as errorMessage$1, o as fileExists } from "./_utils-
|
|
2
|
+
import { a as errorMessage$1, o as fileExists } from "./_utils-0DHbcqUb.mjs";
|
|
3
3
|
import { t as withPreservedNodeEnv } from "./_vite-env-Dg_QlVv0.mjs";
|
|
4
4
|
import { existsSync, unlinkSync, writeFileSync } from "node:fs";
|
|
5
5
|
import path from "node:path";
|
package/dist/client-bundler.mjs
CHANGED