argus-media-cli 0.1.0 → 0.1.2
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 +80 -0
- package/dist/index.js +326 -139
- package/package.json +24 -6
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# argus-media-cli
|
|
2
|
+
|
|
3
|
+
CLI for [Argus](https://argus.build) — AI-native media asset management.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g argus-media-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or run directly:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx argus-media-cli upload photo.jpg
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Setup
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
argus-media-cli login
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or set your API key as an environment variable:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
export ARGUS_API_KEY=ak_your_key_here
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Commands
|
|
30
|
+
|
|
31
|
+
### Upload
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
argus-media-cli upload photo.jpg
|
|
35
|
+
argus-media-cli upload hero.png --project campaign-q2 --tags hero,banner
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Search
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
argus-media-cli search "sunset landscape"
|
|
42
|
+
argus-media-cli search --project website --status ready --json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### List
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
argus-media-cli list
|
|
49
|
+
argus-media-cli list --project website --limit 20
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Get
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
argus-media-cli get <asset-id>
|
|
56
|
+
argus-media-cli get abc12345 --json
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Login
|
|
60
|
+
|
|
61
|
+
```bash
|
|
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
|
+
## Options
|
|
68
|
+
|
|
69
|
+
All commands support `--json` for structured JSON output.
|
|
70
|
+
|
|
71
|
+
## Environment Variables
|
|
72
|
+
|
|
73
|
+
| Variable | Description |
|
|
74
|
+
|---|---|
|
|
75
|
+
| `ARGUS_API_KEY` | API key (overrides saved config) |
|
|
76
|
+
| `ARGUS_BASE_URL` | API base URL (default: `https://argus.build`) |
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -1,180 +1,367 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
import { homedir } from "os";
|
|
5
|
-
|
|
2
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
3
|
+
import { basename, extname, join } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import * as readline from "node:readline";
|
|
6
|
+
// ─── Config ────────────────────────────────────────────────────────────────
|
|
6
7
|
const CONFIG_DIR = join(homedir(), ".argus");
|
|
7
8
|
const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
8
|
-
|
|
9
|
-
function loadConfig() {
|
|
9
|
+
async function loadConfig() {
|
|
10
10
|
try {
|
|
11
|
-
|
|
11
|
+
const data = await readFile(CONFIG_FILE, "utf-8");
|
|
12
|
+
return JSON.parse(data);
|
|
12
13
|
}
|
|
13
14
|
catch {
|
|
14
15
|
return {};
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
|
-
function saveConfig(config) {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
async function saveConfig(config) {
|
|
19
|
+
await mkdir(CONFIG_DIR, { recursive: true });
|
|
20
|
+
await writeFile(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n");
|
|
20
21
|
}
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
// ─── API Client ────────────────────────────────────────────────────────────
|
|
23
|
+
function getBaseUrl(config) {
|
|
24
|
+
return process.env.ARGUS_BASE_URL || config.baseUrl || "https://argus.build";
|
|
25
|
+
}
|
|
26
|
+
function getApiKey(config) {
|
|
27
|
+
const key = process.env.ARGUS_API_KEY || config.apiKey;
|
|
23
28
|
if (!key) {
|
|
24
|
-
console.error("No API key
|
|
25
|
-
console.error("
|
|
29
|
+
console.error("Error: No API key configured.");
|
|
30
|
+
console.error("Run `argus-media-cli login` to authenticate, or set ARGUS_API_KEY.");
|
|
26
31
|
process.exit(1);
|
|
27
32
|
}
|
|
28
33
|
return key;
|
|
29
34
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
35
|
+
async function apiRequest(config, method, path, body) {
|
|
36
|
+
const url = `${getBaseUrl(config)}${path}`;
|
|
37
|
+
const apiKey = getApiKey(config);
|
|
38
|
+
const opts = {
|
|
33
39
|
method,
|
|
34
40
|
headers: {
|
|
35
|
-
Authorization: `Bearer ${
|
|
41
|
+
Authorization: `Bearer ${apiKey}`,
|
|
36
42
|
...(body ? { "Content-Type": "application/json" } : {}),
|
|
37
43
|
},
|
|
38
44
|
...(body ? { body: JSON.stringify(body) } : {}),
|
|
39
|
-
}
|
|
40
|
-
const
|
|
45
|
+
};
|
|
46
|
+
const res = await fetch(url, opts);
|
|
41
47
|
if (!res.ok) {
|
|
42
|
-
const
|
|
43
|
-
|
|
48
|
+
const text = await res.text();
|
|
49
|
+
throw new Error(`API ${method} ${path} failed (${res.status}): ${text}`);
|
|
50
|
+
}
|
|
51
|
+
return res.json();
|
|
52
|
+
}
|
|
53
|
+
// ─── MIME Types ────────────────────────────────────────────────────────────
|
|
54
|
+
const MIME_TYPES = {
|
|
55
|
+
".jpg": "image/jpeg",
|
|
56
|
+
".jpeg": "image/jpeg",
|
|
57
|
+
".png": "image/png",
|
|
58
|
+
".gif": "image/gif",
|
|
59
|
+
".webp": "image/webp",
|
|
60
|
+
".svg": "image/svg+xml",
|
|
61
|
+
".mp4": "video/mp4",
|
|
62
|
+
".mov": "video/quicktime",
|
|
63
|
+
".webm": "video/webm",
|
|
64
|
+
".mp3": "audio/mpeg",
|
|
65
|
+
".wav": "audio/wav",
|
|
66
|
+
".pdf": "application/pdf",
|
|
67
|
+
};
|
|
68
|
+
// ─── Formatting ────────────────────────────────────────────────────────────
|
|
69
|
+
function formatBytes(bytes) {
|
|
70
|
+
if (bytes < 1024)
|
|
71
|
+
return `${bytes} B`;
|
|
72
|
+
if (bytes < 1024 * 1024)
|
|
73
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
74
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
75
|
+
}
|
|
76
|
+
function formatAssetRow(a) {
|
|
77
|
+
const status = a.status === "ready" ? "\x1b[32m●\x1b[0m" : a.status === "pending" ? "\x1b[33m●\x1b[0m" : "\x1b[31m●\x1b[0m";
|
|
78
|
+
const size = formatBytes(a.size || 0);
|
|
79
|
+
const project = a.project ? ` [${a.project}]` : "";
|
|
80
|
+
const tags = a.tags?.length ? ` (${a.tags.join(", ")})` : "";
|
|
81
|
+
return `${status} ${a.id.slice(0, 8)} ${a.filename} ${size}${project}${tags}`;
|
|
82
|
+
}
|
|
83
|
+
function formatAssetDetail(a) {
|
|
84
|
+
const lines = [
|
|
85
|
+
`\x1b[1m${a.filename}\x1b[0m`,
|
|
86
|
+
` ID: ${a.id}`,
|
|
87
|
+
` Status: ${a.status}`,
|
|
88
|
+
` Type: ${a.mimeType}`,
|
|
89
|
+
` Size: ${formatBytes(a.size || 0)}`,
|
|
90
|
+
];
|
|
91
|
+
if (a.project)
|
|
92
|
+
lines.push(` Project: ${a.project}`);
|
|
93
|
+
if (a.url)
|
|
94
|
+
lines.push(` URL: ${a.url}`);
|
|
95
|
+
if (a.tags?.length)
|
|
96
|
+
lines.push(` Tags: ${a.tags.join(", ")}`);
|
|
97
|
+
if (a.uploadedBy)
|
|
98
|
+
lines.push(` Uploader: ${a.uploadedBy}`);
|
|
99
|
+
if (a.uploadedAt)
|
|
100
|
+
lines.push(` Uploaded: ${a.uploadedAt}`);
|
|
101
|
+
if (a.analysis) {
|
|
102
|
+
lines.push(` \x1b[1mAnalysis:\x1b[0m`);
|
|
103
|
+
if (a.analysis.description)
|
|
104
|
+
lines.push(` ${a.analysis.description}`);
|
|
105
|
+
if (a.analysis.mood)
|
|
106
|
+
lines.push(` Mood: ${a.analysis.mood}`);
|
|
107
|
+
if (a.analysis.dominantColors?.length) {
|
|
108
|
+
const colors = a.analysis.dominantColors.map((c) => `${c.name} (${c.hex})`).join(", ");
|
|
109
|
+
lines.push(` Colors: ${colors}`);
|
|
110
|
+
}
|
|
111
|
+
if (a.analysis.useCases?.length)
|
|
112
|
+
lines.push(` Uses: ${a.analysis.useCases.join(", ")}`);
|
|
113
|
+
if (a.analysis.tags?.length)
|
|
114
|
+
lines.push(` Tags: ${a.analysis.tags.join(", ")}`);
|
|
115
|
+
}
|
|
116
|
+
return lines.join("\n");
|
|
117
|
+
}
|
|
118
|
+
// ─── Commands ──────────────────────────────────────────────────────────────
|
|
119
|
+
async function cmdLogin(args, flags) {
|
|
120
|
+
const config = await loadConfig();
|
|
121
|
+
if (flags.key) {
|
|
122
|
+
config.apiKey = flags.key;
|
|
123
|
+
await saveConfig(config);
|
|
124
|
+
console.log("API key saved to ~/.argus/config.json");
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (flags.url) {
|
|
128
|
+
config.baseUrl = flags.url;
|
|
129
|
+
await saveConfig(config);
|
|
130
|
+
console.log(`Base URL set to ${flags.url}`);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
134
|
+
const ask = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
135
|
+
console.log("Argus CLI Login");
|
|
136
|
+
console.log("Get your API key at https://argus.build/ui\n");
|
|
137
|
+
const key = await ask("API key: ");
|
|
138
|
+
rl.close();
|
|
139
|
+
if (!key.trim()) {
|
|
140
|
+
console.error("No key provided.");
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
config.apiKey = key.trim();
|
|
144
|
+
await saveConfig(config);
|
|
145
|
+
// Verify the key works
|
|
146
|
+
try {
|
|
147
|
+
const res = await apiRequest(config, "GET", "/usage");
|
|
148
|
+
console.log(`\nAuthenticated! Workspace tier: ${res.tier}`);
|
|
149
|
+
console.log(`Assets: ${res.assets?.used ?? 0}/${res.assets?.limit ?? "unlimited"}`);
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
console.error(`\nWarning: Could not verify key — ${e.message}`);
|
|
153
|
+
console.log("Key saved anyway. Check it with `argus-media-cli list`.");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async function cmdUpload(args, flags) {
|
|
157
|
+
const filePath = args[0];
|
|
158
|
+
if (!filePath) {
|
|
159
|
+
console.error("Usage: argus-media-cli upload <file> [--project NAME] [--tags a,b,c]");
|
|
44
160
|
process.exit(1);
|
|
45
161
|
}
|
|
46
|
-
|
|
162
|
+
const config = await loadConfig();
|
|
163
|
+
const apiKey = getApiKey(config);
|
|
164
|
+
const baseUrl = getBaseUrl(config);
|
|
165
|
+
// Read file
|
|
166
|
+
const fileData = await readFile(filePath);
|
|
167
|
+
const fileName = basename(filePath);
|
|
168
|
+
const ext = extname(fileName).toLowerCase();
|
|
169
|
+
const mimeType = MIME_TYPES[ext] || "application/octet-stream";
|
|
170
|
+
// Build multipart form data
|
|
171
|
+
const blob = new Blob([fileData], { type: mimeType });
|
|
172
|
+
const form = new FormData();
|
|
173
|
+
form.append("file", blob, fileName);
|
|
174
|
+
if (flags.project)
|
|
175
|
+
form.append("project", flags.project);
|
|
176
|
+
if (flags.tags)
|
|
177
|
+
form.append("tags", flags.tags);
|
|
178
|
+
const res = await fetch(`${baseUrl}/assets/upload`, {
|
|
179
|
+
method: "POST",
|
|
180
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
181
|
+
body: form,
|
|
182
|
+
});
|
|
183
|
+
if (!res.ok) {
|
|
184
|
+
const text = await res.text();
|
|
185
|
+
throw new Error(`Upload failed (${res.status}): ${text}`);
|
|
186
|
+
}
|
|
187
|
+
const data = (await res.json());
|
|
188
|
+
const asset = data.asset;
|
|
189
|
+
if (flags.json) {
|
|
190
|
+
console.log(JSON.stringify(data, null, 2));
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
console.log(`Uploaded: ${asset.filename} (${asset.id})`);
|
|
194
|
+
console.log(`Status: ${asset.status}`);
|
|
195
|
+
if (asset.url)
|
|
196
|
+
console.log(`URL: ${asset.url}`);
|
|
197
|
+
}
|
|
47
198
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
199
|
+
async function cmdSearch(args, flags) {
|
|
200
|
+
const query = args.join(" ");
|
|
201
|
+
const config = await loadConfig();
|
|
202
|
+
const params = new URLSearchParams();
|
|
203
|
+
if (query)
|
|
204
|
+
params.set("q", query);
|
|
205
|
+
if (flags.project)
|
|
206
|
+
params.set("project", flags.project);
|
|
207
|
+
if (flags.status)
|
|
208
|
+
params.set("status", flags.status);
|
|
209
|
+
if (flags.tags)
|
|
210
|
+
params.set("tags", flags.tags);
|
|
211
|
+
if (flags.limit)
|
|
212
|
+
params.set("limit", flags.limit);
|
|
213
|
+
if (flags.offset)
|
|
214
|
+
params.set("offset", flags.offset);
|
|
215
|
+
const qs = params.toString();
|
|
216
|
+
const data = (await apiRequest(config, "GET", `/assets${qs ? `?${qs}` : ""}`));
|
|
217
|
+
if (flags.json) {
|
|
51
218
|
console.log(JSON.stringify(data, null, 2));
|
|
52
219
|
return;
|
|
53
220
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
221
|
+
if (!data.assets?.length) {
|
|
222
|
+
console.log("No assets found.");
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
console.log(`${data.total} asset${data.total === 1 ? "" : "s"} found:\n`);
|
|
226
|
+
for (const a of data.assets) {
|
|
227
|
+
console.log(formatAssetRow(a));
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
async function cmdList(_args, flags) {
|
|
231
|
+
return cmdSearch([], flags);
|
|
232
|
+
}
|
|
233
|
+
async function cmdGet(args, flags) {
|
|
234
|
+
const id = args[0];
|
|
235
|
+
if (!id) {
|
|
236
|
+
console.error("Usage: argus-media-cli get <asset-id>");
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
const config = await loadConfig();
|
|
240
|
+
const data = (await apiRequest(config, "GET", `/assets/${id}`));
|
|
241
|
+
if (flags.json) {
|
|
61
242
|
console.log(JSON.stringify(data, null, 2));
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
console.log(formatAssetDetail(data.asset));
|
|
62
246
|
}
|
|
63
|
-
function
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
console.log(`
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
console.error("Usage: argus login <api-key>");
|
|
89
|
-
process.exit(1);
|
|
90
|
-
}
|
|
91
|
-
saveConfig({ ...loadConfig(), apiKey: key });
|
|
92
|
-
console.log("API key saved to ~/.argus/config.json");
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
95
|
-
case "upload": {
|
|
96
|
-
const file = rest[0];
|
|
97
|
-
const project = rest[1];
|
|
98
|
-
if (!file || !existsSync(file)) {
|
|
99
|
-
console.error("Usage: argus upload <file> [project]");
|
|
100
|
-
process.exit(1);
|
|
101
|
-
}
|
|
102
|
-
const { createReadStream, statSync } = await import("fs");
|
|
103
|
-
const { basename } = await import("path");
|
|
104
|
-
const fd = new FormData();
|
|
105
|
-
const bytes = readFileSync(file);
|
|
106
|
-
fd.append("file", new Blob([bytes]), basename(file));
|
|
107
|
-
if (project)
|
|
108
|
-
fd.append("project", project);
|
|
109
|
-
const res = await fetch(`${BASE_URL}/assets/upload`, {
|
|
110
|
-
method: "POST",
|
|
111
|
-
headers: { Authorization: `Bearer ${getApiKey()}` },
|
|
112
|
-
body: fd,
|
|
113
|
-
});
|
|
114
|
-
const data = await res.json().catch(() => ({}));
|
|
115
|
-
if (!res.ok) {
|
|
116
|
-
console.error(`Error: ${data.error || res.statusText}`);
|
|
117
|
-
process.exit(1);
|
|
118
|
-
}
|
|
119
|
-
output(data, jsonFlag);
|
|
120
|
-
break;
|
|
247
|
+
async function cmdUsage(_args, flags) {
|
|
248
|
+
const config = await loadConfig();
|
|
249
|
+
const data = (await apiRequest(config, "GET", "/usage"));
|
|
250
|
+
if (flags.json) {
|
|
251
|
+
console.log(JSON.stringify(data, null, 2));
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
console.log(`\x1b[1mWorkspace Usage\x1b[0m`);
|
|
255
|
+
console.log(` Tier: ${data.tier}`);
|
|
256
|
+
console.log(` Assets: ${data.assets?.used ?? 0} / ${data.assets?.limit ?? "unlimited"}`);
|
|
257
|
+
if (data.credits != null) {
|
|
258
|
+
console.log(` Credits: ${data.credits?.used ?? 0} / ${data.credits?.limit ?? "unlimited"}`);
|
|
259
|
+
}
|
|
260
|
+
if (data.storage != null) {
|
|
261
|
+
console.log(` Storage: ${data.storage?.used != null ? formatBytes(data.storage.used) : "0 B"} / ${data.storage?.limit != null ? formatBytes(data.storage.limit) : "unlimited"}`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
function parseArgs(argv) {
|
|
265
|
+
const command = argv[0] || "help";
|
|
266
|
+
const flags = {};
|
|
267
|
+
const args = [];
|
|
268
|
+
for (let i = 1; i < argv.length; i++) {
|
|
269
|
+
const arg = argv[i];
|
|
270
|
+
if (arg === "--json") {
|
|
271
|
+
flags.json = true;
|
|
121
272
|
}
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
273
|
+
else if (arg.startsWith("--")) {
|
|
274
|
+
const key = arg.slice(2);
|
|
275
|
+
const next = argv[i + 1];
|
|
276
|
+
if (next && !next.startsWith("--")) {
|
|
277
|
+
flags[key] = next;
|
|
278
|
+
i++;
|
|
127
279
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
break;
|
|
131
|
-
}
|
|
132
|
-
case "list": {
|
|
133
|
-
const project = rest[0];
|
|
134
|
-
const qs = project ? `?project=${encodeURIComponent(project)}` : "";
|
|
135
|
-
const data = await api("GET", `/assets${qs}`);
|
|
136
|
-
output(data, jsonFlag);
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
case "get": {
|
|
140
|
-
const id = rest[0];
|
|
141
|
-
if (!id) {
|
|
142
|
-
console.error("Usage: argus get <id>");
|
|
143
|
-
process.exit(1);
|
|
280
|
+
else {
|
|
281
|
+
flags[key] = true;
|
|
144
282
|
}
|
|
145
|
-
const data = await api("GET", `/assets/${id}`);
|
|
146
|
-
output(data, jsonFlag);
|
|
147
|
-
break;
|
|
148
283
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
output(data, jsonFlag);
|
|
152
|
-
break;
|
|
284
|
+
else {
|
|
285
|
+
args.push(arg);
|
|
153
286
|
}
|
|
154
|
-
|
|
155
|
-
|
|
287
|
+
}
|
|
288
|
+
return { command, args, flags };
|
|
289
|
+
}
|
|
290
|
+
function printHelp() {
|
|
291
|
+
console.log(`\x1b[1margus-media-cli\x1b[0m — AI-native media asset management
|
|
292
|
+
|
|
293
|
+
\x1b[1mUsage:\x1b[0m
|
|
294
|
+
argus-media-cli <command> [options]
|
|
295
|
+
|
|
296
|
+
\x1b[1mCommands:\x1b[0m
|
|
297
|
+
login Authenticate with Argus
|
|
298
|
+
upload <file> Upload a media file
|
|
299
|
+
search <query> Search assets by description, tags, mood
|
|
300
|
+
list List all assets
|
|
301
|
+
get <id> Get asset details and analysis
|
|
302
|
+
usage Show workspace usage and limits
|
|
303
|
+
|
|
304
|
+
\x1b[1mGlobal Options:\x1b[0m
|
|
305
|
+
--json Output raw JSON
|
|
156
306
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
search <query> Search assets by keyword
|
|
161
|
-
list [project] List assets
|
|
162
|
-
get <id> Get asset by ID
|
|
163
|
-
usage Show credit and asset usage
|
|
307
|
+
\x1b[1mUpload Options:\x1b[0m
|
|
308
|
+
--project NAME Assign to a project
|
|
309
|
+
--tags a,b,c Comma-separated tags
|
|
164
310
|
|
|
165
|
-
Options
|
|
166
|
-
--
|
|
311
|
+
\x1b[1mSearch/List Options:\x1b[0m
|
|
312
|
+
--project NAME Filter by project
|
|
313
|
+
--status STATUS Filter by status (pending, ready, error)
|
|
314
|
+
--tags a,b,c Filter by tags
|
|
315
|
+
--limit N Max results (default 50)
|
|
316
|
+
--offset N Pagination offset
|
|
167
317
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
318
|
+
\x1b[1mLogin Options:\x1b[0m
|
|
319
|
+
--key KEY Set API key non-interactively
|
|
320
|
+
--url URL Set custom API base URL
|
|
171
321
|
|
|
172
|
-
|
|
322
|
+
\x1b[1mEnvironment:\x1b[0m
|
|
323
|
+
ARGUS_API_KEY API key (overrides saved config)
|
|
324
|
+
ARGUS_BASE_URL API base URL (default: https://argus.build)
|
|
325
|
+
|
|
326
|
+
\x1b[1mExamples:\x1b[0m
|
|
327
|
+
argus-media-cli login
|
|
328
|
+
argus-media-cli upload photo.jpg --project campaign-q2 --tags hero,banner
|
|
329
|
+
argus-media-cli search "sunset landscape" --json
|
|
330
|
+
argus-media-cli list --project website --limit 20
|
|
331
|
+
argus-media-cli get abc12345-def6-7890-abcd-ef1234567890
|
|
173
332
|
`);
|
|
174
|
-
|
|
333
|
+
}
|
|
334
|
+
// ─── Main ──────────────────────────────────────────────────────────────────
|
|
335
|
+
const COMMANDS = {
|
|
336
|
+
login: cmdLogin,
|
|
337
|
+
upload: cmdUpload,
|
|
338
|
+
search: cmdSearch,
|
|
339
|
+
list: cmdList,
|
|
340
|
+
get: cmdGet,
|
|
341
|
+
usage: cmdUsage,
|
|
342
|
+
};
|
|
343
|
+
async function main() {
|
|
344
|
+
const { command, args, flags } = parseArgs(process.argv.slice(2));
|
|
345
|
+
if (command === "help" || command === "--help" || command === "-h") {
|
|
346
|
+
printHelp();
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (command === "version" || command === "--version" || command === "-v") {
|
|
350
|
+
console.log("argus-media-cli 0.1.2");
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const handler = COMMANDS[command];
|
|
354
|
+
if (!handler) {
|
|
355
|
+
console.error(`Unknown command: ${command}`);
|
|
356
|
+
console.error('Run "argus-media-cli help" for usage.');
|
|
357
|
+
process.exit(1);
|
|
358
|
+
}
|
|
359
|
+
try {
|
|
360
|
+
await handler(args, flags);
|
|
361
|
+
}
|
|
362
|
+
catch (err) {
|
|
363
|
+
console.error(`Error: ${err.message}`);
|
|
364
|
+
process.exit(1);
|
|
175
365
|
}
|
|
176
366
|
}
|
|
177
|
-
main()
|
|
178
|
-
console.error(err.message || err);
|
|
179
|
-
process.exit(1);
|
|
180
|
-
});
|
|
367
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,17 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "argus-media-cli",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "CLI for Argus — AI-
|
|
5
|
-
"keywords": [
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "CLI for Argus — AI-native media asset management. Upload, search, analyze, and manage media assets from the terminal.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"argus",
|
|
7
|
+
"media",
|
|
8
|
+
"assets",
|
|
9
|
+
"ai",
|
|
10
|
+
"cli",
|
|
11
|
+
"upload",
|
|
12
|
+
"image",
|
|
13
|
+
"video"
|
|
14
|
+
],
|
|
6
15
|
"license": "MIT",
|
|
7
16
|
"author": "Brookfield Digital",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/brookfield-digital/argus"
|
|
20
|
+
},
|
|
8
21
|
"homepage": "https://argus.build",
|
|
9
22
|
"type": "module",
|
|
10
23
|
"bin": {
|
|
11
|
-
"argus": "./dist/index.js"
|
|
24
|
+
"argus-media-cli": "./dist/index.js"
|
|
12
25
|
},
|
|
13
26
|
"main": "./dist/index.js",
|
|
14
|
-
"files": [
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md"
|
|
30
|
+
],
|
|
15
31
|
"scripts": {
|
|
16
32
|
"build": "tsc",
|
|
17
33
|
"prepublishOnly": "npm run build"
|
|
@@ -20,5 +36,7 @@
|
|
|
20
36
|
"@types/node": "^20.0.0",
|
|
21
37
|
"typescript": "^5.4.0"
|
|
22
38
|
},
|
|
23
|
-
"engines": {
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=18"
|
|
41
|
+
}
|
|
24
42
|
}
|