@animaapp/cli 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command10 } from "commander";
4
+ import { Command as Command13 } from "commander";
5
5
 
6
6
  // src/commands/create.ts
7
7
  import { Command } from "commander";
@@ -271,7 +271,7 @@ function connectionError(err) {
271
271
  const message = err instanceof Error ? err.message : String(err);
272
272
  return new CliError(
273
273
  "CONNECTION_ERROR",
274
- `Could not reach the Anima MCP endpoint: ${message}`,
274
+ `Could not reach the AgentGrid MCP endpoint: ${message}`,
275
275
  1
276
276
  );
277
277
  }
@@ -370,7 +370,7 @@ function printSessionResult(result) {
370
370
  printSuccess("Playground created successfully!");
371
371
  printKeyValue("Session ID", result.sessionId);
372
372
  if (result.playgroundUrl) {
373
- printKeyValue("Playground", chalk.cyan.underline(result.playgroundUrl));
373
+ printKeyValue("Your playground", chalk.cyan.underline(result.playgroundUrl));
374
374
  }
375
375
  if (result.tokenUsage) {
376
376
  printKeyValue("Token usage", result.tokenUsage.toLocaleString());
@@ -514,13 +514,32 @@ function collectProjectSource(fromPath) {
514
514
  return { kind: "files", files, fileCount: paths.length };
515
515
  }
516
516
 
517
+ // src/utils/playgroundUrl.ts
518
+ var PLAYGROUND_BASE = "https://dev.animaapp.com/chat";
519
+ function parsePlaygroundUrl(input) {
520
+ if (!input.includes("/")) {
521
+ return input;
522
+ }
523
+ try {
524
+ const url = new URL(input);
525
+ const parts = url.pathname.split("/").filter(Boolean);
526
+ const markerIndex = parts.findIndex((p) => p === "chat" || p === "artifacts");
527
+ if (markerIndex !== -1 && markerIndex + 1 < parts.length) {
528
+ return parts[markerIndex + 1];
529
+ }
530
+ return parts[parts.length - 1];
531
+ } catch {
532
+ return input;
533
+ }
534
+ }
535
+
517
536
  // src/config/store.ts
518
537
  import fs3 from "fs";
519
538
  import path3 from "path";
520
539
  import os2 from "os";
521
540
  var CONFIG_DIR2 = path3.join(os2.homedir(), ".config", "anima");
522
541
  var CONFIG_FILE = path3.join(CONFIG_DIR2, "config.json");
523
- var DEFAULT_API_URL = "https://public-api.animaapp.com";
542
+ var DEFAULT_API_URL = "https://api.agentgrid.io";
524
543
  var CONFIG_KEYS = {
525
544
  "api-url": "apiUrl"
526
545
  };
@@ -570,12 +589,11 @@ function resolveApiUrl(flagValue) {
570
589
  }
571
590
 
572
591
  // src/commands/create.ts
573
- var PLAYGROUND_BASE = "https://dev.animaapp.com/chat";
574
592
  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)"
593
+ "Create a playground from your own code: empty for code you'll push (instant) or import your existing code (instant). Also supports AI generation: p2c/l2c/f2c (3-7 min)."
576
594
  ).requiredOption(
577
595
  "-t, --type <type>",
578
- "p2c, l2c, f2c, empty (empty repo you push to), or import (create FROM your code \u2014 use --from)"
596
+ "empty (empty repo you push to), import (create FROM your code \u2014 use --from), or AI-generated: p2c, l2c, f2c"
579
597
  ).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
598
  "--framework <fw>",
581
599
  "html | react \u2014 the only supported frameworks. REQUIRED for empty (declare react if you will push React code); detected from package.json for import"
