faces-cli 1.5.2 → 1.5.4

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/dist/base.d.ts CHANGED
@@ -12,5 +12,8 @@ export declare abstract class BaseCommand extends Command {
12
12
  token?: string;
13
13
  'api-key'?: string;
14
14
  }, _requireJwt?: boolean): FacesClient;
15
+ catch(err: Error & {
16
+ exitCode?: number;
17
+ }): Promise<unknown>;
15
18
  protected printHuman(data: unknown, indent?: number): void;
16
19
  }
package/dist/base.js CHANGED
@@ -23,6 +23,16 @@ export class BaseCommand extends Command {
23
23
  const apiKey = resolveApiKey(flags['api-key']);
24
24
  return new FacesClient(baseUrl, token, apiKey);
25
25
  }
26
+ async catch(err) {
27
+ // When --json is enabled, oclif swallows error messages. Override to
28
+ // include the message in structured JSON output so agents can parse it.
29
+ if (this.jsonEnabled()) {
30
+ const code = err.exitCode ?? 1;
31
+ process.stdout.write(JSON.stringify({ error: { message: err.message, code } }) + '\n');
32
+ process.exit(code);
33
+ }
34
+ throw err;
35
+ }
26
36
  printHuman(data, indent = 0) {
27
37
  const prefix = ' '.repeat(indent);
28
38
  if (Array.isArray(data)) {
@@ -7,6 +7,7 @@ export default class CompileDoc extends BaseCommand {
7
7
  file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
8
  perspective: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
9
  timeout: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
10
+ 'no-wait': import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
11
  'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
12
  token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
13
  'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -16,6 +16,10 @@ export default class CompileDoc extends BaseCommand {
16
16
  default: 'first-person',
17
17
  }),
18
18
  timeout: Flags.integer({ description: 'Compile timeout in seconds (default: 600)', default: 600 }),
19
+ 'no-wait': Flags.boolean({
20
+ description: 'Create and trigger compilation, then return immediately without polling.',
21
+ default: false,
22
+ }),
19
23
  };
