faces-cli 1.7.1 → 1.7.3

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.
@@ -1,9 +1,11 @@
1
1
  import { BaseCommand } from '../../base.js';
2
2
  export default class ChatChat extends BaseCommand {
3
3
  static description: string;
4
+ static examples: string[];
4
5
  static flags: {
5
6
  message: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
6
7
  llm: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
+ formula: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
9
  system: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
10
  stream: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
11
  'max-tokens': import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -16,7 +18,7 @@ export default class ChatChat extends BaseCommand {
16
18
  'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
19
  };
18
20
  static args: {
19
- face_username: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
21
+ face_username: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
20
22
  };
21
23
  run(): Promise<unknown>;
22
24
  private oauthHint;
@@ -3,13 +3,19 @@ import fs from 'node:fs';
3
3
  import { BaseCommand } from '../../base.js';
4
4
  import { FacesAPIError } from '../../client.js';
5
5
  import { extractStreamDelta } from '../../utils.js';
6
- import { resolveEndpoint, MESSAGES_ENDPOINT, RESPONSES_ENDPOINT } from '../../routing.js';
6
+ import { resolveEndpoint, MESSAGES_ENDPOINT, RESPONSES_ENDPOINT, isCompositeFormula, faceSpecOf, llmFromArg } from '../../routing.js';
7
7
  export default class ChatChat extends BaseCommand {
8
8
  static description = 'Chat via a face. Auto-routes to the correct API endpoint based on the model catalog.';
9
+ static examples = [
10
+ '<%= config.bin %> <%= command.id %> socrates -m "What is virtue?"',
11
+ '<%= config.bin %> <%= command.id %> "(socrates | nietzsche)@claude-sonnet-4-6" -m "What is virtue?"',
12
+ '<%= config.bin %> <%= command.id %> --formula "socrates | nietzsche" --llm claude-sonnet-4-6 -m "What is virtue?"',
13
+ ];
9
14
  static flags = {
10
15
  ...BaseCommand.baseFlags,
11
16
  message: Flags.string({ char: 'm', description: 'User message (repeatable)', multiple: true, required: false }),
12
17
  llm: Flags.string({ description: 'LLM override (e.g. gpt-4o-mini, claude-sonnet-4-6)' }),
18
+ formula: Flags.string({ description: 'Compose a run-time composite from your own faces, e.g. "socrates | nietzsche" (operators: | & ^ -). Requires --llm. The composite takes the name of its first operand; use face:create --formula for a named, persisted composite.' }),
13
19
  system: Flags.string({ description: 'System prompt / instructions' }),
14
20
  stream: Flags.boolean({ description: 'Stream the response', default: false }),
15
21
  'max-tokens': Flags.integer({ description: 'Max tokens' }),
@@ -19,20 +25,39 @@ export default class ChatChat extends BaseCommand {
19
25
  'oauth-only': Flags.boolean({ description: 'Prevent fallback to paid system key (use OAuth only)', default: false }),
20
26
  };
21
27
  static args = {
22
- face_username: Args.string({ description: 'Face alias (alias@model, or owner:alias@model for a published face)', required: true }),
28
+ face_username: Args.string({
29
+ description: 'Face alias (alias@model, owner:alias@model for a published face, or a composite formula like "(a | b)@model"). Omit when using --formula.',
30
+ required: false,
31
+ }),
23
32
  };
24
33
  async run() {
25
34
  const { args, flags } = await this.parse(ChatChat);
26
35
  const client = this.makeClient(flags);
27
36
  // Build model string
28
37
  let model;
29
- if (flags.llm) {
30
- const base = args.face_username.split('@')[0];
38
+ if (flags.formula) {
39
+ if (args.face_username)
40
+ this.error('Pass either a face argument or --formula, not both.');
41
+ if (!flags.llm)
42
+ this.error('--formula needs a model. Add --llm <model>, e.g. --llm claude-sonnet-4-6.');
43
+ model = `(${flags.formula.trim()})@${flags.llm}`;
44
+ }
45
+ else if (!args.face_username) {
46
+ this.error('Provide a face (alias, owner:alias, or a composite formula), or use --formula.');
47
+ }
48
+ else if (flags.llm) {
49
+ const base = faceSpecOf(args.face_username);
31
50
  model = `${base}@${flags.llm}`;
32
51
  }
33
52
  else {
34
53
  model = args.face_username;
35
54
  }
55
+ // A run-time composite has no stored default_model — require an explicit @model (rule #1).
56
+ if (isCompositeFormula(model) && !llmFromArg(model)) {
57
+ const spec = faceSpecOf(model);
58
+ this.error(`Composite face '${spec}' has no default model. Specify one explicitly, ` +
59
+ `e.g. '${spec}@claude-sonnet-4-6', or pass --llm <model>.`);
60
+ }
36
61
  // Collect user messages
37
62
  const userMessages = [];
38
63
  if (flags.file) {
package/dist/routing.d.ts CHANGED
@@ -11,6 +11,15 @@ export interface RouteInfo {
11
11
  }
12
12
  /** Split `alias@llm` → llm; bare `alias` → undefined. */
13
13
  export declare function llmFromArg(modelArg: string): string | undefined;
14
+ /** The face-spec (everything left of the trailing `@model`), e.g. `(a | b)@x` → `(a | b)`. */
15
+ export declare function faceSpecOf(modelArg: string): string;
16
+ /**
17
+ * True when a model arg's face-spec is a run-time composite formula, i.e. it
18
+ * contains a set operator (`| & ^`), grouping parens, or a space-delimited `-`
19
+ * difference. None of these characters are legal in an alias (`^[a-z0-9-]+$`) or
20
+ * in `owner:alias`, so detection is unambiguous. Mirrors the backend's check.
21
+ */
22
+ export declare function isCompositeFormula(modelArg: string): boolean;
14
23
  /**
15
24
  * Decide which API endpoint a chat request should be posted to, driven entirely
16
25
  * by the model catalog (GET /v1/models). For a bare alias we resolve the face's
package/dist/routing.js CHANGED
@@ -88,6 +88,21 @@ export function llmFromArg(modelArg) {
88
88
  const i = modelArg.lastIndexOf('@');
89
89
  return i >= 0 ? modelArg.slice(i + 1) : undefined;
90
90
  }
91
+ /** The face-spec (everything left of the trailing `@model`), e.g. `(a | b)@x` → `(a | b)`. */
92
+ export function faceSpecOf(modelArg) {
93
+ const i = modelArg.lastIndexOf('@');
94
+ return i >= 0 ? modelArg.slice(0, i) : modelArg;
95
+ }
96
+ /**
97
+ * True when a model arg's face-spec is a run-time composite formula, i.e. it
98
+ * contains a set operator (`| & ^`), grouping parens, or a space-delimited `-`
99
+ * difference. None of these characters are legal in an alias (`^[a-z0-9-]+$`) or
100
+ * in `owner:alias`, so detection is unambiguous. Mirrors the backend's check.
101
+ */
102
+ export function isCompositeFormula(modelArg) {
103
+ const spec = faceSpecOf(modelArg).trim();
104
+ return /[|&^()]/.test(spec) || /\S\s+\S/.test(spec);
105
+ }
91
106
  /**
92
107
  * Decide which API endpoint a chat request should be posted to, driven entirely
93
108
  * by the model catalog (GET /v1/models). For a bare alias we resolve the face's
@@ -95,7 +110,9 @@ export function llmFromArg(modelArg) {
95
110
  */
96
111
  export async function resolveEndpoint(client, modelArg) {
97
112
  let llm = llmFromArg(modelArg);
98
- if (!llm) {
113
+ // A composite formula has no stored default_model and isn't a catalog face, so
114
+ // never attempt an alias lookup — route purely off the explicit `@model`.
115
+ if (!llm && !isCompositeFormula(modelArg)) {
99
116
  const alias = modelArg.split('@')[0];
100
117
  llm = defaultModelFromCatalog(alias);
101
118
  if (!llm) {
@@ -120,10 +120,23 @@
120
120
  "state.js"
121
121
  ]
122
122
  },
123
- "billing:balance": {
123
+ "auth:connect": {
124
124
  "aliases": [],
125
- "args": {},
126
- "description": "Show credit balance and payment method status",
125
+ "args": {
126
+ "provider": {
127
+ "description": "OAuth provider to connect",
128
+ "name": "provider",
129
+ "options": [
130
+ "openai"
131
+ ],
132
+ "required": true
133
+ }
134
+ },
135
+ "description": "Connect your ChatGPT account to Faces via device-code authorization (Subscription Connect plan)",
136
+ "examples": [
137
+ "<%= config.bin %> auth connect openai",
138
+ "<%= config.bin %> auth connect openai --json"
139
+ ],
127
140
  "flags": {
128
141
  "json": {
129
142
  "description": "Format output as json.",
@@ -159,7 +172,7 @@
159
172
  },
160
173
  "hasDynamicHelp": false,
161
174
  "hiddenAliases": [],
162
- "id": "billing:balance",
175
+ "id": "auth:connect",
163
176
  "pluginAlias": "faces-cli",
164
177
  "pluginName": "faces-cli",
165
178
  "pluginType": "core",
@@ -169,14 +182,18 @@
169
182
  "relativePath": [
170
183
  "dist",
171
184
  "commands",
172
- "billing",
173
- "balance.js"
185
+ "auth",
186
+ "connect.js"
174
187
  ]
175
188
  },
176
- "billing:card-setup": {
189
+ "auth:connections": {
177
190
  "aliases": [],
178
191
  "args": {},
179
- "description": "Get a Stripe card setup URL to save a payment method",
192
+ "description": "List connected OAuth provider accounts",
193
+ "examples": [
194
+ "<%= config.bin %> auth connections",
195
+ "<%= config.bin %> auth connections --json"
196
+ ],
180
197
  "flags": {
181
198
  "json": {
182
199
  "description": "Format output as json.",
@@ -212,7 +229,7 @@
212
229
  },
213
230
  "hasDynamicHelp": false,
214
231
  "hiddenAliases": [],
215
- "id": "billing:card-setup",
232
+ "id": "auth:connections",
216
233
  "pluginAlias": "faces-cli",
217
234
  "pluginName": "faces-cli",
218
235
  "pluginType": "core",
@@ -222,14 +239,26 @@
222
239
  "relativePath": [
223
240
  "dist",
224
241
  "commands",
225
- "billing",
226
- "card-setup.js"
242
+ "auth",
243
+ "connections.js"
227
244
  ]
228
245
  },
229
- "billing:llm-costs": {
246
+ "auth:disconnect": {
230
247
  "aliases": [],
231
- "args": {},
232
- "description": "List available LLMs and their per-token costs",
248
+ "args": {
249
+ "provider": {
250
+ "description": "OAuth provider to disconnect",
251
+ "name": "provider",
252
+ "options": [
253
+ "openai"
254
+ ],
255
+ "required": true
256
+ }
257
+ },
258
+ "description": "Disconnect a linked OAuth provider account",
259
+ "examples": [
260
+ "<%= config.bin %> auth disconnect openai"
261
+ ],
233
262
  "flags": {
234
263
  "json": {
235
264
  "description": "Format output as json.",
@@ -261,18 +290,11 @@
261
290
  "hasDynamicHelp": false,
262
291
  "multiple": false,
263
292
  "type": "option"
264
- },
265
- "provider": {
266
- "description": "Filter by provider (e.g. openai, anthropic)",
267
- "name": "provider",
268
- "hasDynamicHelp": false,
269
- "multiple": false,
270
- "type": "option"
271
293
  }
272
294
  },
273
295
  "hasDynamicHelp": false,
274
296
  "hiddenAliases": [],
275
- "id": "billing:llm-costs",
297
+ "id": "auth:disconnect",
276
298
  "pluginAlias": "faces-cli",
277
299
  "pluginName": "faces-cli",
278
300
  "pluginType": "core",
@@ -282,14 +304,14 @@
282
304
  "relativePath": [
283
305
  "dist",
284
306
  "commands",
285
- "billing",
286
- "llm-costs.js"
307
+ "auth",
308
+ "disconnect.js"
287
309
  ]
288
310
  },
289
- "billing:quota": {
311
+ "auth:login": {
290
312
  "aliases": [],
291
313
  "args": {},
292
- "description": "Show compilation stats per face (deprecated — use compile:stats)",
314
+ "description": "Login and save JWT credentials",
293
315
  "flags": {
294
316
  "json": {
295
317
  "description": "Format output as json.",
@@ -321,11 +343,27 @@
321
343
  "hasDynamicHelp": false,
322
344
  "multiple": false,
323
345
  "type": "option"
346
+ },
347
+ "email": {
348
+ "description": "Account email",
349
+ "name": "email",
350
+ "required": true,
351
+ "hasDynamicHelp": false,
352
+ "multiple": false,
353
+ "type": "option"
354
+ },
355
+ "password": {
356
+ "description": "Account password",
357
+ "name": "password",
358
+ "required": true,
359
+ "hasDynamicHelp": false,
360
+ "multiple": false,
361
+ "type": "option"
324
362
  }
325
363
  },
326
364
  "hasDynamicHelp": false,
327
365
  "hiddenAliases": [],
328
- "id": "billing:quota",
366
+ "id": "auth:login",
329
367
  "pluginAlias": "faces-cli",
330
368
  "pluginName": "faces-cli",
331
369
  "pluginType": "core",
@@ -335,14 +373,14 @@
335
373
  "relativePath": [
336
374
  "dist",
337
375
  "commands",
338
- "billing",
339
- "quota.js"
376
+ "auth",
377
+ "login.js"
340
378
  ]
341
379
  },
342
- "billing:subscription": {
380
+ "auth:logout": {
343
381
  "aliases": [],
344
382
  "args": {},
345
- "description": "Show current plan, face count, and renewal date",
383
+ "description": "Clear saved credentials",
346
384
  "flags": {
347
385
  "json": {
348
386
  "description": "Format output as json.",
@@ -378,7 +416,7 @@
378
416
  },
379
417
  "hasDynamicHelp": false,
380
418
  "hiddenAliases": [],
381
- "id": "billing:subscription",
419
+ "id": "auth:logout",
382
420
  "pluginAlias": "faces-cli",
383
421
  "pluginName": "faces-cli",
384
422
  "pluginType": "core",
@@ -388,14 +426,14 @@
388
426
  "relativePath": [
389
427
  "dist",
390
428
  "commands",
391
- "billing",
392
- "subscription.js"
429
+ "auth",
430
+ "logout.js"
393
431
  ]
394
432
  },
395
- "billing:topup": {
433
+ "auth:refresh": {
396
434
  "aliases": [],
397
435
  "args": {},
398
- "description": "Top up credit balance using saved payment method",
436
+ "description": "Exchange current JWT for a fresh one",
399
437
  "flags": {
400
438
  "json": {
401
439
  "description": "Format output as json.",
@@ -427,26 +465,11 @@
427
465
  "hasDynamicHelp": false,
428
466
  "multiple": false,
429
467
  "type": "option"
430
- },
431
- "amount": {
432
- "description": "Top-up amount in USD (min $1)",
433
- "name": "amount",
434
- "required": true,
435
- "hasDynamicHelp": false,
436
- "multiple": false,
437
- "type": "option"
438
- },
439
- "payment-ref": {
440
- "description": "Payment reference (admin/test path)",
441
- "name": "payment-ref",
442
- "hasDynamicHelp": false,
443
- "multiple": false,
444
- "type": "option"
445
468
  }
446
469
  },
447
470
  "hasDynamicHelp": false,
448
471
  "hiddenAliases": [],
449
- "id": "billing:topup",
472
+ "id": "auth:refresh",
450
473
  "pluginAlias": "faces-cli",
451
474
  "pluginName": "faces-cli",
452
475
  "pluginType": "core",
@@ -456,14 +479,14 @@
456
479
  "relativePath": [
457
480
  "dist",
458
481
  "commands",
459
- "billing",
460
- "topup.js"
482
+ "auth",
483
+ "refresh.js"
461
484
  ]
462
485
  },
463
- "billing:usage": {
486
+ "auth:register": {
464
487
  "aliases": [],
465
488
  "args": {},
466
- "description": "Aggregated usage analytics",
489
+ "description": "Create a new Faces account",
467
490
  "flags": {
468
491
  "json": {
469
492
  "description": "Format output as json.",
@@ -496,37 +519,53 @@
496
519
  "multiple": false,
497
520
  "type": "option"
498
521
  },
499
- "group-by": {
500
- "description": "Group results",
501
- "name": "group-by",
522
+ "email": {
523
+ "description": "Email address",
524
+ "name": "email",
525
+ "required": true,
502
526
  "hasDynamicHelp": false,
503
527
  "multiple": false,
504
- "options": [
505
- "api_key",
506
- "model",
507
- "llm",
508
- "date"
509
- ],
510
528
  "type": "option"
511
529
  },
512
- "from": {
513
- "description": "Start date (YYYY-MM-DD)",
514
- "name": "from",
530
+ "password": {
531
+ "description": "Password",
532
+ "name": "password",
533
+ "required": true,
515
534
  "hasDynamicHelp": false,
516
535
  "multiple": false,
517
536
  "type": "option"
518
537
  },
519
- "to": {
520
- "description": "End date (YYYY-MM-DD)",
521
- "name": "to",
538
+ "username": {
539
+ "description": "Username (lowercase, dashes, numbers)",
540
+ "name": "username",
541
+ "required": true,
542
+ "hasDynamicHelp": false,
543
+ "multiple": false,
544
+ "type": "option"
545
+ },
546
+ "invite-key": {
547
+ "description": "Invite key (if required)",
548
+ "name": "invite-key",
549
+ "hasDynamicHelp": false,
550
+ "multiple": false,
551
+ "type": "option"
552
+ },
553
+ "plan": {
554
+ "description": "Plan to subscribe to: \"free\" ($5 activation) or \"connect\" ($17/mo, no activation fee)",
555
+ "name": "plan",
556
+ "default": "free",
522
557
  "hasDynamicHelp": false,
523
558
  "multiple": false,
559
+ "options": [
560
+ "free",
561
+ "connect"
562
+ ],
524
563
  "type": "option"
525
564
  }
526
565
  },
527
566
  "hasDynamicHelp": false,
528
567
  "hiddenAliases": [],
529
- "id": "billing:usage",
568
+ "id": "auth:register",
530
569
  "pluginAlias": "faces-cli",
531
570
  "pluginName": "faces-cli",
532
571
  "pluginType": "core",
@@ -536,27 +575,14 @@
536
575
  "relativePath": [
537
576
  "dist",
538
577
  "commands",
539
- "billing",
540
- "usage.js"
578
+ "auth",
579
+ "register.js"
541
580
  ]
542
581
  },
543
- "auth:connect": {
582
+ "auth:whoami": {
544
583
  "aliases": [],
545
- "args": {
546
- "provider": {
547
- "description": "OAuth provider to connect",
548
- "name": "provider",
549
- "options": [
550
- "openai"
551
- ],
552
- "required": true
553
- }
554
- },
555
- "description": "Connect your ChatGPT account to Faces via device-code authorization (Subscription Connect plan)",
556
- "examples": [
557
- "<%= config.bin %> auth connect openai",
558
- "<%= config.bin %> auth connect openai --json"
559
- ],
584
+ "args": {},
585
+ "description": "Print current user profile and auth diagnostic",
560
586
  "flags": {
561
587
  "json": {
562
588
  "description": "Format output as json.",
@@ -592,7 +618,7 @@
592
618
  },
593
619
  "hasDynamicHelp": false,
594
620
  "hiddenAliases": [],
595
- "id": "auth:connect",
621
+ "id": "auth:whoami",
596
622
  "pluginAlias": "faces-cli",
597
623
  "pluginName": "faces-cli",
598
624
  "pluginType": "core",
@@ -603,17 +629,13 @@
603
629
  "dist",
604
630
  "commands",
605
631
  "auth",
606
- "connect.js"
632
+ "whoami.js"
607
633
  ]
608
634
  },
609
- "auth:connections": {
635
+ "catalog:backup": {
610
636
  "aliases": [],
611
637
  "args": {},
612
- "description": "List connected OAuth provider accounts",
613
- "examples": [
614
- "<%= config.bin %> auth connections",
615
- "<%= config.bin %> auth connections --json"
616
- ],
638
+ "description": "Snapshot all faces, teams, and source material for migration",
617
639
  "flags": {
618
640
  "json": {
619
641
  "description": "Format output as json.",
@@ -649,7 +671,7 @@
649
671
  },
650
672
  "hasDynamicHelp": false,
651
673
  "hiddenAliases": [],
652
- "id": "auth:connections",
674
+ "id": "catalog:backup",
653
675
  "pluginAlias": "faces-cli",
654
676
  "pluginName": "faces-cli",
655
677
  "pluginType": "core",
@@ -659,26 +681,14 @@
659
681
  "relativePath": [
660
682
  "dist",
661
683
  "commands",
662
- "auth",
663
- "connections.js"
684
+ "catalog",
685
+ "backup.js"
664
686
  ]
665
687
  },
666
- "auth:disconnect": {
688
+ "catalog:doctor": {
667
689
  "aliases": [],
668
- "args": {
669
- "provider": {
670
- "description": "OAuth provider to disconnect",
671
- "name": "provider",
672
- "options": [
673
- "openai"
674
- ],
675
- "required": true
676
- }
677
- },
678
- "description": "Disconnect a linked OAuth provider account",
679
- "examples": [
680
- "<%= config.bin %> auth disconnect openai"
681
- ],
690
+ "args": {},
691
+ "description": "Diagnose and repair the local face and team catalog",
682
692
  "flags": {
683
693
  "json": {
684
694
  "description": "Format output as json.",
@@ -710,11 +720,23 @@
710
720
  "hasDynamicHelp": false,
711
721
  "multiple": false,
712
722
  "type": "option"
723
+ },
724
+ "fix": {
725
+ "description": "Rebuild missing or stale catalog entries from API",
726
+ "name": "fix",
727
+ "allowNo": false,
728
+ "type": "boolean"
729
+ },
730
+ "generate": {
731
+ "description": "Fix + generate missing descriptions via LLM",
732
+ "name": "generate",
733
+ "allowNo": false,
734
+ "type": "boolean"
713
735
  }
714
736
  },
715
737
  "hasDynamicHelp": false,
716
738
  "hiddenAliases": [],
717
- "id": "auth:disconnect",
739
+ "id": "catalog:doctor",
718
740
  "pluginAlias": "faces-cli",
719
741
  "pluginName": "faces-cli",
720
742
  "pluginType": "core",
@@ -724,14 +746,14 @@
724
746
  "relativePath": [
725
747
  "dist",
726
748
  "commands",
727
- "auth",
728
- "disconnect.js"
749
+ "catalog",
750
+ "doctor.js"
729
751
  ]
730
752
  },
731
- "auth:login": {
753
+ "catalog:list": {
732
754
  "aliases": [],
733
755
  "args": {},
734
- "description": "Login and save JWT credentials",
756
+ "description": "List all faces in the local catalog",
735
757
  "flags": {
736
758
  "json": {
737
759
  "description": "Format output as json.",
@@ -763,27 +785,11 @@
763
785
  "hasDynamicHelp": false,
764
786
  "multiple": false,
765
787
  "type": "option"
766
- },
767
- "email": {
768
- "description": "Account email",
769
- "name": "email",
770
- "required": true,
771
- "hasDynamicHelp": false,
772
- "multiple": false,
773
- "type": "option"
774
- },
775
- "password": {
776
- "description": "Account password",
777
- "name": "password",
778
- "required": true,
779
- "hasDynamicHelp": false,
780
- "multiple": false,
781
- "type": "option"
782
788
  }
783
789
  },
784
790
  "hasDynamicHelp": false,
785
791
  "hiddenAliases": [],
786
- "id": "auth:login",
792
+ "id": "catalog:list",
787
793
  "pluginAlias": "faces-cli",
788
794
  "pluginName": "faces-cli",
789
795
  "pluginType": "core",
@@ -793,14 +799,14 @@
793
799
  "relativePath": [
794
800
  "dist",
795
801
  "commands",
796
- "auth",
797
- "login.js"
802
+ "catalog",
803
+ "list.js"
798
804
  ]
799
805
  },
800
- "auth:logout": {
806
+ "catalog:manyfaced": {
801
807
  "aliases": [],
802
808
  "args": {},
803
- "description": "Clear saved credentials",
809
+ "description": "Browse and install community manyfaced skills from github.com/facessh/manyfaced",
804
810
  "flags": {
805
811
  "json": {
806
812
  "description": "Format output as json.",
@@ -832,11 +838,38 @@
832
838
  "hasDynamicHelp": false,
833
839
  "multiple": false,
834
840
  "type": "option"
841
+ },
842
+ "skill": {
843
+ "description": "Show details for a specific skill",
844
+ "name": "skill",
845
+ "hasDynamicHelp": false,
846
+ "multiple": false,
847
+ "type": "option"
848
+ },
849
+ "install": {
850
+ "description": "Install a skill by name",
851
+ "name": "install",
852
+ "hasDynamicHelp": false,
853
+ "multiple": false,
854
+ "type": "option"
855
+ },
856
+ "skills-dir": {
857
+ "description": "Directory to install skills into (required for --install)",
858
+ "name": "skills-dir",
859
+ "hasDynamicHelp": false,
860
+ "multiple": false,
861
+ "type": "option"
862
+ },
863
+ "refresh": {
864
+ "description": "Force refresh the skill index (ignore cache)",
865
+ "name": "refresh",
866
+ "allowNo": false,
867
+ "type": "boolean"
835
868
  }
836
869
  },
837
870
  "hasDynamicHelp": false,
838
871
  "hiddenAliases": [],
839
- "id": "auth:logout",
872
+ "id": "catalog:manyfaced",
840
873
  "pluginAlias": "faces-cli",
841
874
  "pluginName": "faces-cli",
842
875
  "pluginType": "core",
@@ -846,14 +879,19 @@
846
879
  "relativePath": [
847
880
  "dist",
848
881
  "commands",
849
- "auth",
850
- "logout.js"
882
+ "catalog",
883
+ "manyfaced.js"
851
884
  ]
852
885
  },
853
- "auth:refresh": {
886
+ "catalog:restore": {
854
887
  "aliases": [],
855
- "args": {},
856
- "description": "Exchange current JWT for a fresh one",
888
+ "args": {
889
+ "file": {
890
+ "description": "Backup file path (default: most recent in ~/.faces/backups/)",
891
+ "name": "file"
892
+ }
893
+ },
894
+ "description": "Restore faces, teams, and source material from a backup snapshot",
857
895
  "flags": {
858
896
  "json": {
859
897
  "description": "Format output as json.",
@@ -885,11 +923,17 @@
885
923
  "hasDynamicHelp": false,
886
924
  "multiple": false,
887
925
  "type": "option"
926
+ },
927
+ "compile": {
928
+ "description": "Run compile:all after restoring",
929
+ "name": "compile",
930
+ "allowNo": false,
931
+ "type": "boolean"
888
932
  }
889
933
  },
890
934
  "hasDynamicHelp": false,
891
935
  "hiddenAliases": [],
892
- "id": "auth:refresh",
936
+ "id": "catalog:restore",
893
937
  "pluginAlias": "faces-cli",
894
938
  "pluginName": "faces-cli",
895
939
  "pluginType": "core",
@@ -899,14 +943,14 @@
899
943
  "relativePath": [
900
944
  "dist",
901
945
  "commands",
902
- "auth",
903
- "refresh.js"
946
+ "catalog",
947
+ "restore.js"
904
948
  ]
905
949
  },
906
- "auth:register": {
950
+ "billing:balance": {
907
951
  "aliases": [],
908
952
  "args": {},
909
- "description": "Create a new Faces account",
953
+ "description": "Show credit balance and payment method status",
910
954
  "flags": {
911
955
  "json": {
912
956
  "description": "Format output as json.",
@@ -938,54 +982,11 @@
938
982
  "hasDynamicHelp": false,
939
983
  "multiple": false,
940
984
  "type": "option"
941
- },
942
- "email": {
943
- "description": "Email address",
944
- "name": "email",
945
- "required": true,
946
- "hasDynamicHelp": false,
947
- "multiple": false,
948
- "type": "option"
949
- },
950
- "password": {
951
- "description": "Password",
952
- "name": "password",
953
- "required": true,
954
- "hasDynamicHelp": false,
955
- "multiple": false,
956
- "type": "option"
957
- },
958
- "username": {
959
- "description": "Username (lowercase, dashes, numbers)",
960
- "name": "username",
961
- "required": true,
962
- "hasDynamicHelp": false,
963
- "multiple": false,
964
- "type": "option"
965
- },
966
- "invite-key": {
967
- "description": "Invite key (if required)",
968
- "name": "invite-key",
969
- "hasDynamicHelp": false,
970
- "multiple": false,
971
- "type": "option"
972
- },
973
- "plan": {
974
- "description": "Plan to subscribe to: \"free\" ($5 activation) or \"connect\" ($17/mo, no activation fee)",
975
- "name": "plan",
976
- "default": "free",
977
- "hasDynamicHelp": false,
978
- "multiple": false,
979
- "options": [
980
- "free",
981
- "connect"
982
- ],
983
- "type": "option"
984
985
  }
985
986
  },
986
987
  "hasDynamicHelp": false,
987
988
  "hiddenAliases": [],
988
- "id": "auth:register",
989
+ "id": "billing:balance",
989
990
  "pluginAlias": "faces-cli",
990
991
  "pluginName": "faces-cli",
991
992
  "pluginType": "core",
@@ -995,14 +996,14 @@
995
996
  "relativePath": [
996
997
  "dist",
997
998
  "commands",
998
- "auth",
999
- "register.js"
999
+ "billing",
1000
+ "balance.js"
1000
1001
  ]
1001
1002
  },
1002
- "auth:whoami": {
1003
+ "billing:card-setup": {
1003
1004
  "aliases": [],
1004
1005
  "args": {},
1005
- "description": "Print current user profile and auth diagnostic",
1006
+ "description": "Get a Stripe card setup URL to save a payment method",
1006
1007
  "flags": {
1007
1008
  "json": {
1008
1009
  "description": "Format output as json.",
@@ -1038,7 +1039,7 @@
1038
1039
  },
1039
1040
  "hasDynamicHelp": false,
1040
1041
  "hiddenAliases": [],
1041
- "id": "auth:whoami",
1042
+ "id": "billing:card-setup",
1042
1043
  "pluginAlias": "faces-cli",
1043
1044
  "pluginName": "faces-cli",
1044
1045
  "pluginType": "core",
@@ -1048,14 +1049,14 @@
1048
1049
  "relativePath": [
1049
1050
  "dist",
1050
1051
  "commands",
1051
- "auth",
1052
- "whoami.js"
1052
+ "billing",
1053
+ "card-setup.js"
1053
1054
  ]
1054
1055
  },
1055
- "catalog:backup": {
1056
+ "billing:llm-costs": {
1056
1057
  "aliases": [],
1057
1058
  "args": {},
1058
- "description": "Snapshot all faces, teams, and source material for migration",
1059
+ "description": "List available LLMs and their per-token costs",
1059
1060
  "flags": {
1060
1061
  "json": {
1061
1062
  "description": "Format output as json.",
@@ -1087,11 +1088,18 @@
1087
1088
  "hasDynamicHelp": false,
1088
1089
  "multiple": false,
1089
1090
  "type": "option"
1091
+ },
1092
+ "provider": {
1093
+ "description": "Filter by provider (e.g. openai, anthropic)",
1094
+ "name": "provider",
1095
+ "hasDynamicHelp": false,
1096
+ "multiple": false,
1097
+ "type": "option"
1090
1098
  }
1091
1099
  },
1092
1100
  "hasDynamicHelp": false,
1093
1101
  "hiddenAliases": [],
1094
- "id": "catalog:backup",
1102
+ "id": "billing:llm-costs",
1095
1103
  "pluginAlias": "faces-cli",
1096
1104
  "pluginName": "faces-cli",
1097
1105
  "pluginType": "core",
@@ -1101,14 +1109,14 @@
1101
1109
  "relativePath": [
1102
1110
  "dist",
1103
1111
  "commands",
1104
- "catalog",
1105
- "backup.js"
1112
+ "billing",
1113
+ "llm-costs.js"
1106
1114
  ]
1107
1115
  },
1108
- "catalog:doctor": {
1116
+ "billing:quota": {
1109
1117
  "aliases": [],
1110
1118
  "args": {},
1111
- "description": "Diagnose and repair the local face and team catalog",
1119
+ "description": "Show compilation stats per face (deprecated use compile:stats)",
1112
1120
  "flags": {
1113
1121
  "json": {
1114
1122
  "description": "Format output as json.",
@@ -1140,23 +1148,11 @@
1140
1148
  "hasDynamicHelp": false,
1141
1149
  "multiple": false,
1142
1150
  "type": "option"
1143
- },
1144
- "fix": {
1145
- "description": "Rebuild missing or stale catalog entries from API",
1146
- "name": "fix",
1147
- "allowNo": false,
1148
- "type": "boolean"
1149
- },
1150
- "generate": {
1151
- "description": "Fix + generate missing descriptions via LLM",
1152
- "name": "generate",
1153
- "allowNo": false,
1154
- "type": "boolean"
1155
1151
  }
1156
1152
  },
1157
1153
  "hasDynamicHelp": false,
1158
1154
  "hiddenAliases": [],
1159
- "id": "catalog:doctor",
1155
+ "id": "billing:quota",
1160
1156
  "pluginAlias": "faces-cli",
1161
1157
  "pluginName": "faces-cli",
1162
1158
  "pluginType": "core",
@@ -1166,14 +1162,14 @@
1166
1162
  "relativePath": [
1167
1163
  "dist",
1168
1164
  "commands",
1169
- "catalog",
1170
- "doctor.js"
1165
+ "billing",
1166
+ "quota.js"
1171
1167
  ]
1172
1168
  },
1173
- "catalog:list": {
1169
+ "billing:subscription": {
1174
1170
  "aliases": [],
1175
1171
  "args": {},
1176
- "description": "List all faces in the local catalog",
1172
+ "description": "Show current plan, face count, and renewal date",
1177
1173
  "flags": {
1178
1174
  "json": {
1179
1175
  "description": "Format output as json.",
@@ -1209,7 +1205,7 @@
1209
1205
  },
1210
1206
  "hasDynamicHelp": false,
1211
1207
  "hiddenAliases": [],
1212
- "id": "catalog:list",
1208
+ "id": "billing:subscription",
1213
1209
  "pluginAlias": "faces-cli",
1214
1210
  "pluginName": "faces-cli",
1215
1211
  "pluginType": "core",
@@ -1219,14 +1215,14 @@
1219
1215
  "relativePath": [
1220
1216
  "dist",
1221
1217
  "commands",
1222
- "catalog",
1223
- "list.js"
1218
+ "billing",
1219
+ "subscription.js"
1224
1220
  ]
1225
1221
  },
1226
- "catalog:manyfaced": {
1222
+ "billing:topup": {
1227
1223
  "aliases": [],
1228
1224
  "args": {},
1229
- "description": "Browse and install community manyfaced skills from github.com/facessh/manyfaced",
1225
+ "description": "Top up credit balance using saved payment method",
1230
1226
  "flags": {
1231
1227
  "json": {
1232
1228
  "description": "Format output as json.",
@@ -1259,37 +1255,25 @@
1259
1255
  "multiple": false,
1260
1256
  "type": "option"
1261
1257
  },
1262
- "skill": {
1263
- "description": "Show details for a specific skill",
1264
- "name": "skill",
1265
- "hasDynamicHelp": false,
1266
- "multiple": false,
1267
- "type": "option"
1268
- },
1269
- "install": {
1270
- "description": "Install a skill by name",
1271
- "name": "install",
1258
+ "amount": {
1259
+ "description": "Top-up amount in USD (min $1)",
1260
+ "name": "amount",
1261
+ "required": true,
1272
1262
  "hasDynamicHelp": false,
1273
1263
  "multiple": false,
1274
1264
  "type": "option"
1275
1265
  },
1276
- "skills-dir": {
1277
- "description": "Directory to install skills into (required for --install)",
1278
- "name": "skills-dir",
1266
+ "payment-ref": {
1267
+ "description": "Payment reference (admin/test path)",
1268
+ "name": "payment-ref",
1279
1269
  "hasDynamicHelp": false,
1280
1270
  "multiple": false,
1281
1271
  "type": "option"
1282
- },
1283
- "refresh": {
1284
- "description": "Force refresh the skill index (ignore cache)",
1285
- "name": "refresh",
1286
- "allowNo": false,
1287
- "type": "boolean"
1288
1272
  }
1289
1273
  },
1290
1274
  "hasDynamicHelp": false,
1291
1275
  "hiddenAliases": [],
1292
- "id": "catalog:manyfaced",
1276
+ "id": "billing:topup",
1293
1277
  "pluginAlias": "faces-cli",
1294
1278
  "pluginName": "faces-cli",
1295
1279
  "pluginType": "core",
@@ -1299,19 +1283,14 @@
1299
1283
  "relativePath": [
1300
1284
  "dist",
1301
1285
  "commands",
1302
- "catalog",
1303
- "manyfaced.js"
1286
+ "billing",
1287
+ "topup.js"
1304
1288
  ]
1305
1289
  },
1306
- "catalog:restore": {
1290
+ "billing:usage": {
1307
1291
  "aliases": [],
1308
- "args": {
1309
- "file": {
1310
- "description": "Backup file path (default: most recent in ~/.faces/backups/)",
1311
- "name": "file"
1312
- }
1313
- },
1314
- "description": "Restore faces, teams, and source material from a backup snapshot",
1292
+ "args": {},
1293
+ "description": "Aggregated usage analytics",
1315
1294
  "flags": {
1316
1295
  "json": {
1317
1296
  "description": "Format output as json.",
@@ -1344,16 +1323,37 @@
1344
1323
  "multiple": false,
1345
1324
  "type": "option"
1346
1325
  },
1347
- "compile": {
1348
- "description": "Run compile:all after restoring",
1349
- "name": "compile",
1350
- "allowNo": false,
1351
- "type": "boolean"
1326
+ "group-by": {
1327
+ "description": "Group results",
1328
+ "name": "group-by",
1329
+ "hasDynamicHelp": false,
1330
+ "multiple": false,
1331
+ "options": [
1332
+ "api_key",
1333
+ "model",
1334
+ "llm",
1335
+ "date"
1336
+ ],
1337
+ "type": "option"
1338
+ },
1339
+ "from": {
1340
+ "description": "Start date (YYYY-MM-DD)",
1341
+ "name": "from",
1342
+ "hasDynamicHelp": false,
1343
+ "multiple": false,
1344
+ "type": "option"
1345
+ },
1346
+ "to": {
1347
+ "description": "End date (YYYY-MM-DD)",
1348
+ "name": "to",
1349
+ "hasDynamicHelp": false,
1350
+ "multiple": false,
1351
+ "type": "option"
1352
1352
  }
1353
1353
  },
1354
1354
  "hasDynamicHelp": false,
1355
1355
  "hiddenAliases": [],
1356
- "id": "catalog:restore",
1356
+ "id": "billing:usage",
1357
1357
  "pluginAlias": "faces-cli",
1358
1358
  "pluginName": "faces-cli",
1359
1359
  "pluginType": "core",
@@ -1363,20 +1363,25 @@
1363
1363
  "relativePath": [
1364
1364
  "dist",
1365
1365
  "commands",
1366
- "catalog",
1367
- "restore.js"
1366
+ "billing",
1367
+ "usage.js"
1368
1368
  ]
1369
1369
  },
1370
1370
  "chat:chat": {
1371
1371
  "aliases": [],
1372
1372
  "args": {
1373
1373
  "face_username": {
1374
- "description": "Face alias (alias@model, or owner:alias@model for a published face)",
1374
+ "description": "Face alias (alias@model, owner:alias@model for a published face, or a composite formula like \"(a | b)@model\"). Omit when using --formula.",
1375
1375
  "name": "face_username",
1376
- "required": true
1376
+ "required": false
1377
1377
  }
1378
1378
  },
1379
1379
  "description": "Chat via a face. Auto-routes to the correct API endpoint based on the model catalog.",
1380
+ "examples": [
1381
+ "<%= config.bin %> <%= command.id %> socrates -m \"What is virtue?\"",
1382
+ "<%= config.bin %> <%= command.id %> \"(socrates | nietzsche)@claude-sonnet-4-6\" -m \"What is virtue?\"",
1383
+ "<%= config.bin %> <%= command.id %> --formula \"socrates | nietzsche\" --llm claude-sonnet-4-6 -m \"What is virtue?\""
1384
+ ],
1380
1385
  "flags": {
1381
1386
  "json": {
1382
1387
  "description": "Format output as json.",
@@ -1425,6 +1430,13 @@
1425
1430
  "multiple": false,
1426
1431
  "type": "option"
1427
1432
  },
1433
+ "formula": {
1434
+ "description": "Compose a run-time composite from your own faces, e.g. \"socrates | nietzsche\" (operators: | & ^ -). Requires --llm. The composite takes the name of its first operand; use face:create --formula for a named, persisted composite.",
1435
+ "name": "formula",
1436
+ "hasDynamicHelp": false,
1437
+ "multiple": false,
1438
+ "type": "option"
1439
+ },
1428
1440
  "system": {
1429
1441
  "description": "System prompt / instructions",
1430
1442
  "name": "system",
@@ -6066,5 +6078,5 @@
6066
6078
  ]
6067
6079
  }
6068
6080
  },
6069
- "version": "1.7.1"
6081
+ "version": "1.7.3"
6070
6082
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "faces-cli",
3
- "version": "1.7.1",
3
+ "version": "1.7.3",
4
4
  "description": "CLI for the Faces AI platform",
5
5
  "type": "module",
6
6
  "author": "sybileak <sybileak@proton.me>",