@animaapp/cli 0.3.10 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -95,10 +95,13 @@ npx @animaapp/cli create -t p2c -p "E-commerce product page with cart"
95
95
  npx @animaapp/cli create -t l2c -u https://linear.app
96
96
  npx @animaapp/cli create -t f2c --file-key <key> --nodes 42:15
97
97
 
98
- # 3. Or bring YOUR OWN code: blank playground -> git push -> publish
99
- npx @animaapp/cli create -t blank --name "My project"
100
- npx @animaapp/cli get-git-token <sessionId> # then: git clone <url>, add code, git push
98
+ # 3. Or bring YOUR OWN code: import it in one step -> publish
99
+ npx @animaapp/cli create -t import --from ./my-project
101
100
  npx @animaapp/cli publish <sessionId>
101
+
102
+ # ...or start empty and push over git
103
+ npx @animaapp/cli create -t empty --framework react --name "My project"
104
+ npx @animaapp/cli get-git-token <sessionId> # then: git clone <url>, add code, git push
102
105
  ```
103
106
 
104
107
  ---
@@ -112,10 +115,12 @@ npx @animaapp/cli login
112
115
  npx @animaapp/cli login --client-name "My CI Agent" # label on the consent screen
113
116
  npx @animaapp/cli login --no-open # don't auto-open the browser
114
117
  npx @animaapp/cli login --print-mcp-config # also emit an MCP server config
118
+ npx @animaapp/cli login --invite <url-or-code> # redeem a pre-approved invite — no approval step
115
119
  ```
116
120
 
117
121
  | Option | Description | Default |
118
122
  |--------|-------------|---------|
123
+ | `--invite <url-or-code>` | Redeem an invite link (`…/invite/<code>.md`) or bare code. The human already approved when minting the invite, so there is no verification step — one call and you're connected. The invite URL's origin is persisted as the `api-url`, so follow-up commands target the right server with no flags | — |
119
124
  | `--client-name <name>` | How the CLI appears on the consent screen | `Anima CLI` |
120
125
  | `--no-open` | Don't try to open the verification page in a browser | — |
121
126
  | `--print-mcp-config` | One-shot: after this fresh login, also print the MCP server config. If you are already logged in, use `mcp-config` instead — this flag always starts a new login | off |
@@ -140,21 +145,25 @@ by `mcp-config` and `--print-mcp-config`.
140
145
  ### `create` — a playground for your code, or AI-generated
141
146
 
142
147
  ```bash
143
- npx @animaapp/cli create -t blank --name "My project" # EMPTY playground for your own code (instant)
148
+ npx @animaapp/cli create -t import --from ./my-project # import YOUR code (instant)
149
+ npx @animaapp/cli create -t empty --framework react --name "My project" # empty repo you push to (instant)
144
150
  npx @animaapp/cli create -t p2c -p "Analytics dashboard with a sidebar"
145
151
  npx @animaapp/cli create -t l2c -u https://stripe.com
146
152
  npx @animaapp/cli create -t f2c --file-key <key> --nodes 42:15
147
153
  ```
148
154
 
149
- `-t blank` is the upload path: it creates an empty playground and returns a
150
- `sessionId` — follow with `get-git-token <sessionId>`, `git clone`, add your
151
- code, and `git push`; then `publish <sessionId>` for a live URL. The other
152
- types are AI generation (3–7 min).
155
+ `-t import` is the one-step upload path: your folder (or .zip) becomes the
156
+ playground's first commit — small text-only projects are sent inline, larger
157
+ or binary ones are zipped and uploaded via a presigned URL automatically.
158
+ `-t empty` creates an empty repository instead: follow with `git clone` of the
159
+ returned URL, add your code, and `git push`. Then `publish <sessionId>` for a
160
+ live URL. The other types are AI generation (3–7 min).
153
161
 
154
162
  | Option | Values | Default |
155
163
  |--------|--------|---------|
156
- | `-t, --type` | `blank` (own code), `p2c` (prompt), `l2c` (URL), `f2c` (Figma) | _required_ |
157
- | `--name` | project name | _(blank)_ |
164
+ | `-t, --type` | `import` (your code, with `--from`), `empty` (repo to push to), `p2c` (prompt), `l2c` (URL), `f2c` (Figma) | _required_ |
165
+ | `--name` | project name | _(empty/import)_ |
166
+ | `--from` | folder or .zip to import | _(import)_ |
158
167
  | `-p, --prompt` | free text | _(p2c)_ |
159
168
  | `-u, --url` | website URL | _(l2c)_ |
160
169
  | `--file-key` | Figma file key or URL | _(f2c)_ |
@@ -225,15 +234,18 @@ secret, and re-mint rather than store it.
225
234
  npx @animaapp/cli logout
226
235
  ```
227
236
 
228
- Clears **all** stored credentials (Anima token, Figma token, agent metadata) and
229
- removes the config directory. This only forgets the token locally — to actually
230
- disable an agent, revoke it from your team settings.
237
+ A full local reset: clears **all** stored credentials (Anima token, Figma
238
+ token, agent metadata) **and the CLI config** (including an `api-url` persisted
239
+ by `login --invite`) — the machine ends up pristine, as if the CLI was never
240
+ used. This only forgets the token locally — to actually disable an agent,
241
+ revoke it from your team settings.
231
242
 
232
243
  ### `config` — store CLI preferences
233
244
 
234
245
  Persist non-secret settings to `~/.config/anima/config.json` so you don't have to
235
246
  pass flags every time — handy for pointing at a local API during development.
236
- Kept separate from credentials, so `logout` never touches it.
247
+ Note: `logout` removes this file too (full machine reset); `login --invite`
248
+ writes `api-url` automatically from the invite URL's origin.
237
249
 
238
250
  ```bash
239
251
  npx @animaapp/cli config set api-url http://localhost:3789
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import { Command as Command10 } from "commander";
5
5
 
6
6
  // src/commands/create.ts
7
7
  import { Command } from "commander";
8
+ import chalk2 from "chalk";
8
9
 
9
10
  // src/auth/store.ts
10
11
  import fs from "fs";
@@ -309,6 +310,7 @@ var ProgressReporter = class {
309
310
  start(message) {
310
311
  this.#startTime = Date.now();
311
312
  if (this.#mode === "pretty") {
313
+ this.#spinner?.stop();
312
314
  this.#spinner = ora(message).start();
313
315
  } else if (this.#verbose) {
314
316
  process.stderr.write(JSON.stringify({ status: "started", message }) + "\n");
@@ -428,6 +430,90 @@ function normalizeNodeId(nodeId) {
428
430
  return nodeId.replace(/-/g, ":");
429
431
  }
430
432
 
433
+ // src/utils/projectSource.ts
434
+ import { readdirSync, readFileSync, statSync } from "fs";
435
+ import { join, relative, extname } from "path";
436
+ import AdmZip from "adm-zip";
437
+ var SKIPPED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", "build", ".next", "out", "coverage", ".turbo", ".cache"]);
438
+ var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
439
+ ".png",
440
+ ".jpg",
441
+ ".jpeg",
442
+ ".gif",
443
+ ".webp",
444
+ ".ico",
445
+ ".bmp",
446
+ ".woff",
447
+ ".woff2",
448
+ ".ttf",
449
+ ".otf",
450
+ ".eot",
451
+ ".mp4",
452
+ ".webm",
453
+ ".mp3",
454
+ ".wav",
455
+ ".ogg",
456
+ ".zip",
457
+ ".tar",
458
+ ".gz",
459
+ ".pdf",
460
+ ".wasm"
461
+ ]);
462
+ var MAX_INLINE_FILES = 1e3;
463
+ var MAX_INLINE_BYTES = 10 * 1024 * 1024;
464
+ function walk(root, dir, out) {
465
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
466
+ if (entry.isDirectory()) {
467
+ if (!SKIPPED_DIRS.has(entry.name)) walk(root, join(dir, entry.name), out);
468
+ } else if (entry.isFile()) {
469
+ out.push(relative(root, join(dir, entry.name)));
470
+ }
471
+ }
472
+ }
473
+ function zipFolder(root) {
474
+ const zip = new AdmZip();
475
+ zip.addLocalFolder(root, "", (entryPath) => {
476
+ const segments = entryPath.split(/[\\/]/);
477
+ return !segments.some((segment) => SKIPPED_DIRS.has(segment));
478
+ });
479
+ return zip.toBuffer();
480
+ }
481
+ function isProbablyBinary(path5, buffer) {
482
+ if (BINARY_EXTENSIONS.has(extname(path5).toLowerCase())) return true;
483
+ return buffer.includes(0);
484
+ }
485
+ function collectProjectSource(fromPath) {
486
+ const stats = statSync(fromPath);
487
+ if (stats.isFile()) {
488
+ if (extname(fromPath).toLowerCase() !== ".zip") {
489
+ throw new Error(`--from must be a folder or a .zip file, got: ${fromPath}`);
490
+ }
491
+ return { kind: "zip", buffer: readFileSync(fromPath), reason: "zip file given" };
492
+ }
493
+ const paths = [];
494
+ walk(fromPath, fromPath, paths);
495
+ if (paths.length === 0) {
496
+ throw new Error(`--from folder is empty: ${fromPath}`);
497
+ }
498
+ if (paths.length > MAX_INLINE_FILES) {
499
+ return { kind: "zip", buffer: zipFolder(fromPath), reason: `${paths.length} files exceeds the inline limit` };
500
+ }
501
+ const files = {};
502
+ let totalBytes = 0;
503
+ for (const path5 of paths) {
504
+ const buffer = readFileSync(join(fromPath, path5));
505
+ if (isProbablyBinary(path5, buffer)) {
506
+ return { kind: "zip", buffer: zipFolder(fromPath), reason: `binary file present (${path5})` };
507
+ }
508
+ totalBytes += buffer.length;
509
+ if (totalBytes > MAX_INLINE_BYTES) {
510
+ return { kind: "zip", buffer: zipFolder(fromPath), reason: "project exceeds the inline size limit" };
511
+ }
512
+ files[path5.split("\\").join("/")] = buffer.toString("utf8");
513
+ }
514
+ return { kind: "files", files, fileCount: paths.length };
515
+ }
516
+
431
517
  // src/config/store.ts
432
518
  import fs3 from "fs";
433
519
  import path3 from "path";
@@ -458,6 +544,15 @@ function setConfig(key, value) {
458
544
  fs3.mkdirSync(CONFIG_DIR2, { recursive: true });
459
545
  fs3.writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2) + "\n");
460
546
  }