20
24
  static args = {
21
25
  face_id: Args.string({ description: 'Face alias', required: true }),
@@ -64,6 +68,13 @@ export default class CompileDoc extends BaseCommand {
64
68
  throw err;
65
69
  }
66
70
  const chunksTotal = makeResponse.chunks_total;
71
+ if (flags['no-wait']) {
72
+ if (!json) {
73
+ process.stderr.write(`Compilation started in background${chunksTotal ? ` (${chunksTotal} chunks)` : ''}.\n`);
74
+ process.stderr.write(`Poll with: faces compile:doc:get ${docId} --json\n`);
75
+ }
76
+ return makeResponse;
77
+ }
67
78
  if (!json)
68
79
  process.stderr.write(`Compiling${chunksTotal ? ` (${chunksTotal} chunks)` : ''}:\n`);
69
80
  // Step 3: Poll until synced
@@ -37,10 +37,11 @@ export default class CompileThreadEdit extends BaseCommand {
37
37
  if (!messages || messages.length === 0) {
38
38
  this.error('Thread has no messages to remap');
39
39
  }
40
- // Remap roles
40
+ // Remap roles — case-insensitive exact match against speaker label
41
41
  let remapped = 0;
42
+ const speakerLower = speaker.toLowerCase();
42
43
  const updated = messages.map((m) => {
43
- const isFace = m.name && m.name.toLowerCase() === speaker.toLowerCase();
44
+ const isFace = (m.name ?? '').toLowerCase() === speakerLower;
44
45
  const newRole = isFace ? 'user' : 'assistant';
45
46
  if (m.role !== newRole)
46
47
  remapped++;
@@ -1453,10 +1453,16 @@
1453
1453
  "responses.js"
1454
1454
  ]
1455
1455
  },
1456
- "config:clear": {
1456
+ "compile:import": {
1457
1457
  "aliases": [],
1458
- "args": {},
1459
- "description": "Delete all saved credentials and config",
1458
+ "args": {
1459
+ "face_id": {
1460
+ "description": "Face alias",
1461
+ "name": "face_id",
1462
+ "required": true
1463
+ }
1464
+ },
1465
+ "description": "Import a YouTube video into a face via server-side download and transcription",
1460
1466
  "flags": {
1461
1467
  "json": {
1462
1468
  "description": "Format output as json.",
@@ -1489,16 +1495,55 @@
1489
1495
  "multiple": false,
1490
1496
  "type": "option"
1491
1497
  },
1492
- "yes": {
1493
- "description": "Skip confirmation",
1494
- "name": "yes",
1498
+ "url": {
1499
+ "description": "YouTube URL (youtube.com/watch?v=... or youtu.be/...)",
1500
+ "name": "url",
1501
+ "required": true,
1502
+ "hasDynamicHelp": false,
1503
+ "multiple": false,
1504
+ "type": "option"
1505
+ },
1506
+ "type": {
1507
+ "description": "\"document\" for solo talks, lectures, monologues; \"thread\" for interviews or multi-speaker conversations",
1508
+ "name": "type",
1509
+ "default": "document",
1510
+ "hasDynamicHelp": false,
1511
+ "multiple": false,
1512
+ "options": [
1513
+ "document",
1514
+ "thread"
1515
+ ],
1516
+ "type": "option"
1517
+ },
1518
+ "perspective": {
1519
+ "description": "\"first-person\" if the face is the speaker; \"third-person\" if the video is about the face",
1520
+ "name": "perspective",
1521
+ "default": "third-person",
1522
+ "hasDynamicHelp": false,
1523
+ "multiple": false,
1524
+ "options": [
1525
+ "first-person",
1526
+ "third-person"
1527
+ ],
1528
+ "type": "option"
1529
+ },
1530
+ "face-speaker": {
1531
+ "description": "For --type thread: AssemblyAI speaker label (e.g. \"A\") that corresponds to the face. Defaults to first detected speaker.",
1532
+ "name": "face-speaker",
1533
+ "hasDynamicHelp": false,
1534
+ "multiple": false,
1535
+ "type": "option"
1536
+ },
1537
+ "no-wait": {
1538
+ "description": "Return immediately after import starts (do not poll for transcription). Prints the ID for manual polling.",
1539
+ "name": "no-wait",
1495
1540
  "allowNo": false,
1496
1541
  "type": "boolean"
1497
1542
  }
1498
1543
  },
1499
1544
  "hasDynamicHelp": false,
1500
1545
  "hiddenAliases": [],
1501
- "id": "config:clear",
1546
+ "id": "compile:import",
1502
1547
  "pluginAlias": "faces-cli",
1503
1548
  "pluginName": "faces-cli",
1504
1549
  "pluginType": "core",
@@ -1508,25 +1553,20 @@
1508
1553
  "relativePath": [
1509
1554
  "dist",
1510
1555
  "commands",
1511
- "config",
1512
- "clear.js"
1556
+ "compile",
1557
+ "import.js"
1513
1558
  ]
1514
1559
  },
1515
- "config:set": {
1560
+ "compile:upload": {
1516
1561
  "aliases": [],
1517
1562
  "args": {
1518
- "key": {
1519
- "description": "Config key",
1520
- "name": "key",
1521
- "required": true
1522
- },
1523
- "value": {
1524
- "description": "Config value",
1525
- "name": "value",
1563
+ "alias": {
1564
+ "description": "Face alias",
1565
+ "name": "alias",
1526
1566
  "required": true
1527
1567
  }
1528
1568
  },
1529
- "description": "Set a config value (e.g. base_url, api_key, token)",
1569
+ "description": "Upload a file (text/PDF/audio/video) to compile into a face",
1530
1570
  "flags": {
1531
1571
  "json": {
1532
1572
  "description": "Format output as json.",
@@ -1558,11 +1598,56 @@
1558
1598
  "hasDynamicHelp": false,
1559
1599
  "multiple": false,
1560
1600
  "type": "option"
1601
+ },
1602
+ "file": {
1603
+ "description": "File to upload",
1604
+ "name": "file",
1605
+ "required": true,
1606
+ "hasDynamicHelp": false,
1607
+ "multiple": false,
1608
+ "type": "option"
1609
+ },
1610
+ "kind": {
1611
+ "description": "Upload kind: document or thread",
1612
+ "name": "kind",
1613
+ "default": "document",
1614
+ "hasDynamicHelp": false,
1615
+ "multiple": false,
1616
+ "options": [
1617
+ "document",
1618
+ "thread"
1619
+ ],
1620
+ "type": "option"
1621
+ },
1622
+ "perspective": {
1623
+ "description": "Perspective (document only)",
1624
+ "name": "perspective",
1625
+ "default": "third-person",
1626
+ "hasDynamicHelp": false,
1627
+ "multiple": false,
1628
+ "options": [
1629
+ "first-person",
1630
+ "third-person"
1631
+ ],
1632
+ "type": "option"
1633
+ },
1634
+ "face-speaker": {
1635
+ "description": "Speaker name to map to the face (thread only). If omitted, auto-detected from face name.",
1636
+ "name": "face-speaker",
1637
+ "hasDynamicHelp": false,
1638
+ "multiple": false,
1639
+ "type": "option"
1640
+ },
1641
+ "no-wait": {
1642
+ "description": "Return immediately after upload (do not poll for transcription). Prints the ID for manual polling.",
1643
+ "name": "no-wait",
1644
+ "allowNo": false,
1645
+ "type": "boolean"
1561
1646
  }
1562
1647
  },
1563
1648
  "hasDynamicHelp": false,
1564
1649
  "hiddenAliases": [],
1565
- "id": "config:set",
1650
+ "id": "compile:upload",
1566
1651
  "pluginAlias": "faces-cli",
1567
1652
  "pluginName": "faces-cli",
1568
1653
  "pluginType": "core",
@@ -1572,14 +1657,14 @@
1572
1657
  "relativePath": [
1573
1658
  "dist",
1574
1659
  "commands",
1575
- "config",
1576
- "set.js"
1660
+ "compile",
1661
+ "upload.js"
1577
1662
  ]
1578
1663
  },
1579
- "config:show": {
1664
+ "config:clear": {
1580
1665
  "aliases": [],
1581
1666
  "args": {},
1582
- "description": "Print current config (credentials are masked)",
1667
+ "description": "Delete all saved credentials and config",
1583
1668
  "flags": {
1584
1669
  "json": {
1585
1670
  "description": "Format output as json.",
@@ -1611,11 +1696,17 @@
1611
1696
  "hasDynamicHelp": false,
1612
1697
  "multiple": false,
1613
1698
  "type": "option"
1699
+ },
1700
+ "yes": {
1701
+ "description": "Skip confirmation",
1702
+ "name": "yes",
1703
+ "allowNo": false,
1704
+ "type": "boolean"
1614
1705
  }
1615
1706
  },
1616
1707
  "hasDynamicHelp": false,
1617
1708
  "hiddenAliases": [],
1618
- "id": "config:show",
1709
+ "id": "config:clear",
1619
1710
  "pluginAlias": "faces-cli",
1620
1711
  "pluginName": "faces-cli",
1621
1712
  "pluginType": "core",
@@ -1626,19 +1717,24 @@
1626
1717
  "dist",
1627
1718
  "commands",
1628
1719
  "config",
1629
- "show.js"
1720
+ "clear.js"
1630
1721
  ]
1631
1722
  },
1632
- "compile:import": {
1723
+ "config:set": {
1633
1724
  "aliases": [],
1634
1725
  "args": {
1635
- "face_id": {
1636
- "description": "Face alias",
1637
- "name": "face_id",
1726
+ "key": {
1727
+ "description": "Config key",
1728
+ "name": "key",
1729
+ "required": true
1730
+ },
1731
+ "value": {
1732
+ "description": "Config value",
1733
+ "name": "value",
1638
1734
  "required": true
1639
1735
  }
1640
1736
  },
1641
- "description": "Import a YouTube video into a face via server-side download and transcription",
1737
+ "description": "Set a config value (e.g. base_url, api_key, token)",
1642
1738
  "flags": {
1643
1739
  "json": {
1644
1740
  "description": "Format output as json.",
@@ -1670,56 +1766,11 @@
1670
1766
  "hasDynamicHelp": false,
1671
1767
  "multiple": false,
1672
1768
  "type": "option"
1673
- },
1674
- "url": {
1675
- "description": "YouTube URL (youtube.com/watch?v=... or youtu.be/...)",
1676
- "name": "url",
1677
- "required": true,
1678
- "hasDynamicHelp": false,
1679
- "multiple": false,
1680
- "type": "option"
1681
- },
1682
- "type": {
1683
- "description": "\"document\" for solo talks, lectures, monologues; \"thread\" for interviews or multi-speaker conversations",
1684
- "name": "type",
1685
- "default": "document",
1686
- "hasDynamicHelp": false,
1687
- "multiple": false,
1688
- "options": [
1689
- "document",
1690
- "thread"
1691
- ],
1692
- "type": "option"
1693
- },
1694
- "perspective": {
1695
- "description": "\"first-person\" if the face is the speaker; \"third-person\" if the video is about the face",
1696
- "name": "perspective",
1697
- "default": "third-person",
1698
- "hasDynamicHelp": false,
1699
- "multiple": false,
1700
- "options": [
1701
- "first-person",
1702
- "third-person"
1703
- ],
1704
- "type": "option"
1705
- },
1706
- "face-speaker": {
1707
- "description": "For --type thread: AssemblyAI speaker label (e.g. \"A\") that corresponds to the face. Defaults to first detected speaker.",
1708
- "name": "face-speaker",
1709
- "hasDynamicHelp": false,
1710
- "multiple": false,
1711
- "type": "option"
1712
- },
1713
- "no-wait": {
1714
- "description": "Return immediately after import starts (do not poll for transcription). Prints the ID for manual polling.",
1715
- "name": "no-wait",
1716
- "allowNo": false,
1717
- "type": "boolean"
1718
1769
  }
1719
1770
  },
1720
1771
  "hasDynamicHelp": false,
1721
1772
  "hiddenAliases": [],
1722
- "id": "compile:import",
1773
+ "id": "config:set",
1723
1774
  "pluginAlias": "faces-cli",
1724
1775
  "pluginName": "faces-cli",
1725
1776
  "pluginType": "core",
@@ -1729,20 +1780,14 @@
1729
1780
  "relativePath": [
1730
1781
  "dist",
1731
1782
  "commands",
1732
- "compile",
1733
- "import.js"
1783
+ "config",
1784
+ "set.js"
1734
1785
  ]
1735
1786
  },
1736
- "compile:upload": {
1787
+ "config:show": {
1737
1788
  "aliases": [],
1738
- "args": {
1739
- "alias": {
1740
- "description": "Face alias",
1741
- "name": "alias",
1742
- "required": true
1743
- }
1744
- },
1745
- "description": "Upload a file (text/PDF/audio/video) to compile into a face",
1789
+ "args": {},
1790
+ "description": "Print current config (credentials are masked)",
1746
1791
  "flags": {
1747
1792
  "json": {
1748
1793
  "description": "Format output as json.",
@@ -1774,56 +1819,11 @@
1774
1819
  "hasDynamicHelp": false,
1775
1820
  "multiple": false,
1776
1821
  "type": "option"
1777
- },
1778
- "file": {
1779
- "description": "File to upload",
1780
- "name": "file",
1781
- "required": true,
1782
- "hasDynamicHelp": false,
1783
- "multiple": false,
1784
- "type": "option"
1785
- },
1786
- "kind": {
1787
- "description": "Upload kind: document or thread",
1788
- "name": "kind",
1789
- "default": "document",
1790
- "hasDynamicHelp": false,
1791
- "multiple": false,
1792
- "options": [
1793
- "document",
1794
- "thread"
1795
- ],
1796
- "type": "option"
1797
- },
1798
- "perspective": {
1799
- "description": "Perspective (document only)",
1800
- "name": "perspective",
1801
- "default": "third-person",
1802
- "hasDynamicHelp": false,
1803
- "multiple": false,
1804
- "options": [
1805
- "first-person",
1806
- "third-person"
1807
- ],
1808
- "type": "option"
1809
- },
1810
- "face-speaker": {
1811
- "description": "Speaker name to map to the face (thread only). If omitted, auto-detected from face name.",
1812
- "name": "face-speaker",
1813
- "hasDynamicHelp": false,
1814
- "multiple": false,
1815
- "type": "option"
1816
- },
1817
- "no-wait": {
1818
- "description": "Return immediately after upload (do not poll for transcription). Prints the ID for manual polling.",
1819
- "name": "no-wait",
1820
- "allowNo": false,
1821
- "type": "boolean"
1822
1822
  }
1823
1823
  },
1824
1824
  "hasDynamicHelp": false,
1825
1825
  "hiddenAliases": [],
1826
- "id": "compile:upload",
1826
+ "id": "config:show",
1827
1827
  "pluginAlias": "faces-cli",
1828
1828
  "pluginName": "faces-cli",
1829
1829
  "pluginType": "core",
@@ -1833,8 +1833,8 @@
1833
1833
  "relativePath": [
1834
1834
  "dist",
1835
1835
  "commands",
1836
- "compile",
1837
- "upload.js"
1836
+ "config",
1837
+ "show.js"
1838
1838
  ]
1839
1839
  },
1840
1840
  "face:create": {
@@ -3197,6 +3197,12 @@
3197
3197
  "hasDynamicHelp": false,
3198
3198
  "multiple": false,
3199
3199
  "type": "option"
3200
+ },
3201
+ "no-wait": {
3202
+ "description": "Create and trigger compilation, then return immediately without polling.",
3203
+ "name": "no-wait",
3204
+ "allowNo": false,
3205
+ "type": "boolean"
3200
3206
  }
3201
3207
  },
3202
3208
  "hasDynamicHelp": false,
@@ -3881,5 +3887,5 @@
3881
3887
  ]
3882
3888
  }
3883
3889
  },
3884
- "version": "1.5.2"
3890
+ "version": "1.5.4"
3885
3891
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "faces-cli",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "description": "CLI for the Faces AI platform",
5
5
  "type": "module",
6
6
  "author": "sybileak <sybileak@proton.me>",