@@ -690,8 +708,8 @@ ${result.nextSteps}` : message, result);
690
708
  }
691
709
  });
692
710
  function validateCreateOptions(type, opts) {
693
- if (!["p2c", "l2c", "f2c", "empty", "import"].includes(type)) {
694
- throw validationError(`Invalid type "${type}". Must be p2c, l2c, f2c, empty, or import.`);
711
+ if (!["empty", "import", "p2c", "l2c", "f2c"].includes(type)) {
712
+ throw validationError(`Invalid type "${type}". Must be empty, import, p2c, l2c, or f2c.`);
695
713
  }
696
714
  if (type === "p2c" && !opts.prompt) {
697
715
  throw validationError("--prompt is required for p2c type");
@@ -764,9 +782,86 @@ function buildCreateArgs(type, opts) {
764
782
  return args;
765
783
  }
766
784
 
767
- // src/commands/publish.ts
785
+ // src/commands/list.ts
768
786
  import { Command as Command2 } from "commander";
769
- var publishCommand = new Command2("publish").description("Deploy playground to live URL or npm package (1-3 min)").argument("<sessionId>", "Session ID from create command").option("--mode <mode>", "webapp | designSystem", "webapp").option("--package-name <name>", "NPM package name (designSystem mode)").option("--package-version <version>", "NPM package version (designSystem mode)").option("--json", "Output as JSON").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 (sessionId, opts) => {
787
+ import chalk3 from "chalk";
788
+ var listCommand = new Command2("list").aliases(["ls", "artifacts"]).description(
789
+ "List your team's artifacts (most-recently-updated first) so you can resume existing work."
790
+ ).option("--json", "Output as JSON").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) => {
791
+ const mode = detectOutputMode(opts);
792
+ initLogger(opts.logFile);
793
+ try {
794
+ const auth = resolveAuth();
795
+ const result = await withMcp(
796
+ { apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId },
797
+ (client) => client.callTool("workspace-list_artifacts", {})
798
+ );
799
+ if (!result.success) {
800
+ const message = result.reason || result.error || "Could not list artifacts";
801
+ throw apiError(message, result);
802
+ }
803
+ const artifacts = result.artifacts ?? [];
804
+ logEvent("artifacts_listed", { count: artifacts.length, truncated: result.truncated ?? false });
805
+ if (mode === "pretty") {
806
+ if (artifacts.length === 0) {
807
+ console.log();
808
+ console.log(
809
+ " No artifacts yet \u2014 create one with `create -t empty` or `create -t import`."
810
+ );
811
+ console.log();
812
+ } else {
813
+ console.log();
814
+ for (const a of artifacts) {
815
+ console.log(` ${chalk3.bold(a.name)} ${chalk3.gray(`(${a.type})`)}`);
816
+ if (a.sessionId) {
817
+ console.log(` ${chalk3.gray("session:")} ${a.sessionId}`);
818
+ }
819
+ console.log(` ${chalk3.gray("updated:")} ${formatUpdatedAt(a.updatedAt)}`);
820
+ if (a.sessionId) {
821
+ console.log(
822
+ ` ${chalk3.cyan.underline(`${PLAYGROUND_BASE}/${a.sessionId}`)}`
823
+ );
824
+ }
825
+ console.log();
826
+ }
827
+ if (result.truncated) {
828
+ console.log(
829
+ chalk3.yellow(" The list was capped \u2014 some artifacts are not shown.")
830
+ );
831
+ console.log();
832
+ }
833
+ }
834
+ } else {
835
+ outputResult(mode, {
836
+ success: true,
837
+ workspaceId: result.workspaceId,
838
+ artifacts,
839
+ truncated: result.truncated ?? false
840
+ });
841
+ }
842
+ } catch (err) {
843
+ if (err instanceof CliError) {
844
+ if (mode === "pretty") {
845
+ console.error(err.message);
846
+ } else {
847
+ outputError(mode, { code: err.code, message: err.message });
848
+ }
849
+ process.exit(err.exitCode);
850
+ }
851
+ throw err;
852
+ }
853
+ });
854
+ function formatUpdatedAt(iso) {
855
+ const then = new Date(iso).getTime();
856
+ if (Number.isNaN(then)) return iso;
857
+ const seconds = Math.max(0, Math.round((Date.now() - then) / 1e3));
858
+ const relative2 = seconds < 60 ? "just now" : seconds < 3600 ? `${Math.floor(seconds / 60)}m ago` : seconds < 86400 ? `${Math.floor(seconds / 3600)}h ago` : `${Math.floor(seconds / 86400)}d ago`;
859
+ return `${relative2} (${iso})`;
860
+ }
861
+
862
+ // src/commands/publish.ts
863
+ import { Command as Command3 } from "commander";
864
+ var publishCommand = new Command3("publish").description("Deploy playground to live URL or npm package (1-3 min)").argument("<sessionId>", "Session ID from create command").option("--mode <mode>", "webapp | designSystem", "webapp").option("--package-name <name>", "NPM package name (designSystem mode)").option("--package-version <version>", "NPM package version (designSystem mode)").option("--json", "Output as JSON").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 (sessionId, opts) => {
770
865
  const mode = detectOutputMode(opts);
771
866
  initLogger(opts.logFile);
772
867
  const progress = new ProgressReporter(mode, opts.verbose);
@@ -836,7 +931,7 @@ var publishCommand = new Command2("publish").description("Deploy playground to l
836
931
  });
837
932
 
838
933
  // src/commands/codegen.ts
839
- import { Command as Command3 } from "commander";
934
+ import { Command as Command4 } from "commander";
840
935
 
841
936
  // src/utils/files.ts
842
937
  import fs4 from "fs";
@@ -864,7 +959,7 @@ function writeFilesToDisk(files, outputDir) {
864
959
  }
865
960
 
866
961
  // src/commands/codegen.ts
867
- var codegenCommand = new Command3("codegen").description("Convert Figma design to code files (no playground)").requiredOption("--file-key <key>", "Figma file key or URL").option("--nodes <nodes>", "Figma node IDs, comma-separated").option("--figma-token <token>", "Figma personal access token (or set FIGMA_TOKEN env var)").option("-o, --output <dir>", "Output directory", "./generated").option("--framework <fw>", "react | html", "react").option("--styling <style>", "tailwind | plain_css", "tailwind").option("--language <lang>", "typescript | javascript").option("--ui-library <lib>", "mui | antd | shadcn | clean_react").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) => {
962
+ var codegenCommand = new Command4("codegen").description("Convert Figma design to code files (no playground)").requiredOption("--file-key <key>", "Figma file key or URL").option("--nodes <nodes>", "Figma node IDs, comma-separated").option("--figma-token <token>", "Figma personal access token (or set FIGMA_TOKEN env var)").option("-o, --output <dir>", "Output directory", "./generated").option("--framework <fw>", "react | html", "react").option("--styling <style>", "tailwind | plain_css", "tailwind").option("--language <lang>", "typescript | javascript").option("--ui-library <lib>", "mui | antd | shadcn | clean_react").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) => {
868
963
  const mode = detectOutputMode(opts);
869
964
  initLogger(opts.logFile);
870
965
  const progress = new ProgressReporter(mode, opts.verbose);
@@ -936,26 +1031,8 @@ var codegenCommand = new Command3("codegen").description("Convert Figma design t
936
1031
  });
937
1032
 
938
1033
  // src/commands/getGitToken.ts
939
- import { Command as Command4 } from "commander";
940
- import chalk3 from "chalk";
941
-
942
- // src/utils/playgroundUrl.ts
943
- function parsePlaygroundUrl(input) {
944
- if (!input.includes("/")) {
945
- return input;
946
- }
947
- try {
948
- const url = new URL(input);
949
- const parts = url.pathname.split("/").filter(Boolean);
950
- const chatIndex = parts.indexOf("chat");
951
- if (chatIndex !== -1 && chatIndex + 1 < parts.length) {
952
- return parts[chatIndex + 1];
953
- }
954
- return parts[parts.length - 1];
955
- } catch {
956
- return input;
957
- }
958
- }
1034
+ import { Command as Command5 } from "commander";
1035
+ import chalk4 from "chalk";
959
1036
 
960
1037
  // src/utils/gitToken.ts
961
1038
  function preview(payload) {
@@ -989,7 +1066,7 @@ function parseGitTokenResponse(payload) {
989
1066
  }
990
1067
 
991
1068
  // src/commands/getGitToken.ts
992
- var getGitTokenCommand = new Command4("get-git-token").description("Mint a short-lived git remote URL for a playground (clone/push with git)").argument("<playgroundUrl>", "Playground URL or session ID").option("--json", "Output as JSON").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 (playgroundUrl, opts) => {
1069
+ var getGitTokenCommand = new Command5("get-git-token").description("Mint a short-lived git remote URL for a playground (clone/push with git)").argument("<playgroundUrl>", "Playground URL or session ID").option("--json", "Output as JSON").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 (playgroundUrl, opts) => {
993
1070
  const mode = detectOutputMode(opts);
994
1071
  initLogger(opts.logFile);
995
1072
  const progress = new ProgressReporter(mode, opts.verbose);
@@ -1006,7 +1083,7 @@ var getGitTokenCommand = new Command4("get-git-token").description("Mint a short
1006
1083
  progress.succeed(`Git access granted (${grant.access === "rw" ? "read-write" : "read-only"})`);
1007
1084
  if (mode === "pretty") {
1008
1085
  console.log();
1009
- console.log(` ${chalk3.cyan(`git clone ${grant.gitRemoteUrl}`)}`);
1086
+ console.log(` ${chalk4.cyan(`git clone ${grant.gitRemoteUrl}`)}`);
1010
1087
  console.log();
1011
1088
  if (grant.access === "rw") {
1012
1089
  console.log(" Commit and push to update the live playground.");
@@ -1016,7 +1093,7 @@ var getGitTokenCommand = new Command4("get-git-token").description("Mint a short
1016
1093
  if (grant.expiresAt) {
1017
1094
  console.log(
1018
1095
  ` The URL embeds a token that expires at ${grant.expiresAt} and cannot be renewed;