547
+ function deleteConfig() {
548
+ try {
549
+ if (!fs3.existsSync(CONFIG_FILE)) return false;
550
+ fs3.unlinkSync(CONFIG_FILE);
551
+ return true;
552
+ } catch {
553
+ return false;
554
+ }
555
+ }
461
556
  function unsetConfig(key) {
462
557
  const config = readConfig();
463
558
  const field = CONFIG_KEYS[key];
@@ -476,7 +571,15 @@ function resolveApiUrl(flagValue) {
476
571
 
477
572
  // src/commands/create.ts
478
573
  var PLAYGROUND_BASE = "https://dev.animaapp.com/chat";
479
- var createCommand = new Command("create").description("Create a playground: AI-generated (p2c/l2c/f2c, 3-7 min) or blank for your own code (instant)").requiredOption("-t, --type <type>", "p2c, l2c, f2c, or blank (empty playground \u2014 push your own code with get-git-token)").option("-p, --prompt <prompt>", "Text prompt (p2c)").option("-u, --url <url>", "Website URL (l2c)").option("--file-key <key>", "Figma file key or URL (f2c)").option("--nodes <nodes>", "Figma node IDs, comma-separated (f2c)").option("--figma-token <token>", "Figma personal access token (f2c)").option("--framework <fw>", "html | react \u2014 the only supported frameworks (default: html)").option("--styling <style>", "tailwind | css | plain_css | css_modules | inline_styles", "tailwind").option("--language <lang>", "typescript | javascript").option("--ui-library <lib>", "mui | antd | shadcn | clean_react").option("--guidelines <text>", "Additional constraints (p2c only)").option("--name <name>", "Project name (blank only)").option("--json", "Output as JSON").option("--timeout <ms>", "Timeout in milliseconds", "600000").option("--verbose", "Show progress on stderr").option("--api-url <url>", "API base URL (overrides config / ANIMA_API_URL)").option("--log-file <path>", "Append a JSON debug log of each step to this file").action(async (opts) => {
574
+ var createCommand = new Command("create").description(
575
+ "Create a playground: AI-generated (p2c/l2c/f2c, 3-7 min), empty for code you'll push (instant), or import your existing code (instant)"
576
+ ).requiredOption(
577
+ "-t, --type <type>",
578
+ "p2c, l2c, f2c, empty (empty repo you push to), or import (create FROM your code \u2014 use --from)"
579
+ ).option("-p, --prompt <prompt>", "Text prompt (p2c)").option("-u, --url <url>", "Website URL (l2c)").option("--file-key <key>", "Figma file key or URL (f2c)").option("--nodes <nodes>", "Figma node IDs, comma-separated (f2c)").option("--figma-token <token>", "Figma personal access token (f2c)").option(
580
+ "--framework <fw>",
581
+ "html | react \u2014 the only supported frameworks. REQUIRED for empty (declare react if you will push React code); detected from package.json for import"
582
+ ).option("--styling <style>", "tailwind | css | plain_css | css_modules | inline_styles", "tailwind").option("--language <lang>", "typescript | javascript").option("--ui-library <lib>", "mui | antd | shadcn | clean_react").option("--guidelines <text>", "Additional constraints (p2c only)").option("--name <name>", "Project name (empty/import only)").option("--from <path>", "Folder or .zip with your project (import only) \u2014 becomes the first commit").option("--json", "Output as JSON").option("--timeout <ms>", "Timeout in milliseconds", "600000").option("--verbose", "Show progress on stderr").option("--api-url <url>", "API base URL (overrides config / ANIMA_API_URL)").option("--log-file <path>", "Append a JSON debug log of each step to this file").action(async (opts) => {
480
583
  const mode = detectOutputMode(opts);
481
584
  initLogger(opts.logFile);
482
585
  const progress = new ProgressReporter(mode, opts.verbose);
@@ -486,40 +589,90 @@ var createCommand = new Command("create").description("Create a playground: AI-g
486
589
  const auth = resolveAuth();
487
590
  const figmaToken = type === "f2c" ? resolveFigmaToken(opts, auth.figmaToken) : void 0;
488
591
  const args = buildCreateArgs(type, opts);
489
- progress.start(type === "blank" ? "Creating blank playground..." : `Creating ${type.toUpperCase()} playground...`);
592
+ const mcpConfig = { apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId, figmaToken };
593
+ if (type === "import") {
594
+ progress.start("Collecting project files...");
595
+ const source = collectProjectSource(opts.from);
596
+ if (source.kind === "files") {
597
+ args.files = source.files;
598
+ } else {
599
+ progress.update(`Uploading project zip (${source.reason})...`);
600
+ const grant = await withMcp(
601
+ mcpConfig,
602
+ (client) => client.callTool("playground-get_zip_upload_url", {})
603
+ );
604
+ if (!grant.success || !grant.uploadUrl || !grant.zipUploadId) {
605
+ const message = grant.reason || grant.error || "Could not get a zip upload URL";
606
+ throw apiError(grant.nextSteps ? `${message}
607
+ ${grant.nextSteps}` : message, grant);
608
+ }
609
+ const putResponse = await fetch(grant.uploadUrl, {
610
+ method: "PUT",
611
+ body: new Uint8Array(source.buffer)
612
+ });
613
+ if (!putResponse.ok) {
614
+ throw apiError(`Zip upload failed: HTTP ${putResponse.status}`, { status: putResponse.status });
615
+ }
616
+ args.zipUploadId = grant.zipUploadId;
617
+ }
618
+ }
619
+ progress.start(
620
+ type === "empty" ? "Creating empty playground..." : type === "import" ? "Importing your project..." : `Creating ${type.toUpperCase()} playground...`
621
+ );
490
622
  const result = await withMcp(
491
- { apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId, figmaToken },
623
+ mcpConfig,
492
624
  (client) => client.callTool("playground-create", args, {
493
625
  timeoutMs: parseInt(opts.timeout, 10),
494
626
  onProgress: (p) => progress.update(p.message ?? `Generating (${Math.round(p.progress)}%)...`)
495
627
  })
496
628
  );
497
629
  if (!result.success || !result.sessionId) {
498
- throw apiError(result.reason || result.error || "Generation failed", result);
630
+ const message = result.reason || result.error || "Generation failed";
631
+ throw apiError(result.nextSteps ? `${message}
632
+ ${result.nextSteps}` : message, result);
499
633
  }
500
634
  const playgroundUrl = result.playgroundUrl || `${PLAYGROUND_BASE}/${result.sessionId}`;
501
635
  progress.succeed("Playground created!");
502
636
  if (mode === "pretty") {
503
637
  printSessionResult({ sessionId: result.sessionId, playgroundUrl });
504
638
  if (result.gitRemoteUrl) {
505
- console.log(` git clone ${result.gitRemoteUrl}`);
639
+ console.log(` ${chalk2.cyan(`git clone ${result.gitRemoteUrl}`)}`);
506
640
  console.log();
507
- console.log(
508
- ` Add your code, commit, and git push \u2014 the playground goes live. The URL embeds a token${result.expiresAt ? ` (expires ${result.expiresAt})` : ""}; when it expires, run anima get-git-token ${result.sessionId} and git remote set-url origin <new url>.`
509
- );
641
+ console.log(" Commit and push to update the live playground.");
642
+ if (result.expiresAt) {
643
+ console.log(
644
+ ` The URL embeds a token that expires at ${result.expiresAt} and cannot be renewed;
645
+ run ${chalk2.cyan(`anima get-git-token ${result.sessionId}`)} and ${chalk2.cyan("git remote set-url origin <new url>")} to keep pushing.`
646
+ );
647
+ }
648
+ console.log(" Treat the URL as a secret \u2014 it grants access to this playground.");
510
649
  console.log();
511
- } else if (type === "blank") {
650
+ } else if (type === "empty") {
512
651
  console.log(
513
652
  ` Next: anima get-git-token ${result.sessionId} \u2014 then git clone, add your code, and git push.`
514
653
  );
515
654
  console.log();
516
655
  }
656
+ if (type === "import" && result.fileCount !== void 0) {
657
+ console.log(` ${result.fileCount} files committed (framework: ${result.framework ?? "detected server-side"}).`);
658
+ if (result.skippedFiles?.length) {
659
+ console.log(` Skipped (blocked/hidden): ${result.skippedFiles.join(", ")}`);
660
+ }
661
+ if (result.notes) {
662
+ console.log(` Note: ${result.notes}`);
663
+ }
664
+ console.log();
665
+ }
517
666
  } else {
518
667
  outputResult(mode, {
519
668
  success: true,
520
669
  sessionId: result.sessionId,
521
670
  playgroundUrl,
522
671
  ...result.gitRemoteUrl ? { gitRemoteUrl: result.gitRemoteUrl, access: result.access, expiresAt: result.expiresAt } : {},
672
+ ...result.framework ? { framework: result.framework } : {},
673
+ ...result.fileCount !== void 0 ? { fileCount: result.fileCount } : {},
674
+ ...result.skippedFiles?.length ? { skippedFiles: result.skippedFiles } : {},
675
+ ...result.notes ? { notes: result.notes } : {},
523
676
  ...result.nextSteps ? { nextSteps: result.nextSteps } : {}
524
677
  });
525
678
  }
@@ -537,8 +690,8 @@ var createCommand = new Command("create").description("Create a playground: AI-g
537
690
  }
538
691
  });
539
692
  function validateCreateOptions(type, opts) {
540
- if (!["p2c", "l2c", "f2c", "blank"].includes(type)) {
541
- throw validationError(`Invalid type "${type}". Must be p2c, l2c, f2c, or blank.`);
693
+ if (!["p2c", "l2c", "f2c", "empty", "import"].includes(type)) {
694
+ throw validationError(`Invalid type "${type}". Must be p2c, l2c, f2c, empty, or import.`);
542
695
  }
543
696
  if (type === "p2c" && !opts.prompt) {
544
697
  throw validationError("--prompt is required for p2c type");
@@ -549,6 +702,17 @@ function validateCreateOptions(type, opts) {
549
702
  if (type === "f2c" && !opts.fileKey) {
550
703
  throw validationError("--file-key is required for f2c type");
551
704
  }
705
+ if (type === "empty" && !opts.framework) {
706
+ throw validationError(
707
+ "--framework is required for type empty \u2014 html for plain HTML/CSS/JS, react for React (declare react if you will push React code)"
708
+ );
709
+ }
710
+ if (type === "import" && !opts.from) {
711
+ throw validationError("--from <folder|zip> is required for type import \u2014 the path to the project to import");
712
+ }
713
+ if (type !== "import" && opts.from) {
714
+ throw validationError("--from is only valid with -t import");
715
+ }
552
716
  }
553
717
  function resolveFigmaToken(opts, stored) {
554
718
  const figmaToken = opts.figmaToken || process.env.FIGMA_TOKEN || stored;
@@ -560,10 +724,14 @@ function resolveFigmaToken(opts, stored) {
560
724
  return figmaToken;
561
725
  }
562
726
  function buildCreateArgs(type, opts) {
563
- const framework = opts.framework ?? "html";
564
- if (type === "blank") {
565
- return { type, framework, ...opts.name ? { name: opts.name } : {} };
727
+ if (type === "empty" || type === "import") {
728
+ return {
729
+ type,
730
+ ...opts.framework ? { framework: opts.framework } : {},
731
+ ...opts.name ? { name: opts.name } : {}
732
+ };
566
733
  }
734
+ const framework = opts.framework ?? "html";
567
735
  const language = opts.language ?? (framework === "react" ? "typescript" : void 0);
568
736
  const args = {
569
737
  type,
@@ -769,7 +937,7 @@ var codegenCommand = new Command3("codegen").description("Convert Figma design t
769
937
 
770
938
  // src/commands/getGitToken.ts
771
939
  import { Command as Command4 } from "commander";
772
- import chalk2 from "chalk";
940
+ import chalk3 from "chalk";
773
941
 
774
942
  // src/utils/playgroundUrl.ts
775
943
  function parsePlaygroundUrl(input) {
@@ -838,7 +1006,7 @@ var getGitTokenCommand = new Command4("get-git-token").description("Mint a short
838
1006
  progress.succeed(`Git access granted (${grant.access === "rw" ? "read-write" : "read-only"})`);
839
1007
  if (mode === "pretty") {
840
1008
  console.log();
841
- console.log(` ${chalk2.cyan(`git clone ${grant.gitRemoteUrl}`)}`);
1009
+ console.log(` ${chalk3.cyan(`git clone ${grant.gitRemoteUrl}`)}`);
842
1010
  console.log();
843
1011
  if (grant.access === "rw") {
844
1012
  console.log(" Commit and push to update the live playground.");
@@ -848,7 +1016,7 @@ var getGitTokenCommand = new Command4("get-git-token").description("Mint a short
848
1016
  if (grant.expiresAt) {
849
1017
  console.log(
850
1018
  ` The URL embeds a token that expires at ${grant.expiresAt} and cannot be renewed;
851
- re-run this command and ${chalk2.cyan("git remote set-url origin <new url>")} to keep pushing.`
1019
+ re-run this command and ${chalk3.cyan("git remote set-url origin <new url>")} to keep pushing.`
852
1020
  );
853
1021
  }
854
1022
  console.log(" Treat the URL as a secret \u2014 it grants access to this playground.");
@@ -881,7 +1049,7 @@ import { Command as Command6 } from "commander";
881
1049
 
882
1050
  // src/commands/login.ts
883
1051
  import { Command as Command5 } from "commander";
884
- import chalk3 from "chalk";
1052
+ import chalk4 from "chalk";
885
1053
  import open from "open";
886
1054
 
887
1055
  // src/auth/device.ts
@@ -1062,6 +1230,9 @@ var loginCommand = new Command5("login").description("Log in via the device flow
1062
1230
  const apiUrl2 = opts.apiUrl ? resolveApiUrl(opts.apiUrl) : inviteOrigin ?? resolveApiUrl();
1063
1231
  try {
1064
1232
  const result = await loginWithInvite({ apiUrl: apiUrl2, invite: opts.invite });
1233
+ if (inviteOrigin && readConfig().apiUrl !== apiUrl2) {
1234
+ setConfig("api-url", apiUrl2);
1235
+ }
1065
1236
  const mcpConfig = opts.printMcpConfig ? buildMcpConfig(apiUrl2, result.token) : void 0;
1066
1237
  if (mode === "pretty") {
1067
1238
  printSuccess("Connected!");
@@ -1111,9 +1282,9 @@ var loginCommand = new Command5("login").description("Log in via the device flow
1111
1282
  console.log();
1112
1283
  printInfo("To connect, open the verification page and enter this code:");
1113
1284
  console.log();
1114
- console.log(` ${chalk3.cyan.underline(info.verificationUri)}`);
1285
+ console.log(` ${chalk4.cyan.underline(info.verificationUri)}`);
1115
1286
  console.log();
1116
- console.log(` ${chalk3.bold.white(info.userCode)}`);
1287
+ console.log(` ${chalk4.bold.white(info.userCode)}`);
1117
1288
  console.log();
1118
1289
  printInfo(`Waiting for approval\u2026 (code expires in ${Math.round(info.expiresInSeconds / 60)} minutes)`);
1119
1290
  } else {
@@ -1221,7 +1392,7 @@ var mcpConfigCommand = new Command6("mcp-config").description("Print an MCP serv
1221
1392
 
1222
1393
  // src/commands/auth.ts
1223
1394
  import { Command as Command7 } from "commander";
1224
- import chalk4 from "chalk";
1395
+ import chalk5 from "chalk";
1225
1396
  var DEFAULT_API_URL2 = "https://public-api.animaapp.com";
1226
1397
  var authCommand = new Command7("auth").description("Manage authentication").option("--token <token>", "Store Anima API token").option("--figma-token <token>", "Store Figma personal access token").option("--team-id <teamId>", "Team ID to associate with token").option("--status", "Show current auth status").option("--logout", "Clear stored credentials (alias for `anima logout`)").option("--json", "Output as JSON").option("--api-url <url>", "API base URL", DEFAULT_API_URL2).action(async (opts) => {
1227
1398
  const mode = detectOutputMode(opts);
@@ -1310,12 +1481,12 @@ var authCommand = new Command7("auth").description("Manage authentication").opti
1310
1481
  if (mode === "pretty") {
1311
1482
  console.log();
1312
1483
  printInfo("Auth commands:");
1313
- console.log(` ${chalk4.cyan("anima login")} Log in (device flow \u2014 approve on any browser)`);
1314
- console.log(` ${chalk4.cyan("anima logout")} Clear all credentials`);
1315
- console.log(` ${chalk4.cyan("anima auth --status")} Check auth status`);
1316
- console.log(` ${chalk4.cyan("anima auth --figma-token <T>")} Save Figma token (needed for codegen/f2c)`);
1484
+ console.log(` ${chalk5.cyan("anima login")} Log in (device flow \u2014 approve on any browser)`);
1485
+ console.log(` ${chalk5.cyan("anima logout")} Clear all credentials`);
1486
+ console.log(` ${chalk5.cyan("anima auth --status")} Check auth status`);
1487
+ console.log(` ${chalk5.cyan("anima auth --figma-token <T>")} Save Figma token (needed for codegen/f2c)`);
1317
1488
  console.log();
1318
- console.log(` Figma token: ${chalk4.cyan.underline("https://www.figma.com")} > Settings > Personal access tokens`);
1489
+ console.log(` Figma token: ${chalk5.cyan.underline("https://www.figma.com")} > Settings > Personal access tokens`);
1319
1490
  console.log();
1320
1491
  } else {
1321
1492
  outputResult(mode, {
@@ -1341,6 +1512,7 @@ import { Command as Command8 } from "commander";
1341
1512
  var logoutCommand = new Command8("logout").description("Clear all stored credentials (Anima + Figma tokens) from this machine").option("--json", "Output as JSON").action((opts) => {
1342
1513
  const mode = detectOutputMode(opts);
1343
1514
  const hadCredentials = clearStorage();
1515
+ deleteConfig();
1344
1516
  if (mode === "pretty") {
1345
1517
  if (hadCredentials) {
1346
1518
  printSuccess("Logged out \u2014 all credentials cleared from " + getCredentialsPath());
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/create.ts","../src/auth/store.ts","../src/api/errors.ts","../src/auth/token.ts","../src/api/mcp.ts","../src/output/log.ts","../src/version.ts","../src/output/formatter.ts","../src/output/progress.ts","../src/output/pretty.ts","../src/utils/figma.ts","../src/config/store.ts","../src/commands/publish.ts","../src/commands/codegen.ts","../src/utils/files.ts","../src/commands/getGitToken.ts","../src/utils/playgroundUrl.ts","../src/utils/gitToken.ts","../src/commands/mcpConfig.ts","../src/commands/login.ts","../src/auth/device.ts","../src/auth/invite.ts","../src/commands/auth.ts","../src/commands/logout.ts","../src/commands/config.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { createCommand } from \"./commands/create.js\";\nimport { publishCommand } from \"./commands/publish.js\";\nimport { codegenCommand } from \"./commands/codegen.js\";\nimport { getGitTokenCommand } from \"./commands/getGitToken.js\";\nimport { mcpConfigCommand } from \"./commands/mcpConfig.js\";\nimport { authCommand } from \"./commands/auth.js\";\nimport { loginCommand } from \"./commands/login.js\";\nimport { logoutCommand } from \"./commands/logout.js\";\nimport { configCommand } from \"./commands/config.js\";\nimport { CliError } from \"./api/errors.js\";\n\n// Version comes from package.json so `--version` always matches the published\n// build (shared with the MCP clientInfo).\nimport { version } from \"./version.js\";\n\nconst program = new Command()\n .name(\"anima\")\n .description(\n `Anima CLI - Generate production-ready apps from prompts, URLs, or Figma designs.\n\nAUTHENTICATION:\n Run: npx @animaapp/cli login\n Approve in a browser on any device — the CLI receives a scoped agent token\n (stored in ~/.config/anima/). CI/automation can set ANIMA_API_TOKEN instead.\n\nTIMING (important for AI agents):\n create → 3-7 minutes (keep the default 600000ms timeout)\n publish → 1-3 minutes\n codegen → 2-5 minutes\n get-git-token → seconds\n The --timeout default is 600000ms (10 min). Do NOT reduce it.\n\nCOMMANDS:\n login Log in via the device flow (no browser needed on this machine)\n logout Clear all stored credentials from this machine\n mcp-config Print an MCP server config from stored credentials (no new login)\n create Create app from prompt, URL, or Figma design\n publish Deploy playground to live URL or npm package\n codegen Convert Figma design to code files (no playground)\n get-git-token Mint a git remote URL for a playground; clone/edit/push with git\n config Store CLI preferences (e.g. a default API URL)\n auth Inspect or manage credentials (status / figma token)\n\nEXAMPLES:\n npx @animaapp/cli login\n npx @animaapp/cli create -t p2c -p \"SaaS dashboard with sidebar and analytics\"\n npx @animaapp/cli create -t l2c -u https://stripe.com\n npx @animaapp/cli create -t f2c --file-key abc --nodes 42:15\n npx @animaapp/cli publish abc123xyz\n npx @animaapp/cli codegen --file-key abc --nodes 42:15 -o ./components\n npx @animaapp/cli get-git-token https://dev.animaapp.com/chat/abc123xyz\n\nOUTPUT: JSON to stdout when piped (for AI tools), pretty text in terminals.\n Progress is streamed to stderr via --verbose when in JSON mode.`\n )\n .version(version, \"-v, --version\");\n\nprogram.addCommand(loginCommand);\nprogram.addCommand(logoutCommand);\nprogram.addCommand(createCommand);\nprogram.addCommand(publishCommand);\nprogram.addCommand(codegenCommand);\nprogram.addCommand(getGitTokenCommand);\nprogram.addCommand(mcpConfigCommand);\nprogram.addCommand(configCommand);\nprogram.addCommand(authCommand);\n\nprogram.parseAsync(process.argv).catch((err) => {\n if (err instanceof CliError) {\n if (process.stdout.isTTY) {\n console.error(err.message);\n } else {\n process.stdout.write(\n JSON.stringify({\n success: false,\n error: { code: err.code, message: err.message },\n }) + \"\\n\"\n );\n }\n process.exit(err.exitCode);\n }\n\n console.error(err);\n process.exit(1);\n});\n","import { Command } from \"commander\";\nimport { resolveAuth } from \"../auth/token.js\";\nimport { withMcp } from \"../api/mcp.js\";\nimport { detectOutputMode, outputResult, outputError } from \"../output/formatter.js\";\nimport { ProgressReporter } from \"../output/progress.js\";\nimport { initLogger } from \"../output/log.js\";\nimport { printSessionResult } from \"../output/pretty.js\";\nimport { parseFigmaUrl, normalizeNodeId } from \"../utils/figma.js\";\nimport { resolveApiUrl } from \"../config/store.js\";\nimport { validationError, apiError, CliError } from \"../api/errors.js\";\nimport type { CreateType } from \"../api/types.js\";\n\nconst PLAYGROUND_BASE = \"https://dev.animaapp.com/chat\";\n\ntype CreateResult = {\n success: boolean;\n sessionId?: string;\n playgroundUrl?: string;\n nextSteps?: string;\n // Since the server's inline-git-token change, playground-create also mints a\n // rw git token in the same response — clone immediately, no second call.\n gitRemoteUrl?: string;\n access?: \"ro\" | \"rw\";\n expiresAt?: string;\n error?: string;\n reason?: string;\n};\n\nexport const createCommand = new Command(\"create\")\n .description(\"Create a playground: AI-generated (p2c/l2c/f2c, 3-7 min) or blank for your own code (instant)\")\n .requiredOption(\"-t, --type <type>\", \"p2c, l2c, f2c, or blank (empty playground — push your own code with get-git-token)\")\n .option(\"-p, --prompt <prompt>\", \"Text prompt (p2c)\")\n .option(\"-u, --url <url>\", \"Website URL (l2c)\")\n .option(\"--file-key <key>\", \"Figma file key or URL (f2c)\")\n .option(\"--nodes <nodes>\", \"Figma node IDs, comma-separated (f2c)\")\n .option(\"--figma-token <token>\", \"Figma personal access token (f2c)\")\n .option(\"--framework <fw>\", \"html | react — the only supported frameworks (default: html)\")\n .option(\"--styling <style>\", \"tailwind | css | plain_css | css_modules | inline_styles\", \"tailwind\")\n .option(\"--language <lang>\", \"typescript | javascript\")\n .option(\"--ui-library <lib>\", \"mui | antd | shadcn | clean_react\")\n .option(\"--guidelines <text>\", \"Additional constraints (p2c only)\")\n .option(\"--name <name>\", \"Project name (blank only)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--timeout <ms>\", \"Timeout in milliseconds\", \"600000\")\n .option(\"--verbose\", \"Show progress on stderr\")\n .option(\"--api-url <url>\", \"API base URL (overrides config / ANIMA_API_URL)\")\n .option(\"--log-file <path>\", \"Append a JSON debug log of each step to this file\")\n .action(async (opts) => {\n const mode = detectOutputMode(opts);\n initLogger(opts.logFile);\n const progress = new ProgressReporter(mode, opts.verbose);\n\n try {\n const type = opts.type as CreateType;\n validateCreateOptions(type, opts);\n\n const auth = resolveAuth();\n const figmaToken = type === \"f2c\" ? resolveFigmaToken(opts, auth.figmaToken) : undefined;\n const args = buildCreateArgs(type, opts);\n\n progress.start(type === \"blank\" ? \"Creating blank playground...\" : `Creating ${type.toUpperCase()} playground...`);\n\n const result = await withMcp(\n { apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId, figmaToken },\n (client) =>\n client.callTool<CreateResult>(\"playground-create\", args, {\n timeoutMs: parseInt(opts.timeout, 10),\n onProgress: (p) => progress.update(p.message ?? `Generating (${Math.round(p.progress)}%)...`),\n })\n );\n\n if (!result.success || !result.sessionId) {\n throw apiError(result.reason || result.error || \"Generation failed\", result);\n }\n\n const playgroundUrl = result.playgroundUrl || `${PLAYGROUND_BASE}/${result.sessionId}`;\n\n progress.succeed(\"Playground created!\");\n\n if (mode === \"pretty\") {\n printSessionResult({ sessionId: result.sessionId, playgroundUrl });\n if (result.gitRemoteUrl) {\n console.log(` git clone ${result.gitRemoteUrl}`);\n console.log();\n console.log(\n ` Add your code, commit, and git push — the playground goes live. The URL embeds a` +\n ` token${result.expiresAt ? ` (expires ${result.expiresAt})` : \"\"}; when it expires,` +\n ` run anima get-git-token ${result.sessionId} and git remote set-url origin <new url>.`\n );\n console.log();\n } else if (type === \"blank\") {\n console.log(\n ` Next: anima get-git-token ${result.sessionId} — then git clone, add your code, and git push.`\n );\n console.log();\n }\n } else {\n outputResult(mode, {\n success: true,\n sessionId: result.sessionId,\n playgroundUrl,\n ...(result.gitRemoteUrl\n ? { gitRemoteUrl: result.gitRemoteUrl, access: result.access, expiresAt: result.expiresAt }\n : {}),\n ...(result.nextSteps ? { nextSteps: result.nextSteps } : {}),\n });\n }\n } catch (err) {\n progress.fail(\"Failed\");\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n console.error(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n process.exit(err.exitCode);\n }\n throw err;\n }\n });\n\nfunction validateCreateOptions(type: CreateType, opts: Record<string, string>): void {\n if (![\"p2c\", \"l2c\", \"f2c\", \"blank\"].includes(type)) {\n throw validationError(`Invalid type \"${type}\". Must be p2c, l2c, f2c, or blank.`);\n }\n if (type === \"p2c\" && !opts.prompt) {\n throw validationError(\"--prompt is required for p2c type\");\n }\n if (type === \"l2c\" && !opts.url) {\n throw validationError(\"--url is required for l2c type\");\n }\n if (type === \"f2c\" && !opts.fileKey) {\n throw validationError(\"--file-key is required for f2c type\");\n }\n}\n\nfunction resolveFigmaToken(opts: Record<string, string>, stored?: string): string {\n const figmaToken = opts.figmaToken || process.env.FIGMA_TOKEN || stored;\n if (!figmaToken) {\n throw validationError(\n \"Figma token required for f2c. Use --figma-token, set FIGMA_TOKEN env var, or run: anima auth --figma-token <token>\\n\" +\n \"Get one at: https://www.figma.com > Settings > Personal access tokens\"\n );\n }\n return figmaToken;\n}\n\nfunction buildCreateArgs(type: CreateType, opts: Record<string, string>): Record<string, unknown> {\n // Always sent: the server requires framework for blank (declare what\n // you'll push), and html is the default for every type — aligned with the\n // MCP playground-create surface. Only html and react are supported.\n const framework = opts.framework ?? \"html\";\n if (type === \"blank\") {\n return { type, framework, ...(opts.name ? { name: opts.name } : {}) };\n }\n // Default language to typescript when framework is react (matches the web import form).\n const language = opts.language ?? (framework === \"react\" ? \"typescript\" : undefined);\n\n const args: Record<string, unknown> = {\n type,\n framework,\n styling: opts.styling,\n };\n if (language) args.language = language;\n if (opts.uiLibrary) args.uiLibrary = opts.uiLibrary;\n\n switch (type) {\n case \"p2c\":\n args.prompt = opts.prompt;\n if (opts.guidelines) args.guidelines = opts.guidelines;\n break;\n case \"l2c\":\n args.url = opts.url;\n break;\n case \"f2c\": {\n const { fileKey, nodeId: parsedNodeId } = parseFigmaUrl(opts.fileKey);\n let nodesId: string[] = [];\n if (opts.nodes) {\n nodesId = opts.nodes.split(\",\").map((n) => normalizeNodeId(n.trim()));\n } else if (parsedNodeId) {\n nodesId = [parsedNodeId];\n }\n args.fileKey = fileKey;\n args.nodesId = nodesId;\n break;\n }\n }\n\n return args;\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\nconst CONFIG_DIR = path.join(os.homedir(), \".config\", \"anima\");\nconst CREDENTIALS_FILE = path.join(CONFIG_DIR, \"credentials.json\");\n\ntype Credentials = {\n token: string;\n teamId?: string;\n figmaToken?: string;\n // Set by the device login: a scoped, revocable AGENT token — never to be\n // confused with a personal API token (which carries the user's full\n // authority and is not governed by workspace scopes).\n tokenType?: \"agent\" | \"personal\";\n agentId?: string;\n expiresAt?: string; // ISO — agent tokens expire (~7 days); re-run the login\n};\n\nexport function readCredentials(): Credentials | null {\n try {\n if (!fs.existsSync(CREDENTIALS_FILE)) return null;\n const content = fs.readFileSync(CREDENTIALS_FILE, \"utf-8\");\n const parsed = JSON.parse(content);\n if (!parsed.token) return null;\n return parsed;\n } catch {\n return null;\n }\n}\n\nexport function writeCredentials(credentials: Partial<Credentials>): void {\n // Merge with existing credentials so we can update fields independently\n const existing = readCredentials() ?? {};\n const merged = { ...existing, ...credentials };\n\n // Remove undefined values\n for (const key of Object.keys(merged) as (keyof Credentials)[]) {\n if (merged[key] === undefined) delete merged[key];\n }\n\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n fs.writeFileSync(\n CREDENTIALS_FILE,\n JSON.stringify(merged, null, 2) + \"\\n\",\n { mode: 0o600 }\n );\n}\n\nexport function deleteCredentials(): boolean {\n try {\n if (fs.existsSync(CREDENTIALS_FILE)) {\n fs.unlinkSync(CREDENTIALS_FILE);\n return true;\n }\n return false;\n } catch {\n return false;\n }\n}\n\n/**\n * Full logout: remove every stored token (all live in credentials.json) and\n * the config directory itself when nothing else is left in it. Returns whether\n * any credentials were present.\n */\nexport function clearStorage(): boolean {\n const had = deleteCredentials();\n try {\n if (fs.existsSync(CONFIG_DIR) && fs.readdirSync(CONFIG_DIR).length === 0) {\n fs.rmdirSync(CONFIG_DIR);\n }\n } catch {\n /* leaving an empty dir behind is harmless */\n }\n return had;\n}\n\nexport function getCredentialsPath(): string {\n return CREDENTIALS_FILE;\n}\n\n/**\n * Extract the defaultTeamId from a JWT token payload (base64-decoded, no verification).\n * Returns undefined if extraction fails.\n */\nexport function extractTeamIdFromJWT(token: string): string | undefined {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) return undefined;\n const payload = JSON.parse(\n Buffer.from(parts[1], \"base64url\").toString(\"utf-8\")\n );\n return payload.defaultTeamId ?? undefined;\n } catch {\n return undefined;\n }\n}\n","export const EXIT_CODES = {\n SUCCESS: 0,\n API_ERROR: 1,\n AUTH_ERROR: 2,\n VALIDATION_ERROR: 3,\n TIMEOUT: 4,\n} as const;\n\nexport type ErrorCode =\n | \"AUTH_REQUIRED\"\n | \"AUTH_INVALID\"\n | \"VALIDATION_ERROR\"\n | \"API_ERROR\"\n | \"TIMEOUT\"\n | \"CONNECTION_ERROR\";\n\nexport class CliError extends Error {\n code: ErrorCode;\n exitCode: number;\n detail?: unknown;\n\n constructor(\n code: ErrorCode,\n message: string,\n exitCode: number,\n detail?: unknown\n ) {\n super(message);\n this.name = \"CliError\";\n this.code = code;\n this.exitCode = exitCode;\n this.detail = detail;\n }\n}\n\nexport function authError(message: string): CliError {\n return new CliError(\"AUTH_REQUIRED\", message, EXIT_CODES.AUTH_ERROR);\n}\n\nexport function validationError(message: string, detail?: unknown): CliError {\n return new CliError(\n \"VALIDATION_ERROR\",\n message,\n EXIT_CODES.VALIDATION_ERROR,\n detail\n );\n}\n\nexport function apiError(message: string, detail?: unknown): CliError {\n return new CliError(\"API_ERROR\", message, EXIT_CODES.API_ERROR, detail);\n}\n\nexport function timeoutError(): CliError {\n return new CliError(\n \"TIMEOUT\",\n \"Request timed out. Generation can take 3-7 minutes. Try increasing --timeout.\",\n EXIT_CODES.TIMEOUT\n );\n}\n","import { readCredentials } from \"./store.js\";\nimport { authError } from \"../api/errors.js\";\n\nexport type ResolvedAuth = {\n token: string;\n teamId?: string;\n figmaToken?: string;\n source: \"env\" | \"file\";\n tokenType?: \"agent\" | \"personal\";\n};\n\nexport function resolveAuth(): ResolvedAuth {\n const creds = readCredentials();\n\n // 1. Environment variable (primary — what AI tools use)\n const envToken = process.env.ANIMA_API_TOKEN;\n if (envToken) {\n return {\n token: envToken,\n teamId: process.env.ANIMA_TEAM_ID,\n figmaToken: process.env.FIGMA_TOKEN || creds?.figmaToken,\n source: \"env\",\n };\n }\n\n // 2. Stored credentials file\n if (creds) {\n // Agent tokens expire (~7 days); renewal is a fresh device login, which\n // reconnects to the same agent when the same name is approved.\n if (creds.tokenType === \"agent\" && creds.expiresAt && new Date(creds.expiresAt) <= new Date()) {\n throw authError(\"Your agent token has expired. Run: anima login\");\n }\n return {\n token: creds.token,\n teamId: creds.teamId,\n figmaToken: process.env.FIGMA_TOKEN || creds.figmaToken,\n source: \"file\",\n tokenType: creds.tokenType,\n };\n }\n\n // 3. No token found\n throw authError(\"No credentials found. Run: anima login\\n(or set the ANIMA_API_TOKEN env var)\");\n}\n","import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { CallToolResultSchema, ErrorCode } from \"@modelcontextprotocol/sdk/types.js\";\nimport { apiError, timeoutError, CliError } from \"./errors.js\";\nimport { logEvent } from \"../output/log.js\";\nimport { version } from \"../version.js\";\n\n/**\n * The CLI talks to Anima only through the MCP endpoint (`/v1/mcp`), the single\n * governed surface (see anima-design-to-code docs/grids/DECISIONS.md \"D47\").\n * Every command runs a tool through this client — there is no other transport.\n */\n\nconst MCP_PATH = \"/v1/mcp\";\n// MCP clientInfo version tracks package.json so server logs see the real release.\nconst CLIENT_INFO = { name: \"anima-cli\", version };\n\nexport type McpConfig = {\n apiBaseUrl: string;\n token: string;\n teamId?: string;\n /** Sent as X-Figma-Token; f2c tools read it from the header, not the args. */\n figmaToken?: string;\n};\n\n/** Progress reported by long-running tools (generation, deploy). */\nexport type ToolProgress = { progress: number; total?: number; message?: string };\n\nexport type CallToolOptions = {\n onProgress?: (p: ToolProgress) => void;\n /** Idle timeout; reset on each progress notification so long jobs don't trip it. */\n timeoutMs?: number;\n};\n\nconst DEFAULT_TIMEOUT_MS = 600_000;\n\nexport class AnimaMcpClient {\n #client: Client;\n #transport: StreamableHTTPClientTransport;\n #url: string;\n\n constructor(config: McpConfig) {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${config.token}`,\n };\n if (config.teamId) headers[\"X-Team-Id\"] = config.teamId;\n if (config.figmaToken) headers[\"X-Figma-Token\"] = config.figmaToken;\n\n this.#url = new URL(MCP_PATH, config.apiBaseUrl).toString();\n this.#transport = new StreamableHTTPClientTransport(new URL(this.#url), {\n requestInit: { headers },\n });\n this.#client = new Client(CLIENT_INFO, { capabilities: {} });\n }\n\n async connect(): Promise<void> {\n logEvent(\"mcp_connect\", { url: this.#url });\n try {\n await this.#client.connect(this.#transport);\n } catch (err) {\n logEvent(\"mcp_connect_failed\", { url: this.#url, error: (err as Error)?.message });\n throw connectionError(err);\n }\n }\n\n /**\n * Call a tool and return its parsed result. Anima tools return a single JSON\n * text block; a `{ success: false }` payload is a normal result, so callers\n * still inspect `success` themselves.\n */\n async callTool<T = unknown>(\n name: string,\n args: Record<string, unknown>,\n options: CallToolOptions = {}\n ): Promise<T> {\n logEvent(\"mcp_tool_call\", { tool: name, arguments: args });\n let result;\n try {\n result = await this.#client.callTool(\n { name, arguments: args },\n CallToolResultSchema,\n {\n timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n resetTimeoutOnProgress: true,\n onprogress: options.onProgress\n ? (p) => options.onProgress!({ progress: p.progress, total: p.total, message: p.message })\n : undefined,\n }\n );\n } catch (err) {\n logEvent(\"mcp_tool_error\", { tool: name, error: (err as Error)?.message });\n if ((err as { code?: number })?.code === ErrorCode.RequestTimeout) {\n throw timeoutError();\n }\n throw err;\n }\n logEvent(\"mcp_tool_result\", { tool: name, isError: result.isError ?? false });\n\n const content = Array.isArray(result.content) ? result.content : [];\n const text = content.find((c): c is { type: \"text\"; text: string } => c.type === \"text\")?.text;\n\n if (result.isError) {\n throw apiError(text || \"MCP tool returned an error\");\n }\n if (!text) {\n throw apiError(\"MCP tool returned no text content\");\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n return text as T;\n }\n }\n\n async close(): Promise<void> {\n await this.#transport.close().catch(() => {});\n }\n}\n\n/** Connect, run `fn`, and always close the transport. */\nexport async function withMcp<T>(\n config: McpConfig,\n fn: (client: AnimaMcpClient) => Promise<T>\n): Promise<T> {\n const client = new AnimaMcpClient(config);\n await client.connect();\n try {\n return await fn(client);\n } finally {\n await client.close();\n }\n}\n\nfunction connectionError(err: unknown): CliError {\n const message = err instanceof Error ? err.message : String(err);\n return new CliError(\n \"CONNECTION_ERROR\",\n `Could not reach the Anima MCP endpoint: ${message}`,\n 1\n );\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Opt-in debug log. When a command is given `--log-file <path>` (or the\n * ANIMA_LOG_FILE env var is set), every network step appends one JSON line to\n * that file. Off by default and a no-op until enabled, so it never touches\n * stdout/stderr. Secret-bearing keys (tokens, auth headers) are redacted.\n *\n * Writes are synchronous (appendFileSync) so nothing is lost when a command\n * ends with process.exit() on an error path.\n */\n\nlet logPath: string | null = null;\n\nconst REDACT_KEY = /token|authorization|secret|password|_auth|api[-_]?key/i;\nconst REDACTED = \"***REDACTED***\";\n\nexport function initLogger(filePath?: string): void {\n const target = filePath || process.env.ANIMA_LOG_FILE;\n if (!target || logPath) return;\n logPath = path.resolve(target);\n fs.mkdirSync(path.dirname(logPath), { recursive: true });\n logEvent(\"log_started\", { pid: process.pid, argv: process.argv.slice(2) });\n}\n\nexport function logEvent(event: string, data?: Record<string, unknown>): void {\n if (!logPath) return;\n const entry = { ts: new Date().toISOString(), event, ...(data ? redact(data) : {}) };\n fs.appendFileSync(logPath, JSON.stringify(entry) + \"\\n\");\n}\n\nfunction redact(value: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value)) {\n if (REDACT_KEY.test(key)) {\n out[key] = REDACTED;\n } else if (val && typeof val === \"object\" && !Array.isArray(val)) {\n out[key] = redact(val as Record<string, unknown>);\n } else {\n out[key] = val;\n }\n }\n return out;\n}\n","import { createRequire } from \"node:module\";\n\n// Single source for the CLI version: package.json. `../package.json` resolves\n// from src/ in dev and from dist/index.js in the published bundle — this file\n// must stay directly under src/ for that to hold.\nexport const { version } = createRequire(import.meta.url)(\"../package.json\") as { version: string };\n","export type OutputMode = \"json\" | \"pretty\";\n\nexport function detectOutputMode(flags: {\n json?: boolean;\n}): OutputMode {\n if (flags.json !== undefined) {\n return flags.json ? \"json\" : \"pretty\";\n }\n // Auto-detect: JSON when piped, pretty in TTY\n return process.stdout.isTTY ? \"pretty\" : \"json\";\n}\n\nexport function outputResult(mode: OutputMode, data: unknown): void {\n if (mode === \"json\") {\n process.stdout.write(JSON.stringify(data) + \"\\n\");\n }\n // Pretty mode output is handled inline by commands using chalk/ora\n}\n\nexport function outputError(\n mode: OutputMode,\n error: { code: string; message: string }\n): void {\n if (mode === \"json\") {\n process.stdout.write(\n JSON.stringify({ success: false, error }) + \"\\n\"\n );\n }\n // Pretty mode errors are handled inline by commands\n}\n","import ora, { type Ora } from \"ora\";\nimport type { OutputMode } from \"./formatter.js\";\n\nexport class ProgressReporter {\n #spinner: Ora | null = null;\n #mode: OutputMode;\n #startTime: number = 0;\n #verbose: boolean;\n\n constructor(mode: OutputMode, verbose: boolean = false) {\n this.#mode = mode;\n this.#verbose = verbose;\n }\n\n start(message: string): void {\n this.#startTime = Date.now();\n if (this.#mode === \"pretty\") {\n this.#spinner = ora(message).start();\n } else if (this.#verbose) {\n process.stderr.write(JSON.stringify({ status: \"started\", message }) + \"\\n\");\n }\n }\n\n update(message: string): void {\n if (this.#mode === \"pretty\" && this.#spinner) {\n const elapsed = this.#elapsed();\n this.#spinner.text = `${message} ${elapsed}`;\n } else if (this.#verbose) {\n process.stderr.write(JSON.stringify({ status: \"progress\", message }) + \"\\n\");\n }\n }\n\n succeed(message: string): void {\n if (this.#mode === \"pretty\" && this.#spinner) {\n const elapsed = this.#elapsed();\n this.#spinner.succeed(`${message} ${elapsed}`);\n } else if (this.#verbose) {\n process.stderr.write(JSON.stringify({ status: \"done\", message }) + \"\\n\");\n }\n this.#spinner = null;\n }\n\n fail(message: string): void {\n if (this.#mode === \"pretty\" && this.#spinner) {\n this.#spinner.fail(message);\n } else if (this.#verbose) {\n process.stderr.write(JSON.stringify({ status: \"error\", message }) + \"\\n\");\n }\n this.#spinner = null;\n }\n\n #elapsed(): string {\n const ms = Date.now() - this.#startTime;\n const seconds = Math.floor(ms / 1000);\n if (seconds < 60) return `(${seconds}s)`;\n const minutes = Math.floor(seconds / 60);\n const secs = seconds % 60;\n return `(${minutes}m ${secs}s)`;\n }\n}\n","import chalk from \"chalk\";\n\nexport function printSuccess(message: string): void {\n console.log(chalk.green(\"✓\") + \" \" + message);\n}\n\nexport function printError(message: string): void {\n console.error(chalk.red(\"✗\") + \" \" + message);\n}\n\nexport function printInfo(message: string): void {\n console.log(chalk.blue(\"ℹ\") + \" \" + message);\n}\n\nexport function printWarning(message: string): void {\n console.log(chalk.yellow(\"⚠\") + \" \" + message);\n}\n\nexport function printKeyValue(key: string, value: string): void {\n console.log(` ${chalk.gray(key + \":\")} ${value}`);\n}\n\nexport function printSessionResult(result: {\n sessionId: string;\n playgroundUrl?: string;\n tokenUsage?: number;\n}): void {\n console.log();\n printSuccess(\"Playground created successfully!\");\n printKeyValue(\"Session ID\", result.sessionId);\n if (result.playgroundUrl) {\n printKeyValue(\"Playground\", chalk.cyan.underline(result.playgroundUrl));\n }\n if (result.tokenUsage) {\n printKeyValue(\"Token usage\", result.tokenUsage.toLocaleString());\n }\n console.log();\n}\n\nexport function printDeployResult(result: {\n url?: string;\n packageUrl?: string;\n packageName?: string;\n packageVersion?: string;\n}): void {\n console.log();\n printSuccess(\"Published successfully!\");\n if (result.url) {\n printKeyValue(\"Live URL\", chalk.cyan.underline(result.url));\n }\n if (result.packageName) {\n printKeyValue(\"Package\", result.packageName);\n printKeyValue(\"Version\", result.packageVersion ?? \"\");\n if (result.packageUrl) {\n printKeyValue(\"URL\", chalk.cyan.underline(result.packageUrl));\n }\n }\n console.log();\n}\n\nexport function printFilesWritten(outputDir: string, count: number): void {\n console.log();\n printSuccess(`${count} files written to ${chalk.cyan(outputDir)}`);\n console.log();\n}\n","/**\n * Parse a Figma URL to extract fileKey and nodeId.\n *\n * Supported formats:\n * - https://www.figma.com/file/ABC123/FileName?node-id=42-15\n * - https://www.figma.com/design/ABC123/FileName?node-id=42-15\n * - https://figma.com/file/ABC123/FileName?node-id=42%3A15\n * - Just a fileKey string\n */\nexport function parseFigmaUrl(input: string): {\n fileKey: string;\n nodeId?: string;\n} {\n // If it doesn't look like a URL, treat as a raw file key\n if (!input.includes(\"figma.com\")) {\n return { fileKey: input };\n }\n\n try {\n const url = new URL(input);\n const pathParts = url.pathname.split(\"/\").filter(Boolean);\n\n // Expected format: /file/KEY/name or /design/KEY/name\n const typeIndex = pathParts.findIndex(\n (p) => p === \"file\" || p === \"design\"\n );\n if (typeIndex === -1 || typeIndex + 1 >= pathParts.length) {\n throw new Error(\"Could not find file key in Figma URL\");\n }\n\n const fileKey = pathParts[typeIndex + 1];\n const nodeIdParam = url.searchParams.get(\"node-id\");\n\n let nodeId: string | undefined;\n if (nodeIdParam) {\n // Convert dash format (42-15) to colon format (42:15)\n nodeId = nodeIdParam.replace(/-/g, \":\");\n }\n\n return { fileKey, nodeId };\n } catch (err) {\n if (err instanceof Error && err.message.includes(\"file key\")) {\n throw err;\n }\n throw new Error(`Invalid Figma URL: ${input}`);\n }\n}\n\n/**\n * Normalize a node ID: convert dash format to colon format.\n * \"42-15\" -> \"42:15\"\n */\nexport function normalizeNodeId(nodeId: string): string {\n return nodeId.replace(/-/g, \":\");\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\n/**\n * Persistent, non-secret CLI preferences (e.g. a default API URL for local\n * development). Kept separate from credentials.json so `anima logout` never\n * wipes your machine config. Manage it with `anima config`.\n */\n\nconst CONFIG_DIR = path.join(os.homedir(), \".config\", \"anima\");\nconst CONFIG_FILE = path.join(CONFIG_DIR, \"config.json\");\n\nexport const DEFAULT_API_URL = \"https://public-api.animaapp.com\";\n\nexport type Config = {\n apiUrl?: string;\n};\n\n/** User-facing config keys (kebab) mapped to their stored (camel) field. */\nexport const CONFIG_KEYS = {\n \"api-url\": \"apiUrl\",\n} as const satisfies Record<string, keyof Config>;\n\nexport type ConfigKey = keyof typeof CONFIG_KEYS;\n\nexport function isConfigKey(key: string): key is ConfigKey {\n return key in CONFIG_KEYS;\n}\n\nexport function configKeys(): ConfigKey[] {\n return Object.keys(CONFIG_KEYS) as ConfigKey[];\n}\n\nexport function readConfig(): Config {\n try {\n if (!fs.existsSync(CONFIG_FILE)) return {};\n const parsed = JSON.parse(fs.readFileSync(CONFIG_FILE, \"utf-8\"));\n return parsed && typeof parsed === \"object\" ? parsed : {};\n } catch {\n return {};\n }\n}\n\nexport function setConfig(key: ConfigKey, value: string): void {\n const merged = { ...readConfig(), [CONFIG_KEYS[key]]: value };\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n fs.writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2) + \"\\n\");\n}\n\n/** Remove one key; returns whether it was set. */\nexport function unsetConfig(key: ConfigKey): boolean {\n const config = readConfig();\n const field = CONFIG_KEYS[key];\n if (!(field in config)) return false;\n delete config[field];\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + \"\\n\");\n return true;\n}\n\nexport function getConfigPath(): string {\n return CONFIG_FILE;\n}\n\n/**\n * Resolve the API base URL. Precedence: explicit flag → ANIMA_API_URL env →\n * stored config → built-in default.\n */\nexport function resolveApiUrl(flagValue?: string): string {\n return flagValue || process.env.ANIMA_API_URL || readConfig().apiUrl || DEFAULT_API_URL;\n}\n","import { Command } from \"commander\";\nimport { resolveAuth } from \"../auth/token.js\";\nimport { withMcp } from \"../api/mcp.js\";\nimport { detectOutputMode, outputResult, outputError } from \"../output/formatter.js\";\nimport { ProgressReporter } from \"../output/progress.js\";\nimport { initLogger } from \"../output/log.js\";\nimport { printDeployResult } from \"../output/pretty.js\";\nimport { resolveApiUrl } from \"../config/store.js\";\nimport { validationError, CliError } from \"../api/errors.js\";\n\nexport const publishCommand = new Command(\"publish\")\n .description(\"Deploy playground to live URL or npm package (1-3 min)\")\n .argument(\"<sessionId>\", \"Session ID from create command\")\n .option(\"--mode <mode>\", \"webapp | designSystem\", \"webapp\")\n .option(\"--package-name <name>\", \"NPM package name (designSystem mode)\")\n .option(\"--package-version <version>\", \"NPM package version (designSystem mode)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--verbose\", \"Show progress on stderr\")\n .option(\"--api-url <url>\", \"API base URL (overrides config / ANIMA_API_URL)\")\n .option(\"--log-file <path>\", \"Append a JSON debug log of each step to this file\")\n .action(async (sessionId: string, opts) => {\n const mode = detectOutputMode(opts);\n initLogger(opts.logFile);\n const progress = new ProgressReporter(mode, opts.verbose);\n\n try {\n if (![\"webapp\", \"designSystem\"].includes(opts.mode)) {\n throw validationError(\n `Invalid mode \"${opts.mode}\". Must be webapp or designSystem.`\n );\n }\n\n if (opts.mode === \"designSystem\" && !opts.packageName) {\n throw validationError(\"--package-name is required for designSystem mode\");\n }\n\n const auth = resolveAuth();\n\n const args: Record<string, unknown> = {\n sessionId,\n mode: opts.mode,\n };\n if (opts.packageName) args.packageName = opts.packageName;\n if (opts.packageVersion) args.packageVersion = opts.packageVersion;\n\n progress.start(`Publishing as ${opts.mode}...`);\n\n const result = await withMcp(\n { apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId },\n (client) =>\n client.callTool<Record<string, unknown>>(\"playground-publish\", args, {\n onProgress: (p) => progress.update(p.message ?? \"Publishing...\"),\n })\n );\n\n if (!result.success) {\n throw new CliError(\n \"API_ERROR\",\n (result.error as string) || (result.reason as string) || \"Publish failed\",\n 1,\n result\n );\n }\n\n progress.succeed(\"Published!\");\n\n if (mode === \"pretty\") {\n printDeployResult({\n url: result.liveUrl as string | undefined,\n packageUrl: result.packageUrl as string | undefined,\n packageName: result.packageName as string | undefined,\n packageVersion: result.packageVersion as string | undefined,\n });\n } else {\n outputResult(mode, {\n success: true,\n sessionId,\n ...(result.liveUrl ? { liveUrl: result.liveUrl, subdomain: result.subdomain } : {}),\n ...(result.packageName\n ? {\n packageName: result.packageName,\n packageVersion: result.packageVersion,\n packageUrl: result.packageUrl,\n }\n : {}),\n });\n }\n } catch (err) {\n progress.fail(\"Failed\");\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n console.error(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n process.exit(err.exitCode);\n }\n throw err;\n }\n });\n","import { Command } from \"commander\";\nimport { resolveAuth } from \"../auth/token.js\";\nimport { withMcp } from \"../api/mcp.js\";\nimport { detectOutputMode, outputResult, outputError } from \"../output/formatter.js\";\nimport { ProgressReporter } from \"../output/progress.js\";\nimport { initLogger } from \"../output/log.js\";\nimport { printFilesWritten } from \"../output/pretty.js\";\nimport { parseFigmaUrl, normalizeNodeId } from \"../utils/figma.js\";\nimport { writeFilesToDisk } from \"../utils/files.js\";\nimport { resolveApiUrl } from \"../config/store.js\";\nimport { validationError, apiError, CliError } from \"../api/errors.js\";\nimport type { AnimaFiles } from \"../api/types.js\";\n\ntype CodegenResult = {\n success: boolean;\n sessionId?: string;\n files?: AnimaFiles;\n tokenUsage?: number;\n error?: string;\n reason?: string;\n};\n\nexport const codegenCommand = new Command(\"codegen\")\n .description(\"Convert Figma design to code files (no playground)\")\n .requiredOption(\"--file-key <key>\", \"Figma file key or URL\")\n .option(\"--nodes <nodes>\", \"Figma node IDs, comma-separated\")\n .option(\"--figma-token <token>\", \"Figma personal access token (or set FIGMA_TOKEN env var)\")\n .option(\"-o, --output <dir>\", \"Output directory\", \"./generated\")\n .option(\"--framework <fw>\", \"react | html\", \"react\")\n .option(\"--styling <style>\", \"tailwind | plain_css\", \"tailwind\")\n .option(\"--language <lang>\", \"typescript | javascript\")\n .option(\"--ui-library <lib>\", \"mui | antd | shadcn | clean_react\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--timeout <ms>\", \"Timeout in milliseconds\", \"600000\")\n .option(\"--verbose\", \"Show progress on stderr\")\n .option(\"--api-url <url>\", \"API base URL (overrides config / ANIMA_API_URL)\")\n .option(\"--log-file <path>\", \"Append a JSON debug log of each step to this file\")\n .action(async (opts) => {\n const mode = detectOutputMode(opts);\n initLogger(opts.logFile);\n const progress = new ProgressReporter(mode, opts.verbose);\n\n try {\n const { fileKey, nodeId: parsedNodeId } = parseFigmaUrl(opts.fileKey);\n let nodesId: string[] = [];\n if (opts.nodes) {\n nodesId = opts.nodes.split(\",\").map((n: string) => normalizeNodeId(n.trim()));\n } else if (parsedNodeId) {\n nodesId = [parsedNodeId];\n }\n\n if (nodesId.length === 0) {\n throw validationError(\n \"No node IDs provided. Use --nodes or include node-id in the Figma URL.\"\n );\n }\n\n const auth = resolveAuth();\n\n // Resolve Figma token: flag > env var > stored credentials > error.\n // Sent via the X-Figma-Token header; the tool reads it from the header.\n const figmaToken = opts.figmaToken || process.env.FIGMA_TOKEN || auth.figmaToken;\n if (!figmaToken) {\n throw validationError(\n \"Figma token required. Use --figma-token, set FIGMA_TOKEN env var, or run: anima auth --figma-token <token>\\n\" +\n \"Get one at: https://www.figma.com > Settings > Personal access tokens\"\n );\n }\n\n // Default language to typescript when framework is react.\n const language = opts.language ?? (opts.framework === \"react\" ? \"typescript\" : undefined);\n\n const args: Record<string, unknown> = {\n fileKey,\n nodesId,\n framework: opts.framework,\n styling: opts.styling,\n };\n if (language) args.language = language;\n if (opts.uiLibrary) args.uiLibrary = opts.uiLibrary;\n\n progress.start(\"Generating code from Figma...\");\n\n const result = await withMcp(\n { apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId, figmaToken },\n (client) =>\n client.callTool<CodegenResult>(\"codegen-figma_to_code\", args, {\n timeoutMs: parseInt(opts.timeout, 10),\n onProgress: (p) => progress.update(p.message ?? `Generating (${Math.round(p.progress)}%)...`),\n })\n );\n\n if (!result.success || !result.files) {\n throw apiError(result.reason || result.error || \"Code generation failed\", result);\n }\n\n const count = writeFilesToDisk(result.files, opts.output);\n\n progress.succeed(`Generated ${count} files`);\n\n if (mode === \"pretty\") {\n printFilesWritten(opts.output, count);\n } else {\n outputResult(mode, {\n success: true,\n output: opts.output,\n fileCount: count,\n sessionId: result.sessionId,\n tokenUsage: result.tokenUsage,\n });\n }\n } catch (err) {\n progress.fail(\"Failed\");\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n console.error(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n process.exit(err.exitCode);\n }\n throw err;\n }\n });\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { AnimaFiles } from \"../api/types.js\";\n\n/**\n * Write generated files to disk.\n * Handles both code (text) and binary (base64-encoded) files.\n */\nexport function writeFilesToDisk(\n files: AnimaFiles,\n outputDir: string\n): number {\n // Create output directory\n fs.mkdirSync(outputDir, { recursive: true });\n\n let count = 0;\n\n const resolvedOutput = path.resolve(outputDir);\n\n for (const [filePath, fileContent] of Object.entries(files)) {\n const fullPath = path.resolve(outputDir, filePath);\n\n if (!fullPath.startsWith(resolvedOutput + path.sep)) {\n throw new Error(`Path traversal detected: ${filePath}`);\n }\n\n // Create parent directories\n const dirPath = path.dirname(fullPath);\n fs.mkdirSync(dirPath, { recursive: true });\n\n if (fileContent.isBinary) {\n const buffer = Buffer.from(fileContent.content, \"base64\");\n fs.writeFileSync(fullPath, buffer);\n } else {\n fs.writeFileSync(fullPath, fileContent.content, \"utf-8\");\n }\n\n count++;\n }\n\n return count;\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { resolveAuth } from \"../auth/token.js\";\nimport { withMcp } from \"../api/mcp.js\";\nimport { detectOutputMode, outputResult, outputError } from \"../output/formatter.js\";\nimport { ProgressReporter } from \"../output/progress.js\";\nimport { initLogger, logEvent } from \"../output/log.js\";\nimport { parsePlaygroundUrl } from \"../utils/playgroundUrl.js\";\nimport { parseGitTokenResponse } from \"../utils/gitToken.js\";\nimport { resolveApiUrl } from \"../config/store.js\";\nimport { CliError } from \"../api/errors.js\";\n\n/**\n * Mirror of the `project-get_git_token` MCP tool — git is the only content\n * plane for playground code. This mints a short-lived, repo-scoped git remote\n * URL; the caller runs git itself:\n *\n * git clone <gitRemoteUrl> # read (and edit locally)\n * git push # rw access: updates the live playground\n * git remote set-url origin <url> # after expiry: point the clone at a fresh URL\n *\n * The token expires within an hour and cannot be renewed — re-run this command\n * for a fresh URL.\n */\nexport const getGitTokenCommand = new Command(\"get-git-token\")\n .description(\"Mint a short-lived git remote URL for a playground (clone/push with git)\")\n .argument(\"<playgroundUrl>\", \"Playground URL or session ID\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--verbose\", \"Show progress on stderr\")\n .option(\"--api-url <url>\", \"API base URL (overrides config / ANIMA_API_URL)\")\n .option(\"--log-file <path>\", \"Append a JSON debug log of each step to this file\")\n .action(async (playgroundUrl: string, opts) => {\n const mode = detectOutputMode(opts);\n initLogger(opts.logFile);\n const progress = new ProgressReporter(mode, opts.verbose);\n\n try {\n const sessionId = parsePlaygroundUrl(playgroundUrl);\n const auth = resolveAuth();\n\n progress.start(\"Requesting git access...\");\n\n const response = await withMcp(\n { apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId },\n (client) =>\n client.callTool<unknown>(\"project-get_git_token\", { sessionId })\n );\n\n const grant = parseGitTokenResponse(response);\n logEvent(\"git_token_granted\", { sessionId, access: grant.access, expiresAt: grant.expiresAt });\n\n progress.succeed(`Git access granted (${grant.access === \"rw\" ? \"read-write\" : \"read-only\"})`);\n\n if (mode === \"pretty\") {\n console.log();\n console.log(` ${chalk.cyan(`git clone ${grant.gitRemoteUrl}`)}`);\n console.log();\n if (grant.access === \"rw\") {\n console.log(\" Commit and push to update the live playground.\");\n } else {\n console.log(\" Read-only: cloning works, pushing will be rejected.\");\n }\n if (grant.expiresAt) {\n console.log(\n ` The URL embeds a token that expires at ${grant.expiresAt} and cannot be renewed;\\n` +\n ` re-run this command and ${chalk.cyan(\"git remote set-url origin <new url>\")} to keep pushing.`\n );\n }\n console.log(\" Treat the URL as a secret — it grants access to this playground.\");\n console.log();\n } else {\n outputResult(mode, {\n success: true,\n sessionId,\n gitRemoteUrl: grant.gitRemoteUrl,\n access: grant.access,\n expiresAt: grant.expiresAt,\n });\n }\n } catch (err) {\n progress.fail(\"Failed\");\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n console.error(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n process.exit(err.exitCode);\n }\n throw err;\n }\n });\n","/**\n * Parse a playground URL to extract the session ID.\n * Supported formats:\n * - https://dev.animaapp.com/chat/SESSION_ID\n * - Just a session ID string\n */\nexport function parsePlaygroundUrl(input: string): string {\n if (!input.includes(\"/\")) {\n return input;\n }\n\n try {\n const url = new URL(input);\n const parts = url.pathname.split(\"/\").filter(Boolean);\n // Expected: /chat/SESSION_ID\n const chatIndex = parts.indexOf(\"chat\");\n if (chatIndex !== -1 && chatIndex + 1 < parts.length) {\n return parts[chatIndex + 1];\n }\n // Fallback: last path segment\n return parts[parts.length - 1];\n } catch {\n // Not a URL, treat as session ID\n return input;\n }\n}\n","import { apiError } from \"../api/errors.js\";\n\n/**\n * Parsed outcome of the `project-get_git_token` MCP tool.\n *\n * The tool returns JSON: `{ success, gitRemoteUrl, access, expiresAt }` on a\n * grant, or `{ success: false, error, reason }` on a denial. The MCP client\n * (api/mcp.ts) already JSON-parses tool text, so this receives the parsed\n * object — a string only arrives if that parse failed. The clone URL embeds a\n * short-lived access token scoped to the one playground.\n */\nexport type GitTokenGrant = {\n gitRemoteUrl: string;\n access: \"ro\" | \"rw\";\n expiresAt?: string;\n};\n\nfunction preview(payload: unknown): string {\n const text = typeof payload === \"string\" ? payload : JSON.stringify(payload);\n return (text ?? String(payload)).slice(0, 200);\n}\n\nexport function parseGitTokenResponse(payload: unknown): GitTokenGrant {\n let value = payload;\n if (typeof value === \"string\") {\n try {\n value = JSON.parse(value);\n } catch {\n throw apiError(`Unexpected response from project-get_git_token: ${preview(payload)}`);\n }\n }\n\n if (value === null || typeof value !== \"object\") {\n throw apiError(`Unexpected response from project-get_git_token: ${preview(payload)}`);\n }\n\n const body = value as {\n success?: boolean;\n error?: string;\n reason?: string;\n gitRemoteUrl?: string;\n access?: string;\n expiresAt?: string;\n };\n\n if (body.success === false) {\n throw apiError(`Git access ${body.error ?? \"denied\"}: ${(body.reason ?? \"\").trim()}`);\n }\n\n if (!body.gitRemoteUrl) {\n throw apiError(`Unexpected response from project-get_git_token: ${preview(payload)}`);\n }\n\n return {\n gitRemoteUrl: body.gitRemoteUrl,\n access: body.access === \"rw\" ? \"rw\" : \"ro\",\n expiresAt: body.expiresAt,\n };\n}\n","import { Command } from \"commander\";\nimport { resolveAuth } from \"../auth/token.js\";\nimport { readCredentials } from \"../auth/store.js\";\nimport { buildMcpConfig } from \"./login.js\";\nimport { detectOutputMode, outputResult, outputError } from \"../output/formatter.js\";\nimport { printInfo } from \"../output/pretty.js\";\nimport { resolveApiUrl } from \"../config/store.js\";\nimport { CliError } from \"../api/errors.js\";\n\n/**\n * Print the MCP server config from EXISTING credentials — no network, no new\n * device flow. This is the \"I'm already logged in, give me my config\" command\n * the /connect guide's Step 2 points at; `login --print-mcp-config` remains\n * the one-shot variant (fresh login, then print).\n */\nexport const mcpConfigCommand = new Command(\"mcp-config\")\n .description(\"Print an MCP server config from your stored credentials (run `login` first)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--api-url <url>\", \"API base URL (overrides config / ANIMA_API_URL)\")\n .action(async (opts) => {\n const mode = detectOutputMode(opts);\n\n try {\n // Resolution + expiry checks live in resolveAuth: env token → stored\n // credentials (expired agent token → clear \"run anima login\" error).\n const auth = resolveAuth();\n const creds = readCredentials();\n const expiresAt = auth.source === \"env\" ? undefined : creds?.expiresAt;\n\n const mcpConfig = buildMcpConfig(resolveApiUrl(opts.apiUrl), auth.token);\n\n if (mode === \"pretty\") {\n printInfo(\"MCP server config (add to your MCP client; the token is a secret):\");\n console.log();\n console.log(JSON.stringify(mcpConfig, null, 2));\n console.log();\n if (expiresAt) {\n printInfo(`Token expires ${expiresAt} — run \\`anima login\\` then \\`anima mcp-config\\` to refresh.`);\n }\n } else {\n outputResult(mode, {\n success: true,\n mcpConfig,\n ...(expiresAt ? { expiresAt } : {}),\n ...(creds?.agentId && auth.source !== \"env\" ? { agentId: creds.agentId } : {}),\n });\n }\n } catch (err) {\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n console.error(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n process.exit(err.exitCode);\n }\n throw err;\n }\n });\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport open from \"open\";\nimport { loginWithDeviceFlow } from \"../auth/device.js\";\nimport { loginWithInvite, parseInvite } from \"../auth/invite.js\";\nimport { getCredentialsPath } from \"../auth/store.js\";\nimport { initLogger } from \"../output/log.js\";\nimport { resolveApiUrl } from \"../config/store.js\";\nimport { detectOutputMode, outputResult, outputError } from \"../output/formatter.js\";\nimport { printSuccess, printError, printKeyValue, printInfo } from \"../output/pretty.js\";\nimport { CliError } from \"../api/errors.js\";\n\n/**\n * `anima login` — connect this machine as a governed agent.\n *\n * Two doors, one credential store:\n * - Default: the OAuth device flow. The command prints a short code and a\n * verification URL; a human approves on any device — choosing which\n * workspaces and capabilities this agent gets — and the CLI picks up its\n * scoped token automatically.\n * - `--invite <url-or-code>`: redeem a pre-approved invite (the human already\n * consented in-app when minting it) — a single exchange, no human step and\n * no browser.\n * Either way the token expires after ~7 days; logging in again with the same\n * agent name reconnects to the same agent identity.\n */\nexport const loginCommand = new Command(\"login\")\n .description(\"Log in via the device flow, or redeem a pre-approved invite with --invite\")\n .option(\"--invite <url-or-code>\", \"Redeem an invite link (…/invite/<code>.md) or bare code — no approval step\")\n .option(\"--client-name <name>\", \"How this CLI appears on the consent screen\", \"Anima CLI\")\n .option(\"--no-open\", \"Do not try to open the verification page in a browser\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--api-url <url>\", \"API base URL (overrides config / ANIMA_API_URL)\")\n .option(\"--log-file <path>\", \"Append a JSON debug log of each step to this file\")\n .option(\n \"--print-mcp-config\",\n \"After login, also print an MCP server config (includes the token) to paste into an MCP-capable agent\"\n )\n .action(async (opts) => {\n const mode = detectOutputMode(opts);\n initLogger(opts.logFile);\n\n if (opts.invite) {\n // The invite URL was minted on the API the human used, so its origin is\n // the right base unless the caller explicitly overrides it.\n const inviteOrigin = parseInvite(opts.invite).origin;\n const apiUrl = opts.apiUrl ? resolveApiUrl(opts.apiUrl) : (inviteOrigin ?? resolveApiUrl());\n\n try {\n const result = await loginWithInvite({ apiUrl, invite: opts.invite });\n const mcpConfig = opts.printMcpConfig ? buildMcpConfig(apiUrl, result.token) : undefined;\n\n if (mode === \"pretty\") {\n printSuccess(\"Connected!\");\n printKeyValue(\"Credentials\", getCredentialsPath());\n if (result.agentId) printKeyValue(\"Agent\", result.agentId);\n if (result.teamId) printKeyValue(\"Team ID\", result.teamId);\n if (result.expiresAt) printKeyValue(\"Token expires\", result.expiresAt);\n printInfo(\"This is a scoped agent token — it acts within what was approved, and the team can revoke it.\");\n if (mcpConfig) {\n console.log();\n printInfo(\"MCP server config (token expires ~7 days — a fresh invite renews it):\");\n console.log();\n console.log(JSON.stringify(mcpConfig, null, 2));\n }\n } else {\n outputResult(mode, {\n success: true,\n action: \"logged_in\",\n via: \"invite\",\n tokenType: \"agent\",\n agentId: result.agentId,\n teamId: result.teamId,\n expiresAt: result.expiresAt,\n ...(mcpConfig ? { mcpConfig } : {}),\n });\n }\n } catch (err) {\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n printError(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n process.exit(err.exitCode);\n }\n throw err;\n }\n return;\n }\n\n const apiUrl = resolveApiUrl(opts.apiUrl);\n\n try {\n const result = await loginWithDeviceFlow({\n apiUrl,\n clientName: opts.clientName,\n onVerification: (info) => {\n if (mode === \"pretty\") {\n console.log();\n printInfo(\"To connect, open the verification page and enter this code:\");\n console.log();\n console.log(` ${chalk.cyan.underline(info.verificationUri)}`);\n console.log();\n console.log(` ${chalk.bold.white(info.userCode)}`);\n console.log();\n printInfo(`Waiting for approval… (code expires in ${Math.round(info.expiresInSeconds / 60)} minutes)`);\n } else {\n // JSON mode: emit the verification info to stderr so a wrapping\n // agent can surface it to its human while stdout stays reserved\n // for the final result object.\n process.stderr.write(\n JSON.stringify({\n event: \"verification_required\",\n verificationUri: info.verificationUri,\n verificationUriComplete: info.verificationUriComplete,\n userCode: info.userCode,\n expiresIn: info.expiresInSeconds,\n }) + \"\\n\"\n );\n }\n\n // Best-effort convenience in a terminal; the printed URL + code are\n // the real path (the whole point of the flow is that THIS machine\n // may have no browser).\n if (mode === \"pretty\" && opts.open) {\n open(info.verificationUriComplete).catch(() => {});\n }\n },\n });\n\n const mcpConfig = opts.printMcpConfig ? buildMcpConfig(apiUrl, result.token) : undefined;\n\n if (mode === \"pretty\") {\n printSuccess(\"Connected!\");\n printKeyValue(\"Credentials\", getCredentialsPath());\n if (result.agentId) printKeyValue(\"Agent\", result.agentId);\n if (result.teamId) printKeyValue(\"Team ID\", result.teamId);\n if (result.expiresAt) printKeyValue(\"Token expires\", result.expiresAt);\n printInfo(\"This is a scoped agent token — it acts within what you approved, and your team can revoke it.\");\n if (mcpConfig) {\n console.log();\n printInfo(\"MCP server config (token expires ~7 days — re-run `anima login` to refresh):\");\n console.log();\n console.log(JSON.stringify(mcpConfig, null, 2));\n }\n } else {\n outputResult(mode, {\n success: true,\n action: \"logged_in\",\n tokenType: \"agent\",\n agentId: result.agentId,\n teamId: result.teamId,\n expiresAt: result.expiresAt,\n ...(mcpConfig ? { mcpConfig } : {}),\n });\n }\n } catch (err) {\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n printError(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n process.exit(err.exitCode);\n }\n throw err;\n }\n });\n\n/**\n * A remote MCP server entry an MCP-capable agent can add to talk to Anima\n * directly (no CLI in the loop). Exact keys vary by client; this is the common\n * `mcpServers` shape with a bearer header. The URL honors --api-url/config so a\n * local login yields a local config.\n */\nexport function buildMcpConfig(apiUrl: string, token: string) {\n return {\n mcpServers: {\n anima: {\n type: \"http\",\n url: `${apiUrl.replace(/\\/$/, \"\")}/v1/mcp`,\n headers: { Authorization: `Bearer ${token}` },\n },\n },\n };\n}\n","import { writeCredentials } from \"./store.js\";\nimport { authError, CliError, EXIT_CODES } from \"../api/errors.js\";\nimport { logEvent } from \"../output/log.js\";\n\n/**\n * OAuth 2.0 Device Authorization Grant (RFC 8628) against the Anima\n * authorization server. The flow needs no browser on this machine: the server\n * returns a short human code, the human approves at the verification URL (any\n * device), and this client polls the token endpoint until the decision lands.\n *\n * The issued token is a scoped AGENT token: it acts within the workspaces and\n * capabilities the human approved on the consent screen, and the team can\n * revoke it at any time. It expires after ~7 days; renewal is simply running\n * the flow again (re-approval reconnects to the same agent when the same\n * agent name is kept).\n */\n\nconst DEVICE_GRANT_TYPE = \"urn:ietf:params:oauth:grant-type:device_code\";\nconst DEFAULT_CLIENT_NAME = \"Anima CLI\";\n\nexport type DeviceVerificationInfo = {\n userCode: string;\n verificationUri: string;\n verificationUriComplete: string;\n expiresInSeconds: number;\n};\n\nexport type DeviceLoginResult = {\n token: string;\n teamId?: string;\n agentId?: string;\n expiresAt?: string;\n};\n\ntype DeviceLoginOptions = {\n apiUrl: string;\n clientName?: string;\n /** Called once with the code the human must enter — the caller renders it. */\n onVerification: (info: DeviceVerificationInfo) => void;\n /** Injectable for tests. */\n fetchFn?: typeof fetch;\n sleepFn?: (ms: number) => Promise<void>;\n};\n\nconst defaultSleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));\n\n/** Decode a JWT payload without verification (display/bookkeeping only). */\nfunction decodeJwtPayload(token: string): Record<string, unknown> | undefined {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) return undefined;\n return JSON.parse(Buffer.from(parts[1], \"base64url\").toString(\"utf-8\"));\n } catch {\n return undefined;\n }\n}\n\nexport async function loginWithDeviceFlow(options: DeviceLoginOptions): Promise<DeviceLoginResult> {\n const fetchFn = options.fetchFn ?? fetch;\n const sleep = options.sleepFn ?? defaultSleep;\n const base = options.apiUrl.replace(/\\/$/, \"\");\n\n // Step 1 — start the flow. No client registration: the server namespaces\n // device-flow agents itself; client_name is display-only on the consent page.\n const startUrl = `${base}/oauth/device_authorization`;\n logEvent(\"device_authorization_request\", { url: startUrl });\n const startResponse = await fetchFn(startUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({ client_name: options.clientName ?? DEFAULT_CLIENT_NAME }).toString(),\n });\n logEvent(\"device_authorization_response\", { url: startUrl, status: startResponse.status });\n\n if (!startResponse.ok) {\n const detail = await startResponse.text().catch(() => \"\");\n logEvent(\"device_authorization_failed\", { url: startUrl, status: startResponse.status, body: detail.slice(0, 500) });\n const hint =\n startResponse.status === 404\n ? ` — no device endpoint at ${startUrl}. Check --api-url points to an API that has the device grant deployed.`\n : \"\";\n throw new CliError(\n \"API_ERROR\",\n `Device authorization failed (HTTP ${startResponse.status})${hint}`,\n EXIT_CODES.API_ERROR\n );\n }\n\n const start = (await startResponse.json()) as {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n expires_in: number;\n interval: number;\n };\n\n options.onVerification({\n userCode: start.user_code,\n verificationUri: start.verification_uri,\n verificationUriComplete: start.verification_uri_complete,\n expiresInSeconds: start.expires_in,\n });\n\n // Step 2 — poll until the human decides. The server enforces pacing:\n // slow_down means add 5 seconds to the interval (RFC 8628 §3.5).\n let intervalMs = Math.max(1, start.interval) * 1000;\n const deadline = Date.now() + start.expires_in * 1000;\n\n while (Date.now() < deadline) {\n await sleep(intervalMs);\n\n const pollResponse = await fetchFn(`${base}/oauth/token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: DEVICE_GRANT_TYPE,\n device_code: start.device_code,\n }).toString(),\n });\n\n const body = (await pollResponse.json()) as Record<string, unknown>;\n logEvent(\"device_token_poll\", { status: pollResponse.status, error: body.error });\n\n if (pollResponse.ok && typeof body.access_token === \"string\") {\n const token = body.access_token;\n const claims = decodeJwtPayload(token);\n const result: DeviceLoginResult = {\n token,\n teamId: typeof claims?.team_id === \"string\" ? claims.team_id : undefined,\n agentId: typeof claims?.agent_id === \"string\" ? claims.agent_id : undefined,\n expiresAt:\n typeof claims?.exp === \"number\" ? new Date(claims.exp * 1000).toISOString() : undefined,\n };\n\n writeCredentials({\n token: result.token,\n teamId: result.teamId,\n tokenType: \"agent\",\n agentId: result.agentId,\n expiresAt: result.expiresAt,\n });\n\n return result;\n }\n\n switch (body.error) {\n case \"authorization_pending\":\n continue;\n case \"slow_down\":\n intervalMs += 5000;\n continue;\n case \"access_denied\":\n throw authError(\"The authorization request was denied.\");\n case \"expired_token\":\n throw authError(\"The device code expired before approval. Run the login again.\");\n default:\n throw new CliError(\n \"API_ERROR\",\n `Unexpected token response: ${body.error ?? `HTTP ${pollResponse.status}`}`,\n EXIT_CODES.API_ERROR\n );\n }\n }\n\n throw authError(\"The device code expired before approval. Run the login again.\");\n}\n","import { writeCredentials } from \"./store.js\";\nimport { CliError, EXIT_CODES } from \"../api/errors.js\";\nimport { logEvent } from \"../output/log.js\";\n\n/**\n * Invite-door redemption: exchange a pre-approved, single-use invite code for\n * a scoped agent token (`grant_type=urn:ietf:params:oauth:grant-type:\n * pre-authorized_code`) and store it exactly like the device login — so\n * `logout`, `mcp-config`, `get-git-token`, and the rest of the CLI work\n * identically for invited agents.\n *\n * The human mints the invite in-app and hands the agent a URL like\n * `https://public-api.animaapp.com/invite/<code>.md`; this accepts either\n * that full URL or the bare code. A single POST returns the token directly —\n * there is no polling and no browser step (consent already happened at mint).\n */\n\nconst PRE_AUTHORIZED_GRANT = \"urn:ietf:params:oauth:grant-type:pre-authorized_code\";\n\nexport type InviteLoginResult = {\n token: string;\n teamId?: string;\n agentId?: string;\n expiresAt?: string;\n};\n\nexport type ParsedInvite = {\n code: string;\n /** Origin of the invite URL, when a URL was given — the API the invite was minted on. */\n origin?: string;\n};\n\n/**\n * Accept the invite URL (`…/invite/<code>.md`), the same without `.md`, or the\n * bare code. When a URL is given, its origin is returned too: the invite was\n * minted on that host, so it is the right API base unless the caller overrides.\n */\nexport function parseInvite(input: string): ParsedInvite {\n const trimmed = input.trim();\n if (/^https?:\\/\\//i.test(trimmed)) {\n let url: URL;\n try {\n url = new URL(trimmed);\n } catch {\n throw new CliError(\"VALIDATION_ERROR\", `Not a valid invite URL: ${trimmed}`, EXIT_CODES.VALIDATION_ERROR);\n }\n const last = url.pathname.split(\"/\").filter(Boolean).pop() ?? \"\";\n const code = last.replace(/\\.md$/, \"\");\n if (!code) {\n throw new CliError(\n \"VALIDATION_ERROR\",\n \"The invite URL carries no code — expected …/invite/<code>.md\",\n EXIT_CODES.VALIDATION_ERROR\n );\n }\n return { code, origin: url.origin };\n }\n return { code: trimmed.replace(/\\.md$/, \"\") };\n}\n\ntype InviteLoginOptions = {\n apiUrl: string;\n invite: string;\n /** Injectable for tests. */\n fetchFn?: typeof fetch;\n};\n\n/** Decode a JWT payload without verification (display/bookkeeping only). */\nfunction decodeJwtPayload(token: string): Record<string, unknown> | undefined {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) return undefined;\n return JSON.parse(Buffer.from(parts[1], \"base64url\").toString(\"utf-8\"));\n } catch {\n return undefined;\n }\n}\n\nexport async function loginWithInvite(options: InviteLoginOptions): Promise<InviteLoginResult> {\n const fetchFn = options.fetchFn ?? fetch;\n const { code } = parseInvite(options.invite);\n const base = options.apiUrl.replace(/\\/$/, \"\");\n\n const tokenUrl = `${base}/oauth/token`;\n logEvent(\"invite_redeem_request\", { url: tokenUrl });\n const response = await fetchFn(tokenUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: PRE_AUTHORIZED_GRANT,\n \"pre-authorized_code\": code,\n }).toString(),\n });\n\n const body = (await response.json().catch(() => ({}))) as Record<string, unknown>;\n logEvent(\"invite_redeem_response\", { status: response.status, error: body.error });\n\n if (!response.ok || typeof body.access_token !== \"string\") {\n // The server's error_description is prompt-ware written for the agent —\n // surface it verbatim.\n const description =\n typeof body.error_description === \"string\"\n ? body.error_description\n : `Invite redemption failed (HTTP ${response.status})`;\n throw new CliError(\"AUTH_INVALID\", description, EXIT_CODES.AUTH_ERROR);\n }\n\n const token = body.access_token;\n const claims = decodeJwtPayload(token);\n const result: InviteLoginResult = {\n token,\n teamId: typeof claims?.team_id === \"string\" ? claims.team_id : undefined,\n agentId: typeof claims?.agent_id === \"string\" ? claims.agent_id : undefined,\n expiresAt: typeof claims?.exp === \"number\" ? new Date(claims.exp * 1000).toISOString() : undefined,\n };\n\n // Same credential shape as the device login — the whole CLI surface\n // (logout, mcp-config, get-git-token, …) works identically from here.\n writeCredentials({\n token: result.token,\n teamId: result.teamId,\n tokenType: \"agent\",\n agentId: result.agentId,\n expiresAt: result.expiresAt,\n });\n\n return result;\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { writeCredentials, clearStorage, readCredentials, getCredentialsPath, extractTeamIdFromJWT } from \"../auth/store.js\";\nimport { resolveAuth } from \"../auth/token.js\";\nimport { detectOutputMode, outputResult, outputError } from \"../output/formatter.js\";\nimport { printSuccess, printError, printKeyValue, printInfo } from \"../output/pretty.js\";\nimport { CliError } from \"../api/errors.js\";\n\nconst DEFAULT_API_URL = \"https://public-api.animaapp.com\";\n\nexport const authCommand = new Command(\"auth\")\n .description(\"Manage authentication\")\n .option(\"--token <token>\", \"Store Anima API token\")\n .option(\"--figma-token <token>\", \"Store Figma personal access token\")\n .option(\"--team-id <teamId>\", \"Team ID to associate with token\")\n .option(\"--status\", \"Show current auth status\")\n .option(\"--logout\", \"Clear stored credentials (alias for `anima logout`)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--api-url <url>\", \"API base URL\", DEFAULT_API_URL)\n .action(async (opts) => {\n const mode = detectOutputMode(opts);\n\n try {\n if (opts.token || opts.figmaToken) {\n const toSave: Record<string, string> = {};\n\n if (opts.token) {\n toSave.token = opts.token;\n toSave.teamId = opts.teamId ?? extractTeamIdFromJWT(opts.token) ?? \"\";\n }\n if (opts.figmaToken) {\n toSave.figmaToken = opts.figmaToken;\n }\n\n writeCredentials(toSave);\n\n if (mode === \"pretty\") {\n printSuccess(\"Credentials saved to \" + getCredentialsPath());\n if (opts.token) {\n printKeyValue(\"Anima token\", \"saved\");\n if (toSave.teamId) printKeyValue(\"Team ID\", toSave.teamId);\n }\n if (opts.figmaToken) {\n printKeyValue(\"Figma token\", \"saved\");\n }\n } else {\n outputResult(mode, {\n success: true,\n action: \"token_saved\",\n path: getCredentialsPath(),\n ...(opts.token ? { teamId: toSave.teamId } : {}),\n ...(opts.figmaToken ? { figmaToken: true } : {}),\n });\n }\n return;\n }\n\n if (opts.logout) {\n const deleted = clearStorage();\n if (mode === \"pretty\") {\n if (deleted) {\n printSuccess(\"Credentials cleared\");\n } else {\n printInfo(\"No stored credentials found\");\n }\n } else {\n outputResult(mode, { success: true, action: \"logged_out\", hadCredentials: deleted });\n }\n return;\n }\n\n if (opts.status) {\n try {\n const auth = resolveAuth();\n const creds = readCredentials();\n const sourceName = auth.source === \"env\" ? \"ANIMA_API_TOKEN env var\" : getCredentialsPath();\n const hasFigma = !!(process.env.FIGMA_TOKEN || creds?.figmaToken);\n if (mode === \"pretty\") {\n printSuccess(\"Token configured\");\n printKeyValue(\"Source\", sourceName);\n printKeyValue(\"Anima token\", auth.token.slice(0, 12) + \"...\" + auth.token.slice(-4));\n printKeyValue(\"Token type\", auth.tokenType === \"agent\" ? \"agent (scoped, revocable)\" : \"personal/API\");\n if (creds?.tokenType === \"agent\" && creds.expiresAt) printKeyValue(\"Expires\", creds.expiresAt);\n if (auth.teamId) printKeyValue(\"Team ID\", auth.teamId);\n printKeyValue(\"Figma token\", hasFigma ? \"configured\" : \"not set (needed for codegen/f2c)\");\n } else {\n outputResult(mode, {\n success: true,\n source: auth.source,\n tokenType: auth.tokenType ?? \"personal\",\n tokenPreview: auth.token.slice(0, 12) + \"...\" + auth.token.slice(-4),\n teamId: auth.teamId,\n expiresAt: creds?.tokenType === \"agent\" ? creds.expiresAt : undefined,\n figmaToken: hasFigma,\n });\n }\n } catch (err) {\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n printError(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n } else {\n throw err;\n }\n }\n return;\n }\n\n // No flag: show help\n if (mode === \"pretty\") {\n console.log();\n printInfo(\"Auth commands:\");\n console.log(` ${chalk.cyan(\"anima login\")} Log in (device flow — approve on any browser)`);\n console.log(` ${chalk.cyan(\"anima logout\")} Clear all credentials`);\n console.log(` ${chalk.cyan(\"anima auth --status\")} Check auth status`);\n console.log(` ${chalk.cyan(\"anima auth --figma-token <T>\")} Save Figma token (needed for codegen/f2c)`);\n console.log();\n console.log(` Figma token: ${chalk.cyan.underline(\"https://www.figma.com\")} > Settings > Personal access tokens`);\n console.log();\n } else {\n outputResult(mode, {\n success: true,\n message: \"Run `anima login`, or use --status / --logout / --figma-token\",\n });\n }\n } catch (err) {\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n printError(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n process.exit(err.exitCode);\n }\n throw err;\n }\n });\n","import { Command } from \"commander\";\nimport { clearStorage, getCredentialsPath } from \"../auth/store.js\";\nimport { detectOutputMode, outputResult } from \"../output/formatter.js\";\nimport { printSuccess, printInfo } from \"../output/pretty.js\";\n\n/**\n * `anima logout` — clear all stored credentials from this machine. Removes the\n * credentials file (Anima token, Figma token, agent metadata) and the config\n * directory. Note: this only forgets the token locally; to actually disable an\n * agent, revoke it from your team settings.\n */\nexport const logoutCommand = new Command(\"logout\")\n .description(\"Clear all stored credentials (Anima + Figma tokens) from this machine\")\n .option(\"--json\", \"Output as JSON\")\n .action((opts) => {\n const mode = detectOutputMode(opts);\n const hadCredentials = clearStorage();\n\n if (mode === \"pretty\") {\n if (hadCredentials) {\n printSuccess(\"Logged out — all credentials cleared from \" + getCredentialsPath());\n } else {\n printInfo(\"No stored credentials found\");\n }\n } else {\n outputResult(mode, { success: true, action: \"logged_out\", hadCredentials });\n }\n });\n","import { Command } from \"commander\";\nimport {\n readConfig,\n setConfig,\n unsetConfig,\n getConfigPath,\n isConfigKey,\n configKeys,\n CONFIG_KEYS,\n resolveApiUrl,\n DEFAULT_API_URL,\n type ConfigKey,\n} from \"../config/store.js\";\nimport { detectOutputMode, outputResult } from \"../output/formatter.js\";\nimport { printSuccess, printInfo, printKeyValue } from \"../output/pretty.js\";\nimport { validationError } from \"../api/errors.js\";\n\n/**\n * `anima config` — store non-secret CLI preferences in\n * ~/.config/anima/config.json so you don't have to pass flags like `--api-url`\n * every time. Resolution precedence for the API URL: flag → ANIMA_API_URL env →\n * stored config → default.\n *\n * anima config set api-url http://localhost:3789\n * anima config get api-url\n * anima config list\n * anima config unset api-url\n */\nexport const configCommand = new Command(\"config\").description(\n `Store CLI preferences (keys: ${configKeys().join(\", \")})`\n);\n\nconfigCommand\n .command(\"set <key> <value>\")\n .description(\"Set a config value\")\n .option(\"--json\", \"Output as JSON\")\n .action((key: string, value: string, opts) => {\n const mode = detectOutputMode(opts);\n assertKey(key);\n if (key === \"api-url\") assertUrl(value);\n setConfig(key, value);\n\n if (mode === \"pretty\") printSuccess(`Set ${key} = ${value}`);\n else outputResult(mode, { success: true, action: \"config_set\", key, value });\n });\n\nconfigCommand\n .command(\"get <key>\")\n .description(\"Print a config value\")\n .option(\"--json\", \"Output as JSON\")\n .action((key: string, opts) => {\n const mode = detectOutputMode(opts);\n assertKey(key);\n const value = readConfig()[CONFIG_KEYS[key]];\n\n if (mode === \"pretty\") {\n if (value) console.log(value);\n else printInfo(`${key} is not set`);\n } else {\n outputResult(mode, { success: true, key, value: value ?? null });\n }\n });\n\nconfigCommand\n .command(\"list\")\n .alias(\"ls\")\n .description(\"Show all config values and where the API URL resolves from\")\n .option(\"--json\", \"Output as JSON\")\n .action((opts) => {\n const mode = detectOutputMode(opts);\n const config = readConfig();\n const resolvedApiUrl = resolveApiUrl();\n\n if (mode === \"pretty\") {\n printInfo(\"Config: \" + getConfigPath());\n printKeyValue(\"api-url\", config.apiUrl ?? `(default) ${DEFAULT_API_URL}`);\n if (process.env.ANIMA_API_URL) {\n printInfo(`ANIMA_API_URL env is set — it overrides config (effective: ${resolvedApiUrl})`);\n }\n } else {\n outputResult(mode, {\n success: true,\n path: getConfigPath(),\n config,\n resolved: { apiUrl: resolvedApiUrl },\n });\n }\n });\n\nconfigCommand\n .command(\"unset <key>\")\n .description(\"Remove a config value\")\n .option(\"--json\", \"Output as JSON\")\n .action((key: string, opts) => {\n const mode = detectOutputMode(opts);\n assertKey(key);\n const removed = unsetConfig(key);\n\n if (mode === \"pretty\") {\n if (removed) printSuccess(`Unset ${key}`);\n else printInfo(`${key} was not set`);\n } else {\n outputResult(mode, { success: true, action: \"config_unset\", key, removed });\n }\n });\n\nfunction assertKey(key: string): asserts key is ConfigKey {\n if (!isConfigKey(key)) {\n throw validationError(`Unknown config key \"${key}\". Valid keys: ${configKeys().join(\", \")}`);\n }\n}\n\nfunction assertUrl(value: string): void {\n try {\n new URL(value);\n } catch {\n throw validationError(`\"${value}\" is not a valid URL`);\n }\n}\n"],"mappings":"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","names":["Command","fs","path","fs","path","os","CONFIG_DIR","Command","Command","Command","fs","path","Command","Command","chalk","Command","chalk","Command","Command","chalk","decodeJwtPayload","Command","apiUrl","chalk","Command","Command","chalk","DEFAULT_API_URL","Command","chalk","Command","Command","Command","Command","Command"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/create.ts","../src/auth/store.ts","../src/api/errors.ts","../src/auth/token.ts","../src/api/mcp.ts","../src/output/log.ts","../src/version.ts","../src/output/formatter.ts","../src/output/progress.ts","../src/output/pretty.ts","../src/utils/figma.ts","../src/utils/projectSource.ts","../src/config/store.ts","../src/commands/publish.ts","../src/commands/codegen.ts","../src/utils/files.ts","../src/commands/getGitToken.ts","../src/utils/playgroundUrl.ts","../src/utils/gitToken.ts","../src/commands/mcpConfig.ts","../src/commands/login.ts","../src/auth/device.ts","../src/auth/invite.ts","../src/commands/auth.ts","../src/commands/logout.ts","../src/commands/config.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { createCommand } from \"./commands/create.js\";\nimport { publishCommand } from \"./commands/publish.js\";\nimport { codegenCommand } from \"./commands/codegen.js\";\nimport { getGitTokenCommand } from \"./commands/getGitToken.js\";\nimport { mcpConfigCommand } from \"./commands/mcpConfig.js\";\nimport { authCommand } from \"./commands/auth.js\";\nimport { loginCommand } from \"./commands/login.js\";\nimport { logoutCommand } from \"./commands/logout.js\";\nimport { configCommand } from \"./commands/config.js\";\nimport { CliError } from \"./api/errors.js\";\n\n// Version comes from package.json so `--version` always matches the published\n// build (shared with the MCP clientInfo).\nimport { version } from \"./version.js\";\n\nconst program = new Command()\n .name(\"anima\")\n .description(\n `Anima CLI - Generate production-ready apps from prompts, URLs, or Figma designs.\n\nAUTHENTICATION:\n Run: npx @animaapp/cli login\n Approve in a browser on any device — the CLI receives a scoped agent token\n (stored in ~/.config/anima/). CI/automation can set ANIMA_API_TOKEN instead.\n\nTIMING (important for AI agents):\n create → 3-7 minutes (keep the default 600000ms timeout)\n publish → 1-3 minutes\n codegen → 2-5 minutes\n get-git-token → seconds\n The --timeout default is 600000ms (10 min). Do NOT reduce it.\n\nCOMMANDS:\n login Log in via the device flow (no browser needed on this machine)\n logout Clear all stored credentials from this machine\n mcp-config Print an MCP server config from stored credentials (no new login)\n create Create app from prompt, URL, or Figma design\n publish Deploy playground to live URL or npm package\n codegen Convert Figma design to code files (no playground)\n get-git-token Mint a git remote URL for a playground; clone/edit/push with git\n config Store CLI preferences (e.g. a default API URL)\n auth Inspect or manage credentials (status / figma token)\n\nEXAMPLES:\n npx @animaapp/cli login\n npx @animaapp/cli create -t p2c -p \"SaaS dashboard with sidebar and analytics\"\n npx @animaapp/cli create -t l2c -u https://stripe.com\n npx @animaapp/cli create -t f2c --file-key abc --nodes 42:15\n npx @animaapp/cli publish abc123xyz\n npx @animaapp/cli codegen --file-key abc --nodes 42:15 -o ./components\n npx @animaapp/cli get-git-token https://dev.animaapp.com/chat/abc123xyz\n\nOUTPUT: JSON to stdout when piped (for AI tools), pretty text in terminals.\n Progress is streamed to stderr via --verbose when in JSON mode.`\n )\n .version(version, \"-v, --version\");\n\nprogram.addCommand(loginCommand);\nprogram.addCommand(logoutCommand);\nprogram.addCommand(createCommand);\nprogram.addCommand(publishCommand);\nprogram.addCommand(codegenCommand);\nprogram.addCommand(getGitTokenCommand);\nprogram.addCommand(mcpConfigCommand);\nprogram.addCommand(configCommand);\nprogram.addCommand(authCommand);\n\nprogram.parseAsync(process.argv).catch((err) => {\n if (err instanceof CliError) {\n if (process.stdout.isTTY) {\n console.error(err.message);\n } else {\n process.stdout.write(\n JSON.stringify({\n success: false,\n error: { code: err.code, message: err.message },\n }) + \"\\n\"\n );\n }\n process.exit(err.exitCode);\n }\n\n console.error(err);\n process.exit(1);\n});\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { resolveAuth } from \"../auth/token.js\";\nimport { withMcp } from \"../api/mcp.js\";\nimport { detectOutputMode, outputResult, outputError } from \"../output/formatter.js\";\nimport { ProgressReporter } from \"../output/progress.js\";\nimport { initLogger } from \"../output/log.js\";\nimport { printSessionResult } from \"../output/pretty.js\";\nimport { parseFigmaUrl, normalizeNodeId } from \"../utils/figma.js\";\nimport { collectProjectSource } from \"../utils/projectSource.js\";\nimport { resolveApiUrl } from \"../config/store.js\";\nimport { validationError, apiError, CliError } from \"../api/errors.js\";\nimport type { CreateType } from \"../api/types.js\";\n\nconst PLAYGROUND_BASE = \"https://dev.animaapp.com/chat\";\n\ntype CreateResult = {\n success: boolean;\n sessionId?: string;\n playgroundUrl?: string;\n // Minted with the playground, same shape as project-get_git_token.\n gitRemoteUrl?: string;\n access?: \"ro\" | \"rw\";\n expiresAt?: string;\n // Own-code only\n framework?: \"html\" | \"react\";\n fileCount?: number;\n skippedFiles?: string[];\n notes?: string;\n nextSteps?: string;\n error?: string;\n reason?: string;\n};\n\ntype ZipUploadGrant = {\n success: boolean;\n zipUploadId?: string;\n uploadUrl?: string;\n uploadUrlExpiresAt?: string;\n nextSteps?: string | string[];\n error?: string;\n reason?: string;\n};\n\nexport const createCommand = new Command(\"create\")\n .description(\n \"Create a playground: AI-generated (p2c/l2c/f2c, 3-7 min), empty for code you'll push (instant), or import your existing code (instant)\"\n )\n .requiredOption(\n \"-t, --type <type>\",\n \"p2c, l2c, f2c, empty (empty repo you push to), or import (create FROM your code — use --from)\"\n )\n .option(\"-p, --prompt <prompt>\", \"Text prompt (p2c)\")\n .option(\"-u, --url <url>\", \"Website URL (l2c)\")\n .option(\"--file-key <key>\", \"Figma file key or URL (f2c)\")\n .option(\"--nodes <nodes>\", \"Figma node IDs, comma-separated (f2c)\")\n .option(\"--figma-token <token>\", \"Figma personal access token (f2c)\")\n .option(\n \"--framework <fw>\",\n \"html | react — the only supported frameworks. REQUIRED for empty (declare react if you will push React code); detected from package.json for import\"\n )\n .option(\"--styling <style>\", \"tailwind | css | plain_css | css_modules | inline_styles\", \"tailwind\")\n .option(\"--language <lang>\", \"typescript | javascript\")\n .option(\"--ui-library <lib>\", \"mui | antd | shadcn | clean_react\")\n .option(\"--guidelines <text>\", \"Additional constraints (p2c only)\")\n .option(\"--name <name>\", \"Project name (empty/import only)\")\n .option(\"--from <path>\", \"Folder or .zip with your project (import only) — becomes the first commit\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--timeout <ms>\", \"Timeout in milliseconds\", \"600000\")\n .option(\"--verbose\", \"Show progress on stderr\")\n .option(\"--api-url <url>\", \"API base URL (overrides config / ANIMA_API_URL)\")\n .option(\"--log-file <path>\", \"Append a JSON debug log of each step to this file\")\n .action(async (opts) => {\n const mode = detectOutputMode(opts);\n initLogger(opts.logFile);\n const progress = new ProgressReporter(mode, opts.verbose);\n\n try {\n const type = opts.type as CreateType;\n validateCreateOptions(type, opts);\n\n const auth = resolveAuth();\n const figmaToken = type === \"f2c\" ? resolveFigmaToken(opts, auth.figmaToken) : undefined;\n const args = buildCreateArgs(type, opts);\n const mcpConfig = { apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId, figmaToken };\n\n // Import: attach the local project. Small text-only projects go inline;\n // anything with binaries or over the inline caps is zipped and uploaded\n // via a presigned URL first (playground-get_zip_upload_url).\n if (type === \"import\") {\n progress.start(\"Collecting project files...\");\n const source = collectProjectSource(opts.from);\n if (source.kind === \"files\") {\n args.files = source.files;\n } else {\n progress.update(`Uploading project zip (${source.reason})...`);\n const grant = await withMcp(mcpConfig, (client) =>\n client.callTool<ZipUploadGrant>(\"playground-get_zip_upload_url\", {})\n );\n if (!grant.success || !grant.uploadUrl || !grant.zipUploadId) {\n const message = grant.reason || grant.error || \"Could not get a zip upload URL\";\n throw apiError(grant.nextSteps ? `${message}\\n${grant.nextSteps}` : message, grant);\n }\n const putResponse = await fetch(grant.uploadUrl, {\n method: \"PUT\",\n body: new Uint8Array(source.buffer),\n });\n if (!putResponse.ok) {\n throw apiError(`Zip upload failed: HTTP ${putResponse.status}`, { status: putResponse.status });\n }\n args.zipUploadId = grant.zipUploadId;\n }\n }\n\n progress.start(\n type === \"empty\"\n ? \"Creating empty playground...\"\n : type === \"import\"\n ? \"Importing your project...\"\n : `Creating ${type.toUpperCase()} playground...`\n );\n\n const result = await withMcp(mcpConfig, (client) =>\n client.callTool<CreateResult>(\"playground-create\", args, {\n timeoutMs: parseInt(opts.timeout, 10),\n onProgress: (p) => progress.update(p.message ?? `Generating (${Math.round(p.progress)}%)...`),\n })\n );\n\n if (!result.success || !result.sessionId) {\n const message = result.reason || result.error || \"Generation failed\";\n // Own-code failures carry recovery guidance (e.g. the upload_not_found\n // duplicate-playground warning) — losing it at the CLI boundary would\n // strip exactly what the caller needs to retry correctly.\n throw apiError(result.nextSteps ? `${message}\\n${result.nextSteps}` : message, result);\n }\n\n const playgroundUrl = result.playgroundUrl || `${PLAYGROUND_BASE}/${result.sessionId}`;\n\n progress.succeed(\"Playground created!\");\n\n if (mode === \"pretty\") {\n printSessionResult({ sessionId: result.sessionId, playgroundUrl });\n if (result.gitRemoteUrl) {\n console.log(` ${chalk.cyan(`git clone ${result.gitRemoteUrl}`)}`);\n console.log();\n console.log(\" Commit and push to update the live playground.\");\n if (result.expiresAt) {\n console.log(\n ` The URL embeds a token that expires at ${result.expiresAt} and cannot be renewed;\\n` +\n ` run ${chalk.cyan(`anima get-git-token ${result.sessionId}`)} and ` +\n `${chalk.cyan(\"git remote set-url origin <new url>\")} to keep pushing.`\n );\n }\n console.log(\" Treat the URL as a secret — it grants access to this playground.\");\n console.log();\n } else if (type === \"empty\") {\n console.log(\n ` Next: anima get-git-token ${result.sessionId} — then git clone, add your code, and git push.`\n );\n console.log();\n }\n if (type === \"import\" && result.fileCount !== undefined) {\n console.log(` ${result.fileCount} files committed (framework: ${result.framework ?? \"detected server-side\"}).`);\n if (result.skippedFiles?.length) {\n console.log(` Skipped (blocked/hidden): ${result.skippedFiles.join(\", \")}`);\n }\n if (result.notes) {\n console.log(` Note: ${result.notes}`);\n }\n console.log();\n }\n } else {\n outputResult(mode, {\n success: true,\n sessionId: result.sessionId,\n playgroundUrl,\n ...(result.gitRemoteUrl\n ? { gitRemoteUrl: result.gitRemoteUrl, access: result.access, expiresAt: result.expiresAt }\n : {}),\n ...(result.framework ? { framework: result.framework } : {}),\n ...(result.fileCount !== undefined ? { fileCount: result.fileCount } : {}),\n ...(result.skippedFiles?.length ? { skippedFiles: result.skippedFiles } : {}),\n ...(result.notes ? { notes: result.notes } : {}),\n ...(result.nextSteps ? { nextSteps: result.nextSteps } : {}),\n });\n }\n } catch (err) {\n progress.fail(\"Failed\");\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n console.error(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n process.exit(err.exitCode);\n }\n throw err;\n }\n });\n\nfunction validateCreateOptions(type: CreateType, opts: Record<string, string>): void {\n if (![\"p2c\", \"l2c\", \"f2c\", \"empty\", \"import\"].includes(type)) {\n throw validationError(`Invalid type \"${type}\". Must be p2c, l2c, f2c, empty, or import.`);\n }\n if (type === \"p2c\" && !opts.prompt) {\n throw validationError(\"--prompt is required for p2c type\");\n }\n if (type === \"l2c\" && !opts.url) {\n throw validationError(\"--url is required for l2c type\");\n }\n if (type === \"f2c\" && !opts.fileKey) {\n throw validationError(\"--file-key is required for f2c type\");\n }\n if (type === \"empty\" && !opts.framework) {\n throw validationError(\n \"--framework is required for type empty — html for plain HTML/CSS/JS, react for React (declare react if you will push React code)\"\n );\n }\n if (type === \"import\" && !opts.from) {\n throw validationError(\"--from <folder|zip> is required for type import — the path to the project to import\");\n }\n if (type !== \"import\" && opts.from) {\n throw validationError(\"--from is only valid with -t import\");\n }\n}\n\nfunction resolveFigmaToken(opts: Record<string, string>, stored?: string): string {\n const figmaToken = opts.figmaToken || process.env.FIGMA_TOKEN || stored;\n if (!figmaToken) {\n throw validationError(\n \"Figma token required for f2c. Use --figma-token, set FIGMA_TOKEN env var, or run: anima auth --figma-token <token>\\n\" +\n \"Get one at: https://www.figma.com > Settings > Personal access tokens\"\n );\n }\n return figmaToken;\n}\n\nfunction buildCreateArgs(type: CreateType, opts: Record<string, string>): Record<string, unknown> {\n // empty: framework is required (validated above) — the caller declares what\n // they'll push. import: framework only when explicit — the server detects\n // it from package.json otherwise. The files/zipUploadId for import are\n // attached later by the action (they may need the upload leg first).\n if (type === \"empty\" || type === \"import\") {\n return {\n type,\n ...(opts.framework ? { framework: opts.framework } : {}),\n ...(opts.name ? { name: opts.name } : {}),\n };\n }\n\n // Generation types: html is the default — aligned with the MCP\n // playground-create surface. Only html and react are supported.\n const framework = opts.framework ?? \"html\";\n // Default language to typescript when framework is react (matches the web import form).\n const language = opts.language ?? (framework === \"react\" ? \"typescript\" : undefined);\n\n const args: Record<string, unknown> = {\n type,\n framework,\n styling: opts.styling,\n };\n if (language) args.language = language;\n if (opts.uiLibrary) args.uiLibrary = opts.uiLibrary;\n\n switch (type) {\n case \"p2c\":\n args.prompt = opts.prompt;\n if (opts.guidelines) args.guidelines = opts.guidelines;\n break;\n case \"l2c\":\n args.url = opts.url;\n break;\n case \"f2c\": {\n const { fileKey, nodeId: parsedNodeId } = parseFigmaUrl(opts.fileKey);\n let nodesId: string[] = [];\n if (opts.nodes) {\n nodesId = opts.nodes.split(\",\").map((n) => normalizeNodeId(n.trim()));\n } else if (parsedNodeId) {\n nodesId = [parsedNodeId];\n }\n args.fileKey = fileKey;\n args.nodesId = nodesId;\n break;\n }\n }\n\n return args;\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\nconst CONFIG_DIR = path.join(os.homedir(), \".config\", \"anima\");\nconst CREDENTIALS_FILE = path.join(CONFIG_DIR, \"credentials.json\");\n\ntype Credentials = {\n token: string;\n teamId?: string;\n figmaToken?: string;\n // Set by the device login: a scoped, revocable AGENT token — never to be\n // confused with a personal API token (which carries the user's full\n // authority and is not governed by workspace scopes).\n tokenType?: \"agent\" | \"personal\";\n agentId?: string;\n expiresAt?: string; // ISO — agent tokens expire (~7 days); re-run the login\n};\n\nexport function readCredentials(): Credentials | null {\n try {\n if (!fs.existsSync(CREDENTIALS_FILE)) return null;\n const content = fs.readFileSync(CREDENTIALS_FILE, \"utf-8\");\n const parsed = JSON.parse(content);\n if (!parsed.token) return null;\n return parsed;\n } catch {\n return null;\n }\n}\n\nexport function writeCredentials(credentials: Partial<Credentials>): void {\n // Merge with existing credentials so we can update fields independently\n const existing = readCredentials() ?? {};\n const merged = { ...existing, ...credentials };\n\n // Remove undefined values\n for (const key of Object.keys(merged) as (keyof Credentials)[]) {\n if (merged[key] === undefined) delete merged[key];\n }\n\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n fs.writeFileSync(\n CREDENTIALS_FILE,\n JSON.stringify(merged, null, 2) + \"\\n\",\n { mode: 0o600 }\n );\n}\n\nexport function deleteCredentials(): boolean {\n try {\n if (fs.existsSync(CREDENTIALS_FILE)) {\n fs.unlinkSync(CREDENTIALS_FILE);\n return true;\n }\n return false;\n } catch {\n return false;\n }\n}\n\n/**\n * Full logout: remove every stored token (all live in credentials.json) and\n * the config directory itself when nothing else is left in it. Returns whether\n * any credentials were present.\n */\nexport function clearStorage(): boolean {\n const had = deleteCredentials();\n try {\n if (fs.existsSync(CONFIG_DIR) && fs.readdirSync(CONFIG_DIR).length === 0) {\n fs.rmdirSync(CONFIG_DIR);\n }\n } catch {\n /* leaving an empty dir behind is harmless */\n }\n return had;\n}\n\nexport function getCredentialsPath(): string {\n return CREDENTIALS_FILE;\n}\n\n/**\n * Extract the defaultTeamId from a JWT token payload (base64-decoded, no verification).\n * Returns undefined if extraction fails.\n */\nexport function extractTeamIdFromJWT(token: string): string | undefined {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) return undefined;\n const payload = JSON.parse(\n Buffer.from(parts[1], \"base64url\").toString(\"utf-8\")\n );\n return payload.defaultTeamId ?? undefined;\n } catch {\n return undefined;\n }\n}\n","export const EXIT_CODES = {\n SUCCESS: 0,\n API_ERROR: 1,\n AUTH_ERROR: 2,\n VALIDATION_ERROR: 3,\n TIMEOUT: 4,\n} as const;\n\nexport type ErrorCode =\n | \"AUTH_REQUIRED\"\n | \"AUTH_INVALID\"\n | \"VALIDATION_ERROR\"\n | \"API_ERROR\"\n | \"TIMEOUT\"\n | \"CONNECTION_ERROR\";\n\nexport class CliError extends Error {\n code: ErrorCode;\n exitCode: number;\n detail?: unknown;\n\n constructor(\n code: ErrorCode,\n message: string,\n exitCode: number,\n detail?: unknown\n ) {\n super(message);\n this.name = \"CliError\";\n this.code = code;\n this.exitCode = exitCode;\n this.detail = detail;\n }\n}\n\nexport function authError(message: string): CliError {\n return new CliError(\"AUTH_REQUIRED\", message, EXIT_CODES.AUTH_ERROR);\n}\n\nexport function validationError(message: string, detail?: unknown): CliError {\n return new CliError(\n \"VALIDATION_ERROR\",\n message,\n EXIT_CODES.VALIDATION_ERROR,\n detail\n );\n}\n\nexport function apiError(message: string, detail?: unknown): CliError {\n return new CliError(\"API_ERROR\", message, EXIT_CODES.API_ERROR, detail);\n}\n\nexport function timeoutError(): CliError {\n return new CliError(\n \"TIMEOUT\",\n \"Request timed out. Generation can take 3-7 minutes. Try increasing --timeout.\",\n EXIT_CODES.TIMEOUT\n );\n}\n","import { readCredentials } from \"./store.js\";\nimport { authError } from \"../api/errors.js\";\n\nexport type ResolvedAuth = {\n token: string;\n teamId?: string;\n figmaToken?: string;\n source: \"env\" | \"file\";\n tokenType?: \"agent\" | \"personal\";\n};\n\nexport function resolveAuth(): ResolvedAuth {\n const creds = readCredentials();\n\n // 1. Environment variable (primary — what AI tools use)\n const envToken = process.env.ANIMA_API_TOKEN;\n if (envToken) {\n return {\n token: envToken,\n teamId: process.env.ANIMA_TEAM_ID,\n figmaToken: process.env.FIGMA_TOKEN || creds?.figmaToken,\n source: \"env\",\n };\n }\n\n // 2. Stored credentials file\n if (creds) {\n // Agent tokens expire (~7 days); renewal is a fresh device login, which\n // reconnects to the same agent when the same name is approved.\n if (creds.tokenType === \"agent\" && creds.expiresAt && new Date(creds.expiresAt) <= new Date()) {\n throw authError(\"Your agent token has expired. Run: anima login\");\n }\n return {\n token: creds.token,\n teamId: creds.teamId,\n figmaToken: process.env.FIGMA_TOKEN || creds.figmaToken,\n source: \"file\",\n tokenType: creds.tokenType,\n };\n }\n\n // 3. No token found\n throw authError(\"No credentials found. Run: anima login\\n(or set the ANIMA_API_TOKEN env var)\");\n}\n","import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { CallToolResultSchema, ErrorCode } from \"@modelcontextprotocol/sdk/types.js\";\nimport { apiError, timeoutError, CliError } from \"./errors.js\";\nimport { logEvent } from \"../output/log.js\";\nimport { version } from \"../version.js\";\n\n/**\n * The CLI talks to Anima only through the MCP endpoint (`/v1/mcp`), the single\n * governed surface (see anima-design-to-code docs/grids/DECISIONS.md \"D47\").\n * Every command runs a tool through this client — there is no other transport.\n */\n\nconst MCP_PATH = \"/v1/mcp\";\n// MCP clientInfo version tracks package.json so server logs see the real release.\nconst CLIENT_INFO = { name: \"anima-cli\", version };\n\nexport type McpConfig = {\n apiBaseUrl: string;\n token: string;\n teamId?: string;\n /** Sent as X-Figma-Token; f2c tools read it from the header, not the args. */\n figmaToken?: string;\n};\n\n/** Progress reported by long-running tools (generation, deploy). */\nexport type ToolProgress = { progress: number; total?: number; message?: string };\n\nexport type CallToolOptions = {\n onProgress?: (p: ToolProgress) => void;\n /** Idle timeout; reset on each progress notification so long jobs don't trip it. */\n timeoutMs?: number;\n};\n\nconst DEFAULT_TIMEOUT_MS = 600_000;\n\nexport class AnimaMcpClient {\n #client: Client;\n #transport: StreamableHTTPClientTransport;\n #url: string;\n\n constructor(config: McpConfig) {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${config.token}`,\n };\n if (config.teamId) headers[\"X-Team-Id\"] = config.teamId;\n if (config.figmaToken) headers[\"X-Figma-Token\"] = config.figmaToken;\n\n this.#url = new URL(MCP_PATH, config.apiBaseUrl).toString();\n this.#transport = new StreamableHTTPClientTransport(new URL(this.#url), {\n requestInit: { headers },\n });\n this.#client = new Client(CLIENT_INFO, { capabilities: {} });\n }\n\n async connect(): Promise<void> {\n logEvent(\"mcp_connect\", { url: this.#url });\n try {\n await this.#client.connect(this.#transport);\n } catch (err) {\n logEvent(\"mcp_connect_failed\", { url: this.#url, error: (err as Error)?.message });\n throw connectionError(err);\n }\n }\n\n /**\n * Call a tool and return its parsed result. Anima tools return a single JSON\n * text block; a `{ success: false }` payload is a normal result, so callers\n * still inspect `success` themselves.\n */\n async callTool<T = unknown>(\n name: string,\n args: Record<string, unknown>,\n options: CallToolOptions = {}\n ): Promise<T> {\n logEvent(\"mcp_tool_call\", { tool: name, arguments: args });\n let result;\n try {\n result = await this.#client.callTool(\n { name, arguments: args },\n CallToolResultSchema,\n {\n timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n resetTimeoutOnProgress: true,\n onprogress: options.onProgress\n ? (p) => options.onProgress!({ progress: p.progress, total: p.total, message: p.message })\n : undefined,\n }\n );\n } catch (err) {\n logEvent(\"mcp_tool_error\", { tool: name, error: (err as Error)?.message });\n if ((err as { code?: number })?.code === ErrorCode.RequestTimeout) {\n throw timeoutError();\n }\n throw err;\n }\n logEvent(\"mcp_tool_result\", { tool: name, isError: result.isError ?? false });\n\n const content = Array.isArray(result.content) ? result.content : [];\n const text = content.find((c): c is { type: \"text\"; text: string } => c.type === \"text\")?.text;\n\n if (result.isError) {\n throw apiError(text || \"MCP tool returned an error\");\n }\n if (!text) {\n throw apiError(\"MCP tool returned no text content\");\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n return text as T;\n }\n }\n\n async close(): Promise<void> {\n await this.#transport.close().catch(() => {});\n }\n}\n\n/** Connect, run `fn`, and always close the transport. */\nexport async function withMcp<T>(\n config: McpConfig,\n fn: (client: AnimaMcpClient) => Promise<T>\n): Promise<T> {\n const client = new AnimaMcpClient(config);\n await client.connect();\n try {\n return await fn(client);\n } finally {\n await client.close();\n }\n}\n\nfunction connectionError(err: unknown): CliError {\n const message = err instanceof Error ? err.message : String(err);\n return new CliError(\n \"CONNECTION_ERROR\",\n `Could not reach the Anima MCP endpoint: ${message}`,\n 1\n );\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Opt-in debug log. When a command is given `--log-file <path>` (or the\n * ANIMA_LOG_FILE env var is set), every network step appends one JSON line to\n * that file. Off by default and a no-op until enabled, so it never touches\n * stdout/stderr. Secret-bearing keys (tokens, auth headers) are redacted.\n *\n * Writes are synchronous (appendFileSync) so nothing is lost when a command\n * ends with process.exit() on an error path.\n */\n\nlet logPath: string | null = null;\n\nconst REDACT_KEY = /token|authorization|secret|password|_auth|api[-_]?key/i;\nconst REDACTED = \"***REDACTED***\";\n\nexport function initLogger(filePath?: string): void {\n const target = filePath || process.env.ANIMA_LOG_FILE;\n if (!target || logPath) return;\n logPath = path.resolve(target);\n fs.mkdirSync(path.dirname(logPath), { recursive: true });\n logEvent(\"log_started\", { pid: process.pid, argv: process.argv.slice(2) });\n}\n\nexport function logEvent(event: string, data?: Record<string, unknown>): void {\n if (!logPath) return;\n const entry = { ts: new Date().toISOString(), event, ...(data ? redact(data) : {}) };\n fs.appendFileSync(logPath, JSON.stringify(entry) + \"\\n\");\n}\n\nfunction redact(value: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value)) {\n if (REDACT_KEY.test(key)) {\n out[key] = REDACTED;\n } else if (val && typeof val === \"object\" && !Array.isArray(val)) {\n out[key] = redact(val as Record<string, unknown>);\n } else {\n out[key] = val;\n }\n }\n return out;\n}\n","import { createRequire } from \"node:module\";\n\n// Single source for the CLI version: package.json. `../package.json` resolves\n// from src/ in dev and from dist/index.js in the published bundle — this file\n// must stay directly under src/ for that to hold.\nexport const { version } = createRequire(import.meta.url)(\"../package.json\") as { version: string };\n","export type OutputMode = \"json\" | \"pretty\";\n\nexport function detectOutputMode(flags: {\n json?: boolean;\n}): OutputMode {\n if (flags.json !== undefined) {\n return flags.json ? \"json\" : \"pretty\";\n }\n // Auto-detect: JSON when piped, pretty in TTY\n return process.stdout.isTTY ? \"pretty\" : \"json\";\n}\n\nexport function outputResult(mode: OutputMode, data: unknown): void {\n if (mode === \"json\") {\n process.stdout.write(JSON.stringify(data) + \"\\n\");\n }\n // Pretty mode output is handled inline by commands using chalk/ora\n}\n\nexport function outputError(\n mode: OutputMode,\n error: { code: string; message: string }\n): void {\n if (mode === \"json\") {\n process.stdout.write(\n JSON.stringify({ success: false, error }) + \"\\n\"\n );\n }\n // Pretty mode errors are handled inline by commands\n}\n","import ora, { type Ora } from \"ora\";\nimport type { OutputMode } from \"./formatter.js\";\n\nexport class ProgressReporter {\n #spinner: Ora | null = null;\n #mode: OutputMode;\n #startTime: number = 0;\n #verbose: boolean;\n\n constructor(mode: OutputMode, verbose: boolean = false) {\n this.#mode = mode;\n this.#verbose = verbose;\n }\n\n start(message: string): void {\n this.#startTime = Date.now();\n if (this.#mode === \"pretty\") {\n // A previous phase's spinner must be stopped first: an orphaned ora\n // interval keeps the event loop (and its repaints) alive forever.\n this.#spinner?.stop();\n this.#spinner = ora(message).start();\n } else if (this.#verbose) {\n process.stderr.write(JSON.stringify({ status: \"started\", message }) + \"\\n\");\n }\n }\n\n update(message: string): void {\n if (this.#mode === \"pretty\" && this.#spinner) {\n const elapsed = this.#elapsed();\n this.#spinner.text = `${message} ${elapsed}`;\n } else if (this.#verbose) {\n process.stderr.write(JSON.stringify({ status: \"progress\", message }) + \"\\n\");\n }\n }\n\n succeed(message: string): void {\n if (this.#mode === \"pretty\" && this.#spinner) {\n const elapsed = this.#elapsed();\n this.#spinner.succeed(`${message} ${elapsed}`);\n } else if (this.#verbose) {\n process.stderr.write(JSON.stringify({ status: \"done\", message }) + \"\\n\");\n }\n this.#spinner = null;\n }\n\n fail(message: string): void {\n if (this.#mode === \"pretty\" && this.#spinner) {\n this.#spinner.fail(message);\n } else if (this.#verbose) {\n process.stderr.write(JSON.stringify({ status: \"error\", message }) + \"\\n\");\n }\n this.#spinner = null;\n }\n\n #elapsed(): string {\n const ms = Date.now() - this.#startTime;\n const seconds = Math.floor(ms / 1000);\n if (seconds < 60) return `(${seconds}s)`;\n const minutes = Math.floor(seconds / 60);\n const secs = seconds % 60;\n return `(${minutes}m ${secs}s)`;\n }\n}\n","import chalk from \"chalk\";\n\nexport function printSuccess(message: string): void {\n console.log(chalk.green(\"✓\") + \" \" + message);\n}\n\nexport function printError(message: string): void {\n console.error(chalk.red(\"✗\") + \" \" + message);\n}\n\nexport function printInfo(message: string): void {\n console.log(chalk.blue(\"ℹ\") + \" \" + message);\n}\n\nexport function printWarning(message: string): void {\n console.log(chalk.yellow(\"⚠\") + \" \" + message);\n}\n\nexport function printKeyValue(key: string, value: string): void {\n console.log(` ${chalk.gray(key + \":\")} ${value}`);\n}\n\nexport function printSessionResult(result: {\n sessionId: string;\n playgroundUrl?: string;\n tokenUsage?: number;\n}): void {\n console.log();\n printSuccess(\"Playground created successfully!\");\n printKeyValue(\"Session ID\", result.sessionId);\n if (result.playgroundUrl) {\n printKeyValue(\"Playground\", chalk.cyan.underline(result.playgroundUrl));\n }\n if (result.tokenUsage) {\n printKeyValue(\"Token usage\", result.tokenUsage.toLocaleString());\n }\n console.log();\n}\n\nexport function printDeployResult(result: {\n url?: string;\n packageUrl?: string;\n packageName?: string;\n packageVersion?: string;\n}): void {\n console.log();\n printSuccess(\"Published successfully!\");\n if (result.url) {\n printKeyValue(\"Live URL\", chalk.cyan.underline(result.url));\n }\n if (result.packageName) {\n printKeyValue(\"Package\", result.packageName);\n printKeyValue(\"Version\", result.packageVersion ?? \"\");\n if (result.packageUrl) {\n printKeyValue(\"URL\", chalk.cyan.underline(result.packageUrl));\n }\n }\n console.log();\n}\n\nexport function printFilesWritten(outputDir: string, count: number): void {\n console.log();\n printSuccess(`${count} files written to ${chalk.cyan(outputDir)}`);\n console.log();\n}\n","/**\n * Parse a Figma URL to extract fileKey and nodeId.\n *\n * Supported formats:\n * - https://www.figma.com/file/ABC123/FileName?node-id=42-15\n * - https://www.figma.com/design/ABC123/FileName?node-id=42-15\n * - https://figma.com/file/ABC123/FileName?node-id=42%3A15\n * - Just a fileKey string\n */\nexport function parseFigmaUrl(input: string): {\n fileKey: string;\n nodeId?: string;\n} {\n // If it doesn't look like a URL, treat as a raw file key\n if (!input.includes(\"figma.com\")) {\n return { fileKey: input };\n }\n\n try {\n const url = new URL(input);\n const pathParts = url.pathname.split(\"/\").filter(Boolean);\n\n // Expected format: /file/KEY/name or /design/KEY/name\n const typeIndex = pathParts.findIndex(\n (p) => p === \"file\" || p === \"design\"\n );\n if (typeIndex === -1 || typeIndex + 1 >= pathParts.length) {\n throw new Error(\"Could not find file key in Figma URL\");\n }\n\n const fileKey = pathParts[typeIndex + 1];\n const nodeIdParam = url.searchParams.get(\"node-id\");\n\n let nodeId: string | undefined;\n if (nodeIdParam) {\n // Convert dash format (42-15) to colon format (42:15)\n nodeId = nodeIdParam.replace(/-/g, \":\");\n }\n\n return { fileKey, nodeId };\n } catch (err) {\n if (err instanceof Error && err.message.includes(\"file key\")) {\n throw err;\n }\n throw new Error(`Invalid Figma URL: ${input}`);\n }\n}\n\n/**\n * Normalize a node ID: convert dash format to colon format.\n * \"42-15\" -> \"42:15\"\n */\nexport function normalizeNodeId(nodeId: string): string {\n return nodeId.replace(/-/g, \":\");\n}\n","import { readdirSync, readFileSync, statSync } from \"fs\";\nimport { join, relative, extname } from \"path\";\nimport AdmZip from \"adm-zip\";\n\n/**\n * Collect a local project for `create -t import --from <path>`.\n *\n * Two transports, mirroring the server's contract:\n * - inline: small, text-only projects → `files` map on playground-create\n * - zip: anything with binaries or over the inline caps, or a .zip given\n * directly → playground-get_zip_upload_url + PUT + zipUploadId\n */\n\nconst SKIPPED_DIRS = new Set([\".git\", \"node_modules\", \"dist\", \"build\", \".next\", \"out\", \"coverage\", \".turbo\", \".cache\"]);\n\nconst BINARY_EXTENSIONS = new Set([\n \".png\", \".jpg\", \".jpeg\", \".gif\", \".webp\", \".ico\", \".bmp\",\n \".woff\", \".woff2\", \".ttf\", \".otf\", \".eot\",\n \".mp4\", \".webm\", \".mp3\", \".wav\", \".ogg\",\n \".zip\", \".tar\", \".gz\", \".pdf\", \".wasm\",\n]);\n\n/** Server-side inline caps (kept in sync with playground-create). */\nconst MAX_INLINE_FILES = 1000;\nconst MAX_INLINE_BYTES = 10 * 1024 * 1024;\n\nexport type ProjectSource =\n | { kind: \"files\"; files: Record<string, string>; fileCount: number }\n | { kind: \"zip\"; buffer: Buffer; reason: string };\n\nfunction walk(root: string, dir: string, out: string[]): void {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n if (!SKIPPED_DIRS.has(entry.name)) walk(root, join(dir, entry.name), out);\n } else if (entry.isFile()) {\n out.push(relative(root, join(dir, entry.name)));\n }\n }\n}\n\nfunction zipFolder(root: string): Buffer {\n const zip = new AdmZip();\n zip.addLocalFolder(root, \"\", (entryPath) => {\n const segments = entryPath.split(/[\\\\/]/);\n return !segments.some((segment) => SKIPPED_DIRS.has(segment));\n });\n return zip.toBuffer();\n}\n\nfunction isProbablyBinary(path: string, buffer: Buffer): boolean {\n if (BINARY_EXTENSIONS.has(extname(path).toLowerCase())) return true;\n return buffer.includes(0);\n}\n\n/**\n * Read a folder or .zip into the transport the server expects.\n * Never sends binaries inline: any binary file, or exceeding the inline caps,\n * switches the whole project to the zip transport.\n */\nexport function collectProjectSource(fromPath: string): ProjectSource {\n const stats = statSync(fromPath);\n\n if (stats.isFile()) {\n if (extname(fromPath).toLowerCase() !== \".zip\") {\n throw new Error(`--from must be a folder or a .zip file, got: ${fromPath}`);\n }\n return { kind: \"zip\", buffer: readFileSync(fromPath), reason: \"zip file given\" };\n }\n\n const paths: string[] = [];\n walk(fromPath, fromPath, paths);\n if (paths.length === 0) {\n throw new Error(`--from folder is empty: ${fromPath}`);\n }\n if (paths.length > MAX_INLINE_FILES) {\n return { kind: \"zip\", buffer: zipFolder(fromPath), reason: `${paths.length} files exceeds the inline limit` };\n }\n\n const files: Record<string, string> = {};\n let totalBytes = 0;\n for (const path of paths) {\n const buffer = readFileSync(join(fromPath, path));\n if (isProbablyBinary(path, buffer)) {\n return { kind: \"zip\", buffer: zipFolder(fromPath), reason: `binary file present (${path})` };\n }\n totalBytes += buffer.length;\n if (totalBytes > MAX_INLINE_BYTES) {\n return { kind: \"zip\", buffer: zipFolder(fromPath), reason: \"project exceeds the inline size limit\" };\n }\n // Normalize Windows separators — the server rejects backslashes\n files[path.split(\"\\\\\").join(\"/\")] = buffer.toString(\"utf8\");\n }\n\n return { kind: \"files\", files, fileCount: paths.length };\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\n/**\n * Persistent, non-secret CLI preferences (e.g. a default API URL for local\n * development). Kept separate from credentials.json so `anima logout` never\n * wipes your machine config. Manage it with `anima config`.\n */\n\nconst CONFIG_DIR = path.join(os.homedir(), \".config\", \"anima\");\nconst CONFIG_FILE = path.join(CONFIG_DIR, \"config.json\");\n\nexport const DEFAULT_API_URL = \"https://public-api.animaapp.com\";\n\nexport type Config = {\n apiUrl?: string;\n};\n\n/** User-facing config keys (kebab) mapped to their stored (camel) field. */\nexport const CONFIG_KEYS = {\n \"api-url\": \"apiUrl\",\n} as const satisfies Record<string, keyof Config>;\n\nexport type ConfigKey = keyof typeof CONFIG_KEYS;\n\nexport function isConfigKey(key: string): key is ConfigKey {\n return key in CONFIG_KEYS;\n}\n\nexport function configKeys(): ConfigKey[] {\n return Object.keys(CONFIG_KEYS) as ConfigKey[];\n}\n\nexport function readConfig(): Config {\n try {\n if (!fs.existsSync(CONFIG_FILE)) return {};\n const parsed = JSON.parse(fs.readFileSync(CONFIG_FILE, \"utf-8\"));\n return parsed && typeof parsed === \"object\" ? parsed : {};\n } catch {\n return {};\n }\n}\n\nexport function setConfig(key: ConfigKey, value: string): void {\n const merged = { ...readConfig(), [CONFIG_KEYS[key]]: value };\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n fs.writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2) + \"\\n\");\n}\n\n/** Remove one key; returns whether it was set. */\n/** Remove the whole config file (used by logout — full machine reset). */\nexport function deleteConfig(): boolean {\n try {\n if (!fs.existsSync(CONFIG_FILE)) return false;\n fs.unlinkSync(CONFIG_FILE);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function unsetConfig(key: ConfigKey): boolean {\n const config = readConfig();\n const field = CONFIG_KEYS[key];\n if (!(field in config)) return false;\n delete config[field];\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + \"\\n\");\n return true;\n}\n\nexport function getConfigPath(): string {\n return CONFIG_FILE;\n}\n\n/**\n * Resolve the API base URL. Precedence: explicit flag → ANIMA_API_URL env →\n * stored config → built-in default.\n */\nexport function resolveApiUrl(flagValue?: string): string {\n return flagValue || process.env.ANIMA_API_URL || readConfig().apiUrl || DEFAULT_API_URL;\n}\n","import { Command } from \"commander\";\nimport { resolveAuth } from \"../auth/token.js\";\nimport { withMcp } from \"../api/mcp.js\";\nimport { detectOutputMode, outputResult, outputError } from \"../output/formatter.js\";\nimport { ProgressReporter } from \"../output/progress.js\";\nimport { initLogger } from \"../output/log.js\";\nimport { printDeployResult } from \"../output/pretty.js\";\nimport { resolveApiUrl } from \"../config/store.js\";\nimport { validationError, CliError } from \"../api/errors.js\";\n\nexport const publishCommand = new Command(\"publish\")\n .description(\"Deploy playground to live URL or npm package (1-3 min)\")\n .argument(\"<sessionId>\", \"Session ID from create command\")\n .option(\"--mode <mode>\", \"webapp | designSystem\", \"webapp\")\n .option(\"--package-name <name>\", \"NPM package name (designSystem mode)\")\n .option(\"--package-version <version>\", \"NPM package version (designSystem mode)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--verbose\", \"Show progress on stderr\")\n .option(\"--api-url <url>\", \"API base URL (overrides config / ANIMA_API_URL)\")\n .option(\"--log-file <path>\", \"Append a JSON debug log of each step to this file\")\n .action(async (sessionId: string, opts) => {\n const mode = detectOutputMode(opts);\n initLogger(opts.logFile);\n const progress = new ProgressReporter(mode, opts.verbose);\n\n try {\n if (![\"webapp\", \"designSystem\"].includes(opts.mode)) {\n throw validationError(\n `Invalid mode \"${opts.mode}\". Must be webapp or designSystem.`\n );\n }\n\n if (opts.mode === \"designSystem\" && !opts.packageName) {\n throw validationError(\"--package-name is required for designSystem mode\");\n }\n\n const auth = resolveAuth();\n\n const args: Record<string, unknown> = {\n sessionId,\n mode: opts.mode,\n };\n if (opts.packageName) args.packageName = opts.packageName;\n if (opts.packageVersion) args.packageVersion = opts.packageVersion;\n\n progress.start(`Publishing as ${opts.mode}...`);\n\n const result = await withMcp(\n { apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId },\n (client) =>\n client.callTool<Record<string, unknown>>(\"playground-publish\", args, {\n onProgress: (p) => progress.update(p.message ?? \"Publishing...\"),\n })\n );\n\n if (!result.success) {\n throw new CliError(\n \"API_ERROR\",\n (result.error as string) || (result.reason as string) || \"Publish failed\",\n 1,\n result\n );\n }\n\n progress.succeed(\"Published!\");\n\n if (mode === \"pretty\") {\n printDeployResult({\n url: result.liveUrl as string | undefined,\n packageUrl: result.packageUrl as string | undefined,\n packageName: result.packageName as string | undefined,\n packageVersion: result.packageVersion as string | undefined,\n });\n } else {\n outputResult(mode, {\n success: true,\n sessionId,\n ...(result.liveUrl ? { liveUrl: result.liveUrl, subdomain: result.subdomain } : {}),\n ...(result.packageName\n ? {\n packageName: result.packageName,\n packageVersion: result.packageVersion,\n packageUrl: result.packageUrl,\n }\n : {}),\n });\n }\n } catch (err) {\n progress.fail(\"Failed\");\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n console.error(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n process.exit(err.exitCode);\n }\n throw err;\n }\n });\n","import { Command } from \"commander\";\nimport { resolveAuth } from \"../auth/token.js\";\nimport { withMcp } from \"../api/mcp.js\";\nimport { detectOutputMode, outputResult, outputError } from \"../output/formatter.js\";\nimport { ProgressReporter } from \"../output/progress.js\";\nimport { initLogger } from \"../output/log.js\";\nimport { printFilesWritten } from \"../output/pretty.js\";\nimport { parseFigmaUrl, normalizeNodeId } from \"../utils/figma.js\";\nimport { writeFilesToDisk } from \"../utils/files.js\";\nimport { resolveApiUrl } from \"../config/store.js\";\nimport { validationError, apiError, CliError } from \"../api/errors.js\";\nimport type { AnimaFiles } from \"../api/types.js\";\n\ntype CodegenResult = {\n success: boolean;\n sessionId?: string;\n files?: AnimaFiles;\n tokenUsage?: number;\n error?: string;\n reason?: string;\n};\n\nexport const codegenCommand = new Command(\"codegen\")\n .description(\"Convert Figma design to code files (no playground)\")\n .requiredOption(\"--file-key <key>\", \"Figma file key or URL\")\n .option(\"--nodes <nodes>\", \"Figma node IDs, comma-separated\")\n .option(\"--figma-token <token>\", \"Figma personal access token (or set FIGMA_TOKEN env var)\")\n .option(\"-o, --output <dir>\", \"Output directory\", \"./generated\")\n .option(\"--framework <fw>\", \"react | html\", \"react\")\n .option(\"--styling <style>\", \"tailwind | plain_css\", \"tailwind\")\n .option(\"--language <lang>\", \"typescript | javascript\")\n .option(\"--ui-library <lib>\", \"mui | antd | shadcn | clean_react\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--timeout <ms>\", \"Timeout in milliseconds\", \"600000\")\n .option(\"--verbose\", \"Show progress on stderr\")\n .option(\"--api-url <url>\", \"API base URL (overrides config / ANIMA_API_URL)\")\n .option(\"--log-file <path>\", \"Append a JSON debug log of each step to this file\")\n .action(async (opts) => {\n const mode = detectOutputMode(opts);\n initLogger(opts.logFile);\n const progress = new ProgressReporter(mode, opts.verbose);\n\n try {\n const { fileKey, nodeId: parsedNodeId } = parseFigmaUrl(opts.fileKey);\n let nodesId: string[] = [];\n if (opts.nodes) {\n nodesId = opts.nodes.split(\",\").map((n: string) => normalizeNodeId(n.trim()));\n } else if (parsedNodeId) {\n nodesId = [parsedNodeId];\n }\n\n if (nodesId.length === 0) {\n throw validationError(\n \"No node IDs provided. Use --nodes or include node-id in the Figma URL.\"\n );\n }\n\n const auth = resolveAuth();\n\n // Resolve Figma token: flag > env var > stored credentials > error.\n // Sent via the X-Figma-Token header; the tool reads it from the header.\n const figmaToken = opts.figmaToken || process.env.FIGMA_TOKEN || auth.figmaToken;\n if (!figmaToken) {\n throw validationError(\n \"Figma token required. Use --figma-token, set FIGMA_TOKEN env var, or run: anima auth --figma-token <token>\\n\" +\n \"Get one at: https://www.figma.com > Settings > Personal access tokens\"\n );\n }\n\n // Default language to typescript when framework is react.\n const language = opts.language ?? (opts.framework === \"react\" ? \"typescript\" : undefined);\n\n const args: Record<string, unknown> = {\n fileKey,\n nodesId,\n framework: opts.framework,\n styling: opts.styling,\n };\n if (language) args.language = language;\n if (opts.uiLibrary) args.uiLibrary = opts.uiLibrary;\n\n progress.start(\"Generating code from Figma...\");\n\n const result = await withMcp(\n { apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId, figmaToken },\n (client) =>\n client.callTool<CodegenResult>(\"codegen-figma_to_code\", args, {\n timeoutMs: parseInt(opts.timeout, 10),\n onProgress: (p) => progress.update(p.message ?? `Generating (${Math.round(p.progress)}%)...`),\n })\n );\n\n if (!result.success || !result.files) {\n throw apiError(result.reason || result.error || \"Code generation failed\", result);\n }\n\n const count = writeFilesToDisk(result.files, opts.output);\n\n progress.succeed(`Generated ${count} files`);\n\n if (mode === \"pretty\") {\n printFilesWritten(opts.output, count);\n } else {\n outputResult(mode, {\n success: true,\n output: opts.output,\n fileCount: count,\n sessionId: result.sessionId,\n tokenUsage: result.tokenUsage,\n });\n }\n } catch (err) {\n progress.fail(\"Failed\");\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n console.error(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n process.exit(err.exitCode);\n }\n throw err;\n }\n });\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { AnimaFiles } from \"../api/types.js\";\n\n/**\n * Write generated files to disk.\n * Handles both code (text) and binary (base64-encoded) files.\n */\nexport function writeFilesToDisk(\n files: AnimaFiles,\n outputDir: string\n): number {\n // Create output directory\n fs.mkdirSync(outputDir, { recursive: true });\n\n let count = 0;\n\n const resolvedOutput = path.resolve(outputDir);\n\n for (const [filePath, fileContent] of Object.entries(files)) {\n const fullPath = path.resolve(outputDir, filePath);\n\n if (!fullPath.startsWith(resolvedOutput + path.sep)) {\n throw new Error(`Path traversal detected: ${filePath}`);\n }\n\n // Create parent directories\n const dirPath = path.dirname(fullPath);\n fs.mkdirSync(dirPath, { recursive: true });\n\n if (fileContent.isBinary) {\n const buffer = Buffer.from(fileContent.content, \"base64\");\n fs.writeFileSync(fullPath, buffer);\n } else {\n fs.writeFileSync(fullPath, fileContent.content, \"utf-8\");\n }\n\n count++;\n }\n\n return count;\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { resolveAuth } from \"../auth/token.js\";\nimport { withMcp } from \"../api/mcp.js\";\nimport { detectOutputMode, outputResult, outputError } from \"../output/formatter.js\";\nimport { ProgressReporter } from \"../output/progress.js\";\nimport { initLogger, logEvent } from \"../output/log.js\";\nimport { parsePlaygroundUrl } from \"../utils/playgroundUrl.js\";\nimport { parseGitTokenResponse } from \"../utils/gitToken.js\";\nimport { resolveApiUrl } from \"../config/store.js\";\nimport { CliError } from \"../api/errors.js\";\n\n/**\n * Mirror of the `project-get_git_token` MCP tool — git is the only content\n * plane for playground code. This mints a short-lived, repo-scoped git remote\n * URL; the caller runs git itself:\n *\n * git clone <gitRemoteUrl> # read (and edit locally)\n * git push # rw access: updates the live playground\n * git remote set-url origin <url> # after expiry: point the clone at a fresh URL\n *\n * The token expires within an hour and cannot be renewed — re-run this command\n * for a fresh URL.\n */\nexport const getGitTokenCommand = new Command(\"get-git-token\")\n .description(\"Mint a short-lived git remote URL for a playground (clone/push with git)\")\n .argument(\"<playgroundUrl>\", \"Playground URL or session ID\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--verbose\", \"Show progress on stderr\")\n .option(\"--api-url <url>\", \"API base URL (overrides config / ANIMA_API_URL)\")\n .option(\"--log-file <path>\", \"Append a JSON debug log of each step to this file\")\n .action(async (playgroundUrl: string, opts) => {\n const mode = detectOutputMode(opts);\n initLogger(opts.logFile);\n const progress = new ProgressReporter(mode, opts.verbose);\n\n try {\n const sessionId = parsePlaygroundUrl(playgroundUrl);\n const auth = resolveAuth();\n\n progress.start(\"Requesting git access...\");\n\n const response = await withMcp(\n { apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId },\n (client) =>\n client.callTool<unknown>(\"project-get_git_token\", { sessionId })\n );\n\n const grant = parseGitTokenResponse(response);\n logEvent(\"git_token_granted\", { sessionId, access: grant.access, expiresAt: grant.expiresAt });\n\n progress.succeed(`Git access granted (${grant.access === \"rw\" ? \"read-write\" : \"read-only\"})`);\n\n if (mode === \"pretty\") {\n console.log();\n console.log(` ${chalk.cyan(`git clone ${grant.gitRemoteUrl}`)}`);\n console.log();\n if (grant.access === \"rw\") {\n console.log(\" Commit and push to update the live playground.\");\n } else {\n console.log(\" Read-only: cloning works, pushing will be rejected.\");\n }\n if (grant.expiresAt) {\n console.log(\n ` The URL embeds a token that expires at ${grant.expiresAt} and cannot be renewed;\\n` +\n ` re-run this command and ${chalk.cyan(\"git remote set-url origin <new url>\")} to keep pushing.`\n );\n }\n console.log(\" Treat the URL as a secret — it grants access to this playground.\");\n console.log();\n } else {\n outputResult(mode, {\n success: true,\n sessionId,\n gitRemoteUrl: grant.gitRemoteUrl,\n access: grant.access,\n expiresAt: grant.expiresAt,\n });\n }\n } catch (err) {\n progress.fail(\"Failed\");\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n console.error(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n process.exit(err.exitCode);\n }\n throw err;\n }\n });\n","/**\n * Parse a playground URL to extract the session ID.\n * Supported formats:\n * - https://dev.animaapp.com/chat/SESSION_ID\n * - Just a session ID string\n */\nexport function parsePlaygroundUrl(input: string): string {\n if (!input.includes(\"/\")) {\n return input;\n }\n\n try {\n const url = new URL(input);\n const parts = url.pathname.split(\"/\").filter(Boolean);\n // Expected: /chat/SESSION_ID\n const chatIndex = parts.indexOf(\"chat\");\n if (chatIndex !== -1 && chatIndex + 1 < parts.length) {\n return parts[chatIndex + 1];\n }\n // Fallback: last path segment\n return parts[parts.length - 1];\n } catch {\n // Not a URL, treat as session ID\n return input;\n }\n}\n","import { apiError } from \"../api/errors.js\";\n\n/**\n * Parsed outcome of the `project-get_git_token` MCP tool.\n *\n * The tool returns JSON: `{ success, gitRemoteUrl, access, expiresAt }` on a\n * grant, or `{ success: false, error, reason }` on a denial. The MCP client\n * (api/mcp.ts) already JSON-parses tool text, so this receives the parsed\n * object — a string only arrives if that parse failed. The clone URL embeds a\n * short-lived access token scoped to the one playground.\n */\nexport type GitTokenGrant = {\n gitRemoteUrl: string;\n access: \"ro\" | \"rw\";\n expiresAt?: string;\n};\n\nfunction preview(payload: unknown): string {\n const text = typeof payload === \"string\" ? payload : JSON.stringify(payload);\n return (text ?? String(payload)).slice(0, 200);\n}\n\nexport function parseGitTokenResponse(payload: unknown): GitTokenGrant {\n let value = payload;\n if (typeof value === \"string\") {\n try {\n value = JSON.parse(value);\n } catch {\n throw apiError(`Unexpected response from project-get_git_token: ${preview(payload)}`);\n }\n }\n\n if (value === null || typeof value !== \"object\") {\n throw apiError(`Unexpected response from project-get_git_token: ${preview(payload)}`);\n }\n\n const body = value as {\n success?: boolean;\n error?: string;\n reason?: string;\n gitRemoteUrl?: string;\n access?: string;\n expiresAt?: string;\n };\n\n if (body.success === false) {\n throw apiError(`Git access ${body.error ?? \"denied\"}: ${(body.reason ?? \"\").trim()}`);\n }\n\n if (!body.gitRemoteUrl) {\n throw apiError(`Unexpected response from project-get_git_token: ${preview(payload)}`);\n }\n\n return {\n gitRemoteUrl: body.gitRemoteUrl,\n access: body.access === \"rw\" ? \"rw\" : \"ro\",\n expiresAt: body.expiresAt,\n };\n}\n","import { Command } from \"commander\";\nimport { resolveAuth } from \"../auth/token.js\";\nimport { readCredentials } from \"../auth/store.js\";\nimport { buildMcpConfig } from \"./login.js\";\nimport { detectOutputMode, outputResult, outputError } from \"../output/formatter.js\";\nimport { printInfo } from \"../output/pretty.js\";\nimport { resolveApiUrl } from \"../config/store.js\";\nimport { CliError } from \"../api/errors.js\";\n\n/**\n * Print the MCP server config from EXISTING credentials — no network, no new\n * device flow. This is the \"I'm already logged in, give me my config\" command\n * the /connect guide's Step 2 points at; `login --print-mcp-config` remains\n * the one-shot variant (fresh login, then print).\n */\nexport const mcpConfigCommand = new Command(\"mcp-config\")\n .description(\"Print an MCP server config from your stored credentials (run `login` first)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--api-url <url>\", \"API base URL (overrides config / ANIMA_API_URL)\")\n .action(async (opts) => {\n const mode = detectOutputMode(opts);\n\n try {\n // Resolution + expiry checks live in resolveAuth: env token → stored\n // credentials (expired agent token → clear \"run anima login\" error).\n const auth = resolveAuth();\n const creds = readCredentials();\n const expiresAt = auth.source === \"env\" ? undefined : creds?.expiresAt;\n\n const mcpConfig = buildMcpConfig(resolveApiUrl(opts.apiUrl), auth.token);\n\n if (mode === \"pretty\") {\n printInfo(\"MCP server config (add to your MCP client; the token is a secret):\");\n console.log();\n console.log(JSON.stringify(mcpConfig, null, 2));\n console.log();\n if (expiresAt) {\n printInfo(`Token expires ${expiresAt} — run \\`anima login\\` then \\`anima mcp-config\\` to refresh.`);\n }\n } else {\n outputResult(mode, {\n success: true,\n mcpConfig,\n ...(expiresAt ? { expiresAt } : {}),\n ...(creds?.agentId && auth.source !== \"env\" ? { agentId: creds.agentId } : {}),\n });\n }\n } catch (err) {\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n console.error(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n process.exit(err.exitCode);\n }\n throw err;\n }\n });\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport open from \"open\";\nimport { loginWithDeviceFlow } from \"../auth/device.js\";\nimport { loginWithInvite, parseInvite } from \"../auth/invite.js\";\nimport { getCredentialsPath } from \"../auth/store.js\";\nimport { initLogger } from \"../output/log.js\";\nimport { resolveApiUrl, setConfig, readConfig } from \"../config/store.js\";\nimport { detectOutputMode, outputResult, outputError } from \"../output/formatter.js\";\nimport { printSuccess, printError, printKeyValue, printInfo } from \"../output/pretty.js\";\nimport { CliError } from \"../api/errors.js\";\n\n/**\n * `anima login` — connect this machine as a governed agent.\n *\n * Two doors, one credential store:\n * - Default: the OAuth device flow. The command prints a short code and a\n * verification URL; a human approves on any device — choosing which\n * workspaces and capabilities this agent gets — and the CLI picks up its\n * scoped token automatically.\n * - `--invite <url-or-code>`: redeem a pre-approved invite (the human already\n * consented in-app when minting it) — a single exchange, no human step and\n * no browser.\n * Either way the token expires after ~7 days; logging in again with the same\n * agent name reconnects to the same agent identity.\n */\nexport const loginCommand = new Command(\"login\")\n .description(\"Log in via the device flow, or redeem a pre-approved invite with --invite\")\n .option(\"--invite <url-or-code>\", \"Redeem an invite link (…/invite/<code>.md) or bare code — no approval step\")\n .option(\"--client-name <name>\", \"How this CLI appears on the consent screen\", \"Anima CLI\")\n .option(\"--no-open\", \"Do not try to open the verification page in a browser\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--api-url <url>\", \"API base URL (overrides config / ANIMA_API_URL)\")\n .option(\"--log-file <path>\", \"Append a JSON debug log of each step to this file\")\n .option(\n \"--print-mcp-config\",\n \"After login, also print an MCP server config (includes the token) to paste into an MCP-capable agent\"\n )\n .action(async (opts) => {\n const mode = detectOutputMode(opts);\n initLogger(opts.logFile);\n\n if (opts.invite) {\n // The invite URL was minted on the API the human used, so its origin is\n // the right base unless the caller explicitly overrides it.\n const inviteOrigin = parseInvite(opts.invite).origin;\n const apiUrl = opts.apiUrl ? resolveApiUrl(opts.apiUrl) : (inviteOrigin ?? resolveApiUrl());\n\n try {\n const result = await loginWithInvite({ apiUrl, invite: opts.invite });\n // Persist the origin the invite was redeemed on: the token is only\n // valid THERE, so later commands (get-git-token, mcp-config, …) must\n // default to it instead of the built-in API URL.\n if (inviteOrigin && readConfig().apiUrl !== apiUrl) {\n setConfig(\"api-url\", apiUrl);\n }\n const mcpConfig = opts.printMcpConfig ? buildMcpConfig(apiUrl, result.token) : undefined;\n\n if (mode === \"pretty\") {\n printSuccess(\"Connected!\");\n printKeyValue(\"Credentials\", getCredentialsPath());\n if (result.agentId) printKeyValue(\"Agent\", result.agentId);\n if (result.teamId) printKeyValue(\"Team ID\", result.teamId);\n if (result.expiresAt) printKeyValue(\"Token expires\", result.expiresAt);\n printInfo(\"This is a scoped agent token — it acts within what was approved, and the team can revoke it.\");\n if (mcpConfig) {\n console.log();\n printInfo(\"MCP server config (token expires ~7 days — a fresh invite renews it):\");\n console.log();\n console.log(JSON.stringify(mcpConfig, null, 2));\n }\n } else {\n outputResult(mode, {\n success: true,\n action: \"logged_in\",\n via: \"invite\",\n tokenType: \"agent\",\n agentId: result.agentId,\n teamId: result.teamId,\n expiresAt: result.expiresAt,\n ...(mcpConfig ? { mcpConfig } : {}),\n });\n }\n } catch (err) {\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n printError(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n process.exit(err.exitCode);\n }\n throw err;\n }\n return;\n }\n\n const apiUrl = resolveApiUrl(opts.apiUrl);\n\n try {\n const result = await loginWithDeviceFlow({\n apiUrl,\n clientName: opts.clientName,\n onVerification: (info) => {\n if (mode === \"pretty\") {\n console.log();\n printInfo(\"To connect, open the verification page and enter this code:\");\n console.log();\n console.log(` ${chalk.cyan.underline(info.verificationUri)}`);\n console.log();\n console.log(` ${chalk.bold.white(info.userCode)}`);\n console.log();\n printInfo(`Waiting for approval… (code expires in ${Math.round(info.expiresInSeconds / 60)} minutes)`);\n } else {\n // JSON mode: emit the verification info to stderr so a wrapping\n // agent can surface it to its human while stdout stays reserved\n // for the final result object.\n process.stderr.write(\n JSON.stringify({\n event: \"verification_required\",\n verificationUri: info.verificationUri,\n verificationUriComplete: info.verificationUriComplete,\n userCode: info.userCode,\n expiresIn: info.expiresInSeconds,\n }) + \"\\n\"\n );\n }\n\n // Best-effort convenience in a terminal; the printed URL + code are\n // the real path (the whole point of the flow is that THIS machine\n // may have no browser).\n if (mode === \"pretty\" && opts.open) {\n open(info.verificationUriComplete).catch(() => {});\n }\n },\n });\n\n const mcpConfig = opts.printMcpConfig ? buildMcpConfig(apiUrl, result.token) : undefined;\n\n if (mode === \"pretty\") {\n printSuccess(\"Connected!\");\n printKeyValue(\"Credentials\", getCredentialsPath());\n if (result.agentId) printKeyValue(\"Agent\", result.agentId);\n if (result.teamId) printKeyValue(\"Team ID\", result.teamId);\n if (result.expiresAt) printKeyValue(\"Token expires\", result.expiresAt);\n printInfo(\"This is a scoped agent token — it acts within what you approved, and your team can revoke it.\");\n if (mcpConfig) {\n console.log();\n printInfo(\"MCP server config (token expires ~7 days — re-run `anima login` to refresh):\");\n console.log();\n console.log(JSON.stringify(mcpConfig, null, 2));\n }\n } else {\n outputResult(mode, {\n success: true,\n action: \"logged_in\",\n tokenType: \"agent\",\n agentId: result.agentId,\n teamId: result.teamId,\n expiresAt: result.expiresAt,\n ...(mcpConfig ? { mcpConfig } : {}),\n });\n }\n } catch (err) {\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n printError(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n process.exit(err.exitCode);\n }\n throw err;\n }\n });\n\n/**\n * A remote MCP server entry an MCP-capable agent can add to talk to Anima\n * directly (no CLI in the loop). Exact keys vary by client; this is the common\n * `mcpServers` shape with a bearer header. The URL honors --api-url/config so a\n * local login yields a local config.\n */\nexport function buildMcpConfig(apiUrl: string, token: string) {\n return {\n mcpServers: {\n anima: {\n type: \"http\",\n url: `${apiUrl.replace(/\\/$/, \"\")}/v1/mcp`,\n headers: { Authorization: `Bearer ${token}` },\n },\n },\n };\n}\n","import { writeCredentials } from \"./store.js\";\nimport { authError, CliError, EXIT_CODES } from \"../api/errors.js\";\nimport { logEvent } from \"../output/log.js\";\n\n/**\n * OAuth 2.0 Device Authorization Grant (RFC 8628) against the Anima\n * authorization server. The flow needs no browser on this machine: the server\n * returns a short human code, the human approves at the verification URL (any\n * device), and this client polls the token endpoint until the decision lands.\n *\n * The issued token is a scoped AGENT token: it acts within the workspaces and\n * capabilities the human approved on the consent screen, and the team can\n * revoke it at any time. It expires after ~7 days; renewal is simply running\n * the flow again (re-approval reconnects to the same agent when the same\n * agent name is kept).\n */\n\nconst DEVICE_GRANT_TYPE = \"urn:ietf:params:oauth:grant-type:device_code\";\nconst DEFAULT_CLIENT_NAME = \"Anima CLI\";\n\nexport type DeviceVerificationInfo = {\n userCode: string;\n verificationUri: string;\n verificationUriComplete: string;\n expiresInSeconds: number;\n};\n\nexport type DeviceLoginResult = {\n token: string;\n teamId?: string;\n agentId?: string;\n expiresAt?: string;\n};\n\ntype DeviceLoginOptions = {\n apiUrl: string;\n clientName?: string;\n /** Called once with the code the human must enter — the caller renders it. */\n onVerification: (info: DeviceVerificationInfo) => void;\n /** Injectable for tests. */\n fetchFn?: typeof fetch;\n sleepFn?: (ms: number) => Promise<void>;\n};\n\nconst defaultSleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));\n\n/** Decode a JWT payload without verification (display/bookkeeping only). */\nfunction decodeJwtPayload(token: string): Record<string, unknown> | undefined {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) return undefined;\n return JSON.parse(Buffer.from(parts[1], \"base64url\").toString(\"utf-8\"));\n } catch {\n return undefined;\n }\n}\n\nexport async function loginWithDeviceFlow(options: DeviceLoginOptions): Promise<DeviceLoginResult> {\n const fetchFn = options.fetchFn ?? fetch;\n const sleep = options.sleepFn ?? defaultSleep;\n const base = options.apiUrl.replace(/\\/$/, \"\");\n\n // Step 1 — start the flow. No client registration: the server namespaces\n // device-flow agents itself; client_name is display-only on the consent page.\n const startUrl = `${base}/oauth/device_authorization`;\n logEvent(\"device_authorization_request\", { url: startUrl });\n const startResponse = await fetchFn(startUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({ client_name: options.clientName ?? DEFAULT_CLIENT_NAME }).toString(),\n });\n logEvent(\"device_authorization_response\", { url: startUrl, status: startResponse.status });\n\n if (!startResponse.ok) {\n const detail = await startResponse.text().catch(() => \"\");\n logEvent(\"device_authorization_failed\", { url: startUrl, status: startResponse.status, body: detail.slice(0, 500) });\n const hint =\n startResponse.status === 404\n ? ` — no device endpoint at ${startUrl}. Check --api-url points to an API that has the device grant deployed.`\n : \"\";\n throw new CliError(\n \"API_ERROR\",\n `Device authorization failed (HTTP ${startResponse.status})${hint}`,\n EXIT_CODES.API_ERROR\n );\n }\n\n const start = (await startResponse.json()) as {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n expires_in: number;\n interval: number;\n };\n\n options.onVerification({\n userCode: start.user_code,\n verificationUri: start.verification_uri,\n verificationUriComplete: start.verification_uri_complete,\n expiresInSeconds: start.expires_in,\n });\n\n // Step 2 — poll until the human decides. The server enforces pacing:\n // slow_down means add 5 seconds to the interval (RFC 8628 §3.5).\n let intervalMs = Math.max(1, start.interval) * 1000;\n const deadline = Date.now() + start.expires_in * 1000;\n\n while (Date.now() < deadline) {\n await sleep(intervalMs);\n\n const pollResponse = await fetchFn(`${base}/oauth/token`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: DEVICE_GRANT_TYPE,\n device_code: start.device_code,\n }).toString(),\n });\n\n const body = (await pollResponse.json()) as Record<string, unknown>;\n logEvent(\"device_token_poll\", { status: pollResponse.status, error: body.error });\n\n if (pollResponse.ok && typeof body.access_token === \"string\") {\n const token = body.access_token;\n const claims = decodeJwtPayload(token);\n const result: DeviceLoginResult = {\n token,\n teamId: typeof claims?.team_id === \"string\" ? claims.team_id : undefined,\n agentId: typeof claims?.agent_id === \"string\" ? claims.agent_id : undefined,\n expiresAt:\n typeof claims?.exp === \"number\" ? new Date(claims.exp * 1000).toISOString() : undefined,\n };\n\n writeCredentials({\n token: result.token,\n teamId: result.teamId,\n tokenType: \"agent\",\n agentId: result.agentId,\n expiresAt: result.expiresAt,\n });\n\n return result;\n }\n\n switch (body.error) {\n case \"authorization_pending\":\n continue;\n case \"slow_down\":\n intervalMs += 5000;\n continue;\n case \"access_denied\":\n throw authError(\"The authorization request was denied.\");\n case \"expired_token\":\n throw authError(\"The device code expired before approval. Run the login again.\");\n default:\n throw new CliError(\n \"API_ERROR\",\n `Unexpected token response: ${body.error ?? `HTTP ${pollResponse.status}`}`,\n EXIT_CODES.API_ERROR\n );\n }\n }\n\n throw authError(\"The device code expired before approval. Run the login again.\");\n}\n","import { writeCredentials } from \"./store.js\";\nimport { CliError, EXIT_CODES } from \"../api/errors.js\";\nimport { logEvent } from \"../output/log.js\";\n\n/**\n * Invite-door redemption: exchange a pre-approved, single-use invite code for\n * a scoped agent token (`grant_type=urn:ietf:params:oauth:grant-type:\n * pre-authorized_code`) and store it exactly like the device login — so\n * `logout`, `mcp-config`, `get-git-token`, and the rest of the CLI work\n * identically for invited agents.\n *\n * The human mints the invite in-app and hands the agent a URL like\n * `https://public-api.animaapp.com/invite/<code>.md`; this accepts either\n * that full URL or the bare code. A single POST returns the token directly —\n * there is no polling and no browser step (consent already happened at mint).\n */\n\nconst PRE_AUTHORIZED_GRANT = \"urn:ietf:params:oauth:grant-type:pre-authorized_code\";\n\nexport type InviteLoginResult = {\n token: string;\n teamId?: string;\n agentId?: string;\n expiresAt?: string;\n};\n\nexport type ParsedInvite = {\n code: string;\n /** Origin of the invite URL, when a URL was given — the API the invite was minted on. */\n origin?: string;\n};\n\n/**\n * Accept the invite URL (`…/invite/<code>.md`), the same without `.md`, or the\n * bare code. When a URL is given, its origin is returned too: the invite was\n * minted on that host, so it is the right API base unless the caller overrides.\n */\nexport function parseInvite(input: string): ParsedInvite {\n const trimmed = input.trim();\n if (/^https?:\\/\\//i.test(trimmed)) {\n let url: URL;\n try {\n url = new URL(trimmed);\n } catch {\n throw new CliError(\"VALIDATION_ERROR\", `Not a valid invite URL: ${trimmed}`, EXIT_CODES.VALIDATION_ERROR);\n }\n const last = url.pathname.split(\"/\").filter(Boolean).pop() ?? \"\";\n const code = last.replace(/\\.md$/, \"\");\n if (!code) {\n throw new CliError(\n \"VALIDATION_ERROR\",\n \"The invite URL carries no code — expected …/invite/<code>.md\",\n EXIT_CODES.VALIDATION_ERROR\n );\n }\n return { code, origin: url.origin };\n }\n return { code: trimmed.replace(/\\.md$/, \"\") };\n}\n\ntype InviteLoginOptions = {\n apiUrl: string;\n invite: string;\n /** Injectable for tests. */\n fetchFn?: typeof fetch;\n};\n\n/** Decode a JWT payload without verification (display/bookkeeping only). */\nfunction decodeJwtPayload(token: string): Record<string, unknown> | undefined {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) return undefined;\n return JSON.parse(Buffer.from(parts[1], \"base64url\").toString(\"utf-8\"));\n } catch {\n return undefined;\n }\n}\n\nexport async function loginWithInvite(options: InviteLoginOptions): Promise<InviteLoginResult> {\n const fetchFn = options.fetchFn ?? fetch;\n const { code } = parseInvite(options.invite);\n const base = options.apiUrl.replace(/\\/$/, \"\");\n\n const tokenUrl = `${base}/oauth/token`;\n logEvent(\"invite_redeem_request\", { url: tokenUrl });\n const response = await fetchFn(tokenUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: PRE_AUTHORIZED_GRANT,\n \"pre-authorized_code\": code,\n }).toString(),\n });\n\n const body = (await response.json().catch(() => ({}))) as Record<string, unknown>;\n logEvent(\"invite_redeem_response\", { status: response.status, error: body.error });\n\n if (!response.ok || typeof body.access_token !== \"string\") {\n // The server's error_description is prompt-ware written for the agent —\n // surface it verbatim.\n const description =\n typeof body.error_description === \"string\"\n ? body.error_description\n : `Invite redemption failed (HTTP ${response.status})`;\n throw new CliError(\"AUTH_INVALID\", description, EXIT_CODES.AUTH_ERROR);\n }\n\n const token = body.access_token;\n const claims = decodeJwtPayload(token);\n const result: InviteLoginResult = {\n token,\n teamId: typeof claims?.team_id === \"string\" ? claims.team_id : undefined,\n agentId: typeof claims?.agent_id === \"string\" ? claims.agent_id : undefined,\n expiresAt: typeof claims?.exp === \"number\" ? new Date(claims.exp * 1000).toISOString() : undefined,\n };\n\n // Same credential shape as the device login — the whole CLI surface\n // (logout, mcp-config, get-git-token, …) works identically from here.\n writeCredentials({\n token: result.token,\n teamId: result.teamId,\n tokenType: \"agent\",\n agentId: result.agentId,\n expiresAt: result.expiresAt,\n });\n\n return result;\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { writeCredentials, clearStorage, readCredentials, getCredentialsPath, extractTeamIdFromJWT } from \"../auth/store.js\";\nimport { resolveAuth } from \"../auth/token.js\";\nimport { detectOutputMode, outputResult, outputError } from \"../output/formatter.js\";\nimport { printSuccess, printError, printKeyValue, printInfo } from \"../output/pretty.js\";\nimport { CliError } from \"../api/errors.js\";\n\nconst DEFAULT_API_URL = \"https://public-api.animaapp.com\";\n\nexport const authCommand = new Command(\"auth\")\n .description(\"Manage authentication\")\n .option(\"--token <token>\", \"Store Anima API token\")\n .option(\"--figma-token <token>\", \"Store Figma personal access token\")\n .option(\"--team-id <teamId>\", \"Team ID to associate with token\")\n .option(\"--status\", \"Show current auth status\")\n .option(\"--logout\", \"Clear stored credentials (alias for `anima logout`)\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--api-url <url>\", \"API base URL\", DEFAULT_API_URL)\n .action(async (opts) => {\n const mode = detectOutputMode(opts);\n\n try {\n if (opts.token || opts.figmaToken) {\n const toSave: Record<string, string> = {};\n\n if (opts.token) {\n toSave.token = opts.token;\n toSave.teamId = opts.teamId ?? extractTeamIdFromJWT(opts.token) ?? \"\";\n }\n if (opts.figmaToken) {\n toSave.figmaToken = opts.figmaToken;\n }\n\n writeCredentials(toSave);\n\n if (mode === \"pretty\") {\n printSuccess(\"Credentials saved to \" + getCredentialsPath());\n if (opts.token) {\n printKeyValue(\"Anima token\", \"saved\");\n if (toSave.teamId) printKeyValue(\"Team ID\", toSave.teamId);\n }\n if (opts.figmaToken) {\n printKeyValue(\"Figma token\", \"saved\");\n }\n } else {\n outputResult(mode, {\n success: true,\n action: \"token_saved\",\n path: getCredentialsPath(),\n ...(opts.token ? { teamId: toSave.teamId } : {}),\n ...(opts.figmaToken ? { figmaToken: true } : {}),\n });\n }\n return;\n }\n\n if (opts.logout) {\n const deleted = clearStorage();\n if (mode === \"pretty\") {\n if (deleted) {\n printSuccess(\"Credentials cleared\");\n } else {\n printInfo(\"No stored credentials found\");\n }\n } else {\n outputResult(mode, { success: true, action: \"logged_out\", hadCredentials: deleted });\n }\n return;\n }\n\n if (opts.status) {\n try {\n const auth = resolveAuth();\n const creds = readCredentials();\n const sourceName = auth.source === \"env\" ? \"ANIMA_API_TOKEN env var\" : getCredentialsPath();\n const hasFigma = !!(process.env.FIGMA_TOKEN || creds?.figmaToken);\n if (mode === \"pretty\") {\n printSuccess(\"Token configured\");\n printKeyValue(\"Source\", sourceName);\n printKeyValue(\"Anima token\", auth.token.slice(0, 12) + \"...\" + auth.token.slice(-4));\n printKeyValue(\"Token type\", auth.tokenType === \"agent\" ? \"agent (scoped, revocable)\" : \"personal/API\");\n if (creds?.tokenType === \"agent\" && creds.expiresAt) printKeyValue(\"Expires\", creds.expiresAt);\n if (auth.teamId) printKeyValue(\"Team ID\", auth.teamId);\n printKeyValue(\"Figma token\", hasFigma ? \"configured\" : \"not set (needed for codegen/f2c)\");\n } else {\n outputResult(mode, {\n success: true,\n source: auth.source,\n tokenType: auth.tokenType ?? \"personal\",\n tokenPreview: auth.token.slice(0, 12) + \"...\" + auth.token.slice(-4),\n teamId: auth.teamId,\n expiresAt: creds?.tokenType === \"agent\" ? creds.expiresAt : undefined,\n figmaToken: hasFigma,\n });\n }\n } catch (err) {\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n printError(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n } else {\n throw err;\n }\n }\n return;\n }\n\n // No flag: show help\n if (mode === \"pretty\") {\n console.log();\n printInfo(\"Auth commands:\");\n console.log(` ${chalk.cyan(\"anima login\")} Log in (device flow — approve on any browser)`);\n console.log(` ${chalk.cyan(\"anima logout\")} Clear all credentials`);\n console.log(` ${chalk.cyan(\"anima auth --status\")} Check auth status`);\n console.log(` ${chalk.cyan(\"anima auth --figma-token <T>\")} Save Figma token (needed for codegen/f2c)`);\n console.log();\n console.log(` Figma token: ${chalk.cyan.underline(\"https://www.figma.com\")} > Settings > Personal access tokens`);\n console.log();\n } else {\n outputResult(mode, {\n success: true,\n message: \"Run `anima login`, or use --status / --logout / --figma-token\",\n });\n }\n } catch (err) {\n if (err instanceof CliError) {\n if (mode === \"pretty\") {\n printError(err.message);\n } else {\n outputError(mode, { code: err.code, message: err.message });\n }\n process.exit(err.exitCode);\n }\n throw err;\n }\n });\n","import { Command } from \"commander\";\nimport { clearStorage, getCredentialsPath } from \"../auth/store.js\";\nimport { deleteConfig } from \"../config/store.js\";\nimport { detectOutputMode, outputResult } from \"../output/formatter.js\";\nimport { printSuccess, printInfo } from \"../output/pretty.js\";\n\n/**\n * `anima logout` — clear all stored credentials from this machine. Removes the\n * credentials file (Anima token, Figma token, agent metadata) and the config\n * directory. Note: this only forgets the token locally; to actually disable an\n * agent, revoke it from your team settings.\n */\nexport const logoutCommand = new Command(\"logout\")\n .description(\"Clear all stored credentials (Anima + Figma tokens) from this machine\")\n .option(\"--json\", \"Output as JSON\")\n .action((opts) => {\n const mode = detectOutputMode(opts);\n const hadCredentials = clearStorage();\n // Full machine reset: logout removes stored config too (e.g. the api-url\n // persisted by `login --invite`), so the machine is pristine afterwards.\n deleteConfig();\n\n if (mode === \"pretty\") {\n if (hadCredentials) {\n printSuccess(\"Logged out — all credentials cleared from \" + getCredentialsPath());\n } else {\n printInfo(\"No stored credentials found\");\n }\n } else {\n outputResult(mode, { success: true, action: \"logged_out\", hadCredentials });\n }\n });\n","import { Command } from \"commander\";\nimport {\n readConfig,\n setConfig,\n unsetConfig,\n getConfigPath,\n isConfigKey,\n configKeys,\n CONFIG_KEYS,\n resolveApiUrl,\n DEFAULT_API_URL,\n type ConfigKey,\n} from \"../config/store.js\";\nimport { detectOutputMode, outputResult } from \"../output/formatter.js\";\nimport { printSuccess, printInfo, printKeyValue } from \"../output/pretty.js\";\nimport { validationError } from \"../api/errors.js\";\n\n/**\n * `anima config` — store non-secret CLI preferences in\n * ~/.config/anima/config.json so you don't have to pass flags like `--api-url`\n * every time. Resolution precedence for the API URL: flag → ANIMA_API_URL env →\n * stored config → default.\n *\n * anima config set api-url http://localhost:3789\n * anima config get api-url\n * anima config list\n * anima config unset api-url\n */\nexport const configCommand = new Command(\"config\").description(\n `Store CLI preferences (keys: ${configKeys().join(\", \")})`\n);\n\nconfigCommand\n .command(\"set <key> <value>\")\n .description(\"Set a config value\")\n .option(\"--json\", \"Output as JSON\")\n .action((key: string, value: string, opts) => {\n const mode = detectOutputMode(opts);\n assertKey(key);\n if (key === \"api-url\") assertUrl(value);\n setConfig(key, value);\n\n if (mode === \"pretty\") printSuccess(`Set ${key} = ${value}`);\n else outputResult(mode, { success: true, action: \"config_set\", key, value });\n });\n\nconfigCommand\n .command(\"get <key>\")\n .description(\"Print a config value\")\n .option(\"--json\", \"Output as JSON\")\n .action((key: string, opts) => {\n const mode = detectOutputMode(opts);\n assertKey(key);\n const value = readConfig()[CONFIG_KEYS[key]];\n\n if (mode === \"pretty\") {\n if (value) console.log(value);\n else printInfo(`${key} is not set`);\n } else {\n outputResult(mode, { success: true, key, value: value ?? null });\n }\n });\n\nconfigCommand\n .command(\"list\")\n .alias(\"ls\")\n .description(\"Show all config values and where the API URL resolves from\")\n .option(\"--json\", \"Output as JSON\")\n .action((opts) => {\n const mode = detectOutputMode(opts);\n const config = readConfig();\n const resolvedApiUrl = resolveApiUrl();\n\n if (mode === \"pretty\") {\n printInfo(\"Config: \" + getConfigPath());\n printKeyValue(\"api-url\", config.apiUrl ?? `(default) ${DEFAULT_API_URL}`);\n if (process.env.ANIMA_API_URL) {\n printInfo(`ANIMA_API_URL env is set — it overrides config (effective: ${resolvedApiUrl})`);\n }\n } else {\n outputResult(mode, {\n success: true,\n path: getConfigPath(),\n config,\n resolved: { apiUrl: resolvedApiUrl },\n });\n }\n });\n\nconfigCommand\n .command(\"unset <key>\")\n .description(\"Remove a config value\")\n .option(\"--json\", \"Output as JSON\")\n .action((key: string, opts) => {\n const mode = detectOutputMode(opts);\n assertKey(key);\n const removed = unsetConfig(key);\n\n if (mode === \"pretty\") {\n if (removed) printSuccess(`Unset ${key}`);\n else printInfo(`${key} was not set`);\n } else {\n outputResult(mode, { success: true, action: \"config_unset\", key, removed });\n }\n });\n\nfunction assertKey(key: string): asserts key is ConfigKey {\n if (!isConfigKey(key)) {\n throw validationError(`Unknown config key \"${key}\". Valid keys: ${configKeys().join(\", \")}`);\n }\n}\n\nfunction assertUrl(value: string): void {\n try {\n new URL(value);\n } catch {\n throw validationError(`\"${value}\" is not a valid URL`);\n }\n}\n"],"mappings":"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","names":["Command","chalk","fs","path","path","fs","path","os","CONFIG_DIR","chalk","Command","Command","Command","fs","path","Command","Command","chalk","Command","chalk","Command","Command","chalk","decodeJwtPayload","Command","apiUrl","chalk","Command","Command","chalk","DEFAULT_API_URL","Command","chalk","Command","Command","Command","Command","Command"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@animaapp/cli",
3
- "version": "0.3.10",
3
+ "version": "0.4.0",
4
4
  "description": "Generate production-ready apps from prompts, URLs, or Figma designs",
5
5
  "type": "module",
6
6
  "bin": {
@@ -24,6 +24,7 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@modelcontextprotocol/sdk": "^1.26.0",
27
+ "adm-zip": "^0.6.0",
27
28
  "chalk": "^5.3.0",
28
29
  "commander": "^12.1.0",
29
30
  "open": "^10.1.0",
@@ -31,6 +32,7 @@
31
32
  "zod": "^3.23.8"
32
33
  },
33
34
  "devDependencies": {
35
+ "@types/adm-zip": "^0.5.8",
34
36
  "@types/node": "^20.14.0",
35
37
  "@typescript-eslint/eslint-plugin": "^8.46.0",
36
38
  "@typescript-eslint/parser": "^8.46.0",