@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 +45 -22
- package/dist/api-client.d.ts +49 -29
- package/dist/auth.d.ts +8 -0
- package/dist/bundle.d.ts +23 -9
- package/dist/commands/billing.d.ts +34 -0
- package/dist/commands/claim.d.ts +41 -0
- package/dist/commands/functions.d.ts +28 -3
- package/dist/commands/init.d.ts +69 -0
- package/dist/commands/projects.d.ts +8 -0
- package/dist/credentials.d.ts +259 -0
- package/dist/index.js +3657 -425
- package/dist/project-config.d.ts +11 -0
- package/dist/sandbox.d.ts +309 -0
- package/dist/skill-installer.d.ts +95 -0
- package/dist/skills/presets.d.ts +146 -0
- package/dist/skills.d.ts +266 -0
- package/package.json +7 -2
- package/skill-bundle/SKILL.md +324 -0
- package/skill-bundle/references/economy.md +331 -0
- package/skill-bundle/references/engagement.md +400 -0
- package/skill-bundle/references/gamification.md +316 -0
- package/skill-bundle/references/identity.md +395 -0
- package/skill-bundle/references/infrastructure.md +348 -0
- package/skill-bundle/references/social.md +366 -0
package/dist/project-config.d.ts
CHANGED
|
@@ -14,3 +14,14 @@ export interface ProjectConfig {
|
|
|
14
14
|
apiUrl: string;
|
|
15
15
|
}
|
|
16
16
|
export declare function loadProjectConfig(cwd?: string): Promise<ProjectConfig>;
|
|
17
|
+
/**
|
|
18
|
+
* Parse a `.env`-style file body into a flat string map.
|
|
19
|
+
*
|
|
20
|
+
* Lines are trimmed; blank lines and `#`-comments are skipped; lines
|
|
21
|
+
* without an `=` are skipped. Values may be wrapped in matching single
|
|
22
|
+
* or double quotes which are stripped on read. Bug fixes should land
|
|
23
|
+
* here once — both `project-config.ts` (resolves `AMBA_PROJECT_ID`)
|
|
24
|
+
* and `commands/functions.ts` (loads `.env.local` for the local dev
|
|
25
|
+
* server) call this.
|
|
26
|
+
*/
|
|
27
|
+
export declare function parseEnv(content: string): Record<string, string>;
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless agentic sandbox bootstrap.
|
|
3
|
+
*
|
|
4
|
+
* Implements `amba init --sandbox`: the zero-question, no-browser path
|
|
5
|
+
* an AI coding agent runs when a developer pastes the homepage prompt:
|
|
6
|
+
*
|
|
7
|
+
* Run `npx @layers/amba init --sandbox` and follow the
|
|
8
|
+
* instructions it prints.
|
|
9
|
+
*
|
|
10
|
+
* The CLI does everything: synthesize an anonymous email + password,
|
|
11
|
+
* sign the developer up via the public `/v1/auth/developer/signup`
|
|
12
|
+
* endpoint (no Bearer needed), pluck the returned PAT + project
|
|
13
|
+
* credentials, and write them into:
|
|
14
|
+
*
|
|
15
|
+
* - `~/.amba/credentials.json` (chmod 0600)
|
|
16
|
+
* - `<cwd>/.env.local` (.gitignored — SDK reads it)
|
|
17
|
+
* - `<cwd>/AMBA.md` (markdown context for the agent)
|
|
18
|
+
* - every detected MCP client config (`~/.claude.json`,
|
|
19
|
+
* `~/.cursor/mcp.json`, `~/.codeium/windsurf/mcp_config.json`,
|
|
20
|
+
* plus their project-local equivalents WHEN already present —
|
|
21
|
+
* never created from scratch, to avoid cluttering repos)
|
|
22
|
+
*
|
|
23
|
+
* The MCP-config merge is non-destructive: an existing `mcpServers.amba`
|
|
24
|
+
* entry is replaced with the new PAT, but the prior file is copied
|
|
25
|
+
* aside to `<path>.bak-<unix-ms>` first so a developer who had a real
|
|
26
|
+
* production PAT wired in can recover. Every other server entry is
|
|
27
|
+
* preserved. JSON files that already exist but lack an `mcpServers`
|
|
28
|
+
* key gain one; missing files for the global locations get scaffolded
|
|
29
|
+
* with a minimal `{ "mcpServers": { "amba": … }}`.
|
|
30
|
+
*
|
|
31
|
+
* Similarly, a pre-existing `~/.amba/credentials.json` whose `source`
|
|
32
|
+
* is not `'sandbox-init'` is backed up to `credentials.json.bak-<ms>`
|
|
33
|
+
* before the sandbox PAT replaces it. Idempotent re-runs from our own
|
|
34
|
+
* sandbox session do NOT trigger a backup.
|
|
35
|
+
*
|
|
36
|
+
* Provisioning polling: deliberately skipped. The server returns the
|
|
37
|
+
* project row with `provisioning_status: 'provisioning'` immediately and
|
|
38
|
+
* the workflow flips it to `'active'` within ~5s. The agent's next SDK
|
|
39
|
+
* call may briefly retry — fine. Blocking the CLI here would just hide
|
|
40
|
+
* the same wait behind a different progress indicator.
|
|
41
|
+
*/
|
|
42
|
+
export interface SandboxSignupRequest {
|
|
43
|
+
email: string;
|
|
44
|
+
password: string;
|
|
45
|
+
name?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Shape returned by `POST /v1/auth/developer/signup`. Only the fields the
|
|
49
|
+
* sandbox flow actually consumes are typed — the response body has more
|
|
50
|
+
* (refresh token, expiry, etc.) but we don't need them here.
|
|
51
|
+
*/
|
|
52
|
+
export interface SandboxSignupResponse {
|
|
53
|
+
pat: string;
|
|
54
|
+
project_id: string;
|
|
55
|
+
client_key: string;
|
|
56
|
+
server_key?: string;
|
|
57
|
+
api_url: string;
|
|
58
|
+
/** `'provisioning'` immediately after signup; flips to `'active'` once the workflow finishes. */
|
|
59
|
+
provisioning_status?: string;
|
|
60
|
+
/** Email-verification URL — surfaced by the API so we can echo it for upgrade. */
|
|
61
|
+
verify_url?: string;
|
|
62
|
+
/** The actual email we used (may be the auto-generated one). */
|
|
63
|
+
email: string;
|
|
64
|
+
/**
|
|
65
|
+
* Developer row returned in `data.developer`. Required for callers
|
|
66
|
+
* (e.g. `ensureDeveloperIdentity`) to populate the developer_id on
|
|
67
|
+
* the freshly-minted local credentials without a second round trip
|
|
68
|
+
* to `/developer/me`.
|
|
69
|
+
*/
|
|
70
|
+
developer_id: string;
|
|
71
|
+
/** Developer name, if set on the row. */
|
|
72
|
+
developer_name?: string;
|
|
73
|
+
}
|
|
74
|
+
export interface McpClientConfigTarget {
|
|
75
|
+
/** Display name for logging. */
|
|
76
|
+
label: string;
|
|
77
|
+
/** Absolute path on disk. */
|
|
78
|
+
path: string;
|
|
79
|
+
/** Whether to create the file if it doesn't exist. Global configs: yes. Project-local: no. */
|
|
80
|
+
scaffoldIfMissing: boolean;
|
|
81
|
+
}
|
|
82
|
+
export interface SandboxResult {
|
|
83
|
+
email: string;
|
|
84
|
+
projectId: string;
|
|
85
|
+
pat: string;
|
|
86
|
+
patPreview: string;
|
|
87
|
+
clientKey: string;
|
|
88
|
+
/** The exact API URL the signup POST hit. Source of truth for callers. */
|
|
89
|
+
apiUrl: string;
|
|
90
|
+
credentialsPath: string;
|
|
91
|
+
/** Backup of a pre-existing non-sandbox `~/.amba/credentials.json`, or null. */
|
|
92
|
+
credentialsBackedUpTo: string | null;
|
|
93
|
+
envLocalPath: string;
|
|
94
|
+
ambaMdPath: string;
|
|
95
|
+
/** One record per MCP client config we touched; includes per-file backup info. */
|
|
96
|
+
mcpConfigsWritten: McpConfigPathResult[];
|
|
97
|
+
/** Best-guess SDK package for the framework detected in CWD. */
|
|
98
|
+
sdkPackage: string;
|
|
99
|
+
framework: string;
|
|
100
|
+
verifyUrl: string | null;
|
|
101
|
+
provisioningStatus: string;
|
|
102
|
+
/**
|
|
103
|
+
* Absolute path of the `.claude/skills/amba-build/SKILL.md` we wrote
|
|
104
|
+
* during the sandbox init, or `null` if the skill install was skipped
|
|
105
|
+
* (e.g. `--no-skills`).
|
|
106
|
+
*/
|
|
107
|
+
skillPath: string | null;
|
|
108
|
+
/**
|
|
109
|
+
* Per-agent setup-guide fan-out result. One entry per writer that
|
|
110
|
+
* succeeded. Empty array when `--no-skills` was passed (the same flag
|
|
111
|
+
* gates both the build-task skill and the cross-agent fan-out — they
|
|
112
|
+
* write into the same project surfaces and there's no use-case for
|
|
113
|
+
* skipping one but not the other).
|
|
114
|
+
*/
|
|
115
|
+
setupTargets: Array<{
|
|
116
|
+
target: string;
|
|
117
|
+
path: string;
|
|
118
|
+
mode: 'created' | 'refreshed';
|
|
119
|
+
}>;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Generate a deterministic-looking but globally-unique sandbox email.
|
|
123
|
+
*
|
|
124
|
+
* Pattern: `sandbox-<epoch>-<6char>@layers.com`.
|
|
125
|
+
*
|
|
126
|
+
* The control DB's `developers` table has a UNIQUE(email) constraint and
|
|
127
|
+
* a 5-per-minute / 50-per-day per-IP rate limit on signup. Embedding the
|
|
128
|
+
* epoch + a 6-char nonce keeps the collision probability negligible even
|
|
129
|
+
* across a herd of CI agents all running `amba init --sandbox` from the
|
|
130
|
+
* same VPC.
|
|
131
|
+
*
|
|
132
|
+
* We use `@layers.com` (not the customer's own domain) because the
|
|
133
|
+
* sandbox tier is pre-verification — the developer never receives or
|
|
134
|
+
* actions a verification email for this address. When they want to
|
|
135
|
+
* upgrade, the CLI prints the verify URL the API returned so they can
|
|
136
|
+
* claim a real email in the console.
|
|
137
|
+
*/
|
|
138
|
+
export declare function generateSandboxEmail(): string;
|
|
139
|
+
/**
|
|
140
|
+
* Random URL-safe password. 24 raw bytes → 32 base64url chars; well over
|
|
141
|
+
* the 8-char minimum the API enforces, with ~192 bits of entropy.
|
|
142
|
+
*
|
|
143
|
+
* The password is never shown to the developer or written anywhere — the
|
|
144
|
+
* PAT is what gets stored. We generate it solely because `POST /signup`
|
|
145
|
+
* requires it (and demands a non-empty value); a future API change could
|
|
146
|
+
* accept "agent signup" with no password and we'd drop this entirely.
|
|
147
|
+
*/
|
|
148
|
+
export declare function generateSandboxPassword(): string;
|
|
149
|
+
/**
|
|
150
|
+
* POST the synthesized credentials at the public signup endpoint.
|
|
151
|
+
*
|
|
152
|
+
* No Bearer auth — this is the bootstrap call that mints one. We use
|
|
153
|
+
* `fetch` directly (not the api-client wrapper) because that wrapper
|
|
154
|
+
* always resolves a bearer token first, which is exactly what we don't
|
|
155
|
+
* have yet.
|
|
156
|
+
*
|
|
157
|
+
* Returns the unwrapped, flattened shape consumed by the rest of the
|
|
158
|
+
* sandbox flow. Throws with a human-readable message on any non-2xx so
|
|
159
|
+
* the CLI's `runAction` wrapper can surface it without crashing on a
|
|
160
|
+
* generic 'fetch failed'.
|
|
161
|
+
*/
|
|
162
|
+
export declare function performSandboxSignup(req: SandboxSignupRequest, options?: {
|
|
163
|
+
apiUrl?: string;
|
|
164
|
+
fetchImpl?: typeof fetch;
|
|
165
|
+
}): Promise<SandboxSignupResponse>;
|
|
166
|
+
/**
|
|
167
|
+
* Write or update `<cwd>/.env.local` with the sandbox project's keys.
|
|
168
|
+
*
|
|
169
|
+
* Mirrors the `init` interactive flow exactly so the existing env-read
|
|
170
|
+
* conventions in the SDKs and CLI commands keep working. The merge
|
|
171
|
+
* logic: if the file already exists and contains an `AMBA_PROJECT_ID`
|
|
172
|
+
* line we replace the Amba lines in place; otherwise we append a
|
|
173
|
+
* fresh stanza.
|
|
174
|
+
*
|
|
175
|
+
* `serverKey` is optional — pass it on the new two-scope credential
|
|
176
|
+
* model where init mints both client+server. Pre-existing AMBA_SERVER_KEY
|
|
177
|
+
* lines are refreshed when a new value is provided and removed when
|
|
178
|
+
* serverKey is null AND no prior line existed (no-op on second case).
|
|
179
|
+
*/
|
|
180
|
+
export declare function writeSandboxEnvLocal(cwd: string, projectId: string, clientKey: string, apiUrl: string, serverKey?: string | null): Promise<string>;
|
|
181
|
+
/**
|
|
182
|
+
* Write the AMBA.md sandbox-tier guide to `<cwd>/AMBA.md`.
|
|
183
|
+
*
|
|
184
|
+
* Always overwrites — the file is meant to be regenerated, and the
|
|
185
|
+
* interactive `init` flow's longer AMBA.md template is replaced here
|
|
186
|
+
* with a sandbox-specific shorter one (with upgrade instructions).
|
|
187
|
+
*/
|
|
188
|
+
export declare function writeSandboxAmbaMd(cwd: string, ctx: {
|
|
189
|
+
projectId: string;
|
|
190
|
+
email: string;
|
|
191
|
+
verifyUrl: string | null;
|
|
192
|
+
sdkPackage: string;
|
|
193
|
+
framework: string;
|
|
194
|
+
apiUrl: string;
|
|
195
|
+
}): Promise<string>;
|
|
196
|
+
/**
|
|
197
|
+
* The canonical Amba MCP entry. Used as the value of
|
|
198
|
+
* `mcpServers.amba` in every detected client config.
|
|
199
|
+
*
|
|
200
|
+
* Shape note: Claude Code, Cursor, and Windsurf all read the same
|
|
201
|
+
* `type` + `url` + `headers` triple. (Windsurf historically also
|
|
202
|
+
* accepted `serverUrl` — we emit `url` to match the modern shape it
|
|
203
|
+
* also accepts, and skip emitting the legacy alias to keep the JSON
|
|
204
|
+
* minimal.)
|
|
205
|
+
*/
|
|
206
|
+
export declare function buildAmbaMcpEntry(pat: string): Record<string, unknown>;
|
|
207
|
+
/**
|
|
208
|
+
* Identifier for the MCP client family a config file belongs to.
|
|
209
|
+
* Kept around so callers can reason about which agent runtime a given
|
|
210
|
+
* config path targets — the CLI no longer prints per-client restart
|
|
211
|
+
* bullets (the new flow frames MCP wiring as "active next agent
|
|
212
|
+
* launch" rather than asking the developer to restart), but the
|
|
213
|
+
* classifier is still useful for callers that want to render per-
|
|
214
|
+
* client labels in their own UI.
|
|
215
|
+
*/
|
|
216
|
+
export type McpClientKind = 'claude-code' | 'cursor' | 'windsurf';
|
|
217
|
+
/**
|
|
218
|
+
* Map an MCP config file path back to its client family. Returns null
|
|
219
|
+
* for paths that don't match any known config location — defensive
|
|
220
|
+
* against future additions to `mcpClientTargets`.
|
|
221
|
+
*
|
|
222
|
+
* The match is on path tail rather than full equality so the cwd /
|
|
223
|
+
* homedir-injected variants both classify correctly. We deliberately
|
|
224
|
+
* accept both global and project-local Claude Code paths
|
|
225
|
+
* (`.claude.json` and `.mcp.json`) as 'claude-code'.
|
|
226
|
+
*/
|
|
227
|
+
export declare function classifyMcpPath(path: string): McpClientKind | null;
|
|
228
|
+
/**
|
|
229
|
+
* Reduce a list of written-config paths to the set of unique client
|
|
230
|
+
* families they belong to. Order: claude-code, cursor, windsurf (so
|
|
231
|
+
* the done-message renders consistently). Skips unclassified paths
|
|
232
|
+
* silently.
|
|
233
|
+
*/
|
|
234
|
+
export declare function clientKindsFromPaths(paths: string[]): McpClientKind[];
|
|
235
|
+
/**
|
|
236
|
+
* The list of MCP client config files we probe. Order matters only for
|
|
237
|
+
* the printed report.
|
|
238
|
+
*
|
|
239
|
+
* Project-local entries are listed but only get touched when the file
|
|
240
|
+
* already exists in CWD — we don't want to scatter `.mcp.json` /
|
|
241
|
+
* `.cursor/mcp.json` files into random user repos that have never been
|
|
242
|
+
* MCP-configured.
|
|
243
|
+
*/
|
|
244
|
+
export declare function mcpClientTargets(cwd: string, options?: {
|
|
245
|
+
homeDir?: string;
|
|
246
|
+
}): McpClientConfigTarget[];
|
|
247
|
+
/**
|
|
248
|
+
* Per-target result of an MCP config merge.
|
|
249
|
+
*
|
|
250
|
+
* - `path: null` means the target file didn't exist and scaffolding was
|
|
251
|
+
* not allowed (project-local targets in unconfigured repos).
|
|
252
|
+
* - `backedUpTo` is the absolute path of the backup file when an
|
|
253
|
+
* existing `mcpServers.amba` entry was present (so a developer who
|
|
254
|
+
* had a real PAT wired in can recover); `null` when no backup was
|
|
255
|
+
* needed.
|
|
256
|
+
*/
|
|
257
|
+
export interface McpConfigWriteResult {
|
|
258
|
+
path: string | null;
|
|
259
|
+
backedUpTo: string | null;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Merge the `amba` entry into a single client config file.
|
|
263
|
+
*
|
|
264
|
+
* Strategy:
|
|
265
|
+
* - If the file exists, load + JSON-parse. If parse fails, throw with
|
|
266
|
+
* a clear "we won't clobber malformed JSON" error.
|
|
267
|
+
* - If the file doesn't exist and scaffolding is allowed, create the
|
|
268
|
+
* parent dir and write `{ "mcpServers": { "amba": ... } }`.
|
|
269
|
+
* - In all cases, `mcpServers.amba` ends up set; every other
|
|
270
|
+
* `mcpServers.*` entry is preserved.
|
|
271
|
+
*
|
|
272
|
+
* Real-credential safety: if the existing file ALREADY has a
|
|
273
|
+
* `mcpServers.amba` entry, we copy the whole file aside to
|
|
274
|
+
* `<path>.bak-<unix-ms>` BEFORE merging. This protects a developer who
|
|
275
|
+
* had a real production PAT wired in and then ran `amba init --sandbox`
|
|
276
|
+
* to "try" the flow. Idempotent re-runs from the same sandbox session
|
|
277
|
+
* still trigger a backup — cheap, and the developer can `rm *.bak-*`
|
|
278
|
+
* any time.
|
|
279
|
+
*/
|
|
280
|
+
export declare function mergeMcpConfigFile(target: McpClientConfigTarget, pat: string): Promise<McpConfigWriteResult>;
|
|
281
|
+
/**
|
|
282
|
+
* Per-target result returned by `writeAllMcpConfigs`. Same shape as
|
|
283
|
+
* `McpConfigWriteResult` but always carries a non-null `path` (skipped
|
|
284
|
+
* targets aren't included in the list).
|
|
285
|
+
*/
|
|
286
|
+
export interface McpConfigPathResult {
|
|
287
|
+
path: string;
|
|
288
|
+
backedUpTo: string | null;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Probe every known MCP client location and merge our entry into the
|
|
292
|
+
* ones that exist (or that are flagged scaffoldIfMissing). Returns one
|
|
293
|
+
* record per touched file (skipped files are omitted).
|
|
294
|
+
*
|
|
295
|
+
* `warn` is invoked (instead of `console.warn`) for per-target errors
|
|
296
|
+
* so callers using `--json` can route those notices to stderr and keep
|
|
297
|
+
* stdout machine-parseable.
|
|
298
|
+
*/
|
|
299
|
+
export declare function writeAllMcpConfigs(cwd: string, pat: string, options?: {
|
|
300
|
+
homeDir?: string;
|
|
301
|
+
warn?: (msg: string) => void;
|
|
302
|
+
}): Promise<McpConfigPathResult[]>;
|
|
303
|
+
/**
|
|
304
|
+
* Render the canonical Amba MCP snippet for clients we can't auto-wire
|
|
305
|
+
* (anything outside the {Claude Code, Cursor, Windsurf} set). Printed by
|
|
306
|
+
* the CLI when no client configs are detected so the developer at least
|
|
307
|
+
* has a paste-ready JSON blob.
|
|
308
|
+
*/
|
|
309
|
+
export declare function formatManualMcpSnippet(pat: string): string;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Amba skill bundle installer.
|
|
3
|
+
*
|
|
4
|
+
* The bundled `skill-bundle/` directory contains `SKILL.md` plus a
|
|
5
|
+
* `references/` folder with one file per Amba surface area. The skill
|
|
6
|
+
* teaches the agent the classify → confirm → wire-up playbook for
|
|
7
|
+
* adding Amba primitives to a developer's codebase. See
|
|
8
|
+
* `packages/cli/skill-bundle/SKILL.md` for the source.
|
|
9
|
+
*
|
|
10
|
+
* Why ship a bundled skill (instead of `npx skills add layers/amba`):
|
|
11
|
+
* the CLI run is the same install step. Bundling avoids a second
|
|
12
|
+
* fetch, keeps the skill version locked to the CLI version, and means
|
|
13
|
+
* `amba init` produces a fully-wired agent on offline networks too.
|
|
14
|
+
*
|
|
15
|
+
* Cross-agent install — we drop the same body into every detected
|
|
16
|
+
* coding agent's skill directory. Agents read their own location:
|
|
17
|
+
*
|
|
18
|
+
* - Claude Code: `.claude/skills/amba/`
|
|
19
|
+
* - Cursor: `.cursor/skills/amba/`
|
|
20
|
+
* - Codex CLI: `.codex/skills/amba/`
|
|
21
|
+
* - Windsurf: `.windsurf/skills/amba/`
|
|
22
|
+
*
|
|
23
|
+
* We also write a project-root copy at `.agents/skills/amba/` which
|
|
24
|
+
* the `npx skills add ...` distribution tool reads from (and which any
|
|
25
|
+
* agent that pre-registers an `.agents/skills/` lookup picks up). Five
|
|
26
|
+
* locations, one body — same fan-out pattern `writeAllSetupTargets`
|
|
27
|
+
* already uses for the legacy setup guide.
|
|
28
|
+
*
|
|
29
|
+
* Idempotency: re-running `amba init` overwrites the bundled
|
|
30
|
+
* `SKILL.md` and `references/*.md` so every developer ends up on the
|
|
31
|
+
* latest playbook. We back up a pre-existing `SKILL.md` to a sibling
|
|
32
|
+
* `.bak-<unix-ms>` ONLY when its first frontmatter key (`name:`) is
|
|
33
|
+
* not `amba` — that's the signal it was hand-authored / unrelated and
|
|
34
|
+
* shouldn't be silently clobbered. Bundled Amba files are refreshed
|
|
35
|
+
* without backup.
|
|
36
|
+
*/
|
|
37
|
+
export type SkillInstallTargetKind = 'claude-code' | 'cursor' | 'codex' | 'windsurf' | 'generic-agents';
|
|
38
|
+
export interface SkillInstallTarget {
|
|
39
|
+
kind: SkillInstallTargetKind;
|
|
40
|
+
/** Absolute path to the `amba/` directory inside the agent's skill root. */
|
|
41
|
+
path: string;
|
|
42
|
+
}
|
|
43
|
+
export interface SkillFileWritten {
|
|
44
|
+
/** Absolute path of the file written. */
|
|
45
|
+
path: string;
|
|
46
|
+
/** Backup path when an existing non-Amba SKILL.md was preserved; otherwise null. */
|
|
47
|
+
backedUpTo: string | null;
|
|
48
|
+
}
|
|
49
|
+
export interface SkillInstallResult {
|
|
50
|
+
/** Target directory the skill was installed under. */
|
|
51
|
+
target: SkillInstallTarget;
|
|
52
|
+
/** Files written this run. */
|
|
53
|
+
files: SkillFileWritten[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolve the bundled skill source directory.
|
|
57
|
+
*
|
|
58
|
+
* The bundle lives at `<package-root>/skill-bundle/` in both the
|
|
59
|
+
* source tree and the published tarball (via `files[]` in
|
|
60
|
+
* `package.json`). From a built `dist/commands/init.js` the path is
|
|
61
|
+
* `../../skill-bundle/`. From the source tree
|
|
62
|
+
* (`src/skill-installer.ts`) the path is `../skill-bundle/`. We try
|
|
63
|
+
* both relative to `import.meta.url` and pick the one that exists.
|
|
64
|
+
*/
|
|
65
|
+
export declare function resolveBundleDir(): Promise<string>;
|
|
66
|
+
/**
|
|
67
|
+
* List the five install targets the CLI fans out to. Project-local
|
|
68
|
+
* directories (`<cwd>/.claude/skills/amba/`, etc.) — the agent reads
|
|
69
|
+
* project-local skills with priority over global ones, so this is the
|
|
70
|
+
* canonical install location for a tool meant to wire up THIS project.
|
|
71
|
+
*/
|
|
72
|
+
export declare function skillInstallTargets(cwd: string): SkillInstallTarget[];
|
|
73
|
+
/**
|
|
74
|
+
* Copy SKILL.md + every file under references/ into the target
|
|
75
|
+
* directory. Creates the directory tree if missing. Returns the list
|
|
76
|
+
* of files touched and any backup paths.
|
|
77
|
+
*
|
|
78
|
+
* Backup rule: a pre-existing `SKILL.md` is backed up to
|
|
79
|
+
* `SKILL.md.bak-<unix-ms>` ONLY when its first `name:` frontmatter
|
|
80
|
+
* line is NOT `name: amba`. That's the signal it was authored by the
|
|
81
|
+
* user for an unrelated purpose and shouldn't be silently overwritten.
|
|
82
|
+
* Amba-owned files get refreshed without backup so developers
|
|
83
|
+
* tracking the latest playbook don't accumulate junk.
|
|
84
|
+
*/
|
|
85
|
+
export declare function installSkillBundle(cwd: string, options?: {
|
|
86
|
+
bundleDir?: string;
|
|
87
|
+
}): Promise<SkillInstallResult[]>;
|
|
88
|
+
/**
|
|
89
|
+
* Convenience: returns the count of skill files written and the list
|
|
90
|
+
* of target kinds, for the CLI's done-message summary.
|
|
91
|
+
*/
|
|
92
|
+
export declare function summarizeSkillInstall(results: SkillInstallResult[]): {
|
|
93
|
+
totalFiles: number;
|
|
94
|
+
targetKinds: SkillInstallTargetKind[];
|
|
95
|
+
};
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App-kind presets for the "Hey Claude, get amba.dev in my app" onboarding.
|
|
3
|
+
*
|
|
4
|
+
* The classifier picks one of 10 kinds (9 opinionated + `custom`); the
|
|
5
|
+
* wire-up engine reads the matching preset to know:
|
|
6
|
+
*
|
|
7
|
+
* - which Amba surface areas to enable (used to scope the docs the
|
|
8
|
+
* coding agent pulls into context),
|
|
9
|
+
* - which follow-up questions to ask the developer when the preset has
|
|
10
|
+
* genuine ambiguity (e.g. friends-vs-global leaderboard scope),
|
|
11
|
+
* - the exact MCP tool calls to issue against `mcp.amba.dev` to create
|
|
12
|
+
* the starter resources (currencies, achievements, streaks, …),
|
|
13
|
+
* - the literal SDK init snippet to paste into the developer's project
|
|
14
|
+
* for whichever of the six supported stacks they're on.
|
|
15
|
+
*
|
|
16
|
+
* The MCP tool names and argument shapes here MUST match the registered
|
|
17
|
+
* tools in `packages/mcp/src/tools/*`. The validation surface for that
|
|
18
|
+
* is the per-tool zod schema; this file is the single source of truth
|
|
19
|
+
* for "what does Amba install for a fitness app" and lives in the CLI
|
|
20
|
+
* because the CLI's classifier (Task #3) reads it directly. The MCP
|
|
21
|
+
* server doesn't import this — its job is to expose the underlying
|
|
22
|
+
* tools, not to know about preset choices.
|
|
23
|
+
*
|
|
24
|
+
* Naming discipline (see CLAUDE.md): no `cf_*` / `neon_*` / `temporal_*`
|
|
25
|
+
* field names; achievement icons reference customer-replaceable URLs on
|
|
26
|
+
* the Amba CDN; SDK snippets never name an underlying vendor.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* The closed set of app kinds the classifier returns. `custom` is the
|
|
30
|
+
* escape hatch — when the classifier can't confidently pick, the CLI
|
|
31
|
+
* presents the full surface-area picker instead of applying a preset.
|
|
32
|
+
*/
|
|
33
|
+
export type AppKind = 'fitness' | 'social' | 'marketplace' | 'productivity' | 'education' | 'game' | 'dating' | 'content_creator' | 'ai_chatbot' | 'custom';
|
|
34
|
+
/**
|
|
35
|
+
* The surface areas (Amba primitives) a preset can opt into.
|
|
36
|
+
*
|
|
37
|
+
* `identity` is implicit in every preset — anonymous user provisioning is
|
|
38
|
+
* a precondition of every other surface — but listing it explicitly in
|
|
39
|
+
* `surfaces` makes the wire-up output self-describing.
|
|
40
|
+
*/
|
|
41
|
+
export type AmbaSurface = 'identity' | 'xp' | 'streaks' | 'achievements' | 'leaderboards' | 'currencies' | 'catalog' | 'stores' | 'inventory' | 'friendships' | 'groups' | 'feeds' | 'messaging' | 'moderation' | 'reviews' | 'push' | 'content' | 'referrals' | 'deeplinks' | 'segments' | 'onboarding' | 'ai_prompts';
|
|
42
|
+
/** The 6 SDK stacks for which we emit a copy-pasteable init snippet. */
|
|
43
|
+
export type SdkStack = 'expo' | 'reactNative' | 'web' | 'swift' | 'kotlin' | 'flutter';
|
|
44
|
+
export interface FollowUpOption {
|
|
45
|
+
value: string;
|
|
46
|
+
label: string;
|
|
47
|
+
/**
|
|
48
|
+
* Marks the option the CLI selects by default if the developer accepts
|
|
49
|
+
* the recommended answer without interaction. Exactly zero or one
|
|
50
|
+
* option per question carries this flag.
|
|
51
|
+
*/
|
|
52
|
+
recommended?: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface FollowUpQuestion {
|
|
55
|
+
/** The surface the answer mutates. Used by the wire-up engine to route. */
|
|
56
|
+
surface: AmbaSurface;
|
|
57
|
+
/**
|
|
58
|
+
* Stable identifier used to look up the answer in the wire-up engine.
|
|
59
|
+
* Tied to `WireUpAction.dependsOn` references.
|
|
60
|
+
*/
|
|
61
|
+
id: string;
|
|
62
|
+
question: string;
|
|
63
|
+
options: FollowUpOption[];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* A single MCP tool call the wire-up engine should issue.
|
|
67
|
+
*
|
|
68
|
+
* `args` mirrors the tool's zod input schema MINUS `project_id`, which
|
|
69
|
+
* the engine injects from the active project context — the developer
|
|
70
|
+
* never passes a project id at this layer.
|
|
71
|
+
*
|
|
72
|
+
* `dependsOn` is the id of a follow-up question whose answer mutates
|
|
73
|
+
* the action (e.g. leaderboard scope drives `metric` / `name`). The
|
|
74
|
+
* engine reads the answer, applies `whenAnswer` to transform `args`,
|
|
75
|
+
* and skips the action entirely if `whenAnswer` returns `null`.
|
|
76
|
+
*/
|
|
77
|
+
export interface WireUpAction {
|
|
78
|
+
tool: string;
|
|
79
|
+
args: Record<string, unknown>;
|
|
80
|
+
/**
|
|
81
|
+
* Optional follow-up dependency. The engine resolves the developer's
|
|
82
|
+
* answer to `dependsOn.id`, then calls `dependsOn.whenAnswer(value)`
|
|
83
|
+
* to produce the final args. Returning `null` means "skip this
|
|
84
|
+
* action for that answer."
|
|
85
|
+
*/
|
|
86
|
+
dependsOn?: {
|
|
87
|
+
id: string;
|
|
88
|
+
whenAnswer: (answer: string) => Record<string, unknown> | null;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
export interface SdkInitSnippets {
|
|
92
|
+
/** Expo (managed) — uses `@layers/amba-expo`. */
|
|
93
|
+
expo: string;
|
|
94
|
+
/** Bare React Native — uses `@layers/amba-react-native`. */
|
|
95
|
+
reactNative: string;
|
|
96
|
+
/** Browser / SSR — uses `@layers/amba-web`. */
|
|
97
|
+
web: string;
|
|
98
|
+
/** iOS / macOS / tvOS / watchOS — Swift Package Manager. */
|
|
99
|
+
swift: string;
|
|
100
|
+
/** Android — Maven Central artifact `com.layers.amba:amba-sdk-android`. */
|
|
101
|
+
kotlin: string;
|
|
102
|
+
/** Flutter / Dart — `amba` on pub.dev. */
|
|
103
|
+
flutter: string;
|
|
104
|
+
}
|
|
105
|
+
export interface AppKindPreset {
|
|
106
|
+
kind: AppKind;
|
|
107
|
+
label: string;
|
|
108
|
+
description: string;
|
|
109
|
+
/**
|
|
110
|
+
* Surfaces to enable. `identity` always appears first — every preset
|
|
111
|
+
* requires user identity. The order in the array is the order the
|
|
112
|
+
* wire-up engine renders to the developer (logical, not arbitrary).
|
|
113
|
+
*/
|
|
114
|
+
surfaces: AmbaSurface[];
|
|
115
|
+
/**
|
|
116
|
+
* Genuinely ambiguous choices the developer needs to make. Decisions
|
|
117
|
+
* with a clear default (e.g. "should we install identity?" — yes,
|
|
118
|
+
* always) are NOT follow-ups; they're baked into `wireUp.actions`.
|
|
119
|
+
*/
|
|
120
|
+
followUpQuestions: FollowUpQuestion[];
|
|
121
|
+
wireUp: {
|
|
122
|
+
actions: WireUpAction[];
|
|
123
|
+
sdkInit: SdkInitSnippets;
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Canonical preset registry. Lookup is by `AppKind`; iteration order is
|
|
128
|
+
* the order the CLI presents to the developer when classification is
|
|
129
|
+
* ambiguous and we fall back to a manual menu (alphabetical-ish by
|
|
130
|
+
* common usage, with `custom` last).
|
|
131
|
+
*/
|
|
132
|
+
export declare const PRESETS: Record<AppKind, AppKindPreset>;
|
|
133
|
+
/**
|
|
134
|
+
* Ordered list of the 9 non-custom presets. Useful when the CLI
|
|
135
|
+
* renders the "pick an app type" menu — `custom` is appended by the
|
|
136
|
+
* caller as the final escape-hatch option.
|
|
137
|
+
*/
|
|
138
|
+
export declare const PRESET_ORDER: readonly AppKind[];
|
|
139
|
+
/**
|
|
140
|
+
* Type-narrowing helper for the classifier output. Returns the preset
|
|
141
|
+
* verbatim when the kind is known; the caller is expected to surface a
|
|
142
|
+
* helpful error if classification produced a value outside the closed
|
|
143
|
+
* set (the type system blocks that in TypeScript, but the boundary
|
|
144
|
+
* between classifier-JSON and this module is a runtime trust check).
|
|
145
|
+
*/
|
|
146
|
+
export declare function getPreset(kind: AppKind): AppKindPreset;
|