@animaapp/cli 0.8.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 +60 -6
- package/dist/index.js +378 -142
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
4
|
+
import { Command as Command24 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/create.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -176,7 +176,19 @@ function validationError(message, detail) {
|
|
|
176
176
|
);
|
|
177
177
|
}
|
|
178
178
|
function apiError(message, detail) {
|
|
179
|
-
|
|
179
|
+
const text = message.replace(/^Error: /, "");
|
|
180
|
+
return new CliError("API_ERROR", withWorkspaceHint(text), EXIT_CODES.API_ERROR, detail);
|
|
181
|
+
}
|
|
182
|
+
function withWorkspaceHint(message) {
|
|
183
|
+
if (/\bworkspaceId\b/.test(message)) {
|
|
184
|
+
return `${message}
|
|
185
|
+
Pass it with --workspace <id>; \`anima workspaces\` lists the ids.`;
|
|
186
|
+
}
|
|
187
|
+
if (message === "Workspace not found") {
|
|
188
|
+
return `${message}
|
|
189
|
+
\`anima workspaces\` lists the workspaces you can reach, with their ids.`;
|
|
190
|
+
}
|
|
191
|
+
return message;
|
|
180
192
|
}
|
|
181
193
|
function timeoutError() {
|
|
182
194
|
return new CliError(
|
|
@@ -423,9 +435,16 @@ import { CallToolResultSchema, ErrorCode } from "@modelcontextprotocol/sdk/types
|
|
|
423
435
|
import { createRequire } from "module";
|
|
424
436
|
var { version } = createRequire(import.meta.url)("../package.json");
|
|
425
437
|
|
|
438
|
+
// src/clientIdentity.ts
|
|
439
|
+
var ANIMA_CLIENT_IDENTITY = {
|
|
440
|
+
type: "cli",
|
|
441
|
+
name: "anima-cli",
|
|
442
|
+
version
|
|
443
|
+
};
|
|
444
|
+
|
|
426
445
|
// src/api/mcp.ts
|
|
427
446
|
var MCP_PATH = "/v1/mcp";
|
|
428
|
-
var CLIENT_INFO = { name:
|
|
447
|
+
var CLIENT_INFO = { name: ANIMA_CLIENT_IDENTITY.name, version: ANIMA_CLIENT_IDENTITY.version };
|
|
429
448
|
var DEFAULT_TIMEOUT_MS = 6e5;
|
|
430
449
|
var AnimaMcpClient = class {
|
|
431
450
|
#client;
|
|
@@ -433,7 +452,10 @@ var AnimaMcpClient = class {
|
|
|
433
452
|
#url;
|
|
434
453
|
constructor(config) {
|
|
435
454
|
const headers = {
|
|
436
|
-
Authorization: `Bearer ${config.token}
|
|
455
|
+
Authorization: `Bearer ${config.token}`,
|
|
456
|
+
"X-Anima-Client-Type": ANIMA_CLIENT_IDENTITY.type,
|
|
457
|
+
"X-Anima-Client-Name": ANIMA_CLIENT_IDENTITY.name,
|
|
458
|
+
"X-Anima-Client-Version": ANIMA_CLIENT_IDENTITY.version
|
|
437
459
|
};
|
|
438
460
|
if (config.teamId) headers["X-Team-Id"] = config.teamId;
|
|
439
461
|
if (config.figmaToken) headers["X-Figma-Token"] = config.figmaToken;
|
|
@@ -475,6 +497,11 @@ var AnimaMcpClient = class {
|
|
|
475
497
|
if (err?.code === ErrorCode.RequestTimeout) {
|
|
476
498
|
throw timeoutError();
|
|
477
499
|
}
|
|
500
|
+
if (err?.code === ErrorCode.InvalidParams && /\bnot found\b/.test(err.message)) {
|
|
501
|
+
throw apiError(
|
|
502
|
+
`${name} is not available to this credential. An agent is offered it only once a human has granted it the access it needs in a workspace of this team (read to list, write to create).`
|
|
503
|
+
);
|
|
504
|
+
}
|
|
478
505
|
throw err;
|
|
479
506
|
}
|
|
480
507
|
logEvent("mcp_tool_result", { tool: name, isError: result.isError ?? false });
|
|
@@ -827,6 +854,7 @@ async function createAnonymousArtifact(request, fetchFn = fetch) {
|
|
|
827
854
|
const url = `${request.apiUrl.replace(/\/$/, "")}/v1/generationSessions`;
|
|
828
855
|
const body = {
|
|
829
856
|
type: "import",
|
|
857
|
+
clientType: ANIMA_CLIENT_IDENTITY.type,
|
|
830
858
|
...request.files ? { files: request.files } : {},
|
|
831
859
|
...request.zipUploadId ? { zipUploadId: request.zipUploadId } : {},
|
|
832
860
|
...request.framework ? { framework: request.framework } : {},
|
|
@@ -867,6 +895,14 @@ async function getAnonymousZipUploadUrl(apiUrl, fetchFn = fetch) {
|
|
|
867
895
|
return { zipUploadId: payload.zipUploadId, uploadUrl: payload.uploadUrl };
|
|
868
896
|
}
|
|
869
897
|
|
|
898
|
+
// src/utils/workspaceFlag.ts
|
|
899
|
+
function workspaceFlag(value) {
|
|
900
|
+
if (value !== void 0 && value.trim() === "") {
|
|
901
|
+
throw validationError("--workspace needs a workspace id; `anima workspaces` lists them");
|
|
902
|
+
}
|
|
903
|
+
return value;
|
|
904
|
+
}
|
|
905
|
+
|
|
870
906
|
// src/commands/create.ts
|
|
871
907
|
var createCommand = new Command("create").summary("Create an artifact: your code, an empty repo, or AI generation").description(
|
|
872
908
|
"Create an artifact 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)."
|
|
@@ -879,7 +915,10 @@ var createCommand = new Command("create").summary("Create an artifact: your code
|
|
|
879
915
|
).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(
|
|
880
916
|
"--artifact-type <kind>",
|
|
881
917
|
"app | markdown \u2014 what the artifact IS. app (default) needs an index.html; markdown needs .md files"
|
|
882
|
-
).option("--name <name>", "Project name (empty/import only)").option(
|
|
918
|
+
).option("--name <name>", "Project name (empty/import only)").option(
|
|
919
|
+
"-w, --workspace <id>",
|
|
920
|
+
"The workspace to create it in (id from `anima workspaces`). Optional when you can create in only one workspace; otherwise required, since there is no default"
|
|
921
|
+
).option("--from <path>", "Folder or .zip with your project (import only) \u2014 becomes the first commit").option(
|
|
883
922
|
"--anonymous",
|
|
884
923
|
"Create without an account (import only). Returns a claim link to send a human, and a handoff token to log in with once they claim it"
|
|
885
924
|
).option(
|
|
@@ -946,7 +985,7 @@ ${grant.nextSteps}` : message, grant);
|
|
|
946
985
|
return { created, status: status2 };
|
|
947
986
|
}).then(({ created, status: status2 }) => ({ result: created, settled: status2 }));
|
|
948
987
|
if (!result.success || !result.sessionId) {
|
|
949
|
-
const message = result.reason || result.error || "Generation failed";
|
|
988
|
+
const message = result.message || result.reason || result.error || "Generation failed";
|
|
950
989
|
throw apiError(result.nextSteps ? `${message}
|
|
951
990
|
${result.nextSteps}` : message, result);
|
|
952
991
|
}
|
|
@@ -1152,6 +1191,12 @@ Log in first for the other types: anima login`
|
|
|
1152
1191
|
if (type !== "import" && opts.from) {
|
|
1153
1192
|
throw validationError("--from is only valid with -t import");
|
|
1154
1193
|
}
|
|
1194
|
+
workspaceFlag(opts.workspace);
|
|
1195
|
+
if (opts.workspace !== void 0 && opts.anonymous) {
|
|
1196
|
+
throw validationError(
|
|
1197
|
+
"--workspace does not apply to --anonymous creates \u2014 they belong to no team until a human claims them"
|
|
1198
|
+
);
|
|
1199
|
+
}
|
|
1155
1200
|
}
|
|
1156
1201
|
function resolveFigmaToken(opts, stored) {
|
|
1157
1202
|
const figmaToken = opts.figmaToken || process.env.FIGMA_TOKEN || stored;
|
|
@@ -1170,7 +1215,8 @@ function buildCreateArgs(type, opts) {
|
|
|
1170
1215
|
// import is what made markdown artifacts render as empty apps.
|
|
1171
1216
|
...opts.framework && opts.artifactType !== "markdown" ? { framework: opts.framework } : {},
|
|
1172
1217
|
...opts.artifactType ? { artifactType: opts.artifactType } : {},
|
|
1173
|
-
...opts.name ? { name: opts.name } : {}
|
|
1218
|
+
...opts.name ? { name: opts.name } : {},
|
|
1219
|
+
...opts.workspace !== void 0 ? { workspaceId: opts.workspace } : {}
|
|
1174
1220
|
};
|
|
1175
1221
|
}
|
|
1176
1222
|
const framework = opts.framework ?? "html";
|
|
@@ -1185,6 +1231,7 @@ function buildCreateArgs(type, opts) {
|
|
|
1185
1231
|
};
|
|
1186
1232
|
if (language) args.language = language;
|
|
1187
1233
|
if (opts.uiLibrary) args.uiLibrary = opts.uiLibrary;
|
|
1234
|
+
if (opts.workspace !== void 0) args.workspaceId = opts.workspace;
|
|
1188
1235
|
switch (type) {
|
|
1189
1236
|
case "p2c":
|
|
1190
1237
|
args.prompt = opts.prompt;
|
|
@@ -1209,22 +1256,107 @@ function buildCreateArgs(type, opts) {
|
|
|
1209
1256
|
return args;
|
|
1210
1257
|
}
|
|
1211
1258
|
|
|
1212
|
-
// src/commands/
|
|
1259
|
+
// src/commands/createKnowledge.ts
|
|
1213
1260
|
import { Command as Command2 } from "commander";
|
|
1261
|
+
|
|
1262
|
+
// src/commands/runner.ts
|
|
1263
|
+
async function withCommandErrors(mode, fn) {
|
|
1264
|
+
try {
|
|
1265
|
+
await fn();
|
|
1266
|
+
} catch (err) {
|
|
1267
|
+
if (err instanceof CliError) {
|
|
1268
|
+
if (mode === "pretty") {
|
|
1269
|
+
printError(err.message);
|
|
1270
|
+
} else {
|
|
1271
|
+
outputError(mode, { code: err.code, message: err.message });
|
|
1272
|
+
}
|
|
1273
|
+
process.exit(err.exitCode);
|
|
1274
|
+
}
|
|
1275
|
+
throw err;
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
// src/commands/createKnowledge.ts
|
|
1280
|
+
function buildCreateKnowledgeArgs(name, workspaceId) {
|
|
1281
|
+
if (name !== void 0 && name.length > 120) {
|
|
1282
|
+
throw validationError("--name must be at most 120 characters");
|
|
1283
|
+
}
|
|
1284
|
+
return {
|
|
1285
|
+
...name === void 0 ? {} : { name },
|
|
1286
|
+
...workspaceFlag(workspaceId) === void 0 ? {} : { workspaceId }
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
function makeCreateKnowledgeCommand() {
|
|
1290
|
+
return new Command2("create-knowledge").summary("Create a knowledge artifact from Anima's template").description(
|
|
1291
|
+
"Create a ready knowledge artifact from Anima's server-provided template. The template supplies the files and framework; only an optional display name is accepted."
|
|
1292
|
+
).option("--name <name>", 'Display name (defaults to "Untitled project"; max 120 characters)').option(
|
|
1293
|
+
"-w, --workspace <id>",
|
|
1294
|
+
"The workspace to create it in (id from `anima workspaces`). Optional when you can create in only one workspace; otherwise required, since there is no default"
|
|
1295
|
+
).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 (opts) => {
|
|
1296
|
+
const mode = detectOutputMode(opts);
|
|
1297
|
+
initLogger(opts.logFile);
|
|
1298
|
+
const progress = new ProgressReporter(mode, opts.verbose);
|
|
1299
|
+
await withCommandErrors(mode, async () => {
|
|
1300
|
+
try {
|
|
1301
|
+
await run();
|
|
1302
|
+
} catch (err) {
|
|
1303
|
+
progress.fail("Failed");
|
|
1304
|
+
throw err;
|
|
1305
|
+
}
|
|
1306
|
+
});
|
|
1307
|
+
async function run() {
|
|
1308
|
+
const args = buildCreateKnowledgeArgs(opts.name, opts.workspace);
|
|
1309
|
+
const auth = await resolveAuth(opts.apiUrl);
|
|
1310
|
+
progress.start("Creating knowledge artifact from template...");
|
|
1311
|
+
const result = await withMcp(
|
|
1312
|
+
{ apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId },
|
|
1313
|
+
(client) => client.callTool("artifact-create_knowledge", args)
|
|
1314
|
+
);
|
|
1315
|
+
if (!result.success || !result.sessionId) {
|
|
1316
|
+
throw apiError(result.message || result.reason || result.error || "Knowledge artifact creation failed", result);
|
|
1317
|
+
}
|
|
1318
|
+
progress.succeed("Knowledge artifact created");
|
|
1319
|
+
if (mode === "pretty") {
|
|
1320
|
+
printSessionResult({
|
|
1321
|
+
sessionId: result.sessionId,
|
|
1322
|
+
artifactUrl: result.artifactUrl,
|
|
1323
|
+
playgroundUrl: result.playgroundUrl
|
|
1324
|
+
});
|
|
1325
|
+
if (result.fileCount !== void 0) {
|
|
1326
|
+
printKeyValue("Template files", String(result.fileCount));
|
|
1327
|
+
}
|
|
1328
|
+
console.log();
|
|
1329
|
+
} else {
|
|
1330
|
+
outputResult(mode, result);
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
var createKnowledgeCommand = makeCreateKnowledgeCommand();
|
|
1336
|
+
|
|
1337
|
+
// src/commands/list.ts
|
|
1338
|
+
import { Command as Command3 } from "commander";
|
|
1214
1339
|
import chalk3 from "chalk";
|
|
1215
|
-
var listCommand = new
|
|
1216
|
-
"List
|
|
1340
|
+
var listCommand = new Command3("list").summary("List the artifacts you can read, most-recently-updated first").aliases(["ls", "artifacts"]).description(
|
|
1341
|
+
"List the artifacts you can read, across every workspace you can reach or in one (most-recently-updated first), so you can resume existing work."
|
|
1342
|
+
).option(
|
|
1343
|
+
"-w, --workspace <id>",
|
|
1344
|
+
"Only this workspace (id from `anima workspaces`); omit to span every workspace you can read"
|
|
1217
1345
|
).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) => {
|
|
1218
1346
|
const mode = detectOutputMode(opts);
|
|
1219
1347
|
initLogger(opts.logFile);
|
|
1220
1348
|
try {
|
|
1221
1349
|
const auth = await resolveAuth(opts.apiUrl);
|
|
1350
|
+
const workspaceId = workspaceFlag(opts.workspace);
|
|
1222
1351
|
const result = await withMcp(
|
|
1223
1352
|
{ apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId },
|
|
1224
|
-
(client) => client.callTool(
|
|
1353
|
+
(client) => client.callTool(
|
|
1354
|
+
"workspace-list_artifacts",
|
|
1355
|
+
workspaceId !== void 0 ? { workspaceId } : {}
|
|
1356
|
+
)
|
|
1225
1357
|
);
|
|
1226
1358
|
if (!result.success) {
|
|
1227
|
-
const message = result.reason || result.error || "Could not list artifacts";
|
|
1359
|
+
const message = result.message || result.reason || result.error || "Could not list artifacts";
|
|
1228
1360
|
throw apiError(message, result);
|
|
1229
1361
|
}
|
|
1230
1362
|
const artifacts = result.artifacts ?? [];
|
|
@@ -1233,20 +1365,19 @@ var listCommand = new Command2("list").summary("List your team's artifacts, most
|
|
|
1233
1365
|
if (artifacts.length === 0) {
|
|
1234
1366
|
console.log();
|
|
1235
1367
|
console.log(
|
|
1236
|
-
" No artifacts
|
|
1368
|
+
workspaceId !== void 0 ? " Nothing you can read in that workspace." : " No artifacts you can read \u2014 create one with `create -t empty` or `create -t import`."
|
|
1237
1369
|
);
|
|
1238
1370
|
console.log();
|
|
1239
1371
|
} else {
|
|
1240
1372
|
console.log();
|
|
1241
1373
|
for (const a of artifacts) {
|
|
1242
1374
|
console.log(` ${chalk3.bold(a.name)} ${chalk3.gray(`(${a.type})`)}`);
|
|
1243
|
-
|
|
1244
|
-
|
|
1375
|
+
console.log(` ${chalk3.gray("session:")} ${a.sessionId}`);
|
|
1376
|
+
if (a.workspaceName) {
|
|
1377
|
+
console.log(` ${chalk3.gray("workspace:")} ${a.workspaceName}`);
|
|
1245
1378
|
}
|
|
1246
1379
|
console.log(` ${chalk3.gray("updated:")} ${formatUpdatedAt(a.updatedAt)}`);
|
|
1247
|
-
|
|
1248
|
-
console.log(` ${chalk3.cyan.underline(artifactUrlFor(a.sessionId))}`);
|
|
1249
|
-
}
|
|
1380
|
+
console.log(` ${chalk3.cyan.underline(artifactUrlFor(a.sessionId))}`);
|
|
1250
1381
|
console.log();
|
|
1251
1382
|
}
|
|
1252
1383
|
if (result.truncated) {
|
|
@@ -1259,13 +1390,9 @@ var listCommand = new Command2("list").summary("List your team's artifacts, most
|
|
|
1259
1390
|
} else {
|
|
1260
1391
|
outputResult(mode, {
|
|
1261
1392
|
success: true,
|
|
1262
|
-
workspaceId: result.workspaceId,
|
|
1263
1393
|
// The listing tool returns no URL; deriving it here saves every caller
|
|
1264
1394
|
// the same string concatenation, and keeps one definition of the link.
|
|
1265
|
-
artifacts: artifacts.map((a) => ({
|
|
1266
|
-
...a,
|
|
1267
|
-
...a.sessionId ? { artifactUrl: artifactUrlFor(a.sessionId) } : {}
|
|
1268
|
-
})),
|
|
1395
|
+
artifacts: artifacts.map((a) => ({ ...a, artifactUrl: artifactUrlFor(a.sessionId) })),
|
|
1269
1396
|
truncated: result.truncated ?? false
|
|
1270
1397
|
});
|
|
1271
1398
|
}
|
|
@@ -1289,10 +1416,65 @@ function formatUpdatedAt(iso) {
|
|
|
1289
1416
|
return `${relative2} (${iso})`;
|
|
1290
1417
|
}
|
|
1291
1418
|
|
|
1292
|
-
// src/commands/
|
|
1293
|
-
import { Command as
|
|
1419
|
+
// src/commands/workspaces.ts
|
|
1420
|
+
import { Command as Command4 } from "commander";
|
|
1294
1421
|
import chalk4 from "chalk";
|
|
1295
|
-
var
|
|
1422
|
+
var workspacesCommand = new Command4("workspaces").summary("List the workspaces you can reach, and what you may do in each").aliases(["ws"]).description(
|
|
1423
|
+
"List the workspaces you can read in your team, with the capabilities you hold in each. Use a workspace id with `list --workspace` or `create --workspace`."
|
|
1424
|
+
).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) => {
|
|
1425
|
+
const mode = detectOutputMode(opts);
|
|
1426
|
+
initLogger(opts.logFile);
|
|
1427
|
+
try {
|
|
1428
|
+
const auth = await resolveAuth(opts.apiUrl);
|
|
1429
|
+
const result = await withMcp(
|
|
1430
|
+
{ apiBaseUrl: resolveApiUrl(opts.apiUrl), token: auth.token, teamId: auth.teamId },
|
|
1431
|
+
(client) => client.callTool("workspace-list_workspaces", {})
|
|
1432
|
+
);
|
|
1433
|
+
if (!result.success) {
|
|
1434
|
+
const message = result.message || result.reason || result.error || "Could not list workspaces";
|
|
1435
|
+
throw apiError(message, result);
|
|
1436
|
+
}
|
|
1437
|
+
const workspaces = result.workspaces ?? [];
|
|
1438
|
+
logEvent("workspaces_listed", { count: workspaces.length });
|
|
1439
|
+
if (mode === "pretty") {
|
|
1440
|
+
console.log();
|
|
1441
|
+
if (workspaces.length === 0) {
|
|
1442
|
+
console.log(" You cannot reach any workspace in this team.");
|
|
1443
|
+
console.log(
|
|
1444
|
+
chalk4.gray(" Someone who manages the team can grant you access to one.")
|
|
1445
|
+
);
|
|
1446
|
+
console.log();
|
|
1447
|
+
} else {
|
|
1448
|
+
for (const workspace of workspaces) {
|
|
1449
|
+
const label = workspace.isGeneral && workspace.name !== "General" ? chalk4.gray(" (General)") : "";
|
|
1450
|
+
console.log(` ${chalk4.bold(workspace.name)}${label}`);
|
|
1451
|
+
console.log(` ${chalk4.gray("id:")} ${workspace.workspaceId}`);
|
|
1452
|
+
console.log(
|
|
1453
|
+
` ${chalk4.gray("you can:")} ${workspace.capabilities.join(", ") || chalk4.gray("nothing")}`
|
|
1454
|
+
);
|
|
1455
|
+
console.log();
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
} else {
|
|
1459
|
+
outputResult(mode, { success: true, workspaces });
|
|
1460
|
+
}
|
|
1461
|
+
} catch (err) {
|
|
1462
|
+
if (err instanceof CliError) {
|
|
1463
|
+
if (mode === "pretty") {
|
|
1464
|
+
console.error(err.message);
|
|
1465
|
+
} else {
|
|
1466
|
+
outputError(mode, { code: err.code, message: err.message });
|
|
1467
|
+
}
|
|
1468
|
+
process.exit(err.exitCode);
|
|
1469
|
+
}
|
|
1470
|
+
throw err;
|
|
1471
|
+
}
|
|
1472
|
+
});
|
|
1473
|
+
|
|
1474
|
+
// src/commands/status.ts
|
|
1475
|
+
import { Command as Command5 } from "commander";
|
|
1476
|
+
import chalk5 from "chalk";
|
|
1477
|
+
var statusCommand = new Command5("status").summary("Check whether an artifact finished generating").description(
|
|
1296
1478
|
"Check whether an artifact finished generating. --wait blocks until it is ready or failed."
|
|
1297
1479
|
).argument("<artifactUrl>", "Artifact URL or session ID").option("--wait", "Block until generation finishes instead of returning a snapshot").option("--json", "Output as JSON").option("--timeout <ms>", "How long --wait may block", "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 (artifactUrl, opts) => {
|
|
1298
1480
|
const mode = detectOutputMode(opts);
|
|
@@ -1348,10 +1530,10 @@ function printArtifactStatus(sessionId, result) {
|
|
|
1348
1530
|
printKeyValue("Progress", `${result.progress}%`);
|
|
1349
1531
|
}
|
|
1350
1532
|
if (result.artifactUrl) {
|
|
1351
|
-
printKeyValue("Your artifact",
|
|
1533
|
+
printKeyValue("Your artifact", chalk5.cyan.underline(result.artifactUrl));
|
|
1352
1534
|
}
|
|
1353
1535
|
if (result.playgroundUrl) {
|
|
1354
|
-
printKeyValue("Edit in Playground",
|
|
1536
|
+
printKeyValue("Edit in Playground", chalk5.cyan.underline(result.playgroundUrl));
|
|
1355
1537
|
}
|
|
1356
1538
|
if (result.nextStep) {
|
|
1357
1539
|
console.log();
|
|
@@ -1361,8 +1543,8 @@ function printArtifactStatus(sessionId, result) {
|
|
|
1361
1543
|
}
|
|
1362
1544
|
|
|
1363
1545
|
// src/commands/publish.ts
|
|
1364
|
-
import { Command as
|
|
1365
|
-
var publishCommand = new
|
|
1546
|
+
import { Command as Command6 } from "commander";
|
|
1547
|
+
var publishCommand = new Command6("publish").summary("Deploy to a public live URL (only when asked)").description("Deploy an artifact's app to a live public URL (1-3 min)").argument("<sessionId>", "Session ID from create command").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) => {
|
|
1366
1548
|
const mode = detectOutputMode(opts);
|
|
1367
1549
|
initLogger(opts.logFile);
|
|
1368
1550
|
const progress = new ProgressReporter(mode, opts.verbose);
|
|
@@ -1408,7 +1590,7 @@ var publishCommand = new Command4("publish").summary("Deploy to a public live UR
|
|
|
1408
1590
|
});
|
|
1409
1591
|
|
|
1410
1592
|
// src/commands/codegen.ts
|
|
1411
|
-
import { Command as
|
|
1593
|
+
import { Command as Command7 } from "commander";
|
|
1412
1594
|
|
|
1413
1595
|
// src/utils/files.ts
|
|
1414
1596
|
import fs4 from "fs";
|
|
@@ -1436,7 +1618,7 @@ function writeFilesToDisk(files, outputDir) {
|
|
|
1436
1618
|
}
|
|
1437
1619
|
|
|
1438
1620
|
// src/commands/codegen.ts
|
|
1439
|
-
var codegenCommand = new
|
|
1621
|
+
var codegenCommand = new Command7("codegen").summary("Convert a Figma design to local code files").description("Convert Figma design to code files (no artifact)").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) => {
|
|
1440
1622
|
const mode = detectOutputMode(opts);
|
|
1441
1623
|
initLogger(opts.logFile);
|
|
1442
1624
|
const progress = new ProgressReporter(mode, opts.verbose);
|
|
@@ -1508,8 +1690,8 @@ var codegenCommand = new Command5("codegen").summary("Convert a Figma design to
|
|
|
1508
1690
|
});
|
|
1509
1691
|
|
|
1510
1692
|
// src/commands/getGitToken.ts
|
|
1511
|
-
import { Command as
|
|
1512
|
-
import
|
|
1693
|
+
import { Command as Command8 } from "commander";
|
|
1694
|
+
import chalk6 from "chalk";
|
|
1513
1695
|
|
|
1514
1696
|
// src/utils/gitToken.ts
|
|
1515
1697
|
function preview(payload) {
|
|
@@ -1555,7 +1737,7 @@ function gitConfigCommands(commitAuthor) {
|
|
|
1555
1737
|
}
|
|
1556
1738
|
|
|
1557
1739
|
// src/commands/getGitToken.ts
|
|
1558
|
-
var getGitTokenCommand = new
|
|
1740
|
+
var getGitTokenCommand = new Command8("get-git-token").summary("Mint git access to an artifact's repository").description("Mint a short-lived git remote URL for an artifact (clone/push with git)").argument("<artifactUrl>", "Artifact 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 (artifactUrl, opts) => {
|
|
1559
1741
|
const mode = detectOutputMode(opts);
|
|
1560
1742
|
initLogger(opts.logFile);
|
|
1561
1743
|
const progress = new ProgressReporter(mode, opts.verbose);
|
|
@@ -1572,12 +1754,12 @@ var getGitTokenCommand = new Command6("get-git-token").summary("Mint git access
|
|
|
1572
1754
|
progress.succeed(`Git access granted (${grant.access === "rw" ? "read-write" : "read-only"})`);
|
|
1573
1755
|
if (mode === "pretty") {
|
|
1574
1756
|
console.log();
|
|
1575
|
-
console.log(` ${
|
|
1757
|
+
console.log(` ${chalk6.cyan(`git clone ${grant.gitRemoteUrl}`)}`);
|
|
1576
1758
|
console.log();
|
|
1577
1759
|
if (grant.access === "rw") {
|
|
1578
1760
|
if (grant.commitAuthor) {
|
|
1579
1761
|
console.log(" In the clone, set who your commits are from:");
|
|
1580
|
-
console.log(` ${
|
|
1762
|
+
console.log(` ${chalk6.cyan(gitConfigCommands(grant.commitAuthor))}`);
|
|
1581
1763
|
console.log();
|
|
1582
1764
|
}
|
|
1583
1765
|
console.log(" Commit and push to update the live artifact.");
|
|
@@ -1587,7 +1769,7 @@ var getGitTokenCommand = new Command6("get-git-token").summary("Mint git access
|
|
|
1587
1769
|
if (grant.expiresAt) {
|
|
1588
1770
|
console.log(
|
|
1589
1771
|
` The URL embeds a token that expires at ${grant.expiresAt} and cannot be renewed;
|
|
1590
|
-
re-run this command and ${
|
|
1772
|
+
re-run this command and ${chalk6.cyan("git remote set-url origin <new url>")} to keep pushing.`
|
|
1591
1773
|
);
|
|
1592
1774
|
}
|
|
1593
1775
|
console.log(" Treat the URL as a secret \u2014 it grants access to this artifact.");
|
|
@@ -1620,11 +1802,11 @@ var getGitTokenCommand = new Command6("get-git-token").summary("Mint git access
|
|
|
1620
1802
|
});
|
|
1621
1803
|
|
|
1622
1804
|
// src/commands/mcpConfig.ts
|
|
1623
|
-
import { Command as
|
|
1805
|
+
import { Command as Command10 } from "commander";
|
|
1624
1806
|
|
|
1625
1807
|
// src/commands/login.ts
|
|
1626
|
-
import { Command as
|
|
1627
|
-
import
|
|
1808
|
+
import { Command as Command9 } from "commander";
|
|
1809
|
+
import chalk7 from "chalk";
|
|
1628
1810
|
import open from "open";
|
|
1629
1811
|
|
|
1630
1812
|
// src/auth/device.ts
|
|
@@ -1814,7 +1996,7 @@ function resolveDeadline(claimableUntil, now) {
|
|
|
1814
1996
|
}
|
|
1815
1997
|
|
|
1816
1998
|
// src/commands/login.ts
|
|
1817
|
-
var loginCommand = new
|
|
1999
|
+
var loginCommand = new Command9("login").summary("Connect this machine as a scoped agent identity").description("Log in via the device flow, redeem an invite with --invite, or finish an anonymous create with --handoff").option("--invite <url-or-code>", "Redeem an invite link (\u2026/invite/<code>.md) or bare code \u2014 no approval step").option(
|
|
1818
2000
|
"--handoff [token]",
|
|
1819
2001
|
"Log in with the handoff token from an anonymous create. Waits until a human claims the artifact. Defaults to your last one"
|
|
1820
2002
|
).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(
|
|
@@ -1884,9 +2066,9 @@ var loginCommand = new Command7("login").summary("Connect this machine as a scop
|
|
|
1884
2066
|
console.log();
|
|
1885
2067
|
printInfo("To connect, open the verification page and enter this code:");
|
|
1886
2068
|
console.log();
|
|
1887
|
-
console.log(` ${
|
|
2069
|
+
console.log(` ${chalk7.cyan.underline(info.verificationUri)}`);
|
|
1888
2070
|
console.log();
|
|
1889
|
-
console.log(` ${
|
|
2071
|
+
console.log(` ${chalk7.bold.white(info.userCode)}`);
|
|
1890
2072
|
console.log();
|
|
1891
2073
|
printInfo(`Waiting for approval\u2026 (code expires in ${Math.round(info.expiresInSeconds / 60)} minutes)`);
|
|
1892
2074
|
} else {
|
|
@@ -1963,7 +2145,7 @@ async function runHandoffLogin(opts, mode) {
|
|
|
1963
2145
|
printInfo("Waiting for a human to claim the artifact:");
|
|
1964
2146
|
if (pending.artifactUrl) {
|
|
1965
2147
|
console.log();
|
|
1966
|
-
console.log(` ${
|
|
2148
|
+
console.log(` ${chalk7.cyan.underline(pending.artifactUrl)}`);
|
|
1967
2149
|
}
|
|
1968
2150
|
console.log();
|
|
1969
2151
|
printInfo(
|
|
@@ -2038,7 +2220,7 @@ function buildMcpConfig(apiUrl) {
|
|
|
2038
2220
|
}
|
|
2039
2221
|
|
|
2040
2222
|
// src/commands/mcpConfig.ts
|
|
2041
|
-
var mcpConfigCommand = new
|
|
2223
|
+
var mcpConfigCommand = new Command10("mcp-config").summary("Print an MCP server config for your MCP client").description("Print an MCP server config for your MCP client").option("--json", "Output as JSON").option("--api-url <url>", "API base URL (overrides config / ANIMA_API_URL)").action(async (opts) => {
|
|
2042
2224
|
const mode = detectOutputMode(opts);
|
|
2043
2225
|
try {
|
|
2044
2226
|
const mcpConfig = buildMcpConfig(resolveApiUrl(opts.apiUrl));
|
|
@@ -2065,8 +2247,8 @@ var mcpConfigCommand = new Command8("mcp-config").summary("Print an MCP server c
|
|
|
2065
2247
|
});
|
|
2066
2248
|
|
|
2067
2249
|
// src/commands/auth.ts
|
|
2068
|
-
import { Command as
|
|
2069
|
-
import
|
|
2250
|
+
import { Command as Command11 } from "commander";
|
|
2251
|
+
import chalk8 from "chalk";
|
|
2070
2252
|
var DEFAULT_API_URL2 = "https://api.agentgrid.io";
|
|
2071
2253
|
function describePendingHandoff(pending, state) {
|
|
2072
2254
|
return {
|
|
@@ -2084,10 +2266,10 @@ function printPendingHandoff(pending, state) {
|
|
|
2084
2266
|
return;
|
|
2085
2267
|
}
|
|
2086
2268
|
printInfo(`Anonymous artifact ${pending.sessionId} is awaiting a claim (until ${pending.claimableUntil}):`);
|
|
2087
|
-
console.log(` ${
|
|
2088
|
-
console.log(` Run ${
|
|
2269
|
+
console.log(` ${chalk8.cyan.underline(pending.artifactUrl)}`);
|
|
2270
|
+
console.log(` Run ${chalk8.cyan("anima login --handoff")} to wait for it.`);
|
|
2089
2271
|
}
|
|
2090
|
-
var authCommand = new
|
|
2272
|
+
var authCommand = new Command11("auth").summary("Inspect or manage stored credentials").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) => {
|
|
2091
2273
|
const mode = detectOutputMode(opts);
|
|
2092
2274
|
try {
|
|
2093
2275
|
if (opts.token || opts.figmaToken) {
|
|
@@ -2187,13 +2369,13 @@ var authCommand = new Command9("auth").summary("Inspect or manage stored credent
|
|
|
2187
2369
|
if (mode === "pretty") {
|
|
2188
2370
|
console.log();
|
|
2189
2371
|
printInfo("Auth commands:");
|
|
2190
|
-
console.log(` ${
|
|
2191
|
-
console.log(` ${
|
|
2192
|
-
console.log(` ${
|
|
2193
|
-
console.log(` ${
|
|
2194
|
-
console.log(` ${
|
|
2372
|
+
console.log(` ${chalk8.cyan("anima login")} Log in (device flow \u2014 approve on any browser)`);
|
|
2373
|
+
console.log(` ${chalk8.cyan("anima login --handoff")} Wait for a human to claim your anonymous artifact`);
|
|
2374
|
+
console.log(` ${chalk8.cyan("anima logout")} Clear all credentials`);
|
|
2375
|
+
console.log(` ${chalk8.cyan("anima auth --status")} Check auth status`);
|
|
2376
|
+
console.log(` ${chalk8.cyan("anima auth --figma-token <T>")} Save Figma token (needed for codegen/f2c)`);
|
|
2195
2377
|
console.log();
|
|
2196
|
-
console.log(` Figma token: ${
|
|
2378
|
+
console.log(` Figma token: ${chalk8.cyan.underline("https://www.figma.com")} > Settings > Personal access tokens`);
|
|
2197
2379
|
console.log();
|
|
2198
2380
|
} else {
|
|
2199
2381
|
outputResult(mode, {
|
|
@@ -2215,8 +2397,8 @@ var authCommand = new Command9("auth").summary("Inspect or manage stored credent
|
|
|
2215
2397
|
});
|
|
2216
2398
|
|
|
2217
2399
|
// src/commands/logout.ts
|
|
2218
|
-
import { Command as
|
|
2219
|
-
var logoutCommand = new
|
|
2400
|
+
import { Command as Command12 } from "commander";
|
|
2401
|
+
var logoutCommand = new Command12("logout").summary("Disconnect: revoke and clear every stored credential").description("Clear all stored credentials (AgentGrid + Figma tokens) from this machine").option("--json", "Output as JSON").option("--api-url <url>", "API base URL (overrides config / ANIMA_API_URL)").action(async (opts) => {
|
|
2220
2402
|
const mode = detectOutputMode(opts);
|
|
2221
2403
|
const revoked = await revokeStoredRefreshToken(resolveApiUrl(opts.apiUrl));
|
|
2222
2404
|
const hadCredentials = clearStorage();
|
|
@@ -2234,8 +2416,8 @@ var logoutCommand = new Command10("logout").summary("Disconnect: revoke and clea
|
|
|
2234
2416
|
});
|
|
2235
2417
|
|
|
2236
2418
|
// src/commands/unpublish.ts
|
|
2237
|
-
import { Command as
|
|
2238
|
-
var unpublishCommand = new
|
|
2419
|
+
import { Command as Command13 } from "commander";
|
|
2420
|
+
var unpublishCommand = new Command13("unpublish").summary("Take a published artifact offline").description("Take a published artifact offline (clears its live URL; code and artifact stay intact)").argument("<sessionId>", "Session ID of the published artifact").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) => {
|
|
2239
2421
|
const mode = detectOutputMode(opts);
|
|
2240
2422
|
initLogger(opts.logFile);
|
|
2241
2423
|
const progress = new ProgressReporter(mode, opts.verbose);
|
|
@@ -2270,8 +2452,8 @@ var unpublishCommand = new Command11("unpublish").summary("Take a published arti
|
|
|
2270
2452
|
});
|
|
2271
2453
|
|
|
2272
2454
|
// src/commands/update.ts
|
|
2273
|
-
import { Command as
|
|
2274
|
-
var updateCommand = new
|
|
2455
|
+
import { Command as Command14 } from "commander";
|
|
2456
|
+
var updateCommand = new Command14("update").summary("Rename an artifact or change its visibility").description("Update an artifact's metadata: display name and/or visibility (never touches code)").argument("<sessionId>", "Session ID of the artifact").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) => {
|
|
2275
2457
|
const mode = detectOutputMode(opts);
|
|
2276
2458
|
initLogger(opts.logFile);
|
|
2277
2459
|
const progress = new ProgressReporter(mode, opts.verbose);
|
|
@@ -2316,8 +2498,8 @@ var updateCommand = new Command12("update").summary("Rename an artifact or chang
|
|
|
2316
2498
|
});
|
|
2317
2499
|
|
|
2318
2500
|
// src/commands/config.ts
|
|
2319
|
-
import { Command as
|
|
2320
|
-
var configCommand = new
|
|
2501
|
+
import { Command as Command15 } from "commander";
|
|
2502
|
+
var configCommand = new Command15("config").summary("Store CLI preferences (e.g. a default API URL)").description(
|
|
2321
2503
|
`Store CLI preferences (keys: ${configKeys().join(", ")})`
|
|
2322
2504
|
);
|
|
2323
2505
|
configCommand.command("set <key> <value>").description("Set a config value").option("--json", "Output as JSON").action((key, value, opts) => {
|
|
@@ -2383,9 +2565,9 @@ function assertUrl(value) {
|
|
|
2383
2565
|
}
|
|
2384
2566
|
|
|
2385
2567
|
// src/commands/duplicate.ts
|
|
2386
|
-
import { Command as
|
|
2387
|
-
import
|
|
2388
|
-
function buildDuplicateArgs(artifactUrl, name) {
|
|
2568
|
+
import { Command as Command16 } from "commander";
|
|
2569
|
+
import chalk9 from "chalk";
|
|
2570
|
+
function buildDuplicateArgs(artifactUrl, name, workspaceId) {
|
|
2389
2571
|
const sessionId = parseArtifactUrl(artifactUrl);
|
|
2390
2572
|
if (!sessionId) {
|
|
2391
2573
|
throw validationError("A source artifact URL or session ID is required");
|
|
@@ -2393,17 +2575,24 @@ function buildDuplicateArgs(artifactUrl, name) {
|
|
|
2393
2575
|
if (name !== void 0 && (name.length === 0 || name.length > 120)) {
|
|
2394
2576
|
throw validationError("--name must be between 1 and 120 characters");
|
|
2395
2577
|
}
|
|
2396
|
-
return {
|
|
2578
|
+
return {
|
|
2579
|
+
sessionId,
|
|
2580
|
+
...name !== void 0 ? { name } : {},
|
|
2581
|
+
...workspaceFlag(workspaceId) !== void 0 ? { workspaceId } : {}
|
|
2582
|
+
};
|
|
2397
2583
|
}
|
|
2398
2584
|
function createDuplicateCommand() {
|
|
2399
|
-
return new
|
|
2585
|
+
return new Command16("duplicate").summary("Copy an artifact into a new, independent one").description(
|
|
2400
2586
|
"Duplicate an artifact into a new, independent artifact. Copies code, assets, and supported database content; chat and custom domains are not copied. Duplication is non-idempotent: if a request times out or its response is lost, list recent artifacts before retrying because the first request may already have created the copy."
|
|
2401
|
-
).argument("<artifactUrl>", "Source artifact URL or session ID").option("--name <name>", "Display name for the duplicate (defaults to '<source name> (Copy)')").option(
|
|
2587
|
+
).argument("<artifactUrl>", "Source artifact URL or session ID").option("--name <name>", "Display name for the duplicate (defaults to '<source name> (Copy)')").option(
|
|
2588
|
+
"-w, --workspace <id>",
|
|
2589
|
+
"The workspace to put the copy in (id from `anima workspaces`). Optional when you can create in only one workspace; otherwise required, since there is no default"
|
|
2590
|
+
).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) => {
|
|
2402
2591
|
const mode = detectOutputMode(opts);
|
|
2403
2592
|
initLogger(opts.logFile);
|
|
2404
2593
|
const progress = new ProgressReporter(mode, opts.verbose);
|
|
2405
2594
|
try {
|
|
2406
|
-
const args = buildDuplicateArgs(artifactUrl, opts.name);
|
|
2595
|
+
const args = buildDuplicateArgs(artifactUrl, opts.name, opts.workspace);
|
|
2407
2596
|
const auth = await resolveAuth(opts.apiUrl);
|
|
2408
2597
|
progress.start("Duplicating artifact...");
|
|
2409
2598
|
const result = await withMcp(
|
|
@@ -2411,7 +2600,7 @@ function createDuplicateCommand() {
|
|
|
2411
2600
|
(client) => client.callTool("artifact-duplicate", args)
|
|
2412
2601
|
);
|
|
2413
2602
|
if (!result.success) {
|
|
2414
|
-
throw apiError(result.reason || result.error || "Artifact duplication failed", result);
|
|
2603
|
+
throw apiError(result.message || result.reason || result.error || "Artifact duplication failed", result);
|
|
2415
2604
|
}
|
|
2416
2605
|
progress.succeed("Artifact duplicated");
|
|
2417
2606
|
if (mode === "pretty") {
|
|
@@ -2420,12 +2609,12 @@ function createDuplicateCommand() {
|
|
|
2420
2609
|
printKeyValue("Name", result.name);
|
|
2421
2610
|
printKeyValue("Session ID", result.sessionId);
|
|
2422
2611
|
printKeyValue("Source session", result.sourceSessionId);
|
|
2423
|
-
printKeyValue("Artifact",
|
|
2612
|
+
printKeyValue("Artifact", chalk9.cyan.underline(result.artifactUrl));
|
|
2424
2613
|
if (result.playgroundUrl) {
|
|
2425
|
-
printKeyValue("Edit in Playground",
|
|
2614
|
+
printKeyValue("Edit in Playground", chalk9.cyan.underline(result.playgroundUrl));
|
|
2426
2615
|
}
|
|
2427
2616
|
if (result.previewUrl) {
|
|
2428
|
-
printKeyValue("Preview",
|
|
2617
|
+
printKeyValue("Preview", chalk9.cyan.underline(result.previewUrl));
|
|
2429
2618
|
}
|
|
2430
2619
|
printKeyValue("Next steps", result.nextSteps);
|
|
2431
2620
|
console.log();
|
|
@@ -2448,9 +2637,68 @@ function createDuplicateCommand() {
|
|
|
2448
2637
|
}
|
|
2449
2638
|
var duplicateCommand = createDuplicateCommand();
|
|
2450
2639
|
|
|
2640
|
+
// src/commands/move.ts
|
|
2641
|
+
import { Command as Command17 } from "commander";
|
|
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
|
+
|
|
2451
2699
|
// src/commands/explore.ts
|
|
2452
|
-
import { Command as
|
|
2453
|
-
import
|
|
2700
|
+
import { Command as Command18 } from "commander";
|
|
2701
|
+
import chalk11 from "chalk";
|
|
2454
2702
|
|
|
2455
2703
|
// src/api/tool.ts
|
|
2456
2704
|
async function runTool(toolName, args, options = {}) {
|
|
@@ -2476,25 +2724,8 @@ function describeFailure(result) {
|
|
|
2476
2724
|
${nextSteps}` : base;
|
|
2477
2725
|
}
|
|
2478
2726
|
|
|
2479
|
-
// src/commands/runner.ts
|
|
2480
|
-
async function withCommandErrors(mode, fn) {
|
|
2481
|
-
try {
|
|
2482
|
-
await fn();
|
|
2483
|
-
} catch (err) {
|
|
2484
|
-
if (err instanceof CliError) {
|
|
2485
|
-
if (mode === "pretty") {
|
|
2486
|
-
printError(err.message);
|
|
2487
|
-
} else {
|
|
2488
|
-
outputError(mode, { code: err.code, message: err.message });
|
|
2489
|
-
}
|
|
2490
|
-
process.exit(err.exitCode);
|
|
2491
|
-
}
|
|
2492
|
-
throw err;
|
|
2493
|
-
}
|
|
2494
|
-
}
|
|
2495
|
-
|
|
2496
2727
|
// src/commands/explore.ts
|
|
2497
|
-
var exploreCommand = new
|
|
2728
|
+
var exploreCommand = new Command18("explore").summary("Read an artifact's files: list, search, read, history").description(
|
|
2498
2729
|
"Inspect an artifact's files without git: list them (--tree), search them (--search), read them (--read), or show commits (--history)."
|
|
2499
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) => {
|
|
2500
2731
|
const mode = detectOutputMode(opts);
|
|
@@ -2567,42 +2798,42 @@ function printExplore(action, result) {
|
|
|
2567
2798
|
if (action === "tree") {
|
|
2568
2799
|
for (const file of result.files ?? []) {
|
|
2569
2800
|
const kind = result.unwritable?.[file];
|
|
2570
|
-
console.log(` ${file}${kind ?
|
|
2801
|
+
console.log(` ${file}${kind ? chalk11.gray(` (${kind} \u2014 git only)`) : ""}`);
|
|
2571
2802
|
}
|
|
2572
2803
|
if (result.matchedFiles !== void 0) {
|
|
2573
2804
|
console.log();
|
|
2574
|
-
console.log(
|
|
2805
|
+
console.log(chalk11.gray(` ${(result.files ?? []).length} of ${result.matchedFiles} shown`));
|
|
2575
2806
|
}
|
|
2576
2807
|
} else if (action === "search") {
|
|
2577
2808
|
for (const match of result.matches ?? []) {
|
|
2578
|
-
console.log(` ${
|
|
2809
|
+
console.log(` ${chalk11.cyan(match.path)}:${match.line} ${match.lineText.trim()}`);
|
|
2579
2810
|
}
|
|
2580
2811
|
if (!result.matches?.length) {
|
|
2581
2812
|
console.log(" No matches.");
|
|
2582
2813
|
const skipped = result.notSearched;
|
|
2583
2814
|
if (skipped?.excluded) {
|
|
2584
2815
|
console.log(
|
|
2585
|
-
|
|
2816
|
+
chalk11.yellow(
|
|
2586
2817
|
` ${skipped.excluded} files were skipped (node_modules, dist, build) \u2014 retry with --include-excluded.`
|
|
2587
2818
|
)
|
|
2588
2819
|
);
|
|
2589
2820
|
}
|
|
2590
2821
|
if (skipped?.assets) {
|
|
2591
|
-
console.log(
|
|
2822
|
+
console.log(chalk11.gray(` ${skipped.assets} binary files cannot match a text query.`));
|
|
2592
2823
|
}
|
|
2593
2824
|
}
|
|
2594
2825
|
} else if (action === "read") {
|
|
2595
2826
|
for (const file of result.files ?? []) {
|
|
2596
|
-
console.log(
|
|
2827
|
+
console.log(chalk11.bold(` ${file.path}`));
|
|
2597
2828
|
if (file.asset) {
|
|
2598
|
-
console.log(
|
|
2829
|
+
console.log(chalk11.gray(` binary \u2014 ${file.size ?? "?"} bytes, ${file.mime ?? "unknown type"}`));
|
|
2599
2830
|
} else if (file.deferred) {
|
|
2600
|
-
console.log(
|
|
2831
|
+
console.log(chalk11.yellow(" not returned: the response ran out of budget \u2014 read it on its own"));
|
|
2601
2832
|
} else {
|
|
2602
2833
|
console.log(file.content ?? "");
|
|
2603
2834
|
if (file.truncated) {
|
|
2604
2835
|
console.log(
|
|
2605
|
-
|
|
2836
|
+
chalk11.yellow(
|
|
2606
2837
|
` lines ${file.startLine}-${file.endLine} of ${file.totalLines} \u2014 read the rest with --range`
|
|
2607
2838
|
)
|
|
2608
2839
|
);
|
|
@@ -2612,33 +2843,33 @@ function printExplore(action, result) {
|
|
|
2612
2843
|
}
|
|
2613
2844
|
for (const missing of result.missingPaths ?? []) {
|
|
2614
2845
|
const near = result.suggestions?.[missing];
|
|
2615
|
-
console.log(
|
|
2846
|
+
console.log(chalk11.yellow(` Not found: ${missing}${near?.length ? ` \u2014 did you mean ${near.join(", ")}?` : ""}`));
|
|
2616
2847
|
}
|
|
2617
2848
|
} else {
|
|
2618
2849
|
const commits = result.commit ? [result.commit] : result.commits ?? [];
|
|
2619
2850
|
for (const commit of commits) {
|
|
2620
|
-
console.log(` ${
|
|
2621
|
-
console.log(
|
|
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}`));
|
|
2622
2853
|
}
|
|
2623
2854
|
for (const changed of result.commit?.changedFiles ?? []) {
|
|
2624
|
-
console.log(
|
|
2855
|
+
console.log(chalk11.gray(` ${changed.change.padEnd(8)} ${changed.path}`));
|
|
2625
2856
|
}
|
|
2626
2857
|
}
|
|
2627
2858
|
if (result.truncated) {
|
|
2628
|
-
console.log(
|
|
2859
|
+
console.log(chalk11.yellow(" The list was capped \u2014 raise --limit to see more."));
|
|
2629
2860
|
}
|
|
2630
2861
|
if (result.revision) {
|
|
2631
2862
|
console.log();
|
|
2632
|
-
console.log(
|
|
2863
|
+
console.log(chalk11.gray(` revision: ${result.revision} (pass to \`anima edit --base-revision\`)`));
|
|
2633
2864
|
}
|
|
2634
2865
|
console.log();
|
|
2635
2866
|
}
|
|
2636
2867
|
|
|
2637
2868
|
// src/commands/edit.ts
|
|
2638
|
-
import { Command as
|
|
2869
|
+
import { Command as Command19 } from "commander";
|
|
2639
2870
|
import fs5 from "fs";
|
|
2640
|
-
import
|
|
2641
|
-
var editCommand = new
|
|
2871
|
+
import chalk12 from "chalk";
|
|
2872
|
+
var editCommand = new Command19("edit").summary("Change an artifact's files and commit them").description(
|
|
2642
2873
|
"Change an artifact's files and commit them, without git. All changes land as one commit."
|
|
2643
2874
|
).argument("<artifactUrl>", "Artifact URL or session ID").requiredOption("-m, --message <message>", "Commit message").option(
|
|
2644
2875
|
"--base-revision <rev>",
|
|
@@ -2660,7 +2891,7 @@ var editCommand = new Command16("edit").summary("Change an artifact's files and
|
|
|
2660
2891
|
printSuccess("Committed.");
|
|
2661
2892
|
for (const changed of result.changedFiles ?? []) {
|
|
2662
2893
|
const detail = changed.op === "move" ? `${changed.fromPath} \u2192 ${changed.path}` : changed.replacements !== void 0 ? `${changed.path} (${changed.replacements} replaced)` : changed.path;
|
|
2663
|
-
console.log(` ${
|
|
2894
|
+
console.log(` ${chalk12.gray(changed.op.padEnd(12))} ${detail}`);
|
|
2664
2895
|
}
|
|
2665
2896
|
console.log();
|
|
2666
2897
|
printKeyValue("Revision", result.revision ?? "unknown");
|
|
@@ -2758,11 +2989,11 @@ function readFile(path7) {
|
|
|
2758
2989
|
}
|
|
2759
2990
|
|
|
2760
2991
|
// src/commands/uploadAsset.ts
|
|
2761
|
-
import { Command as
|
|
2992
|
+
import { Command as Command20 } from "commander";
|
|
2762
2993
|
import fs6 from "fs";
|
|
2763
2994
|
import path5 from "path";
|
|
2764
|
-
import
|
|
2765
|
-
var uploadAssetCommand = new
|
|
2995
|
+
import chalk13 from "chalk";
|
|
2996
|
+
var uploadAssetCommand = new Command20("upload-asset").summary("Add an image, font or media file over 256 KB").description(
|
|
2766
2997
|
"Add a large image, font or media file (over 256 KB) to an artifact: stage it, upload it, and commit it at --path."
|
|
2767
2998
|
).argument("<artifactUrl>", "Artifact URL or session ID").argument("<file>", "Local file to upload").option(
|
|
2768
2999
|
"--path <path>",
|
|
@@ -2799,7 +3030,7 @@ var uploadAssetCommand = new Command17("upload-asset").summary("Add an image, fo
|
|
|
2799
3030
|
console.log();
|
|
2800
3031
|
console.log(" Commit it where it belongs with:");
|
|
2801
3032
|
console.log(
|
|
2802
|
-
` ${
|
|
3033
|
+
` ${chalk13.cyan(
|
|
2803
3034
|
`anima edit ${sessionId} -m "Add asset" --changes '[{"op":"write","path":"public/${path5.basename(file)}","assetUploadId":"${grant.assetUploadId}"}]'`
|
|
2804
3035
|
)}`
|
|
2805
3036
|
);
|
|
@@ -2876,8 +3107,8 @@ function readAsset(file) {
|
|
|
2876
3107
|
}
|
|
2877
3108
|
|
|
2878
3109
|
// src/commands/delete.ts
|
|
2879
|
-
import { Command as
|
|
2880
|
-
var deleteCommand = new
|
|
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) => {
|
|
2881
3112
|
const mode = detectOutputMode(opts);
|
|
2882
3113
|
initLogger(opts.logFile);
|
|
2883
3114
|
const progress = new ProgressReporter(mode, opts.verbose);
|
|
@@ -2918,9 +3149,9 @@ var deleteCommand = new Command18("delete").summary("Delete an artifact (reversi
|
|
|
2918
3149
|
});
|
|
2919
3150
|
|
|
2920
3151
|
// src/commands/review.ts
|
|
2921
|
-
import { Command as
|
|
2922
|
-
import
|
|
2923
|
-
var listSubcommand = new
|
|
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) => {
|
|
2924
3155
|
const mode = detectOutputMode(opts);
|
|
2925
3156
|
initLogger(opts.logFile);
|
|
2926
3157
|
await withCommandErrors(mode, async () => {
|
|
@@ -2935,7 +3166,7 @@ var listSubcommand = new Command19("list").summary("Read the comments addressed
|
|
|
2935
3166
|
}
|
|
2936
3167
|
});
|
|
2937
3168
|
});
|
|
2938
|
-
var resolveSubcommand = new
|
|
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) => {
|
|
2939
3170
|
const mode = detectOutputMode(opts);
|
|
2940
3171
|
initLogger(opts.logFile);
|
|
2941
3172
|
await withCommandErrors(mode, async () => {
|
|
@@ -2954,7 +3185,7 @@ var resolveSubcommand = new Command19("resolve").summary("Close one comment with
|
|
|
2954
3185
|
}
|
|
2955
3186
|
});
|
|
2956
3187
|
});
|
|
2957
|
-
var replySubcommand = new
|
|
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) => {
|
|
2958
3189
|
const mode = detectOutputMode(opts);
|
|
2959
3190
|
initLogger(opts.logFile);
|
|
2960
3191
|
await withCommandErrors(mode, async () => {
|
|
@@ -2973,7 +3204,7 @@ var replySubcommand = new Command19("reply").summary("Answer one comment, leavin
|
|
|
2973
3204
|
}
|
|
2974
3205
|
});
|
|
2975
3206
|
});
|
|
2976
|
-
var reviewCommand = new
|
|
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);
|
|
2977
3208
|
function parseLimit2(value) {
|
|
2978
3209
|
const limit = Number(value);
|
|
2979
3210
|
if (!Number.isInteger(limit) || limit < 1 || limit > 50) {
|
|
@@ -2990,29 +3221,29 @@ function printReviews(result) {
|
|
|
2990
3221
|
return;
|
|
2991
3222
|
}
|
|
2992
3223
|
for (const review of reviews) {
|
|
2993
|
-
console.log(` ${
|
|
2994
|
-
console.log(` ${
|
|
3224
|
+
console.log(` ${chalk14.bold(`Review ${review.reviewId}`)} ${chalk14.gray(`by ${review.author.name}`)}`);
|
|
3225
|
+
console.log(` ${chalk14.cyan.underline(review.artifactUrl)}`);
|
|
2995
3226
|
if (!review.isLatest) {
|
|
2996
3227
|
console.log(
|
|
2997
|
-
|
|
3228
|
+
chalk14.yellow(" The artifact moved since this was written \u2014 check the comments still apply.")
|
|
2998
3229
|
);
|
|
2999
3230
|
}
|
|
3000
3231
|
console.log();
|
|
3001
3232
|
for (const comment of review.comments) {
|
|
3002
3233
|
const marks = [
|
|
3003
|
-
comment.status !== "open" ?
|
|
3004
|
-
comment.unassigned ?
|
|
3234
|
+
comment.status !== "open" ? chalk14.gray(comment.status) : null,
|
|
3235
|
+
comment.unassigned ? chalk14.yellow("unassigned") : null
|
|
3005
3236
|
].filter(Boolean).join(" ");
|
|
3006
|
-
console.log(` ${
|
|
3007
|
-
console.log(
|
|
3237
|
+
console.log(` ${chalk14.bold(`#${comment.index}`)} ${comment.body}${marks ? ` ${marks}` : ""}`);
|
|
3238
|
+
console.log(chalk14.gray(` ${comment.commentId}${describeAnchor(comment)}`));
|
|
3008
3239
|
for (const reply of comment.replies ?? []) {
|
|
3009
|
-
console.log(
|
|
3240
|
+
console.log(chalk14.gray(` \u21B3 ${reply.author.name}: ${reply.body}`));
|
|
3010
3241
|
}
|
|
3011
3242
|
console.log();
|
|
3012
3243
|
}
|
|
3013
3244
|
printKeyValue("To close these in a commit", "");
|
|
3014
3245
|
for (const line of review.resolveTrailer.split("\n")) {
|
|
3015
|
-
console.log(` ${
|
|
3246
|
+
console.log(` ${chalk14.gray(line)}`);
|
|
3016
3247
|
}
|
|
3017
3248
|
console.log();
|
|
3018
3249
|
}
|
|
@@ -3033,13 +3264,13 @@ function describeAnchor(comment) {
|
|
|
3033
3264
|
}
|
|
3034
3265
|
|
|
3035
3266
|
// src/commands/skill.ts
|
|
3036
|
-
import { Command as
|
|
3267
|
+
import { Command as Command23 } from "commander";
|
|
3037
3268
|
import fs7 from "fs";
|
|
3038
3269
|
import path6 from "path";
|
|
3039
|
-
import
|
|
3270
|
+
import chalk15 from "chalk";
|
|
3040
3271
|
var GUIDE_PATH = "/guide.md";
|
|
3041
3272
|
function createSkillCommand() {
|
|
3042
|
-
return new
|
|
3273
|
+
return new Command23("skill").summary("Install the AgentGrid guide as a skill your agent can read").description(
|
|
3043
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."
|
|
3044
3275
|
).argument(
|
|
3045
3276
|
"[path]",
|
|
@@ -3066,8 +3297,8 @@ ${body}
|
|
|
3066
3297
|
logEvent("skill_installed", { path: target, bytes: document.length });
|
|
3067
3298
|
if (mode === "pretty") {
|
|
3068
3299
|
console.log();
|
|
3069
|
-
printSuccess(`Skill written to ${
|
|
3070
|
-
console.log(` ${
|
|
3300
|
+
printSuccess(`Skill written to ${chalk15.cyan(target)}`);
|
|
3301
|
+
console.log(` ${chalk15.gray(`${document.length} bytes, from ${apiUrl}${GUIDE_PATH}`)}`);
|
|
3071
3302
|
console.log();
|
|
3072
3303
|
} else {
|
|
3073
3304
|
outputResult(mode, {
|
|
@@ -3196,7 +3427,7 @@ function writeDocument(target, document) {
|
|
|
3196
3427
|
}
|
|
3197
3428
|
|
|
3198
3429
|
// src/index.ts
|
|
3199
|
-
var program = new
|
|
3430
|
+
var program = new Command24().name("anima").description(
|
|
3200
3431
|
`AgentGrid CLI \u2014 create, change, publish and share artifacts on AgentGrid.
|
|
3201
3432
|
An artifact is a real git repository, and every command below runs one
|
|
3202
3433
|
AgentGrid MCP tool for you. The command list is at the bottom; run
|
|
@@ -3206,6 +3437,7 @@ THE MAIN FLOW (build something and put it on AgentGrid):
|
|
|
3206
3437
|
1. anima login # once; a human approves
|
|
3207
3438
|
2. anima create -t import --from ./my-project # your code \u2192 a live app
|
|
3208
3439
|
(or: create -t empty --framework html \u2014 an empty repo you push to)
|
|
3440
|
+
(can create in several workspaces? add --workspace <id>; see "workspaces")
|
|
3209
3441
|
3. Change it. Two doors, same git repository:
|
|
3210
3442
|
- no clone: "explore" to read the files, "edit" to commit them. Needs no
|
|
3211
3443
|
shell, no git binary and no network of its own \u2014 prefer it.
|
|
@@ -3241,6 +3473,7 @@ EXAMPLES:
|
|
|
3241
3473
|
anima explore <sessionId> --search "buttonColor"
|
|
3242
3474
|
anima edit <sessionId> -m "Blue pill" --replace src/App.tsx --old red --new blue
|
|
3243
3475
|
anima review list # what humans asked you to change
|
|
3476
|
+
anima move <sessionId> -w <workspaceId> # re-file it; the URL is unchanged
|
|
3244
3477
|
anima publish <sessionId> # only on explicit request
|
|
3245
3478
|
|
|
3246
3479
|
OUTPUT: pretty text in a terminal; a single JSON object on stdout when piped
|
|
@@ -3249,8 +3482,10 @@ OUTPUT: pretty text in a terminal; a single JSON object on stdout when piped
|
|
|
3249
3482
|
).version(version, "-v, --version");
|
|
3250
3483
|
program.addCommand(loginCommand);
|
|
3251
3484
|
program.addCommand(logoutCommand);
|
|
3485
|
+
program.addCommand(workspacesCommand);
|
|
3252
3486
|
program.addCommand(listCommand);
|
|
3253
3487
|
program.addCommand(createCommand);
|
|
3488
|
+
program.addCommand(createKnowledgeCommand);
|
|
3254
3489
|
program.addCommand(statusCommand);
|
|
3255
3490
|
program.addCommand(exploreCommand);
|
|
3256
3491
|
program.addCommand(editCommand);
|
|
@@ -3258,6 +3493,7 @@ program.addCommand(uploadAssetCommand);
|
|
|
3258
3493
|
program.addCommand(getGitTokenCommand);
|
|
3259
3494
|
program.addCommand(reviewCommand);
|
|
3260
3495
|
program.addCommand(duplicateCommand);
|
|
3496
|
+
program.addCommand(moveCommand);
|
|
3261
3497
|
program.addCommand(publishCommand);
|
|
3262
3498
|
program.addCommand(unpublishCommand);
|
|
3263
3499
|
program.addCommand(updateCommand);
|