argus-media-cli 0.1.2 → 0.3.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 +12 -0
- package/dist/index.js +371 -24
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -64,6 +64,18 @@ argus-media-cli login --key ak_xxx # Non-interactive
|
|
|
64
64
|
argus-media-cli login --url http://localhost:8787 # Custom API URL
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
### API Keys
|
|
68
|
+
|
|
69
|
+
Manage API keys for the current workspace. Works with either a session (from
|
|
70
|
+
`login`) or an existing API key. Use this to rotate a dead or expired key:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
argus-media-cli login # Magic-link session (no key needed)
|
|
74
|
+
argus-media-cli keys list # List active keys
|
|
75
|
+
argus-media-cli keys create --name "MCP" # Mint a new key (shown once)
|
|
76
|
+
argus-media-cli keys revoke <id> # Revoke a key (admin only)
|
|
77
|
+
```
|
|
78
|
+
|
|
67
79
|
## Options
|
|
68
80
|
|
|
69
81
|
All commands support `--json` for structured JSON output.
|
package/dist/index.js
CHANGED
|
@@ -23,22 +23,27 @@ async function saveConfig(config) {
|
|
|
23
23
|
function getBaseUrl(config) {
|
|
24
24
|
return process.env.ARGUS_BASE_URL || config.baseUrl || "https://argus.build";
|
|
25
25
|
}
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
function getAuthHeaders(config) {
|
|
27
|
+
// API key takes precedence (CI / backward compat)
|
|
28
|
+
const apiKey = process.env.ARGUS_API_KEY || config.apiKey;
|
|
29
|
+
if (apiKey) {
|
|
30
|
+
return { Authorization: `Bearer ${apiKey}` };
|
|
31
|
+
}
|
|
32
|
+
// Session-based auth (interactive login)
|
|
33
|
+
const sessionId = config.sessionId;
|
|
34
|
+
if (sessionId) {
|
|
35
|
+
return { Cookie: `session=${sessionId}` };
|
|
32
36
|
}
|
|
33
|
-
|
|
37
|
+
console.error("Error: Not authenticated.");
|
|
38
|
+
console.error("Run `argus-media-cli login` to sign in, or set ARGUS_API_KEY.");
|
|
39
|
+
process.exit(1);
|
|
34
40
|
}
|
|
35
41
|
async function apiRequest(config, method, path, body) {
|
|
36
42
|
const url = `${getBaseUrl(config)}${path}`;
|
|
37
|
-
const apiKey = getApiKey(config);
|
|
38
43
|
const opts = {
|
|
39
44
|
method,
|
|
40
45
|
headers: {
|
|
41
|
-
|
|
46
|
+
...getAuthHeaders(config),
|
|
42
47
|
...(body ? { "Content-Type": "application/json" } : {}),
|
|
43
48
|
},
|
|
44
49
|
...(body ? { body: JSON.stringify(body) } : {}),
|
|
@@ -92,6 +97,8 @@ function formatAssetDetail(a) {
|
|
|
92
97
|
lines.push(` Project: ${a.project}`);
|
|
93
98
|
if (a.url)
|
|
94
99
|
lines.push(` URL: ${a.url}`);
|
|
100
|
+
if (a.displayUrl)
|
|
101
|
+
lines.push(` Display: ${a.displayUrl}`);
|
|
95
102
|
if (a.tags?.length)
|
|
96
103
|
lines.push(` Tags: ${a.tags.join(", ")}`);
|
|
97
104
|
if (a.uploadedBy)
|
|
@@ -118,6 +125,7 @@ function formatAssetDetail(a) {
|
|
|
118
125
|
// ─── Commands ──────────────────────────────────────────────────────────────
|
|
119
126
|
async function cmdLogin(args, flags) {
|
|
120
127
|
const config = await loadConfig();
|
|
128
|
+
// Backward-compat: --key sets API key directly (useful for CI)
|
|
121
129
|
if (flags.key) {
|
|
122
130
|
config.apiKey = flags.key;
|
|
123
131
|
await saveConfig(config);
|
|
@@ -132,25 +140,62 @@ async function cmdLogin(args, flags) {
|
|
|
132
140
|
}
|
|
133
141
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
134
142
|
const ask = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
135
|
-
|
|
136
|
-
console.log("
|
|
137
|
-
const
|
|
143
|
+
const baseUrl = getBaseUrl(config);
|
|
144
|
+
console.log("\x1b[1mArgus CLI Login\x1b[0m\n");
|
|
145
|
+
const email = (await ask("Email: ")).trim().toLowerCase();
|
|
146
|
+
if (!email) {
|
|
147
|
+
rl.close();
|
|
148
|
+
console.error("No email provided.");
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
// Request magic code
|
|
152
|
+
console.log("Sending login code...");
|
|
153
|
+
const magicRes = await fetch(`${baseUrl}/auth/magic`, {
|
|
154
|
+
method: "POST",
|
|
155
|
+
headers: { "Content-Type": "application/json" },
|
|
156
|
+
body: JSON.stringify({ email }),
|
|
157
|
+
});
|
|
158
|
+
if (!magicRes.ok) {
|
|
159
|
+
rl.close();
|
|
160
|
+
const err = await magicRes.json().catch(() => ({ error: "Request failed" }));
|
|
161
|
+
console.error(`Error: ${err.error || "Could not send login code."}`);
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
console.log(`\nCheck your email for a 6-digit code.\n`);
|
|
165
|
+
const code = (await ask("Code: ")).trim();
|
|
138
166
|
rl.close();
|
|
139
|
-
if (!
|
|
140
|
-
console.error("No
|
|
167
|
+
if (!code) {
|
|
168
|
+
console.error("No code provided.");
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
// Verify code and get session
|
|
172
|
+
const verifyRes = await fetch(`${baseUrl}/auth/magic/verify`, {
|
|
173
|
+
method: "POST",
|
|
174
|
+
headers: { "Content-Type": "application/json" },
|
|
175
|
+
body: JSON.stringify({ email, code, source: "cli" }),
|
|
176
|
+
});
|
|
177
|
+
if (!verifyRes.ok) {
|
|
178
|
+
const err = await verifyRes.json().catch(() => ({ error: "Verification failed" }));
|
|
179
|
+
console.error(`Error: ${err.error || "Invalid or expired code."}`);
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
const data = await verifyRes.json();
|
|
183
|
+
if (!data.session) {
|
|
184
|
+
console.error("Error: No session returned from server.");
|
|
141
185
|
process.exit(1);
|
|
142
186
|
}
|
|
143
|
-
config.
|
|
187
|
+
config.sessionId = data.session;
|
|
188
|
+
delete config.apiKey; // prefer session auth
|
|
144
189
|
await saveConfig(config);
|
|
145
|
-
|
|
190
|
+
console.log("\nAuthenticated! Session saved to ~/.argus/config.json");
|
|
191
|
+
// Show usage summary
|
|
146
192
|
try {
|
|
147
193
|
const res = await apiRequest(config, "GET", "/usage");
|
|
148
|
-
console.log(
|
|
194
|
+
console.log(`Workspace tier: ${res.tier}`);
|
|
149
195
|
console.log(`Assets: ${res.assets?.used ?? 0}/${res.assets?.limit ?? "unlimited"}`);
|
|
150
196
|
}
|
|
151
|
-
catch
|
|
152
|
-
|
|
153
|
-
console.log("Key saved anyway. Check it with `argus-media-cli list`.");
|
|
197
|
+
catch {
|
|
198
|
+
// non-fatal
|
|
154
199
|
}
|
|
155
200
|
}
|
|
156
201
|
async function cmdUpload(args, flags) {
|
|
@@ -160,7 +205,6 @@ async function cmdUpload(args, flags) {
|
|
|
160
205
|
process.exit(1);
|
|
161
206
|
}
|
|
162
207
|
const config = await loadConfig();
|
|
163
|
-
const apiKey = getApiKey(config);
|
|
164
208
|
const baseUrl = getBaseUrl(config);
|
|
165
209
|
// Read file
|
|
166
210
|
const fileData = await readFile(filePath);
|
|
@@ -177,7 +221,7 @@ async function cmdUpload(args, flags) {
|
|
|
177
221
|
form.append("tags", flags.tags);
|
|
178
222
|
const res = await fetch(`${baseUrl}/assets/upload`, {
|
|
179
223
|
method: "POST",
|
|
180
|
-
headers: {
|
|
224
|
+
headers: { ...getAuthHeaders(config) },
|
|
181
225
|
body: form,
|
|
182
226
|
});
|
|
183
227
|
if (!res.ok) {
|
|
@@ -194,6 +238,8 @@ async function cmdUpload(args, flags) {
|
|
|
194
238
|
console.log(`Status: ${asset.status}`);
|
|
195
239
|
if (asset.url)
|
|
196
240
|
console.log(`URL: ${asset.url}`);
|
|
241
|
+
if (asset.displayUrl)
|
|
242
|
+
console.log(`Display: ${asset.displayUrl}`);
|
|
197
243
|
}
|
|
198
244
|
}
|
|
199
245
|
async function cmdSearch(args, flags) {
|
|
@@ -261,6 +307,234 @@ async function cmdUsage(_args, flags) {
|
|
|
261
307
|
console.log(` Storage: ${data.storage?.used != null ? formatBytes(data.storage.used) : "0 B"} / ${data.storage?.limit != null ? formatBytes(data.storage.limit) : "unlimited"}`);
|
|
262
308
|
}
|
|
263
309
|
}
|
|
310
|
+
// ─── Phase 2: Generative Commands ─────────────────────────────────────────
|
|
311
|
+
async function cmdCreativeDirection(args, flags) {
|
|
312
|
+
const id = args[0];
|
|
313
|
+
if (!id) {
|
|
314
|
+
console.error("Usage: argus-media-cli creative-direction <asset-id> [--purpose TEXT] [--audience TEXT] [--tone TEXT] [--style TEXT]");
|
|
315
|
+
process.exit(1);
|
|
316
|
+
}
|
|
317
|
+
const config = await loadConfig();
|
|
318
|
+
const body = {};
|
|
319
|
+
if (flags.purpose)
|
|
320
|
+
body.purpose = flags.purpose;
|
|
321
|
+
if (flags.audience)
|
|
322
|
+
body.audience = flags.audience;
|
|
323
|
+
if (flags.tone)
|
|
324
|
+
body.tone = flags.tone;
|
|
325
|
+
if (flags.style)
|
|
326
|
+
body.style = flags.style;
|
|
327
|
+
const data = (await apiRequest(config, "POST", `/assets/${id}/creative-direction`, body));
|
|
328
|
+
if (flags.json) {
|
|
329
|
+
console.log(JSON.stringify(data, null, 2));
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
const cd = data.creativeDirection;
|
|
333
|
+
console.log(`\x1b[1mCreative Direction\x1b[0m${data.cached ? " (cached)" : ""}\n`);
|
|
334
|
+
console.log(cd.rationale);
|
|
335
|
+
if (cd.googleFontsUrl)
|
|
336
|
+
console.log(`\nGoogle Fonts: ${cd.googleFontsUrl}`);
|
|
337
|
+
if (cd.typography?.length) {
|
|
338
|
+
console.log(`\n\x1b[1mTypography:\x1b[0m`);
|
|
339
|
+
for (const t of cd.typography) {
|
|
340
|
+
console.log(` ${t.role}: ${t.css.fontFamily} (${t.css.fontWeight}) — ${t.semantic}`);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
if (cd.colors?.length) {
|
|
344
|
+
console.log(`\n\x1b[1mColors:\x1b[0m`);
|
|
345
|
+
for (const c of cd.colors) {
|
|
346
|
+
console.log(` ${c.role}: ${c.css.color} — ${c.semantic}`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (cd.layout?.length) {
|
|
350
|
+
console.log(`\n\x1b[1mLayout:\x1b[0m`);
|
|
351
|
+
for (const l of cd.layout) {
|
|
352
|
+
console.log(` ${l.pattern} — ${l.semantic}`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
async function cmdTypography(args, flags) {
|
|
357
|
+
const id = args[0];
|
|
358
|
+
if (!id) {
|
|
359
|
+
console.error("Usage: argus-media-cli typography <asset-id> [--purpose TEXT]");
|
|
360
|
+
process.exit(1);
|
|
361
|
+
}
|
|
362
|
+
const config = await loadConfig();
|
|
363
|
+
const body = {};
|
|
364
|
+
if (flags.purpose)
|
|
365
|
+
body.purpose = flags.purpose;
|
|
366
|
+
const data = (await apiRequest(config, "POST", `/assets/${id}/typography`, body));
|
|
367
|
+
if (flags.json) {
|
|
368
|
+
console.log(JSON.stringify(data, null, 2));
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
const typo = data.typography;
|
|
372
|
+
console.log(`\x1b[1mTypography Suggestions\x1b[0m${data.cached ? " (cached)" : ""}\n`);
|
|
373
|
+
if (typo.pairings?.length) {
|
|
374
|
+
for (const t of typo.pairings) {
|
|
375
|
+
console.log(` ${t.role}: ${t.css.fontFamily} (${t.css.fontWeight}) — ${t.semantic}`);
|
|
376
|
+
if (t.googleFontsUrl)
|
|
377
|
+
console.log(` Font: ${t.googleFontsUrl}`);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (typo.googleFontsUrl)
|
|
381
|
+
console.log(`\nGoogle Fonts: ${typo.googleFontsUrl}`);
|
|
382
|
+
if (typo.rationale)
|
|
383
|
+
console.log(`\n${typo.rationale}`);
|
|
384
|
+
}
|
|
385
|
+
async function cmdPalette(args, flags) {
|
|
386
|
+
const id = args[0];
|
|
387
|
+
if (!id) {
|
|
388
|
+
console.error("Usage: argus-media-cli palette <asset-id>");
|
|
389
|
+
process.exit(1);
|
|
390
|
+
}
|
|
391
|
+
const config = await loadConfig();
|
|
392
|
+
const data = (await apiRequest(config, "POST", `/assets/${id}/palette`));
|
|
393
|
+
if (flags.json) {
|
|
394
|
+
console.log(JSON.stringify(data, null, 2));
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
const palette = data.palette;
|
|
398
|
+
console.log(`\x1b[1mColor Palette\x1b[0m${data.cached ? " (cached)" : ""}\n`);
|
|
399
|
+
if (palette.colors?.length) {
|
|
400
|
+
for (const c of palette.colors) {
|
|
401
|
+
console.log(` ${c.role}: ${c.css.color} — ${c.semantic}`);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (palette.rationale)
|
|
405
|
+
console.log(`\n${palette.rationale}`);
|
|
406
|
+
}
|
|
407
|
+
async function cmdCohesion(args, flags) {
|
|
408
|
+
if (args.length < 2) {
|
|
409
|
+
console.error("Usage: argus-media-cli cohesion <asset-id> <asset-id> [<asset-id>...] [--purpose TEXT] [--brand TEXT]");
|
|
410
|
+
process.exit(1);
|
|
411
|
+
}
|
|
412
|
+
const config = await loadConfig();
|
|
413
|
+
const body = { assetIds: args };
|
|
414
|
+
if (flags.purpose || flags.brand) {
|
|
415
|
+
const context = {};
|
|
416
|
+
if (flags.purpose)
|
|
417
|
+
context.purpose = flags.purpose;
|
|
418
|
+
if (flags.brand)
|
|
419
|
+
context.brandName = flags.brand;
|
|
420
|
+
body.context = context;
|
|
421
|
+
}
|
|
422
|
+
const data = (await apiRequest(config, "POST", "/assets/compare-cohesion", body));
|
|
423
|
+
if (flags.json) {
|
|
424
|
+
console.log(JSON.stringify(data, null, 2));
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
const c = data.cohesion;
|
|
428
|
+
console.log(`\x1b[1mCohesion Report\x1b[0m${data.cached ? " (cached)" : ""}\n`);
|
|
429
|
+
console.log(` Overall: ${c.overallScore}/100`);
|
|
430
|
+
console.log(` Typography: ${c.typography.score}/100 — ${c.typography.consistency}`);
|
|
431
|
+
console.log(` Color: ${c.color.score}/100 — ${c.color.harmony}`);
|
|
432
|
+
console.log(` Mood: ${c.mood.score}/100 — ${c.mood.alignment}`);
|
|
433
|
+
if (c.suggestions?.length) {
|
|
434
|
+
console.log(`\n\x1b[1mSuggestions:\x1b[0m`);
|
|
435
|
+
for (const s of c.suggestions) {
|
|
436
|
+
const sev = s.severity === "high" ? "\x1b[31m" : s.severity === "medium" ? "\x1b[33m" : "\x1b[32m";
|
|
437
|
+
console.log(` ${sev}${s.severity}\x1b[0m ${s.asset.slice(0, 8)}: ${s.suggestion}`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
if (c.rationale)
|
|
441
|
+
console.log(`\n${c.rationale}`);
|
|
442
|
+
}
|
|
443
|
+
// ─── API Key Management ───────────────────────────────────────────────────
|
|
444
|
+
async function cmdKeys(args, flags) {
|
|
445
|
+
const sub = args[0];
|
|
446
|
+
const rest = args.slice(1);
|
|
447
|
+
if (!sub || sub === "list" || sub === "ls") {
|
|
448
|
+
return cmdKeysList(rest, flags);
|
|
449
|
+
}
|
|
450
|
+
if (sub === "create" || sub === "new") {
|
|
451
|
+
return cmdKeysCreate(rest, flags);
|
|
452
|
+
}
|
|
453
|
+
if (sub === "revoke" || sub === "delete" || sub === "rm") {
|
|
454
|
+
return cmdKeysRevoke(rest, flags);
|
|
455
|
+
}
|
|
456
|
+
console.error(`Unknown keys subcommand: ${sub}`);
|
|
457
|
+
console.error("Usage: argus-media-cli keys <list|create|revoke>");
|
|
458
|
+
process.exit(1);
|
|
459
|
+
}
|
|
460
|
+
async function cmdKeysList(_args, flags) {
|
|
461
|
+
const config = await loadConfig();
|
|
462
|
+
const data = (await apiRequest(config, "GET", "/keys"));
|
|
463
|
+
if (flags.json) {
|
|
464
|
+
console.log(JSON.stringify(data, null, 2));
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
const keys = data.keys || [];
|
|
468
|
+
if (!keys.length) {
|
|
469
|
+
console.log("No API keys found.");
|
|
470
|
+
console.log("Create one with: argus-media-cli keys create --name 'My Key'");
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
console.log(`\x1b[1m${keys.length} API key${keys.length === 1 ? "" : "s"}\x1b[0m\n`);
|
|
474
|
+
for (const k of keys) {
|
|
475
|
+
const status = k.revoked_at ? "\x1b[31mrevoked\x1b[0m" : "\x1b[32mactive\x1b[0m ";
|
|
476
|
+
const lastUsed = k.last_used_at ? `used ${k.last_used_at}` : "never used";
|
|
477
|
+
console.log(` ${status} ${k.key_prefix}… ${k.name}`);
|
|
478
|
+
console.log(` id: ${k.id}`);
|
|
479
|
+
console.log(` created ${k.created_at}, ${lastUsed}`);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
async function cmdKeysCreate(args, flags) {
|
|
483
|
+
const name = flags.name || args[0] || "API Key";
|
|
484
|
+
const config = await loadConfig();
|
|
485
|
+
const data = (await apiRequest(config, "POST", "/keys", { name }));
|
|
486
|
+
if (flags.json) {
|
|
487
|
+
console.log(JSON.stringify(data, null, 2));
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
console.log(`\x1b[1mAPI key created\x1b[0m\n`);
|
|
491
|
+
console.log(` Name: ${data.name}`);
|
|
492
|
+
console.log(` ID: ${data.id}`);
|
|
493
|
+
console.log(` Prefix: ${data.key_prefix}`);
|
|
494
|
+
console.log(`\n\x1b[1m\x1b[33mKey (shown once — store it now):\x1b[0m`);
|
|
495
|
+
console.log(` ${data.key}\n`);
|
|
496
|
+
console.log(`Use it by setting:`);
|
|
497
|
+
console.log(` export ARGUS_API_KEY=${data.key}`);
|
|
498
|
+
}
|
|
499
|
+
async function cmdKeysRevoke(args, flags) {
|
|
500
|
+
const id = args[0];
|
|
501
|
+
if (!id) {
|
|
502
|
+
console.error("Usage: argus-media-cli keys revoke <id>");
|
|
503
|
+
process.exit(1);
|
|
504
|
+
}
|
|
505
|
+
const config = await loadConfig();
|
|
506
|
+
const data = (await apiRequest(config, "DELETE", `/keys/${id}`));
|
|
507
|
+
if (flags.json) {
|
|
508
|
+
console.log(JSON.stringify(data, null, 2));
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
console.log(`Key ${id} revoked.`);
|
|
512
|
+
}
|
|
513
|
+
async function cmdStyleGuide(args, flags) {
|
|
514
|
+
if (args.length < 1) {
|
|
515
|
+
console.error("Usage: argus-media-cli style-guide <asset-id> [<asset-id>...] [--name TEXT] [--guide-id ID]");
|
|
516
|
+
process.exit(1);
|
|
517
|
+
}
|
|
518
|
+
const config = await loadConfig();
|
|
519
|
+
const body = { assetIds: args };
|
|
520
|
+
if (flags.name)
|
|
521
|
+
body.name = flags.name;
|
|
522
|
+
if (flags["guide-id"])
|
|
523
|
+
body.guideId = flags["guide-id"];
|
|
524
|
+
const data = (await apiRequest(config, "POST", "/style-guides", body));
|
|
525
|
+
if (flags.json) {
|
|
526
|
+
console.log(JSON.stringify(data, null, 2));
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
const sg = data.styleGuide;
|
|
530
|
+
console.log(`\x1b[1mStyle Guide: ${sg.name || sg.id}\x1b[0m\n`);
|
|
531
|
+
console.log(` ID: ${sg.id}`);
|
|
532
|
+
console.log(` Assets: ${sg.sourceAssetIds?.length ?? 0}`);
|
|
533
|
+
if (data.googleFontsUrl)
|
|
534
|
+
console.log(` Fonts: ${data.googleFontsUrl}`);
|
|
535
|
+
if (data.rationale)
|
|
536
|
+
console.log(`\n${data.rationale}`);
|
|
537
|
+
}
|
|
264
538
|
function parseArgs(argv) {
|
|
265
539
|
const command = argv[0] || "help";
|
|
266
540
|
const flags = {};
|
|
@@ -300,6 +574,14 @@ function printHelp() {
|
|
|
300
574
|
list List all assets
|
|
301
575
|
get <id> Get asset details and analysis
|
|
302
576
|
usage Show workspace usage and limits
|
|
577
|
+
creative-direction <id> Generate creative brief for an asset
|
|
578
|
+
typography <id> Suggest typography pairings for an asset
|
|
579
|
+
palette <id> Generate extended color palette from an asset
|
|
580
|
+
cohesion <id> <id> ... Compare visual cohesion across assets
|
|
581
|
+
style-guide <id> ... Generate a style guide from assets
|
|
582
|
+
keys list List API keys in the current workspace
|
|
583
|
+
keys create [--name] Create a new API key (shown once)
|
|
584
|
+
keys revoke <id> Revoke an API key (admin only)
|
|
303
585
|
|
|
304
586
|
\x1b[1mGlobal Options:\x1b[0m
|
|
305
587
|
--json Output raw JSON
|
|
@@ -315,10 +597,30 @@ function printHelp() {
|
|
|
315
597
|
--limit N Max results (default 50)
|
|
316
598
|
--offset N Pagination offset
|
|
317
599
|
|
|
600
|
+
\x1b[1mCreative Direction Options:\x1b[0m
|
|
601
|
+
--purpose TEXT Intended use (e.g. 'hero banner')
|
|
602
|
+
--audience TEXT Target audience
|
|
603
|
+
--tone TEXT Desired tone (e.g. 'professional')
|
|
604
|
+
--style TEXT Visual style (e.g. 'minimalist')
|
|
605
|
+
|
|
606
|
+
\x1b[1mTypography Options:\x1b[0m
|
|
607
|
+
--purpose TEXT Intended use context
|
|
608
|
+
|
|
609
|
+
\x1b[1mCohesion Options:\x1b[0m
|
|
610
|
+
--purpose TEXT Comparison context
|
|
611
|
+
--brand TEXT Brand name for context
|
|
612
|
+
|
|
613
|
+
\x1b[1mStyle Guide Options:\x1b[0m
|
|
614
|
+
--name TEXT Name for the style guide
|
|
615
|
+
--guide-id ID Existing guide ID to update
|
|
616
|
+
|
|
318
617
|
\x1b[1mLogin Options:\x1b[0m
|
|
319
618
|
--key KEY Set API key non-interactively
|
|
320
619
|
--url URL Set custom API base URL
|
|
321
620
|
|
|
621
|
+
\x1b[1mKeys Options:\x1b[0m
|
|
622
|
+
--name TEXT Name for the new key (keys create)
|
|
623
|
+
|
|
322
624
|
\x1b[1mEnvironment:\x1b[0m
|
|
323
625
|
ARGUS_API_KEY API key (overrides saved config)
|
|
324
626
|
ARGUS_BASE_URL API base URL (default: https://argus.build)
|
|
@@ -331,23 +633,68 @@ function printHelp() {
|
|
|
331
633
|
argus-media-cli get abc12345-def6-7890-abcd-ef1234567890
|
|
332
634
|
`);
|
|
333
635
|
}
|
|
636
|
+
// ─── Onboarding ───────────────────────────────────────────────────────────
|
|
637
|
+
function isAuthenticated(config) {
|
|
638
|
+
return !!(process.env.ARGUS_API_KEY || config.apiKey || config.sessionId);
|
|
639
|
+
}
|
|
640
|
+
async function cmdDashboard(_args, flags) {
|
|
641
|
+
const config = await loadConfig();
|
|
642
|
+
const res = await apiRequest(config, "GET", "/usage");
|
|
643
|
+
console.log(`\x1b[1mArgus Dashboard\x1b[0m\n`);
|
|
644
|
+
console.log(` Tier: ${res.tier}`);
|
|
645
|
+
console.log(` Assets: ${res.assets?.used ?? 0} / ${res.assets?.limit ?? "unlimited"}`);
|
|
646
|
+
if (res.storage != null) {
|
|
647
|
+
console.log(` Storage: ${res.storage?.used != null ? formatBytes(res.storage.used) : "0 B"} / ${res.storage?.limit != null ? formatBytes(res.storage.limit) : "unlimited"}`);
|
|
648
|
+
}
|
|
649
|
+
console.log(`\nRun \x1b[1margus-media-cli help\x1b[0m for available commands.`);
|
|
650
|
+
}
|
|
334
651
|
// ─── Main ──────────────────────────────────────────────────────────────────
|
|
335
652
|
const COMMANDS = {
|
|
653
|
+
dashboard: cmdDashboard,
|
|
336
654
|
login: cmdLogin,
|
|
337
655
|
upload: cmdUpload,
|
|
338
656
|
search: cmdSearch,
|
|
339
657
|
list: cmdList,
|
|
340
658
|
get: cmdGet,
|
|
341
659
|
usage: cmdUsage,
|
|
660
|
+
"creative-direction": cmdCreativeDirection,
|
|
661
|
+
typography: cmdTypography,
|
|
662
|
+
palette: cmdPalette,
|
|
663
|
+
cohesion: cmdCohesion,
|
|
664
|
+
"style-guide": cmdStyleGuide,
|
|
665
|
+
keys: cmdKeys,
|
|
342
666
|
};
|
|
343
667
|
async function main() {
|
|
344
|
-
const
|
|
668
|
+
const rawArgs = process.argv.slice(2);
|
|
669
|
+
// No args: onboarding — show dashboard or prompt login
|
|
670
|
+
if (rawArgs.length === 0) {
|
|
671
|
+
const config = await loadConfig();
|
|
672
|
+
if (isAuthenticated(config)) {
|
|
673
|
+
try {
|
|
674
|
+
await cmdDashboard([], {});
|
|
675
|
+
}
|
|
676
|
+
catch {
|
|
677
|
+
console.log("\x1b[1mArgus Media CLI\x1b[0m\n");
|
|
678
|
+
console.log("Run \x1b[1margus-media-cli help\x1b[0m for available commands.");
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
else {
|
|
682
|
+
console.log("\x1b[1mWelcome to Argus!\x1b[0m\n");
|
|
683
|
+
console.log("Get started by signing in:\n");
|
|
684
|
+
console.log(" argus-media-cli login\n");
|
|
685
|
+
console.log("Or set an API key for CI use:\n");
|
|
686
|
+
console.log(" argus-media-cli login --key <your-key>\n");
|
|
687
|
+
console.log("Run \x1b[1margus-media-cli help\x1b[0m for all commands.");
|
|
688
|
+
}
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
const { command, args, flags } = parseArgs(rawArgs);
|
|
345
692
|
if (command === "help" || command === "--help" || command === "-h") {
|
|
346
693
|
printHelp();
|
|
347
694
|
return;
|
|
348
695
|
}
|
|
349
696
|
if (command === "version" || command === "--version" || command === "-v") {
|
|
350
|
-
console.log("argus-media-cli 0.
|
|
697
|
+
console.log("argus-media-cli 0.3.0");
|
|
351
698
|
return;
|
|
352
699
|
}
|
|
353
700
|
const handler = COMMANDS[command];
|
package/package.json
CHANGED