1019
- re-run this command and ${chalk3.cyan("git remote set-url origin <new url>")} to keep pushing.`
1096
+ re-run this command and ${chalk4.cyan("git remote set-url origin <new url>")} to keep pushing.`
1020
1097
  );
1021
1098
  }
1022
1099
  console.log(" Treat the URL as a secret \u2014 it grants access to this playground.");
@@ -1045,16 +1122,16 @@ var getGitTokenCommand = new Command4("get-git-token").description("Mint a short
1045
1122
  });
1046
1123
 
1047
1124
  // src/commands/mcpConfig.ts
1048
- import { Command as Command6 } from "commander";
1125
+ import { Command as Command7 } from "commander";
1049
1126
 
1050
1127
  // src/commands/login.ts
1051
- import { Command as Command5 } from "commander";
1052
- import chalk4 from "chalk";
1128
+ import { Command as Command6 } from "commander";
1129
+ import chalk5 from "chalk";
1053
1130
  import open from "open";
1054
1131
 
1055
1132
  // src/auth/device.ts
1056
1133
  var DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
1057
- var DEFAULT_CLIENT_NAME = "Anima CLI";
1134
+ var DEFAULT_CLIENT_NAME = "AgentGrid CLI";
1058
1135
  var defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1059
1136
  function decodeJwtPayload(token) {
1060
1137
  try {
@@ -1219,7 +1296,7 @@ async function loginWithInvite(options) {
1219
1296
  }
1220
1297
 
1221
1298
  // src/commands/login.ts
1222
- var loginCommand = new Command5("login").description("Log in via the device flow, or redeem a pre-approved invite with --invite").option("--invite <url-or-code>", "Redeem an invite link (\u2026/invite/<code>.md) or bare code \u2014 no approval step").option("--client-name <name>", "How this CLI appears on the consent screen", "Anima CLI").option("--no-open", "Do not try to open the verification page in a browser").option("--json", "Output as JSON").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").option(
1299
+ var loginCommand = new Command6("login").description("Log in via the device flow, or redeem a pre-approved invite with --invite").option("--invite <url-or-code>", "Redeem an invite link (\u2026/invite/<code>.md) or bare code \u2014 no approval step").option("--client-name <name>", "How this CLI appears on the consent screen", "AgentGrid CLI").option("--no-open", "Do not try to open the verification page in a browser").option("--json", "Output as JSON").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").option(
1223
1300
  "--print-mcp-config",
1224
1301
  "After login, also print an MCP server config (includes the token) to paste into an MCP-capable agent"
1225
1302
  ).action(async (opts) => {
@@ -1282,9 +1359,9 @@ var loginCommand = new Command5("login").description("Log in via the device flow
1282
1359
  console.log();
1283
1360
  printInfo("To connect, open the verification page and enter this code:");
1284
1361
  console.log();
1285
- console.log(` ${chalk4.cyan.underline(info.verificationUri)}`);
1362
+ console.log(` ${chalk5.cyan.underline(info.verificationUri)}`);
1286
1363
  console.log();
1287
- console.log(` ${chalk4.bold.white(info.userCode)}`);
1364
+ console.log(` ${chalk5.bold.white(info.userCode)}`);
1288
1365
  console.log();
1289
1366
  printInfo(`Waiting for approval\u2026 (code expires in ${Math.round(info.expiresInSeconds / 60)} minutes)`);
1290
1367
  } else {
@@ -1354,7 +1431,7 @@ function buildMcpConfig(apiUrl, token) {
1354
1431
  }
1355
1432
 
1356
1433
  // src/commands/mcpConfig.ts
1357
- var mcpConfigCommand = new Command6("mcp-config").description("Print an MCP server config from your stored credentials (run `login` first)").option("--json", "Output as JSON").option("--api-url <url>", "API base URL (overrides config / ANIMA_API_URL)").action(async (opts) => {
1434
+ var mcpConfigCommand = new Command7("mcp-config").description("Print an MCP server config from your stored credentials (run `login` first)").option("--json", "Output as JSON").option("--api-url <url>", "API base URL (overrides config / ANIMA_API_URL)").action(async (opts) => {
1358
1435
  const mode = detectOutputMode(opts);
1359
1436
  try {
1360
1437
  const auth = resolveAuth();
@@ -1391,10 +1468,10 @@ var mcpConfigCommand = new Command6("mcp-config").description("Print an MCP serv
1391
1468
  });
1392
1469
 
1393
1470
  // src/commands/auth.ts
1394
- import { Command as Command7 } from "commander";
1395
- import chalk5 from "chalk";
1396
- var DEFAULT_API_URL2 = "https://public-api.animaapp.com";
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) => {
1471
+ import { Command as Command8 } from "commander";
1472
+ import chalk6 from "chalk";
1473
+ var DEFAULT_API_URL2 = "https://api.agentgrid.io";
1474
+ var authCommand = new Command8("auth").description("Manage authentication").option("--token <token>", "Store AgentGrid 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) => {
1398
1475
  const mode = detectOutputMode(opts);
1399
1476
  try {
1400
1477
  if (opts.token || opts.figmaToken) {
@@ -1410,7 +1487,7 @@ var authCommand = new Command7("auth").description("Manage authentication").opti
1410
1487
  if (mode === "pretty") {
1411
1488
  printSuccess("Credentials saved to " + getCredentialsPath());
1412
1489
  if (opts.token) {
1413
- printKeyValue("Anima token", "saved");
1490
+ printKeyValue("AgentGrid token", "saved");
1414
1491
  if (toSave.teamId) printKeyValue("Team ID", toSave.teamId);
1415
1492
  }
1416
1493
  if (opts.figmaToken) {
@@ -1449,7 +1526,7 @@ var authCommand = new Command7("auth").description("Manage authentication").opti
1449
1526
  if (mode === "pretty") {
1450
1527
  printSuccess("Token configured");
1451
1528
  printKeyValue("Source", sourceName);
1452
- printKeyValue("Anima token", auth.token.slice(0, 12) + "..." + auth.token.slice(-4));
1529
+ printKeyValue("AgentGrid token", auth.token.slice(0, 12) + "..." + auth.token.slice(-4));
1453
1530
  printKeyValue("Token type", auth.tokenType === "agent" ? "agent (scoped, revocable)" : "personal/API");
1454
1531
  if (creds?.tokenType === "agent" && creds.expiresAt) printKeyValue("Expires", creds.expiresAt);
1455
1532
  if (auth.teamId) printKeyValue("Team ID", auth.teamId);
@@ -1481,12 +1558,12 @@ var authCommand = new Command7("auth").description("Manage authentication").opti
1481
1558
  if (mode === "pretty") {
1482
1559
  console.log();
1483
1560
  printInfo("Auth commands:");
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)`);
1561
+ console.log(` ${chalk6.cyan("anima login")} Log in (device flow \u2014 approve on any browser)`);
1562
+ console.log(` ${chalk6.cyan("anima logout")} Clear all credentials`);
1563
+ console.log(` ${chalk6.cyan("anima auth --status")} Check auth status`);
1564
+ console.log(` ${chalk6.cyan("anima auth --figma-token <T>")} Save Figma token (needed for codegen/f2c)`);
1488
1565
  console.log();
1489
- console.log(` Figma token: ${chalk5.cyan.underline("https://www.figma.com")} > Settings > Personal access tokens`);
1566
+ console.log(` Figma token: ${chalk6.cyan.underline("https://www.figma.com")} > Settings > Personal access tokens`);
1490
1567
  console.log();
1491
1568
  } else {
1492
1569
  outputResult(mode, {
@@ -1508,8 +1585,8 @@ var authCommand = new Command7("auth").description("Manage authentication").opti
1508
1585
  });
1509
1586
 
1510
1587
  // src/commands/logout.ts
1511
- import { Command as Command8 } from "commander";
1512
- var logoutCommand = new Command8("logout").description("Clear all stored credentials (Anima + Figma tokens) from this machine").option("--json", "Output as JSON").action((opts) => {
1588
+ import { Command as Command9 } from "commander";
1589
+ var logoutCommand = new Command9("logout").description("Clear all stored credentials (AgentGrid + Figma tokens) from this machine").option("--json", "Output as JSON").action((opts) => {
1513
1590
  const mode = detectOutputMode(opts);
1514
1591
  const hadCredentials = clearStorage();
1515
1592
  deleteConfig();
@@ -1524,9 +1601,91 @@ var logoutCommand = new Command8("logout").description("Clear all stored credent
1524
1601
  }
1525
1602
  });
1526
1603
 
1604
+ // src/commands/unpublish.ts
1605
+ import { Command as Command10 } from "commander";
1606
+ var unpublishCommand = new Command10("unpublish").description("Take a published playground offline (clears its live URL; code and playground stay intact)").argument("<sessionId>", "Session ID of the published playground").option("--json", "Output as JSON").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 (sessionId, opts) => {
1607
+ const mode = detectOutputMode(opts);
1608
+ initLogger(opts.logFile);
1609
+ const progress = new ProgressReporter(mode, opts.verbose);
1610
+ try {
1611
+ const auth = resolveAuth();
1612
+ progress.start("Unpublishing...");
1613
+ const result = await withMcp(
1614
+ { apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId },
1615
+ (client) => client.callTool("playground-unpublish", { sessionId })
1616
+ );
1617
+ if (!result.success) {
1618
+ throw apiError(result.reason || result.error || "Unpublish failed", result);
1619
+ }
1620
+ progress.succeed("Unpublished");
1621
+ if (mode === "pretty") {
1622
+ printSuccess(result.message || `Playground ${sessionId} is no longer publicly reachable.`);
1623
+ } else {
1624
+ outputResult(mode, { success: true, sessionId, ...result.message ? { message: result.message } : {} });
1625
+ }
1626
+ } catch (err) {
1627
+ progress.fail("Failed");
1628
+ if (err instanceof CliError) {
1629
+ if (mode === "pretty") {
1630
+ printError(err.message);
1631
+ } else {
1632
+ outputError(mode, { code: err.code, message: err.message });
1633
+ }
1634
+ process.exit(err.exitCode);
1635
+ }
1636
+ throw err;
1637
+ }
1638
+ });
1639
+
1640
+ // src/commands/update.ts
1641
+ import { Command as Command11 } from "commander";
1642
+ var updateCommand = new Command11("update").description("Update a playground's metadata: display name and/or visibility (never touches code)").argument("<sessionId>", "Session ID of the playground").option("--name <name>", "New display name").option("--privacy <privacy>", "public (anyone with the link) | private (team only)").option("--json", "Output as JSON").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 (sessionId, opts) => {
1643
+ const mode = detectOutputMode(opts);
1644
+ initLogger(opts.logFile);
1645
+ const progress = new ProgressReporter(mode, opts.verbose);
1646
+ try {
1647
+ if (!opts.name && !opts.privacy) {
1648
+ throw validationError("Nothing to update \u2014 pass --name and/or --privacy");
1649
+ }
1650
+ if (opts.privacy && !["public", "private"].includes(opts.privacy)) {
1651
+ throw validationError(`Invalid privacy "${opts.privacy}". Must be public or private.`);
1652
+ }
1653
+ const auth = resolveAuth();
1654
+ progress.start("Updating...");
1655
+ const result = await withMcp(
1656
+ { apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId },
1657
+ (client) => client.callTool("playground-metadata-update", {
1658
+ sessionId,
1659
+ ...opts.name ? { name: opts.name } : {},
1660
+ ...opts.privacy ? { privacy: opts.privacy } : {}
1661
+ })
1662
+ );
1663
+ if (!result.success) {
1664
+ throw apiError(result.reason || result.error || "Update failed", result);
1665
+ }
1666
+ progress.succeed("Updated");
1667
+ if (mode === "pretty") {
1668
+ printSuccess(result.message || `Playground ${sessionId} updated.`);
1669
+ } else {
1670
+ outputResult(mode, { success: true, sessionId, ...result.message ? { message: result.message } : {} });
1671
+ }
1672
+ } catch (err) {
1673
+ progress.fail("Failed");
1674
+ if (err instanceof CliError) {
1675
+ if (mode === "pretty") {
1676
+ printError(err.message);
1677
+ } else {
1678
+ outputError(mode, { code: err.code, message: err.message });
1679
+ }
1680
+ process.exit(err.exitCode);
1681
+ }
1682
+ throw err;
1683
+ }
1684
+ });
1685
+
1527
1686
  // src/commands/config.ts
1528
- import { Command as Command9 } from "commander";
1529
- var configCommand = new Command9("config").description(
1687
+ import { Command as Command12 } from "commander";
1688
+ var configCommand = new Command12("config").description(
1530
1689
  `Store CLI preferences (keys: ${configKeys().join(", ")})`
1531
1690
  );
1532
1691
  configCommand.command("set <key> <value>").description("Set a config value").option("--json", "Output as JSON").action((key, value, opts) => {
@@ -1592,48 +1751,64 @@ function assertUrl(value) {
1592
1751
  }
1593
1752
 
1594
1753
  // src/index.ts
1595
- var program = new Command10().name("anima").description(
1596
- `Anima CLI - Generate production-ready apps from prompts, URLs, or Figma designs.
1754
+ var program = new Command13().name("anima").description(
1755
+ `AgentGrid CLI \u2014 host, edit, and publish your work on AgentGrid. Every playground is a
1756
+ real git repository; each command runs an AgentGrid tool for you.
1757
+
1758
+ THE MAIN FLOW (build something and put it on AgentGrid):
1759
+ 1. npx @animaapp/cli login # once; a human approves
1760
+ 2. npx @animaapp/cli create -t import --from ./my-project # your code \u2192 a live playground
1761
+ (or: create -t empty --framework html \u2014 an empty repo you push to)
1762
+ 3. The response includes a rw gitRemoteUrl \u2014 git clone, edit, commit, push:
1763
+ every push updates the live playground.
1764
+ 4. Share the playgroundUrl with your human. That IS sharing \u2014 the playground
1765
+ is visible at its URL. Do NOT run publish unless the human explicitly
1766
+ asked for a public site; offer it as a follow-up question instead.
1597
1767
 
1598
1768
  AUTHENTICATION:
1599
- Run: npx @animaapp/cli login
1600
- Approve in a browser on any device \u2014 the CLI receives a scoped agent token
1601
- (stored in ~/.config/anima/). CI/automation can set ANIMA_API_TOKEN instead.
1769
+ npx @animaapp/cli login # device flow \u2014 a human approves on any device
1770
+ npx @animaapp/cli login --invite <url> # redeem a pre-approved invite link (no approval step)
1771
+ Credentials live in ~/.config/anima/; logout removes everything.
1602
1772
 
1603
1773
  TIMING (important for AI agents):
1604
- create \u2192 3-7 minutes (keep the default 600000ms timeout)
1605
- publish \u2192 1-3 minutes
1606
- codegen \u2192 2-5 minutes
1607
- get-git-token \u2192 seconds
1608
- The --timeout default is 600000ms (10 min). Do NOT reduce it.
1774
+ create -t empty|import \u2192 seconds
1775
+ create -t p2c|l2c|f2c \u2192 3-7 minutes AI generation (keep the default 600000ms timeout)
1776
+ publish/unpublish \u2192 1-3 minutes
1777
+ get-git-token / update \u2192 seconds
1609
1778
 
1610
1779
  COMMANDS:
1611
- login Log in via the device flow (no browser needed on this machine)
1612
- logout Clear all stored credentials from this machine
1780
+ login Connect (device flow, or --invite to redeem an invite link)
1781
+ logout Full local reset \u2014 clears credentials and CLI config
1782
+ list List your team's artifacts (most-recently-updated first) to resume work
1783
+ create Make a playground: import your code, empty repo, or AI-generated (p2c/l2c/f2c)
1784
+ get-git-token Fresh git access to an existing playground (or after token expiry)
1785
+ update Rename a playground or set visibility public/private (metadata only)
1786
+ publish Deploy to a public live URL \u2014 ONLY when the human asked for it
1787
+ unpublish Take a published playground offline (inverse of publish)
1613
1788
  mcp-config Print an MCP server config from stored credentials (no new login)
1614
- create Create app from prompt, URL, or Figma design
1615
- publish Deploy playground to live URL or npm package
1616
- codegen Convert Figma design to code files (no playground)
1617
- get-git-token Mint a git remote URL for a playground; clone/edit/push with git
1789
+ codegen Convert Figma design to local code files (no playground)
1618
1790
  config Store CLI preferences (e.g. a default API URL)
1619
1791
  auth Inspect or manage credentials (status / figma token)
1620
1792
 
1621
- EXAMPLES:
1622
- npx @animaapp/cli login
1623
- npx @animaapp/cli create -t p2c -p "SaaS dashboard with sidebar and analytics"
1624
- npx @animaapp/cli create -t l2c -u https://stripe.com
1625
- npx @animaapp/cli create -t f2c --file-key abc --nodes 42:15
1626
- npx @animaapp/cli publish abc123xyz
1627
- npx @animaapp/cli codegen --file-key abc --nodes 42:15 -o ./components
1628
- npx @animaapp/cli get-git-token https://dev.animaapp.com/chat/abc123xyz
1793
+ EXAMPLES (headless flow):
1794
+ npx @animaapp/cli login --invite https://api.agentgrid.io/invite/<code>.md
1795
+ npx @animaapp/cli create -t import --from ./my-project
1796
+ npx @animaapp/cli create -t empty --framework react --name "My app"
1797
+ npx @animaapp/cli get-git-token <sessionId>
1798
+ npx @animaapp/cli update <sessionId> --privacy public
1799
+ npx @animaapp/cli publish <sessionId> # only on explicit request
1800
+ npx @animaapp/cli unpublish <sessionId>
1629
1801
 
1630
1802
  OUTPUT: JSON to stdout when piped (for AI tools), pretty text in terminals.
1631
1803
  Progress is streamed to stderr via --verbose when in JSON mode.`
1632
1804
  ).version(version, "-v, --version");
1633
1805
  program.addCommand(loginCommand);
1634
1806
  program.addCommand(logoutCommand);
1807
+ program.addCommand(listCommand);
1635
1808
  program.addCommand(createCommand);
1636
1809
  program.addCommand(publishCommand);
1810
+ program.addCommand(unpublishCommand);
1811
+ program.addCommand(updateCommand);
1637
1812
  program.addCommand(codegenCommand);
1638
1813
  program.addCommand(getGitTokenCommand);
1639
1814
  program.addCommand(mcpConfigCommand);