@layers/amba 1.0.1 → 4.0.2

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 CHANGED
@@ -1,13 +1,11 @@
1
- # `@layers/amba` — the amba CLI
1
+ # @layers/amba
2
2
 
3
- amba is an agent-native backend-as-a-service for mobile apps: functions,
4
- collections, storage, AI, queues, and static sites — one CLI to spin up
5
- your project and ship to production.
3
+ Amba is the agent-native backend-as-a-service for mobile and web apps. This package is the `amba` command-line interface.
6
4
 
7
5
  ## Install
8
6
 
9
7
  ```bash
10
- npm install -g @layers/amba
8
+ npm install -g @layers/amba@1.0.1
11
9
  ```
12
10
 
13
11
  …or run on demand:
@@ -16,40 +14,65 @@ npm install -g @layers/amba
16
14
  npx @layers/amba init
17
15
  ```
18
16
 
19
- ## Quick start
17
+ Requires Node.js 22 or newer.
18
+
19
+ ## Agent mode (recommended)
20
+
21
+ For AI coding agents (Claude Code, Cursor, Windsurf): one command, no
22
+ browser, no prompts.
20
23
 
21
24
  ```bash
22
- amba init # mint a personal dev project and scaffold context
23
- amba login # authenticate (browser flow)
24
- amba projects list # list projects you own
25
- amba projects create --name my-app
25
+ npx @layers/amba init --sandbox
26
+ ```
27
+
28
+ This signs up an agent-mode developer account, provisions a project,
29
+ writes `.env.local` + `AMBA.md`, auto-wires `mcpServers.amba` into
30
+ every MCP client config it finds on disk, and installs the
31
+ `/amba-build` Claude Code skill at `.claude/skills/amba-build/SKILL.md`.
32
+
33
+ After restarting your MCP client, paste:
34
+
35
+ ```
36
+ /amba-build <design-url-or-description>
37
+ ```
38
+
39
+ …to scaffold a full Expo app with Amba as the only backend. The skill
40
+ fetches the canonical prompt from
41
+ <https://docs.amba.dev/prompts/expo-build> at invocation time and
42
+ falls back to an inlined snapshot when offline. Use `--no-skills` to
43
+ skip the skill install.
44
+
45
+ ## Configure + first call
46
+
47
+ ```bash
48
+ amba init # mint a personal project and write .amba/ config
49
+ amba login # browser-based auth (skip with --token / AMBA_PAT)
50
+ amba projects list
51
+ ```
52
+
53
+ Track your first event from the CLI:
54
+
55
+ ```bash
56
+ amba events track app_opened --prop source=cli
26
57
  ```
27
58
 
28
59
  ## Common commands
29
60
 
30
61
  ```bash
31
62
  amba functions deploy ./functions/hello.ts
32
- amba functions list
33
- amba functions schedule hello "0 * * * *" --tz UTC
34
-
35
63
  amba collections create messages --field user_id:uuid --field body:text
36
- amba collections list
37
- amba types generate # emit .amba/types.d.ts
38
-
64
+ amba types generate # emits .amba/types.d.ts
39
65
  amba secrets set OPENAI_KEY --function hello --from-stdin
40
-
41
66
  amba sites deploy ./out --name marketing
