@vigilhq/cli 0.1.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 ADDED
@@ -0,0 +1,62 @@
1
+ # @vigilhq/cli
2
+
3
+ Command-line interface for [Vigil](https://vigilhq.dev) — screen entities against global sanctions and PEP lists from your terminal.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @vigilhq/cli
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ ```bash
14
+ export VIGIL_API_KEY=vgl_sk_live_...
15
+ ```
16
+
17
+ Or pass `--api-key` to any command.
18
+
19
+ ## Usage
20
+
21
+ ### Screen an entity
22
+
23
+ ```bash
24
+ vigil check "John Doe"
25
+ vigil check "Acme Corp" --type organization
26
+ vigil check "Jane Smith" --context transaction --dob 1990-01-15 --nationality CA
27
+ vigil check "Entity" --json # raw JSON output
28
+ ```
29
+
30
+ ### List watchlist sources
31
+
32
+ ```bash
33
+ vigil lists
34
+ ```
35
+
36
+ ### Continuous monitoring
37
+
38
+ ```bash
39
+ vigil monitor add "Acme Corp" --type organization
40
+ vigil monitor list
41
+ vigil monitor remove mon_abc123
42
+ ```
43
+
44
+ ### API key management
45
+
46
+ ```bash
47
+ vigil keys list
48
+ vigil keys create "production"
49
+ vigil keys revoke key_abc123
50
+ ```
51
+
52
+ ## Options
53
+
54
+ All commands support:
55
+
56
+ - `--api-key <key>` — API key (default: `VIGIL_API_KEY` env var)
57
+ - `--base-url <url>` — API base URL (default: `https://api.vigilhq.dev`)
58
+ - `--json` — Output raw JSON (where applicable)
59
+
60
+ ## License
61
+
62
+ MIT
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Vigil CLI — Screen entities against global sanctions and PEP lists.
4
+ *
5
+ * Usage:
6
+ * vigil check "John Doe"
7
+ * vigil check "Osama bin Laden" --context transaction
8
+ * vigil lists
9
+ * VIGIL_API_KEY=vgl_sk_live_... vigil check "entity"
10
+ */
11
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,377 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Vigil CLI — Screen entities against global sanctions and PEP lists.
4
+ *
5
+ * Usage:
6
+ * vigil check "John Doe"
7
+ * vigil check "Osama bin Laden" --context transaction
8
+ * vigil lists
9
+ * VIGIL_API_KEY=vgl_sk_live_... vigil check "entity"
10
+ */
11
+ import { Command } from "commander";
12
+ import chalk from "chalk";
13
+ const program = new Command();
14
+ program
15
+ .name("vigil")
16
+ .description("Vigil CLI — Compliance screening from the command line")
17
+ .version("0.1.0");
18
+ // ── Check Command ──────────────────────────────────────
19
+ program
20
+ .command("check <entity>")
21
+ .description("Screen an entity against sanctions and PEP lists")
22
+ .option("-c, --context <context>", "Check context (onboarding|transaction|monitoring)", "onboarding")
23
+ .option("-t, --type <type>", "Entity type (individual|organization|vessel|aircraft)")
24
+ .option("--dob <date>", "Date of birth (YYYY-MM-DD)")
25
+ .option("--nationality <code>", "ISO country code (e.g., US, GB)")
26
+ .option("--id <number>", "Government ID or passport number")
27
+ .option("--api-key <key>", "API key (or set VIGIL_API_KEY env var)")
28
+ .option("--base-url <url>", "API base URL", "https://api.vigilhq.dev")
29
+ .option("--json", "Output raw JSON")
30
+ .action(async (entity, opts) => {
31
+ const apiKey = opts.apiKey || process.env.VIGIL_API_KEY;
32
+ if (!apiKey) {
33
+ console.error(chalk.red("Error: API key required. Set VIGIL_API_KEY or use --api-key"));
34
+ process.exit(1);
35
+ }
36
+ try {
37
+ const body = { entity, context: opts.context };
38
+ if (opts.type)
39
+ body.entity_type = opts.type;
40
+ if (opts.dob)
41
+ body.date_of_birth = opts.dob;
42
+ if (opts.nationality)
43
+ body.nationality = opts.nationality;
44
+ if (opts.id)
45
+ body.id_number = opts.id;
46
+ const resp = await fetch(`${opts.baseUrl}/v1/screen`, {
47
+ method: "POST",
48
+ headers: {
49
+ "Content-Type": "application/json",
50
+ Authorization: `Bearer ${apiKey}`,
51
+ },
52
+ body: JSON.stringify(body),
53
+ });
54
+ if (!resp.ok) {
55
+ const err = await resp.json().catch(() => ({ error: { message: resp.statusText } }));
56
+ console.error(chalk.red(`Error (${resp.status}): ${err.error?.message || resp.statusText}`));
57
+ process.exit(1);
58
+ }
59
+ const result = await resp.json();
60
+ if (opts.json) {
61
+ console.log(JSON.stringify(result, null, 2));
62
+ return;
63
+ }
64
+ // Pretty output
65
+ console.log();
66
+ console.log(chalk.bold(` Entity: ${entity}`));
67
+ // Sanctions status
68
+ if (result.sanctions?.match) {
69
+ const match = result.matches?.[0];
70
+ const source = match?.source ?? "UNKNOWN";
71
+ const programs = match?.programs?.join(", ") ?? "";
72
+ console.log(chalk.red(` Sanctions: ⛔ MATCH — ${source} (${programs})`));
73
+ }
74
+ else {
75
+ console.log(chalk.green(` Sanctions: ✅ CLEAR (${result.sanctions?.lists_checked ?? 0} lists checked)`));
76
+ }
77
+ // PEP status
78
+ if (result.pep?.match) {
79
+ console.log(chalk.yellow(` PEP: ⚠️ MATCH`));
80
+ }
81
+ else {
82
+ console.log(chalk.green(` PEP: ✅ CLEAR`));
83
+ }
84
+ // Risk score
85
+ const score = result.risk_score ?? 0;
86
+ const level = (result.risk_level ?? "unknown").toUpperCase();
87
+ const scoreColor = score >= 80 ? chalk.red :
88
+ score >= 50 ? chalk.yellow :
89
+ chalk.green;
90
+ console.log(scoreColor(` Risk: ${score}/100 (${level})`));
91
+ // Recommendation
92
+ const rec = (result.recommendation ?? "unknown").toUpperCase();
93
+ const recColor = rec === "BLOCK" ? chalk.red.bold :
94
+ rec === "REVIEW" ? chalk.yellow.bold :
95
+ chalk.green.bold;
96
+ console.log(recColor(` Action: ${rec}`));
97
+ // Timing
98
+ console.log(chalk.dim(` Time: ${result.screening_time_ms ?? 0}ms`));
99
+ console.log(chalk.dim(` Audit: ${result.id}`));
100
+ // Show matches if any
101
+ if (result.matches?.length > 0) {
102
+ console.log();
103
+ console.log(chalk.bold(" Matches:"));
104
+ for (const match of result.matches) {
105
+ console.log(chalk.dim(` • ${match.matched_name} [${match.source}] — confidence: ${match.score}`));
106
+ if (match.aliases?.length > 0) {
107
+ console.log(chalk.dim(` Aliases: ${match.aliases.join(", ")}`));
108
+ }
109
+ if (match.programs?.length > 0) {
110
+ console.log(chalk.dim(` Programs: ${match.programs.join(", ")}`));
111
+ }
112
+ }
113
+ }
114
+ console.log();
115
+ }
116
+ catch (err) {
117
+ console.error(chalk.red(`Error: ${err instanceof Error ? err.message : err}`));
118
+ process.exit(1);
119
+ }
120
+ });
121
+ // ── Lists Command ──────────────────────────────────────
122
+ program
123
+ .command("lists")
124
+ .description("Show active watchlist sources and their status")
125
+ .option("--api-key <key>", "API key (or set VIGIL_API_KEY env var)")
126
+ .option("--base-url <url>", "API base URL", "https://api.vigilhq.dev")
127
+ .action(async (opts) => {
128
+ const apiKey = opts.apiKey || process.env.VIGIL_API_KEY;
129
+ if (!apiKey) {
130
+ console.error(chalk.red("Error: API key required."));
131
+ process.exit(1);
132
+ }
133
+ try {
134
+ const resp = await fetch(`${opts.baseUrl}/v1/lists`, {
135
+ headers: { Authorization: `Bearer ${apiKey}` },
136
+ });
137
+ const data = await resp.json();
138
+ const sources = Array.isArray(data) ? data : data.sources ?? [];
139
+ console.log();
140
+ console.log(chalk.bold(" Active Watchlist Sources:"));
141
+ console.log();
142
+ for (const s of sources) {
143
+ const status = s.is_active ? chalk.green("●") : chalk.red("○");
144
+ console.log(` ${status} ${chalk.bold(s.code)} — ${s.name}`);
145
+ console.log(chalk.dim(` Entities: ${s.entity_count ?? 0} | Last updated: ${s.last_ingested_at ?? "never"}`));
146
+ }
147
+ console.log();
148
+ }
149
+ catch (err) {
150
+ console.error(chalk.red(`Error: ${err instanceof Error ? err.message : err}`));
151
+ process.exit(1);
152
+ }
153
+ });
154
+ // ── Monitor Command ────────────────────────────────────
155
+ const monitor = program
156
+ .command("monitor")
157
+ .description("Manage continuous monitoring of entities");
158
+ monitor
159
+ .command("add <entity>")
160
+ .description("Add an entity to continuous monitoring")
161
+ .option("-t, --type <type>", "Entity type (individual|organization|vessel|aircraft)")
162
+ .option("--api-key <key>", "API key (or set VIGIL_API_KEY env var)")
163
+ .option("--base-url <url>", "API base URL", "https://api.vigilhq.dev")
164
+ .option("--json", "Output raw JSON")
165
+ .action(async (entity, opts) => {
166
+ const apiKey = opts.apiKey || process.env.VIGIL_API_KEY;
167
+ if (!apiKey) {
168
+ console.error(chalk.red("Error: API key required. Set VIGIL_API_KEY or use --api-key"));
169
+ process.exit(1);
170
+ }
171
+ try {
172
+ const body = { entity };
173
+ if (opts.type)
174
+ body.entity_type = opts.type;
175
+ const resp = await fetch(`${opts.baseUrl}/v1/monitor/entities`, {
176
+ method: "POST",
177
+ headers: {
178
+ "Content-Type": "application/json",
179
+ Authorization: `Bearer ${apiKey}`,
180
+ },
181
+ body: JSON.stringify(body),
182
+ });
183
+ if (!resp.ok) {
184
+ const err = await resp.json().catch(() => ({ error: { message: resp.statusText } }));
185
+ console.error(chalk.red(`Error (${resp.status}): ${err.error?.message || resp.statusText}`));
186
+ process.exit(1);
187
+ }
188
+ const result = await resp.json();
189
+ if (opts.json) {
190
+ console.log(JSON.stringify(result, null, 2));
191
+ return;
192
+ }
193
+ console.log();
194
+ console.log(chalk.green(` ✅ Added "${entity}" to continuous monitoring`));
195
+ console.log(chalk.dim(` ID: ${result.id}`));
196
+ console.log();
197
+ }
198
+ catch (err) {
199
+ console.error(chalk.red(`Error: ${err instanceof Error ? err.message : err}`));
200
+ process.exit(1);
201
+ }
202
+ });
203
+ monitor
204
+ .command("list")
205
+ .description("List all monitored entities")
206
+ .option("--api-key <key>", "API key (or set VIGIL_API_KEY env var)")
207
+ .option("--base-url <url>", "API base URL", "https://api.vigilhq.dev")
208
+ .option("--json", "Output raw JSON")
209
+ .action(async (opts) => {
210
+ const apiKey = opts.apiKey || process.env.VIGIL_API_KEY;
211
+ if (!apiKey) {
212
+ console.error(chalk.red("Error: API key required."));
213
+ process.exit(1);
214
+ }
215
+ try {
216
+ const resp = await fetch(`${opts.baseUrl}/v1/monitor/entities`, {
217
+ headers: { Authorization: `Bearer ${apiKey}` },
218
+ });
219
+ const data = await resp.json();
220
+ if (opts.json) {
221
+ console.log(JSON.stringify(data, null, 2));
222
+ return;
223
+ }
224
+ const entities = Array.isArray(data) ? data : data.data ?? [];
225
+ console.log();
226
+ console.log(chalk.bold(` Monitored Entities (${entities.length}):`));
227
+ console.log();
228
+ for (const e of entities) {
229
+ const status = e.last_result?.status === "match" ? chalk.red("⛔") : chalk.green("✅");
230
+ console.log(` ${status} ${chalk.bold(e.entity)} ${chalk.dim(`[${e.id}]`)}`);
231
+ if (e.last_checked_at) {
232
+ console.log(chalk.dim(` Last checked: ${e.last_checked_at}`));
233
+ }
234
+ }
235
+ console.log();
236
+ }
237
+ catch (err) {
238
+ console.error(chalk.red(`Error: ${err instanceof Error ? err.message : err}`));
239
+ process.exit(1);
240
+ }
241
+ });
242
+ monitor
243
+ .command("remove <id>")
244
+ .description("Remove an entity from monitoring by ID")
245
+ .option("--api-key <key>", "API key (or set VIGIL_API_KEY env var)")
246
+ .option("--base-url <url>", "API base URL", "https://api.vigilhq.dev")
247
+ .action(async (id, opts) => {
248
+ const apiKey = opts.apiKey || process.env.VIGIL_API_KEY;
249
+ if (!apiKey) {
250
+ console.error(chalk.red("Error: API key required."));
251
+ process.exit(1);
252
+ }
253
+ try {
254
+ const resp = await fetch(`${opts.baseUrl}/v1/monitor/entities/${id}`, {
255
+ method: "DELETE",
256
+ headers: { Authorization: `Bearer ${apiKey}` },
257
+ });
258
+ if (!resp.ok) {
259
+ const err = await resp.json().catch(() => ({ error: { message: resp.statusText } }));
260
+ console.error(chalk.red(`Error (${resp.status}): ${err.error?.message || resp.statusText}`));
261
+ process.exit(1);
262
+ }
263
+ console.log(chalk.green(` ✅ Removed monitored entity ${id}`));
264
+ }
265
+ catch (err) {
266
+ console.error(chalk.red(`Error: ${err instanceof Error ? err.message : err}`));
267
+ process.exit(1);
268
+ }
269
+ });
270
+ // ── Keys Command ───────────────────────────────────────
271
+ const keys = program
272
+ .command("keys")
273
+ .description("Manage API keys");
274
+ keys
275
+ .command("list")
276
+ .description("List all API keys")
277
+ .option("--api-key <key>", "API key (or set VIGIL_API_KEY env var)")
278
+ .option("--base-url <url>", "API base URL", "https://api.vigilhq.dev")
279
+ .option("--json", "Output raw JSON")
280
+ .action(async (opts) => {
281
+ const apiKey = opts.apiKey || process.env.VIGIL_API_KEY;
282
+ if (!apiKey) {
283
+ console.error(chalk.red("Error: API key required."));
284
+ process.exit(1);
285
+ }
286
+ try {
287
+ const resp = await fetch(`${opts.baseUrl}/v1/keys`, {
288
+ headers: { Authorization: `Bearer ${apiKey}` },
289
+ });
290
+ const data = await resp.json();
291
+ if (opts.json) {
292
+ console.log(JSON.stringify(data, null, 2));
293
+ return;
294
+ }
295
+ const keyList = Array.isArray(data) ? data : data.data ?? [];
296
+ console.log();
297
+ console.log(chalk.bold(` API Keys (${keyList.length}):`));
298
+ console.log();
299
+ for (const k of keyList) {
300
+ const status = k.revoked_at ? chalk.red("revoked") : chalk.green("active");
301
+ console.log(` ${chalk.bold(k.name)} ${chalk.dim(k.key_prefix + "...")} [${status}]`);
302
+ console.log(chalk.dim(` Created: ${k.created_at} | Last used: ${k.last_used_at ?? "never"}`));
303
+ }
304
+ console.log();
305
+ }
306
+ catch (err) {
307
+ console.error(chalk.red(`Error: ${err instanceof Error ? err.message : err}`));
308
+ process.exit(1);
309
+ }
310
+ });
311
+ keys
312
+ .command("create <name>")
313
+ .description("Create a new API key")
314
+ .option("-e, --environment <env>", "Environment (live|test)", "live")
315
+ .option("--api-key <key>", "API key (or set VIGIL_API_KEY env var)")
316
+ .option("--base-url <url>", "API base URL", "https://api.vigilhq.dev")
317
+ .action(async (name, opts) => {
318
+ const apiKey = opts.apiKey || process.env.VIGIL_API_KEY;
319
+ if (!apiKey) {
320
+ console.error(chalk.red("Error: API key required."));
321
+ process.exit(1);
322
+ }
323
+ try {
324
+ const resp = await fetch(`${opts.baseUrl}/v1/keys`, {
325
+ method: "POST",
326
+ headers: {
327
+ "Content-Type": "application/json",
328
+ Authorization: `Bearer ${apiKey}`,
329
+ },
330
+ body: JSON.stringify({ name, environment: opts.environment }),
331
+ });
332
+ if (!resp.ok) {
333
+ const err = await resp.json().catch(() => ({ error: { message: resp.statusText } }));
334
+ console.error(chalk.red(`Error (${resp.status}): ${err.error?.message || resp.statusText}`));
335
+ process.exit(1);
336
+ }
337
+ const result = await resp.json();
338
+ console.log();
339
+ console.log(chalk.green(` ✅ API key created: ${chalk.bold(name)}`));
340
+ console.log(chalk.yellow(` Key: ${result.key}`));
341
+ console.log(chalk.dim(" ⚠️ Save this key — it won't be shown again."));
342
+ console.log();
343
+ }
344
+ catch (err) {
345
+ console.error(chalk.red(`Error: ${err instanceof Error ? err.message : err}`));
346
+ process.exit(1);
347
+ }
348
+ });
349
+ keys
350
+ .command("revoke <id>")
351
+ .description("Revoke an API key by ID")
352
+ .option("--api-key <key>", "API key (or set VIGIL_API_KEY env var)")
353
+ .option("--base-url <url>", "API base URL", "https://api.vigilhq.dev")
354
+ .action(async (id, opts) => {
355
+ const apiKey = opts.apiKey || process.env.VIGIL_API_KEY;
356
+ if (!apiKey) {
357
+ console.error(chalk.red("Error: API key required."));
358
+ process.exit(1);
359
+ }
360
+ try {
361
+ const resp = await fetch(`${opts.baseUrl}/v1/keys/${id}`, {
362
+ method: "DELETE",
363
+ headers: { Authorization: `Bearer ${apiKey}` },
364
+ });
365
+ if (!resp.ok) {
366
+ const err = await resp.json().catch(() => ({ error: { message: resp.statusText } }));
367
+ console.error(chalk.red(`Error (${resp.status}): ${err.error?.message || resp.statusText}`));
368
+ process.exit(1);
369
+ }
370
+ console.log(chalk.green(` ✅ API key ${id} revoked`));
371
+ }
372
+ catch (err) {
373
+ console.error(chalk.red(`Error: ${err instanceof Error ? err.message : err}`));
374
+ process.exit(1);
375
+ }
376
+ });
377
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@vigilhq/cli",
3
+ "version": "0.1.0",
4
+ "description": "Vigil CLI — Screen entities against global sanctions and PEP lists from the command line",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "bin": {
8
+ "vigil": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "dev": "tsx src/index.ts",
12
+ "build": "tsc",
13
+ "typecheck": "tsc --noEmit"
14
+ },
15
+ "dependencies": {
16
+ "@vigilhq/sdk": "workspace:^",
17
+ "chalk": "^5.3.0",
18
+ "commander": "^12.0.0",
19
+ "ora": "^8.0.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^22.10.0",
23
+ "tsx": "^4.19.0",
24
+ "typescript": "^5.7.0"
25
+ },
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/ymatagne/vigil",
35
+ "directory": "packages/cli"
36
+ },
37
+ "keywords": [
38
+ "vigil",
39
+ "sanctions",
40
+ "screening",
41
+ "compliance",
42
+ "cli"
43
+ ]
44
+ }