argus-media-cli 0.1.1 → 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 +24 -12
- package/dist/index.js +381 -34
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ npx argus-media-cli upload photo.jpg
|
|
|
17
17
|
## Setup
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
argus login
|
|
20
|
+
argus-media-cli login
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
Or set your API key as an environment variable:
|
|
@@ -31,37 +31,49 @@ export ARGUS_API_KEY=ak_your_key_here
|
|
|
31
31
|
### Upload
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
argus upload photo.jpg
|
|
35
|
-
argus upload hero.png --project campaign-q2 --tags hero,banner
|
|
34
|
+
argus-media-cli upload photo.jpg
|
|
35
|
+
argus-media-cli upload hero.png --project campaign-q2 --tags hero,banner
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
### Search
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
argus search "sunset landscape"
|
|
42
|
-
argus search --project website --status ready --json
|
|
41
|
+
argus-media-cli search "sunset landscape"
|
|
42
|
+
argus-media-cli search --project website --status ready --json
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
### List
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
-
argus list
|
|
49
|
-
argus list --project website --limit 20
|
|
48
|
+
argus-media-cli list
|
|
49
|
+
argus-media-cli list --project website --limit 20
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
### Get
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
|
-
argus get <asset-id>
|
|
56
|
-
argus get abc12345 --json
|
|
55
|
+
argus-media-cli get <asset-id>
|
|
56
|
+
argus-media-cli get abc12345 --json
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
### Login
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
|
-
argus login # Interactive prompt
|
|
63
|
-
argus login --key ak_xxx # Non-interactive
|
|
64
|
-
argus login --url http://localhost:8787 # Custom API URL
|
|
62
|
+
argus-media-cli login # Interactive prompt
|
|
63
|
+
argus-media-cli login --key ak_xxx # Non-interactive
|
|
64
|
+
argus-media-cli login --url http://localhost:8787 # Custom API URL
|
|
65
|
+
```
|
|
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)
|
|
65
77
|
```
|
|
66
78
|
|
|
67
79
|
## Options
|
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,35 +140,71 @@ 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 list`.");
|
|
197
|
+
catch {
|
|
198
|
+
// non-fatal
|
|
154
199
|
}
|
|
155
200
|
}
|
|
156
201
|
async function cmdUpload(args, flags) {
|
|
157
202
|
const filePath = args[0];
|
|
158
203
|
if (!filePath) {
|
|
159
|
-
console.error("Usage: argus upload <file> [--project NAME] [--tags a,b,c]");
|
|
204
|
+
console.error("Usage: argus-media-cli upload <file> [--project NAME] [--tags a,b,c]");
|
|
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) {
|
|
@@ -233,7 +279,7 @@ async function cmdList(_args, flags) {
|
|
|
233
279
|
async function cmdGet(args, flags) {
|
|
234
280
|
const id = args[0];
|
|
235
281
|
if (!id) {
|
|
236
|
-
console.error("Usage: argus get <asset-id>");
|
|
282
|
+
console.error("Usage: argus-media-cli get <asset-id>");
|
|
237
283
|
process.exit(1);
|
|
238
284
|
}
|
|
239
285
|
const config = await loadConfig();
|
|
@@ -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 = {};
|
|
@@ -288,10 +562,10 @@ function parseArgs(argv) {
|
|
|
288
562
|
return { command, args, flags };
|
|
289
563
|
}
|
|
290
564
|
function printHelp() {
|
|
291
|
-
console.log(`\x1b[1margus\x1b[0m — AI-native media asset management
|
|
565
|
+
console.log(`\x1b[1margus-media-cli\x1b[0m — AI-native media asset management
|
|
292
566
|
|
|
293
567
|
\x1b[1mUsage:\x1b[0m
|
|
294
|
-
argus <command> [options]
|
|
568
|
+
argus-media-cli <command> [options]
|
|
295
569
|
|
|
296
570
|
\x1b[1mCommands:\x1b[0m
|
|
297
571
|
login Authenticate with Argus
|
|
@@ -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,45 +597,110 @@ 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)
|
|
325
627
|
|
|
326
628
|
\x1b[1mExamples:\x1b[0m
|
|
327
|
-
argus login
|
|
328
|
-
argus upload photo.jpg --project campaign-q2 --tags hero,banner
|
|
329
|
-
argus search "sunset landscape" --json
|
|
330
|
-
argus list --project website --limit 20
|
|
331
|
-
argus get abc12345-def6-7890-abcd-ef1234567890
|
|
629
|
+
argus-media-cli login
|
|
630
|
+
argus-media-cli upload photo.jpg --project campaign-q2 --tags hero,banner
|
|
631
|
+
argus-media-cli search "sunset landscape" --json
|
|
632
|
+
argus-media-cli list --project website --limit 20
|
|
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];
|
|
354
701
|
if (!handler) {
|
|
355
702
|
console.error(`Unknown command: ${command}`);
|
|
356
|
-
console.error('Run "argus help" for usage.');
|
|
703
|
+
console.error('Run "argus-media-cli help" for usage.');
|
|
357
704
|
process.exit(1);
|
|
358
705
|
}
|
|
359
706
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "argus-media-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "CLI for Argus — AI-native media asset management. Upload, search, analyze, and manage media assets from the terminal.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"argus",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"homepage": "https://argus.build",
|
|
22
22
|
"type": "module",
|
|
23
23
|
"bin": {
|
|
24
|
-
"argus": "./dist/index.js"
|
|
24
|
+
"argus-media-cli": "./dist/index.js"
|
|
25
25
|
},
|
|
26
26
|
"main": "./dist/index.js",
|
|
27
27
|
"files": [
|