42
- amba sites domain add marketing.example.com --site marketing
43
67
  ```
44
68
 
45
69
  ## Headless / CI
46
70
 
47
- Pass a personal access token via `--token <pat>` or the `AMBA_PAT` env
48
- var to skip the browser-based login flow.
71
+ Pass a Personal Access Token via `--token <pat>` or `AMBA_PAT` to skip the browser login.
49
72
 
50
- ## Requirements
73
+ ## Docs
51
74
 
52
- - Node.js 22+
75
+ Full reference: <https://docs.amba.dev/cli>.
53
76
 
54
77
  ## License
55
78
 
@@ -20,6 +20,7 @@ export interface ProjectSummary {
20
20
  platform: string;
21
21
  environment?: string;
22
22
  bundle_id?: string | null;
23
+ google_oauth_client_id?: string | null;
23
24
  status?: string;
24
25
  created_at?: string;
25
26
  }
@@ -27,6 +28,12 @@ export declare function listProjects(): Promise<ApiListResponse<ProjectSummary>>
27
28
  export declare function createProject(input: {
28
29
  name: string;
29
30
  bundle_id?: string;
31
+ /**
32
+ * Google OAuth 2.0 client id. Doubles as the audience the server
33
+ * expects on Google Sign In id tokens — set this if your app uses
34
+ * Sign in with Google. Public identifier, not a secret.
35
+ */
36
+ google_oauth_client_id?: string;
30
37
  platform?: string;
31
38
  /**
32
39
  * Project environment. `'development'` flags the row as the developer's
@@ -40,6 +47,25 @@ export declare function createProject(input: {
40
47
  platform: string;
41
48
  environment?: string;
42
49
  }>>;
50
+ /**
51
+ * PATCH /admin/projects/:projectId — update mutable fields. Server
52
+ * silently ignores unknown keys; we filter to the documented allow-list
53
+ * before sending so a typo at the CLI doesn't pass the wire silently.
54
+ */
55
+ export declare function updateProject(projectId: string, patch: {
56
+ name?: string;
57
+ bundle_id?: string | null;
58
+ google_oauth_client_id?: string | null;
59
+ platform?: string;
60
+ environment?: string;
61
+ }): Promise<ApiResponse<{
62
+ id: string;
63
+ name: string;
64
+ bundle_id: string | null;
65
+ google_oauth_client_id: string | null;
66
+ platform: string;
67
+ environment: string;
68
+ }>>;
43
69
  export declare function getProject(projectId: string): Promise<ApiResponse<{
44
70
  id: string;
45
71
  name: string;
@@ -53,15 +79,16 @@ export declare function deleteProject(projectId: string): Promise<ApiResponse<{
53
79
  deleted: boolean;
54
80
  }>>;
55
81
  export declare function reprovisionProject(projectId: string): Promise<ApiResponse<{
56
- workflowId?: string;
82
+ projectId: string;
83
+ job_id?: string;
57
84
  status?: string;
58
- message?: string;
85
+ collapsed?: boolean;
59
86
  }>>;
60
87
  export declare function getProvisioningStatus(projectId: string): Promise<ApiResponse<{
61
88
  projectId: string;
62
89
  status: string;
63
- workflowId?: string | null;
64
- errorMessage?: string | null;
90
+ provisioned_at: string | null;
91
+ region: string | null;
65
92
  }>>;
66
93
  export declare function createApiKey(projectId: string, keyType: 'client' | 'server', environment: 'development' | 'production'): Promise<ApiResponse<{
67
94
  id: string;
@@ -245,16 +272,16 @@ export interface FunctionDeploymentRow {
245
272
  project_id: string;
246
273
  name: string;
247
274
  version: number;
248
- cf_script_name: string;
249
- cf_dispatch_namespace: string;
275
+ runtime_script_name: string;
276
+ runtime_namespace: string;
250
277
  bundle_sha: string;
251
278
  status: 'active' | 'superseded' | 'disabled';
252
279
  created_at: string;
253
280
  }
254
281
  export declare function recordFunctionDeployment(projectId: string, input: {
255
282
  name: string;
256
- cf_script_name: string;
257
- cf_dispatch_namespace: string;
283
+ runtime_script_name: string;
284
+ runtime_namespace: string;
258
285
  bundle_sha: string;
259
286
  /**
260
287
  * Optional declarative rate-limit. The CLI passes a validated
@@ -298,13 +325,6 @@ export interface FunctionDeployContext {
298
325
  * step skips the storage binding in that case.
299
326
  */
300
327
  r2_bucket_name: string | null;
301
- /**
302
- * Cloudflare Hyperdrive config id. NULL until storage provisioning
303
- * completes; deploy step skips the Hyperdrive binding when null and
304
- * `ctx.collections` returns `tenant_unavailable` until the column is
305
- * populated.
306
- */
307
- cf_hyperdrive_config_id: string | null;
308
328
  }
309
329
  export declare function getFunctionDispatchNamespace(projectId: string): Promise<ApiResponse<FunctionDeployContext>>;
310
330
  export interface InternalCredentialsResponse {
@@ -528,8 +548,8 @@ export declare function dropCollection(projectId: string, name: string, confirm:
528
548
  export type AiProviderName = 'anthropic' | 'openai';
529
549
  export interface AiProviderRow {
530
550
  name: AiProviderName;
531
- /** Canonical secret name in the secret store. NULL only mid-rotation. */
532
- api_key_secret_name: string | null;
551
+ /** Whether an API key is currently configured for this provider. */
552
+ configured: boolean;
533
553
  /** Preview cue printed to the CLI on register; NOT a real partial key. */
534
554
  api_key_preview?: string;
535
555
  created_at?: string;
@@ -548,7 +568,7 @@ export interface SiteRow {
548
568
  id: string;
549
569
  project_id: string;
550
570
  name: string;
551
- cf_pages_project_name: string;
571
+ slug: string;
552
572
  status: 'active' | 'disabled' | 'archived';
553
573
  created_at: string;
554
574
  updated_at: string;
@@ -557,7 +577,7 @@ export interface SiteDomainRow {
557
577
  id: string;
558
578
  site_id: string;
559
579
  hostname: string;
560
- cf_hostname_id: string | null;
580
+ provider_hostname_id: string | null;
561
581
  cert_status: 'pending_validation' | 'pending_issuance' | 'pending_deployment' | 'active' | 'error';
562
582
  created_at: string;
563
583
  updated_at: string;
@@ -589,18 +609,18 @@ export declare function archiveSite(projectId: string, name: string, confirm: st
589
609
  /** Cascade summary returned by site/function delete proxies. */
590
610
  export interface DeleteCascadeSummary {
591
611
  domains_removed?: number;
592
- cf_pages_project_deleted?: boolean;
593
- cf_dispatch_script_deleted?: boolean;
612
+ site_runtime_removed?: boolean;
613
+ runtime_script_removed?: boolean;
594
614
  function_deployments_marked_disabled?: number;
595
615
  }
596
616
  /**
597
617
  * Add a custom domain to a site. The server-side proxy registers the
598
- * custom hostname, persists the resulting `cf_hostname_id`, and returns
618
+ * custom hostname, persists the resulting `provider_hostname_id`, and returns
599
619
  * the CNAME target the customer should point their DNS at.
600
620
  */
601
621
  export declare function addSiteDomainViaApi(projectId: string, siteName: string, hostname: string): Promise<ApiResponse<{
602
622
  hostname: string;
603
- cf_hostname_id: string;
623
+ provider_hostname_id: string;
604
624
  cert_status: SiteDomainRow["cert_status"];
605
625
  dns_target: string;
606
626
  created_at: string;
@@ -615,10 +635,10 @@ export declare function removeSiteDomainViaApi(projectId: string, siteName: stri
615
635
  deleted: true;
616
636
  }>>;
617
637
  /**
618
- * Roll a live CF Pages deployment back to a prior `deployment_id`. CF's
619
- * rollback creates a NEW deployment that serves the prior bundle (git-
620
- * revert semantics, not git-reset), so the response shape mirrors
621
- * `DeploySiteResult` and the new `deployment_id` is what's now live.
638
+ * Roll a live deployment back to a prior `deployment_id`. Rollback creates
639
+ * a NEW deployment that serves the prior bundle (git-revert semantics,
640
+ * not git-reset), so the response shape mirrors `DeploySiteResult` and
641
+ * the new `deployment_id` is what's now live.
622
642
  */
623
643
  export declare function rollbackSiteViaApi(projectId: string, siteName: string, deploymentId: string): Promise<ApiResponse<DeploySiteResult>>;
624
644
  /**
@@ -650,12 +670,12 @@ export declare function deleteFunctionViaApi(projectId: string, functionName: st
650
670
  }>>;
651
671
  export declare function attachSiteDomain(projectId: string, siteName: string, input: {
652
672
  hostname: string;
653
- cf_hostname_id?: string;
673
+ provider_hostname_id?: string;
654
674
  }): Promise<ApiResponse<SiteDomainRow>>;
655
675
  export declare function listSiteDomains(projectId: string, siteName: string): Promise<ApiListResponse<SiteDomainRow>>;
656
676
  export declare function updateSiteDomain(projectId: string, siteName: string, hostname: string, patch: {
657
677
  cert_status: SiteDomainRow['cert_status'];
658
- cf_hostname_id?: string;
678
+ provider_hostname_id?: string;
659
679
  }): Promise<ApiResponse<SiteDomainRow>>;
660
680
  export declare function detachSiteDomain(projectId: string, siteName: string, hostname: string): Promise<ApiResponse<{
661
681
  deleted: boolean;
package/dist/auth.d.ts CHANGED
@@ -37,6 +37,14 @@ export declare function clearCredentials(): Promise<void>;
37
37
  * `null` clears any prior override.
38
38
  */
39
39
  export declare function setBearerOverride(token: string | null): void;
40
+ /**
41
+ * Read the current bearer override without consuming it. Returns
42
+ * `null` when no override is set. Used by commands that need to know
43
+ * "did the operator supply a PAT for this invocation?" — e.g. `init`
44
+ * branches on whether to bypass stored-creds and use the supplied
45
+ * token verbatim.
46
+ */
47
+ export declare function getBearerOverride(): string | null;
40
48
  /** Test-only: reset the override between cases. */
41
49
  export declare function __resetTokenOverride(): void;
42
50
  /**
package/dist/bundle.d.ts CHANGED
@@ -1,24 +1,38 @@
1
1
  /**
2
2
  * Customer-function bundling for `amba functions deploy`.
3
3
  *
4
- * Uses esbuild (the Workers ecosystem bundler-of-record). The shared
5
- * runtime stdlib is marked `external` so customer bundles don't
6
- * re-include megabytes of `@anthropic-ai/sdk`, `postgres`, `zod`, etc.;
7
- * these resolve at dispatch time via platform-level bindings.
4
+ * Uses esbuild. Customer code is bundled into a single self-contained
5
+ * ES module — the upstream runtime resolves nothing at dispatch time
6
+ * except built-in JavaScript globals.
8
7
  *
9
8
  * Two checks gate the bundle before upload:
10
9
  * 1. Pre-upload size check against `BUNDLE_MAX_SIZE_BYTES` (8 MB
11
10
  * default — the platform's 10 MB compressed cap minus 2 MB
12
11
  * headroom) with a clear error pointing at the externalization
13
12
  * config.
14
- * 2. Bundle-shape report — the CLI prints what's externalized vs
15
- * bundled at deploy time so size issues are debuggable.
13
+ * 2. Bundle-shape report — the CLI prints what's bundled vs
14
+ * externalized at deploy time so size issues are debuggable.
15
+ *
16
+ * History note (2026-05-27): the prior version of this file pinned
17
+ * `@layers/amba-functions` + `@layers/amba-api-middleware` as
18
+ * "platform-level bindings" externals. Neither is — they were
19
+ * server-side packages, and `@layers/amba-functions` was unpublished
20
+ * in the 4.0.2 cutover (a deprecated wrapper that never matched the
21
+ * actual runtime). Any function importing one of them was rejected
22
+ * upstream as "no such module." The default externals list is now
23
+ * empty; customer code is expected to be self-contained.
16
24
  */
17
25
  import { type BuildOptions } from 'esbuild';
18
26
  /**
19
- * Modules customer code MUST externalize. The runtime exposes these as
20
- * platform-level bindings; bundling them per-script wastes hundreds of
21
- * KB to MBs and quickly hits the script-size cap.
27
+ * Modules the bundler treats as `external` by default. The Amba
28
+ * function runtime exposes zero npm packages — there is no "platform
29
+ * stdlib" for customer functions to import. Keep this list empty.
30
+ *
31
+ * The `extraExternals` field on `BundleOptions` is a programmatic
32
+ * escape hatch (used by tests + future CLI wiring). It's intentionally
33
+ * not exposed as a `amba functions deploy` flag today — externalizing
34
+ * a module that isn't actually provided at runtime is exactly the
35
+ * footgun this list-defaults-to-empty change closes.
22
36
  */
23
37
  export declare const RUNTIME_STDLIB_EXTERNALS: readonly string[];
24
38
  /**
@@ -0,0 +1,34 @@
1
+ /**
2
+ * `amba billing *` subcommands — CLI access to the per-project billing
3
+ * surface that ships behind `/v1/admin/projects/:id/billing/*`.
4
+ *
5
+ * amba billing status — tier, headroom on each
6
+ * metered axis, next-bill date,
7
+ * human_action_required.
8
+ *
9
+ * amba billing upgrade --tier <t> — print the Stripe Checkout
10
+ * URL for tier ∈ {pro, scale}
11
+ * [--interval month|year] at the chosen interval. CLI
12
+ * deliberately does NOT auto-
13
+ * open a browser: agents pipe
14
+ * the URL into a confirmation
15
+ * step, humans copy-paste.
16
+ *
17
+ * amba billing portal — print the Customer Portal
18
+ * URL for card / cancel / etc.
19
+ *
20
+ * amba billing set-ceiling <usd|off> — cap (or remove) the monthly
21
+ * spend ceiling.
22
+ *
23
+ * Project is resolved via `loadProjectConfig` (AMBA_PROJECT_ID env, then
24
+ * .env / .env.local in the cwd) — same pattern as `amba secrets *`.
25
+ */
26
+ export declare function billingStatusCommand(): Promise<void>;
27
+ export declare function billingUpgradeCommand(input: {
28
+ tier: 'pro' | 'scale';
29
+ interval?: 'month' | 'year';
30
+ }): Promise<void>;
31
+ export declare function billingPortalCommand(): Promise<void>;
32
+ export declare function billingSetCeilingCommand(input: {
33
+ ceiling: number | null;
34
+ }): Promise<void>;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * `amba claim <email>` — bind a sandbox account to a real email address
3
+ * via a one-click magic link.
4
+ *
5
+ * Sandbox accounts are minted with an auto-generated address
6
+ * (`sandbox-<epoch>-<nonce>@layers.com`) and remain capped at 100 MAU /
7
+ * 10 MB DB until the developer claims a real email. This command POSTs
8
+ * the target email to `/v1/auth/developer/claim` under the developer's
9
+ * stored PAT; the backend emails a single-use magic link that — when
10
+ * clicked — updates the developer row and flips the project tier from
11
+ * `sandbox` to `verified_free` (1,000 MAU, 500 MB DB).
12
+ *
13
+ * Wire shape:
14
+ *
15
+ * POST {AMBA_API_URL}/v1/auth/developer/claim
16
+ * Authorization: Bearer {pat}
17
+ * Content-Type: application/json
18
+ * Body: { "email": "<target-email>" }
19
+ *
20
+ * Success: HTTP 200 `{ "ok": true }`
21
+ * Errors: HTTP 400 INVALID_INPUT
22
+ * HTTP 409 EMAIL_TAKEN — that address already owns another account
23
+ * HTTP 409 ALREADY_CLAIMED — this account is already verified
24
+ * HTTP 429 — rate-limited
25
+ * HTTP 5xx — surface verbatim with code + message
26
+ *
27
+ * UX contract: a single ✓ line + a hint that the link expires in 15
28
+ * minutes. No copy-paste tokens, no follow-up commands. The click in
29
+ * the email is the whole flow.
30
+ */
31
+ export interface ClaimCommandOptions {
32
+ /** Override the API root for tests + ops. Defaults to env or `https://api.amba.dev`. */
33
+ apiUrl?: string;
34
+ /** Inject a fetch implementation — test seam. */
35
+ fetchImpl?: typeof fetch;
36
+ /** Inject the developer PAT directly — test seam. Bypasses ~/.amba lookup. */
37
+ pat?: string;
38
+ /** Override `~/` resolution for credential lookup — test seam. */
39
+ homeDir?: string;
40
+ }
41
+ export declare function claimCommand(email: string, options?: ClaimCommandOptions): Promise<void>;
@@ -32,11 +32,36 @@ export declare function functionsDeleteCommand(name: string, options?: {
32
32
  export declare function functionsScheduleCommand(name: string, cron: string, options?: {
33
33
  tz?: string;
34
34
  }): Promise<void>;
35
+ export interface DevOptions {
36
+ /** Local port. Default 8787 (overridable per project). */
37
+ port?: number;
38
+ /** Don't watch the file for changes. Default false. */
39
+ noWatch?: boolean;
40
+ }
35
41
  /**
36
- * `amba functions dev` — not configured in this release. Use
37
- * `amba functions deploy <file>` to deploy via the platform API.
42
+ * `amba functions dev <file>` — run the function locally with file-change
43
+ * hot reload.
44
+ *
45
+ * Architecture: the CLI process owns the file watcher + bundler; the
46
+ * actual HTTP server lives in a child Node process that imports the
47
+ * bundle and binds to the user's port. On file change, the parent kills
48
+ * the child, writes a fresh bundle, and respawns. This bounds memory
49
+ * (each rebuild = fresh V8 heap) and isolates customer-handler crashes
50
+ * from the CLI. Brief downtime per rebuild (~100ms while the port is
51
+ * released and re-bound); incoming connections during the swap queue
52
+ * at the TCP listen backlog and complete once the new child is up.
53
+ *
54
+ * The bundler is the same esbuild pipeline `amba functions deploy` uses
55
+ * — externalization rules, size cap, and source-map handling are
56
+ * identical so dev → prod parity is automatic.
57
+ *
58
+ * Handler shape: `export default async function (req: Request): Promise<Response>`.
59
+ * `.env.local` values in the customer's working directory are passed
60
+ * through to the child process so the handler can read them via
61
+ * `process.env.MY_KEY`. Existing values in the parent's env take
62
+ * priority (so `MY_KEY=x amba functions dev …` wins).
38
63
  */
39
- export declare function functionsDevCommand(_entryPoint: string): Promise<void>;
64
+ export declare function functionsDevCommand(entryPoint: string, options?: DevOptions): Promise<void>;
40
65
  /**
41
66
  * `amba functions consume <queue> <function>` — bind a function as the
42
67
  * consumer for a queue. Customers send to a queue with `ctx.queue.send`;
@@ -1,3 +1,4 @@
1
+ import { type SandboxResult } from '../sandbox.js';
1
2
  export interface InitOptions {
2
3
  withExample?: boolean;
3
4
  /**
@@ -8,5 +9,73 @@ export interface InitOptions {
8
9
  * minted via `amba projects create --env production` by automation).
9
10
  */
10
11
  env?: 'development' | 'production';
12
+ /**
13
+ * Headless agentic mode. Skips browser auth + interactive prompts:
14
+ * the CLI generates a sandbox email + password, posts to
15
+ * `/v1/auth/developer/signup`, writes credentials everywhere
16
+ * (`~/.amba/credentials.json` + `.env.local` + `AMBA.md`), and
17
+ * auto-wires the Amba MCP server into every detected MCP client
18
+ * config. Designed to be invoked unattended by an AI coding agent
19
+ * that pasted the homepage 3-line prompt.
20
+ */
21
+ sandbox?: boolean;
22
+ /** Override the auto-generated sandbox email. Only meaningful with `--sandbox`. */
23
+ sandboxEmail?: string;
24
+ /** Skip MCP-client-config writes. Mostly for testing. */
25
+ noMcpConfig?: boolean;
26
+ /**
27
+ * Skip installing the `/amba-build` Claude Code skill into
28
+ * `.claude/skills/amba-build/SKILL.md`. Default behavior (when
29
+ * `--sandbox` is on) is to install the skill — pass `--no-skills`
30
+ * to opt out (e.g. in a CI run that doesn't want stray files).
31
+ */
32
+ noSkills?: boolean;
33
+ /** Emit a machine-readable JSON summary instead of human-readable lines. */
34
+ json?: boolean;
35
+ /** Override `~/` resolution. Test seam — production code never sets this. */
36
+ homeDir?: string;
11
37
  }
12
38
  export declare function initCommand(options?: InitOptions): Promise<void>;
39
+ export declare function runSandboxInit(cwd: string, options: {
40
+ sandboxEmail?: string;
41
+ noMcpConfig?: boolean;
42
+ /**
43
+ * Skip the project-local skill install. Default is to install. Set
44
+ * true in CI or during tests that don't want stray files written.
45
+ */
46
+ noSkills?: boolean;
47
+ json?: boolean;
48
+ /**
49
+ * Override `~/` resolution. The CLI itself never passes this — it's
50
+ * the seam tests use to avoid touching the developer's actual home
51
+ * directory.
52
+ */
53
+ homeDir?: string;
54
+ }): Promise<SandboxResult>;
55
+ /**
56
+ * Build the plaintext (no ANSI) success-output block printed at the
57
+ * end of `amba init --sandbox`. Pure function — exported for the
58
+ * vitest cases that assert on per-line content. The CLI wraps the
59
+ * output with picocolors in `printSandboxNextSteps` below.
60
+ *
61
+ * Design: silent-until-done. The install (provision account, mint
62
+ * keys, write .env.local, write MCP config, install skill) is COMPLETE
63
+ * the moment this output lands. The MCP config has been persisted —
64
+ * it activates on the next launch of the developer's coding agent. We
65
+ * do NOT instruct the developer to restart anything; we just state
66
+ * what's wired and what's next.
67
+ *
68
+ * Shape (~6 lines, Vercel/Stripe aesthetic):
69
+ * ✓ Amba ready
70
+ * project: <id>
71
+ * keys → .env.local
72
+ * mcp → <paths> (active next agent launch)
73
+ * skill → <skill paths> (when installed)
74
+ *
75
+ * next: npm install <sdk-pkg>
76
+ * Amba.configure({ projectId, clientKey }) at app startup
77
+ *
78
+ * The fallback for "no MCP client config detected" is a one-line
79
+ * note + a paste-ready snippet — still no restart copy.
80
+ */
81
+ export declare function buildSandboxNextStepsLines(r: SandboxResult): string[];
@@ -3,8 +3,16 @@ export declare function projectsCreateCommand(input: {
3
3
  name: string;
4
4
  env?: string;
5
5
  bundleId?: string;
6
+ googleOauthClientId?: string;
6
7
  platform?: string;
7
8
  }): Promise<void>;
9
+ export declare function projectsUpdateCommand(projectId: string, input: {
10
+ name?: string;
11
+ bundleId?: string;
12
+ googleOauthClientId?: string;
13
+ platform?: string;
14
+ environment?: string;
15
+ }): Promise<void>;
8
16
  export declare function projectsShowCommand(projectId: string): Promise<void>;
9
17
  export declare function projectsDeleteCommand(projectId: string, opts?: {
10
18
  yes?: boolean;