faces-cli 1.5.9 → 1.5.10

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.
@@ -18,12 +18,8 @@ export default class AuthWhoami extends BaseCommand {
18
18
  api_key_configured: Boolean(apiKey),
19
19
  api_key_prefix: apiKey ? apiKey.slice(0, 12) + '...' : null,
20
20
  };
21
- // Try API key first (priority), then JWT
22
- const credential = apiKey || token;
23
- const method = apiKey ? 'api_key' : token ? 'jwt' : null;
24
- if (!credential) {
21
+ if (!apiKey && !token) {
25
22
  diag.authenticated = false;
26
- diag.auth_method = null;
27
23
  diag.error = 'No credentials configured (no API key, no JWT)';
28
24
  if (!json) {
29
25
  process.stderr.write('Auth diagnostic:\n');
@@ -34,57 +30,71 @@ export default class AuthWhoami extends BaseCommand {
34
30
  }
35
31
  return diag;
36
32
  }
37
- const client = new FacesClient(baseUrl, token, apiKey);
38
- try {
39
- const data = await client.get('/auth/me');
40
- const inner = (data.data ?? data);
41
- diag.authenticated = true;
42
- diag.auth_method = method;
43
- diag.user_id = inner.user_id;
44
- diag.username = inner.username;
45
- diag.email = inner.email;
46
- diag.name = inner.name;
47
- diag.is_admin = inner.is_admin;
48
- if (!json) {
49
- process.stderr.write('Auth diagnostic:\n');
50
- process.stderr.write(` base_url: ${baseUrl}\n`);
51
- process.stderr.write(` jwt: ${token ? 'configured' : 'not configured'}\n`);
52
- process.stderr.write(` api_key: ${apiKey ? diag.api_key_prefix : 'not configured'}\n`);
53
- process.stderr.write(` auth_method: ${method}\n`);
54
- process.stderr.write(` status: authenticated\n`);
55
- process.stderr.write('\n');
56
- process.stderr.write(` user_id: ${inner.user_id}\n`);
57
- process.stderr.write(` username: ${inner.username}\n`);
58
- process.stderr.write(` email: ${inner.email}\n`);
59
- process.stderr.write(` name: ${inner.name}\n`);
33
+ // Try API key first (priority), then JWT. Always try both and report.
34
+ let apiKeyResult = null;
35
+ let jwtResult = null;
36
+ if (apiKey) {
37
+ const client = new FacesClient(baseUrl, undefined, apiKey);
38
+ try {
39
+ const data = await client.get('/auth/me');
40
+ apiKeyResult = { ok: true, data: (data.data ?? data) };
60
41
  }
61
- return diag;
62
- }
63
- catch (err) {
64
- const errMsg = err instanceof FacesAPIError ? `${err.statusCode}: ${err.message}` : String(err);
65
- diag.authenticated = false;
66
- diag.auth_method = method;
67
- diag.error = errMsg;
68
- // If API key failed, also report JWT state
69
- if (method === 'api_key' && token) {
70
- diag.jwt_status = 'configured but not tried (API key takes priority)';
42
+ catch (err) {
43
+ const msg = err instanceof FacesAPIError ? `${err.statusCode}: ${err.message}` : String(err);
44
+ apiKeyResult = { ok: false, error: msg };
71
45
  }
72
- if (method === 'jwt') {
73
- diag.jwt_status = 'failed';
74
- if (apiKey) {
75
- diag.api_key_status = 'configured but not valid for this endpoint';
46
+ }
47
+ if (token) {
48
+ // Only try JWT if API key failed or wasn't configured
49
+ if (!apiKeyResult?.ok) {
50
+ const client = new FacesClient(baseUrl, token, undefined);
51
+ try {
52
+ const data = await client.get('/auth/me');
53
+ jwtResult = { ok: true, data: (data.data ?? data) };
54
+ }
55
+ catch (err) {
56
+ const msg = err instanceof FacesAPIError ? `${err.statusCode}: ${err.message}` : String(err);
57
+ jwtResult = { ok: false, error: msg };
76
58
  }
77
59
  }
78
- if (!json) {
79
- process.stderr.write('Auth diagnostic:\n');
80
- process.stderr.write(` base_url: ${baseUrl}\n`);
81
- process.stderr.write(` jwt: ${token ? 'configured' : 'not configured'}\n`);
82
- process.stderr.write(` api_key: ${apiKey ? diag.api_key_prefix : 'not configured'}\n`);
83
- process.stderr.write(` auth_method: ${method}\n`);
84
- process.stderr.write(` status: failed\n`);
85
- process.stderr.write(` error: ${errMsg}\n`);
60
+ else {
61
+ jwtResult = { ok: false, error: 'not tried (API key succeeded)' };
62
+ }
63
+ }
64
+ // Determine the winning result
65
+ const winner = apiKeyResult?.ok ? apiKeyResult : jwtResult?.ok ? jwtResult : null;
66
+ const winnerMethod = apiKeyResult?.ok ? 'api_key' : jwtResult?.ok ? 'jwt' : null;
67
+ diag.authenticated = Boolean(winner);
68
+ diag.auth_method = winnerMethod;
69
+ if (apiKeyResult)
70
+ diag.api_key_status = apiKeyResult.ok ? 'valid' : apiKeyResult.error;
71
+ if (jwtResult)
72
+ diag.jwt_status = jwtResult.ok ? 'valid' : jwtResult.error;
73
+ if (winner?.data) {
74
+ diag.user_id = winner.data.user_id;
75
+ diag.username = winner.data.username;
76
+ diag.email = winner.data.email;
77
+ diag.name = winner.data.name;
78
+ diag.is_admin = winner.data.is_admin;
79
+ }
80
+ else {
81
+ diag.error = 'All credentials failed';
82
+ }
83
+ if (!json) {
84
+ process.stderr.write('Auth diagnostic:\n');
85
+ process.stderr.write(` base_url: ${baseUrl}\n`);
86
+ process.stderr.write(` jwt: ${token ? (jwtResult?.ok ? 'valid' : `failed (${jwtResult?.error})`) : 'not configured'}\n`);
87
+ process.stderr.write(` api_key: ${apiKey ? (apiKeyResult?.ok ? `valid (${diag.api_key_prefix})` : `failed (${apiKeyResult?.error})`) : 'not configured'}\n`);
88
+ process.stderr.write(` auth_method: ${winnerMethod ?? 'none'}\n`);
89
+ process.stderr.write(` status: ${winner ? 'authenticated' : 'failed'}\n`);
90
+ if (winner?.data) {
91
+ process.stderr.write('\n');
92
+ process.stderr.write(` user_id: ${winner.data.user_id}\n`);
93
+ process.stderr.write(` username: ${winner.data.username}\n`);
94
+ process.stderr.write(` email: ${winner.data.email}\n`);
95
+ process.stderr.write(` name: ${winner.data.name}\n`);
86
96
  }
87
- return diag;
88
97
  }
98
+ return diag;
89
99
  }
90
100
  }
package/dist/config.js CHANGED
@@ -50,16 +50,20 @@ export function resolveBaseUrl(override) {
50
50
  return 'https://api.faces.sh';
51
51
  }
52
52
  export function resolveToken(override) {
53
- if (override)
54
- return override;
55
- if (process.env.FACES_TOKEN)
56
- return process.env.FACES_TOKEN;
57
- return loadConfig().token;
53
+ // Empty string override means "no token" — don't fall back to config/env
54
+ if (override !== undefined)
55
+ return override || undefined;
56
+ const env = process.env.FACES_TOKEN;
57
+ if (env)
58
+ return env;
59
+ return loadConfig().token || undefined;
58
60
  }
59
61
  export function resolveApiKey(override) {
60
- if (override)
61
- return override;
62
- if (process.env.FACES_API_KEY)
63
- return process.env.FACES_API_KEY;
64
- return loadConfig().api_key;
62
+ // Empty string override means "no API key" — don't fall back to config/env
63
+ if (override !== undefined)
64
+ return override || undefined;
65
+ const env = process.env.FACES_API_KEY;
66
+ if (env)
67
+ return env;
68
+ return loadConfig().api_key || undefined;
65
69
  }
@@ -53,10 +53,23 @@
53
53
  "state.js"
54
54
  ]
55
55
  },
56
- "billing:balance": {
56
+ "auth:connect": {
57
57
  "aliases": [],
58
- "args": {},
59
- "description": "Show credit balance and payment method status",
58
+ "args": {
59
+ "provider": {
60
+ "description": "OAuth provider to connect",
61
+ "name": "provider",
62
+ "options": [
63
+ "openai"
64
+ ],
65
+ "required": true
66
+ }
67
+ },
68
+ "description": "Connect an OAuth provider account to Faces (e.g. ChatGPT Plus/Pro)",
69
+ "examples": [
70
+ "<%= config.bin %> auth connect openai",
71
+ "<%= config.bin %> auth connect openai --manual"
72
+ ],
60
73
  "flags": {
61
74
  "json": {
62
75
  "description": "Format output as json.",
@@ -88,11 +101,17 @@
88
101
  "hasDynamicHelp": false,
89
102
  "multiple": false,
90
103
  "type": "option"
104
+ },
105
+ "manual": {
106
+ "description": "Manual mode for headless environments: prints the authorize URL and prompts you to paste the callback URL after approving in any browser.",
107
+ "name": "manual",
108
+ "allowNo": false,
109
+ "type": "boolean"
91
110
  }
92
111
  },
93
112
  "hasDynamicHelp": false,
94
113
  "hiddenAliases": [],
95
- "id": "billing:balance",
114
+ "id": "auth:connect",
96
115
  "pluginAlias": "faces-cli",
97
116
  "pluginName": "faces-cli",
98
117
  "pluginType": "core",
@@ -102,14 +121,18 @@
102
121
  "relativePath": [
103
122
  "dist",
104
123
  "commands",
105
- "billing",
106
- "balance.js"
124
+ "auth",
125
+ "connect.js"
107
126
  ]
108
127
  },
109
- "billing:card-setup": {
128
+ "auth:connections": {
110
129
  "aliases": [],
111
130
  "args": {},
112
- "description": "Get a Stripe card setup URL to save a payment method",
131
+ "description": "List connected OAuth provider accounts",
132
+ "examples": [
133
+ "<%= config.bin %> auth connections",
134
+ "<%= config.bin %> auth connections --json"
135
+ ],
113
136
  "flags": {
114
137
  "json": {
115
138
  "description": "Format output as json.",
@@ -145,7 +168,7 @@
145
168
  },
146
169
  "hasDynamicHelp": false,
147
170
  "hiddenAliases": [],
148
- "id": "billing:card-setup",
171
+ "id": "auth:connections",
149
172
  "pluginAlias": "faces-cli",
150
173
  "pluginName": "faces-cli",
151
174
  "pluginType": "core",
@@ -155,14 +178,26 @@
155
178
  "relativePath": [
156
179
  "dist",
157
180
  "commands",
158
- "billing",
159
- "card-setup.js"
181
+ "auth",
182
+ "connections.js"
160
183
  ]
161
184
  },
162
- "billing:checkout": {
185
+ "auth:disconnect": {
163
186
  "aliases": [],
164
- "args": {},
165
- "description": "Get a Stripe checkout URL to upgrade your subscription plan",
187
+ "args": {
188
+ "provider": {
189
+ "description": "OAuth provider to disconnect",
190
+ "name": "provider",
191
+ "options": [
192
+ "openai"
193
+ ],
194
+ "required": true
195
+ }
196
+ },
197
+ "description": "Disconnect a linked OAuth provider account",
198
+ "examples": [
199
+ "<%= config.bin %> auth disconnect openai"
200
+ ],
166
201
  "flags": {
167
202
  "json": {
168
203
  "description": "Format output as json.",
@@ -194,22 +229,11 @@
194
229
  "hasDynamicHelp": false,
195
230
  "multiple": false,
196
231
  "type": "option"
197
- },
198
- "plan": {
199
- "description": "Plan to subscribe to",
200
- "name": "plan",
201
- "default": "connect",
202
- "hasDynamicHelp": false,
203
- "multiple": false,
204
- "options": [
205
- "connect"
206
- ],
207
- "type": "option"
208
232
  }
209
233
  },
210
234
  "hasDynamicHelp": false,
211
235
  "hiddenAliases": [],
212
- "id": "billing:checkout",
236
+ "id": "auth:disconnect",
213
237
  "pluginAlias": "faces-cli",
214
238
  "pluginName": "faces-cli",
215
239
  "pluginType": "core",
@@ -219,14 +243,14 @@
219
243
  "relativePath": [
220
244
  "dist",
221
245
  "commands",
222
- "billing",
223
- "checkout.js"
246
+ "auth",
247
+ "disconnect.js"
224
248
  ]
225
249
  },
226
- "billing:llm-costs": {
250
+ "auth:login": {
227
251
  "aliases": [],
228
252
  "args": {},
229
- "description": "List available LLMs and their per-token costs",
253
+ "description": "Login and save JWT credentials",
230
254
  "flags": {
231
255
  "json": {
232
256
  "description": "Format output as json.",
@@ -259,9 +283,18 @@
259
283
  "multiple": false,
260
284
  "type": "option"
261
285
  },
262
- "provider": {
263
- "description": "Filter by provider (e.g. openai, anthropic)",
264
- "name": "provider",
286
+ "email": {
287
+ "description": "Account email",
288
+ "name": "email",
289
+ "required": true,
290
+ "hasDynamicHelp": false,
291
+ "multiple": false,
292
+ "type": "option"
293
+ },
294
+ "password": {
295
+ "description": "Account password",
296
+ "name": "password",
297
+ "required": true,
265
298
  "hasDynamicHelp": false,
266
299
  "multiple": false,
267
300
  "type": "option"
@@ -269,7 +302,7 @@
269
302
  },
270
303
  "hasDynamicHelp": false,
271
304
  "hiddenAliases": [],
272
- "id": "billing:llm-costs",
305
+ "id": "auth:login",
273
306
  "pluginAlias": "faces-cli",
274
307
  "pluginName": "faces-cli",
275
308
  "pluginType": "core",
@@ -279,14 +312,14 @@
279
312
  "relativePath": [
280
313
  "dist",
281
314
  "commands",
282
- "billing",
283
- "llm-costs.js"
315
+ "auth",
316
+ "login.js"
284
317
  ]
285
318
  },
286
- "billing:quota": {
319
+ "auth:logout": {
287
320
  "aliases": [],
288
321
  "args": {},
289
- "description": "Show compile token quota and per-face stats",
322
+ "description": "Clear saved credentials",
290
323
  "flags": {
291
324
  "json": {
292
325
  "description": "Format output as json.",
@@ -322,7 +355,7 @@
322
355
  },
323
356
  "hasDynamicHelp": false,
324
357
  "hiddenAliases": [],
325
- "id": "billing:quota",
358
+ "id": "auth:logout",
326
359
  "pluginAlias": "faces-cli",
327
360
  "pluginName": "faces-cli",
328
361
  "pluginType": "core",
@@ -332,14 +365,14 @@
332
365
  "relativePath": [
333
366
  "dist",
334
367
  "commands",
335
- "billing",
336
- "quota.js"
368
+ "auth",
369
+ "logout.js"
337
370
  ]
338
371
  },
339
- "billing:subscription": {
372
+ "auth:refresh": {
340
373
  "aliases": [],
341
374
  "args": {},
342
- "description": "Show current plan, face count, and renewal date",
375
+ "description": "Exchange current JWT for a fresh one",
343
376
  "flags": {
344
377
  "json": {
345
378
  "description": "Format output as json.",
@@ -375,7 +408,7 @@
375
408
  },
376
409
  "hasDynamicHelp": false,
377
410
  "hiddenAliases": [],
378
- "id": "billing:subscription",
411
+ "id": "auth:refresh",
379
412
  "pluginAlias": "faces-cli",
380
413
  "pluginName": "faces-cli",
381
414
  "pluginType": "core",
@@ -385,14 +418,14 @@
385
418
  "relativePath": [
386
419
  "dist",
387
420
  "commands",
388
- "billing",
389
- "subscription.js"
421
+ "auth",
422
+ "refresh.js"
390
423
  ]
391
424
  },
392
- "billing:topup": {
425
+ "auth:register": {
393
426
  "aliases": [],
394
427
  "args": {},
395
- "description": "Top up credit balance using saved payment method",
428
+ "description": "Create a new Faces account",
396
429
  "flags": {
397
430
  "json": {
398
431
  "description": "Format output as json.",
@@ -425,25 +458,60 @@
425
458
  "multiple": false,
426
459
  "type": "option"
427
460
  },
428
- "amount": {
429
- "description": "Top-up amount in USD (min $1)",
430
- "name": "amount",
461
+ "email": {
462
+ "description": "Email address",
463
+ "name": "email",
431
464
  "required": true,
432
465
  "hasDynamicHelp": false,
433
466
  "multiple": false,
434
467
  "type": "option"
435
468
  },
436
- "payment-ref": {
437
- "description": "Payment reference (admin/test path)",
438
- "name": "payment-ref",
469
+ "password": {
470
+ "description": "Password",
471
+ "name": "password",
472
+ "required": true,
473
+ "hasDynamicHelp": false,
474
+ "multiple": false,
475
+ "type": "option"
476
+ },
477
+ "name": {
478
+ "description": "Display name (defaults to username)",
479
+ "name": "name",
480
+ "hasDynamicHelp": false,
481
+ "multiple": false,
482
+ "type": "option"
483
+ },
484
+ "username": {
485
+ "description": "Username (lowercase, dashes, numbers)",
486
+ "name": "username",
487
+ "required": true,
488
+ "hasDynamicHelp": false,
489
+ "multiple": false,
490
+ "type": "option"
491
+ },
492
+ "invite-key": {
493
+ "description": "Invite key (if required)",
494
+ "name": "invite-key",
495
+ "hasDynamicHelp": false,
496
+ "multiple": false,
497
+ "type": "option"
498
+ },
499
+ "plan": {
500
+ "description": "Plan to subscribe to: \"free\" ($5 activation) or \"connect\" ($17/mo, no activation fee)",
501
+ "name": "plan",
502
+ "default": "free",
439
503
  "hasDynamicHelp": false,
440
504
  "multiple": false,
505
+ "options": [
506
+ "free",
507
+ "connect"
508
+ ],
441
509
  "type": "option"
442
510
  }
443
511
  },
444
512
  "hasDynamicHelp": false,
445
513
  "hiddenAliases": [],
446
- "id": "billing:topup",
514
+ "id": "auth:register",
447
515
  "pluginAlias": "faces-cli",
448
516
  "pluginName": "faces-cli",
449
517
  "pluginType": "core",
@@ -453,14 +521,14 @@
453
521
  "relativePath": [
454
522
  "dist",
455
523
  "commands",
456
- "billing",
457
- "topup.js"
524
+ "auth",
525
+ "register.js"
458
526
  ]
459
527
  },
460
- "billing:usage": {
528
+ "auth:whoami": {
461
529
  "aliases": [],
462
530
  "args": {},
463
- "description": "Aggregated usage analytics",
531
+ "description": "Print current user profile and auth diagnostic",
464
532
  "flags": {
465
533
  "json": {
466
534
  "description": "Format output as json.",
@@ -492,38 +560,11 @@
492
560
  "hasDynamicHelp": false,
493
561
  "multiple": false,
494
562
  "type": "option"
495
- },
496
- "group-by": {
497
- "description": "Group results",
498
- "name": "group-by",
499
- "hasDynamicHelp": false,
500
- "multiple": false,
501
- "options": [
502
- "api_key",
503
- "model",
504
- "llm",
505
- "date"
506
- ],
507
- "type": "option"
508
- },
509
- "from": {
510
- "description": "Start date (YYYY-MM-DD)",
511
- "name": "from",
512
- "hasDynamicHelp": false,
513
- "multiple": false,
514
- "type": "option"
515
- },
516
- "to": {
517
- "description": "End date (YYYY-MM-DD)",
518
- "name": "to",
519
- "hasDynamicHelp": false,
520
- "multiple": false,
521
- "type": "option"
522
563
  }
523
564
  },
524
565
  "hasDynamicHelp": false,
525
566
  "hiddenAliases": [],
526
- "id": "billing:usage",
567
+ "id": "auth:whoami",
527
568
  "pluginAlias": "faces-cli",
528
569
  "pluginName": "faces-cli",
529
570
  "pluginType": "core",
@@ -533,27 +574,14 @@
533
574
  "relativePath": [
534
575
  "dist",
535
576
  "commands",
536
- "billing",
537
- "usage.js"
577
+ "auth",
578
+ "whoami.js"
538
579
  ]
539
580
  },
540
- "auth:connect": {
581
+ "billing:balance": {
541
582
  "aliases": [],
542
- "args": {
543
- "provider": {
544
- "description": "OAuth provider to connect",
545
- "name": "provider",
546
- "options": [
547
- "openai"
548
- ],
549
- "required": true
550
- }
551
- },
552
- "description": "Connect an OAuth provider account to Faces (e.g. ChatGPT Plus/Pro)",
553
- "examples": [
554
- "<%= config.bin %> auth connect openai",
555
- "<%= config.bin %> auth connect openai --manual"
556
- ],
583
+ "args": {},
584
+ "description": "Show credit balance and payment method status",
557
585
  "flags": {
558
586
  "json": {
559
587
  "description": "Format output as json.",
@@ -585,17 +613,11 @@
585
613
  "hasDynamicHelp": false,
586
614
  "multiple": false,
587
615
  "type": "option"
588
- },
589
- "manual": {
590
- "description": "Manual mode for headless environments: prints the authorize URL and prompts you to paste the callback URL after approving in any browser.",
591
- "name": "manual",
592
- "allowNo": false,
593
- "type": "boolean"
594
616
  }
595
617
  },
596
618
  "hasDynamicHelp": false,
597
619
  "hiddenAliases": [],
598
- "id": "auth:connect",
620
+ "id": "billing:balance",
599
621
  "pluginAlias": "faces-cli",
600
622
  "pluginName": "faces-cli",
601
623
  "pluginType": "core",
@@ -605,18 +627,14 @@
605
627
  "relativePath": [
606
628
  "dist",
607
629
  "commands",
608
- "auth",
609
- "connect.js"
630
+ "billing",
631
+ "balance.js"
610
632
  ]
611
633
  },
612
- "auth:connections": {
634
+ "billing:card-setup": {
613
635
  "aliases": [],
614
636
  "args": {},
615
- "description": "List connected OAuth provider accounts",
616
- "examples": [
617
- "<%= config.bin %> auth connections",
618
- "<%= config.bin %> auth connections --json"
619
- ],
637
+ "description": "Get a Stripe card setup URL to save a payment method",
620
638
  "flags": {
621
639
  "json": {
622
640
  "description": "Format output as json.",
@@ -652,7 +670,7 @@
652
670
  },
653
671
  "hasDynamicHelp": false,
654
672
  "hiddenAliases": [],
655
- "id": "auth:connections",
673
+ "id": "billing:card-setup",
656
674
  "pluginAlias": "faces-cli",
657
675
  "pluginName": "faces-cli",
658
676
  "pluginType": "core",
@@ -662,26 +680,14 @@
662
680
  "relativePath": [
663
681
  "dist",
664
682
  "commands",
665
- "auth",
666
- "connections.js"
683
+ "billing",
684
+ "card-setup.js"
667
685
  ]
668
686
  },
669
- "auth:disconnect": {
687
+ "billing:checkout": {
670
688
  "aliases": [],
671
- "args": {
672
- "provider": {
673
- "description": "OAuth provider to disconnect",
674
- "name": "provider",
675
- "options": [
676
- "openai"
677
- ],
678
- "required": true
679
- }
680
- },
681
- "description": "Disconnect a linked OAuth provider account",
682
- "examples": [
683
- "<%= config.bin %> auth disconnect openai"
684
- ],
689
+ "args": {},
690
+ "description": "Get a Stripe checkout URL to upgrade your subscription plan",
685
691
  "flags": {
686
692
  "json": {
687
693
  "description": "Format output as json.",
@@ -713,11 +719,22 @@
713
719
  "hasDynamicHelp": false,
714
720
  "multiple": false,
715
721
  "type": "option"
722
+ },
723
+ "plan": {
724
+ "description": "Plan to subscribe to",
725
+ "name": "plan",
726
+ "default": "connect",
727
+ "hasDynamicHelp": false,
728
+ "multiple": false,
729
+ "options": [
730
+ "connect"
731
+ ],
732
+ "type": "option"
716
733
  }
717
734
  },
718
735
  "hasDynamicHelp": false,
719
736
  "hiddenAliases": [],
720
- "id": "auth:disconnect",
737
+ "id": "billing:checkout",
721
738
  "pluginAlias": "faces-cli",
722
739
  "pluginName": "faces-cli",
723
740
  "pluginType": "core",
@@ -727,14 +744,14 @@
727
744
  "relativePath": [
728
745
  "dist",
729
746
  "commands",
730
- "auth",
731
- "disconnect.js"
747
+ "billing",
748
+ "checkout.js"
732
749
  ]
733
750
  },
734
- "auth:login": {
751
+ "billing:llm-costs": {
735
752
  "aliases": [],
736
753
  "args": {},
737
- "description": "Login and save JWT credentials",
754
+ "description": "List available LLMs and their per-token costs",
738
755
  "flags": {
739
756
  "json": {
740
757
  "description": "Format output as json.",
@@ -767,18 +784,62 @@
767
784
  "multiple": false,
768
785
  "type": "option"
769
786
  },
770
- "email": {
771
- "description": "Account email",
772
- "name": "email",
773
- "required": true,
787
+ "provider": {
788
+ "description": "Filter by provider (e.g. openai, anthropic)",
789
+ "name": "provider",
790
+ "hasDynamicHelp": false,
791
+ "multiple": false,
792
+ "type": "option"
793
+ }
794
+ },
795
+ "hasDynamicHelp": false,
796
+ "hiddenAliases": [],
797
+ "id": "billing:llm-costs",
798
+ "pluginAlias": "faces-cli",
799
+ "pluginName": "faces-cli",
800
+ "pluginType": "core",
801
+ "strict": true,
802
+ "enableJsonFlag": true,
803
+ "isESM": true,
804
+ "relativePath": [
805
+ "dist",
806
+ "commands",
807
+ "billing",
808
+ "llm-costs.js"
809
+ ]
810
+ },
811
+ "billing:quota": {
812
+ "aliases": [],
813
+ "args": {},
814
+ "description": "Show compile token quota and per-face stats",
815
+ "flags": {
816
+ "json": {
817
+ "description": "Format output as json.",
818
+ "helpGroup": "GLOBAL",
819
+ "name": "json",
820
+ "allowNo": false,
821
+ "type": "boolean"
822
+ },
823
+ "base-url": {
824
+ "description": "API base URL",
825
+ "env": "FACES_BASE_URL",
826
+ "name": "base-url",
774
827
  "hasDynamicHelp": false,
775
828
  "multiple": false,
776
829
  "type": "option"
777
830
  },
778
- "password": {
779
- "description": "Account password",
780
- "name": "password",
781
- "required": true,
831
+ "token": {
832
+ "description": "JWT bearer token",
833
+ "env": "FACES_TOKEN",
834
+ "name": "token",
835
+ "hasDynamicHelp": false,
836
+ "multiple": false,
837
+ "type": "option"
838
+ },
839
+ "api-key": {
840
+ "description": "API key",
841
+ "env": "FACES_API_KEY",
842
+ "name": "api-key",
782
843
  "hasDynamicHelp": false,
783
844
  "multiple": false,
784
845
  "type": "option"
@@ -786,7 +847,7 @@
786
847
  },
787
848
  "hasDynamicHelp": false,
788
849
  "hiddenAliases": [],
789
- "id": "auth:login",
850
+ "id": "billing:quota",
790
851
  "pluginAlias": "faces-cli",
791
852
  "pluginName": "faces-cli",
792
853
  "pluginType": "core",
@@ -796,14 +857,14 @@
796
857
  "relativePath": [
797
858
  "dist",
798
859
  "commands",
799
- "auth",
800
- "login.js"
860
+ "billing",
861
+ "quota.js"
801
862
  ]
802
863
  },
803
- "auth:logout": {
864
+ "billing:subscription": {
804
865
  "aliases": [],
805
866
  "args": {},
806
- "description": "Clear saved credentials",
867
+ "description": "Show current plan, face count, and renewal date",
807
868
  "flags": {
808
869
  "json": {
809
870
  "description": "Format output as json.",
@@ -839,7 +900,7 @@
839
900
  },
840
901
  "hasDynamicHelp": false,
841
902
  "hiddenAliases": [],
842
- "id": "auth:logout",
903
+ "id": "billing:subscription",
843
904
  "pluginAlias": "faces-cli",
844
905
  "pluginName": "faces-cli",
845
906
  "pluginType": "core",
@@ -849,14 +910,14 @@
849
910
  "relativePath": [
850
911
  "dist",
851
912
  "commands",
852
- "auth",
853
- "logout.js"
913
+ "billing",
914
+ "subscription.js"
854
915
  ]
855
916
  },
856
- "auth:refresh": {
917
+ "billing:topup": {
857
918
  "aliases": [],
858
919
  "args": {},
859
- "description": "Exchange current JWT for a fresh one",
920
+ "description": "Top up credit balance using saved payment method",
860
921
  "flags": {
861
922
  "json": {
862
923
  "description": "Format output as json.",
@@ -888,11 +949,26 @@
888
949
  "hasDynamicHelp": false,
889
950
  "multiple": false,
890
951
  "type": "option"
952
+ },
953
+ "amount": {
954
+ "description": "Top-up amount in USD (min $1)",
955
+ "name": "amount",
956
+ "required": true,
957
+ "hasDynamicHelp": false,
958
+ "multiple": false,
959
+ "type": "option"
960
+ },
961
+ "payment-ref": {
962
+ "description": "Payment reference (admin/test path)",
963
+ "name": "payment-ref",
964
+ "hasDynamicHelp": false,
965
+ "multiple": false,
966
+ "type": "option"
891
967
  }
892
968
  },
893
969
  "hasDynamicHelp": false,
894
970
  "hiddenAliases": [],
895
- "id": "auth:refresh",
971
+ "id": "billing:topup",
896
972
  "pluginAlias": "faces-cli",
897
973
  "pluginName": "faces-cli",
898
974
  "pluginType": "core",
@@ -902,14 +978,14 @@
902
978
  "relativePath": [
903
979
  "dist",
904
980
  "commands",
905
- "auth",
906
- "refresh.js"
981
+ "billing",
982
+ "topup.js"
907
983
  ]
908
984
  },
909
- "auth:register": {
985
+ "billing:usage": {
910
986
  "aliases": [],
911
987
  "args": {},
912
- "description": "Create a new Faces account",
988
+ "description": "Aggregated usage analytics",
913
989
  "flags": {
914
990
  "json": {
915
991
  "description": "Format output as json.",
@@ -942,60 +1018,155 @@
942
1018
  "multiple": false,
943
1019
  "type": "option"
944
1020
  },
945
- "email": {
946
- "description": "Email address",
947
- "name": "email",
948
- "required": true,
1021
+ "group-by": {
1022
+ "description": "Group results",
1023
+ "name": "group-by",
949
1024
  "hasDynamicHelp": false,
950
1025
  "multiple": false,
1026
+ "options": [
1027
+ "api_key",
1028
+ "model",
1029
+ "llm",
1030
+ "date"
1031
+ ],
951
1032
  "type": "option"
952
1033
  },
953
- "password": {
954
- "description": "Password",
955
- "name": "password",
956
- "required": true,
1034
+ "from": {
1035
+ "description": "Start date (YYYY-MM-DD)",
1036
+ "name": "from",
957
1037
  "hasDynamicHelp": false,
958
1038
  "multiple": false,
959
1039
  "type": "option"
960
1040
  },
961
- "name": {
962
- "description": "Display name (defaults to username)",
963
- "name": "name",
1041
+ "to": {
1042
+ "description": "End date (YYYY-MM-DD)",
1043
+ "name": "to",
964
1044
  "hasDynamicHelp": false,
965
1045
  "multiple": false,
966
1046
  "type": "option"
1047
+ }
1048
+ },
1049
+ "hasDynamicHelp": false,
1050
+ "hiddenAliases": [],
1051
+ "id": "billing:usage",
1052
+ "pluginAlias": "faces-cli",
1053
+ "pluginName": "faces-cli",
1054
+ "pluginType": "core",
1055
+ "strict": true,
1056
+ "enableJsonFlag": true,
1057
+ "isESM": true,
1058
+ "relativePath": [
1059
+ "dist",
1060
+ "commands",
1061
+ "billing",
1062
+ "usage.js"
1063
+ ]
1064
+ },
1065
+ "catalog:doctor": {
1066
+ "aliases": [],
1067
+ "args": {},
1068
+ "description": "Diagnose and repair the local face catalog",
1069
+ "flags": {
1070
+ "json": {
1071
+ "description": "Format output as json.",
1072
+ "helpGroup": "GLOBAL",
1073
+ "name": "json",
1074
+ "allowNo": false,
1075
+ "type": "boolean"
967
1076
  },
968
- "username": {
969
- "description": "Username (lowercase, dashes, numbers)",
970
- "name": "username",
971
- "required": true,
1077
+ "base-url": {
1078
+ "description": "API base URL",
1079
+ "env": "FACES_BASE_URL",
1080
+ "name": "base-url",
972
1081
  "hasDynamicHelp": false,
973
1082
  "multiple": false,
974
1083
  "type": "option"
975
1084
  },
976
- "invite-key": {
977
- "description": "Invite key (if required)",
978
- "name": "invite-key",
1085
+ "token": {
1086
+ "description": "JWT bearer token",
1087
+ "env": "FACES_TOKEN",
1088
+ "name": "token",
1089
+ "hasDynamicHelp": false,
1090
+ "multiple": false,
1091
+ "type": "option"
1092
+ },
1093
+ "api-key": {
1094
+ "description": "API key",
1095
+ "env": "FACES_API_KEY",
1096
+ "name": "api-key",
1097
+ "hasDynamicHelp": false,
1098
+ "multiple": false,
1099
+ "type": "option"
1100
+ },
1101
+ "fix": {
1102
+ "description": "Rebuild missing or stale catalog entries from API",
1103
+ "name": "fix",
1104
+ "allowNo": false,
1105
+ "type": "boolean"
1106
+ },
1107
+ "generate": {
1108
+ "description": "Fix + generate missing descriptions via LLM",
1109
+ "name": "generate",
1110
+ "allowNo": false,
1111
+ "type": "boolean"
1112
+ }
1113
+ },
1114
+ "hasDynamicHelp": false,
1115
+ "hiddenAliases": [],
1116
+ "id": "catalog:doctor",
1117
+ "pluginAlias": "faces-cli",
1118
+ "pluginName": "faces-cli",
1119
+ "pluginType": "core",
1120
+ "strict": true,
1121
+ "enableJsonFlag": true,
1122
+ "isESM": true,
1123
+ "relativePath": [
1124
+ "dist",
1125
+ "commands",
1126
+ "catalog",
1127
+ "doctor.js"
1128
+ ]
1129
+ },
1130
+ "catalog:list": {
1131
+ "aliases": [],
1132
+ "args": {},
1133
+ "description": "List all faces in the local catalog",
1134
+ "flags": {
1135
+ "json": {
1136
+ "description": "Format output as json.",
1137
+ "helpGroup": "GLOBAL",
1138
+ "name": "json",
1139
+ "allowNo": false,
1140
+ "type": "boolean"
1141
+ },
1142
+ "base-url": {
1143
+ "description": "API base URL",
1144
+ "env": "FACES_BASE_URL",
1145
+ "name": "base-url",
1146
+ "hasDynamicHelp": false,
1147
+ "multiple": false,
1148
+ "type": "option"
1149
+ },
1150
+ "token": {
1151
+ "description": "JWT bearer token",
1152
+ "env": "FACES_TOKEN",
1153
+ "name": "token",
979
1154
  "hasDynamicHelp": false,
980
1155
  "multiple": false,
981
1156
  "type": "option"
982
1157
  },
983
- "plan": {
984
- "description": "Plan to subscribe to: \"free\" ($5 activation) or \"connect\" ($17/mo, no activation fee)",
985
- "name": "plan",
986
- "default": "free",
1158
+ "api-key": {
1159
+ "description": "API key",
1160
+ "env": "FACES_API_KEY",
1161
+ "name": "api-key",
987
1162
  "hasDynamicHelp": false,
988
1163
  "multiple": false,
989
- "options": [
990
- "free",
991
- "connect"
992
- ],
993
1164
  "type": "option"
994
1165
  }
995
1166
  },
996
1167
  "hasDynamicHelp": false,
997
1168
  "hiddenAliases": [],
998
- "id": "auth:register",
1169
+ "id": "catalog:list",
999
1170
  "pluginAlias": "faces-cli",
1000
1171
  "pluginName": "faces-cli",
1001
1172
  "pluginType": "core",
@@ -1005,14 +1176,14 @@
1005
1176
  "relativePath": [
1006
1177
  "dist",
1007
1178
  "commands",
1008
- "auth",
1009
- "register.js"
1179
+ "catalog",
1180
+ "list.js"
1010
1181
  ]
1011
1182
  },
1012
- "auth:whoami": {
1183
+ "catalog:manyfaced": {
1013
1184
  "aliases": [],
1014
1185
  "args": {},
1015
- "description": "Print current user profile and auth diagnostic",
1186
+ "description": "Browse and install community manyfaced skills from github.com/facessh/manyfaced",
1016
1187
  "flags": {
1017
1188
  "json": {
1018
1189
  "description": "Format output as json.",
@@ -1044,11 +1215,38 @@
1044
1215
  "hasDynamicHelp": false,
1045
1216
  "multiple": false,
1046
1217
  "type": "option"
1218
+ },
1219
+ "skill": {
1220
+ "description": "Show details for a specific skill",
1221
+ "name": "skill",
1222
+ "hasDynamicHelp": false,
1223
+ "multiple": false,
1224
+ "type": "option"
1225
+ },
1226
+ "install": {
1227
+ "description": "Install a skill by name",
1228
+ "name": "install",
1229
+ "hasDynamicHelp": false,
1230
+ "multiple": false,
1231
+ "type": "option"
1232
+ },
1233
+ "skills-dir": {
1234
+ "description": "Directory to install skills into (required for --install)",
1235
+ "name": "skills-dir",
1236
+ "hasDynamicHelp": false,
1237
+ "multiple": false,
1238
+ "type": "option"
1239
+ },
1240
+ "refresh": {
1241
+ "description": "Force refresh the skill index (ignore cache)",
1242
+ "name": "refresh",
1243
+ "allowNo": false,
1244
+ "type": "boolean"
1047
1245
  }
1048
1246
  },
1049
1247
  "hasDynamicHelp": false,
1050
1248
  "hiddenAliases": [],
1051
- "id": "auth:whoami",
1249
+ "id": "catalog:manyfaced",
1052
1250
  "pluginAlias": "faces-cli",
1053
1251
  "pluginName": "faces-cli",
1054
1252
  "pluginType": "core",
@@ -1058,8 +1256,8 @@
1058
1256
  "relativePath": [
1059
1257
  "dist",
1060
1258
  "commands",
1061
- "auth",
1062
- "whoami.js"
1259
+ "catalog",
1260
+ "manyfaced.js"
1063
1261
  ]
1064
1262
  },
1065
1263
  "chat:chat": {
@@ -1555,204 +1753,6 @@
1555
1753
  "upload.js"
1556
1754
  ]
1557
1755
  },
1558
- "catalog:doctor": {
1559
- "aliases": [],
1560
- "args": {},
1561
- "description": "Diagnose and repair the local face catalog",
1562
- "flags": {
1563
- "json": {
1564
- "description": "Format output as json.",
1565
- "helpGroup": "GLOBAL",
1566
- "name": "json",
1567
- "allowNo": false,
1568
- "type": "boolean"
1569
- },
1570
- "base-url": {
1571
- "description": "API base URL",
1572
- "env": "FACES_BASE_URL",
1573
- "name": "base-url",
1574
- "hasDynamicHelp": false,
1575
- "multiple": false,
1576
- "type": "option"
1577
- },
1578
- "token": {
1579
- "description": "JWT bearer token",
1580
- "env": "FACES_TOKEN",
1581
- "name": "token",
1582
- "hasDynamicHelp": false,
1583
- "multiple": false,
1584
- "type": "option"
1585
- },
1586
- "api-key": {
1587
- "description": "API key",
1588
- "env": "FACES_API_KEY",
1589
- "name": "api-key",
1590
- "hasDynamicHelp": false,
1591
- "multiple": false,
1592
- "type": "option"
1593
- },
1594
- "fix": {
1595
- "description": "Rebuild missing or stale catalog entries from API",
1596
- "name": "fix",
1597
- "allowNo": false,
1598
- "type": "boolean"
1599
- },
1600
- "generate": {
1601
- "description": "Fix + generate missing descriptions via LLM",
1602
- "name": "generate",
1603
- "allowNo": false,
1604
- "type": "boolean"
1605
- }
1606
- },
1607
- "hasDynamicHelp": false,
1608
- "hiddenAliases": [],
1609
- "id": "catalog:doctor",
1610
- "pluginAlias": "faces-cli",
1611
- "pluginName": "faces-cli",
1612
- "pluginType": "core",
1613
- "strict": true,
1614
- "enableJsonFlag": true,
1615
- "isESM": true,
1616
- "relativePath": [
1617
- "dist",
1618
- "commands",
1619
- "catalog",
1620
- "doctor.js"
1621
- ]
1622
- },
1623
- "catalog:list": {
1624
- "aliases": [],
1625
- "args": {},
1626
- "description": "List all faces in the local catalog",
1627
- "flags": {
1628
- "json": {
1629
- "description": "Format output as json.",
1630
- "helpGroup": "GLOBAL",
1631
- "name": "json",
1632
- "allowNo": false,
1633
- "type": "boolean"
1634
- },
1635
- "base-url": {
1636
- "description": "API base URL",
1637
- "env": "FACES_BASE_URL",
1638
- "name": "base-url",
1639
- "hasDynamicHelp": false,
1640
- "multiple": false,
1641
- "type": "option"
1642
- },
1643
- "token": {
1644
- "description": "JWT bearer token",
1645
- "env": "FACES_TOKEN",
1646
- "name": "token",
1647
- "hasDynamicHelp": false,
1648
- "multiple": false,
1649
- "type": "option"
1650
- },
1651
- "api-key": {
1652
- "description": "API key",
1653
- "env": "FACES_API_KEY",
1654
- "name": "api-key",
1655
- "hasDynamicHelp": false,
1656
- "multiple": false,
1657
- "type": "option"
1658
- }
1659
- },
1660
- "hasDynamicHelp": false,
1661
- "hiddenAliases": [],
1662
- "id": "catalog:list",
1663
- "pluginAlias": "faces-cli",
1664
- "pluginName": "faces-cli",
1665
- "pluginType": "core",
1666
- "strict": true,
1667
- "enableJsonFlag": true,
1668
- "isESM": true,
1669
- "relativePath": [
1670
- "dist",
1671
- "commands",
1672
- "catalog",
1673
- "list.js"
1674
- ]
1675
- },
1676
- "catalog:manyfaced": {
1677
- "aliases": [],
1678
- "args": {},
1679
- "description": "Browse and install community manyfaced skills from github.com/facessh/manyfaced",
1680
- "flags": {
1681
- "json": {
1682
- "description": "Format output as json.",
1683
- "helpGroup": "GLOBAL",
1684
- "name": "json",
1685
- "allowNo": false,
1686
- "type": "boolean"
1687
- },
1688
- "base-url": {
1689
- "description": "API base URL",
1690
- "env": "FACES_BASE_URL",
1691
- "name": "base-url",
1692
- "hasDynamicHelp": false,
1693
- "multiple": false,
1694
- "type": "option"
1695
- },
1696
- "token": {
1697
- "description": "JWT bearer token",
1698
- "env": "FACES_TOKEN",
1699
- "name": "token",
1700
- "hasDynamicHelp": false,
1701
- "multiple": false,
1702
- "type": "option"
1703
- },
1704
- "api-key": {
1705
- "description": "API key",
1706
- "env": "FACES_API_KEY",
1707
- "name": "api-key",
1708
- "hasDynamicHelp": false,
1709
- "multiple": false,
1710
- "type": "option"
1711
- },
1712
- "skill": {
1713
- "description": "Show details for a specific skill",
1714
- "name": "skill",
1715
- "hasDynamicHelp": false,
1716
- "multiple": false,
1717
- "type": "option"
1718
- },
1719
- "install": {
1720
- "description": "Install a skill by name",
1721
- "name": "install",
1722
- "hasDynamicHelp": false,
1723
- "multiple": false,
1724
- "type": "option"
1725
- },
1726
- "skills-dir": {
1727
- "description": "Directory to install skills into (required for --install)",
1728
- "name": "skills-dir",
1729
- "hasDynamicHelp": false,
1730
- "multiple": false,
1731
- "type": "option"
1732
- },
1733
- "refresh": {
1734
- "description": "Force refresh the skill index (ignore cache)",
1735
- "name": "refresh",
1736
- "allowNo": false,
1737
- "type": "boolean"
1738
- }
1739
- },
1740
- "hasDynamicHelp": false,
1741
- "hiddenAliases": [],
1742
- "id": "catalog:manyfaced",
1743
- "pluginAlias": "faces-cli",
1744
- "pluginName": "faces-cli",
1745
- "pluginType": "core",
1746
- "strict": true,
1747
- "enableJsonFlag": true,
1748
- "isESM": true,
1749
- "relativePath": [
1750
- "dist",
1751
- "commands",
1752
- "catalog",
1753
- "manyfaced.js"
1754
- ]
1755
- },
1756
1756
  "config:clear": {
1757
1757
  "aliases": [],
1758
1758
  "args": {},
@@ -4231,5 +4231,5 @@
4231
4231
  ]
4232
4232
  }
4233
4233
  },
4234
- "version": "1.5.9"
4234
+ "version": "1.5.10"
4235
4235
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "faces-cli",
3
- "version": "1.5.9",
3
+ "version": "1.5.10",
4
4
  "description": "CLI for the Faces AI platform",
5
5
  "type": "module",
6
6
  "author": "sybileak <sybileak@proton.me>",