@animaapp/cli 0.9.0 → 0.10.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
@@ -201,6 +201,7 @@ options; `--json` makes any of them agent-readable.
201
201
  | **Ship** | [`publish`](#publish--deploy-a-session-to-a-public-url-13-min) | Deploy to a public live URL — only when asked |
202
202
  | | [`unpublish`](#unpublish--take-a-published-artifact-offline) | Take a published artifact offline |
203
203
  | | [`update`](#update--rename-or-change-visibility-metadata-only) | Rename, or change visibility |
204
+ | | [`move`](#move--file-an-artifact-under-a-different-workspace) | File an artifact under a different workspace |
204
205
  | | [`delete`](#delete--hide-an-artifact-with-reversible-soft-deletion) | Reversible soft deletion |
205
206
  | **Figma** | [`codegen`](#codegen--figma-to-local-files-no-artifact) | Figma → local code files, no artifact |
206
207
  | **Settings** | [`config`](#config--store-cli-preferences) | Store CLI preferences (e.g. a default API URL) |
@@ -565,6 +566,26 @@ npx @animaapp/cli@latest update <sessionId> --privacy private # team only
565
566
  Never touches code or content — that's `edit` (or the git flow via
566
567
  `get-git-token`).
567
568
 
569
+ ### `move` — file an artifact under a different workspace
570
+
571
+ ```bash
572
+ npx @animaapp/cli@latest workspaces # the ids live here
573
+ npx @animaapp/cli@latest move <sessionId> --workspace <id>
574
+ ```
575
+
576
+ **The artifact stays as it is.** Same git repository, session id, URL, history
577
+ and live deployment — there is no new link to send and no copy to reconcile.
578
+
579
+ **What changes is who can reach it.** A private artifact is reached *through*
580
+ the workspace it is filed in, so a move hands it to the people who reach the
581
+ destination and takes it from the rest, including whoever you already sent the
582
+ link to. You need `write` on the artifact and `write` in the destination, which
583
+ is what moving it back would take too.
584
+
585
+ `--workspace` is required and names a workspace of the same team, where `create`
586
+ and `duplicate` fall back to the one workspace you can write in. Moving an
587
+ artifact where it already is leaves everything as it was.
588
+
568
589
  ### `get-git-token` — read/edit an artifact's code over git
569
590
 
570
591
  ```bash
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 Command23 } from "commander";
4
+ import { Command as Command24 } from "commander";
5
5
 
6
6
  // src/commands/create.ts
7
7
  import { Command } from "commander";
@@ -2637,9 +2637,68 @@ function createDuplicateCommand() {
2637
2637
  }
2638
2638
  var duplicateCommand = createDuplicateCommand();
2639
2639
 
2640
- // src/commands/explore.ts
2640
+ // src/commands/move.ts
2641
2641
  import { Command as Command17 } from "commander";
2642
2642
  import chalk10 from "chalk";
2643
+ function buildMoveArgs(artifactUrl, workspaceId) {
2644
+ const sessionId = parseArtifactUrl(artifactUrl);
2645
+ if (!sessionId) {
2646
+ throw validationError("An artifact URL or session ID is required");
2647
+ }
2648
+ const destination = workspaceFlag(workspaceId);
2649
+ if (destination === void 0) {
2650
+ throw validationError("--workspace is required; `anima workspaces` lists the ids you can use");
2651
+ }
2652
+ return { sessionId, workspaceId: destination };
2653
+ }
2654
+ function createMoveCommand() {
2655
+ return new Command17("move").summary("File an artifact under a different workspace").description(
2656
+ "Move an artifact into another workspace of the same team. The artifact stays as it is: same git repository, session ID, URL, history and live deployment, so there is no new link to send. What changes is who can reach it, since a private artifact is reached through the workspace it is filed in: a move hands it to the people who reach the destination and takes it from the rest, including whoever you already sent the link to. Needs write on the artifact and write in the destination. Moving an artifact where it already is leaves everything as it was."
2657
+ ).argument("<artifactUrl>", "Artifact URL or session ID to move").option("-w, --workspace <id>", "The workspace to move it into (id from `anima workspaces`)").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 (artifactUrl, opts) => {
2658
+ const mode = detectOutputMode(opts);
2659
+ initLogger(opts.logFile);
2660
+ const progress = new ProgressReporter(mode, opts.verbose);
2661
+ try {
2662
+ const args = buildMoveArgs(artifactUrl, opts.workspace);
2663
+ const auth = await resolveAuth(opts.apiUrl);
2664
+ progress.start("Moving artifact...");
2665
+ const result = await withMcp(
2666
+ { apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId },
2667
+ (client) => client.callTool("workspace-move_artifact", args)
2668
+ );
2669
+ if (!result.success) {
2670
+ throw apiError(result.message || result.reason || result.error || "Could not move the artifact", result);
2671
+ }
2672
+ progress.succeed("Artifact moved");
2673
+ if (mode === "pretty") {
2674
+ console.log();
2675
+ printSuccess(`Artifact moved to ${result.workspaceName}`);
2676
+ printKeyValue("Session ID", result.sessionId);
2677
+ printKeyValue("Workspace", `${result.workspaceName} (${result.workspaceId})`);
2678
+ console.log(chalk10.gray(" The repository, URL and live deployment are unchanged."));
2679
+ console.log();
2680
+ } else {
2681
+ outputResult(mode, result);
2682
+ }
2683
+ } catch (err) {
2684
+ progress.fail("Failed");
2685
+ if (err instanceof CliError) {
2686
+ if (mode === "pretty") {
2687
+ printError(err.message);
2688
+ } else {
2689
+ outputError(mode, { code: err.code, message: err.message });
2690
+ }
2691
+ process.exit(err.exitCode);
2692
+ }
2693
+ throw err;
2694
+ }
2695
+ });
2696
+ }
2697
+ var moveCommand = createMoveCommand();
2698
+
2699
+ // src/commands/explore.ts
2700
+ import { Command as Command18 } from "commander";
2701
+ import chalk11 from "chalk";
2643
2702
 
2644
2703
  // src/api/tool.ts
2645
2704
  async function runTool(toolName, args, options = {}) {
@@ -2666,7 +2725,7 @@ ${nextSteps}` : base;
2666
2725
  }
2667
2726
 
2668
2727
  // src/commands/explore.ts
2669
- var exploreCommand = new Command17("explore").summary("Read an artifact's files: list, search, read, history").description(
2728
+ var exploreCommand = new Command18("explore").summary("Read an artifact's files: list, search, read, history").description(
2670
2729
  "Inspect an artifact's files without git: list them (--tree), search them (--search), read them (--read), or show commits (--history)."
2671
2730
  ).argument("<artifactUrl>", "Artifact URL or session ID").option("--tree", "List file paths").option("--search <query>", "Find text inside files \u2014 start here when you don't know the file").option("--read <paths...>", "Return the contents of these files").option("--history", "List commits, newest first").option("--path <prefix>", "tree/search: a literal directory prefix (not a glob)").option("--range <start,end>", "read: line window, 1-based inclusive, for a single file").option("--revision <rev>", "Look at the artifact as it was at this commit").option("--regex", "search: treat the query as a JavaScript regular expression").option("--case-sensitive", "search: match case exactly").option("--include-excluded", "tree/search: also look inside node_modules, dist and build").option("--limit <n>", "tree/search/history: maximum rows to return").option("--cursor <cursor>", "history: continue after a previous response's nextCursor").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 (artifactUrl, opts) => {
2672
2731
  const mode = detectOutputMode(opts);
@@ -2739,42 +2798,42 @@ function printExplore(action, result) {
2739
2798
  if (action === "tree") {
2740
2799
  for (const file of result.files ?? []) {
2741
2800
  const kind = result.unwritable?.[file];
2742
- console.log(` ${file}${kind ? chalk10.gray(` (${kind} \u2014 git only)`) : ""}`);
2801
+ console.log(` ${file}${kind ? chalk11.gray(` (${kind} \u2014 git only)`) : ""}`);
2743
2802
  }
2744
2803
  if (result.matchedFiles !== void 0) {
2745
2804
  console.log();
2746
- console.log(chalk10.gray(` ${(result.files ?? []).length} of ${result.matchedFiles} shown`));
2805
+ console.log(chalk11.gray(` ${(result.files ?? []).length} of ${result.matchedFiles} shown`));
2747
2806
  }
2748
2807
  } else if (action === "search") {
2749
2808
  for (const match of result.matches ?? []) {
2750
- console.log(` ${chalk10.cyan(match.path)}:${match.line} ${match.lineText.trim()}`);
2809
+ console.log(` ${chalk11.cyan(match.path)}:${match.line} ${match.lineText.trim()}`);
2751
2810
  }
2752
2811
  if (!result.matches?.length) {
2753
2812
  console.log(" No matches.");
2754
2813
  const skipped = result.notSearched;
2755
2814
  if (skipped?.excluded) {
2756
2815
  console.log(
2757
- chalk10.yellow(
2816
+ chalk11.yellow(
2758
2817
  ` ${skipped.excluded} files were skipped (node_modules, dist, build) \u2014 retry with --include-excluded.`
2759
2818
  )
2760
2819
  );
2761
2820
  }
2762
2821
  if (skipped?.assets) {
2763
- console.log(chalk10.gray(` ${skipped.assets} binary files cannot match a text query.`));
2822
+ console.log(chalk11.gray(` ${skipped.assets} binary files cannot match a text query.`));
2764
2823
  }
2765
2824
  }
2766
2825
  } else if (action === "read") {
2767
2826
  for (const file of result.files ?? []) {
2768
- console.log(chalk10.bold(` ${file.path}`));
2827
+ console.log(chalk11.bold(` ${file.path}`));
2769
2828
  if (file.asset) {
2770
- console.log(chalk10.gray(` binary \u2014 ${file.size ?? "?"} bytes, ${file.mime ?? "unknown type"}`));
2829
+ console.log(chalk11.gray(` binary \u2014 ${file.size ?? "?"} bytes, ${file.mime ?? "unknown type"}`));
2771
2830
  } else if (file.deferred) {
2772
- console.log(chalk10.yellow(" not returned: the response ran out of budget \u2014 read it on its own"));
2831
+ console.log(chalk11.yellow(" not returned: the response ran out of budget \u2014 read it on its own"));
2773
2832
  } else {
2774
2833
  console.log(file.content ?? "");
2775
2834
  if (file.truncated) {
2776
2835
  console.log(
2777
- chalk10.yellow(
2836
+ chalk11.yellow(
2778
2837
  ` lines ${file.startLine}-${file.endLine} of ${file.totalLines} \u2014 read the rest with --range`
2779
2838
  )
2780
2839
  );
@@ -2784,33 +2843,33 @@ function printExplore(action, result) {
2784
2843
  }
2785
2844
  for (const missing of result.missingPaths ?? []) {
2786
2845
  const near = result.suggestions?.[missing];
2787
- console.log(chalk10.yellow(` Not found: ${missing}${near?.length ? ` \u2014 did you mean ${near.join(", ")}?` : ""}`));
2846
+ console.log(chalk11.yellow(` Not found: ${missing}${near?.length ? ` \u2014 did you mean ${near.join(", ")}?` : ""}`));
2788
2847
  }
2789
2848
  } else {
2790
2849
  const commits = result.commit ? [result.commit] : result.commits ?? [];
2791
2850
  for (const commit of commits) {
2792
- console.log(` ${chalk10.yellow(commit.revision.slice(0, 10))} ${commit.message.split("\n")[0]}`);
2793
- console.log(chalk10.gray(` ${commit.author} \u2014 ${commit.date}`));
2851
+ console.log(` ${chalk11.yellow(commit.revision.slice(0, 10))} ${commit.message.split("\n")[0]}`);
2852
+ console.log(chalk11.gray(` ${commit.author} \u2014 ${commit.date}`));
2794
2853
  }
2795
2854
  for (const changed of result.commit?.changedFiles ?? []) {
2796
- console.log(chalk10.gray(` ${changed.change.padEnd(8)} ${changed.path}`));
2855
+ console.log(chalk11.gray(` ${changed.change.padEnd(8)} ${changed.path}`));
2797
2856
  }
2798
2857
  }
2799
2858
  if (result.truncated) {
2800
- console.log(chalk10.yellow(" The list was capped \u2014 raise --limit to see more."));
2859
+ console.log(chalk11.yellow(" The list was capped \u2014 raise --limit to see more."));
2801
2860
  }
2802
2861
  if (result.revision) {
2803
2862
  console.log();
2804
- console.log(chalk10.gray(` revision: ${result.revision} (pass to \`anima edit --base-revision\`)`));
2863
+ console.log(chalk11.gray(` revision: ${result.revision} (pass to \`anima edit --base-revision\`)`));
2805
2864
  }
2806
2865
  console.log();
2807
2866
  }
2808
2867
 
2809
2868
  // src/commands/edit.ts
2810
- import { Command as Command18 } from "commander";
2869
+ import { Command as Command19 } from "commander";
2811
2870
  import fs5 from "fs";
2812
- import chalk11 from "chalk";
2813
- var editCommand = new Command18("edit").summary("Change an artifact's files and commit them").description(
2871
+ import chalk12 from "chalk";
2872
+ var editCommand = new Command19("edit").summary("Change an artifact's files and commit them").description(
2814
2873
  "Change an artifact's files and commit them, without git. All changes land as one commit."
2815
2874
  ).argument("<artifactUrl>", "Artifact URL or session ID").requiredOption("-m, --message <message>", "Commit message").option(
2816
2875
  "--base-revision <rev>",
@@ -2832,7 +2891,7 @@ var editCommand = new Command18("edit").summary("Change an artifact's files and
2832
2891
  printSuccess("Committed.");
2833
2892
  for (const changed of result.changedFiles ?? []) {
2834
2893
  const detail = changed.op === "move" ? `${changed.fromPath} \u2192 ${changed.path}` : changed.replacements !== void 0 ? `${changed.path} (${changed.replacements} replaced)` : changed.path;
2835
- console.log(` ${chalk11.gray(changed.op.padEnd(12))} ${detail}`);
2894
+ console.log(` ${chalk12.gray(changed.op.padEnd(12))} ${detail}`);
2836
2895
  }
2837
2896
  console.log();
2838
2897
  printKeyValue("Revision", result.revision ?? "unknown");
@@ -2930,11 +2989,11 @@ function readFile(path7) {
2930
2989
  }
2931
2990
 
2932
2991
  // src/commands/uploadAsset.ts
2933
- import { Command as Command19 } from "commander";
2992
+ import { Command as Command20 } from "commander";
2934
2993
  import fs6 from "fs";
2935
2994
  import path5 from "path";
2936
- import chalk12 from "chalk";
2937
- var uploadAssetCommand = new Command19("upload-asset").summary("Add an image, font or media file over 256 KB").description(
2995
+ import chalk13 from "chalk";
2996
+ var uploadAssetCommand = new Command20("upload-asset").summary("Add an image, font or media file over 256 KB").description(
2938
2997
  "Add a large image, font or media file (over 256 KB) to an artifact: stage it, upload it, and commit it at --path."
2939
2998
  ).argument("<artifactUrl>", "Artifact URL or session ID").argument("<file>", "Local file to upload").option(
2940
2999
  "--path <path>",
@@ -2971,7 +3030,7 @@ var uploadAssetCommand = new Command19("upload-asset").summary("Add an image, fo
2971
3030
  console.log();
2972
3031
  console.log(" Commit it where it belongs with:");
2973
3032
  console.log(
2974
- ` ${chalk12.cyan(
3033
+ ` ${chalk13.cyan(
2975
3034
  `anima edit ${sessionId} -m "Add asset" --changes '[{"op":"write","path":"public/${path5.basename(file)}","assetUploadId":"${grant.assetUploadId}"}]'`
2976
3035
  )}`
2977
3036
  );
@@ -3048,8 +3107,8 @@ function readAsset(file) {
3048
3107
  }
3049
3108
 
3050
3109
  // src/commands/delete.ts
3051
- import { Command as Command20 } from "commander";
3052
- var deleteCommand = new Command20("delete").summary("Delete an artifact (reversible: hidden, not erased)").description("Soft-delete an artifact only when explicitly requested (unpublish it first; content is retained)").argument("<artifactUrl>", "Artifact URL or session ID to soft-delete").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 (artifactUrl, opts) => {
3110
+ import { Command as Command21 } from "commander";
3111
+ var deleteCommand = new Command21("delete").summary("Delete an artifact (reversible: hidden, not erased)").description("Soft-delete an artifact only when explicitly requested (unpublish it first; content is retained)").argument("<artifactUrl>", "Artifact URL or session ID to soft-delete").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 (artifactUrl, opts) => {
3053
3112
  const mode = detectOutputMode(opts);
3054
3113
  initLogger(opts.logFile);
3055
3114
  const progress = new ProgressReporter(mode, opts.verbose);
@@ -3090,9 +3149,9 @@ var deleteCommand = new Command20("delete").summary("Delete an artifact (reversi
3090
3149
  });
3091
3150
 
3092
3151
  // src/commands/review.ts
3093
- import { Command as Command21 } from "commander";
3094
- import chalk13 from "chalk";
3095
- var listSubcommand = new Command21("list").summary("Read the comments addressed to you").description("Read the review comments addressed to you, newest artifact activity first").argument("[artifactUrl]", "Limit to one artifact; omit for every review addressed to you").option("--limit <n>", "Maximum reviews to return (1-50, default 20)").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 (artifactUrl, opts) => {
3152
+ import { Command as Command22 } from "commander";
3153
+ import chalk14 from "chalk";
3154
+ var listSubcommand = new Command22("list").summary("Read the comments addressed to you").description("Read the review comments addressed to you, newest artifact activity first").argument("[artifactUrl]", "Limit to one artifact; omit for every review addressed to you").option("--limit <n>", "Maximum reviews to return (1-50, default 20)").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 (artifactUrl, opts) => {
3096
3155
  const mode = detectOutputMode(opts);
3097
3156
  initLogger(opts.logFile);
3098
3157
  await withCommandErrors(mode, async () => {
@@ -3107,7 +3166,7 @@ var listSubcommand = new Command21("list").summary("Read the comments addressed
3107
3166
  }
3108
3167
  });
3109
3168
  });
3110
- var resolveSubcommand = new Command21("resolve").summary("Close one comment without a commit").description("Close one comment without a commit \u2014 for a question answered, or a change you decided against").argument("<commentId>", "Comment to close, from `anima review list`").option("--note <text>", "What to tell the reviewer as the closing message").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 (commentId, opts) => {
3169
+ var resolveSubcommand = new Command22("resolve").summary("Close one comment without a commit").description("Close one comment without a commit \u2014 for a question answered, or a change you decided against").argument("<commentId>", "Comment to close, from `anima review list`").option("--note <text>", "What to tell the reviewer as the closing message").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 (commentId, opts) => {
3111
3170
  const mode = detectOutputMode(opts);
3112
3171
  initLogger(opts.logFile);
3113
3172
  await withCommandErrors(mode, async () => {
@@ -3126,7 +3185,7 @@ var resolveSubcommand = new Command21("resolve").summary("Close one comment with
3126
3185
  }
3127
3186
  });
3128
3187
  });
3129
- var replySubcommand = new Command21("reply").summary("Answer one comment, leaving it open").description("Say something back on one comment and LEAVE IT OPEN \u2014 to ask, report, or say you are blocked").argument("<commentId>", "Comment to reply to, from `anima review list`").requiredOption("-m, --message <message>", "What to say to the reviewer").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 (commentId, opts) => {
3188
+ var replySubcommand = new Command22("reply").summary("Answer one comment, leaving it open").description("Say something back on one comment and LEAVE IT OPEN \u2014 to ask, report, or say you are blocked").argument("<commentId>", "Comment to reply to, from `anima review list`").requiredOption("-m, --message <message>", "What to say to the reviewer").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 (commentId, opts) => {
3130
3189
  const mode = detectOutputMode(opts);
3131
3190
  initLogger(opts.logFile);
3132
3191
  await withCommandErrors(mode, async () => {
@@ -3145,7 +3204,7 @@ var replySubcommand = new Command21("reply").summary("Answer one comment, leavin
3145
3204
  }
3146
3205
  });
3147
3206
  });
3148
- var reviewCommand = new Command21("review").summary("Read and answer the comments humans addressed to you").description("Read and answer the review comments humans addressed to you (list / resolve / reply)").addCommand(listSubcommand).addCommand(resolveSubcommand).addCommand(replySubcommand);
3207
+ var reviewCommand = new Command22("review").summary("Read and answer the comments humans addressed to you").description("Read and answer the review comments humans addressed to you (list / resolve / reply)").addCommand(listSubcommand).addCommand(resolveSubcommand).addCommand(replySubcommand);
3149
3208
  function parseLimit2(value) {
3150
3209
  const limit = Number(value);
3151
3210
  if (!Number.isInteger(limit) || limit < 1 || limit > 50) {
@@ -3162,29 +3221,29 @@ function printReviews(result) {
3162
3221
  return;
3163
3222
  }
3164
3223
  for (const review of reviews) {
3165
- console.log(` ${chalk13.bold(`Review ${review.reviewId}`)} ${chalk13.gray(`by ${review.author.name}`)}`);
3166
- console.log(` ${chalk13.cyan.underline(review.artifactUrl)}`);
3224
+ console.log(` ${chalk14.bold(`Review ${review.reviewId}`)} ${chalk14.gray(`by ${review.author.name}`)}`);
3225
+ console.log(` ${chalk14.cyan.underline(review.artifactUrl)}`);
3167
3226
  if (!review.isLatest) {
3168
3227
  console.log(
3169
- chalk13.yellow(" The artifact moved since this was written \u2014 check the comments still apply.")
3228
+ chalk14.yellow(" The artifact moved since this was written \u2014 check the comments still apply.")
3170
3229
  );
3171
3230
  }
3172
3231
  console.log();
3173
3232
  for (const comment of review.comments) {
3174
3233
  const marks = [
3175
- comment.status !== "open" ? chalk13.gray(comment.status) : null,
3176
- comment.unassigned ? chalk13.yellow("unassigned") : null
3234
+ comment.status !== "open" ? chalk14.gray(comment.status) : null,
3235
+ comment.unassigned ? chalk14.yellow("unassigned") : null
3177
3236
  ].filter(Boolean).join(" ");
3178
- console.log(` ${chalk13.bold(`#${comment.index}`)} ${comment.body}${marks ? ` ${marks}` : ""}`);
3179
- console.log(chalk13.gray(` ${comment.commentId}${describeAnchor(comment)}`));
3237
+ console.log(` ${chalk14.bold(`#${comment.index}`)} ${comment.body}${marks ? ` ${marks}` : ""}`);
3238
+ console.log(chalk14.gray(` ${comment.commentId}${describeAnchor(comment)}`));
3180
3239
  for (const reply of comment.replies ?? []) {
3181
- console.log(chalk13.gray(` \u21B3 ${reply.author.name}: ${reply.body}`));
3240
+ console.log(chalk14.gray(` \u21B3 ${reply.author.name}: ${reply.body}`));
3182
3241
  }
3183
3242
  console.log();
3184
3243
  }
3185
3244
  printKeyValue("To close these in a commit", "");
3186
3245
  for (const line of review.resolveTrailer.split("\n")) {
3187
- console.log(` ${chalk13.gray(line)}`);
3246
+ console.log(` ${chalk14.gray(line)}`);
3188
3247
  }
3189
3248
  console.log();
3190
3249
  }
@@ -3205,13 +3264,13 @@ function describeAnchor(comment) {
3205
3264
  }
3206
3265
 
3207
3266
  // src/commands/skill.ts
3208
- import { Command as Command22 } from "commander";
3267
+ import { Command as Command23 } from "commander";
3209
3268
  import fs7 from "fs";
3210
3269
  import path6 from "path";
3211
- import chalk14 from "chalk";
3270
+ import chalk15 from "chalk";
3212
3271
  var GUIDE_PATH = "/guide.md";
3213
3272
  function createSkillCommand() {
3214
- return new Command22("skill").summary("Install the AgentGrid guide as a skill your agent can read").description(
3273
+ return new Command23("skill").summary("Install the AgentGrid guide as a skill your agent can read").description(
3215
3274
  "Fetch the AgentGrid agent guide and write it as a SKILL.md your runtime can load, or print it to stdout. The guide comes from the API, so it stays current; the command reference is generated from this CLI's own commands."
3216
3275
  ).argument(
3217
3276
  "[path]",
@@ -3238,8 +3297,8 @@ ${body}
3238
3297
  logEvent("skill_installed", { path: target, bytes: document.length });
3239
3298
  if (mode === "pretty") {
3240
3299
  console.log();
3241
- printSuccess(`Skill written to ${chalk14.cyan(target)}`);
3242
- console.log(` ${chalk14.gray(`${document.length} bytes, from ${apiUrl}${GUIDE_PATH}`)}`);
3300
+ printSuccess(`Skill written to ${chalk15.cyan(target)}`);
3301
+ console.log(` ${chalk15.gray(`${document.length} bytes, from ${apiUrl}${GUIDE_PATH}`)}`);
3243
3302
  console.log();
3244
3303
  } else {
3245
3304
  outputResult(mode, {
@@ -3368,7 +3427,7 @@ function writeDocument(target, document) {
3368
3427
  }
3369
3428
 
3370
3429
  // src/index.ts
3371
- var program = new Command23().name("anima").description(
3430
+ var program = new Command24().name("anima").description(
3372
3431
  `AgentGrid CLI \u2014 create, change, publish and share artifacts on AgentGrid.
3373
3432
  An artifact is a real git repository, and every command below runs one
3374
3433
  AgentGrid MCP tool for you. The command list is at the bottom; run
@@ -3414,6 +3473,7 @@ EXAMPLES:
3414
3473
  anima explore <sessionId> --search "buttonColor"
3415
3474
  anima edit <sessionId> -m "Blue pill" --replace src/App.tsx --old red --new blue
3416
3475
  anima review list # what humans asked you to change
3476
+ anima move <sessionId> -w <workspaceId> # re-file it; the URL is unchanged
3417
3477
  anima publish <sessionId> # only on explicit request
3418
3478
 
3419
3479
  OUTPUT: pretty text in a terminal; a single JSON object on stdout when piped
@@ -3433,6 +3493,7 @@ program.addCommand(uploadAssetCommand);
3433
3493
  program.addCommand(getGitTokenCommand);
3434
3494
  program.addCommand(reviewCommand);
3435
3495
  program.addCommand(duplicateCommand);
3496
+ program.addCommand(moveCommand);
3436
3497
  program.addCommand(publishCommand);
3437
3498
  program.addCommand(unpublishCommand);
3438
3499
  program.addCommand(updateCommand);